Browse Source

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

pull/56/head
Antonio SJ Musumeci 10 years ago
parent
commit
c022741ffb
  1. 66
      README.md
  2. 8
      src/access.cpp
  3. 18
      src/chmod.cpp
  4. 18
      src/chown.cpp
  5. 2
      src/config.cpp
  6. 20
      src/create.cpp
  7. 86
      src/fs.cpp
  8. 30
      src/fs.hpp
  9. 2
      src/fusefunc.cpp
  10. 8
      src/getattr.cpp
  11. 10
      src/getxattr.cpp
  12. 8
      src/ioctl.cpp
  13. 66
      src/link.cpp
  14. 8
      src/listxattr.cpp
  15. 35
      src/mkdir.cpp
  16. 35
      src/mknod.cpp
  17. 10
      src/open.cpp
  18. 2
      src/policy.cpp
  19. 12
      src/policy.hpp
  20. 8
      src/readlink.cpp
  21. 18
      src/removexattr.cpp
  22. 71
      src/rename.cpp
  23. 18
      src/rmdir.cpp
  24. 18
      src/setxattr.cpp
  25. 30
      src/symlink.cpp
  26. 18
      src/truncate.cpp
  27. 18
      src/unlink.cpp
  28. 18
      src/utimens.cpp

66
README.md

@ -50,12 +50,40 @@ 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**. 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 |
|-------|------------|
| 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 |
| 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 descriptions ####
| Policy | Description | | Policy | Description |
@ -69,7 +97,7 @@ Filesystem calls are broken up into 3 categories: action, create, search. There
#### readdir #### #### 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. 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 [trapexit:/tmp/mount] $ xattr -l .mergerfs
user.mergerfs.srcmounts: /tmp/a:/tmp/b 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.create: epmfs
user.mergerfs.category.search: ff user.mergerfs.category.search: ff
user.mergerfs.func.access: 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.create: epmfs
user.mergerfs.func.getattr: ff user.mergerfs.func.getattr: ff
user.mergerfs.func.getxattr: ff user.mergerfs.func.getxattr: ff
user.mergerfs.func.link: ff
user.mergerfs.func.link: all
user.mergerfs.func.listxattr: ff user.mergerfs.func.listxattr: ff
user.mergerfs.func.mkdir: epmfs user.mergerfs.func.mkdir: epmfs
user.mergerfs.func.mknod: epmfs user.mergerfs.func.mknod: epmfs
user.mergerfs.func.open: ff user.mergerfs.func.open: ff
user.mergerfs.func.readlink: 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 [trapexit:/tmp/mount] $ xattr -p user.mergerfs.category.search .mergerfs
ff ff

8
src/access.cpp

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

18
src/chmod.cpp

@ -39,21 +39,29 @@ using mergerfs::Policy;
static static
int int
_chmod(const fs::SearchFunc searchFunc,
_chmod(const fs::find::Func actionFunc,
const vector<string> &srcmounts, const vector<string> &srcmounts,
const string &fusepath, const string &fusepath,
const mode_t mode) const mode_t mode)
{ {
int rv; int rv;
fs::Path path;
int error;
fs::Paths paths;
rv = searchFunc(srcmounts,fusepath,path);
rv = actionFunc(srcmounts,fusepath,paths,-1);
if(rv == -1) if(rv == -1)
return -errno; 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 namespace mergerfs

18
src/chown.cpp

@ -40,22 +40,30 @@ using mergerfs::Policy;
static static
int int
_chown(const fs::SearchFunc searchFunc,
_chown(const fs::find::Func actionFunc,
const vector<string> &srcmounts, const vector<string> &srcmounts,
const string &fusepath, const string &fusepath,
const uid_t uid, const uid_t uid,
const gid_t gid) const gid_t gid)
{ {
int rv; int rv;
fs::Path path;
int error;
fs::Paths paths;
rv = searchFunc(srcmounts,fusepath,path);
rv = actionFunc(srcmounts,fusepath,paths,-1);
if(rv == -1) if(rv == -1)
return -errno; 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 namespace mergerfs

2
src/config.cpp

@ -69,7 +69,7 @@ namespace mergerfs
{ {
pthread_rwlock_init(&srcmountslock,NULL); 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::create,Policy::Enum::epmfs);
setpolicy(Category::Enum::search,Policy::Enum::ff); setpolicy(Category::Enum::search,Policy::Enum::ff);
} }

20
src/create.cpp

@ -45,8 +45,8 @@ using mergerfs::Policy;
static static
int 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 vector<string> &srcmounts,
const string &fusepath, const string &fusepath,
const mode_t mode, const mode_t mode,
@ -57,25 +57,25 @@ _create(const fs::SearchFunc searchFunc,
int rv; int rv;
string path; string path;
string dirname; string dirname;
fs::Path createpath;
fs::Path existingpath;
fs::Paths createpath;
fs::Paths existingpath;
dirname = fs::dirname(fusepath); dirname = fs::dirname(fusepath);
rv = searchFunc(srcmounts,dirname,existingpath);
rv = searchFunc(srcmounts,dirname,existingpath,1);
if(rv == -1) if(rv == -1)
return -errno; return -errno;
rv = createPathFunc(srcmounts,dirname,createpath);
rv = createFunc(srcmounts,dirname,createpath,1);
if(rv == -1) if(rv == -1)
return -errno; return -errno;
if(createpath.base != existingpath.base)
if(createpath[0].base != existingpath[0].base)
{ {
const mergerfs::ugid::SetResetGuard ugid(0,0); 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); fd = ::open(path.c_str(),flags,mode);
if(fd == -1) if(fd == -1)
@ -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.create,
return _create(*config.getattr,
*config.create, *config.create,
config.srcmounts, config.srcmounts,
fusepath, fusepath,

86
src/fs.cpp

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

30
src/fs.hpp

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

2
src/fusefunc.cpp

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

8
src/getattr.cpp

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

10
src/getxattr.cpp

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

8
src/ioctl.cpp

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

66
src/link.cpp

@ -41,41 +41,64 @@ using mergerfs::Policy;
static static
int int
_link(const fs::SearchFunc searchFunc,
_single_link(const fs::find::Func searchFunc,
const vector<string> &srcmounts, const vector<string> &srcmounts,
const string &from,
const string &to)
const string &base,
const string &oldpath,
const string &newpath)
{ {
int rv; 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) 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) if(rv == -1)
return -errno;
return -1;
{ {
const mergerfs::ugid::SetResetGuard ugid(0,0); 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;
}
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 ((rv == -1) ? -errno : 0);
return -error;
} }
namespace mergerfs namespace mergerfs
@ -91,7 +114,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 _link(*config.link,
return _link(*config.getattr,
*config.link,
config.srcmounts, config.srcmounts,
from, from,
to); to);

8
src/listxattr.cpp

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

35
src/mkdir.cpp

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

35
src/mknod.cpp

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

10
src/open.cpp

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

2
src/policy.cpp

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

12
src/policy.hpp

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

8
src/readlink.cpp

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

18
src/removexattr.cpp

@ -41,22 +41,30 @@ using std::vector;
static static
int int
_removexattr(const fs::SearchFunc searchFunc,
_removexattr(const fs::find::Func actionFunc,
const vector<string> &srcmounts, const vector<string> &srcmounts,
const string &fusepath, const string &fusepath,
const char *attrname) const char *attrname)
{ {
#ifndef WITHOUT_XATTR #ifndef WITHOUT_XATTR
int rv; int rv;
fs::Path path;
int error;
fs::Paths paths;
rv = searchFunc(srcmounts,fusepath,path);
rv = actionFunc(srcmounts,fusepath,paths,-1);
if(rv == -1) if(rv == -1)
return -errno; 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 #else
return -ENOTSUP; return -ENOTSUP;
#endif #endif

71
src/rename.cpp

@ -41,26 +41,62 @@ using std::vector;
static static
int int
_rename(const fs::SearchFunc searchFunc,
_single_rename(const fs::find::Func searchFunc,
const vector<string> &srcmounts, const vector<string> &srcmounts,
const string &from,
const string &to)
const fs::Path &oldpath,
const string &newpath)
{ {
int rv; 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) if(rv == -1)
return -errno;
return -1;
{
const mergerfs::ugid::SetResetGuard ugid(0,0);
fs::clonepath(newpathdir[0].base,oldpath.base,dirname);
}
pathto = fs::make_path(pathfrom.base,to);
rv = ::rename(oldpath.full.c_str(),fullnewpath.c_str());
}
rv = ::rename(pathfrom.full.c_str(),pathto.c_str());
if(rv == -1 && errno == ENOENT)
return -EXDEV;
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;
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;
}
return ((rv == -1) ? -errno : 0);
return -error;
} }
namespace mergerfs namespace mergerfs
@ -68,18 +104,19 @@ namespace mergerfs
namespace rename namespace rename
{ {
int int
rename(const char *from,
const char *to)
rename(const char *oldpath,
const char *newpath)
{ {
const struct fuse_context *fc = fuse_get_context(); const struct fuse_context *fc = fuse_get_context();
const config::Config &config = config::get(); const config::Config &config = config::get();
const ugid::SetResetGuard ugid(fc->uid,fc->gid); const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock); const rwlock::ReadGuard readlock(&config.srcmountslock);
return _rename(*config.rename,
return _rename(*config.getattr,
*config.rename,
config.srcmounts, config.srcmounts,
from,
to);
oldpath,
newpath);
} }
} }
} }

18
src/rmdir.cpp

@ -40,20 +40,28 @@ using mergerfs::Policy;
static static
int int
_rmdir(const fs::SearchFunc searchFunc,
_rmdir(const fs::find::Func actionFunc,
const vector<string> &srcmounts, const vector<string> &srcmounts,
const string &fusepath) const string &fusepath)
{ {
int rv; int rv;
fs::Path path;
int error;
fs::Paths paths;
rv = searchFunc(srcmounts,fusepath,path);
rv = actionFunc(srcmounts,fusepath,paths,-1);
if(rv == -1) if(rv == -1)
return -errno; 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 namespace mergerfs

18
src/setxattr.cpp

@ -256,7 +256,7 @@ _setxattr_controlfile(config::Config &config,
static static
int int
_setxattr(const fs::SearchFunc searchFunc,
_setxattr(const fs::find::Func actionFunc,
const vector<string> &srcmounts, const vector<string> &srcmounts,
const string &fusepath, const string &fusepath,
const char *attrname, const char *attrname,
@ -266,15 +266,23 @@ _setxattr(const fs::SearchFunc searchFunc,
{ {
#ifndef WITHOUT_XATTR #ifndef WITHOUT_XATTR
int rv; int rv;
fs::Path path;
int error;
fs::Paths paths;
rv = searchFunc(srcmounts,fusepath,path);
rv = actionFunc(srcmounts,fusepath,paths,-1);
if(rv == -1) if(rv == -1)
return -errno; 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 #else
return -ENOTSUP; return -ENOTSUP;
#endif #endif

30
src/symlink.cpp

@ -39,22 +39,33 @@ using std::vector;
static static
int 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; 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) if(rv == -1)
return -errno; 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 namespace mergerfs
@ -70,7 +81,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 _symlink(config.srcmounts,
return _symlink(*config.symlink,
config.srcmounts,
oldpath, oldpath,
newpath); newpath);
} }

18
src/truncate.cpp

@ -41,21 +41,29 @@ using std::vector;
static static
int int
_truncate(const fs::SearchFunc searchFunc,
_truncate(const fs::find::Func actionFunc,
const vector<string> &srcmounts, const vector<string> &srcmounts,
const string &fusepath, const string &fusepath,
const off_t size) const off_t size)
{ {
int rv; int rv;
fs::Path path;
int error;
fs::Paths paths;
rv = searchFunc(srcmounts,fusepath,path);
rv = actionFunc(srcmounts,fusepath,paths,-1);
if(rv == -1) if(rv == -1)
return -errno; 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 namespace mergerfs

18
src/unlink.cpp

@ -40,20 +40,28 @@ using std::vector;
static static
int int
_unlink(const fs::SearchFunc searchFunc,
_unlink(const fs::find::Func actionFunc,
const vector<string> &srcmounts, const vector<string> &srcmounts,
const string &fusepath) const string &fusepath)
{ {
int rv; int rv;
fs::Path path;
int error;
fs::Paths paths;
rv = searchFunc(srcmounts,fusepath,path);
rv = actionFunc(srcmounts,fusepath,paths,-1);
if(rv == -1) if(rv == -1)
return -errno; 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 namespace mergerfs

18
src/utimens.cpp

@ -41,21 +41,29 @@ using std::vector;
static static
int int
_utimens(const fs::SearchFunc searchFunc,
_utimens(const fs::find::Func actionFunc,
const vector<string> &srcmounts, const vector<string> &srcmounts,
const string &fusepath, const string &fusepath,
const struct timespec ts[2]) const struct timespec ts[2])
{ {
int rv; int rv;
fs::Path path;
int error;
fs::Paths paths;
rv = searchFunc(srcmounts,fusepath,path);
rv = actionFunc(srcmounts,fusepath,paths,-1);
if(rv == -1) if(rv == -1)
return -errno; 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 namespace mergerfs

Loading…
Cancel
Save