From 54c41c49940b6315c78a2ab407908141f2fb2e38 Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Tue, 24 Sep 2019 10:27:46 -0400 Subject: [PATCH] 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 --- Makefile | 10 +- README.md | 38 ++- libfuse/Makefile | 7 +- libfuse/include/fuse.h | 22 +- libfuse/include/fuse_common.h | 10 +- libfuse/include/fuse_lowlevel.h | 13 +- libfuse/lib/fuse.c | 424 +++++++++++++------------- libfuse/lib/fuse_lowlevel.c | 69 ++--- man/mergerfs.1 | 69 ++++- src/branch.cpp | 239 ++++++++++----- src/branch.hpp | 39 ++- src/config.cpp | 444 +++++++++++++++++++-------- src/config.hpp | 220 ++++++------- src/dirinfo.hpp | 9 +- src/ef.hpp | 21 ++ src/enum.hpp | 78 +++++ src/fh.hpp | 31 ++ src/fileinfo.hpp | 9 +- src/from_string.cpp | 115 +++++++ src/from_string.hpp | 32 ++ src/func.cpp | 39 +++ src/func.hpp | 221 ++++++++++++++ src/func_category.cpp | 90 ++++++ src/func_category.hpp | 69 +++++ src/funcs.hpp | 46 +++ src/fuse_access.cpp | 20 +- src/fuse_chmod.cpp | 22 +- src/fuse_chown.cpp | 24 +- src/fuse_create.cpp | 34 +-- src/fuse_fgetattr.cpp | 20 +- src/fuse_fgetattr.hpp | 7 +- src/fuse_getattr.cpp | 39 ++- src/fuse_getattr.hpp | 5 +- src/fuse_getxattr.cpp | 364 ++-------------------- src/fuse_init.cpp | 18 +- src/fuse_ioctl.cpp | 239 ++++++++++++++- src/fuse_ioctl.hpp | 2 +- src/fuse_link.cpp | 76 +++-- src/fuse_listxattr.cpp | 70 +---- src/fuse_mkdir.cpp | 48 ++- src/fuse_mknod.cpp | 40 ++- src/fuse_open.cpp | 20 +- src/fuse_opendir.cpp | 2 +- src/fuse_readdir_linux.icpp | 4 +- src/fuse_readdir_plus_linux.icpp | 12 +- src/fuse_readdir_plus_posix.icpp | 4 +- src/fuse_readdir_posix.icpp | 4 +- src/fuse_readlink.cpp | 16 +- src/fuse_release.cpp | 4 +- src/fuse_removexattr.cpp | 26 +- src/fuse_rename.cpp | 112 +++---- src/fuse_rmdir.cpp | 20 +- src/fuse_setxattr.cpp | 454 ++------------------------- src/fuse_statfs.cpp | 30 +- src/fuse_symlink.cpp | 36 ++- src/fuse_truncate.cpp | 22 +- src/fuse_unlink.cpp | 20 +- src/fuse_utimens.cpp | 23 +- src/fuse_write.cpp | 5 +- src/fuse_write_buf.cpp | 45 +-- src/fusefunc.cpp | 95 ------ src/fusefunc.hpp | 125 -------- src/hw_cpu.cpp | 35 +++ src/hw_cpu.hpp | 27 ++ src/mergerfs.cpp | 18 +- src/option_parser.cpp | 508 +++++++++++-------------------- src/option_parser.hpp | 8 +- src/policy.hpp | 64 ++-- src/policy_all.cpp | 29 +- src/policy_cache.cpp | 2 - src/policy_epall.cpp | 41 +-- src/policy_epff.cpp | 57 ++-- src/policy_eplfs.cpp | 31 +- src/policy_eplus.cpp | 35 ++- src/policy_epmfs.cpp | 57 ++-- src/policy_eprand.cpp | 6 +- src/policy_erofs.cpp | 8 +- src/policy_ff.cpp | 13 +- src/policy_invalid.cpp | 2 +- src/policy_lfs.cpp | 15 +- src/policy_lus.cpp | 13 +- src/policy_mfs.cpp | 15 +- src/policy_newest.cpp | 35 ++- src/policy_rand.cpp | 6 +- src/str.cpp | 47 ++- src/str.hpp | 17 +- src/to_string.cpp | 58 ++++ src/to_string.hpp | 31 ++ src/tofrom_string.hpp | 47 +++ src/tofrom_wrapper.hpp | 131 ++++++++ 90 files changed, 3250 insertions(+), 2577 deletions(-) create mode 100644 src/ef.hpp create mode 100644 src/enum.hpp create mode 100644 src/fh.hpp create mode 100644 src/from_string.cpp create mode 100644 src/from_string.hpp create mode 100644 src/func.cpp create mode 100644 src/func.hpp create mode 100644 src/func_category.cpp create mode 100644 src/func_category.hpp create mode 100644 src/funcs.hpp delete mode 100644 src/fusefunc.cpp delete mode 100644 src/fusefunc.hpp create mode 100644 src/hw_cpu.cpp create mode 100644 src/hw_cpu.hpp create mode 100644 src/to_string.cpp create mode 100644 src/to_string.hpp create mode 100644 src/tofrom_string.hpp create mode 100644 src/tofrom_wrapper.hpp diff --git a/Makefile b/Makefile index ad577f1a..6c380664 100644 --- a/Makefile +++ b/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) diff --git a/README.md b/README.md index 20703169..9f176af2 100644 --- a/README.md +++ b/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 ``` /.mergerfs diff --git a/libfuse/Makefile b/libfuse/Makefile index 5157ef17..7ae3db80 100644 --- a/libfuse/Makefile +++ b/libfuse/Makefile @@ -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 diff --git a/libfuse/include/fuse.h b/libfuse/include/fuse.h index 4931a168..430bd9eb 100644 --- a/libfuse/include/fuse.h +++ b/libfuse/include/fuse.h @@ -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, diff --git a/libfuse/include/fuse_common.h b/libfuse/include/fuse_common.h index 0e62aaaf..e78b57c1 100644 --- a/libfuse/include/fuse_common.h +++ b/libfuse/include/fuse_common.h @@ -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; diff --git a/libfuse/include/fuse_lowlevel.h b/libfuse/include/fuse_lowlevel.h index 7891e233..ff4b1c1d 100644 --- a/libfuse/include/fuse_lowlevel.h +++ b/libfuse/include/fuse_lowlevel.h @@ -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 diff --git a/libfuse/lib/fuse.c b/libfuse/lib/fuse.c index 7504b44f..6f8735b6 100644 --- a/libfuse/lib/fuse.c +++ b/libfuse/lib/fuse.c @@ -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; - - 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; - } - } + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; + struct node *dot = 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); + 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; + } + } + + 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; -} diff --git a/libfuse/lib/fuse_lowlevel.c b/libfuse/lib/fuse_lowlevel.c index b36dd9f6..d3345e02 100644 --- a/libfuse/lib/fuse_lowlevel.c +++ b/libfuse/lib/fuse_lowlevel.c @@ -319,37 +319,18 @@ void fuse_reply_none(fuse_req_t req) fuse_free_req(req); } -static unsigned long calc_timeout_sec(double t) -{ - 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) +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); } diff --git a/man/mergerfs.1 b/man/mergerfs.1 index 2429d2ad..5cff291a 100644 --- a/man/mergerfs.1 +++ b/man/mergerfs.1 @@ -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] diff --git a/src/branch.cpp b/src/branch.cpp index 149d7925..11b2afd4 100644 --- a/src/branch.cpp +++ b/src/branch.cpp @@ -17,14 +17,16 @@ */ #include "branch.hpp" +#include "ef.hpp" #include "fs.hpp" #include "fs_glob.hpp" #include "str.hpp" -#include - #include +#include +#include + 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; - - 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); + uint64_t offset; - 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 &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 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 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 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 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 &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; +} diff --git a/src/branch.hpp b/src/branch.hpp index 3bdd97ae..34eea2cc 100644 --- a/src/branch.hpp +++ b/src/branch.hpp @@ -18,11 +18,17 @@ #pragma once +#include "rwlock.hpp" +#include "tofrom_string.hpp" + #include #include -struct Branch +#include + +class Branch { +public: enum Mode { INVALID, @@ -39,18 +45,31 @@ struct Branch bool ro_or_nc(void) const; }; -class Branches : public std::vector +class Branches : public std::vector, public ToFromString { public: - std::string to_string(const bool mode_ = false) const; + Branches(); - void to_paths(std::vector &vec_) const; +public: + int from_string(const std::string &str); + std::string to_string(void) const; public: - void set(const std::string &str_); - void add_begin(const std::string &str_); - void add_end(const std::string &str_); - void erase_begin(void); - void erase_end(void); - void erase_fnmatch(const std::string &str_); + void to_paths(std::vector &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; }; diff --git a/src/config.cpp b/src/config.cpp index b64cde4f..772669c2 100644 --- a/src/config.cpp +++ b/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 #include -#include +#include -#include +#include #include +#include #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); - - set_category_policy("action","epall"); - set_category_policy("create","epmfs"); - set_category_policy("search","ff"); + : + open_cache(), + + 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; + return *((Config*)fuse_get_context()->private_data); +} + +Config& +Config::rw(void) +{ + return *((Config*)fuse_get_context()->private_data); +} - fusefunc = FuseFunc::find(fusefunc_); - if(fusefunc == FuseFunc::invalid) - return (errno=ENODATA,-1); +bool +Config::has_key(const std::string &key_) const +{ + return _map.count(key_); +} - policy = Policy::find(policy_); - if(policy == Policy::invalid) - return (errno=EINVAL,-1); +void +Config::keys(std::string &s_) const +{ + Str2TFStrMap::const_iterator i; + Str2TFStrMap::const_iterator ei; - policies[(FuseFunc::Enum::Type)*fusefunc] = policy; + s_.reserve(512); - return 0; + i = _map.begin(); + ei = _map.end(); + + for(; i != ei; ++i) + { + s_ += i->first; + s_ += '\0'; + } + + s_.resize(s_.size() - 1); +} + + +void +Config::keys_xattr(std::string &s_) const +{ + 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::set_category_policy(const string &category_, - const string &policy_) +Config::get(const std::string &key_, + std::string *val_) const { - const Policy *policy; - const Category *category; + Str2TFStrMap::const_iterator i; - category = Category::find(category_); - if(category == Category::invalid) - return (errno=ENODATA,-1); + i = _map.find(key_); + if(i == _map.end()) + return -ENOATTR; - policy = Policy::find(policy_); - if(policy == Policy::invalid) - return (errno=EINVAL,-1); + *val_ = i->second->to_string(); - for(int i = 0; i < FuseFunc::Enum::END; i++) + return 0; +} + +template<> +std::string +Config::StatFS::to_string() const +{ + switch(_data) { - if(FuseFunc::fusefuncs[i] == (Category::Enum::Type)*category) - policies[(FuseFunc::Enum::Type)FuseFunc::fusefuncs[i]] = policy; + 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 + return -EINVAL; + return 0; } -Config::CacheFiles::operator int() const +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_) { - return _data; + 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; } -Config::CacheFiles::operator std::string() const +template<> +std::string +Config::CacheFiles::to_string() const { switch(_data) { - case OFF: + case Config::CacheFiles::ENUM::LIBFUSE: + return "libfuse"; + case Config::CacheFiles::ENUM::OFF: return "off"; - case PARTIAL: + case Config::CacheFiles::ENUM::PARTIAL: return "partial"; - case FULL: + case Config::CacheFiles::ENUM::FULL: return "full"; - case AUTO_FULL: + case Config::CacheFiles::ENUM::AUTO_FULL: return "auto-full"; - case LIBFUSE: - return "libfuse"; - case INVALID: - break; } - return ""; + return "invalid"; } -Config::CacheFiles::CacheFiles() - : _data(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; } -Config::CacheFiles::CacheFiles(Config::CacheFiles::Enum data_) - : _data(data_) +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"; } -bool -Config::CacheFiles::valid() const +template<> +int +Config::XAttr::from_string(const std::string &s_) { - return (_data != INVALID); + 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; } -Config::CacheFiles& -Config::CacheFiles::operator=(const Config::CacheFiles::Enum data_) +int +Config::set_raw(const std::string &key_, + const std::string &value_) { - _data = data_; + Str2TFStrMap::iterator i; - return *this; + i = _map.find(key_); + if(i == _map.end()) + return -ENOATTR; + + return i->second->from_string(value_); } -Config::CacheFiles& -Config::CacheFiles::operator=(const std::string &data_) +int +Config::set(const std::string &key_, + const std::string &value_) { - 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; - else - _data = INVALID; + 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 *this; + return os_; } diff --git a/src/config.hpp b/src/config.hpp index a40fafe8..3d3d9ea7 100644 --- a/src/config.hpp +++ b/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 @@ -29,145 +33,113 @@ #include #include +typedef ToFromWrapper ConfigBOOL; +typedef ToFromWrapper ConfigUINT64; +typedef ToFromWrapper ConfigINT; +typedef ToFromWrapper ConfigSTR; +typedef std::map Str2TFStrMap; + class Config { public: - struct StatFS - { - enum Enum - { - BASE, - FULL - }; - }; - - struct StatFSIgnore - { - enum Enum - { - NONE, - RO, - NC - }; - }; - - class CacheFiles - { - public: - enum Enum - { - INVALID = -1, - LIBFUSE, - OFF, - PARTIAL, - FULL, - AUTO_FULL - }; - - 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 StatFSEnum + { + BASE, + FULL + }; + typedef Enum StatFS; + + enum class StatFSIgnoreEnum + { + NONE, + RO, + NC + }; + typedef Enum StatFSIgnore; + + enum class CacheFilesEnum + { + LIBFUSE, + OFF, + PARTIAL, + FULL, + AUTO_FULL + }; + typedef Enum CacheFiles; + + enum class XAttrEnum + { + PASSTHROUGH = 0, + NOSYS = ENOSYS, + NOATTR = ENOATTR + }; + typedef Enum 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_); + mutable PolicyCache open_cache; 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; + const std::string controlfile; 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; + 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; public: - mutable PolicyCache open_cache; + friend std::ostream& operator<<(std::ostream &s, + const Config &c); public: - const std::string controlfile; + bool has_key(const std::string &key) const; + void keys(std::string &s) const; + void keys_xattr(std::string &s) const; + +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 & - get(void) - { - const fuse_context *fc = fuse_get_context(); - - return get(fc); - } - - static - const Config & - get(const fuse_context *fc) - { - return *((Config*)fc->private_data); - } - - static - Config & - get_writable(void) - { - return (*((Config*)fuse_get_context()->private_data)); - } + static const Config &ro(void); + static Config &rw(void); + +private: + Str2TFStrMap _map; }; diff --git a/src/dirinfo.hpp b/src/dirinfo.hpp index 753b9393..37ee6d3b 100644 --- a/src/dirinfo.hpp +++ b/src/dirinfo.hpp @@ -16,16 +16,15 @@ #pragma once +#include "fh.hpp" + #include -class DirInfo +class DirInfo : public FH { public: DirInfo(const char *fusepath_) - : fusepath(fusepath_) + : FH(fusepath_) { } - -public: - std::string fusepath; }; diff --git a/src/ef.hpp b/src/ef.hpp new file mode 100644 index 00000000..94374b4c --- /dev/null +++ b/src/ef.hpp @@ -0,0 +1,21 @@ +/* + ISC License + + Copyright (c) 2019, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#define ef(X) else if(X) diff --git a/src/enum.hpp b/src/enum.hpp new file mode 100644 index 00000000..14243c4a --- /dev/null +++ b/src/enum.hpp @@ -0,0 +1,78 @@ +/* + ISC License + + Copyright (c) 2019, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "tofrom_string.hpp" + +#include + +template +class Enum : public ToFromString +{ +public: + typedef E ENUM; + +public: + Enum() + { + } + + Enum(const ENUM data_) + : _data(data_) + { + } + +public: + Enum& + operator=(const ENUM data_) + { + _data = data_; + return *this; + } + + 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; +}; diff --git a/src/fh.hpp b/src/fh.hpp new file mode 100644 index 00000000..2060e2a5 --- /dev/null +++ b/src/fh.hpp @@ -0,0 +1,31 @@ +/* + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include + +class FH +{ +public: + FH(const char *fusepath_) + : fusepath(fusepath_) + { + } + +public: + std::string fusepath; +}; diff --git a/src/fileinfo.hpp b/src/fileinfo.hpp index 4f4ed29d..a3ca65b1 100644 --- a/src/fileinfo.hpp +++ b/src/fileinfo.hpp @@ -16,19 +16,20 @@ #pragma once +#include "fh.hpp" + #include -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; }; diff --git a/src/from_string.cpp b/src/from_string.cpp new file mode 100644 index 00000000..73425cce --- /dev/null +++ b/src/from_string.cpp @@ -0,0 +1,115 @@ +/* + ISC License + + Copyright (c) 2019, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "ef.hpp" + +#include + +#include +#include +#include + +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; + } +} diff --git a/src/from_string.hpp b/src/from_string.hpp new file mode 100644 index 00000000..3c06884c --- /dev/null +++ b/src/from_string.hpp @@ -0,0 +1,32 @@ +/* + ISC License + + Copyright (c) 2019, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include + +#include + +namespace 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 *); +} diff --git a/src/func.cpp b/src/func.cpp new file mode 100644 index 00000000..b82773ab --- /dev/null +++ b/src/func.cpp @@ -0,0 +1,39 @@ +/* + ISC License + + Copyright (c) 2019, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "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(); +} diff --git a/src/func.hpp b/src/func.hpp new file mode 100644 index 00000000..f1a390f3 --- /dev/null +++ b/src/func.hpp @@ -0,0 +1,221 @@ +/* + ISC License + + Copyright (c) 2019, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" +#include "tofrom_string.hpp" + +#include +#include + +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) + { + } +}; diff --git a/src/func_category.cpp b/src/func_category.cpp new file mode 100644 index 00000000..eb60c9d3 --- /dev/null +++ b/src/func_category.cpp @@ -0,0 +1,90 @@ +/* + ISC License + + Copyright (c) 2019, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "func_category.hpp" +#include "str.hpp" + +#include "buildvector.hpp" + +#include +#include +#include + +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 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 + (&funcs_.create) + (&funcs_.mkdir) + (&funcs_.mknod) + (&funcs_.symlink); +} + +FuncCategoryAction::FuncCategoryAction(Funcs &funcs_) +{ + _funcs = buildvector + (&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 + (&funcs_.access) + (&funcs_.getattr) + (&funcs_.getxattr) + (&funcs_.listxattr) + (&funcs_.open) + (&funcs_.readlink); +} diff --git a/src/func_category.hpp b/src/func_category.hpp new file mode 100644 index 00000000..775239f5 --- /dev/null +++ b/src/func_category.hpp @@ -0,0 +1,69 @@ +/* + ISC License + + Copyright (c) 2019, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "funcs.hpp" +#include "tofrom_string.hpp" + +#include +#include + +class FuncCategory : public ToFromString +{ +public: + int from_string(const std::string &); + std::string to_string(void) const; + +protected: + std::vector _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; +}; diff --git a/src/funcs.hpp b/src/funcs.hpp new file mode 100644 index 00000000..a482b36e --- /dev/null +++ b/src/funcs.hpp @@ -0,0 +1,46 @@ +/* + ISC License + + Copyright (c) 2019, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "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; +}; diff --git a/src/fuse_access.cpp b/src/fuse_access.cpp index f5b93bbb..74f746c9 100644 --- a/src/fuse_access.cpp +++ b/src/fuse_access.cpp @@ -14,16 +14,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include - #include "config.hpp" #include "errno.hpp" #include "fs_base_access.hpp" #include "fs_path.hpp" -#include "rwlock.hpp" #include "ugid.hpp" +#include +#include + using std::string; using std::vector; @@ -39,9 +38,9 @@ namespace l { int rv; string fullpath; - vector basepaths; + vector 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, diff --git a/src/fuse_chmod.cpp b/src/fuse_chmod.cpp index 486b2dfa..cf1e8113 100644 --- a/src/fuse_chmod.cpp +++ b/src/fuse_chmod.cpp @@ -19,7 +19,6 @@ #include "fs_base_chmod.hpp" #include "fs_path.hpp" #include "rv.hpp" -#include "rwlock.hpp" #include "ugid.hpp" #include @@ -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 &basepaths_, - const char *fusepath_, - const mode_t mode_) + chmod_loop(const vector &basepaths_, + const char *fusepath_, + const mode_t mode_) { int error; @@ -75,9 +74,9 @@ namespace l const mode_t mode_) { int rv; - vector basepaths; + vector 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_, diff --git a/src/fuse_chown.cpp b/src/fuse_chown.cpp index 0cc0a381..59421792 100644 --- a/src/fuse_chown.cpp +++ b/src/fuse_chown.cpp @@ -19,7 +19,6 @@ #include "fs_base_chown.hpp" #include "fs_path.hpp" #include "rv.hpp" -#include "rwlock.hpp" #include "ugid.hpp" #include @@ -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 &basepaths_, - const char *fusepath_, - const uid_t uid_, - const gid_t gid_) + chown_loop(const vector &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 basepaths; + vector 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_, diff --git a/src/fuse_create.cpp b/src/fuse_create.cpp index 8bef3316..4cc5f6b6 100644 --- a/src/fuse_create.cpp +++ b/src/fuse_create.cpp @@ -21,7 +21,6 @@ #include "fs_base_open.hpp" #include "fs_clonepath.hpp" #include "fs_path.hpp" -#include "rwlock.hpp" #include "ugid.hpp" #include @@ -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 createpaths; - vector existingpaths; + vector createpaths; + vector 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_, diff --git a/src/fuse_fgetattr.cpp b/src/fuse_fgetattr.cpp index e4c5c176..22d4b39a 100644 --- a/src/fuse_fgetattr.cpp +++ b/src/fuse_fgetattr.cpp @@ -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(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; } } - diff --git a/src/fuse_fgetattr.hpp b/src/fuse_fgetattr.hpp index 0a9ae76f..a6c29518 100644 --- a/src/fuse_fgetattr.hpp +++ b/src/fuse_fgetattr.hpp @@ -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); } diff --git a/src/fuse_getattr.cpp b/src/fuse_getattr.cpp index 9db004e2..fb08bd71 100644 --- a/src/fuse_getattr.cpp +++ b/src/fuse_getattr.cpp @@ -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 basepaths; + vector 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); + + 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 l::getattr(config.getattr, - config.branches, - config.minfreespace, - fusepath_, - st_, - config.symlinkify, - config.symlinkify_timeout); + return rv; } } diff --git a/src/fuse_getattr.hpp b/src/fuse_getattr.hpp index 17430f1d..a41eccd1 100644 --- a/src/fuse_getattr.hpp +++ b/src/fuse_getattr.hpp @@ -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); } diff --git a/src/fuse_getxattr.cpp b/src/fuse_getxattr.cpp index 89a1485e..4ff08e1b 100644 --- a/src/fuse_getxattr.cpp +++ b/src/fuse_getxattr.cpp @@ -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 #include -#include #include #include #include @@ -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 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 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; - - 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; + key = &attrname[14]; + rv = config.get(key,&val); + if(rv < 0) + return rv; - 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 basepaths; + vector 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, diff --git a/src/fuse_init.cpp b/src/fuse_init.cpp index da875a97..adda4c32 100644 --- a/src/fuse_init.cpp +++ b/src/fuse_init.cpp @@ -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; } } diff --git a/src/fuse_ioctl.cpp b/src/fuse_ioctl.cpp index ef608a62..dd5899a0 100644 --- a/src/fuse_ioctl.cpp +++ b/src/fuse_ioctl.cpp @@ -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 @@ -32,10 +32,23 @@ #include #include +#include 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(ffi_->fh); - const fuse_context *fc = fuse_get_context(); + FileInfo *fi = reinterpret_cast(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 basepaths; + vector 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(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(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 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(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(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 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(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 paths; + vector branches; + string &fusepath = reinterpret_cast(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_); diff --git a/src/fuse_ioctl.hpp b/src/fuse_ioctl.hpp index 224ebfc3..8b3fdd97 100644 --- a/src/fuse_ioctl.hpp +++ b/src/fuse_ioctl.hpp @@ -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_, diff --git a/src/fuse_link.cpp b/src/fuse_link.cpp index 9117975f..fb44c539 100644 --- a/src/fuse_link.cpp +++ b/src/fuse_link.cpp @@ -20,7 +20,6 @@ #include "fs_clonepath.hpp" #include "fs_path.hpp" #include "rv.hpp" -#include "rwlock.hpp" #include "ugid.hpp" #include @@ -55,11 +54,11 @@ namespace l static int - link_create_path_loop(const vector &oldbasepaths_, - const string &newbasepath_, - const char *oldfusepath_, - const char *newfusepath_, - const string &newfusedirpath_) + link_create_path_loop(const vector &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 oldbasepaths; - vector newbasepaths; + vector oldbasepaths; + vector 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 newbasepath; + vector 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 &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 &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 oldbasepaths; + vector 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); - - if(config.create->path_preserving() && !config.ignorepponrename) - return l::link_preserve_path(config.getattr, - config.link, - config.create, + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::ro(); + const ugid::Set ugid(fc->uid,fc->gid); + + 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_, diff --git a/src/fuse_listxattr.cpp b/src/fuse_listxattr.cpp index 98728716..3ac24378 100644 --- a/src/fuse_listxattr.cpp +++ b/src/fuse_listxattr.cpp @@ -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 strs = - buildvector - ("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 basepaths; + vector 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_, diff --git a/src/fuse_mkdir.cpp b/src/fuse_mkdir.cpp index 2a7c8dd9..695a8213 100644 --- a/src/fuse_mkdir.cpp +++ b/src/fuse_mkdir.cpp @@ -14,11 +14,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - -#include -#include - #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 + +#include +#include + using std::string; using std::vector; @@ -66,12 +65,12 @@ namespace l static int - mkdir_loop(const string &existingpath_, - const vector &createpaths_, - const char *fusepath_, - const string &fusedirpath_, - const mode_t mode_, - const mode_t umask_) + mkdir_loop(const string &existingpath_, + const vector &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 createpaths; - vector existingpaths; + vector createpaths; + vector 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_, diff --git a/src/fuse_mknod.cpp b/src/fuse_mknod.cpp index 14a30a45..236dae05 100644 --- a/src/fuse_mknod.cpp +++ b/src/fuse_mknod.cpp @@ -21,7 +21,6 @@ #include "fs_clonepath.hpp" #include "fs_path.hpp" #include "rv.hpp" -#include "rwlock.hpp" #include "ugid.hpp" #include @@ -69,13 +68,13 @@ namespace l static int - mknod_loop(const string &existingpath_, - const vector &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 &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 createpaths; - vector existingpaths; + vector createpaths; + vector 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_, diff --git a/src/fuse_open.cpp b/src/fuse_open.cpp index a4142fd2..2078e233 100644 --- a/src/fuse_open.cpp +++ b/src/fuse_open.cpp @@ -21,7 +21,6 @@ #include "fs_cow.hpp" #include "fs_path.hpp" #include "policy_cache.hpp" -#include "rwlock.hpp" #include "ugid.hpp" #include @@ -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, diff --git a/src/fuse_opendir.cpp b/src/fuse_opendir.cpp index 30c54b2b..3f782895 100644 --- a/src/fuse_opendir.cpp +++ b/src/fuse_opendir.cpp @@ -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(new DirInfo(fusepath_)); diff --git a/src/fuse_readdir_linux.icpp b/src/fuse_readdir_linux.icpp index dd950b45..02689e41 100644 --- a/src/fuse_readdir_linux.icpp +++ b/src/fuse_readdir_linux.icpp @@ -140,9 +140,9 @@ namespace FUSE { DirInfo *di = reinterpret_cast(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(), diff --git a/src/fuse_readdir_plus_linux.icpp b/src/fuse_readdir_plus_linux.icpp index 14f50e6d..1c5c3c88 100644 --- a/src/fuse_readdir_plus_linux.icpp +++ b/src/fuse_readdir_plus_linux.icpp @@ -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(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_); } } diff --git a/src/fuse_readdir_plus_posix.icpp b/src/fuse_readdir_plus_posix.icpp index 57e72f09..aadb2558 100644 --- a/src/fuse_readdir_plus_posix.icpp +++ b/src/fuse_readdir_plus_posix.icpp @@ -137,9 +137,9 @@ namespace FUSE { DirInfo *di = reinterpret_cast(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(), diff --git a/src/fuse_readdir_posix.icpp b/src/fuse_readdir_posix.icpp index 06dae26e..eded8a80 100644 --- a/src/fuse_readdir_posix.icpp +++ b/src/fuse_readdir_posix.icpp @@ -123,9 +123,9 @@ namespace FUSE { DirInfo *di = reinterpret_cast(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(), diff --git a/src/fuse_readlink.cpp b/src/fuse_readlink.cpp index 47c6be6c..aeeba3f4 100644 --- a/src/fuse_readlink.cpp +++ b/src/fuse_readlink.cpp @@ -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 basepaths; + vector 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_, diff --git a/src/fuse_release.cpp b/src/fuse_release.cpp index 336c61d9..21bcd9af 100644 --- a/src/fuse_release.cpp +++ b/src/fuse_release.cpp @@ -53,8 +53,8 @@ namespace FUSE release(const char *fusepath_, fuse_file_info *ffi_) { - const Config &config = Config::get(); - FileInfo *fi = reinterpret_cast(ffi_->fh); + const Config &config = Config::ro(); + FileInfo *fi = reinterpret_cast(ffi_->fh); if(config.open_cache.timeout) config.open_cache.cleanup(10); diff --git a/src/fuse_removexattr.cpp b/src/fuse_removexattr.cpp index d080f0a9..b7a72eee 100644 --- a/src/fuse_removexattr.cpp +++ b/src/fuse_removexattr.cpp @@ -19,7 +19,6 @@ #include "fs_base_removexattr.hpp" #include "fs_path.hpp" #include "rv.hpp" -#include "rwlock.hpp" #include "ugid.hpp" #include @@ -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 &basepaths_, - const char *fusepath_, - const char *attrname_) + removexattr_loop(const vector &basepaths_, + const char *fusepath_, + const char *attrname_) { int error; @@ -76,9 +75,9 @@ namespace l const char *attrname_) { int rv; - vector basepaths; + vector 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_, diff --git a/src/fuse_rename.cpp b/src/fuse_rename.cpp index 02b174f4..bf52e038 100644 --- a/src/fuse_rename.cpp +++ b/src/fuse_rename.cpp @@ -14,11 +14,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include -#include -#include - #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 +#include +#include +#include + using std::string; using std::vector; using std::set; static bool -member(const vector &haystack, - const string &needle) +member(const vector &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 &toremove) static void -_rename_create_path_core(const vector &oldbasepaths, - const string &oldbasepath, - const string &newbasepath, - const char *oldfusepath, - const char *newfusepath, - const string &newfusedirpath, - int &error, - vector &tounlink) +_rename_create_path_core(const vector &oldbasepaths, + const string &oldbasepath, + const string &newbasepath, + const char *oldfusepath, + const char *newfusepath, + const string &newfusedirpath, + int &error, + vector &tounlink) { int rv; bool ismember; @@ -108,26 +107,29 @@ _rename_create_path(Policy::Func::Search searchFunc, int error; string newfusedirpath; vector toremove; - vector newbasepath; - vector oldbasepaths; + vector newbasepath; + vector oldbasepaths; + vector 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 srcbasepath; + vector 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 newbasepath; + vector 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 &oldbasepaths, - const string &oldbasepath, - const char *oldfusepath, - const char *newfusepath, - int &error, - vector &toremove) +_rename_preserve_path_core(Policy::Func::Search searchFunc, + Policy::Func::Create createFunc, + const Branches &branches_, + const uint64_t minfreespace, + const vector &oldbasepaths, + const string &oldbasepath, + const char *oldfusepath, + const char *newfusepath, + int &error, + vector &toremove) { int rv; bool ismember; @@ -245,16 +247,19 @@ _rename_preserve_path(Policy::Func::Search searchFunc, int rv; int error; vector toremove; - vector oldbasepaths; + vector oldbasepaths; + vector 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, diff --git a/src/fuse_rmdir.cpp b/src/fuse_rmdir.cpp index 22895d4d..5aa36a67 100644 --- a/src/fuse_rmdir.cpp +++ b/src/fuse_rmdir.cpp @@ -19,7 +19,6 @@ #include "fs_base_rmdir.hpp" #include "fs_path.hpp" #include "rv.hpp" -#include "rwlock.hpp" #include "ugid.hpp" #include @@ -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 &basepaths_, - const char *fusepath_) + rmdir_loop(const vector &basepaths_, + const char *fusepath_) { int error; @@ -74,9 +73,9 @@ namespace l const char *fusepath_) { int rv; - vector basepaths; + vector 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_); diff --git a/src/fuse_setxattr.cpp b/src/fuse_setxattr.cpp index 10da80d4..57169943 100644 --- a/src/fuse_setxattr.cpp +++ b/src/fuse_setxattr.cpp @@ -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,430 +47,40 @@ 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) + setxattr_controlfile(Config &config, + const string &attrname, + const string &attrval, + const int flags) { int rv; + string key; - 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; + if(!str::startswith(attrname,"user.mergerfs.")) + return -ENOATTR; - return 0; - } + key = &attrname[14]; - static - int - setxattr_controlfile_category_policy(Config &config, - const string &categoryname, - const string &attrval, - const int flags) - { - int rv; + if(config.has_key(key) == false) + return -ENOATTR; 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); + rv = config.set(key,attrval); + if(rv < 0) + return rv; - 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); + config.open_cache.clear(); + fs::statvfs_cache_timeout(config.cache_statfs); return rv; } static int - setxattr_controlfile(Config &config, - const string &attrname, - const string &attrval, - const int flags) - { - vector attr; - - str::split(attr,attrname,'.'); - - 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; - - 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; - - default: - break; - } - - return -EINVAL; - } - - 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 &basepaths, - const char *fusepath, - const char *attrname, - const char *attrval, - const size_t attrvalsize, - const int flags) + setxattr_loop(const vector &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 basepaths; + vector 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, diff --git a/src/fuse_statfs.cpp b/src/fuse_statfs.cpp index a5757956..76955ee1 100644 --- a/src/fuse_statfs.cpp +++ b/src/fuse_statfs.cpp @@ -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::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_, diff --git a/src/fuse_symlink.cpp b/src/fuse_symlink.cpp index 4a452bf2..50f86305 100644 --- a/src/fuse_symlink.cpp +++ b/src/fuse_symlink.cpp @@ -20,7 +20,6 @@ #include "fs_clonepath.hpp" #include "fs_path.hpp" #include "rv.hpp" -#include "rwlock.hpp" #include "ugid.hpp" #include @@ -54,11 +53,11 @@ namespace l static int - symlink_loop(const string &existingpath_, - const vector newbasepaths_, - const char *oldpath_, - const char *newpath_, - const string &newdirpath_) + symlink_loop(const string &existingpath_, + const vector &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 newbasepaths; - vector existingpaths; + vector newbasepaths; + vector 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_, diff --git a/src/fuse_truncate.cpp b/src/fuse_truncate.cpp index 48039934..a235f1e1 100644 --- a/src/fuse_truncate.cpp +++ b/src/fuse_truncate.cpp @@ -19,7 +19,6 @@ #include "fs_base_truncate.hpp" #include "fs_path.hpp" #include "rv.hpp" -#include "rwlock.hpp" #include "ugid.hpp" #include @@ -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 &basepaths_, - const char *fusepath_, - const off_t size_) + truncate_loop(const vector &basepaths_, + const char *fusepath_, + const off_t size_) { int error; @@ -78,9 +77,9 @@ namespace l const off_t size_) { int rv; - vector basepaths; + vector 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_, diff --git a/src/fuse_unlink.cpp b/src/fuse_unlink.cpp index 0a2d0ea4..681e74e6 100644 --- a/src/fuse_unlink.cpp +++ b/src/fuse_unlink.cpp @@ -19,7 +19,6 @@ #include "fs_base_unlink.hpp" #include "fs_path.hpp" #include "rv.hpp" -#include "rwlock.hpp" #include "ugid.hpp" #include @@ -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 &basepaths_, - const char *fusepath_) + unlink_loop(const vector &basepaths_, + const char *fusepath_) { int error; @@ -74,9 +73,9 @@ namespace l const char *fusepath_) { int rv; - vector basepaths; + vector 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_); diff --git a/src/fuse_utimens.cpp b/src/fuse_utimens.cpp index 77454043..f9dd789f 100644 --- a/src/fuse_utimens.cpp +++ b/src/fuse_utimens.cpp @@ -19,8 +19,8 @@ #include "fs_base_utime.hpp" #include "fs_path.hpp" #include "rv.hpp" -#include "rwlock.hpp" #include "ugid.hpp" + #include #include @@ -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 &basepaths_, - const char *fusepath_, - const timespec ts_[2]) + utimens_loop(const vector &basepaths_, + const char *fusepath_, + const timespec ts_[2]) { int error; @@ -76,9 +76,9 @@ namespace l const timespec ts_[2]) { int rv; - vector basepaths; + vector 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_, diff --git a/src/fuse_write.cpp b/src/fuse_write.cpp index 7ca49dd2..56a26850 100644 --- a/src/fuse_write.cpp +++ b/src/fuse_write.cpp @@ -19,7 +19,6 @@ #include "fileinfo.hpp" #include "fs_base_write.hpp" #include "fs_movefile.hpp" -#include "rwlock.hpp" #include "ugid.hpp" #include @@ -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 paths; const ugid::Set ugid(0,0); - const rwlock::ReadGuard readlock(&config.branches_lock); config.branches.to_paths(paths); diff --git a/src/fuse_write_buf.cpp b/src/fuse_write_buf.cpp index 8b220eae..ed4675d6 100644 --- a/src/fuse_write_buf.cpp +++ b/src/fuse_write_buf.cpp @@ -20,7 +20,6 @@ #include "fs_movefile.hpp" #include "fuse_write.hpp" #include "policy.hpp" -#include "rwlock.hpp" #include "ugid.hpp" #include @@ -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 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 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; } diff --git a/src/fusefunc.cpp b/src/fusefunc.cpp deleted file mode 100644 index 52984dc2..00000000 --- a/src/fusefunc.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - Copyright (c) 2016, Antonio SJ Musumeci - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include -#include - -#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::_fusefuncs_ = - buildvector - (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; -} diff --git a/src/fusefunc.hpp b/src/fusefunc.hpp deleted file mode 100644 index 067ef11c..00000000 --- a/src/fusefunc.hpp +++ /dev/null @@ -1,125 +0,0 @@ -/* - Copyright (c) 2016, Antonio SJ Musumeci - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#pragma once - -#include "category.hpp" - -#include -#include - -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 _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; -}; diff --git a/src/hw_cpu.cpp b/src/hw_cpu.cpp new file mode 100644 index 00000000..c65e713b --- /dev/null +++ b/src/hw_cpu.cpp @@ -0,0 +1,35 @@ +/* + ISC License + + Copyright (c) 2019, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include + +namespace hw +{ + namespace cpu + { + int + logical_core_count(void) + { +#if defined _SC_NPROCESSORS_ONLN + return ::sysconf(_SC_NPROCESSORS_ONLN); +#else + return 1; +#endif + } + } +} diff --git a/src/hw_cpu.hpp b/src/hw_cpu.hpp new file mode 100644 index 00000000..dd17c1de --- /dev/null +++ b/src/hw_cpu.hpp @@ -0,0 +1,27 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +namespace hw +{ + namespace cpu + { + int logical_core_count(void); + } +} diff --git a/src/mergerfs.cpp b/src/mergerfs.cpp index e4903f35..a56a9001 100644 --- a/src/mergerfs.cpp +++ b/src/mergerfs.cpp @@ -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 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); diff --git a/src/option_parser.cpp b/src/option_parser.cpp index a6361124..b48463f0 100644 --- a/src/option_parser.cpp +++ b/src/option_parser.cpp @@ -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 +#include #include #include -#include #include #include @@ -46,6 +48,92 @@ enum MERGERFS_OPT_VERSION }; +struct Data +{ + Config *config; + vector *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 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; - - 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; + std::string key(key_); + std::string val(val_); + + 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; + ef(key == "hard_remove") + return 0; + ef(key == "atomic_o_trunc") + return 0; + ef(key == "big_writes") + return 0; + ef(key == "cache.open") + return 0; - tmp = value_; - if(!tmp.valid()) + if(data_->config->has_key(key) == false) 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; + rv = data_->config->set_raw(key,val); + if(rv) + data_->errs->push_back("invalid argument - " + key_ + '=' + val_); return 0; } static int -parse_and_process_statfs(const std::string &value_, - Config::StatFS::Enum &enum_) +process_opt(Data *data_, + const std::string &arg_) { - if(value_ == "base") - enum_ = Config::StatFS::BASE; - else if(value_ == "full") - enum_ = Config::StatFS::FULL; - else - return 1; - - return 0; -} + std::string key; + std::string val; -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; + str::splitkv(arg_,'=',&key,&val); - return 0; + return parse_and_process_kv_arg(data_,key,val); } static int -parse_and_process_statfs_cache(const std::string &value_) +process_branches(Data *data_, + const char *arg_) { int rv; - uint64_t timeout; + string arg; - rv = num::to_uint64_t(value_,timeout); - if(rv == -1) - return 1; - - fs::statvfs_cache_timeout(timeout); + arg = arg_; + rv = data_->config->set_raw("branches",arg); + if(rv) + data_->errs->push_back("unable to parse 'branches' - " + arg); 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") - return 0; - else if(arg == "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") - return 0; - else if(arg == "big_writes") - return 0; - else if(arg == "readdir_ino") - return 0; - - 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 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) +process_mount(Data *data_, + const char *arg_) { int rv; - std::vector argvalue; + string arg; - 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); - - return 0; -} - -static -int -process_destmounts(const char *arg, - Config &config) -{ - config.destmount = 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" " ':' delimited list of directories. Supports\n" " shell globbing (must be escaped in shell)\n" + " -o config= Read options from file in key=val format\n" " -o func.=

Set function to policy

\n" " -o category.=

Set functions in category to

\n" " -o cache.open= '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 *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_); } } diff --git a/src/option_parser.hpp b/src/option_parser.hpp index 3c7702fb..324eb905 100644 --- a/src/option_parser.hpp +++ b/src/option_parser.hpp @@ -18,11 +18,15 @@ #include "config.hpp" +#include +#include + #include namespace options { void - parse(fuse_args *args, - Config *config); + parse(fuse_args *args, + Config *config, + std::vector *errs); } diff --git a/src/policy.hpp b/src/policy.hpp index 67ef6ec7..763861da 100644 --- a/src/policy.hpp +++ b/src/policy.hpp @@ -58,30 +58,33 @@ public: { typedef std::string string; typedef std::vector strvec; - typedef std::vector 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 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 Create; typedef Base 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 _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(); + } +} diff --git a/src/policy_all.cpp b/src/policy_all.cpp index 58007b0e..edb54e83 100644 --- a/src/policy_all.cpp +++ b/src/policy_all.cpp @@ -20,6 +20,7 @@ #include "fs_path.hpp" #include "policy.hpp" #include "policy_error.hpp" +#include "rwlock.hpp" #include #include @@ -31,10 +32,12 @@ namespace all { static int - create(const Branches &branches_, - const uint64_t minfreespace, - vector &paths) + create(const Branches &branches_, + const uint64_t minfreespace_, + vector *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 &paths) + const char *fusepath_, + const uint64_t minfreespace_, + vector *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_); } diff --git a/src/policy_cache.cpp b/src/policy_cache.cpp index b9d20ab8..9bcd7d85 100644 --- a/src/policy_cache.cpp +++ b/src/policy_cache.cpp @@ -3,13 +3,11 @@ #include #include #include -#include #include using std::map; using std::string; -using std::vector; static const uint64_t DEFAULT_TIMEOUT = 0; diff --git a/src/policy_epall.cpp b/src/policy_epall.cpp index a237caf4..e932b341 100644 --- a/src/policy_epall.cpp +++ b/src/policy_epall.cpp @@ -22,6 +22,7 @@ #include "fs_statvfs_cache.hpp" #include "policy.hpp" #include "policy_error.hpp" +#include "rwlock.hpp" #include #include @@ -33,11 +34,13 @@ namespace epall { static int - create(const Branches &branches_, - const char *fusepath, - const uint64_t minfreespace, - vector &paths) + create(const Branches &branches_, + const char *fusepath, + const uint64_t minfreespace, + vector *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 &paths) + action(const Branches &branches_, + const char *fusepath, + vector *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 &paths) + search(const Branches &branches_, + const char *fusepath, + vector *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 &paths) + vector *paths) { switch(type) { diff --git a/src/policy_epff.cpp b/src/policy_epff.cpp index 39f9cf56..2361e7fd 100644 --- a/src/policy_epff.cpp +++ b/src/policy_epff.cpp @@ -22,6 +22,7 @@ #include "fs_statvfs_cache.hpp" #include "policy.hpp" #include "policy_error.hpp" +#include "rwlock.hpp" #include #include @@ -33,11 +34,13 @@ namespace epff { static int - create(const Branches &branches_, - const char *fusepath, - const uint64_t minfreespace, - vector &paths) + create(const Branches &branches_, + const char *fusepath_, + const uint64_t minfreespace_, + vector *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 &paths) + action(const Branches &branches_, + const char *fusepath_, + vector *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 &paths) + search(const Branches &branches_, + const char *fusepath_, + vector *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 &paths) + const char *fusepath_, + const uint64_t minfreespace_, + vector *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_); } } diff --git a/src/policy_eplfs.cpp b/src/policy_eplfs.cpp index 388c3fff..dc424da5 100644 --- a/src/policy_eplfs.cpp +++ b/src/policy_eplfs.cpp @@ -22,6 +22,7 @@ #include "fs_statvfs_cache.hpp" #include "policy.hpp" #include "policy_error.hpp" +#include "rwlock.hpp" #include #include @@ -34,11 +35,13 @@ namespace eplfs { static int - create(const Branches &branches_, - const char *fusepath, - const uint64_t minfreespace, - vector &paths) + create(const Branches &branches_, + const char *fusepath, + const uint64_t minfreespace, + vector *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 &paths) + action(const Branches &branches_, + const char *fusepath, + vector *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 &paths) + vector *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 &paths) + vector *paths) { switch(type) { diff --git a/src/policy_eplus.cpp b/src/policy_eplus.cpp index c11ab070..7b0379b4 100644 --- a/src/policy_eplus.cpp +++ b/src/policy_eplus.cpp @@ -22,6 +22,7 @@ #include "fs_statvfs_cache.hpp" #include "policy.hpp" #include "policy_error.hpp" +#include "rwlock.hpp" #include #include @@ -34,11 +35,13 @@ namespace eplus { static int - create(const Branches &branches_, - const char *fusepath, - const uint64_t minfreespace, - vector &paths) + create(const Branches &branches_, + const char *fusepath, + const uint64_t minfreespace, + vector *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 &paths) + action(const Branches &branches_, + const char *fusepath, + vector *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 &paths) + search(const Branches &branches_, + const char *fusepath, + vector *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 &paths) + vector *paths) { switch(type) { diff --git a/src/policy_epmfs.cpp b/src/policy_epmfs.cpp index 904447f7..c91b7d7e 100644 --- a/src/policy_epmfs.cpp +++ b/src/policy_epmfs.cpp @@ -22,6 +22,7 @@ #include "fs_statvfs_cache.hpp" #include "policy.hpp" #include "policy_error.hpp" +#include "rwlock.hpp" #include #include @@ -34,11 +35,13 @@ namespace epmfs { static int - create(const Branches &branches_, - const char *fusepath, - const uint64_t minfreespace, - vector &paths) + create(const Branches &branches_, + const char *fusepath_, + const uint64_t minfreespace_, + vector *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 &paths) + action(const Branches &branches_, + const char *fusepath_, + vector *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 &paths) + search(const Branches &branches_, + const char *fusepath_, + vector *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 &paths) + const char *fusepath_, + const uint64_t minfreespace_, + vector *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_); } } diff --git a/src/policy_eprand.cpp b/src/policy_eprand.cpp index 1e71bd59..eaa154e6 100644 --- a/src/policy_eprand.cpp +++ b/src/policy_eprand.cpp @@ -29,15 +29,15 @@ Policy::Func::eprand(const Category::Enum::Type type_, const Branches &branches_, const char *fusepath_, const uint64_t minfreespace_, - vector &paths_) + vector *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; diff --git a/src/policy_erofs.cpp b/src/policy_erofs.cpp index 62235678..8daea427 100644 --- a/src/policy_erofs.cpp +++ b/src/policy_erofs.cpp @@ -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 &paths) + const char *fusepath_, + const uint64_t minfreespace_, + vector *paths) { return (errno=EROFS,-1); } diff --git a/src/policy_ff.cpp b/src/policy_ff.cpp index 282805d4..e55fa28e 100644 --- a/src/policy_ff.cpp +++ b/src/policy_ff.cpp @@ -21,6 +21,7 @@ #include "fs_path.hpp" #include "policy.hpp" #include "policy_error.hpp" +#include "rwlock.hpp" #include #include @@ -32,10 +33,12 @@ namespace ff { static int - create(const Branches &branches_, - const uint64_t minfreespace, - vector &paths) + create(const Branches &branches_, + const uint64_t minfreespace, + vector *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 &paths) + vector *paths) { if(type == Category::Enum::create) return ff::create(branches_,minfreespace,paths); diff --git a/src/policy_invalid.cpp b/src/policy_invalid.cpp index 5a113b49..7d0d97b8 100644 --- a/src/policy_invalid.cpp +++ b/src/policy_invalid.cpp @@ -28,7 +28,7 @@ Policy::Func::invalid(const Category::Enum::Type type, const Branches &branches_, const char *fusepath, const uint64_t minfreespace, - vector &paths) + vector *paths) { return (errno=EINVAL,-1); } diff --git a/src/policy_lfs.cpp b/src/policy_lfs.cpp index 1ae8c873..4fb5d135 100644 --- a/src/policy_lfs.cpp +++ b/src/policy_lfs.cpp @@ -21,6 +21,7 @@ #include "fs_path.hpp" #include "policy.hpp" #include "policy_error.hpp" +#include "rwlock.hpp" #include #include @@ -33,10 +34,12 @@ namespace lfs { static int - create(const Branches &branches_, - const uint64_t minfreespace, - vector &paths) + create(const Branches &branches_, + const uint64_t minfreespace_, + vector *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 &paths) + vector *paths) { if(type == Category::Enum::create) return lfs::create(branches_,minfreespace,paths); diff --git a/src/policy_lus.cpp b/src/policy_lus.cpp index 60df2f36..450ea227 100644 --- a/src/policy_lus.cpp +++ b/src/policy_lus.cpp @@ -21,6 +21,7 @@ #include "fs_path.hpp" #include "policy.hpp" #include "policy_error.hpp" +#include "rwlock.hpp" #include #include @@ -33,10 +34,12 @@ namespace lus { static int - create(const Branches &branches_, - const uint64_t minfreespace, - vector &paths) + create(const Branches &branches_, + const uint64_t minfreespace, + vector *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 &paths) + vector *paths) { if(type == Category::Enum::create) return lus::create(branches_,minfreespace,paths); diff --git a/src/policy_mfs.cpp b/src/policy_mfs.cpp index 37e27b0a..e60c194d 100644 --- a/src/policy_mfs.cpp +++ b/src/policy_mfs.cpp @@ -21,6 +21,7 @@ #include "fs_path.hpp" #include "policy.hpp" #include "policy_error.hpp" +#include "rwlock.hpp" #include #include @@ -32,10 +33,12 @@ namespace mfs { static int - create(const Branches &branches_, - const uint64_t minfreespace, - vector &paths) + create(const Branches &branches_, + const uint64_t minfreespace_, + vector *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 &paths) + vector *paths) { if(type == Category::Enum::create) return mfs::create(branches_,minfreespace,paths); diff --git a/src/policy_newest.cpp b/src/policy_newest.cpp index 3151bd1d..d0416c28 100644 --- a/src/policy_newest.cpp +++ b/src/policy_newest.cpp @@ -22,6 +22,7 @@ #include "fs_statvfs_cache.hpp" #include "policy.hpp" #include "policy_error.hpp" +#include "rwlock.hpp" #include #include @@ -36,11 +37,13 @@ namespace newest { static int - create(const Branches &branches_, - const char *fusepath, - const uint64_t minfreespace, - vector &paths) + create(const Branches &branches_, + const char *fusepath, + const uint64_t minfreespace, + vector *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 &paths) + action(const Branches &branches_, + const char *fusepath, + vector *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 &paths) + search(const Branches &branches_, + const char *fusepath, + vector *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 &paths) + vector *paths) { switch(type) { diff --git a/src/policy_rand.cpp b/src/policy_rand.cpp index 9cd35751..7d38db94 100644 --- a/src/policy_rand.cpp +++ b/src/policy_rand.cpp @@ -29,15 +29,15 @@ Policy::Func::rand(const Category::Enum::Type type_, const Branches &branches_, const char *fusepath_, const uint64_t minfreespace_, - vector &paths_) + vector *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; diff --git a/src/str.cpp b/src/str.cpp index eaa0b1c0..5ff73ee2 100644 --- a/src/str.cpp +++ b/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; + } } diff --git a/src/str.hpp b/src/str.hpp index ff7daba6..2b14af90 100644 --- a/src/str.hpp +++ b/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 &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); } diff --git a/src/to_string.cpp b/src/to_string.cpp new file mode 100644 index 00000000..3019b682 --- /dev/null +++ b/src/to_string.cpp @@ -0,0 +1,58 @@ +/* + ISC License + + Copyright (c) 2019, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include + +#include +#include +#include + +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_; + } +} diff --git a/src/to_string.hpp b/src/to_string.hpp new file mode 100644 index 00000000..5e4f04e7 --- /dev/null +++ b/src/to_string.hpp @@ -0,0 +1,31 @@ +/* + ISC License + + Copyright (c) 2019, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include + +#include + +namespace str +{ + std::string to(const bool); + std::string to(const int); + std::string to(const uint64_t); + std::string to(const std::string&); +} diff --git a/src/tofrom_string.hpp b/src/tofrom_string.hpp new file mode 100644 index 00000000..1cf35cda --- /dev/null +++ b/src/tofrom_string.hpp @@ -0,0 +1,47 @@ +/* + ISC License + + Copyright (c) 2019, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include + +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(); + } +} diff --git a/src/tofrom_wrapper.hpp b/src/tofrom_wrapper.hpp new file mode 100644 index 00000000..f71ee1cf --- /dev/null +++ b/src/tofrom_wrapper.hpp @@ -0,0 +1,131 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "from_string.hpp" +#include "to_string.hpp" +#include "tofrom_string.hpp" + +#include + +template +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() + { + } + + ToFromWrapper(const T data_) + : _data(data_) + { + } + +public: + ToFromWrapper& + 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 +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() + { + } + + ROToFromWrapper(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; +};