mirror of https://github.com/trapexit/mergerfs.git
Browse Source
Change getattr and statx to bespoke policies
Change getattr and statx to bespoke policies
* Provides: slight improvement in performance as it no longer will need to find and then act on the files. * It doesn't make sense to support all original policy types. Most people used 'newest' or 'ff' and 'combine' is a better default which has same runtime as 'newest' but with better output.bespoke-policies
145 changed files with 3804 additions and 1193 deletions
-
77libfuse/lib/debug.cpp
-
1libfuse/lib/debug.hpp
-
2libfuse/lib/fuse_lowlevel.cpp
-
108src/atomicsharedptr.hpp
-
11src/category.hpp
-
28src/config.cpp
-
32src/config.hpp
-
8src/config_follow_symlinks.hpp
-
41src/config_getattr_statx.hpp
-
21src/error.hpp
-
9src/follow_symlinks_enum.hpp
-
19src/fs_lstat.hpp
-
0src/fs_stat.cpp
-
61src/fs_stat.hpp
-
62src/fs_statx.hpp
-
36src/fsproxy.cpp
-
54src/fsproxy.hpp
-
16src/func_access.hpp
-
31src/func_access_all.cpp
-
19src/func_access_all.hpp
-
24src/func_access_base.hpp
-
30src/func_access_factory.cpp
-
13src/func_access_factory.hpp
-
17src/func_chmod.hpp
-
35src/func_chmod_all.cpp
-
19src/func_chmod_all.hpp
-
26src/func_chmod_base.hpp
-
30src/func_chmod_factory.cpp
-
13src/func_chmod_factory.hpp
-
18src/func_chown.hpp
-
36src/func_chown_all.cpp
-
20src/func_chown_all.hpp
-
27src/func_chown_base.hpp
-
30src/func_chown_factory.cpp
-
13src/func_chown_factory.hpp
-
19src/func_getattr.hpp
-
35src/func_getattr_base.hpp
-
74src/func_getattr_cdco.cpp
-
21src/func_getattr_cdco.hpp
-
78src/func_getattr_cdfo.cpp
-
21src/func_getattr_cdfo.hpp
-
44src/func_getattr_factory.cpp
-
13src/func_getattr_factory.hpp
-
44src/func_getattr_ff.cpp
-
23src/func_getattr_ff.hpp
-
59src/func_getattr_newest.cpp
-
21src/func_getattr_newest.hpp
-
19src/func_getxattr.hpp
-
25src/func_getxattr_base.hpp
-
30src/func_getxattr_factory.cpp
-
13src/func_getxattr_factory.hpp
-
35src/func_getxattr_ff.cpp
-
21src/func_getxattr_ff.hpp
-
16src/func_ioctl.hpp
-
22src/func_ioctl_base.hpp
-
30src/func_ioctl_factory.cpp
-
13src/func_ioctl_factory.hpp
-
25src/func_ioctl_ff.cpp
-
18src/func_ioctl_ff.hpp
-
18src/func_listxattr.hpp
-
24src/func_listxattr_base.hpp
-
30src/func_listxattr_factory.cpp
-
13src/func_listxattr_factory.hpp
-
53src/func_listxattr_ff.cpp
-
20src/func_listxattr_ff.hpp
-
17src/func_open.hpp
-
26src/func_open_base.hpp
-
30src/func_open_factory.cpp
-
13src/func_open_factory.hpp
-
27src/func_open_ff.cpp
-
19src/func_open_ff.hpp
-
19src/func_readlink.hpp
-
25src/func_readlink_base.hpp
-
30src/func_readlink_factory.cpp
-
13src/func_readlink_factory.hpp
-
104src/func_readlink_ff.cpp
-
21src/func_readlink_ff.hpp
-
17src/func_removexattr.hpp
-
35src/func_removexattr_all.cpp
-
19src/func_removexattr_all.hpp
-
23src/func_removexattr_base.hpp
-
30src/func_removexattr_factory.cpp
-
13src/func_removexattr_factory.hpp
-
16src/func_rmdir.hpp
-
49src/func_rmdir_all.cpp
-
18src/func_rmdir_all.hpp
-
22src/func_rmdir_base.hpp
-
30src/func_rmdir_factory.cpp
-
13src/func_rmdir_factory.hpp
-
20src/func_setxattr.hpp
-
38src/func_setxattr_all.cpp
-
22src/func_setxattr_all.hpp
-
26src/func_setxattr_base.hpp
-
30src/func_setxattr_factory.cpp
-
13src/func_setxattr_factory.hpp
-
21src/func_statx.hpp
-
38src/func_statx_base.hpp
-
81src/func_statx_cdco.cpp
-
23src/func_statx_cdco.hpp
-
84src/func_statx_cdfo.cpp
@ -0,0 +1,108 @@ |
|||
#pragma once
|
|||
|
|||
#include <memory>
|
|||
#include <utility>
|
|||
|
|||
template<typename T> |
|||
class AtomicSharedPtr |
|||
{ |
|||
private: |
|||
std::shared_ptr<T> _ptr; |
|||
|
|||
public: |
|||
AtomicSharedPtr() = default; |
|||
|
|||
explicit |
|||
AtomicSharedPtr(std::shared_ptr<T> ptr_) |
|||
: _ptr(std::move(ptr_)) |
|||
{ |
|||
} |
|||
|
|||
template<typename... Args> |
|||
explicit |
|||
AtomicSharedPtr(Args&&... args) |
|||
: _ptr(std::make_shared<T>(std::forward<Args>(args)...)) |
|||
{ |
|||
} |
|||
|
|||
AtomicSharedPtr(const AtomicSharedPtr&) = delete; |
|||
AtomicSharedPtr& operator=(const AtomicSharedPtr&) = delete; |
|||
|
|||
AtomicSharedPtr(AtomicSharedPtr&& other_) noexcept |
|||
: _ptr(std::move(other_._ptr)) |
|||
{ |
|||
} |
|||
|
|||
AtomicSharedPtr& |
|||
operator=(AtomicSharedPtr&& other_) noexcept |
|||
{ |
|||
if(this != &other_) |
|||
_ptr = std::move(other_._ptr); |
|||
|
|||
return *this; |
|||
} |
|||
|
|||
std::shared_ptr<T> |
|||
load() const |
|||
{ |
|||
return std::atomic_load(&_ptr); |
|||
} |
|||
|
|||
void |
|||
store(std::shared_ptr<T> desired_) |
|||
{ |
|||
std::atomic_store(&_ptr, std::move(desired_)); |
|||
} |
|||
|
|||
std::shared_ptr<T> |
|||
exchange(std::shared_ptr<T> desired_) |
|||
{ |
|||
return std::atomic_exchange(&_ptr, std::move(desired_)); |
|||
} |
|||
|
|||
bool |
|||
compare_exchange_strong(std::shared_ptr<T>& expected_, |
|||
std::shared_ptr<T> desired_) |
|||
{ |
|||
return std::atomic_compare_exchange_strong(&_ptr, |
|||
&expected_, |
|||
std::move(desired_)); |
|||
} |
|||
|
|||
bool |
|||
compare_exchange_weak(std::shared_ptr<T>& expected_, |
|||
std::shared_ptr<T> desired_) |
|||
{ |
|||
return std::atomic_compare_exchange_weak(&_ptr, |
|||
&expected_, |
|||
std::move(desired_)); |
|||
} |
|||
|
|||
bool |
|||
is_null() const |
|||
{ |
|||
return !std::atomic_load(&_ptr); |
|||
} |
|||
|
|||
void |
|||
reset() |
|||
{ |
|||
std::atomic_store(&_ptr, std::shared_ptr<T>()); |
|||
} |
|||
|
|||
T* |
|||
get() const |
|||
{ |
|||
return std::atomic_load(&_ptr).get(); |
|||
} |
|||
|
|||
template<typename... Args> |
|||
auto |
|||
operator()(Args&&... args) const -> |
|||
decltype(std::declval<T>()(std::forward<Args>(args)...)) |
|||
{ |
|||
auto ptr = load(); |
|||
|
|||
return (*ptr)(std::forward<Args>(args)...); |
|||
} |
|||
}; |
|||
@ -0,0 +1,41 @@ |
|||
#pragma once
|
|||
|
|||
#include "config.hpp"
|
|||
#include "tofrom_string.hpp"
|
|||
|
|||
class ConfigGetAttrStatx : public ToFromString |
|||
{ |
|||
private: |
|||
Func2::GetAttr &_getattr; |
|||
Func2::Statx &_statx; |
|||
|
|||
public: |
|||
ConfigGetAttrStatx() = delete; |
|||
ConfigGetAttrStatx(Func2::GetAttr &getattr_, |
|||
Func2::Statx &statx_) |
|||
: _getattr(getattr_), |
|||
_statx(statx_) |
|||
{ |
|||
} |
|||
|
|||
std::string |
|||
to_string() const |
|||
{ |
|||
return _getattr.to_string(); |
|||
} |
|||
|
|||
int |
|||
from_string(const std::string_view str_) |
|||
{ |
|||
int rv; |
|||
|
|||
rv = _getattr.from_string(str_); |
|||
if(rv < 0) |
|||
return rv; |
|||
|
|||
rv = _statx.from_string(str_); |
|||
assert(rv == 0); |
|||
|
|||
return rv; |
|||
} |
|||
}; |
|||
@ -0,0 +1,9 @@ |
|||
#pragma once
|
|||
|
|||
enum class FollowSymlinksEnum |
|||
{ |
|||
NEVER, |
|||
DIRECTORY, |
|||
REGULAR, |
|||
ALL |
|||
}; |
|||
@ -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; |
|||
} |
|||
@ -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; |
|||
}; |
|||
@ -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&>; |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
#include "func_access_all.hpp"
|
|||
|
|||
#include "error.hpp"
|
|||
#include "fs_eaccess.hpp"
|
|||
|
|||
|
|||
std::string_view |
|||
Func2::AccessAll::name() const |
|||
{ |
|||
return "all"; |
|||
} |
|||
|
|||
int |
|||
Func2::AccessAll::operator()(const Branches &branches_, |
|||
const fs::path &fusepath_, |
|||
const int mode_) |
|||
{ |
|||
int rv; |
|||
fs::path fullpath; |
|||
|
|||
for(const auto &branch : branches_) |
|||
{ |
|||
fullpath = branch.path / fusepath_; |
|||
|
|||
rv = fs::eaccess(fullpath,mode_); |
|||
if(rv < 0) |
|||
return rv; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
#include "func_access_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class AccessAll : public AccessBase |
|||
{ |
|||
public: |
|||
AccessAll() {} |
|||
~AccessAll() {} |
|||
|
|||
public: |
|||
std::string_view name() const; |
|||
|
|||
public: |
|||
int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
const int mode); |
|||
}; |
|||
} |
|||
@ -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; |
|||
}; |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
#include "func_access_factory.hpp"
|
|||
|
|||
#include "func_access_all.hpp"
|
|||
|
|||
#include "policies.hpp"
|
|||
|
|||
|
|||
bool |
|||
Func2::AccessFactory::valid(const std::string str_) |
|||
{ |
|||
if(str_ == "all") |
|||
return true; |
|||
|
|||
if(Policies::Action::find(str_)) |
|||
return true; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
std::shared_ptr<Func2::AccessBase> |
|||
Func2::AccessFactory::make(const std::string_view str_) |
|||
{ |
|||
if(str_ == "all") |
|||
return std::make_shared<Func2::AccessAll>(); |
|||
|
|||
if(Policies::Action::find(str_)) |
|||
return std::make_shared<Func2::AccessAll>(); |
|||
|
|||
return {}; |
|||
} |
|||
@ -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); |
|||
}; |
|||
} |
|||
@ -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&>; |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
#include "func_chmod_all.hpp"
|
|||
|
|||
#include "error.hpp"
|
|||
#include "fs_lchmod.hpp"
|
|||
|
|||
|
|||
std::string_view |
|||
Func2::ChmodAll::name() const |
|||
{ |
|||
return "all"; |
|||
} |
|||
|
|||
int |
|||
Func2::ChmodAll::operator()(const Branches &branches_, |
|||
const fs::path &fusepath_, |
|||
const mode_t mode_) |
|||
{ |
|||
Err err; |
|||
fs::path fullpath; |
|||
|
|||
for(const auto &branch : branches_) |
|||
{ |
|||
if(branch.ro()) |
|||
{ |
|||
err = -EROFS; |
|||
continue; |
|||
} |
|||
|
|||
fullpath = branch.path / fusepath_; |
|||
|
|||
err = fs::lchmod(fullpath,mode_); |
|||
} |
|||
|
|||
return err; |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
#include "func_chmod_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class ChmodAll : public ChmodBase |
|||
{ |
|||
public: |
|||
ChmodAll() {} |
|||
~ChmodAll() {} |
|||
|
|||
public: |
|||
std::string_view name() const; |
|||
|
|||
public: |
|||
int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
const mode_t mode); |
|||
}; |
|||
} |
|||
@ -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; |
|||
}; |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
#include "func_chmod_factory.hpp"
|
|||
|
|||
#include "func_chmod_all.hpp"
|
|||
|
|||
#include "policies.hpp"
|
|||
|
|||
|
|||
bool |
|||
Func2::ChmodFactory::valid(const std::string str_) |
|||
{ |
|||
if(str_ == "all") |
|||
return true; |
|||
|
|||
if(Policies::Action::find(str_)) |
|||
return true; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
std::shared_ptr<Func2::ChmodBase> |
|||
Func2::ChmodFactory::make(const std::string_view str_) |
|||
{ |
|||
if(str_ == "all") |
|||
return std::make_shared<Func2::ChmodAll>(); |
|||
|
|||
if(Policies::Action::find(str_)) |
|||
return std::make_shared<Func2::ChmodAll>(); |
|||
|
|||
return {}; |
|||
} |
|||
@ -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); |
|||
}; |
|||
} |
|||
@ -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&>; |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
#include "func_chown_all.hpp"
|
|||
|
|||
#include "error.hpp"
|
|||
#include "fs_lchown.hpp"
|
|||
|
|||
|
|||
std::string_view |
|||
Func2::ChownAll::name() const |
|||
{ |
|||
return "all"; |
|||
} |
|||
|
|||
int |
|||
Func2::ChownAll::operator()(const Branches &branches_, |
|||
const fs::path &fusepath_, |
|||
const uid_t uid_, |
|||
const gid_t gid_) |
|||
{ |
|||
Err err; |
|||
fs::path fullpath; |
|||
|
|||
for(const auto &branch : branches_) |
|||
{ |
|||
if(branch.ro()) |
|||
{ |
|||
err = -EROFS; |
|||
continue; |
|||
} |
|||
|
|||
fullpath = branch.path / fusepath_; |
|||
|
|||
err = fs::lchown(fullpath,uid_,gid_); |
|||
} |
|||
|
|||
return err; |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
#include "func_chown_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class ChownAll : public ChownBase |
|||
{ |
|||
public: |
|||
ChownAll() {} |
|||
~ChownAll() {} |
|||
|
|||
public: |
|||
std::string_view name() const; |
|||
|
|||
public: |
|||
int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
const uid_t uid, |
|||
const gid_t gid); |
|||
}; |
|||
} |
|||
@ -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; |
|||
}; |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
#include "func_chown_factory.hpp"
|
|||
|
|||
#include "func_chown_all.hpp"
|
|||
|
|||
#include "policies.hpp"
|
|||
|
|||
|
|||
bool |
|||
Func2::ChownFactory::valid(const std::string str_) |
|||
{ |
|||
if(str_ == "all") |
|||
return true; |
|||
|
|||
if(Policies::Action::find(str_)) |
|||
return true; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
std::shared_ptr<Func2::ChownBase> |
|||
Func2::ChownFactory::make(const std::string_view str_) |
|||
{ |
|||
if(str_ == "all") |
|||
return std::make_shared<Func2::ChownAll>(); |
|||
|
|||
if(Policies::Action::find(str_)) |
|||
return std::make_shared<Func2::ChownAll>(); |
|||
|
|||
return {}; |
|||
} |
|||
@ -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); |
|||
}; |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_getattr_base.hpp"
|
|||
#include "func_getattr_factory.hpp"
|
|||
|
|||
#include "func_wrapper.hpp"
|
|||
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
using GetAttr = FuncWrapper<Func2::GetAttrBase, |
|||
Func2::GetAttrFactory, |
|||
int, |
|||
const Branches&, |
|||
const fs::path&, |
|||
struct stat*&, |
|||
const FollowSymlinksEnum&, |
|||
const s64&>; |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
#pragma once
|
|||
|
|||
#include "follow_symlinks_enum.hpp"
|
|||
|
|||
#include "fs_path.hpp"
|
|||
#include "branches.hpp"
|
|||
#include "base_types.h"
|
|||
|
|||
#include "fuse.h"
|
|||
|
|||
#include <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 s64 symlinkify_timeout) = 0; |
|||
}; |
|||
} |
|||
@ -0,0 +1,74 @@ |
|||
#include "func_getattr_cdco.hpp"
|
|||
|
|||
#include "error.hpp"
|
|||
#include "fs_inode.hpp"
|
|||
#include "fs_stat.hpp"
|
|||
#include "symlinkify.hpp"
|
|||
#include "timespec_utils.hpp"
|
|||
|
|||
|
|||
std::string_view |
|||
Func2::GetAttrCDCO::name() const |
|||
{ |
|||
return "cdco"; |
|||
} |
|||
|
|||
int |
|||
Func2::GetAttrCDCO::operator()(const Branches &branches_, |
|||
const fs::path &fusepath_, |
|||
struct stat *st_, |
|||
const FollowSymlinksEnum follow_symlinks_, |
|||
const s64 symlinkify_timeout_) |
|||
{ |
|||
int rv; |
|||
Err err; |
|||
fs::path fullpath; |
|||
const Branch *first_branch; |
|||
|
|||
first_branch = nullptr; |
|||
for(const auto &branch : branches_) |
|||
{ |
|||
struct stat tmp_st; |
|||
|
|||
fullpath = branch.path / fusepath_; |
|||
|
|||
err = rv = fs::stat(fullpath,&tmp_st,follow_symlinks_); |
|||
if(rv < 0) |
|||
continue; |
|||
|
|||
if(not first_branch) |
|||
{ |
|||
*st_ = tmp_st; |
|||
first_branch = &branch; |
|||
continue; |
|||
} |
|||
|
|||
// This upgrades the uid:gid because mergerfs now does most
|
|||
// file interaction as root and relies on `default_permissions`
|
|||
// to manage permissions. Want to ensure that root owned files
|
|||
// can't be changed so we treat them all as root owned.
|
|||
if(tmp_st.st_uid == 0) |
|||
st_->st_uid = 0; |
|||
if(tmp_st.st_gid == 0) |
|||
st_->st_gid = 0; |
|||
st_->st_atim = TimeSpec::newest(st_->st_atim,tmp_st.st_atim); |
|||
st_->st_ctim = TimeSpec::newest(st_->st_ctim,tmp_st.st_ctim); |
|||
st_->st_mtim = TimeSpec::newest(st_->st_mtim,tmp_st.st_mtim); |
|||
st_->st_nlink += tmp_st.st_nlink; |
|||
} |
|||
|
|||
if(!first_branch) |
|||
return err; |
|||
|
|||
if(symlinkify_timeout_ >= 0) |
|||
{ |
|||
fullpath = first_branch->path / fusepath_; |
|||
symlinkify::convert_if_can_be_symlink(fullpath, |
|||
st_, |
|||
symlinkify_timeout_); |
|||
} |
|||
|
|||
fs::inode::calc(first_branch->path,fusepath_,st_); |
|||
|
|||
return 0; |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
#include "func_getattr_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class GetAttrCDCO : public GetAttrBase |
|||
{ |
|||
public: |
|||
GetAttrCDCO() {} |
|||
~GetAttrCDCO() {} |
|||
|
|||
public: |
|||
std::string_view name() const; |
|||
|
|||
public: |
|||
int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
struct stat *st, |
|||
const FollowSymlinksEnum follow_symlinks, |
|||
const s64 symlinkify_timeout); |
|||
}; |
|||
} |
|||
@ -0,0 +1,78 @@ |
|||
#include "func_getattr_cdfo.hpp"
|
|||
|
|||
#include "error.hpp"
|
|||
#include "fs_inode.hpp"
|
|||
#include "fs_stat.hpp"
|
|||
#include "symlinkify.hpp"
|
|||
#include "timespec_utils.hpp"
|
|||
|
|||
|
|||
std::string_view |
|||
Func2::GetAttrCDFO::name() const |
|||
{ |
|||
return "cdfo"; |
|||
} |
|||
|
|||
int |
|||
Func2::GetAttrCDFO::operator()(const Branches &branches_, |
|||
const fs::path &fusepath_, |
|||
struct stat *st_, |
|||
const FollowSymlinksEnum follow_symlinks_, |
|||
const s64 symlinkify_timeout_) |
|||
{ |
|||
int rv; |
|||
Err err; |
|||
fs::path fullpath; |
|||
const Branch *first_branch; |
|||
|
|||
first_branch = nullptr; |
|||
for(const auto &branch : branches_) |
|||
{ |
|||
struct stat tmp_st; |
|||
|
|||
fullpath = branch.path / fusepath_; |
|||
|
|||
err = rv = fs::stat(fullpath, |
|||
&tmp_st, |
|||
follow_symlinks_); |
|||
if(rv < 0) |
|||
continue; |
|||
|
|||
if(not first_branch) |
|||
{ |
|||
*st_ = tmp_st; |
|||
first_branch = &branch; |
|||
if(not S_ISDIR(tmp_st.st_mode)) |
|||
break; |
|||
continue; |
|||
} |
|||
|
|||
// This upgrades the uid:gid because mergerfs now does most
|
|||
// file interaction as root and relies on `default_permissions`
|
|||
// to manage permissions. Want to ensure that root owned files
|
|||
// can't be changed so we treat them all as root owned.
|
|||
if(tmp_st.st_uid == 0) |
|||
st_->st_uid = 0; |
|||
if(tmp_st.st_gid == 0) |
|||
st_->st_gid = 0; |
|||
st_->st_atim = TimeSpec::newest(st_->st_atim,tmp_st.st_atim); |
|||
st_->st_ctim = TimeSpec::newest(st_->st_ctim,tmp_st.st_ctim); |
|||
st_->st_mtim = TimeSpec::newest(st_->st_mtim,tmp_st.st_mtim); |
|||
st_->st_nlink += tmp_st.st_nlink; |
|||
} |
|||
|
|||
if(!first_branch) |
|||
return err; |
|||
|
|||
if(symlinkify_timeout_ >= 0) |
|||
{ |
|||
fullpath = first_branch->path / fusepath_; |
|||
symlinkify::convert_if_can_be_symlink(fullpath, |
|||
st_, |
|||
symlinkify_timeout_); |
|||
} |
|||
|
|||
fs::inode::calc(first_branch->path,fusepath_,st_); |
|||
|
|||
return 0; |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
#include "func_getattr_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class GetAttrCDFO : public GetAttrBase |
|||
{ |
|||
public: |
|||
GetAttrCDFO() {} |
|||
~GetAttrCDFO() {} |
|||
|
|||
public: |
|||
std::string_view name() const; |
|||
|
|||
public: |
|||
int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
struct stat *st, |
|||
const FollowSymlinksEnum follow_symlinks, |
|||
const s64 symlinkify_timeout); |
|||
}; |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
#include "func_getattr_factory.hpp"
|
|||
|
|||
#include "func_getattr_cdfo.hpp"
|
|||
#include "func_getattr_cdco.hpp"
|
|||
#include "func_getattr_ff.hpp"
|
|||
#include "func_getattr_newest.hpp"
|
|||
|
|||
#include "policies.hpp"
|
|||
|
|||
bool |
|||
Func2::GetAttrFactory::valid(const std::string str_) |
|||
{ |
|||
if(str_ == "cdfo") |
|||
return true; |
|||
if(str_ == "cdco") |
|||
return true; |
|||
if(str_ == "ff") |
|||
return true; |
|||
if(str_ == "newest") |
|||
return true; |
|||
|
|||
if(Policies::Search::find(str_)) |
|||
return true; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
std::shared_ptr<Func2::GetAttrBase> |
|||
Func2::GetAttrFactory::make(const std::string_view str_) |
|||
{ |
|||
if(str_ == "cdfo") |
|||
return std::make_shared<Func2::GetAttrCDFO>(); |
|||
if(str_ == "cdco") |
|||
return std::make_shared<Func2::GetAttrCDCO>(); |
|||
if(str_ == "ff") |
|||
return std::make_shared<Func2::GetAttrFF>(); |
|||
if(str_ == "newest") |
|||
return std::make_shared<Func2::GetAttrNewest>(); |
|||
|
|||
if(Policies::Search::find(str_)) |
|||
return std::make_shared<Func2::GetAttrCDFO>(); |
|||
|
|||
return {}; |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_getattr_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class GetAttrFactory |
|||
{ |
|||
public: |
|||
static bool valid(const std::string str); |
|||
static std::shared_ptr<GetAttrBase> make(const std::string_view str); |
|||
}; |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
#include "func_getattr_ff.hpp"
|
|||
|
|||
#include "error.hpp"
|
|||
#include "fs_stat.hpp"
|
|||
#include "fs_inode.hpp"
|
|||
#include "symlinkify.hpp"
|
|||
|
|||
|
|||
std::string_view |
|||
Func2::GetAttrFF::name() const |
|||
{ |
|||
return "ff"; |
|||
} |
|||
|
|||
int |
|||
Func2::GetAttrFF::operator()(const Branches &branches_, |
|||
const fs::path &fusepath_, |
|||
struct stat *st_, |
|||
const FollowSymlinksEnum follow_symlinks_, |
|||
const s64 symlinkify_timeout_) |
|||
{ |
|||
int rv; |
|||
Err err; |
|||
fs::path fullpath; |
|||
|
|||
for(const auto &branch : branches_) |
|||
{ |
|||
fullpath = branch.path / fusepath_; |
|||
|
|||
err = rv = fs::stat(fullpath,st_,follow_symlinks_); |
|||
if(rv < 0) |
|||
continue; |
|||
|
|||
symlinkify::convert_if_can_be_symlink(fullpath, |
|||
st_, |
|||
symlinkify_timeout_); |
|||
|
|||
fs::inode::calc(branch.path,fusepath_,st_); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
return err; |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_getattr_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class GetAttrFF : public GetAttrBase |
|||
{ |
|||
public: |
|||
GetAttrFF() {} |
|||
~GetAttrFF() {} |
|||
|
|||
public: |
|||
std::string_view name() const; |
|||
|
|||
public: |
|||
int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
struct stat *st, |
|||
const FollowSymlinksEnum follow_symlinks, |
|||
const s64 symlinkify_timeout); |
|||
}; |
|||
} |
|||
@ -0,0 +1,59 @@ |
|||
#include "func_getattr_newest.hpp"
|
|||
|
|||
#include "error.hpp"
|
|||
#include "fs_stat.hpp"
|
|||
#include "fs_inode.hpp"
|
|||
#include "timespec_utils.hpp"
|
|||
#include "symlinkify.hpp"
|
|||
|
|||
|
|||
std::string_view |
|||
Func2::GetAttrNewest::name() const |
|||
{ |
|||
return "newest"; |
|||
} |
|||
|
|||
int |
|||
Func2::GetAttrNewest::operator()(const Branches &branches_, |
|||
const fs::path &fusepath_, |
|||
struct stat *st_, |
|||
const FollowSymlinksEnum follow_symlinks_, |
|||
const s64 symlinkify_timeout_) |
|||
{ |
|||
int rv; |
|||
Err err; |
|||
fs::path fullpath; |
|||
const Branch *newest_branch; |
|||
|
|||
newest_branch = nullptr; |
|||
for(const auto &branch : branches_) |
|||
{ |
|||
struct stat tmp_st; |
|||
|
|||
fullpath = branch.path / fusepath_; |
|||
err = rv = fs::stat(fullpath,&tmp_st,follow_symlinks_); |
|||
if(rv < 0) |
|||
continue; |
|||
|
|||
if(st_->st_mtim > tmp_st.st_mtim) |
|||
continue; |
|||
|
|||
*st_ = tmp_st; |
|||
newest_branch = &branch; |
|||
} |
|||
|
|||
if(!newest_branch) |
|||
return err; |
|||
|
|||
if(symlinkify_timeout_ >= 0) |
|||
{ |
|||
fullpath = newest_branch->path / fusepath_; |
|||
symlinkify::convert_if_can_be_symlink(fullpath, |
|||
st_, |
|||
symlinkify_timeout_); |
|||
} |
|||
|
|||
fs::inode::calc(newest_branch->path,fusepath_,st_); |
|||
|
|||
return 0; |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
#include "func_getattr_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class GetAttrNewest : public GetAttrBase |
|||
{ |
|||
public: |
|||
GetAttrNewest() {} |
|||
~GetAttrNewest() {} |
|||
|
|||
public: |
|||
std::string_view name() const; |
|||
|
|||
public: |
|||
int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
struct stat *st, |
|||
const FollowSymlinksEnum follow_symlinks, |
|||
const s64 symlinkify_timeout); |
|||
}; |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_getxattr_base.hpp"
|
|||
#include "func_getxattr_factory.hpp"
|
|||
|
|||
#include "func_wrapper.hpp"
|
|||
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
using Getxattr = FuncWrapper<Func2::GetxattrBase, |
|||
Func2::GetxattrFactory, |
|||
int, |
|||
const Branches&, |
|||
const fs::path&, |
|||
const char*&, |
|||
char*&, |
|||
const size_t&>; |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
#pragma once
|
|||
|
|||
#include "branches.hpp"
|
|||
|
|||
#include "fs_path.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class GetxattrBase |
|||
{ |
|||
public: |
|||
GetxattrBase() {} |
|||
~GetxattrBase() {} |
|||
|
|||
public: |
|||
virtual std::string_view name() const = 0; |
|||
|
|||
public: |
|||
virtual int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
const char *attrname, |
|||
char *attrval, |
|||
const size_t attrval_size) = 0; |
|||
}; |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
#include "func_getxattr_factory.hpp"
|
|||
|
|||
#include "func_getxattr_ff.hpp"
|
|||
|
|||
#include "policies.hpp"
|
|||
|
|||
|
|||
bool |
|||
Func2::GetxattrFactory::valid(const std::string str_) |
|||
{ |
|||
if(str_ == "ff") |
|||
return true; |
|||
|
|||
if(Policies::Action::find(str_)) |
|||
return true; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
std::shared_ptr<Func2::GetxattrBase> |
|||
Func2::GetxattrFactory::make(const std::string_view str_) |
|||
{ |
|||
if(str_ == "ff") |
|||
return std::make_shared<Func2::GetxattrFF>(); |
|||
|
|||
if(Policies::Action::find(str_)) |
|||
return std::make_shared<Func2::GetxattrFF>(); |
|||
|
|||
return {}; |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_getxattr_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class GetxattrFactory |
|||
{ |
|||
public: |
|||
static bool valid(const std::string str); |
|||
static std::shared_ptr<GetxattrBase> make(const std::string_view str); |
|||
}; |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
#include "func_getxattr_ff.hpp"
|
|||
|
|||
#include "error.hpp"
|
|||
#include "fs_lgetxattr.hpp"
|
|||
|
|||
|
|||
std::string_view |
|||
Func2::GetxattrFF::name() const |
|||
{ |
|||
return "ff"; |
|||
} |
|||
|
|||
int |
|||
Func2::GetxattrFF::operator()(const Branches &branches_, |
|||
const fs::path &fusepath_, |
|||
const char *attrname_, |
|||
char *attrval_, |
|||
const size_t attrvalsize_) |
|||
{ |
|||
int rv; |
|||
Err err; |
|||
fs::path fullpath; |
|||
|
|||
for(const auto &branch : branches_) |
|||
{ |
|||
fullpath = branch.path / fusepath_; |
|||
|
|||
rv = fs::lgetxattr(fullpath,attrname_,attrval_,attrvalsize_); |
|||
if(rv >= 0) |
|||
return rv; |
|||
err = rv; |
|||
} |
|||
|
|||
return err; |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
#include "func_getxattr_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class GetxattrFF : public GetxattrBase |
|||
{ |
|||
public: |
|||
GetxattrFF() {} |
|||
~GetxattrFF() {} |
|||
|
|||
public: |
|||
std::string_view name() const; |
|||
|
|||
public: |
|||
int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
const char *attrname, |
|||
char *attrval, |
|||
const size_t attrvalsize); |
|||
}; |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_ioctl_base.hpp"
|
|||
#include "func_ioctl_factory.hpp"
|
|||
|
|||
#include "func_wrapper.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
using Ioctl = FuncWrapper<Func2::IoctlBase, |
|||
Func2::IoctlFactory, |
|||
int, |
|||
const Branches&, |
|||
const fs::path&, |
|||
const mode_t&>; |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
#pragma once
|
|||
|
|||
#include "branches.hpp"
|
|||
|
|||
#include "fs_path.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class IoctlBase |
|||
{ |
|||
public: |
|||
IoctlBase() {} |
|||
~IoctlBase() {} |
|||
|
|||
public: |
|||
virtual std::string_view name() const = 0; |
|||
|
|||
public: |
|||
virtual int operator()(const Branches &branches, |
|||
const fs::path &fusepath) = 0; |
|||
}; |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
#include "func_ioctl_factory.hpp"
|
|||
|
|||
#include "func_ioctl_ff.hpp"
|
|||
|
|||
#include "policies.hpp"
|
|||
|
|||
|
|||
bool |
|||
Func2::IoctlFactory::valid(const std::string str_) |
|||
{ |
|||
if(str_ == "ff") |
|||
return true; |
|||
|
|||
if(Policies::Action::find(str_)) |
|||
return true; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
std::shared_ptr<Func2::IoctlBase> |
|||
Func2::IoctlFactory::make(const std::string_view str_) |
|||
{ |
|||
if(str_ == "ff") |
|||
return std::make_shared<Func2::IoctlFF>(); |
|||
|
|||
if(Policies::Action::find(str_)) |
|||
return std::make_shared<Func2::IoctlFF>(); |
|||
|
|||
return {}; |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_ioctl_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class IoctlFactory |
|||
{ |
|||
public: |
|||
static bool valid(const std::string str); |
|||
static std::shared_ptr<IoctlBase> make(const std::string_view str); |
|||
}; |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
#include "func_ioctl_ff.hpp"
|
|||
|
|||
#include "error.hpp"
|
|||
#include "fs_ioctl.hpp"
|
|||
|
|||
|
|||
std::string_view |
|||
Func2::IoctlFF::name() const |
|||
{ |
|||
return "ff"; |
|||
} |
|||
|
|||
int |
|||
Func2::IoctlFF::operator()(const Branches &branches_, |
|||
const fs::path &fusepath_) |
|||
{ |
|||
Err err; |
|||
fs::path fullpath; |
|||
|
|||
for(const auto &branch : branches_) |
|||
{ |
|||
} |
|||
|
|||
return err; |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
#include "func_ioctl_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class IoctlFF : public IoctlBase |
|||
{ |
|||
public: |
|||
IoctlFF() {} |
|||
~IoctlFF() {} |
|||
|
|||
public: |
|||
std::string_view name() const; |
|||
|
|||
public: |
|||
int operator()(const Branches &branches, |
|||
const fs::path &fusepath); |
|||
}; |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_listxattr_base.hpp"
|
|||
#include "func_listxattr_factory.hpp"
|
|||
|
|||
#include "func_wrapper.hpp"
|
|||
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
using Listxattr = FuncWrapper<Func2::ListxattrBase, |
|||
Func2::ListxattrFactory, |
|||
ssize_t, |
|||
const Branches&, |
|||
const fs::path&, |
|||
char*&, |
|||
const size_t&>; |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
#pragma once
|
|||
|
|||
#include "branches.hpp"
|
|||
|
|||
#include "fs_path.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class ListxattrBase |
|||
{ |
|||
public: |
|||
ListxattrBase() {} |
|||
~ListxattrBase() {} |
|||
|
|||
public: |
|||
virtual std::string_view name() const = 0; |
|||
|
|||
public: |
|||
virtual ssize_t operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
char *list, |
|||
const size_t size) = 0; |
|||
}; |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
#include "func_listxattr_factory.hpp"
|
|||
|
|||
#include "func_listxattr_ff.hpp"
|
|||
|
|||
#include "policies.hpp"
|
|||
|
|||
|
|||
bool |
|||
Func2::ListxattrFactory::valid(const std::string str_) |
|||
{ |
|||
if(str_ == "ff") |
|||
return true; |
|||
|
|||
if(Policies::Search::find(str_)) |
|||
return true; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
std::shared_ptr<Func2::ListxattrBase> |
|||
Func2::ListxattrFactory::make(const std::string_view str_) |
|||
{ |
|||
if(str_ == "ff") |
|||
return std::make_shared<Func2::ListxattrFF>(); |
|||
|
|||
if(Policies::Search::find(str_)) |
|||
return std::make_shared<Func2::ListxattrFF>(); |
|||
|
|||
return {}; |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_listxattr_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class ListxattrFactory |
|||
{ |
|||
public: |
|||
static bool valid(const std::string str); |
|||
static std::shared_ptr<ListxattrBase> make(const std::string_view str); |
|||
}; |
|||
} |
|||
@ -0,0 +1,53 @@ |
|||
#include "func_listxattr_ff.hpp"
|
|||
|
|||
#include "error.hpp"
|
|||
#include "fs_llistxattr.hpp"
|
|||
|
|||
|
|||
std::string_view |
|||
Func2::ListxattrFF::name() const |
|||
{ |
|||
return "ff"; |
|||
} |
|||
|
|||
static |
|||
ssize_t |
|||
_listxattr_ff(const Branches &branches_, |
|||
const fs::path &fusepath_, |
|||
char *list_, |
|||
const size_t size_) |
|||
{ |
|||
Err err; |
|||
ssize_t rv; |
|||
fs::path fullpath; |
|||
|
|||
for(const auto &branch : branches_) |
|||
{ |
|||
fullpath = branch.path / fusepath_; |
|||
|
|||
rv = fs::llistxattr(fullpath,list_,size_); |
|||
switch(rv) |
|||
{ |
|||
case -ERANGE: |
|||
case -ENOTSUP: |
|||
case -E2BIG: |
|||
return rv; |
|||
default: |
|||
if(rv >= 0) |
|||
return rv; |
|||
err = rv; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
return err; |
|||
} |
|||
|
|||
ssize_t |
|||
Func2::ListxattrFF::operator()(const Branches &branches_, |
|||
const fs::path &fusepath_, |
|||
char *list_, |
|||
const size_t size_) |
|||
{ |
|||
return ::_listxattr_ff(branches_,fusepath_,list_,size_); |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
#include "func_listxattr_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class ListxattrFF : public ListxattrBase |
|||
{ |
|||
public: |
|||
ListxattrFF() {} |
|||
~ListxattrFF() {} |
|||
|
|||
public: |
|||
std::string_view name() const; |
|||
|
|||
public: |
|||
ssize_t operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
char *list, |
|||
const size_t size); |
|||
}; |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_open_base.hpp"
|
|||
#include "func_open_factory.hpp"
|
|||
|
|||
#include "func_wrapper.hpp"
|
|||
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
using Open = FuncWrapper<Func2::OpenBase, |
|||
Func2::OpenFactory, |
|||
int, |
|||
const Branches&, |
|||
const fs::path&, |
|||
const mode_t&>; |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
#pragma once
|
|||
|
|||
#include "branches.hpp"
|
|||
|
|||
#include "fs_path.hpp"
|
|||
|
|||
#include <sys/types.h>
|
|||
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class OpenBase |
|||
{ |
|||
public: |
|||
OpenBase() {} |
|||
~OpenBase() {} |
|||
|
|||
public: |
|||
virtual std::string_view name() const = 0; |
|||
|
|||
public: |
|||
virtual int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
const mode_t mode) = 0; |
|||
}; |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
#include "func_open_factory.hpp"
|
|||
|
|||
#include "func_open_ff.hpp"
|
|||
|
|||
#include "policies.hpp"
|
|||
|
|||
|
|||
bool |
|||
Func2::OpenFactory::valid(const std::string str_) |
|||
{ |
|||
if(str_ == "ff") |
|||
return true; |
|||
|
|||
if(Policies::Action::find(str_)) |
|||
return true; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
std::shared_ptr<Func2::OpenBase> |
|||
Func2::OpenFactory::make(const std::string_view str_) |
|||
{ |
|||
if(str_ == "ff") |
|||
return std::make_shared<Func2::OpenFF>(); |
|||
|
|||
if(Policies::Action::find(str_)) |
|||
return std::make_shared<Func2::OpenFF>(); |
|||
|
|||
return {}; |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_open_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class OpenFactory |
|||
{ |
|||
public: |
|||
static bool valid(const std::string str); |
|||
static std::shared_ptr<OpenBase> make(const std::string_view str); |
|||
}; |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
#include "func_open_ff.hpp"
|
|||
|
|||
#include "error.hpp"
|
|||
#include "fs_open.hpp"
|
|||
|
|||
|
|||
std::string_view |
|||
Func2::OpenFF::name() const |
|||
{ |
|||
return "ff"; |
|||
} |
|||
|
|||
int |
|||
Func2::OpenFF::operator()(const Branches &branches_, |
|||
const fs::path &fusepath_, |
|||
const mode_t mode_) |
|||
{ |
|||
Err err; |
|||
fs::path fullpath; |
|||
|
|||
for(const auto &branch : branches_) |
|||
{ |
|||
|
|||
} |
|||
|
|||
return err; |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
#include "func_open_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class OpenFF : public OpenBase |
|||
{ |
|||
public: |
|||
OpenFF() {} |
|||
~OpenFF() {} |
|||
|
|||
public: |
|||
std::string_view name() const; |
|||
|
|||
public: |
|||
int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
const mode_t mode); |
|||
}; |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_readlink_base.hpp"
|
|||
#include "func_readlink_factory.hpp"
|
|||
|
|||
#include "func_wrapper.hpp"
|
|||
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
using Readlink = FuncWrapper<Func2::ReadlinkBase, |
|||
Func2::ReadlinkFactory, |
|||
int, |
|||
const Branches&, |
|||
const fs::path&, |
|||
char *&, |
|||
const size_t&, |
|||
const time_t&>; |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
#pragma once
|
|||
|
|||
#include "branches.hpp"
|
|||
|
|||
#include "fs_path.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class ReadlinkBase |
|||
{ |
|||
public: |
|||
ReadlinkBase() {} |
|||
~ReadlinkBase() {} |
|||
|
|||
public: |
|||
virtual std::string_view name() const = 0; |
|||
|
|||
public: |
|||
virtual int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
char *buf, |
|||
const size_t bufsize, |
|||
const time_t symlinkify_timeout) = 0; |
|||
}; |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
#include "func_readlink_factory.hpp"
|
|||
|
|||
#include "func_readlink_ff.hpp"
|
|||
|
|||
#include "policies.hpp"
|
|||
|
|||
|
|||
bool |
|||
Func2::ReadlinkFactory::valid(const std::string str_) |
|||
{ |
|||
if(str_ == "ff") |
|||
return true; |
|||
|
|||
if(Policies::Search::find(str_)) |
|||
return true; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
std::shared_ptr<Func2::ReadlinkBase> |
|||
Func2::ReadlinkFactory::make(const std::string_view str_) |
|||
{ |
|||
if(str_ == "ff") |
|||
return std::make_shared<Func2::ReadlinkFF>(); |
|||
|
|||
if(Policies::Search::find(str_)) |
|||
return std::make_shared<Func2::ReadlinkFF>(); |
|||
|
|||
return {}; |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_readlink_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class ReadlinkFactory |
|||
{ |
|||
public: |
|||
static bool valid(const std::string str); |
|||
static std::shared_ptr<ReadlinkBase> make(const std::string_view str); |
|||
}; |
|||
} |
|||
@ -0,0 +1,104 @@ |
|||
#include "func_readlink_ff.hpp"
|
|||
|
|||
#include "error.hpp"
|
|||
#include "fs_readlink.hpp"
|
|||
#include "fs_lstat.hpp"
|
|||
#include "symlinkify.hpp"
|
|||
|
|||
#include <cstring>
|
|||
|
|||
|
|||
std::string_view |
|||
Func2::ReadlinkFF::name() const |
|||
{ |
|||
return "ff"; |
|||
} |
|||
|
|||
static |
|||
int |
|||
_readlink_symlinkify(const Branches &branches_, |
|||
const fs::path &fusepath_, |
|||
char *buf_, |
|||
const size_t bufsize_, |
|||
const time_t symlinkify_timeout_) |
|||
{ |
|||
int rv; |
|||
Err err; |
|||
struct stat st; |
|||
fs::path fullpath; |
|||
|
|||
for(const auto &branch : branches_) |
|||
{ |
|||
fullpath = branch.path / fusepath_; |
|||
|
|||
err = rv = fs::lstat(fullpath,&st); |
|||
if(rv < 0) |
|||
continue; |
|||
|
|||
if(not symlinkify::can_be_symlink(st,symlinkify_timeout_)) |
|||
{ |
|||
err = rv = fs::readlink(fusepath_,buf_,bufsize_); |
|||
if(rv < 0) |
|||
continue; |
|||
|
|||
buf_[rv] = '\0'; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
strncpy(buf_,fullpath.c_str(),bufsize_); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
return err; |
|||
} |
|||
|
|||
static |
|||
int |
|||
_readlink(const Branches &branches_, |
|||
const fs::path &fusepath_, |
|||
char *buf_, |
|||
const size_t bufsize_) |
|||
{ |
|||
int rv; |
|||
Err err; |
|||
fs::path fullpath; |
|||
|
|||
for(const auto &branch : branches_) |
|||
{ |
|||
fullpath = branch.path / fusepath_; |
|||
|
|||
err = rv = fs::readlink(fusepath_,buf_,bufsize_); |
|||
if(rv < 0) |
|||
continue; |
|||
|
|||
buf_[rv] = '\0'; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
return err; |
|||
} |
|||
|
|||
|
|||
|
|||
int |
|||
Func2::ReadlinkFF::operator()(const Branches &branches_, |
|||
const fs::path &fusepath_, |
|||
char *buf_, |
|||
const size_t bufsize_, |
|||
const time_t symlinkify_timeout_) |
|||
{ |
|||
if(symlinkify_timeout_ > 0) |
|||
return ::_readlink_symlinkify(branches_, |
|||
fusepath_, |
|||
buf_, |
|||
bufsize_, |
|||
symlinkify_timeout_); |
|||
|
|||
return ::_readlink(branches_, |
|||
fusepath_, |
|||
buf_, |
|||
bufsize_); |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
#include "func_readlink_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class ReadlinkFF : public ReadlinkBase |
|||
{ |
|||
public: |
|||
ReadlinkFF() {} |
|||
~ReadlinkFF() {} |
|||
|
|||
public: |
|||
std::string_view name() const; |
|||
|
|||
public: |
|||
int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
char *buf, |
|||
const size_t bufsize, |
|||
const time_t symlinkify_timeout); |
|||
}; |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_removexattr_base.hpp"
|
|||
#include "func_removexattr_factory.hpp"
|
|||
|
|||
#include "func_wrapper.hpp"
|
|||
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
using Removexattr = FuncWrapper<Func2::RemovexattrBase, |
|||
Func2::RemovexattrFactory, |
|||
int, |
|||
const Branches&, |
|||
const fs::path&, |
|||
const char*&>; |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
#include "func_removexattr_all.hpp"
|
|||
|
|||
#include "error.hpp"
|
|||
#include "fs_lremovexattr.hpp"
|
|||
|
|||
|
|||
std::string_view |
|||
Func2::RemovexattrAll::name() const |
|||
{ |
|||
return "all"; |
|||
} |
|||
|
|||
int |
|||
Func2::RemovexattrAll::operator()(const Branches &branches_, |
|||
const fs::path &fusepath_, |
|||
const char *attrname_) |
|||
{ |
|||
Err err; |
|||
fs::path fullpath; |
|||
|
|||
for(const auto &branch : branches_) |
|||
{ |
|||
if(branch.ro()) |
|||
{ |
|||
err = -EROFS; |
|||
continue; |
|||
} |
|||
|
|||
fullpath = branch.path / fusepath_; |
|||
|
|||
err = fs::lremovexattr(fullpath,attrname_); |
|||
} |
|||
|
|||
return err; |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
#include "func_removexattr_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class RemovexattrAll : public RemovexattrBase |
|||
{ |
|||
public: |
|||
RemovexattrAll() {} |
|||
~RemovexattrAll() {} |
|||
|
|||
public: |
|||
std::string_view name() const; |
|||
|
|||
public: |
|||
int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
const char *attrname); |
|||
}; |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
#pragma once
|
|||
|
|||
#include "branches.hpp"
|
|||
|
|||
#include "fs_path.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class RemovexattrBase |
|||
{ |
|||
public: |
|||
RemovexattrBase() {} |
|||
~RemovexattrBase() {} |
|||
|
|||
public: |
|||
virtual std::string_view name() const = 0; |
|||
|
|||
public: |
|||
virtual int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
const char *attrname) = 0; |
|||
}; |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
#include "func_removexattr_factory.hpp"
|
|||
|
|||
#include "func_removexattr_all.hpp"
|
|||
|
|||
#include "policies.hpp"
|
|||
|
|||
|
|||
bool |
|||
Func2::RemovexattrFactory::valid(const std::string str_) |
|||
{ |
|||
if(str_ == "all") |
|||
return true; |
|||
|
|||
if(Policies::Action::find(str_)) |
|||
return true; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
std::shared_ptr<Func2::RemovexattrBase> |
|||
Func2::RemovexattrFactory::make(const std::string_view str_) |
|||
{ |
|||
if(str_ == "all") |
|||
return std::make_shared<Func2::RemovexattrAll>(); |
|||
|
|||
if(Policies::Action::find(str_)) |
|||
return std::make_shared<Func2::RemovexattrAll>(); |
|||
|
|||
return {}; |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_removexattr_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class RemovexattrFactory |
|||
{ |
|||
public: |
|||
static bool valid(const std::string str); |
|||
static std::shared_ptr<RemovexattrBase> make(const std::string_view str); |
|||
}; |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_rmdir_base.hpp"
|
|||
#include "func_rmdir_factory.hpp"
|
|||
|
|||
#include "func_wrapper.hpp"
|
|||
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
using Rmdir = FuncWrapper<Func2::RmdirBase, |
|||
Func2::RmdirFactory, |
|||
int, |
|||
const Branches&, |
|||
const fs::path&>; |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
#include "func_rmdir_all.hpp"
|
|||
|
|||
#include "config.hpp"
|
|||
#include "error.hpp"
|
|||
#include "fs_rmdir.hpp"
|
|||
#include "fs_unlink.hpp"
|
|||
|
|||
|
|||
std::string_view |
|||
Func2::RmdirAll::name() const |
|||
{ |
|||
return "all"; |
|||
} |
|||
|
|||
static |
|||
int |
|||
_should_unlink(int rv_) |
|||
|
|||
{ |
|||
return ((rv_ == -ENOTDIR) && |
|||
(cfg.follow_symlinks != FollowSymlinks::ENUM::NEVER)); |
|||
} |
|||
|
|||
int |
|||
Func2::RmdirAll::operator()(const Branches &branches_, |
|||
const fs::path &fusepath_) |
|||
{ |
|||
int rv; |
|||
Err err; |
|||
fs::path fullpath; |
|||
|
|||
for(const auto &branch : branches_) |
|||
{ |
|||
if(branch.ro()) |
|||
{ |
|||
err = -EROFS; |
|||
continue; |
|||
} |
|||
|
|||
fullpath = branch.path / fusepath_; |
|||
|
|||
rv = fs::rmdir(fullpath); |
|||
if(::_should_unlink(rv)) |
|||
rv = fs::unlink(fullpath); |
|||
err = rv; |
|||
} |
|||
|
|||
return err; |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
#include "func_rmdir_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class RmdirAll : public RmdirBase |
|||
{ |
|||
public: |
|||
RmdirAll() {} |
|||
~RmdirAll() {} |
|||
|
|||
public: |
|||
std::string_view name() const; |
|||
|
|||
public: |
|||
int operator()(const Branches &branches, |
|||
const fs::path &fusepath); |
|||
}; |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
#pragma once
|
|||
|
|||
#include "branches.hpp"
|
|||
|
|||
#include "fs_path.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class RmdirBase |
|||
{ |
|||
public: |
|||
RmdirBase() {} |
|||
~RmdirBase() {} |
|||
|
|||
public: |
|||
virtual std::string_view name() const = 0; |
|||
|
|||
public: |
|||
virtual int operator()(const Branches &branches, |
|||
const fs::path &fusepath) = 0; |
|||
}; |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
#include "func_rmdir_factory.hpp"
|
|||
|
|||
#include "func_rmdir_all.hpp"
|
|||
|
|||
#include "policies.hpp"
|
|||
|
|||
|
|||
bool |
|||
Func2::RmdirFactory::valid(const std::string str_) |
|||
{ |
|||
if(str_ == "all") |
|||
return true; |
|||
|
|||
if(Policies::Action::find(str_)) |
|||
return true; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
std::shared_ptr<Func2::RmdirBase> |
|||
Func2::RmdirFactory::make(const std::string_view str_) |
|||
{ |
|||
if(str_ == "all") |
|||
return std::make_shared<Func2::RmdirAll>(); |
|||
|
|||
if(Policies::Action::find(str_)) |
|||
return std::make_shared<Func2::RmdirAll>(); |
|||
|
|||
return {}; |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_rmdir_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class RmdirFactory |
|||
{ |
|||
public: |
|||
static bool valid(const std::string str); |
|||
static std::shared_ptr<RmdirBase> make(const std::string_view str); |
|||
}; |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_setxattr_base.hpp"
|
|||
#include "func_setxattr_factory.hpp"
|
|||
|
|||
#include "func_wrapper.hpp"
|
|||
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
using Setxattr = FuncWrapper<Func2::SetxattrBase, |
|||
Func2::SetxattrFactory, |
|||
int, |
|||
const Branches&, |
|||
const fs::path&, |
|||
const char*&, |
|||
const char*&, |
|||
const size_t&, |
|||
const int&>; |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
#include "func_setxattr_all.hpp"
|
|||
|
|||
#include "error.hpp"
|
|||
#include "fs_lsetxattr.hpp"
|
|||
|
|||
|
|||
std::string_view |
|||
Func2::SetxattrAll::name() const |
|||
{ |
|||
return "all"; |
|||
} |
|||
|
|||
int |
|||
Func2::SetxattrAll::operator()(const Branches &branches_, |
|||
const fs::path &fusepath_, |
|||
const char *attrname_, |
|||
const char *attrval_, |
|||
size_t attrvalsize_, |
|||
int flags_) |
|||
{ |
|||
Err err; |
|||
fs::path fullpath; |
|||
|
|||
for(const auto &branch : branches_) |
|||
{ |
|||
if(branch.ro()) |
|||
{ |
|||
err = -EROFS; |
|||
continue; |
|||
} |
|||
|
|||
fullpath = branch.path / fusepath_; |
|||
|
|||
err = fs::lsetxattr(fullpath,attrname_,attrval_,attrvalsize_,flags_); |
|||
} |
|||
|
|||
return err; |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
#include "func_setxattr_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class SetxattrAll : public SetxattrBase |
|||
{ |
|||
public: |
|||
SetxattrAll() {} |
|||
~SetxattrAll() {} |
|||
|
|||
public: |
|||
std::string_view name() const; |
|||
|
|||
public: |
|||
int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
const char *attrname_, |
|||
const char *attrval_, |
|||
size_t attrvalsize_, |
|||
int flags_); |
|||
}; |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
#pragma once
|
|||
|
|||
#include "branches.hpp"
|
|||
|
|||
#include "fs_path.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class SetxattrBase |
|||
{ |
|||
public: |
|||
SetxattrBase() {} |
|||
~SetxattrBase() {} |
|||
|
|||
public: |
|||
virtual std::string_view name() const = 0; |
|||
|
|||
public: |
|||
virtual int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
const char *attrname, |
|||
const char *attrval, |
|||
size_t attrvalsize, |
|||
int flags) = 0; |
|||
}; |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
#include "func_setxattr_factory.hpp"
|
|||
|
|||
#include "func_setxattr_all.hpp"
|
|||
|
|||
#include "policies.hpp"
|
|||
|
|||
|
|||
bool |
|||
Func2::SetxattrFactory::valid(const std::string str_) |
|||
{ |
|||
if(str_ == "all") |
|||
return true; |
|||
|
|||
if(Policies::Action::find(str_)) |
|||
return true; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
std::shared_ptr<Func2::SetxattrBase> |
|||
Func2::SetxattrFactory::make(const std::string_view str_) |
|||
{ |
|||
if(str_ == "all") |
|||
return std::make_shared<Func2::SetxattrAll>(); |
|||
|
|||
if(Policies::Action::find(str_)) |
|||
return std::make_shared<Func2::SetxattrAll>(); |
|||
|
|||
return {}; |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_setxattr_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class SetxattrFactory |
|||
{ |
|||
public: |
|||
static bool valid(const std::string str); |
|||
static std::shared_ptr<SetxattrBase> make(const std::string_view str); |
|||
}; |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
#pragma once
|
|||
|
|||
#include "func_statx_base.hpp"
|
|||
#include "func_statx_factory.hpp"
|
|||
|
|||
#include "func_wrapper.hpp"
|
|||
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
using Statx = FuncWrapper<Func2::StatxBase, |
|||
Func2::StatxFactory, |
|||
int, |
|||
const Branches&, |
|||
const fs::path&, |
|||
const u32&, |
|||
const u32&, |
|||
struct fuse_statx*&, |
|||
const FollowSymlinksEnum, |
|||
const s64&>; |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
#pragma once
|
|||
|
|||
#include "follow_symlinks_enum.hpp"
|
|||
|
|||
#include "fs_path.hpp"
|
|||
#include "branches.hpp"
|
|||
#include "base_types.h"
|
|||
|
|||
#include "fuse.h"
|
|||
|
|||
#include <string_view>
|
|||
|
|||
#include <sys/types.h>
|
|||
#include <sys/stat.h>
|
|||
#include <unistd.h>
|
|||
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class StatxBase |
|||
{ |
|||
public: |
|||
StatxBase() {} |
|||
~StatxBase() {} |
|||
|
|||
public: |
|||
virtual std::string_view name() const = 0; |
|||
|
|||
public: |
|||
virtual int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
const u32 flags_, |
|||
const u32 mask_, |
|||
struct fuse_statx *st, |
|||
const FollowSymlinksEnum follow_symlinks, |
|||
const s64 symlinkify_timeout) = 0; |
|||
}; |
|||
} |
|||
@ -0,0 +1,81 @@ |
|||
#include "func_statx_cdco.hpp"
|
|||
|
|||
#include "error.hpp"
|
|||
#include "fs_inode.hpp"
|
|||
#include "fs_statx.hpp"
|
|||
#include "symlinkify.hpp"
|
|||
#include "timespec_utils.hpp"
|
|||
|
|||
|
|||
std::string_view |
|||
Func2::StatxCDCO::name() const |
|||
{ |
|||
return "cdco"; |
|||
} |
|||
|
|||
int |
|||
Func2::StatxCDCO::operator()(const Branches &branches_, |
|||
const fs::path &fusepath_, |
|||
const u32 flags_, |
|||
const u32 mask_, |
|||
struct fuse_statx *st_, |
|||
const FollowSymlinksEnum follow_symlinks_, |
|||
const s64 symlinkify_timeout_) |
|||
{ |
|||
int rv; |
|||
Err err; |
|||
fs::path fullpath; |
|||
const Branch *first_branch; |
|||
|
|||
first_branch = nullptr; |
|||
for(const auto &branch : branches_) |
|||
{ |
|||
struct fuse_statx tmp_st; |
|||
|
|||
fullpath = branch.path / fusepath_; |
|||
err = rv = fs::statx(AT_FDCWD, |
|||
fullpath, |
|||
flags_|AT_SYMLINK_NOFOLLOW, |
|||
mask_, |
|||
&tmp_st, |
|||
follow_symlinks_); |
|||
if(rv < 0) |
|||
continue; |
|||
|
|||
if(!first_branch) |
|||
{ |
|||
*st_ = tmp_st; |
|||
first_branch = &branch; |
|||
continue; |
|||
} |
|||
|
|||
// This upgrades the uid:gid because mergerfs now does most
|
|||
// file interaction as root and relies on `default_permissions`
|
|||
// to manage permissions. Want to ensure that root owned files
|
|||
// can't be changed so we treat them all as root owned.
|
|||
if(tmp_st.uid == 0) |
|||
st_->uid = 0; |
|||
if(tmp_st.gid == 0) |
|||
st_->gid = 0; |
|||
st_->atime = TimeSpec::newest(st_->atime,tmp_st.atime); |
|||
st_->ctime = TimeSpec::newest(st_->ctime,tmp_st.ctime); |
|||
st_->mtime = TimeSpec::newest(st_->mtime,tmp_st.mtime); |
|||
st_->btime = TimeSpec::newest(st_->btime,tmp_st.btime); |
|||
st_->nlink += tmp_st.nlink; |
|||
} |
|||
|
|||
if(!first_branch) |
|||
return err; |
|||
|
|||
if(symlinkify_timeout_ >= 0) |
|||
{ |
|||
fullpath = first_branch->path / fusepath_; |
|||
symlinkify::convert_if_can_be_symlink(fullpath, |
|||
st_, |
|||
symlinkify_timeout_); |
|||
} |
|||
|
|||
fs::inode::calc(first_branch->path,fusepath_,st_); |
|||
|
|||
return 0; |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
#include "func_statx_base.hpp"
|
|||
|
|||
namespace Func2 |
|||
{ |
|||
class StatxCDCO : public StatxBase |
|||
{ |
|||
public: |
|||
StatxCDCO() {} |
|||
~StatxCDCO() {} |
|||
|
|||
public: |
|||
std::string_view name() const; |
|||
|
|||
public: |
|||
int operator()(const Branches &branches, |
|||
const fs::path &fusepath, |
|||
const u32 flags_, |
|||
const u32 mask_, |
|||
struct fuse_statx *st, |
|||
const FollowSymlinksEnum follow_symlinks, |
|||
const s64 symlinkify_timeout); |
|||
}; |
|||
} |
|||
@ -0,0 +1,84 @@ |
|||
#include "func_statx_cdfo.hpp"
|
|||
|
|||
#include "error.hpp"
|
|||
#include "fs_inode.hpp"
|
|||
#include "fs_statx.hpp"
|
|||
#include "symlinkify.hpp"
|
|||
#include "timespec_utils.hpp"
|
|||
|
|||
|
|||
std::string_view |
|||
Func2::StatxCDFO::name() const |
|||
{ |
|||
return "cdfo"; |
|||
} |
|||
|
|||
int |
|||
Func2::StatxCDFO::operator()(const Branches &branches_, |
|||
const fs::path &fusepath_, |
|||
const u32 flags_, |
|||
const u32 mask_, |
|||
struct fuse_statx *st_, |
|||
const FollowSymlinksEnum follow_symlinks_, |
|||
const s64 symlinkify_timeout_) |
|||
{ |
|||
int rv; |
|||
Err err; |
|||
fs::path fullpath; |
|||
const Branch *first_branch; |
|||
|
|||
first_branch = nullptr; |
|||
for(const auto &branch : branches_) |
|||
{ |
|||
struct fuse_statx tmp_st; |
|||
|
|||
fullpath = branch.path / fusepath_; |
|||
|
|||
err = rv = fs::statx(AT_FDCWD, |
|||
fullpath, |
|||
flags_|AT_SYMLINK_NOFOLLOW, |
|||
mask_, |
|||
&tmp_st, |
|||
follow_symlinks_); |
|||
if(rv < 0) |
|||
continue; |
|||
|
|||
if(!first_branch) |
|||
{ |
|||
*st_ = tmp_st; |
|||
first_branch = &branch; |
|||
if(not S_ISDIR(tmp_st.mode)) |
|||
break; |
|||
continue; |
|||
} |
|||
|
|||
// This upgrades the uid:gid because mergerfs now does most
|
|||
// file interaction as root and relies on `default_permissions`
|
|||
// to manage permissions. Want to ensure that root owned files
|
|||
// can't be changed so we treat them all as root owned.
|
|||
if(tmp_st.uid == 0) |
|||
st_->uid = 0; |
|||
if(tmp_st.gid == 0) |
|||
st_->gid = 0; |
|||
st_->atime = TimeSpec::newest(st_->atime,tmp_st.atime); |
|||
st_->ctime = TimeSpec::newest(st_->ctime,tmp_st.ctime); |
|||
st_->mtime = TimeSpec::newest(st_->mtime,tmp_st.mtime); |
|||
st_->btime = TimeSpec::newest(st_->btime,tmp_st.btime); |
|||
st_->nlink += tmp_st.nlink; |
|||
} |
|||
|
|||
if(!first_branch) |
|||
return err; |
|||
|
|||
if(symlinkify_timeout_ >= 0) |
|||
{ |
|||
fullpath = first_branch->path / fusepath_; |
|||
symlinkify::convert_if_can_be_symlink(fullpath, |
|||
st_, |
|||
symlinkify_timeout_); |
|||
} |
|||
|
|||
fs::inode::calc(first_branch->path,fusepath_,st_); |
|||
|
|||
return 0; |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue