revert removal of 'all' policy and relevant behavior. closes #54

This commit is contained in:
Antonio SJ Musumeci 2015-02-24 18:47:31 -05:00
parent a359c88173
commit c022741ffb
28 changed files with 454 additions and 225 deletions

View File

@ -49,13 +49,41 @@ In /etc/fstab it'd look like the following:
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 ####
| Class | FUSE calls |
|-------|------------|
| action | chmod, chown, link, removexattr, rename, rmdir, setxattr, truncate, unlink, utimens |
| search | access, getattr, getxattr, listxattr, open, readlink, symlink |
| create | create, mkdir, mknod |
| N/A | fallocate, fgetattr, fsync, ftruncate, ioctl, read, readdir, statfs, symlink, write, release |
#### Functional classifications ####
| FUSE Function | Class |
|-------------|---------|
| access | search |
| chmod | action |
| chown | action |
| create | create |
| fallocate | N/A |
| fgetattr | N/A |
| fsync | N/A |
| ftruncate | N/A |
| getattr | search |
| getxattr | search |
| ioctl | N/A* |
| link | action |
| listxattr | search |
| mkdir | create |
| mknod | create |
| open | search |
| read | N/A |
| readdir | N/A |
| readlink | search |
| release | N/A |
| removexattr | action |
| rename | action |
| rmdir | action |
| setxattr | action |
| statfs | N/A |
| symlink | create |
| truncate | action |
| unlink | action |
| utimens | action |
| write | N/A |
`ioctl` behaves differently if its acting on a directory. It'll use the `getattr` policy to find and open the directory before issuing the `ioctl`. In other cases where something may be searched (to confirm a directory exists across all source mounts) then `getattr` will be used.
#### Policy descriptions ####
| Policy | Description |
@ -69,7 +97,7 @@ Filesystem calls are broken up into 3 categories: action, create, search. There
#### readdir ####
[readdir](http://linux.die.net/man/3/readdir) is very different from most functions in this realm. It certainly could have it's own set of policies to tweak its behavior. At this time it provides a simple `first found` merging of directories and file found. That is: only the first file or directory found for a directory is returned.
[readdir](http://linux.die.net/man/3/readdir) is very different from most functions in this realm. It certainly could have it's own set of policies to tweak its behavior. At this time it provides a simple `first found` merging of directories and file found. That is: only the first file or directory found for a directory is returned. Given how FUSE works though the data representing the returned entry comes from `getattr`.
It could be extended to offer the ability to see all files found. Perhaps concatinating `#` and a number to the name. But to really be useful you'd need to be able to access them which would complicate file lookup.
@ -133,29 +161,29 @@ Even if xattrs are disabled the [{list,get,set}xattrs](http://linux.die.net/man/
```
[trapexit:/tmp/mount] $ xattr -l .mergerfs
user.mergerfs.srcmounts: /tmp/a:/tmp/b
user.mergerfs.category.action: ff
user.mergerfs.category.action: all
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.chmod: all
user.mergerfs.func.chown: all
user.mergerfs.func.create: epmfs
user.mergerfs.func.getattr: ff
user.mergerfs.func.getxattr: ff
user.mergerfs.func.link: ff
user.mergerfs.func.link: all
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
user.mergerfs.func.removexattr: all
user.mergerfs.func.rename: all
user.mergerfs.func.rmdir: all
user.mergerfs.func.setxattr: all
user.mergerfs.func.symlink: epmfs
user.mergerfs.func.truncate: all
user.mergerfs.func.unlink: all
user.mergerfs.func.utimens: all
[trapexit:/tmp/mount] $ xattr -p user.mergerfs.category.search .mergerfs
ff

View File

@ -45,19 +45,19 @@ using mergerfs::Policy;
static
int
_access(const fs::SearchFunc searchFunc,
_access(const fs::find::Func searchFunc,
const vector<string> &srcmounts,
const string &fusepath,
const int mask)
{
int rv;
fs::Path path;
fs::Paths paths;
rv = searchFunc(srcmounts,fusepath,path);
rv = searchFunc(srcmounts,fusepath,paths,1);
if(rv == -1)
return -errno;
rv = ::eaccess(path.full.c_str(),mask);
rv = ::eaccess(paths[0].full.c_str(),mask);
return ((rv == -1) ? -errno : 0);
}

View File

@ -39,21 +39,29 @@ using mergerfs::Policy;
static
int
_chmod(const fs::SearchFunc searchFunc,
_chmod(const fs::find::Func actionFunc,
const vector<string> &srcmounts,
const string &fusepath,
const mode_t mode)
{
int rv;
fs::Path path;
int error;
fs::Paths paths;
rv = searchFunc(srcmounts,fusepath,path);
rv = actionFunc(srcmounts,fusepath,paths,-1);
if(rv == -1)
return -errno;
rv = ::chmod(path.full.c_str(),mode);
error = 0;
for(fs::Paths::const_iterator
i = paths.begin(), ei = paths.end(); i != ei; ++i)
{
rv = ::chmod(i->full.c_str(),mode);
if(rv == -1)
error = errno;
}
return ((rv == -1) ? -errno : 0);
return -error;
}
namespace mergerfs

View File

@ -40,22 +40,30 @@ using mergerfs::Policy;
static
int
_chown(const fs::SearchFunc searchFunc,
_chown(const fs::find::Func actionFunc,
const vector<string> &srcmounts,
const string &fusepath,
const uid_t uid,
const gid_t gid)
{
int rv;
fs::Path path;
int error;
fs::Paths paths;
rv = searchFunc(srcmounts,fusepath,path);
rv = actionFunc(srcmounts,fusepath,paths,-1);
if(rv == -1)
return -errno;
rv = ::lchown(path.full.c_str(),uid,gid);
error = 0;
for(fs::Paths::const_iterator
i = paths.begin(), ei = paths.end(); i != ei; ++i)
{
rv = ::lchown(i->full.c_str(),uid,gid);
if(rv == -1)
error = errno;
}
return ((rv == -1) ? -errno : 0);
return -error;
}
namespace mergerfs

View File

@ -69,7 +69,7 @@ namespace mergerfs
{
pthread_rwlock_init(&srcmountslock,NULL);
setpolicy(Category::Enum::action,Policy::Enum::ff);
setpolicy(Category::Enum::action,Policy::Enum::all);
setpolicy(Category::Enum::create,Policy::Enum::epmfs);
setpolicy(Category::Enum::search,Policy::Enum::ff);
}

View File

@ -45,8 +45,8 @@ using mergerfs::Policy;
static
int
_create(const fs::SearchFunc searchFunc,
const fs::SearchFunc createPathFunc,
_create(const fs::find::Func searchFunc,
const fs::find::Func createFunc,
const vector<string> &srcmounts,
const string &fusepath,
const mode_t mode,
@ -57,25 +57,25 @@ _create(const fs::SearchFunc searchFunc,
int rv;
string path;
string dirname;
fs::Path createpath;
fs::Path existingpath;
fs::Paths createpath;
fs::Paths existingpath;
dirname = fs::dirname(fusepath);
rv = searchFunc(srcmounts,dirname,existingpath);
rv = searchFunc(srcmounts,dirname,existingpath,1);
if(rv == -1)
return -errno;
rv = createPathFunc(srcmounts,dirname,createpath);
rv = createFunc(srcmounts,dirname,createpath,1);
if(rv == -1)
return -errno;
if(createpath.base != existingpath.base)
if(createpath[0].base != existingpath[0].base)
{
const mergerfs::ugid::SetResetGuard ugid(0,0);
fs::clonepath(existingpath.base,createpath.base,dirname);
fs::clonepath(existingpath[0].base,createpath[0].base,dirname);
}
path = fs::make_path(createpath.base,fusepath);
path = fs::make_path(createpath[0].base,fusepath);
fd = ::open(path.c_str(),flags,mode);
if(fd == -1)
@ -100,7 +100,7 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _create(*config.create,
return _create(*config.getattr,
*config.create,
config.srcmounts,
fusepath,

View File

@ -28,6 +28,7 @@
#include <sstream>
#include <cstdlib>
#include <iterator>
#include <algorithm>
#include <dirent.h>
#include <errno.h>
@ -519,7 +520,8 @@ namespace fs
int
invalid(const vector<string> &basepaths,
const string &fusepath,
Path &rv)
Paths &rv,
size_t count)
{
return (errno = EINVAL,-1);
}
@ -527,7 +529,8 @@ namespace fs
int
ff(const vector<string> &basepaths,
const string &fusepath,
Path &path)
Paths &paths,
size_t count)
{
errno = ENOENT;
for(vector<string>::const_iterator
@ -544,8 +547,7 @@ namespace fs
rv = ::lstat(fullpath.c_str(),&st);
if(rv == 0)
{
path.base = *iter;
path.full = fullpath;
paths.push_back(Path(*iter,fullpath));
return 0;
}
}
@ -556,7 +558,8 @@ namespace fs
int
ffwp(const vector<string> &basepaths,
const string &fusepath,
Path &path)
Paths &paths,
size_t count)
{
Path fallback;
@ -575,8 +578,7 @@ namespace fs
rv = ::lstat(fullpath.c_str(),&st);
if(rv == 0)
{
path.base = *iter;
path.full = fullpath;
paths.push_back(Path(*iter,fullpath));
return 0;
}
else if(errno == EACCES)
@ -587,7 +589,7 @@ namespace fs
}
if(!fallback.base.empty())
return (path = fallback,0);
return (paths.push_back(fallback),0);
return -1;
}
@ -595,7 +597,8 @@ namespace fs
int
newest(const vector<string> &basepaths,
const string &fusepath,
Path &path)
Paths &paths,
size_t count)
{
time_t newest;
string npath;
@ -624,11 +627,7 @@ namespace fs
}
if(newest)
{
path.base = *niter;
path.full = npath;
return 0;
}
return (paths.push_back(Path(*niter,npath)),0);
return -1;
}
@ -636,7 +635,8 @@ namespace fs
int
mfs(const vector<string> &basepaths,
const string &fusepath,
Path &path)
Paths &paths,
size_t count)
{
fsblkcnt_t mfs;
size_t mfsidx;
@ -666,8 +666,8 @@ namespace fs
if(mfs == 0)
return (errno=ENOENT,-1);
path.base = basepaths[mfsidx];
path.full = fs::make_path(path.base,fusepath);
paths.push_back(Path(basepaths[mfsidx],
fs::make_path(basepaths[mfsidx],fusepath)));
return 0;
}
@ -675,7 +675,8 @@ namespace fs
int
epmfs(const vector<string> &basepaths,
const string &fusepath,
Path &path)
Paths &paths,
size_t count)
{
fsblkcnt_t existingmfs = 0;
fsblkcnt_t generalmfs = 0;
@ -726,21 +727,56 @@ namespace fs
if(existingmfspath.empty())
existingmfspath = generalmfspath;
path.base = existingmfspath;
path.full = fullpath;
paths.push_back(Path(existingmfspath,
fullpath));
return 0;
}
int
all(const vector<string> &basepaths,
const string &fusepath,
Paths &paths,
size_t count)
{
int rv;
struct stat st;
string fullpath;
for(vector<string>::const_iterator
iter = basepaths.begin(), eiter = basepaths.end();
iter != eiter && count;
++iter)
{
fullpath = fs::make_path(*iter,fusepath);
rv = ::lstat(fullpath.c_str(),&st);
if(rv == 0)
{
paths.push_back(Path(*iter,fullpath));
count--;
}
}
return paths.empty() ? (errno=ENOENT,-1) : 0;
}
int
rand(const vector<string> &basepaths,
const string &fusepath,
Path &path)
Paths &paths,
size_t count)
{
path.base = *random_element(basepaths.begin(),
basepaths.end());
path.full = fs::make_path(path.base,
fusepath);
int rv;
rv = all(basepaths,fusepath,paths,-1);
if(rv == -1)
return -1;
std::random_shuffle(paths.begin(),paths.end());
if(paths.size() > count)
paths.resize(count);
return 0;
}

View File

@ -31,6 +31,7 @@
namespace fs
{
using std::size_t;
using std::string;
using std::vector;
using std::map;
@ -48,7 +49,7 @@ namespace fs
string full;
};
typedef int (*SearchFunc)(const vector<string>&,const string&,Path&);
typedef vector<Path> Paths;
string dirname(const string &path);
string basename(const string &path);
@ -112,27 +113,40 @@ namespace fs
namespace find
{
typedef int (*Func)(const vector<string>&,const string&,Paths&,size_t);
int invalid(const vector<string> &basepaths,
const string &fusepath,
Path &path);
Paths &path,
size_t max);
int all(const vector<string> &basepaths,
const string &fusepath,
Paths &path,
size_t max);
int ff(const vector<string> &basepaths,
const string &fusepath,
Path &path);
Paths &path,
size_t max);
int ffwp(const vector<string> &paths,
const string &fusepath,
Path &path);
Paths &path,
size_t max);
int newest(const vector<string> &paths,
const string &fusepath,
Path &path);
Paths &path,
size_t max);
int mfs(const vector<string> &paths,
const string &fusepath,
Path &path);
Paths &path,
size_t max);
int epmfs(const vector<string> &paths,
const string &fusepath,
Path &path);
Paths &path,
size_t max);
int rand(const vector<string> &paths,
const string &fusepath,
Path &path);
Paths &path,
size_t max);
}
};

View File

@ -52,7 +52,7 @@ namespace mergerfs
(FUSEFUNC(rename,action))
(FUSEFUNC(rmdir,action))
(FUSEFUNC(setxattr,action))
(FUSEFUNC(symlink,search))
(FUSEFUNC(symlink,create))
(FUSEFUNC(truncate,action))
(FUSEFUNC(unlink,action))
(FUSEFUNC(utimens,action))

View File

@ -65,19 +65,19 @@ _getattr_controlfile(struct stat &buf)
static
int
_getattr(const fs::SearchFunc searchFunc,
_getattr(const fs::find::Func searchFunc,
const vector<string> &srcmounts,
const string &fusepath,
struct stat &buf)
{
int rv;
fs::Path path;
fs::Paths path;
rv = searchFunc(srcmounts,fusepath,path);
rv = searchFunc(srcmounts,fusepath,path,1);
if(rv == -1)
return -errno;
rv = ::lstat(path.full.c_str(),&buf);
rv = ::lstat(path[0].full.c_str(),&buf);
return ((rv == -1) ? -errno : 0);
}

View File

@ -190,7 +190,7 @@ _getxattr_user_mergerfs(const fs::Path &path,
static
int
_getxattr(const fs::SearchFunc searchFunc,
_getxattr(const fs::find::Func searchFunc,
const vector<string> &srcmounts,
const string &fusepath,
const char *attrname,
@ -199,17 +199,17 @@ _getxattr(const fs::SearchFunc searchFunc,
{
#ifndef WITHOUT_XATTR
int rv;
fs::Path path;
fs::Paths path;
rv = searchFunc(srcmounts,fusepath,path);
rv = searchFunc(srcmounts,fusepath,path,1);
if(rv == -1)
return -errno;
if(!strncmp("user.mergerfs.",attrname,sizeof("user.mergerfs.")-1))
rv = _getxattr_user_mergerfs(path,srcmounts,fusepath,attrname,buf,count);
rv = _getxattr_user_mergerfs(path[0],srcmounts,fusepath,attrname,buf,count);
if(rv == -1 && errno == ENOATTR)
rv = ::lgetxattr(path.full.c_str(),attrname,buf,count);
rv = ::lgetxattr(path[0].full.c_str(),attrname,buf,count);
return ((rv == -1) ? -errno : rv);
#else

View File

@ -83,7 +83,7 @@ _ioctl(const int fd,
#ifdef FUSE_IOCTL_DIR
static
int
_ioctl_dir_base(const fs::SearchFunc searchFunc,
_ioctl_dir_base(const fs::find::Func searchFunc,
const vector<string> &srcmounts,
const string &fusepath,
const int cmd,
@ -93,13 +93,13 @@ _ioctl_dir_base(const fs::SearchFunc searchFunc,
{
int fd;
int rv;
fs::Path path;
fs::Paths path;
rv = searchFunc(srcmounts,fusepath,path);
rv = searchFunc(srcmounts,fusepath,path,1);
if(rv == -1)
return -errno;
fd = ::open(path.full.c_str(),flags);
fd = ::open(path[0].full.c_str(),flags);
if(fd == -1)
return -errno;

View File

@ -41,41 +41,64 @@ using mergerfs::Policy;
static
int
_link(const fs::SearchFunc searchFunc,
const vector<string> &srcmounts,
const string &from,
const string &to)
_single_link(const fs::find::Func searchFunc,
const vector<string> &srcmounts,
const string &base,
const string &oldpath,
const string &newpath)
{
int rv;
fs::Path path;
const string fulloldpath = fs::make_path(base,oldpath);
const string fullnewpath = fs::make_path(base,newpath);
rv = searchFunc(srcmounts,from,path);
if(rv == -1)
return -errno;
const string pathfrom = fs::make_path(path.base,from);
const string pathto = fs::make_path(path.base,to);
rv = ::link(pathfrom.c_str(),pathto.c_str());
rv = ::link(fulloldpath.c_str(),fullnewpath.c_str());
if(rv == -1 && errno == ENOENT)
{
string todir;
fs::Path foundpath;
string newpathdir;
fs::Paths foundpath;
todir = fs::dirname(to);
rv = fs::find::ffwp(srcmounts,todir,foundpath);
newpathdir = fs::dirname(newpath);
rv = searchFunc(srcmounts,newpathdir,foundpath,1);
if(rv == -1)
return -errno;
return -1;
{
const mergerfs::ugid::SetResetGuard ugid(0,0);
fs::clonepath(foundpath.base,path.base,todir);
fs::clonepath(foundpath[0].base,base,newpathdir);
}
rv = ::link(pathfrom.c_str(),pathto.c_str());
rv = ::link(fulloldpath.c_str(),fullnewpath.c_str());
}
return ((rv == -1) ? -errno : 0);
return rv;
}
static
int
_link(const fs::find::Func searchFunc,
const fs::find::Func actionFunc,
const vector<string> &srcmounts,
const string &oldpath,
const string &newpath)
{
int rv;
int error;
fs::Paths oldpaths;
rv = actionFunc(srcmounts,oldpath,oldpaths,-1);
if(rv == -1)
return -errno;
error = 0;
for(fs::Paths::const_iterator
i = oldpaths.begin(), ei = oldpaths.end(); i != ei; ++i)
{
rv = _single_link(searchFunc,srcmounts,i->base,oldpath,newpath);
if(rv == -1)
error = errno;
}
return -error;
}
namespace mergerfs
@ -91,7 +114,8 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _link(*config.link,
return _link(*config.getattr,
*config.link,
config.srcmounts,
from,
to);

View File

@ -69,7 +69,7 @@ _listxattr_controlfile(char *list,
static
int
_listxattr(const fs::SearchFunc searchFunc,
_listxattr(const fs::find::Func searchFunc,
const vector<string> &srcmounts,
const string &fusepath,
char *list,
@ -77,13 +77,13 @@ _listxattr(const fs::SearchFunc searchFunc,
{
#ifndef WITHOUT_XATTR
int rv;
fs::Path path;
fs::Paths path;
rv = searchFunc(srcmounts,fusepath,path);
rv = searchFunc(srcmounts,fusepath,path,1);
if(rv == -1)
return -errno;
rv = ::llistxattr(path.full.c_str(),list,size);
rv = ::llistxattr(path[0].full.c_str(),list,size);
return ((rv == -1) ? -errno : rv);
#else

View File

@ -42,41 +42,46 @@ using std::vector;
static
int
_mkdir(const fs::SearchFunc searchFunc,
const fs::SearchFunc createPathFunc,
_mkdir(const fs::find::Func searchFunc,
const fs::find::Func createFunc,
const vector<string> &srcmounts,
const string &fusepath,
const mode_t mode)
{
int rv;
string path;
int error;
string dirname;
fs::Path createpath;
fs::Path existingpath;
if(fs::path_exists(srcmounts,fusepath))
return -EEXIST;
string fullpath;
fs::Paths createpaths;
fs::Paths existingpath;
dirname = fs::dirname(fusepath);
rv = searchFunc(srcmounts,dirname,existingpath);
rv = searchFunc(srcmounts,dirname,existingpath,1);
if(rv == -1)
return -errno;
rv = createPathFunc(srcmounts,dirname,createpath);
rv = createFunc(srcmounts,dirname,createpaths,-1);
if(rv == -1)
return -errno;
if(createpath.base != existingpath.base)
error = 0;
for(fs::Paths::const_iterator
i = createpaths.begin(), ei = createpaths.end(); i != ei; ++i)
{
const mergerfs::ugid::SetResetGuard ugid(0,0);
fs::clonepath(existingpath.base,createpath.base,dirname);
if(i->base != existingpath[0].base)
{
const mergerfs::ugid::SetResetGuard ugid(0,0);
fs::clonepath(existingpath[0].base,i->base,dirname);
}
fullpath = fs::make_path(i->base,fusepath);
rv = ::mkdir(fullpath.c_str(),mode);
if(rv == -1)
error = errno;
}
path = fs::make_path(createpath.base,fusepath);
rv = ::mkdir(path.c_str(),mode);
return ((rv == -1) ? -errno : 0);
return -error;
}
namespace mergerfs

View File

@ -43,42 +43,47 @@ using std::vector;
static
int
_mknod(const fs::SearchFunc searchFunc,
const fs::SearchFunc createPathFunc,
_mknod(const fs::find::Func searchFunc,
const fs::find::Func createFunc,
const vector<string> &srcmounts,
const string &fusepath,
const mode_t mode,
const dev_t dev)
{
int rv;
string path;
int error;
string dirname;
fs::Path createpath;
fs::Path existingpath;
if(fs::path_exists(srcmounts,fusepath))
return -EEXIST;
string fullpath;
fs::Paths createpaths;
fs::Paths existingpath;
dirname = fs::dirname(fusepath);
rv = searchFunc(srcmounts,dirname,existingpath);
rv = searchFunc(srcmounts,dirname,existingpath,1);
if(rv == -1)
return -errno;
rv = createPathFunc(srcmounts,dirname,createpath);
rv = createFunc(srcmounts,dirname,createpaths,-1);
if(rv == -1)
return -errno;
if(existingpath.base != createpath.base)
error = 0;
for(fs::Paths::const_iterator
i = createpaths.begin(), ei = createpaths.end(); i != ei; ++i)
{
const mergerfs::ugid::SetResetGuard ugid(0,0);
fs::clonepath(existingpath.base,createpath.base,dirname);
if(i->base != existingpath[0].base)
{
const mergerfs::ugid::SetResetGuard ugid(0,0);
fs::clonepath(existingpath[0].base,i->base,dirname);
}
fullpath = fs::make_path(i->base,fusepath);
rv = ::mknod(fullpath.c_str(),mode,dev);
if(rv == -1)
error = errno;
}
path = fs::make_path(createpath.base,fusepath);
rv = ::mknod(path.c_str(),mode,dev);
return ((rv == -1) ? -errno : 0);
return -error;
}
namespace mergerfs

View File

@ -43,7 +43,7 @@ using mergerfs::FileInfo;
static
int
_open(const fs::SearchFunc searchFunc,
_open(const fs::find::Func searchFunc,
const vector<string> &srcmounts,
const string &fusepath,
const int flags,
@ -51,17 +51,17 @@ _open(const fs::SearchFunc searchFunc,
{
int fd;
int rv;
fs::Path path;
fs::Paths path;
rv = searchFunc(srcmounts,fusepath,path);
rv = searchFunc(srcmounts,fusepath,path,1);
if(rv == -1)
return -errno;
fd = ::open(path.full.c_str(),flags);
fd = ::open(path[0].full.c_str(),flags);
if(fd == -1)
return -errno;
fh = (uint64_t)new FileInfo(fd,flags,path.full);
fh = (uint64_t)new FileInfo(fd,flags,path[0].full);
return 0;
}

View File

@ -35,6 +35,7 @@ namespace mergerfs
const std::vector<Policy> Policy::_policies_ =
buildvector<Policy,true>
(POLICY(invalid))
(POLICY(all))
(POLICY(epmfs))
(POLICY(ff))
(POLICY(ffwp))
@ -45,6 +46,7 @@ namespace mergerfs
const Policy * const Policy::policies = &_policies_[1];
const Policy &Policy::invalid = Policy::policies[Policy::Enum::invalid];
const Policy &Policy::all = Policy::policies[Policy::Enum::all];
const Policy &Policy::epmfs = Policy::policies[Policy::Enum::epmfs];
const Policy &Policy::ff = Policy::policies[Policy::Enum::ff];
const Policy &Policy::ffwp = Policy::policies[Policy::Enum::ffwp];

View File

@ -41,7 +41,8 @@ namespace mergerfs
{
invalid = -1,
BEGIN = 0,
epmfs = BEGIN,
all = BEGIN,
epmfs,
ff,
ffwp,
mfs,
@ -54,7 +55,7 @@ namespace mergerfs
private:
Enum::Type _enum;
std::string _str;
fs::SearchFunc _func;
fs::find::Func _func;
public:
Policy()
@ -66,7 +67,7 @@ namespace mergerfs
Policy(const Enum::Type enum_,
const std::string &str_,
const fs::SearchFunc func_)
const fs::find::Func func_)
: _enum(enum_),
_str(str_),
_func(func_)
@ -76,14 +77,14 @@ namespace mergerfs
public:
operator const Enum::Type() const { return _enum; }
operator const std::string&() const { return _str; }
operator const fs::SearchFunc() const { return _func; }
operator const fs::find::Func() const { return _func; }
operator const Policy*() const { return this; }
bool operator==(const Enum::Type enum_) const
{ return _enum == enum_; }
bool operator==(const std::string &str_) const
{ return _str == str_; }
bool operator==(const fs::SearchFunc func_) const
bool operator==(const fs::find::Func func_) const
{ return _func == func_; }
bool operator!=(const Policy &r) const
@ -100,6 +101,7 @@ namespace mergerfs
static const std::vector<Policy> _policies_;
static const Policy * const policies;
static const Policy &invalid;
static const Policy &all;
static const Policy &epmfs;
static const Policy &ff;
static const Policy &ffwp;

View File

@ -41,20 +41,20 @@ using mergerfs::Policy;
static
int
_readlink(const fs::SearchFunc searchFunc,
_readlink(const fs::find::Func searchFunc,
const vector<string> &srcmounts,
const string &fusepath,
char *buf,
const size_t size)
{
int rv;
fs::Path path;
fs::Paths path;
rv = searchFunc(srcmounts,fusepath,path);
rv = searchFunc(srcmounts,fusepath,path,1);
if(rv == -1)
return -errno;
rv = ::readlink(path.full.c_str(),buf,size);
rv = ::readlink(path[0].full.c_str(),buf,size);
if(rv == -1)
return -errno;

View File

@ -41,22 +41,30 @@ using std::vector;
static
int
_removexattr(const fs::SearchFunc searchFunc,
_removexattr(const fs::find::Func actionFunc,
const vector<string> &srcmounts,
const string &fusepath,
const char *attrname)
{
#ifndef WITHOUT_XATTR
int rv;
fs::Path path;
int error;
fs::Paths paths;
rv = searchFunc(srcmounts,fusepath,path);
rv = actionFunc(srcmounts,fusepath,paths,-1);
if(rv == -1)
return -errno;
rv = ::lremovexattr(path.full.c_str(),attrname);
error = 0;
for(fs::Paths::const_iterator
i = paths.begin(), ei = paths.end(); i != ei; ++i)
{
rv = ::lremovexattr(i->full.c_str(),attrname);
if(rv == -1)
error = errno;
}
return ((rv == -1) ? -errno : 0);
return -error;
#else
return -ENOTSUP;
#endif

View File

@ -41,26 +41,62 @@ using std::vector;
static
int
_rename(const fs::SearchFunc searchFunc,
const vector<string> &srcmounts,
const string &from,
const string &to)
_single_rename(const fs::find::Func searchFunc,
const vector<string> &srcmounts,
const fs::Path &oldpath,
const string &newpath)
{
int rv;
string pathto;
fs::Path pathfrom;
const string fullnewpath = fs::make_path(oldpath.base,newpath);
rv = searchFunc(srcmounts,from,pathfrom);
rv = ::rename(oldpath.full.c_str(),fullnewpath.c_str());
if(rv == -1 && errno == ENOENT)
{
string dirname;
fs::Paths newpathdir;
dirname = fs::dirname(newpath);
rv = searchFunc(srcmounts,dirname,newpathdir,1);
if(rv == -1)
return -1;
{
const mergerfs::ugid::SetResetGuard ugid(0,0);
fs::clonepath(newpathdir[0].base,oldpath.base,dirname);
}
rv = ::rename(oldpath.full.c_str(),fullnewpath.c_str());
}
return rv;
}
static
int
_rename(const fs::find::Func searchFunc,
const fs::find::Func actionFunc,
const vector<string> &srcmounts,
const string &oldpath,
const string &newpath)
{
int rv;
int error;
fs::Paths oldpaths;
rv = actionFunc(srcmounts,oldpath,oldpaths,-1);
if(rv == -1)
return -errno;
pathto = fs::make_path(pathfrom.base,to);
error = 0;
for(fs::Paths::const_iterator
i = oldpaths.begin(), ei = oldpaths.end(); i != ei; ++i)
{
rv = _single_rename(searchFunc,srcmounts,*i,newpath);
if(rv == -1)
error = errno;
}
rv = ::rename(pathfrom.full.c_str(),pathto.c_str());
if(rv == -1 && errno == ENOENT)
return -EXDEV;
return ((rv == -1) ? -errno : 0);
return -error;
}
namespace mergerfs
@ -68,18 +104,19 @@ namespace mergerfs
namespace rename
{
int
rename(const char *from,
const char *to)
rename(const char *oldpath,
const char *newpath)
{
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.rename,
return _rename(*config.getattr,
*config.rename,
config.srcmounts,
from,
to);
oldpath,
newpath);
}
}
}

View File

@ -40,20 +40,28 @@ using mergerfs::Policy;
static
int
_rmdir(const fs::SearchFunc searchFunc,
_rmdir(const fs::find::Func actionFunc,
const vector<string> &srcmounts,
const string &fusepath)
{
int rv;
fs::Path path;
int error;
fs::Paths paths;
rv = searchFunc(srcmounts,fusepath,path);
rv = actionFunc(srcmounts,fusepath,paths,-1);
if(rv == -1)
return -errno;
rv = ::rmdir(path.full.c_str());
error = 0;
for(fs::Paths::const_iterator
i = paths.begin(), ei = paths.end(); i != ei; ++i)
{
rv = ::rmdir(i->full.c_str());
if(rv == -1)
error = errno;
}
return ((rv == -1) ? -errno : 0);
return -error;
}
namespace mergerfs

View File

@ -256,7 +256,7 @@ _setxattr_controlfile(config::Config &config,
static
int
_setxattr(const fs::SearchFunc searchFunc,
_setxattr(const fs::find::Func actionFunc,
const vector<string> &srcmounts,
const string &fusepath,
const char *attrname,
@ -266,15 +266,23 @@ _setxattr(const fs::SearchFunc searchFunc,
{
#ifndef WITHOUT_XATTR
int rv;
fs::Path path;
int error;
fs::Paths paths;
rv = searchFunc(srcmounts,fusepath,path);
rv = actionFunc(srcmounts,fusepath,paths,-1);
if(rv == -1)
return -errno;
rv = ::lsetxattr(path.full.c_str(),attrname,attrval,attrvalsize,flags);
error = 0;
for(fs::Paths::const_iterator
i = paths.begin(), ei = paths.end(); i != ei; ++i)
{
rv = ::lsetxattr(i->full.c_str(),attrname,attrval,attrvalsize,flags);
if(rv == -1)
error = errno;
}
return ((rv == -1) ? -errno : 0);
return -error;
#else
return -ENOTSUP;
#endif

View File

@ -39,22 +39,33 @@ using std::vector;
static
int
_symlink(const vector<string> &srcmounts,
const string &from,
const string &to)
_symlink(const fs::find::Func createFunc,
const vector<string> &srcmounts,
const string &oldpath,
const string &newpath)
{
int rv;
fs::Path path;
int error;
string newpathdir;
fs::Paths newpathdirs;
rv = fs::find::ff(srcmounts,fs::dirname(to),path);
newpathdir = fs::dirname(newpath);
rv = createFunc(srcmounts,newpathdir,newpathdirs,-1);
if(rv == -1)
return -errno;
path.full = fs::make_path(path.base,to);
error = 0;
for(fs::Paths::iterator
i = newpathdirs.begin(), ei = newpathdirs.end(); i != ei; ++i)
{
i->full = fs::make_path(i->base,newpath);
rv = symlink(from.c_str(),path.full.c_str());
rv = symlink(oldpath.c_str(),i->full.c_str());
if(rv == -1)
error = errno;
}
return ((rv == -1) ? -errno : 0);
return -error;
}
namespace mergerfs
@ -70,7 +81,8 @@ namespace mergerfs
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _symlink(config.srcmounts,
return _symlink(*config.symlink,
config.srcmounts,
oldpath,
newpath);
}

View File

@ -41,21 +41,29 @@ using std::vector;
static
int
_truncate(const fs::SearchFunc searchFunc,
_truncate(const fs::find::Func actionFunc,
const vector<string> &srcmounts,
const string &fusepath,
const off_t size)
{
int rv;
fs::Path path;
int error;
fs::Paths paths;
rv = searchFunc(srcmounts,fusepath,path);
rv = actionFunc(srcmounts,fusepath,paths,-1);
if(rv == -1)
return -errno;
rv = ::truncate(path.full.c_str(),size);
error = 0;
for(fs::Paths::const_iterator
i = paths.begin(), ei = paths.end(); i != ei; ++i)
{
rv = ::truncate(i->full.c_str(),size);
if(rv == -1)
error = errno;
}
return ((rv == -1) ? -errno : 0);
return -error;
}
namespace mergerfs

View File

@ -40,20 +40,28 @@ using std::vector;
static
int
_unlink(const fs::SearchFunc searchFunc,
_unlink(const fs::find::Func actionFunc,
const vector<string> &srcmounts,
const string &fusepath)
{
int rv;
fs::Path path;
int error;
fs::Paths paths;
rv = searchFunc(srcmounts,fusepath,path);
rv = actionFunc(srcmounts,fusepath,paths,-1);
if(rv == -1)
return -errno;
rv = ::unlink(path.full.c_str());
error = 0;
for(fs::Paths::const_iterator
i = paths.begin(), ei = paths.end(); i != ei; ++i)
{
rv = ::unlink(i->full.c_str());
if(rv == -1)
error = errno;
}
return ((rv == -1) ? -errno : 0);
return -error;
}
namespace mergerfs

View File

@ -41,21 +41,29 @@ using std::vector;
static
int
_utimens(const fs::SearchFunc searchFunc,
_utimens(const fs::find::Func actionFunc,
const vector<string> &srcmounts,
const string &fusepath,
const struct timespec ts[2])
{
int rv;
fs::Path path;
int error;
fs::Paths paths;
rv = searchFunc(srcmounts,fusepath,path);
rv = actionFunc(srcmounts,fusepath,paths,-1);
if(rv == -1)
return -errno;
rv = ::utimensat(0,path.full.c_str(),ts,AT_SYMLINK_NOFOLLOW);
error = 0;
for(fs::Paths::const_iterator
i = paths.begin(), ei = paths.end(); i != ei; ++i)
{
rv = ::utimensat(0,i->full.c_str(),ts,AT_SYMLINK_NOFOLLOW);
if(rv == -1)
error = errno;
}
return ((rv == -1) ? -errno : 0);
return -error;
}
namespace mergerfs