mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-26 02:48:59 -04:00
rework config management
* Add standard way to do str2val and val2str conversion * Add support for a config file * Add support for reading and writing settings via ioctl
This commit is contained in:
parent
8d989777f8
commit
54c41c4994
90 changed files with 3292 additions and 2619 deletions
10
Makefile
10
Makefile
|
|
@ -40,9 +40,9 @@ USE_XATTR = 1
|
|||
UGID_USE_RWLOCK = 0
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
DEBUG_FLAGS := -O0 -g
|
||||
OPT_FLAGS := -O0 -g
|
||||
else
|
||||
DEBUG_FLAGS :=
|
||||
OPT_FLAGS := -O2
|
||||
endif
|
||||
|
||||
ifeq ($(STATIC),1)
|
||||
|
|
@ -62,8 +62,8 @@ OBJS = $(SRC:src/%.cpp=build/%.o)
|
|||
DEPS = $(SRC:src/%.cpp=build/%.d)
|
||||
MANPAGE = mergerfs.1
|
||||
CXXFLAGS = \
|
||||
-O2 \
|
||||
$(DEBUG_FLAGS) \
|
||||
-std=c++0x \
|
||||
$(OPT_FLAGS) \
|
||||
$(STATIC_FLAGS) \
|
||||
$(LTO_FLAGS) \
|
||||
-Wall \
|
||||
|
|
@ -230,6 +230,6 @@ install-build-pkgs:
|
|||
|
||||
.PHONY: libfuse
|
||||
libfuse:
|
||||
$(MAKE) -C libfuse
|
||||
$(MAKE) DEBUG=$(DEBUG) -C libfuse
|
||||
|
||||
-include $(DEPS)
|
||||
|
|
|
|||
38
README.md
38
README.md
|
|
@ -92,6 +92,8 @@ See the mergerfs [wiki for real world deployments](https://github.com/trapexit/m
|
|||
|
||||
### mount options
|
||||
|
||||
* **config**: Path to a config file. Same arguments as below in key=val format.
|
||||
* **branches**: Colon delimited list of branches.
|
||||
* **allow_other**: A libfuse option which allows users besides the one which ran mergerfs to see the filesystem. This is required for most use-cases.
|
||||
* **minfreespace=SIZE**: The minimum space value used for creation policies. Understands 'K', 'M', and 'G' to represent kilobyte, megabyte, and gigabyte respectively. (default: 4G)
|
||||
* **moveonenospc=BOOL**: When enabled if a **write** fails with **ENOSPC** (no space left on device) or **EDQUOT** (disk quota exceeded) a scan of all drives will be done looking for the drive with the most free space which is at least the size of the file plus the amount which failed to write. An attempt to move the file to that drive will occur (keeping all metadata possible) and if successful the original is unlinked and the write retried. (default: false)
|
||||
|
|
@ -402,7 +404,41 @@ make LTO=1 - build with link time optimization
|
|||
|
||||
# RUNTIME CONFIG
|
||||
|
||||
#### .mergerfs pseudo file ####
|
||||
#### ioctl
|
||||
|
||||
The original runtime config API was via xattr calls. This however became an issue when needing to disable xattr. While slightly less convenient ioctl does not have the same problems and will be the main API going forward.
|
||||
|
||||
The keys are the same as the command line option arguments as well as the config file.
|
||||
|
||||
##### requests / commands
|
||||
|
||||
All commands take a 4096 byte char buffer.
|
||||
|
||||
* read keys: get a nul '\0' delimited list of option keys
|
||||
* _IOWR(0xDF,0,char[4096]) = 0xD000DF00
|
||||
* on success ioctl return value is the total length
|
||||
* read value: get an option value
|
||||
* _IOWR(0xDF,1,char[4096]) = 0xD000DF01
|
||||
* the key is passed in via the char buffer as a nul '\0' terminated string
|
||||
* on success ioctl return value is the total length
|
||||
* write value: set an option value
|
||||
* _IOW(0xDF,2,char[4096]) = 0x5000DF02
|
||||
* the key and value is passed in via the char buffer as a nul '\0' terminated string in the format of `key=value`
|
||||
* on success ioctl return value is 0
|
||||
* file info: get mergerfs metadata info for a file
|
||||
* _IOWR(0xDF,3,char[4096]) = 0xD000DF03
|
||||
* the key is passed in via the char buffer as a nul '\0' terminated string
|
||||
* on success the ioctl return value is the total length
|
||||
* keys:
|
||||
* basepath: the base mount point for the file according to the getattr policy
|
||||
* relpath: the relative path of the file from the mount point
|
||||
* fullpath: the full path of the underlying file according to the getattr policy
|
||||
* allpaths: a NUL '\0' delimited list of full paths to all files found
|
||||
|
||||
|
||||
#### .mergerfs pseudo file (deprecated) ####
|
||||
|
||||
NOTE: this interface will be removed in mergerfs 3.0
|
||||
|
||||
```
|
||||
<mountpoint>/.mergerfs
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
VERSION = 2.9.7-mergerfs_2.29.0
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
DEBUG_FLAGS := -O0 -g
|
||||
OPT_FLAGS := -O0 -g
|
||||
else
|
||||
DEBUG_FLAGS :=
|
||||
OPT_FLAGS := -O2
|
||||
endif
|
||||
|
||||
DESTDIR =
|
||||
|
|
@ -39,8 +39,7 @@ OBJS = $(SRC:lib/%.c=build/%.o)
|
|||
DEPS = $(SRC:lib/%.c=build/%.d)
|
||||
|
||||
CFLAGS = \
|
||||
-O2 \
|
||||
$(DEBUG_FLAGS) \
|
||||
$(OPT_FLAGS) \
|
||||
-Wall \
|
||||
-pipe \
|
||||
-MMD
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ struct fuse_operations {
|
|||
* ignored. The 'st_ino' field is ignored except if the 'use_ino'
|
||||
* mount option is given.
|
||||
*/
|
||||
int (*getattr) (const char *, struct stat *);
|
||||
int (*getattr) (const char *, struct stat *, fuse_timeouts_t *);
|
||||
|
||||
/** Read the target of a symbolic link
|
||||
*
|
||||
|
|
@ -390,7 +390,7 @@ struct fuse_operations {
|
|||
*
|
||||
* Introduced in version 2.5
|
||||
*/
|
||||
int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *);
|
||||
int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *, fuse_timeouts_t *);
|
||||
|
||||
/**
|
||||
* Perform POSIX file locking operation
|
||||
|
|
@ -504,7 +504,7 @@ struct fuse_operations {
|
|||
* Introduced in version 2.8
|
||||
*/
|
||||
int (*ioctl) (const char *fusepath,
|
||||
int cmd,
|
||||
unsigned long cmd,
|
||||
void *arg,
|
||||
struct fuse_file_info *ffi,
|
||||
unsigned int flags,
|
||||
|
|
@ -853,9 +853,17 @@ struct fuse_fs;
|
|||
* fuse_fs_releasedir and fuse_fs_statfs, which return 0.
|
||||
*/
|
||||
|
||||
int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf);
|
||||
int fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf,
|
||||
struct fuse_file_info *fi);
|
||||
int fuse_fs_getattr(struct fuse_fs *fs,
|
||||
const char *path,
|
||||
struct stat *buf,
|
||||
fuse_timeouts_t *timeout);
|
||||
|
||||
int fuse_fs_fgetattr(struct fuse_fs *fs,
|
||||
const char *path,
|
||||
struct stat *buf,
|
||||
struct fuse_file_info *fi,
|
||||
fuse_timeouts_t *timeout);
|
||||
|
||||
int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
|
||||
const char *newpath);
|
||||
int fuse_fs_unlink(struct fuse_fs *fs, const char *path);
|
||||
|
|
@ -920,7 +928,7 @@ int fuse_fs_removexattr(struct fuse_fs *fs, const char *path,
|
|||
const char *name);
|
||||
int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
|
||||
uint64_t *idx);
|
||||
int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd, void *arg,
|
||||
int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, unsigned long cmd, void *arg,
|
||||
struct fuse_file_info *fi, unsigned int flags,
|
||||
void *data, uint32_t *out_bufsz);
|
||||
int fuse_fs_poll(struct fuse_fs *fs, const char *path,
|
||||
|
|
|
|||
|
|
@ -40,6 +40,13 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct fuse_timeouts_s fuse_timeouts_t;
|
||||
struct fuse_timeouts_s
|
||||
{
|
||||
uint64_t entry;
|
||||
uint64_t attr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Information about open files
|
||||
*
|
||||
|
|
@ -83,9 +90,6 @@ fuse_file_info
|
|||
|
||||
uint32_t auto_cache : 1;
|
||||
|
||||
/** Padding. Do not use*/
|
||||
uint32_t padding : 24;
|
||||
|
||||
/** File handle. May be filled in by filesystem in open().
|
||||
Available in all other file operations */
|
||||
uint64_t fh;
|
||||
|
|
|
|||
|
|
@ -101,11 +101,7 @@ struct fuse_entry_param {
|
|||
*/
|
||||
struct stat attr;
|
||||
|
||||
/** Validity timeout (in seconds) for the attributes */
|
||||
double attr_timeout;
|
||||
|
||||
/** Validity timeout (in seconds) for the name */
|
||||
double entry_timeout;
|
||||
fuse_timeouts_t timeout;
|
||||
};
|
||||
|
||||
/** Additional context associated with requests */
|
||||
|
|
@ -882,7 +878,7 @@ struct fuse_lowlevel_ops {
|
|||
* @param in_bufsz number of fetched bytes
|
||||
* @param out_bufsz maximum size of output data
|
||||
*/
|
||||
void (*ioctl) (fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
|
||||
void (*ioctl) (fuse_req_t req, fuse_ino_t ino, unsigned long cmd, void *arg,
|
||||
struct fuse_file_info *fi, unsigned flags,
|
||||
const void *in_buf, uint32_t in_bufsz, uint32_t out_bufsz);
|
||||
|
||||
|
|
@ -1136,8 +1132,9 @@ int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
|
|||
* @param attr_timeout validity timeout (in seconds) for the attributes
|
||||
* @return zero for success, -errno for failure to send reply
|
||||
*/
|
||||
int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
|
||||
double attr_timeout);
|
||||
int fuse_reply_attr(fuse_req_t req,
|
||||
const struct stat *attr,
|
||||
const uint64_t timeout);
|
||||
|
||||
/**
|
||||
* Reply with the contents of a symbolic link
|
||||
|
|
|
|||
|
|
@ -58,9 +58,6 @@ struct fuse_config {
|
|||
unsigned int uid;
|
||||
unsigned int gid;
|
||||
unsigned int umask;
|
||||
double entry_timeout;
|
||||
double negative_timeout;
|
||||
double attr_timeout;
|
||||
int remember;
|
||||
int nopath;
|
||||
int debug;
|
||||
|
|
@ -1392,8 +1389,7 @@ static int fuse_compat_open(struct fuse_fs *fs, const char *path,
|
|||
else if (fs->compat == 22) {
|
||||
struct fuse_file_info_compat tmp;
|
||||
memcpy(&tmp, fi, sizeof(tmp));
|
||||
err = ((struct fuse_operations_compat22 *) &fs->op)->open(path,
|
||||
&tmp);
|
||||
err = ((struct fuse_operations_compat22 *) &fs->op)->open(path,&tmp);
|
||||
memcpy(fi, &tmp, sizeof(tmp));
|
||||
fi->fh = tmp.fh;
|
||||
} else
|
||||
|
|
@ -1504,37 +1500,49 @@ static inline int fuse_compat_statfs(struct fuse_fs *fs, const char *path,
|
|||
|
||||
#endif /* __FreeBSD__ || __NetBSD__ */
|
||||
|
||||
int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf)
|
||||
int
|
||||
fuse_fs_getattr(struct fuse_fs *fs,
|
||||
const char *path,
|
||||
struct stat *buf,
|
||||
fuse_timeouts_t *timeout)
|
||||
{
|
||||
fuse_get_context()->private_data = fs->user_data;
|
||||
if (fs->op.getattr) {
|
||||
if (fs->debug)
|
||||
fprintf(stderr, "getattr %s\n", path);
|
||||
if(fs->op.getattr == NULL)
|
||||
return -ENOSYS;
|
||||
|
||||
return fs->op.getattr(path, buf);
|
||||
} else {
|
||||
return -ENOSYS;
|
||||
}
|
||||
if(fs->debug)
|
||||
fprintf(stderr,"getattr %s\n",path);
|
||||
|
||||
fuse_get_context()->private_data = fs->user_data;
|
||||
|
||||
return fs->op.getattr(path,buf,timeout);
|
||||
}
|
||||
|
||||
int fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf,
|
||||
struct fuse_file_info *fi)
|
||||
int
|
||||
fuse_fs_fgetattr(struct fuse_fs *fs,
|
||||
const char *path,
|
||||
struct stat *buf,
|
||||
struct fuse_file_info *fi,
|
||||
fuse_timeouts_t *timeout)
|
||||
{
|
||||
fuse_get_context()->private_data = fs->user_data;
|
||||
if (fs->op.fgetattr) {
|
||||
if (fs->debug)
|
||||
fprintf(stderr, "fgetattr[%llu] %s\n",
|
||||
(unsigned long long) fi->fh, path);
|
||||
fuse_get_context()->private_data = fs->user_data;
|
||||
if(fs->op.fgetattr)
|
||||
{
|
||||
if(fs->debug)
|
||||
fprintf(stderr,"fgetattr[%llu] %s\n",(unsigned long long)fi->fh,path);
|
||||
|
||||
return fs->op.fgetattr(path, buf, fi);
|
||||
} else if (path && fs->op.getattr) {
|
||||
if (fs->debug)
|
||||
fprintf(stderr, "getattr %s\n", path);
|
||||
return fs->op.fgetattr(path,buf,fi,timeout);
|
||||
}
|
||||
else if(path && fs->op.getattr)
|
||||
{
|
||||
if(fs->debug)
|
||||
fprintf(stderr,"getattr %s\n",path);
|
||||
|
||||
return fs->op.getattr(path, buf);
|
||||
} else {
|
||||
return -ENOSYS;
|
||||
}
|
||||
return fs->op.getattr(path,buf,timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -2254,14 +2262,14 @@ int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name)
|
|||
}
|
||||
}
|
||||
|
||||
int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd, void *arg,
|
||||
int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, unsigned long cmd, void *arg,
|
||||
struct fuse_file_info *fi, unsigned int flags,
|
||||
void *data, uint32_t *out_size)
|
||||
{
|
||||
fuse_get_context()->private_data = fs->user_data;
|
||||
if (fs->op.ioctl) {
|
||||
if (fs->debug)
|
||||
fprintf(stderr, "ioctl[%llu] 0x%x flags: 0x%x\n",
|
||||
fprintf(stderr, "ioctl[%llu] 0x%lx flags: 0x%x\n",
|
||||
(unsigned long long) fi->fh, cmd, flags);
|
||||
|
||||
return fs->op.ioctl(path, cmd, arg, fi, flags, data, out_size);
|
||||
|
|
@ -2377,41 +2385,53 @@ update_stat(struct node *node_,
|
|||
*stold = *stnew_;
|
||||
}
|
||||
|
||||
static int lookup_path(struct fuse *f, fuse_ino_t nodeid,
|
||||
const char *name, const char *path,
|
||||
struct fuse_entry_param *e, struct fuse_file_info *fi)
|
||||
static
|
||||
int
|
||||
lookup_path(struct fuse *f,
|
||||
fuse_ino_t nodeid,
|
||||
const char *name,
|
||||
const char *path,
|
||||
struct fuse_entry_param *e,
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
int res;
|
||||
int res;
|
||||
|
||||
memset(e, 0, sizeof(struct fuse_entry_param));
|
||||
if (fi)
|
||||
res = fuse_fs_fgetattr(f->fs, path, &e->attr, fi);
|
||||
else
|
||||
res = fuse_fs_getattr(f->fs, path, &e->attr);
|
||||
if (res == 0) {
|
||||
struct node *node;
|
||||
memset(e,0,sizeof(struct fuse_entry_param));
|
||||
|
||||
node = find_node(f, nodeid, name);
|
||||
if (node == NULL)
|
||||
res = -ENOMEM;
|
||||
else {
|
||||
e->ino = node->nodeid;
|
||||
e->generation = node->generation;
|
||||
e->entry_timeout = f->conf.entry_timeout;
|
||||
e->attr_timeout = f->conf.attr_timeout;
|
||||
pthread_mutex_lock(&f->lock);
|
||||
update_stat(node, &e->attr);
|
||||
pthread_mutex_unlock(&f->lock);
|
||||
set_stat(f, e->ino, &e->attr);
|
||||
if(f->conf.debug)
|
||||
fprintf(stderr,
|
||||
" NODEID: %llu\n"
|
||||
" GEN: %llu\n",
|
||||
(unsigned long long)e->ino,
|
||||
(unsigned long long)e->generation);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
if(fi)
|
||||
res = fuse_fs_fgetattr(f->fs,path,&e->attr,fi,&e->timeout);
|
||||
else
|
||||
res = fuse_fs_getattr(f->fs,path,&e->attr,&e->timeout);
|
||||
|
||||
if(res == 0)
|
||||
{
|
||||
struct node *node;
|
||||
|
||||
node = find_node(f,nodeid,name);
|
||||
if(node == NULL)
|
||||
{
|
||||
res = -ENOMEM;
|
||||
}
|
||||
else
|
||||
{
|
||||
e->ino = node->nodeid;
|
||||
e->generation = node->generation;
|
||||
|
||||
pthread_mutex_lock(&f->lock);
|
||||
update_stat(node,&e->attr);
|
||||
pthread_mutex_unlock(&f->lock);
|
||||
|
||||
set_stat(f,e->ino,&e->attr);
|
||||
if(f->conf.debug)
|
||||
fprintf(stderr,
|
||||
" NODEID: %llu\n"
|
||||
" GEN: %llu\n",
|
||||
(unsigned long long)e->ino,
|
||||
(unsigned long long)e->generation);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct fuse_context_i *fuse_get_context_internal(void)
|
||||
|
|
@ -2545,61 +2565,63 @@ static void fuse_lib_destroy(void *data)
|
|||
f->fs = NULL;
|
||||
}
|
||||
|
||||
static void fuse_lib_lookup(fuse_req_t req, fuse_ino_t parent,
|
||||
const char *name)
|
||||
static
|
||||
void
|
||||
fuse_lib_lookup(fuse_req_t req,
|
||||
fuse_ino_t parent,
|
||||
const char *name)
|
||||
{
|
||||
struct fuse *f = req_fuse_prepare(req);
|
||||
struct fuse_entry_param e;
|
||||
char *path;
|
||||
int err;
|
||||
struct node *dot = NULL;
|
||||
struct fuse *f = req_fuse_prepare(req);
|
||||
struct fuse_entry_param e;
|
||||
char *path;
|
||||
int err;
|
||||
struct node *dot = NULL;
|
||||
|
||||
if (name[0] == '.') {
|
||||
int len = strlen(name);
|
||||
if (name[0] == '.') {
|
||||
int len = strlen(name);
|
||||
|
||||
if (len == 1 || (name[1] == '.' && len == 2)) {
|
||||
pthread_mutex_lock(&f->lock);
|
||||
if (len == 1) {
|
||||
if (f->conf.debug)
|
||||
fprintf(stderr, "LOOKUP-DOT\n");
|
||||
dot = get_node_nocheck(f, parent);
|
||||
if (dot == NULL) {
|
||||
pthread_mutex_unlock(&f->lock);
|
||||
reply_entry(req, &e, -ESTALE);
|
||||
return;
|
||||
}
|
||||
dot->refctr++;
|
||||
} else {
|
||||
if (f->conf.debug)
|
||||
fprintf(stderr, "LOOKUP-DOTDOT\n");
|
||||
parent = get_node(f, parent)->parent->nodeid;
|
||||
}
|
||||
pthread_mutex_unlock(&f->lock);
|
||||
name = NULL;
|
||||
}
|
||||
}
|
||||
if (len == 1 || (name[1] == '.' && len == 2)) {
|
||||
pthread_mutex_lock(&f->lock);
|
||||
if (len == 1) {
|
||||
if (f->conf.debug)
|
||||
fprintf(stderr, "LOOKUP-DOT\n");
|
||||
dot = get_node_nocheck(f, parent);
|
||||
if (dot == NULL) {
|
||||
pthread_mutex_unlock(&f->lock);
|
||||
reply_entry(req, &e, -ESTALE);
|
||||
return;
|
||||
}
|
||||
dot->refctr++;
|
||||
} else {
|
||||
if (f->conf.debug)
|
||||
fprintf(stderr, "LOOKUP-DOTDOT\n");
|
||||
parent = get_node(f, parent)->parent->nodeid;
|
||||
}
|
||||
pthread_mutex_unlock(&f->lock);
|
||||
name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
err = get_path_name(f, parent, name, &path);
|
||||
if (!err) {
|
||||
struct fuse_intr_data d;
|
||||
if (f->conf.debug)
|
||||
fprintf(stderr, "LOOKUP %s\n", path);
|
||||
fuse_prepare_interrupt(f, req, &d);
|
||||
err = lookup_path(f, parent, name, path, &e, NULL);
|
||||
if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
|
||||
e.ino = 0;
|
||||
e.entry_timeout = f->conf.negative_timeout;
|
||||
err = 0;
|
||||
}
|
||||
fuse_finish_interrupt(f, req, &d);
|
||||
free_path(f, parent, path);
|
||||
}
|
||||
if (dot) {
|
||||
pthread_mutex_lock(&f->lock);
|
||||
unref_node(f, dot);
|
||||
pthread_mutex_unlock(&f->lock);
|
||||
}
|
||||
reply_entry(req, &e, err);
|
||||
err = get_path_name(f, parent, name, &path);
|
||||
if (!err) {
|
||||
struct fuse_intr_data d;
|
||||
if (f->conf.debug)
|
||||
fprintf(stderr, "LOOKUP %s\n", path);
|
||||
fuse_prepare_interrupt(f, req, &d);
|
||||
err = lookup_path(f, parent, name, path, &e, NULL);
|
||||
if (err == -ENOENT) {
|
||||
e.ino = 0;
|
||||
err = 0;
|
||||
}
|
||||
fuse_finish_interrupt(f, req, &d);
|
||||
free_path(f, parent, path);
|
||||
}
|
||||
if (dot) {
|
||||
pthread_mutex_lock(&f->lock);
|
||||
unref_node(f, dot);
|
||||
pthread_mutex_unlock(&f->lock);
|
||||
}
|
||||
reply_entry(req, &e, err);
|
||||
}
|
||||
|
||||
static
|
||||
|
|
@ -2639,56 +2661,69 @@ static void fuse_lib_forget_multi(fuse_req_t req, size_t count,
|
|||
}
|
||||
|
||||
|
||||
static void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino,
|
||||
struct fuse_file_info *fi)
|
||||
static
|
||||
void
|
||||
fuse_lib_getattr(fuse_req_t req,
|
||||
fuse_ino_t ino,
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
struct fuse *f = req_fuse_prepare(req);
|
||||
struct stat buf;
|
||||
char *path;
|
||||
int err;
|
||||
struct node *node;
|
||||
struct fuse_file_info ffi = {0};
|
||||
|
||||
if(fi == NULL)
|
||||
{
|
||||
pthread_mutex_lock(&f->lock);
|
||||
node = get_node(f,ino);
|
||||
if(node->is_hidden)
|
||||
{
|
||||
fi = &ffi;
|
||||
fi->fh = node->hidden_fh;
|
||||
}
|
||||
pthread_mutex_unlock(&f->lock);
|
||||
}
|
||||
int err;
|
||||
char *path;
|
||||
struct fuse *f;
|
||||
struct stat buf;
|
||||
struct node *node;
|
||||
fuse_timeouts_t timeout;
|
||||
struct fuse_file_info ffi = {0};
|
||||
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
f = req_fuse_prepare(req);
|
||||
if(fi == NULL)
|
||||
{
|
||||
pthread_mutex_lock(&f->lock);
|
||||
node = get_node(f,ino);
|
||||
if(node->is_hidden)
|
||||
{
|
||||
fi = &ffi;
|
||||
fi->fh = node->hidden_fh;
|
||||
}
|
||||
pthread_mutex_unlock(&f->lock);
|
||||
}
|
||||
|
||||
path = NULL;
|
||||
err = (((fi == NULL) || (f->fs->op.fgetattr == NULL)) ?
|
||||
get_path(f,ino,&path) :
|
||||
get_path_nullok(f,ino,&path));
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
|
||||
if (!err) {
|
||||
struct fuse_intr_data d;
|
||||
fuse_prepare_interrupt(f, req, &d);
|
||||
path = NULL;
|
||||
err = (((fi == NULL) || (f->fs->op.fgetattr == NULL)) ?
|
||||
get_path(f,ino,&path) :
|
||||
get_path_nullok(f,ino,&path));
|
||||
|
||||
err = ((fi == NULL) ?
|
||||
fuse_fs_getattr(f->fs,path,&buf) :
|
||||
fuse_fs_fgetattr(f->fs,path,&buf,fi));
|
||||
if(!err)
|
||||
{
|
||||
struct fuse_intr_data d;
|
||||
|
||||
fuse_finish_interrupt(f, req, &d);
|
||||
free_path(f, ino, path);
|
||||
}
|
||||
fuse_prepare_interrupt(f,req,&d);
|
||||
|
||||
if (!err) {
|
||||
pthread_mutex_lock(&f->lock);
|
||||
node = get_node(f, ino);
|
||||
update_stat(node, &buf);
|
||||
pthread_mutex_unlock(&f->lock);
|
||||
set_stat(f, ino, &buf);
|
||||
fuse_reply_attr(req, &buf, f->conf.attr_timeout);
|
||||
} else
|
||||
reply_err(req, err);
|
||||
err = ((fi == NULL) ?
|
||||
fuse_fs_getattr(f->fs,path,&buf,&timeout) :
|
||||
fuse_fs_fgetattr(f->fs,path,&buf,fi,&timeout));
|
||||
|
||||
fuse_finish_interrupt(f,req,&d);
|
||||
|
||||
free_path(f,ino,path);
|
||||
}
|
||||
|
||||
if(!err)
|
||||
{
|
||||
pthread_mutex_lock(&f->lock);
|
||||
node = get_node(f,ino);
|
||||
update_stat(node,&buf);
|
||||
pthread_mutex_unlock(&f->lock);
|
||||
set_stat(f,ino,&buf);
|
||||
fuse_reply_attr(req,&buf,timeout.attr);
|
||||
}
|
||||
else
|
||||
{
|
||||
reply_err(req, err);
|
||||
}
|
||||
}
|
||||
|
||||
int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode)
|
||||
|
|
@ -2715,10 +2750,10 @@ fuse_fs_fchmod(struct fuse_fs *fs_,
|
|||
|
||||
static
|
||||
void
|
||||
fuse_lib_setattr(fuse_req_t req,
|
||||
fuse_ino_t ino,
|
||||
struct stat *attr,
|
||||
int valid,
|
||||
fuse_lib_setattr(fuse_req_t req,
|
||||
fuse_ino_t ino,
|
||||
struct stat *attr,
|
||||
int valid,
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
struct fuse *f = req_fuse_prepare(req);
|
||||
|
|
@ -2726,6 +2761,7 @@ fuse_lib_setattr(fuse_req_t req,
|
|||
char *path;
|
||||
int err;
|
||||
struct node *node;
|
||||
fuse_timeouts_t timeout;
|
||||
struct fuse_file_info ffi = {0};
|
||||
|
||||
if(fi == NULL)
|
||||
|
|
@ -2812,22 +2848,23 @@ fuse_lib_setattr(fuse_req_t req,
|
|||
fuse_fs_futimens(f->fs,fi,tv));
|
||||
}
|
||||
|
||||
if(!err)
|
||||
if (!err)
|
||||
err = ((fi == NULL) ?
|
||||
fuse_fs_getattr(f->fs,path,&buf) :
|
||||
fuse_fs_fgetattr(f->fs,path,&buf,fi));
|
||||
fuse_fs_getattr(f->fs,path,&buf,&timeout) :
|
||||
fuse_fs_fgetattr(f->fs,path,&buf,fi,&timeout));
|
||||
|
||||
fuse_finish_interrupt(f,req,&d);
|
||||
free_path(f,ino,path);
|
||||
}
|
||||
|
||||
|
||||
if(!err)
|
||||
{
|
||||
pthread_mutex_lock(&f->lock);
|
||||
update_stat(get_node(f,ino),&buf);
|
||||
pthread_mutex_unlock(&f->lock);
|
||||
set_stat(f,ino,&buf);
|
||||
fuse_reply_attr(req,&buf,f->conf.attr_timeout);
|
||||
fuse_reply_attr(req,&buf,timeout.attr);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -3191,6 +3228,7 @@ open_auto_cache(struct fuse *f,
|
|||
struct fuse_file_info *fi)
|
||||
{
|
||||
struct node *node;
|
||||
fuse_timeouts_t timeout;
|
||||
|
||||
pthread_mutex_lock(&f->lock);
|
||||
|
||||
|
|
@ -3201,7 +3239,7 @@ open_auto_cache(struct fuse *f,
|
|||
struct stat stbuf;
|
||||
|
||||
pthread_mutex_unlock(&f->lock);
|
||||
err = fuse_fs_fgetattr(f->fs,path,&stbuf,fi);
|
||||
err = fuse_fs_fgetattr(f->fs,path,&stbuf,fi,&timeout);
|
||||
pthread_mutex_lock(&f->lock);
|
||||
|
||||
if(!err)
|
||||
|
|
@ -4078,7 +4116,7 @@ static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
|
|||
reply_err(req, err);
|
||||
}
|
||||
|
||||
static void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
|
||||
static void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, unsigned long cmd, void *arg,
|
||||
struct fuse_file_info *llfi, unsigned int flags,
|
||||
const void *in_buf, uint32_t in_bufsz,
|
||||
uint32_t out_bufsz_)
|
||||
|
|
@ -4228,7 +4266,7 @@ int fuse_clean_cache(struct fuse *f)
|
|||
static struct fuse_lowlevel_ops fuse_path_ops = {
|
||||
.init = fuse_lib_init,
|
||||
.destroy = fuse_lib_destroy,
|
||||
.lookup = fuse_lib_lookup,
|
||||
.lookup = fuse_lib_lookup,
|
||||
.forget = fuse_lib_forget,
|
||||
.forget_multi = fuse_lib_forget_multi,
|
||||
.getattr = fuse_lib_getattr,
|
||||
|
|
@ -4469,9 +4507,6 @@ static const struct fuse_opt fuse_lib_opts[] = {
|
|||
FUSE_LIB_OPT("uid=%d", uid, 0),
|
||||
FUSE_LIB_OPT("gid=", set_gid, 1),
|
||||
FUSE_LIB_OPT("gid=%d", gid, 0),
|
||||
FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
|
||||
FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
|
||||
FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
|
||||
FUSE_LIB_OPT("noforget", remember, -1),
|
||||
FUSE_LIB_OPT("remember=%u", remember, 0),
|
||||
FUSE_LIB_OPT("nopath", nopath, 1),
|
||||
|
|
@ -4488,9 +4523,6 @@ static void fuse_lib_help(void)
|
|||
" -o umask=M set file permissions (octal)\n"
|
||||
" -o uid=N set file owner\n"
|
||||
" -o gid=N set file group\n"
|
||||
" -o entry_timeout=T cache timeout for names (1.0s)\n"
|
||||
" -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
|
||||
" -o attr_timeout=T cache timeout for attributes (1.0s)\n"
|
||||
" -o noforget never forget cached inodes\n"
|
||||
" -o remember=T remember cached inodes for T seconds (0s)\n"
|
||||
" -o nopath don't supply path if not necessary\n"
|
||||
|
|
@ -4657,9 +4689,6 @@ struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
|
|||
llop.setlk = NULL;
|
||||
}
|
||||
|
||||
f->conf.entry_timeout = 1.0;
|
||||
f->conf.attr_timeout = 1.0;
|
||||
f->conf.negative_timeout = 0.0;
|
||||
f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
|
||||
|
||||
f->pagesize = getpagesize();
|
||||
|
|
@ -4889,42 +4918,3 @@ fuse_config_num_threads(const struct fuse *fuse_)
|
|||
{
|
||||
return fuse_->conf.threads;
|
||||
}
|
||||
|
||||
void
|
||||
fuse_config_set_entry_timeout(struct fuse *fuse_,
|
||||
const double entry_timeout_)
|
||||
{
|
||||
fuse_->conf.entry_timeout = entry_timeout_;
|
||||
}
|
||||
|
||||
double
|
||||
fuse_config_get_entry_timeout(const struct fuse *fuse_)
|
||||
{
|
||||
return fuse_->conf.entry_timeout;
|
||||
}
|
||||
|
||||
void
|
||||
fuse_config_set_negative_entry_timeout(struct fuse *fuse_,
|
||||
const double entry_timeout_)
|
||||
{
|
||||
fuse_->conf.negative_timeout = entry_timeout_;
|
||||
}
|
||||
|
||||
double
|
||||
fuse_config_get_negative_entry_timeout(const struct fuse *fuse_)
|
||||
{
|
||||
return fuse_->conf.negative_timeout;
|
||||
}
|
||||
|
||||
void
|
||||
fuse_config_set_attr_timeout(struct fuse *fuse_,
|
||||
const double attr_timeout_)
|
||||
{
|
||||
fuse_->conf.attr_timeout = attr_timeout_;
|
||||
}
|
||||
|
||||
double
|
||||
fuse_config_get_attr_timeout(const struct fuse *fuse_)
|
||||
{
|
||||
return fuse_->conf.attr_timeout;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -319,37 +319,18 @@ void fuse_reply_none(fuse_req_t req)
|
|||
fuse_free_req(req);
|
||||
}
|
||||
|
||||
static unsigned long calc_timeout_sec(double t)
|
||||
static
|
||||
void
|
||||
fill_entry(struct fuse_entry_out *arg,
|
||||
const struct fuse_entry_param *e)
|
||||
{
|
||||
if (t > (double) ULONG_MAX)
|
||||
return ULONG_MAX;
|
||||
else if (t < 0.0)
|
||||
return 0;
|
||||
else
|
||||
return (unsigned long) t;
|
||||
}
|
||||
|
||||
static unsigned int calc_timeout_nsec(double t)
|
||||
{
|
||||
double f = t - (double) calc_timeout_sec(t);
|
||||
if (f < 0.0)
|
||||
return 0;
|
||||
else if (f >= 0.999999999)
|
||||
return 999999999;
|
||||
else
|
||||
return (unsigned int) (f * 1.0e9);
|
||||
}
|
||||
|
||||
static void fill_entry(struct fuse_entry_out *arg,
|
||||
const struct fuse_entry_param *e)
|
||||
{
|
||||
arg->nodeid = e->ino;
|
||||
arg->generation = e->generation;
|
||||
arg->entry_valid = calc_timeout_sec(e->entry_timeout);
|
||||
arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
|
||||
arg->attr_valid = calc_timeout_sec(e->attr_timeout);
|
||||
arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
|
||||
convert_stat(&e->attr, &arg->attr);
|
||||
arg->nodeid = e->ino;
|
||||
arg->generation = e->generation;
|
||||
arg->entry_valid = e->timeout.entry;
|
||||
arg->entry_valid_nsec = 0;
|
||||
arg->attr_valid = e->timeout.attr;
|
||||
arg->attr_valid_nsec = 0;
|
||||
convert_stat(&e->attr,&arg->attr);
|
||||
}
|
||||
|
||||
static void fill_open(struct fuse_open_out *arg,
|
||||
|
|
@ -398,19 +379,21 @@ int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
|
|||
entrysize + sizeof(struct fuse_open_out));
|
||||
}
|
||||
|
||||
int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
|
||||
double attr_timeout)
|
||||
int
|
||||
fuse_reply_attr(fuse_req_t req,
|
||||
const struct stat *attr,
|
||||
const uint64_t timeout)
|
||||
{
|
||||
struct fuse_attr_out arg;
|
||||
size_t size = req->f->conn.proto_minor < 9 ?
|
||||
FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg);
|
||||
struct fuse_attr_out arg;
|
||||
size_t size = req->f->conn.proto_minor < 9 ?
|
||||
FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg);
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg.attr_valid = calc_timeout_sec(attr_timeout);
|
||||
arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
|
||||
convert_stat(attr, &arg.attr);
|
||||
memset(&arg,0,sizeof(arg));
|
||||
arg.attr_valid = timeout;
|
||||
arg.attr_valid_nsec = 0;
|
||||
convert_stat(attr,&arg.attr);
|
||||
|
||||
return send_reply_ok(req, &arg, size);
|
||||
return send_reply_ok(req,&arg,size);
|
||||
}
|
||||
|
||||
int fuse_reply_readlink(fuse_req_t req, const char *linkname)
|
||||
|
|
@ -1712,9 +1695,9 @@ static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
|||
}
|
||||
|
||||
if (req->f->op.ioctl)
|
||||
req->f->op.ioctl(req, nodeid, arg->cmd,
|
||||
(void *)(uintptr_t)arg->arg, &fi, flags,
|
||||
in_buf, arg->in_size, arg->out_size);
|
||||
req->f->op.ioctl(req, nodeid, (unsigned long)arg->cmd,
|
||||
(void *)(uintptr_t)arg->arg, &fi, flags,
|
||||
in_buf, arg->in_size, arg->out_size);
|
||||
else
|
||||
fuse_reply_err(req, ENOSYS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,6 +116,11 @@ for comparisons / ideas.
|
|||
.SH OPTIONS
|
||||
.SS mount options
|
||||
.IP \[bu] 2
|
||||
\f[B]config\f[]: Path to a config file.
|
||||
Same arguments as below in key=val format.
|
||||
.IP \[bu] 2
|
||||
\f[B]branches\f[]: Colon delimited list of branches.
|
||||
.IP \[bu] 2
|
||||
\f[B]allow_other\f[]: A libfuse option which allows users besides the
|
||||
one which ran mergerfs to see the filesystem.
|
||||
This is required for most use\-cases.
|
||||
|
|
@ -940,7 +945,69 @@ make\ LTO=1\ \ \ \ \ \ \ \ \ \ \ \ \-\ build\ with\ link\ time\ optimization
|
|||
\f[]
|
||||
.fi
|
||||
.SH RUNTIME CONFIG
|
||||
.SS .mergerfs pseudo file
|
||||
.SS ioctl
|
||||
.PP
|
||||
The original runtime config API was via xattr calls.
|
||||
This however became an issue when needing to disable xattr.
|
||||
While slightly less convenient ioctl does not have the same problems and
|
||||
will be the main API going forward.
|
||||
.PP
|
||||
The keys are the same as the command line option arguments as well as
|
||||
the config file.
|
||||
.SS requests / commands
|
||||
.PP
|
||||
All commands take a 4096 byte char buffer.
|
||||
.IP \[bu] 2
|
||||
read keys: get a nul \[aq]\[aq] delimited list of option keys
|
||||
.IP \[bu] 2
|
||||
_IOWR(0xDF,0,char[4096]) = 0xD000DF00
|
||||
.IP \[bu] 2
|
||||
on success ioctl return value is the total length
|
||||
.IP \[bu] 2
|
||||
read value: get an option value
|
||||
.IP \[bu] 2
|
||||
_IOWR(0xDF,1,char[4096]) = 0xD000DF01
|
||||
.IP \[bu] 2
|
||||
the key is passed in via the char buffer as a nul \[aq]\[aq] terminated
|
||||
string
|
||||
.IP \[bu] 2
|
||||
on success ioctl return value is the total length
|
||||
.IP \[bu] 2
|
||||
write value: set an option value
|
||||
.IP \[bu] 2
|
||||
_IOW(0xDF,2,char[4096]) = 0x5000DF02
|
||||
.IP \[bu] 2
|
||||
the key and value is passed in via the char buffer as a nul \[aq]\[aq]
|
||||
terminated string in the format of \f[C]key=value\f[]
|
||||
.IP \[bu] 2
|
||||
on success ioctl return value is 0
|
||||
.IP \[bu] 2
|
||||
file info: get mergerfs metadata info for a file
|
||||
.IP \[bu] 2
|
||||
_IOWR(0xDF,3,char[4096]) = 0xD000DF03
|
||||
.IP \[bu] 2
|
||||
the key is passed in via the char buffer as a nul \[aq]\[aq] terminated
|
||||
string
|
||||
.IP \[bu] 2
|
||||
on success the ioctl return value is the total length
|
||||
.IP \[bu] 2
|
||||
keys:
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
basepath: the base mount point for the file according to the getattr
|
||||
policy
|
||||
.IP \[bu] 2
|
||||
relpath: the relative path of the file from the mount point
|
||||
.IP \[bu] 2
|
||||
fullpath: the full path of the underlying file according to the getattr
|
||||
policy
|
||||
.IP \[bu] 2
|
||||
allpaths: a NUL \[aq]\[aq] delimited list of full paths to all files
|
||||
found
|
||||
.RE
|
||||
.SS .mergerfs pseudo file (deprecated)
|
||||
.PP
|
||||
NOTE: this interface will be removed in mergerfs 3.0
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
|
|
|
|||
239
src/branch.cpp
239
src/branch.cpp
|
|
@ -17,14 +17,16 @@
|
|||
*/
|
||||
|
||||
#include "branch.hpp"
|
||||
#include "ef.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "fs_glob.hpp"
|
||||
#include "str.hpp"
|
||||
|
||||
#include <fnmatch.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fnmatch.h>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
|
|
@ -47,53 +49,23 @@ Branch::ro_or_nc(void) const
|
|||
(mode == Branch::NC));
|
||||
}
|
||||
|
||||
string
|
||||
Branches::to_string(const bool mode_) const
|
||||
static
|
||||
void
|
||||
split(const std::string &s_,
|
||||
std::string *instr_,
|
||||
std::string *values_)
|
||||
{
|
||||
string tmp;
|
||||
uint64_t offset;
|
||||
|
||||
for(size_t i = 0; i < size(); i++)
|
||||
{
|
||||
const Branch &branch = (*this)[i];
|
||||
|
||||
tmp += branch.path;
|
||||
|
||||
if(mode_)
|
||||
{
|
||||
tmp += '=';
|
||||
switch(branch.mode)
|
||||
{
|
||||
default:
|
||||
case Branch::RW:
|
||||
tmp += "RW";
|
||||
break;
|
||||
case Branch::RO:
|
||||
tmp += "RO";
|
||||
break;
|
||||
case Branch::NC:
|
||||
tmp += "NC";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tmp += ':';
|
||||
}
|
||||
|
||||
if(*tmp.rbegin() == ':')
|
||||
tmp.erase(tmp.size() - 1);
|
||||
|
||||
return tmp;
|
||||
offset = s_.find_first_of('/');
|
||||
*instr_ = s_.substr(0,offset);
|
||||
if(offset != std::string::npos)
|
||||
*values_ = s_.substr(offset);
|
||||
}
|
||||
|
||||
void
|
||||
Branches::to_paths(vector<string> &vec_) const
|
||||
Branches::Branches()
|
||||
{
|
||||
for(size_t i = 0; i < size(); i++)
|
||||
{
|
||||
const Branch &branch = (*this)[i];
|
||||
|
||||
vec_.push_back(branch.path);
|
||||
}
|
||||
pthread_rwlock_init(&lock,NULL);
|
||||
}
|
||||
|
||||
static
|
||||
|
|
@ -107,11 +79,11 @@ parse(const string &str_,
|
|||
|
||||
str = str_;
|
||||
branch.mode = Branch::INVALID;
|
||||
if(str::ends_with(str,"=RO"))
|
||||
if(str::endswith(str,"=RO"))
|
||||
branch.mode = Branch::RO;
|
||||
else if(str::ends_with(str,"=RW"))
|
||||
ef(str::endswith(str,"=RW"))
|
||||
branch.mode = Branch::RW;
|
||||
else if(str::ends_with(str,"=NC"))
|
||||
ef(str::endswith(str,"=NC"))
|
||||
branch.mode = Branch::NC;
|
||||
|
||||
if(branch.mode != Branch::INVALID)
|
||||
|
|
@ -128,29 +100,33 @@ parse(const string &str_,
|
|||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
Branches::set(const std::string &str_)
|
||||
set(Branches &branches_,
|
||||
const std::string &str_)
|
||||
{
|
||||
vector<string> paths;
|
||||
|
||||
clear();
|
||||
branches_.clear();
|
||||
|
||||
str::split(paths,str_,':');
|
||||
|
||||
for(size_t i = 0; i < paths.size(); i++)
|
||||
{
|
||||
Branches branches;
|
||||
Branches tmp;
|
||||
|
||||
parse(paths[i],branches);
|
||||
parse(paths[i],tmp);
|
||||
|
||||
insert(end(),
|
||||
branches.begin(),
|
||||
branches.end());
|
||||
branches_.insert(branches_.end(),
|
||||
tmp.begin(),
|
||||
tmp.end());
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
Branches::add_begin(const std::string &str_)
|
||||
add_begin(Branches &branches_,
|
||||
const std::string &str_)
|
||||
{
|
||||
vector<string> paths;
|
||||
|
||||
|
|
@ -158,18 +134,20 @@ Branches::add_begin(const std::string &str_)
|
|||
|
||||
for(size_t i = 0; i < paths.size(); i++)
|
||||
{
|
||||
Branches branches;
|
||||
Branches tmp;
|
||||
|
||||
parse(paths[i],branches);
|
||||
parse(paths[i],tmp);
|
||||
|
||||
insert(begin(),
|
||||
branches.begin(),
|
||||
branches.end());
|
||||
branches_.insert(branches_.begin(),
|
||||
tmp.begin(),
|
||||
tmp.end());
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
Branches::add_end(const std::string &str_)
|
||||
add_end(Branches &branches_,
|
||||
const std::string &str_)
|
||||
{
|
||||
vector<string> paths;
|
||||
|
||||
|
|
@ -177,36 +155,41 @@ Branches::add_end(const std::string &str_)
|
|||
|
||||
for(size_t i = 0; i < paths.size(); i++)
|
||||
{
|
||||
Branches branches;
|
||||
Branches tmp;
|
||||
|
||||
parse(paths[i],branches);
|
||||
parse(paths[i],tmp);
|
||||
|
||||
insert(end(),
|
||||
branches.begin(),
|
||||
branches.end());
|
||||
branches_.insert(branches_.end(),
|
||||
tmp.begin(),
|
||||
tmp.end());
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
Branches::erase_begin(void)
|
||||
erase_begin(Branches &branches_)
|
||||
{
|
||||
erase(begin());
|
||||
branches_.erase(branches_.begin());
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
Branches::erase_end(void)
|
||||
erase_end(Branches &branches_)
|
||||
{
|
||||
pop_back();
|
||||
branches_.pop_back();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
Branches::erase_fnmatch(const std::string &str_)
|
||||
erase_fnmatch(Branches &branches_,
|
||||
const std::string &str_)
|
||||
{
|
||||
vector<string> patterns;
|
||||
|
||||
str::split(patterns,str_,':');
|
||||
|
||||
for(iterator i = begin(); i != end();)
|
||||
for(Branches::iterator i = branches_.begin();
|
||||
i != branches_.end();)
|
||||
{
|
||||
int match = FNM_NOMATCH;
|
||||
|
||||
|
|
@ -217,6 +200,116 @@ Branches::erase_fnmatch(const std::string &str_)
|
|||
match = ::fnmatch(pi->c_str(),i->path.c_str(),0);
|
||||
}
|
||||
|
||||
i = ((match == 0) ? erase(i) : (i+1));
|
||||
i = ((match == 0) ? branches_.erase(i) : (i+1));
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
Branches::from_string(const std::string &s_)
|
||||
{
|
||||
rwlock::WriteGuard guard(&lock);
|
||||
std::string instr;
|
||||
std::string values;
|
||||
|
||||
::split(s_,&instr,&values);
|
||||
|
||||
if(instr == "+")
|
||||
::add_end(*this,values);
|
||||
ef(instr == "+<")
|
||||
::add_begin(*this,values);
|
||||
ef(instr == "+>")
|
||||
::add_end(*this,values);
|
||||
ef(instr == "-")
|
||||
::erase_fnmatch(*this,values);
|
||||
ef(instr == "-<")
|
||||
::erase_begin(*this);
|
||||
ef(instr == "->")
|
||||
::erase_end(*this);
|
||||
ef(instr == "=")
|
||||
::set(*this,values);
|
||||
ef(instr.empty())
|
||||
::set(*this,values);
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
string
|
||||
Branches::to_string(void) const
|
||||
{
|
||||
rwlock::ReadGuard guard(&lock);
|
||||
string tmp;
|
||||
|
||||
for(size_t i = 0; i < size(); i++)
|
||||
{
|
||||
const Branch &branch = (*this)[i];
|
||||
|
||||
tmp += branch.path;
|
||||
|
||||
tmp += '=';
|
||||
switch(branch.mode)
|
||||
{
|
||||
default:
|
||||
case Branch::RW:
|
||||
tmp += "RW";
|
||||
break;
|
||||
case Branch::RO:
|
||||
tmp += "RO";
|
||||
break;
|
||||
case Branch::NC:
|
||||
tmp += "NC";
|
||||
break;
|
||||
}
|
||||
|
||||
tmp += ':';
|
||||
}
|
||||
|
||||
if(*tmp.rbegin() == ':')
|
||||
tmp.erase(tmp.size() - 1);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void
|
||||
Branches::to_paths(vector<string> &vec_) const
|
||||
{
|
||||
rwlock::ReadGuard guard(&lock);
|
||||
|
||||
for(size_t i = 0; i < size(); i++)
|
||||
{
|
||||
const Branch &branch = (*this)[i];
|
||||
|
||||
vec_.push_back(branch.path);
|
||||
}
|
||||
}
|
||||
|
||||
SrcMounts::SrcMounts(Branches &b_)
|
||||
: _branches(b_)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
SrcMounts::from_string(const std::string &s_)
|
||||
{
|
||||
return _branches.from_string(s_);
|
||||
}
|
||||
|
||||
std::string
|
||||
SrcMounts::to_string(void) const
|
||||
{
|
||||
rwlock::ReadGuard guard(&_branches.lock);
|
||||
std::string rv;
|
||||
|
||||
for(uint64_t i = 0; i < _branches.size(); i++)
|
||||
{
|
||||
rv += _branches[i].path;
|
||||
rv += ':';
|
||||
}
|
||||
|
||||
if(*rv.rbegin() == ':')
|
||||
rv.erase(rv.size() - 1);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,11 +18,17 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "rwlock.hpp"
|
||||
#include "tofrom_string.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct Branch
|
||||
#include <pthread.h>
|
||||
|
||||
class Branch
|
||||
{
|
||||
public:
|
||||
enum Mode
|
||||
{
|
||||
INVALID,
|
||||
|
|
@ -39,18 +45,31 @@ struct Branch
|
|||
bool ro_or_nc(void) const;
|
||||
};
|
||||
|
||||
class Branches : public std::vector<Branch>
|
||||
class Branches : public std::vector<Branch>, public ToFromString
|
||||
{
|
||||
public:
|
||||
std::string to_string(const bool mode_ = false) const;
|
||||
|
||||
void to_paths(std::vector<std::string> &vec_) const;
|
||||
Branches();
|
||||
|
||||
public:
|
||||
void set(const std::string &str_);
|
||||
void add_begin(const std::string &str_);
|
||||
void add_end(const std::string &str_);
|
||||
void erase_begin(void);
|
||||
void erase_end(void);
|
||||
void erase_fnmatch(const std::string &str_);
|
||||
int from_string(const std::string &str);
|
||||
std::string to_string(void) const;
|
||||
|
||||
public:
|
||||
void to_paths(std::vector<std::string> &vec) const;
|
||||
|
||||
public:
|
||||
mutable pthread_rwlock_t lock;
|
||||
};
|
||||
|
||||
class SrcMounts : public ToFromString
|
||||
{
|
||||
public:
|
||||
SrcMounts(Branches &b_);
|
||||
|
||||
public:
|
||||
int from_string(const std::string &str);
|
||||
std::string to_string(void) const;
|
||||
|
||||
private:
|
||||
Branches &_branches;
|
||||
};
|
||||
|
|
|
|||
506
src/config.cpp
506
src/config.cpp
|
|
@ -15,187 +15,393 @@
|
|||
*/
|
||||
|
||||
#include "config.hpp"
|
||||
#include "ef.hpp"
|
||||
#include "errno.hpp"
|
||||
#include "from_string.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "num.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "to_string.hpp"
|
||||
#include "version.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define MINFREESPACE_DEFAULT (4294967295ULL)
|
||||
#define POLICYINIT(X) X(policies[FuseFunc::Enum::X])
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
#define IFERT(S) if(S == s_) return true
|
||||
|
||||
namespace l
|
||||
{
|
||||
static
|
||||
bool
|
||||
readonly(const std::string &s_)
|
||||
{
|
||||
IFERT("async_read");
|
||||
IFERT("cache.symlinks");
|
||||
IFERT("cache.writeback");
|
||||
IFERT("fsname");
|
||||
IFERT("fuse_msg_size");
|
||||
IFERT("mount");
|
||||
IFERT("nullrw");
|
||||
IFERT("pid");
|
||||
IFERT("readdirplus");
|
||||
IFERT("threads");
|
||||
IFERT("version");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Config::Config()
|
||||
: destmount(),
|
||||
branches(),
|
||||
branches_lock(),
|
||||
minfreespace(MINFREESPACE_DEFAULT),
|
||||
moveonenospc(false),
|
||||
direct_io(false),
|
||||
dropcacheonclose(false),
|
||||
symlinkify(false),
|
||||
symlinkify_timeout(3600),
|
||||
nullrw(false),
|
||||
ignorepponrename(false),
|
||||
security_capability(true),
|
||||
link_cow(false),
|
||||
xattr(0),
|
||||
statfs(StatFS::BASE),
|
||||
statfs_ignore(StatFSIgnore::NONE),
|
||||
posix_acl(false),
|
||||
cache_symlinks(false),
|
||||
cache_readdir(false),
|
||||
async_read(true),
|
||||
writeback_cache(false),
|
||||
readdirplus(false),
|
||||
cache_files(CacheFiles::LIBFUSE),
|
||||
fuse_msg_size(FUSE_MAX_MAX_PAGES),
|
||||
POLICYINIT(access),
|
||||
POLICYINIT(chmod),
|
||||
POLICYINIT(chown),
|
||||
POLICYINIT(create),
|
||||
POLICYINIT(getattr),
|
||||
POLICYINIT(getxattr),
|
||||
POLICYINIT(link),
|
||||
POLICYINIT(listxattr),
|
||||
POLICYINIT(mkdir),
|
||||
POLICYINIT(mknod),
|
||||
POLICYINIT(open),
|
||||
POLICYINIT(readlink),
|
||||
POLICYINIT(removexattr),
|
||||
POLICYINIT(rename),
|
||||
POLICYINIT(rmdir),
|
||||
POLICYINIT(setxattr),
|
||||
POLICYINIT(symlink),
|
||||
POLICYINIT(truncate),
|
||||
POLICYINIT(unlink),
|
||||
POLICYINIT(utimens),
|
||||
controlfile("/.mergerfs")
|
||||
{
|
||||
pthread_rwlock_init(&branches_lock,NULL);
|
||||
:
|
||||
open_cache(),
|
||||
|
||||
set_category_policy("action","epall");
|
||||
set_category_policy("create","epmfs");
|
||||
set_category_policy("search","ff");
|
||||
controlfile("/.mergerfs"),
|
||||
|
||||
async_read(true),
|
||||
auto_cache(false),
|
||||
branches(),
|
||||
cache_attr(1),
|
||||
cache_entry(1),
|
||||
cache_files(CacheFiles::ENUM::LIBFUSE),
|
||||
cache_negative_entry(0),
|
||||
cache_readdir(false),
|
||||
cache_statfs(0),
|
||||
cache_symlinks(false),
|
||||
category(func),
|
||||
direct_io(false),
|
||||
dropcacheonclose(false),
|
||||
fsname(),
|
||||
func(),
|
||||
fuse_msg_size(FUSE_MAX_MAX_PAGES),
|
||||
ignorepponrename(false),
|
||||
link_cow(false),
|
||||
minfreespace(MINFREESPACE_DEFAULT),
|
||||
mount(),
|
||||
moveonenospc(false),
|
||||
nullrw(false),
|
||||
pid(::getpid()),
|
||||
posix_acl(false),
|
||||
readdirplus(false),
|
||||
security_capability(true),
|
||||
srcmounts(branches),
|
||||
statfs(StatFS::ENUM::BASE),
|
||||
statfs_ignore(StatFSIgnore::ENUM::NONE),
|
||||
symlinkify(false),
|
||||
symlinkify_timeout(3600),
|
||||
threads(0),
|
||||
version(MERGERFS_VERSION),
|
||||
writeback_cache(false),
|
||||
xattr(XAttr::ENUM::PASSTHROUGH)
|
||||
{
|
||||
_map["async_read"] = &async_read;
|
||||
_map["auto_cache"] = &auto_cache;
|
||||
_map["branches"] = &branches;
|
||||
_map["cache.attr"] = &cache_attr;
|
||||
_map["cache.entry"] = &cache_entry;
|
||||
_map["cache.files"] = &cache_files;
|
||||
_map["cache.negative_entry"] = &cache_negative_entry;
|
||||
_map["cache.readdir"] = &cache_readdir;
|
||||
_map["cache.statfs"] = &cache_statfs;
|
||||
_map["cache.symlinks"] = &cache_symlinks;
|
||||
_map["cache.writeback"] = &writeback_cache;
|
||||
_map["category.action"] = &category.action;
|
||||
_map["category.create"] = &category.create;
|
||||
_map["category.search"] = &category.search;
|
||||
_map["direct_io"] = &direct_io;
|
||||
_map["dropcacheonclose"] = &dropcacheonclose;
|
||||
_map["fsname"] = &fsname;
|
||||
_map["func.access"] = &func.access;
|
||||
_map["func.chmod"] = &func.chmod;
|
||||
_map["func.chown"] = &func.chown;
|
||||
_map["func.create"] = &func.create;
|
||||
_map["func.getattr"] = &func.getattr;
|
||||
_map["func.getxattr"] = &func.getxattr;
|
||||
_map["func.link"] = &func.link;
|
||||
_map["func.listxattr"] = &func.listxattr;
|
||||
_map["func.mkdir"] = &func.mkdir;
|
||||
_map["func.mknod"] = &func.mknod;
|
||||
_map["func.open"] = &func.open;
|
||||
_map["func.readlink"] = &func.readlink;
|
||||
_map["func.removexattr"] = &func.removexattr;
|
||||
_map["func.rename"] = &func.rename;
|
||||
_map["func.rmdir"] = &func.rmdir;
|
||||
_map["func.setxattr"] = &func.setxattr;
|
||||
_map["func.symlink"] = &func.symlink;
|
||||
_map["func.truncate"] = &func.truncate;
|
||||
_map["func.unlink"] = &func.unlink;
|
||||
_map["func.utimens"] = &func.utimens;
|
||||
_map["fuse_msg_size"] = &fuse_msg_size;
|
||||
_map["ignorepponrename"] = &ignorepponrename;
|
||||
_map["kernel_cache"] = &kernel_cache;
|
||||
_map["link_cow"] = &link_cow;
|
||||
_map["minfreespace"] = &minfreespace;
|
||||
_map["mount"] = &mount;
|
||||
_map["moveonenospc"] = &moveonenospc;
|
||||
_map["nullrw"] = &nullrw;
|
||||
_map["pid"] = &pid;
|
||||
_map["posix_acl"] = &posix_acl;
|
||||
_map["readdirplus"] = &readdirplus;
|
||||
_map["security_capability"] = &security_capability;
|
||||
_map["srcmounts"] = &srcmounts;
|
||||
_map["statfs"] = &statfs;
|
||||
_map["statfs_ignore"] = &statfs_ignore;
|
||||
_map["symlinkify"] = &symlinkify;
|
||||
_map["symlinkify_timeout"] = &symlinkify_timeout;
|
||||
_map["threads"] = &threads;
|
||||
_map["version"] = &version;
|
||||
_map["xattr"] = &xattr;
|
||||
}
|
||||
|
||||
int
|
||||
Config::set_func_policy(const string &fusefunc_,
|
||||
const string &policy_)
|
||||
const
|
||||
Config&
|
||||
Config::ro(void)
|
||||
{
|
||||
const Policy *policy;
|
||||
const FuseFunc *fusefunc;
|
||||
|
||||
fusefunc = FuseFunc::find(fusefunc_);
|
||||
if(fusefunc == FuseFunc::invalid)
|
||||
return (errno=ENODATA,-1);
|
||||
|
||||
policy = Policy::find(policy_);
|
||||
if(policy == Policy::invalid)
|
||||
return (errno=EINVAL,-1);
|
||||
|
||||
policies[(FuseFunc::Enum::Type)*fusefunc] = policy;
|
||||
|
||||
return 0;
|
||||
return *((Config*)fuse_get_context()->private_data);
|
||||
}
|
||||
|
||||
int
|
||||
Config::set_category_policy(const string &category_,
|
||||
const string &policy_)
|
||||
Config&
|
||||
Config::rw(void)
|
||||
{
|
||||
const Policy *policy;
|
||||
const Category *category;
|
||||
|
||||
category = Category::find(category_);
|
||||
if(category == Category::invalid)
|
||||
return (errno=ENODATA,-1);
|
||||
|
||||
policy = Policy::find(policy_);
|
||||
if(policy == Policy::invalid)
|
||||
return (errno=EINVAL,-1);
|
||||
|
||||
for(int i = 0; i < FuseFunc::Enum::END; i++)
|
||||
{
|
||||
if(FuseFunc::fusefuncs[i] == (Category::Enum::Type)*category)
|
||||
policies[(FuseFunc::Enum::Type)FuseFunc::fusefuncs[i]] = policy;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Config::CacheFiles::operator int() const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
Config::CacheFiles::operator std::string() const
|
||||
{
|
||||
switch(_data)
|
||||
{
|
||||
case OFF:
|
||||
return "off";
|
||||
case PARTIAL:
|
||||
return "partial";
|
||||
case FULL:
|
||||
return "full";
|
||||
case AUTO_FULL:
|
||||
return "auto-full";
|
||||
case LIBFUSE:
|
||||
return "libfuse";
|
||||
case INVALID:
|
||||
break;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
Config::CacheFiles::CacheFiles()
|
||||
: _data(INVALID)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Config::CacheFiles::CacheFiles(Config::CacheFiles::Enum data_)
|
||||
: _data(data_)
|
||||
{
|
||||
|
||||
return *((Config*)fuse_get_context()->private_data);
|
||||
}
|
||||
|
||||
bool
|
||||
Config::CacheFiles::valid() const
|
||||
Config::has_key(const std::string &key_) const
|
||||
{
|
||||
return (_data != INVALID);
|
||||
return _map.count(key_);
|
||||
}
|
||||
|
||||
Config::CacheFiles&
|
||||
Config::CacheFiles::operator=(const Config::CacheFiles::Enum data_)
|
||||
void
|
||||
Config::keys(std::string &s_) const
|
||||
{
|
||||
_data = data_;
|
||||
Str2TFStrMap::const_iterator i;
|
||||
Str2TFStrMap::const_iterator ei;
|
||||
|
||||
return *this;
|
||||
s_.reserve(512);
|
||||
|
||||
i = _map.begin();
|
||||
ei = _map.end();
|
||||
|
||||
for(; i != ei; ++i)
|
||||
{
|
||||
s_ += i->first;
|
||||
s_ += '\0';
|
||||
}
|
||||
|
||||
s_.resize(s_.size() - 1);
|
||||
}
|
||||
|
||||
Config::CacheFiles&
|
||||
Config::CacheFiles::operator=(const std::string &data_)
|
||||
|
||||
void
|
||||
Config::keys_xattr(std::string &s_) const
|
||||
{
|
||||
if(data_ == "off")
|
||||
_data = OFF;
|
||||
else if(data_ == "partial")
|
||||
_data = PARTIAL;
|
||||
else if(data_ == "full")
|
||||
_data = FULL;
|
||||
else if(data_ == "auto-full")
|
||||
_data = AUTO_FULL;
|
||||
else if(data_ == "libfuse")
|
||||
_data = LIBFUSE;
|
||||
Str2TFStrMap::const_iterator i;
|
||||
Str2TFStrMap::const_iterator ei;
|
||||
|
||||
s_.reserve(1024);
|
||||
for(i = _map.begin(), ei = _map.end(); i != ei; ++i)
|
||||
{
|
||||
s_ += "user.mergerfs.";
|
||||
s_ += i->first;
|
||||
s_ += '\0';
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
Config::get(const std::string &key_,
|
||||
std::string *val_) const
|
||||
{
|
||||
Str2TFStrMap::const_iterator i;
|
||||
|
||||
i = _map.find(key_);
|
||||
if(i == _map.end())
|
||||
return -ENOATTR;
|
||||
|
||||
*val_ = i->second->to_string();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string
|
||||
Config::StatFS::to_string() const
|
||||
{
|
||||
switch(_data)
|
||||
{
|
||||
case Config::StatFS::ENUM::BASE:
|
||||
return "base";
|
||||
case Config::StatFS::ENUM::FULL:
|
||||
return "full";
|
||||
}
|
||||
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
template<>
|
||||
int
|
||||
Config::StatFS::from_string(const std::string &s_)
|
||||
{
|
||||
if(s_ == "base")
|
||||
_data = Config::StatFS::ENUM::BASE;
|
||||
ef(s_ == "full")
|
||||
_data = Config::StatFS::ENUM::FULL;
|
||||
else
|
||||
_data = INVALID;
|
||||
return -EINVAL;
|
||||
|
||||
return *this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string
|
||||
Config::StatFSIgnore::to_string() const
|
||||
{
|
||||
switch(_data)
|
||||
{
|
||||
case Config::StatFSIgnore::ENUM::NONE:
|
||||
return "none";
|
||||
case Config::StatFSIgnore::ENUM::RO:
|
||||
return "ro";
|
||||
case Config::StatFSIgnore::ENUM::NC:
|
||||
return "nc";
|
||||
}
|
||||
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
template<>
|
||||
int
|
||||
Config::StatFSIgnore::from_string(const std::string &s_)
|
||||
{
|
||||
if(s_ == "none")
|
||||
_data = Config::StatFSIgnore::ENUM::NONE;
|
||||
ef(s_ == "ro")
|
||||
_data = Config::StatFSIgnore::ENUM::RO;
|
||||
ef(s_ == "nc")
|
||||
_data = Config::StatFSIgnore::ENUM::NC;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string
|
||||
Config::CacheFiles::to_string() const
|
||||
{
|
||||
switch(_data)
|
||||
{
|
||||
case Config::CacheFiles::ENUM::LIBFUSE:
|
||||
return "libfuse";
|
||||
case Config::CacheFiles::ENUM::OFF:
|
||||
return "off";
|
||||
case Config::CacheFiles::ENUM::PARTIAL:
|
||||
return "partial";
|
||||
case Config::CacheFiles::ENUM::FULL:
|
||||
return "full";
|
||||
case Config::CacheFiles::ENUM::AUTO_FULL:
|
||||
return "auto-full";
|
||||
}
|
||||
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
template<>
|
||||
int
|
||||
Config::CacheFiles::from_string(const std::string &s_)
|
||||
{
|
||||
if(s_ == "libfuse")
|
||||
_data = Config::CacheFiles::ENUM::LIBFUSE;
|
||||
ef(s_ == "off")
|
||||
_data = Config::CacheFiles::ENUM::OFF;
|
||||
ef(s_ == "partial")
|
||||
_data = Config::CacheFiles::ENUM::PARTIAL;
|
||||
ef(s_ == "full")
|
||||
_data = Config::CacheFiles::ENUM::FULL;
|
||||
ef(s_ == "auto-full")
|
||||
_data = Config::CacheFiles::ENUM::AUTO_FULL;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string
|
||||
Config::XAttr::to_string() const
|
||||
{
|
||||
switch(_data)
|
||||
{
|
||||
case Config::XAttr::ENUM::PASSTHROUGH:
|
||||
return "passthrough";
|
||||
case Config::XAttr::ENUM::NOSYS:
|
||||
return "nosys";
|
||||
case Config::XAttr::ENUM::NOATTR:
|
||||
return "noattr";
|
||||
}
|
||||
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
template<>
|
||||
int
|
||||
Config::XAttr::from_string(const std::string &s_)
|
||||
{
|
||||
if(s_ == "passthrough")
|
||||
_data = Config::XAttr::ENUM::PASSTHROUGH;
|
||||
ef(s_ == "nosys")
|
||||
_data = Config::XAttr::ENUM::NOSYS;
|
||||
ef(s_ == "noattr")
|
||||
_data = Config::XAttr::ENUM::NOATTR;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
Config::set_raw(const std::string &key_,
|
||||
const std::string &value_)
|
||||
{
|
||||
Str2TFStrMap::iterator i;
|
||||
|
||||
i = _map.find(key_);
|
||||
if(i == _map.end())
|
||||
return -ENOATTR;
|
||||
|
||||
return i->second->from_string(value_);
|
||||
}
|
||||
|
||||
int
|
||||
Config::set(const std::string &key_,
|
||||
const std::string &value_)
|
||||
{
|
||||
if(l::readonly(key_))
|
||||
return -EINVAL;
|
||||
|
||||
return set_raw(key_,value_);
|
||||
}
|
||||
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream &os_,
|
||||
const Config &c_)
|
||||
{
|
||||
Str2TFStrMap::const_iterator i;
|
||||
Str2TFStrMap::const_iterator ei;
|
||||
|
||||
for(i = c_._map.begin(), ei = c_._map.end(); i != ei; ++i)
|
||||
{
|
||||
os_ << i->first << '=' << i->second << '\n';
|
||||
}
|
||||
|
||||
return os_;
|
||||
}
|
||||
|
|
|
|||
216
src/config.hpp
216
src/config.hpp
|
|
@ -17,9 +17,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "branch.hpp"
|
||||
#include "fusefunc.hpp"
|
||||
#include "enum.hpp"
|
||||
#include "errno.hpp"
|
||||
#include "func_category.hpp"
|
||||
#include "funcs.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_cache.hpp"
|
||||
#include "tofrom_wrapper.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
|
||||
|
|
@ -29,117 +33,51 @@
|
|||
#include <stdint.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
typedef ToFromWrapper<bool> ConfigBOOL;
|
||||
typedef ToFromWrapper<uint64_t> ConfigUINT64;
|
||||
typedef ToFromWrapper<int> ConfigINT;
|
||||
typedef ToFromWrapper<std::string> ConfigSTR;
|
||||
typedef std::map<std::string,ToFromString*> Str2TFStrMap;
|
||||
|
||||
class Config
|
||||
{
|
||||
public:
|
||||
struct StatFS
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
BASE,
|
||||
FULL
|
||||
};
|
||||
};
|
||||
enum class StatFSEnum
|
||||
{
|
||||
BASE,
|
||||
FULL
|
||||
};
|
||||
typedef Enum<StatFSEnum> StatFS;
|
||||
|
||||
struct StatFSIgnore
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
NONE,
|
||||
RO,
|
||||
NC
|
||||
};
|
||||
};
|
||||
enum class StatFSIgnoreEnum
|
||||
{
|
||||
NONE,
|
||||
RO,
|
||||
NC
|
||||
};
|
||||
typedef Enum<StatFSIgnoreEnum> StatFSIgnore;
|
||||
|
||||
class CacheFiles
|
||||
{
|
||||
public:
|
||||
enum Enum
|
||||
{
|
||||
INVALID = -1,
|
||||
LIBFUSE,
|
||||
OFF,
|
||||
PARTIAL,
|
||||
FULL,
|
||||
AUTO_FULL
|
||||
};
|
||||
enum class CacheFilesEnum
|
||||
{
|
||||
LIBFUSE,
|
||||
OFF,
|
||||
PARTIAL,
|
||||
FULL,
|
||||
AUTO_FULL
|
||||
};
|
||||
typedef Enum<CacheFilesEnum> CacheFiles;
|
||||
|
||||
CacheFiles();
|
||||
CacheFiles(Enum);
|
||||
|
||||
operator int() const;
|
||||
operator std::string() const;
|
||||
|
||||
CacheFiles& operator=(const Enum);
|
||||
CacheFiles& operator=(const std::string&);
|
||||
|
||||
bool valid() const;
|
||||
|
||||
private:
|
||||
Enum _data;
|
||||
};
|
||||
enum class XAttrEnum
|
||||
{
|
||||
PASSTHROUGH = 0,
|
||||
NOSYS = ENOSYS,
|
||||
NOATTR = ENOATTR
|
||||
};
|
||||
typedef Enum<XAttrEnum> XAttr;
|
||||
|
||||
public:
|
||||
Config();
|
||||
|
||||
public:
|
||||
int set_func_policy(const std::string &fusefunc_,
|
||||
const std::string &policy_);
|
||||
int set_category_policy(const std::string &category_,
|
||||
const std::string &policy_);
|
||||
|
||||
public:
|
||||
std::string fsname;
|
||||
std::string destmount;
|
||||
Branches branches;
|
||||
mutable pthread_rwlock_t branches_lock;
|
||||
uint64_t minfreespace;
|
||||
bool moveonenospc;
|
||||
bool direct_io;
|
||||
bool kernel_cache;
|
||||
bool auto_cache;
|
||||
bool dropcacheonclose;
|
||||
bool symlinkify;
|
||||
time_t symlinkify_timeout;
|
||||
bool nullrw;
|
||||
bool ignorepponrename;
|
||||
bool security_capability;
|
||||
bool link_cow;
|
||||
int xattr;
|
||||
StatFS::Enum statfs;
|
||||
StatFSIgnore::Enum statfs_ignore;
|
||||
bool posix_acl;
|
||||
bool cache_symlinks;
|
||||
bool cache_readdir;
|
||||
bool async_read;
|
||||
bool writeback_cache;
|
||||
bool readdirplus;
|
||||
CacheFiles cache_files;
|
||||
uint16_t fuse_msg_size;
|
||||
|
||||
public:
|
||||
const Policy *policies[FuseFunc::Enum::END];
|
||||
const Policy *&access;
|
||||
const Policy *&chmod;
|
||||
const Policy *&chown;
|
||||
const Policy *&create;
|
||||
const Policy *&getattr;
|
||||
const Policy *&getxattr;
|
||||
const Policy *&link;
|
||||
const Policy *&listxattr;
|
||||
const Policy *&mkdir;
|
||||
const Policy *&mknod;
|
||||
const Policy *&open;
|
||||
const Policy *&readlink;
|
||||
const Policy *&removexattr;
|
||||
const Policy *&rename;
|
||||
const Policy *&rmdir;
|
||||
const Policy *&setxattr;
|
||||
const Policy *&symlink;
|
||||
const Policy *&truncate;
|
||||
const Policy *&unlink;
|
||||
const Policy *&utimens;
|
||||
|
||||
public:
|
||||
mutable PolicyCache open_cache;
|
||||
|
||||
|
|
@ -147,27 +85,61 @@ public:
|
|||
const std::string controlfile;
|
||||
|
||||
public:
|
||||
static
|
||||
const
|
||||
Config &
|
||||
get(void)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
ConfigBOOL async_read;
|
||||
ConfigBOOL auto_cache;
|
||||
Branches branches;
|
||||
ConfigUINT64 cache_attr;
|
||||
ConfigUINT64 cache_entry;
|
||||
CacheFiles cache_files;
|
||||
ConfigUINT64 cache_negative_entry;
|
||||
ConfigBOOL cache_readdir;
|
||||
ConfigUINT64 cache_statfs;
|
||||
ConfigBOOL cache_symlinks;
|
||||
FuncCategories category;
|
||||
ConfigBOOL direct_io;
|
||||
ConfigBOOL dropcacheonclose;
|
||||
ConfigSTR fsname;
|
||||
Funcs func;
|
||||
ConfigUINT64 fuse_msg_size;
|
||||
ConfigBOOL ignorepponrename;
|
||||
ConfigBOOL kernel_cache;
|
||||
ConfigBOOL link_cow;
|
||||
ConfigUINT64 minfreespace;
|
||||
ConfigSTR mount;
|
||||
ConfigBOOL moveonenospc;
|
||||
ConfigBOOL nullrw;
|
||||
ConfigUINT64 pid;
|
||||
ConfigBOOL posix_acl;
|
||||
ConfigBOOL readdirplus;
|
||||
ConfigBOOL security_capability;
|
||||
SrcMounts srcmounts;
|
||||
StatFS statfs;
|
||||
StatFSIgnore statfs_ignore;
|
||||
ConfigBOOL symlinkify;
|
||||
ConfigUINT64 symlinkify_timeout;
|
||||
ConfigINT threads;
|
||||
ConfigSTR version;
|
||||
ConfigBOOL writeback_cache;
|
||||
XAttr xattr;
|
||||
|
||||
return get(fc);
|
||||
}
|
||||
public:
|
||||
friend std::ostream& operator<<(std::ostream &s,
|
||||
const Config &c);
|
||||
|
||||
static
|
||||
const Config &
|
||||
get(const fuse_context *fc)
|
||||
{
|
||||
return *((Config*)fc->private_data);
|
||||
}
|
||||
public:
|
||||
bool has_key(const std::string &key) const;
|
||||
void keys(std::string &s) const;
|
||||
void keys_xattr(std::string &s) const;
|
||||
|
||||
static
|
||||
Config &
|
||||
get_writable(void)
|
||||
{
|
||||
return (*((Config*)fuse_get_context()->private_data));
|
||||
}
|
||||
public:
|
||||
int get(const std::string &key, std::string *val) const;
|
||||
int set_raw(const std::string &key, const std::string &val);
|
||||
int set(const std::string &key, const std::string &val);
|
||||
|
||||
public:
|
||||
static const Config &ro(void);
|
||||
static Config &rw(void);
|
||||
|
||||
private:
|
||||
Str2TFStrMap _map;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -16,16 +16,15 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "fh.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
class DirInfo
|
||||
class DirInfo : public FH
|
||||
{
|
||||
public:
|
||||
DirInfo(const char *fusepath_)
|
||||
: fusepath(fusepath_)
|
||||
: FH(fusepath_)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
std::string fusepath;
|
||||
};
|
||||
|
|
|
|||
21
src/ef.hpp
Normal file
21
src/ef.hpp
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, 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
|
||||
|
||||
#define ef(X) else if(X)
|
||||
78
src/enum.hpp
Normal file
78
src/enum.hpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#include "tofrom_string.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
template<typename E>
|
||||
class Enum : public ToFromString
|
||||
{
|
||||
public:
|
||||
typedef E ENUM;
|
||||
|
||||
public:
|
||||
Enum<ENUM>()
|
||||
{
|
||||
}
|
||||
|
||||
Enum<ENUM>(const ENUM data_)
|
||||
: _data(data_)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
Enum<ENUM>&
|
||||
operator=(const ENUM data_)
|
||||
{
|
||||
_data = data_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Enum<ENUM>&
|
||||
operator=(const std::string &s_)
|
||||
{
|
||||
from_string(s_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
operator ENUM() const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
public:
|
||||
bool operator==(const ENUM data_) const
|
||||
{
|
||||
return (_data == data_);
|
||||
}
|
||||
|
||||
public:
|
||||
std::string to_string() const;
|
||||
int from_string(const std::string &);
|
||||
|
||||
public:
|
||||
int to_int() const
|
||||
{
|
||||
return (int)_data;
|
||||
}
|
||||
|
||||
private:
|
||||
ENUM _data;
|
||||
};
|
||||
31
src/fh.hpp
Normal file
31
src/fh.hpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
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>
|
||||
|
||||
class FH
|
||||
{
|
||||
public:
|
||||
FH(const char *fusepath_)
|
||||
: fusepath(fusepath_)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
std::string fusepath;
|
||||
};
|
||||
|
|
@ -16,19 +16,20 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "fh.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
class FileInfo
|
||||
class FileInfo : public FH
|
||||
{
|
||||
public:
|
||||
FileInfo(const int fd_,
|
||||
const char *fusepath_)
|
||||
: fd(fd_),
|
||||
fusepath(fusepath_)
|
||||
: FH(fusepath_),
|
||||
fd(fd_)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
int fd;
|
||||
std::string fusepath;
|
||||
};
|
||||
|
|
|
|||
115
src/from_string.cpp
Normal file
115
src/from_string.cpp
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#include "ef.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace str
|
||||
{
|
||||
int
|
||||
from(const std::string &value_,
|
||||
bool *bool_)
|
||||
{
|
||||
if((value_ == "true") ||
|
||||
(value_ == "1") ||
|
||||
(value_ == "on") ||
|
||||
(value_ == "yes"))
|
||||
*bool_ = true;
|
||||
ef((value_ == "false") ||
|
||||
(value_ == "0") ||
|
||||
(value_ == "off") ||
|
||||
(value_ == "no"))
|
||||
*bool_ = false;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
from(const std::string &value_,
|
||||
int *int_)
|
||||
{
|
||||
*int_ = ::strtol(value_.c_str(),NULL,10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
from(const std::string &value_,
|
||||
uint64_t *uint64_)
|
||||
{
|
||||
char *endptr;
|
||||
uint64_t tmp;
|
||||
|
||||
tmp = ::strtoll(value_.c_str(),&endptr,10);
|
||||
switch(*endptr)
|
||||
{
|
||||
case 'k':
|
||||
case 'K':
|
||||
tmp *= 1024;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
case 'M':
|
||||
tmp *= (1024 * 1024);
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
case 'G':
|
||||
tmp *= (1024 * 1024 * 1024);
|
||||
break;
|
||||
|
||||
case 't':
|
||||
case 'T':
|
||||
tmp *= (1024ULL * 1024 * 1024 * 1024);
|
||||
break;
|
||||
|
||||
case '\0':
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*uint64_ = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
from(const std::string &value_,
|
||||
std::string *str_)
|
||||
{
|
||||
*str_ = value_;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
from(const std::string &value_,
|
||||
const std::string *key_)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
32
src/from_string.hpp
Normal file
32
src/from_string.hpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, 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 <stdint.h>
|
||||
|
||||
namespace str
|
||||
{
|
||||
int from(const std::string &, bool *);
|
||||
int from(const std::string &, int *);
|
||||
int from(const std::string &, uint64_t *);
|
||||
int from(const std::string &, std::string *);
|
||||
int from(const std::string &, const std::string *);
|
||||
}
|
||||
39
src/func.cpp
Normal file
39
src/func.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#include "func.hpp"
|
||||
|
||||
int
|
||||
Func::from_string(const std::string &s_)
|
||||
{
|
||||
const Policy *tmp;
|
||||
|
||||
tmp = &Policy::find(s_);
|
||||
if(tmp == Policy::invalid)
|
||||
return -EINVAL;
|
||||
|
||||
policy = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string
|
||||
Func::to_string(void) const
|
||||
{
|
||||
return policy->to_string();
|
||||
}
|
||||
221
src/func.hpp
Normal file
221
src/func.hpp
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, 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 "policy.hpp"
|
||||
#include "tofrom_string.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
class Func : public ToFromString
|
||||
{
|
||||
public:
|
||||
Func(const Policy &policy_)
|
||||
: policy(&policy_)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
int from_string(const std::string &s);
|
||||
std::string to_string() const;
|
||||
|
||||
public:
|
||||
const Policy *policy;
|
||||
};
|
||||
|
||||
class FuncAccess : public Func
|
||||
{
|
||||
public:
|
||||
FuncAccess()
|
||||
: Func(Policy::ff)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncChmod : public Func
|
||||
{
|
||||
public:
|
||||
FuncChmod()
|
||||
: Func(Policy::epall)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncChown : public Func
|
||||
{
|
||||
public:
|
||||
FuncChown()
|
||||
: Func(Policy::epall)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncCreate : public Func
|
||||
{
|
||||
public:
|
||||
FuncCreate()
|
||||
: Func(Policy::epmfs)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncGetAttr : public Func
|
||||
{
|
||||
public:
|
||||
FuncGetAttr()
|
||||
: Func(Policy::ff)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncGetXAttr : public Func
|
||||
{
|
||||
public:
|
||||
FuncGetXAttr()
|
||||
: Func(Policy::ff)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncLink : public Func
|
||||
{
|
||||
public:
|
||||
FuncLink()
|
||||
: Func(Policy::epall)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncListXAttr : public Func
|
||||
{
|
||||
public:
|
||||
FuncListXAttr()
|
||||
: Func(Policy::ff)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncMkdir : public Func
|
||||
{
|
||||
public:
|
||||
FuncMkdir()
|
||||
: Func(Policy::epmfs)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncMknod : public Func
|
||||
{
|
||||
public:
|
||||
FuncMknod()
|
||||
: Func(Policy::epmfs)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncOpen : public Func
|
||||
{
|
||||
public:
|
||||
FuncOpen()
|
||||
: Func(Policy::ff)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncReadlink : public Func
|
||||
{
|
||||
public:
|
||||
FuncReadlink()
|
||||
: Func(Policy::ff)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncRemoveXAttr : public Func
|
||||
{
|
||||
public:
|
||||
FuncRemoveXAttr()
|
||||
: Func(Policy::epall)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncRename : public Func
|
||||
{
|
||||
public:
|
||||
FuncRename()
|
||||
: Func(Policy::epall)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncRmdir : public Func
|
||||
{
|
||||
public:
|
||||
FuncRmdir()
|
||||
: Func(Policy::epall)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncSetXAttr : public Func
|
||||
{
|
||||
public:
|
||||
FuncSetXAttr()
|
||||
: Func(Policy::epall)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncSymlink : public Func
|
||||
{
|
||||
public:
|
||||
FuncSymlink()
|
||||
: Func(Policy::epmfs)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncTruncate : public Func
|
||||
{
|
||||
public:
|
||||
FuncTruncate()
|
||||
: Func(Policy::epall)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncUnlink : public Func
|
||||
{
|
||||
public:
|
||||
FuncUnlink()
|
||||
: Func(Policy::epall)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncUtimens : public Func
|
||||
{
|
||||
public:
|
||||
FuncUtimens()
|
||||
: Func(Policy::epall)
|
||||
{
|
||||
}
|
||||
};
|
||||
90
src/func_category.cpp
Normal file
90
src/func_category.cpp
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#include "func_category.hpp"
|
||||
#include "str.hpp"
|
||||
|
||||
#include "buildvector.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
int
|
||||
FuncCategory::from_string(const std::string &s_)
|
||||
{
|
||||
const Policy *tmp;
|
||||
|
||||
tmp = &Policy::find(s_);
|
||||
if(tmp == &Policy::invalid)
|
||||
return -EINVAL;
|
||||
|
||||
for(uint64_t i = 0; i < _funcs.size(); i++)
|
||||
_funcs[i]->policy = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string
|
||||
FuncCategory::to_string(void) const
|
||||
{
|
||||
std::vector<std::string> rv;
|
||||
|
||||
for(uint64_t i = 0; i < _funcs.size(); i++)
|
||||
rv.push_back(_funcs[i]->policy->to_string());
|
||||
|
||||
std::sort(rv.begin(),rv.end());
|
||||
rv.erase(std::unique(rv.begin(),rv.end()),rv.end());
|
||||
|
||||
return str::join(rv,',');
|
||||
}
|
||||
|
||||
FuncCategoryCreate::FuncCategoryCreate(Funcs &funcs_)
|
||||
{
|
||||
_funcs = buildvector<Func*>
|
||||
(&funcs_.create)
|
||||
(&funcs_.mkdir)
|
||||
(&funcs_.mknod)
|
||||
(&funcs_.symlink);
|
||||
}
|
||||
|
||||
FuncCategoryAction::FuncCategoryAction(Funcs &funcs_)
|
||||
{
|
||||
_funcs = buildvector<Func*>
|
||||
(&funcs_.chmod)
|
||||
(&funcs_.chown)
|
||||
(&funcs_.link)
|
||||
(&funcs_.removexattr)
|
||||
(&funcs_.rename)
|
||||
(&funcs_.rmdir)
|
||||
(&funcs_.setxattr)
|
||||
(&funcs_.truncate)
|
||||
(&funcs_.unlink)
|
||||
(&funcs_.utimens);
|
||||
}
|
||||
|
||||
FuncCategorySearch::FuncCategorySearch(Funcs &funcs_)
|
||||
{
|
||||
_funcs = buildvector<Func*>
|
||||
(&funcs_.access)
|
||||
(&funcs_.getattr)
|
||||
(&funcs_.getxattr)
|
||||
(&funcs_.listxattr)
|
||||
(&funcs_.open)
|
||||
(&funcs_.readlink);
|
||||
}
|
||||
69
src/func_category.hpp
Normal file
69
src/func_category.hpp
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, 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 "funcs.hpp"
|
||||
#include "tofrom_string.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class FuncCategory : public ToFromString
|
||||
{
|
||||
public:
|
||||
int from_string(const std::string &);
|
||||
std::string to_string(void) const;
|
||||
|
||||
protected:
|
||||
std::vector<Func*> _funcs;
|
||||
};
|
||||
|
||||
class FuncCategoryCreate : public FuncCategory
|
||||
{
|
||||
public:
|
||||
FuncCategoryCreate(Funcs &funcs_);
|
||||
};
|
||||
|
||||
class FuncCategoryAction : public FuncCategory
|
||||
{
|
||||
public:
|
||||
FuncCategoryAction(Funcs &funcs_);
|
||||
};
|
||||
|
||||
class FuncCategorySearch : public FuncCategory
|
||||
{
|
||||
public:
|
||||
FuncCategorySearch(Funcs &funcs_);
|
||||
};
|
||||
|
||||
class FuncCategories
|
||||
{
|
||||
public:
|
||||
FuncCategories(Funcs &funcs_)
|
||||
: action(funcs_),
|
||||
create(funcs_),
|
||||
search(funcs_)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
FuncCategoryAction action;
|
||||
FuncCategoryCreate create;
|
||||
FuncCategorySearch search;
|
||||
};
|
||||
46
src/funcs.hpp
Normal file
46
src/funcs.hpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, 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 "func.hpp"
|
||||
|
||||
class Funcs
|
||||
{
|
||||
public:
|
||||
FuncAccess access;
|
||||
FuncChmod chmod;
|
||||
FuncChown chown;
|
||||
FuncCreate create;
|
||||
FuncGetAttr getattr;
|
||||
FuncGetXAttr getxattr;
|
||||
FuncLink link;
|
||||
FuncListXAttr listxattr;
|
||||
FuncMkdir mkdir;
|
||||
FuncMknod mknod;
|
||||
FuncOpen open;
|
||||
FuncReadlink readlink;
|
||||
FuncRemoveXAttr removexattr;
|
||||
FuncRename rename;
|
||||
FuncRmdir rmdir;
|
||||
FuncSetXAttr setxattr;
|
||||
FuncSymlink symlink;
|
||||
FuncTruncate truncate;
|
||||
FuncUnlink unlink;
|
||||
FuncUtimens utimens;
|
||||
};
|
||||
|
|
@ -14,16 +14,15 @@
|
|||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "config.hpp"
|
||||
#include "errno.hpp"
|
||||
#include "fs_base_access.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
|
|
@ -39,9 +38,9 @@ namespace l
|
|||
{
|
||||
int rv;
|
||||
string fullpath;
|
||||
vector<const string*> basepaths;
|
||||
vector<string> basepaths;
|
||||
|
||||
rv = searchFunc(branches_,fusepath,minfreespace,basepaths);
|
||||
rv = searchFunc(branches_,fusepath,minfreespace,&basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
|
@ -59,12 +58,11 @@ namespace FUSE
|
|||
access(const char *fusepath,
|
||||
int mask)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
return l::access(config.access,
|
||||
return l::access(config.func.access.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include "fs_base_chmod.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rv.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
|
|
@ -34,7 +33,7 @@ namespace l
|
|||
{
|
||||
static
|
||||
int
|
||||
chmod_loop_core(const string *basepath_,
|
||||
chmod_loop_core(const string &basepath_,
|
||||
const char *fusepath_,
|
||||
const mode_t mode_,
|
||||
const int error_)
|
||||
|
|
@ -51,9 +50,9 @@ namespace l
|
|||
|
||||
static
|
||||
int
|
||||
chmod_loop(const vector<const string*> &basepaths_,
|
||||
const char *fusepath_,
|
||||
const mode_t mode_)
|
||||
chmod_loop(const vector<string> &basepaths_,
|
||||
const char *fusepath_,
|
||||
const mode_t mode_)
|
||||
{
|
||||
int error;
|
||||
|
||||
|
|
@ -75,9 +74,9 @@ namespace l
|
|||
const mode_t mode_)
|
||||
{
|
||||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
vector<string> basepaths;
|
||||
|
||||
rv = actionFunc_(branches_,fusepath_,minfreespace_,basepaths);
|
||||
rv = actionFunc_(branches_,fusepath_,minfreespace_,&basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
|
@ -91,12 +90,11 @@ namespace FUSE
|
|||
chmod(const char *fusepath_,
|
||||
mode_t mode_)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
return l::chmod(config.chmod,
|
||||
return l::chmod(config.func.chmod.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath_,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include "fs_base_chown.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rv.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
|
|
@ -34,7 +33,7 @@ namespace l
|
|||
{
|
||||
static
|
||||
int
|
||||
chown_loop_core(const string *basepath_,
|
||||
chown_loop_core(const string &basepath_,
|
||||
const char *fusepath_,
|
||||
const uid_t uid_,
|
||||
const gid_t gid_,
|
||||
|
|
@ -52,10 +51,10 @@ namespace l
|
|||
|
||||
static
|
||||
int
|
||||
chown_loop(const vector<const string*> &basepaths_,
|
||||
const char *fusepath_,
|
||||
const uid_t uid_,
|
||||
const gid_t gid_)
|
||||
chown_loop(const vector<string> &basepaths_,
|
||||
const char *fusepath_,
|
||||
const uid_t uid_,
|
||||
const gid_t gid_)
|
||||
{
|
||||
int error;
|
||||
|
||||
|
|
@ -78,9 +77,9 @@ namespace l
|
|||
const gid_t gid_)
|
||||
{
|
||||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
vector<string> basepaths;
|
||||
|
||||
rv = actionFunc_(branches_,fusepath_,minfreespace_,basepaths);
|
||||
rv = actionFunc_(branches_,fusepath_,minfreespace_,&basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
|
@ -95,12 +94,11 @@ namespace FUSE
|
|||
uid_t uid_,
|
||||
gid_t gid_)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
return l::chown(config.chown,
|
||||
return l::chown(config.func.chown.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath_,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
#include "fs_base_open.hpp"
|
||||
#include "fs_clonepath.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
|
|
@ -61,27 +60,27 @@ namespace l
|
|||
{
|
||||
switch(config_.cache_files)
|
||||
{
|
||||
case CacheFiles::LIBFUSE:
|
||||
case CacheFiles::ENUM::LIBFUSE:
|
||||
ffi_->direct_io = config_.direct_io;
|
||||
ffi_->keep_cache = config_.kernel_cache;
|
||||
ffi_->auto_cache = config_.auto_cache;
|
||||
break;
|
||||
case CacheFiles::OFF:
|
||||
case CacheFiles::ENUM::OFF:
|
||||
ffi_->direct_io = 1;
|
||||
ffi_->keep_cache = 0;
|
||||
ffi_->auto_cache = 0;
|
||||
break;
|
||||
case CacheFiles::PARTIAL:
|
||||
case CacheFiles::ENUM::PARTIAL:
|
||||
ffi_->direct_io = 0;
|
||||
ffi_->keep_cache = 0;
|
||||
ffi_->auto_cache = 0;
|
||||
break;
|
||||
case CacheFiles::FULL:
|
||||
case CacheFiles::ENUM::FULL:
|
||||
ffi_->direct_io = 0;
|
||||
ffi_->keep_cache = 1;
|
||||
ffi_->auto_cache = 0;
|
||||
break;
|
||||
case CacheFiles::AUTO_FULL:
|
||||
case CacheFiles::ENUM::AUTO_FULL:
|
||||
ffi_->direct_io = 0;
|
||||
ffi_->keep_cache = 0;
|
||||
ffi_->auto_cache = 1;
|
||||
|
|
@ -140,24 +139,24 @@ namespace l
|
|||
int rv;
|
||||
string fullpath;
|
||||
string fusedirpath;
|
||||
vector<const string*> createpaths;
|
||||
vector<const string*> existingpaths;
|
||||
vector<string> createpaths;
|
||||
vector<string> existingpaths;
|
||||
|
||||
fusedirpath = fs::path::dirname(fusepath_);
|
||||
|
||||
rv = searchFunc_(branches_,fusedirpath,minfreespace_,existingpaths);
|
||||
rv = searchFunc_(branches_,fusedirpath,minfreespace_,&existingpaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
rv = createFunc_(branches_,fusedirpath,minfreespace_,createpaths);
|
||||
rv = createFunc_(branches_,fusedirpath,minfreespace_,&createpaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
rv = fs::clonepath_as_root(*existingpaths[0],*createpaths[0],fusedirpath);
|
||||
rv = fs::clonepath_as_root(existingpaths[0],createpaths[0],fusedirpath);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
return l::create_core(*createpaths[0],
|
||||
return l::create_core(createpaths[0],
|
||||
fusepath_,
|
||||
mode_,
|
||||
umask_,
|
||||
|
|
@ -173,18 +172,17 @@ namespace FUSE
|
|||
mode_t mode_,
|
||||
fuse_file_info *ffi_)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
l::config_to_ffi_flags(config,ffi_);
|
||||
|
||||
if(config.writeback_cache)
|
||||
l::tweak_flags_writeback_cache(&ffi_->flags);
|
||||
|
||||
return l::create(config.getattr,
|
||||
config.create,
|
||||
return l::create(config.func.getattr.policy,
|
||||
config.func.create.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath_,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.hpp"
|
||||
#include "errno.hpp"
|
||||
#include "fileinfo.hpp"
|
||||
#include "fs_base_stat.hpp"
|
||||
|
|
@ -43,13 +44,22 @@ namespace l
|
|||
namespace FUSE
|
||||
{
|
||||
int
|
||||
fgetattr(const char *fusepath_,
|
||||
struct stat *st_,
|
||||
fuse_file_info *ffi_)
|
||||
fgetattr(const char *fusepath_,
|
||||
struct stat *st_,
|
||||
fuse_file_info *ffi_,
|
||||
fuse_timeouts_t *timeout_)
|
||||
{
|
||||
int rv;
|
||||
const Config &config = Config::ro();
|
||||
FileInfo *fi = reinterpret_cast<FileInfo*>(ffi_->fh);
|
||||
|
||||
return l::fgetattr(fi->fd,st_);
|
||||
rv = l::fgetattr(fi->fd,st_);
|
||||
|
||||
timeout_->entry = ((rv >= 0) ?
|
||||
config.cache_entry :
|
||||
config.cache_negative_entry);
|
||||
timeout_->attr = config.cache_attr;
|
||||
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@
|
|||
namespace FUSE
|
||||
{
|
||||
int
|
||||
fgetattr(const char *fusepath_,
|
||||
struct stat *st_,
|
||||
fuse_file_info *ffi_);
|
||||
fgetattr(const char *fusepath,
|
||||
struct stat *st,
|
||||
fuse_file_info *ffi,
|
||||
fuse_timeouts_t *timeout);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include "fs_base_stat.hpp"
|
||||
#include "fs_inode.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "symlinkify.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
|
|
@ -70,9 +69,9 @@ namespace l
|
|||
{
|
||||
int rv;
|
||||
string fullpath;
|
||||
vector<const string*> basepaths;
|
||||
vector<string> basepaths;
|
||||
|
||||
rv = searchFunc_(branches_,fusepath_,minfreespace_,basepaths);
|
||||
rv = searchFunc_(branches_,fusepath_,minfreespace_,&basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
|
@ -94,24 +93,32 @@ namespace l
|
|||
namespace FUSE
|
||||
{
|
||||
int
|
||||
getattr(const char *fusepath_,
|
||||
struct stat *st_)
|
||||
getattr(const char *fusepath_,
|
||||
struct stat *st_,
|
||||
fuse_timeouts_t *timeout_)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
int rv;
|
||||
const Config &config = Config::ro();
|
||||
|
||||
if(fusepath_ == config.controlfile)
|
||||
return l::getattr_controlfile(st_);
|
||||
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
return l::getattr(config.getattr,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath_,
|
||||
st_,
|
||||
config.symlinkify,
|
||||
config.symlinkify_timeout);
|
||||
rv = l::getattr(config.func.getattr.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath_,
|
||||
st_,
|
||||
config.symlinkify,
|
||||
config.symlinkify_timeout);
|
||||
|
||||
timeout_->entry = ((rv >= 0) ?
|
||||
config.cache_entry :
|
||||
config.cache_negative_entry);
|
||||
timeout_->attr = config.cache_attr;
|
||||
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
namespace FUSE
|
||||
{
|
||||
int
|
||||
getattr(const char *fusepath_,
|
||||
struct stat *buf_);
|
||||
getattr(const char *fusepath,
|
||||
struct stat *buf,
|
||||
fuse_timeouts_t *timeout);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include "fs_base_getxattr.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "fs_statvfs_cache.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "str.hpp"
|
||||
#include "ugid.hpp"
|
||||
#include "version.hpp"
|
||||
|
|
@ -27,7 +26,6 @@
|
|||
#include <fuse.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -39,7 +37,6 @@ static const char SECURITY_CAPABILITY[] = "security.capability";
|
|||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::set;
|
||||
|
||||
namespace l
|
||||
{
|
||||
|
|
@ -64,254 +61,6 @@ namespace l
|
|||
return ((rv == -1) ? -errno : rv);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile_fusefunc_policy(const Config &config_,
|
||||
const string &attr_,
|
||||
string &attrvalue_)
|
||||
{
|
||||
FuseFunc fusefunc;
|
||||
|
||||
fusefunc = FuseFunc::find(attr_);
|
||||
if(fusefunc != FuseFunc::invalid)
|
||||
attrvalue_ = (std::string)*config_.policies[(FuseFunc::Enum::Type)*fusefunc];
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile_category_policy(const Config &config_,
|
||||
const string &attr_,
|
||||
string &attrvalue_)
|
||||
{
|
||||
Category cat;
|
||||
|
||||
cat = Category::find(attr_);
|
||||
if(cat != Category::invalid)
|
||||
{
|
||||
vector<string> policies;
|
||||
for(int i = FuseFunc::Enum::BEGIN; i < FuseFunc::Enum::END; i++)
|
||||
{
|
||||
if(cat == (Category::Enum::Type)*FuseFunc::fusefuncs[i])
|
||||
policies.push_back(*config_.policies[i]);
|
||||
}
|
||||
|
||||
std::sort(policies.begin(),policies.end());
|
||||
policies.erase(std::unique(policies.begin(),policies.end()),
|
||||
policies.end());
|
||||
attrvalue_ = str::join(policies,',');
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile_srcmounts(const Config &config_,
|
||||
string &attrvalue_)
|
||||
{
|
||||
attrvalue_ = config_.branches.to_string();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile_branches(const Config &config_,
|
||||
string &attrvalue_)
|
||||
{
|
||||
attrvalue_ = config_.branches.to_string(true);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile_uint64_t(const uint64_t uint_,
|
||||
string &attrvalue_)
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
||||
os << uint_;
|
||||
|
||||
attrvalue_ = os.str();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile_double(const double d_,
|
||||
string &attrvalue_)
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
||||
os << d_;
|
||||
|
||||
attrvalue_ = os.str();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile_time_t(const time_t time,
|
||||
string &attrvalue)
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
||||
os << time;
|
||||
|
||||
attrvalue = os.str();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile_bool(const bool boolvalue,
|
||||
string &attrvalue)
|
||||
{
|
||||
attrvalue = (boolvalue ? "true" : "false");
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile_errno(const int errno_,
|
||||
string &attrvalue)
|
||||
{
|
||||
switch(errno_)
|
||||
{
|
||||
case 0:
|
||||
attrvalue = "passthrough";
|
||||
break;
|
||||
case ENOATTR:
|
||||
attrvalue = "noattr";
|
||||
break;
|
||||
case ENOSYS:
|
||||
attrvalue = "nosys";
|
||||
break;
|
||||
default:
|
||||
attrvalue = "ERROR";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile_statfs(const Config::StatFS::Enum enum_,
|
||||
string &attrvalue_)
|
||||
{
|
||||
switch(enum_)
|
||||
{
|
||||
case Config::StatFS::BASE:
|
||||
attrvalue_ = "base";
|
||||
break;
|
||||
case Config::StatFS::FULL:
|
||||
attrvalue_ = "full";
|
||||
break;
|
||||
default:
|
||||
attrvalue_ = "ERROR";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile_statfsignore(const Config::StatFSIgnore::Enum enum_,
|
||||
string &attrvalue_)
|
||||
{
|
||||
switch(enum_)
|
||||
{
|
||||
case Config::StatFSIgnore::NONE:
|
||||
attrvalue_ = "none";
|
||||
break;
|
||||
case Config::StatFSIgnore::RO:
|
||||
attrvalue_ = "ro";
|
||||
break;
|
||||
case Config::StatFSIgnore::NC:
|
||||
attrvalue_ = "nc";
|
||||
break;
|
||||
default:
|
||||
attrvalue_ = "ERROR";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile(const Config::CacheFiles &cache_files_,
|
||||
string &attrvalue_)
|
||||
{
|
||||
attrvalue_ = (string)cache_files_;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile(const uint16_t &uint16_,
|
||||
string &attrvalue_)
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
||||
os << uint16_;
|
||||
|
||||
attrvalue_ = os.str();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile_policies(const Config &config,
|
||||
string &attrvalue)
|
||||
{
|
||||
size_t i = Policy::Enum::begin();
|
||||
|
||||
attrvalue = (string)Policy::policies[i];
|
||||
for(i++; i < Policy::Enum::end(); i++)
|
||||
attrvalue += ',' + (string)Policy::policies[i];
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile_version(string &attrvalue)
|
||||
{
|
||||
attrvalue = MERGERFS_VERSION;
|
||||
if(attrvalue.empty())
|
||||
attrvalue = "unknown_possible_problem_with_build";
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile_pid(string &attrvalue)
|
||||
{
|
||||
int pid;
|
||||
char buf[32];
|
||||
|
||||
pid = getpid();
|
||||
snprintf(buf,sizeof(buf),"%d",pid);
|
||||
|
||||
attrvalue = buf;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile_cache_attr(string &attrvalue)
|
||||
{
|
||||
double d;
|
||||
|
||||
d = fuse_config_get_attr_timeout(fuse_get_context()->fuse);
|
||||
|
||||
l::getxattr_controlfile_double(d,attrvalue);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile_cache_entry(string &attrvalue)
|
||||
{
|
||||
double d;
|
||||
|
||||
d = fuse_config_get_entry_timeout(fuse_get_context()->fuse);
|
||||
|
||||
l::getxattr_controlfile_double(d,attrvalue);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
getxattr_controlfile_cache_negative_entry(string &attrvalue)
|
||||
{
|
||||
double d;
|
||||
|
||||
d = fuse_config_get_negative_entry_timeout(fuse_get_context()->fuse);
|
||||
|
||||
l::getxattr_controlfile_double(d,attrvalue);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
getxattr_controlfile(const Config &config,
|
||||
|
|
@ -319,93 +68,21 @@ namespace l
|
|||
char *buf,
|
||||
const size_t count)
|
||||
{
|
||||
int rv;
|
||||
size_t len;
|
||||
string attrvalue;
|
||||
string key;
|
||||
string val;
|
||||
vector<string> attr;
|
||||
|
||||
str::split(attr,attrname,'.');
|
||||
if((attr[0] != "user") || (attr[1] != "mergerfs"))
|
||||
if(!str::startswith(attrname,"user.mergerfs."))
|
||||
return -ENOATTR;
|
||||
|
||||
switch(attr.size())
|
||||
{
|
||||
case 3:
|
||||
if(attr[2] == "srcmounts")
|
||||
l::getxattr_controlfile_srcmounts(config,attrvalue);
|
||||
else if(attr[2] == "branches")
|
||||
l::getxattr_controlfile_branches(config,attrvalue);
|
||||
else if(attr[2] == "minfreespace")
|
||||
l::getxattr_controlfile_uint64_t(config.minfreespace,attrvalue);
|
||||
else if(attr[2] == "moveonenospc")
|
||||
l::getxattr_controlfile_bool(config.moveonenospc,attrvalue);
|
||||
else if(attr[2] == "dropcacheonclose")
|
||||
l::getxattr_controlfile_bool(config.dropcacheonclose,attrvalue);
|
||||
else if(attr[2] == "symlinkify")
|
||||
l::getxattr_controlfile_bool(config.symlinkify,attrvalue);
|
||||
else if(attr[2] == "symlinkify_timeout")
|
||||
l::getxattr_controlfile_time_t(config.symlinkify_timeout,attrvalue);
|
||||
else if(attr[2] == "nullrw")
|
||||
l::getxattr_controlfile_bool(config.nullrw,attrvalue);
|
||||
else if(attr[2] == "ignorepponrename")
|
||||
l::getxattr_controlfile_bool(config.ignorepponrename,attrvalue);
|
||||
else if(attr[2] == "security_capability")
|
||||
l::getxattr_controlfile_bool(config.security_capability,attrvalue);
|
||||
else if(attr[2] == "xattr")
|
||||
l::getxattr_controlfile_errno(config.xattr,attrvalue);
|
||||
else if(attr[2] == "link_cow")
|
||||
l::getxattr_controlfile_bool(config.link_cow,attrvalue);
|
||||
else if(attr[2] == "statfs")
|
||||
l::getxattr_controlfile_statfs(config.statfs,attrvalue);
|
||||
else if(attr[2] == "statfs_ignore")
|
||||
l::getxattr_controlfile_statfsignore(config.statfs_ignore,attrvalue);
|
||||
else if(attr[2] == "policies")
|
||||
l::getxattr_controlfile_policies(config,attrvalue);
|
||||
else if(attr[2] == "version")
|
||||
l::getxattr_controlfile_version(attrvalue);
|
||||
else if(attr[2] == "pid")
|
||||
l::getxattr_controlfile_pid(attrvalue);
|
||||
else if(attr[2] == "direct_io")
|
||||
l::getxattr_controlfile_bool(config.direct_io,attrvalue);
|
||||
else if(attr[2] == "posix_acl")
|
||||
l::getxattr_controlfile_bool(config.posix_acl,attrvalue);
|
||||
else if(attr[2] == "async_read")
|
||||
l::getxattr_controlfile_bool(config.async_read,attrvalue);
|
||||
else if(attr[2] == "fuse_msg_size")
|
||||
l::getxattr_controlfile(config.fuse_msg_size,attrvalue);
|
||||
else if(attr[2] == "readdirplus")
|
||||
l::getxattr_controlfile_bool(config.readdirplus,attrvalue);
|
||||
break;
|
||||
key = &attrname[14];
|
||||
rv = config.get(key,&val);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
|
||||
case 4:
|
||||
if(attr[2] == "category")
|
||||
l::getxattr_controlfile_category_policy(config,attr[3],attrvalue);
|
||||
else if(attr[2] == "func")
|
||||
l::getxattr_controlfile_fusefunc_policy(config,attr[3],attrvalue);
|
||||
else if((attr[2] == "cache") && (attr[3] == "open"))
|
||||
l::getxattr_controlfile_uint64_t(config.open_cache.timeout,attrvalue);
|
||||
else if((attr[2] == "cache") && (attr[3] == "statfs"))
|
||||
l::getxattr_controlfile_uint64_t(fs::statvfs_cache_timeout(),attrvalue);
|
||||
else if((attr[2] == "cache") && (attr[3] == "attr"))
|
||||
l::getxattr_controlfile_cache_attr(attrvalue);
|
||||
else if((attr[2] == "cache") && (attr[3] == "entry"))
|
||||
l::getxattr_controlfile_cache_entry(attrvalue);
|
||||
else if((attr[2] == "cache") && (attr[3] == "negative_entry"))
|
||||
l::getxattr_controlfile_cache_negative_entry(attrvalue);
|
||||
else if((attr[2] == "cache") && (attr[3] == "symlinks"))
|
||||
l::getxattr_controlfile_bool(config.cache_symlinks,attrvalue);
|
||||
else if((attr[2] == "cache") && (attr[3] == "readdir"))
|
||||
l::getxattr_controlfile_bool(config.cache_readdir,attrvalue);
|
||||
else if((attr[2] == "cache") && (attr[3] == "files"))
|
||||
l::getxattr_controlfile(config.cache_files,attrvalue);
|
||||
else if((attr[2] == "cache") && (attr[3] == "writeback"))
|
||||
l::getxattr_controlfile_bool(config.writeback_cache,attrvalue);
|
||||
break;
|
||||
}
|
||||
|
||||
if(attrvalue.empty())
|
||||
return -ENOATTR;
|
||||
|
||||
len = attrvalue.size();
|
||||
len = val.size();
|
||||
|
||||
if(count == 0)
|
||||
return len;
|
||||
|
|
@ -413,7 +90,7 @@ namespace l
|
|||
if(count < len)
|
||||
return -ERANGE;
|
||||
|
||||
memcpy(buf,attrvalue.c_str(),len);
|
||||
memcpy(buf,val.c_str(),len);
|
||||
|
||||
return (int)len;
|
||||
}
|
||||
|
|
@ -495,16 +172,16 @@ namespace l
|
|||
{
|
||||
int rv;
|
||||
string fullpath;
|
||||
vector<const string*> basepaths;
|
||||
vector<string> basepaths;
|
||||
|
||||
rv = searchFunc(branches_,fusepath,minfreespace,basepaths);
|
||||
rv = searchFunc(branches_,fusepath,minfreespace,&basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
fullpath = fs::path::make(basepaths[0],fusepath);
|
||||
|
||||
if(str::isprefix(attrname,"user.mergerfs."))
|
||||
return l::getxattr_user_mergerfs(*basepaths[0],
|
||||
if(str::startswith(attrname,"user.mergerfs."))
|
||||
return l::getxattr_user_mergerfs(basepaths[0],
|
||||
fusepath,
|
||||
fullpath,
|
||||
branches_,
|
||||
|
|
@ -524,8 +201,7 @@ namespace FUSE
|
|||
char *buf,
|
||||
size_t count)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const Config &config = Config::ro();
|
||||
|
||||
if(fusepath == config.controlfile)
|
||||
return l::getxattr_controlfile(config,
|
||||
|
|
@ -537,13 +213,13 @@ namespace FUSE
|
|||
l::is_attrname_security_capability(attrname))
|
||||
return -ENOATTR;
|
||||
|
||||
if(config.xattr)
|
||||
return -config.xattr;
|
||||
if(config.xattr.to_int())
|
||||
return -config.xattr.to_int();
|
||||
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
return l::getxattr(config.getxattr,
|
||||
return l::getxattr(config.func.getxattr.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath,
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ namespace l
|
|||
void
|
||||
want_if_capable(fuse_conn_info *conn_,
|
||||
const int flag_,
|
||||
bool *want_)
|
||||
ConfigBOOL *want_)
|
||||
{
|
||||
if(*want_ && l::capable(conn_,flag_))
|
||||
{
|
||||
|
|
@ -83,24 +83,24 @@ namespace FUSE
|
|||
void *
|
||||
init(fuse_conn_info *conn_)
|
||||
{
|
||||
Config &c = Config::get_writable();
|
||||
Config &config = Config::rw();
|
||||
|
||||
ugid::init();
|
||||
|
||||
l::want_if_capable(conn_,FUSE_CAP_ASYNC_DIO);
|
||||
l::want_if_capable(conn_,FUSE_CAP_ASYNC_READ,&c.async_read);
|
||||
l::want_if_capable(conn_,FUSE_CAP_ASYNC_READ,&config.async_read);
|
||||
l::want_if_capable(conn_,FUSE_CAP_ATOMIC_O_TRUNC);
|
||||
l::want_if_capable(conn_,FUSE_CAP_BIG_WRITES);
|
||||
l::want_if_capable(conn_,FUSE_CAP_CACHE_SYMLINKS,&c.cache_symlinks);
|
||||
l::want_if_capable(conn_,FUSE_CAP_CACHE_SYMLINKS,&config.cache_symlinks);
|
||||
l::want_if_capable(conn_,FUSE_CAP_DONT_MASK);
|
||||
l::want_if_capable(conn_,FUSE_CAP_IOCTL_DIR);
|
||||
l::want_if_capable(conn_,FUSE_CAP_PARALLEL_DIROPS);
|
||||
l::want_if_capable(conn_,FUSE_CAP_READDIR_PLUS,&c.readdirplus);
|
||||
l::want_if_capable(conn_,FUSE_CAP_READDIR_PLUS,&config.readdirplus);
|
||||
//l::want_if_capable(conn_,FUSE_CAP_READDIR_PLUS_AUTO);
|
||||
l::want_if_capable(conn_,FUSE_CAP_POSIX_ACL,&c.posix_acl);
|
||||
l::want_if_capable(conn_,FUSE_CAP_WRITEBACK_CACHE,&c.writeback_cache);
|
||||
l::want_if_capable_max_pages(conn_,c);
|
||||
l::want_if_capable(conn_,FUSE_CAP_POSIX_ACL,&config.posix_acl);
|
||||
l::want_if_capable(conn_,FUSE_CAP_WRITEBACK_CACHE,&config.writeback_cache);
|
||||
l::want_if_capable_max_pages(conn_,config);
|
||||
|
||||
return &c;
|
||||
return &config;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
#include "fs_base_ioctl.hpp"
|
||||
#include "fs_base_open.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "str.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
|
|
@ -32,10 +32,23 @@
|
|||
#include <vector>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
typedef char IOCTL_BUF[4096];
|
||||
#define IOCTL_APP_TYPE 0xDF
|
||||
//#define IOCTL_READ_KEYS 0xD000DF00
|
||||
//#define IOCTL_READ_VAL 0xD000DF01
|
||||
//#define IOCTL_WRITE_VAL 0x5000DF02
|
||||
//#define IOCTL_FILE_INFO 0xD000DF03
|
||||
#define IOCTL_READ_KEYS _IOWR(IOCTL_APP_TYPE,0,IOCTL_BUF)
|
||||
#define IOCTL_READ_VAL _IOWR(IOCTL_APP_TYPE,1,IOCTL_BUF)
|
||||
#define IOCTL_WRITE_VAL _IOW(IOCTL_APP_TYPE,2,IOCTL_BUF)
|
||||
#define IOCTL_FILE_INFO _IOWR(IOCTL_APP_TYPE,3,IOCTL_BUF)
|
||||
|
||||
|
||||
#ifndef FS_IOC_GETFLAGS
|
||||
# define FS_IOC_GETFLAGS _IOR('f',1,long)
|
||||
#endif
|
||||
|
|
@ -69,7 +82,7 @@ using std::vector;
|
|||
is not possible to safely handle the situation.
|
||||
|
||||
https://lwn.net/Articles/575846/
|
||||
*/
|
||||
*/
|
||||
|
||||
namespace l
|
||||
{
|
||||
|
|
@ -107,8 +120,8 @@ namespace l
|
|||
void *data_,
|
||||
uint32_t *out_bufsz_)
|
||||
{
|
||||
FileInfo *fi = reinterpret_cast<FileInfo*>(ffi_->fh);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
FileInfo *fi = reinterpret_cast<FileInfo*>(ffi_->fh);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
return l::ioctl(fi->fd,cmd_,data_,out_bufsz_);
|
||||
|
|
@ -131,16 +144,15 @@ namespace l
|
|||
int fd;
|
||||
int rv;
|
||||
string fullpath;
|
||||
vector<const string*> basepaths;
|
||||
vector<string> basepaths;
|
||||
|
||||
rv = searchFunc_(branches_,fusepath_,minfreespace_,basepaths);
|
||||
rv = searchFunc_(branches_,fusepath_,minfreespace_,&basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
fullpath = fs::path::make(basepaths[0],fusepath_);
|
||||
|
||||
const int flags = O_RDONLY | O_NOATIME | O_NONBLOCK;
|
||||
fd = fs::open(fullpath,flags);
|
||||
fd = fs::open(fullpath,O_RDONLY|O_NOATIME|O_NONBLOCK);
|
||||
if(fd == -1)
|
||||
return -errno;
|
||||
|
||||
|
|
@ -158,13 +170,12 @@ namespace l
|
|||
void *data_,
|
||||
uint32_t *out_bufsz_)
|
||||
{
|
||||
DirInfo *di = reinterpret_cast<DirInfo*>(ffi_->fh);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
DirInfo *di = reinterpret_cast<DirInfo*>(ffi_->fh);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
return l::ioctl_dir_base(config.open,
|
||||
return l::ioctl_dir_base(config.func.open.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
di->fusepath.c_str(),
|
||||
|
|
@ -172,19 +183,217 @@ namespace l
|
|||
data_,
|
||||
out_bufsz_);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
strcpy(const std::string &s_,
|
||||
void *data_)
|
||||
{
|
||||
char *data = (char*)data_;
|
||||
|
||||
if(s_.size() >= (sizeof(IOCTL_BUF) - 1))
|
||||
return -ERANGE;
|
||||
|
||||
memcpy(data,s_.c_str(),s_.size());
|
||||
data[s_.size()] = '\0';
|
||||
|
||||
return s_.size();
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
read_keys(void *data_)
|
||||
{
|
||||
std::string keys;
|
||||
const Config &config = Config::ro();
|
||||
|
||||
config.keys(keys);
|
||||
|
||||
return l::strcpy(keys,data_);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
read_val(void *data_)
|
||||
{
|
||||
int rv;
|
||||
char *data;
|
||||
std::string key;
|
||||
std::string val;
|
||||
const Config &config = Config::ro();
|
||||
|
||||
data = (char*)data_;
|
||||
data[sizeof(IOCTL_BUF) - 1] = '\0';
|
||||
|
||||
key = data;
|
||||
rv = config.get(key,&val);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
|
||||
return l::strcpy(val,data_);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
write_val(void *data_)
|
||||
{
|
||||
char *data;
|
||||
std::string kv;
|
||||
std::string key;
|
||||
std::string val;
|
||||
Config &config = Config::rw();
|
||||
|
||||
data = (char*)data_;
|
||||
data[sizeof(IOCTL_BUF) - 1] = '\0';
|
||||
|
||||
kv = data;
|
||||
str::splitkv(kv,'=',&key,&val);
|
||||
|
||||
return config.set(key,val);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
file_basepath(Policy::Func::Search searchFunc_,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace_,
|
||||
const char *fusepath_,
|
||||
void *data_)
|
||||
{
|
||||
int rv;
|
||||
vector<string> basepaths;
|
||||
|
||||
rv = searchFunc_(branches_,fusepath_,minfreespace_,&basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
return l::strcpy(basepaths[0],data_);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
file_basepath(fuse_file_info *ffi_,
|
||||
void *data_)
|
||||
{
|
||||
const Config &config = Config::ro();
|
||||
std::string &fusepath = reinterpret_cast<FH*>(ffi_->fh)->fusepath;
|
||||
|
||||
return l::file_basepath(config.func.open.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath.c_str(),
|
||||
data_);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
file_relpath(fuse_file_info *ffi_,
|
||||
void *data_)
|
||||
{
|
||||
std::string &fusepath = reinterpret_cast<FH*>(ffi_->fh)->fusepath;
|
||||
|
||||
return l::strcpy(fusepath,data_);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
file_fullpath(Policy::Func::Search searchFunc_,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace_,
|
||||
const string &fusepath_,
|
||||
void *data_)
|
||||
{
|
||||
int rv;
|
||||
string fullpath;
|
||||
vector<string> basepaths;
|
||||
|
||||
rv = searchFunc_(branches_,fusepath_,minfreespace_,&basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
fullpath = fs::path::make(basepaths[0],fusepath_);
|
||||
|
||||
return l::strcpy(fullpath,data_);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
file_fullpath(fuse_file_info *ffi_,
|
||||
void *data_)
|
||||
{
|
||||
const Config &config = Config::ro();
|
||||
std::string &fusepath = reinterpret_cast<FH*>(ffi_->fh)->fusepath;
|
||||
|
||||
return l::file_fullpath(config.func.open.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath,
|
||||
data_);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
file_allpaths(fuse_file_info *ffi_,
|
||||
void *data_)
|
||||
{
|
||||
string concated;
|
||||
vector<string> paths;
|
||||
vector<string> branches;
|
||||
string &fusepath = reinterpret_cast<FH*>(ffi_->fh)->fusepath;
|
||||
const Config &config = Config::ro();
|
||||
|
||||
config.branches.to_paths(branches);
|
||||
|
||||
fs::findallfiles(branches,fusepath.c_str(),paths);
|
||||
|
||||
concated = str::join(paths,'\0');
|
||||
|
||||
return l::strcpy(concated,data_);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
file_info(fuse_file_info *ffi_,
|
||||
void *data_)
|
||||
{
|
||||
char *key = (char*)data_;
|
||||
|
||||
if(!strcmp("basepath",key))
|
||||
return l::file_basepath(ffi_,data_);
|
||||
if(!strcmp("relpath",key))
|
||||
return l::file_relpath(ffi_,data_);
|
||||
if(!strcmp("fullpath",key))
|
||||
return l::file_fullpath(ffi_,data_);
|
||||
if(!strcmp("allpaths",key))
|
||||
return l::file_allpaths(ffi_,data_);
|
||||
|
||||
return -ENOATTR;
|
||||
}
|
||||
}
|
||||
|
||||
namespace FUSE
|
||||
{
|
||||
int
|
||||
ioctl(const char *fusepath_,
|
||||
int cmd_,
|
||||
unsigned long cmd_,
|
||||
void *arg_,
|
||||
fuse_file_info *ffi_,
|
||||
unsigned int flags_,
|
||||
void *data_,
|
||||
uint32_t *out_bufsz_)
|
||||
{
|
||||
switch(cmd_)
|
||||
{
|
||||
case IOCTL_READ_KEYS:
|
||||
return l::read_keys(data_);
|
||||
case IOCTL_READ_VAL:
|
||||
return l::read_val(data_);
|
||||
case IOCTL_WRITE_VAL:
|
||||
return l::write_val(data_);
|
||||
case IOCTL_FILE_INFO:
|
||||
return l::file_info(ffi_,data_);
|
||||
}
|
||||
|
||||
if(flags_ & FUSE_IOCTL_DIR)
|
||||
return l::ioctl_dir(ffi_,cmd_,data_,out_bufsz_);
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace FUSE
|
|||
{
|
||||
int
|
||||
ioctl(const char *fusepath_,
|
||||
int cmd_,
|
||||
unsigned long cmd_,
|
||||
void *arg_,
|
||||
fuse_file_info *ffi_,
|
||||
unsigned int flags_,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include "fs_clonepath.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rv.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
|
|
@ -55,11 +54,11 @@ namespace l
|
|||
|
||||
static
|
||||
int
|
||||
link_create_path_loop(const vector<const string*> &oldbasepaths_,
|
||||
const string &newbasepath_,
|
||||
const char *oldfusepath_,
|
||||
const char *newfusepath_,
|
||||
const string &newfusedirpath_)
|
||||
link_create_path_loop(const vector<string> &oldbasepaths_,
|
||||
const string &newbasepath_,
|
||||
const char *oldfusepath_,
|
||||
const char *newfusepath_,
|
||||
const string &newfusedirpath_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
|
|
@ -67,11 +66,11 @@ namespace l
|
|||
error = -1;
|
||||
for(size_t i = 0, ei = oldbasepaths_.size(); i != ei; i++)
|
||||
{
|
||||
rv = fs::clonepath_as_root(newbasepath_,*oldbasepaths_[i],newfusedirpath_);
|
||||
rv = fs::clonepath_as_root(newbasepath_,oldbasepaths_[i],newfusedirpath_);
|
||||
if(rv == -1)
|
||||
error = error::calc(rv,error,errno);
|
||||
else
|
||||
error = l::link_create_path_core(*oldbasepaths_[i],newbasepath_,
|
||||
error = l::link_create_path_core(oldbasepaths_[i],newbasepath_,
|
||||
oldfusepath_,newfusepath_,
|
||||
error);
|
||||
}
|
||||
|
|
@ -90,20 +89,20 @@ namespace l
|
|||
{
|
||||
int rv;
|
||||
string newfusedirpath;
|
||||
vector<const string*> oldbasepaths;
|
||||
vector<const string*> newbasepaths;
|
||||
vector<string> oldbasepaths;
|
||||
vector<string> newbasepaths;
|
||||
|
||||
rv = actionFunc_(branches_,oldfusepath_,minfreespace_,oldbasepaths);
|
||||
rv = actionFunc_(branches_,oldfusepath_,minfreespace_,&oldbasepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
newfusedirpath = fs::path::dirname(newfusepath_);
|
||||
|
||||
rv = searchFunc_(branches_,newfusedirpath,minfreespace_,newbasepaths);
|
||||
rv = searchFunc_(branches_,newfusedirpath,minfreespace_,&newbasepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
return l::link_create_path_loop(oldbasepaths,*newbasepaths[0],
|
||||
return l::link_create_path_loop(oldbasepaths,newbasepaths[0],
|
||||
oldfusepath_,newfusepath_,
|
||||
newfusedirpath);
|
||||
}
|
||||
|
|
@ -120,22 +119,22 @@ namespace l
|
|||
{
|
||||
int rv;
|
||||
string newfusedirpath;
|
||||
vector<const string*> newbasepath;
|
||||
vector<string> newbasepath;
|
||||
|
||||
newfusedirpath = fs::path::dirname(newfusepath_);
|
||||
|
||||
rv = createFunc_(branches_,newfusedirpath,minfreespace_,newbasepath);
|
||||
rv = createFunc_(branches_,newfusedirpath,minfreespace_,&newbasepath);
|
||||
if(rv == -1)
|
||||
return -1;
|
||||
|
||||
if(oldbasepath_ != *newbasepath[0])
|
||||
if(oldbasepath_ != newbasepath[0])
|
||||
return (errno=EXDEV,-1);
|
||||
|
||||
rv = searchFunc_(branches_,newfusedirpath,minfreespace_,newbasepath);
|
||||
rv = searchFunc_(branches_,newfusedirpath,minfreespace_,&newbasepath);
|
||||
if(rv == -1)
|
||||
return -1;
|
||||
|
||||
return fs::clonepath_as_root(*newbasepath[0],oldbasepath_,newfusedirpath);
|
||||
return fs::clonepath_as_root(newbasepath[0],oldbasepath_,newfusedirpath);
|
||||
}
|
||||
|
||||
static
|
||||
|
|
@ -172,13 +171,13 @@ namespace l
|
|||
|
||||
static
|
||||
int
|
||||
link_preserve_path_loop(Policy::Func::Search searchFunc_,
|
||||
Policy::Func::Create createFunc_,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace_,
|
||||
const char *oldfusepath_,
|
||||
const char *newfusepath_,
|
||||
const vector<const string*> &oldbasepaths_)
|
||||
link_preserve_path_loop(Policy::Func::Search searchFunc_,
|
||||
Policy::Func::Create createFunc_,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace_,
|
||||
const char *oldfusepath_,
|
||||
const char *newfusepath_,
|
||||
const vector<string> &oldbasepaths_)
|
||||
{
|
||||
int error;
|
||||
|
||||
|
|
@ -187,7 +186,7 @@ namespace l
|
|||
{
|
||||
error = l::link_preserve_path_core(searchFunc_,createFunc_,
|
||||
branches_,minfreespace_,
|
||||
*oldbasepaths_[i],
|
||||
oldbasepaths_[i],
|
||||
oldfusepath_,newfusepath_,
|
||||
error);
|
||||
}
|
||||
|
|
@ -206,9 +205,9 @@ namespace l
|
|||
const char *newfusepath_)
|
||||
{
|
||||
int rv;
|
||||
vector<const string*> oldbasepaths;
|
||||
vector<string> oldbasepaths;
|
||||
|
||||
rv = actionFunc_(branches_,oldfusepath_,minfreespace_,oldbasepaths);
|
||||
rv = actionFunc_(branches_,oldfusepath_,minfreespace_,&oldbasepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
|
@ -225,22 +224,21 @@ namespace FUSE
|
|||
link(const char *from_,
|
||||
const char *to_)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
if(config.create->path_preserving() && !config.ignorepponrename)
|
||||
return l::link_preserve_path(config.getattr,
|
||||
config.link,
|
||||
config.create,
|
||||
if(config.func.create.policy->path_preserving() && !config.ignorepponrename)
|
||||
return l::link_preserve_path(config.func.getattr.policy,
|
||||
config.func.link.policy,
|
||||
config.func.create.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
from_,
|
||||
to_);
|
||||
|
||||
return l::link_create_path(config.link,
|
||||
config.create,
|
||||
return l::link_create_path(config.func.link.policy,
|
||||
config.func.create.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
from_,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include "errno.hpp"
|
||||
#include "fs_base_listxattr.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
#include "xattr.hpp"
|
||||
|
||||
|
|
@ -38,53 +37,13 @@ namespace l
|
|||
{
|
||||
static
|
||||
int
|
||||
listxattr_controlfile(char *list_,
|
||||
listxattr_controlfile(const Config &config_,
|
||||
char *list_,
|
||||
const size_t size_)
|
||||
{
|
||||
string xattrs;
|
||||
const vector<string> strs =
|
||||
buildvector<string>
|
||||
("user.mergerfs.async_read")
|
||||
("user.mergerfs.branches")
|
||||
("user.mergerfs.cache.attr")
|
||||
("user.mergerfs.cache.entry")
|
||||
("user.mergerfs.cache.files")
|
||||
("user.mergerfs.cache.negative_entry")
|
||||
("user.mergerfs.cache.open")
|
||||
("user.mergerfs.cache.readdir")
|
||||
("user.mergerfs.cache.statfs")
|
||||
("user.mergerfs.cache.symlinks")
|
||||
("user.mergerfs.cache.writeback")
|
||||
("user.mergerfs.direct_io")
|
||||
("user.mergerfs.dropcacheonclose")
|
||||
("user.mergerfs.fuse_msg_size")
|
||||
("user.mergerfs.ignorepponrename")
|
||||
("user.mergerfs.link_cow")
|
||||
("user.mergerfs.minfreespace")
|
||||
("user.mergerfs.moveonenospc")
|
||||
("user.mergerfs.nullrw")
|
||||
("user.mergerfs.pid")
|
||||
("user.mergerfs.policies")
|
||||
("user.mergerfs.posix_acl")
|
||||
("user.mergerfs.readdirplus")
|
||||
("user.mergerfs.security_capability")
|
||||
("user.mergerfs.srcmounts")
|
||||
("user.mergerfs.statfs")
|
||||
("user.mergerfs.statfs_ignore")
|
||||
("user.mergerfs.symlinkify")
|
||||
("user.mergerfs.symlinkify_timeout")
|
||||
("user.mergerfs.version")
|
||||
("user.mergerfs.xattr")
|
||||
;
|
||||
|
||||
xattrs.reserve(1024);
|
||||
for(size_t i = 0; i < strs.size(); i++)
|
||||
xattrs += (strs[i] + '\0');
|
||||
for(size_t i = Category::Enum::BEGIN; i < Category::Enum::END; i++)
|
||||
xattrs += ("user.mergerfs.category." + (std::string)*Category::categories[i] + '\0');
|
||||
for(size_t i = FuseFunc::Enum::BEGIN; i < FuseFunc::Enum::END; i++)
|
||||
xattrs += ("user.mergerfs.func." + (std::string)*FuseFunc::fusefuncs[i] + '\0');
|
||||
|
||||
config_.keys_xattr(xattrs);
|
||||
if(size_ == 0)
|
||||
return xattrs.size();
|
||||
|
||||
|
|
@ -107,9 +66,9 @@ namespace l
|
|||
{
|
||||
int rv;
|
||||
string fullpath;
|
||||
vector<const string*> basepaths;
|
||||
vector<string> basepaths;
|
||||
|
||||
rv = searchFunc_(branches_,fusepath_,minfreespace_,basepaths);
|
||||
rv = searchFunc_(branches_,fusepath_,minfreespace_,&basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
|
@ -128,26 +87,25 @@ namespace FUSE
|
|||
char *list_,
|
||||
size_t size_)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const Config &config = Config::ro();
|
||||
|
||||
if(fusepath_ == config.controlfile)
|
||||
return l::listxattr_controlfile(list_,size_);
|
||||
return l::listxattr_controlfile(config,list_,size_);
|
||||
|
||||
switch(config.xattr)
|
||||
{
|
||||
case 0:
|
||||
case Config::XAttr::ENUM::PASSTHROUGH:
|
||||
break;
|
||||
case ENOATTR:
|
||||
case Config::XAttr::ENUM::NOATTR:
|
||||
return 0;
|
||||
default:
|
||||
return -config.xattr;
|
||||
case Config::XAttr::ENUM::NOSYS:
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
return l::listxattr(config.listxattr,
|
||||
return l::listxattr(config.func.listxattr.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath_,
|
||||
|
|
|
|||
|
|
@ -14,11 +14,6 @@
|
|||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <fuse.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "config.hpp"
|
||||
#include "errno.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
|
|
@ -26,9 +21,13 @@
|
|||
#include "fs_clonepath.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rv.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
|
|
@ -66,12 +65,12 @@ namespace l
|
|||
|
||||
static
|
||||
int
|
||||
mkdir_loop(const string &existingpath_,
|
||||
const vector<const string*> &createpaths_,
|
||||
const char *fusepath_,
|
||||
const string &fusedirpath_,
|
||||
const mode_t mode_,
|
||||
const mode_t umask_)
|
||||
mkdir_loop(const string &existingpath_,
|
||||
const vector<string> &createpaths_,
|
||||
const char *fusepath_,
|
||||
const string &fusedirpath_,
|
||||
const mode_t mode_,
|
||||
const mode_t umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
|
|
@ -79,11 +78,11 @@ namespace l
|
|||
error = -1;
|
||||
for(size_t i = 0, ei = createpaths_.size(); i != ei; i++)
|
||||
{
|
||||
rv = fs::clonepath_as_root(existingpath_,*createpaths_[i],fusedirpath_);
|
||||
rv = fs::clonepath_as_root(existingpath_,createpaths_[i],fusedirpath_);
|
||||
if(rv == -1)
|
||||
error = error::calc(rv,error,errno);
|
||||
else
|
||||
error = l::mkdir_loop_core(*createpaths_[i],
|
||||
error = l::mkdir_loop_core(createpaths_[i],
|
||||
fusepath_,
|
||||
mode_,
|
||||
umask_,
|
||||
|
|
@ -105,20 +104,20 @@ namespace l
|
|||
{
|
||||
int rv;
|
||||
string fusedirpath;
|
||||
vector<const string*> createpaths;
|
||||
vector<const string*> existingpaths;
|
||||
vector<string> createpaths;
|
||||
vector<string> existingpaths;
|
||||
|
||||
fusedirpath = fs::path::dirname(fusepath_);
|
||||
|
||||
rv = searchFunc_(branches_,fusedirpath,minfreespace_,existingpaths);
|
||||
rv = searchFunc_(branches_,fusedirpath,minfreespace_,&existingpaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
rv = createFunc_(branches_,fusedirpath,minfreespace_,createpaths);
|
||||
rv = createFunc_(branches_,fusedirpath,minfreespace_,&createpaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
return l::mkdir_loop(*existingpaths[0],
|
||||
return l::mkdir_loop(existingpaths[0],
|
||||
createpaths,
|
||||
fusepath_,
|
||||
fusedirpath,
|
||||
|
|
@ -133,13 +132,12 @@ namespace FUSE
|
|||
mkdir(const char *fusepath_,
|
||||
mode_t mode_)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
return l::mkdir(config.getattr,
|
||||
config.mkdir,
|
||||
return l::mkdir(config.func.getattr.policy,
|
||||
config.func.mkdir.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath_,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
#include "fs_clonepath.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rv.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
|
|
@ -69,13 +68,13 @@ namespace l
|
|||
|
||||
static
|
||||
int
|
||||
mknod_loop(const string &existingpath_,
|
||||
const vector<const string*> &createpaths_,
|
||||
const char *fusepath_,
|
||||
const string &fusedirpath_,
|
||||
const mode_t mode_,
|
||||
const mode_t umask_,
|
||||
const dev_t dev_)
|
||||
mknod_loop(const string &existingpath_,
|
||||
const vector<string> &createpaths_,
|
||||
const char *fusepath_,
|
||||
const string &fusedirpath_,
|
||||
const mode_t mode_,
|
||||
const mode_t umask_,
|
||||
const dev_t dev_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
|
|
@ -83,11 +82,11 @@ namespace l
|
|||
error = -1;
|
||||
for(size_t i = 0, ei = createpaths_.size(); i != ei; i++)
|
||||
{
|
||||
rv = fs::clonepath_as_root(existingpath_,*createpaths_[i],fusedirpath_);
|
||||
rv = fs::clonepath_as_root(existingpath_,createpaths_[i],fusedirpath_);
|
||||
if(rv == -1)
|
||||
error = error::calc(rv,error,errno);
|
||||
else
|
||||
error = l::mknod_loop_core(*createpaths_[i],
|
||||
error = l::mknod_loop_core(createpaths_[i],
|
||||
fusepath_,
|
||||
mode_,umask_,dev_,error);
|
||||
}
|
||||
|
|
@ -108,20 +107,20 @@ namespace l
|
|||
{
|
||||
int rv;
|
||||
string fusedirpath;
|
||||
vector<const string*> createpaths;
|
||||
vector<const string*> existingpaths;
|
||||
vector<string> createpaths;
|
||||
vector<string> existingpaths;
|
||||
|
||||
fusedirpath = fs::path::dirname(fusepath_);
|
||||
|
||||
rv = searchFunc_(branches_,fusedirpath,minfreespace_,existingpaths);
|
||||
rv = searchFunc_(branches_,fusedirpath,minfreespace_,&existingpaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
rv = createFunc_(branches_,fusedirpath,minfreespace_,createpaths);
|
||||
rv = createFunc_(branches_,fusedirpath,minfreespace_,&createpaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
return l::mknod_loop(*existingpaths[0],createpaths,
|
||||
return l::mknod_loop(existingpaths[0],createpaths,
|
||||
fusepath_,fusedirpath,
|
||||
mode_,umask_,dev_);
|
||||
}
|
||||
|
|
@ -134,13 +133,12 @@ namespace FUSE
|
|||
mode_t mode_,
|
||||
dev_t rdev_)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
return l::mknod(config.getattr,
|
||||
config.mknod,
|
||||
return l::mknod(config.func.getattr.policy,
|
||||
config.func.mknod.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath_,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
#include "fs_cow.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "policy_cache.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
|
|
@ -61,27 +60,27 @@ namespace l
|
|||
{
|
||||
switch(config_.cache_files)
|
||||
{
|
||||
case CacheFiles::LIBFUSE:
|
||||
case CacheFiles::ENUM::LIBFUSE:
|
||||
ffi_->direct_io = config_.direct_io;
|
||||
ffi_->keep_cache = config_.kernel_cache;
|
||||
ffi_->auto_cache = config_.auto_cache;
|
||||
break;
|
||||
case CacheFiles::OFF:
|
||||
case CacheFiles::ENUM::OFF:
|
||||
ffi_->direct_io = 1;
|
||||
ffi_->keep_cache = 0;
|
||||
ffi_->auto_cache = 0;
|
||||
break;
|
||||
case CacheFiles::PARTIAL:
|
||||
case CacheFiles::ENUM::PARTIAL:
|
||||
ffi_->direct_io = 0;
|
||||
ffi_->keep_cache = 0;
|
||||
ffi_->auto_cache = 0;
|
||||
break;
|
||||
case CacheFiles::FULL:
|
||||
case CacheFiles::ENUM::FULL:
|
||||
ffi_->direct_io = 0;
|
||||
ffi_->keep_cache = 1;
|
||||
ffi_->auto_cache = 0;
|
||||
break;
|
||||
case CacheFiles::AUTO_FULL:
|
||||
case CacheFiles::ENUM::AUTO_FULL:
|
||||
ffi_->direct_io = 0;
|
||||
ffi_->keep_cache = 0;
|
||||
ffi_->auto_cache = 1;
|
||||
|
|
@ -142,17 +141,16 @@ namespace FUSE
|
|||
open(const char *fusepath_,
|
||||
fuse_file_info *ffi_)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
l::config_to_ffi_flags(config,ffi_);
|
||||
|
||||
if(config.writeback_cache)
|
||||
l::tweak_flags_writeback_cache(&ffi_->flags);
|
||||
|
||||
return l::open(config.open,
|
||||
return l::open(config.func.open.policy,
|
||||
config.open_cache,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ namespace FUSE
|
|||
opendir(const char *fusepath_,
|
||||
fuse_file_info *ffi_)
|
||||
{
|
||||
const Config &config = Config::get();
|
||||
const Config &config = Config::ro();
|
||||
|
||||
ffi_->fh = reinterpret_cast<uint64_t>(new DirInfo(fusepath_));
|
||||
|
||||
|
|
|
|||
|
|
@ -140,9 +140,9 @@ namespace FUSE
|
|||
{
|
||||
DirInfo *di = reinterpret_cast<DirInfo*>(ffi_->fh);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const rwlock::ReadGuard readlock(&config.branches.lock);
|
||||
|
||||
return l::readdir(config.branches,
|
||||
di->fusepath.c_str(),
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@ namespace l
|
|||
int
|
||||
readdir_plus(const Branches &branches_,
|
||||
const char *dirname_,
|
||||
const uint64_t entry_timeout_,
|
||||
const uint64_t attr_timeout_,
|
||||
fuse_dirents_t *buf_)
|
||||
{
|
||||
int rv;
|
||||
|
|
@ -85,8 +87,8 @@ namespace l
|
|||
|
||||
entry.nodeid = 0;
|
||||
entry.generation = 0;
|
||||
entry.entry_valid = 1;
|
||||
entry.attr_valid = 1;
|
||||
entry.entry_valid = entry_timeout_;
|
||||
entry.attr_valid = attr_timeout_;
|
||||
entry.entry_valid_nsec = 0;
|
||||
entry.attr_valid_nsec = 0;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
|
|
@ -151,12 +153,14 @@ namespace FUSE
|
|||
{
|
||||
DirInfo *di = reinterpret_cast<DirInfo*>(ffi_->fh);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const rwlock::ReadGuard guard(&config.branches.lock);
|
||||
|
||||
return l::readdir_plus(config.branches,
|
||||
di->fusepath.c_str(),
|
||||
config.cache_entry,
|
||||
config.cache_attr,
|
||||
buf_);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,9 +137,9 @@ namespace FUSE
|
|||
{
|
||||
DirInfo *di = reinterpret_cast<DirInfo*>(ffi_->fh);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const rwlock::ReadGuard guard(&config.branches.lock);
|
||||
|
||||
return l::readdir_plus(config.branches,
|
||||
di->fusepath.c_str(),
|
||||
|
|
|
|||
|
|
@ -123,9 +123,9 @@ namespace FUSE
|
|||
{
|
||||
DirInfo *di = reinterpret_cast<DirInfo*>(ffi_->fh);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const rwlock::ReadGuard guard(&config.branches.lock);
|
||||
|
||||
return l::readdir(config.branches,
|
||||
di->fusepath.c_str(),
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include "fs_base_readlink.hpp"
|
||||
#include "fs_base_stat.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "symlinkify.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
|
|
@ -74,7 +73,7 @@ namespace l
|
|||
|
||||
static
|
||||
int
|
||||
readlink_core(const string *basepath_,
|
||||
readlink_core(const string &basepath_,
|
||||
const char *fusepath_,
|
||||
char *buf_,
|
||||
const size_t size_,
|
||||
|
|
@ -103,9 +102,9 @@ namespace l
|
|||
const time_t symlinkify_timeout_)
|
||||
{
|
||||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
vector<string> basepaths;
|
||||
|
||||
rv = searchFunc_(branches_,fusepath_,minfreespace_,basepaths);
|
||||
rv = searchFunc_(branches_,fusepath_,minfreespace_,&basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
|
@ -121,12 +120,11 @@ namespace FUSE
|
|||
char *buf_,
|
||||
size_t size_)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
return l::readlink(config.readlink,
|
||||
return l::readlink(config.func.readlink.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath_,
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ namespace FUSE
|
|||
release(const char *fusepath_,
|
||||
fuse_file_info *ffi_)
|
||||
{
|
||||
const Config &config = Config::get();
|
||||
FileInfo *fi = reinterpret_cast<FileInfo*>(ffi_->fh);
|
||||
const Config &config = Config::ro();
|
||||
FileInfo *fi = reinterpret_cast<FileInfo*>(ffi_->fh);
|
||||
|
||||
if(config.open_cache.timeout)
|
||||
config.open_cache.cleanup(10);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include "fs_base_removexattr.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rv.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
|
|
@ -34,7 +33,7 @@ namespace l
|
|||
{
|
||||
static
|
||||
int
|
||||
removexattr_loop_core(const string *basepath_,
|
||||
removexattr_loop_core(const string &basepath_,
|
||||
const char *fusepath_,
|
||||
const char *attrname_,
|
||||
const int error_)
|
||||
|
|
@ -51,9 +50,9 @@ namespace l
|
|||
|
||||
static
|
||||
int
|
||||
removexattr_loop(const vector<const string*> &basepaths_,
|
||||
const char *fusepath_,
|
||||
const char *attrname_)
|
||||
removexattr_loop(const vector<string> &basepaths_,
|
||||
const char *fusepath_,
|
||||
const char *attrname_)
|
||||
{
|
||||
int error;
|
||||
|
||||
|
|
@ -76,9 +75,9 @@ namespace l
|
|||
const char *attrname_)
|
||||
{
|
||||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
vector<string> basepaths;
|
||||
|
||||
rv = actionFunc_(branches_,fusepath_,minfreespace_,basepaths);
|
||||
rv = actionFunc_(branches_,fusepath_,minfreespace_,&basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
|
@ -92,18 +91,17 @@ namespace FUSE
|
|||
removexattr(const char *fusepath_,
|
||||
const char *attrname_)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const Config &config = Config::ro();
|
||||
|
||||
if(fusepath_ == config.controlfile)
|
||||
return -ENOATTR;
|
||||
if(config.xattr)
|
||||
return -config.xattr;
|
||||
if(config.xattr.to_int())
|
||||
return -config.xattr.to_int();
|
||||
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
return l::removexattr(config.removexattr,
|
||||
return l::removexattr(config.func.removexattr.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath_,
|
||||
|
|
|
|||
|
|
@ -14,11 +14,6 @@
|
|||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "config.hpp"
|
||||
#include "errno.hpp"
|
||||
#include "fs_base_remove.hpp"
|
||||
|
|
@ -26,21 +21,25 @@
|
|||
#include "fs_clonepath.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rv.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::set;
|
||||
|
||||
static
|
||||
bool
|
||||
member(const vector<const string*> &haystack,
|
||||
const string &needle)
|
||||
member(const vector<string> &haystack,
|
||||
const string &needle)
|
||||
{
|
||||
for(size_t i = 0, ei = haystack.size(); i != ei; i++)
|
||||
{
|
||||
if(*haystack[i] == needle)
|
||||
if(haystack[i] == needle)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -57,14 +56,14 @@ _remove(const vector<string> &toremove)
|
|||
|
||||
static
|
||||
void
|
||||
_rename_create_path_core(const vector<const string*> &oldbasepaths,
|
||||
const string &oldbasepath,
|
||||
const string &newbasepath,
|
||||
const char *oldfusepath,
|
||||
const char *newfusepath,
|
||||
const string &newfusedirpath,
|
||||
int &error,
|
||||
vector<string> &tounlink)
|
||||
_rename_create_path_core(const vector<string> &oldbasepaths,
|
||||
const string &oldbasepath,
|
||||
const string &newbasepath,
|
||||
const char *oldfusepath,
|
||||
const char *newfusepath,
|
||||
const string &newfusedirpath,
|
||||
int &error,
|
||||
vector<string> &tounlink)
|
||||
{
|
||||
int rv;
|
||||
bool ismember;
|
||||
|
|
@ -108,26 +107,29 @@ _rename_create_path(Policy::Func::Search searchFunc,
|
|||
int error;
|
||||
string newfusedirpath;
|
||||
vector<string> toremove;
|
||||
vector<const string*> newbasepath;
|
||||
vector<const string*> oldbasepaths;
|
||||
vector<string> newbasepath;
|
||||
vector<string> oldbasepaths;
|
||||
vector<string> branches;
|
||||
|
||||
rv = actionFunc(branches_,oldfusepath,minfreespace,oldbasepaths);
|
||||
rv = actionFunc(branches_,oldfusepath,minfreespace,&oldbasepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
newfusedirpath = fs::path::dirname(newfusepath);
|
||||
|
||||
rv = searchFunc(branches_,newfusedirpath,minfreespace,newbasepath);
|
||||
rv = searchFunc(branches_,newfusedirpath,minfreespace,&newbasepath);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
branches_.to_paths(branches);
|
||||
|
||||
error = -1;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
for(size_t i = 0, ei = branches.size(); i != ei; i++)
|
||||
{
|
||||
const string &oldbasepath = branches_[i].path;
|
||||
const string &oldbasepath = branches[i];
|
||||
|
||||
_rename_create_path_core(oldbasepaths,
|
||||
oldbasepath,*newbasepath[0],
|
||||
oldbasepath,newbasepath[0],
|
||||
oldfusepath,newfusepath,
|
||||
newfusedirpath,
|
||||
error,toremove);
|
||||
|
|
@ -149,13 +151,13 @@ _clonepath(Policy::Func::Search searchFunc,
|
|||
const string &fusedirpath)
|
||||
{
|
||||
int rv;
|
||||
vector<const string*> srcbasepath;
|
||||
vector<string> srcbasepath;
|
||||
|
||||
rv = searchFunc(branches_,fusedirpath,minfreespace,srcbasepath);
|
||||
rv = searchFunc(branches_,fusedirpath,minfreespace,&srcbasepath);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
fs::clonepath_as_root(*srcbasepath[0],dstbasepath,fusedirpath);
|
||||
fs::clonepath_as_root(srcbasepath[0],dstbasepath,fusedirpath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -172,15 +174,15 @@ _clonepath_if_would_create(Policy::Func::Search searchFunc,
|
|||
{
|
||||
int rv;
|
||||
string newfusedirpath;
|
||||
vector<const string*> newbasepath;
|
||||
vector<string> newbasepath;
|
||||
|
||||
newfusedirpath = fs::path::dirname(newfusepath);
|
||||
|
||||
rv = createFunc(branches_,newfusedirpath,minfreespace,newbasepath);
|
||||
rv = createFunc(branches_,newfusedirpath,minfreespace,&newbasepath);
|
||||
if(rv == -1)
|
||||
return rv;
|
||||
|
||||
if(oldbasepath == *newbasepath[0])
|
||||
if(oldbasepath == newbasepath[0])
|
||||
return _clonepath(searchFunc,branches_,minfreespace,oldbasepath,newfusedirpath);
|
||||
|
||||
return (errno=EXDEV,-1);
|
||||
|
|
@ -188,16 +190,16 @@ _clonepath_if_would_create(Policy::Func::Search searchFunc,
|
|||
|
||||
static
|
||||
void
|
||||
_rename_preserve_path_core(Policy::Func::Search searchFunc,
|
||||
Policy::Func::Create createFunc,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const vector<const string*> &oldbasepaths,
|
||||
const string &oldbasepath,
|
||||
const char *oldfusepath,
|
||||
const char *newfusepath,
|
||||
int &error,
|
||||
vector<string> &toremove)
|
||||
_rename_preserve_path_core(Policy::Func::Search searchFunc,
|
||||
Policy::Func::Create createFunc,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const vector<string> &oldbasepaths,
|
||||
const string &oldbasepath,
|
||||
const char *oldfusepath,
|
||||
const char *newfusepath,
|
||||
int &error,
|
||||
vector<string> &toremove)
|
||||
{
|
||||
int rv;
|
||||
bool ismember;
|
||||
|
|
@ -245,16 +247,19 @@ _rename_preserve_path(Policy::Func::Search searchFunc,
|
|||
int rv;
|
||||
int error;
|
||||
vector<string> toremove;
|
||||
vector<const string*> oldbasepaths;
|
||||
vector<string> oldbasepaths;
|
||||
vector<string> branches;
|
||||
|
||||
rv = actionFunc(branches_,oldfusepath,minfreespace,oldbasepaths);
|
||||
rv = actionFunc(branches_,oldfusepath,minfreespace,&oldbasepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
branches_.to_paths(branches);
|
||||
|
||||
error = -1;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
for(size_t i = 0, ei = branches.size(); i != ei; i++)
|
||||
{
|
||||
const string &oldbasepath = branches_[i].path;
|
||||
const string &oldbasepath = branches[i];
|
||||
|
||||
_rename_preserve_path_core(searchFunc,createFunc,
|
||||
branches_,minfreespace,
|
||||
|
|
@ -275,24 +280,23 @@ namespace FUSE
|
|||
rename(const char *oldpath,
|
||||
const char *newpath)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
Config &config = Config::rw();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
config.open_cache.erase(oldpath);
|
||||
|
||||
if(config.create->path_preserving() && !config.ignorepponrename)
|
||||
return _rename_preserve_path(config.getattr,
|
||||
config.rename,
|
||||
config.create,
|
||||
if(config.func.create.policy->path_preserving() && !config.ignorepponrename)
|
||||
return _rename_preserve_path(config.func.getattr.policy,
|
||||
config.func.rename.policy,
|
||||
config.func.create.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
oldpath,
|
||||
newpath);
|
||||
|
||||
return _rename_create_path(config.getattr,
|
||||
config.rename,
|
||||
return _rename_create_path(config.func.getattr.policy,
|
||||
config.func.rename.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
oldpath,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include "fs_base_rmdir.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rv.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
|
|
@ -35,7 +34,7 @@ namespace l
|
|||
{
|
||||
static
|
||||
int
|
||||
rmdir_loop_core(const string *basepath_,
|
||||
rmdir_loop_core(const string &basepath_,
|
||||
const char *fusepath_,
|
||||
const int error_)
|
||||
{
|
||||
|
|
@ -52,8 +51,8 @@ namespace l
|
|||
|
||||
static
|
||||
int
|
||||
rmdir_loop(const vector<const string*> &basepaths_,
|
||||
const char *fusepath_)
|
||||
rmdir_loop(const vector<string> &basepaths_,
|
||||
const char *fusepath_)
|
||||
{
|
||||
int error;
|
||||
|
||||
|
|
@ -74,9 +73,9 @@ namespace l
|
|||
const char *fusepath_)
|
||||
{
|
||||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
vector<string> basepaths;
|
||||
|
||||
rv = actionFunc_(branches_,fusepath_,minfreespace_,basepaths);
|
||||
rv = actionFunc_(branches_,fusepath_,minfreespace_,&basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
|
@ -89,12 +88,11 @@ namespace FUSE
|
|||
int
|
||||
rmdir(const char *fusepath_)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readguard(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
return l::rmdir(config.rmdir,
|
||||
return l::rmdir(config.func.rmdir.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath_);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
#include "fs_statvfs_cache.hpp"
|
||||
#include "num.hpp"
|
||||
#include "rv.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "str.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
|
|
@ -48,317 +47,6 @@ namespace l
|
|||
return (strcmp(attrname_,SECURITY_CAPABILITY) == 0);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
split_attrval(const string &attrval,
|
||||
string &instruction,
|
||||
string &values)
|
||||
{
|
||||
size_t offset;
|
||||
|
||||
offset = attrval.find_first_of('/');
|
||||
instruction = attrval.substr(0,offset);
|
||||
if(offset != string::npos)
|
||||
values = attrval.substr(offset);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
setxattr_srcmounts(const string &attrval,
|
||||
const int flags,
|
||||
Branches &branches_,
|
||||
pthread_rwlock_t &branches_lock)
|
||||
{
|
||||
const rwlock::WriteGuard wrg(&branches_lock);
|
||||
|
||||
string instruction;
|
||||
string values;
|
||||
|
||||
if((flags & XATTR_CREATE) == XATTR_CREATE)
|
||||
return -EEXIST;
|
||||
|
||||
l::split_attrval(attrval,instruction,values);
|
||||
|
||||
if(instruction == "+")
|
||||
branches_.add_end(values);
|
||||
else if(instruction == "+<")
|
||||
branches_.add_begin(values);
|
||||
else if(instruction == "+>")
|
||||
branches_.add_end(values);
|
||||
else if(instruction == "-")
|
||||
branches_.erase_fnmatch(values);
|
||||
else if(instruction == "-<")
|
||||
branches_.erase_begin();
|
||||
else if(instruction == "->")
|
||||
branches_.erase_end();
|
||||
else if(instruction == "=")
|
||||
branches_.set(values);
|
||||
else if(instruction.empty())
|
||||
branches_.set(values);
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
setxattr_uint64_t(const string &attrval,
|
||||
const int flags,
|
||||
uint64_t &uint)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if((flags & XATTR_CREATE) == XATTR_CREATE)
|
||||
return -EEXIST;
|
||||
|
||||
rv = num::to_uint64_t(attrval,uint);
|
||||
if(rv == -1)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
setxattr_double(const string &attrval_,
|
||||
const int flags_,
|
||||
double *d_)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if((flags_ & XATTR_CREATE) == XATTR_CREATE)
|
||||
return -EEXIST;
|
||||
|
||||
rv = num::to_double(attrval_,d_);
|
||||
if(rv == -1)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
setxattr_time_t(const string &attrval,
|
||||
const int flags,
|
||||
time_t &time)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if((flags & XATTR_CREATE) == XATTR_CREATE)
|
||||
return -EEXIST;
|
||||
|
||||
rv = num::to_time_t(attrval,time);
|
||||
if(rv == -1)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
setxattr_bool(const string &attrval,
|
||||
const int flags,
|
||||
bool &value)
|
||||
{
|
||||
if((flags & XATTR_CREATE) == XATTR_CREATE)
|
||||
return -EEXIST;
|
||||
|
||||
if(attrval == "false")
|
||||
value = false;
|
||||
else if(attrval == "true")
|
||||
value = true;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
setxattr_xattr(const string &attrval_,
|
||||
const int flags_,
|
||||
int &xattr_)
|
||||
{
|
||||
if((flags_ & XATTR_CREATE) == XATTR_CREATE)
|
||||
return -EEXIST;
|
||||
|
||||
if(attrval_ == "passthrough")
|
||||
xattr_ = 0;
|
||||
else if(attrval_ == "noattr")
|
||||
xattr_ = ENOATTR;
|
||||
else if(attrval_ == "nosys")
|
||||
xattr_ = ENOSYS;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
setxattr_statfs(const string &attrval_,
|
||||
const int flags_,
|
||||
Config::StatFS::Enum &enum_)
|
||||
{
|
||||
if((flags_ & XATTR_CREATE) == XATTR_CREATE)
|
||||
return -EEXIST;
|
||||
|
||||
if(attrval_ == "base")
|
||||
enum_ = Config::StatFS::BASE;
|
||||
else if(attrval_ == "full")
|
||||
enum_ = Config::StatFS::FULL;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
setxattr_statfsignore(const string &attrval_,
|
||||
const int flags_,
|
||||
Config::StatFSIgnore::Enum &enum_)
|
||||
{
|
||||
if((flags_ & XATTR_CREATE) == XATTR_CREATE)
|
||||
return -EEXIST;
|
||||
|
||||
if(attrval_ == "none")
|
||||
enum_ = Config::StatFSIgnore::NONE;
|
||||
else if(attrval_ == "ro")
|
||||
enum_ = Config::StatFSIgnore::RO;
|
||||
else if(attrval_ == "nc")
|
||||
enum_ = Config::StatFSIgnore::NC;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
setxattr(const string &attrval_,
|
||||
const int flags_,
|
||||
Config::CacheFiles &cache_files_)
|
||||
{
|
||||
Config::CacheFiles tmp;
|
||||
|
||||
if((flags_ & XATTR_CREATE) == XATTR_CREATE)
|
||||
return -EEXIST;
|
||||
|
||||
tmp = attrval_;
|
||||
if(!tmp.valid())
|
||||
return -EINVAL;
|
||||
|
||||
cache_files_ = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
setxattr_controlfile_func_policy(Config &config,
|
||||
const string &funcname,
|
||||
const string &attrval,
|
||||
const int flags)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if((flags & XATTR_CREATE) == XATTR_CREATE)
|
||||
return -EEXIST;
|
||||
|
||||
if(funcname == "open")
|
||||
config.open_cache.clear();
|
||||
|
||||
rv = config.set_func_policy(funcname,attrval);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
setxattr_controlfile_category_policy(Config &config,
|
||||
const string &categoryname,
|
||||
const string &attrval,
|
||||
const int flags)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if((flags & XATTR_CREATE) == XATTR_CREATE)
|
||||
return -EEXIST;
|
||||
|
||||
if(categoryname == "search")
|
||||
config.open_cache.clear();
|
||||
|
||||
rv = config.set_category_policy(categoryname,attrval);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
setxattr_statfs_timeout(const string &attrval_,
|
||||
const int flags_)
|
||||
{
|
||||
int rv;
|
||||
uint64_t timeout;
|
||||
|
||||
rv = l::setxattr_uint64_t(attrval_,flags_,timeout);
|
||||
if(rv >= 0)
|
||||
fs::statvfs_cache_timeout(timeout);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
setxattr_controlfile_cache_attr(const string &attrval_,
|
||||
const int flags_)
|
||||
{
|
||||
int rv;
|
||||
double d;
|
||||
|
||||
rv = l::setxattr_double(attrval_,flags_,&d);
|
||||
if(rv >= 0)
|
||||
fuse_config_set_attr_timeout(fuse_get_context()->fuse,d);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
setxattr_controlfile_cache_entry(const string &attrval_,
|
||||
const int flags_)
|
||||
{
|
||||
int rv;
|
||||
double d;
|
||||
|
||||
rv = l::setxattr_double(attrval_,flags_,&d);
|
||||
if(rv >= 0)
|
||||
fuse_config_set_entry_timeout(fuse_get_context()->fuse,d);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
setxattr_controlfile_cache_negative_entry(const string &attrval_,
|
||||
const int flags_)
|
||||
{
|
||||
int rv;
|
||||
double d;
|
||||
|
||||
rv = l::setxattr_double(attrval_,flags_,&d);
|
||||
if(rv >= 0)
|
||||
fuse_config_set_negative_entry_timeout(fuse_get_context()->fuse,d);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
setxattr_controlfile(Config &config,
|
||||
|
|
@ -366,112 +54,33 @@ namespace l
|
|||
const string &attrval,
|
||||
const int flags)
|
||||
{
|
||||
vector<string> attr;
|
||||
int rv;
|
||||
string key;
|
||||
|
||||
str::split(attr,attrname,'.');
|
||||
if(!str::startswith(attrname,"user.mergerfs."))
|
||||
return -ENOATTR;
|
||||
|
||||
switch(attr.size())
|
||||
{
|
||||
case 3:
|
||||
if(attr[2] == "srcmounts")
|
||||
return l::setxattr_srcmounts(attrval,
|
||||
flags,
|
||||
config.branches,
|
||||
config.branches_lock);
|
||||
else if(attr[2] == "branches")
|
||||
return l::setxattr_srcmounts(attrval,
|
||||
flags,
|
||||
config.branches,
|
||||
config.branches_lock);
|
||||
else if(attr[2] == "minfreespace")
|
||||
return l::setxattr_uint64_t(attrval,
|
||||
flags,
|
||||
config.minfreespace);
|
||||
else if(attr[2] == "moveonenospc")
|
||||
return l::setxattr_bool(attrval,
|
||||
flags,
|
||||
config.moveonenospc);
|
||||
else if(attr[2] == "dropcacheonclose")
|
||||
return l::setxattr_bool(attrval,
|
||||
flags,
|
||||
config.dropcacheonclose);
|
||||
else if(attr[2] == "symlinkify")
|
||||
return l::setxattr_bool(attrval,
|
||||
flags,
|
||||
config.symlinkify);
|
||||
else if(attr[2] == "symlinkify_timeout")
|
||||
return l::setxattr_time_t(attrval,
|
||||
flags,
|
||||
config.symlinkify_timeout);
|
||||
else if(attr[2] == "ignorepponrename")
|
||||
return l::setxattr_bool(attrval,
|
||||
flags,
|
||||
config.ignorepponrename);
|
||||
else if(attr[2] == "security_capability")
|
||||
return l::setxattr_bool(attrval,
|
||||
flags,
|
||||
config.security_capability);
|
||||
else if(attr[2] == "xattr")
|
||||
return l::setxattr_xattr(attrval,
|
||||
flags,
|
||||
config.xattr);
|
||||
else if(attr[2] == "link_cow")
|
||||
return l::setxattr_bool(attrval,
|
||||
flags,
|
||||
config.link_cow);
|
||||
else if(attr[2] == "statfs")
|
||||
return l::setxattr_statfs(attrval,
|
||||
flags,
|
||||
config.statfs);
|
||||
else if(attr[2] == "statfs_ignore")
|
||||
return l::setxattr_statfsignore(attrval,
|
||||
flags,
|
||||
config.statfs_ignore);
|
||||
else if(attr[2] == "direct_io")
|
||||
return l::setxattr_bool(attrval,
|
||||
flags,
|
||||
config.direct_io);
|
||||
break;
|
||||
key = &attrname[14];
|
||||
|
||||
case 4:
|
||||
if(attr[2] == "category")
|
||||
return l::setxattr_controlfile_category_policy(config,
|
||||
attr[3],
|
||||
attrval,
|
||||
flags);
|
||||
else if(attr[2] == "func")
|
||||
return l::setxattr_controlfile_func_policy(config,
|
||||
attr[3],
|
||||
attrval,
|
||||
flags);
|
||||
else if((attr[2] == "cache") && (attr[3] == "open"))
|
||||
return l::setxattr_uint64_t(attrval,
|
||||
flags,
|
||||
config.open_cache.timeout);
|
||||
else if((attr[2] == "cache") && (attr[3] == "statfs"))
|
||||
return l::setxattr_statfs_timeout(attrval,flags);
|
||||
else if((attr[2] == "cache") && (attr[3] == "attr"))
|
||||
return l::setxattr_controlfile_cache_attr(attrval,flags);
|
||||
else if((attr[2] == "cache") && (attr[3] == "entry"))
|
||||
return l::setxattr_controlfile_cache_entry(attrval,flags);
|
||||
else if((attr[2] == "cache") && (attr[3] == "negative_entry"))
|
||||
return l::setxattr_controlfile_cache_negative_entry(attrval,flags);
|
||||
else if((attr[2] == "cache") && (attr[3] == "readdir"))
|
||||
return l::setxattr_bool(attrval,flags,config.cache_readdir);
|
||||
else if((attr[2] == "cache") && (attr[3] == "files"))
|
||||
return l::setxattr(attrval,flags,config.cache_files);
|
||||
break;
|
||||
if(config.has_key(key) == false)
|
||||
return -ENOATTR;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if((flags & XATTR_CREATE) == XATTR_CREATE)
|
||||
return -EEXIST;
|
||||
|
||||
return -EINVAL;
|
||||
rv = config.set(key,attrval);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
|
||||
config.open_cache.clear();
|
||||
fs::statvfs_cache_timeout(config.cache_statfs);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
setxattr_loop_core(const string *basepath,
|
||||
setxattr_loop_core(const string &basepath,
|
||||
const char *fusepath,
|
||||
const char *attrname,
|
||||
const char *attrval,
|
||||
|
|
@ -491,12 +100,12 @@ namespace l
|
|||
|
||||
static
|
||||
int
|
||||
setxattr_loop(const vector<const string*> &basepaths,
|
||||
const char *fusepath,
|
||||
const char *attrname,
|
||||
const char *attrval,
|
||||
const size_t attrvalsize,
|
||||
const int flags)
|
||||
setxattr_loop(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
const char *attrname,
|
||||
const char *attrval,
|
||||
const size_t attrvalsize,
|
||||
const int flags)
|
||||
{
|
||||
int error;
|
||||
|
||||
|
|
@ -523,9 +132,9 @@ namespace l
|
|||
const int flags)
|
||||
{
|
||||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
vector<string> basepaths;
|
||||
|
||||
rv = actionFunc(branches_,fusepath,minfreespace,basepaths);
|
||||
rv = actionFunc(branches_,fusepath,minfreespace,&basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
|
@ -542,11 +151,10 @@ namespace FUSE
|
|||
size_t attrvalsize,
|
||||
int flags)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
Config &config = Config::rw();
|
||||
|
||||
if(fusepath == config.controlfile)
|
||||
return l::setxattr_controlfile(Config::get_writable(),
|
||||
return l::setxattr_controlfile(config,
|
||||
attrname,
|
||||
string(attrval,attrvalsize),
|
||||
flags);
|
||||
|
|
@ -555,13 +163,13 @@ namespace FUSE
|
|||
l::is_attrname_security_capability(attrname))
|
||||
return -ENOATTR;
|
||||
|
||||
if(config.xattr)
|
||||
return -config.xattr;
|
||||
if(config.xattr.to_int())
|
||||
return -config.xattr.to_int();
|
||||
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
return l::setxattr(config.setxattr,
|
||||
return l::setxattr(config.func.setxattr.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include "fs_base_stat.hpp"
|
||||
#include "fs_base_statvfs.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "statvfs_util.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
|
|
@ -70,22 +69,22 @@ namespace l
|
|||
|
||||
static
|
||||
bool
|
||||
should_ignore(const StatFSIgnore::Enum ignore_,
|
||||
const Branch *branch_,
|
||||
const bool readonly_)
|
||||
should_ignore(const StatFSIgnore ignore_,
|
||||
const Branch *branch_,
|
||||
const bool readonly_)
|
||||
{
|
||||
return ((((ignore_ == StatFSIgnore::RO) || readonly_) &&
|
||||
return ((((ignore_ == StatFSIgnore::ENUM::RO) || readonly_) &&
|
||||
(branch_->ro_or_nc())) ||
|
||||
((ignore_ == StatFSIgnore::NC) && (branch_->nc())));
|
||||
((ignore_ == StatFSIgnore::ENUM::NC) && (branch_->nc())));
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
statfs(const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
const StatFS::Enum mode_,
|
||||
const StatFSIgnore::Enum ignore_,
|
||||
struct statvfs *fsstat_)
|
||||
statfs(const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
const StatFS mode_,
|
||||
const StatFSIgnore ignore_,
|
||||
struct statvfs *fsstat_)
|
||||
{
|
||||
int rv;
|
||||
string fullpath;
|
||||
|
|
@ -101,7 +100,7 @@ namespace l
|
|||
min_namemax = std::numeric_limits<unsigned long>::max();
|
||||
for(size_t i = 0, ei = branches_.size(); i < ei; i++)
|
||||
{
|
||||
fullpath = ((mode_ == StatFS::FULL) ?
|
||||
fullpath = ((mode_ == StatFS::ENUM::FULL) ?
|
||||
fs::path::make(&branches_[i].path,fusepath_) :
|
||||
branches_[i].path);
|
||||
|
||||
|
|
@ -153,10 +152,9 @@ namespace FUSE
|
|||
statfs(const char *fusepath_,
|
||||
struct statvfs *st_)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
return l::statfs(config.branches,
|
||||
fusepath_,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include "fs_clonepath.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rv.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
|
|
@ -54,11 +53,11 @@ namespace l
|
|||
|
||||
static
|
||||
int
|
||||
symlink_loop(const string &existingpath_,
|
||||
const vector<const string*> newbasepaths_,
|
||||
const char *oldpath_,
|
||||
const char *newpath_,
|
||||
const string &newdirpath_)
|
||||
symlink_loop(const string &existingpath_,
|
||||
const vector<string> &newbasepaths_,
|
||||
const char *oldpath_,
|
||||
const char *newpath_,
|
||||
const string &newdirpath_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
|
|
@ -66,11 +65,11 @@ namespace l
|
|||
error = -1;
|
||||
for(size_t i = 0, ei = newbasepaths_.size(); i != ei; i++)
|
||||
{
|
||||
rv = fs::clonepath_as_root(existingpath_,*newbasepaths_[i],newdirpath_);
|
||||
rv = fs::clonepath_as_root(existingpath_,newbasepaths_[i],newdirpath_);
|
||||
if(rv == -1)
|
||||
error = error::calc(rv,error,errno);
|
||||
else
|
||||
error = l::symlink_loop_core(*newbasepaths_[i],
|
||||
error = l::symlink_loop_core(newbasepaths_[i],
|
||||
oldpath_,
|
||||
newpath_,
|
||||
error);
|
||||
|
|
@ -90,20 +89,20 @@ namespace l
|
|||
{
|
||||
int rv;
|
||||
string newdirpath;
|
||||
vector<const string*> newbasepaths;
|
||||
vector<const string*> existingpaths;
|
||||
vector<string> newbasepaths;
|
||||
vector<string> existingpaths;
|
||||
|
||||
newdirpath = fs::path::dirname(newpath_);
|
||||
|
||||
rv = searchFunc_(branches_,newdirpath,minfreespace_,existingpaths);
|
||||
rv = searchFunc_(branches_,newdirpath,minfreespace_,&existingpaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
rv = createFunc_(branches_,newdirpath,minfreespace_,newbasepaths);
|
||||
rv = createFunc_(branches_,newdirpath,minfreespace_,&newbasepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
return l::symlink_loop(*existingpaths[0],newbasepaths,
|
||||
return l::symlink_loop(existingpaths[0],newbasepaths,
|
||||
oldpath_,newpath_,newdirpath);
|
||||
}
|
||||
}
|
||||
|
|
@ -114,13 +113,12 @@ namespace FUSE
|
|||
symlink(const char *oldpath_,
|
||||
const char *newpath_)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
return l::symlink(config.getattr,
|
||||
config.symlink,
|
||||
return l::symlink(config.func.getattr.policy,
|
||||
config.func.symlink.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
oldpath_,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include "fs_base_truncate.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rv.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
|
|
@ -37,7 +36,7 @@ namespace l
|
|||
{
|
||||
static
|
||||
int
|
||||
truncate_loop_core(const string *basepath_,
|
||||
truncate_loop_core(const string &basepath_,
|
||||
const char *fusepath_,
|
||||
const off_t size_,
|
||||
const int error_)
|
||||
|
|
@ -54,9 +53,9 @@ namespace l
|
|||
|
||||
static
|
||||
int
|
||||
truncate_loop(const vector<const string*> &basepaths_,
|
||||
const char *fusepath_,
|
||||
const off_t size_)
|
||||
truncate_loop(const vector<string> &basepaths_,
|
||||
const char *fusepath_,
|
||||
const off_t size_)
|
||||
{
|
||||
int error;
|
||||
|
||||
|
|
@ -78,9 +77,9 @@ namespace l
|
|||
const off_t size_)
|
||||
{
|
||||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
vector<string> basepaths;
|
||||
|
||||
rv = actionFunc_(branches_,fusepath_,minfreespace_,basepaths);
|
||||
rv = actionFunc_(branches_,fusepath_,minfreespace_,&basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
|
@ -94,12 +93,11 @@ namespace FUSE
|
|||
truncate(const char *fusepath_,
|
||||
off_t size_)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
return l::truncate(config.truncate,
|
||||
return l::truncate(config.func.truncate.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath_,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include "fs_base_unlink.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rv.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
|
|
@ -36,7 +35,7 @@ namespace l
|
|||
{
|
||||
static
|
||||
int
|
||||
unlink_loop_core(const string *basepath_,
|
||||
unlink_loop_core(const string &basepath_,
|
||||
const char *fusepath_,
|
||||
const int error_)
|
||||
{
|
||||
|
|
@ -52,8 +51,8 @@ namespace l
|
|||
|
||||
static
|
||||
int
|
||||
unlink_loop(const vector<const string*> &basepaths_,
|
||||
const char *fusepath_)
|
||||
unlink_loop(const vector<string> &basepaths_,
|
||||
const char *fusepath_)
|
||||
{
|
||||
int error;
|
||||
|
||||
|
|
@ -74,9 +73,9 @@ namespace l
|
|||
const char *fusepath_)
|
||||
{
|
||||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
vector<string> basepaths;
|
||||
|
||||
rv = actionFunc_(branches_,fusepath_,minfreespace_,basepaths);
|
||||
rv = actionFunc_(branches_,fusepath_,minfreespace_,&basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
|
@ -89,14 +88,13 @@ namespace FUSE
|
|||
int
|
||||
unlink(const char *fusepath_)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
config.open_cache.erase(fusepath_);
|
||||
|
||||
return l::unlink(config.unlink,
|
||||
return l::unlink(config.func.unlink.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath_);
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@
|
|||
#include "fs_base_utime.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "rv.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
|
||||
#include <string>
|
||||
|
|
@ -35,7 +35,7 @@ namespace l
|
|||
{
|
||||
static
|
||||
int
|
||||
utimens_loop_core(const string *basepath_,
|
||||
utimens_loop_core(const string &basepath_,
|
||||
const char *fusepath_,
|
||||
const timespec ts_[2],
|
||||
const int error_)
|
||||
|
|
@ -52,9 +52,9 @@ namespace l
|
|||
|
||||
static
|
||||
int
|
||||
utimens_loop(const vector<const string*> &basepaths_,
|
||||
const char *fusepath_,
|
||||
const timespec ts_[2])
|
||||
utimens_loop(const vector<string> &basepaths_,
|
||||
const char *fusepath_,
|
||||
const timespec ts_[2])
|
||||
{
|
||||
int error;
|
||||
|
||||
|
|
@ -76,9 +76,9 @@ namespace l
|
|||
const timespec ts_[2])
|
||||
{
|
||||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
vector<string> basepaths;
|
||||
|
||||
rv = actionFunc_(branches_,fusepath_,minfreespace_,basepaths);
|
||||
rv = actionFunc_(branches_,fusepath_,minfreespace_,&basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
|
@ -92,12 +92,11 @@ namespace FUSE
|
|||
utimens(const char *fusepath_,
|
||||
const timespec ts_[2])
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::ro();
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
|
||||
return l::utimens(config.utimens,
|
||||
return l::utimens(config.func.utimens.policy,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath_,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include "fileinfo.hpp"
|
||||
#include "fs_base_write.hpp"
|
||||
#include "fs_movefile.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <string>
|
||||
|
|
@ -92,14 +91,12 @@ namespace l
|
|||
rv = func_(fi->fd,buf_,count_,offset_);
|
||||
if(l::out_of_space(-rv))
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const Config &config = Config::ro();
|
||||
|
||||
if(config.moveonenospc)
|
||||
{
|
||||
vector<string> paths;
|
||||
const ugid::Set ugid(0,0);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
config.branches.to_paths(paths);
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include "fs_movefile.hpp"
|
||||
#include "fuse_write.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
|
|
@ -61,6 +60,28 @@ namespace l
|
|||
|
||||
return fuse_buf_copy(&dst,src_,cpflags);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
move_and_write_buf(fuse_bufvec *src_,
|
||||
off_t offset_,
|
||||
FileInfo *fi_)
|
||||
{
|
||||
int rv;
|
||||
uint64_t extra;
|
||||
vector<string> paths;
|
||||
const ugid::Set ugid(0,0);
|
||||
const Config &config = Config::ro();
|
||||
|
||||
config.branches.to_paths(paths);
|
||||
|
||||
extra = fuse_buf_size(src_);
|
||||
rv = fs::movefile(paths,fi_->fusepath,extra,fi_->fd);
|
||||
if(rv == -1)
|
||||
return -ENOSPC;
|
||||
|
||||
return l::write_buf(fi_->fd,src_,offset_);
|
||||
}
|
||||
}
|
||||
|
||||
namespace FUSE
|
||||
|
|
@ -76,27 +97,7 @@ namespace FUSE
|
|||
|
||||
rv = l::write_buf(fi->fd,src_,offset_);
|
||||
if(l::out_of_space(-rv))
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
|
||||
if(config.moveonenospc)
|
||||
{
|
||||
size_t extra;
|
||||
vector<string> paths;
|
||||
const ugid::Set ugid(0,0);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
config.branches.to_paths(paths);
|
||||
|
||||
extra = fuse_buf_size(src_);
|
||||
rv = fs::movefile(paths,fi->fusepath,extra,fi->fd);
|
||||
if(rv == -1)
|
||||
return -ENOSPC;
|
||||
|
||||
rv = l::write_buf(fi->fd,src_,offset_);
|
||||
}
|
||||
}
|
||||
rv = l::move_and_write_buf(src_,offset_,fi);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2016, 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.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "buildvector.hpp"
|
||||
#include "category.hpp"
|
||||
#include "fusefunc.hpp"
|
||||
|
||||
#define FUSEFUNC(X,Y) FuseFunc(FuseFunc::Enum::X,#X,Category::Enum::Y)
|
||||
|
||||
const std::vector<FuseFunc> FuseFunc::_fusefuncs_ =
|
||||
buildvector<FuseFunc,true>
|
||||
(FUSEFUNC(invalid,invalid))
|
||||
(FUSEFUNC(access,search))
|
||||
(FUSEFUNC(chmod,action))
|
||||
(FUSEFUNC(chown,action))
|
||||
(FUSEFUNC(create,create))
|
||||
(FUSEFUNC(getattr,search))
|
||||
(FUSEFUNC(getxattr,search))
|
||||
(FUSEFUNC(link,action))
|
||||
(FUSEFUNC(listxattr,search))
|
||||
(FUSEFUNC(mkdir,create))
|
||||
(FUSEFUNC(mknod,create))
|
||||
(FUSEFUNC(open,search))
|
||||
(FUSEFUNC(readlink,search))
|
||||
(FUSEFUNC(removexattr,action))
|
||||
(FUSEFUNC(rename,action))
|
||||
(FUSEFUNC(rmdir,action))
|
||||
(FUSEFUNC(setxattr,action))
|
||||
(FUSEFUNC(symlink,create))
|
||||
(FUSEFUNC(truncate,action))
|
||||
(FUSEFUNC(unlink,action))
|
||||
(FUSEFUNC(utimens,action))
|
||||
;
|
||||
|
||||
const FuseFunc * const FuseFunc::fusefuncs = &_fusefuncs_[1];
|
||||
|
||||
const FuseFunc &FuseFunc::invalid = FuseFunc::fusefuncs[FuseFunc::Enum::invalid];
|
||||
const FuseFunc &FuseFunc::access = FuseFunc::fusefuncs[FuseFunc::Enum::access];
|
||||
const FuseFunc &FuseFunc::chmod = FuseFunc::fusefuncs[FuseFunc::Enum::chmod];
|
||||
const FuseFunc &FuseFunc::chown = FuseFunc::fusefuncs[FuseFunc::Enum::chown];
|
||||
const FuseFunc &FuseFunc::create = FuseFunc::fusefuncs[FuseFunc::Enum::create];
|
||||
const FuseFunc &FuseFunc::getattr = FuseFunc::fusefuncs[FuseFunc::Enum::getattr];
|
||||
const FuseFunc &FuseFunc::getxattr = FuseFunc::fusefuncs[FuseFunc::Enum::getxattr];
|
||||
const FuseFunc &FuseFunc::link = FuseFunc::fusefuncs[FuseFunc::Enum::link];
|
||||
const FuseFunc &FuseFunc::listxattr = FuseFunc::fusefuncs[FuseFunc::Enum::listxattr];
|
||||
const FuseFunc &FuseFunc::mkdir = FuseFunc::fusefuncs[FuseFunc::Enum::mkdir];
|
||||
const FuseFunc &FuseFunc::mknod = FuseFunc::fusefuncs[FuseFunc::Enum::mknod];
|
||||
const FuseFunc &FuseFunc::open = FuseFunc::fusefuncs[FuseFunc::Enum::open];
|
||||
const FuseFunc &FuseFunc::readlink = FuseFunc::fusefuncs[FuseFunc::Enum::readlink];
|
||||
const FuseFunc &FuseFunc::removexattr = FuseFunc::fusefuncs[FuseFunc::Enum::removexattr];
|
||||
const FuseFunc &FuseFunc::rmdir = FuseFunc::fusefuncs[FuseFunc::Enum::rmdir];
|
||||
const FuseFunc &FuseFunc::setxattr = FuseFunc::fusefuncs[FuseFunc::Enum::setxattr];
|
||||
const FuseFunc &FuseFunc::symlink = FuseFunc::fusefuncs[FuseFunc::Enum::symlink];
|
||||
const FuseFunc &FuseFunc::truncate = FuseFunc::fusefuncs[FuseFunc::Enum::truncate];
|
||||
const FuseFunc &FuseFunc::unlink = FuseFunc::fusefuncs[FuseFunc::Enum::unlink];
|
||||
const FuseFunc &FuseFunc::utimens = FuseFunc::fusefuncs[FuseFunc::Enum::utimens];
|
||||
|
||||
const
|
||||
FuseFunc&
|
||||
FuseFunc::find(const std::string &str)
|
||||
{
|
||||
for(int i = Enum::BEGIN; i != Enum::END; ++i)
|
||||
{
|
||||
if(fusefuncs[i] == str)
|
||||
return fusefuncs[i];
|
||||
}
|
||||
|
||||
return invalid;
|
||||
}
|
||||
|
||||
const
|
||||
FuseFunc&
|
||||
FuseFunc::find(const FuseFunc::Enum::Type i)
|
||||
{
|
||||
if((i >= FuseFunc::Enum::BEGIN) && (i < FuseFunc::Enum::END))
|
||||
return fusefuncs[i];
|
||||
|
||||
return invalid;
|
||||
}
|
||||
125
src/fusefunc.hpp
125
src/fusefunc.hpp
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2016, 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 "category.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class FuseFunc
|
||||
{
|
||||
public:
|
||||
struct Enum
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
invalid = -1,
|
||||
BEGIN = 0,
|
||||
access = BEGIN,
|
||||
chmod,
|
||||
chown,
|
||||
create,
|
||||
getattr,
|
||||
getxattr,
|
||||
link,
|
||||
listxattr,
|
||||
mkdir,
|
||||
mknod,
|
||||
open,
|
||||
readlink,
|
||||
removexattr,
|
||||
rename,
|
||||
rmdir,
|
||||
setxattr,
|
||||
symlink,
|
||||
truncate,
|
||||
unlink,
|
||||
utimens,
|
||||
END
|
||||
};
|
||||
};
|
||||
|
||||
private:
|
||||
Enum::Type _enum;
|
||||
std::string _str;
|
||||
Category::Enum::Type _category;
|
||||
|
||||
public:
|
||||
FuseFunc()
|
||||
: _enum(invalid),
|
||||
_str(invalid),
|
||||
_category(Category::Enum::invalid)
|
||||
{
|
||||
}
|
||||
|
||||
FuseFunc(const Enum::Type enum_,
|
||||
const std::string &str_,
|
||||
const Category::Enum::Type category_)
|
||||
: _enum(enum_),
|
||||
_str(str_),
|
||||
_category(category_)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
operator const Enum::Type() const { return _enum; }
|
||||
operator const std::string&() const { return _str; }
|
||||
operator const Category::Enum::Type() const { return _category; }
|
||||
operator const FuseFunc*() const { return this; }
|
||||
|
||||
bool operator==(const std::string &str_) const
|
||||
{ return _str == str_; }
|
||||
|
||||
bool operator==(const Enum::Type enum_) const
|
||||
{ return _enum == enum_; }
|
||||
|
||||
bool operator!=(const FuseFunc &r) const
|
||||
{ return _enum != r._enum; }
|
||||
|
||||
bool operator<(const FuseFunc &r) const
|
||||
{ return _enum < r._enum; }
|
||||
|
||||
public:
|
||||
static const FuseFunc &find(const std::string&);
|
||||
static const FuseFunc &find(const Enum::Type);
|
||||
|
||||
public:
|
||||
static const std::vector<FuseFunc> _fusefuncs_;
|
||||
static const FuseFunc * const fusefuncs;
|
||||
static const FuseFunc &invalid;
|
||||
static const FuseFunc &access;
|
||||
static const FuseFunc &chmod;
|
||||
static const FuseFunc &chown;
|
||||
static const FuseFunc &create;
|
||||
static const FuseFunc &getattr;
|
||||
static const FuseFunc &getxattr;
|
||||
static const FuseFunc &link;
|
||||
static const FuseFunc &listxattr;
|
||||
static const FuseFunc &mkdir;
|
||||
static const FuseFunc &mknod;
|
||||
static const FuseFunc &open;
|
||||
static const FuseFunc &readlink;
|
||||
static const FuseFunc &removexattr;
|
||||
static const FuseFunc &rename;
|
||||
static const FuseFunc &rmdir;
|
||||
static const FuseFunc &setxattr;
|
||||
static const FuseFunc &symlink;
|
||||
static const FuseFunc &truncate;
|
||||
static const FuseFunc &unlink;
|
||||
static const FuseFunc &utimens;
|
||||
};
|
||||
35
src/hw_cpu.cpp
Normal file
35
src/hw_cpu.cpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
namespace hw
|
||||
{
|
||||
namespace cpu
|
||||
{
|
||||
int
|
||||
logical_core_count(void)
|
||||
{
|
||||
#if defined _SC_NPROCESSORS_ONLN
|
||||
return ::sysconf(_SC_NPROCESSORS_ONLN);
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/hw_cpu.hpp
Normal file
27
src/hw_cpu.hpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
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
|
||||
|
||||
namespace hw
|
||||
{
|
||||
namespace cpu
|
||||
{
|
||||
int logical_core_count(void);
|
||||
}
|
||||
}
|
||||
|
|
@ -155,15 +155,25 @@ namespace l
|
|||
main(const int argc_,
|
||||
char **argv_)
|
||||
{
|
||||
fuse_args args;
|
||||
fuse_operations ops = {0};
|
||||
Config config;
|
||||
Config config;
|
||||
fuse_args args;
|
||||
fuse_operations ops;
|
||||
std::vector<std::string> errs;
|
||||
|
||||
memset(&ops,0,sizeof(fuse_operations));
|
||||
|
||||
args.argc = argc_;
|
||||
args.argv = argv_;
|
||||
args.allocated = 0;
|
||||
|
||||
options::parse(&args,&config);
|
||||
options::parse(&args,&config,&errs);
|
||||
if(errs.size())
|
||||
{
|
||||
for(uint64_t i = 0; i < errs.size(); i++)
|
||||
std::cerr << "* ERROR: " << errs[i] << std::endl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
l::setup_resources();
|
||||
l::get_fuse_operations(ops,config.nullrw);
|
||||
|
|
|
|||
|
|
@ -15,9 +15,11 @@
|
|||
*/
|
||||
|
||||
#include "config.hpp"
|
||||
#include "ef.hpp"
|
||||
#include "errno.hpp"
|
||||
#include "fs_glob.hpp"
|
||||
#include "fs_statvfs_cache.hpp"
|
||||
#include "hw_cpu.hpp"
|
||||
#include "num.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "str.hpp"
|
||||
|
|
@ -25,9 +27,9 @@
|
|||
|
||||
#include <fuse.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -46,6 +48,92 @@ enum
|
|||
MERGERFS_OPT_VERSION
|
||||
};
|
||||
|
||||
struct Data
|
||||
{
|
||||
Config *config;
|
||||
vector<string> *errs;
|
||||
};
|
||||
|
||||
|
||||
namespace l
|
||||
{
|
||||
static
|
||||
int
|
||||
calculate_thread_count(int threads_)
|
||||
{
|
||||
int tc;
|
||||
|
||||
if(threads_ > 0)
|
||||
return threads_;
|
||||
|
||||
tc = hw::cpu::logical_core_count();
|
||||
if(threads_ < 0)
|
||||
tc /= -threads_;
|
||||
if(tc == 0)
|
||||
tc = 1;
|
||||
|
||||
return tc;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
read_config(Data *data_,
|
||||
std::istream &is_)
|
||||
{
|
||||
int rv;
|
||||
std::string key;
|
||||
std::string val;
|
||||
std::string line;
|
||||
|
||||
rv = 0;
|
||||
while(std::getline(is_,line,'\n'))
|
||||
{
|
||||
line = str::trim(line);
|
||||
if(!line.empty() && (line[0] == '#'))
|
||||
continue;
|
||||
|
||||
str::splitkv(line,'=',&key,&val);
|
||||
key = str::trim(key);
|
||||
val = str::trim(val);
|
||||
|
||||
if(key.empty() || val.empty())
|
||||
continue;
|
||||
|
||||
rv = data_->config->set_raw(key,val);
|
||||
switch(rv)
|
||||
{
|
||||
case -EINVAL:
|
||||
data_->errs->push_back("invalid argument - " + line);
|
||||
break;
|
||||
case -ENOATTR:
|
||||
data_->errs->push_back("unknown option - " + line);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
read_config(Data *data_,
|
||||
const std::string &filepath_)
|
||||
{
|
||||
std::ifstream is;
|
||||
|
||||
is.open(filepath_);
|
||||
if(is.bad())
|
||||
{
|
||||
data_->errs->push_back("unable to open config - " + filepath_);
|
||||
}
|
||||
else
|
||||
{
|
||||
l::read_config(data_,is);
|
||||
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
|
|
@ -70,12 +158,26 @@ set_kv_option(fuse_args *args,
|
|||
set_option(args,option);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
set_threads(fuse_args *args_,
|
||||
Config *config_)
|
||||
{
|
||||
int threads;
|
||||
|
||||
threads = l::calculate_thread_count(config_->threads);
|
||||
|
||||
config_->threads = threads;
|
||||
|
||||
set_kv_option(args_,"threads",config_->threads.to_string());
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
set_fsname(fuse_args *args_,
|
||||
Config *config_)
|
||||
{
|
||||
if(config_->fsname.empty())
|
||||
if(config_->fsname->empty())
|
||||
{
|
||||
vector<string> branches;
|
||||
|
||||
|
|
@ -104,337 +206,95 @@ set_default_options(fuse_args *args)
|
|||
|
||||
static
|
||||
int
|
||||
parse_and_process(const std::string &value_,
|
||||
uint16_t &uint16_,
|
||||
uint16_t min_,
|
||||
uint16_t max_)
|
||||
parse_and_process_kv_arg(Data *data_,
|
||||
const std::string &key_,
|
||||
const std::string &val_)
|
||||
{
|
||||
int rv;
|
||||
uint64_t uint64;
|
||||
std::string key(key_);
|
||||
std::string val(val_);
|
||||
|
||||
rv = num::to_uint64_t(value_,uint64);
|
||||
if(rv == -1)
|
||||
return 1;
|
||||
|
||||
if((uint64 > max_) || (uint64 < min_))
|
||||
return 1;
|
||||
|
||||
uint16_ = uint64;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
parse_and_process(const std::string &value_,
|
||||
uint64_t &int_)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = num::to_uint64_t(value_,int_);
|
||||
if(rv == -1)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
parse_and_process(const std::string &value,
|
||||
time_t &time)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = num::to_time_t(value,time);
|
||||
if(rv == -1)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
parse_and_process(const std::string &value_,
|
||||
bool &boolean_)
|
||||
{
|
||||
if((value_ == "false") || (value_ == "0") || (value_ == "off"))
|
||||
boolean_ = false;
|
||||
else if((value_ == "true") || (value_ == "1") || (value_ == "on"))
|
||||
boolean_ = true;
|
||||
else
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
parse_and_process(const std::string &value_,
|
||||
std::string &str_)
|
||||
{
|
||||
str_ = value_;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
parse_and_process(const std::string &value_,
|
||||
Config::CacheFiles &cache_files_)
|
||||
{
|
||||
Config::CacheFiles tmp;
|
||||
|
||||
tmp = value_;
|
||||
if(!tmp.valid())
|
||||
return 1;
|
||||
|
||||
cache_files_ = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
parse_and_process_errno(const std::string &value_,
|
||||
int &errno_)
|
||||
{
|
||||
if(value_ == "passthrough")
|
||||
errno_ = 0;
|
||||
else if(value_ == "nosys")
|
||||
errno_ = ENOSYS;
|
||||
else if(value_ == "noattr")
|
||||
errno_ = ENOATTR;
|
||||
else
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
parse_and_process_statfs(const std::string &value_,
|
||||
Config::StatFS::Enum &enum_)
|
||||
{
|
||||
if(value_ == "base")
|
||||
enum_ = Config::StatFS::BASE;
|
||||
else if(value_ == "full")
|
||||
enum_ = Config::StatFS::FULL;
|
||||
else
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
parse_and_process_statfsignore(const std::string &value_,
|
||||
Config::StatFSIgnore::Enum &enum_)
|
||||
{
|
||||
if(value_ == "none")
|
||||
enum_ = Config::StatFSIgnore::NONE;
|
||||
else if(value_ == "ro")
|
||||
enum_ = Config::StatFSIgnore::RO;
|
||||
else if(value_ == "nc")
|
||||
enum_ = Config::StatFSIgnore::NC;
|
||||
else
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
parse_and_process_statfs_cache(const std::string &value_)
|
||||
{
|
||||
int rv;
|
||||
uint64_t timeout;
|
||||
|
||||
rv = num::to_uint64_t(value_,timeout);
|
||||
if(rv == -1)
|
||||
return 1;
|
||||
|
||||
fs::statvfs_cache_timeout(timeout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
parse_and_process_cache(Config &config_,
|
||||
const string &func_,
|
||||
const string &value_,
|
||||
fuse_args *outargs)
|
||||
{
|
||||
if(func_ == "open")
|
||||
return parse_and_process(value_,config_.open_cache.timeout);
|
||||
else if(func_ == "statfs")
|
||||
return parse_and_process_statfs_cache(value_);
|
||||
else if(func_ == "entry")
|
||||
return (set_kv_option(outargs,"entry_timeout",value_),0);
|
||||
else if(func_ == "negative_entry")
|
||||
return (set_kv_option(outargs,"negative_timeout",value_),0);
|
||||
else if(func_ == "attr")
|
||||
return (set_kv_option(outargs,"attr_timeout",value_),0);
|
||||
else if(func_ == "symlinks")
|
||||
return parse_and_process(value_,config_.cache_symlinks);
|
||||
else if(func_ == "readdir")
|
||||
return parse_and_process(value_,config_.cache_readdir);
|
||||
else if(func_ == "files")
|
||||
return parse_and_process(value_,config_.cache_files);
|
||||
else if(func_ == "writeback")
|
||||
return parse_and_process(value_,config_.writeback_cache);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
parse_and_process_arg(Config &config,
|
||||
const std::string &arg)
|
||||
{
|
||||
if(arg == "defaults")
|
||||
rv = 0;
|
||||
if(key == "config")
|
||||
return (l::read_config(data_,val_),0);
|
||||
ef(key == "attr_timeout")
|
||||
key = "cache.attr";
|
||||
ef(key == "entry_timeout")
|
||||
key = "cache.entry";
|
||||
ef(key == "negative_entry")
|
||||
key = "cache.negative_entry";
|
||||
ef(key == "direct_io" && val.empty())
|
||||
val = "true";
|
||||
ef(key == "kernel_cache" && val.empty())
|
||||
val = "true";
|
||||
ef(key == "auto_cache" && val.empty())
|
||||
val = "true";
|
||||
ef(key == "async_read" && val.empty())
|
||||
val = "true";
|
||||
ef(key == "sync_read" && val.empty())
|
||||
{key = "async_read", val = "false";}
|
||||
ef(key == "defaults")
|
||||
return 0;
|
||||
else if(arg == "hard_remove")
|
||||
ef(key == "hard_remove")
|
||||
return 0;
|
||||
else if(arg == "direct_io")
|
||||
return (config.direct_io=true,0);
|
||||
else if(arg == "kernel_cache")
|
||||
return (config.kernel_cache=true,0);
|
||||
else if(arg == "auto_cache")
|
||||
return (config.auto_cache=true,0);
|
||||
else if(arg == "async_read")
|
||||
return (config.async_read=true,0);
|
||||
else if(arg == "sync_read")
|
||||
return (config.async_read=false,0);
|
||||
else if(arg == "atomic_o_trunc")
|
||||
ef(key == "atomic_o_trunc")
|
||||
return 0;
|
||||
else if(arg == "big_writes")
|
||||
ef(key == "big_writes")
|
||||
return 0;
|
||||
else if(arg == "readdir_ino")
|
||||
ef(key == "cache.open")
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
if(data_->config->has_key(key) == false)
|
||||
return 1;
|
||||
|
||||
static
|
||||
int
|
||||
parse_and_process_kv_arg(Config &config,
|
||||
const std::string &key,
|
||||
const std::string &value,
|
||||
fuse_args *outargs)
|
||||
{
|
||||
int rv;
|
||||
std::vector<std::string> keypart;
|
||||
|
||||
rv = -1;
|
||||
str::split(keypart,key,'.');
|
||||
if(keypart.size() == 2)
|
||||
{
|
||||
if(keypart[0] == "func")
|
||||
rv = config.set_func_policy(keypart[1],value);
|
||||
else if(keypart[0] == "category")
|
||||
rv = config.set_category_policy(keypart[1],value);
|
||||
else if(keypart[0] == "cache")
|
||||
rv = parse_and_process_cache(config,keypart[1],value,outargs);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(key == "minfreespace")
|
||||
rv = parse_and_process(value,config.minfreespace);
|
||||
else if(key == "moveonenospc")
|
||||
rv = parse_and_process(value,config.moveonenospc);
|
||||
else if(key == "dropcacheonclose")
|
||||
rv = parse_and_process(value,config.dropcacheonclose);
|
||||
else if(key == "symlinkify")
|
||||
rv = parse_and_process(value,config.symlinkify);
|
||||
else if(key == "symlinkify_timeout")
|
||||
rv = parse_and_process(value,config.symlinkify_timeout);
|
||||
else if(key == "nullrw")
|
||||
rv = parse_and_process(value,config.nullrw);
|
||||
else if(key == "ignorepponrename")
|
||||
rv = parse_and_process(value,config.ignorepponrename);
|
||||
else if(key == "security_capability")
|
||||
rv = parse_and_process(value,config.security_capability);
|
||||
else if(key == "link_cow")
|
||||
rv = parse_and_process(value,config.link_cow);
|
||||
else if(key == "xattr")
|
||||
rv = parse_and_process_errno(value,config.xattr);
|
||||
else if(key == "statfs")
|
||||
rv = parse_and_process_statfs(value,config.statfs);
|
||||
else if(key == "statfs_ignore")
|
||||
rv = parse_and_process_statfsignore(value,config.statfs_ignore);
|
||||
else if(key == "fsname")
|
||||
rv = parse_and_process(value,config.fsname);
|
||||
else if(key == "posix_acl")
|
||||
rv = parse_and_process(value,config.posix_acl);
|
||||
else if(key == "direct_io")
|
||||
rv = parse_and_process(value,config.direct_io);
|
||||
else if(key == "kernel_cache")
|
||||
rv = parse_and_process(value,config.kernel_cache);
|
||||
else if(key == "auto_cache")
|
||||
rv = parse_and_process(value,config.auto_cache);
|
||||
else if(key == "async_read")
|
||||
rv = parse_and_process(value,config.async_read);
|
||||
else if(key == "readdirplus")
|
||||
rv = parse_and_process(value,config.readdirplus);
|
||||
else if(key == "max_write")
|
||||
rv = 0;
|
||||
else if(key == "fuse_msg_size")
|
||||
rv = parse_and_process(value,config.fuse_msg_size,
|
||||
1,
|
||||
FUSE_MAX_MAX_PAGES);
|
||||
}
|
||||
|
||||
if(rv == -1)
|
||||
rv = 1;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
process_opt(Config &config,
|
||||
const std::string &arg,
|
||||
fuse_args *outargs)
|
||||
{
|
||||
int rv;
|
||||
std::vector<std::string> argvalue;
|
||||
|
||||
str::split(argvalue,arg,'=');
|
||||
switch(argvalue.size())
|
||||
{
|
||||
case 1:
|
||||
rv = parse_and_process_arg(config,argvalue[0]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
rv = parse_and_process_kv_arg(config,argvalue[0],argvalue[1],outargs);
|
||||
break;
|
||||
|
||||
default:
|
||||
rv = 1;
|
||||
break;
|
||||
};
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
process_branches(const char *arg,
|
||||
Config &config)
|
||||
{
|
||||
config.branches.set(arg);
|
||||
rv = data_->config->set_raw(key,val);
|
||||
if(rv)
|
||||
data_->errs->push_back("invalid argument - " + key_ + '=' + val_);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
process_destmounts(const char *arg,
|
||||
Config &config)
|
||||
process_opt(Data *data_,
|
||||
const std::string &arg_)
|
||||
{
|
||||
config.destmount = arg;
|
||||
std::string key;
|
||||
std::string val;
|
||||
|
||||
str::splitkv(arg_,'=',&key,&val);
|
||||
|
||||
return parse_and_process_kv_arg(data_,key,val);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
process_branches(Data *data_,
|
||||
const char *arg_)
|
||||
{
|
||||
int rv;
|
||||
string arg;
|
||||
|
||||
arg = arg_;
|
||||
rv = data_->config->set_raw("branches",arg);
|
||||
if(rv)
|
||||
data_->errs->push_back("unable to parse 'branches' - " + arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
process_mount(Data *data_,
|
||||
const char *arg_)
|
||||
{
|
||||
int rv;
|
||||
string arg;
|
||||
|
||||
arg = arg_;
|
||||
rv = data_->config->set_raw("mount",arg);
|
||||
if(rv)
|
||||
data_->errs->push_back("unable to set 'mount' - " + arg);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -453,6 +313,7 @@ usage(void)
|
|||
"mergerfs options:\n"
|
||||
" <branches> ':' delimited list of directories. Supports\n"
|
||||
" shell globbing (must be escaped in shell)\n"
|
||||
" -o config=<file> Read options from file in key=val format\n"
|
||||
" -o func.<f>=<p> Set function <f> to policy <p>\n"
|
||||
" -o category.<c>=<p> Set functions in category <c> to <p>\n"
|
||||
" -o cache.open=<int> 'open' policy cache timeout in seconds.\n"
|
||||
|
|
@ -536,53 +397,53 @@ usage(void)
|
|||
|
||||
static
|
||||
int
|
||||
option_processor(void *data,
|
||||
const char *arg,
|
||||
int key,
|
||||
fuse_args *outargs)
|
||||
option_processor(void *data_,
|
||||
const char *arg_,
|
||||
int key_,
|
||||
fuse_args *outargs_)
|
||||
{
|
||||
int rv = 0;
|
||||
Config &config = *(Config*)data;
|
||||
Data *data = (Data*)data_;
|
||||
|
||||
switch(key)
|
||||
switch(key_)
|
||||
{
|
||||
case FUSE_OPT_KEY_OPT:
|
||||
rv = process_opt(config,arg,outargs);
|
||||
break;
|
||||
return process_opt(data,arg_);
|
||||
|
||||
case FUSE_OPT_KEY_NONOPT:
|
||||
rv = config.branches.empty() ?
|
||||
process_branches(arg,config) :
|
||||
process_destmounts(arg,config);
|
||||
break;
|
||||
if(data->config->branches.empty())
|
||||
return process_branches(data,arg_);
|
||||
else
|
||||
return process_mount(data,arg_);
|
||||
|
||||
case MERGERFS_OPT_HELP:
|
||||
usage();
|
||||
close(2);
|
||||
dup(1);
|
||||
fuse_opt_add_arg(outargs,"-ho");
|
||||
fuse_opt_add_arg(outargs_,"-ho");
|
||||
break;
|
||||
|
||||
case MERGERFS_OPT_VERSION:
|
||||
std::cout << "mergerfs version: "
|
||||
<< (MERGERFS_VERSION[0] ? MERGERFS_VERSION : "unknown")
|
||||
<< std::endl;
|
||||
fuse_opt_add_arg(outargs,"--version");
|
||||
fuse_opt_add_arg(outargs_,"--version");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return rv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace options
|
||||
{
|
||||
void
|
||||
parse(fuse_args *args_,
|
||||
Config *config_)
|
||||
parse(fuse_args *args_,
|
||||
Config *config_,
|
||||
std::vector<std::string> *errs_)
|
||||
{
|
||||
Data data;
|
||||
const struct fuse_opt opts[] =
|
||||
{
|
||||
FUSE_OPT_KEY("-h",MERGERFS_OPT_HELP),
|
||||
|
|
@ -593,13 +454,16 @@ namespace options
|
|||
{NULL,-1U,0}
|
||||
};
|
||||
|
||||
data.config = config_;
|
||||
data.errs = errs_;
|
||||
fuse_opt_parse(args_,
|
||||
config_,
|
||||
&data,
|
||||
opts,
|
||||
::option_processor);
|
||||
|
||||
set_default_options(args_);
|
||||
set_fsname(args_,config_);
|
||||
set_subtype(args_);
|
||||
set_threads(args_,config_);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,11 +18,15 @@
|
|||
|
||||
#include "config.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <fuse.h>
|
||||
|
||||
namespace options
|
||||
{
|
||||
void
|
||||
parse(fuse_args *args,
|
||||
Config *config);
|
||||
parse(fuse_args *args,
|
||||
Config *config,
|
||||
std::vector<std::string> *errs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,30 +58,33 @@ public:
|
|||
{
|
||||
typedef std::string string;
|
||||
typedef std::vector<string> strvec;
|
||||
typedef std::vector<const string*> cstrptrvec;
|
||||
typedef const string cstring;
|
||||
typedef const uint64_t cuint64_t;
|
||||
typedef const strvec cstrvec;
|
||||
typedef const Category::Enum::Type CType;
|
||||
|
||||
typedef int (*Ptr)(CType,const Branches &,const char *,cuint64_t,cstrptrvec &);
|
||||
typedef int (*Ptr)(CType,const Branches &,const char *,cuint64_t,strvec *);
|
||||
|
||||
template <CType T>
|
||||
class Base
|
||||
{
|
||||
public:
|
||||
Base(const Policy *p)
|
||||
: func(p->_func)
|
||||
Base(const Policy &p_)
|
||||
: func(p_._func)
|
||||
{}
|
||||
|
||||
Base(const Policy *p_)
|
||||
: func(p_->_func)
|
||||
{}
|
||||
|
||||
int
|
||||
operator()(const Branches &b,const char *c,cuint64_t d,cstrptrvec &e)
|
||||
operator()(const Branches &b,const char *c,cuint64_t d,strvec *e)
|
||||
{
|
||||
return func(T,b,c,d,e);
|
||||
}
|
||||
|
||||
int
|
||||
operator()(const Branches &b,const string &c,cuint64_t d,cstrptrvec &e)
|
||||
operator()(const Branches &b,const string &c,cuint64_t d,strvec *e)
|
||||
{
|
||||
return func(T,b,c.c_str(),d,e);
|
||||
}
|
||||
|
|
@ -90,11 +93,11 @@ public:
|
|||
operator()(const Branches &b,const char *c,cuint64_t d,string *e)
|
||||
{
|
||||
int rv;
|
||||
cstrptrvec v;
|
||||
strvec v;
|
||||
|
||||
rv = func(T,b,c,d,v);
|
||||
rv = func(T,b,c,d,&v);
|
||||
if(!v.empty())
|
||||
*e = *v[0];
|
||||
*e = v[0];
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
|
@ -107,21 +110,21 @@ public:
|
|||
typedef Base<Category::Enum::create> Create;
|
||||
typedef Base<Category::Enum::search> Search;
|
||||
|
||||
static int invalid(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int all(CType,const Branches&,const char*,cuint64_t,cstrptrvec&);
|
||||
static int epall(CType,const Branches&,const char*,cuint64_t,cstrptrvec&);
|
||||
static int epff(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int eplfs(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int eplus(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int epmfs(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int eprand(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int erofs(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int ff(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int lfs(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int lus(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int mfs(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int newest(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int rand(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int invalid(CType,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int all(CType,const Branches&,const char*,cuint64_t,strvec*);
|
||||
static int epall(CType,const Branches&,const char*,cuint64_t,strvec*);
|
||||
static int epff(CType,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int eplfs(CType,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int eplus(CType,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int epmfs(CType,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int eprand(CType,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int erofs(CType,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int ff(CType,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int lfs(CType,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int lus(CType,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int mfs(CType,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int newest(CType,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int rand(CType,const Branches&,const char *,cuint64_t,strvec*);
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
@ -161,6 +164,7 @@ public:
|
|||
operator const std::string&() const { return _str; }
|
||||
operator const Func::Ptr() const { return _func; }
|
||||
operator const Policy*() const { return this; }
|
||||
const std::string& to_string() const { return _str; }
|
||||
|
||||
bool operator==(const Enum::Type enum_) const
|
||||
{ return _enum == enum_; }
|
||||
|
|
@ -180,6 +184,7 @@ public:
|
|||
static const Policy &find(const Enum::Type);
|
||||
|
||||
public:
|
||||
|
||||
static const std::vector<Policy> _policies_;
|
||||
static const Policy * const policies;
|
||||
|
||||
|
|
@ -199,3 +204,14 @@ public:
|
|||
static const Policy &newest;
|
||||
static const Policy &rand;
|
||||
};
|
||||
|
||||
namespace std
|
||||
{
|
||||
static
|
||||
inline
|
||||
string
|
||||
to_string(const Policy &p_)
|
||||
{
|
||||
return p_.to_string();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "fs_path.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -31,10 +32,12 @@ namespace all
|
|||
{
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
create(const Branches &branches_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
|
|
@ -52,13 +55,13 @@ namespace all
|
|||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < minfreespace)
|
||||
if(info.spaceavail < minfreespace_)
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
paths.push_back(&branch->path);
|
||||
paths_->push_back(branch->path);
|
||||
}
|
||||
|
||||
if(paths.empty())
|
||||
if(paths_->empty())
|
||||
return (errno=error,-1);
|
||||
|
||||
return 0;
|
||||
|
|
@ -66,14 +69,14 @@ namespace all
|
|||
}
|
||||
|
||||
int
|
||||
Policy::Func::all(const Category::Enum::Type type,
|
||||
Policy::Func::all(const Category::Enum::Type type_,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
if(type == Category::Enum::create)
|
||||
return all::create(branches_,minfreespace,paths);
|
||||
if(type_ == Category::Enum::create)
|
||||
return all::create(branches_,minfreespace_,paths_);
|
||||
|
||||
return Policy::Func::epall(type,branches_,fusepath,minfreespace,paths);
|
||||
return Policy::Func::epall(type_,branches_,fusepath_,minfreespace_,paths_);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,11 @@
|
|||
#include <cstdlib>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
using std::map;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
static const uint64_t DEFAULT_TIMEOUT = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "fs_statvfs_cache.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -33,11 +34,13 @@ namespace epall
|
|||
{
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<string> *paths)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
|
|
@ -60,10 +63,10 @@ namespace epall
|
|||
if(info.spaceavail < minfreespace)
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
paths.push_back(&branch->path);
|
||||
paths->push_back(branch->path);
|
||||
}
|
||||
|
||||
if(paths.empty())
|
||||
if(paths->empty())
|
||||
return (errno=error,-1);
|
||||
|
||||
return 0;
|
||||
|
|
@ -71,10 +74,12 @@ namespace epall
|
|||
|
||||
static
|
||||
int
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<string> *paths)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
int error;
|
||||
bool readonly;
|
||||
|
|
@ -95,10 +100,10 @@ namespace epall
|
|||
if(readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
|
||||
paths.push_back(&branch->path);
|
||||
paths->push_back(branch->path);
|
||||
}
|
||||
|
||||
if(paths.empty())
|
||||
if(paths->empty())
|
||||
return (errno=error,-1);
|
||||
|
||||
return 0;
|
||||
|
|
@ -106,10 +111,12 @@ namespace epall
|
|||
|
||||
static
|
||||
int
|
||||
search(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
search(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<string> *paths)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
const Branch *branch;
|
||||
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
|
|
@ -119,10 +126,10 @@ namespace epall
|
|||
if(!fs::exists(branch->path,fusepath))
|
||||
continue;
|
||||
|
||||
paths.push_back(&branch->path);
|
||||
paths->push_back(branch->path);
|
||||
}
|
||||
|
||||
if(paths.empty())
|
||||
if(paths->empty())
|
||||
return (errno=ENOENT,-1);
|
||||
|
||||
return 0;
|
||||
|
|
@ -134,7 +141,7 @@ Policy::Func::epall(const Category::Enum::Type type,
|
|||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
vector<string> *paths)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "fs_statvfs_cache.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -33,11 +34,13 @@ namespace epff
|
|||
{
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
|
|
@ -48,7 +51,7 @@ namespace epff
|
|||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
if(!fs::exists(branch->path,fusepath_))
|
||||
error_and_continue(error,ENOENT);
|
||||
if(branch->ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
|
|
@ -57,10 +60,10 @@ namespace epff
|
|||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < minfreespace)
|
||||
if(info.spaceavail < minfreespace_)
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
paths.push_back(&branch->path);
|
||||
paths_->push_back(branch->path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -70,10 +73,12 @@ namespace epff
|
|||
|
||||
static
|
||||
int
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
int error;
|
||||
bool readonly;
|
||||
|
|
@ -84,7 +89,7 @@ namespace epff
|
|||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
if(!fs::exists(branch->path,fusepath_))
|
||||
error_and_continue(error,ENOENT);
|
||||
if(branch->ro())
|
||||
error_and_continue(error,EROFS);
|
||||
|
|
@ -94,7 +99,7 @@ namespace epff
|
|||
if(readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
|
||||
paths.push_back(&branch->path);
|
||||
paths_->push_back(branch->path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -104,20 +109,22 @@ namespace epff
|
|||
|
||||
static
|
||||
int
|
||||
search(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
search(const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
const Branch *branch;
|
||||
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
if(!fs::exists(branch->path,fusepath_))
|
||||
continue;
|
||||
|
||||
paths.push_back(&branch->path);
|
||||
paths_->push_back(branch->path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -127,20 +134,20 @@ namespace epff
|
|||
}
|
||||
|
||||
int
|
||||
Policy::Func::epff(const Category::Enum::Type type,
|
||||
Policy::Func::epff(const Category::Enum::Type type_,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
switch(type)
|
||||
switch(type_)
|
||||
{
|
||||
case Category::Enum::create:
|
||||
return epff::create(branches_,fusepath,minfreespace,paths);
|
||||
return epff::create(branches_,fusepath_,minfreespace_,paths_);
|
||||
case Category::Enum::action:
|
||||
return epff::action(branches_,fusepath,paths);
|
||||
return epff::action(branches_,fusepath_,paths_);
|
||||
case Category::Enum::search:
|
||||
default:
|
||||
return epff::search(branches_,fusepath,paths);
|
||||
return epff::search(branches_,fusepath_,paths_);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "fs_statvfs_cache.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
|
@ -34,11 +35,13 @@ namespace eplfs
|
|||
{
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<string> *paths)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
int error;
|
||||
uint64_t eplfs;
|
||||
|
|
@ -74,17 +77,19 @@ namespace eplfs
|
|||
if(eplfsbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(eplfsbasepath);
|
||||
paths->push_back(*eplfsbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<string> *paths)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
int error;
|
||||
uint64_t eplfs;
|
||||
|
|
@ -118,7 +123,7 @@ namespace eplfs
|
|||
if(eplfsbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(eplfsbasepath);
|
||||
paths->push_back(*eplfsbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -127,8 +132,10 @@ namespace eplfs
|
|||
int
|
||||
search(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
vector<string> *paths)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
uint64_t eplfs;
|
||||
uint64_t spaceavail;
|
||||
|
|
@ -156,7 +163,7 @@ namespace eplfs
|
|||
if(eplfsbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
|
||||
paths.push_back(eplfsbasepath);
|
||||
paths->push_back(*eplfsbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -167,7 +174,7 @@ Policy::Func::eplfs(const Category::Enum::Type type,
|
|||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
vector<string> *paths)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "fs_statvfs_cache.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
|
@ -34,11 +35,13 @@ namespace eplus
|
|||
{
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<string> *paths)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
int error;
|
||||
uint64_t eplus;
|
||||
|
|
@ -74,17 +77,19 @@ namespace eplus
|
|||
if(eplusbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(eplusbasepath);
|
||||
paths->push_back(*eplusbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<string> *paths)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
int error;
|
||||
uint64_t eplus;
|
||||
|
|
@ -118,17 +123,19 @@ namespace eplus
|
|||
if(eplusbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(eplusbasepath);
|
||||
paths->push_back(*eplusbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
search(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
search(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<string> *paths)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
uint64_t eplus;
|
||||
uint64_t spaceused;
|
||||
|
|
@ -156,7 +163,7 @@ namespace eplus
|
|||
if(eplusbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
|
||||
paths.push_back(eplusbasepath);
|
||||
paths->push_back(*eplusbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -167,7 +174,7 @@ Policy::Func::eplus(const Category::Enum::Type type,
|
|||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
vector<string> *paths)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "fs_statvfs_cache.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
|
@ -34,11 +35,13 @@ namespace epmfs
|
|||
{
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
int error;
|
||||
uint64_t epmfs;
|
||||
|
|
@ -53,7 +56,7 @@ namespace epmfs
|
|||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
if(!fs::exists(branch->path,fusepath_))
|
||||
error_and_continue(error,ENOENT);
|
||||
if(branch->ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
|
|
@ -62,7 +65,7 @@ namespace epmfs
|
|||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < minfreespace)
|
||||
if(info.spaceavail < minfreespace_)
|
||||
error_and_continue(error,ENOSPC);
|
||||
if(info.spaceavail < epmfs)
|
||||
continue;
|
||||
|
|
@ -74,17 +77,19 @@ namespace epmfs
|
|||
if(epmfsbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(epmfsbasepath);
|
||||
paths_->push_back(*epmfsbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
int error;
|
||||
uint64_t epmfs;
|
||||
|
|
@ -99,7 +104,7 @@ namespace epmfs
|
|||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
if(!fs::exists(branch->path,fusepath_))
|
||||
error_and_continue(error,ENOENT);
|
||||
if(branch->ro())
|
||||
error_and_continue(error,EROFS);
|
||||
|
|
@ -118,17 +123,19 @@ namespace epmfs
|
|||
if(epmfsbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(epmfsbasepath);
|
||||
paths_->push_back(*epmfsbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
search(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
search(const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
uint64_t epmfs;
|
||||
uint64_t spaceavail;
|
||||
|
|
@ -141,7 +148,7 @@ namespace epmfs
|
|||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
if(!fs::exists(branch->path,fusepath_))
|
||||
continue;
|
||||
rv = fs::statvfs_cache_spaceavail(branch->path,&spaceavail);
|
||||
if(rv == -1)
|
||||
|
|
@ -156,27 +163,27 @@ namespace epmfs
|
|||
if(epmfsbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
|
||||
paths.push_back(epmfsbasepath);
|
||||
paths_->push_back(*epmfsbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
Policy::Func::epmfs(const Category::Enum::Type type,
|
||||
Policy::Func::epmfs(const Category::Enum::Type type_,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
switch(type)
|
||||
switch(type_)
|
||||
{
|
||||
case Category::Enum::create:
|
||||
return epmfs::create(branches_,fusepath,minfreespace,paths);
|
||||
return epmfs::create(branches_,fusepath_,minfreespace_,paths_);
|
||||
case Category::Enum::action:
|
||||
return epmfs::action(branches_,fusepath,paths);
|
||||
return epmfs::action(branches_,fusepath_,paths_);
|
||||
case Category::Enum::search:
|
||||
default:
|
||||
return epmfs::search(branches_,fusepath,paths);
|
||||
return epmfs::search(branches_,fusepath_,paths_);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,15 +29,15 @@ Policy::Func::eprand(const Category::Enum::Type type_,
|
|||
const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<const string*> &paths_)
|
||||
vector<string> *paths_)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = Policy::Func::epall(type_,branches_,fusepath_,minfreespace_,paths_);
|
||||
if(rv == 0)
|
||||
{
|
||||
std::random_shuffle(paths_.begin(),paths_.end());
|
||||
paths_.resize(1);
|
||||
std::random_shuffle(paths_->begin(),paths_->end());
|
||||
paths_->resize(1);
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@ using std::string;
|
|||
using std::vector;
|
||||
|
||||
int
|
||||
Policy::Func::erofs(const Category::Enum::Type type,
|
||||
Policy::Func::erofs(const Category::Enum::Type type_,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<string> *paths)
|
||||
{
|
||||
return (errno=EROFS,-1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "fs_path.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -32,10 +33,12 @@ namespace ff
|
|||
{
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
create(const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
vector<string> *paths)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
|
|
@ -56,7 +59,7 @@ namespace ff
|
|||
if(info.spaceavail < minfreespace)
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
paths.push_back(&branch->path);
|
||||
paths->push_back(branch->path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -70,7 +73,7 @@ Policy::Func::ff(const Category::Enum::Type type,
|
|||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
vector<string> *paths)
|
||||
{
|
||||
if(type == Category::Enum::create)
|
||||
return ff::create(branches_,minfreespace,paths);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ Policy::Func::invalid(const Category::Enum::Type type,
|
|||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
vector<string> *paths)
|
||||
{
|
||||
return (errno=EINVAL,-1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "fs_path.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
|
@ -33,10 +34,12 @@ namespace lfs
|
|||
{
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
create(const Branches &branches_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
int error;
|
||||
uint64_t lfs;
|
||||
|
|
@ -58,7 +61,7 @@ namespace lfs
|
|||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < minfreespace)
|
||||
if(info.spaceavail < minfreespace_)
|
||||
error_and_continue(error,ENOSPC);
|
||||
if(info.spaceavail > lfs)
|
||||
continue;
|
||||
|
|
@ -70,7 +73,7 @@ namespace lfs
|
|||
if(lfsbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(lfsbasepath);
|
||||
paths_->push_back(*lfsbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -81,7 +84,7 @@ Policy::Func::lfs(const Category::Enum::Type type,
|
|||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
vector<string> *paths)
|
||||
{
|
||||
if(type == Category::Enum::create)
|
||||
return lfs::create(branches_,minfreespace,paths);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "fs_path.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
|
@ -33,10 +34,12 @@ namespace lus
|
|||
{
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
create(const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
vector<string> *paths)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
int error;
|
||||
uint64_t lus;
|
||||
|
|
@ -70,7 +73,7 @@ namespace lus
|
|||
if(lusbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(lusbasepath);
|
||||
paths->push_back(*lusbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -81,7 +84,7 @@ Policy::Func::lus(const Category::Enum::Type type,
|
|||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
vector<string> *paths)
|
||||
{
|
||||
if(type == Category::Enum::create)
|
||||
return lus::create(branches_,minfreespace,paths);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "fs_path.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -32,10 +33,12 @@ namespace mfs
|
|||
{
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
create(const Branches &branches_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
int error;
|
||||
uint64_t mfs;
|
||||
|
|
@ -57,7 +60,7 @@ namespace mfs
|
|||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < minfreespace)
|
||||
if(info.spaceavail < minfreespace_)
|
||||
error_and_continue(error,ENOSPC);
|
||||
if(info.spaceavail < mfs)
|
||||
continue;
|
||||
|
|
@ -69,7 +72,7 @@ namespace mfs
|
|||
if(mfsbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(mfsbasepath);
|
||||
paths_->push_back(*mfsbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -80,7 +83,7 @@ Policy::Func::mfs(const Category::Enum::Type type,
|
|||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
vector<string> *paths)
|
||||
{
|
||||
if(type == Category::Enum::create)
|
||||
return mfs::create(branches_,minfreespace,paths);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "fs_statvfs_cache.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -36,11 +37,13 @@ namespace newest
|
|||
{
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<string> *paths)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
int error;
|
||||
time_t newest;
|
||||
|
|
@ -77,17 +80,19 @@ namespace newest
|
|||
if(newestbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(newestbasepath);
|
||||
paths->push_back(*newestbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<string> *paths)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
int rv;
|
||||
int error;
|
||||
bool readonly;
|
||||
|
|
@ -122,17 +127,19 @@ namespace newest
|
|||
if(newestbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(newestbasepath);
|
||||
paths->push_back(*newestbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
search(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
search(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<string> *paths)
|
||||
{
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
time_t newest;
|
||||
struct stat st;
|
||||
const Branch *branch;
|
||||
|
|
@ -156,7 +163,7 @@ namespace newest
|
|||
if(newestbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
|
||||
paths.push_back(newestbasepath);
|
||||
paths->push_back(*newestbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -167,7 +174,7 @@ Policy::Func::newest(const Category::Enum::Type type,
|
|||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
vector<string> *paths)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -29,15 +29,15 @@ Policy::Func::rand(const Category::Enum::Type type_,
|
|||
const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<const string*> &paths_)
|
||||
vector<string> *paths_)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = Policy::Func::all(type_,branches_,fusepath_,minfreespace_,paths_);
|
||||
if(rv == 0)
|
||||
{
|
||||
std::random_shuffle(paths_.begin(),paths_.end());
|
||||
paths_.resize(1);
|
||||
std::random_shuffle(paths_->begin(),paths_->end());
|
||||
paths_->resize(1);
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
|
|
|||
47
src/str.cpp
47
src/str.cpp
|
|
@ -43,7 +43,25 @@ namespace str
|
|||
const string &str,
|
||||
const char delimiter)
|
||||
{
|
||||
return split(result,str.c_str(),delimiter);
|
||||
return str::split(result,str.c_str(),delimiter);
|
||||
}
|
||||
|
||||
void
|
||||
splitkv(const string &str_,
|
||||
const char delimiter_,
|
||||
string *key_,
|
||||
string *val_)
|
||||
{
|
||||
istringstream iss;
|
||||
std::string key;
|
||||
std::string val;
|
||||
|
||||
iss.str(str_);
|
||||
std::getline(iss,key,delimiter_);
|
||||
std::getline(iss,val,'\0');
|
||||
|
||||
*key_ = key;
|
||||
*val_ = val;
|
||||
}
|
||||
|
||||
string
|
||||
|
|
@ -149,8 +167,16 @@ namespace str
|
|||
}
|
||||
|
||||
bool
|
||||
ends_with(const string &str_,
|
||||
const string &suffix_)
|
||||
startswith(const string &str_,
|
||||
const string &prefix_)
|
||||
{
|
||||
return ((str_.size() >= prefix_.size()) &&
|
||||
(str_.compare(0,prefix_.size(),prefix_) == 0));
|
||||
}
|
||||
|
||||
bool
|
||||
endswith(const string &str_,
|
||||
const string &suffix_)
|
||||
{
|
||||
if(suffix_.size() > str_.size())
|
||||
return false;
|
||||
|
|
@ -159,4 +185,19 @@ namespace str
|
|||
suffix_.rend(),
|
||||
str_.rbegin());
|
||||
}
|
||||
|
||||
std::string
|
||||
trim(const std::string &str_)
|
||||
{
|
||||
std::string rv;
|
||||
|
||||
rv = str_;
|
||||
|
||||
while(!rv.empty() && (rv[0] == ' '))
|
||||
rv.erase(0);
|
||||
while(!rv.empty() && (rv[rv.size()-1] == ' '))
|
||||
rv.erase(rv.size()-1);
|
||||
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
17
src/str.hpp
17
src/str.hpp
|
|
@ -30,6 +30,12 @@ namespace str
|
|||
const std::string &str,
|
||||
const char delimiter);
|
||||
|
||||
void
|
||||
splitkv(const std::string &str,
|
||||
const char delimiter,
|
||||
std::string *key,
|
||||
std::string *value);
|
||||
|
||||
std::string
|
||||
join(const std::vector<std::string> &vec,
|
||||
const size_t substridx,
|
||||
|
|
@ -58,6 +64,13 @@ namespace str
|
|||
const std::string &s1);
|
||||
|
||||
bool
|
||||
ends_with(const std::string &str_,
|
||||
const std::string &suffix_);
|
||||
startswith(const std::string &str_,
|
||||
const std::string &prefix_);
|
||||
|
||||
bool
|
||||
endswith(const std::string &str_,
|
||||
const std::string &suffix_);
|
||||
|
||||
std::string
|
||||
trim(const std::string &str);
|
||||
}
|
||||
|
|
|
|||
58
src/to_string.cpp
Normal file
58
src/to_string.cpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace str
|
||||
{
|
||||
std::string
|
||||
to(const bool bool_)
|
||||
{
|
||||
return (bool_ ? "true" : "false");
|
||||
}
|
||||
|
||||
std::string
|
||||
to(const int int_)
|
||||
{
|
||||
char buf[24];
|
||||
|
||||
sprintf(buf,"%d",int_);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string
|
||||
to(const uint64_t uint64_)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
sprintf(buf,"%llu",(unsigned long long)uint64_);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string
|
||||
to(const std::string &s_)
|
||||
{
|
||||
return s_;
|
||||
}
|
||||
}
|
||||
31
src/to_string.hpp
Normal file
31
src/to_string.hpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, 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 <stdint.h>
|
||||
|
||||
namespace str
|
||||
{
|
||||
std::string to(const bool);
|
||||
std::string to(const int);
|
||||
std::string to(const uint64_t);
|
||||
std::string to(const std::string&);
|
||||
}
|
||||
47
src/tofrom_string.hpp
Normal file
47
src/tofrom_string.hpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, 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>
|
||||
|
||||
class ToFromString
|
||||
{
|
||||
public:
|
||||
virtual std::string to_string() const = 0;
|
||||
virtual int from_string(const std::string &) = 0;
|
||||
};
|
||||
|
||||
namespace std
|
||||
{
|
||||
inline
|
||||
static
|
||||
std::string
|
||||
to_string(const ToFromString *o_)
|
||||
{
|
||||
return o_->to_string();
|
||||
}
|
||||
|
||||
inline
|
||||
static
|
||||
std::string
|
||||
to_string(const ToFromString &o_)
|
||||
{
|
||||
return o_.to_string();
|
||||
}
|
||||
}
|
||||
131
src/tofrom_wrapper.hpp
Normal file
131
src/tofrom_wrapper.hpp
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
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 "from_string.hpp"
|
||||
#include "to_string.hpp"
|
||||
#include "tofrom_string.hpp"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
template<typename T>
|
||||
class ToFromWrapper : public ToFromString
|
||||
{
|
||||
public:
|
||||
int
|
||||
from_string(const std::string &s_)
|
||||
{
|
||||
return str::from(s_,&_data);
|
||||
}
|
||||
|
||||
std::string
|
||||
to_string(void) const
|
||||
{
|
||||
return str::to(_data);
|
||||
}
|
||||
|
||||
public:
|
||||
ToFromWrapper<T>()
|
||||
{
|
||||
}
|
||||
|
||||
ToFromWrapper<T>(const T data_)
|
||||
: _data(data_)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
ToFromWrapper<T>&
|
||||
operator=(const T data_)
|
||||
{
|
||||
_data = data_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
operator T() const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
T*
|
||||
operator->()
|
||||
{
|
||||
return &_data;
|
||||
}
|
||||
|
||||
public:
|
||||
bool
|
||||
operator==(const T data_) const
|
||||
{
|
||||
return (_data == data_);
|
||||
}
|
||||
|
||||
private:
|
||||
T _data;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class ROToFromWrapper : public ToFromString
|
||||
{
|
||||
public:
|
||||
int
|
||||
from_string(const std::string &s_)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
std::string
|
||||
to_string(void) const
|
||||
{
|
||||
return str::to(_data);
|
||||
}
|
||||
|
||||
public:
|
||||
ROToFromWrapper<T>()
|
||||
{
|
||||
}
|
||||
|
||||
ROToFromWrapper<T>(const T data_)
|
||||
: _data(data_)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
operator T() const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
T*
|
||||
operator->()
|
||||
{
|
||||
return &_data;
|
||||
}
|
||||
|
||||
public:
|
||||
bool
|
||||
operator==(const T data_) const
|
||||
{
|
||||
return (_data == data_);
|
||||
}
|
||||
|
||||
private:
|
||||
T _data;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue