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

Also added unit tests. Should have done separately but found a number of bugs.
This commit is contained in:
Antonio SJ Musumeci 2020-12-19 15:06:08 -05:00
parent 2e4c6c5fd1
commit 538467b86d
327 changed files with 6691 additions and 3036 deletions

View File

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

View File

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

View File

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

View File

@ -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;
public:
int from_string(const std::string &str) final;
std::string to_string(void) const final;
public:
uint64_t minfreespace() const;
void set_minfreespace(const uint64_t);
public:
Mode mode;
std::string path;
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;
};
class SrcMounts : public ToFromString
{
public:
SrcMounts(Branches &b_);
public:
int from_string(const std::string &str);
std::string to_string(void) const;
private:
Branches &_branches;
};

429
src/branches.cpp Normal file
View File

@ -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 Normal file
View File

@ -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 Normal file
View File

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

View File

@ -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
{
ACTION,
CREATE,
SEARCH
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
{
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;
};

View File

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

View File

@ -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:
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:
class Write
{
public:
Write();
public:
Config* operator->();
private:
Config &_cfg;
};
public:
Config();
public:
mutable PolicyCache open_cache;
public:
const std::string controlfile;
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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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