mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-20 00:17:43 +00:00
Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d436cd231 | ||
|
|
562295be90 | ||
|
|
04844420dc | ||
|
|
9c352ac555 | ||
|
|
5a3184359d | ||
|
|
24f03b04eb | ||
|
|
610c75fa90 | ||
|
|
dbc4774e8e | ||
|
|
73e8ed72cd | ||
|
|
e694585561 | ||
|
|
0b1af2b8ef | ||
|
|
668ac4000a | ||
|
|
767039c492 |
@@ -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`
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -88,6 +88,7 @@ public:
|
||||
ConfigBOOL posix_acl;
|
||||
ReadDir readdir;
|
||||
ConfigBOOL readdirplus;
|
||||
ConfigBOOL readfailover;
|
||||
ConfigBOOL security_capability;
|
||||
SrcMounts srcmounts;
|
||||
StatFS statfs;
|
||||
|
||||
+5
-2
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
};
|
||||
}
|
||||
@@ -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_);
|
||||
|
||||
@@ -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_));
|
||||
}
|
||||
};
|
||||
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user