Browse Source

per FUSE function policies. closes #52, #53

pull/55/head
Antonio SJ Musumeci 10 years ago
parent
commit
12f393a55e
  1. 84
      README.md
  2. 2
      src/access.cpp
  3. 2
      src/category.cpp
  4. 4
      src/category.hpp
  5. 2
      src/chmod.cpp
  6. 2
      src/chown.cpp
  7. 42
      src/config.cpp
  8. 29
      src/config.hpp
  9. 2
      src/create.cpp
  10. 29
      src/fs.cpp
  11. 3
      src/fs.hpp
  12. 105
      src/fusefunc.cpp
  13. 139
      src/fusefunc.hpp
  14. 2
      src/getattr.cpp
  15. 70
      src/getxattr.cpp
  16. 2
      src/ioctl.cpp
  17. 2
      src/link.cpp
  18. 23
      src/listxattr.cpp
  19. 4
      src/mkdir.cpp
  20. 4
      src/mknod.cpp
  21. 2
      src/open.cpp
  22. 9
      src/option_parser.cpp
  23. 2
      src/readlink.cpp
  24. 2
      src/removexattr.cpp
  25. 2
      src/rename.cpp
  26. 2
      src/rmdir.cpp
  27. 74
      src/setxattr.cpp
  28. 28
      src/str.cpp
  29. 4
      src/str.hpp
  30. 2
      src/truncate.cpp
  31. 2
      src/unlink.cpp
  32. 2
      src/utimens.cpp

84
README.md

@ -8,7 +8,7 @@ mergerfs - another FUSE union filesystem
# SYNOPSIS # SYNOPSIS
mergerfs -ocreate=epmfs,search=ff <srcpoints> <mountpoint>
mergerfs -o<options> <srcpoints> <mountpoint>
# DESCRIPTION # DESCRIPTION
@ -20,10 +20,11 @@ Why create mergerfs when those exist? mhddfs isn't really maintained or flexible
###options### ###options###
| Option | Default |
|--------|--------|
| search | ff |
| create | epmfs |
All [FUSE](http://fuse.sourceforge.net) functions which have a category (see below) are option keys. The syntax being `<func>=<policy>`.
To set all function policies in a category use `category.<category>=<policy>` such as `category.create=mfs`.
They are evaluated in the order listed so if the options are `rmdir=rand,category.action=ff` the `action` category setting will override the `rmdir` setting.
###srcpoints### ###srcpoints###
@ -46,14 +47,15 @@ In /etc/fstab it'd look like the following:
# POLICIES # POLICIES
Filesystem calls are broken up into 2 categories: search and create. There are also some calls which have no policy attached due to state being kept between calls. These categories can be assigned a policy which dictates how [mergerfs](http://github.com/trapexit/mergerfs) behaves. Any policy can be assigned to a category though some aren't terribly practical. For instance: rand (Random) may be useful for **create** but could lead to very odd behavior if used for **search**.
Filesystem calls are broken up into 3 categories: action, create, search. There are also some calls which have no policy attached due to state being kept between calls. These categories can be assigned a policy which dictates how [mergerfs](http://github.com/trapexit/mergerfs) behaves. Any policy can be assigned to a category though some aren't terribly practical. For instance: rand (Random) may be useful for **create** but could lead to very odd behavior if used for **search**.
#### Functional classifications #### #### Functional classifications ####
| Class | FUSE calls | | Class | FUSE calls |
|-------|------------| |-------|------------|
| search | access, getattr, getxattr, listxattr, open, readlink, chmod, link, removexattr, rmdir, setxattr, truncate, unlink, utimens |
| action | chmod, chown, link, removexattr, rename, rmdir, setxattr, truncate, unlink, utimens |
| search | access, getattr, getxattr, listxattr, open, readlink, symlink |
| create | create, mkdir, mknod | | create | create, mkdir, mknod |
| none | fallocate, fgetattr, fsync, ftruncate, ioctl, read, readdir, rename, statfs, symlink, write, release |
| N/A | fallocate, fgetattr, fsync, ftruncate, ioctl, read, readdir, statfs, symlink, write, release |
#### Policy descriptions #### #### Policy descriptions ####
| Policy | Description | | Policy | Description |
@ -100,22 +102,66 @@ 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. Even if xattrs are disabled the [{list,get,set}xattrs](http://linux.die.net/man/2/listxattr) calls will still work.
The keys are:
##### Keys #####
* user.mergerfs.srcmounts * user.mergerfs.srcmounts
* user.mergerfs.create
* user.mergerfs.search
* user.mergerfs.category.action
* user.mergerfs.category.create
* user.mergerfs.category.search
* user.mergerfs.func.access
* user.mergerfs.func.chmod
* user.mergerfs.func.chown
* user.mergerfs.func.create
* user.mergerfs.func.getattr
* user.mergerfs.func.getxattr
* user.mergerfs.func.link
* user.mergerfs.func.listxattr
* user.mergerfs.func.mkdir
* user.mergerfs.func.mknod
* user.mergerfs.func.open
* user.mergerfs.func.readlink
* user.mergerfs.func.removexattr
* user.mergerfs.func.rename
* user.mergerfs.func.rmdir
* user.mergerfs.func.setxattr
* user.mergerfs.func.symlink
* user.mergerfs.func.truncate
* user.mergerfs.func.unlink
* user.mergerfs.func.utimens
##### Example #####
``` ```
[trapexit:/tmp/mount] $ xattr -l .mergerfs [trapexit:/tmp/mount] $ xattr -l .mergerfs
user.mergerfs.srcmounts: /tmp/a:/tmp/b user.mergerfs.srcmounts: /tmp/a:/tmp/b
user.mergerfs.create: epmfs
user.mergerfs.search: ff
[trapexit:/tmp/mount] $ xattr -p user.mergerfs.search .mergerfs
user.mergerfs.category.action: ff
user.mergerfs.category.create: epmfs
user.mergerfs.category.search: ff
user.mergerfs.func.access: ff
user.mergerfs.func.chmod: ff
user.mergerfs.func.chown: ff
user.mergerfs.func.create: epmfs
user.mergerfs.func.getattr: ff
user.mergerfs.func.getxattr: ff
user.mergerfs.func.link: ff
user.mergerfs.func.listxattr: ff
user.mergerfs.func.mkdir: epmfs
user.mergerfs.func.mknod: epmfs
user.mergerfs.func.open: ff
user.mergerfs.func.readlink: ff
user.mergerfs.func.removexattr: ff
user.mergerfs.func.rename: ff
user.mergerfs.func.rmdir: ff
user.mergerfs.func.setxattr: ff
user.mergerfs.func.symlink: ff
user.mergerfs.func.truncate: ff
user.mergerfs.func.unlink: ff
user.mergerfs.func.utimens: ff
[trapexit:/tmp/mount] $ xattr -p user.mergerfs.category.search .mergerfs
ff ff
[trapexit:/tmp/mount] $ xattr -w user.mergerfs.search ffwp .mergerfs
[trapexit:/tmp/mount] $ xattr -p user.mergerfs.search .mergerfs
[trapexit:/tmp/mount] $ xattr -w user.mergerfs.category.search ffwp .mergerfs
[trapexit:/tmp/mount] $ xattr -p user.mergerfs.category.search .mergerfs
ffwp ffwp
[trapexit:/tmp/mount] $ xattr -w user.mergerfs.srcmounts +/tmp/c .mergerfs [trapexit:/tmp/mount] $ xattr -w user.mergerfs.srcmounts +/tmp/c .mergerfs
@ -131,6 +177,8 @@ ffwp
/tmp/a:/tmp/b:/tmp/c /tmp/a:/tmp/b:/tmp/c
``` ```
##### Extra Details #####
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. 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 | | Instruction | Description |
@ -144,6 +192,8 @@ For **user.mergerfs.srcmounts** there are several instructions available for man
| =[list] | set | | =[list] | set |
| [list] | set | | [list] | set |
Categories and funcs take a policy as described in the previous section. When reading funcs you'll get the policy string. However, with categories you'll get a coma separated list of policies for each type found. For example: if all search functions are `ff` except for `access` which is `ffwp` the value for `user.mergerfs.category.search` will be `ff,ffwp`.
#### mergerfs file xattrs #### #### 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: 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:

2
src/access.cpp

@ -75,7 +75,7 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _access(*config.search,
return _access(*config.access,
config.srcmounts, config.srcmounts,
fusepath, fusepath,
mask); mask);

2
src/category.cpp

@ -35,12 +35,14 @@ namespace mergerfs
const std::vector<Category> Category::_categories_ = const std::vector<Category> Category::_categories_ =
buildvector<Category,true> buildvector<Category,true>
(CATEGORY(invalid)) (CATEGORY(invalid))
(CATEGORY(action))
(CATEGORY(create)) (CATEGORY(create))
(CATEGORY(search)); (CATEGORY(search));
const Category * const Category::categories = &_categories_[1]; const Category * const Category::categories = &_categories_[1];
const Category &Category::invalid = Category::categories[Category::Enum::invalid]; const Category &Category::invalid = Category::categories[Category::Enum::invalid];
const Category &Category::action = Category::categories[Category::Enum::action];
const Category &Category::create = Category::categories[Category::Enum::create]; const Category &Category::create = Category::categories[Category::Enum::create];
const Category &Category::search = Category::categories[Category::Enum::search]; const Category &Category::search = Category::categories[Category::Enum::search];

4
src/category.hpp

@ -39,7 +39,8 @@ namespace mergerfs
{ {
invalid = -1, invalid = -1,
BEGIN = 0, BEGIN = 0,
create = BEGIN,
action = BEGIN,
create,
search, search,
END END
}; };
@ -88,6 +89,7 @@ namespace mergerfs
static const std::vector<Category> _categories_; static const std::vector<Category> _categories_;
static const Category * const categories; static const Category * const categories;
static const Category &invalid; static const Category &invalid;
static const Category &action;
static const Category &create; static const Category &create;
static const Category &search; static const Category &search;
}; };

2
src/chmod.cpp

@ -69,7 +69,7 @@ namespace mergerfs
const config::Config &config = config::get(); const config::Config &config = config::get();
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _chmod(*config.search,
return _chmod(*config.chmod,
config.srcmounts, config.srcmounts,
fusepath, fusepath,
mode); mode);

2
src/chown.cpp

@ -72,7 +72,7 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _chown(*config.search,
return _chown(*config.chown,
config.srcmounts, config.srcmounts,
fusepath, fusepath,
uid, uid,

42
src/config.cpp

@ -32,6 +32,8 @@
#include "rwlock.hpp" #include "rwlock.hpp"
#include "fs.hpp" #include "fs.hpp"
#define POLICYINIT(X) X(policies[FuseFunc::Enum::X])
using std::string; using std::string;
using std::vector; using std::vector;
@ -43,14 +45,46 @@ namespace mergerfs
: destmount(), : destmount(),
srcmounts(), srcmounts(),
srcmountslock(), srcmountslock(),
create(policies[Category::Enum::create]),
search(policies[Category::Enum::search]),
POLICYINIT(access),
POLICYINIT(chmod),
POLICYINIT(chown),
POLICYINIT(create),
POLICYINIT(getattr),
POLICYINIT(getxattr),
POLICYINIT(link),
POLICYINIT(listxattr),
POLICYINIT(mkdir),
POLICYINIT(mknod),
POLICYINIT(open),
POLICYINIT(readlink),
POLICYINIT(removexattr),
POLICYINIT(rename),
POLICYINIT(rmdir),
POLICYINIT(setxattr),
POLICYINIT(symlink),
POLICYINIT(truncate),
POLICYINIT(unlink),
POLICYINIT(utimens),
controlfile("/.mergerfs") controlfile("/.mergerfs")
{ {
pthread_rwlock_init(&srcmountslock,NULL); pthread_rwlock_init(&srcmountslock,NULL);
create = &Policy::epmfs;
search = &Policy::ff;
setpolicy(Category::Enum::action,Policy::Enum::ff);
setpolicy(Category::Enum::create,Policy::Enum::epmfs);
setpolicy(Category::Enum::search,Policy::Enum::ff);
}
void
Config::setpolicy(const Category::Enum::Type category,
const Policy::Enum::Type policy_)
{
const Policy *policy = Policy::find(policy_);
for(int i = 0; i < FuseFunc::Enum::END; i++)
{
if(FuseFunc::fusefuncs[i] == category)
policies[(FuseFunc::Enum::Type)FuseFunc::fusefuncs[i]] = policy;
}
} }
const Config& const Config&

29
src/config.hpp

@ -33,7 +33,7 @@
#include <vector> #include <vector>
#include "policy.hpp" #include "policy.hpp"
#include "category.hpp"
#include "fusefunc.hpp"
namespace mergerfs namespace mergerfs
{ {
@ -44,14 +44,37 @@ namespace mergerfs
public: public:
Config(); Config();
public:
void setpolicy(const Category::Enum::Type category,
const Policy::Enum::Type policy);
public: public:
std::string destmount; std::string destmount;
std::vector<std::string> srcmounts; std::vector<std::string> srcmounts;
mutable pthread_rwlock_t srcmountslock; mutable pthread_rwlock_t srcmountslock;
const Policy *policies[Category::Enum::END];
public:
const Policy *policies[FuseFunc::Enum::END];
const Policy *&access;
const Policy *&chmod;
const Policy *&chown;
const Policy *&create; const Policy *&create;
const Policy *&search;
const Policy *&getattr;
const Policy *&getxattr;
const Policy *&link;
const Policy *&listxattr;
const Policy *&mkdir;
const Policy *&mknod;
const Policy *&open;
const Policy *&readlink;
const Policy *&removexattr;
const Policy *&rename;
const Policy *&rmdir;
const Policy *&setxattr;
const Policy *&symlink;
const Policy *&truncate;
const Policy *&unlink;
const Policy *&utimens;
public: public:
const std::string controlfile; const std::string controlfile;

2
src/create.cpp

@ -100,7 +100,7 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _create(*config.search,
return _create(*config.create,
*config.create, *config.create,
config.srcmounts, config.srcmounts,
fusepath, fusepath,

29
src/fs.cpp

@ -39,7 +39,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <glob.h> #include <glob.h>
#include <fnmatch.h>
#include "fs.hpp" #include "fs.hpp"
#include "xattr.hpp" #include "xattr.hpp"
@ -492,7 +491,7 @@ namespace fs
if(rv == -1 && errno != ENOTTY) if(rv == -1 && errno != ENOTTY)
return -1; return -1;
return (errno = 0);
return 0;
} }
void void
@ -515,32 +514,6 @@ namespace fs
globfree(&gbuf); 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 namespace find
{ {
int int

3
src/fs.hpp

@ -110,9 +110,6 @@ namespace fs
void glob(const vector<string> &patterns, void glob(const vector<string> &patterns,
vector<string> &strs); vector<string> &strs);
void erase_fnmatches(const vector<string> &patterns,
vector<string> &strs);
namespace find namespace find
{ {
int invalid(const vector<string> &basepaths, int invalid(const vector<string> &basepaths,

105
src/fusefunc.cpp

@ -0,0 +1,105 @@
/*
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 "fusefunc.hpp"
#include "category.hpp"
#include "buildvector.hpp"
#define FUSEFUNC(X,Y) FuseFunc(FuseFunc::Enum::X,#X,Category::Enum::Y)
namespace mergerfs
{
const std::vector<FuseFunc> FuseFunc::_fusefuncs_ =
buildvector<FuseFunc,true>
(FUSEFUNC(invalid,invalid))
(FUSEFUNC(access,search))
(FUSEFUNC(chmod,action))
(FUSEFUNC(chown,action))
(FUSEFUNC(create,create))
(FUSEFUNC(getattr,search))
(FUSEFUNC(getxattr,search))
(FUSEFUNC(link,action))
(FUSEFUNC(listxattr,search))
(FUSEFUNC(mkdir,create))
(FUSEFUNC(mknod,create))
(FUSEFUNC(open,search))
(FUSEFUNC(readlink,search))
(FUSEFUNC(removexattr,action))
(FUSEFUNC(rename,action))
(FUSEFUNC(rmdir,action))
(FUSEFUNC(setxattr,action))
(FUSEFUNC(symlink,search))
(FUSEFUNC(truncate,action))
(FUSEFUNC(unlink,action))
(FUSEFUNC(utimens,action))
;
const FuseFunc * const FuseFunc::fusefuncs = &_fusefuncs_[1];
const FuseFunc &FuseFunc::invalid = FuseFunc::fusefuncs[FuseFunc::Enum::invalid];
const FuseFunc &FuseFunc::access = FuseFunc::fusefuncs[FuseFunc::Enum::access];
const FuseFunc &FuseFunc::chmod = FuseFunc::fusefuncs[FuseFunc::Enum::chmod];
const FuseFunc &FuseFunc::chown = FuseFunc::fusefuncs[FuseFunc::Enum::chown];
const FuseFunc &FuseFunc::create = FuseFunc::fusefuncs[FuseFunc::Enum::create];
const FuseFunc &FuseFunc::getattr = FuseFunc::fusefuncs[FuseFunc::Enum::getattr];
const FuseFunc &FuseFunc::getxattr = FuseFunc::fusefuncs[FuseFunc::Enum::getxattr];
const FuseFunc &FuseFunc::link = FuseFunc::fusefuncs[FuseFunc::Enum::link];
const FuseFunc &FuseFunc::listxattr = FuseFunc::fusefuncs[FuseFunc::Enum::listxattr];
const FuseFunc &FuseFunc::mkdir = FuseFunc::fusefuncs[FuseFunc::Enum::mkdir];
const FuseFunc &FuseFunc::mknod = FuseFunc::fusefuncs[FuseFunc::Enum::mknod];
const FuseFunc &FuseFunc::open = FuseFunc::fusefuncs[FuseFunc::Enum::open];
const FuseFunc &FuseFunc::readlink = FuseFunc::fusefuncs[FuseFunc::Enum::readlink];
const FuseFunc &FuseFunc::removexattr = FuseFunc::fusefuncs[FuseFunc::Enum::removexattr];
const FuseFunc &FuseFunc::rmdir = FuseFunc::fusefuncs[FuseFunc::Enum::rmdir];
const FuseFunc &FuseFunc::setxattr = FuseFunc::fusefuncs[FuseFunc::Enum::setxattr];
const FuseFunc &FuseFunc::symlink = FuseFunc::fusefuncs[FuseFunc::Enum::symlink];
const FuseFunc &FuseFunc::truncate = FuseFunc::fusefuncs[FuseFunc::Enum::truncate];
const FuseFunc &FuseFunc::unlink = FuseFunc::fusefuncs[FuseFunc::Enum::unlink];
const FuseFunc &FuseFunc::utimens = FuseFunc::fusefuncs[FuseFunc::Enum::utimens];
const FuseFunc&
FuseFunc::find(const std::string &str)
{
for(int i = Enum::BEGIN; i != Enum::END; ++i)
{
if(fusefuncs[i] == str)
return fusefuncs[i];
}
return invalid;
}
const FuseFunc&
FuseFunc::find(const FuseFunc::Enum::Type i)
{
if(i >= FuseFunc::Enum::BEGIN &&
i < FuseFunc::Enum::END)
return fusefuncs[i];
return invalid;
}
}

139
src/fusefunc.hpp

@ -0,0 +1,139 @@
/*
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.
*/
#ifndef __FUSEFUNC_HPP__
#define __FUSEFUNC_HPP__
#include <string>
#include <vector>
#include "category.hpp"
namespace mergerfs
{
class FuseFunc
{
public:
struct Enum
{
enum Type
{
invalid = -1,
BEGIN = 0,
access = BEGIN,
chmod,
chown,
create,
getattr,
getxattr,
link,
listxattr,
mkdir,
mknod,
open,
readlink,
removexattr,
rename,
rmdir,
setxattr,
symlink,
truncate,
unlink,
utimens,
END
};
};
private:
Enum::Type _enum;
std::string _str;
Category::Enum::Type _category;
public:
FuseFunc()
: _enum(invalid),
_str(invalid),
_category(Category::Enum::invalid)
{
}
FuseFunc(const Enum::Type enum_,
const std::string &str_,
const Category::Enum::Type category_)
: _enum(enum_),
_str(str_),
_category(category_)
{
}
public:
operator const Enum::Type() const { return _enum; }
operator const std::string&() const { return _str; }
operator const Category::Enum::Type() const { return _category; }
operator const FuseFunc*() const { return this; }
bool operator==(const std::string &str_) const
{ return _str == str_; }
bool operator==(const Enum::Type enum_) const
{ return _enum == enum_; }
bool operator!=(const FuseFunc &r) const
{ return _enum != r._enum; }
bool operator<(const FuseFunc &r) const
{ return _enum < r._enum; }
public:
static const FuseFunc &find(const std::string&);
static const FuseFunc &find(const Enum::Type);
public:
static const std::vector<FuseFunc> _fusefuncs_;
static const FuseFunc * const fusefuncs;
static const FuseFunc &invalid;
static const FuseFunc &access;
static const FuseFunc &chmod;
static const FuseFunc &chown;
static const FuseFunc &create;
static const FuseFunc &getattr;
static const FuseFunc &getxattr;
static const FuseFunc &link;
static const FuseFunc &listxattr;
static const FuseFunc &mkdir;
static const FuseFunc &mknod;
static const FuseFunc &open;
static const FuseFunc &readlink;
static const FuseFunc &removexattr;
static const FuseFunc &rename;
static const FuseFunc &rmdir;
static const FuseFunc &setxattr;
static const FuseFunc &symlink;
static const FuseFunc &truncate;
static const FuseFunc &unlink;
static const FuseFunc &utimens;
};
}
#endif

2
src/getattr.cpp

@ -99,7 +99,7 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _getattr(*config.search,
return _getattr(*config.getattr,
config.srcmounts, config.srcmounts,
fusepath, fusepath,
*st); *st);

70
src/getxattr.cpp

@ -26,6 +26,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <set>
#include <algorithm>
#include <errno.h> #include <errno.h>
#include <sys/types.h> #include <sys/types.h>
@ -40,24 +42,76 @@
using std::string; using std::string;
using std::vector; using std::vector;
using std::set;
using namespace mergerfs;
using namespace mergerfs::config; using namespace mergerfs::config;
static
void
_getxattr_controlfile_fusefunc_policy(const Config &config,
const char *attrbasename,
string &attrvalue)
{
FuseFunc fusefunc;
fusefunc = FuseFunc::find(attrbasename);
if(fusefunc != FuseFunc::invalid)
attrvalue = (std::string)*config.policies[(FuseFunc::Enum::Type)*fusefunc];
}
static
void
_getxattr_controlfile_category_policy(const Config &config,
const char *attrbasename,
string &attrvalue)
{
Category cat;
cat = Category::find(attrbasename);
if(cat != Category::invalid)
{
vector<string> policies;
for(int i = FuseFunc::Enum::BEGIN; i < FuseFunc::Enum::END; i++)
{
if(cat == (Category::Enum::Type)*FuseFunc::fusefuncs[i])
policies.push_back(*config.policies[i]);
}
std::sort(policies.begin(),policies.end());
policies.erase(std::unique(policies.begin(),policies.end()),
policies.end());
attrvalue = str::join(policies,',');
}
}
static
void
_getxattr_controlfile_srcmounts(const Config &config,
string &attrvalue)
{
attrvalue = str::join(config.srcmounts,':');
}
static static
int int
_getxattr_controlfile(const Config &config, _getxattr_controlfile(const Config &config,
const string &attrname,
const char *attrname,
char *buf, char *buf,
const size_t count) const size_t count)
{ {
size_t len; size_t len;
string attrvalue; string attrvalue;
const char *attrbasename = &attrname[sizeof("user.mergerfs.")-1];
if(attrname == "user.mergerfs.create")
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(strncmp("user.mergerfs.",attrname,sizeof("user.mergerfs.")-1))
return -ENOATTR;
if(!strcmp("srcmounts",attrbasename))
_getxattr_controlfile_srcmounts(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);
if(attrvalue.empty()) if(attrvalue.empty())
return -ENOATTR; return -ENOATTR;
@ -185,7 +239,7 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _getxattr(*config.search,
return _getxattr(*config.getxattr,
config.srcmounts, config.srcmounts,
fusepath, fusepath,
attrname, attrname,

2
src/ioctl.cpp

@ -123,7 +123,7 @@ _ioctl_dir(const string &fusepath,
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _ioctl_dir_base(*config.search,
return _ioctl_dir_base(*config.getattr,
config.srcmounts, config.srcmounts,
fusepath, fusepath,
cmd, cmd,

2
src/link.cpp

@ -91,7 +91,7 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _link(*config.search,
return _link(*config.link,
config.srcmounts, config.srcmounts,
from, from,
to); to);

23
src/listxattr.cpp

@ -47,21 +47,24 @@ int
_listxattr_controlfile(char *list, _listxattr_controlfile(char *list,
const size_t size) const size_t size)
{ {
const char xattrs[] =
"user.mergerfs.srcmounts\0"
"user.mergerfs.create\0"
"user.mergerfs.search"
;
string xattrs;
xattrs.reserve(512);
xattrs.append("user.mergerfs.srcmounts",sizeof("user.mergerfs.srcmounts"));
for(int i = Category::Enum::BEGIN; i < Category::Enum::END; i++)
xattrs += ("user.mergerfs.category." + (std::string)*Category::categories[i] + '\0');
for(int i = FuseFunc::Enum::BEGIN; i < FuseFunc::Enum::END; i++)
xattrs += ("user.mergerfs.func." + (std::string)*FuseFunc::fusefuncs[i] + '\0');
if(size == 0) if(size == 0)
return sizeof(xattrs);
return xattrs.size();
if(size < sizeof(xattrs))
if(size < xattrs.size())
return -ERANGE; return -ERANGE;
memcpy(list,xattrs,sizeof(xattrs));
memcpy(list,xattrs.c_str(),xattrs.size());
return sizeof(xattrs);
return xattrs.size();
} }
static static
@ -107,7 +110,7 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _listxattr(*config.search,
return _listxattr(*config.listxattr,
config.srcmounts, config.srcmounts,
fusepath, fusepath,
list, list,

4
src/mkdir.cpp

@ -92,8 +92,8 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _mkdir(*config.search,
*config.create,
return _mkdir(*config.getattr,
*config.mkdir,
config.srcmounts, config.srcmounts,
fusepath, fusepath,
(mode & ~fc->umask)); (mode & ~fc->umask));

4
src/mknod.cpp

@ -95,8 +95,8 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _mknod(*config.search,
*config.create,
return _mknod(*config.getattr,
*config.mknod,
config.srcmounts, config.srcmounts,
fusepath, fusepath,
(mode & ~fc->umask), (mode & ~fc->umask),

2
src/open.cpp

@ -79,7 +79,7 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _open(*config.search,
return _open(*config.open,
config.srcmounts, config.srcmounts,
fusepath, fusepath,
fileinfo->flags, fileinfo->flags,

9
src/option_parser.cpp

@ -53,12 +53,13 @@ process_opt(config::Config &config,
switch(argvalue.size()) switch(argvalue.size())
{ {
case 2: case 2:
if(argvalue[0] == "create")
config.create = Policy::find(argvalue[1]);
else if(argvalue[0] == "search")
config.search = Policy::find(argvalue[1]);
{
FuseFunc fusefunc = FuseFunc::find(argvalue[0]);
if(fusefunc != FuseFunc::invalid)
config.policies[(FuseFunc::Enum::Type)*fusefunc] = Policy::find(argvalue[1]);
else else
rv = 1; rv = 1;
}
break; break;
default: default:

2
src/readlink.cpp

@ -77,7 +77,7 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _readlink(*config.search,
return _readlink(*config.readlink,
config.srcmounts, config.srcmounts,
fusepath, fusepath,
buf, buf,

2
src/removexattr.cpp

@ -79,7 +79,7 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _removexattr(*config.search,
return _removexattr(*config.removexattr,
config.srcmounts, config.srcmounts,
fusepath, fusepath,
attrname); attrname);

2
src/rename.cpp

@ -76,7 +76,7 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _rename(*config.search,
return _rename(*config.rename,
config.srcmounts, config.srcmounts,
from, from,
to); to);

2
src/rmdir.cpp

@ -68,7 +68,7 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readguard(&config.srcmountslock); const rwlock::ReadGuard readguard(&config.srcmountslock);
return _rmdir(*config.search,
return _rmdir(*config.rmdir,
config.srcmounts, config.srcmounts,
fusepath); fusepath);
} }

74
src/setxattr.cpp

@ -30,6 +30,7 @@
#include <errno.h> #include <errno.h>
#include <sys/types.h> #include <sys/types.h>
#include <string.h>
#include "config.hpp" #include "config.hpp"
#include "fs.hpp" #include "fs.hpp"
@ -41,7 +42,7 @@
using std::string; using std::string;
using std::vector; using std::vector;
using mergerfs::Policy; using mergerfs::Policy;
using mergerfs::Category;
using mergerfs::FuseFunc;
using namespace mergerfs; using namespace mergerfs;
static static
@ -86,7 +87,7 @@ _erase_srcmounts(vector<string> &srcmounts,
{ {
const rwlock::WriteGuard wrg(&srcmountslock); const rwlock::WriteGuard wrg(&srcmountslock);
fs::erase_fnmatches(patterns,srcmounts);
str::erase_fnmatches(patterns,srcmounts);
} }
return 0; return 0;
@ -166,60 +167,91 @@ _setxattr_srcmounts(vector<string> &srcmounts,
static static
int int
_setxattr_policy(const Policy *policies[],
const string &attrname,
_setxattr_controlfile_func_policy(const Policy *policies[],
const char *funcname,
const string &attrval, const string &attrval,
const int flags) const int flags)
{ {
const Category *cat;
const FuseFunc *fusefunc;
const Policy *policy; const Policy *policy;
cat = Category::find(attrname);
if(cat == Category::invalid)
fusefunc = FuseFunc::find(funcname);
if(fusefunc == FuseFunc::invalid)
return -ENOATTR; return -ENOATTR;
if((flags & XATTR_CREATE) == XATTR_CREATE) if((flags & XATTR_CREATE) == XATTR_CREATE)
return -EEXIST; return -EEXIST;
policy = Policy::find(attrval); policy = Policy::find(attrval);
if(policy == Policy::invalid)
if((policy == Policy::invalid) &&
(attrval != "invalid"))
return -EINVAL; return -EINVAL;
policies[*cat] = policy;
policies[(FuseFunc::Enum::Type)*fusefunc] = policy;
return 0; return 0;
} }
static static
int int
_setxattr_controlfile(config::Config &config,
const string &attrname,
_setxattr_controlfile_category_policy(config::Config &config,
const char *categoryname,
const string &attrval, const string &attrval,
const int flags) const int flags)
{ {
vector<string> nameparts;
const Category *category;
const Policy *policy;
category = Category::find(categoryname);
if(category == Category::invalid)
return -ENOATTR;
if((flags & XATTR_CREATE) == XATTR_CREATE)
return -EEXIST;
policy = Policy::find(attrval);
if((policy == Policy::invalid) &&
(attrval != "invalid"))
return -EINVAL;
config.setpolicy(*category,*policy);
return 0;
}
str::split(nameparts,attrname,'.');
static
int
_setxattr_controlfile(config::Config &config,
const char *attrname,
const string &attrval,
const int flags)
{
const char *attrbasename = &attrname[sizeof("user.mergerfs.")-1];
if(nameparts.size() != 3 ||
nameparts[0] != "user" ||
nameparts[1] != "mergerfs")
if(strncmp("user.mergerfs.",attrname,sizeof("user.mergerfs.")-1))
return -ENOATTR; return -ENOATTR;
if(attrval.empty()) if(attrval.empty())
return -EINVAL; return -EINVAL;
if(nameparts[2] == "srcmounts")
if(!strcmp("srcmounts",attrbasename))
return _setxattr_srcmounts(config.srcmounts, return _setxattr_srcmounts(config.srcmounts,
config.srcmountslock, config.srcmountslock,
config.destmount, config.destmount,
attrval, attrval,
flags); flags);
return _setxattr_policy(config.policies,
nameparts[2],
else if(!strncmp("category.",attrbasename,sizeof("category.")-1))
return _setxattr_controlfile_category_policy(config,
&attrbasename[sizeof("category.")-1],
attrval,
flags);
else if(!strncmp("func.",attrbasename,sizeof("func.")-1))
return _setxattr_controlfile_func_policy(config.policies,
&attrbasename[sizeof("func.")-1],
attrval, attrval,
flags); flags);
return -EINVAL;
} }
static static
@ -271,7 +303,7 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _setxattr(*config.search,
return _setxattr(*config.setxattr,
config.srcmounts, config.srcmounts,
fusepath, fusepath,
attrname, attrname,

28
src/str.cpp

@ -26,6 +26,8 @@
#include <vector> #include <vector>
#include <sstream> #include <sstream>
#include <fnmatch.h>
using std::string; using std::string;
using std::vector; using std::vector;
using std::istringstream; using std::istringstream;
@ -111,4 +113,30 @@ namespace str
return str::join(vec,idx,sep); return str::join(vec,idx,sep);
} }
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;
}
}
} }

4
src/str.hpp

@ -50,4 +50,8 @@ namespace str
std::string std::string
remove_common_prefix_and_join(const std::vector<std::string> &vec, remove_common_prefix_and_join(const std::vector<std::string> &vec,
const char sep); const char sep);
void
erase_fnmatches(const std::vector<std::string> &pattern,
std::vector<std::string> &strs);
} }

2
src/truncate.cpp

@ -71,7 +71,7 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _truncate(*config.search,
return _truncate(*config.truncate,
config.srcmounts, config.srcmounts,
fusepath, fusepath,
size); size);

2
src/unlink.cpp

@ -68,7 +68,7 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _unlink(*config.search,
return _unlink(*config.unlink,
config.srcmounts, config.srcmounts,
fusepath); fusepath);
} }

2
src/utimens.cpp

@ -71,7 +71,7 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _utimens(*config.search,
return _utimens(*config.utimens,
config.srcmounts, config.srcmounts,
fusepath, fusepath,
ts); ts);

Loading…
Cancel
Save