mirror of
https://github.com/trapexit/mergerfs.git
synced 2025-02-16 23:32:47 +08:00
support runtime setting of srcmounts. closes #12
This commit is contained in:
parent
992e05e897
commit
7e9ccd0317
40
README.md
40
README.md
|
@ -93,14 +93,19 @@ make XATTR_AVAILABLE=0 - to build program without xattrs functionality (auto dis
|
|||
<mountpoint>/.mergerfs
|
||||
```
|
||||
|
||||
There is a pseudo file available at the mountpoint which allows for the runtime modification of certain mergerfs options. The file will not show up in readdirs but can be stat'ed and manipulated via [{list,get,set}xattrs](http://linux.die.net/man/2/listxattr) calls.
|
||||
There is a pseudo file available at the mountpoint which allows for the runtime modification of certain mergerfs options. The file will not show up in readdirs but can be stat'ed and manipulated via [{list,get,set}xattrs](http://linux.die.net/man/2/listxattr) calls.
|
||||
|
||||
Even if xattrs are disabled the [{list,get,set}xattrs](http://linux.die.net/man/2/listxattr) calls will still work.
|
||||
|
||||
The keys are **user.mergerfs.action**, **user.mergerfs.create**, and **user.mergerfs.search**.
|
||||
The keys are:
|
||||
* user.mergerfs.srcmounts
|
||||
* user.mergerfs.action
|
||||
* user.mergerfs.create
|
||||
* user.mergerfs.search
|
||||
|
||||
```
|
||||
[trapexit:/tmp/mount] $ xattr -l .mergerfs
|
||||
user.mergerfs.srcmounts: /tmp/a:/tmp/b
|
||||
user.mergerfs.action: ff
|
||||
user.mergerfs.create: epmfs
|
||||
user.mergerfs.search: ff
|
||||
|
@ -111,9 +116,34 @@ ff
|
|||
[trapexit:/tmp/mount] $ xattr -w user.mergerfs.action ffwp .mergerfs
|
||||
[trapexit:/tmp/mount] $ xattr -p user.mergerfs.action .mergerfs
|
||||
ffwp
|
||||
|
||||
[trapexit:/tmp/mount] $ xattr -w user.mergerfs.srcmounts +/tmp/c .mergerfs
|
||||
[trapexit:/tmp/mount] $ xattr -p user.mergerfs.srcmounts .mergerfs
|
||||
/tmp/a:/tmp/b:/tmp/c
|
||||
|
||||
[trapexit:/tmp/mount] $ xattr -w user.mergerfs.srcmounts =/tmp/c .mergerfs
|
||||
[trapexit:/tmp/mount] $ xattr -p user.mergerfs.srcmounts .mergerfs
|
||||
/tmp/c
|
||||
|
||||
[trapexit:/tmp/mount] $ xattr -w user.mergerfs.srcmounts '+</tmp/a:/tmp/b' .mergerfs
|
||||
[trapexit:/tmp/mount] $ xattr -p user.mergerfs.srcmounts .mergerfs
|
||||
/tmp/a:/tmp/b:/tmp/c
|
||||
```
|
||||
|
||||
#### mergerfs xattrs ####
|
||||
For **user.mergerfs.srcmounts** there are several instructions available for manipulating the list. The value provided is just as the value used at mount time. A colon (':') delimited list of full path globs.
|
||||
|
||||
| Instruction | Description |
|
||||
|--------------|-------------|
|
||||
| +[list] | append |
|
||||
| +<[list] | prepend |
|
||||
| +>[list] | append |
|
||||
| -[list] | remove all values provided |
|
||||
| -< | remove first in list |
|
||||
| -> | remove last in list |
|
||||
| =[list] | set |
|
||||
| [list] | set |
|
||||
|
||||
#### mergerfs file xattrs ####
|
||||
|
||||
While they won't show up when using [listxattr](http://linux.die.net/man/2/listxattr) mergerfs offers a number of special xattrs to query information about the files served. To access the values you will need to issue a [getxattr](http://linux.die.net/man/2/getxattr) for one of the following:
|
||||
|
||||
|
@ -124,5 +154,7 @@ While they won't show up when using [listxattr](http://linux.die.net/man/2/listx
|
|||
[trapexit:/tmp/mount] $ ls
|
||||
A B C
|
||||
[trapexit:/tmp/mount] $ xattr -p user.mergerfs.fullpath A
|
||||
/mnt/full/path/to/A
|
||||
/mnt/a/full/path/to/A
|
||||
[trapexit:/tmp/mount] $ xattr -p user.mergerfs.basepath A
|
||||
/mnt/a
|
||||
```
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#include "ugid.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "config.hpp"
|
||||
#include "assert.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -73,6 +73,7 @@ namespace mergerfs
|
|||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _access(*config.search,
|
||||
config.srcmounts,
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include "ugid.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "config.hpp"
|
||||
#include "assert.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -76,6 +76,7 @@ namespace mergerfs
|
|||
const struct fuse_context *fc = fuse_get_context();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const config::Config &config = config::get();
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _chmod(*config.action,
|
||||
config.srcmounts,
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include "ugid.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "config.hpp"
|
||||
#include "assert.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -79,6 +79,7 @@ namespace mergerfs
|
|||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _chown(*config.action,
|
||||
config.srcmounts,
|
||||
|
|
|
@ -24,23 +24,34 @@
|
|||
|
||||
#include <fuse.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "config.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "fs.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
namespace config
|
||||
{
|
||||
Config::Config()
|
||||
: action(policies[0]),
|
||||
create(policies[1]),
|
||||
search(policies[2]),
|
||||
: destmount(),
|
||||
srcmounts(),
|
||||
srcmountslock(),
|
||||
action(policies[Category::Enum::action]),
|
||||
create(policies[Category::Enum::create]),
|
||||
search(policies[Category::Enum::search]),
|
||||
controlfile("/.mergerfs")
|
||||
{
|
||||
pthread_rwlock_init(&srcmountslock,NULL);
|
||||
|
||||
action = &Policy::ff;
|
||||
create = &Policy::epmfs;
|
||||
search = &Policy::ff;
|
||||
|
|
|
@ -45,6 +45,7 @@ namespace mergerfs
|
|||
public:
|
||||
std::string destmount;
|
||||
std::vector<std::string> srcmounts;
|
||||
mutable pthread_rwlock_t srcmountslock;
|
||||
|
||||
const Policy *policies[Category::Enum::END];
|
||||
const Policy *&action;
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
#include "ugid.hpp"
|
||||
#include "fileinfo.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "assert.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -94,6 +94,7 @@ namespace mergerfs
|
|||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _create(*config.search,
|
||||
*config.create,
|
||||
|
|
66
src/fs.cpp
66
src/fs.cpp
|
@ -38,30 +38,18 @@
|
|||
#include <sys/statvfs.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <glob.h>
|
||||
#include <fnmatch.h>
|
||||
|
||||
#include "fs.hpp"
|
||||
#include "xattr.hpp"
|
||||
#include "str.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::map;
|
||||
using std::istringstream;
|
||||
|
||||
template<typename Container>
|
||||
Container&
|
||||
split(Container &result,
|
||||
const typename Container::value_type &s,
|
||||
typename Container::value_type::value_type delimiter)
|
||||
{
|
||||
string str;
|
||||
istringstream ss(s);
|
||||
|
||||
while(std::getline(ss,str,delimiter))
|
||||
result.push_back(str);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Iter>
|
||||
Iter
|
||||
random_element(Iter begin,
|
||||
|
@ -208,7 +196,7 @@ namespace fs
|
|||
if(rv != -1)
|
||||
{
|
||||
string tmp(attrs.begin(),attrs.end());
|
||||
split(attrvector,tmp,'\0');
|
||||
str::split(attrvector,tmp,'\0');
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
@ -453,6 +441,52 @@ namespace fs
|
|||
return (errno = 0);
|
||||
}
|
||||
|
||||
void
|
||||
glob(const vector<string> &patterns,
|
||||
vector<string> &strs)
|
||||
{
|
||||
int flags;
|
||||
glob_t gbuf;
|
||||
|
||||
flags = 0;
|
||||
for(size_t i = 0; i < patterns.size(); i++)
|
||||
{
|
||||
glob(patterns[i].c_str(),flags,NULL,&gbuf);
|
||||
flags = GLOB_APPEND;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < gbuf.gl_pathc; ++i)
|
||||
strs.push_back(gbuf.gl_pathv[i]);
|
||||
|
||||
globfree(&gbuf);
|
||||
}
|
||||
|
||||
void
|
||||
erase_fnmatches(const vector<string> &patterns,
|
||||
vector<string> &strs)
|
||||
{
|
||||
vector<string>::iterator si;
|
||||
vector<string>::const_iterator pi;
|
||||
|
||||
si = strs.begin();
|
||||
while(si != strs.end())
|
||||
{
|
||||
int match = FNM_NOMATCH;
|
||||
|
||||
for(pi = patterns.begin();
|
||||
pi != patterns.end() && match != 0;
|
||||
++pi)
|
||||
{
|
||||
match = fnmatch(pi->c_str(),si->c_str(),0);
|
||||
}
|
||||
|
||||
if(match == 0)
|
||||
si = strs.erase(si);
|
||||
else
|
||||
++si;
|
||||
}
|
||||
}
|
||||
|
||||
namespace find
|
||||
{
|
||||
void
|
||||
|
|
|
@ -104,6 +104,12 @@ namespace fs
|
|||
int copyattr(const string from,
|
||||
const string to);
|
||||
|
||||
void glob(const vector<string> &patterns,
|
||||
vector<string> &strs);
|
||||
|
||||
void erase_fnmatches(const vector<string> &patterns,
|
||||
vector<string> &strs);
|
||||
|
||||
namespace find
|
||||
{
|
||||
void invalid(const vector<string> &basepaths,
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include "config.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "ugid.hpp"
|
||||
#include "assert.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -90,13 +90,15 @@ namespace mergerfs
|
|||
getattr(const char *fusepath,
|
||||
struct stat *st)
|
||||
{
|
||||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const config::Config &config = config::get();
|
||||
|
||||
if(fusepath == config.controlfile)
|
||||
return _getattr_controlfile(*st);
|
||||
|
||||
const struct fuse_context *fc = fuse_get_context();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _getattr(*config.search,
|
||||
config.srcmounts,
|
||||
fusepath,
|
||||
|
|
|
@ -34,8 +34,9 @@
|
|||
#include "config.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "ugid.hpp"
|
||||
#include "assert.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "xattr.hpp"
|
||||
#include "str.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -57,6 +58,8 @@ _getxattr_controlfile(const Config &config,
|
|||
attrvalue = (std::string)*config.create;
|
||||
else if(attrname == "user.mergerfs.search")
|
||||
attrvalue = (std::string)*config.search;
|
||||
else if(attrname == "user.mergerfs.srcmounts")
|
||||
attrvalue = str::join(config.srcmounts,':');
|
||||
|
||||
if(attrvalue.empty())
|
||||
return -ENOATTR;
|
||||
|
@ -133,9 +136,7 @@ namespace mergerfs
|
|||
char *buf,
|
||||
size_t count)
|
||||
{
|
||||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const config::Config &config = config::get();
|
||||
|
||||
if(fusepath == config.controlfile)
|
||||
return _getxattr_controlfile(config,
|
||||
|
@ -143,6 +144,10 @@ namespace mergerfs
|
|||
buf,
|
||||
count);
|
||||
|
||||
const struct fuse_context *fc = fuse_get_context();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _getxattr(*config.search,
|
||||
config.srcmounts,
|
||||
fusepath,
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include "config.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "ugid.hpp"
|
||||
#include "assert.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -97,6 +97,7 @@ namespace mergerfs
|
|||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _link(*config.action,
|
||||
config.srcmounts,
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include "category.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "ugid.hpp"
|
||||
#include "assert.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "xattr.hpp"
|
||||
|
||||
using std::string;
|
||||
|
@ -47,23 +47,22 @@ int
|
|||
_listxattr_controlfile(char *list,
|
||||
const size_t size)
|
||||
{
|
||||
size_t xattrssize;
|
||||
string xattrs;
|
||||
|
||||
for(int i = Category::Enum::BEGIN; i < Category::Enum::END; ++i)
|
||||
xattrs += "user.mergerfs." + (string)Category::categories[i] + '\0';
|
||||
|
||||
xattrssize = xattrs.size();
|
||||
const char xattrs[] =
|
||||
"user.mergerfs.srcmounts\0"
|
||||
"user.mergerfs.action\0"
|
||||
"user.mergerfs.create\0"
|
||||
"user.mergerfs.search"
|
||||
;
|
||||
|
||||
if(size == 0)
|
||||
return xattrssize;
|
||||
return sizeof(xattrs);
|
||||
|
||||
if(size < xattrssize)
|
||||
if(size < sizeof(xattrs))
|
||||
return -ERANGE;
|
||||
|
||||
memcpy(list,xattrs.data(),xattrssize);
|
||||
memcpy(list,xattrs,sizeof(xattrs));
|
||||
|
||||
return xattrssize;
|
||||
return sizeof(xattrs);
|
||||
}
|
||||
|
||||
static
|
||||
|
@ -99,14 +98,16 @@ namespace mergerfs
|
|||
char *list,
|
||||
size_t size)
|
||||
{
|
||||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const config::Config &config = config::get();
|
||||
|
||||
if(fusepath == config.controlfile)
|
||||
return _listxattr_controlfile(list,
|
||||
size);
|
||||
|
||||
const struct fuse_context *fc = fuse_get_context();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _listxattr(*config.search,
|
||||
config.srcmounts,
|
||||
fusepath,
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include "fileinfo.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "config.hpp"
|
||||
#include "assert.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -84,6 +84,7 @@ namespace mergerfs
|
|||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _mkdir(*config.search,
|
||||
*config.create,
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
#include "ugid.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "config.hpp"
|
||||
#include "assert.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -87,6 +87,7 @@ namespace mergerfs
|
|||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _mknod(*config.search,
|
||||
*config.create,
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include "fileinfo.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "config.hpp"
|
||||
#include "assert.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -75,7 +75,8 @@ namespace mergerfs
|
|||
{
|
||||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);;
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _open(*config.search,
|
||||
config.srcmounts,
|
||||
|
|
|
@ -27,13 +27,13 @@
|
|||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <glob.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "str.hpp"
|
||||
#include "config.hpp"
|
||||
#include "policy.hpp"
|
||||
|
||||
|
@ -41,25 +41,6 @@ using std::string;
|
|||
using std::vector;
|
||||
using namespace mergerfs;
|
||||
|
||||
template<typename Container>
|
||||
Container&
|
||||
split(Container &result,
|
||||
const typename Container::value_type &s,
|
||||
typename Container::value_type::value_type delimiter)
|
||||
{
|
||||
std::istringstream ss(s);
|
||||
while(!ss.eof())
|
||||
{
|
||||
typename Container::value_type field;
|
||||
std::getline(ss,field,delimiter);
|
||||
if(field.empty())
|
||||
continue;
|
||||
result.push_back(field);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
process_opt(config::Config &config,
|
||||
|
@ -68,7 +49,7 @@ process_opt(config::Config &config,
|
|||
int rv = 0;
|
||||
std::vector<std::string> argvalue;
|
||||
|
||||
split(argvalue,arg,'=');
|
||||
str::split(argvalue,arg,'=');
|
||||
switch(argvalue.size())
|
||||
{
|
||||
case 2:
|
||||
|
@ -91,26 +72,27 @@ process_opt(config::Config &config,
|
|||
}
|
||||
|
||||
static
|
||||
void
|
||||
int
|
||||
process_srcmounts(const char *arg,
|
||||
config::Config &config)
|
||||
{
|
||||
int flags;
|
||||
glob_t gbuf;
|
||||
vector<string> paths;
|
||||
|
||||
flags = 0;
|
||||
split(paths,arg,':');
|
||||
for(size_t i = 0; i < paths.size(); i++)
|
||||
{
|
||||
glob(paths[i].c_str(),flags,NULL,&gbuf);
|
||||
flags = GLOB_APPEND;
|
||||
}
|
||||
str::split(paths,arg,':');
|
||||
|
||||
for(size_t i = 0; i < gbuf.gl_pathc; ++i)
|
||||
config.srcmounts.push_back(gbuf.gl_pathv[i]);
|
||||
fs::glob(paths,config.srcmounts);
|
||||
|
||||
globfree(&gbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
process_destmounts(const char *arg,
|
||||
config::Config &config)
|
||||
{
|
||||
config.destmount = arg;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static
|
||||
|
@ -130,10 +112,9 @@ option_processor(void *data,
|
|||
break;
|
||||
|
||||
case FUSE_OPT_KEY_NONOPT:
|
||||
if(config.srcmounts.empty())
|
||||
process_srcmounts(arg,config);
|
||||
else
|
||||
rv = (config.destmount = arg,1);
|
||||
rv = config.srcmounts.empty() ?
|
||||
process_srcmounts(arg,config) :
|
||||
process_destmounts(arg,config);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -152,10 +133,7 @@ set_fsname(struct fuse_args &args,
|
|||
{
|
||||
std::string fsname;
|
||||
|
||||
fsname = "-ofsname=";
|
||||
fsname += config.srcmounts[0];
|
||||
for(size_t i = 1; i < config.srcmounts.size(); i++)
|
||||
fsname += ';' + config.srcmounts[i];
|
||||
fsname = "-ofsname=" + str::join(config.srcmounts,':');
|
||||
|
||||
fuse_opt_insert_arg(&args,1,fsname.c_str());
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "fileinfo.hpp"
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "config.hpp"
|
||||
#include "ugid.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -125,6 +126,7 @@ namespace mergerfs
|
|||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _readdir(config.srcmounts,
|
||||
fusepath,
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include "config.hpp"
|
||||
#include "ugid.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "assert.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -75,6 +75,7 @@ namespace mergerfs
|
|||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _readlink(*config.search,
|
||||
config.srcmounts,
|
||||
|
|
|
@ -54,9 +54,9 @@ namespace mergerfs
|
|||
{
|
||||
int
|
||||
release(const char *fusepath,
|
||||
struct fuse_file_info *fi)
|
||||
struct fuse_file_info *ffi)
|
||||
{
|
||||
return _release(fi->fh);
|
||||
return _release(ffi->fh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include "config.hpp"
|
||||
#include "ugid.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "assert.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "xattr.hpp"
|
||||
|
||||
using std::string;
|
||||
|
@ -79,13 +79,15 @@ namespace mergerfs
|
|||
removexattr(const char *fusepath,
|
||||
const char *attrname)
|
||||
{
|
||||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const config::Config &config = config::get();
|
||||
|
||||
if(fusepath == config.controlfile)
|
||||
return -ENOTSUP;
|
||||
|
||||
const struct fuse_context *fc = fuse_get_context();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _removexattr(*config.action,
|
||||
config.srcmounts,
|
||||
fusepath,
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "ugid.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "config.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -73,6 +74,7 @@ namespace mergerfs
|
|||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _rename(*config.search,
|
||||
config.srcmounts,
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "ugid.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "config.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -74,6 +75,7 @@ namespace mergerfs
|
|||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readguard(&config.srcmountslock);
|
||||
|
||||
return _rmdir(*config.action,
|
||||
config.srcmounts,
|
||||
|
|
71
src/rwlock.hpp
Normal file
71
src/rwlock.hpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
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 <pthread.h>
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
namespace rwlock
|
||||
{
|
||||
class ReadGuard
|
||||
{
|
||||
public:
|
||||
ReadGuard(pthread_rwlock_t *lock)
|
||||
{
|
||||
_lock = lock;
|
||||
pthread_rwlock_rdlock(_lock);
|
||||
}
|
||||
|
||||
~ReadGuard()
|
||||
{
|
||||
pthread_rwlock_unlock(_lock);
|
||||
}
|
||||
|
||||
pthread_rwlock_t *_lock;
|
||||
|
||||
private:
|
||||
ReadGuard();
|
||||
};
|
||||
|
||||
class WriteGuard
|
||||
{
|
||||
public:
|
||||
WriteGuard(pthread_rwlock_t *lock)
|
||||
{
|
||||
_lock = lock;
|
||||
pthread_rwlock_wrlock(_lock);
|
||||
}
|
||||
|
||||
~WriteGuard()
|
||||
{
|
||||
pthread_rwlock_unlock(_lock);
|
||||
}
|
||||
|
||||
pthread_rwlock_t *_lock;
|
||||
|
||||
private:
|
||||
WriteGuard();
|
||||
};
|
||||
}
|
||||
}
|
208
src/setxattr.cpp
208
src/setxattr.cpp
|
@ -34,8 +34,9 @@
|
|||
#include "config.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "ugid.hpp"
|
||||
#include "assert.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "xattr.hpp"
|
||||
#include "str.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -43,45 +44,135 @@ using mergerfs::Policy;
|
|||
using mergerfs::Category;
|
||||
using namespace mergerfs;
|
||||
|
||||
template<typename Container>
|
||||
Container&
|
||||
split(Container &result,
|
||||
const typename Container::value_type &s,
|
||||
typename Container::value_type::value_type delimiter)
|
||||
static
|
||||
int
|
||||
_add_srcmounts(vector<string> &srcmounts,
|
||||
pthread_rwlock_t &srcmountslock,
|
||||
const string destmount,
|
||||
const string values,
|
||||
vector<string>::iterator pos)
|
||||
{
|
||||
std::string str;
|
||||
std::istringstream ss(s);
|
||||
vector<string> patterns;
|
||||
vector<string> additions;
|
||||
|
||||
while(std::getline(ss,str,delimiter))
|
||||
result.push_back(str);
|
||||
str::split(patterns,values,':');
|
||||
fs::glob(patterns,additions);
|
||||
|
||||
return result;
|
||||
if(!additions.empty())
|
||||
{
|
||||
const rwlock::WriteGuard wrg(&srcmountslock);
|
||||
|
||||
srcmounts.insert(pos,
|
||||
additions.begin(),
|
||||
additions.end());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_setxattr_controlfile(config::Config &config,
|
||||
const string attrname,
|
||||
const string attrval,
|
||||
const size_t attrvalsize,
|
||||
const int flags)
|
||||
_erase_srcmounts(vector<string> &srcmounts,
|
||||
pthread_rwlock_t srcmountslock,
|
||||
const string &values)
|
||||
{
|
||||
if(srcmounts.empty())
|
||||
return 0;
|
||||
|
||||
vector<string> patterns;
|
||||
|
||||
str::split(patterns,values,':');
|
||||
|
||||
const rwlock::WriteGuard wrg(&srcmountslock);
|
||||
|
||||
fs::erase_fnmatches(patterns,srcmounts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_replace_srcmounts(vector<string> &srcmounts,
|
||||
pthread_rwlock_t srcmountslock,
|
||||
const string destmount,
|
||||
const string values)
|
||||
{
|
||||
vector<string> patterns;
|
||||
vector<string> newmounts;
|
||||
|
||||
str::split(patterns,values,':');
|
||||
fs::glob(patterns,newmounts);
|
||||
|
||||
{
|
||||
const rwlock::WriteGuard wrg(&srcmountslock);
|
||||
|
||||
srcmounts.swap(newmounts);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
_split_attrval(const string attrval,
|
||||
string &instruction,
|
||||
string &values)
|
||||
{
|
||||
size_t offset;
|
||||
|
||||
offset = attrval.find_first_of('/');
|
||||
instruction = attrval.substr(0,offset);
|
||||
if(offset != string::npos)
|
||||
values = attrval.substr(offset);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_setxattr_srcmounts(vector<string> &srcmounts,
|
||||
pthread_rwlock_t &srcmountslock,
|
||||
const string destmount,
|
||||
const string attrval,
|
||||
const int flags)
|
||||
{
|
||||
string instruction;
|
||||
string values;
|
||||
|
||||
if((flags & XATTR_CREATE) == XATTR_CREATE)
|
||||
return -EEXIST;
|
||||
|
||||
_split_attrval(attrval,instruction,values);
|
||||
|
||||
if(instruction == "+")
|
||||
return _add_srcmounts(srcmounts,srcmountslock,destmount,values,srcmounts.end());
|
||||
else if(instruction == "+<")
|
||||
return _add_srcmounts(srcmounts,srcmountslock,destmount,values,srcmounts.begin());
|
||||
else if(instruction == "+>")
|
||||
return _add_srcmounts(srcmounts,srcmountslock,destmount,values,srcmounts.end());
|
||||
else if(instruction == "-")
|
||||
return _erase_srcmounts(srcmounts,srcmountslock,values);
|
||||
else if(instruction == "-<")
|
||||
return _erase_srcmounts(srcmounts,srcmountslock,srcmounts.front());
|
||||
else if(instruction == "->")
|
||||
return _erase_srcmounts(srcmounts,srcmountslock,srcmounts.back());
|
||||
else if(instruction == "=")
|
||||
return _replace_srcmounts(srcmounts,srcmountslock,destmount,values);
|
||||
else if(instruction.empty())
|
||||
return _replace_srcmounts(srcmounts,srcmountslock,destmount,values);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_setxattr_policy(const Policy *policies[],
|
||||
const string attrname,
|
||||
const string attrval,
|
||||
const int flags)
|
||||
{
|
||||
const Category *cat;
|
||||
const Policy *policy;
|
||||
vector<string> nameparts;
|
||||
|
||||
split(nameparts,attrname,'.');
|
||||
|
||||
if(nameparts.size() != 3)
|
||||
return -EINVAL;
|
||||
|
||||
if(nameparts[0] != "user")
|
||||
return -ENOATTR;
|
||||
|
||||
if(nameparts[1] != "mergerfs")
|
||||
return -ENOATTR;
|
||||
|
||||
cat = Category::find(nameparts[2]);
|
||||
cat = Category::find(attrname);
|
||||
if(cat == Category::invalid)
|
||||
return -ENOATTR;
|
||||
|
||||
|
@ -92,11 +183,43 @@ _setxattr_controlfile(config::Config &config,
|
|||
if(policy == Policy::invalid)
|
||||
return -EINVAL;
|
||||
|
||||
config.policies[*cat] = policy;
|
||||
policies[*cat] = policy;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_setxattr_controlfile(config::Config &config,
|
||||
const string attrname,
|
||||
const string attrval,
|
||||
const int flags)
|
||||
{
|
||||
vector<string> nameparts;
|
||||
|
||||
str::split(nameparts,attrname,'.');
|
||||
|
||||
if(nameparts.size() != 3 ||
|
||||
nameparts[0] != "user" ||
|
||||
nameparts[1] != "mergerfs")
|
||||
return -ENOATTR;
|
||||
|
||||
if(attrval.empty())
|
||||
return -EINVAL;
|
||||
|
||||
if(nameparts[2] == "srcmounts")
|
||||
return _setxattr_srcmounts(config.srcmounts,
|
||||
config.srcmountslock,
|
||||
config.destmount,
|
||||
attrval,
|
||||
flags);
|
||||
|
||||
return _setxattr_policy(config.policies,
|
||||
nameparts[2],
|
||||
attrval,
|
||||
flags);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_setxattr(const fs::SearchFunc searchFunc,
|
||||
|
@ -142,24 +265,27 @@ namespace mergerfs
|
|||
size_t attrvalsize,
|
||||
int flags)
|
||||
{
|
||||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const config::Config &config = config::get();
|
||||
|
||||
if(fusepath == config.controlfile)
|
||||
return _setxattr_controlfile(config::get_writable(),
|
||||
attrname,
|
||||
string(attrval,attrvalsize),
|
||||
attrvalsize,
|
||||
flags);
|
||||
|
||||
return _setxattr(*config.action,
|
||||
config.srcmounts,
|
||||
fusepath,
|
||||
attrname,
|
||||
attrval,
|
||||
attrvalsize,
|
||||
flags);
|
||||
{
|
||||
const struct fuse_context *fc = fuse_get_context();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _setxattr(*config.action,
|
||||
config.srcmounts,
|
||||
fusepath,
|
||||
attrname,
|
||||
attrval,
|
||||
attrvalsize,
|
||||
flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include "ugid.hpp"
|
||||
#include "config.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -126,6 +127,7 @@ namespace mergerfs
|
|||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _statfs(config.srcmounts,
|
||||
*stat);
|
||||
|
|
60
src/str.cpp
Normal file
60
src/str.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
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 <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::istringstream;
|
||||
|
||||
namespace str
|
||||
{
|
||||
void
|
||||
split(vector<string> &result,
|
||||
const string str,
|
||||
const char delimiter)
|
||||
{
|
||||
string part;
|
||||
istringstream ss(str);
|
||||
|
||||
while(std::getline(ss,part,delimiter))
|
||||
result.push_back(part);
|
||||
}
|
||||
|
||||
string
|
||||
join(const vector<string> &vec,
|
||||
const char sep)
|
||||
{
|
||||
if(vec.empty())
|
||||
return string();
|
||||
|
||||
string rv = vec[0];
|
||||
for(size_t i = 1; i < vec.size(); i++)
|
||||
rv += sep + vec[i];
|
||||
|
||||
return rv;
|
||||
}
|
||||
}
|
36
src/str.hpp
Normal file
36
src/str.hpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
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 <string>
|
||||
#include <vector>
|
||||
|
||||
namespace str
|
||||
{
|
||||
void split(std::vector<std::string> &result,
|
||||
const std::string str,
|
||||
const char delimiter);
|
||||
|
||||
std::string join(const std::vector<std::string> &vec,
|
||||
const char sep);
|
||||
}
|
|
@ -32,6 +32,7 @@
|
|||
#include "fs.hpp"
|
||||
#include "config.hpp"
|
||||
#include "ugid.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -67,6 +68,7 @@ namespace mergerfs
|
|||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _symlink(config.srcmounts,
|
||||
oldpath,
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "ugid.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "config.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -77,6 +78,7 @@ namespace mergerfs
|
|||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _truncate(*config.action,
|
||||
config.srcmounts,
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "ugid.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "config.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -74,6 +75,7 @@ namespace mergerfs
|
|||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _unlink(*config.action,
|
||||
config.srcmounts,
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "ugid.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "config.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -77,6 +78,7 @@ namespace mergerfs
|
|||
const struct fuse_context *fc = fuse_get_context();
|
||||
const config::Config &config = config::get();
|
||||
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
|
||||
return _utimens(*config.action,
|
||||
config.srcmounts,
|
||||
|
|
|
@ -52,9 +52,9 @@ namespace mergerfs
|
|||
const char *buf,
|
||||
size_t count,
|
||||
off_t offset,
|
||||
struct fuse_file_info *fi)
|
||||
struct fuse_file_info *ffi)
|
||||
{
|
||||
return _write(((FileInfo*)fi->fh)->fd,
|
||||
return _write(((FileInfo*)ffi->fh)->fd,
|
||||
buf,
|
||||
count,
|
||||
offset);
|
||||
|
|
Loading…
Reference in New Issue
Block a user