diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index ee3f78b5..e44044e8 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -2,6 +2,6 @@ github: [trapexit] patreon: trapexit -open_collective: trapexit +custom: ['https://paypal.me/trapexit','https://buymeacoff.ee/trapexit','https://www.subscribestar.com/trapexit'] ko_fi: trapexit -custom: ['https://paypal.me/trapexit','https://www.subscribestar.com/trapexit'] +open_collective: trapexit diff --git a/LICENSE b/LICENSE index f867f7d7..b4fdad4f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ /* ISC License - Copyright (c) 2020, Antonio SJ Musumeci + Copyright (c) 2021, 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 diff --git a/Makefile b/Makefile index d98021c4..ddbc8a2e 100644 --- a/Makefile +++ b/Makefile @@ -58,13 +58,20 @@ LTO_FLAGS := endif SRC = $(wildcard src/*.cpp) -OBJS = $(SRC:src/%.cpp=build/%.o) -DEPS = $(SRC:src/%.cpp=build/%.d) +OBJS = $(SRC:src/%.cpp=build/.src/%.o) +DEPS = $(SRC:src/%.cpp=build/.src/%.d) + +TESTS = $(wildcard tests/*.cpp) +TESTS_OBJS = $(filter-out build/.src/mergerfs.o,$(OBJS)) +TESTS_OBJS += $(TESTS:tests/%.cpp=build/.tests/%.o) +TESTS_DEPS = $(TESTS:tests/%.cpp=build/.tests/%.d) +TESTS_DEPS += $(DEPS) + MANPAGE = mergerfs.1 CXXFLAGS ?= ${OPT_FLAGS} CXXFLAGS := \ ${CXXFLAGS} \ - -std=c++0x \ + -std=c++11 \ $(STATIC_FLAGS) \ $(LTO_FLAGS) \ -Wall \ @@ -77,6 +84,9 @@ FUSE_FLAGS = \ MFS_FLAGS = \ -DUSE_XATTR=$(USE_XATTR) \ -DUGID_USE_RWLOCK=$(UGID_USE_RWLOCK) +TESTS_FLAGS = \ + -Isrc \ + -DTESTS LDFLAGS := \ ${LDFLAGS} \ @@ -110,11 +120,19 @@ help: objects: version build/stamp $(MAKE) $(OBJS) +tests-objects: + $(MAKE) $(TESTS_OBJS) + build/mergerfs: libfuse objects $(CXX) $(CXXFLAGS) $(FUSE_FLAGS) $(MFS_FLAGS) $(CPPFLAGS) $(OBJS) -o $@ libfuse/build/libfuse.a $(LDFLAGS) +build/tests: build/mergerfs tests-objects + $(CXX) $(CXXFLAGS) $(TESTS_FLAGS) $(FUSE_FLAGS) $(MFS_FLAGS) $(CPPFLAGS) $(TESTS_OBJS) -o $@ libfuse/build/libfuse.a $(LDFLAGS) + mergerfs: build/mergerfs +tests: build/tests + changelog: ifeq ($(GIT_REPO),1) $(GIT2DEBCL) --name mergerfs > ChangeLog @@ -127,12 +145,16 @@ version: tools/update-version build/stamp: - $(MKDIR) -p build + $(MKDIR) -p build/.src build/.tests $(TOUCH) $@ -build/%.o: src/%.cpp +build/.src/%.o: src/%.cpp $(CXX) $(CXXFLAGS) $(FUSE_FLAGS) $(MFS_FLAGS) $(CPPFLAGS) -c $< -o $@ +build/.tests/%.o: tests/%.cpp + $(CXX) $(CXXFLAGS) $(TESTS_FLAGS) $(FUSE_FLAGS) $(MFS_FLAGS) $(CPPFLAGS) -c $< -o $@ + + .PHONY: clean clean: rpm-clean $(RM) -rf build diff --git a/README.md b/README.md index 38873c98..673ecfcf 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ % mergerfs(1) mergerfs user manual % Antonio SJ Musumeci -% 2020-08-30 +% 2021-02-08 # NAME @@ -31,7 +31,7 @@ mergerfs -o<options> <branches> <mountpoint> * Handles pool of read-only and read/write drives * Can turn read-only files into symlinks to underlying file * Hard link copy-on-write / CoW -* supports POSIX ACLs +* Support for POSIX ACLs # HOW IT WORKS @@ -59,7 +59,7 @@ A + B = C +-- file6 ``` -mergerfs does **not** support the copy-on-write (CoW) behavior found in **aufs** and **overlayfs**. You can **not** mount a read-only filesystem and write to it. However, mergerfs will ignore read-only drives when creating new files so you can mix read-write and read-only drives. It also does **not** split data across drives. It is not RAID0 / striping. It is simply a union. +mergerfs does **NOT** support the copy-on-write (CoW) or whiteout behaviors found in **aufs** and **overlayfs**. You can **not** mount a read-only filesystem and write to it. However, mergerfs will ignore read-only drives when creating new files so you can mix read-write and read-only drives. It also does **NOT** split data across drives. It is not RAID0 / striping. It is simply a union of other filesystems. # TERMINOLOGY @@ -67,9 +67,9 @@ mergerfs does **not** support the copy-on-write (CoW) behavior found in **aufs** * branch: A base path used in the pool. * pool: The mergerfs mount. The union of the branches. * relative path: The path in the pool relative to the branch and mount. +* function: A filesystem call (open, unlink, create, getattr, rmdir, etc.) +* category: A collection of functions based on basic behavior (action, create, search). * policy: The algorithm used to select a file when performing a function. -* function: A filesystem call (open, unlink, create, getattr, etc.) -* category: A collection of functions (action, create, search). * path preservation: Aspect of some policies which includes checking the path for which a file would be created. @@ -77,22 +77,25 @@ mergerfs does **not** support the copy-on-write (CoW) behavior found in **aufs** If you don't already know that you have a special use case then just start with one of the following option sets. -#### You don't need `mmap` +#### You need `mmap` (used by rtorrent and many sqlite3 base software) + +`allow_other,use_ino,cache.files=partial,dropcacheonclose=true,category.create=mfs` -`use_ino,cache.files=off,dropcacheonclose=true,allow_other,category.create=mfs` +#### You don't need `mmap` -#### You do need `mmap` (used by rtorrent and some other programs) +`allow_other,use_ino,cache.files=off,dropcacheonclose=true,category.create=mfs` -`use_ino,cache.files=partial,dropcacheonclose=true,allow_other,category.create=mfs` See the mergerfs [wiki for real world deployments](https://github.com/trapexit/mergerfs/wiki/Real-World-Deployments) for comparisons / ideas. # OPTIONS +These options are the same regardless you use them with the `mergerfs` commandline program, used in fstab, or in a config file. + ### mount options -* **config**: Path to a config file. Same arguments as below in key=val format. +* **config**: Path to a config file. Same arguments as below in key=val / ini style 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. Can be overridden by branch specific option. Understands 'K', 'M', and 'G' to represent kilobyte, megabyte, and gigabyte respectively. (default: 4G) @@ -101,7 +104,7 @@ See the mergerfs [wiki for real world deployments](https://github.com/trapexit/m * **inodecalc=passthrough|path-hash|devino-hash|hybrid-hash**: Selects the inode calculation algorithm. (default: hybrid-hash) * **dropcacheonclose=BOOL**: When a file is requested to be closed call `posix_fadvise` on it first to instruct the kernel that we no longer need the data and it can drop its cache. Recommended when **cache.files=partial|full|auto-full** to limit double caching. (default: false) * **symlinkify=BOOL**: When enabled and a file is not writable and its mtime or ctime is older than **symlinkify_timeout** files will be reported as symlinks to the original files. Please read more below before using. (default: false) -* **symlinkify_timeout=INT**: Time to wait, in seconds, to activate the **symlinkify** behavior. (default: 3600) +* **symlinkify_timeout=UINT**: Time to wait, in seconds, to activate the **symlinkify** behavior. (default: 3600) * **nullrw=BOOL**: Turns reads and writes into no-ops. The request will succeed but do nothing. Useful for benchmarking mergerfs. (default: false) * **ignorepponrename=BOOL**: Ignore path preserving on rename. Typically rename and link act differently depending on the policy of `create` (read below). Enabling this will cause rename and link to always use the non-path preserving behavior. This means files, when renamed or linked, will stay on the same drive. (default: false) * **security_capability=BOOL**: If false return ENOATTR when xattr security.capability is queried. (default: true) @@ -112,16 +115,18 @@ See the mergerfs [wiki for real world deployments](https://github.com/trapexit/m * **nfsopenhack=off|git|all**: A workaround for exporting mergerfs over NFS where there are issues with creating files for write while setting the mode to read-only. (default: off) * **posix_acl=BOOL**: Enable POSIX ACL support (if supported by kernel and underlying filesystem). (default: false) * **async_read=BOOL**: Perform reads asynchronously. If disabled or unavailable the kernel will ensure there is at most one pending read request per file handle and will attempt to order requests by offset. (default: true) -* **fuse_msg_size=INT**: Set the max number of pages per FUSE message. Only available on Linux >= 4.20 and ignored otherwise. (min: 1; max: 256; default: 256) +* **fuse_msg_size=UINT**: Set the max number of pages per FUSE message. Only available on Linux >= 4.20 and ignored otherwise. (min: 1; max: 256; default: 256) * **threads=INT**: Number of threads to use in multithreaded mode. When set to zero it will attempt to discover and use the number of logical cores. If the lookup fails it will fall back to using 4. If the thread count is set negative it will look up the number of cores then divide by the absolute value. ie. threads=-2 on an 8 core machine will result in 8 / 2 = 4 threads. There will always be at least 1 thread. NOTE: higher number of threads increases parallelism but usually decreases throughput. (default: 0) * **fsname=STR**: Sets the name of the filesystem as seen in **mount**, **df**, etc. Defaults to a list of the source paths concatenated together with the longest common prefix removed. * **func.FUNC=POLICY**: Sets the specific FUSE function's policy. See below for the list of value types. Example: **func.getattr=newest** -* **category.CATEGORY=POLICY**: Sets policy of all FUSE functions in the provided category. See POLICIES section for defaults. Example: **category.create=mfs** -* **cache.open=INT**: 'open' policy cache timeout in seconds. (default: 0) -* **cache.statfs=INT**: 'statfs' cache timeout in seconds. (default: 0) -* **cache.attr=INT**: File attribute cache timeout in seconds. (default: 1) -* **cache.entry=INT**: File name lookup cache timeout in seconds. (default: 1) -* **cache.negative_entry=INT**: Negative file name lookup cache timeout in seconds. (default: 0) +* **category.action=POLICY**: Sets policy of all FUSE functions in the action category. (default: epall) +* **category.create=POLICY**: Sets policy of all FUSE functions in the create category. (default: epmfs) +* **category.search=POLICY**: Sets policy of all FUSE functions in the search category. (default: ff) +* **cache.open=UINT**: 'open' policy cache timeout in seconds. (default: 0) +* **cache.statfs=UINT**: 'statfs' cache timeout in seconds. (default: 0) +* **cache.attr=UINT**: File attribute cache timeout in seconds. (default: 1) +* **cache.entry=UINT**: File name lookup cache timeout in seconds. (default: 1) +* **cache.negative_entry=UINT**: Negative file name lookup cache timeout in seconds. (default: 0) * **cache.files=libfuse|off|partial|full|auto-full**: File page caching mode (default: libfuse) * **cache.writeback=BOOL**: Enable kernel writeback caching (default: false) * **cache.symlinks=BOOL**: Cache symlinks (if supported by kernel) (default: false) @@ -139,17 +144,18 @@ See the mergerfs [wiki for real world deployments](https://github.com/trapexit/m #### Value Types * BOOL = 'true' | 'false' -* INT = [0,MAX_INT] +* INT = [MIN_INT,MAX_INT] +* UINT = [0,MAX_INT] * SIZE = 'NNM'; NN = INT, M = 'K' | 'M' | 'G' | 'T' * STR = string -* FUNC = FUSE function -* CATEGORY = FUSE function category +* FUNC = filesystem function +* CATEGORY = function category * POLICY = mergerfs function policy ### branches -The 'branches' (formerly 'srcmounts') argument is a colon (':') delimited list of paths to be pooled together. It does not matter if the paths are on the same or different drives nor does it matter the filesystem (within reason). Used and available space will not be duplicated for paths on the same device and any features which aren't supported by the underlying filesystem (such as file attributes or extended attributes) will return the appropriate errors. +The 'branches' argument is a colon (':') delimited list of paths to be pooled together. It does not matter if the paths are on the same or different drives nor does it matter the filesystem (within reason). Used and available space will not be duplicated for paths on the same device and any features which aren't supported by the underlying filesystem (such as file attributes or extended attributes) will return the appropriate errors. Branches currently have two options which can be set. A type which impacts whether or not the branch is included in a policy calculation and a individual minfreespace value. The values are set by prepending an `=` at the end of a branch designation and using commas as delimiters. Example: /mnt/drive=RW,1234 @@ -270,25 +276,47 @@ This hack addresses the issue where the creation of a file with a read-only mode Even though it's a more niche situation this hack breaks normal security and behavior and as such is `off` by default. If set to `git` it will only perform the hack when the path in question includes `/.git/`. `all` will result it it applying anytime a readonly file which is empty is opened for writing. -# FUNCTIONS / POLICIES / CATEGORIES +# FUNCTIONS, CATEGORIES and POLICIES + +The POSIX filesystem API is made up of a number of functions. **creat**, **stat**, **chown**, etc. For ease of configuration in mergerfs most of the core functions are grouped into 3 categories: **action**, **create**, and **search**. These functions and categories can be assigned a policy which dictates which branch is chosen when performing that function. -The POSIX filesystem API is made up of a number of functions. **creat**, **stat**, **chown**, etc. For ease of configuration in mergerfs most of the core functions are grouped into 3 categories: **action**, **create**, and **search**. These functions and categories can be assigned a policy which dictates which underlying branch/file/directory is chosen when performing that behavior. Any policy can be assigned to a function or category though some may not be very useful in practice. For instance: **rand** (random) may be useful for file creation (create) but could lead to very odd behavior if used for `chmod` if there were more than one copy of the file. +Some functions, listed in the category `N/A` below, can not be assigned the normal policies. These functions work with file handles, rather than file paths, which were created by `open` or `create`. That said many times the current FUSE kernel driver will not always provide the file handle when a client calls `fgetattr`, `fchown`, `fchmod`, `futimens`, `ftruncate`, etc. This means it will call the regular, path based, versions. `readdir` has no real need for a policy given the purpose is merely to return a list of entries in a directory. `statfs`'s behavior can be modified via other options. -Some functions, listed in the category `N/A` below, can not be assigned the normal policies. All functions which work on file handles use the handle which was acquired by `open` or `create`. `readdir` has no real need for a policy given the purpose is merely to return a list of entries in a directory. `statfs`'s behavior can be modified via other options. That said many times the current FUSE kernel driver will not always provide the file handle when a client calls `fgetattr`, `fchown`, `fchmod`, `futimens`, `ftruncate`, etc. This means it will call the regular, path based, versions. +When using policies which are based on a branch's available space the base path provided is used. Not the full path to the file in question. Meaning that mounts in the branch won't be considered in the space calculations. The reason is that it doesn't really work for non-path preserving policies and can lead to non-obvious behaviors. -When using policies which are based on a branch's available space the base path provided is used. Not the full path to the file in question. Meaning that sub mounts won't be considered in the space calculations. The reason is that it doesn't really work for non-path preserving policies and can lead to non-obvious behaviors. +NOTE: While any policy can be assigned to a function or category though some may not be very useful in practice. For instance: **rand** (random) may be useful for file creation (create) but could lead to very odd behavior if used for `chmod` if there were more than one copy of the file. -#### Functions and their Category classifications +### Functions and their Category classifications | Category | FUSE Functions | |----------|-------------------------------------------------------------------------------------| | action | chmod, chown, link, removexattr, rename, rmdir, setxattr, truncate, unlink, utimens | | create | create, mkdir, mknod, symlink | -| search | access, getattr, getxattr, ioctl (directories), listxattr, open, readlink | +| search | access, getattr, getxattr, ioctl (directories), listxattr, open, readlink | | N/A | fchmod, fchown, futimens, ftruncate, fallocate, fgetattr, fsync, ioctl (files), read, readdir, release, statfs, write, copy_file_range | -In cases where something may be searched (to confirm a directory exists across all source mounts) **getattr** will be used. +In cases where something may be searched for (such as a path to clone) **getattr** will usually be used. + + +### Policies + +A policy is the algorithm used to choose a branch or branches for a function to work on. Think of them as ways to filter and sort branches. + +Any function in the `create` category will clone the relative path if needed. Some other functions (`rename`,`link`,`ioctl`) have special requirements or behaviors which you can read more about below. + + +#### Filtering + +Policies basically search branches and create a list of files / paths for functions to work on. The policy is responsible for filtering and sorting the branches. Filters include **minfreespace**, whether or not a branch is mounted read-only, and the branch tagging (RO,NC,RW). These filters are applied across all policies unless otherwise noted. + +* No **search** function policies filter. +* All **action** function policies filter out branches which are mounted **read-only** or tagged as **RO (read-only)**. +* All **create** function policies filter out branches which are mounted **read-only**, tagged **RO (read-only)** or **NC (no create)**, or has available space less than `minfreespace`. + +Policies may have their own additional filtering such as those that require existing paths to be present. + +If all branches are filtered an error will be returned. Typically **EROFS** (read-only filesystem) or **ENOSPC** (no space left on device) depending on the most recent reason for filtering a branch. **ENOENT** will be returned if no elegible branch is found. #### Path Preservation @@ -304,20 +332,9 @@ When using non-path preserving policies paths will be cloned to target drives as With the `msp` or `most shared path` policies they are defined as `path preserving` for the purpose of controlling `link` and `rename`'s behaviors since `ignorepponrename` is available to disable that behavior. In mergerfs v3.0 the path preserving behavior of rename and link will likely be separated from the policy all together. -#### Filters - -Policies basically search branches and create a list of files / paths for functions to work on. The policy is responsible for filtering and sorting. Filters include **minfreespace**, whether or not a branch is mounted read-only, and the branch tagging (RO,NC,RW). The policy defines the sorting but filtering is mostly uniform as described below. - -* No **search** policies filter. -* All **action** policies will filter out branches which are mounted **read-only** or tagged as **RO (read-only)**. -* All **create** policies will filter out branches which are mounted **read-only**, tagged **RO (read-only)** or **NC (no create)**, or has available space less than `minfreespace`. - -If all branches are filtered an error will be returned. Typically **EROFS** (read-only filesystem) or **ENOSPC** (no space left on device) depending on the most recent reason for filtering a branch. - - #### Policy descriptions -Because of the nature of the behavior the policies act differently depending on the function it is used with (based on the category). +A policy's behavior differs, as mentioned above, based on the function it is used with. Sometimes it really might not make sense to even offer certain policies because they are literally the same as others but it makes things a bit more uniform. In mergerfs 3.0 this might change. | Policy | Description | @@ -360,19 +377,6 @@ Because of the nature of the behavior the policies act differently depending on When `ioctl` is used with an open file then it will use the file handle which was created at the original `open` call. However, when using `ioctl` with a directory mergerfs will use the `open` policy to find the directory to act on. -#### unlink - -In FUSE there is an opaque "file handle" which is created by `open`, `create`, or `opendir`, passed to the kernel, and then is passed back to the FUSE userland application by the kernel. Unfortunately, the FUSE kernel driver does not always send the file handle when it theoretically could/should. This complicates certain behaviors / workflows particularly in the high level API. As a result mergerfs is currently doing a few hacky things. - -libfuse2 and libfuse3, when using the high level API, will rename names to `.fuse_hiddenXXXXXX` if the file is open when unlinked or renamed over. It does this so the file is still available when a request referencing the now missing file is made. This file however keeps a `rmdir` from succeeding and can be picked up by software reading directories. - -The change mergerfs has done is that if a file is open when an unlink or rename happens it will open the file and keep it open till closed by all those who opened it prior. When a request comes in referencing that file and it doesn't include a file handle it will instead use the file handle created at unlink/rename time. - -This won't result in technically proper behavior but close enough for many usecases. - -The plan is to rewrite mergerfs to use the low level API so these invasive libfuse changes are no longer necessary. - - #### rename & link #### **NOTE:** If you're receiving errors from software when files are moved / renamed / linked then you should consider changing the create policy to one which is **not** path preserving, enabling `ignorepponrename`, or contacting the author of the offending software and requesting that `EXDEV` (cross device / improper link) be properly handled. @@ -473,7 +477,7 @@ $ wget https://github.com/trapexit/mergerfs/releases/download//mergerfs-_.deb ``` #### RHEL / CentOS /Fedora @@ -664,7 +668,6 @@ A B C * mergerfs.dup: Ensure there are at least N copies of a file across the pool * mergerfs.balance: Rebalance files across drives by moving them from the most filled to the least filled * mergerfs.consolidate: move files within a single mergerfs directory to the drive with most free space - * mergerfs.mktrash: Creates FreeDesktop.org Trash specification compatible directories on a mergerfs mount * https://github.com/trapexit/scorch * scorch: A tool to help discover silent corruption of files and keep track of files * https://github.com/trapexit/bbf @@ -764,6 +767,9 @@ With #2 one could use dm-cache as well but there is another solution which requi Move files from cache to backing pool based only on the last time the file was accessed. Replace `-atime` with `-amin` if you want minutes rather than days. May want to use the `fadvise` / `--drop-cache` version of rsync or run rsync with the tool "nocache". +*NOTE:* The arguments to these scripts include the cache **drive**. Not the pool with the cache drive. You could have data loss if the source is the cache pool. + + ``` #!/bin/bash @@ -785,6 +791,8 @@ find "${CACHE}" -type f -atime +${N} -printf '%P\n' | \ Move the oldest file from the cache to the backing pool. Continue till below percentage threshold. +*NOTE:* The arguments to these scripts include the cache **drive**. Not the pool with the cache drive. You could have data loss if the source is the cache pool. + ``` #!/bin/bash @@ -869,6 +877,8 @@ $ dd if=/mnt/mergerfs/1GB.file of=/dev/null bs=1M count=1024 iflag=nocache conv= # TIPS / NOTES +* This document is very literal and thorough. Unless there is a bug things work as described. If a suspected feature isn't mentioned it doesn't exist. +* Ensure you're using the latest version. Few distros have the latest version. * **use_ino** will only work when used with mergerfs 2.18.0 and above. * Run mergerfs as `root` (with **allow_other**) unless you're merging paths which are owned by the same user otherwise strange permission issues may arise. * https://github.com/trapexit/backup-and-recovery-howtos : A set of guides / howtos on creating a data storage system, backing it up, maintaining it, and recovering from failure. @@ -885,6 +895,7 @@ $ dd if=/mnt/mergerfs/1GB.file of=/dev/null bs=1M count=1024 iflag=nocache conv= [https://github.com/trapexit/mergerfs/wiki/Kernel-Issues-&-Bugs](https://github.com/trapexit/mergerfs/wiki/Kernel-Issues-&-Bugs) + #### directory mtime is not being updated Remember that the default policy for `getattr` is `ff`. The information for the first directory found will be returned. If it wasn't the directory which had been updated then it will appear outdated. @@ -1061,17 +1072,21 @@ The default create policy is `epmfs`. That is a path preserving algorithm. With This catches a lot of new users off guard but changing the default would break the setup for many existing users. If you do not care about path preservation and wish your files to be spread across all your drives change to `mfs` or similar policy as described above. If you do want path preservation you'll need to perform the manual act of creating paths on the drives you want the data to land on before transferring your data. Setting `func.mkdir=epall` can simplify managing path preservation for `create`. Or use `func.mkdir=rand` if you're interested in just grouping together directory content by drive. -#### Do hard links work? +#### Do hardlinks work? Yes. You need to use `use_ino` to support proper reporting of inodes but they work regardless. See also the option `inodecalc`. What mergerfs does not do is fake hard links across branches. Read the section "rename & link" for how it works. +Remember that hardlinks will NOT work across devices. That includes between the original filesystem and a mergerfs pool, between two separate pools of the same underlying filesystems, or bind mounts of paths within the mergerfs pool. The latter is common when using Docker or Podman. Multiple volumes (bind mounts) to the same underlying filesystem are considered different devices. There is no way to link between them. You should mount in the highest directory in the mergerfs pool that includes all the paths you need if you want links to work. -#### Does mergerfs support CoW / copy-on-write? + +#### Does mergerfs support CoW / copy-on-write / writes to read-only filesystems? Not in the sense of a filesystem like BTRFS or ZFS nor in the overlayfs or aufs sense. It does offer a [cow-shell](http://manpages.ubuntu.com/manpages/bionic/man1/cow-shell.1.html) like hard link breaking (copy to temp file then rename over original) which can be useful when wanting to save space by hardlinking duplicate files but wish to treat each name as if it were a unique and separate file. +If you want to write to a read-only filesystem you should look at overlayfs. You can always include the overlayfs mount into a mergerfs pool. + #### Why can't I see my files / directories? @@ -1268,21 +1283,34 @@ This software is free to use and released under a very liberal license (ISC). Th At the moment my preference would be GitHub Sponsors only because I am part of the matching program. That said please use whatever platform you prefer. -* PayPal: https://paypal.me/trapexit * GitHub Sponsors: https://github.com/sponsors/trapexit +* PayPal: https://paypal.me/trapexit * Patreon: https://www.patreon.com/trapexit -* SubscribeStar: https://www.subscribestar.com/trapexit * Ko-Fi: https://ko-fi.com/trapexit * Open Collective: https://opencollective.com/trapexit -* Bitcoin (BTC): 1DfoUd2m5WCxJAMvcFuvDpT4DR2gWX2PWb -* Bitcoin Cash (BCH): qrf257j0l09yxty4kur8dk2uma8p5vntdcpks72l8z -* Ethereum (ETH): 0xb486C0270fF75872Fc51d85879b9c15C380E66CA -* Litecoin (LTC): LW1rvHRPWtm2NUEMhJpP4DjHZY1FaJ1WYs -* Monero (XMR): 8AuU7PeK1fVhGP9yug8fdgKBssvUQoBVFKGhtT5DzWQt7fcTKC1SUx3Eb7xCAiVt3McWJp2Z9gX2wU7SPhh1GfWYBTCs6SS -* Basic Attention Token (BAT): 0xE651d4900B4C305284Da43E2e182e9abE149A87A +* Bitcoin (BTC): bc1qu537hqlnmn2wawx9n7nws0dlkz55h0cd93ny28 +* Bitcoin Cash (BCH): bitcoincash:qqp0vh9v44us74gaggwjfv9y54zfjmmd7srlqxa3xt +* Bitcoin SV (BSV): 1FkFuxRtt3f8LbkpeUKRZq7gKJFzGSGgZV +* Bitcoin Gold (BTG): AaPuJgJeohPjkB3LxJM6NKGnaHoRJ8ieT3 +* Litecoin (LTC): MJQzsHBdNnkyGqCFdcAdHYKugicBmfAXfQ +* Dogecoin (DOGE): DLJNLVe28vZ4SMQSxDJLBQBv57rGtUoWFh +* Ethereum (ETH): 0xB8d6d55c0319aacC327860d13f891427caEede7a + * Basic Attention Token (BAT): 0xB8d6d55c0319aacC327860d13f891427caEede7a + * Chainlink (LINK): 0xB8d6d55c0319aacC327860d13f891427caEede7a + * Reserve Rights (RSR): 0xB8d6d55c0319aacC327860d13f891427caEede7a + * Reef Finance (REEF): 0xB8d6d55c0319aacC327860d13f891427caEede7a + * Any ERC20 Token: 0xB8d6d55c0319aacC327860d13f891427caEede7a +* Ethereum Classic (ETC): 0x2B6054428e69a1201B6555f7a2aEc0Fba01EAD9F +* Dash (DASH): XvsFrohu8tbjA4E8p7xsc86E2ADxLHGXHL +* Monero (XMR): 45BBZMrJwPSaFwSoqLVNEggWR2BJJsXxz7bNz8FXnnFo3GyhVJFSCrCFSS7zYwDa9r1TmFmGMxQ2HTntuc11yZ9q1LeCE8f +* Filecoin (FIL): f1wpypkjcluufzo74yha7p67nbxepzizlroockgcy * LBRY Credits (LBC): bFusyoZPkSuzM2Pr8mcthgvkymaosJZt5r -* Zcash (ZEC): t1ZwTgmbQF23DJrzqbAmw8kXWvU2xUkkhTt -* Zcoin (XZC): a8L5Vz35KdCQe7Y7urK2pcCGau7JsqZ5Gw +* Ripple (XRP): r9f6aoxaGD8aymxqH89Ke1PCUPkNiFdZZC +* Tezos (XTZ): tz1ZxerkbbALsuU9XGV9K9fFpuLWnKAGfc1C +* Zcash (ZEC): t1Zo1GGn2T3GrhKvgdtnTsTnWu6tCPaCaHG +* DigiByte (DGB): Sb8r1qTrryY9Sp4YkTE1eeKEGVzgArnE5N +* Namecoin (NMC): NDzb9FkoptGu5QbgetCkodJqo2zE1cTwyb +* Vertcoin (VTC): 3PYdhokAGXJwWrwHRoTywxG4iUDk6EHjKe * Other crypto currencies: contact me for address diff --git a/man/mergerfs.1 b/man/mergerfs.1 index 62682465..993eb7e3 100644 --- a/man/mergerfs.1 +++ b/man/mergerfs.1 @@ -1,7 +1,7 @@ .\"t .\" Automatically generated by Pandoc 1.19.2.4 .\" -.TH "mergerfs" "1" "2020\-08\-30" "mergerfs user manual" "" +.TH "mergerfs" "1" "2021\-02\-08" "mergerfs user manual" "" .hy .SH NAME .PP @@ -42,7 +42,7 @@ Can turn read\-only files into symlinks to underlying file .IP \[bu] 2 Hard link copy\-on\-write / CoW .IP \[bu] 2 -supports POSIX ACLs +Support for POSIX ACLs .SH HOW IT WORKS .PP mergerfs logically merges multiple paths together. @@ -74,14 +74,14 @@ A\ \ \ \ \ \ \ \ \ +\ \ \ \ \ \ B\ \ \ \ \ \ \ \ =\ \ \ \ \ \ \ C \f[] .fi .PP -mergerfs does \f[B]not\f[] support the copy\-on\-write (CoW) behavior -found in \f[B]aufs\f[] and \f[B]overlayfs\f[]. +mergerfs does \f[B]NOT\f[] support the copy\-on\-write (CoW) or whiteout +behaviors found in \f[B]aufs\f[] and \f[B]overlayfs\f[]. You can \f[B]not\f[] mount a read\-only filesystem and write to it. However, mergerfs will ignore read\-only drives when creating new files so you can mix read\-write and read\-only drives. -It also does \f[B]not\f[] split data across drives. +It also does \f[B]NOT\f[] split data across drives. It is not RAID0 / striping. -It is simply a union. +It is simply a union of other filesystems. .SH TERMINOLOGY .IP \[bu] 2 branch: A base path used in the pool. @@ -91,11 +91,12 @@ The union of the branches. .IP \[bu] 2 relative path: The path in the pool relative to the branch and mount. .IP \[bu] 2 -policy: The algorithm used to select a file when performing a function. +function: A filesystem call (open, unlink, create, getattr, rmdir, etc.) .IP \[bu] 2 -function: A filesystem call (open, unlink, create, getattr, etc.) +category: A collection of functions based on basic behavior (action, +create, search). .IP \[bu] 2 -category: A collection of functions (action, create, search). +policy: The algorithm used to select a file when performing a function. .IP \[bu] 2 path preservation: Aspect of some policies which includes checking the path for which a file would be created. @@ -103,21 +104,26 @@ path for which a file would be created. .PP If you don\[aq]t already know that you have a special use case then just start with one of the following option sets. -.SS You don\[aq]t need \f[C]mmap\f[] +.SS You need \f[C]mmap\f[] (used by rtorrent and many sqlite3 base +software) .PP -\f[C]use_ino,cache.files=off,dropcacheonclose=true,allow_other,category.create=mfs\f[] -.SS You do need \f[C]mmap\f[] (used by rtorrent and some other programs) +\f[C]allow_other,use_ino,cache.files=partial,dropcacheonclose=true,category.create=mfs\f[] +.SS You don\[aq]t need \f[C]mmap\f[] .PP -\f[C]use_ino,cache.files=partial,dropcacheonclose=true,allow_other,category.create=mfs\f[] +\f[C]allow_other,use_ino,cache.files=off,dropcacheonclose=true,category.create=mfs\f[] .PP See the mergerfs wiki for real world deployments (https://github.com/trapexit/mergerfs/wiki/Real-World-Deployments) for comparisons / ideas. .SH OPTIONS +.PP +These options are the same regardless you use them with the +\f[C]mergerfs\f[] commandline program, used in fstab, or in a config +file. .SS mount options .IP \[bu] 2 \f[B]config\f[]: Path to a config file. -Same arguments as below in key=val format. +Same arguments as below in key=val / ini style format. .IP \[bu] 2 \f[B]branches\f[]: Colon delimited list of branches. .IP \[bu] 2 @@ -163,7 +169,7 @@ be reported as symlinks to the original files. Please read more below before using. (default: false) .IP \[bu] 2 -\f[B]symlinkify_timeout=INT\f[]: Time to wait, in seconds, to activate +\f[B]symlinkify_timeout=UINT\f[]: Time to wait, in seconds, to activate the \f[B]symlinkify\f[] behavior. (default: 3600) .IP \[bu] 2 @@ -227,7 +233,7 @@ pending read request per file handle and will attempt to order requests by offset. (default: true) .IP \[bu] 2 -\f[B]fuse_msg_size=INT\f[]: Set the max number of pages per FUSE +\f[B]fuse_msg_size=UINT\f[]: Set the max number of pages per FUSE message. Only available on Linux >= 4.20 and ignored otherwise. (min: 1; max: 256; default: 256) @@ -254,24 +260,32 @@ longest common prefix removed. See below for the list of value types. Example: \f[B]func.getattr=newest\f[] .IP \[bu] 2 -\f[B]category.CATEGORY=POLICY\f[]: Sets policy of all FUSE functions in -the provided category. -See POLICIES section for defaults. -Example: \f[B]category.create=mfs\f[] +\f[B]category.action=POLICY\f[]: Sets policy of all FUSE functions in +the action category. +(default: epall) +.IP \[bu] 2 +\f[B]category.create=POLICY\f[]: Sets policy of all FUSE functions in +the create category. +(default: epmfs) +.IP \[bu] 2 +\f[B]category.search=POLICY\f[]: Sets policy of all FUSE functions in +the search category. +(default: ff) .IP \[bu] 2 -\f[B]cache.open=INT\f[]: \[aq]open\[aq] policy cache timeout in seconds. +\f[B]cache.open=UINT\f[]: \[aq]open\[aq] policy cache timeout in +seconds. (default: 0) .IP \[bu] 2 -\f[B]cache.statfs=INT\f[]: \[aq]statfs\[aq] cache timeout in seconds. +\f[B]cache.statfs=UINT\f[]: \[aq]statfs\[aq] cache timeout in seconds. (default: 0) .IP \[bu] 2 -\f[B]cache.attr=INT\f[]: File attribute cache timeout in seconds. +\f[B]cache.attr=UINT\f[]: File attribute cache timeout in seconds. (default: 1) .IP \[bu] 2 -\f[B]cache.entry=INT\f[]: File name lookup cache timeout in seconds. +\f[B]cache.entry=UINT\f[]: File name lookup cache timeout in seconds. (default: 1) .IP \[bu] 2 -\f[B]cache.negative_entry=INT\f[]: Negative file name lookup cache +\f[B]cache.negative_entry=UINT\f[]: Negative file name lookup cache timeout in seconds. (default: 0) .IP \[bu] 2 @@ -315,22 +329,24 @@ setting. .IP \[bu] 2 BOOL = \[aq]true\[aq] | \[aq]false\[aq] .IP \[bu] 2 -INT = [0,MAX_INT] +INT = [MIN_INT,MAX_INT] +.IP \[bu] 2 +UINT = [0,MAX_INT] .IP \[bu] 2 SIZE = \[aq]NNM\[aq]; NN = INT, M = \[aq]K\[aq] | \[aq]M\[aq] | \[aq]G\[aq] | \[aq]T\[aq] .IP \[bu] 2 STR = string .IP \[bu] 2 -FUNC = FUSE function +FUNC = filesystem function .IP \[bu] 2 -CATEGORY = FUSE function category +CATEGORY = function category .IP \[bu] 2 POLICY = mergerfs function policy .SS branches .PP -The \[aq]branches\[aq] (formerly \[aq]srcmounts\[aq]) argument is a -colon (\[aq]:\[aq]) delimited list of paths to be pooled together. +The \[aq]branches\[aq] argument is a colon (\[aq]:\[aq]) delimited list +of paths to be pooled together. It does not matter if the paths are on the same or different drives nor does it matter the filesystem (within reason). Used and available space will not be duplicated for paths on the same @@ -613,7 +629,7 @@ If set to \f[C]git\f[] it will only perform the hack when the path in question includes \f[C]/.git/\f[]. \f[C]all\f[] will result it it applying anytime a readonly file which is empty is opened for writing. -.SH FUNCTIONS / POLICIES / CATEGORIES +.SH FUNCTIONS, CATEGORIES and POLICIES .PP The POSIX filesystem API is made up of a number of functions. \f[B]creat\f[], \f[B]stat\f[], \f[B]chown\f[], etc. @@ -621,34 +637,34 @@ For ease of configuration in mergerfs most of the core functions are grouped into 3 categories: \f[B]action\f[], \f[B]create\f[], and \f[B]search\f[]. These functions and categories can be assigned a policy which dictates -which underlying branch/file/directory is chosen when performing that -behavior. -Any policy can be assigned to a function or category though some may not -be very useful in practice. -For instance: \f[B]rand\f[] (random) may be useful for file creation -(create) but could lead to very odd behavior if used for \f[C]chmod\f[] -if there were more than one copy of the file. +which branch is chosen when performing that function. .PP Some functions, listed in the category \f[C]N/A\f[] below, can not be assigned the normal policies. -All functions which work on file handles use the handle which was -acquired by \f[C]open\f[] or \f[C]create\f[]. -\f[C]readdir\f[] has no real need for a policy given the purpose is -merely to return a list of entries in a directory. -\f[C]statfs\f[]\[aq]s behavior can be modified via other options. +These functions work with file handles, rather than file paths, which +were created by \f[C]open\f[] or \f[C]create\f[]. That said many times the current FUSE kernel driver will not always provide the file handle when a client calls \f[C]fgetattr\f[], \f[C]fchown\f[], \f[C]fchmod\f[], \f[C]futimens\f[], \f[C]ftruncate\f[], etc. This means it will call the regular, path based, versions. +\f[C]readdir\f[] has no real need for a policy given the purpose is +merely to return a list of entries in a directory. +\f[C]statfs\f[]\[aq]s behavior can be modified via other options. .PP When using policies which are based on a branch\[aq]s available space the base path provided is used. Not the full path to the file in question. -Meaning that sub mounts won\[aq]t be considered in the space +Meaning that mounts in the branch won\[aq]t be considered in the space calculations. The reason is that it doesn\[aq]t really work for non\-path preserving policies and can lead to non\-obvious behaviors. +.PP +NOTE: While any policy can be assigned to a function or category though +some may not be very useful in practice. +For instance: \f[B]rand\f[] (random) may be useful for file creation +(create) but could lead to very odd behavior if used for \f[C]chmod\f[] +if there were more than one copy of the file. .SS Functions and their Category classifications .PP .TS @@ -685,8 +701,44 @@ fchmod, fchown, futimens, ftruncate, fallocate, fgetattr, fsync, ioctl T} .TE .PP -In cases where something may be searched (to confirm a directory exists -across all source mounts) \f[B]getattr\f[] will be used. +In cases where something may be searched for (such as a path to clone) +\f[B]getattr\f[] will usually be used. +.SS Policies +.PP +A policy is the algorithm used to choose a branch or branches for a +function to work on. +Think of them as ways to filter and sort branches. +.PP +Any function in the \f[C]create\f[] category will clone the relative +path if needed. +Some other functions (\f[C]rename\f[],\f[C]link\f[],\f[C]ioctl\f[]) have +special requirements or behaviors which you can read more about below. +.SS Filtering +.PP +Policies basically search branches and create a list of files / paths +for functions to work on. +The policy is responsible for filtering and sorting the branches. +Filters include \f[B]minfreespace\f[], whether or not a branch is +mounted read\-only, and the branch tagging (RO,NC,RW). +These filters are applied across all policies unless otherwise noted. +.IP \[bu] 2 +No \f[B]search\f[] function policies filter. +.IP \[bu] 2 +All \f[B]action\f[] function policies filter out branches which are +mounted \f[B]read\-only\f[] or tagged as \f[B]RO (read\-only)\f[]. +.IP \[bu] 2 +All \f[B]create\f[] function policies filter out branches which are +mounted \f[B]read\-only\f[], tagged \f[B]RO (read\-only)\f[] or \f[B]NC +(no create)\f[], or has available space less than \f[C]minfreespace\f[]. +.PP +Policies may have their own additional filtering such as those that +require existing paths to be present. +.PP +If all branches are filtered an error will be returned. +Typically \f[B]EROFS\f[] (read\-only filesystem) or \f[B]ENOSPC\f[] (no +space left on device) depending on the most recent reason for filtering +a branch. +\f[B]ENOENT\f[] will be returned if no elegible branch is found. .SS Path Preservation .PP Policies, as described below, are of two basic types. @@ -709,33 +761,14 @@ defined as \f[C]path\ preserving\f[] for the purpose of controlling \f[C]ignorepponrename\f[] is available to disable that behavior. In mergerfs v3.0 the path preserving behavior of rename and link will likely be separated from the policy all together. -.SS Filters -.PP -Policies basically search branches and create a list of files / paths -for functions to work on. -The policy is responsible for filtering and sorting. -Filters include \f[B]minfreespace\f[], whether or not a branch is -mounted read\-only, and the branch tagging (RO,NC,RW). -The policy defines the sorting but filtering is mostly uniform as -described below. -.IP \[bu] 2 -No \f[B]search\f[] policies filter. -.IP \[bu] 2 -All \f[B]action\f[] policies will filter out branches which are mounted -\f[B]read\-only\f[] or tagged as \f[B]RO (read\-only)\f[]. -.IP \[bu] 2 -All \f[B]create\f[] policies will filter out branches which are mounted -\f[B]read\-only\f[], tagged \f[B]RO (read\-only)\f[] or \f[B]NC (no -create)\f[], or has available space less than \f[C]minfreespace\f[]. -.PP -If all branches are filtered an error will be returned. -Typically \f[B]EROFS\f[] (read\-only filesystem) or \f[B]ENOSPC\f[] (no -space left on device) depending on the most recent reason for filtering -a branch. .SS Policy descriptions .PP -Because of the nature of the behavior the policies act differently -depending on the function it is used with (based on the category). +A policy\[aq]s behavior differs, as mentioned above, based on the +function it is used with. +Sometimes it really might not make sense to even offer certain policies +because they are literally the same as others but it makes things a bit +more uniform. +In mergerfs 3.0 this might change. .PP .TS tab(@); @@ -930,38 +963,6 @@ When \f[C]ioctl\f[] is used with an open file then it will use the file handle which was created at the original \f[C]open\f[] call. However, when using \f[C]ioctl\f[] with a directory mergerfs will use the \f[C]open\f[] policy to find the directory to act on. -.SS unlink -.PP -In FUSE there is an opaque "file handle" which is created by -\f[C]open\f[], \f[C]create\f[], or \f[C]opendir\f[], passed to the -kernel, and then is passed back to the FUSE userland application by the -kernel. -Unfortunately, the FUSE kernel driver does not always send the file -handle when it theoretically could/should. -This complicates certain behaviors / workflows particularly in the high -level API. -As a result mergerfs is currently doing a few hacky things. -.PP -libfuse2 and libfuse3, when using the high level API, will rename names -to \f[C]\&.fuse_hiddenXXXXXX\f[] if the file is open when unlinked or -renamed over. -It does this so the file is still available when a request referencing -the now missing file is made. -This file however keeps a \f[C]rmdir\f[] from succeeding and can be -picked up by software reading directories. -.PP -The change mergerfs has done is that if a file is open when an unlink or -rename happens it will open the file and keep it open till closed by all -those who opened it prior. -When a request comes in referencing that file and it doesn\[aq]t include -a file handle it will instead use the file handle created at -unlink/rename time. -.PP -This won\[aq]t result in technically proper behavior but close enough -for many usecases. -.PP -The plan is to rewrite mergerfs to use the low level API so these -invasive libfuse changes are no longer necessary. .SS rename & link .PP \f[B]NOTE:\f[] If you\[aq]re receiving errors from software when files @@ -1152,7 +1153,7 @@ $\ wget\ https://github.com/trapexit/mergerfs/releases/download//mergerfs\- $\ cd\ mergerfs $\ sudo\ tools/install\-build\-pkgs $\ make\ deb -$\ sudo\ dpkg\ \-i\ ../mergerfs_version_arch.deb +$\ sudo\ dpkg\ \-i\ ../mergerfs__.deb \f[] .fi .SS RHEL / CentOS /Fedora @@ -1449,9 +1450,6 @@ most filled to the least filled mergerfs.consolidate: move files within a single mergerfs directory to the drive with most free space .IP \[bu] 2 -mergerfs.mktrash: Creates FreeDesktop.org Trash specification compatible -directories on a mergerfs mount -.IP \[bu] 2 https://github.com/trapexit/scorch .IP \[bu] 2 scorch: A tool to help discover silent corruption of files and keep @@ -1697,6 +1695,11 @@ Replace \f[C]\-atime\f[] with \f[C]\-amin\f[] if you want minutes rather than days. May want to use the \f[C]fadvise\f[] / \f[C]\-\-drop\-cache\f[] version of rsync or run rsync with the tool "nocache". +.PP +\f[I]NOTE:\f[] The arguments to these scripts include the cache +\f[B]drive\f[]. +Not the pool with the cache drive. +You could have data loss if the source is the cache pool. .IP .nf \f[C] @@ -1719,6 +1722,11 @@ find\ "${CACHE}"\ \-type\ f\ \-atime\ +${N}\ \-printf\ \[aq]%P\\n\[aq]\ |\ \\ .PP Move the oldest file from the cache to the backing pool. Continue till below percentage threshold. +.PP +\f[I]NOTE:\f[] The arguments to these scripts include the cache +\f[B]drive\f[]. +Not the pool with the cache drive. +You could have data loss if the source is the cache pool. .IP .nf \f[C] @@ -1741,7 +1749,7 @@ do \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ head\ \-n\ 1\ |\ \\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cut\ \-d\[aq]\ \[aq]\ \-f2\-) \ \ \ \ test\ \-n\ "${FILE}" -\ \ \ \ rsync\ \-axqHAXWES\ \-\-preallocate\ \-\-remove\-source\-files\ "${CACHE}/./${FILE}"\ "${BACKING}/" +\ \ \ \ rsync\ \-axqHAXWESR\ \-\-preallocate\ \-\-remove\-source\-files\ "${CACHE}/./${FILE}"\ "${BACKING}/" done \f[] .fi @@ -1893,6 +1901,13 @@ $\ dd\ if=/mnt/mergerfs/1GB.file\ of=/dev/null\ bs=1M\ count=1024\ iflag=nocache .fi .SH TIPS / NOTES .IP \[bu] 2 +This document is very literal and thorough. +Unless there is a bug things work as described. +If a suspected feature isn\[aq]t mentioned it doesn\[aq]t exist. +.IP \[bu] 2 +Ensure you\[aq]re using the latest version. +Few distros have the latest version. +.IP \[bu] 2 \f[B]use_ino\f[] will only work when used with mergerfs 2.18.0 and above. .IP \[bu] 2 @@ -2305,7 +2320,7 @@ Setting \f[C]func.mkdir=epall\f[] can simplify managing path preservation for \f[C]create\f[]. Or use \f[C]func.mkdir=rand\f[] if you\[aq]re interested in just grouping together directory content by drive. -.SS Do hard links work? +.SS Do hardlinks work? .PP Yes. You need to use \f[C]use_ino\f[] to support proper reporting of inodes @@ -2314,7 +2329,19 @@ See also the option \f[C]inodecalc\f[]. .PP What mergerfs does not do is fake hard links across branches. Read the section "rename & link" for how it works. -.SS Does mergerfs support CoW / copy\-on\-write? +.PP +Remember that hardlinks will NOT work across devices. +That includes between the original filesystem and a mergerfs pool, +between two separate pools of the same underlying filesystems, or bind +mounts of paths within the mergerfs pool. +The latter is common when using Docker or Podman. +Multiple volumes (bind mounts) to the same underlying filesystem are +considered different devices. +There is no way to link between them. +You should mount in the highest directory in the mergerfs pool that +includes all the paths you need if you want links to work. +.SS Does mergerfs support CoW / copy\-on\-write / writes to read\-only +filesystems? .PP Not in the sense of a filesystem like BTRFS or ZFS nor in the overlayfs or aufs sense. @@ -2324,6 +2351,10 @@ like hard link breaking (copy to temp file then rename over original) which can be useful when wanting to save space by hardlinking duplicate files but wish to treat each name as if it were a unique and separate file. +.PP +If you want to write to a read\-only filesystem you should look at +overlayfs. +You can always include the overlayfs mount into a mergerfs pool. .SS Why can\[aq]t I see my files / directories? .PP It\[aq]s almost always a permissions issue. @@ -2691,36 +2722,63 @@ At the moment my preference would be GitHub Sponsors only because I am part of the matching program. That said please use whatever platform you prefer. .IP \[bu] 2 -PayPal: https://paypal.me/trapexit -.IP \[bu] 2 GitHub Sponsors: https://github.com/sponsors/trapexit .IP \[bu] 2 -Patreon: https://www.patreon.com/trapexit +PayPal: https://paypal.me/trapexit .IP \[bu] 2 -SubscribeStar: https://www.subscribestar.com/trapexit +Patreon: https://www.patreon.com/trapexit .IP \[bu] 2 Ko\-Fi: https://ko\-fi.com/trapexit .IP \[bu] 2 Open Collective: https://opencollective.com/trapexit .IP \[bu] 2 -Bitcoin (BTC): 1DfoUd2m5WCxJAMvcFuvDpT4DR2gWX2PWb +Bitcoin (BTC): bc1qu537hqlnmn2wawx9n7nws0dlkz55h0cd93ny28 +.IP \[bu] 2 +Bitcoin Cash (BCH): +bitcoincash:qqp0vh9v44us74gaggwjfv9y54zfjmmd7srlqxa3xt +.IP \[bu] 2 +Bitcoin SV (BSV): 1FkFuxRtt3f8LbkpeUKRZq7gKJFzGSGgZV +.IP \[bu] 2 +Bitcoin Gold (BTG): AaPuJgJeohPjkB3LxJM6NKGnaHoRJ8ieT3 +.IP \[bu] 2 +Litecoin (LTC): MJQzsHBdNnkyGqCFdcAdHYKugicBmfAXfQ +.IP \[bu] 2 +Dogecoin (DOGE): DLJNLVe28vZ4SMQSxDJLBQBv57rGtUoWFh .IP \[bu] 2 -Bitcoin Cash (BCH): qrf257j0l09yxty4kur8dk2uma8p5vntdcpks72l8z +Ethereum (ETH): 0xB8d6d55c0319aacC327860d13f891427caEede7a .IP \[bu] 2 -Ethereum (ETH): 0xb486C0270fF75872Fc51d85879b9c15C380E66CA +Basic Attention Token (BAT): 0xB8d6d55c0319aacC327860d13f891427caEede7a .IP \[bu] 2 -Litecoin (LTC): LW1rvHRPWtm2NUEMhJpP4DjHZY1FaJ1WYs +Chainlink (LINK): 0xB8d6d55c0319aacC327860d13f891427caEede7a +.IP \[bu] 2 +Reserve Rights (RSR): 0xB8d6d55c0319aacC327860d13f891427caEede7a +.IP \[bu] 2 +Reef Finance (REEF): 0xB8d6d55c0319aacC327860d13f891427caEede7a +.IP \[bu] 2 +Any ERC20 Token: 0xB8d6d55c0319aacC327860d13f891427caEede7a +.IP \[bu] 2 +Ethereum Classic (ETC): 0x2B6054428e69a1201B6555f7a2aEc0Fba01EAD9F +.IP \[bu] 2 +Dash (DASH): XvsFrohu8tbjA4E8p7xsc86E2ADxLHGXHL .IP \[bu] 2 Monero (XMR): -8AuU7PeK1fVhGP9yug8fdgKBssvUQoBVFKGhtT5DzWQt7fcTKC1SUx3Eb7xCAiVt3McWJp2Z9gX2wU7SPhh1GfWYBTCs6SS +45BBZMrJwPSaFwSoqLVNEggWR2BJJsXxz7bNz8FXnnFo3GyhVJFSCrCFSS7zYwDa9r1TmFmGMxQ2HTntuc11yZ9q1LeCE8f .IP \[bu] 2 -Basic Attention Token (BAT): 0xE651d4900B4C305284Da43E2e182e9abE149A87A +Filecoin (FIL): f1wpypkjcluufzo74yha7p67nbxepzizlroockgcy .IP \[bu] 2 LBRY Credits (LBC): bFusyoZPkSuzM2Pr8mcthgvkymaosJZt5r .IP \[bu] 2 -Zcash (ZEC): t1ZwTgmbQF23DJrzqbAmw8kXWvU2xUkkhTt +Ripple (XRP): r9f6aoxaGD8aymxqH89Ke1PCUPkNiFdZZC +.IP \[bu] 2 +Tezos (XTZ): tz1ZxerkbbALsuU9XGV9K9fFpuLWnKAGfc1C +.IP \[bu] 2 +Zcash (ZEC): t1Zo1GGn2T3GrhKvgdtnTsTnWu6tCPaCaHG +.IP \[bu] 2 +DigiByte (DGB): Sb8r1qTrryY9Sp4YkTE1eeKEGVzgArnE5N +.IP \[bu] 2 +Namecoin (NMC): NDzb9FkoptGu5QbgetCkodJqo2zE1cTwyb .IP \[bu] 2 -Zcoin (XZC): a8L5Vz35KdCQe7Y7urK2pcCGau7JsqZ5Gw +Vertcoin (VTC): 3PYdhokAGXJwWrwHRoTywxG4iUDk6EHjKe .IP \[bu] 2 Other crypto currencies: contact me for address .SH LINKS diff --git a/src/branch.cpp b/src/branch.cpp index 34d79442..a693b8df 100644 --- a/src/branch.cpp +++ b/src/branch.cpp @@ -18,21 +18,8 @@ #include "branch.hpp" #include "ef.hpp" -#include "from_string.hpp" -#include "fs_glob.hpp" -#include "fs_realpathize.hpp" -#include "nonstd/optional.hpp" +#include "errno.hpp" #include "num.hpp" -#include "str.hpp" - -#include - -#include -#include - -using std::string; -using std::vector; -using nonstd::optional; Branch::Branch(const uint64_t &default_minfreespace_) @@ -108,354 +95,3 @@ Branch::ro_or_nc(void) const return ((mode == Branch::Mode::RO) || (mode == Branch::Mode::NC)); } - -namespace l -{ - static - void - split(const std::string &s_, - std::string *instr_, - std::string *values_) - { - uint64_t offset; - - offset = s_.find_first_of('/'); - *instr_ = s_.substr(0,offset); - if(offset != std::string::npos) - *values_ = s_.substr(offset); - } -} - -Branches::Branches(const uint64_t &default_minfreespace_) - : default_minfreespace(default_minfreespace_) -{ - pthread_rwlock_init(&lock,NULL); -} - -namespace l -{ - static - int - parse_mode(const string &str_, - Branch::Mode *mode_) - { - if(str_ == "RW") - *mode_ = Branch::Mode::RW; - ef(str_ == "RO") - *mode_ = Branch::Mode::RO; - ef(str_ == "NC") - *mode_ = Branch::Mode::NC; - else - return -EINVAL; - - return 0; - } - - static - int - parse_minfreespace(const string &str_, - optional *minfreespace_) - { - int rv; - uint64_t uint64; - - rv = str::from(str_,&uint64); - if(rv < 0) - return rv; - - *minfreespace_ = uint64; - - return 0; - } - - static - int - parse_branch(const string &str_, - string *glob_, - Branch::Mode *mode_, - optional *minfreespace_) - { - int rv; - string options; - vector v; - - str::rsplit1(str_,'=',&v); - switch(v.size()) - { - case 1: - *glob_ = v[0]; - *mode_ = Branch::Mode::RW; - break; - case 2: - *glob_ = v[0]; - options = v[1]; - v.clear(); - str::split(options,',',&v); - switch(v.size()) - { - case 2: - rv = l::parse_minfreespace(v[1],minfreespace_); - if(rv < 0) - return rv; - case 1: - rv = l::parse_mode(v[0],mode_); - if(rv < 0) - return rv; - break; - case 0: - return -EINVAL; - } - break; - default: - return -EINVAL; - } - - return 0; - } - - static - int - parse(const string &str_, - const uint64_t &default_minfreespace_, - BranchVec *branches_) - { - int rv; - string glob; - vector globbed; - optional minfreespace; - Branch branch(default_minfreespace_); - - rv = l::parse_branch(str_,&glob,&branch.mode,&minfreespace); - if(rv < 0) - return rv; - - if(minfreespace.has_value()) - branch.set_minfreespace(minfreespace.value()); - - fs::glob(glob,&globbed); - fs::realpathize(&globbed); - for(size_t i = 0; i < globbed.size(); i++) - { - branch.path = globbed[i]; - branches_->push_back(branch); - } - - return 0; - } - - static - int - set(const std::string &str_, - Branches *branches_) - { - int rv; - vector paths; - BranchVec tmp_branchvec; - - str::split(str_,':',&paths); - - for(size_t i = 0; i < paths.size(); i++) - { - rv = l::parse(paths[i],branches_->default_minfreespace,&tmp_branchvec); - if(rv < 0) - return rv; - } - - branches_->vec.clear(); - branches_->vec.insert(branches_->vec.end(), - tmp_branchvec.begin(), - tmp_branchvec.end()); - - return 0; - } - - static - int - add_begin(const std::string &str_, - Branches *branches_) - { - int rv; - vector paths; - BranchVec tmp_branchvec; - - str::split(str_,':',&paths); - - for(size_t i = 0; i < paths.size(); i++) - { - rv = l::parse(paths[i],branches_->default_minfreespace,&tmp_branchvec); - if(rv < 0) - return rv; - } - - branches_->vec.insert(branches_->vec.begin(), - tmp_branchvec.begin(), - tmp_branchvec.end()); - - return 0; - } - - static - int - add_end(const std::string &str_, - Branches *branches_) - { - int rv; - vector paths; - BranchVec tmp_branchvec; - - str::split(str_,':',&paths); - - for(size_t i = 0; i < paths.size(); i++) - { - rv = l::parse(paths[i],branches_->default_minfreespace,&tmp_branchvec); - if(rv < 0) - return rv; - } - - branches_->vec.insert(branches_->vec.end(), - tmp_branchvec.begin(), - tmp_branchvec.end()); - - return 0; - } - - static - int - erase_begin(BranchVec *branches_) - { - branches_->erase(branches_->begin()); - - return 0; - } - - static - int - erase_end(BranchVec *branches_) - { - branches_->pop_back(); - - return 0; - } - - static - int - erase_fnmatch(const std::string &str_, - Branches *branches_) - { - vector patterns; - - str::split(str_,':',&patterns); - - for(BranchVec::iterator i = branches_->vec.begin(); - i != branches_->vec.end();) - { - int match = FNM_NOMATCH; - - for(vector::const_iterator pi = patterns.begin(); - pi != patterns.end() && match != 0; - ++pi) - { - match = ::fnmatch(pi->c_str(),i->path.c_str(),0); - } - - i = ((match == 0) ? branches_->vec.erase(i) : (i+1)); - } - - return 0; - } -} - -int -Branches::from_string(const std::string &s_) -{ - rwlock::WriteGuard guard(lock); - - std::string instr; - std::string values; - - l::split(s_,&instr,&values); - - if(instr == "+") - return l::add_end(values,this); - if(instr == "+<") - return l::add_begin(values,this); - if(instr == "+>") - return l::add_end(values,this); - if(instr == "-") - return l::erase_fnmatch(values,this); - if(instr == "-<") - return l::erase_begin(&vec); - if(instr == "->") - return l::erase_end(&vec); - if(instr == "=") - return l::set(values,this); - if(instr.empty()) - return l::set(values,this); - - return -EINVAL; -} - -string -Branches::to_string(void) const -{ - rwlock::ReadGuard guard(lock); - - string tmp; - - for(size_t i = 0; i < vec.size(); i++) - { - const Branch &branch = vec[i]; - - tmp += branch.to_string(); - 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 < vec.size(); i++) - { - const Branch &branch = vec[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.vec.size(); i++) - { - rv += _branches.vec[i].path; - rv += ':'; - } - - if(*rv.rbegin() == ':') - rv.erase(rv.size() - 1); - - return rv; -} diff --git a/src/branch.hpp b/src/branch.hpp index 421f0e3c..588aa79a 100644 --- a/src/branch.hpp +++ b/src/branch.hpp @@ -18,81 +18,50 @@ #pragma once -#include "rwlock.hpp" -#include "tofrom_string.hpp" #include "nonstd/optional.hpp" +#include "strvec.hpp" +#include "tofrom_string.hpp" +#include #include #include -#include -#include -class Branch : public ToFromString +class Branch final : public ToFromString { public: - Branch(const uint64_t &default_minfreespace); + typedef std::vector Vector; public: - int from_string(const std::string &str); - std::string to_string(void) const; + Branch(const uint64_t &default_minfreespace_); public: enum class Mode { - INVALID, - RO, - RW, - NC + INVALID, + RO, + RW, + NC }; -public: - Mode mode; - std::string path; - uint64_t minfreespace() const; - -public: - void set_minfreespace(const uint64_t minfreespace); - public: bool ro(void) const; bool nc(void) const; bool ro_or_nc(void) const; -private: - nonstd::optional _minfreespace; - const uint64_t *_default_minfreespace; -}; - -typedef std::vector BranchVec; - -class Branches : public ToFromString -{ -public: - Branches(const uint64_t &default_minfreespace_); - -public: - int from_string(const std::string &str); - std::string to_string(void) const; - -public: - void to_paths(std::vector &vec) const; - public: - mutable pthread_rwlock_t lock; - BranchVec vec; - const uint64_t &default_minfreespace; -}; + int from_string(const std::string &str) final; + std::string to_string(void) const final; -class SrcMounts : public ToFromString -{ public: - SrcMounts(Branches &b_); + uint64_t minfreespace() const; + void set_minfreespace(const uint64_t); public: - int from_string(const std::string &str); - std::string to_string(void) const; + Mode mode; + std::string path; private: - Branches &_branches; + nonstd::optional _minfreespace; + const uint64_t *_default_minfreespace; }; diff --git a/src/branches.cpp b/src/branches.cpp new file mode 100644 index 00000000..b8ca5ebb --- /dev/null +++ b/src/branches.cpp @@ -0,0 +1,429 @@ +/* + ISC License + + Copyright (c) 2021, 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 "branches.hpp" +#include "ef.hpp" +#include "errno.hpp" +#include "from_string.hpp" +#include "fs_glob.hpp" +#include "fs_realpathize.hpp" +#include "nonstd/optional.hpp" +#include "num.hpp" +#include "str.hpp" + +#include + +#include + +using std::string; +using std::vector; +using nonstd::optional; + + +Branches::Impl::Impl(const uint64_t &default_minfreespace_) + : _default_minfreespace(default_minfreespace_) +{ +} + +Branches::Impl& +Branches::Impl::operator=(Branches::Impl &rval_) +{ + auto this_base = dynamic_cast(this); + auto rval_base = dynamic_cast(&rval_); + + *this_base = *rval_base; + + return *this; +} + +Branches::Impl& +Branches::Impl::operator=(Branches::Impl &&rval_) +{ + auto this_base = dynamic_cast(this); + auto rval_base = dynamic_cast(&rval_); + + *this_base = std::move(*rval_base); + + return *this; +} + +const +uint64_t& +Branches::Impl::minfreespace(void) const +{ + return _default_minfreespace; +} + +namespace l +{ + static + void + split(const std::string &s_, + std::string *instr_, + std::string *values_) + { + uint64_t offset; + + offset = s_.find_first_of('/'); + *instr_ = s_.substr(0,offset); + if(offset != std::string::npos) + *values_ = s_.substr(offset); + } + + static + int + parse_mode(const string &str_, + Branch::Mode *mode_) + { + if(str_ == "RW") + *mode_ = Branch::Mode::RW; + ef(str_ == "RO") + *mode_ = Branch::Mode::RO; + ef(str_ == "NC") + *mode_ = Branch::Mode::NC; + else + return -EINVAL; + + return 0; + } + + static + int + parse_minfreespace(const string &str_, + optional *minfreespace_) + { + int rv; + uint64_t uint64; + + rv = str::from(str_,&uint64); + if(rv < 0) + return rv; + + *minfreespace_ = uint64; + + return 0; + } + + static + int + parse_branch(const string &str_, + string *glob_, + Branch::Mode *mode_, + optional *minfreespace_) + { + int rv; + string options; + vector v; + + str::rsplit1(str_,'=',&v); + switch(v.size()) + { + case 1: + *glob_ = v[0]; + *mode_ = Branch::Mode::RW; + break; + case 2: + *glob_ = v[0]; + options = v[1]; + v.clear(); + str::split(options,',',&v); + switch(v.size()) + { + case 2: + rv = l::parse_minfreespace(v[1],minfreespace_); + if(rv < 0) + return rv; + case 1: + rv = l::parse_mode(v[0],mode_); + if(rv < 0) + return rv; + break; + case 0: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + return 0; + } + + static + int + parse(const string &str_, + Branches::Impl *branches_) + { + int rv; + string glob; + StrVec paths; + optional minfreespace; + Branch branch(branches_->minfreespace()); + + rv = l::parse_branch(str_,&glob,&branch.mode,&minfreespace); + if(rv < 0) + return rv; + + if(minfreespace.has_value()) + branch.set_minfreespace(minfreespace.value()); + + fs::glob(glob,&paths); + fs::realpathize(&paths); + for(auto &path : paths) + { + branch.path = path; + branches_->push_back(branch); + } + + return 0; + } + + static + int + set(const std::string &str_, + Branches::Impl *branches_) + { + int rv; + StrVec paths; + Branches::Impl tmp_branches(branches_->minfreespace()); + + str::split(str_,':',&paths); + for(auto &path : paths) + { + rv = l::parse(path,&tmp_branches); + if(rv < 0) + return rv; + } + + *branches_ = std::move(tmp_branches); + + return 0; + } + + static + int + add_begin(const std::string &str_, + Branches::Impl *branches_) + { + int rv; + vector paths; + Branches::Impl tmp_branches(branches_->minfreespace()); + + str::split(str_,':',&paths); + for(auto &path : paths) + { + rv = l::parse(path,&tmp_branches); + if(rv < 0) + return rv; + } + + branches_->insert(branches_->begin(), + tmp_branches.begin(), + tmp_branches.end()); + + return 0; + } + + static + int + add_end(const std::string &str_, + Branches::Impl *branches_) + { + int rv; + StrVec paths; + Branches::Impl tmp_branches(branches_->minfreespace()); + + str::split(str_,':',&paths); + for(auto &path : paths) + { + rv = l::parse(path,&tmp_branches); + if(rv < 0) + return rv; + } + + branches_->insert(branches_->end(), + tmp_branches.begin(), + tmp_branches.end()); + + return 0; + } + + static + int + erase_begin(Branches::Impl *branches_) + { + branches_->erase(branches_->begin()); + + return 0; + } + + static + int + erase_end(Branches::Impl *branches_) + { + branches_->pop_back(); + + return 0; + } + + static + int + erase_fnmatch(const std::string &str_, + Branches::Impl *branches_) + { + StrVec patterns; + + str::split(str_,':',&patterns); + for(auto i = branches_->begin(); i != branches_->end();) + { + int match = FNM_NOMATCH; + + for(auto pi = patterns.cbegin(); pi != patterns.cend() && match != 0; ++pi) + { + match = ::fnmatch(pi->c_str(),i->path.c_str(),0); + } + + i = ((match == 0) ? branches_->erase(i) : (i+1)); + } + + return 0; + } +} + +int +Branches::Impl::from_string(const std::string &s_) +{ + std::string instr; + std::string values; + + l::split(s_,&instr,&values); + + if(instr == "+") + return l::add_end(values,this); + if(instr == "+<") + return l::add_begin(values,this); + if(instr == "+>") + return l::add_end(values,this); + if(instr == "-") + return l::erase_fnmatch(values,this); + if(instr == "-<") + return l::erase_begin(this); + if(instr == "->") + return l::erase_end(this); + if(instr == "=") + return l::set(values,this); + if(instr.empty()) + return l::set(values,this); + + return -EINVAL; +} + +std::string +Branches::Impl::to_string(void) const +{ + string tmp; + + if(empty()) + return tmp; + + for(auto &branch : *this) + { + tmp += branch.to_string(); + tmp += ':'; + } + + tmp.pop_back(); + + return tmp; +} + +void +Branches::Impl::to_paths(StrVec &paths_) const +{ + for(auto &branch : *this) + { + paths_.push_back(branch.path); + } +} + +int +Branches::from_string(const std::string &str_) +{ + int rv; + Branches::Ptr impl; + Branches::Ptr new_impl; + + { + std::lock_guard lock_guard(_mutex); + impl = _impl; + } + + new_impl = std::make_shared(impl->minfreespace()); + *new_impl = *impl; + + rv = new_impl->from_string(str_); + if(rv < 0) + return rv; + + { + std::lock_guard lock_guard(_mutex); + _impl = new_impl; + } + + return 0; +} + +string +Branches::to_string(void) const +{ + std::lock_guard lock_guard(_mutex); + + return _impl->to_string(); +} + +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 +{ + std::string rv; + Branches::CPtr branches = _branches; + + if(branches->empty()) + return rv; + + for(const auto &branch : *branches) + { + rv += branch.path; + rv += ':'; + } + + rv.pop_back(); + + return rv; +} diff --git a/src/branches.hpp b/src/branches.hpp new file mode 100644 index 00000000..28731847 --- /dev/null +++ b/src/branches.hpp @@ -0,0 +1,94 @@ +/* + ISC License + + Copyright (c) 2021, 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 "branch.hpp" +#include "nonstd/optional.hpp" +#include "strvec.hpp" +#include "tofrom_string.hpp" + +#include +#include +#include +#include +#include + + +class Branches final : public ToFromString +{ +public: + class Impl final : public ToFromString, public Branch::Vector + { + public: + typedef std::shared_ptr Ptr; + typedef std::shared_ptr CPtr; + + public: + Impl(const uint64_t &default_minfreespace_); + + public: + int from_string(const std::string &str) final; + std::string to_string(void) const final; + + public: + const uint64_t& minfreespace(void) const; + void to_paths(StrVec &strvec) const; + + public: + Impl& operator=(Impl &impl_); + Impl& operator=(Impl &&impl_); + + private: + const uint64_t &_default_minfreespace; + }; + +public: + typedef Branches::Impl::Ptr Ptr; + typedef Branches::Impl::CPtr CPtr; + +public: + Branches(const uint64_t &default_minfreespace_) + : _impl(std::make_shared(default_minfreespace_)) + {} + +public: + int from_string(const std::string &str) final; + std::string to_string(void) const final; + +public: + operator CPtr() const { std::lock_guard lg(_mutex); return _impl; } + CPtr operator->() const { std::lock_guard lg(_mutex); return _impl; } + +private: + mutable std::mutex _mutex; + Ptr _impl; +}; + +class SrcMounts : public ToFromString +{ +public: + SrcMounts(Branches &b_); + +public: + int from_string(const std::string &str) final; + std::string to_string(void) const final; + +private: + Branches &_branches; +}; diff --git a/src/category.cpp b/src/category.cpp new file mode 100644 index 00000000..e1fd7f2a --- /dev/null +++ b/src/category.cpp @@ -0,0 +1,49 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "category.hpp" +#include "errno.hpp" +#include "str.hpp" + +#include + +int +Category::Base::from_string(const std::string &s_) +{ + int rv; + + for(auto func : funcs) + { + rv = func->from_string(s_); + if(rv < 0) + return rv; + } + + return 0; +} + +std::string +Category::Base::to_string(void) const +{ + std::set rv; + + for(auto func : funcs) + rv.insert(func->to_string()); + + return str::join(rv,','); +} diff --git a/src/category.hpp b/src/category.hpp index 08a7c00a..ff3b87f2 100644 --- a/src/category.hpp +++ b/src/category.hpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2016, Antonio SJ Musumeci + Copyright (c) 2020, Antonio SJ Musumeci Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -16,9 +16,92 @@ #pragma once -enum class Category +#include "tofrom_string.hpp" +#include "funcs.hpp" +#include "func.hpp" + +#include + +namespace Category +{ + class Base : public ToFromString + { + public: + int from_string(const std::string &s) final; + std::string to_string() const final; + + protected: + std::vector funcs; + }; + + class Action final : public Base + { + private: + Action(); + + public: + Action(Funcs &funcs_) + { + funcs.push_back(&funcs_.chmod); + funcs.push_back(&funcs_.chown); + funcs.push_back(&funcs_.link); + funcs.push_back(&funcs_.removexattr); + funcs.push_back(&funcs_.rename); + funcs.push_back(&funcs_.rmdir); + funcs.push_back(&funcs_.setxattr); + funcs.push_back(&funcs_.truncate); + funcs.push_back(&funcs_.unlink); + funcs.push_back(&funcs_.utimens); + } + }; + + class Create final : public Base { - ACTION, - CREATE, - SEARCH + private: + Create(); + + public: + Create(Funcs &funcs_) + { + funcs.push_back(&funcs_.create); + funcs.push_back(&funcs_.mkdir); + funcs.push_back(&funcs_.mknod); + funcs.push_back(&funcs_.symlink); + } }; + + class Search final : public Base + { + private: + Search(); + + public: + Search(Funcs &funcs_) + { + funcs.push_back(&funcs_.access); + funcs.push_back(&funcs_.getattr); + funcs.push_back(&funcs_.getxattr); + funcs.push_back(&funcs_.listxattr); + funcs.push_back(&funcs_.open); + funcs.push_back(&funcs_.readlink); + } + }; +} + +class Categories final +{ +private: + Categories(); + +public: + Categories(Funcs &funcs_) + : action(funcs_), + create(funcs_), + search(funcs_) + {} + +public: + Category::Action action; + Category::Create create; + Category::Search search; +}; diff --git a/src/config.cpp b/src/config.cpp index 6c8e1064..aadb2ae6 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -20,14 +20,18 @@ #include "from_string.hpp" #include "num.hpp" #include "rwlock.hpp" +#include "str.hpp" #include "to_string.hpp" #include "version.hpp" #include -#include +#include +#include #include +#include -#include +#include +#include #include #include @@ -37,6 +41,11 @@ using std::string; #define IFERT(S) if(S == s_) return true +const std::string CONTROLFILE = "/.mergerfs"; + +Config Config::_singleton; + + namespace l { static @@ -60,49 +69,44 @@ namespace l } Config::Config() - : - open_cache(), - - controlfile("/.mergerfs"), - - async_read(true), - auto_cache(false), - branches(minfreespace), - 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), - inodecalc("hybrid-hash"), - link_cow(false), - minfreespace(MINFREESPACE_DEFAULT), - mount(), - moveonenospc(false), - nfsopenhack(NFSOpenHack::ENUM::OFF), - nullrw(false), - pid(::getpid()), - posix_acl(false), - readdir(ReadDir::ENUM::POSIX), - 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) + : async_read(true), + auto_cache(false), + branches(minfreespace), + 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), + inodecalc("hybrid-hash"), + link_cow(false), + minfreespace(MINFREESPACE_DEFAULT), + mount(), + moveonenospc(false), + nfsopenhack(NFSOpenHack::ENUM::OFF), + nullrw(false), + pid(::getpid()), + posix_acl(false), + readdir(ReadDir::ENUM::POSIX), + 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; @@ -166,17 +170,22 @@ Config::Config() _map["xattr"] = &xattr; } -const Config& -Config::ro(void) +Config::operator=(const Config &cfg_) { - return *((Config*)fuse_get_context()->private_data); -} + int rv; + std::string val; -Config& -Config::rw(void) -{ - return *((Config*)fuse_get_context()->private_data); + for(auto &kv : _map) + { + rv = cfg_.get(kv.first,&val); + if(rv) + continue; + + kv.second->from_string(val); + } + + return *this; } bool @@ -254,11 +263,80 @@ Config::set(const std::string &key_, const std::string &value_) { if(l::readonly(key_)) - return -EINVAL; + return -EROFS; return set_raw(key_,value_); } +int +Config::set(const std::string &kv_) +{ + std::string key; + std::string val; + + str::splitkv(kv_,'=',&key,&val); + key = str::trim(key); + val = str::trim(val); + + return set(key,val); +} + +int +Config::from_stream(std::istream &istrm_, + ErrVec *errs_) +{ + int rv; + std::string line; + std::string key; + std::string val; + Config newcfg; + + newcfg = *this; + + while(std::getline(istrm_,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); + + rv = newcfg.set(key,val); + if(rv < 0) + errs_->push_back({rv,key}); + } + + if(!errs_->empty()) + return -EINVAL; + + *this = newcfg; + + return 0; +} + +int +Config::from_file(const std::string &filepath_, + ErrVec *errs_) +{ + int rv; + std::ifstream ifstrm; + + ifstrm.open(filepath_); + if(!ifstrm.good()) + { + errs_->push_back({-errno,filepath_}); + return -errno; + } + + rv = from_stream(ifstrm,errs_); + + ifstrm.close(); + + return rv; +} + std::ostream& operator<<(std::ostream &os_, const Config &c_) @@ -268,7 +346,47 @@ operator<<(std::ostream &os_, for(i = c_._map.begin(), ei = c_._map.end(); i != ei; ++i) { - os_ << i->first << '=' << i->second << '\n'; + os_ << i->first << '=' << i->second->to_string() << std::endl; + } + + return os_; +} + + +static +std::string +err2str(const int err_) +{ + switch(err_) + { + case 0: + return std::string(); + case -EINVAL: + return "invalid value"; + case -ENOATTR: + return "unknown option"; + case -EROFS: + return "read-only option"; + default: + return strerror(-err_); + } + + return std::string(); +} + +std::ostream& +operator<<(std::ostream &os_, + const Config::ErrVec &ev_) +{ + std::string errstr; + + for(auto &err : ev_) + { + os_ << "* ERROR: "; + errstr = err2str(err.err); + if(!errstr.empty()) + os_ << errstr << " - "; + os_ << err.str << std::endl; } return os_; diff --git a/src/config.hpp b/src/config.hpp index c66f3815..6bd1d02b 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -16,7 +16,8 @@ #pragma once -#include "branch.hpp" +#include "branches.hpp" +#include "category.hpp" #include "config_cachefiles.hpp" #include "config_inodecalc.hpp" #include "config_moveonenospc.hpp" @@ -27,18 +28,20 @@ #include "config_xattr.hpp" #include "enum.hpp" #include "errno.hpp" -#include "func_category.hpp" #include "funcs.hpp" #include "policy.hpp" -#include "policy_cache.hpp" +#include "rwlock.hpp" #include "tofrom_wrapper.hpp" -#include +#include "fuse.h" +#include +#include +#include +#include #include #include -#include #include typedef ToFromWrapper ConfigBOOL; @@ -47,16 +50,50 @@ typedef ToFromWrapper ConfigINT; typedef ToFromWrapper ConfigSTR; typedef std::map Str2TFStrMap; +extern const std::string CONTROLFILE; + class Config { public: - Config(); + struct Err + { + int err; + std::string str; + }; + + typedef std::vector ErrVec; + +public: + class Read + { + public: + Read(); + + public: + inline const Config* operator->() const; + + private: + const Config &_cfg; + }; public: - mutable PolicyCache open_cache; + class Write + { + public: + Write(); + + public: + Config* operator->(); + + private: + Config &_cfg; + }; public: - const std::string controlfile; + Config(); + +public: + Config& operator=(const Config&); public: ConfigBOOL async_read; @@ -69,7 +106,7 @@ public: ConfigBOOL cache_readdir; ConfigUINT64 cache_statfs; ConfigBOOL cache_symlinks; - FuncCategories category; + Categories category; ConfigBOOL direct_io; ConfigBOOL dropcacheonclose; ConfigSTR fsname; @@ -112,11 +149,50 @@ 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); + int set(const std::string &kv); public: - static const Config &ro(void); - static Config &rw(void); + int from_stream(std::istream &istrm, ErrVec *errs); + int from_file(const std::string &filepath, ErrVec *errs); private: Str2TFStrMap _map; + +private: + static Config _singleton; + +public: + friend class Read; + friend class Write; }; + +std::ostream& operator<<(std::ostream &s,const Config::ErrVec &ev); + +inline +Config::Read::Read() + : _cfg(Config::_singleton) +{ + +} + +inline +const +Config* +Config::Read::operator->() const +{ + return &_cfg; +} + +inline +Config::Write::Write() + : _cfg(Config::_singleton) +{ + +} + +inline +Config* +Config::Write::operator->() +{ + return &_cfg; +} diff --git a/src/config_cachefiles.hpp b/src/config_cachefiles.hpp index c2df5d7e..b6c9a2dc 100644 --- a/src/config_cachefiles.hpp +++ b/src/config_cachefiles.hpp @@ -20,6 +20,7 @@ #include "enum.hpp" + enum class CacheFilesEnum { LIBFUSE, diff --git a/src/config_inodecalc.cpp b/src/config_inodecalc.cpp index b471004d..aa21e048 100644 --- a/src/config_inodecalc.cpp +++ b/src/config_inodecalc.cpp @@ -19,6 +19,7 @@ #include "config_inodecalc.hpp" #include "fs_inode.hpp" + InodeCalc::InodeCalc(const std::string &s_) { fs::inode::set_algo(s_); diff --git a/src/config_inodecalc.hpp b/src/config_inodecalc.hpp index b87b7fc5..8a882593 100644 --- a/src/config_inodecalc.hpp +++ b/src/config_inodecalc.hpp @@ -20,12 +20,13 @@ #include "tofrom_string.hpp" + class InodeCalc : public ToFromString { public: InodeCalc(const std::string &); public: - std::string to_string(void) const; - int from_string(const std::string &); + std::string to_string(void) const final; + int from_string(const std::string &) final; }; diff --git a/src/config_moveonenospc.cpp b/src/config_moveonenospc.cpp index a1975459..17950cc8 100644 --- a/src/config_moveonenospc.cpp +++ b/src/config_moveonenospc.cpp @@ -21,12 +21,13 @@ #include "errno.hpp" #include "from_string.hpp" + int MoveOnENOSPC::from_string(const std::string &s_) { int rv; std::string s; - const Policy *tmp; + Policy::CreateImpl *tmp; rv = str::from(s_,&enabled); if((rv == 0) && (enabled == true)) @@ -36,8 +37,8 @@ MoveOnENOSPC::from_string(const std::string &s_) else return 0; - tmp = &Policy::find(s); - if(tmp == Policy::invalid) + tmp = Policies::Create::find(s); + if(tmp == NULL) return -EINVAL; policy = tmp; @@ -50,6 +51,6 @@ std::string MoveOnENOSPC::to_string(void) const { if(enabled) - return policy->to_string(); + return policy.name(); return "false"; } diff --git a/src/config_moveonenospc.hpp b/src/config_moveonenospc.hpp index a7aa4fe1..2aac71fb 100644 --- a/src/config_moveonenospc.hpp +++ b/src/config_moveonenospc.hpp @@ -19,26 +19,26 @@ #pragma once #include "policy.hpp" +#include "policies.hpp" #include "tofrom_string.hpp" #include + class MoveOnENOSPC : public ToFromString { public: MoveOnENOSPC(const bool enabled_) - : enabled(enabled_) + : enabled(enabled_), + policy(&Policies::Create::mfs) { - policy = (enabled ? - &Policy::mfs : - &Policy::invalid); } public: - int from_string(const std::string &s); - std::string to_string() const; + int from_string(const std::string &s) final; + std::string to_string() const final; public: bool enabled; - const Policy *policy; + Policy::Create policy; }; diff --git a/src/config_nfsopenhack.cpp b/src/config_nfsopenhack.cpp index 81c9b169..55cad062 100644 --- a/src/config_nfsopenhack.cpp +++ b/src/config_nfsopenhack.cpp @@ -20,6 +20,7 @@ #include "ef.hpp" #include "errno.hpp" + template<> int NFSOpenHack::from_string(const std::string &s_) diff --git a/src/config_nfsopenhack.hpp b/src/config_nfsopenhack.hpp index e6a3e797..0e54b482 100644 --- a/src/config_nfsopenhack.hpp +++ b/src/config_nfsopenhack.hpp @@ -20,6 +20,7 @@ #include "enum.hpp" + enum class NFSOpenHackEnum { OFF, diff --git a/src/config_readdir.cpp b/src/config_readdir.cpp index b0dd07bd..f03b2a77 100644 --- a/src/config_readdir.cpp +++ b/src/config_readdir.cpp @@ -20,6 +20,7 @@ #include "ef.hpp" #include "errno.hpp" + template<> int ReadDir::from_string(const std::string &s_) diff --git a/src/config_readdir.hpp b/src/config_readdir.hpp index fe041d87..96767f20 100644 --- a/src/config_readdir.hpp +++ b/src/config_readdir.hpp @@ -20,6 +20,7 @@ #include "enum.hpp" + enum class ReadDirEnum { POSIX, diff --git a/src/config_statfs.cpp b/src/config_statfs.cpp index 07642786..50910367 100644 --- a/src/config_statfs.cpp +++ b/src/config_statfs.cpp @@ -20,6 +20,7 @@ #include "ef.hpp" #include "errno.hpp" + template<> std::string StatFS::to_string() const diff --git a/src/config_statfs.hpp b/src/config_statfs.hpp index f217371b..0d408aeb 100644 --- a/src/config_statfs.hpp +++ b/src/config_statfs.hpp @@ -20,6 +20,7 @@ #include "enum.hpp" + enum class StatFSEnum { BASE, diff --git a/src/config_statfsignore.cpp b/src/config_statfsignore.cpp index e3355053..14b5ded3 100644 --- a/src/config_statfsignore.cpp +++ b/src/config_statfsignore.cpp @@ -20,6 +20,7 @@ #include "ef.hpp" #include "errno.hpp" + template<> std::string StatFSIgnore::to_string() const diff --git a/src/config_xattr.cpp b/src/config_xattr.cpp index 8b243c0f..bb626f22 100644 --- a/src/config_xattr.cpp +++ b/src/config_xattr.cpp @@ -20,6 +20,7 @@ #include "ef.hpp" #include "errno.hpp" + template<> std::string XAttr::to_string() const diff --git a/src/config_xattr.hpp b/src/config_xattr.hpp index c9eac263..34329fa4 100644 --- a/src/config_xattr.hpp +++ b/src/config_xattr.hpp @@ -21,6 +21,7 @@ #include "enum.hpp" #include "errno.hpp" + enum class XAttrEnum { PASSTHROUGH = 0, diff --git a/src/dirinfo.hpp b/src/dirinfo.hpp index 37ee6d3b..7048fbf4 100644 --- a/src/dirinfo.hpp +++ b/src/dirinfo.hpp @@ -20,6 +20,7 @@ #include + class DirInfo : public FH { public: diff --git a/src/endian.hpp b/src/endian.hpp index d294dba8..d5454994 100644 --- a/src/endian.hpp +++ b/src/endian.hpp @@ -18,6 +18,7 @@ #pragma once + namespace endian { static diff --git a/src/enum.hpp b/src/enum.hpp index 6f0dd35a..848ffca8 100644 --- a/src/enum.hpp +++ b/src/enum.hpp @@ -22,6 +22,7 @@ #include + template class Enum : public ToFromString { diff --git a/src/fh.hpp b/src/fh.hpp index 2060e2a5..4187b7f5 100644 --- a/src/fh.hpp +++ b/src/fh.hpp @@ -18,6 +18,7 @@ #include + class FH { public: diff --git a/src/fileinfo.hpp b/src/fileinfo.hpp index a3ca65b1..4d4948e4 100644 --- a/src/fileinfo.hpp +++ b/src/fileinfo.hpp @@ -20,6 +20,7 @@ #include + class FileInfo : public FH { public: diff --git a/src/fixed_mem_pool.hpp b/src/fixed_mem_pool.hpp index e81f1343..2f012b17 100644 --- a/src/fixed_mem_pool.hpp +++ b/src/fixed_mem_pool.hpp @@ -18,8 +18,10 @@ #pragma once +#include + #include -#include + typedef struct fixed_mem_pool_t fixed_mem_pool_t; struct fixed_mem_pool_t diff --git a/src/from_string.cpp b/src/from_string.cpp index 796f9256..638c8772 100644 --- a/src/from_string.cpp +++ b/src/from_string.cpp @@ -17,13 +17,14 @@ */ #include "ef.hpp" +#include "errno.hpp" +#include #include -#include -#include #include + namespace str { int @@ -50,7 +51,17 @@ namespace str from(const std::string &value_, int *int_) { - *int_ = ::strtol(value_.c_str(),NULL,10); + int tmp; + char *endptr; + + errno = 0; + tmp = ::strtol(value_.c_str(),&endptr,10); + if(errno != 0) + return -EINVAL; + if(endptr == value_.c_str()) + return -EINVAL; + + *int_ = tmp; return 0; } diff --git a/src/from_string.hpp b/src/from_string.hpp index 3c06884c..018bc2b7 100644 --- a/src/from_string.hpp +++ b/src/from_string.hpp @@ -18,9 +18,9 @@ #pragma once +#include #include -#include namespace str { diff --git a/src/fs_acl.cpp b/src/fs_acl.cpp index 148f21dc..3737bc16 100644 --- a/src/fs_acl.cpp +++ b/src/fs_acl.cpp @@ -23,6 +23,7 @@ const char POSIX_ACL_DEFAULT_XATTR[] = "system.posix_acl_default"; + namespace fs { namespace acl diff --git a/src/fs_acl.hpp b/src/fs_acl.hpp index f3b16e43..92fef84b 100644 --- a/src/fs_acl.hpp +++ b/src/fs_acl.hpp @@ -20,6 +20,7 @@ #include + namespace fs { namespace acl diff --git a/src/fs_attr.hpp b/src/fs_attr.hpp index c9bee84e..96d9944b 100644 --- a/src/fs_attr.hpp +++ b/src/fs_attr.hpp @@ -18,6 +18,7 @@ #include + namespace fs { namespace attr diff --git a/src/fs_attr_linux.icpp b/src/fs_attr_linux.icpp index 8d346190..abae1e5e 100644 --- a/src/fs_attr_linux.icpp +++ b/src/fs_attr_linux.icpp @@ -26,6 +26,7 @@ using std::string; + namespace fs { namespace attr diff --git a/src/fs_attr_unsupported.icpp b/src/fs_attr_unsupported.icpp index 852038fc..4a5c37bb 100644 --- a/src/fs_attr_unsupported.icpp +++ b/src/fs_attr_unsupported.icpp @@ -18,6 +18,7 @@ #include + namespace fs { namespace attr diff --git a/src/fs_clonefile.cpp b/src/fs_clonefile.cpp index 6dabde05..69d94c04 100644 --- a/src/fs_clonefile.cpp +++ b/src/fs_clonefile.cpp @@ -22,6 +22,7 @@ #include "fs_fchmod.hpp" #include "fs_futimens.hpp" + namespace l { static diff --git a/src/fs_clonefile.hpp b/src/fs_clonefile.hpp index a9835e57..67eeca33 100644 --- a/src/fs_clonefile.hpp +++ b/src/fs_clonefile.hpp @@ -16,6 +16,7 @@ #pragma once + namespace fs { int diff --git a/src/fs_clonepath.cpp b/src/fs_clonepath.cpp index 9e42946a..4fec3ae7 100644 --- a/src/fs_clonepath.cpp +++ b/src/fs_clonepath.cpp @@ -14,8 +14,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - #include "errno.h" #include "fs_attr.hpp" #include "fs_clonepath.hpp" @@ -27,8 +25,11 @@ #include "fs_xattr.hpp" #include "ugid.hpp" +#include + using std::string; + namespace l { static diff --git a/src/fs_clonepath.hpp b/src/fs_clonepath.hpp index 34904d0c..8ad68c97 100644 --- a/src/fs_clonepath.hpp +++ b/src/fs_clonepath.hpp @@ -18,6 +18,7 @@ #include + namespace fs { int clonepath(const std::string &from, diff --git a/src/fs_close.hpp b/src/fs_close.hpp index 236d290d..646482fa 100644 --- a/src/fs_close.hpp +++ b/src/fs_close.hpp @@ -20,6 +20,7 @@ #include + namespace fs { static diff --git a/src/fs_closedir.hpp b/src/fs_closedir.hpp index 03ae8785..f7fc081f 100644 --- a/src/fs_closedir.hpp +++ b/src/fs_closedir.hpp @@ -21,6 +21,7 @@ #include #include + namespace fs { static diff --git a/src/fs_copy_file_range.hpp b/src/fs_copy_file_range.hpp index aab5fc9e..5ffdc656 100644 --- a/src/fs_copy_file_range.hpp +++ b/src/fs_copy_file_range.hpp @@ -18,10 +18,12 @@ #pragma once +#include + #include -#include #include + namespace fs { int64_t diff --git a/src/fs_copy_file_range_linux.icpp b/src/fs_copy_file_range_linux.icpp index 7df4f845..79103443 100644 --- a/src/fs_copy_file_range_linux.icpp +++ b/src/fs_copy_file_range_linux.icpp @@ -22,13 +22,15 @@ #include "errno.hpp" +#include + #include -#include #include #include #include #include + namespace l { static diff --git a/src/fs_copy_file_range_unsupported.icpp b/src/fs_copy_file_range_unsupported.icpp index c0e87fc8..2e87ecb7 100644 --- a/src/fs_copy_file_range_unsupported.icpp +++ b/src/fs_copy_file_range_unsupported.icpp @@ -18,10 +18,12 @@ #include "errno.h" +#include + #include -#include #include + namespace fs { ssize_t diff --git a/src/fs_copydata.cpp b/src/fs_copydata.cpp index 979b31b7..fee8821a 100644 --- a/src/fs_copydata.cpp +++ b/src/fs_copydata.cpp @@ -24,6 +24,7 @@ #include + namespace fs { int diff --git a/src/fs_copydata.hpp b/src/fs_copydata.hpp index 48e0784d..4347bcb6 100644 --- a/src/fs_copydata.hpp +++ b/src/fs_copydata.hpp @@ -20,6 +20,7 @@ #include + namespace fs { int diff --git a/src/fs_copydata_copy_file_range.cpp b/src/fs_copydata_copy_file_range.cpp index f8e7c388..5722750b 100644 --- a/src/fs_copydata_copy_file_range.cpp +++ b/src/fs_copydata_copy_file_range.cpp @@ -18,7 +18,8 @@ #include "fs_copy_file_range.hpp" #include "fs_fstat.hpp" -#include +#include + namespace l { diff --git a/src/fs_copydata_copy_file_range.hpp b/src/fs_copydata_copy_file_range.hpp index 6b0f7567..b22f53ec 100644 --- a/src/fs_copydata_copy_file_range.hpp +++ b/src/fs_copydata_copy_file_range.hpp @@ -16,7 +16,8 @@ #pragma once -#include +#include + namespace fs { diff --git a/src/fs_copydata_readwrite.cpp b/src/fs_copydata_readwrite.cpp index c119585d..e2c48795 100644 --- a/src/fs_copydata_readwrite.cpp +++ b/src/fs_copydata_readwrite.cpp @@ -24,6 +24,7 @@ using std::vector; + namespace l { static diff --git a/src/fs_copydata_readwrite.hpp b/src/fs_copydata_readwrite.hpp index 9e900d03..43271165 100644 --- a/src/fs_copydata_readwrite.hpp +++ b/src/fs_copydata_readwrite.hpp @@ -16,6 +16,7 @@ #pragma once + namespace fs { int diff --git a/src/fs_cow.cpp b/src/fs_cow.cpp index 63379fe5..37855329 100644 --- a/src/fs_cow.cpp +++ b/src/fs_cow.cpp @@ -34,6 +34,7 @@ using std::string; + namespace l { static diff --git a/src/fs_cow.hpp b/src/fs_cow.hpp index 5cb9353d..7403e5d9 100644 --- a/src/fs_cow.hpp +++ b/src/fs_cow.hpp @@ -21,6 +21,7 @@ #include #include + namespace fs { namespace cow diff --git a/src/fs_devid.hpp b/src/fs_devid.hpp index 2f9bde05..d75bcf3e 100644 --- a/src/fs_devid.hpp +++ b/src/fs_devid.hpp @@ -20,6 +20,7 @@ #include "fs_fstat.hpp" + namespace fs { static diff --git a/src/fs_dirfd.hpp b/src/fs_dirfd.hpp index d4afa76e..767d6685 100644 --- a/src/fs_dirfd.hpp +++ b/src/fs_dirfd.hpp @@ -21,6 +21,7 @@ #include #include + namespace fs { static diff --git a/src/fs_dup.hpp b/src/fs_dup.hpp index fc1dd106..fdb82c66 100644 --- a/src/fs_dup.hpp +++ b/src/fs_dup.hpp @@ -20,6 +20,7 @@ #include + namespace fs { static diff --git a/src/fs_eaccess.hpp b/src/fs_eaccess.hpp index f661566a..03f55287 100644 --- a/src/fs_eaccess.hpp +++ b/src/fs_eaccess.hpp @@ -20,6 +20,7 @@ #include "fs_faccessat.hpp" + namespace fs { static diff --git a/src/fs_exists.hpp b/src/fs_exists.hpp index 808bc8b1..2abdd646 100644 --- a/src/fs_exists.hpp +++ b/src/fs_exists.hpp @@ -23,6 +23,7 @@ #include + namespace fs { static diff --git a/src/fs_faccessat.hpp b/src/fs_faccessat.hpp index 02729b87..80329f47 100644 --- a/src/fs_faccessat.hpp +++ b/src/fs_faccessat.hpp @@ -23,6 +23,7 @@ #include #include + namespace fs { static diff --git a/src/fs_fadvise.hpp b/src/fs_fadvise.hpp index 96fa8360..e1126228 100644 --- a/src/fs_fadvise.hpp +++ b/src/fs_fadvise.hpp @@ -18,6 +18,7 @@ #include + namespace fs { int diff --git a/src/fs_fadvise_posix.icpp b/src/fs_fadvise_posix.icpp index a51e5de5..15bc8601 100644 --- a/src/fs_fadvise_posix.icpp +++ b/src/fs_fadvise_posix.icpp @@ -16,6 +16,7 @@ #include + namespace fs { static diff --git a/src/fs_fadvise_unsupported.icpp b/src/fs_fadvise_unsupported.icpp index b25aebcb..40617b01 100644 --- a/src/fs_fadvise_unsupported.icpp +++ b/src/fs_fadvise_unsupported.icpp @@ -16,6 +16,7 @@ #include "errno.hpp" + namespace fs { static diff --git a/src/fs_fallocate.hpp b/src/fs_fallocate.hpp index d6691472..74d33feb 100644 --- a/src/fs_fallocate.hpp +++ b/src/fs_fallocate.hpp @@ -18,6 +18,7 @@ #include + namespace fs { int diff --git a/src/fs_fallocate_linux.icpp b/src/fs_fallocate_linux.icpp index ae274eeb..f3eb2821 100644 --- a/src/fs_fallocate_linux.icpp +++ b/src/fs_fallocate_linux.icpp @@ -16,6 +16,7 @@ #include + namespace fs { int diff --git a/src/fs_fallocate_osx.icpp b/src/fs_fallocate_osx.icpp index d98c2795..746d7fb4 100644 --- a/src/fs_fallocate_osx.icpp +++ b/src/fs_fallocate_osx.icpp @@ -14,10 +14,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "errno.hpp" + #include #include -#include "errno.hpp" namespace l { diff --git a/src/fs_fallocate_posix.icpp b/src/fs_fallocate_posix.icpp index 17f99e95..bbd2678c 100644 --- a/src/fs_fallocate_posix.icpp +++ b/src/fs_fallocate_posix.icpp @@ -18,6 +18,7 @@ #include + namespace fs { int diff --git a/src/fs_fallocate_unsupported.icpp b/src/fs_fallocate_unsupported.icpp index 9c913e84..c4211986 100644 --- a/src/fs_fallocate_unsupported.icpp +++ b/src/fs_fallocate_unsupported.icpp @@ -16,6 +16,7 @@ #include "errno.hpp" + namespace fs { int diff --git a/src/fs_fchmod.hpp b/src/fs_fchmod.hpp index 5300d43d..5d8c8195 100644 --- a/src/fs_fchmod.hpp +++ b/src/fs_fchmod.hpp @@ -24,6 +24,7 @@ #define MODE_BITS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) + namespace fs { static diff --git a/src/fs_fchmodat.hpp b/src/fs_fchmodat.hpp index 209efbc6..e6e5ec9d 100644 --- a/src/fs_fchmodat.hpp +++ b/src/fs_fchmodat.hpp @@ -23,6 +23,7 @@ #include #include + namespace fs { static diff --git a/src/fs_fchown.hpp b/src/fs_fchown.hpp index 1b879e07..f8d92561 100644 --- a/src/fs_fchown.hpp +++ b/src/fs_fchown.hpp @@ -25,6 +25,7 @@ #include #include + namespace fs { static diff --git a/src/fs_fdatasync.hpp b/src/fs_fdatasync.hpp index 7b7fa72f..ac6183c1 100644 --- a/src/fs_fdatasync.hpp +++ b/src/fs_fdatasync.hpp @@ -26,6 +26,7 @@ #include + namespace fs { static diff --git a/src/fs_fgetxattr.hpp b/src/fs_fgetxattr.hpp index 57541eb0..7530d5d6 100644 --- a/src/fs_fgetxattr.hpp +++ b/src/fs_fgetxattr.hpp @@ -25,6 +25,7 @@ #include + namespace fs { static diff --git a/src/fs_ficlone.hpp b/src/fs_ficlone.hpp index 6900a82b..fd046c64 100644 --- a/src/fs_ficlone.hpp +++ b/src/fs_ficlone.hpp @@ -18,6 +18,7 @@ #pragma once + namespace fs { int diff --git a/src/fs_ficlone_linux.icpp b/src/fs_ficlone_linux.icpp index a36196fd..f0ce01bd 100644 --- a/src/fs_ficlone_linux.icpp +++ b/src/fs_ficlone_linux.icpp @@ -21,6 +21,7 @@ #include + namespace fs { int diff --git a/src/fs_ficlone_unsupported.icpp b/src/fs_ficlone_unsupported.icpp index aa6c4f0f..e7b864f5 100644 --- a/src/fs_ficlone_unsupported.icpp +++ b/src/fs_ficlone_unsupported.icpp @@ -18,6 +18,7 @@ #include "errno.hpp" + namespace fs { int diff --git a/src/fs_file_size.cpp b/src/fs_file_size.cpp index d06b7007..5528dbe1 100644 --- a/src/fs_file_size.cpp +++ b/src/fs_file_size.cpp @@ -18,7 +18,8 @@ #include "fs_fstat.hpp" -#include +#include + namespace fs { diff --git a/src/fs_file_size.hpp b/src/fs_file_size.hpp index 4977663e..1b01ea31 100644 --- a/src/fs_file_size.hpp +++ b/src/fs_file_size.hpp @@ -18,7 +18,8 @@ #pragma once -#include +#include + namespace fs { diff --git a/src/fs_findallfiles.cpp b/src/fs_findallfiles.cpp index a7a60d42..fc15f445 100644 --- a/src/fs_findallfiles.cpp +++ b/src/fs_findallfiles.cpp @@ -22,6 +22,7 @@ #include #include + namespace fs { void diff --git a/src/fs_findallfiles.hpp b/src/fs_findallfiles.hpp index ff3d81ed..db3e5895 100644 --- a/src/fs_findallfiles.hpp +++ b/src/fs_findallfiles.hpp @@ -18,13 +18,16 @@ #pragma once +#include "strvec.hpp" + #include #include + namespace fs { void - findallfiles(const std::vector &basepaths, - const char *fusepath, - std::vector *paths); + findallfiles(const StrVec &basepaths, + const char *fusepath, + StrVec *paths); } diff --git a/src/fs_findonfs.cpp b/src/fs_findonfs.cpp index e52c7333..ec8b2dc1 100644 --- a/src/fs_findonfs.cpp +++ b/src/fs_findonfs.cpp @@ -16,7 +16,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "branch.hpp" +#include "branches.hpp" #include "errno.hpp" #include "fs_fstat.hpp" #include "fs_lstat.hpp" @@ -24,31 +24,29 @@ #include + namespace l { static int - findonfs(const BranchVec &branches_, - const std::string &fusepath_, - const int fd_, - std::string *basepath_) + findonfs(const Branches::CPtr &branches_, + const std::string &fusepath_, + const int fd_, + std::string *basepath_) { int rv; dev_t dev; struct stat st; std::string fullpath; - const Branch *branch; rv = fs::fstat(fd_,&st); if(rv == -1) return -1; dev = st.st_dev; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(const auto &branch : *branches_) { - branch = &branches_[i]; - - fullpath = fs::path::make(branch->path,fusepath_); + fullpath = fs::path::make(branch.path,fusepath_); rv = fs::lstat(fullpath,&st); if(rv == -1) @@ -57,7 +55,7 @@ namespace l if(st.st_dev != dev) continue; - *basepath_ = branch->path; + *basepath_ = branch.path; return 0; } @@ -69,13 +67,11 @@ namespace l namespace fs { int - findonfs(const Branches &branches_, - const std::string &fusepath_, - const int fd_, - std::string *basepath_) + findonfs(const Branches::CPtr &branches_, + const std::string &fusepath_, + const int fd_, + std::string *basepath_) { - rwlock::ReadGuard guard(branches_.lock); - - return l::findonfs(branches_.vec,fusepath_,fd_,basepath_); + return l::findonfs(branches_,fusepath_,fd_,basepath_); } } diff --git a/src/fs_findonfs.hpp b/src/fs_findonfs.hpp index 3a72fd26..af7441a9 100644 --- a/src/fs_findonfs.hpp +++ b/src/fs_findonfs.hpp @@ -18,15 +18,16 @@ #pragma once -#include "branch.hpp" +#include "branches.hpp" #include + namespace fs { int - findonfs(const Branches &branches, - const std::string &fusepath, - const int fd, - std::string *basepath); + findonfs(const Branches::CPtr &branches, + const std::string &fusepath, + const int fd, + std::string *basepath); } diff --git a/src/fs_flistxattr.hpp b/src/fs_flistxattr.hpp index cbfa3425..1a9f6ae8 100644 --- a/src/fs_flistxattr.hpp +++ b/src/fs_flistxattr.hpp @@ -23,6 +23,7 @@ #include + namespace fs { static diff --git a/src/fs_flock.hpp b/src/fs_flock.hpp index 1cee9c6d..a6fd59f8 100644 --- a/src/fs_flock.hpp +++ b/src/fs_flock.hpp @@ -20,6 +20,7 @@ #include + namespace fs { static diff --git a/src/fs_fsetxattr.hpp b/src/fs_fsetxattr.hpp index d2cfb023..c2f2e129 100644 --- a/src/fs_fsetxattr.hpp +++ b/src/fs_fsetxattr.hpp @@ -25,6 +25,7 @@ #include + namespace fs { static diff --git a/src/fs_fstat.hpp b/src/fs_fstat.hpp index 233d72fb..702b1030 100644 --- a/src/fs_fstat.hpp +++ b/src/fs_fstat.hpp @@ -23,6 +23,7 @@ #include #include + namespace fs { static diff --git a/src/fs_fstatat.hpp b/src/fs_fstatat.hpp index 6148d9d5..cfada9fb 100644 --- a/src/fs_fstatat.hpp +++ b/src/fs_fstatat.hpp @@ -23,6 +23,7 @@ #include #include + namespace fs { static diff --git a/src/fs_fsync.hpp b/src/fs_fsync.hpp index c91e0181..91374487 100644 --- a/src/fs_fsync.hpp +++ b/src/fs_fsync.hpp @@ -20,6 +20,7 @@ #include + namespace fs { static diff --git a/src/fs_ftruncate.hpp b/src/fs_ftruncate.hpp index 0244bd2d..ec2c17a3 100644 --- a/src/fs_ftruncate.hpp +++ b/src/fs_ftruncate.hpp @@ -21,6 +21,7 @@ #include #include + namespace fs { static diff --git a/src/fs_futimens.hpp b/src/fs_futimens.hpp index 9f223303..2e4b8874 100644 --- a/src/fs_futimens.hpp +++ b/src/fs_futimens.hpp @@ -33,6 +33,7 @@ #include "fs_futimens_generic.hpp" #endif + namespace fs { static diff --git a/src/fs_futimens_freebsd_11.hpp b/src/fs_futimens_freebsd_11.hpp index 745bedee..d3e25247 100644 --- a/src/fs_futimens_freebsd_11.hpp +++ b/src/fs_futimens_freebsd_11.hpp @@ -20,6 +20,7 @@ #include + namespace fs { static diff --git a/src/fs_futimens_generic.hpp b/src/fs_futimens_generic.hpp index d6124151..ead03dc8 100644 --- a/src/fs_futimens_generic.hpp +++ b/src/fs_futimens_generic.hpp @@ -33,6 +33,7 @@ # define UTIME_OMIT ((1l << 30) - 2l) #endif + namespace l { static diff --git a/src/fs_futimens_linux.hpp b/src/fs_futimens_linux.hpp index 745bedee..d3e25247 100644 --- a/src/fs_futimens_linux.hpp +++ b/src/fs_futimens_linux.hpp @@ -20,6 +20,7 @@ #include + namespace fs { static diff --git a/src/fs_futimesat.hpp b/src/fs_futimesat.hpp index d18c44c4..f5a34d64 100644 --- a/src/fs_futimesat.hpp +++ b/src/fs_futimesat.hpp @@ -20,6 +20,7 @@ #include + namespace fs { int diff --git a/src/fs_futimesat_generic.icpp b/src/fs_futimesat_generic.icpp index 4f2b2134..acf49095 100644 --- a/src/fs_futimesat_generic.icpp +++ b/src/fs_futimesat_generic.icpp @@ -19,6 +19,7 @@ #include #include + namespace fs { int diff --git a/src/fs_futimesat_osx.icpp b/src/fs_futimesat_osx.icpp index e00c4ddd..b96b4623 100644 --- a/src/fs_futimesat_osx.icpp +++ b/src/fs_futimesat_osx.icpp @@ -26,6 +26,7 @@ #include #include + namespace l { static diff --git a/src/fs_getdents64.cpp b/src/fs_getdents64.cpp index a955fa12..0015cc07 100644 --- a/src/fs_getdents64.cpp +++ b/src/fs_getdents64.cpp @@ -23,6 +23,7 @@ #include #endif + namespace fs { int diff --git a/src/fs_getdents64.hpp b/src/fs_getdents64.hpp index e1c12d6a..f328c431 100644 --- a/src/fs_getdents64.hpp +++ b/src/fs_getdents64.hpp @@ -18,6 +18,7 @@ #pragma once + namespace fs { int diff --git a/src/fs_getfl.cpp b/src/fs_getfl.cpp index 891561db..f84676a6 100644 --- a/src/fs_getfl.cpp +++ b/src/fs_getfl.cpp @@ -18,6 +18,7 @@ #include + namespace fs { int diff --git a/src/fs_getfl.hpp b/src/fs_getfl.hpp index ddb30034..0abb3e20 100644 --- a/src/fs_getfl.hpp +++ b/src/fs_getfl.hpp @@ -18,6 +18,7 @@ #pragma once + namespace fs { int getfl(const int fd); diff --git a/src/fs_glob.cpp b/src/fs_glob.cpp index 02efe6c5..fb7177dd 100644 --- a/src/fs_glob.cpp +++ b/src/fs_glob.cpp @@ -14,16 +14,16 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - #include +#include #include #include using std::string; using std::vector; + namespace fs { void diff --git a/src/fs_glob.hpp b/src/fs_glob.hpp index ed16c95c..9d2b3b06 100644 --- a/src/fs_glob.hpp +++ b/src/fs_glob.hpp @@ -19,6 +19,7 @@ #include #include + namespace fs { void diff --git a/src/fs_has_space.cpp b/src/fs_has_space.cpp index f41ee8b5..3ce5bc18 100644 --- a/src/fs_has_space.cpp +++ b/src/fs_has_space.cpp @@ -19,9 +19,9 @@ #include "fs_statvfs.hpp" #include "statvfs_util.hpp" +#include #include -#include namespace fs { diff --git a/src/fs_has_space.hpp b/src/fs_has_space.hpp index ed4c5c79..64aa7825 100644 --- a/src/fs_has_space.hpp +++ b/src/fs_has_space.hpp @@ -18,9 +18,9 @@ #pragma once +#include #include -#include namespace fs { diff --git a/src/fs_info.cpp b/src/fs_info.cpp index e36d41f7..6368036e 100644 --- a/src/fs_info.cpp +++ b/src/fs_info.cpp @@ -23,12 +23,12 @@ #include "fs_statvfs_cache.hpp" #include "statvfs_util.hpp" -#include - +#include #include using std::string; + namespace fs { int diff --git a/src/fs_info.hpp b/src/fs_info.hpp index cc8639a3..ec7cf30d 100644 --- a/src/fs_info.hpp +++ b/src/fs_info.hpp @@ -22,6 +22,7 @@ #include + namespace fs { int diff --git a/src/fs_info_t.hpp b/src/fs_info_t.hpp index 623617d7..7db05d74 100644 --- a/src/fs_info_t.hpp +++ b/src/fs_info_t.hpp @@ -18,7 +18,8 @@ #pragma once -#include +#include + namespace fs { diff --git a/src/fs_inode.cpp b/src/fs_inode.cpp index 20256940..b0330c77 100644 --- a/src/fs_inode.cpp +++ b/src/fs_inode.cpp @@ -21,10 +21,10 @@ #include "fs_inode.hpp" #include "wyhash.h" +#include #include #include -#include #include #include @@ -184,10 +184,16 @@ namespace fs return "passthrough"; if(g_func == path_hash) return "path-hash"; + if(g_func == path_hash32) + return "path-hash32"; if(g_func == devino_hash) return "devino-hash"; + if(g_func == devino_hash32) + return "devino-hash32"; if(g_func == hybrid_hash) return "hybrid-hash"; + if(g_func == hybrid_hash32) + return "hybrid-hash32"; return std::string(); } diff --git a/src/fs_inode.hpp b/src/fs_inode.hpp index a7e0fb76..baf7d718 100644 --- a/src/fs_inode.hpp +++ b/src/fs_inode.hpp @@ -18,9 +18,9 @@ #pragma once +#include #include -#include #include diff --git a/src/fs_ioctl.hpp b/src/fs_ioctl.hpp index cdb74e2b..86ee9bdf 100644 --- a/src/fs_ioctl.hpp +++ b/src/fs_ioctl.hpp @@ -20,6 +20,7 @@ #include + namespace fs { static diff --git a/src/fs_lchmod.hpp b/src/fs_lchmod.hpp index 21c94500..95012ab0 100644 --- a/src/fs_lchmod.hpp +++ b/src/fs_lchmod.hpp @@ -26,6 +26,7 @@ #define MODE_BITS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) + namespace fs { static diff --git a/src/fs_lchown.hpp b/src/fs_lchown.hpp index 83fa30d8..6091a269 100644 --- a/src/fs_lchown.hpp +++ b/src/fs_lchown.hpp @@ -22,6 +22,7 @@ #include + namespace fs { static diff --git a/src/fs_lgetxattr.hpp b/src/fs_lgetxattr.hpp index 482fa35c..7d4fe8e1 100644 --- a/src/fs_lgetxattr.hpp +++ b/src/fs_lgetxattr.hpp @@ -25,6 +25,7 @@ #include + namespace fs { static diff --git a/src/fs_link.hpp b/src/fs_link.hpp index 09ef6459..8b41d4a2 100644 --- a/src/fs_link.hpp +++ b/src/fs_link.hpp @@ -22,6 +22,7 @@ #include + namespace fs { static diff --git a/src/fs_llistxattr.hpp b/src/fs_llistxattr.hpp index e8c83dc4..9818a665 100644 --- a/src/fs_llistxattr.hpp +++ b/src/fs_llistxattr.hpp @@ -25,6 +25,7 @@ #include + namespace fs { static diff --git a/src/fs_lremovexattr.hpp b/src/fs_lremovexattr.hpp index 4d9f3f53..06258f9d 100644 --- a/src/fs_lremovexattr.hpp +++ b/src/fs_lremovexattr.hpp @@ -23,6 +23,7 @@ #include + namespace fs { static diff --git a/src/fs_lseek.hpp b/src/fs_lseek.hpp index 34744c49..79bcfe3b 100644 --- a/src/fs_lseek.hpp +++ b/src/fs_lseek.hpp @@ -21,6 +21,7 @@ #include #include + namespace fs { static diff --git a/src/fs_lsetxattr.hpp b/src/fs_lsetxattr.hpp index 41baf862..ba3a7325 100644 --- a/src/fs_lsetxattr.hpp +++ b/src/fs_lsetxattr.hpp @@ -25,6 +25,7 @@ #include + namespace fs { static diff --git a/src/fs_lstat.hpp b/src/fs_lstat.hpp index 83254b83..dd8e8384 100644 --- a/src/fs_lstat.hpp +++ b/src/fs_lstat.hpp @@ -24,6 +24,7 @@ #include #include + namespace fs { static diff --git a/src/fs_lutimens.hpp b/src/fs_lutimens.hpp index ab1ce218..e2937a6d 100644 --- a/src/fs_lutimens.hpp +++ b/src/fs_lutimens.hpp @@ -21,6 +21,7 @@ #include "fs_utimensat.hpp" #include "fs_stat_utils.hpp" + namespace fs { static diff --git a/src/fs_mkdir.hpp b/src/fs_mkdir.hpp index 05eb78b5..8d55c595 100644 --- a/src/fs_mkdir.hpp +++ b/src/fs_mkdir.hpp @@ -23,6 +23,7 @@ #include #include + namespace fs { static diff --git a/src/fs_mknod.hpp b/src/fs_mknod.hpp index bf85f3b2..9bf80636 100644 --- a/src/fs_mknod.hpp +++ b/src/fs_mknod.hpp @@ -23,6 +23,7 @@ #include #include + namespace fs { static diff --git a/src/fs_mktemp.cpp b/src/fs_mktemp.cpp index 1f2166eb..bd4ea2cf 100644 --- a/src/fs_mktemp.cpp +++ b/src/fs_mktemp.cpp @@ -29,6 +29,7 @@ using std::string; #define PADLEN 6 #define MAX_ATTEMPTS 10 + static string generate_tmp_path(const string &base_) diff --git a/src/fs_mktemp.hpp b/src/fs_mktemp.hpp index 2bd19b16..aecf0e74 100644 --- a/src/fs_mktemp.hpp +++ b/src/fs_mktemp.hpp @@ -20,6 +20,7 @@ #include + namespace fs { int diff --git a/src/fs_movefile.cpp b/src/fs_movefile.cpp index 2c2c13e2..bd9c37b6 100644 --- a/src/fs_movefile.cpp +++ b/src/fs_movefile.cpp @@ -43,12 +43,13 @@ using std::string; using std::vector; + namespace l { static int - movefile(Policy::Func::Create createFunc_, - const Branches &branches_, + movefile(const Policy::Create &createFunc_, + const Branches::CPtr &branches_, const string &fusepath_, int *origfd_) { @@ -132,19 +133,19 @@ namespace l namespace fs { int - movefile(const Policy *policy_, - const Branches &basepaths_, - const string &fusepath_, - int *origfd_) + movefile(const Policy::Create &policy_, + const Branches::CPtr &basepaths_, + const string &fusepath_, + int *origfd_) { return l::movefile(policy_,basepaths_,fusepath_,origfd_); } int - movefile_as_root(const Policy *policy_, - const Branches &basepaths_, - const string &fusepath_, - int *origfd_) + movefile_as_root(const Policy::Create &policy_, + const Branches::CPtr &basepaths_, + const string &fusepath_, + int *origfd_) { const ugid::Set ugid(0,0); diff --git a/src/fs_movefile.hpp b/src/fs_movefile.hpp index 7b21312e..8df1e1c2 100644 --- a/src/fs_movefile.hpp +++ b/src/fs_movefile.hpp @@ -16,22 +16,23 @@ #pragma once -#include "branch.hpp" +#include "branches.hpp" #include "policy.hpp" #include + namespace fs { int - movefile(const Policy *policy, - const Branches &branches, - const std::string &fusepath, - int *origfd); + movefile(const Policy::Create &policy, + const Branches::CPtr &branches, + const std::string &fusepath, + int *origfd); int - movefile_as_root(const Policy *policy, - const Branches &branches, - const std::string &fusepath, - int *origfd); + movefile_as_root(const Policy::Create &policy, + const Branches::CPtr &branches, + const std::string &fusepath, + int *origfd); } diff --git a/src/fs_open.hpp b/src/fs_open.hpp index 2e4a7279..02364361 100644 --- a/src/fs_open.hpp +++ b/src/fs_open.hpp @@ -24,6 +24,7 @@ #include #include + namespace fs { static diff --git a/src/fs_opendir.hpp b/src/fs_opendir.hpp index 7b62aecf..a7f1197e 100644 --- a/src/fs_opendir.hpp +++ b/src/fs_opendir.hpp @@ -23,6 +23,7 @@ #include #include + namespace fs { static diff --git a/src/fs_path.cpp b/src/fs_path.cpp index 861973f3..90c65a5c 100644 --- a/src/fs_path.cpp +++ b/src/fs_path.cpp @@ -14,17 +14,18 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "fs_path.hpp" + +#include + #include #include #include #include -#include - -#include "fs_path.hpp" - using std::string; + namespace fs { namespace path diff --git a/src/fs_path.hpp b/src/fs_path.hpp index 531c21df..d36b8fd6 100644 --- a/src/fs_path.hpp +++ b/src/fs_path.hpp @@ -19,6 +19,7 @@ #include #include + namespace fs { namespace path diff --git a/src/fs_read.hpp b/src/fs_read.hpp index d794543e..c1021fe7 100644 --- a/src/fs_read.hpp +++ b/src/fs_read.hpp @@ -20,6 +20,7 @@ #include + namespace fs { static diff --git a/src/fs_readdir.hpp b/src/fs_readdir.hpp index 7a82d61e..cad0d643 100644 --- a/src/fs_readdir.hpp +++ b/src/fs_readdir.hpp @@ -20,6 +20,7 @@ #include + namespace fs { static diff --git a/src/fs_readlink.hpp b/src/fs_readlink.hpp index a8fc1a5b..0cd2df0f 100644 --- a/src/fs_readlink.hpp +++ b/src/fs_readlink.hpp @@ -22,6 +22,7 @@ #include + namespace fs { static diff --git a/src/fs_realpath.hpp b/src/fs_realpath.hpp index d31a270c..31c30316 100644 --- a/src/fs_realpath.hpp +++ b/src/fs_realpath.hpp @@ -23,6 +23,7 @@ #include #include + namespace fs { static diff --git a/src/fs_realpathize.cpp b/src/fs_realpathize.cpp index 42db33b6..fe85d2d2 100644 --- a/src/fs_realpathize.cpp +++ b/src/fs_realpathize.cpp @@ -21,6 +21,7 @@ #include #include + namespace fs { void diff --git a/src/fs_realpathize.hpp b/src/fs_realpathize.hpp index dfd6270d..0702097e 100644 --- a/src/fs_realpathize.hpp +++ b/src/fs_realpathize.hpp @@ -21,6 +21,7 @@ #include #include + namespace fs { void diff --git a/src/fs_remove.hpp b/src/fs_remove.hpp index 07ae25cc..b9d7f417 100644 --- a/src/fs_remove.hpp +++ b/src/fs_remove.hpp @@ -22,6 +22,7 @@ #include + namespace fs { static diff --git a/src/fs_rename.hpp b/src/fs_rename.hpp index 7bfdba7e..a0fe92b3 100644 --- a/src/fs_rename.hpp +++ b/src/fs_rename.hpp @@ -20,6 +20,7 @@ #include + namespace fs { static diff --git a/src/fs_rmdir.hpp b/src/fs_rmdir.hpp index d87a3f42..dd39a5b4 100644 --- a/src/fs_rmdir.hpp +++ b/src/fs_rmdir.hpp @@ -22,6 +22,7 @@ #include + namespace fs { static diff --git a/src/fs_sendfile.hpp b/src/fs_sendfile.hpp index 54238426..ae2fb017 100644 --- a/src/fs_sendfile.hpp +++ b/src/fs_sendfile.hpp @@ -16,6 +16,7 @@ #pragma once + namespace fs { ssize_t diff --git a/src/fs_sendfile_linux.icpp b/src/fs_sendfile_linux.icpp index a6291ddc..5f62c70a 100644 --- a/src/fs_sendfile_linux.icpp +++ b/src/fs_sendfile_linux.icpp @@ -14,9 +14,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "errno.hpp" + #include -#include "errno.hpp" namespace fs { diff --git a/src/fs_sendfile_unsupported.icpp b/src/fs_sendfile_unsupported.icpp index a08fc1a4..96a8827a 100644 --- a/src/fs_sendfile_unsupported.icpp +++ b/src/fs_sendfile_unsupported.icpp @@ -14,9 +14,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "errno.hpp" + #include -#include "errno.hpp" namespace fs { diff --git a/src/fs_setfl.cpp b/src/fs_setfl.cpp index faf1b2e4..7251c66b 100644 --- a/src/fs_setfl.cpp +++ b/src/fs_setfl.cpp @@ -18,6 +18,7 @@ #include + namespace fs { int diff --git a/src/fs_setfl.hpp b/src/fs_setfl.hpp index 9b146f10..31c07f71 100644 --- a/src/fs_setfl.hpp +++ b/src/fs_setfl.hpp @@ -20,6 +20,7 @@ #include + namespace fs { int diff --git a/src/fs_stat.hpp b/src/fs_stat.hpp index 5b5fed7c..b1c7c864 100644 --- a/src/fs_stat.hpp +++ b/src/fs_stat.hpp @@ -24,6 +24,7 @@ #include #include + namespace fs { static diff --git a/src/fs_stat_utils.hpp b/src/fs_stat_utils.hpp index 42f13dd8..777a7140 100644 --- a/src/fs_stat_utils.hpp +++ b/src/fs_stat_utils.hpp @@ -24,6 +24,7 @@ #include #include + namespace fs { static diff --git a/src/fs_statvfs.hpp b/src/fs_statvfs.hpp index 26f8a054..db0c1cf1 100644 --- a/src/fs_statvfs.hpp +++ b/src/fs_statvfs.hpp @@ -22,6 +22,7 @@ #include "fs_close.hpp" #include "fs_open.hpp" +#include #include #include @@ -30,6 +31,7 @@ # define O_PATH 0 #endif + namespace fs { static diff --git a/src/fs_statvfs_cache.cpp b/src/fs_statvfs_cache.cpp index 4cea84d0..a0c73192 100644 --- a/src/fs_statvfs_cache.cpp +++ b/src/fs_statvfs_cache.cpp @@ -19,14 +19,15 @@ #include "fs_statvfs.hpp" #include "statvfs_util.hpp" +#include #include #include #include -#include #include #include + struct Element { uint64_t time; diff --git a/src/fs_statvfs_cache.hpp b/src/fs_statvfs_cache.hpp index 1beb46f3..d48d075d 100644 --- a/src/fs_statvfs_cache.hpp +++ b/src/fs_statvfs_cache.hpp @@ -18,9 +18,11 @@ #pragma once -#include +#include + #include + namespace fs { uint64_t diff --git a/src/fs_symlink.hpp b/src/fs_symlink.hpp index 6fa9e535..1db1823e 100644 --- a/src/fs_symlink.hpp +++ b/src/fs_symlink.hpp @@ -22,6 +22,7 @@ #include + namespace fs { static diff --git a/src/fs_truncate.hpp b/src/fs_truncate.hpp index 512214cc..9a88ba60 100644 --- a/src/fs_truncate.hpp +++ b/src/fs_truncate.hpp @@ -23,6 +23,7 @@ #include #include + namespace fs { static diff --git a/src/fs_unlink.hpp b/src/fs_unlink.hpp index 08828595..5fad40d2 100644 --- a/src/fs_unlink.hpp +++ b/src/fs_unlink.hpp @@ -22,6 +22,7 @@ #include + namespace fs { static diff --git a/src/fs_utimensat_freebsd.hpp b/src/fs_utimensat_freebsd.hpp index ef3935ff..251c3f56 100644 --- a/src/fs_utimensat_freebsd.hpp +++ b/src/fs_utimensat_freebsd.hpp @@ -23,6 +23,7 @@ #include #include + namespace fs { static diff --git a/src/fs_utimensat_generic.hpp b/src/fs_utimensat_generic.hpp index 1834c0c3..2bd5bf26 100644 --- a/src/fs_utimensat_generic.hpp +++ b/src/fs_utimensat_generic.hpp @@ -36,6 +36,7 @@ # define UTIME_OMIT ((1l << 30) - 2l) #endif + namespace l { static diff --git a/src/fs_utimensat_linux.hpp b/src/fs_utimensat_linux.hpp index ef3935ff..251c3f56 100644 --- a/src/fs_utimensat_linux.hpp +++ b/src/fs_utimensat_linux.hpp @@ -23,6 +23,7 @@ #include #include + namespace fs { static diff --git a/src/fs_write.hpp b/src/fs_write.hpp index 96eebbb1..750bef03 100644 --- a/src/fs_write.hpp +++ b/src/fs_write.hpp @@ -20,6 +20,7 @@ #include + namespace fs { static diff --git a/src/fs_xattr.cpp b/src/fs_xattr.cpp index c73766d6..e7ac84a3 100644 --- a/src/fs_xattr.cpp +++ b/src/fs_xattr.cpp @@ -31,12 +31,12 @@ #include #include - using std::string; using std::vector; using std::map; using std::istringstream; + namespace fs { namespace xattr diff --git a/src/fs_xattr.hpp b/src/fs_xattr.hpp index caad0749..da7d2ba3 100644 --- a/src/fs_xattr.hpp +++ b/src/fs_xattr.hpp @@ -20,6 +20,7 @@ #include #include + namespace fs { namespace xattr diff --git a/src/func.cpp b/src/func.cpp index b82773ab..39aa7194 100644 --- a/src/func.cpp +++ b/src/func.cpp @@ -18,22 +18,45 @@ #include "func.hpp" + int -Func::from_string(const std::string &s_) +Func::Base::Action::from_string(const std::string &policyname_) +{ + policy = Policies::Action::find(policyname_); + + return 0; +} + +std::string +Func::Base::Action::to_string(void) const { - const Policy *tmp; + return policy.name(); +} - tmp = &Policy::find(s_); - if(tmp == Policy::invalid) - return -EINVAL; +int +Func::Base::Create::from_string(const std::string &policyname_) +{ + policy = Policies::Create::find(policyname_); - policy = tmp; + return 0; +} + +std::string +Func::Base::Create::to_string(void) const +{ + return policy.name(); +} + +int +Func::Base::Search::from_string(const std::string &policyname_) +{ + policy = Policies::Search::find(policyname_); return 0; } std::string -Func::to_string(void) const +Func::Base::Search::to_string(void) const { - return policy->to_string(); + return policy.name(); } diff --git a/src/func.hpp b/src/func.hpp index f1a390f3..97ef6f64 100644 --- a/src/func.hpp +++ b/src/func.hpp @@ -19,203 +19,166 @@ #pragma once #include "policy.hpp" +#include "policies.hpp" #include "tofrom_string.hpp" #include -#include -class Func : public ToFromString + +namespace Func { -public: - Func(const Policy &policy_) - : policy(&policy_) + namespace Base { - } + class Action : public ToFromString + { + public: + Action(Policy::ActionImpl *policy_) + : policy(policy_) + {} -public: - int from_string(const std::string &s); - std::string to_string() const; + public: + int from_string(const std::string &s) final; + std::string to_string() const final; -public: - const Policy *policy; -}; + public: + Policy::Action policy; + }; -class FuncAccess : public Func -{ -public: - FuncAccess() - : Func(Policy::ff) - { + class Create : public ToFromString + { + public: + Create(Policy::CreateImpl *policy_) + : policy(policy_) + {} + + public: + int from_string(const std::string &s) final; + std::string to_string() const final; + + public: + Policy::Create policy; + }; + + class Search : public ToFromString + { + public: + Search(Policy::SearchImpl *policy_) + : policy(policy_) + {} + + public: + int from_string(const std::string &s) final; + std::string to_string() const final; + + public: + Policy::Search policy; + }; + + class ActionDefault : public Action + { + public: + ActionDefault() + : Func::Base::Action(&Policies::Action::epall) + { + } + }; + + class CreateDefault : public Create + { + public: + CreateDefault() + : Func::Base::Create(&Policies::Create::epmfs) + { + } + }; + + class SearchDefault : public Search + { + public: + SearchDefault() + : Func::Base::Search(&Policies::Search::ff) + { + } + }; } -}; -class FuncChmod : public Func -{ -public: - FuncChmod() - : Func(Policy::epall) + class Access final : public Base::SearchDefault { - } -}; + }; -class FuncChown : public Func -{ -public: - FuncChown() - : Func(Policy::epall) + class Chmod final : public Base::ActionDefault { - } -}; + }; -class FuncCreate : public Func -{ -public: - FuncCreate() - : Func(Policy::epmfs) + class Chown final : public Base::ActionDefault { - } -}; + }; -class FuncGetAttr : public Func -{ -public: - FuncGetAttr() - : Func(Policy::ff) + class Create final : public Base::CreateDefault { - } -}; + }; -class FuncGetXAttr : public Func -{ -public: - FuncGetXAttr() - : Func(Policy::ff) + class GetAttr final : public Base::SearchDefault { - } -}; + }; -class FuncLink : public Func -{ -public: - FuncLink() - : Func(Policy::epall) + class GetXAttr final : public Base::SearchDefault { - } -}; + }; -class FuncListXAttr : public Func -{ -public: - FuncListXAttr() - : Func(Policy::ff) + class Link final : public Base::ActionDefault { - } -}; + }; -class FuncMkdir : public Func -{ -public: - FuncMkdir() - : Func(Policy::epmfs) + class ListXAttr final : public Base::SearchDefault { - } -}; + }; -class FuncMknod : public Func -{ -public: - FuncMknod() - : Func(Policy::epmfs) + class Mkdir final : public Base::CreateDefault { - } -}; + }; -class FuncOpen : public Func -{ -public: - FuncOpen() - : Func(Policy::ff) + class Mknod final : public Base::CreateDefault { - } -}; + }; -class FuncReadlink : public Func -{ -public: - FuncReadlink() - : Func(Policy::ff) + class Open final : public Base::SearchDefault { - } -}; + }; -class FuncRemoveXAttr : public Func -{ -public: - FuncRemoveXAttr() - : Func(Policy::epall) + class Readlink final : public Base::SearchDefault { - } -}; + }; -class FuncRename : public Func -{ -public: - FuncRename() - : Func(Policy::epall) + class RemoveXAttr final : public Base::ActionDefault { - } -}; + }; -class FuncRmdir : public Func -{ -public: - FuncRmdir() - : Func(Policy::epall) + class Rename final : public Base::ActionDefault { - } -}; + }; -class FuncSetXAttr : public Func -{ -public: - FuncSetXAttr() - : Func(Policy::epall) + class Rmdir final : public Base::ActionDefault { - } -}; + }; -class FuncSymlink : public Func -{ -public: - FuncSymlink() - : Func(Policy::epmfs) + class SetXAttr final : public Base::ActionDefault { - } -}; + }; -class FuncTruncate : public Func -{ -public: - FuncTruncate() - : Func(Policy::epall) + class Symlink final : public Base::CreateDefault { - } -}; + }; -class FuncUnlink : public Func -{ -public: - FuncUnlink() - : Func(Policy::epall) + class Truncate final : public Base::ActionDefault { - } -}; + }; -class FuncUtimens : public Func -{ -public: - FuncUtimens() - : Func(Policy::epall) + class Unlink final : public Base::ActionDefault { - } -}; + }; + + class Utimens final : public Base::ActionDefault + { + }; +} diff --git a/src/func_category.cpp b/src/func_category.cpp deleted file mode 100644 index eb60c9d3..00000000 --- a/src/func_category.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - 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 deleted file mode 100644 index 775239f5..00000000 --- a/src/func_category.hpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - 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 index a482b36e..dbb1eb8c 100644 --- a/src/funcs.hpp +++ b/src/funcs.hpp @@ -20,27 +20,27 @@ #include "func.hpp" -class Funcs + +struct 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; + Func::Access access; + Func::Chmod chmod; + Func::Chown chown; + Func::Create create; + Func::GetAttr getattr; + Func::GetXAttr getxattr; + Func::Link link; + Func::ListXAttr listxattr; + Func::Mkdir mkdir; + Func::Mknod mknod; + Func::Open open; + Func::Readlink readlink; + Func::RemoveXAttr removexattr; + Func::Rename rename; + Func::Rmdir rmdir; + Func::SetXAttr setxattr; + Func::Symlink symlink; + Func::Truncate truncate; + Func::Unlink unlink; + Func::Utimens utimens; }; diff --git a/src/fuse_access.cpp b/src/fuse_access.cpp index e9705ce3..6e196295 100644 --- a/src/fuse_access.cpp +++ b/src/fuse_access.cpp @@ -26,26 +26,27 @@ using std::string; using std::vector; + namespace l { static int - access(Policy::Func::Search searchFunc, + access(const Policy::Search &searchFunc_, const Branches &branches_, - const char *fusepath, - const int mask) + const char *fusepath_, + const int mask_) { int rv; string fullpath; - vector basepaths; + StrVec basepaths; - rv = searchFunc(branches_,fusepath,&basepaths); + rv = searchFunc_(branches_,fusepath_,&basepaths); if(rv == -1) return -errno; - fullpath = fs::path::make(basepaths[0],fusepath); + fullpath = fs::path::make(basepaths[0],fusepath_); - rv = fs::eaccess(fullpath,mask); + rv = fs::eaccess(fullpath,mask_); return ((rv == -1) ? -errno : 0); } @@ -54,16 +55,16 @@ namespace l namespace FUSE { int - access(const char *fusepath, - int mask) + access(const char *fusepath_, + int mask_) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::ro(); + Config::Read cfg; + const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - return l::access(config.func.access.policy, - config.branches, - fusepath, - mask); + return l::access(cfg->func.access.policy, + cfg->branches, + fusepath_, + mask_); } } diff --git a/src/fuse_access.hpp b/src/fuse_access.hpp index 7fc64277..72386aae 100644 --- a/src/fuse_access.hpp +++ b/src/fuse_access.hpp @@ -16,6 +16,7 @@ #pragma once + namespace FUSE { int diff --git a/src/fuse_chmod.cpp b/src/fuse_chmod.cpp index 938427b9..c2e0e709 100644 --- a/src/fuse_chmod.cpp +++ b/src/fuse_chmod.cpp @@ -24,12 +24,10 @@ #include "fuse.h" #include -#include #include using std::string; -using std::vector; namespace l @@ -73,10 +71,10 @@ namespace l static void - chmod_loop(const vector &basepaths_, - const char *fusepath_, - const mode_t mode_, - PolicyRV *prv_) + chmod_loop(const StrVec &basepaths_, + const char *fusepath_, + const mode_t mode_, + PolicyRV *prv_) { for(size_t i = 0, ei = basepaths_.size(); i != ei; i++) { @@ -86,15 +84,15 @@ namespace l static int - chmod(Policy::Func::Action actionFunc_, - Policy::Func::Search searchFunc_, + chmod(const Policy::Action &actionFunc_, + const Policy::Search &searchFunc_, const Branches &branches_, const char *fusepath_, const mode_t mode_) { int rv; PolicyRV prv; - vector basepaths; + StrVec basepaths; rv = actionFunc_(branches_,fusepath_,&basepaths); if(rv == -1) @@ -121,13 +119,13 @@ namespace FUSE chmod(const char *fusepath_, mode_t mode_) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::ro(); + Config::Read cfg; + const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - return l::chmod(config.func.chmod.policy, - config.func.getattr.policy, - config.branches, + return l::chmod(cfg->func.chmod.policy, + cfg->func.getattr.policy, + cfg->branches, fusepath_, mode_); } diff --git a/src/fuse_chmod.hpp b/src/fuse_chmod.hpp index 6bbcdb40..ea335a34 100644 --- a/src/fuse_chmod.hpp +++ b/src/fuse_chmod.hpp @@ -16,6 +16,7 @@ #pragma once + namespace FUSE { int diff --git a/src/fuse_chown.cpp b/src/fuse_chown.cpp index 70788687..106545b4 100644 --- a/src/fuse_chown.cpp +++ b/src/fuse_chown.cpp @@ -21,7 +21,7 @@ #include "policy_rv.hpp" #include "ugid.hpp" -#include +#include "fuse.h" #include #include @@ -86,8 +86,8 @@ namespace l static int - chown(Policy::Func::Action actionFunc_, - Policy::Func::Search searchFunc_, + chown(const Policy::Action &actionFunc_, + const Policy::Search &searchFunc_, const Branches &branches_, const char *fusepath_, const uid_t uid_, @@ -123,13 +123,13 @@ namespace FUSE uid_t uid_, gid_t gid_) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::ro(); + Config::Read cfg; + const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - return l::chown(config.func.chown.policy, - config.func.getattr.policy, - config.branches, + return l::chown(cfg->func.chown.policy, + cfg->func.getattr.policy, + cfg->branches, fusepath_, uid_, gid_); diff --git a/src/fuse_chown.hpp b/src/fuse_chown.hpp index cda0058d..1a367acf 100644 --- a/src/fuse_chown.hpp +++ b/src/fuse_chown.hpp @@ -16,6 +16,7 @@ #pragma once + namespace FUSE { int diff --git a/src/fuse_copy_file_range.cpp b/src/fuse_copy_file_range.cpp index 2c88733e..34988d86 100644 --- a/src/fuse_copy_file_range.cpp +++ b/src/fuse_copy_file_range.cpp @@ -18,10 +18,11 @@ #include "fileinfo.hpp" #include "fs_copy_file_range.hpp" -#include +#include "fuse.h" #include + namespace l { static diff --git a/src/fuse_copy_file_range.hpp b/src/fuse_copy_file_range.hpp index 30185ad3..ef18a3e6 100644 --- a/src/fuse_copy_file_range.hpp +++ b/src/fuse_copy_file_range.hpp @@ -16,6 +16,7 @@ #pragma once + namespace FUSE { ssize_t diff --git a/src/fuse_create.cpp b/src/fuse_create.cpp index 4a854d1a..5d66d5eb 100644 --- a/src/fuse_create.cpp +++ b/src/fuse_create.cpp @@ -23,7 +23,7 @@ #include "fs_path.hpp" #include "ugid.hpp" -#include +#include "fuse.h" #include #include @@ -31,6 +31,7 @@ using std::string; using std::vector; + namespace l { /* @@ -54,15 +55,15 @@ namespace l static void - config_to_ffi_flags(const Config &config_, + config_to_ffi_flags(Config::Read &cfg_, fuse_file_info_t *ffi_) { - switch(config_.cache_files) + switch(cfg_->cache_files) { case CacheFiles::ENUM::LIBFUSE: - ffi_->direct_io = config_.direct_io; - ffi_->keep_cache = config_.kernel_cache; - ffi_->auto_cache = config_.auto_cache; + ffi_->direct_io = cfg_->direct_io; + ffi_->keep_cache = cfg_->kernel_cache; + ffi_->auto_cache = cfg_->auto_cache; break; case CacheFiles::ENUM::OFF: ffi_->direct_io = 1; @@ -125,8 +126,8 @@ namespace l static int - create(Policy::Func::Search searchFunc_, - Policy::Func::Create createFunc_, + create(const Policy::Search &searchFunc_, + const Policy::Create &createFunc_, const Branches &branches_, const char *fusepath_, const mode_t mode_, @@ -137,8 +138,8 @@ namespace l int rv; string fullpath; string fusedirpath; - vector createpaths; - vector existingpaths; + StrVec createpaths; + StrVec existingpaths; fusedirpath = fs::path::dirname(fusepath_); @@ -170,18 +171,18 @@ namespace FUSE mode_t mode_, fuse_file_info_t *ffi_) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::ro(); + Config::Read cfg; + const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - l::config_to_ffi_flags(config,ffi_); + l::config_to_ffi_flags(cfg,ffi_); - if(config.writeback_cache) + if(cfg->writeback_cache) l::tweak_flags_writeback_cache(&ffi_->flags); - return l::create(config.func.getattr.policy, - config.func.create.policy, - config.branches, + return l::create(cfg->func.getattr.policy, + cfg->func.create.policy, + cfg->branches, fusepath_, mode_, fc->umask, diff --git a/src/fuse_create.hpp b/src/fuse_create.hpp index 0fa08a80..36a74d17 100644 --- a/src/fuse_create.hpp +++ b/src/fuse_create.hpp @@ -16,10 +16,11 @@ #pragma once -#include +#include "fuse.h" #include + namespace FUSE { int diff --git a/src/fuse_destroy.hpp b/src/fuse_destroy.hpp index 60ae8577..31410ee3 100644 --- a/src/fuse_destroy.hpp +++ b/src/fuse_destroy.hpp @@ -16,6 +16,7 @@ #pragma once + namespace FUSE { void diff --git a/src/fuse_fallocate.cpp b/src/fuse_fallocate.cpp index 8235ce43..c1b4e82d 100644 --- a/src/fuse_fallocate.cpp +++ b/src/fuse_fallocate.cpp @@ -18,7 +18,8 @@ #include "fileinfo.hpp" #include "fs_fallocate.hpp" -#include +#include "fuse.h" + namespace l { diff --git a/src/fuse_fallocate.hpp b/src/fuse_fallocate.hpp index f29e4a7f..978cc032 100644 --- a/src/fuse_fallocate.hpp +++ b/src/fuse_fallocate.hpp @@ -18,6 +18,7 @@ #include "fuse.h" + namespace FUSE { int diff --git a/src/fuse_fchmod.cpp b/src/fuse_fchmod.cpp index 3b8cdf8c..27d802de 100644 --- a/src/fuse_fchmod.cpp +++ b/src/fuse_fchmod.cpp @@ -18,7 +18,8 @@ #include "fileinfo.hpp" #include "fs_fchmod.hpp" -#include +#include "fuse.h" + namespace l { diff --git a/src/fuse_fchmod.hpp b/src/fuse_fchmod.hpp index 96d4be7e..64f9e7a5 100644 --- a/src/fuse_fchmod.hpp +++ b/src/fuse_fchmod.hpp @@ -16,10 +16,11 @@ #pragma once -#include +#include "fuse.h" #include + namespace FUSE { int diff --git a/src/fuse_fchown.cpp b/src/fuse_fchown.cpp index 5bf873ab..48e8aa16 100644 --- a/src/fuse_fchown.cpp +++ b/src/fuse_fchown.cpp @@ -18,10 +18,11 @@ #include "fileinfo.hpp" #include "fs_fchown.hpp" -#include +#include "fuse.h" #include + namespace l { static diff --git a/src/fuse_fchown.hpp b/src/fuse_fchown.hpp index 6b043282..991734f6 100644 --- a/src/fuse_fchown.hpp +++ b/src/fuse_fchown.hpp @@ -16,7 +16,8 @@ #pragma once -#include +#include "fuse.h" + namespace FUSE { diff --git a/src/fuse_fgetattr.cpp b/src/fuse_fgetattr.cpp index eb5242ec..bc8b44d4 100644 --- a/src/fuse_fgetattr.cpp +++ b/src/fuse_fgetattr.cpp @@ -20,7 +20,8 @@ #include "fs_fstat.hpp" #include "fs_inode.hpp" -#include +#include "fuse.h" + namespace l { @@ -50,15 +51,15 @@ namespace FUSE fuse_timeouts_t *timeout_) { int rv; - const Config &config = Config::ro(); + Config::Read cfg; FileInfo *fi = reinterpret_cast(ffi_->fh); rv = l::fgetattr(fi->fd,fi->fusepath,st_); timeout_->entry = ((rv >= 0) ? - config.cache_entry : - config.cache_negative_entry); - timeout_->attr = config.cache_attr; + cfg->cache_entry : + cfg->cache_negative_entry); + timeout_->attr = cfg->cache_attr; return rv; } diff --git a/src/fuse_fgetattr.hpp b/src/fuse_fgetattr.hpp index ce032ac5..e58a061a 100644 --- a/src/fuse_fgetattr.hpp +++ b/src/fuse_fgetattr.hpp @@ -16,12 +16,13 @@ #pragma once -#include +#include "fuse.h" #include #include #include + namespace FUSE { int diff --git a/src/fuse_flock.cpp b/src/fuse_flock.cpp index f1df49fa..4a6a2bb3 100644 --- a/src/fuse_flock.cpp +++ b/src/fuse_flock.cpp @@ -18,7 +18,8 @@ #include "fileinfo.hpp" #include "fs_flock.hpp" -#include +#include "fuse.h" + namespace l { diff --git a/src/fuse_flock.hpp b/src/fuse_flock.hpp index cab3c845..194da4de 100644 --- a/src/fuse_flock.hpp +++ b/src/fuse_flock.hpp @@ -16,7 +16,8 @@ #pragma once -#include +#include "fuse.h" + namespace FUSE { diff --git a/src/fuse_flush.cpp b/src/fuse_flush.cpp index 33935530..37dc87b2 100644 --- a/src/fuse_flush.cpp +++ b/src/fuse_flush.cpp @@ -19,7 +19,8 @@ #include "fs_close.hpp" #include "fs_dup.hpp" -#include +#include "fuse.h" + namespace l { diff --git a/src/fuse_flush.hpp b/src/fuse_flush.hpp index 27ca708b..b8d447c3 100644 --- a/src/fuse_flush.hpp +++ b/src/fuse_flush.hpp @@ -16,7 +16,8 @@ #pragma once -#include +#include "fuse.h" + namespace FUSE { diff --git a/src/fuse_free_hide.cpp b/src/fuse_free_hide.cpp index 778d4bf7..4c057d5f 100644 --- a/src/fuse_free_hide.cpp +++ b/src/fuse_free_hide.cpp @@ -19,7 +19,8 @@ #include "fileinfo.hpp" #include "fs_close.hpp" -#include +#include + namespace FUSE { diff --git a/src/fuse_free_hide.hpp b/src/fuse_free_hide.hpp index c8f7c471..8b6be9ee 100644 --- a/src/fuse_free_hide.hpp +++ b/src/fuse_free_hide.hpp @@ -18,7 +18,8 @@ #pragma once -#include +#include + namespace FUSE { diff --git a/src/fuse_fsync.cpp b/src/fuse_fsync.cpp index 96dbc083..1ab9824b 100644 --- a/src/fuse_fsync.cpp +++ b/src/fuse_fsync.cpp @@ -19,11 +19,12 @@ #include "fs_fdatasync.hpp" #include "fs_fsync.hpp" -#include +#include "fuse.h" #include #include + namespace l { static diff --git a/src/fuse_fsync.hpp b/src/fuse_fsync.hpp index c97e569f..58302504 100644 --- a/src/fuse_fsync.hpp +++ b/src/fuse_fsync.hpp @@ -16,12 +16,13 @@ #pragma once -#include +#include "fuse.h" + namespace FUSE { int fsync(const fuse_file_info_t *ffi, int isdatasync); - + } diff --git a/src/fuse_fsyncdir.cpp b/src/fuse_fsyncdir.cpp index 21ae8efd..1388b410 100644 --- a/src/fuse_fsyncdir.cpp +++ b/src/fuse_fsyncdir.cpp @@ -18,11 +18,12 @@ #include "dirinfo.hpp" #include "fs_fsync.hpp" -#include +#include "fuse.h" #include #include + namespace l { static diff --git a/src/fuse_fsyncdir.hpp b/src/fuse_fsyncdir.hpp index 7db828cd..e1eba800 100644 --- a/src/fuse_fsyncdir.hpp +++ b/src/fuse_fsyncdir.hpp @@ -16,7 +16,8 @@ #pragma once -#include +#include "fuse.h" + namespace FUSE { diff --git a/src/fuse_ftruncate.cpp b/src/fuse_ftruncate.cpp index c68a312f..4e3116d4 100644 --- a/src/fuse_ftruncate.cpp +++ b/src/fuse_ftruncate.cpp @@ -18,7 +18,8 @@ #include "fileinfo.hpp" #include "fs_ftruncate.hpp" -#include +#include "fuse.h" + namespace l { diff --git a/src/fuse_ftruncate.hpp b/src/fuse_ftruncate.hpp index 78c8fb9e..16d1c720 100644 --- a/src/fuse_ftruncate.hpp +++ b/src/fuse_ftruncate.hpp @@ -16,11 +16,12 @@ #pragma once -#include +#include "fuse.h" #include #include + namespace FUSE { int diff --git a/src/fuse_futimens.cpp b/src/fuse_futimens.cpp index 2f21b319..8dd27323 100644 --- a/src/fuse_futimens.cpp +++ b/src/fuse_futimens.cpp @@ -18,10 +18,11 @@ #include "fileinfo.hpp" #include "fs_futimens.hpp" -#include +#include "fuse.h" #include + namespace l { static diff --git a/src/fuse_futimens.hpp b/src/fuse_futimens.hpp index 6d149ed7..7e373cc4 100644 --- a/src/fuse_futimens.hpp +++ b/src/fuse_futimens.hpp @@ -16,10 +16,11 @@ #pragma once -#include +#include "fuse.h" #include + namespace FUSE { int diff --git a/src/fuse_getattr.cpp b/src/fuse_getattr.cpp index 54669a09..38ca49ae 100644 --- a/src/fuse_getattr.cpp +++ b/src/fuse_getattr.cpp @@ -22,13 +22,12 @@ #include "symlinkify.hpp" #include "ugid.hpp" -#include +#include "fuse.h" #include -#include using std::string; -using std::vector; + namespace l { @@ -59,7 +58,7 @@ namespace l static int - getattr(Policy::Func::Search searchFunc_, + getattr(const Policy::Search &searchFunc_, const Branches &branches_, const char *fusepath_, struct stat *st_, @@ -68,7 +67,7 @@ namespace l { int rv; string fullpath; - vector basepaths; + StrVec basepaths; rv = searchFunc_(branches_,fusepath_,&basepaths); if(rv == -1) @@ -87,36 +86,43 @@ namespace l return 0; } -} -namespace FUSE -{ int getattr(const char *fusepath_, struct stat *st_, fuse_timeouts_t *timeout_) { int rv; - const Config &config = Config::ro(); - - if(fusepath_ == config.controlfile) - return l::getattr_controlfile(st_); - + Config::Read cfg; const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - rv = l::getattr(config.func.getattr.policy, - config.branches, + rv = l::getattr(cfg->func.getattr.policy, + cfg->branches, fusepath_, st_, - config.symlinkify, - config.symlinkify_timeout); + cfg->symlinkify, + cfg->symlinkify_timeout); timeout_->entry = ((rv >= 0) ? - config.cache_entry : - config.cache_negative_entry); - timeout_->attr = config.cache_attr; + cfg->cache_entry : + cfg->cache_negative_entry); + timeout_->attr = cfg->cache_attr; return rv; } } + +namespace FUSE +{ + int + getattr(const char *fusepath_, + struct stat *st_, + fuse_timeouts_t *timeout_) + { + if(fusepath_ == CONTROLFILE) + return l::getattr_controlfile(st_); + + return l::getattr(fusepath_,st_,timeout_); + } +} diff --git a/src/fuse_getattr.hpp b/src/fuse_getattr.hpp index a41eccd1..03e4b6c1 100644 --- a/src/fuse_getattr.hpp +++ b/src/fuse_getattr.hpp @@ -20,6 +20,7 @@ #include #include + namespace FUSE { int diff --git a/src/fuse_getxattr.cpp b/src/fuse_getxattr.cpp index e0fd6ca8..2f8145a2 100644 --- a/src/fuse_getxattr.cpp +++ b/src/fuse_getxattr.cpp @@ -24,12 +24,11 @@ #include "ugid.hpp" #include "version.hpp" -#include +#include "fuse.h" #include #include #include -#include #include #include @@ -37,7 +36,7 @@ static const char SECURITY_CAPABILITY[] = "security.capability"; using std::string; -using std::vector; + namespace l { @@ -64,7 +63,7 @@ namespace l static int - getxattr_controlfile(const Config &config_, + getxattr_controlfile(Config::Read &cfg_, const char *attrname_, char *buf_, const size_t count_) @@ -73,13 +72,13 @@ namespace l size_t len; string key; string val; - vector attr; + StrVec attr; if(!str::startswith(attrname_,"user.mergerfs.")) return -ENOATTR; key = &attrname_[14]; - rv = config_.get(key,&val); + rv = cfg_->get(key,&val); if(rv < 0) return rv; @@ -117,16 +116,16 @@ namespace l static int - getxattr_user_mergerfs_allpaths(const Branches &branches_, - const char *fusepath_, - char *buf_, - const size_t count_) + getxattr_user_mergerfs_allpaths(const Branches::CPtr &branches_, + const char *fusepath_, + char *buf_, + const size_t count_) { string concated; - vector paths; - vector branches; + StrVec paths; + StrVec branches; - branches_.to_paths(branches); + branches_->to_paths(branches); fs::findallfiles(branches,fusepath_,&paths); @@ -145,7 +144,7 @@ namespace l char *buf_, const size_t count_) { - vector attr; + StrVec attr; str::split(attrname_,'.',&attr); @@ -163,7 +162,7 @@ namespace l static int - getxattr(Policy::Func::Search searchFunc_, + getxattr(const Policy::Search &searchFunc_, const Branches &branches_, const char *fusepath_, const char *attrname_, @@ -172,7 +171,7 @@ namespace l { int rv; string fullpath; - vector basepaths; + StrVec basepaths; rv = searchFunc_(branches_,fusepath_,&basepaths); if(rv == -1) @@ -201,26 +200,26 @@ namespace FUSE char *buf_, size_t count_) { - const Config &config = Config::ro(); + Config::Read cfg; - if(fusepath_ == config.controlfile) - return l::getxattr_controlfile(config, + if(fusepath_ == CONTROLFILE) + return l::getxattr_controlfile(cfg, attrname_, buf_, count_); - if((config.security_capability == false) && + if((cfg->security_capability == false) && l::is_attrname_security_capability(attrname_)) return -ENOATTR; - if(config.xattr.to_int()) - return -config.xattr.to_int(); + if(cfg->xattr.to_int()) + return -cfg->xattr.to_int(); const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - return l::getxattr(config.func.getxattr.policy, - config.branches, + return l::getxattr(cfg->func.getxattr.policy, + cfg->branches, fusepath_, attrname_, buf_, diff --git a/src/fuse_getxattr.hpp b/src/fuse_getxattr.hpp index 4ff565c0..60869c87 100644 --- a/src/fuse_getxattr.hpp +++ b/src/fuse_getxattr.hpp @@ -16,6 +16,7 @@ #pragma once + namespace FUSE { int diff --git a/src/fuse_init.cpp b/src/fuse_init.cpp index adda4c32..2dccd9c8 100644 --- a/src/fuse_init.cpp +++ b/src/fuse_init.cpp @@ -17,7 +17,8 @@ #include "config.hpp" #include "ugid.hpp" -#include +#include "fuse.h" + namespace l { @@ -64,16 +65,16 @@ namespace l static void want_if_capable_max_pages(fuse_conn_info *conn_, - Config &c_) + Config::Write &cfg_) { if(l::capable(conn_,FUSE_CAP_MAX_PAGES)) { l::want(conn_,FUSE_CAP_MAX_PAGES); - conn_->max_pages = c_.fuse_msg_size; + conn_->max_pages = cfg_->fuse_msg_size; } else { - c_.fuse_msg_size = FUSE_DEFAULT_MAX_PAGES_PER_REQ; + cfg_->fuse_msg_size = FUSE_DEFAULT_MAX_PAGES_PER_REQ; } } } @@ -83,24 +84,24 @@ namespace FUSE void * init(fuse_conn_info *conn_) { - Config &config = Config::rw(); + Config::Write cfg; ugid::init(); l::want_if_capable(conn_,FUSE_CAP_ASYNC_DIO); - l::want_if_capable(conn_,FUSE_CAP_ASYNC_READ,&config.async_read); + l::want_if_capable(conn_,FUSE_CAP_ASYNC_READ,&cfg->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,&config.cache_symlinks); + l::want_if_capable(conn_,FUSE_CAP_CACHE_SYMLINKS,&cfg->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,&config.readdirplus); + l::want_if_capable(conn_,FUSE_CAP_READDIR_PLUS,&cfg->readdirplus); //l::want_if_capable(conn_,FUSE_CAP_READDIR_PLUS_AUTO); - 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); + l::want_if_capable(conn_,FUSE_CAP_POSIX_ACL,&cfg->posix_acl); + l::want_if_capable(conn_,FUSE_CAP_WRITEBACK_CACHE,&cfg->writeback_cache); + l::want_if_capable_max_pages(conn_,cfg); - return &config; + return NULL; } } diff --git a/src/fuse_init.hpp b/src/fuse_init.hpp index d36b9070..5867d646 100644 --- a/src/fuse_init.hpp +++ b/src/fuse_init.hpp @@ -16,7 +16,8 @@ #pragma once -#include +#include "fuse.h" + namespace FUSE { diff --git a/src/fuse_ioctl.cpp b/src/fuse_ioctl.cpp index 88d49610..db7199e0 100644 --- a/src/fuse_ioctl.cpp +++ b/src/fuse_ioctl.cpp @@ -27,7 +27,7 @@ #include "str.hpp" #include "ugid.hpp" -#include +#include "fuse.h" #include #include @@ -134,7 +134,7 @@ namespace l static int - ioctl_dir_base(Policy::Func::Search searchFunc_, + ioctl_dir_base(const Policy::Search &searchFunc_, const Branches &branches_, const char *fusepath_, const uint32_t cmd_, @@ -144,7 +144,7 @@ namespace l int fd; int rv; string fullpath; - vector basepaths; + StrVec basepaths; rv = searchFunc_(branches_,fusepath_,&basepaths); if(rv == -1) @@ -170,13 +170,13 @@ 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::ro(); + Config::Read cfg; + DirInfo *di = reinterpret_cast(ffi_->fh); + const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - return l::ioctl_dir_base(config.func.open.policy, - config.branches, + return l::ioctl_dir_base(cfg->func.open.policy, + cfg->branches, di->fusepath.c_str(), cmd_, data_, @@ -203,10 +203,10 @@ namespace l int read_keys(void *data_) { - std::string keys; - const Config &config = Config::ro(); + Config::Read cfg; + std::string keys; - config.keys(keys); + cfg->keys(keys); return l::strcpy(keys,data_); } @@ -215,17 +215,17 @@ namespace l int read_val(void *data_) { + Config::Read cfg; 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); + rv = cfg->get(key,&val); if(rv < 0) return rv; @@ -236,11 +236,11 @@ namespace l int write_val(void *data_) { + Config::Write cfg; char *data; std::string kv; std::string key; std::string val; - Config &config = Config::rw(); data = (char*)data_; data[sizeof(IOCTL_BUF) - 1] = '\0'; @@ -248,18 +248,18 @@ namespace l kv = data; str::splitkv(kv,'=',&key,&val); - return config.set(key,val); + return cfg->set(key,val); } static int - file_basepath(Policy::Func::Search searchFunc_, + file_basepath(const Policy::Search &searchFunc_, const Branches &branches_, const char *fusepath_, void *data_) { int rv; - vector basepaths; + StrVec basepaths; rv = searchFunc_(branches_,fusepath_,&basepaths); if(rv == -1) @@ -273,11 +273,11 @@ namespace l file_basepath(const fuse_file_info_t *ffi_, void *data_) { - const Config &config = Config::ro(); + Config::Read cfg; std::string &fusepath = reinterpret_cast(ffi_->fh)->fusepath; - return l::file_basepath(config.func.open.policy, - config.branches, + return l::file_basepath(cfg->func.open.policy, + cfg->branches, fusepath.c_str(), data_); } @@ -294,14 +294,14 @@ namespace l static int - file_fullpath(Policy::Func::Search searchFunc_, + file_fullpath(const Policy::Search &searchFunc_, const Branches &branches_, const string &fusepath_, void *data_) { int rv; string fullpath; - vector basepaths; + StrVec basepaths; rv = searchFunc_(branches_,fusepath_,&basepaths); if(rv == -1) @@ -317,11 +317,11 @@ namespace l file_fullpath(const fuse_file_info_t *ffi_, void *data_) { - const Config &config = Config::ro(); + Config::Read cfg; std::string &fusepath = reinterpret_cast(ffi_->fh)->fusepath; - return l::file_fullpath(config.func.open.policy, - config.branches, + return l::file_fullpath(cfg->func.open.policy, + cfg->branches, fusepath, data_); } @@ -331,13 +331,13 @@ namespace l file_allpaths(const fuse_file_info_t *ffi_, void *data_) { + Config::Read cfg; string concated; - vector paths; - vector branches; + StrVec paths; + StrVec branches; string &fusepath = reinterpret_cast(ffi_->fh)->fusepath; - const Config &config = Config::ro(); - config.branches.to_paths(branches); + cfg->branches->to_paths(branches); fs::findallfiles(branches,fusepath.c_str(),&paths); diff --git a/src/fuse_ioctl.hpp b/src/fuse_ioctl.hpp index 98b6f863..11ea6233 100644 --- a/src/fuse_ioctl.hpp +++ b/src/fuse_ioctl.hpp @@ -16,7 +16,10 @@ #pragma once -#include +#include + +#include "fuse.h" + namespace FUSE { diff --git a/src/fuse_link.cpp b/src/fuse_link.cpp index ecc1ed41..4b06adcf 100644 --- a/src/fuse_link.cpp +++ b/src/fuse_link.cpp @@ -21,7 +21,7 @@ #include "fs_path.hpp" #include "ugid.hpp" -#include +#include "fuse.h" #include #include @@ -29,6 +29,7 @@ using std::string; using std::vector; + namespace error { static @@ -73,11 +74,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 StrVec &oldbasepaths_, + const string &newbasepath_, + const char *oldfusepath_, + const char *newfusepath_, + const string &newfusedirpath_) { int rv; int error; @@ -99,16 +100,16 @@ namespace l static int - link_create_path(Policy::Func::Search searchFunc_, - Policy::Func::Action actionFunc_, + link_create_path(const Policy::Search &searchFunc_, + const Policy::Action &actionFunc_, const Branches &branches_, const char *oldfusepath_, const char *newfusepath_) { int rv; string newfusedirpath; - vector oldbasepaths; - vector newbasepaths; + StrVec oldbasepaths; + StrVec newbasepaths; rv = actionFunc_(branches_,oldfusepath_,&oldbasepaths); if(rv == -1) @@ -127,8 +128,8 @@ namespace l static int - clonepath_if_would_create(Policy::Func::Search searchFunc_, - Policy::Func::Create createFunc_, + clonepath_if_would_create(const Policy::Search &searchFunc_, + const Policy::Create &createFunc_, const Branches &branches_, const string &oldbasepath_, const char *oldfusepath_, @@ -136,7 +137,7 @@ namespace l { int rv; string newfusedirpath; - vector newbasepath; + StrVec newbasepath; newfusedirpath = fs::path::dirname(newfusepath_); @@ -156,8 +157,8 @@ namespace l static int - link_preserve_path_core(Policy::Func::Search searchFunc_, - Policy::Func::Create createFunc_, + link_preserve_path_core(const Policy::Search &searchFunc_, + const Policy::Create &createFunc_, const Branches &branches_, const string &oldbasepath_, const char *oldfusepath_, @@ -187,12 +188,12 @@ namespace l static int - link_preserve_path_loop(Policy::Func::Search searchFunc_, - Policy::Func::Create createFunc_, + link_preserve_path_loop(const Policy::Search &searchFunc_, + const Policy::Create &createFunc_, const Branches &branches_, const char *oldfusepath_, const char *newfusepath_, - const vector &oldbasepaths_) + const StrVec &oldbasepaths_) { int error; @@ -211,15 +212,15 @@ namespace l static int - link_preserve_path(Policy::Func::Search searchFunc_, - Policy::Func::Action actionFunc_, - Policy::Func::Create createFunc_, + link_preserve_path(const Policy::Search &searchFunc_, + const Policy::Action &actionFunc_, + const Policy::Create &createFunc_, const Branches &branches_, const char *oldfusepath_, const char *newfusepath_) { int rv; - vector oldbasepaths; + StrVec oldbasepaths; rv = actionFunc_(branches_,oldfusepath_,&oldbasepaths); if(rv == -1) @@ -238,21 +239,21 @@ namespace FUSE link(const char *from_, const char *to_) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::ro(); + Config::Read cfg; + const fuse_context *fc = fuse_get_context(); 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, + if(cfg->func.create.policy.path_preserving() && !cfg->ignorepponrename) + return l::link_preserve_path(cfg->func.getattr.policy, + cfg->func.link.policy, + cfg->func.create.policy, + cfg->branches, from_, to_); - return l::link_create_path(config.func.link.policy, - config.func.create.policy, - config.branches, + return l::link_create_path(cfg->func.getattr.policy, + cfg->func.link.policy, + cfg->branches, from_, to_); } diff --git a/src/fuse_link.hpp b/src/fuse_link.hpp index bb1eb2ec..ab601f88 100644 --- a/src/fuse_link.hpp +++ b/src/fuse_link.hpp @@ -16,6 +16,7 @@ #pragma once + namespace FUSE { int diff --git a/src/fuse_listxattr.cpp b/src/fuse_listxattr.cpp index 29b3f57c..1f69b15c 100644 --- a/src/fuse_listxattr.cpp +++ b/src/fuse_listxattr.cpp @@ -14,7 +14,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "buildvector.hpp" #include "category.hpp" #include "config.hpp" #include "errno.hpp" @@ -23,27 +22,26 @@ #include "ugid.hpp" #include "xattr.hpp" -#include +#include "fuse.h" #include -#include #include using std::string; -using std::vector; + namespace l { static int - listxattr_controlfile(const Config &config_, + listxattr_controlfile(Config::Read &cfg_, char *list_, const size_t size_) { string xattrs; - config_.keys_xattr(xattrs); + cfg_->keys_xattr(xattrs); if(size_ == 0) return xattrs.size(); @@ -57,7 +55,7 @@ namespace l static int - listxattr(Policy::Func::Search searchFunc_, + listxattr(const Policy::Search &searchFunc_, const Branches &branches_, const char *fusepath_, char *list_, @@ -65,7 +63,7 @@ namespace l { int rv; string fullpath; - vector basepaths; + StrVec basepaths; rv = searchFunc_(branches_,fusepath_,&basepaths); if(rv == -1) @@ -86,12 +84,12 @@ namespace FUSE char *list_, size_t size_) { - const Config &config = Config::ro(); + Config::Read cfg; - if(fusepath_ == config.controlfile) - return l::listxattr_controlfile(config,list_,size_); + if(fusepath_ == CONTROLFILE) + return l::listxattr_controlfile(cfg,list_,size_); - switch(config.xattr) + switch(cfg->xattr) { case XAttr::ENUM::PASSTHROUGH: break; @@ -104,8 +102,8 @@ namespace FUSE const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - return l::listxattr(config.func.listxattr.policy, - config.branches, + return l::listxattr(cfg->func.listxattr.policy, + cfg->branches, fusepath_, list_, size_); diff --git a/src/fuse_listxattr.hpp b/src/fuse_listxattr.hpp index cef0b91c..f06c32c8 100644 --- a/src/fuse_listxattr.hpp +++ b/src/fuse_listxattr.hpp @@ -16,6 +16,7 @@ #pragma once + namespace FUSE { int diff --git a/src/fuse_mkdir.cpp b/src/fuse_mkdir.cpp index 66efccd7..c8bc3e57 100644 --- a/src/fuse_mkdir.cpp +++ b/src/fuse_mkdir.cpp @@ -20,15 +20,15 @@ #include "fs_clonepath.hpp" #include "fs_mkdir.hpp" #include "fs_path.hpp" +#include "policy.hpp" #include "ugid.hpp" -#include +#include "fuse.h" #include -#include using std::string; -using std::vector; + namespace error { @@ -84,12 +84,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 StrVec &createpaths_, + const char *fusepath_, + const string &fusedirpath_, + const mode_t mode_, + const mode_t umask_) { int rv; int error; @@ -113,8 +113,8 @@ namespace l static int - mkdir(Policy::Func::Search searchFunc_, - Policy::Func::Create createFunc_, + mkdir(const Policy::Search &getattrPolicy_, + const Policy::Create &mkdirPolicy_, const Branches &branches_, const char *fusepath_, const mode_t mode_, @@ -122,16 +122,16 @@ namespace l { int rv; string fusedirpath; - vector createpaths; - vector existingpaths; + StrVec createpaths; + StrVec existingpaths; fusedirpath = fs::path::dirname(fusepath_); - rv = searchFunc_(branches_,fusedirpath,&existingpaths); + rv = getattrPolicy_(branches_,fusedirpath.c_str(),&existingpaths); if(rv == -1) return -errno; - rv = createFunc_(branches_,fusedirpath,&createpaths); + rv = mkdirPolicy_(branches_,fusedirpath.c_str(),&createpaths); if(rv == -1) return -errno; @@ -150,13 +150,13 @@ namespace FUSE mkdir(const char *fusepath_, mode_t mode_) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::ro(); + Config::Read cfg; + const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - return l::mkdir(config.func.getattr.policy, - config.func.mkdir.policy, - config.branches, + return l::mkdir(cfg->func.getattr.policy, + cfg->func.mkdir.policy, + cfg->branches, fusepath_, mode_, fc->umask); diff --git a/src/fuse_mkdir.hpp b/src/fuse_mkdir.hpp index e70fa64e..f2c515b2 100644 --- a/src/fuse_mkdir.hpp +++ b/src/fuse_mkdir.hpp @@ -16,6 +16,7 @@ #pragma once + namespace FUSE { int diff --git a/src/fuse_mknod.cpp b/src/fuse_mknod.cpp index 042efefc..ad7b4f46 100644 --- a/src/fuse_mknod.cpp +++ b/src/fuse_mknod.cpp @@ -22,7 +22,7 @@ #include "fs_path.hpp" #include "ugid.hpp" -#include +#include "fuse.h" #include #include @@ -30,6 +30,7 @@ using std::string; using std::vector; + namespace error { static @@ -115,8 +116,8 @@ namespace l static int - mknod(Policy::Func::Search searchFunc_, - Policy::Func::Create createFunc_, + mknod(const Policy::Search &searchFunc_, + const Policy::Create &createFunc_, const Branches &branches_, const char *fusepath_, const mode_t mode_, @@ -151,13 +152,13 @@ namespace FUSE mode_t mode_, dev_t rdev_) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::ro(); + Config::Read cfg; + const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - return l::mknod(config.func.getattr.policy, - config.func.mknod.policy, - config.branches, + return l::mknod(cfg->func.getattr.policy, + cfg->func.mknod.policy, + cfg->branches, fusepath_, mode_, fc->umask, diff --git a/src/fuse_mknod.hpp b/src/fuse_mknod.hpp index adb56d8d..6350f310 100644 --- a/src/fuse_mknod.hpp +++ b/src/fuse_mknod.hpp @@ -17,6 +17,7 @@ #pragma once + namespace FUSE { int diff --git a/src/fuse_open.cpp b/src/fuse_open.cpp index 583714f4..2e86fe5a 100644 --- a/src/fuse_open.cpp +++ b/src/fuse_open.cpp @@ -23,7 +23,6 @@ #include "fs_open.hpp" #include "fs_path.hpp" #include "fs_stat.hpp" -#include "policy_cache.hpp" #include "stat_util.hpp" #include "ugid.hpp" @@ -35,6 +34,7 @@ using std::string; using std::vector; + namespace l { static @@ -117,15 +117,15 @@ namespace l static void - config_to_ffi_flags(const Config &config_, + config_to_ffi_flags(Config::Read &cfg_, fuse_file_info_t *ffi_) { - switch(config_.cache_files) + switch(cfg_->cache_files) { case CacheFiles::ENUM::LIBFUSE: - ffi_->direct_io = config_.direct_io; - ffi_->keep_cache = config_.kernel_cache; - ffi_->auto_cache = config_.auto_cache; + ffi_->direct_io = cfg_->direct_io; + ffi_->keep_cache = cfg_->kernel_cache; + ffi_->auto_cache = cfg_->auto_cache; break; case CacheFiles::ENUM::OFF: ffi_->direct_io = 1; @@ -180,8 +180,7 @@ namespace l static int - open(Policy::Func::Search searchFunc_, - PolicyCache &cache, + open(const Policy::Search &searchFunc_, const Branches &branches_, const char *fusepath_, const int flags_, @@ -190,13 +189,13 @@ namespace l uint64_t *fh_) { int rv; - string basepath; + StrVec basepaths; - rv = cache(searchFunc_,branches_,fusepath_,&basepath); + rv = searchFunc_(branches_,fusepath_,&basepaths); if(rv == -1) return -errno; - return l::open_core(basepath,fusepath_,flags_,link_cow_,nfsopenhack_,fh_); + return l::open_core(basepaths[0],fusepath_,flags_,link_cow_,nfsopenhack_,fh_); } } @@ -206,22 +205,21 @@ namespace FUSE open(const char *fusepath_, fuse_file_info_t *ffi_) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::ro(); + Config::Read cfg; + const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - l::config_to_ffi_flags(config,ffi_); + l::config_to_ffi_flags(cfg,ffi_); - if(config.writeback_cache) + if(cfg->writeback_cache) l::tweak_flags_writeback_cache(&ffi_->flags); - return l::open(config.func.open.policy, - config.open_cache, - config.branches, + return l::open(cfg->func.open.policy, + cfg->branches, fusepath_, ffi_->flags, - config.link_cow, - config.nfsopenhack, + cfg->link_cow, + cfg->nfsopenhack, &ffi_->fh); } } diff --git a/src/fuse_open.hpp b/src/fuse_open.hpp index 2d7cadee..34c758bc 100644 --- a/src/fuse_open.hpp +++ b/src/fuse_open.hpp @@ -16,7 +16,8 @@ #pragma once -#include +#include "fuse.h" + namespace FUSE { diff --git a/src/fuse_opendir.cpp b/src/fuse_opendir.cpp index 6bd5e864..43c706ae 100644 --- a/src/fuse_opendir.cpp +++ b/src/fuse_opendir.cpp @@ -17,7 +17,8 @@ #include "config.hpp" #include "dirinfo.hpp" -#include +#include "fuse.h" + namespace FUSE { @@ -25,11 +26,11 @@ namespace FUSE opendir(const char *fusepath_, fuse_file_info_t *ffi_) { - const Config &config = Config::ro(); + Config::Read cfg; ffi_->fh = reinterpret_cast(new DirInfo(fusepath_)); - if(config.cache_readdir) + if(cfg->cache_readdir) { ffi_->keep_cache = 1; ffi_->cache_readdir = 1; diff --git a/src/fuse_opendir.hpp b/src/fuse_opendir.hpp index 7bc83339..1a2dca84 100644 --- a/src/fuse_opendir.hpp +++ b/src/fuse_opendir.hpp @@ -16,7 +16,8 @@ #pragma once -#include +#include "fuse.h" + namespace FUSE { diff --git a/src/fuse_prepare_hide.cpp b/src/fuse_prepare_hide.cpp index 73c8e74b..fbd741ea 100644 --- a/src/fuse_prepare_hide.cpp +++ b/src/fuse_prepare_hide.cpp @@ -18,10 +18,11 @@ #include "fuse_open.hpp" -#include +#include #include + namespace FUSE { int diff --git a/src/fuse_prepare_hide.hpp b/src/fuse_prepare_hide.hpp index 696f5819..9e38760b 100644 --- a/src/fuse_prepare_hide.hpp +++ b/src/fuse_prepare_hide.hpp @@ -18,7 +18,8 @@ #pragma once -#include +#include + namespace FUSE { diff --git a/src/fuse_read.cpp b/src/fuse_read.cpp index 34a4b2e5..cc177de4 100644 --- a/src/fuse_read.cpp +++ b/src/fuse_read.cpp @@ -18,7 +18,8 @@ #include "fileinfo.hpp" #include "fs_read.hpp" -#include +#include "fuse.h" + namespace l { diff --git a/src/fuse_read.hpp b/src/fuse_read.hpp index 21110ee2..b15c8d27 100644 --- a/src/fuse_read.hpp +++ b/src/fuse_read.hpp @@ -16,7 +16,8 @@ #pragma once -#include +#include "fuse.h" + namespace FUSE { diff --git a/src/fuse_read_buf.cpp b/src/fuse_read_buf.cpp index d43355a9..733940f1 100644 --- a/src/fuse_read_buf.cpp +++ b/src/fuse_read_buf.cpp @@ -17,13 +17,14 @@ #include "errno.hpp" #include "fileinfo.hpp" -#include +#include "fuse.h" #include #include typedef struct fuse_bufvec fuse_bufvec; + namespace l { static diff --git a/src/fuse_read_buf.hpp b/src/fuse_read_buf.hpp index 34ecc46f..f614e916 100644 --- a/src/fuse_read_buf.hpp +++ b/src/fuse_read_buf.hpp @@ -16,10 +16,11 @@ #pragma once -#include +#include "fuse.h" #include + namespace FUSE { int diff --git a/src/fuse_readdir.cpp b/src/fuse_readdir.cpp index e9607442..2ef0b3e4 100644 --- a/src/fuse_readdir.cpp +++ b/src/fuse_readdir.cpp @@ -24,7 +24,8 @@ #include "rwlock.hpp" #include "ugid.hpp" -#include +#include "fuse.h" + namespace FUSE { @@ -32,18 +33,18 @@ namespace FUSE readdir(const fuse_file_info_t *ffi_, fuse_dirents_t *buf_) { - DirInfo *di = reinterpret_cast(ffi_->fh); - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::ro(); + Config::Read cfg; + DirInfo *di = reinterpret_cast(ffi_->fh); + const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - switch(config.readdir) + switch(cfg->readdir) { case ReadDir::ENUM::LINUX: - return FUSE::readdir_linux(config.branches,di->fusepath.c_str(),buf_); + return FUSE::readdir_linux(cfg->branches,di->fusepath.c_str(),buf_); default: case ReadDir::ENUM::POSIX: - return FUSE::readdir_posix(config.branches,di->fusepath.c_str(),buf_); + return FUSE::readdir_posix(cfg->branches,di->fusepath.c_str(),buf_); } } } diff --git a/src/fuse_readdir.hpp b/src/fuse_readdir.hpp index 92741edd..c82937c3 100644 --- a/src/fuse_readdir.hpp +++ b/src/fuse_readdir.hpp @@ -16,7 +16,8 @@ #pragma once -#include +#include "fuse.h" + namespace FUSE { diff --git a/src/fuse_readdir_linux.cpp b/src/fuse_readdir_linux.cpp index f7eeeb4a..6f857b1b 100644 --- a/src/fuse_readdir_linux.cpp +++ b/src/fuse_readdir_linux.cpp @@ -14,7 +14,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "branch.hpp" +#include "branches.hpp" #include "errno.hpp" #include "fs_close.hpp" #include "fs_devid.hpp" @@ -26,10 +26,9 @@ #include "hashset.hpp" #include "linux_dirent64.h" #include "mempools.hpp" -#include "rwlock.hpp" -#include -#include +#include "fuse.h" +#include "fuse_dirents.h" #include #include @@ -53,9 +52,9 @@ namespace l static int - readdir(const BranchVec &branches_, - const char *dirname_, - fuse_dirents_t *buf_) + readdir(const Branches::CPtr &branches_, + const char *dirname_, + fuse_dirents_t *buf_) { int rv; dev_t dev; @@ -72,20 +71,18 @@ namespace l if(buf == NULL) return -ENOMEM; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(const auto &branch : *branches_) { int dirfd; int64_t nread; - basepath = fs::path::make(branches_[i].path,dirname_); + basepath = fs::path::make(branch.path,dirname_); dirfd = fs::open_dir_ro(basepath); if(dirfd == -1) continue; dev = fs::devid(dirfd); - if(dev == (dev_t)-1) - dev = i; for(;;) { @@ -124,25 +121,14 @@ namespace l return 0; } - - static - int - readdir(const Branches &branches_, - const char *dirname_, - fuse_dirents_t *buf_) - { - rwlock::ReadGuard guard(branches_.lock); - - return l::readdir(branches_.vec,dirname_,buf_); - } } namespace FUSE { int - readdir_linux(const Branches &branches_, - const char *dirname_, - fuse_dirents_t *buf_) + readdir_linux(const Branches::CPtr &branches_, + const char *dirname_, + fuse_dirents_t *buf_) { return l::readdir(branches_,dirname_,buf_); } diff --git a/src/fuse_readdir_linux.hpp b/src/fuse_readdir_linux.hpp index d6b9b09d..26cfff6a 100644 --- a/src/fuse_readdir_linux.hpp +++ b/src/fuse_readdir_linux.hpp @@ -18,16 +18,17 @@ #pragma once -#include "branch.hpp" +#include "branches.hpp" -#include +#include "fuse.h" + +#include -#include namespace FUSE { int - readdir_linux(const Branches &branches, - const char *dirname, - fuse_dirents_t *buf); + readdir_linux(const Branches::CPtr &branches, + const char *dirname, + fuse_dirents_t *buf); } diff --git a/src/fuse_readdir_plus.cpp b/src/fuse_readdir_plus.cpp index 6ee1f52a..e9870fa2 100644 --- a/src/fuse_readdir_plus.cpp +++ b/src/fuse_readdir_plus.cpp @@ -24,7 +24,8 @@ #include "rwlock.hpp" #include "ugid.hpp" -#include +#include "fuse.h" + namespace FUSE { @@ -32,25 +33,25 @@ namespace FUSE readdir_plus(const fuse_file_info_t *ffi_, fuse_dirents_t *buf_) { - DirInfo *di = reinterpret_cast(ffi_->fh); - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::ro(); + Config::Read cfg; + DirInfo *di = reinterpret_cast(ffi_->fh); + const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - switch(config.readdir) + switch(cfg->readdir) { case ReadDir::ENUM::LINUX: - return FUSE::readdir_plus_linux(config.branches, + return FUSE::readdir_plus_linux(cfg->branches, di->fusepath.c_str(), - config.cache_entry, - config.cache_attr, + cfg->cache_entry, + cfg->cache_attr, buf_); default: case ReadDir::ENUM::POSIX: - return FUSE::readdir_plus_posix(config.branches, + return FUSE::readdir_plus_posix(cfg->branches, di->fusepath.c_str(), - config.cache_entry, - config.cache_attr, + cfg->cache_entry, + cfg->cache_attr, buf_); } } diff --git a/src/fuse_readdir_plus.hpp b/src/fuse_readdir_plus.hpp index 20278f0c..8e298e61 100644 --- a/src/fuse_readdir_plus.hpp +++ b/src/fuse_readdir_plus.hpp @@ -16,7 +16,8 @@ #pragma once -#include +#include "fuse.h" + namespace FUSE { diff --git a/src/fuse_readdir_plus_linux.cpp b/src/fuse_readdir_plus_linux.cpp index ef2e855d..880f158b 100644 --- a/src/fuse_readdir_plus_linux.cpp +++ b/src/fuse_readdir_plus_linux.cpp @@ -14,7 +14,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "branch.hpp" +#include "branches.hpp" #include "errno.hpp" #include "fs_close.hpp" #include "fs_devid.hpp" @@ -28,8 +28,8 @@ #include "linux_dirent64.h" #include "mempools.hpp" -#include -#include +#include "fuse.h" +#include "fuse_dirents.h" #include #include @@ -53,11 +53,11 @@ namespace l static int - readdir_plus(const BranchVec &branches_, - const char *dirname_, - const uint64_t entry_timeout_, - const uint64_t attr_timeout_, - fuse_dirents_t *buf_) + readdir_plus(const Branches::CPtr &branches_, + const char *dirname_, + const uint64_t entry_timeout_, + const uint64_t attr_timeout_, + fuse_dirents_t *buf_) { int rv; dev_t dev; @@ -80,20 +80,17 @@ namespace l 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++) + for(auto &branch : *branches_) { int dirfd; int64_t nread; - basepath = fs::path::make(branches_[i].path,dirname_); + basepath = fs::path::make(branch.path,dirname_); dirfd = fs::open_dir_ro(basepath); if(dirfd == -1) continue; - dev = fs::devid(dirfd); - if(dev == (dev_t)-1) - dev = i; for(;;) { @@ -138,29 +135,16 @@ namespace l return 0; } - - static - int - readdir_plus(const Branches &branches_, - const char *dirname_, - const uint64_t entry_timeout_, - const uint64_t attr_timeout_, - fuse_dirents_t *buf_) - { - rwlock::ReadGuard guard(branches_.lock); - - return l::readdir_plus(branches_.vec,dirname_,entry_timeout_,attr_timeout_,buf_); - } } namespace FUSE { int - readdir_plus_linux(const Branches &branches_, - const char *dirname_, - const uint64_t entry_timeout_, - const uint64_t attr_timeout_, - fuse_dirents_t *buf_) + readdir_plus_linux(const Branches::CPtr &branches_, + const char *dirname_, + const uint64_t entry_timeout_, + const uint64_t attr_timeout_, + fuse_dirents_t *buf_) { return l::readdir_plus(branches_,dirname_,entry_timeout_,attr_timeout_,buf_); } diff --git a/src/fuse_readdir_plus_linux.hpp b/src/fuse_readdir_plus_linux.hpp index 68020b7f..a0bca539 100644 --- a/src/fuse_readdir_plus_linux.hpp +++ b/src/fuse_readdir_plus_linux.hpp @@ -18,18 +18,19 @@ #pragma once -#include "branch.hpp" +#include "branches.hpp" -#include +#include "fuse.h" + +#include -#include namespace FUSE { int - readdir_plus_linux(const Branches &branches, - const char *dirname, - const uint64_t entry_timeout, - const uint64_t attr_timeout, - fuse_dirents_t *buf); + readdir_plus_linux(const Branches::CPtr &branches, + const char *dirname, + const uint64_t entry_timeout, + const uint64_t attr_timeout, + fuse_dirents_t *buf); } diff --git a/src/fuse_readdir_plus_posix.cpp b/src/fuse_readdir_plus_posix.cpp index 27b6e07a..0d974e6e 100644 --- a/src/fuse_readdir_plus_posix.cpp +++ b/src/fuse_readdir_plus_posix.cpp @@ -16,7 +16,7 @@ #define _DEFAULT_SOURCE -#include "branch.hpp" +#include "branches.hpp" #include "errno.hpp" #include "fs_closedir.hpp" #include "fs_devid.hpp" @@ -28,10 +28,9 @@ #include "fs_readdir.hpp" #include "fs_stat.hpp" #include "hashset.hpp" -#include "rwlock.hpp" -#include -#include +#include "fuse.h" +#include "fuse_dirents.h" #include #include @@ -58,11 +57,11 @@ namespace l static int - readdir_plus(const BranchVec &branches_, - const char *dirname_, - const uint64_t entry_timeout_, - const uint64_t attr_timeout_, - fuse_dirents_t *buf_) + readdir_plus(const Branches::CPtr &branches_, + const char *dirname_, + const uint64_t entry_timeout_, + const uint64_t attr_timeout_, + fuse_dirents_t *buf_) { dev_t dev; HashSet names; @@ -80,13 +79,13 @@ namespace l 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++) + for(auto &branch : *branches_) { int rv; int dirfd; DIR *dh; - basepath = fs::path::make(branches_[i].path,dirname_); + basepath = fs::path::make(branch.path,dirname_); dh = fs::opendir(basepath); if(!dh) @@ -94,8 +93,6 @@ namespace l dirfd = fs::dirfd(dh); dev = fs::devid(dirfd); - if(dev == (dev_t)-1) - dev = i; rv = 0; for(struct dirent *de = fs::readdir(dh); de && !rv; de = fs::readdir(dh)) @@ -129,33 +126,16 @@ namespace l return 0; } - - static - int - readdir_plus(const Branches &branches_, - const char *dirname_, - const uint64_t entry_timeout_, - const uint64_t attr_timeout_, - fuse_dirents_t *buf_) - { - rwlock::ReadGuard guard(branches_.lock); - - return l::readdir_plus(branches_.vec, - dirname_, - entry_timeout_, - attr_timeout_, - buf_); - } } namespace FUSE { int - readdir_plus_posix(const Branches &branches_, - const char *dirname_, - const uint64_t entry_timeout_, - const uint64_t attr_timeout_, - fuse_dirents_t *buf_) + readdir_plus_posix(const Branches::CPtr &branches_, + const char *dirname_, + const uint64_t entry_timeout_, + const uint64_t attr_timeout_, + fuse_dirents_t *buf_) { return l::readdir_plus(branches_,dirname_,entry_timeout_,attr_timeout_,buf_); } diff --git a/src/fuse_readdir_plus_posix.hpp b/src/fuse_readdir_plus_posix.hpp index ac040673..910cab5f 100644 --- a/src/fuse_readdir_plus_posix.hpp +++ b/src/fuse_readdir_plus_posix.hpp @@ -18,18 +18,19 @@ #pragma once -#include "branch.hpp" +#include "branches.hpp" -#include +#include "fuse.h" + +#include -#include namespace FUSE { int - readdir_plus_posix(const Branches &branches, - const char *dirname, - const uint64_t entry_timeout, - const uint64_t attr_timeout, - fuse_dirents_t *buf); + readdir_plus_posix(const Branches::CPtr &branches, + const char *dirname, + const uint64_t entry_timeout, + const uint64_t attr_timeout, + fuse_dirents_t *buf); } diff --git a/src/fuse_readdir_posix.cpp b/src/fuse_readdir_posix.cpp index b08f23e0..0e200073 100644 --- a/src/fuse_readdir_posix.cpp +++ b/src/fuse_readdir_posix.cpp @@ -16,7 +16,7 @@ #define _DEFAULT_SOURCE -#include "branch.hpp" +#include "branches.hpp" #include "errno.hpp" #include "fs_closedir.hpp" #include "fs_devid.hpp" @@ -27,10 +27,9 @@ #include "fs_readdir.hpp" #include "fs_stat.hpp" #include "hashset.hpp" -#include "rwlock.hpp" -#include -#include +#include "fuse.h" +#include "fuse_dirents.h" #include #include @@ -40,6 +39,7 @@ using std::string; using std::vector; + namespace l { static @@ -57,9 +57,9 @@ namespace l static int - readdir(const BranchVec &branches_, - const char *dirname_, - fuse_dirents_t *buf_) + readdir(const Branches::CPtr &branches_, + const char *dirname_, + fuse_dirents_t *buf_) { dev_t dev; HashSet names; @@ -69,13 +69,13 @@ namespace l fuse_dirents_reset(buf_); - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(const auto &branch : *branches_) { int rv; int dirfd; DIR *dh; - basepath = fs::path::make(branches_[i].path,dirname_); + basepath = fs::path::make(branch.path,dirname_); dh = fs::opendir(basepath); if(!dh) @@ -83,8 +83,6 @@ namespace l dirfd = fs::dirfd(dh); dev = fs::devid(dirfd); - if(dev == (dev_t)-1) - dev = i; rv = 0; for(struct dirent *de = fs::readdir(dh); de && !rv; de = fs::readdir(dh)) @@ -112,25 +110,14 @@ namespace l return 0; } - - static - int - readdir(const Branches &branches_, - const char *dirname_, - fuse_dirents_t *buf_) - { - rwlock::ReadGuard guard(branches_.lock); - - return l::readdir(branches_.vec,dirname_,buf_); - } } namespace FUSE { int - readdir_posix(const Branches &branches_, - const char *dirname_, - fuse_dirents_t *buf_) + readdir_posix(const Branches::CPtr &branches_, + const char *dirname_, + fuse_dirents_t *buf_) { return l::readdir(branches_,dirname_,buf_); } diff --git a/src/fuse_readdir_posix.hpp b/src/fuse_readdir_posix.hpp index 04eea9d3..36d08dbb 100644 --- a/src/fuse_readdir_posix.hpp +++ b/src/fuse_readdir_posix.hpp @@ -18,16 +18,17 @@ #pragma once -#include "branch.hpp" +#include "branches.hpp" -#include +#include "fuse.h" + +#include -#include namespace FUSE { int - readdir_posix(const Branches &branches, - const char *dirname, - fuse_dirents_t *buf); + readdir_posix(const Branches::CPtr &branches, + const char *dirname, + fuse_dirents_t *buf); } diff --git a/src/fuse_readlink.cpp b/src/fuse_readlink.cpp index 8cebea19..e24354f4 100644 --- a/src/fuse_readlink.cpp +++ b/src/fuse_readlink.cpp @@ -22,12 +22,12 @@ #include "symlinkify.hpp" #include "ugid.hpp" -#include +#include "fuse.h" #include using std::string; -using std::vector; + namespace l { @@ -92,7 +92,7 @@ namespace l static int - readlink(Policy::Func::Search searchFunc_, + readlink(const Policy::Search &searchFunc_, const Branches &branches_, const char *fusepath_, char *buf_, @@ -101,7 +101,7 @@ namespace l const time_t symlinkify_timeout_) { int rv; - vector basepaths; + StrVec basepaths; rv = searchFunc_(branches_,fusepath_,&basepaths); if(rv == -1) @@ -119,16 +119,16 @@ namespace FUSE char *buf_, size_t size_) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::ro(); + Config::Read cfg; + const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - return l::readlink(config.func.readlink.policy, - config.branches, + return l::readlink(cfg->func.readlink.policy, + cfg->branches, fusepath_, buf_, size_, - config.symlinkify, - config.symlinkify_timeout); + cfg->symlinkify, + cfg->symlinkify_timeout); } } diff --git a/src/fuse_readlink.hpp b/src/fuse_readlink.hpp index e9f37a15..b7e5e6f2 100644 --- a/src/fuse_readlink.hpp +++ b/src/fuse_readlink.hpp @@ -16,6 +16,7 @@ #pragma once + namespace FUSE { int diff --git a/src/fuse_release.cpp b/src/fuse_release.cpp index 88c1357e..03b6dcdb 100644 --- a/src/fuse_release.cpp +++ b/src/fuse_release.cpp @@ -20,10 +20,11 @@ #include "fs_close.hpp" #include "fs_fadvise.hpp" -#include +#include "fuse.h" #include + namespace l { static @@ -52,12 +53,9 @@ namespace FUSE int release(const fuse_file_info_t *ffi_) { - const Config &config = Config::ro(); + Config::Read cfg; FileInfo *fi = reinterpret_cast(ffi_->fh); - if(config.open_cache.timeout) - config.open_cache.cleanup(10); - - return l::release(fi,config.dropcacheonclose); + return l::release(fi,cfg->dropcacheonclose); } } diff --git a/src/fuse_release.hpp b/src/fuse_release.hpp index 547490fa..94858839 100644 --- a/src/fuse_release.hpp +++ b/src/fuse_release.hpp @@ -16,7 +16,8 @@ #pragma once -#include +#include "fuse.h" + namespace FUSE { diff --git a/src/fuse_releasedir.cpp b/src/fuse_releasedir.cpp index b4a096ac..8a7c15c5 100644 --- a/src/fuse_releasedir.cpp +++ b/src/fuse_releasedir.cpp @@ -17,7 +17,8 @@ #include "config.hpp" #include "dirinfo.hpp" -#include +#include "fuse.h" + namespace l { diff --git a/src/fuse_releasedir.hpp b/src/fuse_releasedir.hpp index caf7acce..28d278e0 100644 --- a/src/fuse_releasedir.hpp +++ b/src/fuse_releasedir.hpp @@ -16,7 +16,8 @@ #pragma once -#include +#include "fuse.h" + namespace FUSE { diff --git a/src/fuse_removexattr.cpp b/src/fuse_removexattr.cpp index 9f0ba7ef..d22367ac 100644 --- a/src/fuse_removexattr.cpp +++ b/src/fuse_removexattr.cpp @@ -21,7 +21,7 @@ #include "policy_rv.hpp" #include "ugid.hpp" -#include +#include "fuse.h" #include #include @@ -84,8 +84,8 @@ namespace l static int - removexattr(Policy::Func::Action actionFunc_, - Policy::Func::Search searchFunc_, + removexattr(const Policy::Action &actionFunc_, + const Policy::Search &searchFunc_, const Branches &branches_, const char *fusepath_, const char *attrname_) @@ -119,19 +119,20 @@ namespace FUSE removexattr(const char *fusepath_, const char *attrname_) { - const Config &config = Config::ro(); + Config::Read cfg; - if(fusepath_ == config.controlfile) + if(fusepath_ == CONTROLFILE) return -ENOATTR; - if(config.xattr.to_int()) - return -config.xattr.to_int(); + + if(cfg->xattr.to_int()) + return -cfg->xattr.to_int(); const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - return l::removexattr(config.func.removexattr.policy, - config.func.getxattr.policy, - config.branches, + return l::removexattr(cfg->func.removexattr.policy, + cfg->func.getxattr.policy, + cfg->branches, fusepath_, attrname_); } diff --git a/src/fuse_removexattr.hpp b/src/fuse_removexattr.hpp index 7dbef5de..4c7357f9 100644 --- a/src/fuse_removexattr.hpp +++ b/src/fuse_removexattr.hpp @@ -16,6 +16,7 @@ #pragma once + namespace FUSE { int diff --git a/src/fuse_rename.cpp b/src/fuse_rename.cpp index e9fdf0cf..541bce8e 100644 --- a/src/fuse_rename.cpp +++ b/src/fuse_rename.cpp @@ -24,10 +24,8 @@ #include #include -#include using std::string; -using std::vector; namespace error @@ -52,8 +50,8 @@ namespace error static bool -member(const vector &haystack, - const string &needle) +member(const StrVec &haystack, + const string &needle) { for(size_t i = 0, ei = haystack.size(); i != ei; i++) { @@ -66,7 +64,7 @@ member(const vector &haystack, static void -_remove(const vector &toremove) +_remove(const StrVec &toremove) { for(size_t i = 0, ei = toremove.size(); i != ei; i++) fs::remove(toremove[i]); @@ -74,14 +72,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 StrVec &oldbasepaths, + const string &oldbasepath, + const string &newbasepath, + const char *oldfusepath, + const char *newfusepath, + const string &newfusedirpath, + int &error, + StrVec &tounlink) { int rv; bool ismember; @@ -114,19 +112,19 @@ _rename_create_path_core(const vector &oldbasepaths, static int -_rename_create_path(Policy::Func::Search searchFunc, - Policy::Func::Action actionFunc, - const Branches &branches_, +_rename_create_path(const Policy::Search &searchFunc, + const Policy::Action &actionFunc, + const Branches::CPtr &branches_, const char *oldfusepath, const char *newfusepath) { int rv; int error; string newfusedirpath; - vector toremove; - vector newbasepath; - vector oldbasepaths; - vector branches; + StrVec toremove; + StrVec newbasepath; + StrVec oldbasepaths; + StrVec branches; rv = actionFunc(branches_,oldfusepath,&oldbasepaths); if(rv == -1) @@ -134,11 +132,11 @@ _rename_create_path(Policy::Func::Search searchFunc, newfusedirpath = fs::path::dirname(newfusepath); - rv = searchFunc(branches_,newfusedirpath,&newbasepath); + rv = searchFunc(branches_,newfusedirpath.c_str(),&newbasepath); if(rv == -1) return -errno; - branches_.to_paths(branches); + branches_->to_paths(branches); error = -1; for(size_t i = 0, ei = branches.size(); i != ei; i++) @@ -161,15 +159,15 @@ _rename_create_path(Policy::Func::Search searchFunc, static int -_clonepath(Policy::Func::Search searchFunc, - const Branches &branches_, +_clonepath(const Policy::Search &searchFunc, + const Branches::CPtr &branches_, const string &dstbasepath, const string &fusedirpath) { int rv; - vector srcbasepath; + StrVec srcbasepath; - rv = searchFunc(branches_,fusedirpath,&srcbasepath); + rv = searchFunc(branches_,fusedirpath.c_str(),&srcbasepath); if(rv == -1) return -errno; @@ -180,20 +178,20 @@ _clonepath(Policy::Func::Search searchFunc, static int -_clonepath_if_would_create(Policy::Func::Search searchFunc, - Policy::Func::Create createFunc, - const Branches &branches_, +_clonepath_if_would_create(const Policy::Search &searchFunc, + const Policy::Create &createFunc, + const Branches::CPtr &branches_, const string &oldbasepath, const char *oldfusepath, const char *newfusepath) { int rv; string newfusedirpath; - vector newbasepath; + StrVec newbasepath; newfusedirpath = fs::path::dirname(newfusepath); - rv = createFunc(branches_,newfusedirpath,&newbasepath); + rv = createFunc(branches_,newfusedirpath.c_str(),&newbasepath); if(rv == -1) return rv; @@ -205,15 +203,15 @@ _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 vector &oldbasepaths, +_rename_preserve_path_core(const Policy::Search &searchFunc, + const Policy::Create &createFunc, + const Branches::CPtr &branches_, + const StrVec &oldbasepaths, const string &oldbasepath, const char *oldfusepath, const char *newfusepath, int &error, - vector &toremove) + StrVec &toremove) { int rv; bool ismember; @@ -250,24 +248,24 @@ _rename_preserve_path_core(Policy::Func::Search searchFunc, static int -_rename_preserve_path(Policy::Func::Search searchFunc, - Policy::Func::Action actionFunc, - Policy::Func::Create createFunc, - const Branches &branches_, +_rename_preserve_path(const Policy::Search &searchFunc, + const Policy::Action &actionFunc, + const Policy::Create &createFunc, + const Branches::CPtr &branches_, const char *oldfusepath, const char *newfusepath) { int rv; int error; - vector toremove; - vector oldbasepaths; - vector branches; + StrVec toremove; + StrVec oldbasepaths; + StrVec branches; rv = actionFunc(branches_,oldfusepath,&oldbasepaths); if(rv == -1) return -errno; - branches_.to_paths(branches); + branches_->to_paths(branches); error = -1; for(size_t i = 0, ei = branches.size(); i != ei; i++) @@ -293,23 +291,21 @@ namespace FUSE rename(const char *oldpath, const char *newpath) { - const fuse_context *fc = fuse_get_context(); - Config &config = Config::rw(); + Config::Read cfg; + const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - config.open_cache.erase(oldpath); - - 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, + if(cfg->func.create.policy.path_preserving() && !cfg->ignorepponrename) + return _rename_preserve_path(cfg->func.getattr.policy, + cfg->func.rename.policy, + cfg->func.create.policy, + cfg->branches, oldpath, newpath); - return _rename_create_path(config.func.getattr.policy, - config.func.rename.policy, - config.branches, + return _rename_create_path(cfg->func.getattr.policy, + cfg->func.rename.policy, + cfg->branches, oldpath, newpath); } diff --git a/src/fuse_rename.hpp b/src/fuse_rename.hpp index affa01d2..abbcf515 100644 --- a/src/fuse_rename.hpp +++ b/src/fuse_rename.hpp @@ -16,6 +16,7 @@ #pragma once + namespace FUSE { int diff --git a/src/fuse_rmdir.cpp b/src/fuse_rmdir.cpp index 9c650caf..c7c6e107 100644 --- a/src/fuse_rmdir.cpp +++ b/src/fuse_rmdir.cpp @@ -20,7 +20,7 @@ #include "fs_path.hpp" #include "ugid.hpp" -#include +#include "fuse.h" #include @@ -66,8 +66,8 @@ namespace l static int - rmdir_loop(const vector &basepaths_, - const char *fusepath_) + rmdir_loop(const StrVec &basepaths_, + const char *fusepath_) { int error; @@ -82,7 +82,7 @@ namespace l static int - rmdir(Policy::Func::Action actionFunc_, + rmdir(const Policy::Action &actionFunc_, const Branches &branches_, const char *fusepath_) { @@ -102,12 +102,12 @@ namespace FUSE int rmdir(const char *fusepath_) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::ro(); + Config::Read cfg; + const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - return l::rmdir(config.func.rmdir.policy, - config.branches, + return l::rmdir(cfg->func.rmdir.policy, + cfg->branches, fusepath_); } } diff --git a/src/fuse_rmdir.hpp b/src/fuse_rmdir.hpp index 0c59659c..d2782468 100644 --- a/src/fuse_rmdir.hpp +++ b/src/fuse_rmdir.hpp @@ -16,6 +16,7 @@ #pragma once + namespace FUSE { int diff --git a/src/fuse_setxattr.cpp b/src/fuse_setxattr.cpp index 6bb9d041..c46bc7c1 100644 --- a/src/fuse_setxattr.cpp +++ b/src/fuse_setxattr.cpp @@ -25,7 +25,7 @@ #include "str.hpp" #include "ugid.hpp" -#include +#include "fuse.h" #include #include @@ -69,31 +69,30 @@ namespace l static int - setxattr_controlfile(Config &config_, - const string &attrname_, + setxattr_controlfile(const string &attrname_, const string &attrval_, const int flags_) { int rv; string key; + Config::Write cfg; if(!str::startswith(attrname_,"user.mergerfs.")) return -ENOATTR; key = &attrname_[14]; - if(config_.has_key(key) == false) + if(cfg->has_key(key) == false) return -ENOATTR; if((flags_ & XATTR_CREATE) == XATTR_CREATE) return -EEXIST; - rv = config_.set(key,attrval_); + rv = cfg->set(key,attrval_); if(rv < 0) return rv; - config_.open_cache.clear(); - fs::statvfs_cache_timeout(config_.cache_statfs); + fs::statvfs_cache_timeout(cfg->cache_statfs); return rv; } @@ -120,13 +119,13 @@ namespace l static void - setxattr_loop(const vector &basepaths_, - const char *fusepath_, - const char *attrname_, - const char *attrval_, - const size_t attrvalsize_, - const int flags_, - PolicyRV *prv_) + setxattr_loop(const StrVec &basepaths_, + const char *fusepath_, + const char *attrname_, + const char *attrval_, + const size_t attrvalsize_, + const int flags_, + PolicyRV *prv_) { for(size_t i = 0, ei = basepaths_.size(); i != ei; i++) { @@ -138,8 +137,8 @@ namespace l static int - setxattr(Policy::Func::Action actionFunc_, - Policy::Func::Search searchFunc_, + setxattr(const Policy::Action &setxattrPolicy_, + const Policy::Search &getxattrPolicy_, const Branches &branches_, const char *fusepath_, const char *attrname_, @@ -149,9 +148,9 @@ namespace l { int rv; PolicyRV prv; - vector basepaths; + StrVec basepaths; - rv = actionFunc_(branches_,fusepath_,&basepaths); + rv = setxattrPolicy_(branches_,fusepath_,&basepaths); if(rv == -1) return -errno; @@ -162,16 +161,13 @@ namespace l return prv.error[0].rv; basepaths.clear(); - rv = searchFunc_(branches_,fusepath_,&basepaths); + rv = getxattrPolicy_(branches_,fusepath_,&basepaths); if(rv == -1) return -errno; return l::get_error(prv,basepaths[0]); } -} -namespace FUSE -{ int setxattr(const char *fusepath_, const char *attrname_, @@ -179,27 +175,21 @@ namespace FUSE size_t attrvalsize_, int flags_) { - Config &config = Config::rw(); - - if(fusepath_ == config.controlfile) - return l::setxattr_controlfile(config, - attrname_, - string(attrval_,attrvalsize_), - flags_); + Config::Read cfg; - if((config.security_capability == false) && + if((cfg->security_capability == false) && l::is_attrname_security_capability(attrname_)) return -ENOATTR; - if(config.xattr.to_int()) - return -config.xattr.to_int(); + if(cfg->xattr.to_int()) + return -cfg->xattr.to_int(); const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - return l::setxattr(config.func.setxattr.policy, - config.func.getxattr.policy, - config.branches, + return l::setxattr(cfg->func.setxattr.policy, + cfg->func.getxattr.policy, + cfg->branches, fusepath_, attrname_, attrval_, @@ -207,3 +197,21 @@ namespace FUSE flags_); } } + +namespace FUSE +{ + int + setxattr(const char *fusepath_, + const char *attrname_, + const char *attrval_, + size_t attrvalsize_, + int flags_) + { + if(fusepath_ == CONTROLFILE) + return l::setxattr_controlfile(attrname_, + string(attrval_,attrvalsize_), + flags_); + + return l::setxattr(fusepath_,attrname_,attrval_,attrvalsize_,flags_); + } +} diff --git a/src/fuse_setxattr.hpp b/src/fuse_setxattr.hpp index 2b882b66..6ae1f52e 100644 --- a/src/fuse_setxattr.hpp +++ b/src/fuse_setxattr.hpp @@ -16,6 +16,7 @@ #pragma once + namespace FUSE { int diff --git a/src/fuse_statfs.cpp b/src/fuse_statfs.cpp index 0c15f7bf..68ffb2cf 100644 --- a/src/fuse_statfs.cpp +++ b/src/fuse_statfs.cpp @@ -19,11 +19,10 @@ #include "fs_lstat.hpp" #include "fs_path.hpp" #include "fs_statvfs.hpp" -#include "rwlock.hpp" #include "statvfs_util.hpp" #include "ugid.hpp" -#include +#include "fuse.h" #include #include @@ -35,6 +34,7 @@ using std::string; using std::map; using std::vector; + namespace l { static @@ -69,24 +69,22 @@ namespace l static bool should_ignore(const StatFSIgnore ignore_, - const Branch *branch_, + const Branch &branch_, const bool readonly_) { return ((((ignore_ == StatFSIgnore::ENUM::RO) || readonly_) && - (branch_->ro_or_nc())) || - ((ignore_ == StatFSIgnore::ENUM::NC) && (branch_->nc()))); + (branch_.ro_or_nc())) || + ((ignore_ == StatFSIgnore::ENUM::NC) && (branch_.nc()))); } static int - statfs(const Branches &branches_, - const char *fusepath_, - const StatFS mode_, - const StatFSIgnore ignore_, - struct statvfs *fsstat_) + statfs(const Branches::CPtr &branches_, + const char *fusepath_, + const StatFS mode_, + const StatFSIgnore ignore_, + struct statvfs *fsstat_) { - rwlock::ReadGuard guard(branches_.lock); - int rv; string fullpath; struct stat st; @@ -99,11 +97,11 @@ namespace l min_bsize = std::numeric_limits::max(); min_frsize = std::numeric_limits::max(); min_namemax = std::numeric_limits::max(); - for(size_t i = 0, ei = branches_.vec.size(); i < ei; i++) + for(const auto &branch : *branches_) { fullpath = ((mode_ == StatFS::ENUM::FULL) ? - fs::path::make(branches_.vec[i].path,fusepath_) : - branches_.vec[i].path); + fs::path::make(branch.path,fusepath_) : + branch.path); rv = fs::lstat(fullpath,&st); if(rv == -1) @@ -120,7 +118,7 @@ namespace l if(stvfs.f_namemax && (min_namemax > stvfs.f_namemax)) min_namemax = stvfs.f_namemax; - if(l::should_ignore(ignore_,&branches_.vec[i],StatVFS::readonly(stvfs))) + if(l::should_ignore(ignore_,branch,StatVFS::readonly(stvfs))) { stvfs.f_bavail = 0; stvfs.f_favail = 0; @@ -153,14 +151,14 @@ namespace FUSE statfs(const char *fusepath_, struct statvfs *st_) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::ro(); + Config::Read cfg; + const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - return l::statfs(config.branches, + return l::statfs(cfg->branches, fusepath_, - config.statfs, - config.statfs_ignore, + cfg->statfs, + cfg->statfs_ignore, st_); } } diff --git a/src/fuse_statfs.hpp b/src/fuse_statfs.hpp index 8d0933bb..c34ac43a 100644 --- a/src/fuse_statfs.hpp +++ b/src/fuse_statfs.hpp @@ -18,6 +18,7 @@ #include + namespace FUSE { int diff --git a/src/fuse_symlink.cpp b/src/fuse_symlink.cpp index c332d6f4..cdfb407c 100644 --- a/src/fuse_symlink.cpp +++ b/src/fuse_symlink.cpp @@ -21,7 +21,7 @@ #include "fs_path.hpp" #include "ugid.hpp" -#include +#include "fuse.h" #include @@ -29,7 +29,6 @@ #include using std::string; -using std::vector; namespace error @@ -73,11 +72,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 StrVec &newbasepaths_, + const char *oldpath_, + const char *newpath_, + const string &newdirpath_) { int rv; int error; @@ -100,16 +99,16 @@ namespace l static int - symlink(Policy::Func::Search searchFunc_, - Policy::Func::Create createFunc_, + symlink(const Policy::Search &searchFunc_, + const Policy::Create &createFunc_, const Branches &branches_, const char *oldpath_, const char *newpath_) { int rv; string newdirpath; - vector newbasepaths; - vector existingpaths; + StrVec newbasepaths; + StrVec existingpaths; newdirpath = fs::path::dirname(newpath_); @@ -132,13 +131,13 @@ namespace FUSE symlink(const char *oldpath_, const char *newpath_) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::ro(); + Config::Read cfg; + const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - return l::symlink(config.func.getattr.policy, - config.func.symlink.policy, - config.branches, + return l::symlink(cfg->func.getattr.policy, + cfg->func.symlink.policy, + cfg->branches, oldpath_, newpath_); } diff --git a/src/fuse_symlink.hpp b/src/fuse_symlink.hpp index 561a8300..0bbced2e 100644 --- a/src/fuse_symlink.hpp +++ b/src/fuse_symlink.hpp @@ -16,6 +16,7 @@ #pragma once + namespace FUSE { int diff --git a/src/fuse_truncate.cpp b/src/fuse_truncate.cpp index 331f0c4d..669715a8 100644 --- a/src/fuse_truncate.cpp +++ b/src/fuse_truncate.cpp @@ -21,16 +21,14 @@ #include "policy_rv.hpp" #include "ugid.hpp" -#include +#include "fuse.h" #include -#include #include #include using std::string; -using std::vector; namespace l @@ -74,10 +72,10 @@ namespace l static void - truncate_loop(const vector &basepaths_, - const char *fusepath_, - const off_t size_, - PolicyRV *prv_) + truncate_loop(const StrVec &basepaths_, + const char *fusepath_, + const off_t size_, + PolicyRV *prv_) { for(size_t i = 0, ei = basepaths_.size(); i != ei; i++) { @@ -87,15 +85,15 @@ namespace l static int - truncate(Policy::Func::Action actionFunc_, - Policy::Func::Search searchFunc_, + truncate(const Policy::Action &actionFunc_, + const Policy::Search &searchFunc_, const Branches &branches_, const char *fusepath_, const off_t size_) { int rv; PolicyRV prv; - vector basepaths; + StrVec basepaths; rv = actionFunc_(branches_,fusepath_,&basepaths); if(rv == -1) @@ -122,13 +120,13 @@ namespace FUSE truncate(const char *fusepath_, off_t size_) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::ro(); + Config::Read cfg; + const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - return l::truncate(config.func.truncate.policy, - config.func.getattr.policy, - config.branches, + return l::truncate(cfg->func.truncate.policy, + cfg->func.getattr.policy, + cfg->branches, fusepath_, size_); } diff --git a/src/fuse_truncate.hpp b/src/fuse_truncate.hpp index ea7557db..61331295 100644 --- a/src/fuse_truncate.hpp +++ b/src/fuse_truncate.hpp @@ -18,6 +18,7 @@ #include + namespace FUSE { int diff --git a/src/fuse_unlink.cpp b/src/fuse_unlink.cpp index 507590c1..5f551935 100644 --- a/src/fuse_unlink.cpp +++ b/src/fuse_unlink.cpp @@ -20,7 +20,7 @@ #include "fs_unlink.hpp" #include "ugid.hpp" -#include +#include "fuse.h" #include #include @@ -84,14 +84,14 @@ namespace l static int - unlink(Policy::Func::Action actionFunc_, + unlink(const Policy::Action &unlinkPolicy_, const Branches &branches_, const char *fusepath_) { int rv; vector basepaths; - rv = actionFunc_(branches_,fusepath_,&basepaths); + rv = unlinkPolicy_(branches_,fusepath_,&basepaths); if(rv == -1) return -errno; @@ -104,14 +104,12 @@ namespace FUSE int unlink(const char *fusepath_) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::ro(); + Config::Read cfg; + const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - config.open_cache.erase(fusepath_); - - return l::unlink(config.func.unlink.policy, - config.branches, + return l::unlink(cfg->func.unlink.policy, + cfg->branches, fusepath_); } } diff --git a/src/fuse_unlink.hpp b/src/fuse_unlink.hpp index e7f1a272..845ac186 100644 --- a/src/fuse_unlink.hpp +++ b/src/fuse_unlink.hpp @@ -16,6 +16,7 @@ #pragma once + namespace FUSE { int diff --git a/src/fuse_utimens.cpp b/src/fuse_utimens.cpp index e5a072ac..83c4b584 100644 --- a/src/fuse_utimens.cpp +++ b/src/fuse_utimens.cpp @@ -21,15 +21,13 @@ #include "policy_rv.hpp" #include "ugid.hpp" -#include +#include "fuse.h" #include -#include #include using std::string; -using std::vector; namespace l @@ -73,10 +71,10 @@ namespace l static void - utimens_loop(const vector &basepaths_, - const char *fusepath_, - const timespec ts_[2], - PolicyRV *prv_) + utimens_loop(const StrVec &basepaths_, + const char *fusepath_, + const timespec ts_[2], + PolicyRV *prv_) { for(size_t i = 0, ei = basepaths_.size(); i != ei; i++) { @@ -86,17 +84,17 @@ namespace l static int - utimens(Policy::Func::Action actionFunc_, - Policy::Func::Search searchFunc_, + utimens(const Policy::Action &utimensPolicy_, + const Policy::Search &getattrPolicy_, const Branches &branches_, const char *fusepath_, const timespec ts_[2]) { int rv; PolicyRV prv; - vector basepaths; + StrVec basepaths; - rv = actionFunc_(branches_,fusepath_,&basepaths); + rv = utimensPolicy_(branches_,fusepath_,&basepaths); if(rv == -1) return -errno; @@ -107,7 +105,7 @@ namespace l return prv.error[0].rv; basepaths.clear(); - rv = searchFunc_(branches_,fusepath_,&basepaths); + rv = getattrPolicy_(branches_,fusepath_,&basepaths); if(rv == -1) return -errno; @@ -121,13 +119,13 @@ namespace FUSE utimens(const char *fusepath_, const timespec ts_[2]) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::ro(); + Config::Read cfg; + const fuse_context *fc = fuse_get_context(); const ugid::Set ugid(fc->uid,fc->gid); - return l::utimens(config.func.utimens.policy, - config.func.getattr.policy, - config.branches, + return l::utimens(cfg->func.utimens.policy, + cfg->func.getattr.policy, + cfg->branches, fusepath_, ts_); } diff --git a/src/fuse_utimens.hpp b/src/fuse_utimens.hpp index cb78c181..2b24258e 100644 --- a/src/fuse_utimens.hpp +++ b/src/fuse_utimens.hpp @@ -18,6 +18,7 @@ #include + namespace FUSE { int diff --git a/src/fuse_write.cpp b/src/fuse_write.cpp index 9dbad931..303b6cba 100644 --- a/src/fuse_write.cpp +++ b/src/fuse_write.cpp @@ -21,16 +21,17 @@ #include "fs_write.hpp" #include "ugid.hpp" +#include "fuse.h" + #include #include -#include - using std::string; using std::vector; typedef int (*WriteFunc)(const int,const void*,const size_t,const off_t); + namespace l { static @@ -85,13 +86,13 @@ namespace l int err_) { int rv; - const Config &config = Config::ro(); + Config::Read cfg; - if(config.moveonenospc.enabled == false) + if(cfg->moveonenospc.enabled == false) return err_; - rv = fs::movefile_as_root(config.moveonenospc.policy, - config.branches, + rv = fs::movefile_as_root(cfg->moveonenospc.policy, + cfg->branches, fi_->fusepath, &fi_->fd); if(rv == -1) diff --git a/src/fuse_write.hpp b/src/fuse_write.hpp index 7d439b7c..abbfd093 100644 --- a/src/fuse_write.hpp +++ b/src/fuse_write.hpp @@ -16,7 +16,8 @@ #pragma once -#include +#include "fuse.h" + namespace FUSE { diff --git a/src/fuse_write_buf.cpp b/src/fuse_write_buf.cpp index 899e377e..fb06e4de 100644 --- a/src/fuse_write_buf.cpp +++ b/src/fuse_write_buf.cpp @@ -31,6 +31,7 @@ using std::string; using std::vector; + namespace l { static @@ -67,13 +68,13 @@ namespace l int err_) { int rv; - const Config &config = Config::ro(); + Config::Read cfg; - if(config.moveonenospc.enabled == false) + if(cfg->moveonenospc.enabled == false) return err_; - rv = fs::movefile_as_root(config.moveonenospc.policy, - config.branches, + rv = fs::movefile_as_root(cfg->moveonenospc.policy, + cfg->branches, fi_->fusepath, &fi_->fd); if(rv == -1) diff --git a/src/fuse_write_buf.hpp b/src/fuse_write_buf.hpp index cf225918..be4779df 100644 --- a/src/fuse_write_buf.hpp +++ b/src/fuse_write_buf.hpp @@ -16,10 +16,11 @@ #pragma once -#include +#include "fuse.h" #include + namespace FUSE { int diff --git a/src/hw_cpu.cpp b/src/hw_cpu.cpp index c65e713b..b829c2fc 100644 --- a/src/hw_cpu.cpp +++ b/src/hw_cpu.cpp @@ -18,6 +18,7 @@ #include + namespace hw { namespace cpu diff --git a/src/hw_cpu.hpp b/src/hw_cpu.hpp index dd17c1de..7c702219 100644 --- a/src/hw_cpu.hpp +++ b/src/hw_cpu.hpp @@ -18,6 +18,7 @@ #pragma once + namespace hw { namespace cpu diff --git a/src/mergerfs.cpp b/src/mergerfs.cpp index a5b65a15..11c7fc67 100644 --- a/src/mergerfs.cpp +++ b/src/mergerfs.cpp @@ -18,6 +18,7 @@ #include "mergerfs.hpp" #include "option_parser.hpp" #include "resources.hpp" +#include "strvec.hpp" #include "fuse_access.hpp" #include "fuse_chmod.hpp" @@ -66,13 +67,14 @@ #include "fuse_write.hpp" #include "fuse_write_buf.hpp" -#include +#include "fuse.h" #include #include #include + namespace l { static @@ -151,10 +153,10 @@ namespace l main(const int argc_, char **argv_) { - Config config; - fuse_args args; - fuse_operations ops; - std::vector errs; + Config::Read cfg; + Config::ErrVec errs; + fuse_args args; + fuse_operations ops; memset(&ops,0,sizeof(fuse_operations)); @@ -162,22 +164,17 @@ namespace l args.argv = argv_; args.allocated = 0; - options::parse(&args,&config,&errs); + options::parse(&args,&errs); if(errs.size()) - { - for(uint64_t i = 0; i < errs.size(); i++) - std::cerr << "* ERROR: " << errs[i] << std::endl; - - return 1; - } + std::cerr << errs << std::endl; l::setup_resources(); - l::get_fuse_operations(ops,config.nullrw); + l::get_fuse_operations(ops,cfg->nullrw); return fuse_main(args.argc, args.argv, &ops, - &config); + NULL); } } diff --git a/src/num.cpp b/src/num.cpp index 67ad43b7..667be092 100644 --- a/src/num.cpp +++ b/src/num.cpp @@ -16,9 +16,9 @@ #include "ef.hpp" +#include #include -#include #include #include #include @@ -28,6 +28,7 @@ #define GB (MB * 1024UL) #define TB (GB * 1024UL) + namespace num { int diff --git a/src/num.hpp b/src/num.hpp index 40ba30c2..4e8dc79e 100644 --- a/src/num.hpp +++ b/src/num.hpp @@ -16,10 +16,11 @@ #pragma once -#include - +#include #include +#include + namespace num { int to_uint64_t(const std::string &str, uint64_t *value); diff --git a/src/option_parser.cpp b/src/option_parser.cpp index 5646ee14..519b52c3 100644 --- a/src/option_parser.cpp +++ b/src/option_parser.cpp @@ -25,7 +25,7 @@ #include "str.hpp" #include "version.hpp" -#include +#include "fuse.h" #include #include @@ -48,12 +48,6 @@ enum MERGERFS_OPT_VERSION }; -struct Data -{ - Config *config; - vector *errs; -}; - namespace l { @@ -74,140 +68,81 @@ namespace l 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); - if(!is.eof()) - data_->errs->push_back("failure reading config file"); - is.close(); - } - } } static void -set_option(fuse_args *args, - const std::string &option_) +set_option(const std::string &option_, + fuse_args *args_) { - fuse_opt_add_arg(args,"-o"); - fuse_opt_add_arg(args,option_.c_str()); + fuse_opt_add_arg(args_,"-o"); + fuse_opt_add_arg(args_,option_.c_str()); } static void -set_kv_option(fuse_args *args, - const std::string &key, - const std::string &value) +set_kv_option(const std::string &key_, + const std::string &val_, + fuse_args *args_) { std::string option; - option = key + '=' + value; + option = key_ + '=' + val_; - set_option(args,option); + set_option(option,args_); } static void -set_threads(fuse_args *args_, - Config *config_) +set_threads(Config::Write &cfg_, + fuse_args *args_) { int threads; - threads = l::calculate_thread_count(config_->threads); + threads = l::calculate_thread_count(cfg_->threads); - config_->threads = threads; + cfg_->threads = threads; - set_kv_option(args_,"threads",config_->threads.to_string()); + set_kv_option("threads",cfg_->threads.to_string(),args_); } static void -set_fsname(fuse_args *args_, - Config *config_) +set_fsname(Config::Write &cfg_, + fuse_args *args_) { - if(config_->fsname->empty()) + if(cfg_->fsname->empty()) { - vector branches; + vector paths; - config_->branches.to_paths(branches); + cfg_->branches->to_paths(paths); - if(branches.size() > 0) - config_->fsname = str::remove_common_prefix_and_join(branches,':'); + if(paths.size() > 0) + cfg_->fsname = str::remove_common_prefix_and_join(paths,':'); } - set_kv_option(args_,"fsname",config_->fsname); + set_kv_option("fsname",cfg_->fsname,args_); } static void -set_subtype(fuse_args *args) +set_subtype(fuse_args *args_) { - set_kv_option(args,"subtype","mergerfs"); + set_kv_option("subtype","mergerfs",args_); } static void -set_default_options(fuse_args *args) +set_default_options(fuse_args *args_) { - set_option(args,"default_permissions"); + set_option("default_permissions",args_); } static int -parse_and_process_kv_arg(Data *data_, +parse_and_process_kv_arg(Config::Write &cfg_, + Config::ErrVec *errs_, const std::string &key_, const std::string &val_) { @@ -217,7 +152,7 @@ parse_and_process_kv_arg(Data *data_, rv = 0; if(key == "config") - return (l::read_config(data_,val_),0); + return ((cfg_->from_file(val_,errs_) < 0) ? 1 : 0); ef(key == "attr_timeout") key = "cache.attr"; ef(key == "entry_timeout") @@ -245,57 +180,62 @@ parse_and_process_kv_arg(Data *data_, ef(key == "cache.open") return 0; - if(data_->config->has_key(key) == false) + if(cfg_->has_key(key) == false) return 1; - rv = data_->config->set_raw(key,val); + rv = cfg_->set_raw(key,val); if(rv) - data_->errs->push_back("invalid argument - " + key_ + '=' + val_); + errs_->push_back({rv,key+'='+val}); return 0; } static int -process_opt(Data *data_, +process_opt(Config::Write &cfg_, + Config::ErrVec *errs_, const std::string &arg_) { std::string key; std::string val; str::splitkv(arg_,'=',&key,&val); + key = str::trim(key); + val = str::trim(val); - return parse_and_process_kv_arg(data_,key,val); + return parse_and_process_kv_arg(cfg_,errs_,key,val); } static int -process_branches(Data *data_, - const char *arg_) +process_branches(Config::Write &cfg_, + Config::ErrVec *errs_, + const char *arg_) { int rv; string arg; arg = arg_; - rv = data_->config->set_raw("branches",arg); + rv = cfg_->set_raw("branches",arg); if(rv) - data_->errs->push_back("unable to parse 'branches' - " + arg); + errs_->push_back({rv,"branches="+arg}); return 0; } static int -process_mount(Data *data_, - const char *arg_) +process_mount(Config::Write &cfg_, + Config::ErrVec *errs_, + const char *arg_) { int rv; string arg; arg = arg_; - rv = data_->config->set_raw("mount",arg); + rv = cfg_->set_raw("mount",arg); if(rv) - data_->errs->push_back("unable to set 'mount' - " + arg); + errs_->push_back({rv,"mount="+arg}); return 1; } @@ -412,18 +352,19 @@ option_processor(void *data_, int key_, fuse_args *outargs_) { - Data *data = (Data*)data_; + Config::Write cfg; + Config::ErrVec *errs = (Config::ErrVec*)data_; switch(key_) { case FUSE_OPT_KEY_OPT: - return process_opt(data,arg_); + return process_opt(cfg,errs,arg_); case FUSE_OPT_KEY_NONOPT: - if(data->config->branches.vec.empty()) - return process_branches(data,arg_); + if(cfg->branches->empty()) + return process_branches(cfg,errs,arg_); else - return process_mount(data,arg_); + return process_mount(cfg,errs,arg_); case MERGERFS_OPT_HELP: usage(); @@ -445,11 +386,10 @@ option_processor(void *data_, namespace options { void - parse(fuse_args *args_, - Config *config_, - std::vector *errs_) + parse(fuse_args *args_, + Config::ErrVec *errs_) { - Data data; + Config::Write cfg; const struct fuse_opt opts[] = { FUSE_OPT_KEY("-h",MERGERFS_OPT_HELP), @@ -460,21 +400,19 @@ namespace options {NULL,-1U,0} }; - data.config = config_; - data.errs = errs_; fuse_opt_parse(args_, - &data, + errs_, opts, ::option_processor); - if(config_->branches.vec.empty()) - errs_->push_back("branches not set"); - if(config_->mount->empty()) - errs_->push_back("mountpoint not set"); + if(cfg->branches->empty()) + errs_->push_back({0,"branches not set"}); + if(cfg->mount->empty()) + errs_->push_back({0,"mountpoint not set"}); set_default_options(args_); - set_fsname(args_,config_); + set_fsname(cfg,args_); set_subtype(args_); - set_threads(args_,config_); + set_threads(cfg,args_); } } diff --git a/src/option_parser.hpp b/src/option_parser.hpp index 324eb905..1e9c4122 100644 --- a/src/option_parser.hpp +++ b/src/option_parser.hpp @@ -18,15 +18,12 @@ #include "config.hpp" -#include -#include +#include "fuse.h" -#include namespace options { void - parse(fuse_args *args, - Config *config, - std::vector *errs); + parse(fuse_args *args, + Config::ErrVec *errs); } diff --git a/src/policies.cpp b/src/policies.cpp new file mode 100644 index 00000000..dc64370c --- /dev/null +++ b/src/policies.cpp @@ -0,0 +1,132 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "policies.hpp" + +#define IFERTA(X) if(name_ == #X) return &Policies::Action::X; +#define IFERTC(X) if(name_ == #X) return &Policies::Create::X; +#define IFERTS(X) if(name_ == #X) return &Policies::Search::X; + +#define IFERT(FUNC) \ + FUNC(all) \ + FUNC(epall) \ + FUNC(epff) \ + FUNC(eplfs) \ + FUNC(eplus) \ + FUNC(epmfs) \ + FUNC(eppfrd) \ + FUNC(eprand) \ + FUNC(erofs) \ + FUNC(ff) \ + FUNC(lfs) \ + FUNC(lus) \ + FUNC(mfs) \ + FUNC(msplfs) \ + FUNC(msplus) \ + FUNC(mspmfs) \ + FUNC(msppfrd) \ + FUNC(newest) \ + FUNC(pfrd) \ + FUNC(rand) + +Policy::ActionImpl* +Policies::Action::find(const std::string &name_) +{ + IFERT(IFERTA); + + return NULL; +} + +Policy::CreateImpl* +Policies::Create::find(const std::string &name_) +{ + IFERT(IFERTC); + + return NULL; +} + +Policy::SearchImpl* +Policies::Search::find(const std::string &name_) +{ + IFERT(IFERTS); + + return NULL; +} + +Policy::All::Action Policies::Action::all; +Policy::EPAll::Action Policies::Action::epall; +Policy::EPFF::Action Policies::Action::epff; +Policy::EPLFS::Action Policies::Action::eplfs; +Policy::EPLUS::Action Policies::Action::eplus; +Policy::EPMFS::Action Policies::Action::epmfs; +Policy::EPPFRD::Action Policies::Action::eppfrd; +Policy::EPRand::Action Policies::Action::eprand; +Policy::ERoFS::Action Policies::Action::erofs; +Policy::FF::Action Policies::Action::ff; +Policy::LFS::Action Policies::Action::lfs; +Policy::LUS::Action Policies::Action::lus; +Policy::MFS::Action Policies::Action::mfs; +Policy::MSPLFS::Action Policies::Action::msplfs; +Policy::MSPLUS::Action Policies::Action::msplus; +Policy::MSPMFS::Action Policies::Action::mspmfs; +Policy::MSPPFRD::Action Policies::Action::msppfrd; +Policy::Newest::Action Policies::Action::newest; +Policy::PFRD::Action Policies::Action::pfrd; +Policy::Rand::Action Policies::Action::rand; + +Policy::All::Create Policies::Create::all; +Policy::EPAll::Create Policies::Create::epall; +Policy::EPFF::Create Policies::Create::epff; +Policy::EPLFS::Create Policies::Create::eplfs; +Policy::EPLUS::Create Policies::Create::eplus; +Policy::EPMFS::Create Policies::Create::epmfs; +Policy::EPPFRD::Create Policies::Create::eppfrd; +Policy::EPRand::Create Policies::Create::eprand; +Policy::ERoFS::Create Policies::Create::erofs; +Policy::FF::Create Policies::Create::ff; +Policy::LFS::Create Policies::Create::lfs; +Policy::LUS::Create Policies::Create::lus; +Policy::MFS::Create Policies::Create::mfs; +Policy::MSPLFS::Create Policies::Create::msplfs; +Policy::MSPLUS::Create Policies::Create::msplus; +Policy::MSPMFS::Create Policies::Create::mspmfs; +Policy::MSPPFRD::Create Policies::Create::msppfrd; +Policy::Newest::Create Policies::Create::newest; +Policy::PFRD::Create Policies::Create::pfrd; +Policy::Rand::Create Policies::Create::rand; + +Policy::All::Search Policies::Search::all; +Policy::EPAll::Search Policies::Search::epall; +Policy::EPFF::Search Policies::Search::epff; +Policy::EPLFS::Search Policies::Search::eplfs; +Policy::EPLUS::Search Policies::Search::eplus; +Policy::EPMFS::Search Policies::Search::epmfs; +Policy::EPPFRD::Search Policies::Search::eppfrd; +Policy::EPRand::Search Policies::Search::eprand; +Policy::ERoFS::Search Policies::Search::erofs; +Policy::FF::Search Policies::Search::ff; +Policy::LFS::Search Policies::Search::lfs; +Policy::LUS::Search Policies::Search::lus; +Policy::MFS::Search Policies::Search::mfs; +Policy::MSPLFS::Search Policies::Search::msplfs; +Policy::MSPLUS::Search Policies::Search::msplus; +Policy::MSPMFS::Search Policies::Search::mspmfs; +Policy::MSPPFRD::Search Policies::Search::msppfrd; +Policy::Newest::Search Policies::Search::newest; +Policy::PFRD::Search Policies::Search::pfrd; +Policy::Rand::Search Policies::Search::rand; diff --git a/src/policies.hpp b/src/policies.hpp new file mode 100644 index 00000000..65d7f7a0 --- /dev/null +++ b/src/policies.hpp @@ -0,0 +1,121 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy_all.hpp" +#include "policy_epall.hpp" +#include "policy_epff.hpp" +#include "policy_eplfs.hpp" +#include "policy_eplus.hpp" +#include "policy_epmfs.hpp" +#include "policy_eppfrd.hpp" +#include "policy_eprand.hpp" +#include "policy_erofs.hpp" +#include "policy_ff.hpp" +#include "policy_lfs.hpp" +#include "policy_lus.hpp" +#include "policy_mfs.hpp" +#include "policy_msplfs.hpp" +#include "policy_msplus.hpp" +#include "policy_mspmfs.hpp" +#include "policy_msppfrd.hpp" +#include "policy_newest.hpp" +#include "policy_pfrd.hpp" +#include "policy_rand.hpp" + +struct Policies +{ + struct Action + { + static Policy::ActionImpl *find(const std::string &name); + + static Policy::All::Action all; + static Policy::EPAll::Action epall; + static Policy::EPFF::Action epff; + static Policy::EPLFS::Action eplfs; + static Policy::EPLUS::Action eplus; + static Policy::EPMFS::Action epmfs; + static Policy::EPPFRD::Action eppfrd; + static Policy::EPRand::Action eprand; + static Policy::ERoFS::Action erofs; + static Policy::FF::Action ff; + static Policy::LFS::Action lfs; + static Policy::LUS::Action lus; + static Policy::MFS::Action mfs; + static Policy::MSPLFS::Action msplfs; + static Policy::MSPLUS::Action msplus; + static Policy::MSPMFS::Action mspmfs; + static Policy::MSPPFRD::Action msppfrd; + static Policy::Newest::Action newest; + static Policy::PFRD::Action pfrd; + static Policy::Rand::Action rand; + }; + + struct Create + { + static Policy::CreateImpl *find(const std::string &name); + + static Policy::All::Create all; + static Policy::EPAll::Create epall; + static Policy::EPFF::Create epff; + static Policy::EPLFS::Create eplfs; + static Policy::EPLUS::Create eplus; + static Policy::EPMFS::Create epmfs; + static Policy::EPPFRD::Create eppfrd; + static Policy::EPRand::Create eprand; + static Policy::ERoFS::Create erofs; + static Policy::FF::Create ff; + static Policy::LFS::Create lfs; + static Policy::LUS::Create lus; + static Policy::MFS::Create mfs; + static Policy::MSPLFS::Create msplfs; + static Policy::MSPLUS::Create msplus; + static Policy::MSPMFS::Create mspmfs; + static Policy::MSPPFRD::Create msppfrd; + static Policy::Newest::Create newest; + static Policy::PFRD::Create pfrd; + static Policy::Rand::Create rand; + }; + + struct Search + { + static Policy::SearchImpl *find(const std::string &name); + + static Policy::All::Search all; + static Policy::EPAll::Search epall; + static Policy::EPFF::Search epff; + static Policy::EPLFS::Search eplfs; + static Policy::EPLUS::Search eplus; + static Policy::EPMFS::Search epmfs; + static Policy::EPPFRD::Search eppfrd; + static Policy::EPRand::Search eprand; + static Policy::ERoFS::Search erofs; + static Policy::FF::Search ff; + static Policy::LFS::Search lfs; + static Policy::LUS::Search lus; + static Policy::MFS::Search mfs; + static Policy::MSPLFS::Search msplfs; + static Policy::MSPLUS::Search msplus; + static Policy::MSPMFS::Search mspmfs; + static Policy::MSPPFRD::Search msppfrd; + static Policy::Newest::Search newest; + static Policy::PFRD::Search pfrd; + static Policy::Rand::Search rand; + }; +}; diff --git a/src/policy.cpp b/src/policy.cpp deleted file mode 100644 index 3e854bad..00000000 --- a/src/policy.cpp +++ /dev/null @@ -1,96 +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 "buildvector.hpp" -#include "policy.hpp" - -#define POLICY(X,PP) (Policy(Policy::Enum::X,#X,Policy::Func::X,PP)) -#define PRESERVES_PATH true -#define DOESNT_PRESERVE_PATH false - -const std::vector Policy::_policies_ = - buildvector - (POLICY(invalid,DOESNT_PRESERVE_PATH)) - (POLICY(all,DOESNT_PRESERVE_PATH)) - (POLICY(epall,PRESERVES_PATH)) - (POLICY(epff,PRESERVES_PATH)) - (POLICY(eplfs,PRESERVES_PATH)) - (POLICY(eplus,PRESERVES_PATH)) - (POLICY(epmfs,PRESERVES_PATH)) - (POLICY(eppfrd,PRESERVES_PATH)) - (POLICY(eprand,PRESERVES_PATH)) - (POLICY(erofs,DOESNT_PRESERVE_PATH)) - (POLICY(ff,DOESNT_PRESERVE_PATH)) - (POLICY(lfs,DOESNT_PRESERVE_PATH)) - (POLICY(lus,DOESNT_PRESERVE_PATH)) - (POLICY(mfs,DOESNT_PRESERVE_PATH)) - (POLICY(msplfs,PRESERVES_PATH)) - (POLICY(msplus,PRESERVES_PATH)) - (POLICY(mspmfs,PRESERVES_PATH)) - (POLICY(msppfrd,PRESERVES_PATH)) - (POLICY(newest,DOESNT_PRESERVE_PATH)) - (POLICY(pfrd,DOESNT_PRESERVE_PATH)) - (POLICY(rand,DOESNT_PRESERVE_PATH)); - -const Policy * const Policy::policies = &_policies_[1]; - -#define CONST_POLICY(X) const Policy &Policy::X = Policy::policies[Policy::Enum::X] - -CONST_POLICY(invalid); -CONST_POLICY(all); -CONST_POLICY(epall); -CONST_POLICY(epff); -CONST_POLICY(eplfs); -CONST_POLICY(eplus); -CONST_POLICY(epmfs); -CONST_POLICY(eppfrd); -CONST_POLICY(eprand); -CONST_POLICY(erofs); -CONST_POLICY(ff); -CONST_POLICY(lfs); -CONST_POLICY(lus); -CONST_POLICY(mfs); -CONST_POLICY(msplfs); -CONST_POLICY(msplus); -CONST_POLICY(mspmfs); -CONST_POLICY(msppfrd); -CONST_POLICY(newest); -CONST_POLICY(pfrd); -CONST_POLICY(rand); - -const Policy& -Policy::find(const std::string &str) -{ - for(int i = Enum::BEGIN; i != Enum::END; ++i) - { - if(policies[i] == str) - return policies[i]; - } - - return invalid; -} - -const Policy& -Policy::find(const Policy::Enum::Type i) -{ - if(i >= Policy::Enum::BEGIN && - i < Policy::Enum::END) - return policies[i]; - - return invalid; -} diff --git a/src/policy.hpp b/src/policy.hpp index 1663e618..e527b94a 100644 --- a/src/policy.hpp +++ b/src/policy.hpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2016, Antonio SJ Musumeci + Copyright (c) 2020, Antonio SJ Musumeci Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -16,217 +16,179 @@ #pragma once -#include "branch.hpp" -#include "category.hpp" +#include "branches.hpp" +#include "strvec.hpp" #include -#include -class Policy +namespace Policy { -public: - struct Enum + class ActionImpl { - enum Type - { - invalid = -1, - BEGIN = 0, - all = BEGIN, - epall, - epff, - eplfs, - eplus, - epmfs, - eppfrd, - eprand, - erofs, - ff, - lfs, - lus, - mfs, - msplfs, - msplus, - mspmfs, - msppfrd, - newest, - pfrd, - rand, - END - }; - - static size_t begin() { return BEGIN; } - static size_t end() { return END; } + public: + ActionImpl(const std::string &name_) + : name(name_) + { + } + + public: + std::string name; + virtual int operator()(const Branches::CPtr&,const char*,StrVec*) const = 0; }; - struct Func + class Action { - typedef std::string string; - typedef std::vector strvec; - typedef const string cstring; - typedef const uint64_t cuint64_t; - typedef const strvec cstrvec; - - typedef int (*Ptr)(Category,const Branches&,const char*,strvec *); - - template - class Base - { - public: - Base(const Policy &p_) - : func(p_._func) - {} - - Base(const Policy *p_) - : func(p_->_func) - {} - - int - operator()(const Branches &a,const char *b,strvec *c) - { - return func(T,a,b,c); - } - - int - operator()(const Branches &a,const string &b,strvec *c) - { - return func(T,a,b.c_str(),c); - } - - int - operator()(const Branches &a,const char *b,string *c) - { - int rv; - strvec v; - - rv = func(T,a,b,&v); - if(!v.empty()) - *c = v[0]; - - return rv; - } - - private: - const Ptr func; - }; - - typedef Base Action; - typedef Base Create; - typedef Base Search; - - static int invalid(Category,const Branches&,const char *,strvec*); - static int all(Category,const Branches&,const char*,strvec*); - static int epall(Category,const Branches&,const char*,strvec*); - static int epff(Category,const Branches&,const char *,strvec*); - static int eplfs(Category,const Branches&,const char *,strvec*); - static int eplus(Category,const Branches&,const char *,strvec*); - static int epmfs(Category,const Branches&,const char *,strvec*); - static int eppfrd(Category,const Branches&,const char *,strvec*); - static int eprand(Category,const Branches&,const char *,strvec*); - static int erofs(Category,const Branches&,const char *,strvec*); - static int ff(Category,const Branches&,const char *,strvec*); - static int lfs(Category,const Branches&,const char *,strvec*); - static int lus(Category,const Branches&,const char *,strvec*); - static int mfs(Category,const Branches&,const char *,strvec*); - static int msplfs(Category,const Branches&,const char *,strvec*); - static int msplus(Category,const Branches&,const char *,strvec*); - static int mspmfs(Category,const Branches&,const char *,strvec*); - static int msppfrd(Category,const Branches&,const char *,strvec*); - static int newest(Category,const Branches&,const char *,strvec*); - static int pfrd(Category,const Branches&,const char *,strvec*); - static int rand(Category,const Branches&,const char *,strvec*); + public: + Action(ActionImpl *impl_) + : impl(impl_) + {} + + Action& + operator=(ActionImpl *impl_) + { + impl = impl_; + return *this; + } + + const + std::string& + name(void) const + { + return impl->name; + } + + int + operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const + { + return (*impl)(branches_,fusepath_,paths_); + } + + int + operator()(const Branches::CPtr &branches_, + const std::string &fusepath_, + StrVec *paths_) const + { + return (*impl)(branches_,fusepath_.c_str(),paths_); + } + + private: + ActionImpl *impl; }; -private: - Enum::Type _enum; - std::string _str; - Func::Ptr _func; - bool _path_preserving; - -public: - Policy() - : _enum(invalid), - _str(invalid), - _func(invalid), - _path_preserving(false) + class CreateImpl { - } - - Policy(const Enum::Type enum_, - const std::string &str_, - const Func::Ptr func_, - const bool path_preserving_) - : _enum(enum_), - _str(str_), - _func(func_), - _path_preserving(path_preserving_) + public: + CreateImpl(const std::string &name_) + : name(name_) + { + } + + public: + std::string name; + virtual int operator()(const Branches::CPtr&,const char*,StrVec*) const = 0; + virtual bool path_preserving(void) const = 0; + }; + + class Create { - } + public: + Create(CreateImpl *impl_) + : impl(impl_) + {} + + Create& + operator=(CreateImpl *impl_) + { + impl = impl_; + return *this; + } + + const + std::string& + name(void) const + { + return impl->name; + } + + bool + path_preserving(void) const + { + return impl->path_preserving(); + } - bool - path_preserving() const + int + operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const + { + return (*impl)(branches_,fusepath_,paths_); + } + + int + operator()(const Branches::CPtr &branches_, + const std::string &fusepath_, + StrVec *paths_) const + { + return (*impl)(branches_,fusepath_.c_str(),paths_); + } + + private: + CreateImpl *impl; + }; + + class SearchImpl { - return _path_preserving; - } - -public: - operator const Enum::Type() const { return _enum; } - 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_; } - bool operator==(const std::string &str_) const - { return _str == str_; } - bool operator==(const Func::Ptr func_) const - { return _func == func_; } - - bool operator!=(const Policy &r) const - { return _enum != r._enum; } - - bool operator<(const Policy &r) const - { return _enum < r._enum; } - -public: - static const Policy &find(const std::string&); - static const Policy &find(const Enum::Type); - -public: - - static const std::vector _policies_; - static const Policy * const policies; - - static const Policy &invalid; - static const Policy &all; - static const Policy &epall; - static const Policy &epff; - static const Policy &eplfs; - static const Policy ⩱ - static const Policy &epmfs; - static const Policy &eppfrd; - static const Policy &eprand; - static const Policy &erofs; - static const Policy &ff; - static const Policy &lfs; - static const Policy &lus; - static const Policy &mfs; - static const Policy &msplfs; - static const Policy &msplus; - static const Policy &mspmfs; - static const Policy &msppfrd; - static const Policy &newest; - static const Policy &pfrd; - static const Policy &rand; -}; - -namespace std -{ - static - inline - string - to_string(const Policy &p_) + public: + SearchImpl(const std::string &name_) + : name(name_) + { + } + + public: + std::string name; + virtual int operator()(const Branches::CPtr&,const char*,StrVec*) const = 0; + }; + + class Search { - return p_.to_string(); - } + public: + Search(SearchImpl *impl_) + : impl(impl_) + {} + + Search& + operator=(SearchImpl *impl_) + { + impl = impl_; + return *this; + } + + const + std::string& + name(void) const + { + return impl->name; + } + + int + operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const + { + return (*impl)(branches_,fusepath_,paths_); + } + + int + operator()(const Branches::CPtr &branches_, + const std::string &fusepath_, + StrVec *paths_) const + { + return (*impl)(branches_,fusepath_.c_str(),paths_); + } + + private: + SearchImpl *impl; + }; } diff --git a/src/policy_all.cpp b/src/policy_all.cpp index 92d86bfc..785a634b 100644 --- a/src/policy_all.cpp +++ b/src/policy_all.cpp @@ -19,43 +19,39 @@ #include "fs_info.hpp" #include "fs_path.hpp" #include "policy.hpp" +#include "policies.hpp" #include "policy_error.hpp" -#include "rwlock.hpp" +#include "strvec.hpp" #include -#include using std::string; -using std::vector; namespace all { static int - create(const BranchVec &branches_, - vector *paths_) + create(const Branches::CPtr &branches_, + StrVec *paths_) { int rv; int error; fs::info_t info; - const Branch *branch; error = ENOENT; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro_or_nc()) + if(branch.ro_or_nc()) error_and_continue(error,EROFS); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(error,ENOENT); if(info.readonly) error_and_continue(error,EROFS); - if(info.spaceavail < branch->minfreespace()) + if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); - paths_->push_back(branch->path); + paths_->push_back(branch.path); } if(paths_->empty()) @@ -63,26 +59,28 @@ namespace all return 0; } +} - static - int - create(const Branches &branches_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return all::create(branches_.vec,paths_); - } +int +Policy::All::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return Policies::Action::epall(branches_,fusepath_,paths_); } int -Policy::Func::all(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::All::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { - if(type_ == Category::CREATE) - return all::create(branches_,paths_); + return ::all::create(branches_,paths_); +} - return Policy::Func::epall(type_,branches_,fusepath_,paths_); +int +Policy::All::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return Policies::Search::epall(branches_,fusepath_,paths_); } diff --git a/src/policy_all.hpp b/src/policy_all.hpp new file mode 100644 index 00000000..8f5b67c8 --- /dev/null +++ b/src/policy_all.hpp @@ -0,0 +1,61 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace All + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("all") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("all") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving(void) const final { return false; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("all") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_cache.cpp b/src/policy_cache.cpp index 08645eab..590ea54f 100644 --- a/src/policy_cache.cpp +++ b/src/policy_cache.cpp @@ -28,7 +28,7 @@ namespace l PolicyCache::Value::Value() : time(0), - path() + paths() { } @@ -91,18 +91,17 @@ PolicyCache::clear(void) } int -PolicyCache::operator()(Policy::Func::Search &func_, +PolicyCache::operator()(const Policy::Search &policy_, const Branches &branches_, const char *fusepath_, - std::string *branch_) + StrVec *paths_) { int rv; Value *v; uint64_t now; - string branch; if(timeout == 0) - return func_(branches_,fusepath_,branch_); + return policy_(branches_,fusepath_,paths_); now = l::get_time(); @@ -112,16 +111,19 @@ PolicyCache::operator()(Policy::Func::Search &func_, if((now - v->time) >= timeout) { pthread_mutex_unlock(&_lock); - rv = func_(branches_,fusepath_,&branch); + + rv = policy_(branches_,fusepath_,paths_); if(rv == -1) return -1; pthread_mutex_lock(&_lock); - v->time = now; - v->path = branch; + v->time = now; + v->paths = *paths_; + } + else + { + *paths_ = v->paths; } - - *branch_ = v->path; pthread_mutex_unlock(&_lock); diff --git a/src/policy_cache.hpp b/src/policy_cache.hpp index dc7218d9..6cdb9280 100644 --- a/src/policy_cache.hpp +++ b/src/policy_cache.hpp @@ -19,12 +19,14 @@ #pragma once #include "policy.hpp" +#include "strvec.hpp" +#include #include #include #include -#include + class PolicyCache { @@ -33,8 +35,8 @@ public: { Value(); - uint64_t time; - std::string path; + uint64_t time; + StrVec paths; }; public: @@ -46,10 +48,10 @@ public: void clear(void); public: - int operator()(Policy::Func::Search &func, + int operator()(const Policy::Search &policy, const Branches &branches, const char *fusepath, - std::string *branch); + StrVec *paths); public: uint64_t timeout; diff --git a/src/policy_epall.cpp b/src/policy_epall.cpp index 47c1992e..af4b526b 100644 --- a/src/policy_epall.cpp +++ b/src/policy_epall.cpp @@ -20,46 +20,43 @@ #include "fs_path.hpp" #include "fs_statvfs_cache.hpp" #include "policy.hpp" +#include "policy_epall.hpp" #include "policy_error.hpp" -#include "rwlock.hpp" +#include "strvec.hpp" #include -#include using std::string; -using std::vector; + namespace epall { static int - create(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + create(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int rv; int error; fs::info_t info; - const Branch *branch; error = ENOENT; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro_or_nc()) + if(branch.ro_or_nc()) error_and_continue(error,EROFS); - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) error_and_continue(error,ENOENT); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(error,ENOENT); if(info.readonly) error_and_continue(error,EROFS); - if(info.spaceavail < branch->minfreespace()) + if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); - paths_->push_back(branch->path); + paths_->push_back(branch.path); } if(paths_->empty()) @@ -70,42 +67,28 @@ namespace epall static int - create(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return epall::create(branches_.vec,fusepath_,paths_); - } - - static - int - action(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + action(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int rv; int error; bool readonly; - const Branch *branch; error = ENOENT; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro()) + if(branch.ro()) error_and_continue(error,EROFS); - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) error_and_continue(error,ENOENT); - rv = fs::statvfs_cache_readonly(branch->path,&readonly); + rv = fs::statvfs_cache_readonly(branch.path,&readonly); if(rv == -1) error_and_continue(error,ENOENT); if(readonly) error_and_continue(error,EROFS); - paths_->push_back(branch->path); + paths_->push_back(branch.path); } if(paths_->empty()) @@ -116,31 +99,16 @@ namespace epall static int - action(const Branches &branches_, - const char *fusepath_, - vector *paths_) + search(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { - rwlock::ReadGuard guard(branches_.lock); - - return epall::action(branches_.vec,fusepath_,paths_); - } - - static - int - search(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) - { - const Branch *branch; - - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(auto &branch : *branches_) { - 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); } if(paths_->empty()) @@ -148,33 +116,28 @@ namespace epall return 0; } +} - static - int - search(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); +int +Policy::EPAll::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return ::epall::action(branches_,fusepath_,paths_); +} - return epall::search(branches_.vec,fusepath_,paths_); - } +int +Policy::EPAll::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return ::epall::create(branches_,fusepath_,paths_); } int -Policy::Func::epall(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::EPAll::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { - switch(type_) - { - case Category::CREATE: - return epall::create(branches_,fusepath_,paths_); - case Category::ACTION: - return epall::action(branches_,fusepath_,paths_); - case Category::SEARCH: - default: - return epall::search(branches_,fusepath_,paths_); - } + return ::epall::search(branches_,fusepath_,paths_); } diff --git a/src/policy_epall.hpp b/src/policy_epall.hpp new file mode 100644 index 00000000..1b665671 --- /dev/null +++ b/src/policy_epall.hpp @@ -0,0 +1,64 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace EPAll + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("epall") + { + } + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("epall") + { + } + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving(void) const final { return true; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("epall") + { + } + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_epff.cpp b/src/policy_epff.cpp index ac519c96..d2980f42 100644 --- a/src/policy_epff.cpp +++ b/src/policy_epff.cpp @@ -14,12 +14,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "branches.hpp" #include "errno.hpp" #include "fs_exists.hpp" #include "fs_info.hpp" #include "fs_path.hpp" #include "fs_statvfs_cache.hpp" #include "policy.hpp" +#include "policy_epff.hpp" #include "policy_error.hpp" #include "rwlock.hpp" @@ -33,33 +35,30 @@ namespace epff { static int - create(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + create(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int rv; int error; fs::info_t info; - const Branch *branch; error = ENOENT; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro_or_nc()) + if(branch.ro_or_nc()) error_and_continue(error,EROFS); - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) error_and_continue(error,ENOENT); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(error,ENOENT); if(info.readonly) error_and_continue(error,EROFS); - if(info.spaceavail < branch->minfreespace()) + if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); - paths_->push_back(branch->path); + paths_->push_back(branch.path); return 0; } @@ -69,42 +68,28 @@ namespace epff static int - create(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return epff::create(branches_.vec,fusepath_,paths_); - } - - static - int - action(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + action(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int rv; int error; bool readonly; - const Branch *branch; error = ENOENT; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro()) + if(branch.ro()) error_and_continue(error,EROFS); - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) error_and_continue(error,ENOENT); - rv = fs::statvfs_cache_readonly(branch->path,&readonly); + rv = fs::statvfs_cache_readonly(branch.path,&readonly); if(rv == -1) error_and_continue(error,ENOENT); if(readonly) error_and_continue(error,EROFS); - paths_->push_back(branch->path); + paths_->push_back(branch.path); return 0; } @@ -114,64 +99,44 @@ namespace epff static int - action(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return epff::action(branches_.vec,fusepath_,paths_); - } - - static - int - search(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + search(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { - const Branch *branch; - - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(auto &branch : *branches_) { - 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; } return (errno=ENOENT,-1); } +} - static - int - search(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); +int +Policy::EPFF::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return ::epff::action(branches_,fusepath_,paths_); +} - return epff::search(branches_.vec,fusepath_,paths_); - } +int +Policy::EPFF::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return ::epff::create(branches_,fusepath_,paths_); } int -Policy::Func::epff(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::EPFF::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { - switch(type_) - { - case Category::CREATE: - return epff::create(branches_,fusepath_,paths_); - case Category::ACTION: - return epff::action(branches_,fusepath_,paths_); - case Category::SEARCH: - default: - return epff::search(branches_,fusepath_,paths_); - } + return ::epff::search(branches_,fusepath_,paths_); } diff --git a/src/policy_epff.hpp b/src/policy_epff.hpp new file mode 100644 index 00000000..0e3e5f4a --- /dev/null +++ b/src/policy_epff.hpp @@ -0,0 +1,61 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace EPFF + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("epff") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("epff") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving(void) const final { return true; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("epff") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_eplfs.cpp b/src/policy_eplfs.cpp index 26164fdd..3ef4ed18 100644 --- a/src/policy_eplfs.cpp +++ b/src/policy_eplfs.cpp @@ -19,9 +19,10 @@ #include "fs_info.hpp" #include "fs_path.hpp" #include "fs_statvfs_cache.hpp" +#include "policies.hpp" #include "policy.hpp" +#include "policy_eplfs.hpp" #include "policy_error.hpp" -#include "rwlock.hpp" #include #include @@ -34,40 +35,37 @@ namespace eplfs { static int - create(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + create(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int rv; int error; uint64_t eplfs; fs::info_t info; - const Branch *branch; const string *basepath; error = ENOENT; eplfs = std::numeric_limits::max(); basepath = NULL; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(const auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro_or_nc()) + if(branch.ro_or_nc()) error_and_continue(error,EROFS); - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) error_and_continue(error,ENOENT); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(error,ENOENT); if(info.readonly) error_and_continue(error,EROFS); - if(info.spaceavail < branch->minfreespace()) + if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); if(info.spaceavail > eplfs) continue; eplfs = info.spaceavail; - basepath = &branch->path; + basepath = &branch.path; } if(basepath == NULL) @@ -80,40 +78,26 @@ namespace eplfs static int - create(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return eplfs::create(branches_.vec,fusepath_,paths_); - } - - static - int - action(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + action(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int rv; int error; uint64_t eplfs; fs::info_t info; - const Branch *branch; const string *basepath; error = ENOENT; eplfs = std::numeric_limits::max(); basepath = NULL; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(const auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro()) + if(branch.ro()) error_and_continue(error,EROFS); - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) error_and_continue(error,ENOENT); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(error,ENOENT); if(info.readonly) @@ -122,7 +106,7 @@ namespace eplfs continue; eplfs = info.spaceavail; - basepath = &branch->path; + basepath = &branch.path; } if(basepath == NULL) @@ -135,43 +119,29 @@ namespace eplfs static int - action(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return eplfs::action(branches_.vec,fusepath_,paths_); - } - - static - int - search(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + search(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int rv; uint64_t eplfs; uint64_t spaceavail; - const Branch *branch; const string *basepath; eplfs = std::numeric_limits::max(); basepath = NULL; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(const auto &branch : *branches_) { - branch = &branches_[i]; - - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) continue; - rv = fs::statvfs_cache_spaceavail(branch->path,&spaceavail); + rv = fs::statvfs_cache_spaceavail(branch.path,&spaceavail); if(rv == -1) continue; if(spaceavail > eplfs) continue; eplfs = spaceavail; - basepath = &branch->path; + basepath = &branch.path; } if(basepath == NULL) @@ -181,33 +151,28 @@ namespace eplfs return 0; } +} - static - int - search(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); +int +Policy::EPLFS::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return ::eplfs::action(branches_,fusepath_,paths_); +} - return eplfs::search(branches_.vec,fusepath_,paths_); - } +int +Policy::EPLFS::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return ::eplfs::create(branches_,fusepath_,paths_); } int -Policy::Func::eplfs(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::EPLFS::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { - switch(type_) - { - case Category::CREATE: - return eplfs::create(branches_,fusepath_,paths_); - case Category::ACTION: - return eplfs::action(branches_,fusepath_,paths_); - case Category::SEARCH: - default: - return eplfs::search(branches_,fusepath_,paths_); - } + return ::eplfs::search(branches_,fusepath_,paths_); } diff --git a/src/policy_eplfs.hpp b/src/policy_eplfs.hpp new file mode 100644 index 00000000..60006b06 --- /dev/null +++ b/src/policy_eplfs.hpp @@ -0,0 +1,61 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace EPLFS + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("eplfs") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("eplfs") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving(void) const final { return true; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("eplfs") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_eplus.cpp b/src/policy_eplus.cpp index b8c79ab1..e5bac154 100644 --- a/src/policy_eplus.cpp +++ b/src/policy_eplus.cpp @@ -20,54 +20,50 @@ #include "fs_path.hpp" #include "fs_statvfs_cache.hpp" #include "policy.hpp" +#include "policy_eplus.hpp" #include "policy_error.hpp" #include "rwlock.hpp" #include #include -#include using std::string; -using std::vector; namespace eplus { static int - create(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + create(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int rv; int error; uint64_t eplus; fs::info_t info; - const Branch *branch; const string *basepath; error = ENOENT; eplus = std::numeric_limits::max(); basepath = NULL; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro_or_nc()) + if(branch.ro_or_nc()) error_and_continue(error,EROFS); - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) error_and_continue(error,ENOENT); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(error,ENOENT); if(info.readonly) error_and_continue(error,EROFS); - if(info.spaceavail < branch->minfreespace()) + if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); if(info.spaceused >= eplus) continue; eplus = info.spaceused; - basepath = &branch->path; + basepath = &branch.path; } if(basepath == NULL) @@ -80,40 +76,26 @@ namespace eplus static int - create(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return eplus::create(branches_.vec,fusepath_,paths_); - } - - static - int - action(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + action(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int rv; int error; uint64_t eplus; fs::info_t info; - const Branch *branch; const string *basepath; error = ENOENT; eplus = std::numeric_limits::max(); basepath = NULL; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro()) + if(branch.ro()) error_and_continue(error,EROFS); - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) error_and_continue(error,ENOENT); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(error,ENOENT); if(info.readonly) @@ -122,7 +104,7 @@ namespace eplus continue; eplus = info.spaceused; - basepath = &branch->path; + basepath = &branch.path; } if(basepath == NULL) @@ -135,43 +117,29 @@ namespace eplus static int - action(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return eplus::action(branches_.vec,fusepath_,paths_); - } - - static - int - search(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + search(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int rv; uint64_t eplus; uint64_t spaceused; - const Branch *branch; const string *basepath; eplus = 0; basepath = NULL; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) continue; - rv = fs::statvfs_cache_spaceused(branch->path,&spaceused); + rv = fs::statvfs_cache_spaceused(branch.path,&spaceused); if(rv == -1) continue; if(spaceused >= eplus) continue; eplus = spaceused; - basepath = &branch->path; + basepath = &branch.path; } if(basepath == NULL) @@ -181,33 +149,28 @@ namespace eplus return 0; } +} - static - int - search(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); +int +Policy::EPLUS::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return ::eplus::action(branches_,fusepath_,paths_); +} - return eplus::search(branches_.vec,fusepath_,paths_); - } +int +Policy::EPLUS::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return ::eplus::create(branches_,fusepath_,paths_); } int -Policy::Func::eplus(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::EPLUS::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { - switch(type_) - { - case Category::CREATE: - return eplus::create(branches_,fusepath_,paths_); - case Category::ACTION: - return eplus::action(branches_,fusepath_,paths_); - case Category::SEARCH: - default: - return eplus::search(branches_,fusepath_,paths_); - } + return ::eplus::search(branches_,fusepath_,paths_); } diff --git a/src/policy_eplus.hpp b/src/policy_eplus.hpp new file mode 100644 index 00000000..ca253f7e --- /dev/null +++ b/src/policy_eplus.hpp @@ -0,0 +1,61 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace EPLUS + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("eplus") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("eplus") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving(void) const final { return true; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("eplus") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_epmfs.cpp b/src/policy_epmfs.cpp index b4e24919..7f44c032 100644 --- a/src/policy_epmfs.cpp +++ b/src/policy_epmfs.cpp @@ -20,54 +20,51 @@ #include "fs_path.hpp" #include "fs_statvfs_cache.hpp" #include "policy.hpp" +#include "policy_epmfs.hpp" #include "policy_error.hpp" -#include "rwlock.hpp" #include #include -#include + using std::string; -using std::vector; + namespace epmfs { static int - create(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + create(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int rv; int error; uint64_t epmfs; fs::info_t info; - const Branch *branch; const string *basepath; error = ENOENT; epmfs = std::numeric_limits::min(); basepath = NULL; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(const auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro_or_nc()) + if(branch.ro_or_nc()) error_and_continue(error,EROFS); - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) error_and_continue(error,ENOENT); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(error,ENOENT); if(info.readonly) error_and_continue(error,EROFS); - if(info.spaceavail < branch->minfreespace()) + if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); if(info.spaceavail < epmfs) continue; epmfs = info.spaceavail; - basepath = &branch->path; + basepath = &branch.path; } if(basepath == NULL) @@ -80,40 +77,26 @@ namespace epmfs static int - create(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return epmfs::create(branches_.vec,fusepath_,paths_); - } - - static - int - action(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + action(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int rv; int error; uint64_t epmfs; fs::info_t info; - const Branch *branch; const string *basepath; error = ENOENT; epmfs = std::numeric_limits::min(); basepath = NULL; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(const auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro()) + if(branch.ro()) error_and_continue(error,EROFS); - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) error_and_continue(error,ENOENT); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(error,ENOENT); if(info.readonly) @@ -122,7 +105,7 @@ namespace epmfs continue; epmfs = info.spaceavail; - basepath = &branch->path; + basepath = &branch.path; } if(basepath == NULL) @@ -135,43 +118,29 @@ namespace epmfs static int - action(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return epmfs::action(branches_.vec,fusepath_,paths_); - } - - static - int - search(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + search(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int rv; uint64_t epmfs; uint64_t spaceavail; - const Branch *branch; const string *basepath; epmfs = 0; basepath = NULL; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(const auto &branch : *branches_) { - branch = &branches_[i]; - - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) continue; - rv = fs::statvfs_cache_spaceavail(branch->path,&spaceavail); + rv = fs::statvfs_cache_spaceavail(branch.path,&spaceavail); if(rv == -1) continue; if(spaceavail < epmfs) continue; epmfs = spaceavail; - basepath = &branch->path; + basepath = &branch.path; } if(basepath == NULL) @@ -181,33 +150,28 @@ namespace epmfs return 0; } +} - static - int - search(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); +int +Policy::EPMFS::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return ::epmfs::action(branches_,fusepath_,paths_); +} - return epmfs::search(branches_.vec,fusepath_,paths_); - } +int +Policy::EPMFS::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return ::epmfs::create(branches_,fusepath_,paths_); } int -Policy::Func::epmfs(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::EPMFS::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { - switch(type_) - { - case Category::CREATE: - return epmfs::create(branches_,fusepath_,paths_); - case Category::ACTION: - return epmfs::action(branches_,fusepath_,paths_); - case Category::SEARCH: - default: - return epmfs::search(branches_,fusepath_,paths_); - } + return ::epmfs::search(branches_,fusepath_,paths_); } diff --git a/src/policy_epmfs.hpp b/src/policy_epmfs.hpp new file mode 100644 index 00000000..e0b8382a --- /dev/null +++ b/src/policy_epmfs.hpp @@ -0,0 +1,64 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace EPMFS + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("epmfs") + { + } + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("epmfs") + { + } + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving(void) const final { return true; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("epmfs") + { + } + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_eppfrd.cpp b/src/policy_eppfrd.cpp index 2c38efc2..d2ba449c 100644 --- a/src/policy_eppfrd.cpp +++ b/src/policy_eppfrd.cpp @@ -20,9 +20,11 @@ #include "fs_path.hpp" #include "fs_statvfs_cache.hpp" #include "policy.hpp" +#include "policy_eppfrd.hpp" #include "policy_error.hpp" #include "rnd.hpp" #include "rwlock.hpp" +#include "strvec.hpp" #include #include @@ -42,39 +44,36 @@ namespace eppfrd { static int - get_branchinfo_create(const BranchVec &branches_, - const char *fusepath_, - BranchInfoVec *branchinfo_, - uint64_t *sum_) + get_branchinfo_create(const Branches::CPtr &branches_, + const char *fusepath_, + BranchInfoVec *branchinfo_, + uint64_t *sum_) { int rv; int error; BranchInfo bi; fs::info_t info; - const Branch *branch; *sum_ = 0; error = ENOENT; - for(size_t i = 0, ei = branches_.size(); i < ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro_or_nc()) + if(branch.ro_or_nc()) error_and_continue(error,EROFS); - if(!fs::exists(branch->path,fusepath_)) - error_and_continue(error,ENOENT); - rv = fs::info(branch->path,&info); + if(!fs::exists(branch.path,fusepath_)) + error_and_continue(error,ENOENT); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(error,ENOENT); if(info.readonly) error_and_continue(error,EROFS); - if(info.spaceavail < branch->minfreespace()) + if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); *sum_ += info.spaceavail; bi.spaceavail = info.spaceavail; - bi.basepath = &branch->path; + bi.basepath = &branch.path; branchinfo_->push_back(bi); } @@ -83,42 +82,25 @@ namespace eppfrd static int - get_branchinfo_create(const Branches &branches_, - const char *fusepath_, - BranchInfoVec *branchinfo_, - uint64_t *sum_) - { - rwlock::ReadGuard guard(branches_.lock); - - branchinfo_->reserve(branches_.vec.size()); - - return eppfrd::get_branchinfo_create(branches_.vec,fusepath_,branchinfo_,sum_); - } - - static - int - get_branchinfo_action(const BranchVec &branches_, - const char *fusepath_, - BranchInfoVec *branchinfo_, - uint64_t *sum_) + get_branchinfo_action(const Branches::CPtr &branches_, + const char *fusepath_, + BranchInfoVec *branchinfo_, + uint64_t *sum_) { int rv; int error; BranchInfo bi; fs::info_t info; - const Branch *branch; *sum_ = 0; error = ENOENT; - for(size_t i = 0, ei = branches_.size(); i < ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro()) + if(branch.ro()) error_and_continue(error,EROFS); - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) error_and_continue(error,ENOENT); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(error,ENOENT); if(info.readonly) @@ -127,7 +109,7 @@ namespace eppfrd *sum_ += info.spaceavail; bi.spaceavail = info.spaceavail; - bi.basepath = &branch->path; + bi.basepath = &branch.path; branchinfo_->push_back(bi); } @@ -136,65 +118,34 @@ namespace eppfrd static int - get_branchinfo_action(const Branches &branches_, - const char *fusepath_, - BranchInfoVec *branchinfo_, - uint64_t *sum_) - { - rwlock::ReadGuard guard(branches_.lock); - - branchinfo_->reserve(branches_.vec.size()); - - return eppfrd::get_branchinfo_action(branches_.vec,fusepath_,branchinfo_,sum_); - } - - static - int - get_branchinfo_search(const BranchVec &branches_, - const char *fusepath_, - BranchInfoVec *branchinfo_, - uint64_t *sum_) + get_branchinfo_search(const Branches::CPtr &branches_, + const char *fusepath_, + BranchInfoVec *branchinfo_, + uint64_t *sum_) { int rv; BranchInfo bi; uint64_t spaceavail; - const Branch *branch; *sum_ = 0; - for(size_t i = 0, ei = branches_.size(); i < ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) continue; - rv = fs::statvfs_cache_spaceavail(branch->path,&spaceavail); + rv = fs::statvfs_cache_spaceavail(branch.path,&spaceavail); if(rv == -1) continue; *sum_ += spaceavail; bi.spaceavail = spaceavail; - bi.basepath = &branch->path; + bi.basepath = &branch.path; branchinfo_->push_back(bi); } return ENOENT; } - static - int - get_branchinfo_search(const Branches &branches_, - const char *fusepath_, - BranchInfoVec *branchinfo_, - uint64_t *sum_) - { - rwlock::ReadGuard guard(branches_.lock); - - branchinfo_->reserve(branches_.vec.size()); - - return eppfrd::get_branchinfo_search(branches_.vec,fusepath_,branchinfo_,sum_); - } - static const string* @@ -221,9 +172,9 @@ namespace eppfrd static int - create(const Branches &branches_, - const char *fusepath_, - vector *paths_) + create(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int error; uint64_t sum; @@ -242,9 +193,9 @@ namespace eppfrd static int - action(const Branches &branches_, - const char *fusepath_, - vector *paths_) + action(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int error; uint64_t sum; @@ -263,9 +214,9 @@ namespace eppfrd static int - search(const Branches &branches_, - const char *fusepath_, - vector *paths_) + search(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int error; uint64_t sum; @@ -284,19 +235,25 @@ namespace eppfrd } int -Policy::Func::eppfrd(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::EPPFRD::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return ::eppfrd::action(branches_,fusepath_,paths_); +} + +int +Policy::EPPFRD::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return ::eppfrd::create(branches_,fusepath_,paths_); +} + +int +Policy::EPPFRD::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { - switch(type_) - { - case Category::CREATE: - return eppfrd::create(branches_,fusepath_,paths_); - case Category::ACTION: - return eppfrd::action(branches_,fusepath_,paths_); - default: - case Category::SEARCH: - return eppfrd::search(branches_,fusepath_,paths_); - } + return ::eppfrd::search(branches_,fusepath_,paths_); } diff --git a/src/policy_eppfrd.hpp b/src/policy_eppfrd.hpp new file mode 100644 index 00000000..f3b6cbc3 --- /dev/null +++ b/src/policy_eppfrd.hpp @@ -0,0 +1,61 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace EPPFRD + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("eppfrd") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("eppfrd") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving(void) const final { return true; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("eppfrd") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_eprand.cpp b/src/policy_eprand.cpp index 65dd9ffa..248249c8 100644 --- a/src/policy_eprand.cpp +++ b/src/policy_eprand.cpp @@ -15,24 +15,54 @@ */ #include "errno.hpp" +#include "policies.hpp" #include "policy.hpp" +#include "policy_eprand.hpp" #include -#include -#include -using std::string; -using std::vector; +int +Policy::EPRand::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + int rv; + + rv = Policies::Action::epall(branches_,fusepath_,paths_); + if(rv == 0) + { + std::random_shuffle(paths_->begin(),paths_->end()); + paths_->resize(1); + } + + return rv; +} + +int +Policy::EPRand::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + int rv; + + rv = Policies::Create::epall(branches_,fusepath_,paths_); + if(rv == 0) + { + std::random_shuffle(paths_->begin(),paths_->end()); + paths_->resize(1); + } + + return rv; +} int -Policy::Func::eprand(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::EPRand::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { int rv; - rv = Policy::Func::epall(type_,branches_,fusepath_,paths_); + rv = Policies::Search::epall(branches_,fusepath_,paths_); if(rv == 0) { std::random_shuffle(paths_->begin(),paths_->end()); diff --git a/src/policy_eprand.hpp b/src/policy_eprand.hpp new file mode 100644 index 00000000..f0a62b4f --- /dev/null +++ b/src/policy_eprand.hpp @@ -0,0 +1,61 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace EPRand + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("eprand") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("eprand") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving(void) const final { return true; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("eprand") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_erofs.cpp b/src/policy_erofs.cpp index c7ee6682..27376be3 100644 --- a/src/policy_erofs.cpp +++ b/src/policy_erofs.cpp @@ -16,18 +16,33 @@ #include "errno.hpp" #include "policy.hpp" +#include "policy_erofs.hpp" #include -#include using std::string; -using std::vector; + + +int +Policy::ERoFS::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return (errno=EROFS,-1); +} + +int +Policy::ERoFS::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return (errno=EROFS,-1); +} int -Policy::Func::erofs(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths) +Policy::ERoFS::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { return (errno=EROFS,-1); } diff --git a/src/policy_erofs.hpp b/src/policy_erofs.hpp new file mode 100644 index 00000000..f17f4053 --- /dev/null +++ b/src/policy_erofs.hpp @@ -0,0 +1,61 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace ERoFS + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("erofs") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("erofs") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving(void) const final { return false; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("erofs") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_ff.cpp b/src/policy_ff.cpp index 72a8f1e2..4cf00b32 100644 --- a/src/policy_ff.cpp +++ b/src/policy_ff.cpp @@ -18,70 +18,68 @@ #include "fs_exists.hpp" #include "fs_info.hpp" #include "fs_path.hpp" +#include "policies.hpp" #include "policy.hpp" #include "policy_error.hpp" -#include "rwlock.hpp" +#include "policy_ff.hpp" #include -#include using std::string; -using std::vector; namespace ff { static int - create(const BranchVec &branches_, - vector *paths_) + create(const Branches::CPtr &branches_, + StrVec *paths_) { int rv; int error; fs::info_t info; - const Branch *branch; error = ENOENT; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro_or_nc()) + if(branch.ro_or_nc()) error_and_continue(error,EROFS); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(error,ENOENT); if(info.readonly) error_and_continue(error,EROFS); - if(info.spaceavail < branch->minfreespace()) + if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); - paths_->push_back(branch->path); + paths_->push_back(branch.path); return 0; } return (errno=error,-1); } +} - static - int - create(const Branches &branches_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return ff::create(branches_.vec,paths_); - } +int +Policy::FF::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return Policies::Action::epff(branches_,fusepath_,paths_); } int -Policy::Func::ff(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::FF::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { - if(type_ == Category::CREATE) - return ff::create(branches_,paths_); + return ::ff::create(branches_,paths_); +} - return Policy::Func::epff(type_,branches_,fusepath_,paths_); +int +Policy::FF::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return Policies::Search::epff(branches_,fusepath_,paths_); } diff --git a/src/policy_ff.hpp b/src/policy_ff.hpp new file mode 100644 index 00000000..1b0db87f --- /dev/null +++ b/src/policy_ff.hpp @@ -0,0 +1,61 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace FF + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("ff") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("ff") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving(void) const final { return false; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("ff") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_lfs.cpp b/src/policy_lfs.cpp index 05000c18..ace2a1bf 100644 --- a/src/policy_lfs.cpp +++ b/src/policy_lfs.cpp @@ -18,23 +18,23 @@ #include "fs_exists.hpp" #include "fs_info.hpp" #include "fs_path.hpp" +#include "policies.hpp" #include "policy.hpp" #include "policy_error.hpp" -#include "rwlock.hpp" +#include "policy_lfs.hpp" +#include "strvec.hpp" #include #include -#include using std::string; -using std::vector; namespace lfs { static int - create(const BranchVec &branches_, - vector *paths_) + create(const Branches::CPtr &branches_, + StrVec *paths_) { int rv; int error; @@ -46,24 +46,22 @@ namespace lfs error = ENOENT; lfs = std::numeric_limits::max(); basepath = NULL; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(const auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro_or_nc()) + if(branch.ro_or_nc()) error_and_continue(error,EROFS); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(error,ENOENT); if(info.readonly) error_and_continue(error,EROFS); - if(info.spaceavail < branch->minfreespace()) + if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); if(info.spaceavail > lfs) continue; lfs = info.spaceavail; - basepath = &branch->path; + basepath = &branch.path; } if(basepath == NULL) @@ -73,26 +71,28 @@ namespace lfs return 0; } +} - static - int - create(const Branches &branches_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return lfs::create(branches_.vec,paths_); - } +int +Policy::LFS::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return Policies::Action::eplfs(branches_,fusepath_,paths_); } int -Policy::Func::lfs(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::LFS::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { - if(type_ == Category::CREATE) - return lfs::create(branches_,paths_); + return ::lfs::create(branches_,paths_); +} - return Policy::Func::eplfs(type_,branches_,fusepath_,paths_); +int +Policy::LFS::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return Policies::Search::eplfs(branches_,fusepath_,paths_); } diff --git a/src/policy_lfs.hpp b/src/policy_lfs.hpp new file mode 100644 index 00000000..e0b456ef --- /dev/null +++ b/src/policy_lfs.hpp @@ -0,0 +1,61 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace LFS + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("lfs") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("lfs") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving() const final { return false; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("lfs") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_lus.cpp b/src/policy_lus.cpp index 3576afad..c23570aa 100644 --- a/src/policy_lus.cpp +++ b/src/policy_lus.cpp @@ -18,9 +18,11 @@ #include "fs_exists.hpp" #include "fs_info.hpp" #include "fs_path.hpp" +#include "policies.hpp" #include "policy.hpp" #include "policy_error.hpp" -#include "rwlock.hpp" +#include "policy_lus.hpp" +#include "strvec.hpp" #include #include @@ -33,37 +35,34 @@ namespace lus { static int - create(const BranchVec &branches_, - vector *paths_) + create(const Branches::CPtr &branches_, + StrVec *paths_) { int rv; int error; uint64_t lus; fs::info_t info; - const Branch *branch; const string *basepath; error = ENOENT; lus = std::numeric_limits::max(); basepath = NULL; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro_or_nc()) + if(branch.ro_or_nc()) error_and_continue(error,EROFS); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(error,ENOENT); if(info.readonly) error_and_continue(error,EROFS); - if(info.spaceavail < branch->minfreespace()) + if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); if(info.spaceused >= lus) continue; lus = info.spaceused; - basepath = &branch->path; + basepath = &branch.path; } if(basepath == NULL) @@ -73,26 +72,28 @@ namespace lus return 0; } +} - static - int - create(const Branches &branches_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return lus::create(branches_.vec,paths_); - } +int +Policy::LUS::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return Policies::Action::eplus(branches_,fusepath_,paths_); } int -Policy::Func::lus(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::LUS::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { - if(type_ == Category::CREATE) - return lus::create(branches_,paths_); + return ::lus::create(branches_,paths_); +} - return Policy::Func::eplus(type_,branches_,fusepath_,paths_); +int +Policy::LUS::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return Policies::Search::eplus(branches_,fusepath_,paths_); } diff --git a/src/policy_lus.hpp b/src/policy_lus.hpp new file mode 100644 index 00000000..b6c07717 --- /dev/null +++ b/src/policy_lus.hpp @@ -0,0 +1,61 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace LUS + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("lus") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("lus") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving() const final { return false; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("lus") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_mfs.cpp b/src/policy_mfs.cpp index ed766d95..489e0cd9 100644 --- a/src/policy_mfs.cpp +++ b/src/policy_mfs.cpp @@ -18,51 +18,46 @@ #include "fs_exists.hpp" #include "fs_info.hpp" #include "fs_path.hpp" +#include "policies.hpp" #include "policy.hpp" #include "policy_error.hpp" -#include "rwlock.hpp" #include -#include using std::string; -using std::vector; namespace mfs { static int - create(const BranchVec &branches_, - vector *paths_) + create(const Branches::CPtr &branches_, + StrVec *paths_) { int rv; int error; uint64_t mfs; fs::info_t info; - const Branch *branch; const string *basepath; error = ENOENT; mfs = 0; basepath = NULL; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(const auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro_or_nc()) + if(branch.ro_or_nc()) error_and_continue(error,EROFS); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(error,ENOENT); if(info.readonly) error_and_continue(error,EROFS); - if(info.spaceavail < branch->minfreespace()) + if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); if(info.spaceavail < mfs) continue; mfs = info.spaceavail; - basepath = &branch->path; + basepath = &branch.path; } if(basepath == NULL) @@ -72,26 +67,28 @@ namespace mfs return 0; } +} - static - int - create(const Branches &branches_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return mfs::create(branches_.vec,paths_); - } +int +Policy::MFS::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return Policies::Action::mfs(branches_,fusepath_,paths_); } int -Policy::Func::mfs(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::MFS::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { - if(type_ == Category::CREATE) - return mfs::create(branches_,paths_); + return ::mfs::create(branches_,paths_); +} - return Policy::Func::epmfs(type_,branches_,fusepath_,paths_); +int +Policy::MFS::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return Policies::Search::epmfs(branches_,fusepath_,paths_); } diff --git a/src/policy_mfs.hpp b/src/policy_mfs.hpp new file mode 100644 index 00000000..9247f77a --- /dev/null +++ b/src/policy_mfs.hpp @@ -0,0 +1,61 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace MFS + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("mfs") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("mfs") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving() const final { return false; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("mfs") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_msplfs.cpp b/src/policy_msplfs.cpp index 3d6a6f61..27039a62 100644 --- a/src/policy_msplfs.cpp +++ b/src/policy_msplfs.cpp @@ -19,16 +19,16 @@ #include "fs_info.hpp" #include "fs_path.hpp" #include "fs_statvfs_cache.hpp" +#include "policies.hpp" #include "policy.hpp" #include "policy_error.hpp" -#include "rwlock.hpp" +#include "policy_msplfs.hpp" +#include "strvec.hpp" #include #include -#include using std::string; -using std::vector; namespace msplfs @@ -36,38 +36,35 @@ namespace msplfs static const string* - create_1(const BranchVec &branches_, - const string &fusepath_, - int *err_) + create_1(const Branches::CPtr &branches_, + const string &fusepath_, + int *err_) { int rv; uint64_t lfs; fs::info_t info; - const Branch *branch; const string *basepath; basepath = NULL; lfs = std::numeric_limits::max(); - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(const auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro_or_nc()) + if(branch.ro_or_nc()) error_and_continue(*err_,EROFS); - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) error_and_continue(*err_,ENOENT); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(*err_,ENOENT); if(info.readonly) error_and_continue(*err_,EROFS); - if(info.spaceavail < branch->minfreespace()) + if(info.spaceavail < branch.minfreespace()) error_and_continue(*err_,ENOSPC); if(info.spaceavail > lfs) continue; lfs = info.spaceavail; - basepath = &branch->path; + basepath = &branch.path; } return basepath; @@ -75,9 +72,9 @@ namespace msplfs static int - create(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + create(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int error; string fusepath; @@ -102,27 +99,28 @@ namespace msplfs return 0; } +} - static - int - create(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return msplfs::create(branches_.vec,fusepath_,paths_); - } +int +Policy::MSPLFS::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return Policies::Action::eplfs(branches_,fusepath_,paths_); } int -Policy::Func::msplfs(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::MSPLFS::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { - if(type_ == Category::CREATE) - return msplfs::create(branches_,fusepath_,paths_); + return ::msplfs::create(branches_,fusepath_,paths_); +} - return Policy::Func::eplfs(type_,branches_,fusepath_,paths_); +int +Policy::MSPLFS::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return Policies::Search::eplfs(branches_,fusepath_,paths_); } diff --git a/src/policy_msplfs.hpp b/src/policy_msplfs.hpp new file mode 100644 index 00000000..7e0a8d3e --- /dev/null +++ b/src/policy_msplfs.hpp @@ -0,0 +1,61 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace MSPLFS + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("msplfs") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("msplfs") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving() const final { return true; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("msplfs") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_msplus.cpp b/src/policy_msplus.cpp index 28278fc2..e6e0cb87 100644 --- a/src/policy_msplus.cpp +++ b/src/policy_msplus.cpp @@ -19,55 +19,50 @@ #include "fs_info.hpp" #include "fs_path.hpp" #include "fs_statvfs_cache.hpp" +#include "policies.hpp" #include "policy.hpp" #include "policy_error.hpp" -#include "rwlock.hpp" +#include "policy_msplus.hpp" #include #include -#include using std::string; -using std::vector; - namespace msplus { static const string* - create_1(const BranchVec &branches_, - const string &fusepath_, - int *err_) + create_1(const Branches::CPtr &branches_, + const string &fusepath_, + int *err_) { int rv; uint64_t lus; fs::info_t info; - const Branch *branch; const string *basepath; basepath = NULL; lus = std::numeric_limits::max(); - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro_or_nc()) + if(branch.ro_or_nc()) error_and_continue(*err_,EROFS); - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) error_and_continue(*err_,ENOENT); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(*err_,ENOENT); if(info.readonly) error_and_continue(*err_,EROFS); - if(info.spaceavail < branch->minfreespace()) + if(info.spaceavail < branch.minfreespace()) error_and_continue(*err_,ENOSPC); if(info.spaceused >= lus) continue; lus = info.spaceused;; - basepath = &branch->path; + basepath = &branch.path; } return basepath; @@ -75,9 +70,9 @@ namespace msplus static int - create(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + create(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int error; string fusepath; @@ -102,27 +97,28 @@ namespace msplus return 0; } +} - static - int - create(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return msplus::create(branches_.vec,fusepath_,paths_); - } +int +Policy::MSPLUS::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return Policies::Action::eplus(branches_,fusepath_,paths_); } int -Policy::Func::msplus(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::MSPLUS::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { - if(type_ == Category::CREATE) - return msplus::create(branches_,fusepath_,paths_); + return ::msplus::create(branches_,fusepath_,paths_); +} - return Policy::Func::eplus(type_,branches_,fusepath_,paths_); +int +Policy::MSPLUS::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return Policies::Search::eplus(branches_,fusepath_,paths_); } diff --git a/src/policy_msplus.hpp b/src/policy_msplus.hpp new file mode 100644 index 00000000..5ccf06eb --- /dev/null +++ b/src/policy_msplus.hpp @@ -0,0 +1,61 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace MSPLUS + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("msplus") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("msplus") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving() const final { return true; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("msplus") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_mspmfs.cpp b/src/policy_mspmfs.cpp index edc8e9b6..ec00f496 100644 --- a/src/policy_mspmfs.cpp +++ b/src/policy_mspmfs.cpp @@ -19,9 +19,10 @@ #include "fs_info.hpp" #include "fs_path.hpp" #include "fs_statvfs_cache.hpp" +#include "policies.hpp" #include "policy.hpp" #include "policy_error.hpp" -#include "rwlock.hpp" +#include "policy_mspmfs.hpp" #include #include @@ -36,38 +37,35 @@ namespace mspmfs static const string* - create_1(const BranchVec &branches_, - const string &fusepath_, - int *err_) + create_1(const Branches::CPtr &branches_, + const string &fusepath_, + int *err_) { int rv; uint64_t mfs; fs::info_t info; - const Branch *branch; const string *basepath; basepath = NULL; mfs = std::numeric_limits::min(); - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(const auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro_or_nc()) + if(branch.ro_or_nc()) error_and_continue(*err_,EROFS); - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) error_and_continue(*err_,ENOENT); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(*err_,ENOENT); if(info.readonly) error_and_continue(*err_,EROFS); - if(info.spaceavail < branch->minfreespace()) + if(info.spaceavail < branch.minfreespace()) error_and_continue(*err_,ENOSPC); if(info.spaceavail < mfs) continue; mfs = info.spaceavail; - basepath = &branch->path; + basepath = &branch.path; } return basepath; @@ -75,9 +73,9 @@ namespace mspmfs static int - create(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + create(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int error; string fusepath; @@ -102,27 +100,28 @@ namespace mspmfs return 0; } +} - static - int - create(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return mspmfs::create(branches_.vec,fusepath_,paths_); - } +int +Policy::MSPMFS::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return Policies::Action::epmfs(branches_,fusepath_,paths_); } int -Policy::Func::mspmfs(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::MSPMFS::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { - if(type_ == Category::CREATE) - return mspmfs::create(branches_,fusepath_,paths_); + return ::mspmfs::create(branches_,fusepath_,paths_); +} - return Policy::Func::epmfs(type_,branches_,fusepath_,paths_); +int +Policy::MSPMFS::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return Policies::Search::epmfs(branches_,fusepath_,paths_); } diff --git a/src/policy_mspmfs.hpp b/src/policy_mspmfs.hpp new file mode 100644 index 00000000..3123e952 --- /dev/null +++ b/src/policy_mspmfs.hpp @@ -0,0 +1,61 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace MSPMFS + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("mspmfs") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("mspmfs") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving() const final { return true; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("mspmfs") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_msppfrd.cpp b/src/policy_msppfrd.cpp index dd4f8931..baa1bd95 100644 --- a/src/policy_msppfrd.cpp +++ b/src/policy_msppfrd.cpp @@ -22,9 +22,10 @@ #include "fs_path.hpp" #include "fs_statvfs_cache.hpp" #include "policy.hpp" +#include "policy_msppfrd.hpp" +#include "policies.hpp" #include "policy_error.hpp" #include "rnd.hpp" -#include "rwlock.hpp" #include #include @@ -44,39 +45,36 @@ namespace msppfrd { static int - create_1(const BranchVec &branches_, - const string &fusepath_, - BranchInfoVec *branchinfo_, - uint64_t *sum_) + create_1(const Branches::CPtr &branches_, + const string &fusepath_, + BranchInfoVec *branchinfo_, + uint64_t *sum_) { int rv; int error; BranchInfo bi; fs::info_t info; - const Branch *branch; *sum_ = 0; error = ENOENT; - for(size_t i = 0, ei = branches_.size(); i < ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro_or_nc()) + if(branch.ro_or_nc()) error_and_continue(error,EROFS); - if(!fs::exists(branch->path,fusepath_)) + if(!fs::exists(branch.path,fusepath_)) error_and_continue(error,ENOENT); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(error,ENOENT); if(info.readonly) error_and_continue(error,EROFS); - if(info.spaceavail < branch->minfreespace()) + if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); *sum_ += info.spaceavail; bi.spaceavail = info.spaceavail; - bi.basepath = &branch->path; + bi.basepath = &branch.path; branchinfo_->push_back(bi); } @@ -85,24 +83,10 @@ namespace msppfrd static int - create_1(const Branches &branches_, - const string &fusepath_, - BranchInfoVec *branchinfo_, - uint64_t *sum_) - { - rwlock::ReadGuard guard(branches_.lock); - - branchinfo_->reserve(branches_.vec.size()); - - return msppfrd::create_1(branches_.vec,fusepath_,branchinfo_,sum_); - } - - static - int - get_branchinfo(const Branches &branches_, - const char *fusepath_, - BranchInfoVec *branchinfo_, - uint64_t *sum_) + get_branchinfo(const Branches::CPtr &branches_, + const char *fusepath_, + BranchInfoVec *branchinfo_, + uint64_t *sum_) { int error; string fusepath; @@ -147,9 +131,9 @@ namespace msppfrd static int - create(const Branches &branches_, - const char *fusepath_, - vector *paths_) + create(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int error; uint64_t sum; @@ -168,13 +152,25 @@ namespace msppfrd } int -Policy::Func::msppfrd(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::MSPPFRD::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { - if(type_ == Category::CREATE) - return msppfrd::create(branches_,fusepath_,paths_); + return Policies::Action::eppfrd(branches_,fusepath_,paths_); +} - return Policy::Func::eppfrd(type_,branches_,fusepath_,paths_); +int +Policy::MSPPFRD::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return ::msppfrd::create(branches_,fusepath_,paths_); +} + +int +Policy::MSPPFRD::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return Policies::Search::eppfrd(branches_,fusepath_,paths_); } diff --git a/src/policy_msppfrd.hpp b/src/policy_msppfrd.hpp new file mode 100644 index 00000000..d357d033 --- /dev/null +++ b/src/policy_msppfrd.hpp @@ -0,0 +1,61 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace MSPPFRD + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("msppfrd") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("msppfrd") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving() const final { return true; }; + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("msppfrd") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_newest.cpp b/src/policy_newest.cpp index 520cc1c9..f65e0f66 100644 --- a/src/policy_newest.cpp +++ b/src/policy_newest.cpp @@ -21,56 +21,52 @@ #include "fs_statvfs_cache.hpp" #include "policy.hpp" #include "policy_error.hpp" +#include "policy_newest.hpp" #include "rwlock.hpp" #include -#include #include #include using std::string; -using std::vector; namespace newest { static int - create(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + create(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int rv; int error; time_t newest; struct stat st; fs::info_t info; - const Branch *branch; const string *basepath; error = ENOENT; newest = std::numeric_limits::min(); basepath = NULL; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro_or_nc()) + if(branch.ro_or_nc()) error_and_continue(error,EROFS); - if(!fs::exists(branch->path,fusepath_,&st)) + if(!fs::exists(branch.path,fusepath_,&st)) error_and_continue(error,ENOENT); if(st.st_mtime < newest) continue; - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(error,ENOENT); if(info.readonly) error_and_continue(error,EROFS); - if(info.spaceavail < branch->minfreespace()) + if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); newest = st.st_mtime; - basepath = &branch->path; + basepath = &branch.path; } if(basepath == NULL) @@ -83,50 +79,36 @@ namespace newest static int - create(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return newest::create(branches_.vec,fusepath_,paths_); - } - - static - int - action(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + action(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int rv; int error; bool readonly; time_t newest; struct stat st; - const Branch *branch; const string *basepath; error = ENOENT; newest = std::numeric_limits::min(); basepath = NULL; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro()) + if(branch.ro()) error_and_continue(error,EROFS); - if(!fs::exists(branch->path,fusepath_,&st)) + if(!fs::exists(branch.path,fusepath_,&st)) error_and_continue(error,ENOENT); if(st.st_mtime < newest) continue; - rv = fs::statvfs_cache_readonly(branch->path,&readonly); + rv = fs::statvfs_cache_readonly(branch.path,&readonly); if(rv == -1) error_and_continue(error,ENOENT); if(readonly) error_and_continue(error,EROFS); newest = st.st_mtime; - basepath = &branch->path; + basepath = &branch.path; } if(basepath == NULL) @@ -139,39 +121,25 @@ namespace newest static int - action(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); - - return newest::action(branches_.vec,fusepath_,paths_); - } - - static - int - search(const BranchVec &branches_, - const char *fusepath_, - vector *paths_) + search(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { time_t newest; struct stat st; - const Branch *branch; const string *basepath; newest = std::numeric_limits::min(); basepath = NULL; - for(size_t i = 0, ei = branches_.size(); i != ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(!fs::exists(branch->path,fusepath_,&st)) + if(!fs::exists(branch.path,fusepath_,&st)) continue; if(st.st_mtime < newest) continue; newest = st.st_mtime; - basepath = &branch->path; + basepath = &branch.path; } if(basepath == NULL) @@ -181,33 +149,28 @@ namespace newest return 0; } +} - static - int - search(const Branches &branches_, - const char *fusepath_, - vector *paths_) - { - rwlock::ReadGuard guard(branches_.lock); +int +Policy::Newest::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return ::newest::action(branches_,fusepath_,paths_); +} - return newest::search(branches_.vec,fusepath_,paths_); - } +int +Policy::Newest::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return ::newest::create(branches_,fusepath_,paths_); } int -Policy::Func::newest(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::Newest::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { - switch(type_) - { - case Category::CREATE: - return newest::create(branches_,fusepath_,paths_); - case Category::ACTION: - return newest::action(branches_,fusepath_,paths_); - case Category::SEARCH: - default: - return newest::search(branches_,fusepath_,paths_); - } + return ::newest::search(branches_,fusepath_,paths_); } diff --git a/src/policy_newest.hpp b/src/policy_newest.hpp new file mode 100644 index 00000000..c4baf298 --- /dev/null +++ b/src/policy_newest.hpp @@ -0,0 +1,61 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace Newest + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("newest") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("newest") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving() const final { return false; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("newest") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_pfrd.cpp b/src/policy_pfrd.cpp index ab22e278..2862d3ca 100644 --- a/src/policy_pfrd.cpp +++ b/src/policy_pfrd.cpp @@ -17,10 +17,12 @@ #include "errno.hpp" #include "fs_info.hpp" #include "fs_path.hpp" +#include "policies.hpp" #include "policy.hpp" #include "policy_error.hpp" +#include "policy_pfrd.hpp" #include "rnd.hpp" -#include "rwlock.hpp" +#include "strvec.hpp" #include #include @@ -40,55 +42,39 @@ namespace pfrd { static int - get_branchinfo(const BranchVec &branches_, - BranchInfoVec *branchinfo_, - uint64_t *sum_) + get_branchinfo(const Branches::CPtr &branches_, + BranchInfoVec *branchinfo_, + uint64_t *sum_) { int rv; int error; BranchInfo bi; fs::info_t info; - const Branch *branch; *sum_ = 0; error = ENOENT; - for(size_t i = 0, ei = branches_.size(); i < ei; i++) + for(auto &branch : *branches_) { - branch = &branches_[i]; - - if(branch->ro_or_nc()) + if(branch.ro_or_nc()) error_and_continue(error,EROFS); - rv = fs::info(branch->path,&info); + rv = fs::info(branch.path,&info); if(rv == -1) error_and_continue(error,ENOENT); if(info.readonly) error_and_continue(error,EROFS); - if(info.spaceavail < branch->minfreespace()) + if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); *sum_ += info.spaceavail; bi.spaceavail = info.spaceavail; - bi.basepath = &branch->path; + bi.basepath = &branch.path; branchinfo_->push_back(bi); } return error; } - static - int - get_branchinfo(const Branches &branches_, - BranchInfoVec *branchinfo_, - uint64_t *sum_) - { - rwlock::ReadGuard guard(branches_.lock); - - branchinfo_->reserve(branches_.vec.size()); - - return pfrd::get_branchinfo(branches_.vec,branchinfo_,sum_); - } - static const string* @@ -115,9 +101,9 @@ namespace pfrd static int - create(const Branches &branches_, - const char *fusepath_, - vector *paths_) + create(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) { int error; uint64_t sum; @@ -136,13 +122,25 @@ namespace pfrd } int -Policy::Func::pfrd(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::PFRD::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { - if(type_ == Category::CREATE) - return pfrd::create(branches_,fusepath_,paths_); + return Policies::Action::eppfrd(branches_,fusepath_,paths_); +} - return Policy::Func::eppfrd(type_,branches_,fusepath_,paths_); +int +Policy::PFRD::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return ::pfrd::create(branches_,fusepath_,paths_); +} + +int +Policy::PFRD::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + return Policies::Search::eppfrd(branches_,fusepath_,paths_); } diff --git a/src/policy_pfrd.hpp b/src/policy_pfrd.hpp new file mode 100644 index 00000000..86b3c11c --- /dev/null +++ b/src/policy_pfrd.hpp @@ -0,0 +1,61 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace PFRD + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("pfrd") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("pfrd") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving() const final { return false; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("pfrd") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/policy_rand.cpp b/src/policy_rand.cpp index 160d39e5..9a74f017 100644 --- a/src/policy_rand.cpp +++ b/src/policy_rand.cpp @@ -16,23 +16,53 @@ #include "errno.hpp" #include "policy.hpp" +#include "policy_rand.hpp" +#include "policies.hpp" #include -#include -#include -using std::string; -using std::vector; +int +Policy::Rand::Action::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + int rv; + + rv = Policies::Action::all(branches_,fusepath_,paths_); + if(rv == 0) + { + std::random_shuffle(paths_->begin(),paths_->end()); + paths_->resize(1); + } + + return rv; +} + +int +Policy::Rand::Create::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const +{ + int rv; + + rv = Policies::Create::all(branches_,fusepath_,paths_); + if(rv == 0) + { + std::random_shuffle(paths_->begin(),paths_->end()); + paths_->resize(1); + } + + return rv; +} int -Policy::Func::rand(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) +Policy::Rand::Search::operator()(const Branches::CPtr &branches_, + const char *fusepath_, + StrVec *paths_) const { int rv; - rv = Policy::Func::all(type_,branches_,fusepath_,paths_); + rv = Policies::Search::all(branches_,fusepath_,paths_); if(rv == 0) { std::random_shuffle(paths_->begin(),paths_->end()); diff --git a/src/policy_rand.hpp b/src/policy_rand.hpp new file mode 100644 index 00000000..7d435433 --- /dev/null +++ b/src/policy_rand.hpp @@ -0,0 +1,61 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include "policy.hpp" + +namespace Policy +{ + namespace Rand + { + class Action final : public Policy::ActionImpl + { + public: + Action() + : Policy::ActionImpl("rand") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + + class Create final : public Policy::CreateImpl + { + public: + Create() + : Policy::CreateImpl("rand") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + bool path_preserving() const final { return false; } + }; + + class Search final : public Policy::SearchImpl + { + public: + Search() + : Policy::SearchImpl("rand") + {} + + public: + int operator()(const Branches::CPtr&,const char*,StrVec*) const final; + }; + } +} diff --git a/src/rnd.cpp b/src/rnd.cpp index 5eab6ce1..c30f3a74 100644 --- a/src/rnd.cpp +++ b/src/rnd.cpp @@ -20,9 +20,11 @@ #include "wyhash.h" -#include +#include + #include + static uint64_t G_SEED; static RND G_RND; diff --git a/src/rnd.hpp b/src/rnd.hpp index dd9b6648..e9b300d0 100644 --- a/src/rnd.hpp +++ b/src/rnd.hpp @@ -18,7 +18,8 @@ #pragma once -#include +#include + class RND { diff --git a/src/statvfs_util.hpp b/src/statvfs_util.hpp index 0447d181..a1e83dd1 100644 --- a/src/statvfs_util.hpp +++ b/src/statvfs_util.hpp @@ -16,11 +16,12 @@ #pragma once +#include #include -#include #include + namespace StatVFS { static diff --git a/src/str.cpp b/src/str.cpp index de07ff2c..66d05183 100644 --- a/src/str.cpp +++ b/src/str.cpp @@ -14,15 +14,17 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include +#include #include #include -#include #include +using std::istringstream; +using std::set; using std::string; using std::vector; -using std::istringstream; namespace str { @@ -105,6 +107,25 @@ namespace str return str::join(vec_,0,sep_); } + string + join(const set &set_, + const char sep_) + { + string rv; + set::iterator i; + + if(set_.empty()) + return string(); + + i = set_.begin(); + rv += *i; + ++i; + for(; i != set_.end(); ++i) + rv += sep_ + *i; + + return rv; + } + size_t longest_common_prefix_index(const vector &vec_) { diff --git a/src/str.hpp b/src/str.hpp index c9a6f268..34f19e8c 100644 --- a/src/str.hpp +++ b/src/str.hpp @@ -16,6 +16,7 @@ #pragma once +#include #include #include @@ -50,6 +51,10 @@ namespace str join(const std::vector &vec, const char sep); + std::string + join(const std::set &s, + const char sep); + size_t longest_common_prefix_index(const std::vector &vec); diff --git a/src/policy_invalid.cpp b/src/strvec.hpp similarity index 67% rename from src/policy_invalid.cpp rename to src/strvec.hpp index caedc24f..593263df 100644 --- a/src/policy_invalid.cpp +++ b/src/strvec.hpp @@ -1,5 +1,7 @@ /* - Copyright (c) 2016, Antonio SJ Musumeci + 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 @@ -14,20 +16,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "errno.hpp" -#include "policy.hpp" +#pragma once #include #include -using std::string; -using std::vector; - -int -Policy::Func::invalid(const Category type_, - const Branches &branches_, - const char *fusepath_, - vector *paths_) -{ - return (errno=EINVAL,-1); -} +typedef std::vector StrVec; diff --git a/src/to_string.cpp b/src/to_string.cpp index 3019b682..0d5cddd7 100644 --- a/src/to_string.cpp +++ b/src/to_string.cpp @@ -16,10 +16,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include -#include #include namespace str diff --git a/src/to_string.hpp b/src/to_string.hpp index 5e4f04e7..846147a4 100644 --- a/src/to_string.hpp +++ b/src/to_string.hpp @@ -18,9 +18,9 @@ #pragma once +#include #include -#include namespace str { diff --git a/src/tofrom_wrapper.hpp b/src/tofrom_wrapper.hpp index 9be0d3fe..ebcc605f 100644 --- a/src/tofrom_wrapper.hpp +++ b/src/tofrom_wrapper.hpp @@ -29,13 +29,13 @@ class ToFromWrapper : public ToFromString { public: int - from_string(const std::string &s_) + from_string(const std::string &s_) final { return str::from(s_,&_data); } std::string - to_string(void) const + to_string(void) const final { return str::to(_data); } @@ -70,6 +70,13 @@ public: return &_data; } + const + T* + operator->() const + { + return &_data; + } + public: bool operator==(const T &data_) const @@ -86,13 +93,13 @@ class ROToFromWrapper : public ToFromString { public: int - from_string(const std::string &s_) + from_string(const std::string &s_) final { return -EINVAL; } std::string - to_string(void) const + to_string(void) const final { return str::to(_data); } diff --git a/tests/acutest.h b/tests/acutest.h new file mode 100644 index 00000000..8b49afc8 --- /dev/null +++ b/tests/acutest.h @@ -0,0 +1,1794 @@ +/* + * Acutest -- Another C/C++ Unit Test facility + * + * + * Copyright 2013-2020 Martin Mitas + * Copyright 2019 Garrett D'Amore + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef ACUTEST_H +#define ACUTEST_H + + +/************************ + *** Public interface *** + ************************/ + +/* By default, "acutest.h" provides the main program entry point (function + * main()). However, if the test suite is composed of multiple source files + * which include "acutest.h", then this causes a problem of multiple main() + * definitions. To avoid this problem, #define macro TEST_NO_MAIN in all + * compilation units but one. + */ + +/* Macro to specify list of unit tests in the suite. + * The unit test implementation MUST provide list of unit tests it implements + * with this macro: + * + * TEST_LIST = { + * { "test1_name", test1_func_ptr }, + * { "test2_name", test2_func_ptr }, + * ... + * { NULL, NULL } // zeroed record marking the end of the list + * }; + * + * The list specifies names of each test (must be unique) and pointer to + * a function implementing it. The function does not take any arguments + * and has no return values, i.e. every test function has to be compatible + * with this prototype: + * + * void test_func(void); + * + * Note the list has to be ended with a zeroed record. + */ +#define TEST_LIST const struct test_ test_list_[] + + +/* Macros for testing whether an unit test succeeds or fails. These macros + * can be used arbitrarily in functions implementing the unit tests. + * + * If any condition fails throughout execution of a test, the test fails. + * + * TEST_CHECK takes only one argument (the condition), TEST_CHECK_ allows + * also to specify an error message to print out if the condition fails. + * (It expects printf-like format string and its parameters). The macros + * return non-zero (condition passes) or 0 (condition fails). + * + * That can be useful when more conditions should be checked only if some + * preceding condition passes, as illustrated in this code snippet: + * + * SomeStruct* ptr = allocate_some_struct(); + * if(TEST_CHECK(ptr != NULL)) { + * TEST_CHECK(ptr->member1 < 100); + * TEST_CHECK(ptr->member2 > 200); + * } + */ +#define TEST_CHECK_(cond,...) test_check_((cond), __FILE__, __LINE__, __VA_ARGS__) +#define TEST_CHECK(cond) test_check_((cond), __FILE__, __LINE__, "%s", #cond) + + +/* These macros are the same as TEST_CHECK_ and TEST_CHECK except that if the + * condition fails, the currently executed unit test is immediately aborted. + * + * That is done either by calling abort() if the unit test is executed as a + * child process; or via longjmp() if the unit test is executed within the + * main Acutest process. + * + * As a side effect of such abortion, your unit tests may cause memory leaks, + * unflushed file descriptors, and other phenomena caused by the abortion. + * + * Therefore you should not use these as a general replacement for TEST_CHECK. + * Use it with some caution, especially if your test causes some other side + * effects to the outside world (e.g. communicating with some server, inserting + * into a database etc.). + */ +#define TEST_ASSERT_(cond,...) \ + do { \ + if(!test_check_((cond), __FILE__, __LINE__, __VA_ARGS__)) \ + test_abort_(); \ + } while(0) +#define TEST_ASSERT(cond) \ + do { \ + if(!test_check_((cond), __FILE__, __LINE__, "%s", #cond)) \ + test_abort_(); \ + } while(0) + + +#ifdef __cplusplus +/* Macros to verify that the code (the 1st argument) throws exception of given + * type (the 2nd argument). (Note these macros are only available in C++.) + * + * TEST_EXCEPTION_ is like TEST_EXCEPTION but accepts custom printf-like + * message. + * + * For example: + * + * TEST_EXCEPTION(function_that_throw(), ExpectedExceptionType); + * + * If the function_that_throw() throws ExpectedExceptionType, the check passes. + * If the function throws anything incompatible with ExpectedExceptionType + * (or if it does not thrown an exception at all), the check fails. + */ +#define TEST_EXCEPTION(code, exctype) \ + do { \ + bool exc_ok_ = false; \ + const char *msg_ = NULL; \ + try { \ + code; \ + msg_ = "No exception thrown."; \ + } catch(exctype const&) { \ + exc_ok_= true; \ + } catch(...) { \ + msg_ = "Unexpected exception thrown."; \ + } \ + test_check_(exc_ok_, __FILE__, __LINE__, #code " throws " #exctype); \ + if(msg_ != NULL) \ + test_message_("%s", msg_); \ + } while(0) +#define TEST_EXCEPTION_(code, exctype, ...) \ + do { \ + bool exc_ok_ = false; \ + const char *msg_ = NULL; \ + try { \ + code; \ + msg_ = "No exception thrown."; \ + } catch(exctype const&) { \ + exc_ok_= true; \ + } catch(...) { \ + msg_ = "Unexpected exception thrown."; \ + } \ + test_check_(exc_ok_, __FILE__, __LINE__, __VA_ARGS__); \ + if(msg_ != NULL) \ + test_message_("%s", msg_); \ + } while(0) +#endif /* #ifdef __cplusplus */ + + +/* Sometimes it is useful to split execution of more complex unit tests to some + * smaller parts and associate those parts with some names. + * + * This is especially handy if the given unit test is implemented as a loop + * over some vector of multiple testing inputs. Using these macros allow to use + * sort of subtitle for each iteration of the loop (e.g. outputting the input + * itself or a name associated to it), so that if any TEST_CHECK condition + * fails in the loop, it can be easily seen which iteration triggers the + * failure, without the need to manually output the iteration-specific data in + * every single TEST_CHECK inside the loop body. + * + * TEST_CASE allows to specify only single string as the name of the case, + * TEST_CASE_ provides all the power of printf-like string formatting. + * + * Note that the test cases cannot be nested. Starting a new test case ends + * implicitly the previous one. To end the test case explicitly (e.g. to end + * the last test case after exiting the loop), you may use TEST_CASE(NULL). + */ +#define TEST_CASE_(...) test_case_(__VA_ARGS__) +#define TEST_CASE(name) test_case_("%s", name) + + +/* Maximal output per TEST_CASE call. Longer messages are cut. + * You may define another limit prior including "acutest.h" + */ +#ifndef TEST_CASE_MAXSIZE + #define TEST_CASE_MAXSIZE 64 +#endif + + +/* printf-like macro for outputting an extra information about a failure. + * + * Intended use is to output some computed output versus the expected value, + * e.g. like this: + * + * if(!TEST_CHECK(produced == expected)) { + * TEST_MSG("Expected: %d", expected); + * TEST_MSG("Produced: %d", produced); + * } + * + * Note the message is only written down if the most recent use of any checking + * macro (like e.g. TEST_CHECK or TEST_EXCEPTION) in the current test failed. + * This means the above is equivalent to just this: + * + * TEST_CHECK(produced == expected); + * TEST_MSG("Expected: %d", expected); + * TEST_MSG("Produced: %d", produced); + * + * The macro can deal with multi-line output fairly well. It also automatically + * adds a final new-line if there is none present. + */ +#define TEST_MSG(...) test_message_(__VA_ARGS__) + + +/* Maximal output per TEST_MSG call. Longer messages are cut. + * You may define another limit prior including "acutest.h" + */ +#ifndef TEST_MSG_MAXSIZE + #define TEST_MSG_MAXSIZE 1024 +#endif + + +/* Macro for dumping a block of memory. + * + * Its intended use is very similar to what TEST_MSG is for, but instead of + * generating any printf-like message, this is for dumping raw block of a + * memory in a hexadecimal form: + * + * TEST_CHECK(size_produced == size_expected && + * memcmp(addr_produced, addr_expected, size_produced) == 0); + * TEST_DUMP("Expected:", addr_expected, size_expected); + * TEST_DUMP("Produced:", addr_produced, size_produced); + */ +#define TEST_DUMP(title, addr, size) test_dump_(title, addr, size) + +/* Maximal output per TEST_DUMP call (in bytes to dump). Longer blocks are cut. + * You may define another limit prior including "acutest.h" + */ +#ifndef TEST_DUMP_MAXSIZE + #define TEST_DUMP_MAXSIZE 1024 +#endif + + +/* Common test initialiation/clean-up + * + * In some test suites, it may be needed to perform some sort of the same + * initialization and/or clean-up in all the tests. + * + * Such test suites may use macros TEST_INIT and/or TEST_FINI prior including + * this header. The expansion of the macro is then used as a body of helper + * function called just before executing every single (TEST_INIT) or just after + * it ends (TEST_FINI). + * + * Examples of various ways how to use the macro TEST_INIT: + * + * #define TEST_INIT my_init_func(); + * #define TEST_INIT my_init_func() // Works even without the semicolon + * #define TEST_INIT setlocale(LC_ALL, NULL); + * #define TEST_INIT { setlocale(LC_ALL, NULL); my_init_func(); } + * + * TEST_FINI is to be used in the same way. + */ + + +/********************** + *** Implementation *** + **********************/ + +/* The unit test files should not rely on anything below. */ + +#include +#include +#include +#include +#include +#include + +#if defined(unix) || defined(__unix__) || defined(__unix) || defined(__APPLE__) + #define ACUTEST_UNIX_ 1 + #include + #include + #include + #include + #include + #include + #include + + #if defined CLOCK_PROCESS_CPUTIME_ID && defined CLOCK_MONOTONIC + #define ACUTEST_HAS_POSIX_TIMER_ 1 + #endif +#endif + +#if defined(_gnu_linux_) || defined(__linux__) + #define ACUTEST_LINUX_ 1 + #include + #include +#endif + +#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) + #define ACUTEST_WIN_ 1 + #include + #include +#endif + +#ifdef __cplusplus + #include +#endif + +/* Load valgrind.h, if available. This allows to detect valgrind's presence via RUNNING_ON_VALGRIND. */ +#ifdef __has_include + #if __has_include() + #include + #endif +#endif + +/* Enable the use of the non-standard keyword __attribute__ to silence warnings under some compilers */ +#if defined(__GNUC__) || defined(__clang__) + #define TEST_ATTRIBUTE_(attr) __attribute__((attr)) +#else + #define TEST_ATTRIBUTE_(attr) +#endif + +/* Note our global private identifiers end with '_' to mitigate risk of clash + * with the unit tests implementation. */ + +#ifdef __cplusplus + extern "C" { +#endif + +#ifdef _MSC_VER + /* In the multi-platform code like ours, we cannot use the non-standard + * "safe" functions from Microsoft C lib like e.g. sprintf_s() instead of + * standard sprintf(). Hence, lets disable the warning C4996. */ + #pragma warning(push) + #pragma warning(disable: 4996) +#endif + + +struct test_ { + const char* name; + void (*func)(void); +}; + +struct test_detail_ { + unsigned char flags; + double duration; +}; + +enum { + TEST_FLAG_RUN_ = 1 << 0, + TEST_FLAG_SUCCESS_ = 1 << 1, + TEST_FLAG_FAILURE_ = 1 << 2, +}; + +extern const struct test_ test_list_[]; + +int test_check_(int cond, const char* file, int line, const char* fmt, ...); +void test_case_(const char* fmt, ...); +void test_message_(const char* fmt, ...); +void test_dump_(const char* title, const void* addr, size_t size); +void test_abort_(void) TEST_ATTRIBUTE_(noreturn); + + +#ifndef TEST_NO_MAIN + +static char* test_argv0_ = NULL; +static size_t test_list_size_ = 0; +static struct test_detail_ *test_details_ = NULL; +static size_t test_count_ = 0; +static int test_no_exec_ = -1; +static int test_no_summary_ = 0; +static int test_tap_ = 0; +static int test_skip_mode_ = 0; +static int test_worker_ = 0; +static int test_worker_index_ = 0; +static int test_cond_failed_ = 0; +static int test_was_aborted_ = 0; +static FILE *test_xml_output_ = NULL; + +static int test_stat_failed_units_ = 0; +static int test_stat_run_units_ = 0; + +static const struct test_* test_current_unit_ = NULL; +static int test_current_index_ = 0; +static char test_case_name_[TEST_CASE_MAXSIZE] = ""; +static int test_current_already_logged_ = 0; +static int test_case_current_already_logged_ = 0; +static int test_verbose_level_ = 2; +static int test_current_failures_ = 0; +static int test_colorize_ = 0; +static int test_timer_ = 0; + +static int test_abort_has_jmp_buf_ = 0; +static jmp_buf test_abort_jmp_buf_; + + +static void +test_cleanup_(void) +{ + free((void*) test_details_); +} + +static void +test_exit_(int exit_code) +{ + test_cleanup_(); + exit(exit_code); +} + +#if defined ACUTEST_WIN_ + typedef LARGE_INTEGER test_timer_type_; + static LARGE_INTEGER test_timer_freq_; + static test_timer_type_ test_timer_start_; + static test_timer_type_ test_timer_end_; + + static void + test_timer_init_(void) + { + QueryPerformanceFrequency(&test_timer_freq_); + } + + static void + test_timer_get_time_(LARGE_INTEGER* ts) + { + QueryPerformanceCounter(ts); + } + + static double + test_timer_diff_(LARGE_INTEGER start, LARGE_INTEGER end) + { + double duration = (double)(end.QuadPart - start.QuadPart); + duration /= (double)test_timer_freq_.QuadPart; + return duration; + } + + static void + test_timer_print_diff_(void) + { + printf("%.6lf secs", test_timer_diff_(test_timer_start_, test_timer_end_)); + } +#elif defined ACUTEST_HAS_POSIX_TIMER_ + static clockid_t test_timer_id_; + typedef struct timespec test_timer_type_; + static test_timer_type_ test_timer_start_; + static test_timer_type_ test_timer_end_; + + static void + test_timer_init_(void) + { + if(test_timer_ == 1) + test_timer_id_ = CLOCK_MONOTONIC; + else if(test_timer_ == 2) + test_timer_id_ = CLOCK_PROCESS_CPUTIME_ID; + } + + static void + test_timer_get_time_(struct timespec* ts) + { + clock_gettime(test_timer_id_, ts); + } + + static double + test_timer_diff_(struct timespec start, struct timespec end) + { + double endns; + double startns; + + endns = end.tv_sec; + endns *= 1e9; + endns += end.tv_nsec; + + startns = start.tv_sec; + startns *= 1e9; + startns += start.tv_nsec; + + return ((endns - startns)/ 1e9); + } + + static void + test_timer_print_diff_(void) + { + printf("%.6lf secs", + test_timer_diff_(test_timer_start_, test_timer_end_)); + } +#else + typedef int test_timer_type_; + static test_timer_type_ test_timer_start_; + static test_timer_type_ test_timer_end_; + + void + test_timer_init_(void) + {} + + static void + test_timer_get_time_(int* ts) + { + (void) ts; + } + + static double + test_timer_diff_(int start, int end) + { + (void) start; + (void) end; + return 0.0; + } + + static void + test_timer_print_diff_(void) + {} +#endif + +#define TEST_COLOR_DEFAULT_ 0 +#define TEST_COLOR_GREEN_ 1 +#define TEST_COLOR_RED_ 2 +#define TEST_COLOR_DEFAULT_INTENSIVE_ 3 +#define TEST_COLOR_GREEN_INTENSIVE_ 4 +#define TEST_COLOR_RED_INTENSIVE_ 5 + +static int TEST_ATTRIBUTE_(format (printf, 2, 3)) +test_print_in_color_(int color, const char* fmt, ...) +{ + va_list args; + char buffer[256]; + int n; + + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + buffer[sizeof(buffer)-1] = '\0'; + + if(!test_colorize_) { + return printf("%s", buffer); + } + +#if defined ACUTEST_UNIX_ + { + const char* col_str; + switch(color) { + case TEST_COLOR_GREEN_: col_str = "\033[0;32m"; break; + case TEST_COLOR_RED_: col_str = "\033[0;31m"; break; + case TEST_COLOR_GREEN_INTENSIVE_: col_str = "\033[1;32m"; break; + case TEST_COLOR_RED_INTENSIVE_: col_str = "\033[1;31m"; break; + case TEST_COLOR_DEFAULT_INTENSIVE_: col_str = "\033[1m"; break; + default: col_str = "\033[0m"; break; + } + printf("%s", col_str); + n = printf("%s", buffer); + printf("\033[0m"); + return n; + } +#elif defined ACUTEST_WIN_ + { + HANDLE h; + CONSOLE_SCREEN_BUFFER_INFO info; + WORD attr; + + h = GetStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(h, &info); + + switch(color) { + case TEST_COLOR_GREEN_: attr = FOREGROUND_GREEN; break; + case TEST_COLOR_RED_: attr = FOREGROUND_RED; break; + case TEST_COLOR_GREEN_INTENSIVE_: attr = FOREGROUND_GREEN | FOREGROUND_INTENSITY; break; + case TEST_COLOR_RED_INTENSIVE_: attr = FOREGROUND_RED | FOREGROUND_INTENSITY; break; + case TEST_COLOR_DEFAULT_INTENSIVE_: attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; break; + default: attr = 0; break; + } + if(attr != 0) + SetConsoleTextAttribute(h, attr); + n = printf("%s", buffer); + SetConsoleTextAttribute(h, info.wAttributes); + return n; + } +#else + n = printf("%s", buffer); + return n; +#endif +} + +static void +test_begin_test_line_(const struct test_* test) +{ + if(!test_tap_) { + if(test_verbose_level_ >= 3) { + test_print_in_color_(TEST_COLOR_DEFAULT_INTENSIVE_, "Test %s:\n", test->name); + test_current_already_logged_++; + } else if(test_verbose_level_ >= 1) { + int n; + char spaces[48]; + + n = test_print_in_color_(TEST_COLOR_DEFAULT_INTENSIVE_, "Test %s... ", test->name); + memset(spaces, ' ', sizeof(spaces)); + if(n < (int) sizeof(spaces)) + printf("%.*s", (int) sizeof(spaces) - n, spaces); + } else { + test_current_already_logged_ = 1; + } + } +} + +static void +test_finish_test_line_(int result) +{ + if(test_tap_) { + const char* str = (result == 0) ? "ok" : "not ok"; + + printf("%s %d - %s\n", str, test_current_index_ + 1, test_current_unit_->name); + + if(result == 0 && test_timer_) { + printf("# Duration: "); + test_timer_print_diff_(); + printf("\n"); + } + } else { + int color = (result == 0) ? TEST_COLOR_GREEN_INTENSIVE_ : TEST_COLOR_RED_INTENSIVE_; + const char* str = (result == 0) ? "OK" : "FAILED"; + printf("[ "); + test_print_in_color_(color, "%s", str); + printf(" ]"); + + if(result == 0 && test_timer_) { + printf(" "); + test_timer_print_diff_(); + } + + printf("\n"); + } +} + +static void +test_line_indent_(int level) +{ + static const char spaces[] = " "; + int n = level * 2; + + if(test_tap_ && n > 0) { + n--; + printf("#"); + } + + while(n > 16) { + printf("%s", spaces); + n -= 16; + } + printf("%.*s", n, spaces); +} + +int TEST_ATTRIBUTE_(format (printf, 4, 5)) +test_check_(int cond, const char* file, int line, const char* fmt, ...) +{ + const char *result_str; + int result_color; + int verbose_level; + + if(cond) { + result_str = "ok"; + result_color = TEST_COLOR_GREEN_; + verbose_level = 3; + } else { + if(!test_current_already_logged_ && test_current_unit_ != NULL) + test_finish_test_line_(-1); + + result_str = "failed"; + result_color = TEST_COLOR_RED_; + verbose_level = 2; + test_current_failures_++; + test_current_already_logged_++; + } + + if(test_verbose_level_ >= verbose_level) { + va_list args; + + if(!test_case_current_already_logged_ && test_case_name_[0]) { + test_line_indent_(1); + test_print_in_color_(TEST_COLOR_DEFAULT_INTENSIVE_, "Case %s:\n", test_case_name_); + test_current_already_logged_++; + test_case_current_already_logged_++; + } + + test_line_indent_(test_case_name_[0] ? 2 : 1); + if(file != NULL) { +#ifdef ACUTEST_WIN_ + const char* lastsep1 = strrchr(file, '\\'); + const char* lastsep2 = strrchr(file, '/'); + if(lastsep1 == NULL) + lastsep1 = file-1; + if(lastsep2 == NULL) + lastsep2 = file-1; + file = (lastsep1 > lastsep2 ? lastsep1 : lastsep2) + 1; +#else + const char* lastsep = strrchr(file, '/'); + if(lastsep != NULL) + file = lastsep+1; +#endif + printf("%s:%d: Check ", file, line); + } + + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + + printf("... "); + test_print_in_color_(result_color, "%s", result_str); + printf("\n"); + test_current_already_logged_++; + } + + test_cond_failed_ = (cond == 0); + return !test_cond_failed_; +} + +void TEST_ATTRIBUTE_(format (printf, 1, 2)) +test_case_(const char* fmt, ...) +{ + va_list args; + + if(test_verbose_level_ < 2) + return; + + if(test_case_name_[0]) { + test_case_current_already_logged_ = 0; + test_case_name_[0] = '\0'; + } + + if(fmt == NULL) + return; + + va_start(args, fmt); + vsnprintf(test_case_name_, sizeof(test_case_name_) - 1, fmt, args); + va_end(args); + test_case_name_[sizeof(test_case_name_) - 1] = '\0'; + + if(test_verbose_level_ >= 3) { + test_line_indent_(1); + test_print_in_color_(TEST_COLOR_DEFAULT_INTENSIVE_, "Case %s:\n", test_case_name_); + test_current_already_logged_++; + test_case_current_already_logged_++; + } +} + +void TEST_ATTRIBUTE_(format (printf, 1, 2)) +test_message_(const char* fmt, ...) +{ + char buffer[TEST_MSG_MAXSIZE]; + char* line_beg; + char* line_end; + va_list args; + + if(test_verbose_level_ < 2) + return; + + /* We allow extra message only when something is already wrong in the + * current test. */ + if(test_current_unit_ == NULL || !test_cond_failed_) + return; + + va_start(args, fmt); + vsnprintf(buffer, TEST_MSG_MAXSIZE, fmt, args); + va_end(args); + buffer[TEST_MSG_MAXSIZE-1] = '\0'; + + line_beg = buffer; + while(1) { + line_end = strchr(line_beg, '\n'); + if(line_end == NULL) + break; + test_line_indent_(test_case_name_[0] ? 3 : 2); + printf("%.*s\n", (int)(line_end - line_beg), line_beg); + line_beg = line_end + 1; + } + if(line_beg[0] != '\0') { + test_line_indent_(test_case_name_[0] ? 3 : 2); + printf("%s\n", line_beg); + } +} + +void +test_dump_(const char* title, const void* addr, size_t size) +{ + static const size_t BYTES_PER_LINE = 16; + size_t line_beg; + size_t truncate = 0; + + if(test_verbose_level_ < 2) + return; + + /* We allow extra message only when something is already wrong in the + * current test. */ + if(test_current_unit_ == NULL || !test_cond_failed_) + return; + + if(size > TEST_DUMP_MAXSIZE) { + truncate = size - TEST_DUMP_MAXSIZE; + size = TEST_DUMP_MAXSIZE; + } + + test_line_indent_(test_case_name_[0] ? 3 : 2); + printf((title[strlen(title)-1] == ':') ? "%s\n" : "%s:\n", title); + + for(line_beg = 0; line_beg < size; line_beg += BYTES_PER_LINE) { + size_t line_end = line_beg + BYTES_PER_LINE; + size_t off; + + test_line_indent_(test_case_name_[0] ? 4 : 3); + printf("%08lx: ", (unsigned long)line_beg); + for(off = line_beg; off < line_end; off++) { + if(off < size) + printf(" %02x", ((const unsigned char*)addr)[off]); + else + printf(" "); + } + + printf(" "); + for(off = line_beg; off < line_end; off++) { + unsigned char byte = ((const unsigned char*)addr)[off]; + if(off < size) + printf("%c", (iscntrl(byte) ? '.' : byte)); + else + break; + } + + printf("\n"); + } + + if(truncate > 0) { + test_line_indent_(test_case_name_[0] ? 4 : 3); + printf(" ... (and more %u bytes)\n", (unsigned) truncate); + } +} + +/* This is called just before each test */ +static void +test_init_(const char *test_name) +{ +#ifdef TEST_INIT + TEST_INIT + ; /* Allow for a single unterminated function call */ +#endif + + /* Suppress any warnings about unused variable. */ + (void) test_name; +} + +/* This is called after each test */ +static void +test_fini_(const char *test_name) +{ +#ifdef TEST_FINI + TEST_FINI + ; /* Allow for a single unterminated function call */ +#endif + + /* Suppress any warnings about unused variable. */ + (void) test_name; +} + +void +test_abort_(void) +{ + if(test_abort_has_jmp_buf_) { + longjmp(test_abort_jmp_buf_, 1); + } else { + if(test_current_unit_ != NULL) + test_fini_(test_current_unit_->name); + abort(); + } +} + +static void +test_list_names_(void) +{ + const struct test_* test; + + printf("Unit tests:\n"); + for(test = &test_list_[0]; test->func != NULL; test++) + printf(" %s\n", test->name); +} + +static void +test_remember_(int i) +{ + if(test_details_[i].flags & TEST_FLAG_RUN_) + return; + + test_details_[i].flags |= TEST_FLAG_RUN_; + test_count_++; +} + +static void +test_set_success_(int i, int success) +{ + test_details_[i].flags |= success ? TEST_FLAG_SUCCESS_ : TEST_FLAG_FAILURE_; +} + +static void +test_set_duration_(int i, double duration) +{ + test_details_[i].duration = duration; +} + +static int +test_name_contains_word_(const char* name, const char* pattern) +{ + static const char word_delim[] = " \t-_/.,:;"; + const char* substr; + size_t pattern_len; + + pattern_len = strlen(pattern); + + substr = strstr(name, pattern); + while(substr != NULL) { + int starts_on_word_boundary = (substr == name || strchr(word_delim, substr[-1]) != NULL); + int ends_on_word_boundary = (substr[pattern_len] == '\0' || strchr(word_delim, substr[pattern_len]) != NULL); + + if(starts_on_word_boundary && ends_on_word_boundary) + return 1; + + substr = strstr(substr+1, pattern); + } + + return 0; +} + +static int +test_lookup_(const char* pattern) +{ + int i; + int n = 0; + + /* Try exact match. */ + for(i = 0; i < (int) test_list_size_; i++) { + if(strcmp(test_list_[i].name, pattern) == 0) { + test_remember_(i); + n++; + break; + } + } + if(n > 0) + return n; + + /* Try word match. */ + for(i = 0; i < (int) test_list_size_; i++) { + if(test_name_contains_word_(test_list_[i].name, pattern)) { + test_remember_(i); + n++; + } + } + if(n > 0) + return n; + + /* Try relaxed match. */ + for(i = 0; i < (int) test_list_size_; i++) { + if(strstr(test_list_[i].name, pattern) != NULL) { + test_remember_(i); + n++; + } + } + + return n; +} + + +/* Called if anything goes bad in Acutest, or if the unit test ends in other + * way then by normal returning from its function (e.g. exception or some + * abnormal child process termination). */ +static void TEST_ATTRIBUTE_(format (printf, 1, 2)) +test_error_(const char* fmt, ...) +{ + if(test_verbose_level_ == 0) + return; + + if(test_verbose_level_ >= 2) { + va_list args; + + test_line_indent_(1); + if(test_verbose_level_ >= 3) + test_print_in_color_(TEST_COLOR_RED_INTENSIVE_, "ERROR: "); + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + printf("\n"); + } + + if(test_verbose_level_ >= 3) { + printf("\n"); + } +} + +/* Call directly the given test unit function. */ +static int +test_do_run_(const struct test_* test, int index) +{ + int status = -1; + + test_was_aborted_ = 0; + test_current_unit_ = test; + test_current_index_ = index; + test_current_failures_ = 0; + test_current_already_logged_ = 0; + test_cond_failed_ = 0; + +#ifdef __cplusplus + try { +#endif + test_init_(test->name); + test_begin_test_line_(test); + + /* This is good to do in case the test unit crashes. */ + fflush(stdout); + fflush(stderr); + + if(!test_worker_) { + test_abort_has_jmp_buf_ = 1; + if(setjmp(test_abort_jmp_buf_) != 0) { + test_was_aborted_ = 1; + goto aborted; + } + } + + test_timer_get_time_(&test_timer_start_); + test->func(); +aborted: + test_abort_has_jmp_buf_ = 0; + test_timer_get_time_(&test_timer_end_); + + if(test_verbose_level_ >= 3) { + test_line_indent_(1); + if(test_current_failures_ == 0) { + test_print_in_color_(TEST_COLOR_GREEN_INTENSIVE_, "SUCCESS: "); + printf("All conditions have passed.\n"); + + if(test_timer_) { + test_line_indent_(1); + printf("Duration: "); + test_timer_print_diff_(); + printf("\n"); + } + } else { + test_print_in_color_(TEST_COLOR_RED_INTENSIVE_, "FAILED: "); + if(!test_was_aborted_) { + printf("%d condition%s %s failed.\n", + test_current_failures_, + (test_current_failures_ == 1) ? "" : "s", + (test_current_failures_ == 1) ? "has" : "have"); + } else { + printf("Aborted.\n"); + } + } + printf("\n"); + } else if(test_verbose_level_ >= 1 && test_current_failures_ == 0) { + test_finish_test_line_(0); + } + + status = (test_current_failures_ == 0) ? 0 : -1; + +#ifdef __cplusplus + } catch(std::exception& e) { + const char* what = e.what(); + test_check_(0, NULL, 0, "Threw std::exception"); + if(what != NULL) + test_message_("std::exception::what(): %s", what); + + if(test_verbose_level_ >= 3) { + test_line_indent_(1); + test_print_in_color_(TEST_COLOR_RED_INTENSIVE_, "FAILED: "); + printf("C++ exception.\n\n"); + } + } catch(...) { + test_check_(0, NULL, 0, "Threw an exception"); + + if(test_verbose_level_ >= 3) { + test_line_indent_(1); + test_print_in_color_(TEST_COLOR_RED_INTENSIVE_, "FAILED: "); + printf("C++ exception.\n\n"); + } + } +#endif + + test_fini_(test->name); + test_case_(NULL); + test_current_unit_ = NULL; + + return status; +} + +/* Trigger the unit test. If possible (and not suppressed) it starts a child + * process who calls test_do_run_(), otherwise it calls test_do_run_() + * directly. */ +static void +test_run_(const struct test_* test, int index, int master_index) +{ + int failed = 1; + test_timer_type_ start, end; + + test_current_unit_ = test; + test_current_already_logged_ = 0; + test_timer_get_time_(&start); + + if(!test_no_exec_) { + +#if defined(ACUTEST_UNIX_) + + pid_t pid; + int exit_code; + + /* Make sure the child starts with empty I/O buffers. */ + fflush(stdout); + fflush(stderr); + + pid = fork(); + if(pid == (pid_t)-1) { + test_error_("Cannot fork. %s [%d]", strerror(errno), errno); + failed = 1; + } else if(pid == 0) { + /* Child: Do the test. */ + test_worker_ = 1; + failed = (test_do_run_(test, index) != 0); + test_exit_(failed ? 1 : 0); + } else { + /* Parent: Wait until child terminates and analyze its exit code. */ + waitpid(pid, &exit_code, 0); + if(WIFEXITED(exit_code)) { + switch(WEXITSTATUS(exit_code)) { + case 0: failed = 0; break; /* test has passed. */ + case 1: /* noop */ break; /* "normal" failure. */ + default: test_error_("Unexpected exit code [%d]", WEXITSTATUS(exit_code)); + } + } else if(WIFSIGNALED(exit_code)) { + char tmp[32]; + const char* signame; + switch(WTERMSIG(exit_code)) { + case SIGINT: signame = "SIGINT"; break; + case SIGHUP: signame = "SIGHUP"; break; + case SIGQUIT: signame = "SIGQUIT"; break; + case SIGABRT: signame = "SIGABRT"; break; + case SIGKILL: signame = "SIGKILL"; break; + case SIGSEGV: signame = "SIGSEGV"; break; + case SIGILL: signame = "SIGILL"; break; + case SIGTERM: signame = "SIGTERM"; break; + default: sprintf(tmp, "signal %d", WTERMSIG(exit_code)); signame = tmp; break; + } + test_error_("Test interrupted by %s.", signame); + } else { + test_error_("Test ended in an unexpected way [%d].", exit_code); + } + } + +#elif defined(ACUTEST_WIN_) + + char buffer[512] = {0}; + STARTUPINFOA startupInfo; + PROCESS_INFORMATION processInfo; + DWORD exitCode; + + /* Windows has no fork(). So we propagate all info into the child + * through a command line arguments. */ + _snprintf(buffer, sizeof(buffer)-1, + "%s --worker=%d %s --no-exec --no-summary %s --verbose=%d --color=%s -- \"%s\"", + test_argv0_, index, test_timer_ ? "--time" : "", + test_tap_ ? "--tap" : "", test_verbose_level_, + test_colorize_ ? "always" : "never", + test->name); + memset(&startupInfo, 0, sizeof(startupInfo)); + startupInfo.cb = sizeof(STARTUPINFO); + if(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo)) { + WaitForSingleObject(processInfo.hProcess, INFINITE); + GetExitCodeProcess(processInfo.hProcess, &exitCode); + CloseHandle(processInfo.hThread); + CloseHandle(processInfo.hProcess); + failed = (exitCode != 0); + if(exitCode > 1) { + switch(exitCode) { + case 3: test_error_("Aborted."); break; + case 0xC0000005: test_error_("Access violation."); break; + default: test_error_("Test ended in an unexpected way [%lu].", exitCode); break; + } + } + } else { + test_error_("Cannot create unit test subprocess [%ld].", GetLastError()); + failed = 1; + } + +#else + + /* A platform where we don't know how to run child process. */ + failed = (test_do_run_(test, index) != 0); + +#endif + + } else { + /* Child processes suppressed through --no-exec. */ + failed = (test_do_run_(test, index) != 0); + } + test_timer_get_time_(&end); + + test_current_unit_ = NULL; + + test_stat_run_units_++; + if(failed) + test_stat_failed_units_++; + + test_set_success_(master_index, !failed); + test_set_duration_(master_index, test_timer_diff_(start, end)); +} + +#if defined(ACUTEST_WIN_) +/* Callback for SEH events. */ +static LONG CALLBACK +test_seh_exception_filter_(EXCEPTION_POINTERS *ptrs) +{ + test_check_(0, NULL, 0, "Unhandled SEH exception"); + test_message_("Exception code: 0x%08lx", ptrs->ExceptionRecord->ExceptionCode); + test_message_("Exception address: 0x%p", ptrs->ExceptionRecord->ExceptionAddress); + + fflush(stdout); + fflush(stderr); + + return EXCEPTION_EXECUTE_HANDLER; +} +#endif + + +#define TEST_CMDLINE_OPTFLAG_OPTIONALARG_ 0x0001 +#define TEST_CMDLINE_OPTFLAG_REQUIREDARG_ 0x0002 + +#define TEST_CMDLINE_OPTID_NONE_ 0 +#define TEST_CMDLINE_OPTID_UNKNOWN_ (-0x7fffffff + 0) +#define TEST_CMDLINE_OPTID_MISSINGARG_ (-0x7fffffff + 1) +#define TEST_CMDLINE_OPTID_BOGUSARG_ (-0x7fffffff + 2) + +typedef struct TEST_CMDLINE_OPTION_ { + char shortname; + const char* longname; + int id; + unsigned flags; +} TEST_CMDLINE_OPTION_; + +static int +test_cmdline_handle_short_opt_group_(const TEST_CMDLINE_OPTION_* options, + const char* arggroup, + int (*callback)(int /*optval*/, const char* /*arg*/)) +{ + const TEST_CMDLINE_OPTION_* opt; + int i; + int ret = 0; + + for(i = 0; arggroup[i] != '\0'; i++) { + for(opt = options; opt->id != 0; opt++) { + if(arggroup[i] == opt->shortname) + break; + } + + if(opt->id != 0 && !(opt->flags & TEST_CMDLINE_OPTFLAG_REQUIREDARG_)) { + ret = callback(opt->id, NULL); + } else { + /* Unknown option. */ + char badoptname[3]; + badoptname[0] = '-'; + badoptname[1] = arggroup[i]; + badoptname[2] = '\0'; + ret = callback((opt->id != 0 ? TEST_CMDLINE_OPTID_MISSINGARG_ : TEST_CMDLINE_OPTID_UNKNOWN_), + badoptname); + } + + if(ret != 0) + break; + } + + return ret; +} + +#define TEST_CMDLINE_AUXBUF_SIZE_ 32 + +static int +test_cmdline_read_(const TEST_CMDLINE_OPTION_* options, int argc, char** argv, + int (*callback)(int /*optval*/, const char* /*arg*/)) +{ + + const TEST_CMDLINE_OPTION_* opt; + char auxbuf[TEST_CMDLINE_AUXBUF_SIZE_+1]; + int after_doubledash = 0; + int i = 1; + int ret = 0; + + auxbuf[TEST_CMDLINE_AUXBUF_SIZE_] = '\0'; + + while(i < argc) { + if(after_doubledash || strcmp(argv[i], "-") == 0) { + /* Non-option argument. */ + ret = callback(TEST_CMDLINE_OPTID_NONE_, argv[i]); + } else if(strcmp(argv[i], "--") == 0) { + /* End of options. All the remaining members are non-option arguments. */ + after_doubledash = 1; + } else if(argv[i][0] != '-') { + /* Non-option argument. */ + ret = callback(TEST_CMDLINE_OPTID_NONE_, argv[i]); + } else { + for(opt = options; opt->id != 0; opt++) { + if(opt->longname != NULL && strncmp(argv[i], "--", 2) == 0) { + size_t len = strlen(opt->longname); + if(strncmp(argv[i]+2, opt->longname, len) == 0) { + /* Regular long option. */ + if(argv[i][2+len] == '\0') { + /* with no argument provided. */ + if(!(opt->flags & TEST_CMDLINE_OPTFLAG_REQUIREDARG_)) + ret = callback(opt->id, NULL); + else + ret = callback(TEST_CMDLINE_OPTID_MISSINGARG_, argv[i]); + break; + } else if(argv[i][2+len] == '=') { + /* with an argument provided. */ + if(opt->flags & (TEST_CMDLINE_OPTFLAG_OPTIONALARG_ | TEST_CMDLINE_OPTFLAG_REQUIREDARG_)) { + ret = callback(opt->id, argv[i]+2+len+1); + } else { + sprintf(auxbuf, "--%s", opt->longname); + ret = callback(TEST_CMDLINE_OPTID_BOGUSARG_, auxbuf); + } + break; + } else { + continue; + } + } + } else if(opt->shortname != '\0' && argv[i][0] == '-') { + if(argv[i][1] == opt->shortname) { + /* Regular short option. */ + if(opt->flags & TEST_CMDLINE_OPTFLAG_REQUIREDARG_) { + if(argv[i][2] != '\0') + ret = callback(opt->id, argv[i]+2); + else if(i+1 < argc) + ret = callback(opt->id, argv[++i]); + else + ret = callback(TEST_CMDLINE_OPTID_MISSINGARG_, argv[i]); + break; + } else { + ret = callback(opt->id, NULL); + + /* There might be more (argument-less) short options + * grouped together. */ + if(ret == 0 && argv[i][2] != '\0') + ret = test_cmdline_handle_short_opt_group_(options, argv[i]+2, callback); + break; + } + } + } + } + + if(opt->id == 0) { /* still not handled? */ + if(argv[i][0] != '-') { + /* Non-option argument. */ + ret = callback(TEST_CMDLINE_OPTID_NONE_, argv[i]); + } else { + /* Unknown option. */ + char* badoptname = argv[i]; + + if(strncmp(badoptname, "--", 2) == 0) { + /* Strip any argument from the long option. */ + char* assignment = strchr(badoptname, '='); + if(assignment != NULL) { + size_t len = assignment - badoptname; + if(len > TEST_CMDLINE_AUXBUF_SIZE_) + len = TEST_CMDLINE_AUXBUF_SIZE_; + strncpy(auxbuf, badoptname, len); + auxbuf[len] = '\0'; + badoptname = auxbuf; + } + } + + ret = callback(TEST_CMDLINE_OPTID_UNKNOWN_, badoptname); + } + } + } + + if(ret != 0) + return ret; + i++; + } + + return ret; +} + +static void +test_help_(void) +{ + printf("Usage: %s [options] [test...]\n", test_argv0_); + printf("\n"); + printf("Run the specified unit tests; or if the option '--skip' is used, run all\n"); + printf("tests in the suite but those listed. By default, if no tests are specified\n"); + printf("on the command line, all unit tests in the suite are run.\n"); + printf("\n"); + printf("Options:\n"); + printf(" -s, --skip Execute all unit tests but the listed ones\n"); + printf(" --exec[=WHEN] If supported, execute unit tests as child processes\n"); + printf(" (WHEN is one of 'auto', 'always', 'never')\n"); + printf(" -E, --no-exec Same as --exec=never\n"); +#if defined ACUTEST_WIN_ + printf(" -t, --time Measure test duration\n"); +#elif defined ACUTEST_HAS_POSIX_TIMER_ + printf(" -t, --time Measure test duration (real time)\n"); + printf(" --time=TIMER Measure test duration, using given timer\n"); + printf(" (TIMER is one of 'real', 'cpu')\n"); +#endif + printf(" --no-summary Suppress printing of test results summary\n"); + printf(" --tap Produce TAP-compliant output\n"); + printf(" (See https://testanything.org/)\n"); + printf(" -x, --xml-output=FILE Enable XUnit output to the given file\n"); + printf(" -l, --list List unit tests in the suite and exit\n"); + printf(" -v, --verbose Make output more verbose\n"); + printf(" --verbose=LEVEL Set verbose level to LEVEL:\n"); + printf(" 0 ... Be silent\n"); + printf(" 1 ... Output one line per test (and summary)\n"); + printf(" 2 ... As 1 and failed conditions (this is default)\n"); + printf(" 3 ... As 1 and all conditions (and extended summary)\n"); + printf(" -q, --quiet Same as --verbose=0\n"); + printf(" --color[=WHEN] Enable colorized output\n"); + printf(" (WHEN is one of 'auto', 'always', 'never')\n"); + printf(" --no-color Same as --color=never\n"); + printf(" -h, --help Display this help and exit\n"); + + if(test_list_size_ < 16) { + printf("\n"); + test_list_names_(); + } +} + +static const TEST_CMDLINE_OPTION_ test_cmdline_options_[] = { + { 's', "skip", 's', 0 }, + { 0, "exec", 'e', TEST_CMDLINE_OPTFLAG_OPTIONALARG_ }, + { 'E', "no-exec", 'E', 0 }, +#if defined ACUTEST_WIN_ + { 't', "time", 't', 0 }, + { 0, "timer", 't', 0 }, /* kept for compatibility */ +#elif defined ACUTEST_HAS_POSIX_TIMER_ + { 't', "time", 't', TEST_CMDLINE_OPTFLAG_OPTIONALARG_ }, + { 0, "timer", 't', TEST_CMDLINE_OPTFLAG_OPTIONALARG_ }, /* kept for compatibility */ +#endif + { 0, "no-summary", 'S', 0 }, + { 0, "tap", 'T', 0 }, + { 'l', "list", 'l', 0 }, + { 'v', "verbose", 'v', TEST_CMDLINE_OPTFLAG_OPTIONALARG_ }, + { 'q', "quiet", 'q', 0 }, + { 0, "color", 'c', TEST_CMDLINE_OPTFLAG_OPTIONALARG_ }, + { 0, "no-color", 'C', 0 }, + { 'h', "help", 'h', 0 }, + { 0, "worker", 'w', TEST_CMDLINE_OPTFLAG_REQUIREDARG_ }, /* internal */ + { 'x', "xml-output", 'x', TEST_CMDLINE_OPTFLAG_REQUIREDARG_ }, + { 0, NULL, 0, 0 } +}; + +static int +test_cmdline_callback_(int id, const char* arg) +{ + switch(id) { + case 's': + test_skip_mode_ = 1; + break; + + case 'e': + if(arg == NULL || strcmp(arg, "always") == 0) { + test_no_exec_ = 0; + } else if(strcmp(arg, "never") == 0) { + test_no_exec_ = 1; + } else if(strcmp(arg, "auto") == 0) { + /*noop*/ + } else { + fprintf(stderr, "%s: Unrecognized argument '%s' for option --exec.\n", test_argv0_, arg); + fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0_); + test_exit_(2); + } + break; + + case 'E': + test_no_exec_ = 1; + break; + + case 't': +#if defined ACUTEST_WIN_ || defined ACUTEST_HAS_POSIX_TIMER_ + if(arg == NULL || strcmp(arg, "real") == 0) { + test_timer_ = 1; + #ifndef ACUTEST_WIN_ + } else if(strcmp(arg, "cpu") == 0) { + test_timer_ = 2; + #endif + } else { + fprintf(stderr, "%s: Unrecognized argument '%s' for option --time.\n", test_argv0_, arg); + fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0_); + test_exit_(2); + } +#endif + break; + + case 'S': + test_no_summary_ = 1; + break; + + case 'T': + test_tap_ = 1; + break; + + case 'l': + test_list_names_(); + test_exit_(0); + break; + + case 'v': + test_verbose_level_ = (arg != NULL ? atoi(arg) : test_verbose_level_+1); + break; + + case 'q': + test_verbose_level_ = 0; + break; + + case 'c': + if(arg == NULL || strcmp(arg, "always") == 0) { + test_colorize_ = 1; + } else if(strcmp(arg, "never") == 0) { + test_colorize_ = 0; + } else if(strcmp(arg, "auto") == 0) { + /*noop*/ + } else { + fprintf(stderr, "%s: Unrecognized argument '%s' for option --color.\n", test_argv0_, arg); + fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0_); + test_exit_(2); + } + break; + + case 'C': + test_colorize_ = 0; + break; + + case 'h': + test_help_(); + test_exit_(0); + break; + + case 'w': + test_worker_ = 1; + test_worker_index_ = atoi(arg); + break; + case 'x': + test_xml_output_ = fopen(arg, "w"); + if (!test_xml_output_) { + fprintf(stderr, "Unable to open '%s': %s\n", arg, strerror(errno)); + test_exit_(2); + } + break; + + case 0: + if(test_lookup_(arg) == 0) { + fprintf(stderr, "%s: Unrecognized unit test '%s'\n", test_argv0_, arg); + fprintf(stderr, "Try '%s --list' for list of unit tests.\n", test_argv0_); + test_exit_(2); + } + break; + + case TEST_CMDLINE_OPTID_UNKNOWN_: + fprintf(stderr, "Unrecognized command line option '%s'.\n", arg); + fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0_); + test_exit_(2); + break; + + case TEST_CMDLINE_OPTID_MISSINGARG_: + fprintf(stderr, "The command line option '%s' requires an argument.\n", arg); + fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0_); + test_exit_(2); + break; + + case TEST_CMDLINE_OPTID_BOGUSARG_: + fprintf(stderr, "The command line option '%s' does not expect an argument.\n", arg); + fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0_); + test_exit_(2); + break; + } + + return 0; +} + + +#ifdef ACUTEST_LINUX_ +static int +test_is_tracer_present_(void) +{ + /* Must be large enough so the line 'TracerPid: ${PID}' can fit in. */ + static const int OVERLAP = 32; + + char buf[256+OVERLAP+1]; + int tracer_present = 0; + int fd; + size_t n_read = 0; + + fd = open("/proc/self/status", O_RDONLY); + if(fd == -1) + return 0; + + while(1) { + static const char pattern[] = "TracerPid:"; + const char* field; + + while(n_read < sizeof(buf) - 1) { + ssize_t n; + + n = read(fd, buf + n_read, sizeof(buf) - 1 - n_read); + if(n <= 0) + break; + n_read += n; + } + buf[n_read] = '\0'; + + field = strstr(buf, pattern); + if(field != NULL && field < buf + sizeof(buf) - OVERLAP) { + pid_t tracer_pid = (pid_t) atoi(field + sizeof(pattern) - 1); + tracer_present = (tracer_pid != 0); + break; + } + + if(n_read == sizeof(buf)-1) { + memmove(buf, buf + sizeof(buf)-1 - OVERLAP, OVERLAP); + n_read = OVERLAP; + } else { + break; + } + } + + close(fd); + return tracer_present; +} +#endif + +int +main(int argc, char** argv) +{ + int i; + test_argv0_ = argv[0]; + +#if defined ACUTEST_UNIX_ + test_colorize_ = isatty(STDOUT_FILENO); +#elif defined ACUTEST_WIN_ + #if defined _BORLANDC_ + test_colorize_ = isatty(_fileno(stdout)); + #else + test_colorize_ = _isatty(_fileno(stdout)); + #endif +#else + test_colorize_ = 0; +#endif + + /* Count all test units */ + test_list_size_ = 0; + for(i = 0; test_list_[i].func != NULL; i++) + test_list_size_++; + + test_details_ = (struct test_detail_*)calloc(test_list_size_, sizeof(struct test_detail_)); + if(test_details_ == NULL) { + fprintf(stderr, "Out of memory.\n"); + test_exit_(2); + } + + /* Parse options */ + test_cmdline_read_(test_cmdline_options_, argc, argv, test_cmdline_callback_); + + /* Initialize the proper timer. */ + test_timer_init_(); + +#if defined(ACUTEST_WIN_) + SetUnhandledExceptionFilter(test_seh_exception_filter_); +#ifdef _MSC_VER + _set_abort_behavior(0, _WRITE_ABORT_MSG); +#endif +#endif + + /* By default, we want to run all tests. */ + if(test_count_ == 0) { + for(i = 0; test_list_[i].func != NULL; i++) + test_remember_(i); + } + + /* Guess whether we want to run unit tests as child processes. */ + if(test_no_exec_ < 0) { + test_no_exec_ = 0; + + if(test_count_ <= 1) { + test_no_exec_ = 1; + } else { +#ifdef ACUTEST_WIN_ + if(IsDebuggerPresent()) + test_no_exec_ = 1; +#endif +#ifdef ACUTEST_LINUX_ + if(test_is_tracer_present_()) + test_no_exec_ = 1; +#endif +#ifdef RUNNING_ON_VALGRIND + /* RUNNING_ON_VALGRIND is provided by valgrind.h */ + if(RUNNING_ON_VALGRIND) + test_no_exec_ = 1; +#endif + } + } + + if(test_tap_) { + /* TAP requires we know test result ("ok", "not ok") before we output + * anything about the test, and this gets problematic for larger verbose + * levels. */ + if(test_verbose_level_ > 2) + test_verbose_level_ = 2; + + /* TAP harness should provide some summary. */ + test_no_summary_ = 1; + + if(!test_worker_) + printf("1..%d\n", (int) test_count_); + } + + int index = test_worker_index_; + for(i = 0; test_list_[i].func != NULL; i++) { + int run = (test_details_[i].flags & TEST_FLAG_RUN_); + if (test_skip_mode_) /* Run all tests except those listed. */ + run = !run; + if(run) + test_run_(&test_list_[i], index++, i); + } + + /* Write a summary */ + if(!test_no_summary_ && test_verbose_level_ >= 1) { + if(test_verbose_level_ >= 3) { + test_print_in_color_(TEST_COLOR_DEFAULT_INTENSIVE_, "Summary:\n"); + + printf(" Count of all unit tests: %4d\n", (int) test_list_size_); + printf(" Count of run unit tests: %4d\n", test_stat_run_units_); + printf(" Count of failed unit tests: %4d\n", test_stat_failed_units_); + printf(" Count of skipped unit tests: %4d\n", (int) test_list_size_ - test_stat_run_units_); + } + + if(test_stat_failed_units_ == 0) { + test_print_in_color_(TEST_COLOR_GREEN_INTENSIVE_, "SUCCESS:"); + printf(" All unit tests have passed.\n"); + } else { + test_print_in_color_(TEST_COLOR_RED_INTENSIVE_, "FAILED:"); + printf(" %d of %d unit tests %s failed.\n", + test_stat_failed_units_, test_stat_run_units_, + (test_stat_failed_units_ == 1) ? "has" : "have"); + } + + if(test_verbose_level_ >= 3) + printf("\n"); + } + + if (test_xml_output_) { +#if defined ACUTEST_UNIX_ + char *suite_name = basename(argv[0]); +#elif defined ACUTEST_WIN_ + char suite_name[_MAX_FNAME]; + _splitpath(argv[0], NULL, NULL, suite_name, NULL); +#else + const char *suite_name = argv[0]; +#endif + fprintf(test_xml_output_, "\n"); + fprintf(test_xml_output_, "\n", + suite_name, (int)test_list_size_, test_stat_failed_units_, test_stat_failed_units_, + (int)test_list_size_ - test_stat_run_units_); + for(i = 0; test_list_[i].func != NULL; i++) { + struct test_detail_ *details = &test_details_[i]; + fprintf(test_xml_output_, " \n", test_list_[i].name, details->duration); + if (details->flags & TEST_FLAG_FAILURE_) + fprintf(test_xml_output_, " \n"); + if (!(details->flags & TEST_FLAG_FAILURE_) && !(details->flags & TEST_FLAG_SUCCESS_)) + fprintf(test_xml_output_, " \n"); + fprintf(test_xml_output_, " \n"); + } + fprintf(test_xml_output_, "\n"); + fclose(test_xml_output_); + } + + test_cleanup_(); + + return (test_stat_failed_units_ == 0) ? 0 : 1; +} + + +#endif /* #ifndef TEST_NO_MAIN */ + +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* #ifndef ACUTEST_H */ diff --git a/tests/tests.cpp b/tests/tests.cpp new file mode 100644 index 00000000..98f7ee83 --- /dev/null +++ b/tests/tests.cpp @@ -0,0 +1,283 @@ +#include "acutest.h" + +#include "config.hpp" + +void +test_nop() +{ + TEST_CHECK(true); +} + +void +test_config_bool() +{ + ConfigBOOL v; + + TEST_CHECK(v.from_string("true") == 0); + TEST_CHECK(v == true); + TEST_CHECK(v.to_string() == "true"); + + TEST_CHECK(v.from_string("false") == 0); + TEST_CHECK(v == false); + TEST_CHECK(v.to_string() == "false"); + + TEST_CHECK(v.from_string("asdf") == -EINVAL); +} + +void +test_config_uint64() +{ + ConfigUINT64 v; + + TEST_CHECK(v.from_string("0") == 0); + TEST_CHECK(v == (uint64_t)0); + TEST_CHECK(v.to_string() == "0"); + + TEST_CHECK(v.from_string("123") == 0); + TEST_CHECK(v == (uint64_t)123); + TEST_CHECK(v.to_string() == "123"); + + TEST_CHECK(v.from_string("1234567890") == 0); + TEST_CHECK(v == (uint64_t)1234567890); + TEST_CHECK(v.to_string() == "1234567890"); + + TEST_CHECK(v.from_string("asdf") == -EINVAL); +} + +void +test_config_int() +{ + ConfigINT v; + + TEST_CHECK(v.from_string("0") == 0); + TEST_CHECK(v == (int)0); + TEST_CHECK(v.to_string() == "0"); + + TEST_CHECK(v.from_string("123") == 0); + TEST_CHECK(v == (int)123); + TEST_CHECK(v.to_string() == "123"); + + TEST_CHECK(v.from_string("1234567890") == 0); + TEST_CHECK(v == (int)1234567890); + TEST_CHECK(v.to_string() == "1234567890"); + + TEST_CHECK(v.from_string("asdf") == -EINVAL); +} + +void +test_config_str() +{ + ConfigSTR v; + + TEST_CHECK(v.from_string("foo") == 0); + TEST_CHECK(v == "foo"); + TEST_CHECK(v.to_string() == "foo"); +} + +void +test_config_branches() +{ + uint64_t minfreespace; + Branches b(minfreespace); + Branches::CPtr bcp0; + Branches::CPtr bcp1; + + minfreespace = 1234; + TEST_CHECK(b->minfreespace() == 1234); + TEST_CHECK(b.to_string() == ""); + + bcp0 = b; + TEST_CHECK(b.from_string("/foo/bar") == 0); + TEST_CHECK(b.to_string() == "/foo/bar=RW"); + bcp1 = b; + TEST_CHECK(bcp0.get() != bcp1.get()); + + TEST_CHECK(b.from_string("/foo/bar=RW,1234") == 0); + TEST_CHECK(b.to_string() == "/foo/bar=RW,1234"); + + TEST_CHECK(b.from_string("/foo/bar=RO,1234:/foo/baz=NC,4321") == 0); + TEST_CHECK(b.to_string() == "/foo/bar=RO,1234:/foo/baz=NC,4321"); + bcp0 = b; + TEST_CHECK((*bcp0).size() == 2); + TEST_CHECK((*bcp0)[0].path == "/foo/bar"); + TEST_CHECK((*bcp0)[0].minfreespace() == 1234); + TEST_MSG("minfreespace: expected = %lu; produced = %lu", + 1234, + (*bcp0)[0].minfreespace()); + TEST_CHECK((*bcp0)[1].path == "/foo/baz"); + TEST_CHECK((*bcp0)[1].minfreespace() == 4321); + TEST_MSG("minfreespace: expected = %lu; produced = %lu", + 4321, + (*bcp0)[1].minfreespace()); +} + +void +test_config_cachefiles() +{ + CacheFiles cf; + + TEST_CHECK(cf.from_string("libfuse") == 0); + TEST_CHECK(cf.to_string() == "libfuse"); + TEST_CHECK(cf.from_string("off") == 0); + TEST_CHECK(cf.to_string() == "off"); + TEST_CHECK(cf.from_string("partial") == 0); + TEST_CHECK(cf.to_string() == "partial"); + TEST_CHECK(cf.from_string("full") == 0); + TEST_CHECK(cf.to_string() == "full"); + TEST_CHECK(cf.from_string("auto-full") == 0); + TEST_CHECK(cf.to_string() == "auto-full"); + TEST_CHECK(cf.from_string("foobar") == -EINVAL); +} + +void +test_config_inodecalc() +{ + InodeCalc ic("passthrough"); + + TEST_CHECK(ic.from_string("passthrough") == 0); + TEST_CHECK(ic.to_string() == "passthrough"); + TEST_CHECK(ic.from_string("path-hash") == 0); + TEST_CHECK(ic.to_string() == "path-hash"); + TEST_CHECK(ic.from_string("devino-hash") == 0); + TEST_CHECK(ic.to_string() == "devino-hash"); + TEST_CHECK(ic.from_string("hybrid-hash") == 0); + TEST_CHECK(ic.to_string() == "hybrid-hash"); + TEST_CHECK(ic.from_string("path-hash32") == 0); + TEST_CHECK(ic.to_string() == "path-hash32"); + TEST_CHECK(ic.from_string("devino-hash32") == 0); + TEST_CHECK(ic.to_string() == "devino-hash32"); + TEST_CHECK(ic.from_string("hybrid-hash32") == 0); + TEST_CHECK(ic.to_string() == "hybrid-hash32"); + TEST_CHECK(ic.from_string("asdf") == -EINVAL); +} + +void +test_config_moveonenospc() +{ + MoveOnENOSPC m(false); + + TEST_CHECK(m.to_string() == "false"); + TEST_CHECK(m.from_string("mfs") == 0); + TEST_CHECK(m.to_string() == "mfs"); + TEST_CHECK(m.from_string("mspmfs") == 0); + TEST_CHECK(m.to_string() == "mspmfs"); + TEST_CHECK(m.from_string("true") == 0); + TEST_CHECK(m.to_string() == "mfs"); + TEST_CHECK(m.from_string("blah") == -EINVAL); +} + +void +test_config_nfsopenhack() +{ + NFSOpenHack n; + + TEST_CHECK(n.from_string("off") == 0); + TEST_CHECK(n.to_string() == "off"); + TEST_CHECK(n == NFSOpenHack::ENUM::OFF); + + TEST_CHECK(n.from_string("git") == 0); + TEST_CHECK(n.to_string() == "git"); + TEST_CHECK(n == NFSOpenHack::ENUM::GIT); + + TEST_CHECK(n.from_string("all") == 0); + TEST_CHECK(n.to_string() == "all"); + TEST_CHECK(n == NFSOpenHack::ENUM::ALL); +} + +void +test_config_readdir() +{ + ReadDir r; + + TEST_CHECK(r.from_string("linux") == 0); + TEST_CHECK(r.to_string() == "linux"); + TEST_CHECK(r == ReadDir::ENUM::LINUX); + + TEST_CHECK(r.from_string("posix") == 0); + TEST_CHECK(r.to_string() == "posix"); + TEST_CHECK(r == ReadDir::ENUM::POSIX); +} + +void +test_config_statfs() +{ + StatFS s; + + TEST_CHECK(s.from_string("base") == 0); + TEST_CHECK(s.to_string() == "base"); + TEST_CHECK(s == StatFS::ENUM::BASE); + + TEST_CHECK(s.from_string("full") == 0); + TEST_CHECK(s.to_string() == "full"); + TEST_CHECK(s == StatFS::ENUM::FULL); + + TEST_CHECK(s.from_string("asdf") == -EINVAL); +} + +void +test_config_statfs_ignore() +{ + StatFSIgnore s; + + TEST_CHECK(s.from_string("none") == 0); + TEST_CHECK(s.to_string() == "none"); + TEST_CHECK(s == StatFSIgnore::ENUM::NONE); + + TEST_CHECK(s.from_string("ro") == 0); + TEST_CHECK(s.to_string() == "ro"); + TEST_CHECK(s == StatFSIgnore::ENUM::RO); + + TEST_CHECK(s.from_string("nc") == 0); + TEST_CHECK(s.to_string() == "nc"); + TEST_CHECK(s == StatFSIgnore::ENUM::NC); + + TEST_CHECK(s.from_string("asdf") == -EINVAL); +} + +void +test_config_xattr() +{ + XAttr x; + + TEST_CHECK(x.from_string("passthrough") == 0); + TEST_CHECK(x.to_string() == "passthrough"); + TEST_CHECK(x == XAttr::ENUM::PASSTHROUGH); + + TEST_CHECK(x.from_string("noattr") == 0); + TEST_CHECK(x.to_string() == "noattr"); + TEST_CHECK(x == XAttr::ENUM::NOATTR); + + TEST_CHECK(x.from_string("nosys") == 0); + TEST_CHECK(x.to_string() == "nosys"); + TEST_CHECK(x == XAttr::ENUM::NOSYS); + + TEST_CHECK(x.from_string("asdf") == -EINVAL); +} + +void +test_config() +{ + Config cfg; + + TEST_CHECK(cfg.set_raw("async_read","true") == 0); +} + +TEST_LIST = + { + {"nop",test_nop}, + {"config_bool",test_config_bool}, + {"config_uint64",test_config_uint64}, + {"config_int",test_config_int}, + {"config_str",test_config_str}, + {"config_branches",test_config_branches}, + {"config_cachefiles",test_config_cachefiles}, + {"config_inodecalc",test_config_inodecalc}, + {"config_moveonenospc",test_config_moveonenospc}, + {"config_nfsopenhack",test_config_nfsopenhack}, + {"config_readdir",test_config_readdir}, + {"config_statfs",test_config_statfs}, + {"config_statfsignore",test_config_statfs_ignore}, + {"config_xattr",test_config_xattr}, + {"config",test_config}, + {NULL,NULL} + }; diff --git a/tools/cppfind b/tools/cppfind index 5721d365..51c99029 100755 --- a/tools/cppfind +++ b/tools/cppfind @@ -3,6 +3,6 @@ CXX="${CXX:-c++}" FUSE_CFLAGS="-Ilibfuse/include -D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=29" -echo "#include " | ${CXX} -E ${FUSE_CFLAGS} - | grep "${1}" > /dev/null +echo "#include \"fuse.h\"" | ${CXX} -E ${FUSE_CFLAGS} - | grep "${1}" > /dev/null [ "$?" != "0" ]; echo $?