diff --git a/src/link.cpp b/src/link.cpp index e5b32b34..b7a6f30c 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -246,21 +246,21 @@ namespace mergerfs const ugid::Set ugid(fc->uid,fc->gid); const rwlock::ReadGuard readlock(&config.srcmountslock); - if(config.create != Policy::epmfs) - return _link_create_path(config.link, - config.create, - config.srcmounts, - config.minfreespace, - from, - to); - - return _link_preserve_path(config.getattr, - config.link, - config.create, - config.srcmounts, - config.minfreespace, - from, - to); + if(config.create->path_preserving()) + return _link_preserve_path(config.getattr, + config.link, + config.create, + config.srcmounts, + config.minfreespace, + from, + to); + + return _link_create_path(config.link, + config.create, + config.srcmounts, + config.minfreespace, + from, + to); } } } diff --git a/src/policy.cpp b/src/policy.cpp index b0597d78..33792996 100644 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -20,27 +20,30 @@ #include "fs.hpp" #include "buildvector.hpp" -#define POLICY(X) (Policy(Policy::Enum::X,#X,Policy::Func::X)) +#define POLICY(X,PP) (Policy(Policy::Enum::X,#X,Policy::Func::X,PP)) +#define PRESERVES_PATH true +#define DOESNT_PRESERVE_PATH false namespace mergerfs { const std::vector Policy::_policies_ = buildvector - (POLICY(invalid)) - (POLICY(all)) - (POLICY(einval)) - (POLICY(enosys)) - (POLICY(enotsup)) - (POLICY(epmfs)) - (POLICY(erofs)) - (POLICY(exdev)) - (POLICY(ff)) - (POLICY(ffwp)) - (POLICY(fwfs)) - (POLICY(lfs)) - (POLICY(mfs)) - (POLICY(newest)) - (POLICY(rand)); + (POLICY(invalid,DOESNT_PRESERVE_PATH)) + (POLICY(all,DOESNT_PRESERVE_PATH)) + (POLICY(einval,DOESNT_PRESERVE_PATH)) + (POLICY(enosys,DOESNT_PRESERVE_PATH)) + (POLICY(enotsup,DOESNT_PRESERVE_PATH)) + (POLICY(eplfs,PRESERVES_PATH)) + (POLICY(epmfs,PRESERVES_PATH)) + (POLICY(erofs,DOESNT_PRESERVE_PATH)) + (POLICY(exdev,DOESNT_PRESERVE_PATH)) + (POLICY(ff,DOESNT_PRESERVE_PATH)) + (POLICY(ffwp,DOESNT_PRESERVE_PATH)) + (POLICY(fwfs,DOESNT_PRESERVE_PATH)) + (POLICY(lfs,DOESNT_PRESERVE_PATH)) + (POLICY(mfs,DOESNT_PRESERVE_PATH)) + (POLICY(newest,DOESNT_PRESERVE_PATH)) + (POLICY(rand,DOESNT_PRESERVE_PATH)); const Policy * const Policy::policies = &_policies_[1]; @@ -51,6 +54,7 @@ namespace mergerfs CONST_POLICY(einval); CONST_POLICY(enosys); CONST_POLICY(enotsup); + CONST_POLICY(eplfs); CONST_POLICY(epmfs); CONST_POLICY(erofs); CONST_POLICY(exdev); diff --git a/src/policy.hpp b/src/policy.hpp index bf7cf5ff..84b7a857 100644 --- a/src/policy.hpp +++ b/src/policy.hpp @@ -39,6 +39,7 @@ namespace mergerfs einval, enosys, enotsup, + eplfs, epmfs, erofs, exdev, @@ -95,6 +96,7 @@ namespace mergerfs static int einval(CType,cstrvec&,const char*,csize_t,cstrptrvec&); static int enosys(CType,cstrvec&,const char *,csize_t,cstrptrvec&); static int enotsup(CType,cstrvec&,const char *,csize_t,cstrptrvec&); + static int eplfs(CType,cstrvec&,const char *,csize_t,cstrptrvec&); static int epmfs(CType,cstrvec&,const char *,csize_t,cstrptrvec&); static int erofs(CType,cstrvec&,const char *,csize_t,cstrptrvec&); static int exdev(CType,cstrvec&,const char *,csize_t,cstrptrvec&); @@ -112,24 +114,34 @@ namespace mergerfs Enum::Type _enum; std::string _str; Func::Ptr _func; + bool _path_preserving; public: Policy() : _enum(invalid), _str(invalid), - _func(invalid) + _func(invalid), + _path_preserving(false) { } Policy(const Enum::Type enum_, const std::string &str_, - const Func::Ptr func_) + const Func::Ptr func_, + const bool path_preserving_) : _enum(enum_), _str(str_), - _func(func_) + _func(func_), + _path_preserving(path_preserving_) { } + bool + path_preserving() const + { + return _path_preserving; + } + public: operator const Enum::Type() const { return _enum; } operator const std::string&() const { return _str; } @@ -162,6 +174,7 @@ namespace mergerfs static const Policy &einval; static const Policy &enosys; static const Policy &enotsup; + static const Policy &eplfs; static const Policy &epmfs; static const Policy &erofs; static const Policy &exdev; diff --git a/src/policy_eplfs.cpp b/src/policy_eplfs.cpp new file mode 100644 index 00000000..59624f61 --- /dev/null +++ b/src/policy_eplfs.cpp @@ -0,0 +1,108 @@ +/* + Copyright (c) 2016, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include +#include +#include +#include +#include + +#include +#include + +#include "fs_path.hpp" +#include "policy.hpp" + +using std::string; +using std::vector; +using std::size_t; +using mergerfs::Policy; +using mergerfs::Category; +typedef struct statvfs statvfs_t; + +static +void +_calc_lfs(const statvfs_t &fsstats, + const string *basepath, + const size_t minfreespace, + fsblkcnt_t &lfs, + const string *&lfsbasepath) +{ + fsblkcnt_t spaceavail; + + spaceavail = (fsstats.f_frsize * fsstats.f_bavail); + if((spaceavail > minfreespace) && (spaceavail < lfs)) + { + lfs = spaceavail; + lfsbasepath = basepath; + } +} + +static +int +_eplfs(const Category::Enum::Type type, + const vector &basepaths, + const char *fusepath, + const size_t minfreespace, + vector &paths) +{ + int rv; + string fullpath; + statvfs_t fsstats; + fsblkcnt_t eplfs; + const string *eplfsbasepath; + + eplfs = -1; + eplfsbasepath = NULL; + for(size_t i = 0, ei = basepaths.size(); i != ei; i++) + { + const string *basepath = &basepaths[i]; + + fs::path::make(basepath,fusepath,fullpath); + + rv = ::statvfs(fullpath.c_str(),&fsstats); + if(rv == 0) + _calc_lfs(fsstats,basepath,minfreespace,eplfs,eplfsbasepath); + } + + if(eplfsbasepath == NULL) + return -ENOENT; + + paths.push_back(eplfsbasepath); + + return 0; +} + +namespace mergerfs +{ + int + Policy::Func::eplfs(const Category::Enum::Type type, + const vector &basepaths, + const char *fusepath, + const size_t minfreespace, + vector &paths) + { + int rv; + const size_t minfs = + ((type == Category::Enum::create) ? minfreespace : 0); + + rv = _eplfs(type,basepaths,fusepath,minfs,paths); + if(rv != 0) + rv = Policy::Func::lfs(type,basepaths,fusepath,minfreespace,paths); + + return rv; + } +} diff --git a/src/rename.cpp b/src/rename.cpp index 255ffbc6..5730d7c8 100644 --- a/src/rename.cpp +++ b/src/rename.cpp @@ -275,21 +275,21 @@ namespace mergerfs const ugid::Set ugid(fc->uid,fc->gid); const rwlock::ReadGuard readlock(&config.srcmountslock); - if(config.create != Policy::epmfs) - return _rename_create_path(config.rename, - config.create, - config.srcmounts, - config.minfreespace, - oldpath, - newpath); - - return _rename_preserve_path(config.getattr, - config.rename, - config.create, - config.srcmounts, - config.minfreespace, - oldpath, - newpath); + if(config.create->path_preserving()) + return _rename_preserve_path(config.getattr, + config.rename, + config.create, + config.srcmounts, + config.minfreespace, + oldpath, + newpath); + + return _rename_create_path(config.rename, + config.create, + config.srcmounts, + config.minfreespace, + oldpath, + newpath); } } }