Browse Source

config: rework global config, remove rwlock, make branches RCU like

Also added unit tests. Should have done separately but found a number of bugs.
pull/865/head
Antonio SJ Musumeci 3 years ago
parent
commit
538467b86d
  1. 2
      LICENSE
  2. 32
      Makefile
  3. 366
      src/branch.cpp
  4. 67
      src/branch.hpp
  5. 429
      src/branches.cpp
  6. 94
      src/branches.hpp
  7. 49
      src/category.cpp
  8. 93
      src/category.hpp
  9. 228
      src/config.cpp
  10. 98
      src/config.hpp
  11. 1
      src/config_cachefiles.hpp
  12. 1
      src/config_inodecalc.cpp
  13. 5
      src/config_inodecalc.hpp
  14. 9
      src/config_moveonenospc.cpp
  15. 14
      src/config_moveonenospc.hpp
  16. 1
      src/config_nfsopenhack.cpp
  17. 1
      src/config_nfsopenhack.hpp
  18. 1
      src/config_readdir.cpp
  19. 1
      src/config_readdir.hpp
  20. 1
      src/config_statfs.cpp
  21. 1
      src/config_statfs.hpp
  22. 1
      src/config_statfsignore.cpp
  23. 1
      src/config_xattr.cpp
  24. 1
      src/config_xattr.hpp
  25. 1
      src/dirinfo.hpp
  26. 1
      src/endian.hpp
  27. 1
      src/enum.hpp
  28. 1
      src/fh.hpp
  29. 1
      src/fileinfo.hpp
  30. 4
      src/fixed_mem_pool.hpp
  31. 17
      src/from_string.cpp
  32. 2
      src/from_string.hpp
  33. 1
      src/fs_acl.cpp
  34. 1
      src/fs_acl.hpp
  35. 1
      src/fs_attr.hpp
  36. 1
      src/fs_attr_linux.icpp
  37. 1
      src/fs_attr_unsupported.icpp
  38. 1
      src/fs_clonefile.cpp
  39. 1
      src/fs_clonefile.hpp
  40. 5
      src/fs_clonepath.cpp
  41. 1
      src/fs_clonepath.hpp
  42. 1
      src/fs_close.hpp
  43. 1
      src/fs_closedir.hpp
  44. 4
      src/fs_copy_file_range.hpp
  45. 4
      src/fs_copy_file_range_linux.icpp
  46. 4
      src/fs_copy_file_range_unsupported.icpp
  47. 1
      src/fs_copydata.cpp
  48. 1
      src/fs_copydata.hpp
  49. 3
      src/fs_copydata_copy_file_range.cpp
  50. 3
      src/fs_copydata_copy_file_range.hpp
  51. 1
      src/fs_copydata_readwrite.cpp
  52. 1
      src/fs_copydata_readwrite.hpp
  53. 1
      src/fs_cow.cpp
  54. 1
      src/fs_cow.hpp
  55. 1
      src/fs_devid.hpp
  56. 1
      src/fs_dirfd.hpp
  57. 1
      src/fs_dup.hpp
  58. 1
      src/fs_eaccess.hpp
  59. 1
      src/fs_exists.hpp
  60. 1
      src/fs_faccessat.hpp
  61. 1
      src/fs_fadvise.hpp
  62. 1
      src/fs_fadvise_posix.icpp
  63. 1
      src/fs_fadvise_unsupported.icpp
  64. 1
      src/fs_fallocate.hpp
  65. 1
      src/fs_fallocate_linux.icpp
  66. 3
      src/fs_fallocate_osx.icpp
  67. 1
      src/fs_fallocate_posix.icpp
  68. 1
      src/fs_fallocate_unsupported.icpp
  69. 1
      src/fs_fchmod.hpp
  70. 1
      src/fs_fchmodat.hpp
  71. 1
      src/fs_fchown.hpp
  72. 1
      src/fs_fdatasync.hpp
  73. 1
      src/fs_fgetxattr.hpp
  74. 1
      src/fs_ficlone.hpp
  75. 1
      src/fs_ficlone_linux.icpp
  76. 1
      src/fs_ficlone_unsupported.icpp
  77. 3
      src/fs_file_size.cpp
  78. 3
      src/fs_file_size.hpp
  79. 1
      src/fs_findallfiles.cpp
  80. 9
      src/fs_findallfiles.hpp
  81. 32
      src/fs_findonfs.cpp
  82. 11
      src/fs_findonfs.hpp
  83. 1
      src/fs_flistxattr.hpp
  84. 1
      src/fs_flock.hpp
  85. 1
      src/fs_fsetxattr.hpp
  86. 1
      src/fs_fstat.hpp
  87. 1
      src/fs_fstatat.hpp
  88. 1
      src/fs_fsync.hpp
  89. 1
      src/fs_ftruncate.hpp
  90. 1
      src/fs_futimens.hpp
  91. 1
      src/fs_futimens_freebsd_11.hpp
  92. 1
      src/fs_futimens_generic.hpp
  93. 1
      src/fs_futimens_linux.hpp
  94. 1
      src/fs_futimesat.hpp
  95. 1
      src/fs_futimesat_generic.icpp
  96. 1
      src/fs_futimesat_osx.icpp
  97. 1
      src/fs_getdents64.cpp
  98. 1
      src/fs_getdents64.hpp
  99. 1
      src/fs_getfl.cpp
  100. 1
      src/fs_getfl.hpp

2
LICENSE

@ -1,7 +1,7 @@
/*
ISC License
Copyright (c) 2020, Antonio SJ Musumeci <trapexit@spawn.link>
Copyright (c) 2021, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above

32
Makefile

@ -58,13 +58,20 @@ LTO_FLAGS :=
endif
SRC = $(wildcard src/*.cpp)
OBJS = $(SRC:src/%.cpp=build/%.o)
DEPS = $(SRC:src/%.cpp=build/%.d)
OBJS = $(SRC:src/%.cpp=build/.src/%.o)
DEPS = $(SRC:src/%.cpp=build/.src/%.d)
TESTS = $(wildcard tests/*.cpp)
TESTS_OBJS = $(filter-out build/.src/mergerfs.o,$(OBJS))
TESTS_OBJS += $(TESTS:tests/%.cpp=build/.tests/%.o)
TESTS_DEPS = $(TESTS:tests/%.cpp=build/.tests/%.d)
TESTS_DEPS += $(DEPS)
MANPAGE = mergerfs.1
CXXFLAGS ?= ${OPT_FLAGS}
CXXFLAGS := \
${CXXFLAGS} \
-std=c++0x \
-std=c++11 \
$(STATIC_FLAGS) \
$(LTO_FLAGS) \
-Wall \
@ -77,6 +84,9 @@ FUSE_FLAGS = \
MFS_FLAGS = \
-DUSE_XATTR=$(USE_XATTR) \
-DUGID_USE_RWLOCK=$(UGID_USE_RWLOCK)
TESTS_FLAGS = \
-Isrc \
-DTESTS
LDFLAGS := \
${LDFLAGS} \
@ -110,11 +120,19 @@ help:
objects: version build/stamp
$(MAKE) $(OBJS)
tests-objects:
$(MAKE) $(TESTS_OBJS)
build/mergerfs: libfuse objects
$(CXX) $(CXXFLAGS) $(FUSE_FLAGS) $(MFS_FLAGS) $(CPPFLAGS) $(OBJS) -o $@ libfuse/build/libfuse.a $(LDFLAGS)
build/tests: build/mergerfs tests-objects
$(CXX) $(CXXFLAGS) $(TESTS_FLAGS) $(FUSE_FLAGS) $(MFS_FLAGS) $(CPPFLAGS) $(TESTS_OBJS) -o $@ libfuse/build/libfuse.a $(LDFLAGS)
mergerfs: build/mergerfs
tests: build/tests
changelog:
ifeq ($(GIT_REPO),1)
$(GIT2DEBCL) --name mergerfs > ChangeLog
@ -127,12 +145,16 @@ version:
tools/update-version
build/stamp:
$(MKDIR) -p build
$(MKDIR) -p build/.src build/.tests
$(TOUCH) $@
build/%.o: src/%.cpp
build/.src/%.o: src/%.cpp
$(CXX) $(CXXFLAGS) $(FUSE_FLAGS) $(MFS_FLAGS) $(CPPFLAGS) -c $< -o $@
build/.tests/%.o: tests/%.cpp
$(CXX) $(CXXFLAGS) $(TESTS_FLAGS) $(FUSE_FLAGS) $(MFS_FLAGS) $(CPPFLAGS) -c $< -o $@
.PHONY: clean
clean: rpm-clean
$(RM) -rf build

366
src/branch.cpp

@ -18,21 +18,8 @@
#include "branch.hpp"
#include "ef.hpp"
#include "from_string.hpp"
#include "fs_glob.hpp"
#include "fs_realpathize.hpp"
#include "nonstd/optional.hpp"
#include "errno.hpp"
#include "num.hpp"
#include "str.hpp"
#include <string>
#include <errno.h>
#include <fnmatch.h>
using std::string;
using std::vector;
using nonstd::optional;
Branch::Branch(const uint64_t &default_minfreespace_)
@ -108,354 +95,3 @@ Branch::ro_or_nc(void) const
return ((mode == Branch::Mode::RO) ||
(mode == Branch::Mode::NC));
}
namespace l
{
static
void
split(const std::string &s_,
std::string *instr_,
std::string *values_)
{
uint64_t offset;
offset = s_.find_first_of('/');
*instr_ = s_.substr(0,offset);
if(offset != std::string::npos)
*values_ = s_.substr(offset);
}
}
Branches::Branches(const uint64_t &default_minfreespace_)
: default_minfreespace(default_minfreespace_)
{
pthread_rwlock_init(&lock,NULL);
}
namespace l
{
static
int
parse_mode(const string &str_,
Branch::Mode *mode_)
{
if(str_ == "RW")
*mode_ = Branch::Mode::RW;
ef(str_ == "RO")
*mode_ = Branch::Mode::RO;
ef(str_ == "NC")
*mode_ = Branch::Mode::NC;
else
return -EINVAL;
return 0;
}
static
int
parse_minfreespace(const string &str_,
optional<uint64_t> *minfreespace_)
{
int rv;
uint64_t uint64;
rv = str::from(str_,&uint64);
if(rv < 0)
return rv;
*minfreespace_ = uint64;
return 0;
}
static
int
parse_branch(const string &str_,
string *glob_,
Branch::Mode *mode_,
optional<uint64_t> *minfreespace_)
{
int rv;
string options;
vector<string> v;
str::rsplit1(str_,'=',&v);
switch(v.size())
{
case 1:
*glob_ = v[0];
*mode_ = Branch::Mode::RW;
break;
case 2:
*glob_ = v[0];
options = v[1];
v.clear();
str::split(options,',',&v);
switch(v.size())
{
case 2:
rv = l::parse_minfreespace(v[1],minfreespace_);
if(rv < 0)
return rv;
case 1:
rv = l::parse_mode(v[0],mode_);
if(rv < 0)
return rv;
break;
case 0:
return -EINVAL;
}
break;
default:
return -EINVAL;
}
return 0;
}
static
int
parse(const string &str_,
const uint64_t &default_minfreespace_,
BranchVec *branches_)
{
int rv;
string glob;
vector<string> globbed;
optional<uint64_t> minfreespace;
Branch branch(default_minfreespace_);
rv = l::parse_branch(str_,&glob,&branch.mode,&minfreespace);
if(rv < 0)
return rv;
if(minfreespace.has_value())
branch.set_minfreespace(minfreespace.value());
fs::glob(glob,&globbed);
fs::realpathize(&globbed);
for(size_t i = 0; i < globbed.size(); i++)
{
branch.path = globbed[i];
branches_->push_back(branch);
}
return 0;
}
static
int
set(const std::string &str_,
Branches *branches_)
{
int rv;
vector<string> paths;
BranchVec tmp_branchvec;
str::split(str_,':',&paths);
for(size_t i = 0; i < paths.size(); i++)
{
rv = l::parse(paths[i],branches_->default_minfreespace,&tmp_branchvec);
if(rv < 0)
return rv;
}
branches_->vec.clear();
branches_->vec.insert(branches_->vec.end(),
tmp_branchvec.begin(),
tmp_branchvec.end());
return 0;
}
static
int
add_begin(const std::string &str_,
Branches *branches_)
{
int rv;
vector<string> paths;
BranchVec tmp_branchvec;
str::split(str_,':',&paths);
for(size_t i = 0; i < paths.size(); i++)
{
rv = l::parse(paths[i],branches_->default_minfreespace,&tmp_branchvec);
if(rv < 0)
return rv;
}
branches_->vec.insert(branches_->vec.begin(),
tmp_branchvec.begin(),
tmp_branchvec.end());
return 0;
}
static
int
add_end(const std::string &str_,
Branches *branches_)
{
int rv;
vector<string> paths;
BranchVec tmp_branchvec;
str::split(str_,':',&paths);
for(size_t i = 0; i < paths.size(); i++)
{
rv = l::parse(paths[i],branches_->default_minfreespace,&tmp_branchvec);
if(rv < 0)
return rv;
}
branches_->vec.insert(branches_->vec.end(),
tmp_branchvec.begin(),
tmp_branchvec.end());
return 0;
}
static
int
erase_begin(BranchVec *branches_)
{
branches_->erase(branches_->begin());
return 0;
}
static
int
erase_end(BranchVec *branches_)
{
branches_->pop_back();
return 0;
}
static
int
erase_fnmatch(const std::string &str_,
Branches *branches_)
{
vector<string> patterns;
str::split(str_,':',&patterns);
for(BranchVec::iterator i = branches_->vec.begin();
i != branches_->vec.end();)
{
int match = FNM_NOMATCH;
for(vector<string>::const_iterator pi = patterns.begin();
pi != patterns.end() && match != 0;
++pi)
{
match = ::fnmatch(pi->c_str(),i->path.c_str(),0);
}
i = ((match == 0) ? branches_->vec.erase(i) : (i+1));
}
return 0;
}
}
int
Branches::from_string(const std::string &s_)
{
rwlock::WriteGuard guard(lock);
std::string instr;
std::string values;
l::split(s_,&instr,&values);
if(instr == "+")
return l::add_end(values,this);
if(instr == "+<")
return l::add_begin(values,this);
if(instr == "+>")
return l::add_end(values,this);
if(instr == "-")
return l::erase_fnmatch(values,this);
if(instr == "-<")
return l::erase_begin(&vec);
if(instr == "->")
return l::erase_end(&vec);
if(instr == "=")
return l::set(values,this);
if(instr.empty())
return l::set(values,this);
return -EINVAL;
}
string
Branches::to_string(void) const
{
rwlock::ReadGuard guard(lock);
string tmp;
for(size_t i = 0; i < vec.size(); i++)
{
const Branch &branch = vec[i];
tmp += branch.to_string();
tmp += ':';
}
if(*tmp.rbegin() == ':')
tmp.erase(tmp.size() - 1);
return tmp;
}
void
Branches::to_paths(vector<string> &vec_) const
{
rwlock::ReadGuard guard(lock);
for(size_t i = 0; i < vec.size(); i++)
{
const Branch &branch = vec[i];
vec_.push_back(branch.path);
}
}
SrcMounts::SrcMounts(Branches &b_)
: _branches(b_)
{
}
int
SrcMounts::from_string(const std::string &s_)
{
return _branches.from_string(s_);
}
std::string
SrcMounts::to_string(void) const
{
rwlock::ReadGuard guard(_branches.lock);
std::string rv;
for(uint64_t i = 0; i < _branches.vec.size(); i++)
{
rv += _branches.vec[i].path;
rv += ':';
}
if(*rv.rbegin() == ':')
rv.erase(rv.size() - 1);
return rv;
}

67
src/branch.hpp

@ -18,81 +18,50 @@
#pragma once
#include "rwlock.hpp"
#include "tofrom_string.hpp"
#include "nonstd/optional.hpp"
#include "strvec.hpp"
#include "tofrom_string.hpp"
#include <cstdint>
#include <string>
#include <vector>
#include <stdint.h>
#include <pthread.h>
class Branch : public ToFromString
class Branch final : public ToFromString
{
public:
Branch(const uint64_t &default_minfreespace);
typedef std::vector<Branch> Vector;
public:
int from_string(const std::string &str);
std::string to_string(void) const;
Branch(const uint64_t &default_minfreespace_);
public:
enum class Mode
{
INVALID,
RO,
RW,
NC
INVALID,
RO,
RW,
NC
};
public:
Mode mode;
std::string path;
uint64_t minfreespace() const;
public:
void set_minfreespace(const uint64_t minfreespace);
public:
bool ro(void) const;
bool nc(void) const;
bool ro_or_nc(void) const;
private:
nonstd::optional<uint64_t> _minfreespace;
const uint64_t *_default_minfreespace;
};
typedef std::vector<Branch> BranchVec;
class Branches : public ToFromString
{
public:
Branches(const uint64_t &default_minfreespace_);
public:
int from_string(const std::string &str);
std::string to_string(void) const;
public:
void to_paths(std::vector<std::string> &vec) const;
public:
mutable pthread_rwlock_t lock;
BranchVec vec;
const uint64_t &default_minfreespace;
};
int from_string(const std::string &str) final;
std::string to_string(void) const final;
class SrcMounts : public ToFromString
{
public:
SrcMounts(Branches &b_);
uint64_t minfreespace() const;
void set_minfreespace(const uint64_t);
public:
int from_string(const std::string &str);
std::string to_string(void) const;
Mode mode;
std::string path;
private:
Branches &_branches;
nonstd::optional<uint64_t> _minfreespace;
const uint64_t *_default_minfreespace;
};

429
src/branches.cpp

@ -0,0 +1,429 @@
/*
ISC License
Copyright (c) 2021, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "branches.hpp"
#include "ef.hpp"
#include "errno.hpp"
#include "from_string.hpp"
#include "fs_glob.hpp"
#include "fs_realpathize.hpp"
#include "nonstd/optional.hpp"
#include "num.hpp"
#include "str.hpp"
#include <string>
#include <fnmatch.h>
using std::string;
using std::vector;
using nonstd::optional;
Branches::Impl::Impl(const uint64_t &default_minfreespace_)
: _default_minfreespace(default_minfreespace_)
{
}
Branches::Impl&
Branches::Impl::operator=(Branches::Impl &rval_)
{
auto this_base = dynamic_cast<Branch::Vector*>(this);
auto rval_base = dynamic_cast<Branch::Vector*>(&rval_);
*this_base = *rval_base;
return *this;
}
Branches::Impl&
Branches::Impl::operator=(Branches::Impl &&rval_)
{
auto this_base = dynamic_cast<Branch::Vector*>(this);
auto rval_base = dynamic_cast<Branch::Vector*>(&rval_);
*this_base = std::move(*rval_base);
return *this;
}
const
uint64_t&
Branches::Impl::minfreespace(void) const
{
return _default_minfreespace;
}
namespace l
{
static
void
split(const std::string &s_,
std::string *instr_,
std::string *values_)
{
uint64_t offset;
offset = s_.find_first_of('/');
*instr_ = s_.substr(0,offset);
if(offset != std::string::npos)
*values_ = s_.substr(offset);
}
static
int
parse_mode(const string &str_,
Branch::Mode *mode_)
{
if(str_ == "RW")
*mode_ = Branch::Mode::RW;
ef(str_ == "RO")
*mode_ = Branch::Mode::RO;
ef(str_ == "NC")
*mode_ = Branch::Mode::NC;
else
return -EINVAL;
return 0;
}
static
int
parse_minfreespace(const string &str_,
optional<uint64_t> *minfreespace_)
{
int rv;
uint64_t uint64;
rv = str::from(str_,&uint64);
if(rv < 0)
return rv;
*minfreespace_ = uint64;
return 0;
}
static
int
parse_branch(const string &str_,
string *glob_,
Branch::Mode *mode_,
optional<uint64_t> *minfreespace_)
{
int rv;
string options;
vector<string> v;
str::rsplit1(str_,'=',&v);
switch(v.size())
{
case 1:
*glob_ = v[0];
*mode_ = Branch::Mode::RW;
break;
case 2:
*glob_ = v[0];
options = v[1];
v.clear();
str::split(options,',',&v);
switch(v.size())
{
case 2:
rv = l::parse_minfreespace(v[1],minfreespace_);
if(rv < 0)
return rv;
case 1:
rv = l::parse_mode(v[0],mode_);
if(rv < 0)
return rv;
break;
case 0:
return -EINVAL;
}
break;
default:
return -EINVAL;
}
return 0;
}
static
int
parse(const string &str_,
Branches::Impl *branches_)
{
int rv;
string glob;
StrVec paths;
optional<uint64_t> minfreespace;
Branch branch(branches_->minfreespace());
rv = l::parse_branch(str_,&glob,&branch.mode,&minfreespace);
if(rv < 0)
return rv;
if(minfreespace.has_value())
branch.set_minfreespace(minfreespace.value());
fs::glob(glob,&paths);
fs::realpathize(&paths);
for(auto &path : paths)
{
branch.path = path;
branches_->push_back(branch);
}
return 0;
}
static
int
set(const std::string &str_,
Branches::Impl *branches_)
{
int rv;
StrVec paths;
Branches::Impl tmp_branches(branches_->minfreespace());
str::split(str_,':',&paths);
for(auto &path : paths)
{
rv = l::parse(path,&tmp_branches);
if(rv < 0)
return rv;
}
*branches_ = std::move(tmp_branches);
return 0;
}
static
int
add_begin(const std::string &str_,
Branches::Impl *branches_)
{
int rv;
vector<string> paths;
Branches::Impl tmp_branches(branches_->minfreespace());
str::split(str_,':',&paths);
for(auto &path : paths)
{
rv = l::parse(path,&tmp_branches);
if(rv < 0)
return rv;
}
branches_->insert(branches_->begin(),
tmp_branches.begin(),
tmp_branches.end());
return 0;
}
static
int
add_end(const std::string &str_,
Branches::Impl *branches_)
{
int rv;
StrVec paths;
Branches::Impl tmp_branches(branches_->minfreespace());
str::split(str_,':',&paths);
for(auto &path : paths)
{
rv = l::parse(path,&tmp_branches);
if(rv < 0)
return rv;
}
branches_->insert(branches_->end(),
tmp_branches.begin(),
tmp_branches.end());
return 0;
}
static
int
erase_begin(Branches::Impl *branches_)
{
branches_->erase(branches_->begin());
return 0;
}
static
int
erase_end(Branches::Impl *branches_)
{
branches_->pop_back();
return 0;
}
static
int
erase_fnmatch(const std::string &str_,
Branches::Impl *branches_)
{
StrVec patterns;
str::split(str_,':',&patterns);
for(auto i = branches_->begin(); i != branches_->end();)
{
int match = FNM_NOMATCH;
for(auto pi = patterns.cbegin(); pi != patterns.cend() && match != 0; ++pi)
{
match = ::fnmatch(pi->c_str(),i->path.c_str(),0);
}
i = ((match == 0) ? branches_->erase(i) : (i+1));
}
return 0;
}
}
int
Branches::Impl::from_string(const std::string &s_)
{
std::string instr;
std::string values;
l::split(s_,&instr,&values);
if(instr == "+")
return l::add_end(values,this);
if(instr == "+<")
return l::add_begin(values,this);
if(instr == "+>")
return l::add_end(values,this);
if(instr == "-")
return l::erase_fnmatch(values,this);
if(instr == "-<")
return l::erase_begin(this);
if(instr == "->")
return l::erase_end(this);
if(instr == "=")
return l::set(values,this);
if(instr.empty())
return l::set(values,this);
return -EINVAL;
}
std::string
Branches::Impl::to_string(void) const
{
string tmp;
if(empty())
return tmp;
for(auto &branch : *this)
{
tmp += branch.to_string();
tmp += ':';
}
tmp.pop_back();
return tmp;
}
void
Branches::Impl::to_paths(StrVec &paths_) const
{
for(auto &branch : *this)
{
paths_.push_back(branch.path);
}
}
int
Branches::from_string(const std::string &str_)
{
int rv;
Branches::Ptr impl;
Branches::Ptr new_impl;
{
std::lock_guard<std::mutex> lock_guard(_mutex);
impl = _impl;
}
new_impl = std::make_shared<Branches::Impl>(impl->minfreespace());
*new_impl = *impl;
rv = new_impl->from_string(str_);
if(rv < 0)
return rv;
{
std::lock_guard<std::mutex> lock_guard(_mutex);
_impl = new_impl;
}
return 0;
}
string
Branches::to_string(void) const
{
std::lock_guard<std::mutex> lock_guard(_mutex);
return _impl->to_string();
}
SrcMounts::SrcMounts(Branches &b_)
: _branches(b_)
{
}
int
SrcMounts::from_string(const std::string &s_)
{
return _branches.from_string(s_);
}
std::string
SrcMounts::to_string(void) const
{
std::string rv;
Branches::CPtr branches = _branches;
if(branches->empty())
return rv;
for(const auto &branch : *branches)
{
rv += branch.path;
rv += ':';
}
rv.pop_back();
return rv;
}

94
src/branches.hpp

@ -0,0 +1,94 @@
/*
ISC License
Copyright (c) 2021, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#pragma once
#include "branch.hpp"
#include "nonstd/optional.hpp"
#include "strvec.hpp"
#include "tofrom_string.hpp"
#include <cstdint>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
class Branches final : public ToFromString
{
public:
class Impl final : public ToFromString, public Branch::Vector
{
public:
typedef std::shared_ptr<Impl> Ptr;
typedef std::shared_ptr<const Impl> CPtr;
public:
Impl(const uint64_t &default_minfreespace_);
public:
int from_string(const std::string &str) final;
std::string to_string(void) const final;
public:
const uint64_t& minfreespace(void) const;
void to_paths(StrVec &strvec) const;
public:
Impl& operator=(Impl &impl_);
Impl& operator=(Impl &&impl_);
private:
const uint64_t &_default_minfreespace;
};
public:
typedef Branches::Impl::Ptr Ptr;
typedef Branches::Impl::CPtr CPtr;
public:
Branches(const uint64_t &default_minfreespace_)
: _impl(std::make_shared<Impl>(default_minfreespace_))
{}
public:
int from_string(const std::string &str) final;
std::string to_string(void) const final;
public:
operator CPtr() const { std::lock_guard<std::mutex> lg(_mutex); return _impl; }
CPtr operator->() const { std::lock_guard<std::mutex> lg(_mutex); return _impl; }
private:
mutable std::mutex _mutex;
Ptr _impl;
};
class SrcMounts : public ToFromString
{
public:
SrcMounts(Branches &b_);
public:
int from_string(const std::string &str) final;
std::string to_string(void) const final;
private:
Branches &_branches;
};

49
src/category.cpp

@ -0,0 +1,49 @@
/*
ISC License
Copyright (c) 2020, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "category.hpp"
#include "errno.hpp"
#include "str.hpp"
#include <string>
int
Category::Base::from_string(const std::string &s_)
{
int rv;
for(auto func : funcs)
{
rv = func->from_string(s_);
if(rv < 0)
return rv;
}
return 0;
}
std::string
Category::Base::to_string(void) const
{
std::set<std::string> rv;
for(auto func : funcs)
rv.insert(func->to_string());
return str::join(rv,',');
}

93
src/category.hpp

@ -1,5 +1,5 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Copyright (c) 2020, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@ -16,9 +16,92 @@
#pragma once
enum class Category
#include "tofrom_string.hpp"
#include "funcs.hpp"
#include "func.hpp"
#include <string>
namespace Category
{
class Base : public ToFromString
{
public:
int from_string(const std::string &s) final;
std::string to_string() const final;
protected:
std::vector<ToFromString*> funcs;
};
class Action final : public Base
{
private:
Action();
public:
Action(Funcs &funcs_)
{
funcs.push_back(&funcs_.chmod);
funcs.push_back(&funcs_.chown);
funcs.push_back(&funcs_.link);
funcs.push_back(&funcs_.removexattr);
funcs.push_back(&funcs_.rename);
funcs.push_back(&funcs_.rmdir);
funcs.push_back(&funcs_.setxattr);
funcs.push_back(&funcs_.truncate);
funcs.push_back(&funcs_.unlink);
funcs.push_back(&funcs_.utimens);
}
};
class Create final : public Base
{
ACTION,
CREATE,
SEARCH
private:
Create();
public:
Create(Funcs &funcs_)
{
funcs.push_back(&funcs_.create);
funcs.push_back(&funcs_.mkdir);
funcs.push_back(&funcs_.mknod);
funcs.push_back(&funcs_.symlink);
}
};
class Search final : public Base
{
private:
Search();
public:
Search(Funcs &funcs_)
{
funcs.push_back(&funcs_.access);
funcs.push_back(&funcs_.getattr);
funcs.push_back(&funcs_.getxattr);
funcs.push_back(&funcs_.listxattr);
funcs.push_back(&funcs_.open);
funcs.push_back(&funcs_.readlink);
}
};
}
class Categories final
{
private:
Categories();
public:
Categories(Funcs &funcs_)
: action(funcs_),
create(funcs_),
search(funcs_)
{}
public:
Category::Action action;
Category::Create create;
Category::Search search;
};

228
src/config.cpp

@ -20,14 +20,18 @@
#include "from_string.hpp"
#include "num.hpp"
#include "rwlock.hpp"
#include "str.hpp"
#include "to_string.hpp"
#include "version.hpp"
#include <algorithm>
#include <string>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <string>
#include <stdint.h>
#include <pthread.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
@ -37,6 +41,11 @@ using std::string;
#define IFERT(S) if(S == s_) return true
const std::string CONTROLFILE = "/.mergerfs";
Config Config::_singleton;
namespace l
{
static
@ -60,49 +69,44 @@ namespace l
}
Config::Config()
:
open_cache(),
controlfile("/.mergerfs"),
async_read(true),
auto_cache(false),
branches(minfreespace),
cache_attr(1),
cache_entry(1),
cache_files(CacheFiles::ENUM::LIBFUSE),
cache_negative_entry(0),
cache_readdir(false),
cache_statfs(0),
cache_symlinks(false),
category(func),
direct_io(false),
dropcacheonclose(false),
fsname(),
func(),
fuse_msg_size(FUSE_MAX_MAX_PAGES),
ignorepponrename(false),
inodecalc("hybrid-hash"),
link_cow(false),
minfreespace(MINFREESPACE_DEFAULT),
mount(),
moveonenospc(false),
nfsopenhack(NFSOpenHack::ENUM::OFF),
nullrw(false),
pid(::getpid()),
posix_acl(false),
readdir(ReadDir::ENUM::POSIX),
readdirplus(false),
security_capability(true),
srcmounts(branches),
statfs(StatFS::ENUM::BASE),
statfs_ignore(StatFSIgnore::ENUM::NONE),
symlinkify(false),
symlinkify_timeout(3600),
threads(0),
version(MERGERFS_VERSION),
writeback_cache(false),
xattr(XAttr::ENUM::PASSTHROUGH)
: async_read(true),
auto_cache(false),
branches(minfreespace),
cache_attr(1),
cache_entry(1),
cache_files(CacheFiles::ENUM::LIBFUSE),
cache_negative_entry(0),
cache_readdir(false),
cache_statfs(0),
cache_symlinks(false),
category(func),
direct_io(false),
dropcacheonclose(false),
fsname(),
func(),
fuse_msg_size(FUSE_MAX_MAX_PAGES),
ignorepponrename(false),
inodecalc("hybrid-hash"),
link_cow(false),
minfreespace(MINFREESPACE_DEFAULT),
mount(),
moveonenospc(false),
nfsopenhack(NFSOpenHack::ENUM::OFF),
nullrw(false),
pid(::getpid()),
posix_acl(false),
readdir(ReadDir::ENUM::POSIX),
readdirplus(false),
security_capability(true),
srcmounts(branches),
statfs(StatFS::ENUM::BASE),
statfs_ignore(StatFSIgnore::ENUM::NONE),
symlinkify(false),
symlinkify_timeout(3600),
threads(0),
version(MERGERFS_VERSION),
writeback_cache(false),
xattr(XAttr::ENUM::PASSTHROUGH)
{
_map["async_read"] = &async_read;
_map["auto_cache"] = &auto_cache;
@ -166,17 +170,22 @@ Config::Config()
_map["xattr"] = &xattr;
}
const
Config&
Config::ro(void)
Config::operator=(const Config &cfg_)
{
return *((Config*)fuse_get_context()->private_data);
}
int rv;
std::string val;
Config&
Config::rw(void)
{
return *((Config*)fuse_get_context()->private_data);
for(auto &kv : _map)
{
rv = cfg_.get(kv.first,&val);
if(rv)
continue;
kv.second->from_string(val);
}
return *this;
}
bool
@ -254,11 +263,80 @@ Config::set(const std::string &key_,
const std::string &value_)
{
if(l::readonly(key_))
return -EINVAL;
return -EROFS;
return set_raw(key_,value_);
}
int
Config::set(const std::string &kv_)
{
std::string key;
std::string val;
str::splitkv(kv_,'=',&key,&val);
key = str::trim(key);
val = str::trim(val);
return set(key,val);
}
int
Config::from_stream(std::istream &istrm_,
ErrVec *errs_)
{
int rv;
std::string line;
std::string key;
std::string val;
Config newcfg;
newcfg = *this;
while(std::getline(istrm_,line,'\n'))
{
line = str::trim(line);
if(!line.empty() && (line[0] == '#'))
continue;
str::splitkv(line,'=',&key,&val);
key = str::trim(key);
val = str::trim(val);
rv = newcfg.set(key,val);
if(rv < 0)
errs_->push_back({rv,key});
}
if(!errs_->empty())
return -EINVAL;
*this = newcfg;
return 0;
}
int
Config::from_file(const std::string &filepath_,
ErrVec *errs_)
{
int rv;
std::ifstream ifstrm;
ifstrm.open(filepath_);
if(!ifstrm.good())
{
errs_->push_back({-errno,filepath_});
return -errno;
}
rv = from_stream(ifstrm,errs_);
ifstrm.close();
return rv;
}
std::ostream&
operator<<(std::ostream &os_,
const Config &c_)
@ -268,7 +346,47 @@ operator<<(std::ostream &os_,
for(i = c_._map.begin(), ei = c_._map.end(); i != ei; ++i)
{
os_ << i->first << '=' << i->second << '\n';
os_ << i->first << '=' << i->second->to_string() << std::endl;
}
return os_;
}
static
std::string
err2str(const int err_)
{
switch(err_)
{
case 0:
return std::string();
case -EINVAL:
return "invalid value";
case -ENOATTR:
return "unknown option";
case -EROFS:
return "read-only option";
default:
return strerror(-err_);
}
return std::string();
}
std::ostream&
operator<<(std::ostream &os_,
const Config::ErrVec &ev_)
{
std::string errstr;
for(auto &err : ev_)
{
os_ << "* ERROR: ";
errstr = err2str(err.err);
if(!errstr.empty())
os_ << errstr << " - ";
os_ << err.str << std::endl;
}
return os_;

98
src/config.hpp

@ -16,7 +16,8 @@
#pragma once
#include "branch.hpp"
#include "branches.hpp"
#include "category.hpp"
#include "config_cachefiles.hpp"
#include "config_inodecalc.hpp"
#include "config_moveonenospc.hpp"
@ -27,18 +28,20 @@
#include "config_xattr.hpp"
#include "enum.hpp"
#include "errno.hpp"
#include "func_category.hpp"
#include "funcs.hpp"
#include "policy.hpp"
#include "policy_cache.hpp"
#include "rwlock.hpp"
#include "tofrom_wrapper.hpp"
#include <fuse.h>
#include "fuse.h"
#include <cstdint>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
#include <stdint.h>
#include <sys/stat.h>
typedef ToFromWrapper<bool> ConfigBOOL;
@ -47,16 +50,50 @@ typedef ToFromWrapper<int> ConfigINT;
typedef ToFromWrapper<std::string> ConfigSTR;
typedef std::map<std::string,ToFromString*> Str2TFStrMap;
extern const std::string CONTROLFILE;
class Config
{
public:
Config();
struct Err
{
int err;
std::string str;
};
typedef std::vector<Err> ErrVec;
public:
class Read
{
public:
Read();
public:
inline const Config* operator->() const;
private:
const Config &_cfg;
};
public:
mutable PolicyCache open_cache;
class Write
{
public:
Write();
public:
Config* operator->();
private:
Config &_cfg;
};
public:
const std::string controlfile;
Config();
public:
Config& operator=(const Config&);
public:
ConfigBOOL async_read;
@ -69,7 +106,7 @@ public:
ConfigBOOL cache_readdir;
ConfigUINT64 cache_statfs;
ConfigBOOL cache_symlinks;
FuncCategories category;
Categories category;
ConfigBOOL direct_io;
ConfigBOOL dropcacheonclose;
ConfigSTR fsname;
@ -112,11 +149,50 @@ public:
int get(const std::string &key, std::string *val) const;
int set_raw(const std::string &key, const std::string &val);
int set(const std::string &key, const std::string &val);
int set(const std::string &kv);
public:
static const Config &ro(void);
static Config &rw(void);
int from_stream(std::istream &istrm, ErrVec *errs);
int from_file(const std::string &filepath, ErrVec *errs);
private:
Str2TFStrMap _map;
private:
static Config _singleton;
public:
friend class Read;
friend class Write;
};
std::ostream& operator<<(std::ostream &s,const Config::ErrVec &ev);
inline
Config::Read::Read()
: _cfg(Config::_singleton)
{
}
inline
const
Config*
Config::Read::operator->() const
{
return &_cfg;
}
inline
Config::Write::Write()
: _cfg(Config::_singleton)
{
}
inline
Config*
Config::Write::operator->()
{
return &_cfg;
}

1
src/config_cachefiles.hpp

@ -20,6 +20,7 @@
#include "enum.hpp"
enum class CacheFilesEnum
{
LIBFUSE,

1
src/config_inodecalc.cpp

@ -19,6 +19,7 @@
#include "config_inodecalc.hpp"
#include "fs_inode.hpp"
InodeCalc::InodeCalc(const std::string &s_)
{
fs::inode::set_algo(s_);

5
src/config_inodecalc.hpp

@ -20,12 +20,13 @@
#include "tofrom_string.hpp"
class InodeCalc : public ToFromString
{
public:
InodeCalc(const std::string &);
public:
std::string to_string(void) const;
int from_string(const std::string &);
std::string to_string(void) const final;
int from_string(const std::string &) final;
};

9
src/config_moveonenospc.cpp

@ -21,12 +21,13 @@
#include "errno.hpp"
#include "from_string.hpp"
int
MoveOnENOSPC::from_string(const std::string &s_)
{
int rv;
std::string s;
const Policy *tmp;
Policy::CreateImpl *tmp;
rv = str::from(s_,&enabled);
if((rv == 0) && (enabled == true))
@ -36,8 +37,8 @@ MoveOnENOSPC::from_string(const std::string &s_)
else
return 0;
tmp = &Policy::find(s);
if(tmp == Policy::invalid)
tmp = Policies::Create::find(s);
if(tmp == NULL)
return -EINVAL;
policy = tmp;
@ -50,6 +51,6 @@ std::string
MoveOnENOSPC::to_string(void) const
{
if(enabled)
return policy->to_string();
return policy.name();
return "false";
}

14
src/config_moveonenospc.hpp

@ -19,26 +19,26 @@
#pragma once
#include "policy.hpp"
#include "policies.hpp"
#include "tofrom_string.hpp"
#include <string>
class MoveOnENOSPC : public ToFromString
{
public:
MoveOnENOSPC(const bool enabled_)
: enabled(enabled_)
: enabled(enabled_),
policy(&Policies::Create::mfs)
{
policy = (enabled ?
&Policy::mfs :
&Policy::invalid);
}
public:
int from_string(const std::string &s);
std::string to_string() const;
int from_string(const std::string &s) final;
std::string to_string() const final;
public:
bool enabled;
const Policy *policy;
Policy::Create policy;
};

1
src/config_nfsopenhack.cpp

@ -20,6 +20,7 @@
#include "ef.hpp"
#include "errno.hpp"
template<>
int
NFSOpenHack::from_string(const std::string &s_)

1
src/config_nfsopenhack.hpp

@ -20,6 +20,7 @@
#include "enum.hpp"
enum class NFSOpenHackEnum
{
OFF,

1
src/config_readdir.cpp

@ -20,6 +20,7 @@
#include "ef.hpp"
#include "errno.hpp"
template<>
int
ReadDir::from_string(const std::string &s_)

1
src/config_readdir.hpp

@ -20,6 +20,7 @@
#include "enum.hpp"
enum class ReadDirEnum
{
POSIX,

1
src/config_statfs.cpp

@ -20,6 +20,7 @@
#include "ef.hpp"
#include "errno.hpp"
template<>
std::string
StatFS::to_string() const

1
src/config_statfs.hpp

@ -20,6 +20,7 @@
#include "enum.hpp"
enum class StatFSEnum
{
BASE,

1
src/config_statfsignore.cpp

@ -20,6 +20,7 @@
#include "ef.hpp"
#include "errno.hpp"
template<>
std::string
StatFSIgnore::to_string() const

1
src/config_xattr.cpp

@ -20,6 +20,7 @@
#include "ef.hpp"
#include "errno.hpp"
template<>
std::string
XAttr::to_string() const

1
src/config_xattr.hpp

@ -21,6 +21,7 @@
#include "enum.hpp"
#include "errno.hpp"
enum class XAttrEnum
{
PASSTHROUGH = 0,

1
src/dirinfo.hpp

@ -20,6 +20,7 @@
#include <string>
class DirInfo : public FH
{
public:

1
src/endian.hpp

@ -18,6 +18,7 @@
#pragma once
namespace endian
{
static

1
src/enum.hpp

@ -22,6 +22,7 @@
#include <string>
template<typename E>
class Enum : public ToFromString
{

1
src/fh.hpp

@ -18,6 +18,7 @@
#include <string>
class FH
{
public:

1
src/fileinfo.hpp

@ -20,6 +20,7 @@
#include <string>
class FileInfo : public FH
{
public:

4
src/fixed_mem_pool.hpp

@ -18,8 +18,10 @@
#pragma once
#include <cstdint>
#include <stdlib.h>
#include <stdint.h>
typedef struct fixed_mem_pool_t fixed_mem_pool_t;
struct fixed_mem_pool_t

17
src/from_string.cpp

@ -17,13 +17,14 @@
*/
#include "ef.hpp"
#include "errno.hpp"
#include <cstdint>
#include <string>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
namespace str
{
int
@ -50,7 +51,17 @@ namespace str
from(const std::string &value_,
int *int_)
{
*int_ = ::strtol(value_.c_str(),NULL,10);
int tmp;
char *endptr;
errno = 0;
tmp = ::strtol(value_.c_str(),&endptr,10);
if(errno != 0)
return -EINVAL;
if(endptr == value_.c_str())
return -EINVAL;
*int_ = tmp;
return 0;
}

2
src/from_string.hpp

@ -18,9 +18,9 @@
#pragma once
#include <cstdint>
#include <string>
#include <stdint.h>
namespace str
{

1
src/fs_acl.cpp

@ -23,6 +23,7 @@
const char POSIX_ACL_DEFAULT_XATTR[] = "system.posix_acl_default";
namespace fs
{
namespace acl

1
src/fs_acl.hpp

@ -20,6 +20,7 @@
#include <string>
namespace fs
{
namespace acl

1
src/fs_attr.hpp

@ -18,6 +18,7 @@
#include <string>
namespace fs
{
namespace attr

1
src/fs_attr_linux.icpp

@ -26,6 +26,7 @@
using std::string;
namespace fs
{
namespace attr

1
src/fs_attr_unsupported.icpp

@ -18,6 +18,7 @@
#include <string>
namespace fs
{
namespace attr

1
src/fs_clonefile.cpp

@ -22,6 +22,7 @@
#include "fs_fchmod.hpp"
#include "fs_futimens.hpp"
namespace l
{
static

1
src/fs_clonefile.hpp

@ -16,6 +16,7 @@
#pragma once
namespace fs
{
int

5
src/fs_clonepath.cpp

@ -14,8 +14,6 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <string>
#include "errno.h"
#include "fs_attr.hpp"
#include "fs_clonepath.hpp"
@ -27,8 +25,11 @@
#include "fs_xattr.hpp"
#include "ugid.hpp"
#include <string>
using std::string;
namespace l
{
static

1
src/fs_clonepath.hpp

@ -18,6 +18,7 @@
#include <string>
namespace fs
{
int clonepath(const std::string &from,

1
src/fs_close.hpp

@ -20,6 +20,7 @@
#include <unistd.h>
namespace fs
{
static

1
src/fs_closedir.hpp

@ -21,6 +21,7 @@
#include <dirent.h>
#include <sys/types.h>
namespace fs
{
static

4
src/fs_copy_file_range.hpp

@ -18,10 +18,12 @@
#pragma once
#include <cstdint>
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
namespace fs
{
int64_t

4
src/fs_copy_file_range_linux.icpp

@ -22,13 +22,15 @@
#include "errno.hpp"
#include <cstdint>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
namespace l
{
static

4
src/fs_copy_file_range_unsupported.icpp

@ -18,10 +18,12 @@
#include "errno.h"
#include <cstdint>
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
namespace fs
{
ssize_t

1
src/fs_copydata.cpp

@ -24,6 +24,7 @@
#include <stddef.h>
namespace fs
{
int

1
src/fs_copydata.hpp

@ -20,6 +20,7 @@
#include <stddef.h>
namespace fs
{
int

3
src/fs_copydata_copy_file_range.cpp

@ -18,7 +18,8 @@
#include "fs_copy_file_range.hpp"
#include "fs_fstat.hpp"
#include <stdint.h>
#include <cstdint>
namespace l
{

3
src/fs_copydata_copy_file_range.hpp

@ -16,7 +16,8 @@
#pragma once
#include <stdint.h>
#include <cstdint>
namespace fs
{

1
src/fs_copydata_readwrite.cpp

@ -24,6 +24,7 @@
using std::vector;
namespace l
{
static

1
src/fs_copydata_readwrite.hpp

@ -16,6 +16,7 @@
#pragma once
namespace fs
{
int

1
src/fs_cow.cpp

@ -34,6 +34,7 @@
using std::string;
namespace l
{
static

1
src/fs_cow.hpp

@ -21,6 +21,7 @@
#include <sys/stat.h>
#include <sys/types.h>
namespace fs
{
namespace cow

1
src/fs_devid.hpp

@ -20,6 +20,7 @@
#include "fs_fstat.hpp"
namespace fs
{
static

1
src/fs_dirfd.hpp

@ -21,6 +21,7 @@
#include <dirent.h>
#include <sys/types.h>
namespace fs
{
static

1
src/fs_dup.hpp

@ -20,6 +20,7 @@
#include <unistd.h>
namespace fs
{
static

1
src/fs_eaccess.hpp

@ -20,6 +20,7 @@
#include "fs_faccessat.hpp"
namespace fs
{
static

1
src/fs_exists.hpp

@ -23,6 +23,7 @@
#include <string>
namespace fs
{
static

1
src/fs_faccessat.hpp

@ -23,6 +23,7 @@
#include <fcntl.h>
#include <unistd.h>
namespace fs
{
static

1
src/fs_fadvise.hpp

@ -18,6 +18,7 @@
#include <sys/types.h>
namespace fs
{
int

1
src/fs_fadvise_posix.icpp

@ -16,6 +16,7 @@
#include <fcntl.h>
namespace fs
{
static

1
src/fs_fadvise_unsupported.icpp

@ -16,6 +16,7 @@
#include "errno.hpp"
namespace fs
{
static

1
src/fs_fallocate.hpp

@ -18,6 +18,7 @@
#include <fcntl.h>
namespace fs
{
int

1
src/fs_fallocate_linux.icpp

@ -16,6 +16,7 @@
#include <fcntl.h>
namespace fs
{
int

3
src/fs_fallocate_osx.icpp

@ -14,10 +14,11 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "errno.hpp"
#include <fcntl.h>
#include <unistd.h>
#include "errno.hpp"
namespace l
{

1
src/fs_fallocate_posix.icpp

@ -18,6 +18,7 @@
#include <fcntl.h>
namespace fs
{
int

1
src/fs_fallocate_unsupported.icpp

@ -16,6 +16,7 @@
#include "errno.hpp"
namespace fs
{
int

1
src/fs_fchmod.hpp

@ -24,6 +24,7 @@
#define MODE_BITS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
namespace fs
{
static

1
src/fs_fchmodat.hpp

@ -23,6 +23,7 @@
#include <fcntl.h>
#include <sys/stat.h>
namespace fs
{
static

1
src/fs_fchown.hpp

@ -25,6 +25,7 @@
#include <sys/types.h>
#include <unistd.h>
namespace fs
{
static

1
src/fs_fdatasync.hpp

@ -26,6 +26,7 @@
#include <unistd.h>
namespace fs
{
static

1
src/fs_fgetxattr.hpp

@ -25,6 +25,7 @@
#include <sys/types.h>
namespace fs
{
static

1
src/fs_ficlone.hpp

@ -18,6 +18,7 @@
#pragma once
namespace fs
{
int

1
src/fs_ficlone_linux.icpp

@ -21,6 +21,7 @@
#include <linux/fs.h>
namespace fs
{
int

1
src/fs_ficlone_unsupported.icpp

@ -18,6 +18,7 @@
#include "errno.hpp"
namespace fs
{
int

3
src/fs_file_size.cpp

@ -18,7 +18,8 @@
#include "fs_fstat.hpp"
#include <stdint.h>
#include <cstdint>
namespace fs
{

3
src/fs_file_size.hpp

@ -18,7 +18,8 @@
#pragma once
#include <stdint.h>
#include <cstdint>
namespace fs
{

1
src/fs_findallfiles.cpp

@ -22,6 +22,7 @@
#include <string>
#include <vector>
namespace fs
{
void

9
src/fs_findallfiles.hpp

@ -18,13 +18,16 @@
#pragma once
#include "strvec.hpp"
#include <string>
#include <vector>
namespace fs
{
void
findallfiles(const std::vector<std::string> &basepaths,
const char *fusepath,
std::vector<std::string> *paths);
findallfiles(const StrVec &basepaths,
const char *fusepath,
StrVec *paths);
}

32
src/fs_findonfs.cpp

@ -16,7 +16,7 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "branch.hpp"
#include "branches.hpp"
#include "errno.hpp"
#include "fs_fstat.hpp"
#include "fs_lstat.hpp"
@ -24,31 +24,29 @@
#include <string>
namespace l
{
static
int
findonfs(const BranchVec &branches_,
const std::string &fusepath_,
const int fd_,
std::string *basepath_)
findonfs(const Branches::CPtr &branches_,
const std::string &fusepath_,
const int fd_,
std::string *basepath_)
{
int rv;
dev_t dev;
struct stat st;
std::string fullpath;
const Branch *branch;
rv = fs::fstat(fd_,&st);
if(rv == -1)
return -1;
dev = st.st_dev;
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
for(const auto &branch : *branches_)
{
branch = &branches_[i];
fullpath = fs::path::make(branch->path,fusepath_);
fullpath = fs::path::make(branch.path,fusepath_);
rv = fs::lstat(fullpath,&st);
if(rv == -1)
@ -57,7 +55,7 @@ namespace l
if(st.st_dev != dev)
continue;
*basepath_ = branch->path;
*basepath_ = branch.path;
return 0;
}
@ -69,13 +67,11 @@ namespace l
namespace fs
{
int
findonfs(const Branches &branches_,
const std::string &fusepath_,
const int fd_,
std::string *basepath_)
findonfs(const Branches::CPtr &branches_,
const std::string &fusepath_,
const int fd_,
std::string *basepath_)
{
rwlock::ReadGuard guard(branches_.lock);
return l::findonfs(branches_.vec,fusepath_,fd_,basepath_);
return l::findonfs(branches_,fusepath_,fd_,basepath_);
}
}

11
src/fs_findonfs.hpp

@ -18,15 +18,16 @@
#pragma once
#include "branch.hpp"
#include "branches.hpp"
#include <string>
namespace fs
{
int
findonfs(const Branches &branches,
const std::string &fusepath,
const int fd,
std::string *basepath);
findonfs(const Branches::CPtr &branches,
const std::string &fusepath,
const int fd,
std::string *basepath);
}

1
src/fs_flistxattr.hpp

@ -23,6 +23,7 @@
#include <sys/types.h>
namespace fs
{
static

1
src/fs_flock.hpp

@ -20,6 +20,7 @@
#include <sys/file.h>
namespace fs
{
static

1
src/fs_fsetxattr.hpp

@ -25,6 +25,7 @@
#include <sys/types.h>
namespace fs
{
static

1
src/fs_fstat.hpp

@ -23,6 +23,7 @@
#include <sys/types.h>
#include <unistd.h>
namespace fs
{
static

1
src/fs_fstatat.hpp

@ -23,6 +23,7 @@
#include <unistd.h>
#include <fcntl.h>
namespace fs
{
static

1
src/fs_fsync.hpp

@ -20,6 +20,7 @@
#include <unistd.h>
namespace fs
{
static

1
src/fs_ftruncate.hpp

@ -21,6 +21,7 @@
#include <sys/types.h>
#include <unistd.h>
namespace fs
{
static

1
src/fs_futimens.hpp

@ -33,6 +33,7 @@
#include "fs_futimens_generic.hpp"
#endif
namespace fs
{
static

1
src/fs_futimens_freebsd_11.hpp

@ -20,6 +20,7 @@
#include <sys/stat.h>
namespace fs
{
static

1
src/fs_futimens_generic.hpp

@ -33,6 +33,7 @@
# define UTIME_OMIT ((1l << 30) - 2l)
#endif
namespace l
{
static

1
src/fs_futimens_linux.hpp

@ -20,6 +20,7 @@
#include <sys/stat.h>
namespace fs
{
static

1
src/fs_futimesat.hpp

@ -20,6 +20,7 @@
#include <sys/time.h>
namespace fs
{
int

1
src/fs_futimesat_generic.icpp

@ -19,6 +19,7 @@
#include <fcntl.h>
#include <sys/time.h>
namespace fs
{
int

1
src/fs_futimesat_osx.icpp

@ -26,6 +26,7 @@
#include <sys/time.h>
#include <unistd.h>
namespace l
{
static

1
src/fs_getdents64.cpp

@ -23,6 +23,7 @@
#include <sys/syscall.h>
#endif
namespace fs
{
int

1
src/fs_getdents64.hpp

@ -18,6 +18,7 @@
#pragma once
namespace fs
{
int

1
src/fs_getfl.cpp

@ -18,6 +18,7 @@
#include <fcntl.h>
namespace fs
{
int

1
src/fs_getfl.hpp

@ -18,6 +18,7 @@
#pragma once
namespace fs
{
int getfl(const int fd);

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

Loading…
Cancel
Save