mirror of
https://github.com/trapexit/mergerfs.git
synced 2024-11-29 03:48:23 +08:00
parent
e0f0bb53f7
commit
12f393a55e
82
README.md
82
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 |
|
All [FUSE](http://fuse.sourceforge.net) functions which have a category (see below) are option keys. The syntax being `<func>=<policy>`.
|
||||||
|--------|--------|
|
|
||||||
| search | ff |
|
To set all function policies in a category use `category.<category>=<policy>` such as `category.create=mfs`.
|
||||||
| create | epmfs |
|
|
||||||
|
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.category.action
|
||||||
* user.mergerfs.search
|
* 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.category.action: ff
|
||||||
user.mergerfs.search: 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.search .mergerfs
|
[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 -w user.mergerfs.category.search ffwp .mergerfs
|
||||||
[trapexit:/tmp/mount] $ xattr -p user.mergerfs.search .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:
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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];
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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]),
|
POLICYINIT(access),
|
||||||
search(policies[Category::Enum::search]),
|
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;
|
setpolicy(Category::Enum::action,Policy::Enum::ff);
|
||||||
search = &Policy::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&
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
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
|
||||||
|
|
|
@ -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
Normal file
105
src/fusefunc.cpp
Normal file
|
@ -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
Normal file
139
src/fusefunc.hpp
Normal file
|
@ -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
|
|
@ -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);
|
||||||
|
|
|
@ -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")
|
if(strncmp("user.mergerfs.",attrname,sizeof("user.mergerfs.")-1))
|
||||||
attrvalue = (std::string)*config.create;
|
return -ENOATTR;
|
||||||
else if(attrname == "user.mergerfs.search")
|
|
||||||
attrvalue = (std::string)*config.search;
|
if(!strcmp("srcmounts",attrbasename))
|
||||||
else if(attrname == "user.mergerfs.srcmounts")
|
_getxattr_controlfile_srcmounts(config,attrvalue);
|
||||||
attrvalue = str::join(config.srcmounts,':');
|
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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -47,21 +47,24 @@ int
|
||||||
_listxattr_controlfile(char *list,
|
_listxattr_controlfile(char *list,
|
||||||
const size_t size)
|
const size_t size)
|
||||||
{
|
{
|
||||||
const char xattrs[] =
|
string xattrs;
|
||||||
"user.mergerfs.srcmounts\0"
|
|
||||||
"user.mergerfs.create\0"
|
xattrs.reserve(512);
|
||||||
"user.mergerfs.search"
|
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,
|
||||||
|
|
|
@ -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,
|
return _mkdir(*config.getattr,
|
||||||
*config.create,
|
*config.mkdir,
|
||||||
config.srcmounts,
|
config.srcmounts,
|
||||||
fusepath,
|
fusepath,
|
||||||
(mode & ~fc->umask));
|
(mode & ~fc->umask));
|
||||||
|
|
|
@ -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,
|
return _mknod(*config.getattr,
|
||||||
*config.create,
|
*config.mknod,
|
||||||
config.srcmounts,
|
config.srcmounts,
|
||||||
fusepath,
|
fusepath,
|
||||||
(mode & ~fc->umask),
|
(mode & ~fc->umask),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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]);
|
FuseFunc fusefunc = FuseFunc::find(argvalue[0]);
|
||||||
else if(argvalue[0] == "search")
|
if(fusefunc != FuseFunc::invalid)
|
||||||
config.search = Policy::find(argvalue[1]);
|
config.policies[(FuseFunc::Enum::Type)*fusefunc] = Policy::find(argvalue[1]);
|
||||||
else
|
else
|
||||||
rv = 1;
|
rv = 1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,26 +167,54 @@ _setxattr_srcmounts(vector<string> &srcmounts,
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
_setxattr_policy(const Policy *policies[],
|
_setxattr_controlfile_func_policy(const Policy *policies[],
|
||||||
const string &attrname,
|
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);
|
fusefunc = FuseFunc::find(funcname);
|
||||||
if(cat == Category::invalid)
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
_setxattr_controlfile_category_policy(config::Config &config,
|
||||||
|
const char *categoryname,
|
||||||
|
const string &attrval,
|
||||||
|
const int flags)
|
||||||
|
{
|
||||||
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -193,33 +222,36 @@ _setxattr_policy(const Policy *policies[],
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
_setxattr_controlfile(config::Config &config,
|
_setxattr_controlfile(config::Config &config,
|
||||||
const string &attrname,
|
const char *attrname,
|
||||||
const string &attrval,
|
const string &attrval,
|
||||||
const int flags)
|
const int flags)
|
||||||
{
|
{
|
||||||
vector<string> nameparts;
|
const char *attrbasename = &attrname[sizeof("user.mergerfs.")-1];
|
||||||
|
|
||||||
str::split(nameparts,attrname,'.');
|
if(strncmp("user.mergerfs.",attrname,sizeof("user.mergerfs.")-1))
|
||||||
|
|
||||||
if(nameparts.size() != 3 ||
|
|
||||||
nameparts[0] != "user" ||
|
|
||||||
nameparts[1] != "mergerfs")
|
|
||||||
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);
|
||||||
|
else if(!strncmp("category.",attrbasename,sizeof("category.")-1))
|
||||||
return _setxattr_policy(config.policies,
|
return _setxattr_controlfile_category_policy(config,
|
||||||
nameparts[2],
|
&attrbasename[sizeof("category.")-1],
|
||||||
attrval,
|
attrval,
|
||||||
flags);
|
flags);
|
||||||
|
else if(!strncmp("func.",attrbasename,sizeof("func.")-1))
|
||||||
|
return _setxattr_controlfile_func_policy(config.policies,
|
||||||
|
&attrbasename[sizeof("func.")-1],
|
||||||
|
attrval,
|
||||||
|
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
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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…
Reference in New Issue
Block a user