diff --git a/README.md b/README.md index 8a2283b5..1581fd16 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ % mergerfs(1) mergerfs user manual % Antonio SJ Musumeci -% 2020-06-28 +% 2020-07-14 # NAME @@ -96,7 +96,7 @@ See the mergerfs [wiki for real world deployments](https://github.com/trapexit/m * **branches**: Colon delimited list of branches. * **allow_other**: A libfuse option which allows users besides the one which ran mergerfs to see the filesystem. This is required for most use-cases. * **minfreespace=SIZE**: The minimum space value used for creation policies. Understands 'K', 'M', and 'G' to represent kilobyte, megabyte, and gigabyte respectively. (default: 4G) -* **moveonenospc=BOOL**: When enabled if a **write** fails with **ENOSPC** (no space left on device) or **EDQUOT** (disk quota exceeded) a scan of all drives will be done looking for the drive with the most free space which is at least the size of the file plus the amount which failed to write. An attempt to move the file to that drive will occur (keeping all metadata possible) and if successful the original is unlinked and the write retried. (default: false) +* **moveonenospc=BOOL|POLICY**: When enabled if a **write** fails with **ENOSPC** (no space left on device) or **EDQUOT** (disk quota exceeded) the policy selected will run to find a new location for the file. An attempt to move the file to that branch will occur (keeping all metadata possible) and if successful the original is unlinked and the write retried. (default: false, true = mfs) * **use_ino**: Causes mergerfs to supply file/directory inodes rather than libfuse. While not a default it is recommended it be enabled so that linked files share the same inode value. * **inodecalc=passthrough|path-hash|devino-hash|hybrid-hash**: Selects the inode calculation algorithm. (default: hybrid-hash) * **dropcacheonclose=BOOL**: When a file is requested to be closed call `posix_fadvise` on it first to instruct the kernel that we no longer need the data and it can drop its cache. Recommended when **cache.files=partial|full|auto-full** to limit double caching. (default: false) diff --git a/man/mergerfs.1 b/man/mergerfs.1 index 8321cff5..f44e089e 100644 --- a/man/mergerfs.1 +++ b/man/mergerfs.1 @@ -1,7 +1,7 @@ .\"t .\" Automatically generated by Pandoc 1.19.2.4 .\" -.TH "mergerfs" "1" "2020\-06\-28" "mergerfs user manual" "" +.TH "mergerfs" "1" "2020\-07\-14" "mergerfs user manual" "" .hy .SH NAME .PP @@ -131,15 +131,14 @@ Understands \[aq]K\[aq], \[aq]M\[aq], and \[aq]G\[aq] to represent kilobyte, megabyte, and gigabyte respectively. (default: 4G) .IP \[bu] 2 -\f[B]moveonenospc=BOOL\f[]: When enabled if a \f[B]write\f[] fails with -\f[B]ENOSPC\f[] (no space left on device) or \f[B]EDQUOT\f[] (disk quota -exceeded) a scan of all drives will be done looking for the drive with -the most free space which is at least the size of the file plus the -amount which failed to write. -An attempt to move the file to that drive will occur (keeping all +\f[B]moveonenospc=BOOL|POLICY\f[]: When enabled if a \f[B]write\f[] +fails with \f[B]ENOSPC\f[] (no space left on device) or \f[B]EDQUOT\f[] +(disk quota exceeded) the policy selected will run to find a new +location for the file. +An attempt to move the file to that branch will occur (keeping all metadata possible) and if successful the original is unlinked and the write retried. -(default: false) +(default: false, true = mfs) .IP \[bu] 2 \f[B]use_ino\f[]: Causes mergerfs to supply file/directory inodes rather than libfuse. diff --git a/src/config.hpp b/src/config.hpp index 14c64bbb..5c0d1e1d 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -19,6 +19,7 @@ #include "branch.hpp" #include "config_inodecalc.hpp" #include "config_readdir.hpp" +#include "config_moveonenospc.hpp" #include "enum.hpp" #include "errno.hpp" #include "func_category.hpp" @@ -109,7 +110,7 @@ public: ConfigBOOL link_cow; ConfigUINT64 minfreespace; ConfigSTR mount; - ConfigBOOL moveonenospc; + MoveOnENOSPC moveonenospc; ConfigBOOL nullrw; ConfigUINT64 pid; ConfigBOOL posix_acl; diff --git a/src/config_moveonenospc.cpp b/src/config_moveonenospc.cpp new file mode 100644 index 00000000..916726ad --- /dev/null +++ b/src/config_moveonenospc.cpp @@ -0,0 +1,54 @@ +/* + ISC License + + Copyright (c) 2020, 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 "ef.hpp" +#include "from_string.hpp" +#include "config_moveonenospc.hpp" + +int +MoveOnENOSPC::from_string(const std::string &s_) +{ + int rv; + std::string s; + const Policy *tmp; + + rv = str::from(s_,&enabled); + if((rv == 0) && (enabled == true)) + s = "mfs"; + ef(rv != 0) + s = s_; + else + return 0; + + tmp = &Policy::find(s); + if(tmp == Policy::invalid) + return -EINVAL; + + policy = tmp; + enabled = true; + + return 0; +} + +std::string +MoveOnENOSPC::to_string(void) const +{ + if(enabled) + return policy->to_string(); + return "false"; +} diff --git a/src/config_moveonenospc.hpp b/src/config_moveonenospc.hpp new file mode 100644 index 00000000..a7aa4fe1 --- /dev/null +++ b/src/config_moveonenospc.hpp @@ -0,0 +1,44 @@ +/* + ISC License + + Copyright (c) 2020, 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 "policy.hpp" +#include "tofrom_string.hpp" + +#include + +class MoveOnENOSPC : public ToFromString +{ +public: + MoveOnENOSPC(const bool enabled_) + : enabled(enabled_) + { + policy = (enabled ? + &Policy::mfs : + &Policy::invalid); + } + +public: + int from_string(const std::string &s); + std::string to_string() const; + +public: + bool enabled; + const Policy *policy; +}; diff --git a/src/fs.hpp b/src/fs.hpp index f1cfd140..9f122e6d 100644 --- a/src/fs.hpp +++ b/src/fs.hpp @@ -31,11 +31,6 @@ namespace fs const char *fusepath_, vector &paths_); - int findonfs(const vector &basepaths_, - const string &fusepath_, - const int fd_, - string &basepath_); - void realpathize(vector &strs_); int getfl(const int fd_); diff --git a/src/fs_acl.cpp b/src/fs_acl.cpp index f74bbc92..8c20c2b6 100644 --- a/src/fs_acl.cpp +++ b/src/fs_acl.cpp @@ -33,7 +33,7 @@ namespace fs int rv; std::string dirpath; - dirpath = fs::path::dirname(&fullpath_); + dirpath = fs::path::dirname(fullpath_); rv = fs::lgetxattr(dirpath,POSIX_ACL_DEFAULT_XATTR,NULL,0); diff --git a/src/fs_copydata_copy_file_range.cpp b/src/fs_copydata_copy_file_range.cpp index debc1662..83c6b1d4 100644 --- a/src/fs_copydata_copy_file_range.cpp +++ b/src/fs_copydata_copy_file_range.cpp @@ -28,22 +28,24 @@ namespace l uint64_t size_) { int64_t rv; - uint64_t len; + uint64_t nleft; int64_t src_off; int64_t dst_off; src_off = 0; dst_off = 0; - len = size_; + nleft = size_; do { - rv = fs::copy_file_range(src_fd_,&src_off,dst_fd_,&dst_off,len,0); + rv = fs::copy_file_range(src_fd_,&src_off,dst_fd_,&dst_off,nleft,0); + if((rv == -1) && (errno == EINTR)) + continue; if(rv == -1) return -1; - len -= rv; + nleft -= rv; } - while((len > 0) && (rv > 0)); + while(nleft > 0); return size_; } diff --git a/src/fs_copydata_readwrite.cpp b/src/fs_copydata_readwrite.cpp index ccf2fc13..fc8f361f 100644 --- a/src/fs_copydata_readwrite.cpp +++ b/src/fs_copydata_readwrite.cpp @@ -30,26 +30,26 @@ namespace l int writen(const int fd_, const char *buf_, - const size_t count_) + const size_t size_) { + ssize_t rv; size_t nleft; - ssize_t nwritten; - nleft = count_; + nleft = size_; do { - nwritten = fs::write(fd_,buf_,nleft); - if((nwritten == -1) && (errno == EINTR)) + rv = fs::write(fd_,buf_,nleft); + if((rv == -1) && (errno == EINTR)) continue; - if(nwritten == -1) + if(rv == -1) return -1; - nleft -= nwritten; - buf_ += nwritten; + nleft -= rv; + buf_ += rv; } while(nleft > 0); - return count_; + return size_; } static diff --git a/src/fs_file_size.cpp b/src/fs_file_size.cpp new file mode 100644 index 00000000..b757f057 --- /dev/null +++ b/src/fs_file_size.cpp @@ -0,0 +1,37 @@ +/* + ISC License + + Copyright (c) 2020, 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 "fs_base_stat.hpp" + +#include + +namespace fs +{ + int64_t + file_size(const int fd_) + { + int rv; + struct stat st; + + rv = fs::fstat(fd_,&st); + if(rv == -1) + return -1; + + return st.st_size; + } +} diff --git a/src/fs_file_size.hpp b/src/fs_file_size.hpp new file mode 100644 index 00000000..4977663e --- /dev/null +++ b/src/fs_file_size.hpp @@ -0,0 +1,27 @@ +/* + ISC License + + Copyright (c) 2020, 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 + +namespace fs +{ + int64_t + file_size(const int fd); +} diff --git a/src/fs_findonfs.cpp b/src/fs_findonfs.cpp new file mode 100644 index 00000000..250c8492 --- /dev/null +++ b/src/fs_findonfs.cpp @@ -0,0 +1,65 @@ +/* + ISC License + + Copyright (c) 2020, 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_base_stat.hpp" +#include "fs_path.hpp" + +#include + +namespace fs +{ + int + findonfs(const Branches &branches_, + const std::string &fusepath_, + const int fd_, + std::string *basepath_) + { + int rv; + dev_t dev; + struct stat st; + std::string fullpath; + const Branch *branch; + const rwlock::ReadGuard guard(&branches_.lock); + + rv = fs::fstat(fd_,&st); + if(rv == -1) + return -1; + + dev = st.st_dev; + for(size_t i = 0, ei = branches_.size(); i != ei; i++) + { + branch = &branches_[i]; + + fullpath = fs::path::make(branch->path,fusepath_); + + rv = fs::lstat(fullpath,&st); + if(rv == -1) + continue; + + if(st.st_dev != dev) + continue; + + *basepath_ = branch->path; + + return 0; + } + + return (errno=ENOENT,-1); + } +} diff --git a/src/fs_base_mkstemp.hpp b/src/fs_findonfs.hpp similarity index 67% rename from src/fs_base_mkstemp.hpp rename to src/fs_findonfs.hpp index 744794db..3a72fd26 100644 --- a/src/fs_base_mkstemp.hpp +++ b/src/fs_findonfs.hpp @@ -1,7 +1,7 @@ /* ISC License - Copyright (c) 2016, Antonio SJ Musumeci + Copyright (c) 2020, 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 @@ -18,30 +18,15 @@ #pragma once -#include +#include "branch.hpp" -#include -#include +#include namespace fs { - static - inline int - mkstemp(std::string &filepath_) - { - int fd; - char buf[filepath_.size()+8]; - - strcpy(buf,filepath_.c_str()); - strcpy(buf+filepath_.size(),".XXXXXX"); - - fd = ::mkstemp(buf); - if(fd == -1) - return -1; - - filepath_ = buf; - - return fd; - } + findonfs(const Branches &branches, + const std::string &fusepath, + const int fd, + std::string *basepath); } diff --git a/src/fs_has_space.cpp b/src/fs_has_space.cpp new file mode 100644 index 00000000..ba2dd8dc --- /dev/null +++ b/src/fs_has_space.cpp @@ -0,0 +1,41 @@ +/* + ISC License + + Copyright (c) 2020, 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 "fs_base_statvfs.hpp" +#include "statvfs_util.hpp" + +#include + +#include + +namespace fs +{ + bool + has_space(const std::string &str_, + const int64_t size_) + { + int rv; + struct statvfs st; + + rv = fs::statvfs(str_,&st); + if(rv == -1) + return false; + + return (StatVFS::spaceavail(st) > size_); + } +} diff --git a/src/fs_has_space.hpp b/src/fs_has_space.hpp new file mode 100644 index 00000000..ed4c5c79 --- /dev/null +++ b/src/fs_has_space.hpp @@ -0,0 +1,30 @@ +/* + ISC License + + Copyright (c) 2020, 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 + +namespace fs +{ + bool + has_space(const std::string &str, + const int64_t size); +} diff --git a/src/fs_mktemp.cpp b/src/fs_mktemp.cpp index 91a79929..c0e34353 100644 --- a/src/fs_mktemp.cpp +++ b/src/fs_mktemp.cpp @@ -19,13 +19,16 @@ #include "errno.hpp" #include "fs_base_open.hpp" -#include -#include - #include +#include + +#include using std::string; +#define PADLEN 6 +#define MAX_ATTEMPTS 10 + static string generate_tmp_path(const string &base_) @@ -33,8 +36,10 @@ generate_tmp_path(const string &base_) string tmp; tmp = base_; - tmp += '_'; - for(int i = 0; i < 6; i++) + if((tmp.size() + PADLEN + 1) > PATH_MAX) + tmp.resize(tmp.size() - PADLEN - 1); + tmp += '.'; + for(int i = 0; i < PADLEN; i++) tmp += ('A' + (std::rand() % 26)); return tmp; @@ -52,7 +57,7 @@ namespace fs string tmppath; fd = -1; - count = 10; + count = MAX_ATTEMPTS; flags = (flags_ | O_EXCL | O_CREAT); while(count-- > 0) { diff --git a/src/fs_movefile.cpp b/src/fs_movefile.cpp index 39514a3f..4cfdc3bc 100644 --- a/src/fs_movefile.cpp +++ b/src/fs_movefile.cpp @@ -14,81 +14,90 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include -#include -#include -#include - -#include -#include - #include "errno.hpp" #include "fs.hpp" -#include "fs_base_open.hpp" #include "fs_base_close.hpp" -#include "fs_base_mkstemp.hpp" +#include "fs_base_open.hpp" #include "fs_base_rename.hpp" -#include "fs_base_unlink.hpp" #include "fs_base_stat.hpp" +#include "fs_base_unlink.hpp" #include "fs_clonefile.hpp" #include "fs_clonepath.hpp" +#include "fs_file_size.hpp" +#include "fs_findonfs.hpp" +#include "fs_has_space.hpp" +#include "fs_mktemp.hpp" #include "fs_path.hpp" +#include "policy.hpp" +#include "ugid.hpp" + +#include +#include + +#include +#include +#include +#include +#include using std::string; using std::vector; -namespace fs +namespace l { + static int - movefile(const vector &basepaths, - const string &fusepath, - const size_t additional_size, - int &origfd) + movefile(Policy::Func::Create createFunc_, + const Branches &branches_, + const uint64_t minfreepsace_, + const string &fusepath_, + int *origfd_) { int rv; int fdin; int fdout; int fdin_flags; + int64_t fdin_size; string fusedir; string fdin_path; - string fdout_path; string fdout_temp; - struct stat fdin_st; + vector fdout_path; - fdin = origfd; + fdin = *origfd_; - rv = fs::fstat(fdin,&fdin_st); - if(rv == -1) + fdin_flags = fs::getfl(fdin); + if(fdin_flags == -1) return -1; - fdin_flags = fs::getfl(fdin); + rv = fs::findonfs(branches_,fusepath_,fdin,&fdin_path); if(rv == -1) return -1; - rv = fs::findonfs(basepaths,fusepath,fdin,fdin_path); + rv = createFunc_(branches_,fusepath_,minfreepsace_,&fdout_path); if(rv == -1) return -1; - fdin_st.st_size += additional_size; - rv = fs::mfs(basepaths,fdin_st.st_size,fdout_path); - if(rv == -1) + fdin_size = fs::file_size(fdin); + if(fdin_size == -1) return -1; - fusedir = fs::path::dirname(&fusepath); + if(fs::has_space(fdout_path[0],fdin_size) == false) + return (errno=ENOSPC,-1); + + fusedir = fs::path::dirname(fusepath_); - rv = fs::clonepath(fdin_path,fdout_path,fusedir); + rv = fs::clonepath(fdin_path,fdout_path[0],fusedir); if(rv == -1) return -1; - fs::path::append(fdin_path,fusepath); + fs::path::append(fdin_path,fusepath_); fdin = fs::open(fdin_path,O_RDONLY); if(fdin == -1) return -1; - fs::path::append(fdout_path,fusepath); - fdout_temp = fdout_path; - fdout = fs::mkstemp(fdout_temp); + fs::path::append(fdout_path[0],fusepath_); + fdout_temp = fdout_path[0]; + fdout = fs::mktemp(fdout_temp,fdin_flags); if(fdout == -1) return -1; @@ -96,18 +105,14 @@ namespace fs if(rv == -1) goto cleanup; - rv = fs::setfl(fdout,fdin_flags); - if(rv == -1) - goto cleanup; - - rv = fs::rename(fdout_temp,fdout_path); + rv = fs::rename(fdout_temp,fdout_path[0]); if(rv == -1) goto cleanup; // should we care if it fails? fs::unlink(fdin_path); - std::swap(origfd,fdout); + std::swap(*origfd_,fdout); fs::close(fdin); fs::close(fdout); @@ -124,3 +129,28 @@ namespace fs return -1; } } + +namespace fs +{ + int + movefile(const Policy *policy_, + const Branches &basepaths_, + const uint64_t minfreepsace_, + const string &fusepath_, + int *origfd_) + { + return l::movefile(policy_,basepaths_,minfreepsace_,fusepath_,origfd_); + } + + int + movefile_as_root(const Policy *policy_, + const Branches &basepaths_, + const uint64_t minfreepsace_, + const string &fusepath_, + int *origfd_) + { + const ugid::Set ugid(0,0); + + return fs::movefile(policy_,basepaths_,minfreepsace_,fusepath_,origfd_); + } +} diff --git a/src/fs_movefile.hpp b/src/fs_movefile.hpp index 69a8c3ab..cf7489f4 100644 --- a/src/fs_movefile.hpp +++ b/src/fs_movefile.hpp @@ -16,14 +16,24 @@ #pragma once +#include "branch.hpp" +#include "policy.hpp" + #include -#include namespace fs { int - movefile(const std::vector &basepaths, - const std::string &fusepath, - const size_t additional_size, - int &origfd); + movefile(const Policy *policy, + const Branches &branches, + const uint64_t minfreepsace, + const std::string &fusepath, + int *origfd); + + int + movefile_as_root(const Policy *policy, + const Branches &branches, + const uint64_t minfreepsace, + const std::string &fusepath, + int *origfd); } diff --git a/src/fs_path.cpp b/src/fs_path.cpp index fb5a33ca..e14522d0 100644 --- a/src/fs_path.cpp +++ b/src/fs_path.cpp @@ -29,22 +29,22 @@ namespace fs { namespace path { - string + string dirname(const char *path_) { string path(path_); - return fs::path::dirname(&path); + return fs::path::dirname(path); } string - dirname(const string *path_) + dirname(const string &path_) { string rv; string::reverse_iterator i; string::reverse_iterator ei; - rv = *path_; + rv = path_; i = rv.rbegin(); ei = rv.rend(); diff --git a/src/fs_path.hpp b/src/fs_path.hpp index f0895325..0bffb21f 100644 --- a/src/fs_path.hpp +++ b/src/fs_path.hpp @@ -25,8 +25,8 @@ namespace fs { using std::string; - string dirname(const char *path_); - string dirname(const string *path_); + string dirname(const char *path); + string dirname(const string &path); string basename(const string &path); diff --git a/src/fuse_write.cpp b/src/fuse_write.cpp index 0665181c..00bcfefc 100644 --- a/src/fuse_write.cpp +++ b/src/fuse_write.cpp @@ -75,6 +75,32 @@ namespace l return rv; } + static + int + move_and_write(WriteFunc func_, + const char *buf_, + const size_t count_, + const off_t offset_, + FileInfo *fi_, + int err_) + { + int rv; + const Config &config = Config::ro(); + + if(config.moveonenospc.enabled == false) + return err_; + + rv = fs::movefile_as_root(config.moveonenospc.policy, + config.branches, + config.minfreespace, + fi_->fusepath, + &fi_->fd); + if(rv == -1) + return err_; + + return func_(fi_->fd,buf_,count_,offset_); + } + static int write(WriteFunc func_, @@ -90,23 +116,7 @@ namespace l rv = func_(fi->fd,buf_,count_,offset_); if(l::out_of_space(-rv)) - { - const Config &config = Config::ro(); - - if(config.moveonenospc) - { - vector paths; - const ugid::Set ugid(0,0); - - config.branches.to_paths(paths); - - rv = fs::movefile(paths,fi->fusepath,count_,fi->fd); - if(rv == -1) - return -ENOSPC; - - rv = func_(fi->fd,buf_,count_,offset_); - } - } + rv = l::move_and_write(func_,buf_,count_,offset_,fi,rv); return rv; } diff --git a/src/fuse_write_buf.cpp b/src/fuse_write_buf.cpp index 6435a10d..d21d839e 100644 --- a/src/fuse_write_buf.cpp +++ b/src/fuse_write_buf.cpp @@ -19,10 +19,8 @@ #include "fileinfo.hpp" #include "fs_movefile.hpp" #include "fuse_write.hpp" -#include "policy.hpp" -#include "ugid.hpp" -#include +#include "fuse.h" #include #include @@ -63,22 +61,24 @@ namespace l static int - move_and_write_buf(fuse_bufvec *src_, + move_and_write_buf(FileInfo *fi_, + fuse_bufvec *src_, off_t offset_, - FileInfo *fi_) + int err_) { int rv; - uint64_t extra; - vector paths; - const ugid::Set ugid(0,0); const Config &config = Config::ro(); - config.branches.to_paths(paths); + if(config.moveonenospc.enabled == false) + return err_; - extra = fuse_buf_size(src_); - rv = fs::movefile(paths,fi_->fusepath,extra,fi_->fd); + rv = fs::movefile_as_root(config.moveonenospc.policy, + config.branches, + config.minfreespace, + fi_->fusepath, + &fi_->fd); if(rv == -1) - return -ENOSPC; + return err_; return l::write_buf(fi_->fd,src_,offset_); } @@ -96,7 +96,7 @@ namespace FUSE rv = l::write_buf(fi->fd,src_,offset_); if(l::out_of_space(-rv)) - rv = l::move_and_write_buf(src_,offset_,fi); + rv = l::move_and_write_buf(fi,src_,offset_,rv); return rv; } diff --git a/src/statvfs_util.hpp b/src/statvfs_util.hpp index 092a5646..29b02188 100644 --- a/src/statvfs_util.hpp +++ b/src/statvfs_util.hpp @@ -33,7 +33,7 @@ namespace StatVFS static inline - uint64_t + int64_t spaceavail(const struct statvfs &st) { return (st.f_frsize * st.f_bavail); @@ -41,7 +41,7 @@ namespace StatVFS static inline - uint64_t + int64_t spaceused(const struct statvfs &st) { return (st.f_frsize * (st.f_blocks - st.f_bavail));