Browse Source

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
Antonio SJ Musumeci 3 months ago
parent
commit
b3b8e793f9
  1. 77
      libfuse/lib/debug.cpp
  2. 1
      libfuse/lib/debug.hpp
  3. 2
      libfuse/lib/fuse_lowlevel.cpp
  4. 108
      src/atomicsharedptr.hpp
  5. 11
      src/category.hpp
  6. 28
      src/config.cpp
  7. 32
      src/config.hpp
  8. 8
      src/config_follow_symlinks.hpp
  9. 41
      src/config_getattr_statx.hpp
  10. 21
      src/error.hpp
  11. 9
      src/follow_symlinks_enum.hpp
  12. 19
      src/fs_lstat.hpp
  13. 0
      src/fs_stat.cpp
  14. 61
      src/fs_stat.hpp
  15. 62
      src/fs_statx.hpp
  16. 36
      src/fsproxy.cpp
  17. 54
      src/fsproxy.hpp
  18. 16
      src/func_access.hpp
  19. 31
      src/func_access_all.cpp
  20. 19
      src/func_access_all.hpp
  21. 24
      src/func_access_base.hpp
  22. 30
      src/func_access_factory.cpp
  23. 13
      src/func_access_factory.hpp
  24. 17
      src/func_chmod.hpp
  25. 35
      src/func_chmod_all.cpp
  26. 19
      src/func_chmod_all.hpp
  27. 26
      src/func_chmod_base.hpp
  28. 30
      src/func_chmod_factory.cpp
  29. 13
      src/func_chmod_factory.hpp
  30. 18
      src/func_chown.hpp
  31. 36
      src/func_chown_all.cpp
  32. 20
      src/func_chown_all.hpp
  33. 27
      src/func_chown_base.hpp
  34. 30
      src/func_chown_factory.cpp
  35. 13
      src/func_chown_factory.hpp
  36. 19
      src/func_getattr.hpp
  37. 35
      src/func_getattr_base.hpp
  38. 74
      src/func_getattr_cdco.cpp
  39. 21
      src/func_getattr_cdco.hpp
  40. 78
      src/func_getattr_cdfo.cpp
  41. 21
      src/func_getattr_cdfo.hpp
  42. 44
      src/func_getattr_factory.cpp
  43. 13
      src/func_getattr_factory.hpp
  44. 44
      src/func_getattr_ff.cpp
  45. 23
      src/func_getattr_ff.hpp
  46. 59
      src/func_getattr_newest.cpp
  47. 21
      src/func_getattr_newest.hpp
  48. 19
      src/func_getxattr.hpp
  49. 25
      src/func_getxattr_base.hpp
  50. 30
      src/func_getxattr_factory.cpp
  51. 13
      src/func_getxattr_factory.hpp
  52. 35
      src/func_getxattr_ff.cpp
  53. 21
      src/func_getxattr_ff.hpp
  54. 16
      src/func_ioctl.hpp
  55. 22
      src/func_ioctl_base.hpp
  56. 30
      src/func_ioctl_factory.cpp
  57. 13
      src/func_ioctl_factory.hpp
  58. 25
      src/func_ioctl_ff.cpp
  59. 18
      src/func_ioctl_ff.hpp
  60. 18
      src/func_listxattr.hpp
  61. 24
      src/func_listxattr_base.hpp
  62. 30
      src/func_listxattr_factory.cpp
  63. 13
      src/func_listxattr_factory.hpp
  64. 53
      src/func_listxattr_ff.cpp
  65. 20
      src/func_listxattr_ff.hpp
  66. 17
      src/func_open.hpp
  67. 26
      src/func_open_base.hpp
  68. 30
      src/func_open_factory.cpp
  69. 13
      src/func_open_factory.hpp
  70. 27
      src/func_open_ff.cpp
  71. 19
      src/func_open_ff.hpp
  72. 19
      src/func_readlink.hpp
  73. 25
      src/func_readlink_base.hpp
  74. 30
      src/func_readlink_factory.cpp
  75. 13
      src/func_readlink_factory.hpp
  76. 104
      src/func_readlink_ff.cpp
  77. 21
      src/func_readlink_ff.hpp
  78. 17
      src/func_removexattr.hpp
  79. 35
      src/func_removexattr_all.cpp
  80. 19
      src/func_removexattr_all.hpp
  81. 23
      src/func_removexattr_base.hpp
  82. 30
      src/func_removexattr_factory.cpp
  83. 13
      src/func_removexattr_factory.hpp
  84. 16
      src/func_rmdir.hpp
  85. 49
      src/func_rmdir_all.cpp
  86. 18
      src/func_rmdir_all.hpp
  87. 22
      src/func_rmdir_base.hpp
  88. 30
      src/func_rmdir_factory.cpp
  89. 13
      src/func_rmdir_factory.hpp
  90. 20
      src/func_setxattr.hpp
  91. 38
      src/func_setxattr_all.cpp
  92. 22
      src/func_setxattr_all.hpp
  93. 26
      src/func_setxattr_base.hpp
  94. 30
      src/func_setxattr_factory.cpp
  95. 13
      src/func_setxattr_factory.hpp
  96. 21
      src/func_statx.hpp
  97. 38
      src/func_statx_base.hpp
  98. 81
      src/func_statx_cdco.cpp
  99. 23
      src/func_statx_cdco.hpp
  100. 84
      src/func_statx_cdfo.cpp

77
libfuse/lib/debug.cpp

@ -275,7 +275,9 @@ static
void void
debug_open_flags(const uint32_t flags_) debug_open_flags(const uint32_t flags_)
{ {
fmt::print("{}, ",open_accmode_to_str(flags_));
fmt::print(g_OUTPUT,
"{}, ",
open_accmode_to_str(flags_));
for(size_t i = 0; i < (sizeof(flags_) * 8); i++) for(size_t i = 0; i < (sizeof(flags_) * 8); i++)
{ {
const char *str; const char *str;
@ -287,7 +289,7 @@ debug_open_flags(const uint32_t flags_)
if(str == NULL) if(str == NULL)
continue; continue;
fmt::print("{}, ",str);
fmt::print(g_OUTPUT,"{}, ",str);
} }
} }
@ -315,7 +317,7 @@ fuse_fopen_flag_to_str(const uint32_t offset_)
void void
debug_fuse_open_out(const struct fuse_open_out *arg_) debug_fuse_open_out(const struct fuse_open_out *arg_)
{ {
fmt::print(stderr,
fmt::print(g_OUTPUT,
"fuse_open_out:" "fuse_open_out:"
" fh=0x{:#08x};" " fh=0x{:#08x};"
" open_flags=0x{:#04x} (", " open_flags=0x{:#04x} (",
@ -332,9 +334,9 @@ debug_fuse_open_out(const struct fuse_open_out *arg_)
if(str == NULL) if(str == NULL)
continue; continue;
fmt::print(stderr,"{},",str);
fmt::print(g_OUTPUT,"{},",str);
} }
fmt::print(stderr,");\n");
fmt::print(g_OUTPUT,");\n");
} }
static static
@ -445,7 +447,7 @@ debug_fuse_mkdir_in(const void *arg_)
"fuse_mkdir_in:" "fuse_mkdir_in:"
" mode={:o};" " mode={:o};"
" umask={:o};" " umask={:o};"
" name=%s;"
" name={};"
"\n" "\n"
, ,
arg->mode, arg->mode,
@ -461,7 +463,7 @@ debug_fuse_unlink(const void *arg_)
fmt::print(g_OUTPUT, fmt::print(g_OUTPUT,
"fuse_unlink:" "fuse_unlink:"
" name=%s;"
" name={};"
"\n" "\n"
, ,
name); name);
@ -475,7 +477,7 @@ debug_fuse_rmdir(const void *arg_)
fmt::print(g_OUTPUT, fmt::print(g_OUTPUT,
"fuse_mkdir:" "fuse_mkdir:"
" name=%s;"
" name={};"
"\n" "\n"
, ,
name); name);
@ -493,8 +495,8 @@ debug_fuse_symlink(const void *arg_)
fmt::print(g_OUTPUT, fmt::print(g_OUTPUT,
"fuse_mkdir:" "fuse_mkdir:"
" linkname=%s;"
" name=%s;"
" linkname={};"
" name={};"
"\n" "\n"
, ,
linkname, linkname,
@ -514,9 +516,9 @@ debug_fuse_rename_in(const void *arg_)
fmt::print(g_OUTPUT, fmt::print(g_OUTPUT,
"fuse_rename_in:" "fuse_rename_in:"
" oldname=%s;"
" oldname={};"
" newdir={};" " newdir={};"
" newname=%s;"
" newname={};"
"\n" "\n"
, ,
oldname, oldname,
@ -536,7 +538,7 @@ debug_fuse_link_in(const void *arg_)
fmt::print(g_OUTPUT, fmt::print(g_OUTPUT,
"fuse_link_in:" "fuse_link_in:"
" oldnodeid={};" " oldnodeid={};"
" name=%s;"
" name={};"
"\n" "\n"
, ,
arg->oldnodeid, arg->oldnodeid,
@ -556,7 +558,7 @@ debug_fuse_create_in(const void *arg_)
"fuse_create_in:" "fuse_create_in:"
" mode={:o};" " mode={:o};"
" umask={:o};" " umask={:o};"
" name=%s;"
" name={};"
" flags=0x%X (", " flags=0x%X (",
arg->mode, arg->mode,
arg->umask, arg->umask,
@ -574,7 +576,7 @@ debug_fuse_open_in(const void *arg_)
fmt::print(g_OUTPUT, fmt::print(g_OUTPUT,
"fuse_open_in:" "fuse_open_in:"
" flags=0x%08X (",
" flags=0x{:08X} (",
arg->flags); arg->flags);
debug_open_flags(arg->flags); debug_open_flags(arg->flags);
fmt::print(g_OUTPUT,");\n"); fmt::print(g_OUTPUT,");\n");
@ -639,7 +641,7 @@ debug_fuse_write_in(const void *arg_)
if(str == NULL) if(str == NULL)
continue; continue;
fmt::print(g_OUTPUT,"%s,",str);
fmt::print(g_OUTPUT,"{},",str);
} }
fmt::print(g_OUTPUT,");\n"); fmt::print(g_OUTPUT,");\n");
} }
@ -712,8 +714,8 @@ debug_fuse_setxattr_in(const void *arg_)
"fuse_setxattr_in:" "fuse_setxattr_in:"
" size={};" " size={};"
" flags=0x%X;" " flags=0x%X;"
" name=%s;"
" value=%s;"
" name={};"
" value={};"
"\n" "\n"
, ,
arg->size, arg->size,
@ -734,7 +736,7 @@ debug_fuse_getxattr_in(const void *arg_)
fmt::print(g_OUTPUT, fmt::print(g_OUTPUT,
"fuse_getxattr_in:" "fuse_getxattr_in:"
" size={};" " size={};"
" name=%s;"
" name={};"
"\n" "\n"
, ,
arg->size, arg->size,
@ -763,7 +765,7 @@ debug_fuse_removexattr(const void *arg_)
fmt::print(g_OUTPUT, fmt::print(g_OUTPUT,
"fuse_removexattr:" "fuse_removexattr:"
" name=%s;"
" name={};"
"\n" "\n"
, ,
name); name);
@ -816,7 +818,7 @@ debug_fuse_init_in(const struct fuse_init_in *arg_)
if(str == NULL) if(str == NULL)
continue; continue;
fmt::print(g_OUTPUT,"%s, ",str);
fmt::print(g_OUTPUT,"{}, ",str);
} }
fmt::print(g_OUTPUT,")\n"); fmt::print(g_OUTPUT,")\n");
} }
@ -932,7 +934,7 @@ debug_fuse_init_out(const uint64_t unique_,
if(str == NULL) if(str == NULL)
continue; continue;
fmt::print(g_OUTPUT,"%s, ",str);
fmt::print(g_OUTPUT,"{}, ",str);
} }
fmt::print(g_OUTPUT, fmt::print(g_OUTPUT,
@ -1100,13 +1102,14 @@ opcode_name(enum fuse_opcode op_)
{ {
static const char *names[] = static const char *names[] =
{ {
"INVALID",
"INVALID0",
"LOOKUP", "LOOKUP",
"FORGET", "FORGET",
"GETATTR", "GETATTR",
"SETATTR", "SETATTR",
"READLINK", "READLINK",
"SYMLINK", "SYMLINK",
"INVALID1",
"MKNOD", "MKNOD",
"MKDIR", "MKDIR",
"UNLINK", "UNLINK",
@ -1118,6 +1121,7 @@ opcode_name(enum fuse_opcode op_)
"WRITE", "WRITE",
"STATFS", "STATFS",
"RELEASE", "RELEASE",
"INVALID3",
"FSYNC", "FSYNC",
"SETXATTR", "SETXATTR",
"GETXATTR", "GETXATTR",
@ -1147,7 +1151,10 @@ opcode_name(enum fuse_opcode op_)
"LSEEK", "LSEEK",
"COPY_FILE_RANGE", "COPY_FILE_RANGE",
"SETUPMAPPING", "SETUPMAPPING",
"REMOVEMAPPING"
"REMOVEMAPPING",
"SYNCFS",
"TMPFILE",
"STATX"
}; };
if(op_ >= (sizeof(names) / sizeof(names[0]))) if(op_ >= (sizeof(names) / sizeof(names[0])))
@ -1161,9 +1168,9 @@ debug_fuse_in_header(const struct fuse_in_header *hdr_)
{ {
const void *arg = &hdr_[1]; const void *arg = &hdr_[1];
fmt::print(stderr,
"unique=0x%016" PRIx64 ";"
" opcode=%s ({});"
fmt::print(g_OUTPUT,
"unique=0x{:016x};"
" opcode={} ({});"
" nodeid={};" " nodeid={};"
" uid={};" " uid={};"
" gid={};" " gid={};"
@ -1265,8 +1272,14 @@ debug_fuse_in_header(const struct fuse_in_header *hdr_)
case FUSE_INTERRUPT: case FUSE_INTERRUPT:
debug_fuse_interrupt_in(arg); debug_fuse_interrupt_in(arg);
break; break;
case FUSE_SYNCFS:
break;
case FUSE_TMPFILE:
break;
case FUSE_STATX:
break;
default: default:
fmt::print(g_OUTPUT,"FIXME\n");
fmt::print(g_OUTPUT,"FIXME: {}\n",hdr_->opcode);
break; break;
} }
} }
@ -1275,10 +1288,10 @@ void
debug_fuse_out_header(const struct fuse_out_header *hdr_) debug_fuse_out_header(const struct fuse_out_header *hdr_)
{ {
fmt::print(g_OUTPUT, fmt::print(g_OUTPUT,
"unique=0x%016" PRIx64 ";"
"unique=0x{:016x};"
" opcode=RESPONSE;" " opcode=RESPONSE;"
" error=%d (%s);"
" len={};"
" error={} ({});"
" len={};\n"
, ,
hdr_->unique, hdr_->unique,
hdr_->error, hdr_->error,
@ -1312,7 +1325,7 @@ debug_fuse_readlink(const uint64_t unique_,
" opcode=RESPONSE;" " opcode=RESPONSE;"
" error=0 (Success);" " error=0 (Success);"
" len={}; || " " len={}; || "
"readlink: linkname=%s"
"readlink: linkname={}"
"\n" "\n"
, ,
unique_, unique_,

1
libfuse/lib/debug.hpp

@ -51,6 +51,7 @@ void debug_fuse_lk_out(const uint64_t unique,
void debug_fuse_bmap_out(const uint64_t unique, void debug_fuse_bmap_out(const uint64_t unique,
const struct fuse_bmap_out *arg); const struct fuse_bmap_out *arg);
void debug_fuse_in_header(const struct fuse_in_header *hdr); void debug_fuse_in_header(const struct fuse_in_header *hdr);
void debug_fuse_out_header(const struct fuse_out_header *hdr);
std::string fuse_debug_init_flag_name(const uint64_t); std::string fuse_debug_init_flag_name(const uint64_t);

2
libfuse/lib/fuse_lowlevel.cpp

@ -1797,6 +1797,8 @@ fuse_ll_buf_process_read(struct fuse_session *se_,
if(fuse_ll_funcs[in->opcode] == NULL) if(fuse_ll_funcs[in->opcode] == NULL)
goto reply_err; goto reply_err;
// debug_fuse_in_header(in);
fuse_ll_funcs[in->opcode](req, in); fuse_ll_funcs[in->opcode](req, in);
return; return;

108
src/atomicsharedptr.hpp

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

11
src/category.hpp

@ -42,16 +42,8 @@ namespace Category
public: public:
Action(Funcs &funcs_) Action(Funcs &funcs_)
{ {
funcs.push_back(&funcs_.chmod);
funcs.push_back(&funcs_.chown);
funcs.push_back(&funcs_.link); funcs.push_back(&funcs_.link);
funcs.push_back(&funcs_.removexattr);
funcs.push_back(&funcs_.rename); funcs.push_back(&funcs_.rename);
funcs.push_back(&funcs_.rmdir);
funcs.push_back(&funcs_.setxattr);
funcs.push_back(&funcs_.truncate);
funcs.push_back(&funcs_.unlink);
funcs.push_back(&funcs_.utimens);
} }
}; };
@ -78,12 +70,9 @@ namespace Category
public: public:
Search(Funcs &funcs_) Search(Funcs &funcs_)
{ {
funcs.push_back(&funcs_.access);
funcs.push_back(&funcs_.getattr); funcs.push_back(&funcs_.getattr);
funcs.push_back(&funcs_.getxattr);
funcs.push_back(&funcs_.listxattr); funcs.push_back(&funcs_.listxattr);
funcs.push_back(&funcs_.open); funcs.push_back(&funcs_.open);
funcs.push_back(&funcs_.readlink);
} }
}; };
} }

28
src/config.cpp

@ -138,6 +138,7 @@ Config::Config()
_congestion_threshold(fuse_cfg.congestion_threshold), _congestion_threshold(fuse_cfg.congestion_threshold),
_debug(fuse_cfg.debug), _debug(fuse_cfg.debug),
_getattr_statx(getattr,statx),
_gid(fuse_cfg.gid), _gid(fuse_cfg.gid),
_max_background(fuse_cfg.max_background), _max_background(fuse_cfg.max_background),
_mount(mountpoint), _mount(mountpoint),
@ -225,27 +226,28 @@ Config::Config()
_map["flush-on-close"] = &flushonclose; _map["flush-on-close"] = &flushonclose;
_map["follow-symlinks"] = &follow_symlinks; _map["follow-symlinks"] = &follow_symlinks;
_map["fsname"] = &fsname; _map["fsname"] = &fsname;
_map["func.access"] = &func.access;
_map["func.chmod"] = &func.chmod;
_map["func.chown"] = &func.chown;
_map["func.access"] = &access;
_map["func.chmod"] = &chmod;
_map["func.chown"] = &chown;
_map["func.create"] = &func.create; _map["func.create"] = &func.create;
_map["func.getattr"] = &func.getattr;
_map["func.getxattr"] = &func.getxattr;
_map["func.getattr"] = &_getattr_statx;
_map["func.getxattr"] = &getxattr;
_map["func.link"] = &func.link; _map["func.link"] = &func.link;
_map["func.listxattr"] = &func.listxattr;
_map["func.listxattr"] = &listxattr;
_map["func.mkdir"] = &func.mkdir; _map["func.mkdir"] = &func.mkdir;
_map["func.mknod"] = &func.mknod; _map["func.mknod"] = &func.mknod;
_map["func.open"] = &func.open; _map["func.open"] = &func.open;
_map["func.readdir"] = &readdir; _map["func.readdir"] = &readdir;
_map["func.readlink"] = &func.readlink;
_map["func.removexattr"] = &func.removexattr;
_map["func.readlink"] = &readlink;
_map["func.removexattr"] = &removexattr;
_map["func.rename"] = &func.rename; _map["func.rename"] = &func.rename;
_map["func.rmdir"] = &func.rmdir;
_map["func.setxattr"] = &func.setxattr;
_map["func.rmdir"] = &rmdir;
_map["func.setxattr"] = &setxattr;
_map["func.statx"] = &_getattr_statx;
_map["func.symlink"] = &func.symlink; _map["func.symlink"] = &func.symlink;
_map["func.truncate"] = &func.truncate;
_map["func.unlink"] = &func.unlink;
_map["func.utimens"] = &func.utimens;
_map["func.truncate"] = &truncate;
_map["func.unlink"] = &unlink;
_map["func.utimens"] = &utimens;
_map["fuse-msg-size"] = &fuse_msg_size; _map["fuse-msg-size"] = &fuse_msg_size;
_map["gid"] = &_gid; _map["gid"] = &_gid;
_map["gid-cache.expire-timeout"] = &_dummy; _map["gid-cache.expire-timeout"] = &_dummy;

32
src/config.hpp

@ -16,12 +16,28 @@
#pragma once #pragma once
#include "func_access.hpp"
#include "func_chmod.hpp"
#include "func_chown.hpp"
#include "func_getattr.hpp"
#include "func_getxattr.hpp"
#include "func_listxattr.hpp"
#include "func_readlink.hpp"
#include "func_removexattr.hpp"
#include "func_rmdir.hpp"
#include "func_setxattr.hpp"
#include "func_statx.hpp"
#include "func_truncate.hpp"
#include "func_unlink.hpp"
#include "func_utimens.hpp"
#include "branches.hpp" #include "branches.hpp"
#include "category.hpp" #include "category.hpp"
#include "config_cachefiles.hpp" #include "config_cachefiles.hpp"
#include "config_dummy.hpp" #include "config_dummy.hpp"
#include "config_flushonclose.hpp" #include "config_flushonclose.hpp"
#include "config_follow_symlinks.hpp" #include "config_follow_symlinks.hpp"
#include "config_getattr_statx.hpp"
#include "config_inodecalc.hpp" #include "config_inodecalc.hpp"
#include "config_link_exdev.hpp" #include "config_link_exdev.hpp"
#include "config_log_metrics.hpp" #include "config_log_metrics.hpp"
@ -108,6 +124,21 @@ public:
Config& operator=(const Config&); Config& operator=(const Config&);
public: public:
Func2::Access access{"all"};
Func2::Chmod chmod{"all"};
Func2::Chown chown{"all"};
Func2::GetAttr getattr{"cdfo"};
Func2::Getxattr getxattr{"ff"};
Func2::Listxattr listxattr{"ff"};
Func2::Readlink readlink{"ff"};
Func2::Removexattr removexattr{"all"};
Func2::Rmdir rmdir{"all"};
Func2::Setxattr setxattr{"all"};
Func2::Statx statx{"cdfo"};
Func2::Truncate truncate{"all"};
Func2::Unlink unlink{"all"};
Func2::Utimens utimens{"all"};
ConfigBOOL allow_idmap; ConfigBOOL allow_idmap;
ConfigBOOL async_read; ConfigBOOL async_read;
Branches branches; Branches branches;
@ -171,6 +202,7 @@ private:
TFSRef<int> _congestion_threshold; TFSRef<int> _congestion_threshold;
TFSRef<bool> _debug; TFSRef<bool> _debug;
CfgDummy _dummy; CfgDummy _dummy;
ConfigGetAttrStatx _getattr_statx;
TFSRef<s64> _gid; TFSRef<s64> _gid;
TFSRef<int> _max_background; TFSRef<int> _max_background;
TFSRef<fs::path> _mount; TFSRef<fs::path> _mount;

8
src/config_follow_symlinks.hpp

@ -19,12 +19,6 @@
#pragma once #pragma once
#include "enum.hpp" #include "enum.hpp"
#include "follow_symlinks_enum.hpp"
enum class FollowSymlinksEnum
{
NEVER,
DIRECTORY,
REGULAR,
ALL
};
typedef Enum<FollowSymlinksEnum> FollowSymlinks; typedef Enum<FollowSymlinksEnum> FollowSymlinks;

41
src/config_getattr_statx.hpp

@ -0,0 +1,41 @@
#pragma once
#include "config.hpp"
#include "tofrom_string.hpp"
class ConfigGetAttrStatx : public ToFromString
{
private:
Func2::GetAttr &_getattr;
Func2::Statx &_statx;
public:
ConfigGetAttrStatx() = delete;
ConfigGetAttrStatx(Func2::GetAttr &getattr_,
Func2::Statx &statx_)
: _getattr(getattr_),
_statx(statx_)
{
}
std::string
to_string() const
{
return _getattr.to_string();
}
int
from_string(const std::string_view str_)
{
int rv;
rv = _getattr.from_string(str_);
if(rv < 0)
return rv;
rv = _statx.from_string(str_);
assert(rv == 0);
return rv;
}
};

21
src/error.hpp

@ -15,27 +15,34 @@ public:
{ {
} }
operator int()
operator int() const
{ {
return (_err.has_value() ? _err.value() : -ENOENT);
return (_err.has_value() ? _err.value() : 0);
} }
// A rough heuristic for prioritizing errors. Success always
// overrides failures. ENOENT is lowest errno priority, then EROFS
// (which can be set due to branch mode = RO) then any other error.
Err& Err&
operator=(int v_)
operator=(int new_err_)
{ {
if(!_err.has_value()) if(!_err.has_value())
_err = ((v_ >= 0) ? 0 : v_);
else if(v_ >= 0)
_err = ((new_err_ >= 0) ? 0 : new_err_);
else if(new_err_ >= 0)
_err = 0; _err = 0;
else if(_err == -ENOENT)
_err = new_err_;
else if((_err == -EROFS) && (new_err_ != -ENOENT))
_err = new_err_;
return *this; return *this;
} }
bool bool
operator==(int v_)
operator==(int other_)
{ {
if(_err.has_value()) if(_err.has_value())
return (_err.value() == v_);
return (_err.value() == other_);
return false; return false;
} }
}; };

9
src/follow_symlinks_enum.hpp

@ -0,0 +1,9 @@
#pragma once
enum class FollowSymlinksEnum
{
NEVER,
DIRECTORY,
REGULAR,
ALL
};

19
src/fs_lstat.hpp

@ -19,8 +19,7 @@
#pragma once #pragma once
#include "to_neg_errno.hpp" #include "to_neg_errno.hpp"
#include <string>
#include "to_cstr.hpp"
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
@ -29,25 +28,17 @@
namespace fs namespace fs
{ {
template<typename PathType>
static static
inline inline
int int
lstat(const char *path_,
struct stat *st_)
lstat(const PathType &path_,
struct stat *st_)
{ {
int rv; int rv;
rv = ::lstat(path_,st_);
rv = ::lstat(to_cstr(path_),st_);
return ::to_neg_errno(rv); return ::to_neg_errno(rv);
} }
static
inline
int
lstat(const std::string &path_,
struct stat *st_)
{
return fs::lstat(path_.c_str(),st_);
}
} }

0
src/fs_stat.cpp

61
src/fs_stat.hpp

@ -18,7 +18,10 @@
#pragma once #pragma once
#include "follow_symlinks_enum.hpp"
#include "to_neg_errno.hpp" #include "to_neg_errno.hpp"
#include "to_cstr.hpp"
#include "fs_lstat.hpp"
#include <string> #include <string>
@ -29,25 +32,71 @@
namespace fs namespace fs
{ {
template<typename PathType>
static static
inline inline
int int
stat(const char *path_,
struct stat *st_)
stat(const PathType &path_,
struct stat *st_)
{ {
int rv; int rv;
rv = ::stat(path_,st_);
rv = ::stat(to_cstr(path_),st_);
return ::to_neg_errno(rv); return ::to_neg_errno(rv);
} }
template<typename PathType>
static static
inline inline
int int
stat(const std::string &path_,
struct stat *st_)
stat(const PathType &path_,
struct stat *st_,
FollowSymlinksEnum follow_)
{ {
return fs::stat(path_.c_str(),st_);
int rv;
switch(follow_)
{
default:
case FollowSymlinksEnum::NEVER:
rv = fs::lstat(path_,st_);
return rv;
case FollowSymlinksEnum::DIRECTORY:
rv = fs::lstat(path_,st_);
if((rv >= 0) && S_ISLNK(st_->st_mode))
{
struct stat st;
rv = fs::stat(path_,&st);
if(rv < 0)
return rv;
if(S_ISDIR(st.st_mode))
*st_ = st;
}
return rv;
case FollowSymlinksEnum::REGULAR:
rv = fs::lstat(path_,st_);
if((rv >= 0) && S_ISLNK(st_->st_mode))
{
struct stat st;
rv = fs::stat(path_,&st);
if(rv < 0)
return rv;
if(S_ISREG(st.st_mode))
*st_ = st;
}
return rv;
case FollowSymlinksEnum::ALL:
rv = fs::stat(path_,st_);
if(rv < 0)
rv = fs::lstat(path_,st_);
return rv;
}
return -ENOENT;
} }
} }

62
src/fs_statx.hpp

@ -1,5 +1,7 @@
#pragma once #pragma once
#include "follow_symlinks_enum.hpp"
#include "to_cstr.hpp"
#include "to_neg_errno.hpp" #include "to_neg_errno.hpp"
#include "fuse_kernel.h" #include "fuse_kernel.h"
@ -15,13 +17,15 @@
#include "supported_statx.hpp" #include "supported_statx.hpp"
namespace fs namespace fs
{ {
template<typename PathType>
static static
inline inline
int int
statx(const int dirfd_, statx(const int dirfd_,
const char *pathname_,
const PathType &pathname_,
const int flags_, const int flags_,
const unsigned int mask_, const unsigned int mask_,
struct fuse_statx *st_) struct fuse_statx *st_)
@ -30,7 +34,7 @@ namespace fs
int rv; int rv;
rv = ::statx(dirfd_, rv = ::statx(dirfd_,
pathname_,
to_cstr(pathname_),
flags_, flags_,
mask_, mask_,
(struct statx*)st_); (struct statx*)st_);
@ -41,19 +45,59 @@ namespace fs
#endif #endif
} }
template<typename PathType>
static static
inline inline
int int
statx(const int dirfd_, statx(const int dirfd_,
const std::string &pathname_,
const PathType &pathname_,
const int flags_, const int flags_,
const unsigned int mask_, const unsigned int mask_,
struct fuse_statx *st_)
struct fuse_statx *st_,
FollowSymlinksEnum followsymlinks_)
{ {
return fs::statx(dirfd_,
pathname_.c_str(),
flags_,
mask_,
st_);
int rv;
switch(followsymlinks_)
{
case FollowSymlinksEnum::NEVER:
rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_);
return rv;
case FollowSymlinksEnum::DIRECTORY:
rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_);
if((rv >= 0) && S_ISLNK(st_->mode))
{
struct fuse_statx st;
rv = fs::statx(AT_FDCWD,pathname_,AT_SYMLINK_FOLLOW,STATX_TYPE,&st);
if(rv < 0)
return rv;
if(S_ISDIR(st.mode))
*st_ = st;
}
return rv;
case FollowSymlinksEnum::REGULAR:
rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_);
if((rv >= 0) && S_ISLNK(st_->mode))
{
struct fuse_statx st;
rv = fs::statx(AT_FDCWD,pathname_,AT_SYMLINK_FOLLOW,STATX_TYPE,&st);
if(rv < 0)
return rv;
if(S_ISREG(st.mode))
*st_ = st;
}
return rv;
case FollowSymlinksEnum::ALL:
rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_FOLLOW,mask_,st_);
if(rv < 0)
rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_);
return rv;
}
return -ENOENT;
} }
} }

36
src/fsproxy.cpp

@ -0,0 +1,36 @@
#include "fsproxy.hpp"
#include "fs_close.hpp"
int
FSProxy::_spawn_proxy_if_needed(const uid_t uid_,
const gid_t gid_)
{
int rv;
FSProxy::Process process;
if(_proxies.count({uid_,gid_}))
return 0;
rv = pipe(process.req_pipe);
if(rv == -1)
return rv;
rv = pipe(process.res_pipe);
if(rv == -1)
return rv;
process.pid = fork();
if(process.pid != 0)
{
fs::close(process.req_pipe[1]);
fs::close(process.res_pipe[0]);
// listen on req in loop for instructions
return 0;
}
fs::close(process.req_pipe[0]);
fs::close(process.res_pipe[1]);
_proxies[UGID{uid_,gid_}] = process;
return 0;
}

54
src/fsproxy.hpp

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

16
src/func_access.hpp

@ -0,0 +1,16 @@
#pragma once
#include "func_access_base.hpp"
#include "func_access_factory.hpp"
#include "func_wrapper.hpp"
namespace Func2
{
using Access = FuncWrapper<Func2::AccessBase,
Func2::AccessFactory,
int,
const Branches&,
const fs::path&,
const int&>;
}

31
src/func_access_all.cpp

@ -0,0 +1,31 @@
#include "func_access_all.hpp"
#include "error.hpp"
#include "fs_eaccess.hpp"
std::string_view
Func2::AccessAll::name() const
{
return "all";
}
int
Func2::AccessAll::operator()(const Branches &branches_,
const fs::path &fusepath_,
const int mode_)
{
int rv;
fs::path fullpath;
for(const auto &branch : branches_)
{
fullpath = branch.path / fusepath_;
rv = fs::eaccess(fullpath,mode_);
if(rv < 0)
return rv;
}
return 0;
}

19
src/func_access_all.hpp

@ -0,0 +1,19 @@
#include "func_access_base.hpp"
namespace Func2
{
class AccessAll : public AccessBase
{
public:
AccessAll() {}
~AccessAll() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
const int mode);
};
}

24
src/func_access_base.hpp

@ -0,0 +1,24 @@
#pragma once
#include "branches.hpp"
#include "fs_path.hpp"
namespace Func2
{
class AccessBase
{
public:
AccessBase() {}
~AccessBase() {}
public:
virtual std::string_view name() const = 0;
public:
virtual int operator()(const Branches &branches,
const fs::path &fusepath,
const int mode) = 0;
};
}

30
src/func_access_factory.cpp

@ -0,0 +1,30 @@
#include "func_access_factory.hpp"
#include "func_access_all.hpp"
#include "policies.hpp"
bool
Func2::AccessFactory::valid(const std::string str_)
{
if(str_ == "all")
return true;
if(Policies::Action::find(str_))
return true;
return false;
}
std::shared_ptr<Func2::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 {};
}

13
src/func_access_factory.hpp

@ -0,0 +1,13 @@
#pragma once
#include "func_access_base.hpp"
namespace Func2
{
class AccessFactory
{
public:
static bool valid(const std::string str);
static std::shared_ptr<AccessBase> make(const std::string_view str);
};
}

17
src/func_chmod.hpp

@ -0,0 +1,17 @@
#pragma once
#include "func_chmod_base.hpp"
#include "func_chmod_factory.hpp"
#include "func_wrapper.hpp"
namespace Func2
{
using Chmod = FuncWrapper<Func2::ChmodBase,
Func2::ChmodFactory,
int,
const Branches&,
const fs::path&,
const mode_t&>;
}

35
src/func_chmod_all.cpp

@ -0,0 +1,35 @@
#include "func_chmod_all.hpp"
#include "error.hpp"
#include "fs_lchmod.hpp"
std::string_view
Func2::ChmodAll::name() const
{
return "all";
}
int
Func2::ChmodAll::operator()(const Branches &branches_,
const fs::path &fusepath_,
const mode_t mode_)
{
Err err;
fs::path fullpath;
for(const auto &branch : branches_)
{
if(branch.ro())
{
err = -EROFS;
continue;
}
fullpath = branch.path / fusepath_;
err = fs::lchmod(fullpath,mode_);
}
return err;
}

19
src/func_chmod_all.hpp

@ -0,0 +1,19 @@
#include "func_chmod_base.hpp"
namespace Func2
{
class ChmodAll : public ChmodBase
{
public:
ChmodAll() {}
~ChmodAll() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
const mode_t mode);
};
}

26
src/func_chmod_base.hpp

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

30
src/func_chmod_factory.cpp

@ -0,0 +1,30 @@
#include "func_chmod_factory.hpp"
#include "func_chmod_all.hpp"
#include "policies.hpp"
bool
Func2::ChmodFactory::valid(const std::string str_)
{
if(str_ == "all")
return true;
if(Policies::Action::find(str_))
return true;
return false;
}
std::shared_ptr<Func2::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 {};
}

13
src/func_chmod_factory.hpp

@ -0,0 +1,13 @@
#pragma once
#include "func_chmod_base.hpp"
namespace Func2
{
class ChmodFactory
{
public:
static bool valid(const std::string str);
static std::shared_ptr<ChmodBase> make(const std::string_view str);
};
}

18
src/func_chown.hpp

@ -0,0 +1,18 @@
#pragma once
#include "func_chown_base.hpp"
#include "func_chown_factory.hpp"
#include "func_wrapper.hpp"
namespace Func2
{
using Chown = FuncWrapper<Func2::ChownBase,
Func2::ChownFactory,
int,
const Branches&,
const fs::path&,
const uid_t&,
const gid_t&>;
}

36
src/func_chown_all.cpp

@ -0,0 +1,36 @@
#include "func_chown_all.hpp"
#include "error.hpp"
#include "fs_lchown.hpp"
std::string_view
Func2::ChownAll::name() const
{
return "all";
}
int
Func2::ChownAll::operator()(const Branches &branches_,
const fs::path &fusepath_,
const uid_t uid_,
const gid_t gid_)
{
Err err;
fs::path fullpath;
for(const auto &branch : branches_)
{
if(branch.ro())
{
err = -EROFS;
continue;
}
fullpath = branch.path / fusepath_;
err = fs::lchown(fullpath,uid_,gid_);
}
return err;
}

20
src/func_chown_all.hpp

@ -0,0 +1,20 @@
#include "func_chown_base.hpp"
namespace Func2
{
class ChownAll : public ChownBase
{
public:
ChownAll() {}
~ChownAll() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
const uid_t uid,
const gid_t gid);
};
}

27
src/func_chown_base.hpp

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

30
src/func_chown_factory.cpp

@ -0,0 +1,30 @@
#include "func_chown_factory.hpp"
#include "func_chown_all.hpp"
#include "policies.hpp"
bool
Func2::ChownFactory::valid(const std::string str_)
{
if(str_ == "all")
return true;
if(Policies::Action::find(str_))
return true;
return false;
}
std::shared_ptr<Func2::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 {};
}

13
src/func_chown_factory.hpp

@ -0,0 +1,13 @@
#pragma once
#include "func_chown_base.hpp"
namespace Func2
{
class ChownFactory
{
public:
static bool valid(const std::string str);
static std::shared_ptr<ChownBase> make(const std::string_view str);
};
}

19
src/func_getattr.hpp

@ -0,0 +1,19 @@
#pragma once
#include "func_getattr_base.hpp"
#include "func_getattr_factory.hpp"
#include "func_wrapper.hpp"
namespace Func2
{
using GetAttr = FuncWrapper<Func2::GetAttrBase,
Func2::GetAttrFactory,
int,
const Branches&,
const fs::path&,
struct stat*&,
const FollowSymlinksEnum&,
const s64&>;
}

35
src/func_getattr_base.hpp

@ -0,0 +1,35 @@
#pragma once
#include "follow_symlinks_enum.hpp"
#include "fs_path.hpp"
#include "branches.hpp"
#include "base_types.h"
#include "fuse.h"
#include <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;
};
}

74
src/func_getattr_cdco.cpp

@ -0,0 +1,74 @@
#include "func_getattr_cdco.hpp"
#include "error.hpp"
#include "fs_inode.hpp"
#include "fs_stat.hpp"
#include "symlinkify.hpp"
#include "timespec_utils.hpp"
std::string_view
Func2::GetAttrCDCO::name() const
{
return "cdco";
}
int
Func2::GetAttrCDCO::operator()(const Branches &branches_,
const fs::path &fusepath_,
struct stat *st_,
const FollowSymlinksEnum follow_symlinks_,
const s64 symlinkify_timeout_)
{
int rv;
Err err;
fs::path fullpath;
const Branch *first_branch;
first_branch = nullptr;
for(const auto &branch : branches_)
{
struct stat tmp_st;
fullpath = branch.path / fusepath_;
err = rv = fs::stat(fullpath,&tmp_st,follow_symlinks_);
if(rv < 0)
continue;
if(not first_branch)
{
*st_ = tmp_st;
first_branch = &branch;
continue;
}
// This upgrades the uid:gid because mergerfs now does most
// file interaction as root and relies on `default_permissions`
// to manage permissions. Want to ensure that root owned files
// can't be changed so we treat them all as root owned.
if(tmp_st.st_uid == 0)
st_->st_uid = 0;
if(tmp_st.st_gid == 0)
st_->st_gid = 0;
st_->st_atim = TimeSpec::newest(st_->st_atim,tmp_st.st_atim);
st_->st_ctim = TimeSpec::newest(st_->st_ctim,tmp_st.st_ctim);
st_->st_mtim = TimeSpec::newest(st_->st_mtim,tmp_st.st_mtim);
st_->st_nlink += tmp_st.st_nlink;
}
if(!first_branch)
return err;
if(symlinkify_timeout_ >= 0)
{
fullpath = first_branch->path / fusepath_;
symlinkify::convert_if_can_be_symlink(fullpath,
st_,
symlinkify_timeout_);
}
fs::inode::calc(first_branch->path,fusepath_,st_);
return 0;
}

21
src/func_getattr_cdco.hpp

@ -0,0 +1,21 @@
#include "func_getattr_base.hpp"
namespace Func2
{
class GetAttrCDCO : public GetAttrBase
{
public:
GetAttrCDCO() {}
~GetAttrCDCO() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
struct stat *st,
const FollowSymlinksEnum follow_symlinks,
const s64 symlinkify_timeout);
};
}

78
src/func_getattr_cdfo.cpp

@ -0,0 +1,78 @@
#include "func_getattr_cdfo.hpp"
#include "error.hpp"
#include "fs_inode.hpp"
#include "fs_stat.hpp"
#include "symlinkify.hpp"
#include "timespec_utils.hpp"
std::string_view
Func2::GetAttrCDFO::name() const
{
return "cdfo";
}
int
Func2::GetAttrCDFO::operator()(const Branches &branches_,
const fs::path &fusepath_,
struct stat *st_,
const FollowSymlinksEnum follow_symlinks_,
const s64 symlinkify_timeout_)
{
int rv;
Err err;
fs::path fullpath;
const Branch *first_branch;
first_branch = nullptr;
for(const auto &branch : branches_)
{
struct stat tmp_st;
fullpath = branch.path / fusepath_;
err = rv = fs::stat(fullpath,
&tmp_st,
follow_symlinks_);
if(rv < 0)
continue;
if(not first_branch)
{
*st_ = tmp_st;
first_branch = &branch;
if(not S_ISDIR(tmp_st.st_mode))
break;
continue;
}
// This upgrades the uid:gid because mergerfs now does most
// file interaction as root and relies on `default_permissions`
// to manage permissions. Want to ensure that root owned files
// can't be changed so we treat them all as root owned.
if(tmp_st.st_uid == 0)
st_->st_uid = 0;
if(tmp_st.st_gid == 0)
st_->st_gid = 0;
st_->st_atim = TimeSpec::newest(st_->st_atim,tmp_st.st_atim);
st_->st_ctim = TimeSpec::newest(st_->st_ctim,tmp_st.st_ctim);
st_->st_mtim = TimeSpec::newest(st_->st_mtim,tmp_st.st_mtim);
st_->st_nlink += tmp_st.st_nlink;
}
if(!first_branch)
return err;
if(symlinkify_timeout_ >= 0)
{
fullpath = first_branch->path / fusepath_;
symlinkify::convert_if_can_be_symlink(fullpath,
st_,
symlinkify_timeout_);
}
fs::inode::calc(first_branch->path,fusepath_,st_);
return 0;
}

21
src/func_getattr_cdfo.hpp

@ -0,0 +1,21 @@
#include "func_getattr_base.hpp"
namespace Func2
{
class GetAttrCDFO : public GetAttrBase
{
public:
GetAttrCDFO() {}
~GetAttrCDFO() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
struct stat *st,
const FollowSymlinksEnum follow_symlinks,
const s64 symlinkify_timeout);
};
}

44
src/func_getattr_factory.cpp

@ -0,0 +1,44 @@
#include "func_getattr_factory.hpp"
#include "func_getattr_cdfo.hpp"
#include "func_getattr_cdco.hpp"
#include "func_getattr_ff.hpp"
#include "func_getattr_newest.hpp"
#include "policies.hpp"
bool
Func2::GetAttrFactory::valid(const std::string str_)
{
if(str_ == "cdfo")
return true;
if(str_ == "cdco")
return true;
if(str_ == "ff")
return true;
if(str_ == "newest")
return true;
if(Policies::Search::find(str_))
return true;
return false;
}
std::shared_ptr<Func2::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 {};
}

13
src/func_getattr_factory.hpp

@ -0,0 +1,13 @@
#pragma once
#include "func_getattr_base.hpp"
namespace Func2
{
class GetAttrFactory
{
public:
static bool valid(const std::string str);
static std::shared_ptr<GetAttrBase> make(const std::string_view str);
};
}

44
src/func_getattr_ff.cpp

@ -0,0 +1,44 @@
#include "func_getattr_ff.hpp"
#include "error.hpp"
#include "fs_stat.hpp"
#include "fs_inode.hpp"
#include "symlinkify.hpp"
std::string_view
Func2::GetAttrFF::name() const
{
return "ff";
}
int
Func2::GetAttrFF::operator()(const Branches &branches_,
const fs::path &fusepath_,
struct stat *st_,
const FollowSymlinksEnum follow_symlinks_,
const s64 symlinkify_timeout_)
{
int rv;
Err err;
fs::path fullpath;
for(const auto &branch : branches_)
{
fullpath = branch.path / fusepath_;
err = rv = fs::stat(fullpath,st_,follow_symlinks_);
if(rv < 0)
continue;
symlinkify::convert_if_can_be_symlink(fullpath,
st_,
symlinkify_timeout_);
fs::inode::calc(branch.path,fusepath_,st_);
return 0;
}
return err;
}

23
src/func_getattr_ff.hpp

@ -0,0 +1,23 @@
#pragma once
#include "func_getattr_base.hpp"
namespace Func2
{
class GetAttrFF : public GetAttrBase
{
public:
GetAttrFF() {}
~GetAttrFF() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
struct stat *st,
const FollowSymlinksEnum follow_symlinks,
const s64 symlinkify_timeout);
};
}

59
src/func_getattr_newest.cpp

@ -0,0 +1,59 @@
#include "func_getattr_newest.hpp"
#include "error.hpp"
#include "fs_stat.hpp"
#include "fs_inode.hpp"
#include "timespec_utils.hpp"
#include "symlinkify.hpp"
std::string_view
Func2::GetAttrNewest::name() const
{
return "newest";
}
int
Func2::GetAttrNewest::operator()(const Branches &branches_,
const fs::path &fusepath_,
struct stat *st_,
const FollowSymlinksEnum follow_symlinks_,
const s64 symlinkify_timeout_)
{
int rv;
Err err;
fs::path fullpath;
const Branch *newest_branch;
newest_branch = nullptr;
for(const auto &branch : branches_)
{
struct stat tmp_st;
fullpath = branch.path / fusepath_;
err = rv = fs::stat(fullpath,&tmp_st,follow_symlinks_);
if(rv < 0)
continue;
if(st_->st_mtim > tmp_st.st_mtim)
continue;
*st_ = tmp_st;
newest_branch = &branch;
}
if(!newest_branch)
return err;
if(symlinkify_timeout_ >= 0)
{
fullpath = newest_branch->path / fusepath_;
symlinkify::convert_if_can_be_symlink(fullpath,
st_,
symlinkify_timeout_);
}
fs::inode::calc(newest_branch->path,fusepath_,st_);
return 0;
}

21
src/func_getattr_newest.hpp

@ -0,0 +1,21 @@
#include "func_getattr_base.hpp"
namespace Func2
{
class GetAttrNewest : public GetAttrBase
{
public:
GetAttrNewest() {}
~GetAttrNewest() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
struct stat *st,
const FollowSymlinksEnum follow_symlinks,
const s64 symlinkify_timeout);
};
}

19
src/func_getxattr.hpp

@ -0,0 +1,19 @@
#pragma once
#include "func_getxattr_base.hpp"
#include "func_getxattr_factory.hpp"
#include "func_wrapper.hpp"
namespace Func2
{
using Getxattr = FuncWrapper<Func2::GetxattrBase,
Func2::GetxattrFactory,
int,
const Branches&,
const fs::path&,
const char*&,
char*&,
const size_t&>;
}

25
src/func_getxattr_base.hpp

@ -0,0 +1,25 @@
#pragma once
#include "branches.hpp"
#include "fs_path.hpp"
namespace Func2
{
class GetxattrBase
{
public:
GetxattrBase() {}
~GetxattrBase() {}
public:
virtual std::string_view name() const = 0;
public:
virtual int operator()(const Branches &branches,
const fs::path &fusepath,
const char *attrname,
char *attrval,
const size_t attrval_size) = 0;
};
}

30
src/func_getxattr_factory.cpp

@ -0,0 +1,30 @@
#include "func_getxattr_factory.hpp"
#include "func_getxattr_ff.hpp"
#include "policies.hpp"
bool
Func2::GetxattrFactory::valid(const std::string str_)
{
if(str_ == "ff")
return true;
if(Policies::Action::find(str_))
return true;
return false;
}
std::shared_ptr<Func2::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 {};
}

13
src/func_getxattr_factory.hpp

@ -0,0 +1,13 @@
#pragma once
#include "func_getxattr_base.hpp"
namespace Func2
{
class GetxattrFactory
{
public:
static bool valid(const std::string str);
static std::shared_ptr<GetxattrBase> make(const std::string_view str);
};
}

35
src/func_getxattr_ff.cpp

@ -0,0 +1,35 @@
#include "func_getxattr_ff.hpp"
#include "error.hpp"
#include "fs_lgetxattr.hpp"
std::string_view
Func2::GetxattrFF::name() const
{
return "ff";
}
int
Func2::GetxattrFF::operator()(const Branches &branches_,
const fs::path &fusepath_,
const char *attrname_,
char *attrval_,
const size_t attrvalsize_)
{
int rv;
Err err;
fs::path fullpath;
for(const auto &branch : branches_)
{
fullpath = branch.path / fusepath_;
rv = fs::lgetxattr(fullpath,attrname_,attrval_,attrvalsize_);
if(rv >= 0)
return rv;
err = rv;
}
return err;
}

21
src/func_getxattr_ff.hpp

@ -0,0 +1,21 @@
#include "func_getxattr_base.hpp"
namespace Func2
{
class GetxattrFF : public GetxattrBase
{
public:
GetxattrFF() {}
~GetxattrFF() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
const char *attrname,
char *attrval,
const size_t attrvalsize);
};
}

16
src/func_ioctl.hpp

@ -0,0 +1,16 @@
#pragma once
#include "func_ioctl_base.hpp"
#include "func_ioctl_factory.hpp"
#include "func_wrapper.hpp"
namespace Func2
{
using Ioctl = FuncWrapper<Func2::IoctlBase,
Func2::IoctlFactory,
int,
const Branches&,
const fs::path&,
const mode_t&>;
}

22
src/func_ioctl_base.hpp

@ -0,0 +1,22 @@
#pragma once
#include "branches.hpp"
#include "fs_path.hpp"
namespace Func2
{
class IoctlBase
{
public:
IoctlBase() {}
~IoctlBase() {}
public:
virtual std::string_view name() const = 0;
public:
virtual int operator()(const Branches &branches,
const fs::path &fusepath) = 0;
};
}

30
src/func_ioctl_factory.cpp

@ -0,0 +1,30 @@
#include "func_ioctl_factory.hpp"
#include "func_ioctl_ff.hpp"
#include "policies.hpp"
bool
Func2::IoctlFactory::valid(const std::string str_)
{
if(str_ == "ff")
return true;
if(Policies::Action::find(str_))
return true;
return false;
}
std::shared_ptr<Func2::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 {};
}

13
src/func_ioctl_factory.hpp

@ -0,0 +1,13 @@
#pragma once
#include "func_ioctl_base.hpp"
namespace Func2
{
class IoctlFactory
{
public:
static bool valid(const std::string str);
static std::shared_ptr<IoctlBase> make(const std::string_view str);
};
}

25
src/func_ioctl_ff.cpp

@ -0,0 +1,25 @@
#include "func_ioctl_ff.hpp"
#include "error.hpp"
#include "fs_ioctl.hpp"
std::string_view
Func2::IoctlFF::name() const
{
return "ff";
}
int
Func2::IoctlFF::operator()(const Branches &branches_,
const fs::path &fusepath_)
{
Err err;
fs::path fullpath;
for(const auto &branch : branches_)
{
}
return err;
}

18
src/func_ioctl_ff.hpp

@ -0,0 +1,18 @@
#include "func_ioctl_base.hpp"
namespace Func2
{
class IoctlFF : public IoctlBase
{
public:
IoctlFF() {}
~IoctlFF() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath);
};
}

18
src/func_listxattr.hpp

@ -0,0 +1,18 @@
#pragma once
#include "func_listxattr_base.hpp"
#include "func_listxattr_factory.hpp"
#include "func_wrapper.hpp"
namespace Func2
{
using Listxattr = FuncWrapper<Func2::ListxattrBase,
Func2::ListxattrFactory,
ssize_t,
const Branches&,
const fs::path&,
char*&,
const size_t&>;
}

24
src/func_listxattr_base.hpp

@ -0,0 +1,24 @@
#pragma once
#include "branches.hpp"
#include "fs_path.hpp"
namespace Func2
{
class ListxattrBase
{
public:
ListxattrBase() {}
~ListxattrBase() {}
public:
virtual std::string_view name() const = 0;
public:
virtual ssize_t operator()(const Branches &branches,
const fs::path &fusepath,
char *list,
const size_t size) = 0;
};
}

30
src/func_listxattr_factory.cpp

@ -0,0 +1,30 @@
#include "func_listxattr_factory.hpp"
#include "func_listxattr_ff.hpp"
#include "policies.hpp"
bool
Func2::ListxattrFactory::valid(const std::string str_)
{
if(str_ == "ff")
return true;
if(Policies::Search::find(str_))
return true;
return false;
}
std::shared_ptr<Func2::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 {};
}

13
src/func_listxattr_factory.hpp

@ -0,0 +1,13 @@
#pragma once
#include "func_listxattr_base.hpp"
namespace Func2
{
class ListxattrFactory
{
public:
static bool valid(const std::string str);
static std::shared_ptr<ListxattrBase> make(const std::string_view str);
};
}

53
src/func_listxattr_ff.cpp

@ -0,0 +1,53 @@
#include "func_listxattr_ff.hpp"
#include "error.hpp"
#include "fs_llistxattr.hpp"
std::string_view
Func2::ListxattrFF::name() const
{
return "ff";
}
static
ssize_t
_listxattr_ff(const Branches &branches_,
const fs::path &fusepath_,
char *list_,
const size_t size_)
{
Err err;
ssize_t rv;
fs::path fullpath;
for(const auto &branch : branches_)
{
fullpath = branch.path / fusepath_;
rv = fs::llistxattr(fullpath,list_,size_);
switch(rv)
{
case -ERANGE:
case -ENOTSUP:
case -E2BIG:
return rv;
default:
if(rv >= 0)
return rv;
err = rv;
break;
}
}
return err;
}
ssize_t
Func2::ListxattrFF::operator()(const Branches &branches_,
const fs::path &fusepath_,
char *list_,
const size_t size_)
{
return ::_listxattr_ff(branches_,fusepath_,list_,size_);
}

20
src/func_listxattr_ff.hpp

@ -0,0 +1,20 @@
#include "func_listxattr_base.hpp"
namespace Func2
{
class ListxattrFF : public ListxattrBase
{
public:
ListxattrFF() {}
~ListxattrFF() {}
public:
std::string_view name() const;
public:
ssize_t operator()(const Branches &branches,
const fs::path &fusepath,
char *list,
const size_t size);
};
}

17
src/func_open.hpp

@ -0,0 +1,17 @@
#pragma once
#include "func_open_base.hpp"
#include "func_open_factory.hpp"
#include "func_wrapper.hpp"
namespace Func2
{
using Open = FuncWrapper<Func2::OpenBase,
Func2::OpenFactory,
int,
const Branches&,
const fs::path&,
const mode_t&>;
}

26
src/func_open_base.hpp

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

30
src/func_open_factory.cpp

@ -0,0 +1,30 @@
#include "func_open_factory.hpp"
#include "func_open_ff.hpp"
#include "policies.hpp"
bool
Func2::OpenFactory::valid(const std::string str_)
{
if(str_ == "ff")
return true;
if(Policies::Action::find(str_))
return true;
return false;
}
std::shared_ptr<Func2::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 {};
}

13
src/func_open_factory.hpp

@ -0,0 +1,13 @@
#pragma once
#include "func_open_base.hpp"
namespace Func2
{
class OpenFactory
{
public:
static bool valid(const std::string str);
static std::shared_ptr<OpenBase> make(const std::string_view str);
};
}

27
src/func_open_ff.cpp

@ -0,0 +1,27 @@
#include "func_open_ff.hpp"
#include "error.hpp"
#include "fs_open.hpp"
std::string_view
Func2::OpenFF::name() const
{
return "ff";
}
int
Func2::OpenFF::operator()(const Branches &branches_,
const fs::path &fusepath_,
const mode_t mode_)
{
Err err;
fs::path fullpath;
for(const auto &branch : branches_)
{
}
return err;
}

19
src/func_open_ff.hpp

@ -0,0 +1,19 @@
#include "func_open_base.hpp"
namespace Func2
{
class OpenFF : public OpenBase
{
public:
OpenFF() {}
~OpenFF() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
const mode_t mode);
};
}

19
src/func_readlink.hpp

@ -0,0 +1,19 @@
#pragma once
#include "func_readlink_base.hpp"
#include "func_readlink_factory.hpp"
#include "func_wrapper.hpp"
namespace Func2
{
using Readlink = FuncWrapper<Func2::ReadlinkBase,
Func2::ReadlinkFactory,
int,
const Branches&,
const fs::path&,
char *&,
const size_t&,
const time_t&>;
}

25
src/func_readlink_base.hpp

@ -0,0 +1,25 @@
#pragma once
#include "branches.hpp"
#include "fs_path.hpp"
namespace Func2
{
class ReadlinkBase
{
public:
ReadlinkBase() {}
~ReadlinkBase() {}
public:
virtual std::string_view name() const = 0;
public:
virtual int operator()(const Branches &branches,
const fs::path &fusepath,
char *buf,
const size_t bufsize,
const time_t symlinkify_timeout) = 0;
};
}

30
src/func_readlink_factory.cpp

@ -0,0 +1,30 @@
#include "func_readlink_factory.hpp"
#include "func_readlink_ff.hpp"
#include "policies.hpp"
bool
Func2::ReadlinkFactory::valid(const std::string str_)
{
if(str_ == "ff")
return true;
if(Policies::Search::find(str_))
return true;
return false;
}
std::shared_ptr<Func2::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 {};
}

13
src/func_readlink_factory.hpp

@ -0,0 +1,13 @@
#pragma once
#include "func_readlink_base.hpp"
namespace Func2
{
class ReadlinkFactory
{
public:
static bool valid(const std::string str);
static std::shared_ptr<ReadlinkBase> make(const std::string_view str);
};
}

104
src/func_readlink_ff.cpp

@ -0,0 +1,104 @@
#include "func_readlink_ff.hpp"
#include "error.hpp"
#include "fs_readlink.hpp"
#include "fs_lstat.hpp"
#include "symlinkify.hpp"
#include <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_);
}

21
src/func_readlink_ff.hpp

@ -0,0 +1,21 @@
#include "func_readlink_base.hpp"
namespace Func2
{
class ReadlinkFF : public ReadlinkBase
{
public:
ReadlinkFF() {}
~ReadlinkFF() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
char *buf,
const size_t bufsize,
const time_t symlinkify_timeout);
};
}

17
src/func_removexattr.hpp

@ -0,0 +1,17 @@
#pragma once
#include "func_removexattr_base.hpp"
#include "func_removexattr_factory.hpp"
#include "func_wrapper.hpp"
namespace Func2
{
using Removexattr = FuncWrapper<Func2::RemovexattrBase,
Func2::RemovexattrFactory,
int,
const Branches&,
const fs::path&,
const char*&>;
}

35
src/func_removexattr_all.cpp

@ -0,0 +1,35 @@
#include "func_removexattr_all.hpp"
#include "error.hpp"
#include "fs_lremovexattr.hpp"
std::string_view
Func2::RemovexattrAll::name() const
{
return "all";
}
int
Func2::RemovexattrAll::operator()(const Branches &branches_,
const fs::path &fusepath_,
const char *attrname_)
{
Err err;
fs::path fullpath;
for(const auto &branch : branches_)
{
if(branch.ro())
{
err = -EROFS;
continue;
}
fullpath = branch.path / fusepath_;
err = fs::lremovexattr(fullpath,attrname_);
}
return err;
}

19
src/func_removexattr_all.hpp

@ -0,0 +1,19 @@
#include "func_removexattr_base.hpp"
namespace Func2
{
class RemovexattrAll : public RemovexattrBase
{
public:
RemovexattrAll() {}
~RemovexattrAll() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
const char *attrname);
};
}

23
src/func_removexattr_base.hpp

@ -0,0 +1,23 @@
#pragma once
#include "branches.hpp"
#include "fs_path.hpp"
namespace Func2
{
class RemovexattrBase
{
public:
RemovexattrBase() {}
~RemovexattrBase() {}
public:
virtual std::string_view name() const = 0;
public:
virtual int operator()(const Branches &branches,
const fs::path &fusepath,
const char *attrname) = 0;
};
}

30
src/func_removexattr_factory.cpp

@ -0,0 +1,30 @@
#include "func_removexattr_factory.hpp"
#include "func_removexattr_all.hpp"
#include "policies.hpp"
bool
Func2::RemovexattrFactory::valid(const std::string str_)
{
if(str_ == "all")
return true;
if(Policies::Action::find(str_))
return true;
return false;
}
std::shared_ptr<Func2::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 {};
}

13
src/func_removexattr_factory.hpp

@ -0,0 +1,13 @@
#pragma once
#include "func_removexattr_base.hpp"
namespace Func2
{
class RemovexattrFactory
{
public:
static bool valid(const std::string str);
static std::shared_ptr<RemovexattrBase> make(const std::string_view str);
};
}

16
src/func_rmdir.hpp

@ -0,0 +1,16 @@
#pragma once
#include "func_rmdir_base.hpp"
#include "func_rmdir_factory.hpp"
#include "func_wrapper.hpp"
namespace Func2
{
using Rmdir = FuncWrapper<Func2::RmdirBase,
Func2::RmdirFactory,
int,
const Branches&,
const fs::path&>;
}

49
src/func_rmdir_all.cpp

@ -0,0 +1,49 @@
#include "func_rmdir_all.hpp"
#include "config.hpp"
#include "error.hpp"
#include "fs_rmdir.hpp"
#include "fs_unlink.hpp"
std::string_view
Func2::RmdirAll::name() const
{
return "all";
}
static
int
_should_unlink(int rv_)
{
return ((rv_ == -ENOTDIR) &&
(cfg.follow_symlinks != FollowSymlinks::ENUM::NEVER));
}
int
Func2::RmdirAll::operator()(const Branches &branches_,
const fs::path &fusepath_)
{
int rv;
Err err;
fs::path fullpath;
for(const auto &branch : branches_)
{
if(branch.ro())
{
err = -EROFS;
continue;
}
fullpath = branch.path / fusepath_;
rv = fs::rmdir(fullpath);
if(::_should_unlink(rv))
rv = fs::unlink(fullpath);
err = rv;
}
return err;
}

18
src/func_rmdir_all.hpp

@ -0,0 +1,18 @@
#include "func_rmdir_base.hpp"
namespace Func2
{
class RmdirAll : public RmdirBase
{
public:
RmdirAll() {}
~RmdirAll() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath);
};
}

22
src/func_rmdir_base.hpp

@ -0,0 +1,22 @@
#pragma once
#include "branches.hpp"
#include "fs_path.hpp"
namespace Func2
{
class RmdirBase
{
public:
RmdirBase() {}
~RmdirBase() {}
public:
virtual std::string_view name() const = 0;
public:
virtual int operator()(const Branches &branches,
const fs::path &fusepath) = 0;
};
}

30
src/func_rmdir_factory.cpp

@ -0,0 +1,30 @@
#include "func_rmdir_factory.hpp"
#include "func_rmdir_all.hpp"
#include "policies.hpp"
bool
Func2::RmdirFactory::valid(const std::string str_)
{
if(str_ == "all")
return true;
if(Policies::Action::find(str_))
return true;
return false;
}
std::shared_ptr<Func2::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 {};
}

13
src/func_rmdir_factory.hpp

@ -0,0 +1,13 @@
#pragma once
#include "func_rmdir_base.hpp"
namespace Func2
{
class RmdirFactory
{
public:
static bool valid(const std::string str);
static std::shared_ptr<RmdirBase> make(const std::string_view str);
};
}

20
src/func_setxattr.hpp

@ -0,0 +1,20 @@
#pragma once
#include "func_setxattr_base.hpp"
#include "func_setxattr_factory.hpp"
#include "func_wrapper.hpp"
namespace Func2
{
using Setxattr = FuncWrapper<Func2::SetxattrBase,
Func2::SetxattrFactory,
int,
const Branches&,
const fs::path&,
const char*&,
const char*&,
const size_t&,
const int&>;
}

38
src/func_setxattr_all.cpp

@ -0,0 +1,38 @@
#include "func_setxattr_all.hpp"
#include "error.hpp"
#include "fs_lsetxattr.hpp"
std::string_view
Func2::SetxattrAll::name() const
{
return "all";
}
int
Func2::SetxattrAll::operator()(const Branches &branches_,
const fs::path &fusepath_,
const char *attrname_,
const char *attrval_,
size_t attrvalsize_,
int flags_)
{
Err err;
fs::path fullpath;
for(const auto &branch : branches_)
{
if(branch.ro())
{
err = -EROFS;
continue;
}
fullpath = branch.path / fusepath_;
err = fs::lsetxattr(fullpath,attrname_,attrval_,attrvalsize_,flags_);
}
return err;
}

22
src/func_setxattr_all.hpp

@ -0,0 +1,22 @@
#include "func_setxattr_base.hpp"
namespace Func2
{
class SetxattrAll : public SetxattrBase
{
public:
SetxattrAll() {}
~SetxattrAll() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
const char *attrname_,
const char *attrval_,
size_t attrvalsize_,
int flags_);
};
}

26
src/func_setxattr_base.hpp

@ -0,0 +1,26 @@
#pragma once
#include "branches.hpp"
#include "fs_path.hpp"
namespace Func2
{
class SetxattrBase
{
public:
SetxattrBase() {}
~SetxattrBase() {}
public:
virtual std::string_view name() const = 0;
public:
virtual int operator()(const Branches &branches,
const fs::path &fusepath,
const char *attrname,
const char *attrval,
size_t attrvalsize,
int flags) = 0;
};
}

30
src/func_setxattr_factory.cpp

@ -0,0 +1,30 @@
#include "func_setxattr_factory.hpp"
#include "func_setxattr_all.hpp"
#include "policies.hpp"
bool
Func2::SetxattrFactory::valid(const std::string str_)
{
if(str_ == "all")
return true;
if(Policies::Action::find(str_))
return true;
return false;
}
std::shared_ptr<Func2::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 {};
}

13
src/func_setxattr_factory.hpp

@ -0,0 +1,13 @@
#pragma once
#include "func_setxattr_base.hpp"
namespace Func2
{
class SetxattrFactory
{
public:
static bool valid(const std::string str);
static std::shared_ptr<SetxattrBase> make(const std::string_view str);
};
}

21
src/func_statx.hpp

@ -0,0 +1,21 @@
#pragma once
#include "func_statx_base.hpp"
#include "func_statx_factory.hpp"
#include "func_wrapper.hpp"
namespace Func2
{
using Statx = FuncWrapper<Func2::StatxBase,
Func2::StatxFactory,
int,
const Branches&,
const fs::path&,
const u32&,
const u32&,
struct fuse_statx*&,
const FollowSymlinksEnum,
const s64&>;
}

38
src/func_statx_base.hpp

@ -0,0 +1,38 @@
#pragma once
#include "follow_symlinks_enum.hpp"
#include "fs_path.hpp"
#include "branches.hpp"
#include "base_types.h"
#include "fuse.h"
#include <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;
};
}

81
src/func_statx_cdco.cpp

@ -0,0 +1,81 @@
#include "func_statx_cdco.hpp"
#include "error.hpp"
#include "fs_inode.hpp"
#include "fs_statx.hpp"
#include "symlinkify.hpp"
#include "timespec_utils.hpp"
std::string_view
Func2::StatxCDCO::name() const
{
return "cdco";
}
int
Func2::StatxCDCO::operator()(const Branches &branches_,
const fs::path &fusepath_,
const u32 flags_,
const u32 mask_,
struct fuse_statx *st_,
const FollowSymlinksEnum follow_symlinks_,
const s64 symlinkify_timeout_)
{
int rv;
Err err;
fs::path fullpath;
const Branch *first_branch;
first_branch = nullptr;
for(const auto &branch : branches_)
{
struct fuse_statx tmp_st;
fullpath = branch.path / fusepath_;
err = rv = fs::statx(AT_FDCWD,
fullpath,
flags_|AT_SYMLINK_NOFOLLOW,
mask_,
&tmp_st,
follow_symlinks_);
if(rv < 0)
continue;
if(!first_branch)
{
*st_ = tmp_st;
first_branch = &branch;
continue;
}
// This upgrades the uid:gid because mergerfs now does most
// file interaction as root and relies on `default_permissions`
// to manage permissions. Want to ensure that root owned files
// can't be changed so we treat them all as root owned.
if(tmp_st.uid == 0)
st_->uid = 0;
if(tmp_st.gid == 0)
st_->gid = 0;
st_->atime = TimeSpec::newest(st_->atime,tmp_st.atime);
st_->ctime = TimeSpec::newest(st_->ctime,tmp_st.ctime);
st_->mtime = TimeSpec::newest(st_->mtime,tmp_st.mtime);
st_->btime = TimeSpec::newest(st_->btime,tmp_st.btime);
st_->nlink += tmp_st.nlink;
}
if(!first_branch)
return err;
if(symlinkify_timeout_ >= 0)
{
fullpath = first_branch->path / fusepath_;
symlinkify::convert_if_can_be_symlink(fullpath,
st_,
symlinkify_timeout_);
}
fs::inode::calc(first_branch->path,fusepath_,st_);
return 0;
}

23
src/func_statx_cdco.hpp

@ -0,0 +1,23 @@
#include "func_statx_base.hpp"
namespace Func2
{
class StatxCDCO : public StatxBase
{
public:
StatxCDCO() {}
~StatxCDCO() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
const u32 flags_,
const u32 mask_,
struct fuse_statx *st,
const FollowSymlinksEnum follow_symlinks,
const s64 symlinkify_timeout);
};
}

84
src/func_statx_cdfo.cpp

@ -0,0 +1,84 @@
#include "func_statx_cdfo.hpp"
#include "error.hpp"
#include "fs_inode.hpp"
#include "fs_statx.hpp"
#include "symlinkify.hpp"
#include "timespec_utils.hpp"
std::string_view
Func2::StatxCDFO::name() const
{
return "cdfo";
}
int
Func2::StatxCDFO::operator()(const Branches &branches_,
const fs::path &fusepath_,
const u32 flags_,
const u32 mask_,
struct fuse_statx *st_,
const FollowSymlinksEnum follow_symlinks_,
const s64 symlinkify_timeout_)
{
int rv;
Err err;
fs::path fullpath;
const Branch *first_branch;
first_branch = nullptr;
for(const auto &branch : branches_)
{
struct fuse_statx tmp_st;
fullpath = branch.path / fusepath_;
err = rv = fs::statx(AT_FDCWD,
fullpath,
flags_|AT_SYMLINK_NOFOLLOW,
mask_,
&tmp_st,
follow_symlinks_);
if(rv < 0)
continue;
if(!first_branch)
{
*st_ = tmp_st;
first_branch = &branch;
if(not S_ISDIR(tmp_st.mode))
break;
continue;
}
// This upgrades the uid:gid because mergerfs now does most
// file interaction as root and relies on `default_permissions`
// to manage permissions. Want to ensure that root owned files
// can't be changed so we treat them all as root owned.
if(tmp_st.uid == 0)
st_->uid = 0;
if(tmp_st.gid == 0)
st_->gid = 0;
st_->atime = TimeSpec::newest(st_->atime,tmp_st.atime);
st_->ctime = TimeSpec::newest(st_->ctime,tmp_st.ctime);
st_->mtime = TimeSpec::newest(st_->mtime,tmp_st.mtime);
st_->btime = TimeSpec::newest(st_->btime,tmp_st.btime);
st_->nlink += tmp_st.nlink;
}
if(!first_branch)
return err;
if(symlinkify_timeout_ >= 0)
{
fullpath = first_branch->path / fusepath_;
symlinkify::convert_if_can_be_symlink(fullpath,
st_,
symlinkify_timeout_);
}
fs::inode::calc(first_branch->path,fusepath_,st_);
return 0;
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save