Browse Source

Misc changes (#1513)

* Start moving to string_view where possible
* Rework readdir object to use atomic load/store
pull/1514/head
trapexit 3 weeks ago
committed by GitHub
parent
commit
6ac7f389c5
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      src/branch.cpp
  2. 2
      src/branch.hpp
  3. 28
      src/branches.cpp
  4. 13
      src/branches.hpp
  5. 2
      src/category.cpp
  6. 2
      src/category.hpp
  7. 3
      src/config.hpp
  8. 2
      src/config_cachefiles.cpp
  9. 2
      src/config_flushonclose.cpp
  10. 2
      src/config_follow_symlinks.cpp
  11. 4
      src/config_gidcache.cpp
  12. 4
      src/config_gidcache.hpp
  13. 2
      src/config_inodecalc.cpp
  14. 2
      src/config_inodecalc.hpp
  15. 2
      src/config_link_exdev.cpp
  16. 2
      src/config_log_metrics.cpp
  17. 2
      src/config_log_metrics.hpp
  18. 2
      src/config_moveonenospc.cpp
  19. 2
      src/config_moveonenospc.hpp
  20. 2
      src/config_nfsopenhack.cpp
  21. 2
      src/config_pagesize.cpp
  22. 2
      src/config_pagesize.hpp
  23. 2
      src/config_passthrough.cpp
  24. 2
      src/config_pid.hpp
  25. 2
      src/config_rename_exdev.cpp
  26. 2
      src/config_set.cpp
  27. 2
      src/config_set.hpp
  28. 2
      src/config_statfs.cpp
  29. 2
      src/config_statfsignore.cpp
  30. 2
      src/config_xattr.cpp
  31. 2
      src/enum.hpp
  32. 254
      src/from_string.cpp
  33. 17
      src/from_string.hpp
  34. 2
      src/fs_inode.cpp
  35. 2
      src/fs_inode.hpp
  36. 6
      src/func.cpp
  37. 6
      src/func.hpp
  38. 2
      src/fuse_init.cpp
  39. 55
      src/fuse_readdir.cpp
  40. 23
      src/fuse_readdir.hpp
  41. 2
      src/fuse_readdir_base.hpp
  42. 71
      src/fuse_readdir_factory.cpp
  43. 3
      src/fuse_readdir_factory.hpp
  44. 12
      src/fuse_statx_supported.icpp
  45. 1
      src/mergerfs.cpp
  46. 2
      src/mergerfs_api.cpp
  47. 81
      src/num.cpp
  48. 8
      src/num.hpp
  49. 59
      src/option_parser.cpp
  50. 6
      src/policies.cpp
  51. 6
      src/policies.hpp
  52. 145
      src/resources.cpp
  53. 63
      src/state.cpp
  54. 24
      src/state.hpp
  55. 501
      src/str.cpp
  56. 33
      src/str.hpp
  57. 42
      src/symlinkify.hpp
  58. 65
      src/to_string.cpp
  59. 6
      src/to_string.hpp
  60. 3
      src/tofrom_string.hpp
  61. 2
      src/tofrom_wrapper.hpp

2
src/branch.cpp

@ -38,7 +38,7 @@ Branch::Branch(const u64 &default_minfreespace_)
}
int
Branch::from_string(const std::string &str_)
Branch::from_string(const std::string_view str_)
{
return -EINVAL;
}

2
src/branch.hpp

@ -57,7 +57,7 @@ public:
bool ro_or_nc(void) const;
public:
int from_string(const std::string &str) final;
int from_string(const std::string_view str) final;
std::string to_string(void) const final;
public:

28
src/branches.cpp

@ -74,9 +74,9 @@ namespace l
{
static
void
split(const std::string &s_,
std::string *instr_,
std::string *values_)
split(const std::string_view s_,
std::string *instr_,
std::string *values_)
{
u64 offset;
@ -222,8 +222,8 @@ namespace l
static
int
set(const std::string &str_,
Branches::Impl *branches_)
set(const std::string_view str_,
Branches::Impl *branches_)
{
int rv;
StrVec paths;
@ -244,8 +244,8 @@ namespace l
static
int
add_begin(const std::string &str_,
Branches::Impl *branches_)
add_begin(const std::string_view str_,
Branches::Impl *branches_)
{
int rv;
std::vector<std::string> paths;
@ -268,8 +268,8 @@ namespace l
static
int
add_end(const std::string &str_,
Branches::Impl *branches_)
add_end(const std::string_view str_,
Branches::Impl *branches_)
{
int rv;
StrVec paths;
@ -310,8 +310,8 @@ namespace l
static
int
erase_fnmatch(const std::string &str_,
Branches::Impl *branches_)
erase_fnmatch(const std::string_view str_,
Branches::Impl *branches_)
{
StrVec patterns;
@ -336,7 +336,7 @@ namespace l
}
int
Branches::Impl::from_string(const std::string &s_)
Branches::Impl::from_string(const std::string_view s_)
{
std::string instr;
std::string values;
@ -403,7 +403,7 @@ Branches::Impl::to_paths() const
}
int
Branches::from_string(const std::string &str_)
Branches::from_string(const std::string_view str_)
{
int rv;
Branches::Ptr impl;
@ -462,7 +462,7 @@ SrcMounts::SrcMounts(Branches &b_)
}
int
SrcMounts::from_string(const std::string &s_)
SrcMounts::from_string(const std::string_view s_)
{
// return _branches.from_string(s_);
return 0;

13
src/branches.hpp

@ -46,7 +46,7 @@ public:
Impl(const u64 &default_minfreespace);
public:
int from_string(const std::string &str) final;
int from_string(const std::string_view str) final;
std::string to_string(void) const final;
public:
@ -73,13 +73,20 @@ public:
{}
public:
int from_string(const std::string &str) final;
int from_string(const std::string_view str) final;
std::string to_string(void) const final;
public:
operator Ptr() const { std::lock_guard<std::mutex> lg(_mutex); return _impl; }
Ptr operator->() const { std::lock_guard<std::mutex> lg(_mutex); return _impl; }
public:
Impl::iterator begin() { return _impl->begin(); }
Impl::iterator end() { return _impl->end(); }
Impl::const_iterator begin() const { return _impl->begin(); }
Impl::const_iterator end() const { return _impl->end(); }
public:
void find_and_set_mode_ro();
};
@ -90,7 +97,7 @@ public:
SrcMounts(Branches &b);
public:
int from_string(const std::string &str) final;
int from_string(const std::string_view str) final;
std::string to_string(void) const final;
private:

2
src/category.cpp

@ -23,7 +23,7 @@
#include <string>
int
Category::Base::from_string(const std::string &s_)
Category::Base::from_string(const std::string_view s_)
{
int rv;

2
src/category.hpp

@ -27,7 +27,7 @@ namespace Category
class Base : public ToFromString
{
public:
int from_string(const std::string &s) final;
int from_string(const std::string_view s) final;
std::string to_string() const final;
protected:

3
src/config.hpp

@ -56,6 +56,7 @@
typedef ToFromWrapper<bool> ConfigBOOL;
typedef ToFromWrapper<uint64_t> ConfigUINT64;
typedef ToFromWrapper<int64_t> ConfigS64;
typedef ToFromWrapper<int> ConfigINT;
typedef ToFromWrapper<std::string> ConfigSTR;
typedef ToFromWrapper<std::filesystem::path> ConfigPath;
@ -161,7 +162,7 @@ public:
StatFS statfs;
StatFSIgnore statfs_ignore;
ConfigBOOL symlinkify;
ConfigUINT64 symlinkify_timeout;
ConfigS64 symlinkify_timeout;
ConfigINT fuse_read_thread_count;
ConfigINT fuse_process_thread_count;
ConfigINT fuse_process_thread_queue_depth;

2
src/config_cachefiles.cpp

@ -45,7 +45,7 @@ CacheFiles::to_string() const
template<>
int
CacheFiles::from_string(const std::string &s_)
CacheFiles::from_string(const std::string_view s_)
{
if(s_ == "libfuse")
_data = CacheFiles::ENUM::LIBFUSE;

2
src/config_flushonclose.cpp

@ -39,7 +39,7 @@ FlushOnClose::to_string() const
template<>
int
FlushOnClose::from_string(const std::string &s_)
FlushOnClose::from_string(const std::string_view s_)
{
if(s_ == "never")
_data = FlushOnClose::ENUM::NEVER;

2
src/config_follow_symlinks.cpp

@ -41,7 +41,7 @@ FollowSymlinks::to_string(void) const
template<>
int
FollowSymlinks::from_string(const std::string &s_)
FollowSymlinks::from_string(const std::string_view s_)
{
if(s_ == "never")
_data = FollowSymlinks::ENUM::NEVER;

4
src/config_gidcache.cpp

@ -23,7 +23,7 @@ GIDCacheExpireTimeout::to_string(void) const
}
int
GIDCacheExpireTimeout::from_string(const std::string &s_)
GIDCacheExpireTimeout::from_string(const std::string_view s_)
{
int rv;
@ -53,7 +53,7 @@ GIDCacheRemoveTimeout::to_string(void) const
}
int
GIDCacheRemoveTimeout::from_string(const std::string &s_)
GIDCacheRemoveTimeout::from_string(const std::string_view s_)
{
int rv;

4
src/config_gidcache.hpp

@ -10,7 +10,7 @@ public:
public:
std::string to_string(void) const final;
int from_string(const std::string &) final;
int from_string(const std::string_view) final;
};
class GIDCacheRemoveTimeout : public ToFromString
@ -21,5 +21,5 @@ public:
public:
std::string to_string(void) const final;
int from_string(const std::string &) final;
int from_string(const std::string_view) final;
};

2
src/config_inodecalc.cpp

@ -32,7 +32,7 @@ InodeCalc::to_string(void) const
}
int
InodeCalc::from_string(const std::string &s_)
InodeCalc::from_string(const std::string_view s_)
{
return fs::inode::set_algo(s_);
}

2
src/config_inodecalc.hpp

@ -28,5 +28,5 @@ public:
public:
std::string to_string(void) const final;
int from_string(const std::string &) final;
int from_string(const std::string_view) final;
};

2
src/config_link_exdev.cpp

@ -41,7 +41,7 @@ LinkEXDEV::to_string(void) const
template<>
int
LinkEXDEV::from_string(const std::string &s_)
LinkEXDEV::from_string(const std::string_view s_)
{
if(s_ == "passthrough")
_data = LinkEXDEV::ENUM::PASSTHROUGH;

2
src/config_log_metrics.cpp

@ -38,7 +38,7 @@ LogMetrics::to_string(void) const
}
int
LogMetrics::from_string(const std::string &s_)
LogMetrics::from_string(const std::string_view s_)
{
int rv;
bool val;

2
src/config_log_metrics.hpp

@ -27,5 +27,5 @@ public:
public:
std::string to_string(void) const final;
int from_string(const std::string &) final;
int from_string(const std::string_view) final;
};

2
src/config_moveonenospc.cpp

@ -23,7 +23,7 @@
int
MoveOnENOSPC::from_string(const std::string &s_)
MoveOnENOSPC::from_string(const std::string_view s_)
{
int rv;
std::string s;

2
src/config_moveonenospc.hpp

@ -35,7 +35,7 @@ public:
}
public:
int from_string(const std::string &s) final;
int from_string(const std::string_view s) final;
std::string to_string() const final;
public:

2
src/config_nfsopenhack.cpp

@ -23,7 +23,7 @@
template<>
int
NFSOpenHack::from_string(const std::string &s_)
NFSOpenHack::from_string(const std::string_view s_)
{
if(s_ == "off")
_data = NFSOpenHack::ENUM::OFF;

2
src/config_pagesize.cpp

@ -44,7 +44,7 @@ ConfigPageSize::to_string(void) const
}
int
ConfigPageSize::from_string(const std::string &s_)
ConfigPageSize::from_string(const std::string_view s_)
{
uint64_t v;
uint64_t pagesize;

2
src/config_pagesize.hpp

@ -33,7 +33,7 @@ public:
public:
std::string to_string(void) const final;
int from_string(const std::string &) final;
int from_string(const std::string_view) final;
public:
ConfigPageSize&

2
src/config_passthrough.cpp

@ -41,7 +41,7 @@ Passthrough::to_string() const
template<>
int
Passthrough::from_string(const std::string &s_)
Passthrough::from_string(const std::string_view s_)
{
if(s_ == "off")
_data = Passthrough::ENUM::OFF;

2
src/config_pid.hpp

@ -35,7 +35,7 @@ public:
}
int
from_string(const std::string &) final
from_string(const std::string_view) final
{
return -EROFS;
}

2
src/config_rename_exdev.cpp

@ -39,7 +39,7 @@ RenameEXDEV::to_string(void) const
template<>
int
RenameEXDEV::from_string(const std::string &s_)
RenameEXDEV::from_string(const std::string_view s_)
{
if(s_ == "passthrough")
_data = RenameEXDEV::ENUM::PASSTHROUGH;

2
src/config_set.cpp

@ -33,7 +33,7 @@ ConfigSet::to_string(void) const
}
int
ConfigSet::from_string(const std::string &str_)
ConfigSet::from_string(const std::string_view str_)
{
this->clear();

2
src/config_set.hpp

@ -31,5 +31,5 @@ public:
public:
std::string to_string(void) const final;
int from_string(const std::string &) final;
int from_string(const std::string_view) final;
};

2
src/config_statfs.cpp

@ -38,7 +38,7 @@ StatFS::to_string() const
template<>
int
StatFS::from_string(const std::string &s_)
StatFS::from_string(const std::string_view s_)
{
if(s_ == "base")
_data = StatFS::ENUM::BASE;

2
src/config_statfsignore.cpp

@ -40,7 +40,7 @@ StatFSIgnore::to_string() const
template<>
int
StatFSIgnore::from_string(const std::string &s_)
StatFSIgnore::from_string(const std::string_view s_)
{
if(s_ == "none")
_data = StatFSIgnore::ENUM::NONE;

2
src/config_xattr.cpp

@ -40,7 +40,7 @@ XAttr::to_string() const
template<>
int
XAttr::from_string(const std::string &s_)
XAttr::from_string(const std::string_view s_)
{
if(s_ == "passthrough")
_data = XAttr::ENUM::PASSTHROUGH;

2
src/enum.hpp

@ -68,7 +68,7 @@ public:
public:
std::string to_string() const final;
int from_string(const std::string &) final;
int from_string(const std::string_view) final;
public:
int to_int() const

254
src/from_string.cpp

@ -21,119 +21,175 @@
#include "ef.hpp"
#include "errno.hpp"
#include <charconv>
#include <stdlib.h>
namespace str
int
str::from(const std::string_view value_,
bool *bool_)
{
int
from(const std::string &value_,
bool *bool_)
{
if((value_ == "true") ||
(value_ == "1") ||
(value_ == "on") ||
(value_ == "yes"))
*bool_ = true;
ef((value_ == "false") ||
(value_ == "0") ||
(value_ == "off") ||
(value_ == "no"))
*bool_ = false;
else
return -EINVAL;
if((value_ == "true") ||
(value_ == "1") ||
(value_ == "on") ||
(value_ == "yes"))
*bool_ = true;
ef((value_ == "false") ||
(value_ == "0") ||
(value_ == "off") ||
(value_ == "no"))
*bool_ = false;
else
return -EINVAL;
return 0;
}
int
str::from(const std::string_view val_,
int *rv_)
{
int tmp;
const int base = 10;
auto [ptr,ec] = std::from_chars(val_.begin(),
val_.end(),
tmp,
base);
if(ec != std::errc{})
return -EINVAL;
*rv_ = tmp;
return 0;
}
int
str::from(const std::string_view val_,
int64_t *rv_)
{
int64_t tmp;
const int base = 10;
auto [ptr,ec] = std::from_chars(val_.begin(),
val_.end(),
tmp,
base);
if(ec != std::errc{})
return -EINVAL;
*rv_ = tmp;
if(ptr == val_.end())
return 0;
}
int
from(const std::string &value_,
int *int_)
{
int tmp;
char *endptr;
errno = 0;
tmp = ::strtol(value_.c_str(),&endptr,10);
if(errno != 0)
return -EINVAL;
if(endptr == value_.c_str())
switch(*ptr)
{
case 'b':
case 'B':
*rv_ *= 1ULL;
break;
case 'k':
case 'K':
*rv_ *= 1024ULL;
break;
case 'm':
case 'M':
*rv_ *= (1024ULL * 1024ULL);
break;
case 'g':
case 'G':
*rv_ *= (1024ULL * 1024ULL * 1024ULL);
break;
case 't':
case 'T':
*rv_ *= (1024ULL * 1024ULL * 1024ULL * 1024ULL);
break;
default:
return -EINVAL;
}
*int_ = tmp;
return 0;
}
return 0;
}
int
from(const std::string &value_,
uint64_t *uint64_)
{
char *endptr;
uint64_t tmp;
tmp = ::strtoll(value_.c_str(),&endptr,10);
switch(*endptr)
{
case 'b':
case 'B':
tmp *= 1ULL;
break;
case 'k':
case 'K':
tmp *= 1024ULL;
break;
case 'm':
case 'M':
tmp *= (1024ULL * 1024ULL);
break;
case 'g':
case 'G':
tmp *= (1024ULL * 1024ULL * 1024ULL);
break;
case 't':
case 'T':
tmp *= (1024ULL * 1024ULL * 1024ULL * 1024ULL);
break;
case '\0':
break;
default:
return -EINVAL;
}
*uint64_ = tmp;
int
str::from(const std::string_view val_,
uint64_t *rv_)
{
uint64_t tmp;
const int base = 10;
auto [ptr,ec] = std::from_chars(val_.begin(),
val_.end(),
tmp,
base);
if(ec != std::errc{})
return -EINVAL;
*rv_ = tmp;
if(ptr == val_.end())
return 0;
}
int
from(const std::string &value_,
std::string *str_)
{
*str_ = value_;
switch(*ptr)
{
case 'b':
case 'B':
*rv_ *= 1ULL;
break;
case 'k':
case 'K':
*rv_ *= 1024ULL;
break;
case 'm':
case 'M':
*rv_ *= (1024ULL * 1024ULL);
break;
case 'g':
case 'G':
*rv_ *= (1024ULL * 1024ULL * 1024ULL);
break;
case 't':
case 'T':
*rv_ *= (1024ULL * 1024ULL * 1024ULL * 1024ULL);
break;
default:
return -EINVAL;
}
return 0;
}
return 0;
}
int
from(const std::string &value_,
const std::string *key_)
{
return -EINVAL;
}
int
str::from(const std::string_view value_,
std::string *str_)
{
*str_ = value_;
int
from(const std::string &value_,
fs::Path *path_)
{
*path_ = value_;
return 0;
}
return 0;
}
int
str::from(const std::string_view value_,
const std::string *key_)
{
return -EINVAL;
}
int
str::from(const std::string_view value_,
std::filesystem::path *path_)
{
*path_ = value_;
return 0;
}

17
src/from_string.hpp

@ -18,18 +18,19 @@
#pragma once
#include "fs_path.hpp"
#include <cstdint>
#include <filesystem>
#include <string>
#include <string_view>
namespace str
{
int from(const std::string &, bool *);
int from(const std::string &, int *);
int from(const std::string &, uint64_t *);
int from(const std::string &, std::string *);
int from(const std::string &, const std::string *);
int from(const std::string &, fs::Path *);
int from(const std::string_view, bool *);
int from(const std::string_view, int *);
int from(const std::string_view, uint64_t *);
int from(const std::string_view, int64_t *);
int from(const std::string_view, std::string *);
int from(const std::string_view, const std::string *);
int from(const std::string_view, std::filesystem::path *);
}

2
src/fs_inode.cpp

@ -147,7 +147,7 @@ _hybrid_hash32(const std::string_view branch_path_,
}
int
fs::inode::set_algo(const std::string &algo_)
fs::inode::set_algo(const std::string_view algo_)
{
if(algo_ == "passthrough")
g_func = ::_passthrough;

2
src/fs_inode.hpp

@ -31,7 +31,7 @@ namespace fs
{
namespace inode
{
int set_algo(const std::string &s);
int set_algo(const std::string_view s);
std::string get_algo(void);
uint64_t calc(const std::string_view basepath,

6
src/func.cpp

@ -20,7 +20,7 @@
int
Func::Base::Action::from_string(const std::string &policyname_)
Func::Base::Action::from_string(const std::string_view policyname_)
{
policy = Policies::Action::find(policyname_);
if(!policy)
@ -36,7 +36,7 @@ Func::Base::Action::to_string(void) const
}
int
Func::Base::Create::from_string(const std::string &policyname_)
Func::Base::Create::from_string(const std::string_view policyname_)
{
policy = Policies::Create::find(policyname_);
if(!policy)
@ -52,7 +52,7 @@ Func::Base::Create::to_string(void) const
}
int
Func::Base::Search::from_string(const std::string &policyname_)
Func::Base::Search::from_string(const std::string_view policyname_)
{
policy = Policies::Search::find(policyname_);
if(!policy)

6
src/func.hpp

@ -37,7 +37,7 @@ namespace Func
{}
public:
int from_string(const std::string &s) final;
int from_string(const std::string_view s) final;
std::string to_string() const final;
public:
@ -52,7 +52,7 @@ namespace Func
{}
public:
int from_string(const std::string &s) final;
int from_string(const std::string_view s) final;
std::string to_string() const final;
public:
@ -67,7 +67,7 @@ namespace Func
{}
public:
int from_string(const std::string &s) final;
int from_string(const std::string_view s) final;
std::string to_string() const final;
public:

2
src/fuse_init.cpp

@ -192,8 +192,6 @@ FUSE::init(fuse_conn_info *conn_)
procfs::init();
ugid::init();
cfg->readdir.initialize();
::_want_if_capable(conn_,FUSE_CAP_ASYNC_DIO);
::_want_if_capable(conn_,FUSE_CAP_ASYNC_READ,&cfg->async_read);
::_want_if_capable(conn_,FUSE_CAP_ATOMIC_O_TRUNC);

55
src/fuse_readdir.cpp

@ -44,56 +44,36 @@ FUSE::readdir(const fuse_file_info_t *ffi_,
return cfg->readdir(ffi_,buf_);
}
FUSE::ReadDir::ReadDir(std::string const s_)
: _initialized(false)
FUSE::ReadDir::ReadDir(const std::string_view s_)
: _str(new std::string())
{
from_string(s_);
if(_initialized)
assert(_readdir);
}
std::string
FUSE::ReadDir::to_string() const
{
std::lock_guard<std::mutex> lg(_mutex);
std::shared_ptr<std::string> str;
return _type;
}
str = std::atomic_load(&_str);
void
FUSE::ReadDir::initialize()
{
_initialized = true;
from_string(_type);
return (*str);
}
int
FUSE::ReadDir::from_string(std::string const &str_)
FUSE::ReadDir::from_string(const std::string_view str_)
{
if(_initialized)
{
std::shared_ptr<FUSE::ReadDirBase> tmp;
tmp = FUSE::ReadDirFactory::make(str_);
if(!tmp)
return -EINVAL;
{
std::lock_guard<std::mutex> lg(_mutex);
std::shared_ptr<std::string> tmp_str;
std::shared_ptr<FUSE::ReadDirBase> tmp_readdir;
_type = str_;
std::swap(_readdir,tmp);
}
}
else
{
std::lock_guard<std::mutex> lg(_mutex);
tmp_readdir = FUSE::ReadDirFactory::make(str_);
if(!tmp_readdir)
return -EINVAL;
if(!FUSE::ReadDirFactory::valid(str_))
return -EINVAL;
tmp_str = std::make_shared<std::string>(str_);
_type = str_;
}
std::atomic_store(&_str,tmp_str);
std::atomic_store(&_impl,tmp_readdir);
return 0;
}
@ -113,7 +93,7 @@ _handle_ENOENT(const fuse_file_info_t *ffi_,
de.d_ino = 0;
de.d_off = 0;
de.d_type = DT_REG;
de.d_type = DT_UNKNOWN;
strcpy(de.d_name,"error: no valid mergerfs branch found, check config");
de.d_reclen = sizeof(de);
@ -134,10 +114,7 @@ FUSE::ReadDir::operator()(const fuse_file_info_t *ffi_,
int rv;
std::shared_ptr<FUSE::ReadDirBase> readdir;
{
std::lock_guard<std::mutex> lg(_mutex);
readdir = _readdir;
}
readdir = std::atomic_load(&_impl);
rv = (*readdir)(ffi_,buf_);
if(rv == -ENOENT)

23
src/fuse_readdir.hpp

@ -25,37 +25,30 @@
#include <assert.h>
// The initialization behavior is not pretty but for the moment
// needed due to the daemonizing function of the libfuse library when
// not using foreground mode. The threads need to be created after the
// fork, not before.
namespace FUSE
{
int readdir(fuse_file_info_t const *ffi,
fuse_dirents_t *buf);
}
namespace FUSE
{
class ReadDir : public ToFromString
{
public:
ReadDir(std::string const s_);
ReadDir(const std::string_view s_);
public:
std::string to_string() const;
int from_string(const std::string &);
int from_string(const std::string_view);
public:
int operator()(fuse_file_info_t const *ffi,
fuse_dirents_t *buf);
public:
void initialize();
private:
mutable std::mutex _mutex;
private:
bool _initialized;
std::string _type;
std::shared_ptr<FUSE::ReadDirBase> _readdir;
std::shared_ptr<std::string> _str;
std::shared_ptr<FUSE::ReadDirBase> _impl;
};
}

2
src/fuse_readdir_base.hpp

@ -18,6 +18,8 @@
#include "fuse.h"
#include <string_view>
namespace FUSE
{

71
src/fuse_readdir_factory.cpp

@ -22,31 +22,46 @@
#include "fuse_readdir_cosr.hpp"
#include "fuse_readdir_seq.hpp"
#include <array>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <set>
#include <regex>
// Regex:
// ^([a-z]{1,15}) -> required type
// (?::(\d+))? -> optional colon + concurrency
// (?::(\d+))? -> optional colon + max_queue_depth
// $ -> end of string
static
void
_read_cfg(std::string const str_,
std::string &type_,
unsigned &concurrency_,
unsigned &max_queue_depth_)
_read_cfg(const std::string_view str_,
std::string &type_,
int &concurrency_,
int &max_queue_depth_)
{
char type[16];
std::string type;
int concurrency;
int max_queue_depth;
bool matched;
std::cmatch match;
std::regex re(R"(^([a-z]{1,15})(?::(\d+))?(?::(\d+))?$)");
concurrency = 0;
concurrency = 0;
max_queue_depth = 0;
std::sscanf(str_.c_str(),
"%15[a-z]:%d:%d",
type,
&concurrency,
&max_queue_depth);
matched = std::regex_match(str_.begin(),
str_.end(),
match,
re);
if(matched)
{
type = match[1];
if(match[2].matched)
concurrency = std::stoi(match[2]);
if(match[3].matched)
max_queue_depth = std::stoi(match[3]);
}
if(concurrency == 0)
{
@ -73,37 +88,13 @@ _read_cfg(std::string const str_,
}
bool
FUSE::ReadDirFactory::valid(const std::string str_)
{
unsigned concurrency;
unsigned max_queue_depth;
std::string type;
static const std::set<std::string> types =
{
"seq", "cosr", "cor"
};
::_read_cfg(str_,type,concurrency,max_queue_depth);
if(types.find(type) == types.end())
return false;
if(concurrency <= 0)
return false;
return true;
}
std::shared_ptr<FUSE::ReadDirBase>
FUSE::ReadDirFactory::make(std::string const str_)
FUSE::ReadDirFactory::make(const std::string_view str_)
{
unsigned concurrency;
unsigned max_queue_depth;
int concurrency;
int max_queue_depth;
std::string type;
if(!valid(str_))
return {};
::_read_cfg(str_,type,concurrency,max_queue_depth);
if(type == "seq")

3
src/fuse_readdir_factory.hpp

@ -29,7 +29,6 @@ namespace FUSE
class ReadDirFactory
{
public:
static bool valid(std::string str);
static std::shared_ptr<ReadDirBase> make(std::string const str);
static std::shared_ptr<ReadDirBase> make(const std::string_view str);
};
}

12
src/fuse_statx_supported.icpp

@ -210,7 +210,11 @@ FUSE::statx(const char *fusepath_,
if(Config::is_ctrl_file(fusepath_))
return ::_statx_controlfile(st_);
return ::_statx(fusepath_,flags_|AT_STATX_DONT_SYNC,mask_,st_,timeout_);
return ::_statx(fusepath_,
flags_|AT_STATX_DONT_SYNC,
mask_,
st_,
timeout_);
}
int
@ -222,5 +226,9 @@ FUSE::statx_fh(const uint64_t fh_,
{
FileInfo *fi = reinterpret_cast<FileInfo*>(fh_);
return ::_statx(fi->fusepath.c_str(),flags_,mask_,st_,timeout_);
return ::_statx(fi->fusepath.c_str(),
flags_|AT_STATX_DONT_SYNC,
mask_,
st_,
timeout_);
}

1
src/mergerfs.cpp

@ -181,6 +181,7 @@ namespace l
orig = oom::get_oom_score_adj();
rv = oom::set_oom_score_adj(score);
(void)rv;
SysLog::info("set oom_score_adj to {}, originally {}",
score,
orig);

2
src/mergerfs_api.cpp

@ -44,7 +44,7 @@ mergerfs::api::allpaths(const std::string &input_path_,
if(rv < 0)
return rv;
str::split_on_null(val.data(),val.size(),&output_paths_);
str::split_on_null(val,&output_paths_);
return 0;
}

81
src/num.cpp

@ -24,7 +24,7 @@
#include <time.h>
#include <cstdint>
#include <string>
#define KB (1024ULL)
#define MB (KB * 1024ULL)
@ -33,85 +33,6 @@
namespace num
{
int
to_uint64_t(const std::string &str,
uint64_t &value)
{
char *endptr;
uint64_t tmp;
tmp = strtoll(str.c_str(),&endptr,10);
switch(*endptr)
{
case 'k':
case 'K':
tmp *= 1024;
break;
case 'm':
case 'M':
tmp *= (1024 * 1024);
break;
case 'g':
case 'G':
tmp *= (1024 * 1024 * 1024);
break;
case 't':
case 'T':
tmp *= (1024ULL * 1024 * 1024 * 1024);
break;
case '\0':
break;
default:
return -1;
}
value = tmp;
return 0;
}
int
to_double(const std::string &str_,
double *d_)
{
double tmp;
char *endptr;
tmp = strtod(str_.c_str(),&endptr);
if(*endptr != '\0')
return -1;
*d_ = tmp;
return 0;
}
int
to_time_t(const std::string &str,
time_t &value)
{
time_t tmp;
char *endptr;
tmp = strtoll(str.c_str(),&endptr,10);
if(*endptr != '\0')
return -1;
if(tmp < 0)
return -1;
value = tmp;
return 0;
}
}
namespace num
{
std::string
humanize(const uint64_t bytes_)

8
src/num.hpp

@ -19,14 +19,6 @@
#include <cstdint>
#include <string>
#include <time.h>
namespace num
{
int to_uint64_t(const std::string &str, uint64_t *value);
int to_double(const std::string &str, double *value);
int to_time_t(const std::string &str, time_t *value);
}
namespace num
{

59
src/option_parser.cpp

@ -204,7 +204,7 @@ _parse_and_process_kv_arg(Config::Write &cfg_,
static
int
process_opt(Config::Write &cfg_,
_process_opt(Config::Write &cfg_,
Config::ErrVec *errs_,
const std::string &arg_)
{
@ -220,7 +220,7 @@ process_opt(Config::Write &cfg_,
static
int
process_branches(Config::Write &cfg_,
_process_branches(Config::Write &cfg_,
Config::ErrVec *errs_,
const char *arg_)
{
@ -237,7 +237,7 @@ process_branches(Config::Write &cfg_,
static
int
process_mount(Config::Write &cfg_,
_process_mount(Config::Write &cfg_,
Config::ErrVec *errs_,
const char *arg_)
{
@ -290,10 +290,10 @@ _usage(void)
static
int
option_processor(void *data_,
const char *arg_,
int key_,
fuse_args *outargs_)
_option_processor(void *data_,
const char *arg_,
int key_,
fuse_args *outargs_)
{
Config::Write cfg;
Config::ErrVec *errs = (Config::ErrVec*)data_;
@ -301,13 +301,13 @@ option_processor(void *data_,
switch(key_)
{
case FUSE_OPT_KEY_OPT:
return process_opt(cfg,errs,arg_);
return ::_process_opt(cfg,errs,arg_);
case FUSE_OPT_KEY_NONOPT:
if(cfg->branches->empty())
return process_branches(cfg,errs,arg_);
return ::_process_branches(cfg,errs,arg_);
else
return process_mount(cfg,errs,arg_);
return ::_process_mount(cfg,errs,arg_);
case MERGERFS_OPT_HELP:
::_usage();
@ -367,6 +367,41 @@ _check_for_mount_loop(Config::Write &cfg_,
}
}
static
void
_print_warnings(Config::Write &cfg_)
{
if(cfg_->passthrough != Passthrough::ENUM::OFF)
{
if(cfg_->cache_files == CacheFiles::ENUM::OFF)
{
SysLog::warning("'cache.files' can not be 'off' when using 'passthrough'."
" Setting 'cache.files=auto-full'");
cfg_->cache_files = CacheFiles::ENUM::AUTO_FULL;
}
if(cfg_->writeback_cache == true)
{
SysLog::warning("'cache.writeback' can not be enabled when using 'passthrough'."
" Setting 'cache.writeback=false'");
cfg_->writeback_cache = false;
}
if(cfg_->moveonenospc.enabled == true)
{
SysLog::warning("`moveonenospc` will not function when `passthrough` is enabled");
}
}
}
static
void
_cleanup_options(Config::Write &cfg_)
{
if(!cfg_->symlinkify)
cfg_->symlinkify_timeout = -1;
}
namespace options
{
void
@ -387,7 +422,7 @@ namespace options
fuse_opt_parse(args_,
errs_,
opts,
::option_processor);
::_option_processor);
if(cfg->branches->empty())
errs_->push_back({0,"branches not set"});
@ -400,6 +435,8 @@ namespace options
::_set_fsname(cfg,args_);
::_set_subtype(args_);
::_set_fuse_threads(cfg);
::_print_warnings(cfg);
::_cleanup_options(cfg);
cfg->finish_initializing();
}

6
src/policies.cpp

@ -45,7 +45,7 @@
FUNC(rand)
Policy::ActionImpl*
Policies::Action::find(const std::string &name_)
Policies::Action::find(const std::string_view name_)
{
IFERT(IFERTA);
@ -53,7 +53,7 @@ Policies::Action::find(const std::string &name_)
}
Policy::CreateImpl*
Policies::Create::find(const std::string &name_)
Policies::Create::find(const std::string_view name_)
{
IFERT(IFERTC);
@ -61,7 +61,7 @@ Policies::Create::find(const std::string &name_)
}
Policy::SearchImpl*
Policies::Search::find(const std::string &name_)
Policies::Search::find(const std::string_view name_)
{
IFERT(IFERTS);

6
src/policies.hpp

@ -43,7 +43,7 @@ struct Policies
{
struct Action
{
static Policy::ActionImpl *find(const std::string &name);
static Policy::ActionImpl *find(const std::string_view name);
static Policy::All::Action all;
static Policy::EPAll::Action epall;
@ -69,7 +69,7 @@ struct Policies
struct Create
{
static Policy::CreateImpl *find(const std::string &name);
static Policy::CreateImpl *find(const std::string_view name);
static Policy::All::Create all;
static Policy::EPAll::Create epall;
@ -95,7 +95,7 @@ struct Policies
struct Search
{
static Policy::SearchImpl *find(const std::string &name);
static Policy::SearchImpl *find(const std::string_view name);
static Policy::All::Search all;
static Policy::EPAll::Search epall;

145
src/resources.cpp

@ -14,6 +14,11 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "resources.hpp"
#include "fs_opendir.hpp"
#include "fs_closedir.hpp"
#include "fs_readdir.hpp"
#include "errno.hpp"
#include <unistd.h>
@ -22,63 +27,89 @@
#include <sys/time.h>
#include <sys/resource.h>
namespace resources
int
resources::reset_umask(void)
{
int
reset_umask(void)
{
umask(0);
umask(0);
return 0;
}
int
resources::maxout_rlimit(const int resource)
{
int rv;
struct rlimit rlim;
rlim.rlim_cur = RLIM_INFINITY;
rlim.rlim_max = RLIM_INFINITY;
rv = ::setrlimit(resource,&rlim);
if(rv == 0)
return 0;
}
int
maxout_rlimit(const int resource)
{
int rv;
struct rlimit rlim;
rlim.rlim_cur = RLIM_INFINITY;
rlim.rlim_max = RLIM_INFINITY;
rv = ::setrlimit(resource,&rlim);
if(rv == 0)
return 0;
rv = ::getrlimit(resource,&rlim);
if(rv == -1)
return -errno;
rv = 0;
rlim.rlim_cur = rlim.rlim_max;
while(rv == 0)
{
rv = ::setrlimit(resource,&rlim);
rlim.rlim_max *= 2;
rlim.rlim_cur = rlim.rlim_max;
}
return rv;
}
int
maxout_rlimit_nofile(void)
{
return maxout_rlimit(RLIMIT_NOFILE);
}
int
maxout_rlimit_fsize(void)
{
return maxout_rlimit(RLIMIT_FSIZE);
}
int
setpriority(const int prio)
{
int rv;
const int SELF = 0;
rv = ::setpriority(PRIO_PROCESS,SELF,prio);
return ((rv == -1) ? -errno : rv);
}
rv = ::getrlimit(resource,&rlim);
if(rv == -1)
return -errno;
rv = 0;
rlim.rlim_cur = rlim.rlim_max;
while(rv == 0)
{
rv = ::setrlimit(resource,&rlim);
rlim.rlim_max *= 2;
rlim.rlim_cur = rlim.rlim_max;
}
return rv;
}
int
resources::maxout_rlimit_nofile(void)
{
return maxout_rlimit(RLIMIT_NOFILE);
}
int
resources::maxout_rlimit_fsize(void)
{
return maxout_rlimit(RLIMIT_FSIZE);
}
int
resources::setpriority(const int prio_)
{
DIR *dir;
struct dirent *e;
::setpriority(PRIO_PROCESS,0,prio_);
dir = fs::opendir("/proc/self/task");
if(dir == NULL)
return -errno;
while(true)
{
pid_t tid;
e = fs::readdir(dir);
if(e == NULL)
break;
if(e->d_name[0] == '.')
continue;
try
{
tid = std::stoi(e->d_name);
}
catch(...)
{
continue;
}
::setpriority(PRIO_PROCESS,tid,prio_);
}
fs::closedir(dir);
return 0;
}

63
src/state.cpp

@ -1,3 +1,66 @@
#include "state.hpp"
#include "fmt/core.h"
#include "errno.hpp"
State state;
// static
// void
// _register_getattr(State *state_)
// {
// State::GetSet x;
// x.get = [state_]() -> std::string
// {
// return state_->getattr.to_string();
// };
// x.set = [state_](const std::string_view s_) -> int
// {
// return state_->getattr.from_string(s_);
// };
// state_->set_getset("user.mergerfs.func.getattr",x);
// }
State::State()
{
// _register_getattr(this);
}
void
State::set_getset(const std::string &name_,
const State::GetSet &gs_)
{
_getset[name_] = gs_;
}
int
State::get(const std::string &key_,
std::string &val_)
{
std::map<std::string,State::GetSet>::iterator i;
i = _getset.find(key_);
if((i == _getset.end()) || (!i->second.get))
return -ENOATTR;
val_ = i->second.get();
return 0;
}
int
State::set(const std::string &key_,
const std::string_view val_)
{
std::map<std::string,State::GetSet>::iterator i;
i = _getset.find(key_);
if((i == _getset.end()) || (!i->second.set))
return -ENOATTR;
return i->second.set(val_);
}

24
src/state.hpp

@ -4,11 +4,18 @@
#include "fileinfo.hpp"
#include <functional>
#include <map>
#include <string>
constexpr int INVALID_BACKING_ID = -1;
class State
{
public:
State();
public:
struct OpenFile
{
@ -24,10 +31,27 @@ public:
FileInfo *fi;
};
public:
struct GetSet
{
std::function<std::string()> get;
std::function<int(const std::string_view)> set;
};
void set_getset(const std::string &name,
const State::GetSet &gs);
int get(const std::string &key,
std::string &val);
int set(const std::string &key,
const std::string_view val);
public:
using OpenFileMap = boost::concurrent_flat_map<u64,OpenFile>;
private:
std::map<std::string,GetSet> _getset;
public:
OpenFileMap open_files;
};

501
src/str.cpp

@ -28,275 +28,254 @@
using std::istringstream;
using std::set;
using std::string;
using std::string_view;
using std::vector;
namespace str
void
str::split(const string_view str_,
const char delimiter_,
vector<string> *result_)
{
void
split(const char *str_,
const char delimiter_,
vector<string> *result_)
{
string part;
istringstream ss(str_);
while(std::getline(ss,part,delimiter_))
result_->push_back(part);
}
void
split(const char *str_,
const char delimiter_,
set<string> *result_)
{
string part;
istringstream ss(str_);
while(std::getline(ss,part,delimiter_))
result_->insert(part);
}
void
split(const string &str_,
const char delimiter_,
vector<string> *result_)
{
return str::split(str_.c_str(),delimiter_,result_);
}
void
split(const string &str_,
const char delimiter_,
set<string> *result_)
{
return str::split(str_.c_str(),delimiter_,result_);
}
void
split_on_null(const char *str_,
const size_t len_,
std::vector<std::string> *result_)
{
const char *start;
const char *end;
start = str_;
end = start + len_;
while(start < end)
{
result_->emplace_back(start);
start += (result_->back().size() + 1);
}
}
void
rsplit1(const string &str_,
const char delimiter_,
vector<string> *result_)
{
std::size_t off;
off = str_.rfind('=');
if(off == std::string::npos)
{
result_->push_back(str_);
}
else
{
result_->push_back(str_.substr(0,off));
result_->push_back(str_.substr(off+1));
}
}
void
splitkv(const std::string_view &str_,
const char delimiter_,
std::string &key_,
std::string_view &val_)
{
size_t pos;
pos = str_.find(delimiter_);
if(pos != std::string_view::npos)
{
key_ = str_.substr(0,pos);
val_ = str_.substr(pos + 1,
str_.size() - pos + 1);
}
else
{
key_ = str_;
val_ = std::string_view{};
}
}
void
splitkv(const string &str_,
const char delimiter_,
string *key_,
string *val_)
{
istringstream iss;
std::string key;
std::string val;
iss.str(str_);
std::getline(iss,key,delimiter_);
std::getline(iss,val,'\0');
*key_ = key;
*val_ = val;
}
string
join(const vector<string> &vec_,
const size_t substridx_,
const char sep_)
{
if(vec_.empty())
return string();
string rv = vec_[0].substr(substridx_);
for(size_t i = 1; i < vec_.size(); i++)
rv += sep_ + vec_[i].substr(substridx_);
return rv;
}
string
join(const vector<string> &vec_,
const char sep_)
{
return str::join(vec_,0,sep_);
}
string
join(const set<string> &set_,
const char sep_)
{
string rv;
for(auto const &s : set_)
rv += s + sep_;
rv.pop_back();
return rv;
}
size_t
longest_common_prefix_index(const vector<string> &vec_)
{
if(vec_.empty())
return string::npos;
for(size_t n = 0; n < vec_[0].size(); n++)
{
char chr = vec_[0][n];
for(size_t i = 1; i < vec_.size(); i++)
{
if(n >= vec_[i].size())
return n;
if(vec_[i][n] != chr)
return n;
}
}
size_t pos;
size_t start;
return string::npos;
}
start = 0;
pos = str_.find(delimiter_,start);
while(pos != std::string_view::npos)
{
result_->push_back(std::string{str_.substr(start,pos)});
start = (pos + 1);
pos = str_.find(delimiter_,start);
}
result_->push_back(std::string{str_.substr(start)});
}
void
str::split(const string_view str_,
const char delimiter_,
set<string> *result_)
{
size_t pos;
size_t start;
start = 0;
pos = str_.find(delimiter_,start);
while(pos != std::string_view::npos)
{
result_->insert(std::string{str_.substr(start,pos)});
start = (pos + 1);
pos = str_.find(delimiter_,start);
}
result_->insert(std::string{str_.substr(start)});
}
void
str::split_on_null(const std::string_view str_,
std::vector<std::string> *result_)
{
const char *start;
const char *end;
start = str_.begin();
end = str_.end();
while(start < end)
{
result_->emplace_back(start);
start += (result_->back().size() + 1);
}
}
void
str::rsplit1(const string_view &str_,
const char delimiter_,
vector<string> *result_)
{
std::size_t off;
off = str_.rfind('=');
if(off == std::string::npos)
{
result_->push_back(std::string{str_});
}
else
{
result_->push_back(std::string{str_.substr(0,off)});
result_->push_back(std::string{str_.substr(off+1)});
}
}
string
longest_common_prefix(const vector<string> &vec_)
{
size_t idx;
void
str::splitkv(const std::string_view str_,
const char delimiter_,
std::string *key_,
std::string *val_)
{
size_t pos;
idx = longest_common_prefix_index(vec_);
if(idx != string::npos)
return vec_[0].substr(0,idx);
pos = str_.find(delimiter_);
if(pos != std::string_view::npos)
{
*key_ = str_.substr(0, pos);
*val_ = str_.substr(pos + 1);
}
else
{
*key_ = str_;
*val_ = "";
}
}
string
str::join(const vector<string> &vec_,
const size_t substridx_,
const char sep_)
{
if(vec_.empty())
return string();
}
string
remove_common_prefix_and_join(const vector<string> &vec_,
const char sep_)
{
size_t idx;
idx = str::longest_common_prefix_index(vec_);
if(idx == string::npos)
idx = 0;
return str::join(vec_,idx,sep_);
}
void
erase_fnmatches(const vector<string> &patterns_,
vector<string> &strs_)
{
vector<string>::iterator si;
vector<string>::const_iterator pi;
si = strs_.begin();
while(si != strs_.end())
{
int match = FNM_NOMATCH;
for(pi = patterns_.begin();
pi != patterns_.end() && match != 0;
++pi)
{
match = fnmatch(pi->c_str(),si->c_str(),0);
}
if(match == 0)
si = strs_.erase(si);
else
++si;
}
}
bool
isprefix(const string &s0_,
const string &s1_)
{
return ((s0_.size() >= s1_.size()) &&
(s0_.compare(0,s1_.size(),s1_) == 0));
}
bool
startswith(const string &str_,
const string &prefix_)
{
return ((str_.size() >= prefix_.size()) &&
(str_.compare(0,prefix_.size(),prefix_) == 0));
}
bool
endswith(const string &str_,
const string &suffix_)
{
if(suffix_.size() > str_.size())
return false;
return std::equal(suffix_.rbegin(),
suffix_.rend(),
str_.rbegin());
}
std::string
trim(const std::string &str_)
{
std::string rv;
rv = str_;
while(!rv.empty() && (rv[0] == ' '))
rv.erase(0);
while(!rv.empty() && (rv[rv.size()-1] == ' '))
rv.erase(rv.size()-1);
return rv;
}
string rv = vec_[0].substr(substridx_);
for(size_t i = 1; i < vec_.size(); i++)
rv += sep_ + vec_[i].substr(substridx_);
return rv;
}
string
str::join(const vector<string> &vec_,
const char sep_)
{
return str::join(vec_,0,sep_);
}
string
str::join(const set<string> &set_,
const char sep_)
{
string rv;
for(auto const &s : set_)
rv += s + sep_;
rv.pop_back();
return rv;
}
size_t
str::longest_common_prefix_index(const vector<string> &vec_)
{
if(vec_.empty())
return string::npos;
for(size_t n = 0; n < vec_[0].size(); n++)
{
char chr = vec_[0][n];
for(size_t i = 1; i < vec_.size(); i++)
{
if(n >= vec_[i].size())
return n;
if(vec_[i][n] != chr)
return n;
}
}
return string::npos;
}
string
str::longest_common_prefix(const vector<string> &vec_)
{
size_t idx;
idx = longest_common_prefix_index(vec_);
if(idx != string::npos)
return vec_[0].substr(0,idx);
return string();
}
string
str::remove_common_prefix_and_join(const vector<string> &vec_,
const char sep_)
{
size_t idx;
idx = str::longest_common_prefix_index(vec_);
if(idx == string::npos)
idx = 0;
return str::join(vec_,idx,sep_);
}
void
str::erase_fnmatches(const vector<string> &patterns_,
vector<string> &strs_)
{
vector<string>::iterator si;
vector<string>::const_iterator pi;
si = strs_.begin();
while(si != strs_.end())
{
int match = FNM_NOMATCH;
for(pi = patterns_.begin();
pi != patterns_.end() && match != 0;
++pi)
{
match = fnmatch(pi->c_str(),si->c_str(),0);
}
if(match == 0)
si = strs_.erase(si);
else
++si;
}
}
bool
str::isprefix(const string &s0_,
const string &s1_)
{
return ((s0_.size() >= s1_.size()) &&
(s0_.compare(0,s1_.size(),s1_) == 0));
}
bool
str::startswith(const string &str_,
const string &prefix_)
{
return ((str_.size() >= prefix_.size()) &&
(str_.compare(0,prefix_.size(),prefix_) == 0));
}
bool
str::endswith(const string &str_,
const string &suffix_)
{
if(suffix_.size() > str_.size())
return false;
return std::equal(suffix_.rbegin(),
suffix_.rend(),
str_.rbegin());
}
std::string
str::trim(const std::string &str_)
{
std::string rv;
rv = str_;
while(!rv.empty() && (rv[0] == ' '))
rv.erase(0);
while(!rv.empty() && (rv[rv.size()-1] == ' '))
rv.erase(rv.size()-1);
return rv;
}
bool

33
src/str.hpp

@ -23,44 +23,29 @@
namespace str
{
void
split(const char *str,
const char delimiter,
std::vector<std::string> *result);
void
split(const std::string &str,
split(const std::string_view str,
const char delimiter,
std::vector<std::string> *result);
void
split(const char *str,
const char delimiter,
std::set<std::string> *result);
void
split(const std::string &str,
const char delimiter,
std::set<std::string> *result);
split(const std::string_view str,
const char delimiter,
std::set<std::string> *result);
void
split_on_null(const char *str,
const size_t len,
split_on_null(const std::string_view str,
std::vector<std::string> *result);
void
rsplit1(const std::string &str,
rsplit1(const std::string_view &str,
const char delimiter,
std::vector<std::string> *result);
void
splitkv(const std::string &str,
const char delimiter,
std::string *key,
std::string *value);
void
splitkv(const std::string_view &str,
splitkv(const std::string_view str,
const char delimiter,
std::string &key,
std::string_view &val);
std::string *key,
std::string *value);
std::string
join(const std::vector<std::string> &vec,

42
src/symlinkify.hpp

@ -19,9 +19,7 @@
#pragma once
#include "fuse_kernel.h"
#include <sys/stat.h>
#include <time.h>
#include "int_types.h"
#include <string>
@ -32,13 +30,13 @@ namespace symlinkify
inline
bool
can_be_symlink(const struct stat &st_,
const time_t timeout_)
const s64 timeout_)
{
if(S_ISDIR(st_.st_mode) ||
(st_.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)))
return false;
const time_t now = ::time(NULL);
const s64 now = ::time(NULL);
return (((now - st_.st_mtime) > timeout_) &&
((now - st_.st_ctime) > timeout_));
@ -48,13 +46,13 @@ namespace symlinkify
inline
bool
can_be_symlink(const struct fuse_statx &st_,
const time_t timeout_)
const s64 timeout_)
{
if(S_ISDIR(st_.mode) ||
(st_.mode & (S_IWUSR|S_IWGRP|S_IWOTH)))
return false;
const time_t now = ::time(NULL);
const s64 now = ::time(NULL);
return (((now - st_.mtime.tv_sec) > timeout_) &&
((now - st_.ctime.tv_sec) > timeout_));
@ -81,4 +79,34 @@ namespace symlinkify
st_->size = target_.size();
st_->blocks = 0;
}
static
inline
void
convert_if_can_be_symlink(const std::string &target_,
struct stat *st_,
const s64 timeout_)
{
if(timeout_ < 0)
return;
if(!symlinkify::can_be_symlink(*st_,timeout_))
return;
symlinkify::convert(target_,st_);
}
static
inline
void
convert_if_can_be_symlink(const std::string &target_,
fuse_statx *st_,
const s64 timeout_)
{
if(timeout_ < 0)
return;
if(!symlinkify::can_be_symlink(*st_,timeout_))
return;
symlinkify::convert(target_,st_);
}
}

65
src/to_string.cpp

@ -23,38 +23,39 @@
#include <cstdint>
#include <string>
#include <inttypes.h>
#include <stdio.h>
namespace str
std::string
str::to(const bool bool_)
{
std::string
to(const bool bool_)
{
return (bool_ ? "true" : "false");
}
std::string
to(const int int_)
{
return fmt::format("{}",int_);
}
std::string
to(const uint64_t uint64_)
{
return fmt::format("{}",uint64_);
}
std::string
to(const std::string &s_)
{
return s_;
}
std::string
to(const fs::Path &path_)
{
return path_.string();
}
return (bool_ ? "true" : "false");
}
std::string
str::to(const int int_)
{
return fmt::format("{}",int_);
}
std::string
str::to(const uint64_t uint64_)
{
return fmt::format("{}",uint64_);
}
std::string
str::to(const int64_t int64_)
{
return fmt::format("{}",int64_);
}
std::string
str::to(const std::string &s_)
{
return s_;
}
std::string
str::to(const std::filesystem::path &path_)
{
return path_.string();
}

6
src/to_string.hpp

@ -18,9 +18,8 @@
#pragma once
#include "fs_path.hpp"
#include <cstdint>
#include <filesystem>
#include <string>
@ -29,6 +28,7 @@ namespace str
std::string to(const bool);
std::string to(const int);
std::string to(const uint64_t);
std::string to(const int64_t);
std::string to(const std::string&);
std::string to(const fs::Path&);
std::string to(const std::filesystem::path&);
}

3
src/tofrom_string.hpp

@ -19,10 +19,11 @@
#pragma once
#include <string>
#include <string_view>
class ToFromString
{
public:
virtual std::string to_string() const = 0;
virtual int from_string(const std::string &) = 0;
virtual int from_string(const std::string_view) = 0;
};

2
src/tofrom_wrapper.hpp

@ -29,7 +29,7 @@ class ToFromWrapper : public ToFromString
{
public:
int
from_string(const std::string &s_) final
from_string(const std::string_view s_) final
{
return str::from(s_,&_data);
}

Loading…
Cancel
Save