Compare commits

...
13 Commits
Author SHA1 Message Date
Antonio SJ Musumeci 7d436cd231 readfailover: add new 'readfailover' feature 2020-09-26 19:33:20 -04:00
trapexit 562295be90 Merge pull request #833 from trapexit/wyhash-fix
wyhash: use safety mode 1
2020-09-24 09:03:10 -04:00
Antonio SJ Musumeci 04844420dc wyhash: use safety mode 1
mode 0 is not intended for unaligned buffers
2020-09-24 08:45:34 -04:00
trapexit 9c352ac555 Merge pull request #832 from trapexit/rework-errors
rework some function error handling
2020-09-23 00:26:03 -04:00
Antonio SJ Musumeci 5a3184359d rework some function error handling
chmod, chown, removexattr, setxattr, truncate, utimens:
* if no errors: return 0
* if no successes: return first error
* if file acted on was the same as related search function: return its value
* return 0

rmdir, unlink:
* if no errors: return 0
* return first error
2020-09-23 00:01:25 -04:00
trapexit 24f03b04eb Merge pull request #831 from trapexit/minfreespace-fix
properly return const ref from tofrom string wrapper
2020-09-20 11:18:24 -04:00
Antonio SJ Musumeci 610c75fa90 properly return const ref from tofrom string wrapper 2020-09-19 18:57:13 -04:00
trapexit dbc4774e8e Merge pull request #828 from trapexit/remove-old-issue-template
Delete issue_template.md
2020-09-13 10:30:02 -04:00
trapexit 73e8ed72cd Delete issue_template.md 2020-09-13 10:29:45 -04:00
trapexit e694585561 Merge pull request #827 from trapexit/bug_report
Update bug_report.md
2020-09-13 10:28:34 -04:00
trapexit 0b1af2b8ef Update bug_report.md 2020-09-13 10:28:20 -04:00
trapexit 668ac4000a Merge pull request #825 from trapexit/rv
option_parser: return 0 when requesting help or version
2020-09-10 22:16:03 -04:00
Antonio SJ Musumeci 767039c492 option_parser: return 0 when requesting help or version 2020-09-10 21:58:23 -04:00
34 changed files with 1025 additions and 331 deletions
+8 -2
View File
@@ -8,14 +8,20 @@ assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is. Please do not file bugs for unreleased versions. The master branch is **not** to be considered in a production state.
A clear and concise description of what the bug is. Please do not file bugs for unreleased versions unless you're a tester or sure it's not a work in progress. The master branch is **not** to be considered in a production state.
**To Reproduce**
Steps to reproduce the behavior. List **all** steps to reproduce. All settings.
Steps to reproduce the behavior. List **all** steps to reproduce. **All** settings.
Please simplify the reproduction as much as possible.
- Unless it is dependenat on multiple branches, use a single branch
- Use basic tooling if possible (touch,truncate,rm,rmdir,ln,etc.)
**Expected behavior**
A clear and concise description of what you expected to happen.
**System information:**
- OS, kernel version: `uname -a`
- mergerfs version: `mergerfs -V`
-34
View File
@@ -1,34 +0,0 @@
General description
===================
Expected behavior
=================
Actual behavior
===============
**Precise** steps to reproduce the behavior
===========================================
> Explicitly list **all** steps to reproduce. Preferably create a minimal example of the problem using standard command line tools. The more variables (apps, settings, etc.) that are involved the more difficult it is to debug. Also, **please** be sure to have read all of the README. It contains a lot of information regarding known system and user issues.
System information
==================
Please provide as much of the following information as possible:
* [ ] mergerfs version: `mergerfs -V`
* [ ] mergerfs settings: `cat /etc/fstab` or the command line arguments
* [ ] Linux version: `uname -a`
* [ ] Versions of any additional software being used
* [ ] List of drives, filesystems, & sizes: `df -h`
* [ ] strace of application having problem: `strace -f -o /tmp/app.strace.txt <cmd>` or `strace -f -p <appPID> -o /tmp/app.strace.txt`
* [ ] strace of mergerfs while app tried to do it's thing: `strace -f -p <mergerfsPID> -o /tmp/mergerfs.strace.txt`
+6
View File
@@ -103,6 +103,7 @@ See the mergerfs [wiki for real world deployments](https://github.com/trapexit/m
* **symlinkify=BOOL**: When enabled and a file is not writable and its mtime or ctime is older than **symlinkify_timeout** files will be reported as symlinks to the original files. Please read more below before using. (default: false)
* **symlinkify_timeout=INT**: Time to wait, in seconds, to activate the **symlinkify** behavior. (default: 3600)
* **nullrw=BOOL**: Turns reads and writes into no-ops. The request will succeed but do nothing. Useful for benchmarking mergerfs. (default: false)
* **readfailover=BOOL**: Should a `read` fail search other branches for the same file and use that going forward. (default: false)
* **ignorepponrename=BOOL**: Ignore path preserving on rename. Typically rename and link act differently depending on the policy of `create` (read below). Enabling this will cause rename and link to always use the non-path preserving behavior. This means files, when renamed or linked, will stay on the same drive. (default: false)
* **security_capability=BOOL**: If false return ENOATTR when xattr security.capability is queried. (default: true)
* **xattr=passthrough|noattr|nosys**: Runtime control of xattrs. Default is to passthrough xattr requests. 'noattr' will short circuit as if nothing exists. 'nosys' will respond with ENOSYS as if xattrs are not supported or disabled. (default: passthrough)
@@ -173,6 +174,11 @@ To have the pool mounted at boot or otherwise accessible from related tools use
**NOTE:** for mounting via **fstab** to work you must have **mount.fuse** installed. For Ubuntu/Debian it is included in the **fuse** package.
### readfailover
One usecase of mergerfs is to create a union of mirrored files as a means to provide reliability. Often with networked filesysems such as NFS, sshfs, or rclone. This feature helps with situations where the device or mount of the file currently in use fails. If `read` returns `EIO` or `ENOTCONN` mergerfs will cycle through branches searching for the same relative path. It will `open` and attempt a `read`. Should that succeed the file will be used going forward. Otherwise the original error will be returned. Sometimes when an error occurs the `read` will still succeed but be a "short read." In those cases the kernel will issue a `fstat` to find out the length of the file. As a result this feature also performs a similar search and replacement behavior should `fstat` fail with the same errors.
### inodecalc
Inodes (st_ino) are unique identifiers within a filesystem. Each mounted filesystem has device ID (st_dev) as well and together they can uniquely identify a file on the whole of the system. Entries on the same device with the same inode are in fact references to the same underlying file. It is a many to one relationship between names and an inode. Directories, however, do not have multiple links on most systems due to the complexity they add.
-16
View File
@@ -165,20 +165,6 @@ struct fuse_operations
*/
int (*open) (const char *, struct fuse_file_info *);
/** Read data from an open file
*
* Read should return exactly the number of bytes requested except
* on EOF or error, otherwise the rest of the data will be
* substituted with zeroes. An exception to this is when the
* 'direct_io' mount option is specified, in which case the return
* value of the read system call will reflect the return value of
* this operation.
*
* Changed in version 2.2
*/
int (*read) (char *, size_t, off_t,
struct fuse_file_info *);
/** Write data to an open file
*
* Write should return exactly the number of bytes requested
@@ -791,8 +777,6 @@ int fuse_fs_release(struct fuse_fs *fs,
struct fuse_file_info *fi);
int fuse_fs_open(struct fuse_fs *fs, const char *path,
struct fuse_file_info *fi);
int fuse_fs_read(struct fuse_fs *fs, char *buf, size_t size,
off_t off, struct fuse_file_info *fi);
int fuse_fs_read_buf(struct fuse_fs *fs,
struct fuse_bufvec **bufp, size_t size, off_t off,
struct fuse_file_info *fi);
+30 -66
View File
@@ -1617,77 +1617,41 @@ static void fuse_free_buf(struct fuse_bufvec *buf)
}
}
int fuse_fs_read_buf(struct fuse_fs *fs,
struct fuse_bufvec **bufp, size_t size, off_t off,
struct fuse_file_info *fi)
{
fuse_get_context()->private_data = fs->user_data;
if (fs->op.read || fs->op.read_buf) {
int res;
if (fs->debug)
fprintf(stderr,
"read[%llu] %zu bytes from %llu flags: 0x%x\n",
(unsigned long long) fi->fh,
size, (unsigned long long) off, fi->flags);
if (fs->op.read_buf) {
res = fs->op.read_buf(bufp, size, off, fi);
} else {
struct fuse_bufvec *buf;
void *mem;
buf = malloc(sizeof(struct fuse_bufvec));
if (buf == NULL)
return -ENOMEM;
mem = malloc(size);
if (mem == NULL) {
free(buf);
return -ENOMEM;
}
*buf = FUSE_BUFVEC_INIT(size);
buf->buf[0].mem = mem;
*bufp = buf;
res = fs->op.read(mem, size, off, fi);
if (res >= 0)
buf->buf[0].size = res;
}
if (fs->debug && res >= 0)
fprintf(stderr, " read[%llu] %zu bytes from %llu\n",
(unsigned long long) fi->fh,
fuse_buf_size(*bufp),
(unsigned long long) off);
if (res >= 0 && fuse_buf_size(*bufp) > (int) size)
fprintf(stderr, "fuse: read too many bytes\n");
if (res < 0)
return res;
return 0;
} else {
return -ENOSYS;
}
}
int fuse_fs_read(struct fuse_fs *fs, char *mem, size_t size,
off_t off, struct fuse_file_info *fi)
int
fuse_fs_read_buf(struct fuse_fs *fs_,
struct fuse_bufvec **bufp_,
size_t size_,
off_t off_,
struct fuse_file_info *ffi_)
{
int res;
struct fuse_bufvec *buf = NULL;
res = fuse_fs_read_buf(fs, &buf, size, off, fi);
if (res == 0) {
struct fuse_bufvec dst = FUSE_BUFVEC_INIT(size);
fuse_get_context()->private_data = fs_->user_data;
if(fs_->op.read_buf == NULL)
return -ENOSYS;
dst.buf[0].mem = mem;
res = fuse_buf_copy(&dst, buf, 0);
}
fuse_free_buf(buf);
if(fs_->debug)
fprintf(stderr,
"read[%llu] %zu bytes from %llu flags: 0x%x\n",
(unsigned long long)ffi_->fh,
size_,
(unsigned long long)off_,
ffi_->flags);
return res;
res = fs_->op.read_buf(bufp_,size_,off_,ffi_);
if(fs_->debug && (res >= 0))
fprintf(stderr, " read[%llu] %zu bytes from %llu\n",
(unsigned long long)ffi_->fh,
fuse_buf_size(*bufp_),
(unsigned long long)off_);
if((res >= 0) && (fuse_buf_size(*bufp_) > (int)size_))
fprintf(stderr,"fuse: read too many bytes\n");
if(res < 0)
return res;
return 0;
}
int fuse_fs_write_buf(struct fuse_fs *fs,
+21
View File
@@ -171,6 +171,10 @@ The request will succeed but do nothing.
Useful for benchmarking mergerfs.
(default: false)
.IP \[bu] 2
\f[B]readfailover=BOOL\f[]: Should a \f[C]read\f[] fail search other
branches for the same file and use that going forward.
(default: false)
.IP \[bu] 2
\f[B]ignorepponrename=BOOL\f[]: Ignore path preserving on rename.
Typically rename and link act differently depending on the policy of
\f[C]create\f[] (read below).
@@ -381,6 +385,23 @@ be automatically included.
\f[B]NOTE:\f[] for mounting via \f[B]fstab\f[] to work you must have
\f[B]mount.fuse\f[] installed.
For Ubuntu/Debian it is included in the \f[B]fuse\f[] package.
.SS readfailover
.PP
One usecase of mergerfs is to create a union of mirrored files as a
means to provide reliability.
Often with networked filesysems such as NFS, sshfs, or rclone.
This feature helps with situations where the device or mount of the file
currently in use fails.
If \f[C]read\f[] returns \f[C]EIO\f[] or \f[C]ENOTCONN\f[] mergerfs will
cycle through branches searching for the same relative path.
It will \f[C]open\f[] and attempt a \f[C]read\f[].
Should that succeed the file will be used going forward.
Otherwise the original error will be returned.
Sometimes when an error occurs the \f[C]read\f[] will still succeed but
be a "short read." In those cases the kernel will issue a \f[C]fstat\f[]
to find out the length of the file.
As a result this feature also performs a similar search and replacement
behavior should \f[C]fstat\f[] fail with the same errors.
.SS inodecalc
.PP
Inodes (st_ino) are unique identifiers within a filesystem.
+2
View File
@@ -93,6 +93,7 @@ Config::Config()
posix_acl(false),
readdir(ReadDir::ENUM::POSIX),
readdirplus(false),
readfailover(false),
security_capability(true),
srcmounts(branches),
statfs(StatFS::ENUM::BASE),
@@ -155,6 +156,7 @@ Config::Config()
_map["posix_acl"] = &posix_acl;
// _map["readdir"] = &readdir;
_map["readdirplus"] = &readdirplus;
_map["readfailover"] = &readfailover;
_map["security_capability"] = &security_capability;
_map["srcmounts"] = &srcmounts;
_map["statfs"] = &statfs;
+1
View File
@@ -88,6 +88,7 @@ public:
ConfigBOOL posix_acl;
ReadDir readdir;
ConfigBOOL readdirplus;
ConfigBOOL readfailover;
ConfigBOOL security_capability;
SrcMounts srcmounts;
StatFS statfs;
+5 -2
View File
@@ -24,12 +24,15 @@ class FileInfo : public FH
{
public:
FileInfo(const int fd_,
const char *fusepath_)
const char *fusepath_,
const int flags_)
: FH(fusepath_),
fd(fd_)
fd(fd_),
flags(flags_)
{
}
public:
int fd;
int flags;
};
+45 -14
View File
@@ -18,7 +18,7 @@
#include "errno.hpp"
#include "fs_lchmod.hpp"
#include "fs_path.hpp"
#include "rv.hpp"
#include "policy_rv.hpp"
#include "ugid.hpp"
#include "fuse.h"
@@ -31,57 +31,87 @@
using std::string;
using std::vector;
namespace l
{
static
int
get_error(const PolicyRV &prv_,
const string &basepath_)
{
for(int i = 0, ei = prv_.success.size(); i < ei; i++)
{
if(prv_.success[i].basepath == basepath_)
return prv_.success[i].rv;
}
for(int i = 0, ei = prv_.error.size(); i < ei; i++)
{
if(prv_.error[i].basepath == basepath_)
return prv_.error[i].rv;
}
return 0;
}
static
void
chmod_loop_core(const string &basepath_,
const char *fusepath_,
const mode_t mode_,
const int error_)
PolicyRV *prv_)
{
int rv;
string fullpath;
fullpath = fs::path::make(basepath_,fusepath_);
rv = fs::lchmod(fullpath,mode_);
errno = 0;
fs::lchmod(fullpath,mode_);
return error::calc(rv,error_,errno);
prv_->insert(errno,basepath_);
}
static
int
void
chmod_loop(const vector<string> &basepaths_,
const char *fusepath_,
const mode_t mode_)
const mode_t mode_,
PolicyRV *prv_)
{
int error;
error = -1;
for(size_t i = 0, ei = basepaths_.size(); i != ei; i++)
{
error = l::chmod_loop_core(basepaths_[i],fusepath_,mode_,error);
l::chmod_loop_core(basepaths_[i],fusepath_,mode_,prv_);
}
return -error;
}
static
int
chmod(Policy::Func::Action actionFunc_,
Policy::Func::Search searchFunc_,
const Branches &branches_,
const char *fusepath_,
const mode_t mode_)
{
int rv;
PolicyRV prv;
vector<string> basepaths;
rv = actionFunc_(branches_,fusepath_,&basepaths);
if(rv == -1)
return -errno;
return l::chmod_loop(basepaths,fusepath_,mode_);
l::chmod_loop(basepaths,fusepath_,mode_,&prv);
if(prv.error.empty())
return 0;
if(prv.success.empty())
return prv.error[0].rv;
basepaths.clear();
rv = searchFunc_(branches_,fusepath_,&basepaths);
if(rv == -1)
return -errno;
return l::get_error(prv,basepaths[0]);
}
}
@@ -96,6 +126,7 @@ namespace FUSE
const ugid::Set ugid(fc->uid,fc->gid);
return l::chmod(config.func.chmod.policy,
config.func.getattr.policy,
config.branches,
fusepath_,
mode_);
+45 -14
View File
@@ -18,7 +18,7 @@
#include "errno.hpp"
#include "fs_lchown.hpp"
#include "fs_path.hpp"
#include "rv.hpp"
#include "policy_rv.hpp"
#include "ugid.hpp"
#include <fuse.h>
@@ -29,60 +29,90 @@
using std::string;
using std::vector;
namespace l
{
static
int
get_error(const PolicyRV &prv_,
const string &basepath_)
{
for(int i = 0, ei = prv_.success.size(); i < ei; i++)
{
if(prv_.success[i].basepath == basepath_)
return prv_.success[i].rv;
}
for(int i = 0, ei = prv_.error.size(); i < ei; i++)
{
if(prv_.error[i].basepath == basepath_)
return prv_.error[i].rv;
}
return 0;
}
static
void
chown_loop_core(const string &basepath_,
const char *fusepath_,
const uid_t uid_,
const gid_t gid_,
const int error_)
PolicyRV *prv_)
{
int rv;
string fullpath;
fullpath = fs::path::make(basepath_,fusepath_);
rv = fs::lchown(fullpath,uid_,gid_);
errno = 0;
fs::lchown(fullpath,uid_,gid_);
return error::calc(rv,error_,errno);
prv_->insert(errno,basepath_);
}
static
int
void
chown_loop(const vector<string> &basepaths_,
const char *fusepath_,
const uid_t uid_,
const gid_t gid_)
const gid_t gid_,
PolicyRV *prv_)
{
int error;
error = -1;
for(size_t i = 0, ei = basepaths_.size(); i != ei; i++)
{
error = l::chown_loop_core(basepaths_[i],fusepath_,uid_,gid_,error);
l::chown_loop_core(basepaths_[i],fusepath_,uid_,gid_,prv_);
}
return -error;
}
static
int
chown(Policy::Func::Action actionFunc_,
Policy::Func::Search searchFunc_,
const Branches &branches_,
const char *fusepath_,
const uid_t uid_,
const gid_t gid_)
{
int rv;
PolicyRV prv;
vector<string> basepaths;
rv = actionFunc_(branches_,fusepath_,&basepaths);
if(rv == -1)
return -errno;
return l::chown_loop(basepaths,fusepath_,uid_,gid_);
l::chown_loop(basepaths,fusepath_,uid_,gid_,&prv);
if(prv.error.empty())
return 0;
if(prv.success.empty())
return prv.error[0].rv;
basepaths.clear();
rv = searchFunc_(branches_,fusepath_,&basepaths);
if(rv == -1)
return -errno;
return l::get_error(prv,basepaths[0]);
}
}
@@ -98,6 +128,7 @@ namespace FUSE
const ugid::Set ugid(fc->uid,fc->gid);
return l::chown(config.func.chown.policy,
config.func.getattr.policy,
config.branches,
fusepath_,
uid_,
+1 -1
View File
@@ -118,7 +118,7 @@ namespace l
if(rv == -1)
return -errno;
*fh_ = reinterpret_cast<uint64_t>(new FileInfo(rv,fusepath_));
*fh_ = reinterpret_cast<uint64_t>(new FileInfo(rv,fusepath_,flags_));
return 0;
}
+121 -6
View File
@@ -17,26 +17,141 @@
#include "config.hpp"
#include "errno.hpp"
#include "fileinfo.hpp"
#include "fs_close.hpp"
#include "fs_fstat.hpp"
#include "fs_inode.hpp"
#include "fs_open.hpp"
#include "fs_path.hpp"
#include "fs_read.hpp"
#include "ugid.hpp"
#include <fuse.h>
namespace l
{
static
bool
failoverable_error(const int error_)
{
switch(error_)
{
case EIO:
case ENOTCONN:
return true;
default:
return false;
}
}
static
bool
failoverable_flags(const int flags_)
{
return !(flags_ & (O_CREAT|O_TRUNC));
}
static
void
update_fi_fd(FileInfo *fi_,
const int fd_)
{
int tmp;
tmp = fi_->fd;
fi_->fd = fd_;
fs::close(tmp);
}
static
int
fgetattr(const int fd_,
const std::string &fusepath_,
struct stat *st_)
failover_fstat_loop(FileInfo *fi_,
const BranchVec &branches_,
struct stat *st_,
const int error_)
{
int fd;
int rv;
char buf;
std::string fullpath;
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
{
fullpath = fs::path::make(branches_[i].path,fi_->fusepath);
fd = fs::open(fullpath,fi_->flags);
if(fd == -1)
continue;
rv = fs::pread(fd,&buf,1,0);
if(rv == -1)
{
fs::close(fd);
continue;
}
rv = fs::fstat(fd,st_);
if(rv == -1)
{
fs::close(fd);
continue;
}
l::update_fi_fd(fi_,fd);
return rv;
}
return (errno=error_,-1);
}
static
int
failover_fstat(const Branches &branches_,
FileInfo *fi_,
struct stat *st_,
const int error_)
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::ro();
const ugid::Set ugid(fc->uid,fc->gid);
rwlock::ReadGuard guard(config.branches.lock);
return l::failover_fstat_loop(fi_,config.branches.vec,st_,error_);
}
static
int
maybe_failover_fstat(FileInfo *fi_,
struct stat *st_,
const int error_)
{
const Config &config = Config::ro();
if(config.readfailover == false)
return (errno=error_,-1);
if(l::failoverable_flags(fi_->flags) == false)
return (errno=error_,-1);
if(l::failoverable_error(error_) == false)
return (errno=error_,-1);
return l::failover_fstat(config.branches,fi_,st_,error_);
}
static
int
fgetattr(FileInfo *fi_,
struct stat *st_)
{
int rv;
rv = fs::fstat(fd_,st_);
rv = fs::fstat(fi_->fd,st_);
if(rv == -1)
rv = l::maybe_failover_fstat(fi_,st_,errno);
if(rv == -1)
return -errno;
fs::inode::calc(fusepath_,st_);
fs::inode::calc(fi_->fusepath,st_);
return 0;
}
@@ -53,7 +168,7 @@ namespace FUSE
const Config &config = Config::ro();
FileInfo *fi = reinterpret_cast<FileInfo*>(ffi_->fh);
rv = l::fgetattr(fi->fd,fi->fusepath,st_);
rv = l::fgetattr(fi,st_);
timeout_->entry = ((rv >= 0) ?
config.cache_entry :
+20 -1
View File
@@ -19,7 +19,6 @@
#include "fs_clonepath.hpp"
#include "fs_link.hpp"
#include "fs_path.hpp"
#include "rv.hpp"
#include "ugid.hpp"
#include <fuse.h>
@@ -30,6 +29,26 @@
using std::string;
using std::vector;
namespace error
{
static
inline
int
calc(const int rv_,
const int prev_,
const int cur_)
{
if(rv_ == -1)
{
if(prev_ == 0)
return 0;
return cur_;
}
return 0;
}
}
namespace l
{
static
+20 -1
View File
@@ -20,7 +20,6 @@
#include "fs_clonepath.hpp"
#include "fs_mkdir.hpp"
#include "fs_path.hpp"
#include "rv.hpp"
#include "ugid.hpp"
#include <fuse.h>
@@ -31,6 +30,26 @@
using std::string;
using std::vector;
namespace error
{
static
inline
int
calc(const int rv_,
const int prev_,
const int cur_)
{
if(rv_ == -1)
{
if(prev_ == 0)
return 0;
return cur_;
}
return 0;
}
}
namespace l
{
static
+20 -1
View File
@@ -20,7 +20,6 @@
#include "fs_mknod.hpp"
#include "fs_clonepath.hpp"
#include "fs_path.hpp"
#include "rv.hpp"
#include "ugid.hpp"
#include <fuse.h>
@@ -31,6 +30,26 @@
using std::string;
using std::vector;
namespace error
{
static
inline
int
calc(const int rv_,
const int prev_,
const int cur_)
{
if(rv_ == -1)
{
if(prev_ == 0)
return 0;
return cur_;
}
return 0;
}
}
namespace l
{
static
+1 -1
View File
@@ -173,7 +173,7 @@ namespace l
if(fd == -1)
return -errno;
*fh_ = reinterpret_cast<uint64_t>(new FileInfo(fd,fusepath_));
*fh_ = reinterpret_cast<uint64_t>(new FileInfo(fd,fusepath_,flags_));
return 0;
}
+85 -6
View File
@@ -14,25 +14,101 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "branch.hpp"
#include "config.hpp"
#include "errno.hpp"
#include "fileinfo.hpp"
#include "fs_close.hpp"
#include "fs_open.hpp"
#include "fs_path.hpp"
#include "fs_read.hpp"
#include "ugid.hpp"
#include <fuse.h>
#include <string>
#include <vector>
using std::string;
using std::vector;
namespace l
{
static
bool
can_failover(const int error_,
const int flags_)
{
return (((error_ == EIO) ||
(error_ == ENOTCONN)) &&
!(flags_ & (O_CREAT|O_TRUNC)));
}
static
int
failover_read_loop(FileInfo *fi_,
const BranchVec &branches_,
void *buf_,
const size_t count_,
const off_t offset_,
const int error_)
{
int fd;
int rv;
std::string fullpath;
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
{
fullpath = fs::path::make(branches_[i].path,fi_->fusepath);
fd = fs::open(fullpath,fi_->flags);
if(fd == -1)
continue;
rv = fs::pread(fd,buf_,count_,offset_);
if(rv >= 0)
{
fs::close(fi_->fd);
fi_->fd = fd;
return rv;
}
fs::close(fd);
}
return (errno=error_,-1);
}
static
int
failover_read(FileInfo *fi_,
void *buf_,
const size_t count_,
const off_t offset_,
const int error_)
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::ro();
const ugid::Set ugid(fc->uid,fc->gid);
rwlock::ReadGuard guard(config.branches.lock);
return l::failover_read_loop(fi_,config.branches.vec,buf_,count_,offset_,error_);
}
static
inline
int
read_regular(const int fd_,
read_regular(FileInfo *fi_,
void *buf_,
const size_t count_,
const off_t offset_)
{
int rv;
rv = fs::pread(fd_,buf_,count_,offset_);
rv = fs::pread(fi_->fd,buf_,count_,offset_);
if((rv == -1) && l::can_failover(errno,fi_->flags))
rv = l::failover_read(fi_,buf_,count_,offset_,errno);
if(rv == -1)
return -errno;
if(rv == 0)
@@ -44,14 +120,17 @@ namespace l
static
inline
int
read_direct_io(const int fd_,
read_direct_io(FileInfo *fi_,
void *buf_,
const size_t count_,
const off_t offset_)
{
int rv;
rv = fs::pread(fd_,buf_,count_,offset_);
rv = fs::pread(fi_->fd,buf_,count_,offset_);
if((rv == -1) && l::can_failover(errno,fi_->flags))
rv = l::failover_read(fi_,buf_,count_,offset_,errno);
if(rv == -1)
return -errno;
@@ -72,8 +151,8 @@ namespace FUSE
fi = reinterpret_cast<FileInfo*>(ffi_->fh);
if(ffi_->direct_io)
return l::read_direct_io(fi->fd,buf_,count_,offset_);
return l::read_regular(fi->fd,buf_,count_,offset_);
return l::read_direct_io(fi,buf_,count_,offset_);
return l::read_regular(fi,buf_,count_,offset_);
}
int
+188 -15
View File
@@ -1,5 +1,5 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Copyright (c) 2020, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -14,36 +14,198 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "branch.hpp"
#include "config.hpp"
#include "errno.hpp"
#include "fileinfo.hpp"
#include "fs_close.hpp"
#include "fs_open.hpp"
#include "fs_path.hpp"
#include "fs_read.hpp"
#include "ugid.hpp"
#include <fuse.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
typedef struct fuse_bufvec fuse_bufvec;
namespace l
{
static
int
read_buf(const int fd_,
fuse_bufvec **bufp_,
const size_t size_,
const off_t offset_)
bool
failoverable_error(const int error_)
{
switch(error_)
{
case EIO:
case ENOTCONN:
return true;
default:
return false;
}
}
static
bool
failoverable_flags(const int flags_)
{
return !(flags_ & (O_CREAT|O_TRUNC));
}
static
void
update_fi_fd(FileInfo *fi_,
const int fd_)
{
int tmp;
tmp = fi_->fd;
fi_->fd = fd_;
fs::close(tmp);
}
static
int
failover_read_loop(const BranchVec &branches_,
FileInfo *fi_,
void *buf_,
const size_t count_,
const off_t offset_,
const int error_)
{
int fd;
int rv;
std::string fullpath;
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
{
fullpath = fs::path::make(branches_[i].path,fi_->fusepath);
fd = fs::open(fullpath,fi_->flags);
if(fd == -1)
continue;
rv = fs::pread(fd,buf_,count_,offset_);
if(rv == -1)
{
fs::close(fd);
continue;
}
l::update_fi_fd(fi_,fd);
return rv;
}
return (errno=error_,-1);
}
static
int
failover_read(const Branches &branches_,
FileInfo *fi_,
void *buf_,
const size_t count_,
const off_t offset_,
const int error_)
{
const fuse_context *fc = fuse_get_context();
const ugid::Set ugid(fc->uid,fc->gid);
rwlock::ReadGuard rwlock_guard(branches_.lock);
return l::failover_read_loop(branches_.vec,fi_,buf_,count_,offset_,error_);
}
static
int
maybe_failover_read(FileInfo *fi_,
void *buf_,
const size_t count_,
const off_t offset_,
const int error_)
{
const Config &config = Config::ro();
if(config.readfailover == false)
return (errno=error_,-1);
if(l::failoverable_flags(fi_->flags) == false)
return (errno=error_,-1);
if(l::failoverable_error(error_) == false)
return (errno=error_,-1);
return l::failover_read(config.branches,fi_,buf_,count_,offset_,error_);
}
static
int
read_buf_null(fuse_bufvec **bufp_,
const size_t count_,
const off_t offset_)
{
void *buf;
fuse_bufvec *src;
buf = (void*)calloc(count_,1);
if(buf == NULL)
return -ENOMEM;
src = (fuse_bufvec*)malloc(sizeof(fuse_bufvec));
if(src == NULL)
{
free(buf);
return -ENOMEM;
}
*src = FUSE_BUFVEC_INIT(count_);
src->buf->mem = buf;
src->buf->size = count_;
*bufp_ = src;
return 0;
}
static
int
read_buf(FileInfo *fi_,
fuse_bufvec **bufp_,
const size_t count_,
const off_t offset_)
{
int rv;
void *buf;
fuse_bufvec *src;
buf = (void*)malloc(count_);
if(buf == NULL)
return -ENOMEM;
*src = FUSE_BUFVEC_INIT(size_);
src = (fuse_bufvec*)malloc(sizeof(fuse_bufvec));
if(src == NULL)
{
free(buf);
return -ENOMEM;
}
src->buf->flags = (fuse_buf_flags)(FUSE_BUF_IS_FD|FUSE_BUF_FD_SEEK|FUSE_BUF_FD_RETRY);
src->buf->fd = fd_;
src->buf->pos = offset_;
*src = FUSE_BUFVEC_INIT(count_);
rv = fs::pread(fi_->fd,buf,count_,offset_);
if(rv == -1)
rv = l::maybe_failover_read(fi_,buf,count_,offset_,errno);
if(rv == -1)
{
free(buf);
free(src);
return -errno;
}
src->buf->mem = buf;
src->buf->size = rv;
*bufp_ = src;
@@ -53,17 +215,28 @@ namespace l
namespace FUSE
{
int
read_buf_null(fuse_bufvec **bufp_,
size_t count_,
off_t offset_,
fuse_file_info *ffi_)
{
return l::read_buf_null(bufp_,
count_,
offset_);
}
int
read_buf(fuse_bufvec **bufp_,
size_t size_,
size_t count_,
off_t offset_,
fuse_file_info *ffi_)
{
FileInfo *fi = reinterpret_cast<FileInfo*>(ffi_->fh);
return l::read_buf(fi->fd,
bufp_,
size_,
offset_);
return l::read_buf(fi,
bufp_,
count_,
offset_);
}
}
+6
View File
@@ -27,4 +27,10 @@ namespace FUSE
size_t size,
off_t offset,
fuse_file_info *ffi);
int
read_buf_null(struct fuse_bufvec **buf,
size_t size,
off_t offset,
fuse_file_info *ffi);
}
+45 -15
View File
@@ -18,7 +18,7 @@
#include "errno.hpp"
#include "fs_lremovexattr.hpp"
#include "fs_path.hpp"
#include "rv.hpp"
#include "policy_rv.hpp"
#include "ugid.hpp"
#include <fuse.h>
@@ -29,58 +29,87 @@
using std::string;
using std::vector;
namespace l
{
static
int
get_error(const PolicyRV &prv_,
const string &basepath_)
{
for(int i = 0, ei = prv_.success.size(); i < ei; i++)
{
if(prv_.success[i].basepath == basepath_)
return prv_.success[i].rv;
}
for(int i = 0, ei = prv_.error.size(); i < ei; i++)
{
if(prv_.error[i].basepath == basepath_)
return prv_.error[i].rv;
}
return 0;
}
static
void
removexattr_loop_core(const string &basepath_,
const char *fusepath_,
const char *attrname_,
const int error_)
PolicyRV *prv_)
{
int rv;
string fullpath;
fullpath = fs::path::make(basepath_,fusepath_);
rv = fs::lremovexattr(fullpath,attrname_);
errno = 0;
fs::lremovexattr(fullpath,attrname_);
return error::calc(rv,error_,errno);
prv_->insert(errno,basepath_);
}
static
int
void
removexattr_loop(const vector<string> &basepaths_,
const char *fusepath_,
const char *attrname_)
const char *attrname_,
PolicyRV *prv_)
{
int error;
error = -1;
for(size_t i = 0, ei = basepaths_.size(); i != ei; i++)
{
error = l::removexattr_loop_core(basepaths_[i],fusepath_,attrname_,error);
l::removexattr_loop_core(basepaths_[i],fusepath_,attrname_,prv_);
}
return -error;
}
static
int
removexattr(Policy::Func::Action actionFunc_,
Policy::Func::Search searchFunc_,
const Branches &branches_,
const char *fusepath_,
const char *attrname_)
{
int rv;
PolicyRV prv;
vector<string> basepaths;
rv = actionFunc_(branches_,fusepath_,&basepaths);
if(rv == -1)
return -errno;
return l::removexattr_loop(basepaths,fusepath_,attrname_);
l::removexattr_loop(basepaths,fusepath_,attrname_,&prv);
if(prv.error.empty())
return 0;
if(prv.success.empty())
return prv.error[0].rv;
basepaths.clear();
rv = searchFunc_(branches_,fusepath_,&basepaths);
if(rv == -1)
return -errno;
return l::get_error(prv,basepaths[0]);
}
}
@@ -101,6 +130,7 @@ namespace FUSE
const ugid::Set ugid(fc->uid,fc->gid);
return l::removexattr(config.func.removexattr.policy,
config.func.getxattr.policy,
config.branches,
fusepath_,
attrname_);
+21 -3
View File
@@ -20,17 +20,35 @@
#include "fs_path.hpp"
#include "fs_remove.hpp"
#include "fs_rename.hpp"
#include "rv.hpp"
#include "ugid.hpp"
#include <algorithm>
#include <set>
#include <string>
#include <vector>
using std::string;
using std::vector;
using std::set;
namespace error
{
static
inline
int
calc(const int rv_,
const int prev_,
const int cur_)
{
if(rv_ == -1)
{
if(prev_ == 0)
return 0;
return cur_;
}
return 0;
}
}
static
bool
+18 -3
View File
@@ -18,7 +18,6 @@
#include "errno.hpp"
#include "fs_rmdir.hpp"
#include "fs_path.hpp"
#include "rv.hpp"
#include "ugid.hpp"
#include <fuse.h>
@@ -30,6 +29,23 @@
using std::string;
using std::vector;
namespace error
{
static
int
calc(const int rv_,
const int prev_,
const int cur_)
{
if(prev_ != 0)
return prev_;
if(rv_ == -1)
return cur_;
return 0;
}
}
namespace l
{
static
@@ -48,7 +64,6 @@ namespace l
return error::calc(rv,error_,errno);
}
static
int
rmdir_loop(const vector<string> &basepaths_,
@@ -56,7 +71,7 @@ namespace l
{
int error;
error = -1;
error = 0;
for(size_t i = 0, ei = basepaths_.size(); i != ei; i++)
{
error = l::rmdir_loop_core(basepaths_[i],fusepath_,error);
+94 -64
View File
@@ -21,13 +21,12 @@
#include "fs_path.hpp"
#include "fs_statvfs_cache.hpp"
#include "num.hpp"
#include "rv.hpp"
#include "policy_rv.hpp"
#include "str.hpp"
#include "ugid.hpp"
#include <fuse.h>
#include <sstream>
#include <string>
#include <vector>
@@ -38,8 +37,29 @@ static const char SECURITY_CAPABILITY[] = "security.capability";
using std::string;
using std::vector;
namespace l
{
static
int
get_error(const PolicyRV &prv_,
const string &basepath_)
{
for(int i = 0, ei = prv_.success.size(); i < ei; i++)
{
if(prv_.success[i].basepath == basepath_)
return prv_.success[i].rv;
}
for(int i = 0, ei = prv_.error.size(); i < ei; i++)
{
if(prv_.error[i].basepath == basepath_)
return prv_.error[i].rv;
}
return 0;
}
static
bool
is_attrname_security_capability(const char *attrname_)
@@ -49,117 +69,126 @@ namespace l
static
int
setxattr_controlfile(Config &config,
const string &attrname,
const string &attrval,
const int flags)
setxattr_controlfile(Config &config_,
const string &attrname_,
const string &attrval_,
const int flags_)
{
int rv;
string key;
if(!str::startswith(attrname,"user.mergerfs."))
if(!str::startswith(attrname_,"user.mergerfs."))
return -ENOATTR;
key = &attrname[14];
key = &attrname_[14];
if(config.has_key(key) == false)
if(config_.has_key(key) == false)
return -ENOATTR;
if((flags & XATTR_CREATE) == XATTR_CREATE)
if((flags_ & XATTR_CREATE) == XATTR_CREATE)
return -EEXIST;
rv = config.set(key,attrval);
rv = config_.set(key,attrval_);
if(rv < 0)
return rv;
config.open_cache.clear();
fs::statvfs_cache_timeout(config.cache_statfs);
config_.open_cache.clear();
fs::statvfs_cache_timeout(config_.cache_statfs);
return rv;
}
static
int
setxattr_loop_core(const string &basepath,
const char *fusepath,
const char *attrname,
const char *attrval,
const size_t attrvalsize,
const int flags,
const int error)
void
setxattr_loop_core(const string &basepath_,
const char *fusepath_,
const char *attrname_,
const char *attrval_,
const size_t attrvalsize_,
const int flags_,
PolicyRV *prv_)
{
int rv;
string fullpath;
fullpath = fs::path::make(basepath,fusepath);
fullpath = fs::path::make(basepath_,fusepath_);
rv = fs::lsetxattr(fullpath,attrname,attrval,attrvalsize,flags);
errno = 0;
fs::lsetxattr(fullpath,attrname_,attrval_,attrvalsize_,flags_);
return error::calc(rv,error,errno);
prv_->insert(errno,basepath_);
}
static
int
setxattr_loop(const vector<string> &basepaths,
const char *fusepath,
const char *attrname,
const char *attrval,
const size_t attrvalsize,
const int flags)
void
setxattr_loop(const vector<string> &basepaths_,
const char *fusepath_,
const char *attrname_,
const char *attrval_,
const size_t attrvalsize_,
const int flags_,
PolicyRV *prv_)
{
int error;
error = -1;
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
for(size_t i = 0, ei = basepaths_.size(); i != ei; i++)
{
error = l::setxattr_loop_core(basepaths[i],fusepath,
attrname,attrval,attrvalsize,flags,
error);
l::setxattr_loop_core(basepaths_[i],fusepath_,
attrname_,attrval_,attrvalsize_,
flags_,prv_);
}
return -error;
}
static
int
setxattr(Policy::Func::Action actionFunc,
setxattr(Policy::Func::Action actionFunc_,
Policy::Func::Search searchFunc_,
const Branches &branches_,
const char *fusepath,
const char *attrname,
const char *attrval,
const size_t attrvalsize,
const int flags)
const char *fusepath_,
const char *attrname_,
const char *attrval_,
const size_t attrvalsize_,
const int flags_)
{
int rv;
PolicyRV prv;
vector<string> basepaths;
rv = actionFunc(branches_,fusepath,&basepaths);
rv = actionFunc_(branches_,fusepath_,&basepaths);
if(rv == -1)
return -errno;
return l::setxattr_loop(basepaths,fusepath,attrname,attrval,attrvalsize,flags);
l::setxattr_loop(basepaths,fusepath_,attrname_,attrval_,attrvalsize_,flags_,&prv);
if(prv.error.empty())
return 0;
if(prv.success.empty())
return prv.error[0].rv;
basepaths.clear();
rv = searchFunc_(branches_,fusepath_,&basepaths);
if(rv == -1)
return -errno;
return l::get_error(prv,basepaths[0]);
}
}
namespace FUSE
{
int
setxattr(const char *fusepath,
const char *attrname,
const char *attrval,
size_t attrvalsize,
int flags)
setxattr(const char *fusepath_,
const char *attrname_,
const char *attrval_,
size_t attrvalsize_,
int flags_)
{
Config &config = Config::rw();
if(fusepath == config.controlfile)
if(fusepath_ == config.controlfile)
return l::setxattr_controlfile(config,
attrname,
string(attrval,attrvalsize),
flags);
attrname_,
string(attrval_,attrvalsize_),
flags_);
if((config.security_capability == false) &&
l::is_attrname_security_capability(attrname))
l::is_attrname_security_capability(attrname_))
return -ENOATTR;
if(config.xattr.to_int())
@@ -169,11 +198,12 @@ namespace FUSE
const ugid::Set ugid(fc->uid,fc->gid);
return l::setxattr(config.func.setxattr.policy,
config.func.getxattr.policy,
config.branches,
fusepath,
attrname,
attrval,
attrvalsize,
flags);
fusepath_,
attrname_,
attrval_,
attrvalsize_,
flags_);
}
}
+21 -1
View File
@@ -19,7 +19,6 @@
#include "fs_symlink.hpp"
#include "fs_clonepath.hpp"
#include "fs_path.hpp"
#include "rv.hpp"
#include "ugid.hpp"
#include <fuse.h>
@@ -32,6 +31,27 @@
using std::string;
using std::vector;
namespace error
{
static
inline
int
calc(const int rv_,
const int prev_,
const int cur_)
{
if(rv_ == -1)
{
if(prev_ == 0)
return 0;
return cur_;
}
return 0;
}
}
namespace l
{
static
+46 -15
View File
@@ -16,9 +16,9 @@
#include "config.hpp"
#include "errno.hpp"
#include "fs_truncate.hpp"
#include "fs_path.hpp"
#include "rv.hpp"
#include "fs_truncate.hpp"
#include "policy_rv.hpp"
#include "ugid.hpp"
#include <fuse.h>
@@ -32,57 +32,87 @@
using std::string;
using std::vector;
namespace l
{
static
int
get_error(const PolicyRV &prv_,
const string &basepath_)
{
for(int i = 0, ei = prv_.success.size(); i < ei; i++)
{
if(prv_.success[i].basepath == basepath_)
return prv_.success[i].rv;
}
for(int i = 0, ei = prv_.error.size(); i < ei; i++)
{
if(prv_.error[i].basepath == basepath_)
return prv_.error[i].rv;
}
return 0;
}
static
void
truncate_loop_core(const string &basepath_,
const char *fusepath_,
const off_t size_,
const int error_)
PolicyRV *prv_)
{
int rv;
string fullpath;
fullpath = fs::path::make(basepath_,fusepath_);
rv = fs::truncate(fullpath,size_);
errno = 0;
fs::truncate(fullpath,size_);
return error::calc(rv,error_,errno);
prv_->insert(errno,basepath_);
}
static
int
void
truncate_loop(const vector<string> &basepaths_,
const char *fusepath_,
const off_t size_)
const off_t size_,
PolicyRV *prv_)
{
int error;
error = -1;
for(size_t i = 0, ei = basepaths_.size(); i != ei; i++)
{
error = l::truncate_loop_core(basepaths_[i],fusepath_,size_,error);
l::truncate_loop_core(basepaths_[i],fusepath_,size_,prv_);
}
return -error;
}
static
int
truncate(Policy::Func::Action actionFunc_,
Policy::Func::Search searchFunc_,
const Branches &branches_,
const char *fusepath_,
const off_t size_)
{
int rv;
PolicyRV prv;
vector<string> basepaths;
rv = actionFunc_(branches_,fusepath_,&basepaths);
if(rv == -1)
return -errno;
return l::truncate_loop(basepaths,fusepath_,size_);
l::truncate_loop(basepaths,fusepath_,size_,&prv);
if(prv.error.empty())
return 0;
if(prv.success.empty())
return prv.error[0].rv;
basepaths.clear();
rv = searchFunc_(branches_,fusepath_,&basepaths);
if(rv == -1)
return -errno;
return l::get_error(prv,basepaths[0]);
}
}
@@ -97,6 +127,7 @@ namespace FUSE
const ugid::Set ugid(fc->uid,fc->gid);
return l::truncate(config.func.truncate.policy,
config.func.getattr.policy,
config.branches,
fusepath_,
size_);
+20 -3
View File
@@ -16,9 +16,8 @@
#include "config.hpp"
#include "errno.hpp"
#include "fs_unlink.hpp"
#include "fs_path.hpp"
#include "rv.hpp"
#include "fs_unlink.hpp"
#include "ugid.hpp"
#include <fuse.h>
@@ -31,6 +30,24 @@
using std::string;
using std::vector;
namespace error
{
static
inline
int
calc(const int rv_,
const int prev_,
const int cur_)
{
if(prev_ != 0)
return prev_;
if(rv_ == -1)
return cur_;
return 0;
}
}
namespace l
{
static
@@ -56,7 +73,7 @@ namespace l
{
int error;
error = -1;
error = 0;
for(size_t i = 0, ei = basepaths_.size(); i != ei; i++)
{
error = l::unlink_loop_core(basepaths_[i],fusepath_,error);
+45 -14
View File
@@ -18,7 +18,7 @@
#include "errno.hpp"
#include "fs_lutimens.hpp"
#include "fs_path.hpp"
#include "rv.hpp"
#include "policy_rv.hpp"
#include "ugid.hpp"
#include <fuse.h>
@@ -31,57 +31,87 @@
using std::string;
using std::vector;
namespace l
{
static
int
get_error(const PolicyRV &prv_,
const string &basepath_)
{
for(int i = 0, ei = prv_.success.size(); i < ei; i++)
{
if(prv_.success[i].basepath == basepath_)
return prv_.success[i].rv;
}
for(int i = 0, ei = prv_.error.size(); i < ei; i++)
{
if(prv_.error[i].basepath == basepath_)
return prv_.error[i].rv;
}
return 0;
}
static
void
utimens_loop_core(const string &basepath_,
const char *fusepath_,
const timespec ts_[2],
const int error_)
PolicyRV *prv_)
{
int rv;
string fullpath;
fullpath = fs::path::make(basepath_,fusepath_);
rv = fs::lutimens(fullpath,ts_);
errno = 0;
fs::lutimens(fullpath,ts_);
return error::calc(rv,error_,errno);
prv_->insert(errno,basepath_);
}
static
int
void
utimens_loop(const vector<string> &basepaths_,
const char *fusepath_,
const timespec ts_[2])
const timespec ts_[2],
PolicyRV *prv_)
{
int error;
error = -1;
for(size_t i = 0, ei = basepaths_.size(); i != ei; i++)
{
error = l::utimens_loop_core(basepaths_[i],fusepath_,ts_,error);
l::utimens_loop_core(basepaths_[i],fusepath_,ts_,prv_);
}
return -error;
}
static
int
utimens(Policy::Func::Action actionFunc_,
Policy::Func::Search searchFunc_,
const Branches &branches_,
const char *fusepath_,
const timespec ts_[2])
{
int rv;
PolicyRV prv;
vector<string> basepaths;
rv = actionFunc_(branches_,fusepath_,&basepaths);
if(rv == -1)
return -errno;
return l::utimens_loop(basepaths,fusepath_,ts_);
l::utimens_loop(basepaths,fusepath_,ts_,&prv);
if(prv.error.empty())
return 0;
if(prv.success.empty())
return prv.error[0].rv;
basepaths.clear();
rv = searchFunc_(branches_,fusepath_,&basepaths);
if(rv == -1)
return -errno;
return l::get_error(prv,basepaths[0]);
}
}
@@ -96,6 +126,7 @@ namespace FUSE
const ugid::Set ugid(fc->uid,fc->gid);
return l::utimens(config.func.utimens.policy,
config.func.getattr.policy,
config.branches,
fusepath_,
ts_);
+1 -2
View File
@@ -111,8 +111,7 @@ namespace l
ops_.opendir = FUSE::opendir;
ops_.poll = NULL;
ops_.prepare_hide = FUSE::prepare_hide;
ops_.read = (nullrw_ ? FUSE::read_null : FUSE::read);
ops_.read_buf = (nullrw_ ? NULL : FUSE::read_buf);
ops_.read_buf = (nullrw_ ? FUSE::read_buf_null : FUSE::read_buf);
ops_.readdir = FUSE::readdir;
ops_.readdir_plus = FUSE::readdir_plus;
ops_.readlink = FUSE::readlink;
+23 -18
View File
@@ -1,5 +1,7 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
ISC License
Copyright (c) 2020, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -16,22 +18,25 @@
#pragma once
namespace error
{
static
inline
int
calc(const int rv_,
const int prev_,
const int cur_)
{
if(rv_ == -1)
{
if(prev_ == 0)
return 0;
return cur_;
}
#include <pthread.h>
return 0;
}
namespace mutex
{
class Guard
{
public:
Guard(pthread_mutex_t &lock_)
: _lock(lock_)
{
pthread_mutex_lock(&_lock);
}
~Guard()
{
pthread_mutex_unlock(&_lock);
}
private:
pthread_mutex_t &_lock;
};
}
+9 -7
View File
@@ -129,7 +129,8 @@ namespace l
else
{
l::read_config(data_,is);
if(is.fail())
data_->errs->push_back("failure reading config file");
is.close();
}
}
@@ -426,17 +427,13 @@ option_processor(void *data_,
case MERGERFS_OPT_HELP:
usage();
close(2);
dup(1);
fuse_opt_add_arg(outargs_,"-ho");
break;
exit(0);
case MERGERFS_OPT_VERSION:
std::cout << "mergerfs version: "
<< (MERGERFS_VERSION[0] ? MERGERFS_VERSION : "unknown")
<< std::endl;
fuse_opt_add_arg(outargs_,"--version");
break;
exit(0);
default:
break;
@@ -470,6 +467,11 @@ namespace options
opts,
::option_processor);
if(config_->branches.vec.empty())
errs_->push_back("branches not set");
if(config_->mount->empty())
errs_->push_back("mountpoint not set");
set_default_options(args_);
set_fsname(args_,config_);
set_subtype(args_);
+51
View File
@@ -0,0 +1,51 @@
/*
ISC License
Copyright (c) 2020, Antonio SJ Musumeci <trapexit@spawn.link>
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 <string>
#include <vector>
struct PolicyRV
{
struct RV
{
RV(const int rv_,
const std::string &basepath_)
: rv(rv_),
basepath(basepath_)
{
}
int rv;
std::string basepath;
};
std::vector<RV> success;
std::vector<RV> error;
void
insert(const int err_,
const std::string &basepath_)
{
if(err_ == 0)
success.push_back(RV(err_,basepath_));
else
error.push_back(RV(-err_,basepath_));
}
};
+4 -4
View File
@@ -52,14 +52,14 @@ public:
public:
ToFromWrapper<T>&
operator=(const T data_)
operator=(const T &data_)
{
_data = data_;
return *this;
}
public:
operator T() const
operator const T&() const
{
return _data;
}
@@ -72,7 +72,7 @@ public:
public:
bool
operator==(const T data_) const
operator==(const T &data_) const
{
return (_data == data_);
}
@@ -121,7 +121,7 @@ public:
public:
bool
operator==(const T data_) const
operator==(const T &data_) const
{
return (_data == data_);
}
+2 -2
View File
@@ -3,7 +3,7 @@
#define wyhash_final_version
//defines that change behavior
#ifndef WYHASH_CONDOM
#define WYHASH_CONDOM 0 //0,1,2
#define WYHASH_CONDOM 1 //0: read 8 bytes before and after boudaries, dangerous but fastest. 1: normal valid behavior 2: extra protection against entropy loss (probability=2^-63), aka. "blind multiplication"
#endif
#define WYHASH_32BIT_MUM 0 //faster on 32 bit system
//includes
@@ -129,7 +129,7 @@ static inline void make_secret(uint64_t seed, uint64_t *secret){
for(size_t j=0;j<i;j++)
#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__)
if(__builtin_popcountll(secret[j]^secret[i])!=32){ ok=0; break; }
#elif defined(_MSC_VER)
#elif defined(_MSC_VER) && defined(_M_X64)
if(_mm_popcnt_u64(secret[j]^secret[i])!=32){ ok=0; break; }
#endif
if(!ok)continue;