From b55ebba4eda5ec9bddf4224c339d1c3631f4bc4a Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Sat, 20 Oct 2018 23:40:02 -0400 Subject: [PATCH] add tagging branches RW/RO/NW This allows users to tag a branch as readonly or not for writing regardless of how the filesystem is mounted. Should simplify deployments and offer more flexibility. --- README.md | 64 ++++++----- man/mergerfs.1 | 113 +++++++++++--------- src/access.cpp | 8 +- src/branch.cpp | 216 +++++++++++++++++++++++++++++++++++++ src/branch.hpp | 55 ++++++++++ src/chmod.cpp | 8 +- src/chown.cpp | 8 +- src/config.cpp | 8 +- src/config.hpp | 5 +- src/create.cpp | 10 +- src/fs.cpp | 14 +-- src/fs.hpp | 4 +- src/fs_glob.cpp | 17 +-- src/fs_glob.hpp | 4 +- src/fs_info.cpp | 18 ---- src/fs_info.hpp | 5 - src/getattr.cpp | 8 +- src/getxattr.cpp | 39 ++++--- src/ioctl.cpp | 8 +- src/link.cpp | 32 +++--- src/listxattr.cpp | 9 +- src/mkdir.cpp | 10 +- src/mknod.cpp | 10 +- src/open.cpp | 8 +- src/option_parser.cpp | 30 +++--- src/policy.hpp | 37 +++---- src/policy_all.cpp | 94 +++++++---------- src/policy_epall.cpp | 153 ++++++++++++++++++--------- src/policy_epff.cpp | 165 +++++++++++++++++------------ src/policy_eplfs.cpp | 235 ++++++++++++++++++++++++----------------- src/policy_eplus.cpp | 235 ++++++++++++++++++++++++----------------- src/policy_epmfs.cpp | 235 ++++++++++++++++++++++++----------------- src/policy_eprand.cpp | 4 +- src/policy_erofs.cpp | 2 +- src/policy_error.hpp | 51 +++++++++ src/policy_ff.cpp | 100 +++++++----------- src/policy_invalid.cpp | 2 +- src/policy_lfs.cpp | 146 +++++++++---------------- src/policy_lus.cpp | 145 +++++++++---------------- src/policy_mfs.cpp | 141 +++++++++---------------- src/policy_newest.cpp | 200 ++++++++++++++++++++++------------- src/policy_rand.cpp | 4 +- src/readdir.cpp | 10 +- src/readlink.cpp | 8 +- src/removexattr.cpp | 8 +- src/rename.cpp | 40 +++---- src/rmdir.cpp | 8 +- src/setxattr.cpp | 117 +++++--------------- src/statfs.cpp | 18 ++-- src/str.cpp | 12 +++ src/str.hpp | 4 + src/symlink.cpp | 10 +- src/truncate.cpp | 8 +- src/unlink.cpp | 8 +- src/utimens.cpp | 8 +- src/write.cpp | 18 +++- src/write_buf.cpp | 25 +++-- 57 files changed, 1669 insertions(+), 1293 deletions(-) create mode 100644 src/branch.cpp create mode 100644 src/branch.hpp create mode 100644 src/policy_error.hpp diff --git a/README.md b/README.md index abfb7e16..67e499a9 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ mergerfs - a featureful union filesystem # SYNOPSIS -mergerfs -o<options> <srcmounts> <mountpoint> +mergerfs -o<options> <branches> <mountpoint> # DESCRIPTION @@ -81,11 +81,13 @@ mergerfs does **not** support the copy-on-write (CoW) behavior found in **aufs** **NOTE:** Options are evaluated in the order listed so if the options are **func.rmdir=rand,category.action=ff** the **action** category setting will override the **rmdir** setting. -### srcmounts +### branches -The srcmounts (source mounts) argument is a colon (':') delimited list of paths to be included in the pool. It does not matter if the paths are on the same or different drives nor does it matter the filesystem. Used and available space will not be duplicated for paths on the same device and any features which aren't supported by the underlying filesystem (such as file attributes or extended attributes) will return the appropriate errors. +The 'branches' (formerly 'srcmounts') argument is a colon (':') delimited list of paths to be pooled together. It does not matter if the paths are on the same or different drives nor does it matter the filesystem. Used and available space will not be duplicated for paths on the same device and any features which aren't supported by the underlying filesystem (such as file attributes or extended attributes) will return the appropriate errors. -To make it easier to include multiple source mounts mergerfs supports [globbing](http://linux.die.net/man/7/glob). **The globbing tokens MUST be escaped when using via the shell else the shell itself will expand it.** +To make it easier to include multiple branches mergerfs supports [globbing](http://linux.die.net/man/7/glob). **The globbing tokens MUST be escaped when using via the shell else the shell itself will apply the glob itself.** + +Each branch can have a suffix of `=RW` (read / write), `=RO` (read only), or `=NW` (no writes). These suffixes work with globs as well and will apply to each path found. `RW` is the default behavior and those paths will be eligible for all policy categories. `RO` will exclude those paths from `create` and `action` policies (just as a filesystem being mounted `ro` would). `NW` will exclude those paths from `create` policies (you can't create but you can change / delete). ``` $ mergerfs -o defaults,allow_other,use_ino /mnt/disk\*:/mnt/cdrom /media/drives @@ -176,34 +178,38 @@ Policies, as described below, are of two core types. `path preserving` and `non- All policies which start with `ep` (**epff**, **eplfs**, **eplus**, **epmfs**, **eprand**) are `path preserving`. `ep` stands for `existing path`. -As the descriptions explain a path preserving policy will only consider drives where the relative path being accessed already exists. +A path preserving policy will only consider drives where the relative path being accessed already exists. When using non-path preserving policies paths will be cloned to target drives as necessary. #### Policy descriptions +All **create** policies will filter out branches which are mounted **read only** or tagged as **read only** or **no write**. All **action** policies will filter out branches which are mounted or tagged as **read only**. + +If all branches are filtered an error will be returned. Typically EROFS or ENOSPC. + | Policy | Description | |------------------|------------------------------------------------------------| -| all | Search category: acts like **ff**. Action category: apply to all found. Create category: for **mkdir**, **mknod**, and **symlink** it will apply to all found. **create** works like **ff**. It will exclude readonly drives and those with free space less than **minfreespace**. | -| epall (existing path, all) | Search category: acts like **epff**. Action category: apply to all found. Create category: for **mkdir**, **mknod**, and **symlink** it will apply to all existing paths found. **create** works like **epff**. Excludes readonly drives and those with free space less than **minfreespace**. | -| epff (existing path, first found) | Given the order of the drives, as defined at mount time or configured at runtime, act on the first one found where the relative path already exists. For **create** category functions it will exclude readonly drives and those with free space less than **minfreespace** (unless there is no other option). Falls back to **ff**. | -| eplfs (existing path, least free space) | Of all the drives on which the relative path exists choose the drive with the least free space. For **create** category functions it will exclude readonly drives and those with free space less than **minfreespace**. Falls back to **lfs**. | -| eplus (existing path, least used space) | Of all the drives on which the relative path exists choose the drive with the least used space. For **create** category functions it will exclude readonly drives and those with free space less than **minfreespace**. Falls back to **lus**. | -| epmfs (existing path, most free space) | Of all the drives on which the relative path exists choose the drive with the most free space. For **create** category functions it will exclude readonly drives and those with free space less than **minfreespace**. Falls back to **mfs**. | +| all | Search category: acts like **ff**. Action category: apply to all found. Create category: for **mkdir**, **mknod**, and **symlink** it will apply to all branches. **create** works like **ff**. It will exclude branches with free space less than **minfreespace**. | +| epall (existing path, all) | Search category: acts like **epff**. Action category: apply to all found. Create category: for **mkdir**, **mknod**, and **symlink** it will apply to all existing paths found. **create** works like **epff**. Excludes branches with free space less than **minfreespace**. | +| epff (existing path, first found) | Given the order of the drives, as defined at mount time or configured at runtime, act on the first one found where the relative path already exists. For **create** category functions it will exclude branches with free space less than **minfreespace**. | +| eplfs (existing path, least free space) | Of all the drives on which the relative path exists choose the drive with the least free space. For **create** category functions it will exclude those with free space less than **minfreespace**. | +| eplus (existing path, least used space) | Of all the drives on which the relative path exists choose the drive with the least used space. For **create** category functions it will exclude those with free space less than **minfreespace**. | +| epmfs (existing path, most free space) | Of all the drives on which the relative path exists choose the drive with the most free space. For **create** category functions it will exclude those with free space less than **minfreespace**. | | eprand (existing path, random) | Calls **epall** and then randomizes. Otherwise behaves the same as **epall**. | -| erofs | Exclusively return **-1** with **errno** set to **EROFS** (Read-only filesystem). By setting **create** functions to this you can in effect turn the filesystem mostly readonly. | -| ff (first found) | Given the order of the drives, as defined at mount time or configured at runtime, act on the first one found. For **create** category functions it will exclude readonly drives and those with free space less than **minfreespace** (unless there is no other option). | -| lfs (least free space) | Pick the drive with the least available free space. For **create** category functions it will exclude readonly drives and those with free space less than **minfreespace**. Falls back to **mfs**. | -| lus (least used space) | Pick the drive with the least used space. For **create** category functions it will exclude readonly drives and those with free space less than **minfreespace**. Falls back to **mfs**. | -| mfs (most free space) | Pick the drive with the most available free space. For **create** category functions it will exclude readonly drives. Falls back to **ff**. | -| newest | Pick the file / directory with the largest mtime. For **create** category functions it will exclude readonly drives and those with free space less than **minfreespace** (unless there is no other option). | +| erofs | Exclusively return **-1** with **errno** set to **EROFS** (Read-only filesystem). | +| ff (first found) | Given the order of the drives, as defined at mount time or configured at runtime, act on the first one found. For **create** category functions it will exclude those with free space less than **minfreespace**. | +| lfs (least free space) | Pick the drive with the least available free space. For **create** category functions it will exclude those with free space less than **minfreespace**. | +| lus (least used space) | Pick the drive with the least used space. For **create** category functions it will exclude those with free space less than **minfreespace**. | +| mfs (most free space) | Pick the drive with the most available free space. | +| newest | Pick the file / directory with the largest mtime. For **create** category functions it will exclude those with free space less than **minfreespace**. | | rand (random) | Calls **all** and then randomizes. | #### Defaults #### | Category | Policy | |----------|--------| -| action | all | +| action | epall | | create | epmfs | | search | ff | @@ -253,7 +259,7 @@ The above behavior will help minimize the likelihood of EXDEV being returned but #### statvfs #### -[statvfs](http://linux.die.net/man/2/statvfs) normalizes the source drives based on the fragment size and sums the number of adjusted blocks and inodes. This means you will see the combined space of all sources. Total, used, and free. The sources however are dedupped based on the drive so multiple sources on the same drive will not result in double counting it's space. Filesystems mounted further down the tree of the src mounts will not be included. +[statvfs](http://linux.die.net/man/2/statvfs) normalizes the source drives based on the fragment size and sums the number of adjusted blocks and inodes. This means you will see the combined space of all sources. Total, used, and free. The sources however are dedupped based on the drive so multiple sources on the same drive will not result in double counting it's space. Filesystems mounted further down the tree of the branch will not be included. # BUILDING @@ -328,7 +334,9 @@ Any changes made at runtime are **not** persisted. If you wish for values to per Use `xattr -l /mount/point/.mergerfs` to see all supported keys. Some are informational and therefore readonly. -###### user.mergerfs.srcmounts ###### +###### user.mergerfs.branches ###### + +**NOTE:** formerly `user.mergerfs.srcmounts` but said key is still supported. Used to query or modify the list of source mounts. When modifying there are several shortcuts to easy manipulation of the list. @@ -341,7 +349,7 @@ Used to query or modify the list of source mounts. When modifying there are seve | -< | remove first in list | | -> | remove last in list | -`xattr -w user.mergerfs.srcmounts + +mergerfs \-o .SH DESCRIPTION .PP \f[B]mergerfs\f[] is a union filesystem geared towards simplifying @@ -202,10 +202,10 @@ Example: \f[B]category.create=mfs\f[] options are \f[B]func.rmdir=rand,category.action=ff\f[] the \f[B]action\f[] category setting will override the \f[B]rmdir\f[] setting. -.SS srcmounts +.SS branches .PP -The srcmounts (source mounts) argument is a colon (\[aq]:\[aq]) -delimited list of paths to be included in the pool. +The \[aq]branches\[aq] (formerly \[aq]srcmounts\[aq]) argument is a +colon (\[aq]:\[aq]) delimited list of paths to be pooled together. It does not matter if the paths are on the same or different drives nor does it matter the filesystem. Used and available space will not be duplicated for paths on the same @@ -213,10 +213,22 @@ device and any features which aren\[aq]t supported by the underlying filesystem (such as file attributes or extended attributes) will return the appropriate errors. .PP -To make it easier to include multiple source mounts mergerfs supports +To make it easier to include multiple branches mergerfs supports globbing (http://linux.die.net/man/7/glob). \f[B]The globbing tokens MUST be escaped when using via the shell else -the shell itself will expand it.\f[] +the shell itself will apply the glob itself.\f[] +.PP +Each branch can have a suffix of \f[C]=RW\f[] (read / write), +\f[C]=RO\f[] (read only), or \f[C]=NW\f[] (no writes). +These suffixes work with globs as well and will apply to each path +found. +\f[C]RW\f[] is the default behavior and those paths will be eligible for +all policy categories. +\f[C]RO\f[] will exclude those paths from \f[C]create\f[] and +\f[C]action\f[] policies (just as a filesystem being mounted \f[C]ro\f[] +would). +\f[C]NW\f[] will exclude those paths from \f[C]create\f[] policies (you +can\[aq]t create but you can change / delete). .IP .nf \f[C] @@ -413,13 +425,21 @@ All policies which start with \f[C]ep\f[] (\f[B]epff\f[], \f[C]path\ preserving\f[]. \f[C]ep\f[] stands for \f[C]existing\ path\f[]. .PP -As the descriptions explain a path preserving policy will only consider -drives where the relative path being accessed already exists. +A path preserving policy will only consider drives where the relative +path being accessed already exists. .PP When using non\-path preserving policies paths will be cloned to target drives as necessary. .SS Policy descriptions .PP +All \f[B]create\f[] policies will filter out branches which are mounted +\f[B]read only\f[] or tagged as \f[B]read only\f[] or \f[B]no write\f[]. +All \f[B]action\f[] policies will filter out branches which are mounted +or tagged as \f[B]read only\f[]. +.PP +If all branches are filtered an error will be returned. +Typically EROFS or ENOSPC. +.PP .TS tab(@); lw(16.6n) lw(53.4n). @@ -435,9 +455,9 @@ T}@T{ Search category: acts like \f[B]ff\f[]. Action category: apply to all found. Create category: for \f[B]mkdir\f[], \f[B]mknod\f[], and -\f[B]symlink\f[] it will apply to all found. +\f[B]symlink\f[] it will apply to all branches. \f[B]create\f[] works like \f[B]ff\f[]. -It will exclude readonly drives and those with free space less than +It will exclude branches with free space less than \f[B]minfreespace\f[]. T} T{ @@ -448,8 +468,7 @@ Action category: apply to all found. Create category: for \f[B]mkdir\f[], \f[B]mknod\f[], and \f[B]symlink\f[] it will apply to all existing paths found. \f[B]create\f[] works like \f[B]epff\f[]. -Excludes readonly drives and those with free space less than -\f[B]minfreespace\f[]. +Excludes branches with free space less than \f[B]minfreespace\f[]. T} T{ epff (existing path, first found) @@ -457,37 +476,32 @@ T}@T{ Given the order of the drives, as defined at mount time or configured at runtime, act on the first one found where the relative path already exists. -For \f[B]create\f[] category functions it will exclude readonly drives -and those with free space less than \f[B]minfreespace\f[] (unless there -is no other option). -Falls back to \f[B]ff\f[]. +For \f[B]create\f[] category functions it will exclude branches with +free space less than \f[B]minfreespace\f[]. T} T{ eplfs (existing path, least free space) T}@T{ Of all the drives on which the relative path exists choose the drive with the least free space. -For \f[B]create\f[] category functions it will exclude readonly drives -and those with free space less than \f[B]minfreespace\f[]. -Falls back to \f[B]lfs\f[]. +For \f[B]create\f[] category functions it will exclude those with free +space less than \f[B]minfreespace\f[]. T} T{ eplus (existing path, least used space) T}@T{ Of all the drives on which the relative path exists choose the drive with the least used space. -For \f[B]create\f[] category functions it will exclude readonly drives -and those with free space less than \f[B]minfreespace\f[]. -Falls back to \f[B]lus\f[]. +For \f[B]create\f[] category functions it will exclude those with free +space less than \f[B]minfreespace\f[]. T} T{ epmfs (existing path, most free space) T}@T{ Of all the drives on which the relative path exists choose the drive with the most free space. -For \f[B]create\f[] category functions it will exclude readonly drives -and those with free space less than \f[B]minfreespace\f[]. -Falls back to \f[B]mfs\f[]. +For \f[B]create\f[] category functions it will exclude those with free +space less than \f[B]minfreespace\f[]. T} T{ eprand (existing path, random) @@ -500,48 +514,40 @@ erofs T}@T{ Exclusively return \f[B]\-1\f[] with \f[B]errno\f[] set to \f[B]EROFS\f[] (Read\-only filesystem). -By setting \f[B]create\f[] functions to this you can in effect turn the -filesystem mostly readonly. T} T{ ff (first found) T}@T{ Given the order of the drives, as defined at mount time or configured at runtime, act on the first one found. -For \f[B]create\f[] category functions it will exclude readonly drives -and those with free space less than \f[B]minfreespace\f[] (unless there -is no other option). +For \f[B]create\f[] category functions it will exclude those with free +space less than \f[B]minfreespace\f[]. T} T{ lfs (least free space) T}@T{ Pick the drive with the least available free space. -For \f[B]create\f[] category functions it will exclude readonly drives -and those with free space less than \f[B]minfreespace\f[]. -Falls back to \f[B]mfs\f[]. +For \f[B]create\f[] category functions it will exclude those with free +space less than \f[B]minfreespace\f[]. T} T{ lus (least used space) T}@T{ Pick the drive with the least used space. -For \f[B]create\f[] category functions it will exclude readonly drives -and those with free space less than \f[B]minfreespace\f[]. -Falls back to \f[B]mfs\f[]. +For \f[B]create\f[] category functions it will exclude those with free +space less than \f[B]minfreespace\f[]. T} T{ mfs (most free space) T}@T{ Pick the drive with the most available free space. -For \f[B]create\f[] category functions it will exclude readonly drives. -Falls back to \f[B]ff\f[]. T} T{ newest T}@T{ Pick the file / directory with the largest mtime. -For \f[B]create\f[] category functions it will exclude readonly drives -and those with free space less than \f[B]minfreespace\f[] (unless there -is no other option). +For \f[B]create\f[] category functions it will exclude those with free +space less than \f[B]minfreespace\f[]. T} T{ rand (random) @@ -563,7 +569,7 @@ _ T{ action T}@T{ -all +epall T} T{ create @@ -694,7 +700,7 @@ This means you will see the combined space of all sources. Total, used, and free. The sources however are dedupped based on the drive so multiple sources on the same drive will not result in double counting it\[aq]s space. -Filesystems mounted further down the tree of the src mounts will not be +Filesystems mounted further down the tree of the branch will not be included. .SH BUILDING .PP @@ -787,7 +793,10 @@ wherever you configure the mounting of mergerfs (/etc/fstab). Use \f[C]xattr\ \-l\ /mount/point/.mergerfs\f[] to see all supported keys. Some are informational and therefore readonly. -.SS user.mergerfs.srcmounts +.SS user.mergerfs.branches +.PP +\f[B]NOTE:\f[] formerly \f[C]user.mergerfs.srcmounts\f[] but said key is +still supported. .PP Used to query or modify the list of source mounts. When modifying there are several shortcuts to easy manipulation of the @@ -834,7 +843,7 @@ remove last in list T} .TE .PP -\f[C]xattr\ \-w\ user.mergerfs.srcmounts\ + &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *fusepath, const int mask) @@ -41,7 +41,7 @@ _access(Policy::Func::Search searchFunc, string fullpath; vector basepaths; - rv = searchFunc(srcmounts,fusepath,minfreespace,basepaths); + rv = searchFunc(branches_,fusepath,minfreespace,basepaths); if(rv == -1) return -errno; @@ -63,10 +63,10 @@ namespace mergerfs const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); return _access(config.access, - config.srcmounts, + config.branches, config.minfreespace, fusepath, mask); diff --git a/src/branch.cpp b/src/branch.cpp new file mode 100644 index 00000000..2dca7081 --- /dev/null +++ b/src/branch.cpp @@ -0,0 +1,216 @@ +/* + ISC License + + Copyright (c) 2018, 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 "branch.hpp" +#include "fs.hpp" +#include "fs_glob.hpp" +#include "str.hpp" + +#include + +#include + +using std::string; +using std::vector; + +bool +Branch::ro(void) const +{ + return (mode == Branch::RO); +} + +bool +Branch::ro_or_nw(void) const +{ + return ((mode == Branch::RO) || + (mode == Branch::NW)); +} + +string +Branches::to_string(const bool mode_) const +{ + string tmp; + + for(size_t i = 0; i < size(); i++) + { + const Branch &branch = (*this)[i]; + + tmp += branch.path; + + if(mode_) + { + tmp += '='; + switch(branch.mode) + { + default: + case Branch::RW: + tmp += "RW"; + break; + case Branch::RO: + tmp += "RO"; + break; + case Branch::NW: + tmp += "NW"; + break; + } + } + + tmp += ':'; + } + + if(*tmp.rbegin() == ':') + tmp.erase(tmp.size() - 1); + + return tmp; +} + +void +Branches::to_paths(vector &vec_) const +{ + for(size_t i = 0; i < size(); i++) + { + const Branch &branch = (*this)[i]; + + vec_.push_back(branch.path); + } +} + +static +void +parse(const string &str_, + Branches &branches_) +{ + string str; + Branch branch; + vector globbed; + + str = str_; + branch.mode = Branch::INVALID; + if(str::ends_with(str,"=RO")) + branch.mode = Branch::RO; + else if(str::ends_with(str,"=RW")) + branch.mode = Branch::RW; + else if(str::ends_with(str,"=NW")) + branch.mode = Branch::NW; + + if(branch.mode != Branch::INVALID) + str.resize(str.size() - 3); + else + branch.mode = Branch::RW; + + fs::glob(str,globbed); + fs::realpathize(globbed); + for(size_t i = 0; i < globbed.size(); i++) + { + branch.path = globbed[i]; + branches_.push_back(branch); + } +} + +void +Branches::set(const std::string &str_) +{ + vector paths; + + clear(); + + str::split(paths,str_,':'); + + for(size_t i = 0; i < paths.size(); i++) + { + Branches branches; + + parse(paths[i],branches); + + insert(end(), + branches.begin(), + branches.end()); + } +} + +void +Branches::add_begin(const std::string &str_) +{ + vector paths; + + str::split(paths,str_,':'); + + for(size_t i = 0; i < paths.size(); i++) + { + Branches branches; + + parse(paths[i],branches); + + insert(begin(), + branches.begin(), + branches.end()); + } +} + +void +Branches::add_end(const std::string &str_) +{ + vector paths; + + str::split(paths,str_,':'); + + for(size_t i = 0; i < paths.size(); i++) + { + Branches branches; + + parse(paths[i],branches); + + insert(end(), + branches.begin(), + branches.end()); + } +} + +void +Branches::erase_begin(void) +{ + erase(begin()); +} + +void +Branches::erase_end(void) +{ + pop_back(); +} + +void +Branches::erase_fnmatch(const std::string &str_) +{ + vector patterns; + + str::split(patterns,str_,':'); + + for(iterator i = begin(); i != end();) + { + int match = FNM_NOMATCH; + + for(vector::const_iterator pi = patterns.begin(); + pi != patterns.end() && match != 0; + ++pi) + { + match = ::fnmatch(pi->c_str(),i->path.c_str(),0); + } + + i = ((match == 0) ? erase(i) : (i+1)); + } +} diff --git a/src/branch.hpp b/src/branch.hpp new file mode 100644 index 00000000..f7cf3c62 --- /dev/null +++ b/src/branch.hpp @@ -0,0 +1,55 @@ +/* + ISC License + + Copyright (c) 2018, 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. +*/ + +#pragma once + +#include +#include + +struct Branch +{ + enum Mode + { + INVALID, + RO, + RW, + NW + }; + + Mode mode; + std::string path; + + bool ro(void) const; + bool ro_or_nw(void) const; +}; + +class Branches : public std::vector +{ +public: + std::string to_string(const bool mode_ = false) const; + + void to_paths(std::vector &vec_) const; + +public: + void set(const std::string &str_); + void add_begin(const std::string &str_); + void add_end(const std::string &str_); + void erase_begin(void); + void erase_end(void); + void erase_fnmatch(const std::string &str_); +}; diff --git a/src/chmod.cpp b/src/chmod.cpp index 13280a36..925a8bf5 100644 --- a/src/chmod.cpp +++ b/src/chmod.cpp @@ -68,7 +68,7 @@ _chmod_loop(const vector &basepaths, static int _chmod(Policy::Func::Action actionFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *fusepath, const mode_t mode) @@ -76,7 +76,7 @@ _chmod(Policy::Func::Action actionFunc, int rv; vector basepaths; - rv = actionFunc(srcmounts,fusepath,minfreespace,basepaths); + rv = actionFunc(branches_,fusepath,minfreespace,basepaths); if(rv == -1) return -errno; @@ -94,10 +94,10 @@ namespace mergerfs const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); return _chmod(config.chmod, - config.srcmounts, + config.branches, config.minfreespace, fusepath, mode); diff --git a/src/chown.cpp b/src/chown.cpp index 2c15ffc1..9784cb59 100644 --- a/src/chown.cpp +++ b/src/chown.cpp @@ -71,7 +71,7 @@ _chown_loop(const vector &basepaths, static int _chown(Policy::Func::Action actionFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *fusepath, const uid_t uid, @@ -80,7 +80,7 @@ _chown(Policy::Func::Action actionFunc, int rv; vector basepaths; - rv = actionFunc(srcmounts,fusepath,minfreespace,basepaths); + rv = actionFunc(branches_,fusepath,minfreespace,basepaths); if(rv == -1) return -errno; @@ -99,10 +99,10 @@ namespace mergerfs const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); return _chown(config.chown, - config.srcmounts, + config.branches, config.minfreespace, fusepath, uid, diff --git a/src/config.cpp b/src/config.cpp index bf7ba0e1..442837f2 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -35,8 +35,8 @@ namespace mergerfs { Config::Config() : destmount(), - srcmounts(), - srcmountslock(), + branches(), + branches_lock(), minfreespace(MINFREESPACE_DEFAULT), moveonenospc(false), direct_io(false), @@ -70,9 +70,9 @@ namespace mergerfs POLICYINIT(utimens), controlfile("/.mergerfs") { - pthread_rwlock_init(&srcmountslock,NULL); + pthread_rwlock_init(&branches_lock,NULL); - set_category_policy("action","all"); + set_category_policy("action","epall"); set_category_policy("create","epmfs"); set_category_policy("search","ff"); } diff --git a/src/config.hpp b/src/config.hpp index 03b12d5d..673e512c 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -16,6 +16,7 @@ #pragma once +#include "branch.hpp" #include "fusefunc.hpp" #include "policy.hpp" @@ -42,8 +43,8 @@ namespace mergerfs public: std::string destmount; - std::vector srcmounts; - mutable pthread_rwlock_t srcmountslock; + Branches branches; + mutable pthread_rwlock_t branches_lock; uint64_t minfreespace; bool moveonenospc; bool direct_io; diff --git a/src/create.cpp b/src/create.cpp index 755fb548..6edbbc0b 100644 --- a/src/create.cpp +++ b/src/create.cpp @@ -73,7 +73,7 @@ static int _create(Policy::Func::Search searchFunc, Policy::Func::Create createFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *fusepath, const mode_t mode, @@ -89,11 +89,11 @@ _create(Policy::Func::Search searchFunc, fusedirpath = fs::path::dirname(fusepath); - rv = searchFunc(srcmounts,fusedirpath,minfreespace,existingpaths); + rv = searchFunc(branches_,fusedirpath,minfreespace,existingpaths); if(rv == -1) return -errno; - rv = createFunc(srcmounts,fusedirpath,minfreespace,createpaths); + rv = createFunc(branches_,fusedirpath,minfreespace,createpaths); if(rv == -1) return -errno; @@ -118,11 +118,11 @@ namespace mergerfs const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); return _create(config.getattr, config.create, - config.srcmounts, + config.branches, config.minfreespace, fusepath, mode, diff --git a/src/fs.cpp b/src/fs.cpp index 8f4935ce..ae323cd3 100644 --- a/src/fs.cpp +++ b/src/fs.cpp @@ -81,15 +81,15 @@ namespace fs } void - findallfiles(const vector &srcmounts, + findallfiles(const vector &basepaths, const char *fusepath, vector &paths) { string fullpath; - for(size_t i = 0, ei = srcmounts.size(); i != ei; i++) + for(size_t i = 0, ei = basepaths.size(); i != ei; i++) { - fs::path::make(&srcmounts[i],fusepath,fullpath); + fs::path::make(&basepaths[i],fusepath,fullpath); if(!fs::exists(fullpath)) continue; @@ -99,7 +99,7 @@ namespace fs } int - findonfs(const vector &srcmounts, + findonfs(const vector &basepaths, const string &fusepath, const int fd, string &basepath) @@ -114,9 +114,9 @@ namespace fs return -1; dev = st.st_dev; - for(size_t i = 0, ei = srcmounts.size(); i != ei; i++) + for(size_t i = 0, ei = basepaths.size(); i != ei; i++) { - fs::path::make(&srcmounts[i],fusepath,fullpath); + fs::path::make(&basepaths[i],fusepath,fullpath); rv = fs::lstat(fullpath,st); if(rv == -1) @@ -125,7 +125,7 @@ namespace fs if(st.st_dev != dev) continue; - basepath = srcmounts[i]; + basepath = basepaths[i]; return 0; } diff --git a/src/fs.hpp b/src/fs.hpp index 9f785edd..7f3dc2ab 100644 --- a/src/fs.hpp +++ b/src/fs.hpp @@ -36,11 +36,11 @@ namespace fs int spaceused(const string *path_, uint64_t *spaceavail_); - void findallfiles(const vector &srcmounts, + void findallfiles(const vector &basepaths, const char *fusepath, vector &paths); - int findonfs(const vector &srcmounts, + int findonfs(const vector &basepaths, const string &fusepath, const int fd, string &basepath); diff --git a/src/fs_glob.cpp b/src/fs_glob.cpp index 421762bf..4cf08a66 100644 --- a/src/fs_glob.cpp +++ b/src/fs_glob.cpp @@ -27,25 +27,16 @@ using std::vector; namespace fs { void - glob(const vector &patterns_, - vector &strs_) + glob(const string &pattern_, + vector &strs_) { int flags; - size_t veclen; glob_t gbuf = {0}; - veclen = patterns_.size(); - if(veclen == 0) - return; - flags = GLOB_NOCHECK; - ::glob(patterns_[0].c_str(),flags,NULL,&gbuf); - - flags = GLOB_APPEND|GLOB_NOCHECK; - for(size_t i = 1; i < veclen; i++) - ::glob(patterns_[i].c_str(),flags,NULL,&gbuf); + ::glob(pattern_.c_str(),flags,NULL,&gbuf); - for(size_t i = 0; i < gbuf.gl_pathc; ++i) + for(size_t i = 0; i < gbuf.gl_pathc; i++) strs_.push_back(gbuf.gl_pathv[i]); ::globfree(&gbuf); diff --git a/src/fs_glob.hpp b/src/fs_glob.hpp index 6858c291..28c49dc0 100644 --- a/src/fs_glob.hpp +++ b/src/fs_glob.hpp @@ -23,6 +23,6 @@ namespace fs using std::vector; void - glob(const vector &patterns_, - vector &strs_); + glob(const string &pattern_, + vector &strs_); } diff --git a/src/fs_info.cpp b/src/fs_info.cpp index fc04a7be..4850e45e 100644 --- a/src/fs_info.cpp +++ b/src/fs_info.cpp @@ -47,22 +47,4 @@ namespace fs return rv; } - - int - info(const string *basepath_, - const char *relpath_, - fs::info_t *info_) - { - int rv; - string fullpath; - struct stat st; - - fullpath = fs::path::make(basepath_,relpath_); - - rv = fs::lstat(fullpath,st); - if(rv == -1) - return -1; - - return fs::info(basepath_,info_); - } } diff --git a/src/fs_info.hpp b/src/fs_info.hpp index a6d63254..0dd8ed2e 100644 --- a/src/fs_info.hpp +++ b/src/fs_info.hpp @@ -24,11 +24,6 @@ namespace fs { - int - info(const std::string *basepath_, - const char *relpath_, - fs::info_t *info_); - int info(const std::string *path_, fs::info_t *info_); diff --git a/src/getattr.cpp b/src/getattr.cpp index 66fb0a8a..ba587aec 100644 --- a/src/getattr.cpp +++ b/src/getattr.cpp @@ -60,7 +60,7 @@ _getattr_controlfile(struct stat &st) static int _getattr(Policy::Func::Search searchFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *fusepath, struct stat &st, @@ -71,7 +71,7 @@ _getattr(Policy::Func::Search searchFunc, string fullpath; vector basepaths; - rv = searchFunc(srcmounts,fusepath,minfreespace,basepaths); + rv = searchFunc(branches_,fusepath,minfreespace,basepaths); if(rv == -1) return -errno; @@ -104,10 +104,10 @@ namespace mergerfs return _getattr_controlfile(*st); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); return _getattr(config.getattr, - config.srcmounts, + config.branches, config.minfreespace, fusepath, *st, diff --git a/src/getxattr.cpp b/src/getxattr.cpp index 18f7780c..9da0a800 100644 --- a/src/getxattr.cpp +++ b/src/getxattr.cpp @@ -105,7 +105,15 @@ void _getxattr_controlfile_srcmounts(const Config &config, string &attrvalue) { - attrvalue = str::join(config.srcmounts,':'); + attrvalue = config.branches.to_string(); +} + +static +void +_getxattr_controlfile_branches(const Config &config, + string &attrvalue) +{ + attrvalue = config.branches.to_string(true); } static @@ -216,6 +224,8 @@ _getxattr_controlfile(const Config &config, case 3: if(attr[2] == "srcmounts") _getxattr_controlfile_srcmounts(config,attrvalue); + else if(attr[2] == "branches") + _getxattr_controlfile_branches(config,attrvalue); else if(attr[2] == "minfreespace") _getxattr_controlfile_uint64_t(config.minfreespace,attrvalue); else if(attr[2] == "moveonenospc") @@ -289,15 +299,18 @@ _getxattr_from_string(char *destbuf, static int -_getxattr_user_mergerfs_allpaths(const vector &srcmounts, - const char *fusepath, - char *buf, - const size_t count) +_getxattr_user_mergerfs_allpaths(const Branches &branches_, + const char *fusepath, + char *buf, + const size_t count) { string concated; vector paths; + vector branches; + + branches_.to_paths(branches); - fs::findallfiles(srcmounts,fusepath,paths); + fs::findallfiles(branches,fusepath,paths); concated = str::join(paths,'\0'); @@ -309,7 +322,7 @@ int _getxattr_user_mergerfs(const string &basepath, const char *fusepath, const string &fullpath, - const vector &srcmounts, + const Branches &branches_, const char *attrname, char *buf, const size_t count) @@ -325,7 +338,7 @@ _getxattr_user_mergerfs(const string &basepath, else if(attr[2] == "fullpath") return _getxattr_from_string(buf,count,fullpath); else if(attr[2] == "allpaths") - return _getxattr_user_mergerfs_allpaths(srcmounts,fusepath,buf,count); + return _getxattr_user_mergerfs_allpaths(branches_,fusepath,buf,count); return -ENOATTR; } @@ -333,7 +346,7 @@ _getxattr_user_mergerfs(const string &basepath, static int _getxattr(Policy::Func::Search searchFunc, - const vector &srcmounts, + const Branches &branches_, const size_t minfreespace, const char *fusepath, const char *attrname, @@ -344,14 +357,14 @@ _getxattr(Policy::Func::Search searchFunc, string fullpath; vector basepaths; - rv = searchFunc(srcmounts,fusepath,minfreespace,basepaths); + rv = searchFunc(branches_,fusepath,minfreespace,basepaths); if(rv == -1) return -errno; fs::path::make(basepaths[0],fusepath,fullpath); if(str::isprefix(attrname,"user.mergerfs.")) - rv = _getxattr_user_mergerfs(*basepaths[0],fusepath,fullpath,srcmounts,attrname,buf,count); + rv = _getxattr_user_mergerfs(*basepaths[0],fusepath,fullpath,branches_,attrname,buf,count); else rv = _lgetxattr(fullpath,attrname,buf,count); @@ -385,10 +398,10 @@ namespace mergerfs return -config.xattr; const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); return _getxattr(config.getxattr, - config.srcmounts, + config.branches, config.minfreespace, fusepath, attrname, diff --git a/src/ioctl.cpp b/src/ioctl.cpp index 46a1fd80..0166029b 100644 --- a/src/ioctl.cpp +++ b/src/ioctl.cpp @@ -69,7 +69,7 @@ _ioctl_file(fuse_file_info *ffi, static int _ioctl_dir_base(Policy::Func::Search searchFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *fusepath, const unsigned long cmd, @@ -80,7 +80,7 @@ _ioctl_dir_base(Policy::Func::Search searchFunc, string fullpath; vector basepaths; - rv = searchFunc(srcmounts,fusepath,minfreespace,basepaths); + rv = searchFunc(branches_,fusepath,minfreespace,basepaths); if(rv == -1) return -errno; @@ -108,10 +108,10 @@ _ioctl_dir(fuse_file_info *ffi, const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); return _ioctl_dir_base(config.getattr, - config.srcmounts, + config.branches, config.minfreespace, di->fusepath.c_str(), cmd, diff --git a/src/link.cpp b/src/link.cpp index fb56127e..87dfc04c 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -83,7 +83,7 @@ static int _link_create_path(Policy::Func::Search searchFunc, Policy::Func::Action actionFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *oldfusepath, const char *newfusepath) @@ -93,13 +93,13 @@ _link_create_path(Policy::Func::Search searchFunc, vector oldbasepaths; vector newbasepaths; - rv = actionFunc(srcmounts,oldfusepath,minfreespace,oldbasepaths); + rv = actionFunc(branches_,oldfusepath,minfreespace,oldbasepaths); if(rv == -1) return -errno; newfusedirpath = fs::path::dirname(newfusepath); - rv = searchFunc(srcmounts,newfusedirpath,minfreespace,newbasepaths); + rv = searchFunc(branches_,newfusedirpath,minfreespace,newbasepaths); if(rv == -1) return -errno; @@ -112,7 +112,7 @@ static int _clonepath_if_would_create(Policy::Func::Search searchFunc, Policy::Func::Create createFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const string &oldbasepath, const char *oldfusepath, @@ -124,14 +124,14 @@ _clonepath_if_would_create(Policy::Func::Search searchFunc, newfusedirpath = fs::path::dirname(newfusepath); - rv = createFunc(srcmounts,newfusedirpath,minfreespace,newbasepath); + rv = createFunc(branches_,newfusedirpath,minfreespace,newbasepath); if(rv == -1) return -1; if(oldbasepath != *newbasepath[0]) return (errno=EXDEV,-1); - rv = searchFunc(srcmounts,newfusedirpath,minfreespace,newbasepath); + rv = searchFunc(branches_,newfusedirpath,minfreespace,newbasepath); if(rv == -1) return -1; @@ -142,7 +142,7 @@ static int _link_preserve_path_core(Policy::Func::Search searchFunc, Policy::Func::Create createFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const string &oldbasepath, const char *oldfusepath, @@ -160,7 +160,7 @@ _link_preserve_path_core(Policy::Func::Search searchFunc, if((rv == -1) && (errno == ENOENT)) { rv = _clonepath_if_would_create(searchFunc,createFunc, - srcmounts,minfreespace, + branches_,minfreespace, oldbasepath, oldfusepath,newfusepath); if(rv != -1) @@ -174,7 +174,7 @@ static int _link_preserve_path_loop(Policy::Func::Search searchFunc, Policy::Func::Create createFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *oldfusepath, const char *newfusepath, @@ -186,7 +186,7 @@ _link_preserve_path_loop(Policy::Func::Search searchFunc, for(size_t i = 0, ei = oldbasepaths.size(); i != ei; i++) { error = _link_preserve_path_core(searchFunc,createFunc, - srcmounts,minfreespace, + branches_,minfreespace, *oldbasepaths[i], oldfusepath,newfusepath, error); @@ -200,7 +200,7 @@ int _link_preserve_path(Policy::Func::Search searchFunc, Policy::Func::Action actionFunc, Policy::Func::Create createFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *oldfusepath, const char *newfusepath) @@ -208,12 +208,12 @@ _link_preserve_path(Policy::Func::Search searchFunc, int rv; vector oldbasepaths; - rv = actionFunc(srcmounts,oldfusepath,minfreespace,oldbasepaths); + rv = actionFunc(branches_,oldfusepath,minfreespace,oldbasepaths); if(rv == -1) return -errno; return _link_preserve_path_loop(searchFunc,createFunc, - srcmounts,minfreespace, + branches_,minfreespace, oldfusepath,newfusepath, oldbasepaths); } @@ -229,20 +229,20 @@ namespace mergerfs const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); if(config.create->path_preserving() && !config.ignorepponrename) return _link_preserve_path(config.getattr, config.link, config.create, - config.srcmounts, + config.branches, config.minfreespace, from, to); return _link_create_path(config.link, config.create, - config.srcmounts, + config.branches, config.minfreespace, from, to); diff --git a/src/listxattr.cpp b/src/listxattr.cpp index 4ec773e8..f8fec8e0 100644 --- a/src/listxattr.cpp +++ b/src/listxattr.cpp @@ -44,6 +44,7 @@ _listxattr_controlfile(char *list, const vector strs = buildvector ("user.mergerfs.srcmounts") + ("user.mergerfs.branches") ("user.mergerfs.minfreespace") ("user.mergerfs.moveonenospc") ("user.mergerfs.dropcacheonclose") @@ -80,7 +81,7 @@ _listxattr_controlfile(char *list, static int _listxattr(Policy::Func::Search searchFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *fusepath, char *list, @@ -90,7 +91,7 @@ _listxattr(Policy::Func::Search searchFunc, string fullpath; vector basepaths; - rv = searchFunc(srcmounts,fusepath,minfreespace,basepaths); + rv = searchFunc(branches_,fusepath,minfreespace,basepaths); if(rv == -1) return -errno; @@ -127,10 +128,10 @@ namespace mergerfs } const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); return _listxattr(config.listxattr, - config.srcmounts, + config.branches, config.minfreespace, fusepath, list, diff --git a/src/mkdir.cpp b/src/mkdir.cpp index 59c95998..3b2170f2 100644 --- a/src/mkdir.cpp +++ b/src/mkdir.cpp @@ -94,7 +94,7 @@ static int _mkdir(Policy::Func::Search searchFunc, Policy::Func::Create createFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *fusepath, const mode_t mode, @@ -107,11 +107,11 @@ _mkdir(Policy::Func::Search searchFunc, fusedirpath = fs::path::dirname(fusepath); - rv = searchFunc(srcmounts,fusedirpath,minfreespace,existingpaths); + rv = searchFunc(branches_,fusedirpath,minfreespace,existingpaths); if(rv == -1) return -errno; - rv = createFunc(srcmounts,fusedirpath,minfreespace,createpaths); + rv = createFunc(branches_,fusedirpath,minfreespace,createpaths); if(rv == -1) return -errno; @@ -130,11 +130,11 @@ namespace mergerfs const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); return _mkdir(config.getattr, config.mkdir, - config.srcmounts, + config.branches, config.minfreespace, fusepath, mode, diff --git a/src/mknod.cpp b/src/mknod.cpp index 60483270..829f7a0a 100644 --- a/src/mknod.cpp +++ b/src/mknod.cpp @@ -98,7 +98,7 @@ static int _mknod(Policy::Func::Search searchFunc, Policy::Func::Create createFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *fusepath, const mode_t mode, @@ -112,11 +112,11 @@ _mknod(Policy::Func::Search searchFunc, fusedirpath = fs::path::dirname(fusepath); - rv = searchFunc(srcmounts,fusedirpath,minfreespace,existingpaths); + rv = searchFunc(branches_,fusedirpath,minfreespace,existingpaths); if(rv == -1) return -errno; - rv = createFunc(srcmounts,fusedirpath,minfreespace,createpaths); + rv = createFunc(branches_,fusedirpath,minfreespace,createpaths); if(rv == -1) return -errno; @@ -137,11 +137,11 @@ namespace mergerfs const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); return _mknod(config.getattr, config.mknod, - config.srcmounts, + config.branches, config.minfreespace, fusepath, mode, diff --git a/src/open.cpp b/src/open.cpp index 43dbadd5..9f7bd4e7 100644 --- a/src/open.cpp +++ b/src/open.cpp @@ -62,7 +62,7 @@ _open_core(const string *basepath_, static int _open(Policy::Func::Search searchFunc_, - const vector &srcmounts_, + const Branches &branches_, const uint64_t minfreespace_, const char *fusepath_, const int flags_, @@ -72,7 +72,7 @@ _open(Policy::Func::Search searchFunc_, int rv; vector basepaths; - rv = searchFunc_(srcmounts_,fusepath_,minfreespace_,basepaths); + rv = searchFunc_(branches_,fusepath_,minfreespace_,basepaths); if(rv == -1) return -errno; @@ -90,10 +90,10 @@ namespace mergerfs const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); return _open(config.open, - config.srcmounts, + config.branches, config.minfreespace, fusepath_, ffi_->flags, diff --git a/src/option_parser.cpp b/src/option_parser.cpp index 4510a9ab..cfb24a26 100644 --- a/src/option_parser.cpp +++ b/src/option_parser.cpp @@ -73,14 +73,18 @@ set_kv_option(fuse_args &args, static void -set_fsname(fuse_args &args, - const vector &srcmounts) +set_fsname(fuse_args &args, + const Branches &branches_) { - if(srcmounts.size() > 0) + vector branches; + + branches_.to_paths(branches); + + if(branches.size() > 0) { std::string fsname; - fsname = str::remove_common_prefix_and_join(srcmounts,':'); + fsname = str::remove_common_prefix_and_join(branches,':'); set_kv_option(args,"fsname",fsname); } @@ -257,16 +261,10 @@ process_opt(Config &config, static int -process_srcmounts(const char *arg, - Config &config) +process_branches(const char *arg, + Config &config) { - vector paths; - - str::split(paths,arg,':'); - - fs::glob(paths,config.srcmounts); - - fs::realpathize(config.srcmounts); + config.branches.set(arg); return 0; } @@ -356,8 +354,8 @@ option_processor(void *data, break; case FUSE_OPT_KEY_NONOPT: - rv = config.srcmounts.empty() ? - process_srcmounts(arg,config) : + rv = config.branches.empty() ? + process_branches(arg,config) : process_destmounts(arg,config); break; @@ -406,7 +404,7 @@ namespace mergerfs opts, ::option_processor); - set_fsname(args,config.srcmounts); + set_fsname(args,config.branches); set_subtype(args); } } diff --git a/src/policy.hpp b/src/policy.hpp index 5b79a528..bd80747f 100644 --- a/src/policy.hpp +++ b/src/policy.hpp @@ -16,6 +16,7 @@ #pragma once +#include "branch.hpp" #include "category.hpp" #include "fs.hpp" @@ -65,7 +66,7 @@ namespace mergerfs typedef const strvec cstrvec; typedef const Category::Enum::Type CType; - typedef int (*Ptr)(CType,cstrvec &,const char *,cuint64_t,cstrptrvec &); + typedef int (*Ptr)(CType,const Branches &,const char *,cuint64_t,cstrptrvec &); template class Base @@ -76,13 +77,13 @@ namespace mergerfs {} int - operator()(cstrvec &b,const char *c,cuint64_t d,cstrptrvec &e) + operator()(const Branches &b,const char *c,cuint64_t d,cstrptrvec &e) { return func(T,b,c,d,e); } int - operator()(cstrvec &b,const string &c,cuint64_t d,cstrptrvec &e) + operator()(const Branches &b,const string &c,cuint64_t d,cstrptrvec &e) { return func(T,b,c.c_str(),d,e); } @@ -95,21 +96,21 @@ namespace mergerfs typedef Base Create; typedef Base Search; - static int invalid(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&); - static int all(CType,cstrvec&,const char*,cuint64_t,cstrptrvec&); - static int epall(CType,cstrvec&,const char*,cuint64_t,cstrptrvec&); - static int epff(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&); - static int eplfs(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&); - static int eplus(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&); - static int epmfs(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&); - static int eprand(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&); - static int erofs(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&); - static int ff(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&); - static int lfs(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&); - static int lus(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&); - static int mfs(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&); - static int newest(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&); - static int rand(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&); + static int invalid(CType,const Branches&,const char *,cuint64_t,cstrptrvec&); + static int all(CType,const Branches&,const char*,cuint64_t,cstrptrvec&); + static int epall(CType,const Branches&,const char*,cuint64_t,cstrptrvec&); + static int epff(CType,const Branches&,const char *,cuint64_t,cstrptrvec&); + static int eplfs(CType,const Branches&,const char *,cuint64_t,cstrptrvec&); + static int eplus(CType,const Branches&,const char *,cuint64_t,cstrptrvec&); + static int epmfs(CType,const Branches&,const char *,cuint64_t,cstrptrvec&); + static int eprand(CType,const Branches&,const char *,cuint64_t,cstrptrvec&); + static int erofs(CType,const Branches&,const char *,cuint64_t,cstrptrvec&); + static int ff(CType,const Branches&,const char *,cuint64_t,cstrptrvec&); + static int lfs(CType,const Branches&,const char *,cuint64_t,cstrptrvec&); + static int lus(CType,const Branches&,const char *,cuint64_t,cstrptrvec&); + static int mfs(CType,const Branches&,const char *,cuint64_t,cstrptrvec&); + static int newest(CType,const Branches&,const char *,cuint64_t,cstrptrvec&); + static int rand(CType,const Branches&,const char *,cuint64_t,cstrptrvec&); }; private: diff --git a/src/policy_all.cpp b/src/policy_all.cpp index 41ae4631..5fa720fd 100644 --- a/src/policy_all.cpp +++ b/src/policy_all.cpp @@ -19,6 +19,7 @@ #include "fs_info.hpp" #include "fs_path.hpp" #include "policy.hpp" +#include "policy_error.hpp" #include #include @@ -26,73 +27,56 @@ using std::string; using std::vector; -static -int -_all_create(const vector &basepaths, - const uint64_t minfreespace, - vector &paths) +namespace all { - int rv; - fs::info_t info; - const string *basepath; - - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - rv = fs::info(basepath,&info); - if(rv == -1) - continue; - if(info.readonly) - continue; - if(info.spaceavail < minfreespace) - continue; - - paths.push_back(basepath); - } - - if(paths.empty()) - return (errno=ENOENT,-1); - - return 0; -} - -static -int -_all_other(const vector &basepaths, - const char *fusepath, - vector &paths) -{ - const string *basepath; - - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - if(!fs::exists(*basepath,fusepath)) - continue; - - paths.push_back(basepath); - } - - if(paths.empty()) - return (errno=ENOENT,-1); - - return 0; + static + int + create(const Branches &branches_, + const uint64_t minfreespace, + vector &paths) + { + int rv; + int error; + fs::info_t info; + const Branch *branch; + + error = ENOENT; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(branch->ro_or_nw()) + error_and_continue(error,EROFS); + rv = fs::info(&branch->path,&info); + if(rv == -1) + error_and_continue(error,ENOENT); + if(info.readonly) + error_and_continue(error,EROFS); + if(info.spaceavail < minfreespace) + error_and_continue(error,ENOSPC); + + paths.push_back(&branch->path); + } + + if(paths.empty()) + return (errno=error,-1); + + return 0; + } } namespace mergerfs { int Policy::Func::all(const Category::Enum::Type type, - const vector &basepaths, + const Branches &branches_, const char *fusepath, const uint64_t minfreespace, vector &paths) { if(type == Category::Enum::create) - return _all_create(basepaths,minfreespace,paths); + return all::create(branches_,minfreespace,paths); - return _all_other(basepaths,fusepath,paths); + return Policy::Func::epall(type,branches_,fusepath,minfreespace,paths); } } diff --git a/src/policy_epall.cpp b/src/policy_epall.cpp index 96121535..cde22b0b 100644 --- a/src/policy_epall.cpp +++ b/src/policy_epall.cpp @@ -20,6 +20,7 @@ #include "fs_info.hpp" #include "fs_path.hpp" #include "policy.hpp" +#include "policy_error.hpp" #include #include @@ -27,74 +28,124 @@ using std::string; using std::vector; -static -int -_epall_create(const vector &basepaths, - const char *fusepath, - const uint64_t minfreespace, - vector &paths) +namespace epall { - int rv; - fs::info_t info; - const string *basepath; - - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - rv = fs::info(basepath,fusepath,&info); - if(rv == -1) - continue; - if(info.readonly) - continue; - if(info.spaceavail < minfreespace) - continue; - - paths.push_back(basepath); - } - - if(paths.empty()) - return (errno=ENOENT,-1); + static + int + create(const Branches &branches_, + const char *fusepath, + const uint64_t minfreespace, + vector &paths) + { + int rv; + int error; + fs::info_t info; + const Branch *branch; + + error = ENOENT; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(!fs::exists(branch->path,fusepath)) + error_and_continue(error,ENOENT); + if(branch->ro_or_nw()) + error_and_continue(error,EROFS); + rv = fs::info(&branch->path,&info); + if(rv == -1) + error_and_continue(error,ENOENT); + if(info.readonly) + error_and_continue(error,EROFS); + if(info.spaceavail < minfreespace) + error_and_continue(error,ENOSPC); + + paths.push_back(&branch->path); + } + + if(paths.empty()) + return (errno=error,-1); + + return 0; + } - return 0; -} + static + int + action(const Branches &branches_, + const char *fusepath, + vector &paths) + { + int rv; + int error; + bool readonly; + const Branch *branch; + + error = ENOENT; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(!fs::exists(branch->path,fusepath)) + error_and_continue(error,ENOENT); + if(branch->ro()) + error_and_continue(error,EROFS); + rv = fs::readonly(&branch->path,&readonly); + if(rv == -1) + error_and_continue(error,ENOENT); + if(readonly) + error_and_continue(error,EROFS); + + paths.push_back(&branch->path); + } + + if(paths.empty()) + return (errno=error,-1); + + return 0; + } -static -int -_epall_other(const vector &basepaths, - const char *fusepath, - vector &paths) -{ - const string *basepath; + static + int + search(const Branches &branches_, + const char *fusepath, + vector &paths) + { + const Branch *branch; - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; - if(!fs::exists(*basepath,fusepath)) - continue; + if(!fs::exists(branch->path,fusepath)) + continue; - paths.push_back(basepath); - } + paths.push_back(&branch->path); + } - if(paths.empty()) - return (errno=ENOENT,-1); + if(paths.empty()) + return (errno=ENOENT,-1); - return 0; + return 0; + } } namespace mergerfs { int Policy::Func::epall(const Category::Enum::Type type, - const vector &basepaths, + const Branches &branches_, const char *fusepath, const uint64_t minfreespace, vector &paths) { - if(type == Category::Enum::create) - return _epall_create(basepaths,fusepath,minfreespace,paths); - - return _epall_other(basepaths,fusepath,paths); + switch(type) + { + case Category::Enum::create: + return epall::create(branches_,fusepath,minfreespace,paths); + case Category::Enum::action: + return epall::action(branches_,fusepath,paths); + case Category::Enum::search: + default: + return epall::search(branches_,fusepath,paths); + } } } diff --git a/src/policy_epff.cpp b/src/policy_epff.cpp index a0fc3217..16bfc9b0 100644 --- a/src/policy_epff.cpp +++ b/src/policy_epff.cpp @@ -20,6 +20,7 @@ #include "fs_info.hpp" #include "fs_path.hpp" #include "policy.hpp" +#include "policy_error.hpp" #include #include @@ -28,89 +29,121 @@ using std::string; using std::vector; using mergerfs::Category; -static -int -_epff_create(const vector &basepaths, - const char *fusepath, - const uint64_t minfreespace, - vector &paths) +namespace epff { - int rv; - fs::info_t info; - const string *basepath; - - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - rv = fs::info(basepath,fusepath,&info); - if(rv == -1) - continue; - if(info.readonly) - continue; - if(info.spaceavail < minfreespace) - continue; - - paths.push_back(basepath); - - return 0; - } - - return (errno=ENOENT,-1); -} - -static -int -_epff_other(const vector &basepaths, - const char *fusepath, - vector &paths) -{ - const string *basepath; + static + int + create(const Branches &branches_, + const char *fusepath, + const uint64_t minfreespace, + vector &paths) + { + int rv; + int error; + fs::info_t info; + const Branch *branch; + + error = ENOENT; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(!fs::exists(branch->path,fusepath)) + error_and_continue(error,ENOENT); + if(branch->ro_or_nw()) + error_and_continue(error,EROFS); + rv = fs::info(&branch->path,&info); + if(rv == -1) + error_and_continue(error,ENOENT); + if(info.readonly) + error_and_continue(error,EROFS); + if(info.spaceavail < minfreespace) + error_and_continue(error,ENOSPC); + + paths.push_back(&branch->path); + + return 0; + } + + return (errno=error,-1); + } - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; + static + int + action(const Branches &branches_, + const char *fusepath, + vector &paths) + { + int rv; + int error; + bool readonly; + const Branch *branch; + + error = ENOENT; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(!fs::exists(branch->path,fusepath)) + error_and_continue(error,ENOENT); + if(branch->ro()) + error_and_continue(error,EROFS); + rv = fs::readonly(&branch->path,&readonly); + if(rv == -1) + error_and_continue(error,ENOENT); + if(readonly) + error_and_continue(error,EROFS); + + paths.push_back(&branch->path); + + return 0; + } + + return (errno=error,-1); + } - if(!fs::exists(*basepath,fusepath)) - continue; + static + int + search(const Branches &branches_, + const char *fusepath, + vector &paths) + { + const Branch *branch; - paths.push_back(basepath); + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; - return 0; - } + if(!fs::exists(branch->path,fusepath)) + continue; - return (errno=ENOENT,-1); -} + paths.push_back(&branch->path); -static -int -_epff(const Category::Enum::Type type, - const vector &basepaths, - const char *fusepath, - const uint64_t minfreespace, - vector &paths) -{ - if(type == Category::Enum::create) - return _epff_create(basepaths,fusepath,minfreespace,paths); + return 0; + } - return _epff_other(basepaths,fusepath,paths); + return (errno=ENOENT,-1); + } } namespace mergerfs { int Policy::Func::epff(const Category::Enum::Type type, - const vector &basepaths, + const Branches &branches_, const char *fusepath, const uint64_t minfreespace, vector &paths) { - int rv; - - rv = _epff(type,basepaths,fusepath,minfreespace,paths); - if(rv == -1) - rv = Policy::Func::ff(type,basepaths,fusepath,minfreespace,paths); - - return rv; + switch(type) + { + case Category::Enum::create: + return epff::create(branches_,fusepath,minfreespace,paths); + case Category::Enum::action: + return epff::action(branches_,fusepath,paths); + case Category::Enum::search: + default: + return epff::search(branches_,fusepath,paths); + } } } diff --git a/src/policy_eplfs.cpp b/src/policy_eplfs.cpp index 9f32cf89..15f1dfec 100644 --- a/src/policy_eplfs.cpp +++ b/src/policy_eplfs.cpp @@ -20,6 +20,7 @@ #include "fs_info.hpp" #include "fs_path.hpp" #include "policy.hpp" +#include "policy_error.hpp" #include #include @@ -29,114 +30,156 @@ using std::string; using std::vector; using mergerfs::Category; -static -int -_eplfs_create(const vector &basepaths, - const char *fusepath, - const uint64_t minfreespace, - vector &paths) +namespace eplfs { - int rv; - uint64_t eplfs; - fs::info_t info; - const string *basepath; - const string *eplfsbasepath; - - eplfs = std::numeric_limits::max(); - eplfsbasepath = NULL; - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - rv = fs::info(basepath,fusepath,&info); - if(rv == -1) - continue; - if(info.readonly) - continue; - if(info.spaceavail < minfreespace) - continue; - if(info.spaceavail > eplfs) - continue; - - eplfs = info.spaceavail; - eplfsbasepath = basepath; - } - - if(eplfsbasepath == NULL) - return (errno=ENOENT,-1); - - paths.push_back(eplfsbasepath); - - return 0; -} - -static -int -_eplfs_other(const vector &basepaths, - const char *fusepath, - vector &paths) -{ - int rv; - uint64_t eplfs; - uint64_t spaceavail; - const string *basepath; - const string *eplfsbasepath; - - eplfs = std::numeric_limits::max(); - eplfsbasepath = NULL; - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - if(!fs::exists(*basepath,fusepath)) - continue; - rv = fs::spaceavail(basepath,&spaceavail); - if(rv == -1) - continue; - if(spaceavail > eplfs) - continue; - - eplfs = spaceavail; - eplfsbasepath = basepath; - } - - if(eplfsbasepath == NULL) - return (errno=ENOENT,-1); - - paths.push_back(eplfsbasepath); - - return 0; -} + static + int + create(const Branches &branches_, + const char *fusepath, + const uint64_t minfreespace, + vector &paths) + { + int rv; + int error; + uint64_t eplfs; + fs::info_t info; + const Branch *branch; + const string *eplfsbasepath; + + error = ENOENT; + eplfs = std::numeric_limits::max(); + eplfsbasepath = NULL; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(!fs::exists(branch->path,fusepath)) + error_and_continue(error,ENOENT); + if(branch->ro_or_nw()) + error_and_continue(error,EROFS); + rv = fs::info(&branch->path,&info); + if(rv == -1) + error_and_continue(error,ENOENT); + if(info.readonly) + error_and_continue(error,EROFS); + if(info.spaceavail < minfreespace) + error_and_continue(error,ENOSPC); + if(info.spaceavail > eplfs) + continue; + + eplfs = info.spaceavail; + eplfsbasepath = &branch->path; + } + + if(eplfsbasepath == NULL) + return (errno=error,-1); + + paths.push_back(eplfsbasepath); + + return 0; + } -static -int -_eplfs(const Category::Enum::Type type, - const vector &basepaths, - const char *fusepath, - const uint64_t minfreespace, - vector &paths) -{ - if(type == Category::Enum::create) - return _eplfs_create(basepaths,fusepath,minfreespace,paths); + static + int + action(const Branches &branches_, + const char *fusepath, + vector &paths) + { + int rv; + int error; + uint64_t eplfs; + fs::info_t info; + const Branch *branch; + const string *eplfsbasepath; + + error = ENOENT; + eplfs = std::numeric_limits::max(); + eplfsbasepath = NULL; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(!fs::exists(branch->path,fusepath)) + error_and_continue(error,ENOENT); + if(branch->ro()) + error_and_continue(error,EROFS); + rv = fs::info(&branch->path,&info); + if(rv == -1) + error_and_continue(error,ENOENT); + if(info.readonly) + error_and_continue(error,EROFS); + if(info.spaceavail > eplfs) + continue; + + eplfs = info.spaceavail; + eplfsbasepath = &branch->path; + } + + if(eplfsbasepath == NULL) + return (errno=error,-1); + + paths.push_back(eplfsbasepath); + + return 0; + } - return _eplfs_other(basepaths,fusepath,paths); + static + int + search(const Branches &branches_, + const char *fusepath, + vector &paths) + { + int rv; + uint64_t eplfs; + uint64_t spaceavail; + const Branch *branch; + const string *eplfsbasepath; + + eplfs = std::numeric_limits::max(); + eplfsbasepath = NULL; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(!fs::exists(branch->path,fusepath)) + continue; + rv = fs::spaceavail(&branch->path,&spaceavail); + if(rv == -1) + continue; + if(spaceavail > eplfs) + continue; + + eplfs = spaceavail; + eplfsbasepath = &branch->path; + } + + if(eplfsbasepath == NULL) + return (errno=ENOENT,-1); + + paths.push_back(eplfsbasepath); + + return 0; + } } namespace mergerfs { int Policy::Func::eplfs(const Category::Enum::Type type, - const vector &basepaths, + const Branches &branches_, const char *fusepath, const uint64_t minfreespace, vector &paths) { - int rv; - - rv = _eplfs(type,basepaths,fusepath,minfreespace,paths); - if(rv == -1) - rv = Policy::Func::lfs(type,basepaths,fusepath,minfreespace,paths); - - return rv; + switch(type) + { + case Category::Enum::create: + return eplfs::create(branches_,fusepath,minfreespace,paths); + case Category::Enum::action: + return eplfs::action(branches_,fusepath,paths); + case Category::Enum::search: + default: + return eplfs::search(branches_,fusepath,paths); + } } } diff --git a/src/policy_eplus.cpp b/src/policy_eplus.cpp index d352ffcd..ecea14f9 100644 --- a/src/policy_eplus.cpp +++ b/src/policy_eplus.cpp @@ -20,6 +20,7 @@ #include "fs_info.hpp" #include "fs_path.hpp" #include "policy.hpp" +#include "policy_error.hpp" #include #include @@ -29,114 +30,156 @@ using std::string; using std::vector; using mergerfs::Category; -static -int -_eplus_create(const vector &basepaths, - const char *fusepath, - const uint64_t minfreespace, - vector &paths) +namespace eplus { - int rv; - uint64_t eplus; - fs::info_t info; - const string *basepath; - const string *eplusbasepath; - - eplus = std::numeric_limits::max(); - eplusbasepath = NULL; - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - rv = fs::info(basepath,fusepath,&info); - if(rv == -1) - continue; - if(info.readonly) - continue; - if(info.spaceavail < minfreespace) - continue; - if(info.spaceused >= eplus) - continue; - - eplus = info.spaceused; - eplusbasepath = basepath; - } - - if(eplusbasepath == NULL) - return (errno=ENOENT,-1); - - paths.push_back(eplusbasepath); - - return 0; -} - -static -int -_eplus_other(const vector &basepaths, - const char *fusepath, - vector &paths) -{ - int rv; - uint64_t eplus; - uint64_t spaceused; - const string *basepath; - const string *eplusbasepath; - - eplus = 0; - eplusbasepath = NULL; - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - if(!fs::exists(*basepath,fusepath)) - continue; - rv = fs::spaceused(basepath,&spaceused); - if(rv == -1) - continue; - if(spaceused >= eplus) - continue; - - eplus = spaceused; - eplusbasepath = basepath; - } - - if(eplusbasepath == NULL) - return (errno=ENOENT,-1); - - paths.push_back(eplusbasepath); - - return 0; -} + static + int + create(const Branches &branches_, + const char *fusepath, + const uint64_t minfreespace, + vector &paths) + { + int rv; + int error; + uint64_t eplus; + fs::info_t info; + const Branch *branch; + const string *eplusbasepath; + + error = ENOENT; + eplus = std::numeric_limits::max(); + eplusbasepath = NULL; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(!fs::exists(branch->path,fusepath)) + error_and_continue(error,ENOENT); + if(branch->ro_or_nw()) + error_and_continue(error,EROFS); + rv = fs::info(&branch->path,&info); + if(rv == -1) + error_and_continue(error,ENOENT); + if(info.readonly) + error_and_continue(error,EROFS); + if(info.spaceavail < minfreespace) + error_and_continue(error,ENOSPC); + if(info.spaceused >= eplus) + continue; + + eplus = info.spaceused; + eplusbasepath = &branch->path; + } + + if(eplusbasepath == NULL) + return (errno=error,-1); + + paths.push_back(eplusbasepath); + + return 0; + } -static -int -_eplus(const Category::Enum::Type type, - const vector &basepaths, - const char *fusepath, - const uint64_t minfreespace, - vector &paths) -{ - if(type == Category::Enum::create) - return _eplus_create(basepaths,fusepath,minfreespace,paths); + static + int + action(const Branches &branches_, + const char *fusepath, + vector &paths) + { + int rv; + int error; + uint64_t eplus; + fs::info_t info; + const Branch *branch; + const string *eplusbasepath; + + error = ENOENT; + eplus = std::numeric_limits::max(); + eplusbasepath = NULL; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(!fs::exists(branch->path,fusepath)) + error_and_continue(error,ENOENT); + if(branch->ro()) + error_and_continue(error,EROFS); + rv = fs::info(&branch->path,&info); + if(rv == -1) + error_and_continue(error,ENOENT); + if(info.readonly) + error_and_continue(error,EROFS); + if(info.spaceused >= eplus) + continue; + + eplus = info.spaceused; + eplusbasepath = &branch->path; + } + + if(eplusbasepath == NULL) + return (errno=error,-1); + + paths.push_back(eplusbasepath); + + return 0; + } - return _eplus_other(basepaths,fusepath,paths); + static + int + search(const Branches &branches_, + const char *fusepath, + vector &paths) + { + int rv; + uint64_t eplus; + uint64_t spaceused; + const Branch *branch; + const string *eplusbasepath; + + eplus = 0; + eplusbasepath = NULL; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(!fs::exists(branch->path,fusepath)) + continue; + rv = fs::spaceused(&branch->path,&spaceused); + if(rv == -1) + continue; + if(spaceused >= eplus) + continue; + + eplus = spaceused; + eplusbasepath = &branch->path; + } + + if(eplusbasepath == NULL) + return (errno=ENOENT,-1); + + paths.push_back(eplusbasepath); + + return 0; + } } namespace mergerfs { int Policy::Func::eplus(const Category::Enum::Type type, - const vector &basepaths, + const Branches &branches_, const char *fusepath, const uint64_t minfreespace, vector &paths) { - int rv; - - rv = _eplus(type,basepaths,fusepath,minfreespace,paths); - if(rv == -1) - rv = Policy::Func::lus(type,basepaths,fusepath,minfreespace,paths); - - return rv; + switch(type) + { + case Category::Enum::create: + return eplus::create(branches_,fusepath,minfreespace,paths); + case Category::Enum::action: + return eplus::action(branches_,fusepath,paths); + case Category::Enum::search: + default: + return eplus::search(branches_,fusepath,paths); + } } } diff --git a/src/policy_epmfs.cpp b/src/policy_epmfs.cpp index 2a53420b..37b332d1 100644 --- a/src/policy_epmfs.cpp +++ b/src/policy_epmfs.cpp @@ -20,6 +20,7 @@ #include "fs_info.hpp" #include "fs_path.hpp" #include "policy.hpp" +#include "policy_error.hpp" #include #include @@ -29,114 +30,156 @@ using std::string; using std::vector; using mergerfs::Category; -static -int -_epmfs_create(const vector &basepaths, - const char *fusepath, - const uint64_t minfreespace, - vector &paths) +namespace epmfs { - int rv; - uint64_t epmfs; - fs::info_t info; - const string *basepath; - const string *epmfsbasepath; - - epmfs = std::numeric_limits::min(); - epmfsbasepath = NULL; - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - rv = fs::info(basepath,fusepath,&info); - if(rv == -1) - continue; - if(info.readonly) - continue; - if(info.spaceavail < minfreespace) - continue; - if(info.spaceavail < epmfs) - continue; - - epmfs = info.spaceavail; - epmfsbasepath = basepath; - } - - if(epmfsbasepath == NULL) - return (errno=ENOENT,-1); - - paths.push_back(epmfsbasepath); - - return 0; -} - -static -int -_epmfs_other(const vector &basepaths, - const char *fusepath, - vector &paths) -{ - int rv; - uint64_t epmfs; - uint64_t spaceavail; - const string *basepath; - const string *epmfsbasepath; - - epmfs = 0; - epmfsbasepath = NULL; - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - if(!fs::exists(*basepath,fusepath)) - continue; - rv = fs::spaceavail(basepath,&spaceavail); - if(rv == -1) - continue; - if(spaceavail < epmfs) - continue; - - epmfs = spaceavail; - epmfsbasepath = basepath; - } - - if(epmfsbasepath == NULL) - return (errno=ENOENT,-1); - - paths.push_back(epmfsbasepath); - - return 0; -} + static + int + create(const Branches &branches_, + const char *fusepath, + const uint64_t minfreespace, + vector &paths) + { + int rv; + int error; + uint64_t epmfs; + fs::info_t info; + const Branch *branch; + const string *epmfsbasepath; + + error = ENOENT; + epmfs = std::numeric_limits::min(); + epmfsbasepath = NULL; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(!fs::exists(branch->path,fusepath)) + error_and_continue(error,ENOENT); + if(branch->ro_or_nw()) + error_and_continue(error,EROFS); + rv = fs::info(&branch->path,&info); + if(rv == -1) + error_and_continue(error,ENOENT); + if(info.readonly) + error_and_continue(error,EROFS); + if(info.spaceavail < minfreespace) + error_and_continue(error,ENOSPC); + if(info.spaceavail < epmfs) + continue; + + epmfs = info.spaceavail; + epmfsbasepath = &branch->path; + } + + if(epmfsbasepath == NULL) + return (errno=error,-1); + + paths.push_back(epmfsbasepath); + + return 0; + } -static -int -_epmfs(const Category::Enum::Type type, - const vector &basepaths, - const char *fusepath, - const uint64_t minfreespace, - vector &paths) -{ - if(type == Category::Enum::create) - return _epmfs_create(basepaths,fusepath,minfreespace,paths); + static + int + action(const Branches &branches_, + const char *fusepath, + vector &paths) + { + int rv; + int error; + uint64_t epmfs; + fs::info_t info; + const Branch *branch; + const string *epmfsbasepath; + + error = ENOENT; + epmfs = std::numeric_limits::min(); + epmfsbasepath = NULL; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(!fs::exists(branch->path,fusepath)) + error_and_continue(error,ENOENT); + if(branch->ro()) + error_and_continue(error,EROFS); + rv = fs::info(&branch->path,&info); + if(rv == -1) + error_and_continue(error,ENOENT); + if(info.readonly) + error_and_continue(error,EROFS); + if(info.spaceavail < epmfs) + continue; + + epmfs = info.spaceavail; + epmfsbasepath = &branch->path; + } + + if(epmfsbasepath == NULL) + return (errno=error,-1); + + paths.push_back(epmfsbasepath); + + return 0; + } - return _epmfs_other(basepaths,fusepath,paths); + static + int + search(const Branches &branches_, + const char *fusepath, + vector &paths) + { + int rv; + uint64_t epmfs; + uint64_t spaceavail; + const Branch *branch; + const string *epmfsbasepath; + + epmfs = 0; + epmfsbasepath = NULL; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(!fs::exists(branch->path,fusepath)) + continue; + rv = fs::spaceavail(&branch->path,&spaceavail); + if(rv == -1) + continue; + if(spaceavail < epmfs) + continue; + + epmfs = spaceavail; + epmfsbasepath = &branch->path; + } + + if(epmfsbasepath == NULL) + return (errno=ENOENT,-1); + + paths.push_back(epmfsbasepath); + + return 0; + } } namespace mergerfs { int Policy::Func::epmfs(const Category::Enum::Type type, - const vector &basepaths, + const Branches &branches_, const char *fusepath, const uint64_t minfreespace, vector &paths) { - int rv; - - rv = _epmfs(type,basepaths,fusepath,minfreespace,paths); - if(rv == -1) - rv = Policy::Func::mfs(type,basepaths,fusepath,minfreespace,paths); - - return rv; + switch(type) + { + case Category::Enum::create: + return epmfs::create(branches_,fusepath,minfreespace,paths); + case Category::Enum::action: + return epmfs::action(branches_,fusepath,paths); + case Category::Enum::search: + default: + return epmfs::search(branches_,fusepath,paths); + } } } diff --git a/src/policy_eprand.cpp b/src/policy_eprand.cpp index 7b739052..4d2bf4b1 100644 --- a/src/policy_eprand.cpp +++ b/src/policy_eprand.cpp @@ -28,14 +28,14 @@ namespace mergerfs { int Policy::Func::eprand(const Category::Enum::Type type, - const vector &basepaths, + const Branches &branches_, const char *fusepath, const uint64_t minfreespace, vector &paths) { int rv; - rv = Policy::Func::epall(type,basepaths,fusepath,minfreespace,paths); + rv = Policy::Func::epall(type,branches_,fusepath,minfreespace,paths); if(rv == 0) std::random_shuffle(paths.begin(),paths.end()); diff --git a/src/policy_erofs.cpp b/src/policy_erofs.cpp index 6a543033..af6acbd0 100644 --- a/src/policy_erofs.cpp +++ b/src/policy_erofs.cpp @@ -27,7 +27,7 @@ namespace mergerfs { int Policy::Func::erofs(const Category::Enum::Type type, - const vector &basepaths, + const Branches &branches_, const char *fusepath, const uint64_t minfreespace, vector &paths) diff --git a/src/policy_error.hpp b/src/policy_error.hpp new file mode 100644 index 00000000..c4e8c0c0 --- /dev/null +++ b/src/policy_error.hpp @@ -0,0 +1,51 @@ +/* + ISC License + + Copyright (c) 2018, 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. +*/ + +#pragma once + +#define error_and_continue(CUR,ERR) \ + { \ + policy::calc_error(CUR,ERR); \ + continue; \ + } + +namespace policy +{ + static + inline + void + calc_error(int &cur_, + int err_) + { + switch(cur_) + { + default: + case ENOENT: + cur_ = err_; + break; + case ENOSPC: + if(err_ != ENOENT) + cur_ = err_; + break; + case EROFS: + if((err_ != ENOENT) && (err_ != ENOSPC)) + cur_ = err_; + break; + } + } +} diff --git a/src/policy_ff.cpp b/src/policy_ff.cpp index 76cb5728..74672bed 100644 --- a/src/policy_ff.cpp +++ b/src/policy_ff.cpp @@ -20,6 +20,7 @@ #include "fs_info.hpp" #include "fs_path.hpp" #include "policy.hpp" +#include "policy_error.hpp" #include #include @@ -27,80 +28,55 @@ using std::string; using std::vector; -static -int -_ff_create(const vector &basepaths, - const uint64_t minfreespace, - vector &paths) +namespace ff { - int rv; - fs::info_t info; - const string *basepath; - const string *fallback; - - fallback = NULL; - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - rv = fs::info(basepath,&info); - if(rv == -1) - continue; - if(info.readonly) - continue; - if(fallback == NULL) - fallback = basepath; - if(info.spaceavail < minfreespace) - continue; - - paths.push_back(basepath); - - return 0; - } - - if(fallback == NULL) - return (errno=ENOENT,-1); - - paths.push_back(fallback); - - return 0; -} - -static -int -_ff_other(const vector &basepaths, - const char *fusepath, - vector &paths) -{ - const string *basepath; - - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - if(!fs::exists(*basepath,fusepath)) - continue; - - paths.push_back(basepath); - - return 0; - } - - return (errno=ENOENT,-1); + static + int + create(const Branches &branches_, + const uint64_t minfreespace, + vector &paths) + { + int rv; + int error; + fs::info_t info; + const Branch *branch; + + error = ENOENT; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(branch->ro_or_nw()) + error_and_continue(error,EROFS); + rv = fs::info(&branch->path,&info); + if(rv == -1) + error_and_continue(error,ENOENT); + if(info.readonly) + error_and_continue(error,EROFS); + if(info.spaceavail < minfreespace) + error_and_continue(error,ENOSPC); + + paths.push_back(&branch->path); + + return 0; + } + + return (errno=error,-1); + } } namespace mergerfs { int Policy::Func::ff(const Category::Enum::Type type, - const vector &basepaths, + const Branches &branches_, const char *fusepath, const uint64_t minfreespace, vector &paths) { if(type == Category::Enum::create) - return _ff_create(basepaths,minfreespace,paths); + return ff::create(branches_,minfreespace,paths); - return _ff_other(basepaths,fusepath,paths); + return Policy::Func::epff(type,branches_,fusepath,minfreespace,paths); } } diff --git a/src/policy_invalid.cpp b/src/policy_invalid.cpp index 1fc49a99..de031ecf 100644 --- a/src/policy_invalid.cpp +++ b/src/policy_invalid.cpp @@ -27,7 +27,7 @@ namespace mergerfs { int Policy::Func::invalid(const Category::Enum::Type type, - const vector &basepaths, + const Branches &branches_, const char *fusepath, const uint64_t minfreespace, vector &paths) diff --git a/src/policy_lfs.cpp b/src/policy_lfs.cpp index f86d09ca..787ec42c 100644 --- a/src/policy_lfs.cpp +++ b/src/policy_lfs.cpp @@ -20,6 +20,7 @@ #include "fs_info.hpp" #include "fs_path.hpp" #include "policy.hpp" +#include "policy_error.hpp" #include #include @@ -29,114 +30,65 @@ using std::string; using std::vector; using mergerfs::Category; -static -int -_lfs_create(const vector &basepaths, - const uint64_t minfreespace, - vector &paths) +namespace lfs { - int rv; - uint64_t lfs; - fs::info_t info; - const string *basepath; - const string *lfsbasepath; - - lfs = std::numeric_limits::max(); - lfsbasepath = NULL; - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - rv = fs::info(basepath,&info); - if(rv == -1) - continue; - if(info.readonly) - continue; - if(info.spaceavail < minfreespace) - continue; - if(info.spaceavail > lfs) - continue; - - lfs = info.spaceavail; - lfsbasepath = basepath; - } - - if(lfsbasepath == NULL) - return (errno=ENOENT,-1); - - paths.push_back(lfsbasepath); - - return 0; -} - -static -int -_lfs_other(const vector &basepaths, - const char *fusepath, - vector &paths) -{ - int rv; - uint64_t lfs; - uint64_t spaceavail; - const string *basepath; - const string *lfsbasepath; - - lfs = std::numeric_limits::max(); - lfsbasepath = NULL; - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - if(!fs::exists(*basepath,fusepath)) - continue; - rv = fs::spaceavail(basepath,&spaceavail); - if(rv == -1) - continue; - if(spaceavail > lfs) - continue; - - lfs = spaceavail; - lfsbasepath = basepath; - } - - if(lfsbasepath == NULL) - return (errno=ENOENT,-1); - - paths.push_back(lfsbasepath); - - return 0; -} - -static -int -_lfs(const Category::Enum::Type type, - const vector &basepaths, - const char *fusepath, - const uint64_t minfreespace, - vector &paths) -{ - if(type == Category::Enum::create) - return _lfs_create(basepaths,minfreespace,paths); - - return _lfs_other(basepaths,fusepath,paths); + static + int + create(const Branches &branches_, + const uint64_t minfreespace, + vector &paths) + { + int rv; + int error; + uint64_t lfs; + fs::info_t info; + const Branch *branch; + const string *lfsbasepath; + + error = ENOENT; + lfs = std::numeric_limits::max(); + lfsbasepath = NULL; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(branch->ro_or_nw()) + error_and_continue(error,EROFS); + rv = fs::info(&branch->path,&info); + if(rv == -1) + error_and_continue(error,ENOENT); + if(info.readonly) + error_and_continue(error,EROFS); + if(info.spaceavail < minfreespace) + error_and_continue(error,ENOSPC); + if(info.spaceavail > lfs) + continue; + + lfs = info.spaceavail; + lfsbasepath = &branch->path; + } + + if(lfsbasepath == NULL) + return (errno=error,-1); + + paths.push_back(lfsbasepath); + + return 0; + } } - namespace mergerfs { int Policy::Func::lfs(const Category::Enum::Type type, - const vector &basepaths, + const Branches &branches_, const char *fusepath, const uint64_t minfreespace, vector &paths) { - int rv; - - rv = _lfs(type,basepaths,fusepath,minfreespace,paths); - if(rv == -1) - rv = Policy::Func::mfs(type,basepaths,fusepath,minfreespace,paths); + if(type == Category::Enum::create) + return lfs::create(branches_,minfreespace,paths); - return rv; + return Policy::Func::eplfs(type,branches_,fusepath,minfreespace,paths); } } diff --git a/src/policy_lus.cpp b/src/policy_lus.cpp index 63a07327..e41c5e44 100644 --- a/src/policy_lus.cpp +++ b/src/policy_lus.cpp @@ -20,6 +20,7 @@ #include "fs_info.hpp" #include "fs_path.hpp" #include "policy.hpp" +#include "policy_error.hpp" #include #include @@ -29,113 +30,65 @@ using std::string; using std::vector; using mergerfs::Category; -static -int -_lus_create(const vector &basepaths, - const uint64_t minfreespace, - vector &paths) +namespace lus { - int rv; - uint64_t lus; - fs::info_t info; - const string *basepath; - const string *lusbasepath; - - lus = std::numeric_limits::max(); - lusbasepath = NULL; - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - rv = fs::info(basepath,&info); - if(rv == -1) - continue; - if(info.readonly) - continue; - if(info.spaceavail < minfreespace) - continue; - if(info.spaceused >= lus) - continue; - - lus = info.spaceused; - lusbasepath = basepath; - } - - if(lusbasepath == NULL) - return (errno=ENOENT,-1); - - paths.push_back(lusbasepath); - - return 0; -} - -static -int -_lus_other(const vector &basepaths, - const char *fusepath, - vector &paths) -{ - int rv; - uint64_t lus; - uint64_t spaceused; - const string *basepath; - const string *lusbasepath; - - lus = 0; - lusbasepath = NULL; - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - if(!fs::exists(*basepath,fusepath)) - continue; - rv = fs::spaceused(basepath,&spaceused); - if(rv == -1) - continue; - if(spaceused >= lus) - continue; - - lus = spaceused; - lusbasepath = basepath; - } - - if(lusbasepath == NULL) - return (errno=ENOENT,-1); - - paths.push_back(lusbasepath); - - return 0; -} - -static -int -_lus(const Category::Enum::Type type, - const vector &basepaths, - const char *fusepath, - const uint64_t minfreespace, - vector &paths) -{ - if(type == Category::Enum::create) - return _lus_create(basepaths,minfreespace,paths); - - return _lus_other(basepaths,fusepath,paths); + static + int + create(const Branches &branches_, + const uint64_t minfreespace, + vector &paths) + { + int rv; + int error; + uint64_t lus; + fs::info_t info; + const Branch *branch; + const string *lusbasepath; + + error = ENOENT; + lus = std::numeric_limits::max(); + lusbasepath = NULL; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(branch->ro_or_nw()) + error_and_continue(error,EROFS); + rv = fs::info(&branch->path,&info); + if(rv == -1) + error_and_continue(error,ENOENT); + if(info.readonly) + error_and_continue(error,EROFS); + if(info.spaceavail < minfreespace) + error_and_continue(error,ENOSPC); + if(info.spaceused >= lus) + continue; + + lus = info.spaceused; + lusbasepath = &branch->path; + } + + if(lusbasepath == NULL) + return (errno=error,-1); + + paths.push_back(lusbasepath); + + return 0; + } } namespace mergerfs { int Policy::Func::lus(const Category::Enum::Type type, - const vector &basepaths, + const Branches &branches_, const char *fusepath, const uint64_t minfreespace, vector &paths) { - int rv; - - rv = _lus(type,basepaths,fusepath,minfreespace,paths); - if(rv == -1) - rv = Policy::Func::mfs(type,basepaths,fusepath,minfreespace,paths); + if(type == Category::Enum::create) + return lus::create(branches_,minfreespace,paths); - return rv; + return Policy::Func::eplus(type,branches_,fusepath,minfreespace,paths); } } diff --git a/src/policy_mfs.cpp b/src/policy_mfs.cpp index 05d45be2..aa87fe3e 100644 --- a/src/policy_mfs.cpp +++ b/src/policy_mfs.cpp @@ -20,6 +20,7 @@ #include "fs_info.hpp" #include "fs_path.hpp" #include "policy.hpp" +#include "policy_error.hpp" #include #include @@ -28,109 +29,65 @@ using std::string; using std::vector; using mergerfs::Category; -static -int -_mfs_create(const vector &basepaths, - vector &paths) +namespace mfs { - int rv; - uint64_t mfs; - fs::info_t info; - const string *basepath; - const string *mfsbasepath; - - mfs = 0; - mfsbasepath = NULL; - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - rv = fs::info(basepath,&info); - if(rv == -1) - continue; - if(info.readonly) - continue; - if(info.spaceavail < mfs) - continue; - - mfs = info.spaceavail; - mfsbasepath = basepath; - } - - if(mfsbasepath == NULL) - return (errno=ENOENT,-1); - - paths.push_back(mfsbasepath); - - return 0; -} - -static -int -_mfs_other(const vector &basepaths, - const char *fusepath, - vector &paths) -{ - int rv; - uint64_t mfs; - uint64_t spaceavail; - const string *basepath; - const string *mfsbasepath; - - mfs = 0; - mfsbasepath = NULL; - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - if(!fs::exists(*basepath,fusepath)) - continue; - rv = fs::spaceavail(basepath,&spaceavail); - if(rv == -1) - continue; - if(spaceavail < mfs) - continue; - - mfs = spaceavail; - mfsbasepath = basepath; - } - - if(mfsbasepath == NULL) - return (errno=ENOENT,-1); - - paths.push_back(mfsbasepath); - - return 0; -} - -static -int -_mfs(const Category::Enum::Type type, - const vector &basepaths, - const char *fusepath, - vector &paths) -{ - if(type == Category::Enum::create) - return _mfs_create(basepaths,paths); - - return _mfs_other(basepaths,fusepath,paths); + static + int + create(const Branches &branches_, + const uint64_t minfreespace, + vector &paths) + { + int rv; + int error; + uint64_t mfs; + fs::info_t info; + const Branch *branch; + const string *mfsbasepath; + + error = ENOENT; + mfs = 0; + mfsbasepath = NULL; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(branch->ro_or_nw()) + error_and_continue(error,EROFS); + rv = fs::info(&branch->path,&info); + if(rv == -1) + error_and_continue(error,ENOENT); + if(info.readonly) + error_and_continue(error,EROFS); + if(info.spaceavail < minfreespace) + error_and_continue(error,ENOSPC); + if(info.spaceavail < mfs) + continue; + + mfs = info.spaceavail; + mfsbasepath = &branch->path; + } + + if(mfsbasepath == NULL) + return (errno=error,-1); + + paths.push_back(mfsbasepath); + + return 0; + } } namespace mergerfs { int Policy::Func::mfs(const Category::Enum::Type type, - const vector &basepaths, + const Branches &branches_, const char *fusepath, const uint64_t minfreespace, vector &paths) { - int rv; - - rv = _mfs(type,basepaths,fusepath,paths); - if(rv == -1) - rv = Policy::Func::ff(type,basepaths,fusepath,minfreespace,paths); + if(type == Category::Enum::create) + return mfs::create(branches_,minfreespace,paths); - return rv; + return Policy::Func::epmfs(type,branches_,fusepath,minfreespace,paths); } } diff --git a/src/policy_newest.cpp b/src/policy_newest.cpp index eee8153b..b3436046 100644 --- a/src/policy_newest.cpp +++ b/src/policy_newest.cpp @@ -14,12 +14,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - #include "errno.hpp" #include "fs.hpp" #include "fs_exists.hpp" #include "fs_path.hpp" #include "policy.hpp" +#include "policy_error.hpp" #include #include @@ -30,93 +30,151 @@ using std::string; using std::vector; -static -int -_newest_create(const vector &basepaths, - const char *fusepath, - vector &paths) +namespace newest { - int rv; - bool readonly; - time_t newest; - struct stat st; - const string *basepath; - const string *newestbasepath; - - newest = std::numeric_limits::min(); - newestbasepath = NULL; - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; - - if(!fs::exists(*basepath,fusepath,st)) - continue; - if(st.st_mtime < newest) - continue; - rv = fs::readonly(basepath,&readonly); - if(rv == -1) - continue; - if(readonly) - continue; - - newest = st.st_mtime; - newestbasepath = basepath; - } - - if(newestbasepath == NULL) - return (errno=ENOENT,-1); - - paths.push_back(newestbasepath); - - return 0; -} + static + int + create(const Branches &branches_, + const char *fusepath, + vector &paths) + { + int rv; + int error; + bool readonly; + time_t newest; + struct stat st; + const Branch *branch; + const string *newestbasepath; + + error = ENOENT; + newest = std::numeric_limits::min(); + newestbasepath = NULL; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(!fs::exists(branch->path,fusepath,st)) + error_and_continue(error,ENOENT); + if(branch->ro_or_nw()) + error_and_continue(error,EROFS); + if(st.st_mtime < newest) + continue; + rv = fs::readonly(&branch->path,&readonly); + if(rv == -1) + error_and_continue(error,ENOENT); + if(readonly) + error_and_continue(error,EROFS); + + newest = st.st_mtime; + newestbasepath = &branch->path; + } + + if(newestbasepath == NULL) + return (errno=error,-1); + + paths.push_back(newestbasepath); + + return 0; + } -static -int -_newest_other(const vector &basepaths, - const char *fusepath, - vector &paths) -{ - time_t newest; - struct stat st; - const string *basepath; - const string *newestbasepath; + static + int + action(const Branches &branches_, + const char *fusepath, + vector &paths) + { + int rv; + int error; + bool readonly; + time_t newest; + struct stat st; + const Branch *branch; + const string *newestbasepath; + + error = ENOENT; + newest = std::numeric_limits::min(); + newestbasepath = NULL; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + if(!fs::exists(branch->path,fusepath,st)) + error_and_continue(error,ENOENT); + if(branch->ro()) + error_and_continue(error,EROFS); + if(st.st_mtime < newest) + continue; + rv = fs::readonly(&branch->path,&readonly); + if(rv == -1) + error_and_continue(error,ENOENT); + if(readonly) + error_and_continue(error,EROFS); + + newest = st.st_mtime; + newestbasepath = &branch->path; + } + + if(newestbasepath == NULL) + return (errno=error,-1); + + paths.push_back(newestbasepath); + + return 0; + } - newest = std::numeric_limits::min(); - newestbasepath = NULL; - for(size_t i = 0, ei = basepaths.size(); i != ei; i++) - { - basepath = &basepaths[i]; + static + int + search(const Branches &branches_, + const char *fusepath, + vector &paths) + { + time_t newest; + struct stat st; + const Branch *branch; + const string *newestbasepath; - if(!fs::exists(*basepath,fusepath,st)) - continue; - if(st.st_mtime < newest) - continue; + newest = std::numeric_limits::min(); + newestbasepath = NULL; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; - newest = st.st_mtime; - newestbasepath = basepath; - } + if(!fs::exists(branch->path,fusepath,st)) + continue; + if(st.st_mtime < newest) + continue; - if(newestbasepath == NULL) - return (errno=ENOENT,-1); + newest = st.st_mtime; + newestbasepath = &branch->path; + } - paths.push_back(newestbasepath); + if(newestbasepath == NULL) + return (errno=ENOENT,-1); - return 0; + paths.push_back(newestbasepath); + + return 0; + } } namespace mergerfs { int Policy::Func::newest(const Category::Enum::Type type, - const vector &basepaths, + const Branches &branches_, const char *fusepath, const uint64_t minfreespace, vector &paths) { - if(type == Category::Enum::create) - return _newest_create(basepaths,fusepath,paths); - - return _newest_other(basepaths,fusepath,paths); + switch(type) + { + case Category::Enum::create: + return newest::create(branches_,fusepath,paths); + case Category::Enum::action: + return newest::action(branches_,fusepath,paths); + case Category::Enum::search: + default: + return newest::search(branches_,fusepath,paths); + } } } diff --git a/src/policy_rand.cpp b/src/policy_rand.cpp index a22b9a98..bc2a146e 100644 --- a/src/policy_rand.cpp +++ b/src/policy_rand.cpp @@ -28,14 +28,14 @@ namespace mergerfs { int Policy::Func::rand(const Category::Enum::Type type, - const vector &basepaths, + const Branches &branches_, const char *fusepath, const uint64_t minfreespace, vector &paths) { int rv; - rv = Policy::Func::all(type,basepaths,fusepath,minfreespace,paths); + rv = Policy::Func::all(type,branches_,fusepath,minfreespace,paths); if(rv == 0) std::random_shuffle(paths.begin(),paths.end()); diff --git a/src/readdir.cpp b/src/readdir.cpp index 42d9748e..16932a88 100644 --- a/src/readdir.cpp +++ b/src/readdir.cpp @@ -45,7 +45,7 @@ using std::vector; static int -_readdir(const vector &srcmounts, +_readdir(const Branches &branches_, const char *dirname, void *buf, const fuse_fill_dir_t filler) @@ -54,13 +54,13 @@ _readdir(const vector &srcmounts, string basepath; struct stat st = {0}; - for(size_t i = 0, ei = srcmounts.size(); i != ei; i++) + for(size_t i = 0, ei = branches_.size(); i != ei; i++) { int rv; int dirfd; DIR *dh; - fs::path::make(&srcmounts[i],dirname,basepath); + basepath = fs::path::make(&branches_[i].path,dirname); dh = fs::opendir(basepath); if(!dh) @@ -109,9 +109,9 @@ namespace mergerfs const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); - return ::_readdir(config.srcmounts, + return ::_readdir(config.branches, di->fusepath.c_str(), buf, filler); diff --git a/src/readlink.cpp b/src/readlink.cpp index 6551d709..5b90e347 100644 --- a/src/readlink.cpp +++ b/src/readlink.cpp @@ -93,7 +93,7 @@ _readlink_core(const string *basepath, static int _readlink(Policy::Func::Search searchFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *fusepath, char *buf, @@ -104,7 +104,7 @@ _readlink(Policy::Func::Search searchFunc, int rv; vector basepaths; - rv = searchFunc(srcmounts,fusepath,minfreespace,basepaths); + rv = searchFunc(branches_,fusepath,minfreespace,basepaths); if(rv == -1) return -errno; @@ -124,10 +124,10 @@ namespace mergerfs const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); return _readlink(config.readlink, - config.srcmounts, + config.branches, config.minfreespace, fusepath, buf, diff --git a/src/removexattr.cpp b/src/removexattr.cpp index e84f4a28..a4227197 100644 --- a/src/removexattr.cpp +++ b/src/removexattr.cpp @@ -69,7 +69,7 @@ _removexattr_loop(const vector &basepaths, static int _removexattr(Policy::Func::Action actionFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *fusepath, const char *attrname) @@ -77,7 +77,7 @@ _removexattr(Policy::Func::Action actionFunc, int rv; vector basepaths; - rv = actionFunc(srcmounts,fusepath,minfreespace,basepaths); + rv = actionFunc(branches_,fusepath,minfreespace,basepaths); if(rv == -1) return -errno; @@ -101,10 +101,10 @@ namespace mergerfs return -config.xattr; const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); return _removexattr(config.removexattr, - config.srcmounts, + config.branches, config.minfreespace, fusepath, attrname); diff --git a/src/rename.cpp b/src/rename.cpp index c64ddd5d..8cfc90b5 100644 --- a/src/rename.cpp +++ b/src/rename.cpp @@ -100,7 +100,7 @@ static int _rename_create_path(Policy::Func::Search searchFunc, Policy::Func::Action actionFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *oldfusepath, const char *newfusepath) @@ -112,20 +112,20 @@ _rename_create_path(Policy::Func::Search searchFunc, vector newbasepath; vector oldbasepaths; - rv = actionFunc(srcmounts,oldfusepath,minfreespace,oldbasepaths); + rv = actionFunc(branches_,oldfusepath,minfreespace,oldbasepaths); if(rv == -1) return -errno; newfusedirpath = fs::path::dirname(newfusepath); - rv = searchFunc(srcmounts,newfusedirpath,minfreespace,newbasepath); + rv = searchFunc(branches_,newfusedirpath,minfreespace,newbasepath); if(rv == -1) return -errno; error = -1; - for(size_t i = 0, ei = srcmounts.size(); i != ei; i++) + for(size_t i = 0, ei = branches_.size(); i != ei; i++) { - const string &oldbasepath = srcmounts[i]; + const string &oldbasepath = branches_[i].path; _rename_create_path_core(oldbasepaths, oldbasepath,*newbasepath[0], @@ -144,7 +144,7 @@ _rename_create_path(Policy::Func::Search searchFunc, static int _clonepath(Policy::Func::Search searchFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const string &dstbasepath, const string &fusedirpath) @@ -152,7 +152,7 @@ _clonepath(Policy::Func::Search searchFunc, int rv; vector srcbasepath; - rv = searchFunc(srcmounts,fusedirpath,minfreespace,srcbasepath); + rv = searchFunc(branches_,fusedirpath,minfreespace,srcbasepath); if(rv == -1) return -errno; @@ -165,7 +165,7 @@ static int _clonepath_if_would_create(Policy::Func::Search searchFunc, Policy::Func::Create createFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const string &oldbasepath, const char *oldfusepath, @@ -177,12 +177,12 @@ _clonepath_if_would_create(Policy::Func::Search searchFunc, newfusedirpath = fs::path::dirname(newfusepath); - rv = createFunc(srcmounts,newfusedirpath,minfreespace,newbasepath); + rv = createFunc(branches_,newfusedirpath,minfreespace,newbasepath); if(rv == -1) return rv; if(oldbasepath == *newbasepath[0]) - return _clonepath(searchFunc,srcmounts,minfreespace,oldbasepath,newfusedirpath); + return _clonepath(searchFunc,branches_,minfreespace,oldbasepath,newfusedirpath); return (errno=EXDEV,-1); } @@ -191,7 +191,7 @@ static void _rename_preserve_path_core(Policy::Func::Search searchFunc, Policy::Func::Create createFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const vector &oldbasepaths, const string &oldbasepath, @@ -217,7 +217,7 @@ _rename_preserve_path_core(Policy::Func::Search searchFunc, if((rv == -1) && (errno == ENOENT)) { rv = _clonepath_if_would_create(searchFunc,createFunc, - srcmounts,minfreespace, + branches_,minfreespace, oldbasepath,oldfusepath,newfusepath); if(rv == 0) rv = fs::rename(oldfullpath,newfullpath); @@ -238,7 +238,7 @@ int _rename_preserve_path(Policy::Func::Search searchFunc, Policy::Func::Action actionFunc, Policy::Func::Create createFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *oldfusepath, const char *newfusepath) @@ -248,17 +248,17 @@ _rename_preserve_path(Policy::Func::Search searchFunc, vector toremove; vector oldbasepaths; - rv = actionFunc(srcmounts,oldfusepath,minfreespace,oldbasepaths); + rv = actionFunc(branches_,oldfusepath,minfreespace,oldbasepaths); if(rv == -1) return -errno; error = -1; - for(size_t i = 0, ei = srcmounts.size(); i != ei; i++) + for(size_t i = 0, ei = branches_.size(); i != ei; i++) { - const string &oldbasepath = srcmounts[i]; + const string &oldbasepath = branches_[i].path; _rename_preserve_path_core(searchFunc,createFunc, - srcmounts,minfreespace, + branches_,minfreespace, oldbasepaths,oldbasepath, oldfusepath,newfusepath, error,toremove); @@ -281,20 +281,20 @@ namespace mergerfs const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); if(config.create->path_preserving() && !config.ignorepponrename) return _rename_preserve_path(config.getattr, config.rename, config.create, - config.srcmounts, + config.branches, config.minfreespace, oldpath, newpath); return _rename_create_path(config.getattr, config.rename, - config.srcmounts, + config.branches, config.minfreespace, oldpath, newpath); diff --git a/src/rmdir.cpp b/src/rmdir.cpp index d64bf633..30772d7d 100644 --- a/src/rmdir.cpp +++ b/src/rmdir.cpp @@ -68,14 +68,14 @@ _rmdir_loop(const vector &basepaths, static int _rmdir(Policy::Func::Action actionFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *fusepath) { int rv; vector basepaths; - rv = actionFunc(srcmounts,fusepath,minfreespace,basepaths); + rv = actionFunc(branches_,fusepath,minfreespace,basepaths); if(rv == -1) return -errno; @@ -92,10 +92,10 @@ namespace mergerfs const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readguard(&config.srcmountslock); + const rwlock::ReadGuard readguard(&config.branches_lock); return _rmdir(config.rmdir, - config.srcmounts, + config.branches, config.minfreespace, fusepath); } diff --git a/src/setxattr.cpp b/src/setxattr.cpp index 518f10b4..a4bd3864 100644 --- a/src/setxattr.cpp +++ b/src/setxattr.cpp @@ -48,78 +48,6 @@ _is_attrname_security_capability(const char *attrname_) return (strcmp(attrname_,SECURITY_CAPABILITY) == 0); } -static -int -_add_srcmounts(vector &srcmounts, - pthread_rwlock_t &srcmountslock, - const string &destmount, - const string &values, - vector::iterator pos) -{ - vector patterns; - vector additions; - - str::split(patterns,values,':'); - fs::glob(patterns,additions); - fs::realpathize(additions); - - if(!additions.empty()) - { - const rwlock::WriteGuard wrg(&srcmountslock); - - srcmounts.insert(pos, - additions.begin(), - additions.end()); - } - - return 0; -} - -static -int -_erase_srcmounts(vector &srcmounts, - pthread_rwlock_t &srcmountslock, - const string &values) -{ - if(srcmounts.empty()) - return 0; - - vector patterns; - - str::split(patterns,values,':'); - - { - const rwlock::WriteGuard wrg(&srcmountslock); - - str::erase_fnmatches(patterns,srcmounts); - } - - return 0; -} - -static -int -_replace_srcmounts(vector &srcmounts, - pthread_rwlock_t &srcmountslock, - const string &destmount, - const string &values) -{ - vector patterns; - vector newmounts; - - str::split(patterns,values,':'); - fs::glob(patterns,newmounts); - fs::realpathize(newmounts); - - { - const rwlock::WriteGuard wrg(&srcmountslock); - - srcmounts.swap(newmounts); - } - - return 0; -} - static void _split_attrval(const string &attrval, @@ -138,10 +66,11 @@ static int _setxattr_srcmounts(const string &attrval, const int flags, - vector &srcmounts, - pthread_rwlock_t &srcmountslock, - const string &destmount) + Branches &branches_, + pthread_rwlock_t &branches_lock) { + const rwlock::WriteGuard wrg(&branches_lock); + string instruction; string values; @@ -151,23 +80,25 @@ _setxattr_srcmounts(const string &attrval, _split_attrval(attrval,instruction,values); if(instruction == "+") - return _add_srcmounts(srcmounts,srcmountslock,destmount,values,srcmounts.end()); + branches_.add_end(values); else if(instruction == "+<") - return _add_srcmounts(srcmounts,srcmountslock,destmount,values,srcmounts.begin()); + branches_.add_begin(values); else if(instruction == "+>") - return _add_srcmounts(srcmounts,srcmountslock,destmount,values,srcmounts.end()); + branches_.add_end(values); else if(instruction == "-") - return _erase_srcmounts(srcmounts,srcmountslock,values); + branches_.erase_fnmatch(values); else if(instruction == "-<") - return _erase_srcmounts(srcmounts,srcmountslock,srcmounts.front()); + branches_.erase_begin(); else if(instruction == "->") - return _erase_srcmounts(srcmounts,srcmountslock,srcmounts.back()); + branches_.erase_end(); else if(instruction == "=") - return _replace_srcmounts(srcmounts,srcmountslock,destmount,values); + branches_.set(values); else if(instruction.empty()) - return _replace_srcmounts(srcmounts,srcmountslock,destmount,values); + branches_.set(values); + else + return -EINVAL; - return -EINVAL; + return 0; } static @@ -280,9 +211,13 @@ _setxattr_controlfile(Config &config, if(attr[2] == "srcmounts") return _setxattr_srcmounts(attrval, flags, - config.srcmounts, - config.srcmountslock, - config.destmount); + config.branches, + config.branches_lock); + else if(attr[2] == "branches") + return _setxattr_srcmounts(attrval, + flags, + config.branches, + config.branches_lock); else if(attr[2] == "minfreespace") return _setxattr_uint64_t(attrval, flags, @@ -382,7 +317,7 @@ _setxattr_loop(const vector &basepaths, static int _setxattr(Policy::Func::Action actionFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *fusepath, const char *attrname, @@ -393,7 +328,7 @@ _setxattr(Policy::Func::Action actionFunc, int rv; vector basepaths; - rv = actionFunc(srcmounts,fusepath,minfreespace,basepaths); + rv = actionFunc(branches_,fusepath,minfreespace,basepaths); if(rv == -1) return -errno; @@ -428,10 +363,10 @@ namespace mergerfs return -config.xattr; const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); return _setxattr(config.setxattr, - config.srcmounts, + config.branches, config.minfreespace, fusepath, attrname, diff --git a/src/statfs.cpp b/src/statfs.cpp index 34f4b9fb..f9d2fd45 100644 --- a/src/statfs.cpp +++ b/src/statfs.cpp @@ -64,7 +64,7 @@ _merge_statvfs(struct statvfs * const out, static void -_statfs_core(const char *srcmount, +_statfs_core(const string &path_, unsigned long &min_bsize, unsigned long &min_frsize, unsigned long &min_namemax, @@ -74,11 +74,11 @@ _statfs_core(const char *srcmount, struct stat st; struct statvfs fsstat; - rv = fs::statvfs(srcmount,fsstat); + rv = fs::statvfs(path_,fsstat); if(rv == -1) return; - rv = fs::stat(srcmount,st); + rv = fs::stat(path_,st); if(rv == -1) return; @@ -94,17 +94,17 @@ _statfs_core(const char *srcmount, static int -_statfs(const vector &srcmounts, - struct statvfs &fsstat) +_statfs(const Branches &branches_, + struct statvfs &fsstat) { map fsstats; unsigned long min_bsize = ULONG_MAX; unsigned long min_frsize = ULONG_MAX; unsigned long min_namemax = ULONG_MAX; - for(size_t i = 0, ei = srcmounts.size(); i < ei; i++) + for(size_t i = 0, ei = branches_.size(); i < ei; i++) { - _statfs_core(srcmounts[i].c_str(),min_bsize,min_frsize,min_namemax,fsstats); + _statfs_core(branches_[i].path,min_bsize,min_frsize,min_namemax,fsstats); } map::iterator iter = fsstats.begin(); @@ -135,9 +135,9 @@ namespace mergerfs const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); - return _statfs(config.srcmounts, + return _statfs(config.branches, *stat); } } diff --git a/src/str.cpp b/src/str.cpp index 1618f490..eaa0b1c0 100644 --- a/src/str.cpp +++ b/src/str.cpp @@ -147,4 +147,16 @@ namespace str return ((s0.size() >= s1.size()) && (s0.compare(0,s1.size(),s1) == 0)); } + + bool + ends_with(const string &str_, + const string &suffix_) + { + if(suffix_.size() > str_.size()) + return false; + + return std::equal(suffix_.rbegin(), + suffix_.rend(), + str_.rbegin()); + } } diff --git a/src/str.hpp b/src/str.hpp index 3538ce48..ff7daba6 100644 --- a/src/str.hpp +++ b/src/str.hpp @@ -56,4 +56,8 @@ namespace str bool isprefix(const std::string &s0, const std::string &s1); + + bool + ends_with(const std::string &str_, + const std::string &suffix_); } diff --git a/src/symlink.cpp b/src/symlink.cpp index 02915940..604cf1d8 100644 --- a/src/symlink.cpp +++ b/src/symlink.cpp @@ -82,7 +82,7 @@ static int _symlink(Policy::Func::Search searchFunc, Policy::Func::Create createFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *oldpath, const char *newpath) @@ -94,11 +94,11 @@ _symlink(Policy::Func::Search searchFunc, newdirpath = fs::path::dirname(newpath); - rv = searchFunc(srcmounts,newdirpath,minfreespace,existingpaths); + rv = searchFunc(branches_,newdirpath,minfreespace,existingpaths); if(rv == -1) return -errno; - rv = createFunc(srcmounts,newdirpath,minfreespace,newbasepaths); + rv = createFunc(branches_,newdirpath,minfreespace,newbasepaths); if(rv == -1) return -errno; @@ -117,11 +117,11 @@ namespace mergerfs const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); return _symlink(config.getattr, config.symlink, - config.srcmounts, + config.branches, config.minfreespace, oldpath, newpath); diff --git a/src/truncate.cpp b/src/truncate.cpp index db43592e..b2ecc648 100644 --- a/src/truncate.cpp +++ b/src/truncate.cpp @@ -71,7 +71,7 @@ _truncate_loop(const vector &basepaths, static int _truncate(Policy::Func::Action actionFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *fusepath, const off_t size) @@ -79,7 +79,7 @@ _truncate(Policy::Func::Action actionFunc, int rv; vector basepaths; - rv = actionFunc(srcmounts,fusepath,minfreespace,basepaths); + rv = actionFunc(branches_,fusepath,minfreespace,basepaths); if(rv == -1) return -errno; @@ -97,10 +97,10 @@ namespace mergerfs const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); return _truncate(config.truncate, - config.srcmounts, + config.branches, config.minfreespace, fusepath, size); diff --git a/src/unlink.cpp b/src/unlink.cpp index 9cf403e2..3bec7cc7 100644 --- a/src/unlink.cpp +++ b/src/unlink.cpp @@ -68,14 +68,14 @@ _unlink_loop(const vector &basepaths, static int _unlink(Policy::Func::Action actionFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *fusepath) { int rv; vector basepaths; - rv = actionFunc(srcmounts,fusepath,minfreespace,basepaths); + rv = actionFunc(branches_,fusepath,minfreespace,basepaths); if(rv == -1) return -errno; @@ -92,10 +92,10 @@ namespace mergerfs const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); return _unlink(config.unlink, - config.srcmounts, + config.branches, config.minfreespace, fusepath); } diff --git a/src/utimens.cpp b/src/utimens.cpp index e99700a2..5eb6a9b0 100644 --- a/src/utimens.cpp +++ b/src/utimens.cpp @@ -70,7 +70,7 @@ _utimens_loop(const vector &basepaths, static int _utimens(Policy::Func::Action actionFunc, - const vector &srcmounts, + const Branches &branches_, const uint64_t minfreespace, const char *fusepath, const timespec ts[2]) @@ -78,7 +78,7 @@ _utimens(Policy::Func::Action actionFunc, int rv; vector basepaths; - rv = actionFunc(srcmounts,fusepath,minfreespace,basepaths); + rv = actionFunc(branches_,fusepath,minfreespace,basepaths); if(rv == -1) return -errno; @@ -96,10 +96,10 @@ namespace mergerfs const fuse_context *fc = fuse_get_context(); const Config &config = Config::get(fc); const ugid::Set ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const rwlock::ReadGuard readlock(&config.branches_lock); return _utimens(config.utimens, - config.srcmounts, + config.branches, config.minfreespace, fusepath, ts); diff --git a/src/write.cpp b/src/write.cpp index d77d3519..1dd73eac 100644 --- a/src/write.cpp +++ b/src/write.cpp @@ -14,8 +14,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - #include "config.hpp" #include "errno.hpp" #include "fileinfo.hpp" @@ -24,7 +22,14 @@ #include "rwlock.hpp" #include "ugid.hpp" +#include + +#include +#include + using namespace mergerfs; +using std::string; +using std::vector; typedef int (*WriteFunc)(const int,const void*,const size_t,const off_t); @@ -96,10 +101,13 @@ namespace mergerfs if(config.moveonenospc) { - const ugid::Set ugid(0,0); - const rwlock::ReadGuard readlock(&config.srcmountslock); + vector paths; + const ugid::Set ugid(0,0); + const rwlock::ReadGuard readlock(&config.branches_lock); + + config.branches.to_paths(paths); - rv = fs::movefile(config.srcmounts,fi->fusepath,count,fi->fd); + rv = fs::movefile(paths,fi->fusepath,count,fi->fd); if(rv == -1) return -ENOSPC; diff --git a/src/write_buf.cpp b/src/write_buf.cpp index 91c3e3fc..8d2e94cc 100644 --- a/src/write_buf.cpp +++ b/src/write_buf.cpp @@ -14,14 +14,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - -#include -#include - -#include -#include - #include "config.hpp" #include "errno.hpp" #include "fileinfo.hpp" @@ -31,6 +23,14 @@ #include "ugid.hpp" #include "write.hpp" +#include + +#include +#include + +#include +#include + using std::string; using std::vector; using namespace mergerfs; @@ -83,11 +83,14 @@ namespace mergerfs if(config.moveonenospc) { size_t extra; - const ugid::Set ugid(0,0); - const rwlock::ReadGuard readlock(&config.srcmountslock); + vector paths; + const ugid::Set ugid(0,0); + const rwlock::ReadGuard readlock(&config.branches_lock); + + config.branches.to_paths(paths); extra = fuse_buf_size(src); - rv = fs::movefile(config.srcmounts,fi->fusepath,extra,fi->fd); + rv = fs::movefile(paths,fi->fusepath,extra,fi->fd); if(rv == -1) return -ENOSPC;