mirror of https://github.com/trapexit/mergerfs.git
Browse Source
config: rework global config, remove rwlock, make branches RCU like
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
4 years ago
327 changed files with 6646 additions and 2991 deletions
-
2LICENSE
-
32Makefile
-
366src/branch.cpp
-
59src/branch.hpp
-
429src/branches.cpp
-
94src/branches.hpp
-
49src/category.cpp
-
93src/category.hpp
-
152src/config.cpp
-
98src/config.hpp
-
1src/config_cachefiles.hpp
-
1src/config_inodecalc.cpp
-
5src/config_inodecalc.hpp
-
9src/config_moveonenospc.cpp
-
14src/config_moveonenospc.hpp
-
1src/config_nfsopenhack.cpp
-
1src/config_nfsopenhack.hpp
-
1src/config_readdir.cpp
-
1src/config_readdir.hpp
-
1src/config_statfs.cpp
-
1src/config_statfs.hpp
-
1src/config_statfsignore.cpp
-
1src/config_xattr.cpp
-
1src/config_xattr.hpp
-
1src/dirinfo.hpp
-
1src/endian.hpp
-
1src/enum.hpp
-
1src/fh.hpp
-
1src/fileinfo.hpp
-
4src/fixed_mem_pool.hpp
-
17src/from_string.cpp
-
2src/from_string.hpp
-
1src/fs_acl.cpp
-
1src/fs_acl.hpp
-
1src/fs_attr.hpp
-
1src/fs_attr_linux.icpp
-
1src/fs_attr_unsupported.icpp
-
1src/fs_clonefile.cpp
-
1src/fs_clonefile.hpp
-
5src/fs_clonepath.cpp
-
1src/fs_clonepath.hpp
-
1src/fs_close.hpp
-
1src/fs_closedir.hpp
-
4src/fs_copy_file_range.hpp
-
4src/fs_copy_file_range_linux.icpp
-
4src/fs_copy_file_range_unsupported.icpp
-
1src/fs_copydata.cpp
-
1src/fs_copydata.hpp
-
3src/fs_copydata_copy_file_range.cpp
-
3src/fs_copydata_copy_file_range.hpp
-
1src/fs_copydata_readwrite.cpp
-
1src/fs_copydata_readwrite.hpp
-
1src/fs_cow.cpp
-
1src/fs_cow.hpp
-
1src/fs_devid.hpp
-
1src/fs_dirfd.hpp
-
1src/fs_dup.hpp
-
1src/fs_eaccess.hpp
-
1src/fs_exists.hpp
-
1src/fs_faccessat.hpp
-
1src/fs_fadvise.hpp
-
1src/fs_fadvise_posix.icpp
-
1src/fs_fadvise_unsupported.icpp
-
1src/fs_fallocate.hpp
-
1src/fs_fallocate_linux.icpp
-
3src/fs_fallocate_osx.icpp
-
1src/fs_fallocate_posix.icpp
-
1src/fs_fallocate_unsupported.icpp
-
1src/fs_fchmod.hpp
-
1src/fs_fchmodat.hpp
-
1src/fs_fchown.hpp
-
1src/fs_fdatasync.hpp
-
1src/fs_fgetxattr.hpp
-
1src/fs_ficlone.hpp
-
1src/fs_ficlone_linux.icpp
-
1src/fs_ficlone_unsupported.icpp
-
3src/fs_file_size.cpp
-
3src/fs_file_size.hpp
-
1src/fs_findallfiles.cpp
-
7src/fs_findallfiles.hpp
-
20src/fs_findonfs.cpp
-
5src/fs_findonfs.hpp
-
1src/fs_flistxattr.hpp
-
1src/fs_flock.hpp
-
1src/fs_fsetxattr.hpp
-
1src/fs_fstat.hpp
-
1src/fs_fstatat.hpp
-
1src/fs_fsync.hpp
-
1src/fs_ftruncate.hpp
-
1src/fs_futimens.hpp
-
1src/fs_futimens_freebsd_11.hpp
-
1src/fs_futimens_generic.hpp
-
1src/fs_futimens_linux.hpp
-
1src/fs_futimesat.hpp
-
1src/fs_futimesat_generic.icpp
-
1src/fs_futimesat_osx.icpp
-
1src/fs_getdents64.cpp
-
1src/fs_getdents64.hpp
-
1src/fs_getfl.cpp
-
1src/fs_getfl.hpp
@ -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; |
|||
} |
@ -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; |
|||
}; |
@ -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,','); |
|||
} |
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue