From 6ac7f389c5154ee1a55ff26ba23b4529e1c10b80 Mon Sep 17 00:00:00 2001 From: trapexit Date: Thu, 21 Aug 2025 23:42:58 -0400 Subject: [PATCH] Misc changes (#1513) * Start moving to string_view where possible * Rework readdir object to use atomic load/store --- src/branch.cpp | 2 +- src/branch.hpp | 2 +- src/branches.cpp | 28 +- src/branches.hpp | 13 +- src/category.cpp | 2 +- src/category.hpp | 2 +- src/config.hpp | 3 +- src/config_cachefiles.cpp | 2 +- src/config_flushonclose.cpp | 2 +- src/config_follow_symlinks.cpp | 2 +- src/config_gidcache.cpp | 4 +- src/config_gidcache.hpp | 4 +- src/config_inodecalc.cpp | 2 +- src/config_inodecalc.hpp | 2 +- src/config_link_exdev.cpp | 2 +- src/config_log_metrics.cpp | 2 +- src/config_log_metrics.hpp | 2 +- src/config_moveonenospc.cpp | 2 +- src/config_moveonenospc.hpp | 2 +- src/config_nfsopenhack.cpp | 2 +- src/config_pagesize.cpp | 2 +- src/config_pagesize.hpp | 2 +- src/config_passthrough.cpp | 2 +- src/config_pid.hpp | 2 +- src/config_rename_exdev.cpp | 2 +- src/config_set.cpp | 2 +- src/config_set.hpp | 2 +- src/config_statfs.cpp | 2 +- src/config_statfsignore.cpp | 2 +- src/config_xattr.cpp | 2 +- src/enum.hpp | 2 +- src/from_string.cpp | 254 ++++++++++------- src/from_string.hpp | 17 +- src/fs_inode.cpp | 2 +- src/fs_inode.hpp | 2 +- src/func.cpp | 6 +- src/func.hpp | 6 +- src/fuse_init.cpp | 2 - src/fuse_readdir.cpp | 55 ++-- src/fuse_readdir.hpp | 23 +- src/fuse_readdir_base.hpp | 2 + src/fuse_readdir_factory.cpp | 71 ++--- src/fuse_readdir_factory.hpp | 3 +- src/fuse_statx_supported.icpp | 12 +- src/mergerfs.cpp | 1 + src/mergerfs_api.cpp | 2 +- src/num.cpp | 81 +----- src/num.hpp | 8 - src/option_parser.cpp | 59 +++- src/policies.cpp | 6 +- src/policies.hpp | 10 +- src/resources.cpp | 145 ++++++---- src/state.cpp | 63 +++++ src/state.hpp | 24 ++ src/str.cpp | 501 ++++++++++++++++----------------- src/str.hpp | 33 +-- src/symlinkify.hpp | 42 ++- src/to_string.cpp | 65 ++--- src/to_string.hpp | 6 +- src/tofrom_string.hpp | 3 +- src/tofrom_wrapper.hpp | 2 +- 61 files changed, 853 insertions(+), 757 deletions(-) diff --git a/src/branch.cpp b/src/branch.cpp index fccca156..151579a1 100644 --- a/src/branch.cpp +++ b/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; } diff --git a/src/branch.hpp b/src/branch.hpp index f074068f..b6b7d1fe 100644 --- a/src/branch.hpp +++ b/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: diff --git a/src/branches.cpp b/src/branches.cpp index d71d276f..d64941bb 100644 --- a/src/branches.cpp +++ b/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 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; diff --git a/src/branches.hpp b/src/branches.hpp index 31487f40..157cc285 100644 --- a/src/branches.hpp +++ b/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 lg(_mutex); return _impl; } Ptr operator->() const { std::lock_guard 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: diff --git a/src/category.cpp b/src/category.cpp index cc3e52ff..e50acace 100644 --- a/src/category.cpp +++ b/src/category.cpp @@ -23,7 +23,7 @@ #include int -Category::Base::from_string(const std::string &s_) +Category::Base::from_string(const std::string_view s_) { int rv; diff --git a/src/category.hpp b/src/category.hpp index ff3b87f2..da530103 100644 --- a/src/category.hpp +++ b/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: diff --git a/src/config.hpp b/src/config.hpp index 879bf2e4..21b784d9 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -56,6 +56,7 @@ typedef ToFromWrapper ConfigBOOL; typedef ToFromWrapper ConfigUINT64; +typedef ToFromWrapper ConfigS64; typedef ToFromWrapper ConfigINT; typedef ToFromWrapper ConfigSTR; typedef ToFromWrapper 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; diff --git a/src/config_cachefiles.cpp b/src/config_cachefiles.cpp index c07bf639..dd574287 100644 --- a/src/config_cachefiles.cpp +++ b/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; diff --git a/src/config_flushonclose.cpp b/src/config_flushonclose.cpp index 10339262..73dae174 100644 --- a/src/config_flushonclose.cpp +++ b/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; diff --git a/src/config_follow_symlinks.cpp b/src/config_follow_symlinks.cpp index a1a255e7..e57a8e3d 100644 --- a/src/config_follow_symlinks.cpp +++ b/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; diff --git a/src/config_gidcache.cpp b/src/config_gidcache.cpp index 8cdec73e..f5267039 100644 --- a/src/config_gidcache.cpp +++ b/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; diff --git a/src/config_gidcache.hpp b/src/config_gidcache.hpp index f5d68ccf..06a67161 100644 --- a/src/config_gidcache.hpp +++ b/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; }; diff --git a/src/config_inodecalc.cpp b/src/config_inodecalc.cpp index aa21e048..e74b56d3 100644 --- a/src/config_inodecalc.cpp +++ b/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_); } diff --git a/src/config_inodecalc.hpp b/src/config_inodecalc.hpp index 8a882593..dfcbd334 100644 --- a/src/config_inodecalc.hpp +++ b/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; }; diff --git a/src/config_link_exdev.cpp b/src/config_link_exdev.cpp index ccd34f3a..cf08c750 100644 --- a/src/config_link_exdev.cpp +++ b/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; diff --git a/src/config_log_metrics.cpp b/src/config_log_metrics.cpp index 9c269501..c63cff54 100644 --- a/src/config_log_metrics.cpp +++ b/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; diff --git a/src/config_log_metrics.hpp b/src/config_log_metrics.hpp index 9b622fbc..b7fa7d19 100644 --- a/src/config_log_metrics.hpp +++ b/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; }; diff --git a/src/config_moveonenospc.cpp b/src/config_moveonenospc.cpp index 50fcc195..0ccd1ac7 100644 --- a/src/config_moveonenospc.cpp +++ b/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; diff --git a/src/config_moveonenospc.hpp b/src/config_moveonenospc.hpp index a9c827c1..c6122618 100644 --- a/src/config_moveonenospc.hpp +++ b/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: diff --git a/src/config_nfsopenhack.cpp b/src/config_nfsopenhack.cpp index 55cad062..a024441e 100644 --- a/src/config_nfsopenhack.cpp +++ b/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; diff --git a/src/config_pagesize.cpp b/src/config_pagesize.cpp index e486efaa..50f4f2b1 100644 --- a/src/config_pagesize.cpp +++ b/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; diff --git a/src/config_pagesize.hpp b/src/config_pagesize.hpp index 5ab78ad6..22a7c6bf 100644 --- a/src/config_pagesize.hpp +++ b/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& diff --git a/src/config_passthrough.cpp b/src/config_passthrough.cpp index a295c161..879ea665 100644 --- a/src/config_passthrough.cpp +++ b/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; diff --git a/src/config_pid.hpp b/src/config_pid.hpp index 4023db6e..fbff0bab 100644 --- a/src/config_pid.hpp +++ b/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; } diff --git a/src/config_rename_exdev.cpp b/src/config_rename_exdev.cpp index b2fd46d9..c3ff8b68 100644 --- a/src/config_rename_exdev.cpp +++ b/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; diff --git a/src/config_set.cpp b/src/config_set.cpp index 0eef0ad3..4f053d7d 100644 --- a/src/config_set.cpp +++ b/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(); diff --git a/src/config_set.hpp b/src/config_set.hpp index 7b51127a..0fd49b0c 100644 --- a/src/config_set.hpp +++ b/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; }; diff --git a/src/config_statfs.cpp b/src/config_statfs.cpp index 50910367..70c77807 100644 --- a/src/config_statfs.cpp +++ b/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; diff --git a/src/config_statfsignore.cpp b/src/config_statfsignore.cpp index 14b5ded3..9b13faf5 100644 --- a/src/config_statfsignore.cpp +++ b/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; diff --git a/src/config_xattr.cpp b/src/config_xattr.cpp index bb626f22..b9973c5c 100644 --- a/src/config_xattr.cpp +++ b/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; diff --git a/src/enum.hpp b/src/enum.hpp index 8b1a1e12..70232cac 100644 --- a/src/enum.hpp +++ b/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 diff --git a/src/from_string.cpp b/src/from_string.cpp index a4a408fc..5d7f1ed4 100644 --- a/src/from_string.cpp +++ b/src/from_string.cpp @@ -21,119 +21,175 @@ #include "ef.hpp" #include "errno.hpp" +#include + #include -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; } diff --git a/src/from_string.hpp b/src/from_string.hpp index 5944f6c7..16bbd5aa 100644 --- a/src/from_string.hpp +++ b/src/from_string.hpp @@ -18,18 +18,19 @@ #pragma once -#include "fs_path.hpp" - #include +#include #include +#include 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 *); } diff --git a/src/fs_inode.cpp b/src/fs_inode.cpp index 4d0cc3c2..9a0fb133 100644 --- a/src/fs_inode.cpp +++ b/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; diff --git a/src/fs_inode.hpp b/src/fs_inode.hpp index ba3cefeb..9756feb3 100644 --- a/src/fs_inode.hpp +++ b/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, diff --git a/src/func.cpp b/src/func.cpp index 1c6065c6..1368de4d 100644 --- a/src/func.cpp +++ b/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) diff --git a/src/func.hpp b/src/func.hpp index d3c4aa69..cc9616a5 100644 --- a/src/func.hpp +++ b/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: diff --git a/src/fuse_init.cpp b/src/fuse_init.cpp index c6b04e5f..7c9c7795 100644 --- a/src/fuse_init.cpp +++ b/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); diff --git a/src/fuse_readdir.cpp b/src/fuse_readdir.cpp index c1fb9287..69e2f06f 100644 --- a/src/fuse_readdir.cpp +++ b/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 lg(_mutex); + std::shared_ptr 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 tmp; - - tmp = FUSE::ReadDirFactory::make(str_); - if(!tmp) - return -EINVAL; - - { - std::lock_guard lg(_mutex); + std::shared_ptr tmp_str; + std::shared_ptr tmp_readdir; - _type = str_; - std::swap(_readdir,tmp); - } - } - else - { - std::lock_guard 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(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 readdir; - { - std::lock_guard lg(_mutex); - readdir = _readdir; - } + readdir = std::atomic_load(&_impl); rv = (*readdir)(ffi_,buf_); if(rv == -ENOENT) diff --git a/src/fuse_readdir.hpp b/src/fuse_readdir.hpp index 452fbffe..e332b9e3 100644 --- a/src/fuse_readdir.hpp +++ b/src/fuse_readdir.hpp @@ -25,37 +25,30 @@ #include -// 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 _readdir; + std::shared_ptr _str; + std::shared_ptr _impl; }; } diff --git a/src/fuse_readdir_base.hpp b/src/fuse_readdir_base.hpp index 5c60df76..7043ff37 100644 --- a/src/fuse_readdir_base.hpp +++ b/src/fuse_readdir_base.hpp @@ -18,6 +18,8 @@ #include "fuse.h" +#include + namespace FUSE { diff --git a/src/fuse_readdir_factory.cpp b/src/fuse_readdir_factory.cpp index 3942f53d..1d8b09a6 100644 --- a/src/fuse_readdir_factory.cpp +++ b/src/fuse_readdir_factory.cpp @@ -22,31 +22,46 @@ #include "fuse_readdir_cosr.hpp" #include "fuse_readdir_seq.hpp" +#include #include #include #include #include -#include - +#include +// 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 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::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") diff --git a/src/fuse_readdir_factory.hpp b/src/fuse_readdir_factory.hpp index 94c607f3..c085695e 100644 --- a/src/fuse_readdir_factory.hpp +++ b/src/fuse_readdir_factory.hpp @@ -29,7 +29,6 @@ namespace FUSE class ReadDirFactory { public: - static bool valid(std::string str); - static std::shared_ptr make(std::string const str); + static std::shared_ptr make(const std::string_view str); }; } diff --git a/src/fuse_statx_supported.icpp b/src/fuse_statx_supported.icpp index 33731f59..9a1773c6 100644 --- a/src/fuse_statx_supported.icpp +++ b/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(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_); } diff --git a/src/mergerfs.cpp b/src/mergerfs.cpp index 301305b7..7385056f 100644 --- a/src/mergerfs.cpp +++ b/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); diff --git a/src/mergerfs_api.cpp b/src/mergerfs_api.cpp index 15630243..fa6dafce 100644 --- a/src/mergerfs_api.cpp +++ b/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; } diff --git a/src/num.cpp b/src/num.cpp index 28c690fb..f5e6192a 100644 --- a/src/num.cpp +++ b/src/num.cpp @@ -24,7 +24,7 @@ #include #include -#include + #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_) diff --git a/src/num.hpp b/src/num.hpp index 4e8dc79e..74d83b1f 100644 --- a/src/num.hpp +++ b/src/num.hpp @@ -19,14 +19,6 @@ #include #include -#include - -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 { diff --git a/src/option_parser.cpp b/src/option_parser.cpp index 643c7d6f..4e6b86ce 100644 --- a/src/option_parser.cpp +++ b/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(); } diff --git a/src/policies.cpp b/src/policies.cpp index dc64370c..4886a666 100644 --- a/src/policies.cpp +++ b/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); diff --git a/src/policies.hpp b/src/policies.hpp index 65d7f7a0..3ff833c5 100644 --- a/src/policies.hpp +++ b/src/policies.hpp @@ -43,8 +43,8 @@ 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; static Policy::EPFF::Action epff; @@ -69,8 +69,8 @@ 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; static Policy::EPFF::Create epff; @@ -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; diff --git a/src/resources.cpp b/src/resources.cpp index 3df5d2d4..44a9af78 100644 --- a/src/resources.cpp +++ b/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 @@ -22,63 +27,89 @@ #include #include -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; } diff --git a/src/state.cpp b/src/state.cpp index d4040f4b..30a01f2e 100644 --- a/src/state.cpp +++ b/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::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::iterator i; + + i = _getset.find(key_); + if((i == _getset.end()) || (!i->second.set)) + return -ENOATTR; + + return i->second.set(val_); +} diff --git a/src/state.hpp b/src/state.hpp index c7748cd2..97e338f0 100644 --- a/src/state.hpp +++ b/src/state.hpp @@ -4,11 +4,18 @@ #include "fileinfo.hpp" +#include +#include +#include + 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 get; + std::function 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; +private: + std::map _getset; + public: OpenFileMap open_files; }; diff --git a/src/str.cpp b/src/str.cpp index 0dbb0d2b..9039aeb6 100644 --- a/src/str.cpp +++ b/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 *result_) { - void - split(const char *str_, - const char delimiter_, - vector *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 *result_) - { - string part; - istringstream ss(str_); - - while(std::getline(ss,part,delimiter_)) - result_->insert(part); - } - - void - split(const string &str_, - const char delimiter_, - vector *result_) - { - return str::split(str_.c_str(),delimiter_,result_); - } - - void - split(const string &str_, - const char delimiter_, - set *result_) - { - return str::split(str_.c_str(),delimiter_,result_); - } - - void - split_on_null(const char *str_, - const size_t len_, - std::vector *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 *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 &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 &vec_, - const char sep_) - { - return str::join(vec_,0,sep_); - } - - string - join(const set &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 &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 *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 *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 *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 &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 &vec_, + const size_t substridx_, + const char sep_) +{ + if(vec_.empty()) return string(); - } - - string - remove_common_prefix_and_join(const vector &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 &patterns_, - vector &strs_) - { - vector::iterator si; - vector::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 &vec_, + const char sep_) +{ + return str::join(vec_,0,sep_); +} + +string +str::join(const set &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 &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 &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 &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 &patterns_, + vector &strs_) +{ + vector::iterator si; + vector::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 diff --git a/src/str.hpp b/src/str.hpp index c8abcf46..690f253d 100644 --- a/src/str.hpp +++ b/src/str.hpp @@ -23,44 +23,29 @@ namespace str { void - split(const char *str, - const char delimiter, - std::vector *result); - void - split(const std::string &str, + split(const std::string_view str, const char delimiter, std::vector *result); void - split(const char *str, - const char delimiter, - std::set *result); - void - split(const std::string &str, - const char delimiter, - std::set *result); + split(const std::string_view str, + const char delimiter, + std::set *result); void - split_on_null(const char *str, - const size_t len, + split_on_null(const std::string_view str, std::vector *result); void - rsplit1(const std::string &str, + rsplit1(const std::string_view &str, const char delimiter, std::vector *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 &vec, diff --git a/src/symlinkify.hpp b/src/symlinkify.hpp index 3a82d4aa..590003b2 100644 --- a/src/symlinkify.hpp +++ b/src/symlinkify.hpp @@ -19,9 +19,7 @@ #pragma once #include "fuse_kernel.h" - -#include -#include +#include "int_types.h" #include @@ -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_); + } } diff --git a/src/to_string.cpp b/src/to_string.cpp index c16cd093..241b89c8 100644 --- a/src/to_string.cpp +++ b/src/to_string.cpp @@ -23,38 +23,39 @@ #include #include -#include -#include -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(); } diff --git a/src/to_string.hpp b/src/to_string.hpp index d02bca07..8a7b55af 100644 --- a/src/to_string.hpp +++ b/src/to_string.hpp @@ -18,9 +18,8 @@ #pragma once -#include "fs_path.hpp" - #include +#include #include @@ -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&); } diff --git a/src/tofrom_string.hpp b/src/tofrom_string.hpp index ad00a4cf..f3f5b36b 100644 --- a/src/tofrom_string.hpp +++ b/src/tofrom_string.hpp @@ -19,10 +19,11 @@ #pragma once #include +#include 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; }; diff --git a/src/tofrom_wrapper.hpp b/src/tofrom_wrapper.hpp index 99525146..a559ce96 100644 --- a/src/tofrom_wrapper.hpp +++ b/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); }