Browse Source

support runtime setting of srcmounts. closes #12

pull/37/merge 1.4.0
Antonio SJ Musumeci 10 years ago
parent
commit
7e9ccd0317
  1. 38
      README.md
  2. 3
      src/access.cpp
  3. 3
      src/chmod.cpp
  4. 3
      src/chown.cpp
  5. 19
      src/config.cpp
  6. 1
      src/config.hpp
  7. 3
      src/create.cpp
  8. 66
      src/fs.cpp
  9. 6
      src/fs.hpp
  10. 8
      src/getattr.cpp
  11. 11
      src/getxattr.cpp
  12. 3
      src/link.cpp
  13. 29
      src/listxattr.cpp
  14. 3
      src/mkdir.cpp
  15. 3
      src/mknod.cpp
  16. 5
      src/open.cpp
  17. 62
      src/option_parser.cpp
  18. 1
      src/read.cpp
  19. 2
      src/readdir.cpp
  20. 3
      src/readlink.cpp
  21. 4
      src/release.cpp
  22. 8
      src/removexattr.cpp
  23. 2
      src/rename.cpp
  24. 2
      src/rmdir.cpp
  25. 71
      src/rwlock.hpp
  26. 184
      src/setxattr.cpp
  27. 2
      src/statfs.cpp
  28. 60
      src/str.cpp
  29. 36
      src/str.hpp
  30. 2
      src/symlink.cpp
  31. 2
      src/truncate.cpp
  32. 2
      src/unlink.cpp
  33. 2
      src/utimens.cpp
  34. 4
      src/write.cpp

38
README.md

@ -97,10 +97,15 @@ There is a pseudo file available at the mountpoint which allows for the runtime
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
```

3
src/access.cpp

@ -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,

3
src/chmod.cpp

@ -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,

3
src/chown.cpp

@ -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,

19
src/config.cpp

@ -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;

1
src/config.hpp

@ -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;

3
src/create.cpp

@ -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

@ -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

6
src/fs.hpp

@ -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,

8
src/getattr.cpp

@ -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);
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,

11
src/getxattr.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;
@ -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);
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,

3
src/link.cpp

@ -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,

29
src/listxattr.cpp

@ -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);
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,

3
src/mkdir.cpp

@ -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,

3
src/mknod.cpp

@ -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,

5
src/open.cpp

@ -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,

62
src/option_parser.cpp

@ -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());
}

1
src/read.cpp

@ -29,7 +29,6 @@
#include <string.h>
#include <string>
#include <algorithm>
#include "fileinfo.hpp"

2
src/readdir.cpp

@ -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,

3
src/readlink.cpp

@ -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,

4
src/release.cpp

@ -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);
}
}
}

8
src/removexattr.cpp

@ -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);
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,

2
src/rename.cpp

@ -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,

2
src/rmdir.cpp

@ -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

@ -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();
};
}
}

184
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;
str::split(patterns,values,':');
fs::glob(patterns,additions);
while(std::getline(ss,str,delimiter))
result.push_back(str);
if(!additions.empty())
{
const rwlock::WriteGuard wrg(&srcmountslock);
srcmounts.insert(pos,
additions.begin(),
additions.end());
}
return result;
return 0;
}
static
int
_setxattr_controlfile(config::Config &config,
const string attrname,
_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 size_t attrvalsize,
const int flags)
{
const Category *cat;
const Policy *policy;
vector<string> nameparts;
string instruction;
string values;
split(nameparts,attrname,'.');
if((flags & XATTR_CREATE) == XATTR_CREATE)
return -EEXIST;
if(nameparts.size() != 3)
return -EINVAL;
_split_attrval(attrval,instruction,values);
if(nameparts[0] != "user")
return -ENOATTR;
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);
if(nameparts[1] != "mergerfs")
return -ENOATTR;
return -EINVAL;
}
static
int
_setxattr_policy(const Policy *policies[],
const string attrname,
const string attrval,
const int flags)
{
const Category *cat;
const Policy *policy;
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,17 +265,19 @@ 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);
if(fusepath == config.controlfile)
return _setxattr_controlfile(config::get_writable(),
attrname,
string(attrval,attrvalsize),
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,
@ -162,4 +287,5 @@ namespace mergerfs
flags);
}
}
}
}

2
src/statfs.cpp

@ -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

@ -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

@ -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);
}

2
src/symlink.cpp

@ -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,

2
src/truncate.cpp

@ -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,

2
src/unlink.cpp

@ -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,

2
src/utimens.cpp

@ -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,

4
src/write.cpp

@ -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…
Cancel
Save