mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-20 00:17:43 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5850fbe3f1 | ||
|
|
1cc1b1f746 | ||
|
|
a960a7ef46 | ||
|
|
9afd0654b7 | ||
|
|
e0cf97261c | ||
|
|
1782910437 | ||
|
|
f4e3f28153 | ||
|
|
6a96d3b69b | ||
|
|
08c0c2dfae | ||
|
|
ad5380d69e | ||
|
|
3163258a33 | ||
|
|
b194272e39 | ||
|
|
c131310c55 | ||
|
|
8323e16ad2 | ||
|
|
ce9352987c | ||
|
|
accd2d4ae0 | ||
|
|
2d899479c3 | ||
|
|
803b2ae999 | ||
|
|
e98b801c9d | ||
|
|
27cf7f8148 | ||
|
|
b22528bac4 | ||
|
|
adf983c8c3 | ||
|
|
e377d54c93 | ||
|
|
7bee6230ba | ||
|
|
08d07b71e1 | ||
|
|
ce2462042f | ||
|
|
305f190f09 | ||
|
|
d89735abf6 | ||
|
|
8178bf518c |
@@ -33,11 +33,14 @@ INSTALL = $(shell which install)
|
||||
MKTEMP = $(shell which mktemp)
|
||||
STRIP = $(shell which strip)
|
||||
PANDOC = $(shell which pandoc)
|
||||
SED = $(shell which sed)
|
||||
GZIP = $(shell which gzip)
|
||||
RPMBUILD = $(shell which rpmbuild)
|
||||
GIT2DEBCL = ./tools/git2debcl
|
||||
CPPFIND = ./tools/cppfind
|
||||
|
||||
ifeq ($(PKGCONFIG),"")
|
||||
$(error "pkg-config not installed"
|
||||
$(error "pkg-config not installed")
|
||||
endif
|
||||
|
||||
ifeq ($(PANDOC),"")
|
||||
@@ -62,6 +65,8 @@ FLOCK = $(shell $(CPPFIND) "fuse_fs_flock")
|
||||
READ_BUF = $(shell $(CPPFIND) "fuse_fs_read_buf")
|
||||
WRITE_BUF = $(shell $(CPPFIND) "fuse_fs_write_buf")
|
||||
|
||||
UGID_USE_RWLOCK = 0
|
||||
|
||||
OPTS = -O2
|
||||
SRC = $(wildcard src/*.cpp)
|
||||
OBJ = $(SRC:src/%.cpp=obj/%.o)
|
||||
@@ -71,6 +76,7 @@ MANPAGE = $(TARGET).1
|
||||
FUSE_CFLAGS = $(shell $(PKGCONFIG) --cflags fuse)
|
||||
CFLAGS = -g -Wall \
|
||||
$(OPTS) \
|
||||
-Wno-unused-result \
|
||||
$(FUSE_CFLAGS) \
|
||||
-DFUSE_USE_VERSION=26 \
|
||||
-MMD \
|
||||
@@ -78,7 +84,8 @@ CFLAGS = -g -Wall \
|
||||
-DFALLOCATE=$(FALLOCATE) \
|
||||
-DFLOCK=$(FLOCK) \
|
||||
-DREAD_BUF=$(READ_BUF) \
|
||||
-DWRITE_BUF=$(WRITE_BUF)
|
||||
-DWRITE_BUF=$(WRITE_BUF) \
|
||||
-DUGID_USE_RWLOCK=$(UGID_USE_RWLOCK)
|
||||
LDFLAGS = $(shell $(PKGCONFIG) fuse --libs)
|
||||
|
||||
PREFIX = /usr/local
|
||||
@@ -103,7 +110,7 @@ help:
|
||||
@echo "usage: make"
|
||||
@echo "make XATTR_AVAILABLE=0 - to build program without xattrs functionality (auto discovered otherwise)"
|
||||
|
||||
$(TARGET): obj/obj-stamp $(OBJ)
|
||||
$(TARGET): src/version.hpp obj/obj-stamp $(OBJ)
|
||||
$(CXX) $(CFLAGS) $(OBJ) -o $@ $(LDFLAGS)
|
||||
|
||||
clonepath: $(TARGET)
|
||||
@@ -115,6 +122,13 @@ changelog:
|
||||
authors:
|
||||
$(GIT) log --format='%aN <%aE>' | sort -f | uniq > AUTHORS
|
||||
|
||||
src/version.hpp:
|
||||
$(eval VERSION := $(shell $(GIT) describe --always --tags --dirty))
|
||||
@echo "#ifndef _VERSION_HPP" > src/version.hpp
|
||||
@echo "#define _VERSION_HPP" >> src/version.hpp
|
||||
@echo "static const char MERGERFS_VERSION[] = \"$(VERSION)\";" >> src/version.hpp
|
||||
@echo "#endif" >> src/version.hpp
|
||||
|
||||
obj/obj-stamp:
|
||||
$(MKDIR) -p obj
|
||||
$(TOUCH) $@
|
||||
@@ -122,8 +136,9 @@ obj/obj-stamp:
|
||||
obj/%.o: src/%.cpp
|
||||
$(CXX) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
clean: rpm-clean
|
||||
$(RM) -rf obj
|
||||
$(RM) -f src/version.hpp
|
||||
$(RM) -f "$(TARGET)" "$(MANPAGE)" clonepath
|
||||
$(FIND) . -name "*~" -delete
|
||||
|
||||
@@ -160,13 +175,14 @@ $(MANPAGE): README.md
|
||||
|
||||
man: $(MANPAGE)
|
||||
|
||||
tarball: clean man changelog authors
|
||||
tarball: clean man changelog authors src/version.hpp
|
||||
$(eval VERSION := $(shell $(GIT) describe --always --tags --dirty))
|
||||
$(eval VERSION := $(subst -,_,$(VERSION)))
|
||||
$(eval FILENAME := $(TARGET)-$(VERSION))
|
||||
$(eval TMPDIR := $(shell $(MKTEMP) --tmpdir -d .$(FILENAME).XXXXXXXX))
|
||||
$(MKDIR) $(TMPDIR)/$(FILENAME)
|
||||
$(CP) -ar . $(TMPDIR)/$(FILENAME)
|
||||
$(TAR) --exclude=.git -cz -C $(TMPDIR) -f ../$(FILENAME).tar.gz $(FILENAME)
|
||||
$(TAR) --exclude=.git -cz -C $(TMPDIR) -f $(FILENAME).tar.gz $(FILENAME)
|
||||
$(RM) -rf $(TMPDIR)
|
||||
|
||||
debian-changelog:
|
||||
@@ -178,6 +194,19 @@ deb: debian-changelog
|
||||
unsigned-deb: debian-changelog
|
||||
dpkg-buildpackage -uc -us
|
||||
|
||||
rpm-clean:
|
||||
$(RM) -rf rpmbuild
|
||||
|
||||
rpm: tarball
|
||||
$(eval VERSION := $(shell $(GIT) describe --always --tags --dirty))
|
||||
$(eval VERSION := $(subst -,_,$(VERSION)))
|
||||
$(MKDIR) -p rpmbuild/{BUILD,RPMS,SOURCES}
|
||||
$(SED) 's/__VERSION__/$(VERSION)/g' $(TARGET).spec > \
|
||||
rpmbuild/SOURCES/$(TARGET).spec
|
||||
cp -ar $(TARGET)-$(VERSION).tar.gz rpmbuild/SOURCES
|
||||
$(RPMBUILD) -ba rpmbuild/SOURCES/$(TARGET).spec \
|
||||
--define "_topdir $(CURDIR)/rpmbuild"
|
||||
|
||||
.PHONY: all clean install help
|
||||
|
||||
include $(wildcard obj/*.d)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
% mergerfs(1) mergerfs user manual
|
||||
% Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
% 2015-07-03
|
||||
% 2015-09-14
|
||||
|
||||
# NAME
|
||||
|
||||
@@ -20,10 +20,10 @@ Why create **mergerfs** when those exist? **mhddfs** has not been updated in som
|
||||
|
||||
###options###
|
||||
|
||||
* **defaults** is a shortcut for **auto_cache**. **big_writes**, **atomic_o_trunc**, **splice_read**, **splice_write**, and **splice_move** are in effect also enabled (by asking **FUSE** internally for such features) but if unavailable will be ignored. These options seem to provide the best performance.
|
||||
* **defaults** is a shortcut for FUSE's **atomic_o_trunc**, **auto_cache**, **big_writes**, **default_permissions**, **splice_move**, **splice_read**, and **splice_write**. These options seem to provide the best performance.
|
||||
* **minfreespace** (defaults to **4G**) is the minimum space value used for the **lfs**, **fwfs**, and **epmfs** policies. Understands 'K', 'M', and 'G' to represent kilobyte, megabyte, and gigabyte respectively.
|
||||
* All FUSE functions which have a category (see below) are option keys. The syntax being **func.<func>=<policy>**. Example: **func.getattr=newest**.
|
||||
* To set all function policies in a category use **categor.<category>=<policy>**. Example: **category.create=mfs**.
|
||||
* To set all function policies in a category use **category.<category>=<policy>**. Example: **category.create=mfs**.
|
||||
* Options are evaluated in the order listed so if the options are **func.rmdir=rand,category.action=ff** the **action** category setting will override the **rmdir** setting.
|
||||
|
||||
###srcpoints###
|
||||
@@ -31,10 +31,10 @@ Why create **mergerfs** when those exist? **mhddfs** has not been updated in som
|
||||
The source points argument is a colon (':') delimited list of paths. To make it simpler to include multiple source points without having to modify your [fstab](http://linux.die.net/man/5/fstab) we also support [globbing](http://linux.die.net/man/7/glob).
|
||||
|
||||
```
|
||||
$ mergerfs /mnt/disk*:/mnt/cdrom /media/drives
|
||||
$ mergerfs /mnt/disk\*:/mnt/cdrom /media/drives
|
||||
```
|
||||
|
||||
The above line will use all points in /mnt prefixed with *disk* and the directory *cdrom*.
|
||||
The above line will use all points in /mnt prefixed with *disk* and the directory *cdrom*. The `*` (or any glob tokens) must be escaped on the command line else the shell resolve them.
|
||||
|
||||
In /etc/fstab it'd look like the following:
|
||||
|
||||
@@ -117,6 +117,15 @@ $ make deb
|
||||
$ sudo dpkg -i ../mergerfs_version_arch.deb
|
||||
```
|
||||
|
||||
#### Fedora
|
||||
```
|
||||
$ su -
|
||||
# dnf install fuse-devel libattr-devel pandoc gcc-c++
|
||||
# cd mergerfs
|
||||
# make rpm
|
||||
# rpm -i rpmbuild/RPMS/<arch>/mergerfs-<verion>.<arch>.rpm
|
||||
```
|
||||
|
||||
#### Generically
|
||||
|
||||
Have pkg-config, pandoc, libfuse, libattr1 installed.
|
||||
@@ -149,6 +158,8 @@ Use `xattr -l /mount/point/.mergerfs` to see all supported keys.
|
||||
[trapexit:/tmp/mount] $ xattr -l .mergerfs
|
||||
user.mergerfs.srcmounts: /tmp/a:/tmp/b
|
||||
user.mergerfs.minfreespace: 4294967295
|
||||
user.mergerfs.policies: all,einval,enosys,enotsup,epmfs,erofs,exdev,ff,ffwp,fwfs,lfs,mfs,newest,rand
|
||||
user.mergerfs.version: 2.5.0
|
||||
user.mergerfs.category.action: all
|
||||
user.mergerfs.category.create: epmfs
|
||||
user.mergerfs.category.search: ff
|
||||
@@ -236,11 +247,17 @@ A B C
|
||||
|
||||
# TIPS / NOTES
|
||||
|
||||
* If you don't see some directories / files you expect in a merged point be sure the user has permission to all the underlying directories. If `/drive0/a` has is owned by `root:root` with ACLs set to `0700` and `/drive1/a` is `root:root` and `0755` you'll see only `/drive1/a`.
|
||||
* Since POSIX gives you only error or success on calls its difficult to determine the proper behavior when applying the behavior to multiple targets. Generally if something succeeds when reading it returns the data it can. If something fails when making an action we continue on and return the last error.
|
||||
* The recommended options are **defaults,allow_other**. The **allow_other** is to allow users who are not the one which executed mergerfs access to the mountpoint. **defaults** is described above and should offer the best performance. It's possible that if you're running on an older platform the **splice** features aren't available and could error. In that case simply use the other options manually.
|
||||
* Remember that some policies mixed with some functions may result in strange behaviors. Not that some of these behaviors and race conditions couldn't happen outside **mergerfs** but that they are far more likely to occur on account of attempt to merge together multiple sources of data which could be out of sync due to the different policies.
|
||||
* An example: [Kodi](http://kodi.tv) can apparently use directory [mtime](http://linux.die.net/man/2/stat) to more efficiently determine whether or not to scan for new content rather than simply performing a full scan. If using the current default **getattr** policy of **ff** its possible **Kodi** will miss an update on account of it returning the first directory found's **stat** info and its a later directory on another mount which had the **mtime** recently updated. To fix this you will want to set **func.getattr=newest**. Remember though that this is just **stat**. If the file is later **open**'ed or **unlink**'ed and the policy is different for those then a completely different file or directory could be acted on.
|
||||
* An example: [Kodi](http://kodi.tv) and [Plex](http://plex.tv) can apparently use directory [mtime](http://linux.die.net/man/2/stat) to more efficiently determine whether or not to scan for new content rather than simply performing a full scan. If using the current default **getattr** policy of **ff** its possible **Kodi** will miss an update on account of it returning the first directory found's **stat** info and its a later directory on another mount which had the **mtime** recently updated. To fix this you will want to set **func.getattr=newest**. Remember though that this is just **stat**. If the file is later **open**'ed or **unlink**'ed and the policy is different for those then a completely different file or directory could be acted on.
|
||||
* Due to previously mentioned issues its generally best to set **category** wide policies rather than individual **func**'s. This will help limit the confusion of tools such as [rsync](http://linux.die.net/man/1/rsync).
|
||||
|
||||
# Known Issues / Bugs
|
||||
|
||||
* Due to the overhead of [getgroups/setgroups](http://linux.die.net/man/2/setgroups) mergerfs utilizes a cache. This cache is opportunistic and per thread. This means each thread will query the supplemental groups for a user when that particular thread needs to change credentials and currently it will keep that data for the lifetime of the mount or thread. This means that if a user is added to a group it may not be picked up without the restart of mergerfs. However, since the high level FUSE API's (at least the standard version) thread pool dynamically grows and shrinks it's possible that over time a thread will be killed and later a new thread with no cache will start and query the new data.
|
||||
|
||||
# FAQ
|
||||
|
||||
*It's mentioned that there are some security issues with mhddfs. What are they? How does mergerfs address them?*
|
||||
@@ -249,10 +266,12 @@ A B C
|
||||
|
||||
If you are familiar with POSIX standards you'll know that this behavior poses a problem. **seteuid** and **setegid** affect the whole process and **libfuse** is multithreaded by default. We'd need to lock access to **seteuid** and **setegid** with a mutex so that the several threads aren't stepping on one another and files end up with weird permissions and ownership. This however wouldn't scale well. With lots of calls the contention on that mutex would be extremely high. Thankfully on Linux and OSX we have a better solution.
|
||||
|
||||
OSX has a [non-portable pthread extension](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/pthread_setugid_np.2.html) for per-thread user and group impersonation. When building on OSX mergerfs will use this without any mutexes.
|
||||
OSX has a [non-portable pthread extension](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/pthread_setugid_np.2.html) for per-thread user and group impersonation.
|
||||
|
||||
Linux does not support [pthread_setugid_np](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/pthread_setugid_np.2.html) but user and group IDs are a per-thread attribute though documentation on that fact or how to manipulate them is not well distributed. From the **4.00** release of the Linux man-pages project for [setuid](http://man7.org/linux/man-pages/man2/setuid.2.html)
|
||||
|
||||
> At the kernel level, user IDs and group IDs are a per-thread attribute. However, POSIX requires that all threads in a process share the same credentials. The NPTL threading implementation handles the POSIX requirements by providing wrapper functions for the various system calls that change process UIDs and GIDs. These wrapper functions (including the one for setuid()) employ a signal-based technique to ensure that when one thread changes credentials, all of the other threads in the process also change their credentials. For details, see nptl(7).
|
||||
|
||||
Turns out the setreuid syscalls apply only to the thread. GLIBC hides this away using RT signals and other tricks. Taking after **Samba** mergerfs uses **syscall(SYS_setreuid,...)** to set the callers credentials for that thread only. Jumping back to **root** as necessary should escalated privileges be needed (for instance: to clone paths).
|
||||
Turns out the setreuid syscalls apply only to the thread. GLIBC hides this away using RT signals to inform all threads to change credentials. Taking after **Samba** mergerfs uses **syscall(SYS_setreuid,...)** to set the callers credentials for that thread only. Jumping back to **root** as necessary should escalated privileges be needed (for instance: to clone paths).
|
||||
|
||||
For non-Linux systems mergerfs uses a read-write lock and changes credentials only when necessary. If multiple threads are to be user X then only the first one will need to change the processes credentials. So long as the other threads need to be user X they will take a readlock allow multiple threads to share the credentials. Once a request comes in to run as user Y that thread will attempt a write lock and change to Y's credentials when it can. If the ability to give writers priority is supported then that flag will be used so threads trying to change credentials don't starve. This isn't the best solution but should work reasonably well. As new platforms are supported if they offer per thread credentials those APIs will be adopted.
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
Name: mergerfs
|
||||
Version: __VERSION__
|
||||
Release: 1%{?dist}
|
||||
Summary: A FUSE union filesystem
|
||||
|
||||
Group: Applications/System
|
||||
License: MIT
|
||||
URL: https://github.com/trapexit/mergerfs
|
||||
|
||||
Source: mergerfs-%{version}.tar.gz
|
||||
|
||||
BuildRequires: gcc-c++
|
||||
BuildRequires: libattr-devel
|
||||
BuildRequires: fuse-devel
|
||||
# rpmbuild driven by the Makefile uses git to generate a version number
|
||||
BuildRequires: git
|
||||
# pandoc pulls in ~60 packages (87M installed) from EPEL :(
|
||||
BuildRequires: pandoc
|
||||
|
||||
Requires: fuse-libs
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%description
|
||||
mergerfs is similar to mhddfs, unionfs, and aufs. Like mhddfs in that it too
|
||||
uses FUSE. Like aufs in that it provides multiple policies for how to handle
|
||||
behavior.
|
||||
|
||||
%build
|
||||
make %{?_smp_mflags}
|
||||
|
||||
%install
|
||||
make install PREFIX=%{_prefix} DESTDIR=%{buildroot}
|
||||
|
||||
%files
|
||||
%{_bindir}/*
|
||||
%doc %{_mandir}/*
|
||||
|
||||
%changelog
|
||||
* Sat Sep 05 2015 Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
- Include PREFIX to install
|
||||
|
||||
* Mon Dec 29 2014 Joe Lawrence <joe.lawrence@stratus.com>
|
||||
- Tweak rpmbuild to archive current git HEAD into a tarball, then (re)build in
|
||||
the rpmbuild directory -- more complicated but seemingly better suited to
|
||||
generate source and debug rpms.
|
||||
|
||||
* Fri Jun 20 2014 Joe Lawrence <joe.lawrence@stratus.com>
|
||||
- Initial rpm spec file.
|
||||
+4
-4
@@ -74,10 +74,10 @@ namespace mergerfs
|
||||
access(const char *fusepath,
|
||||
int mask)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _access(config.access,
|
||||
config.srcmounts,
|
||||
|
||||
+4
-4
@@ -74,10 +74,10 @@ namespace mergerfs
|
||||
chmod(const char *fusepath,
|
||||
mode_t mode)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _chmod(config.chmod,
|
||||
config.srcmounts,
|
||||
|
||||
+4
-4
@@ -78,10 +78,10 @@ namespace mergerfs
|
||||
uid_t uid,
|
||||
gid_t gid)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _chown(config.chown,
|
||||
config.srcmounts,
|
||||
|
||||
+6
-5
@@ -40,6 +40,7 @@
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using mergerfs::Policy;
|
||||
using namespace mergerfs;
|
||||
|
||||
static
|
||||
int
|
||||
@@ -69,7 +70,7 @@ _create(Policy::Func::Search searchFunc,
|
||||
|
||||
if(createpath[0] != existingpath[0])
|
||||
{
|
||||
const mergerfs::ugid::SetResetGuard ugid(0,0);
|
||||
const ugid::SetRootGuard ugidGuard;
|
||||
fs::clonepath(existingpath[0],createpath[0],dirname);
|
||||
}
|
||||
|
||||
@@ -93,10 +94,10 @@ namespace mergerfs
|
||||
mode_t mode,
|
||||
fuse_file_info *fileinfo)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _create(config.getattr,
|
||||
config.create,
|
||||
|
||||
+18
@@ -29,6 +29,8 @@
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@@ -510,4 +512,20 @@ namespace fs
|
||||
|
||||
globfree(&gbuf);
|
||||
}
|
||||
|
||||
void
|
||||
realpathize(vector<string> &strs)
|
||||
{
|
||||
char *rv;
|
||||
char buf[PATH_MAX];
|
||||
|
||||
for(size_t i = 0; i < strs.size(); i++)
|
||||
{
|
||||
rv = ::realpath(strs[i].c_str(),buf);
|
||||
if(rv == NULL)
|
||||
continue;
|
||||
|
||||
strs[i] = buf;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -122,6 +122,8 @@ namespace fs
|
||||
|
||||
void glob(const vector<string> &patterns,
|
||||
vector<string> &strs);
|
||||
|
||||
void realpathize(vector<string> &strs);
|
||||
};
|
||||
|
||||
#endif // __FS_HPP__
|
||||
|
||||
+7
-5
@@ -45,14 +45,16 @@ static
|
||||
int
|
||||
_getattr_controlfile(struct stat &buf)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
static const uid_t uid = ::getuid();
|
||||
static const gid_t gid = ::getgid();
|
||||
static const time_t now = ::time(NULL);
|
||||
|
||||
buf.st_dev = 0;
|
||||
buf.st_ino = 0;
|
||||
buf.st_mode = (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
|
||||
buf.st_nlink = 1;
|
||||
buf.st_uid = ::getuid();
|
||||
buf.st_gid = ::getgid();
|
||||
buf.st_uid = uid;
|
||||
buf.st_gid = gid;
|
||||
buf.st_rdev = 0;
|
||||
buf.st_size = 0;
|
||||
buf.st_blksize = 1024;
|
||||
@@ -100,8 +102,8 @@ namespace mergerfs
|
||||
if(fusepath == config.controlfile)
|
||||
return _getattr_controlfile(*st);
|
||||
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _getattr(config.getattr,
|
||||
config.srcmounts,
|
||||
|
||||
+89
-40
@@ -40,21 +40,40 @@
|
||||
#include "rwlock.hpp"
|
||||
#include "xattr.hpp"
|
||||
#include "str.hpp"
|
||||
#include "version.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::set;
|
||||
using namespace mergerfs;
|
||||
|
||||
static
|
||||
int
|
||||
_lgetxattr(const string &path,
|
||||
const string &name,
|
||||
void *value,
|
||||
const size_t size)
|
||||
{
|
||||
#ifndef WITHOUT_XATTR
|
||||
int rv;
|
||||
|
||||
rv = ::lgetxattr(path.c_str(),name.c_str(),value,size);
|
||||
|
||||
return ((rv == -1) ? -errno : rv);
|
||||
#else
|
||||
return -ENOSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
_getxattr_controlfile_fusefunc_policy(const Config &config,
|
||||
const char *attrbasename,
|
||||
const string &attr,
|
||||
string &attrvalue)
|
||||
{
|
||||
FuseFunc fusefunc;
|
||||
|
||||
fusefunc = FuseFunc::find(attrbasename);
|
||||
fusefunc = FuseFunc::find(attr);
|
||||
if(fusefunc != FuseFunc::invalid)
|
||||
attrvalue = (std::string)*config.policies[(FuseFunc::Enum::Type)*fusefunc];
|
||||
}
|
||||
@@ -62,12 +81,12 @@ _getxattr_controlfile_fusefunc_policy(const Config &config,
|
||||
static
|
||||
void
|
||||
_getxattr_controlfile_category_policy(const Config &config,
|
||||
const char *attrbasename,
|
||||
const string &attr,
|
||||
string &attrvalue)
|
||||
{
|
||||
Category cat;
|
||||
|
||||
cat = Category::find(attrbasename);
|
||||
cat = Category::find(attr);
|
||||
if(cat != Category::invalid)
|
||||
{
|
||||
vector<string> policies;
|
||||
@@ -104,28 +123,60 @@ _getxattr_controlfile_minfreespace(const Config &config,
|
||||
attrvalue = buf;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
_getxattr_controlfile_policies(const Config &config,
|
||||
string &attrvalue)
|
||||
{
|
||||
size_t i = Policy::Enum::begin();
|
||||
|
||||
attrvalue = (string)Policy::policies[i];
|
||||
for(i++; i < Policy::Enum::end(); i++)
|
||||
attrvalue += ',' + (string)Policy::policies[i];
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
_getxattr_controlfile_version(string &attrvalue)
|
||||
{
|
||||
attrvalue = MERGERFS_VERSION;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_getxattr_controlfile(const Config &config,
|
||||
const char *attrname,
|
||||
const string &attrname,
|
||||
char *buf,
|
||||
const size_t count)
|
||||
{
|
||||
size_t len;
|
||||
string attrvalue;
|
||||
const char *attrbasename = &attrname[sizeof("user.mergerfs.")-1];
|
||||
vector<string> attr;
|
||||
|
||||
if(strncmp("user.mergerfs.",attrname,sizeof("user.mergerfs.")-1))
|
||||
str::split(attr,attrname,'.');
|
||||
if((attr[0] != "user") || (attr[1] != "mergerfs"))
|
||||
return -ENOATTR;
|
||||
|
||||
if(!strcmp("srcmounts",attrbasename))
|
||||
_getxattr_controlfile_srcmounts(config,attrvalue);
|
||||
else if(!strcmp("minfreespace",attrbasename))
|
||||
_getxattr_controlfile_minfreespace(config,attrvalue);
|
||||
else if(!strncmp("category.",attrbasename,sizeof("category.")-1))
|
||||
_getxattr_controlfile_category_policy(config,&attrbasename[sizeof("category.")-1],attrvalue);
|
||||
else if(!strncmp("func.",attrbasename,sizeof("func.")-1))
|
||||
_getxattr_controlfile_fusefunc_policy(config,&attrbasename[sizeof("func.")-1],attrvalue);
|
||||
switch(attr.size())
|
||||
{
|
||||
case 3:
|
||||
if(attr[2] == "srcmounts")
|
||||
_getxattr_controlfile_srcmounts(config,attrvalue);
|
||||
else if(attr[2] == "minfreespace")
|
||||
_getxattr_controlfile_minfreespace(config,attrvalue);
|
||||
else if(attr[2] == "policies")
|
||||
_getxattr_controlfile_policies(config,attrvalue);
|
||||
else if(attr[2] == "version")
|
||||
_getxattr_controlfile_version(attrvalue);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if(attr[2] == "category")
|
||||
_getxattr_controlfile_category_policy(config,attr[3],attrvalue);
|
||||
else if(attr[2] == "func")
|
||||
_getxattr_controlfile_fusefunc_policy(config,attr[3],attrvalue);
|
||||
break;
|
||||
}
|
||||
|
||||
if(attrvalue.empty())
|
||||
return -ENOATTR;
|
||||
@@ -155,7 +206,7 @@ _getxattr_from_string(char *destbuf,
|
||||
return srcbufsize;
|
||||
|
||||
if(srcbufsize > destbufsize)
|
||||
return (errno = ERANGE, -1);
|
||||
return -ERANGE;
|
||||
|
||||
memcpy(destbuf,src.data(),srcbufsize);
|
||||
|
||||
@@ -176,7 +227,7 @@ _getxattr_user_mergerfs_allpaths(const vector<string> &srcmounts,
|
||||
|
||||
concated = str::join(paths,'\0');
|
||||
|
||||
return ::_getxattr_from_string(buf,count,concated);
|
||||
return _getxattr_from_string(buf,count,concated);
|
||||
}
|
||||
|
||||
static
|
||||
@@ -185,22 +236,24 @@ _getxattr_user_mergerfs(const string &basepath,
|
||||
const string &fusepath,
|
||||
const string &fullpath,
|
||||
const vector<string> &srcmounts,
|
||||
const char *attrname,
|
||||
const string &attrname,
|
||||
char *buf,
|
||||
const size_t count)
|
||||
{
|
||||
const char *attrbasename = &attrname[sizeof("user.mergerfs")];
|
||||
vector<string> attr;
|
||||
|
||||
if(!strcmp(attrbasename,"basepath"))
|
||||
return ::_getxattr_from_string(buf,count,basepath);
|
||||
else if(!strcmp(attrbasename,"fullpath"))
|
||||
return ::_getxattr_from_string(buf,count,fullpath);
|
||||
else if(!strcmp(attrbasename,"relpath"))
|
||||
return ::_getxattr_from_string(buf,count,fusepath);
|
||||
else if(!strcmp(attrbasename,"allpaths"))
|
||||
return ::_getxattr_user_mergerfs_allpaths(srcmounts,fusepath,buf,count);
|
||||
str::split(attr,attrname,'.');
|
||||
|
||||
return ::lgetxattr(fullpath.c_str(),attrname,buf,count);
|
||||
if(attr[2] == "basepath")
|
||||
return _getxattr_from_string(buf,count,basepath);
|
||||
else if(attr[2] == "relpath")
|
||||
return _getxattr_from_string(buf,count,fusepath);
|
||||
else if(attr[2] == "fullpath")
|
||||
return _getxattr_from_string(buf,count,fullpath);
|
||||
else if(attr[2] == "allpaths")
|
||||
return _getxattr_user_mergerfs_allpaths(srcmounts,fusepath,buf,count);
|
||||
|
||||
return -ENOATTR;
|
||||
}
|
||||
|
||||
static
|
||||
@@ -209,30 +262,26 @@ _getxattr(Policy::Func::Search searchFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const size_t minfreespace,
|
||||
const string &fusepath,
|
||||
const char *attrname,
|
||||
const string &attrname,
|
||||
char *buf,
|
||||
const size_t count)
|
||||
{
|
||||
#ifndef WITHOUT_XATTR
|
||||
int rv;
|
||||
vector<string> basepath;
|
||||
string fullpath;
|
||||
vector<string> basepath;
|
||||
|
||||
rv = searchFunc(srcmounts,fusepath,minfreespace,basepath);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
fullpath = fs::path::make(basepath[0],fusepath);
|
||||
fs::path::make(basepath[0],fusepath,fullpath);
|
||||
|
||||
if(!strncmp("user.mergerfs.",attrname,sizeof("user.mergerfs.")-1))
|
||||
if(str::isprefix(attrname,"user.mergerfs."))
|
||||
rv = _getxattr_user_mergerfs(basepath[0],fusepath,fullpath,srcmounts,attrname,buf,count);
|
||||
else
|
||||
rv = ::lgetxattr(fullpath.c_str(),attrname,buf,count);
|
||||
rv = _lgetxattr(fullpath,attrname,buf,count);
|
||||
|
||||
return ((rv == -1) ? -errno : rv);
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
||||
namespace mergerfs
|
||||
@@ -254,8 +303,8 @@ namespace mergerfs
|
||||
buf,
|
||||
count);
|
||||
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _getxattr(config.getxattr,
|
||||
config.srcmounts,
|
||||
|
||||
+3
-18
@@ -25,6 +25,7 @@
|
||||
#include <fuse.h>
|
||||
|
||||
#include "config.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
@@ -33,27 +34,11 @@ namespace mergerfs
|
||||
void *
|
||||
init(fuse_conn_info *conn)
|
||||
{
|
||||
#ifdef FUSE_CAP_ASYNC_READ
|
||||
conn->want |= FUSE_CAP_ASYNC_READ;
|
||||
#endif
|
||||
ugid::init();
|
||||
|
||||
#ifdef FUSE_CAP_IOCTL_DIR
|
||||
conn->want |= FUSE_CAP_IOCTL_DIR;
|
||||
#endif
|
||||
#ifdef FUSE_CAP_ATOMIC_O_TRUNC
|
||||
conn->want |= FUSE_CAP_ATOMIC_O_TRUNC;
|
||||
#endif
|
||||
#ifdef FUSE_CAP_BIG_WRITES
|
||||
conn->want |= FUSE_CAP_BIG_WRITES;
|
||||
#endif
|
||||
#ifdef FUSE_CAP_SPLICE_WRITE
|
||||
conn->want |= FUSE_CAP_SPLICE_WRITE;
|
||||
#endif
|
||||
#ifdef FUSE_CAP_SPLICE_READ
|
||||
conn->want |= FUSE_CAP_SPLICE_READ;
|
||||
#endif
|
||||
#ifdef FUSE_CAP_SPLICE_MOVE
|
||||
conn->want |= FUSE_CAP_SPLICE_MOVE;
|
||||
#endif
|
||||
|
||||
return &Config::get_writable();
|
||||
}
|
||||
|
||||
+7
-7
@@ -41,9 +41,9 @@ using namespace mergerfs;
|
||||
|
||||
static
|
||||
int
|
||||
_ioctl(const int fd,
|
||||
const int cmd,
|
||||
void *data)
|
||||
_ioctl(const int fd,
|
||||
const int cmd,
|
||||
void *data)
|
||||
{
|
||||
int rv;
|
||||
|
||||
@@ -98,10 +98,10 @@ _ioctl_dir(const string &fusepath,
|
||||
const int cmd,
|
||||
void *data)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _ioctl_dir_base(config.getattr,
|
||||
config.srcmounts,
|
||||
|
||||
+6
-5
@@ -38,6 +38,7 @@
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using mergerfs::Policy;
|
||||
using namespace mergerfs;
|
||||
|
||||
static
|
||||
int
|
||||
@@ -64,7 +65,7 @@ _single_link(Policy::Func::Search searchFunc,
|
||||
return -1;
|
||||
|
||||
{
|
||||
const mergerfs::ugid::SetResetGuard ugid(0,0);
|
||||
const ugid::SetRootGuard ugidGuard;
|
||||
fs::clonepath(foundpath[0],base,newpathdir);
|
||||
}
|
||||
|
||||
@@ -110,10 +111,10 @@ namespace mergerfs
|
||||
link(const char *from,
|
||||
const char *to)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _link(config.getattr,
|
||||
config.link,
|
||||
|
||||
+6
-4
@@ -52,9 +52,11 @@ _listxattr_controlfile(char *list,
|
||||
const vector<string> strs =
|
||||
buildvector<string>
|
||||
("user.mergerfs.srcmounts")
|
||||
("user.mergerfs.minfreespace");
|
||||
("user.mergerfs.minfreespace")
|
||||
("user.mergerfs.policies")
|
||||
("user.mergerfs.version");
|
||||
|
||||
xattrs.reserve(512);
|
||||
xattrs.reserve(1024);
|
||||
for(size_t i = 0; i < strs.size(); i++)
|
||||
xattrs += (strs[i] + '\0');
|
||||
for(size_t i = Category::Enum::BEGIN; i < Category::Enum::END; i++)
|
||||
@@ -115,8 +117,8 @@ namespace mergerfs
|
||||
if(fusepath == config.controlfile)
|
||||
return _listxattr_controlfile(list,size);
|
||||
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _listxattr(config.listxattr,
|
||||
config.srcmounts,
|
||||
|
||||
+6
-5
@@ -39,6 +39,7 @@
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using mergerfs::Policy;
|
||||
using namespace mergerfs;
|
||||
|
||||
static
|
||||
int
|
||||
@@ -72,7 +73,7 @@ _mkdir(Policy::Func::Search searchFunc,
|
||||
|
||||
if(createpath != existingpath[0])
|
||||
{
|
||||
const mergerfs::ugid::SetResetGuard ugid(0,0);
|
||||
const ugid::SetRootGuard ugidGuard;
|
||||
fs::clonepath(existingpath[0],createpath,dirname);
|
||||
}
|
||||
|
||||
@@ -94,10 +95,10 @@ namespace mergerfs
|
||||
mkdir(const char *fusepath,
|
||||
mode_t mode)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _mkdir(config.getattr,
|
||||
config.mkdir,
|
||||
|
||||
+6
-6
@@ -40,7 +40,7 @@
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using mergerfs::Policy;
|
||||
using namespace mergerfs;
|
||||
|
||||
static
|
||||
int
|
||||
@@ -74,7 +74,7 @@ _mknod(Policy::Func::Search searchFunc,
|
||||
|
||||
if(createpath != existingpath[0])
|
||||
{
|
||||
const mergerfs::ugid::SetResetGuard ugid(0,0);
|
||||
const ugid::SetRootGuard ugidGuard;
|
||||
fs::clonepath(existingpath[0],createpath,dirname);
|
||||
}
|
||||
|
||||
@@ -97,10 +97,10 @@ namespace mergerfs
|
||||
mode_t mode,
|
||||
dev_t rdev)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _mknod(config.getattr,
|
||||
config.mknod,
|
||||
|
||||
@@ -53,6 +53,9 @@ namespace num
|
||||
tmp *= (1024 * 1024 * 1024);
|
||||
break;
|
||||
|
||||
case '\0':
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
+4
-4
@@ -76,10 +76,10 @@ namespace mergerfs
|
||||
open(const char *fusepath,
|
||||
fuse_file_info *fileinfo)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _open(config.open,
|
||||
config.srcmounts,
|
||||
|
||||
@@ -94,12 +94,13 @@ static
|
||||
void
|
||||
set_default_options(fuse_args &args)
|
||||
{
|
||||
// set_option(args,"big_writes");
|
||||
// set_option(args,"splice_read");
|
||||
// set_option(args,"splice_write");
|
||||
// set_option(args,"splice_move");
|
||||
set_option(args,"atomic_o_trunc");
|
||||
set_option(args,"auto_cache");
|
||||
// set_option(args,"atomic_o_trunc");
|
||||
set_option(args,"big_writes");
|
||||
set_option(args,"default_permissions");
|
||||
set_option(args,"splice_move");
|
||||
set_option(args,"splice_read");
|
||||
set_option(args,"splice_write");
|
||||
}
|
||||
|
||||
static
|
||||
@@ -200,6 +201,8 @@ process_srcmounts(const char *arg,
|
||||
|
||||
fs::glob(paths,config.srcmounts);
|
||||
|
||||
fs::realpathize(config.srcmounts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,9 @@ namespace mergerfs
|
||||
rand,
|
||||
END
|
||||
};
|
||||
|
||||
static size_t begin() { return BEGIN; }
|
||||
static size_t end() { return END; }
|
||||
};
|
||||
|
||||
struct Func
|
||||
|
||||
+4
-4
@@ -96,10 +96,10 @@ namespace mergerfs
|
||||
off_t offset,
|
||||
fuse_file_info *fi)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _readdir(config.srcmounts,
|
||||
fusepath,
|
||||
|
||||
+4
-4
@@ -75,10 +75,10 @@ namespace mergerfs
|
||||
char *buf,
|
||||
size_t size)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _readlink(config.readlink,
|
||||
config.srcmounts,
|
||||
|
||||
+2
-2
@@ -87,8 +87,8 @@ namespace mergerfs
|
||||
if(fusepath == config.controlfile)
|
||||
return -ENOTSUP;
|
||||
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _removexattr(config.removexattr,
|
||||
config.srcmounts,
|
||||
|
||||
+4
-4
@@ -130,10 +130,10 @@ namespace mergerfs
|
||||
rename(const char *oldpath,
|
||||
const char *newpath)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _rename(config.getattr,
|
||||
config.rename,
|
||||
|
||||
+4
-4
@@ -73,10 +73,10 @@ namespace mergerfs
|
||||
int
|
||||
rmdir(const char *fusepath)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readguard(&config.srcmountslock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readguard(&config.srcmountslock);
|
||||
|
||||
return _rmdir(config.rmdir,
|
||||
config.srcmounts,
|
||||
|
||||
+41
-37
@@ -59,6 +59,7 @@ _add_srcmounts(vector<string> &srcmounts,
|
||||
|
||||
str::split(patterns,values,':');
|
||||
fs::glob(patterns,additions);
|
||||
fs::realpathize(additions);
|
||||
|
||||
if(!additions.empty())
|
||||
{
|
||||
@@ -106,6 +107,7 @@ _replace_srcmounts(vector<string> &srcmounts,
|
||||
|
||||
str::split(patterns,values,':');
|
||||
fs::glob(patterns,newmounts);
|
||||
fs::realpathize(newmounts);
|
||||
|
||||
{
|
||||
const rwlock::WriteGuard wrg(&srcmountslock);
|
||||
@@ -187,7 +189,7 @@ _setxattr_minfreespace(Config &config,
|
||||
static
|
||||
int
|
||||
_setxattr_controlfile_func_policy(Config &config,
|
||||
const char *funcname,
|
||||
const string &funcname,
|
||||
const string &attrval,
|
||||
const int flags)
|
||||
{
|
||||
@@ -206,7 +208,7 @@ _setxattr_controlfile_func_policy(Config &config,
|
||||
static
|
||||
int
|
||||
_setxattr_controlfile_category_policy(Config &config,
|
||||
const char *categoryname,
|
||||
const string &categoryname,
|
||||
const string &attrval,
|
||||
const int flags)
|
||||
{
|
||||
@@ -225,38 +227,45 @@ _setxattr_controlfile_category_policy(Config &config,
|
||||
static
|
||||
int
|
||||
_setxattr_controlfile(Config &config,
|
||||
const char *attrname,
|
||||
const string &attrname,
|
||||
const string &attrval,
|
||||
const int flags)
|
||||
{
|
||||
const char *attrbasename = &attrname[sizeof("user.mergerfs.")-1];
|
||||
vector<string> attr;
|
||||
|
||||
if(strncmp("user.mergerfs.",attrname,sizeof("user.mergerfs.")-1))
|
||||
return -ENOATTR;
|
||||
str::split(attr,attrname,'.');
|
||||
|
||||
if(attrval.empty())
|
||||
return -EINVAL;
|
||||
switch(attr.size())
|
||||
{
|
||||
case 3:
|
||||
if(attr[2] == "srcmounts")
|
||||
return _setxattr_srcmounts(config.srcmounts,
|
||||
config.srcmountslock,
|
||||
config.destmount,
|
||||
attrval,
|
||||
flags);
|
||||
else if(attr[2] == "minfreespace")
|
||||
return _setxattr_minfreespace(config,
|
||||
attrval,
|
||||
flags);
|
||||
break;
|
||||
|
||||
if(!strcmp("srcmounts",attrbasename))
|
||||
return _setxattr_srcmounts(config.srcmounts,
|
||||
config.srcmountslock,
|
||||
config.destmount,
|
||||
attrval,
|
||||
flags);
|
||||
else if(!strcmp("minfreespace",attrbasename))
|
||||
return _setxattr_minfreespace(config,
|
||||
attrval,
|
||||
flags);
|
||||
else if(!strncmp("category.",attrbasename,sizeof("category.")-1))
|
||||
return _setxattr_controlfile_category_policy(config,
|
||||
&attrbasename[sizeof("category.")-1],
|
||||
case 4:
|
||||
if(attr[2] == "category")
|
||||
return _setxattr_controlfile_category_policy(config,
|
||||
attr[3],
|
||||
attrval,
|
||||
flags);
|
||||
else if(attr[2] == "func")
|
||||
return _setxattr_controlfile_func_policy(config,
|
||||
attr[3],
|
||||
attrval,
|
||||
flags);
|
||||
else if(!strncmp("func.",attrbasename,sizeof("func.")-1))
|
||||
return _setxattr_controlfile_func_policy(config,
|
||||
&attrbasename[sizeof("func.")-1],
|
||||
attrval,
|
||||
flags);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -311,18 +320,13 @@ namespace mergerfs
|
||||
const Config &config = Config::get(fc);
|
||||
|
||||
if(fusepath == config.controlfile)
|
||||
{
|
||||
if((fc->uid != ::getuid()) && (fc->gid != ::getgid()))
|
||||
return -EPERM;
|
||||
return _setxattr_controlfile(Config::get_writable(),
|
||||
attrname,
|
||||
string(attrval,attrvalsize),
|
||||
flags);
|
||||
|
||||
return _setxattr_controlfile(Config::get_writable(),
|
||||
attrname,
|
||||
string(attrval,attrvalsize),
|
||||
flags);
|
||||
}
|
||||
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _setxattr(config.setxattr,
|
||||
config.srcmounts,
|
||||
|
||||
+4
-4
@@ -124,10 +124,10 @@ namespace mergerfs
|
||||
statfs(const char *fusepath,
|
||||
struct statvfs *stat)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _statfs(config.srcmounts,
|
||||
*stat);
|
||||
|
||||
@@ -139,4 +139,12 @@ namespace str
|
||||
++si;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
isprefix(const string &s0,
|
||||
const string &s1)
|
||||
{
|
||||
return ((s0.size() >= s1.size()) &&
|
||||
(s0.compare(0,s1.size(),s1) == 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,4 +54,8 @@ namespace str
|
||||
void
|
||||
erase_fnmatches(const std::vector<std::string> &pattern,
|
||||
std::vector<std::string> &strs);
|
||||
|
||||
bool
|
||||
isprefix(const std::string &s0,
|
||||
const std::string &s1);
|
||||
}
|
||||
|
||||
+4
-4
@@ -77,10 +77,10 @@ namespace mergerfs
|
||||
symlink(const char *oldpath,
|
||||
const char *newpath)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _symlink(config.symlink,
|
||||
config.srcmounts,
|
||||
|
||||
+4
-4
@@ -77,10 +77,10 @@ namespace mergerfs
|
||||
truncate(const char *fusepath,
|
||||
off_t size)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _truncate(config.truncate,
|
||||
config.srcmounts,
|
||||
|
||||
+59
-4
@@ -22,10 +22,65 @@
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ugid.hpp"
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if defined __linux__
|
||||
#elif defined __APPLE__
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
typedef std::vector<gid_t> gid_t_vector;
|
||||
typedef std::map<uid_t,gid_t_vector> gid_t_cache;
|
||||
|
||||
#if defined __linux__ and UGID_USE_RWLOCK == 0
|
||||
#include "ugid_linux.ipp"
|
||||
#else
|
||||
pthread_mutex_t mergerfs::ugid::SetResetGuard::lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
#include "ugid_rwlock.ipp"
|
||||
#endif
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
namespace ugid
|
||||
{
|
||||
static
|
||||
inline
|
||||
void
|
||||
prime_cache(const uid_t uid,
|
||||
const gid_t gid,
|
||||
gid_t_vector &gidlist)
|
||||
{
|
||||
int rv;
|
||||
char buf[4096];
|
||||
struct passwd pwd;
|
||||
struct passwd *pwdrv;
|
||||
|
||||
rv = getpwuid_r(uid,&pwd,buf,sizeof(buf),&pwdrv);
|
||||
if(pwdrv != NULL && rv == 0)
|
||||
{
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
rv = ::getgrouplist(pwd.pw_name,gid,NULL,&count);
|
||||
gidlist.resize(count);
|
||||
rv = ::getgrouplist(pwd.pw_name,gid,&gidlist[0],&count);
|
||||
if(rv == -1)
|
||||
gidlist.resize(1,gid);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
initgroups(const uid_t uid,
|
||||
const gid_t gid)
|
||||
{
|
||||
static __thread gid_t_cache cache;
|
||||
|
||||
gid_t_vector &gidlist = cache[uid];
|
||||
if(gidlist.empty())
|
||||
prime_cache(uid,gid,gidlist);
|
||||
|
||||
setgroups(gidlist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+19
-4
@@ -25,12 +25,27 @@
|
||||
#ifndef __UGID_HPP__
|
||||
#define __UGID_HPP__
|
||||
|
||||
#if defined __linux__
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
typedef std::vector<gid_t> gid_t_vector;
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
namespace ugid
|
||||
{
|
||||
void init();
|
||||
void initgroups(const uid_t uid, const gid_t gid);
|
||||
void setgroups(const gid_t_vector &gidlist);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined __linux__ and UGID_USE_RWLOCK == 0
|
||||
#include "ugid_linux.hpp"
|
||||
#elif defined __APPLE__
|
||||
#include "ugid_osx.hpp"
|
||||
#else
|
||||
#include "ugid_mutex.hpp"
|
||||
#include "ugid_rwlock.hpp"
|
||||
#endif
|
||||
|
||||
#endif /* __UGID_HPP__ */
|
||||
|
||||
+53
-20
@@ -27,38 +27,71 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
namespace ugid
|
||||
{
|
||||
struct SetResetGuard
|
||||
extern __thread uid_t currentuid;
|
||||
extern __thread gid_t currentgid;
|
||||
extern __thread bool initialized;
|
||||
|
||||
struct Set
|
||||
{
|
||||
SetResetGuard(const uid_t _newuid,
|
||||
const gid_t _newgid)
|
||||
Set(const uid_t newuid,
|
||||
const gid_t newgid)
|
||||
{
|
||||
olduid = ::syscall(SYS_geteuid);
|
||||
oldgid = ::syscall(SYS_getegid);
|
||||
newuid = _newuid;
|
||||
newgid = _newgid;
|
||||
if(!initialized)
|
||||
{
|
||||
currentuid = ::syscall(SYS_geteuid);
|
||||
currentgid = ::syscall(SYS_getegid);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
if(newgid != oldgid)
|
||||
::syscall(SYS_setregid,-1,newgid);
|
||||
if(newuid != olduid)
|
||||
if(newuid == currentuid && newgid == currentgid)
|
||||
return;
|
||||
|
||||
if(currentuid != 0)
|
||||
{
|
||||
::syscall(SYS_setreuid,-1,0);
|
||||
::syscall(SYS_setregid,-1,0);
|
||||
}
|
||||
|
||||
if(newgid)
|
||||
{
|
||||
::syscall(SYS_setregid,-1,newgid);
|
||||
initgroups(newuid,newgid);
|
||||
}
|
||||
|
||||
if(newuid)
|
||||
::syscall(SYS_setreuid,-1,newuid);
|
||||
}
|
||||
|
||||
~SetResetGuard()
|
||||
currentuid = newuid;
|
||||
currentgid = newgid;
|
||||
}
|
||||
};
|
||||
|
||||
struct SetRootGuard
|
||||
{
|
||||
SetRootGuard() :
|
||||
prevuid(currentuid),
|
||||
prevgid(currentgid)
|
||||
{
|
||||
if(olduid != newuid)
|
||||
::syscall(SYS_setreuid,-1,olduid);
|
||||
if(oldgid != newgid)
|
||||
::syscall(SYS_setregid,-1,oldgid);
|
||||
Set(0,0);
|
||||
}
|
||||
|
||||
uid_t olduid;
|
||||
gid_t oldgid;
|
||||
uid_t newuid;
|
||||
gid_t newgid;
|
||||
~SetRootGuard()
|
||||
{
|
||||
Set(prevuid,prevgid);
|
||||
}
|
||||
|
||||
const uid_t prevuid;
|
||||
const gid_t prevgid;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,36 +22,32 @@
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
typedef std::vector<gid_t> gid_t_vector;
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
namespace ugid
|
||||
{
|
||||
struct SetResetGuard
|
||||
__thread uid_t currentuid = 0;
|
||||
__thread gid_t currentgid = 0;
|
||||
__thread bool initialized = false;
|
||||
|
||||
void
|
||||
init()
|
||||
{
|
||||
SetResetGuard(const uid_t _newuid,
|
||||
const gid_t _newgid)
|
||||
{
|
||||
pthread_getugid_np(&olduid,&oldgid);
|
||||
newuid = _newuid;
|
||||
newgid = _newgid;
|
||||
}
|
||||
|
||||
if(newgid != oldgid || newuid != olduid)
|
||||
pthread_setugid_np(newuid,newgid);
|
||||
}
|
||||
|
||||
~SetResetGuard()
|
||||
{
|
||||
if(newgid != oldgid || newuid != olduid)
|
||||
pthread_setugid_np(newuid,newgid);
|
||||
}
|
||||
|
||||
uid_t olduid;
|
||||
gid_t oldgid;
|
||||
uid_t newuid;
|
||||
gid_t newgid;
|
||||
};
|
||||
int
|
||||
setgroups(const gid_t_vector &gidlist)
|
||||
{
|
||||
return ::syscall(SYS_setgroups,gidlist.size(),&gidlist[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
namespace ugid
|
||||
{
|
||||
extern uid_t currentuid;
|
||||
extern gid_t currentgid;
|
||||
extern pthread_rwlock_t rwlock;
|
||||
|
||||
static
|
||||
void
|
||||
ugid_set(const uid_t newuid,
|
||||
const gid_t newgid)
|
||||
{
|
||||
pthread_rwlock_rdlock(&rwlock);
|
||||
|
||||
if(newuid == currentuid && newgid == currentgid)
|
||||
return;
|
||||
|
||||
pthread_rwlock_unlock(&rwlock);
|
||||
pthread_rwlock_wrlock(&rwlock);
|
||||
|
||||
if(newuid == currentuid && newgid == currentgid)
|
||||
return;
|
||||
|
||||
if(currentuid != 0)
|
||||
{
|
||||
::seteuid(0);
|
||||
::setegid(0);
|
||||
}
|
||||
|
||||
if(newgid)
|
||||
{
|
||||
::setegid(newgid);
|
||||
initgroups(newuid,newgid);
|
||||
}
|
||||
|
||||
if(newuid)
|
||||
::seteuid(newuid);
|
||||
|
||||
currentuid = newuid;
|
||||
currentgid = newgid;
|
||||
}
|
||||
|
||||
struct Set
|
||||
{
|
||||
Set(const uid_t newuid,
|
||||
const gid_t newgid)
|
||||
{
|
||||
ugid_set(newuid,newgid);
|
||||
}
|
||||
|
||||
~Set()
|
||||
{
|
||||
pthread_rwlock_unlock(&rwlock);
|
||||
}
|
||||
};
|
||||
|
||||
struct SetRootGuard
|
||||
{
|
||||
SetRootGuard() :
|
||||
prevuid(currentuid),
|
||||
prevgid(currentgid)
|
||||
{
|
||||
pthread_rwlock_unlock(&rwlock);
|
||||
ugid_set(0,0);
|
||||
}
|
||||
|
||||
~SetRootGuard()
|
||||
{
|
||||
pthread_rwlock_unlock(&rwlock);
|
||||
ugid_set(prevuid,prevgid);
|
||||
}
|
||||
|
||||
const uid_t prevuid;
|
||||
const gid_t prevgid;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -22,47 +22,43 @@
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
typedef std::vector<gid_t> gid_t_vector;
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
namespace ugid
|
||||
{
|
||||
struct SetResetGuard
|
||||
uid_t currentuid;
|
||||
gid_t currentgid;
|
||||
pthread_rwlock_t rwlock;
|
||||
|
||||
void
|
||||
init()
|
||||
{
|
||||
SetResetGuard(const uid_t _newuid,
|
||||
const gid_t _newgid)
|
||||
{
|
||||
pthread_mutex_lock(&lock);
|
||||
pthread_rwlockattr_t attr;
|
||||
|
||||
olduid = ::geteuid();
|
||||
oldgid = ::getegid();
|
||||
newuid = _newuid;
|
||||
newgid = _newgid;
|
||||
pthread_rwlockattr_init(&attr);
|
||||
# if defined PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
|
||||
pthread_rwlockattr_setkind_np(&attr,PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
|
||||
# endif
|
||||
|
||||
if(newgid != oldgid)
|
||||
setegid(newgid);
|
||||
if(newuid != olduid)
|
||||
seteuid(newuid);
|
||||
}
|
||||
pthread_rwlock_init(&rwlock,&attr);
|
||||
|
||||
~SetResetGuard()
|
||||
{
|
||||
if(olduid != newuid)
|
||||
seteuid(newuid);
|
||||
if(oldgid != newgid)
|
||||
setegid(newgid);
|
||||
}
|
||||
currentuid = ::geteuid();
|
||||
currentgid = ::getegid();
|
||||
}
|
||||
|
||||
uid_t olduid;
|
||||
gid_t oldgid;
|
||||
uid_t newuid;
|
||||
gid_t newgid;
|
||||
|
||||
static pthread_mutex_t lock;
|
||||
};
|
||||
int
|
||||
setgroups(const gid_t_vector &gidlist)
|
||||
{
|
||||
return ::setgroups(gidlist.size(),&gidlist[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -74,10 +74,10 @@ namespace mergerfs
|
||||
int
|
||||
unlink(const char *fusepath)
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _unlink(config.unlink,
|
||||
config.srcmounts,
|
||||
|
||||
+4
-4
@@ -77,10 +77,10 @@ namespace mergerfs
|
||||
utimens(const char *fusepath,
|
||||
const timespec ts[2])
|
||||
{
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _utimens(config.utimens,
|
||||
config.srcmounts,
|
||||
|
||||
Reference in New Issue
Block a user