From c022741ffb490716fea300bf5a715016bc33fcd0 Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Tue, 24 Feb 2015 18:47:31 -0500 Subject: [PATCH] revert removal of 'all' policy and relevant behavior. closes #54 --- README.md | 68 ++++++++++++++++++++++++----------- src/access.cpp | 8 ++--- src/chmod.cpp | 18 +++++++--- src/chown.cpp | 18 +++++++--- src/config.cpp | 2 +- src/create.cpp | 20 +++++------ src/fs.cpp | 86 ++++++++++++++++++++++++++++++++------------- src/fs.hpp | 30 +++++++++++----- src/fusefunc.cpp | 2 +- src/getattr.cpp | 8 ++--- src/getxattr.cpp | 10 +++--- src/ioctl.cpp | 8 ++--- src/link.cpp | 68 +++++++++++++++++++++++------------ src/listxattr.cpp | 8 ++--- src/mkdir.cpp | 39 +++++++++++--------- src/mknod.cpp | 39 +++++++++++--------- src/open.cpp | 10 +++--- src/policy.cpp | 2 ++ src/policy.hpp | 12 ++++--- src/readlink.cpp | 8 ++--- src/removexattr.cpp | 18 +++++++--- src/rename.cpp | 71 ++++++++++++++++++++++++++++--------- src/rmdir.cpp | 18 +++++++--- src/setxattr.cpp | 18 +++++++--- src/symlink.cpp | 30 +++++++++++----- src/truncate.cpp | 18 +++++++--- src/unlink.cpp | 18 +++++++--- src/utimens.cpp | 18 +++++++--- 28 files changed, 451 insertions(+), 222 deletions(-) diff --git a/README.md b/README.md index f3a72d2c..c9132829 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/src/access.cpp b/src/access.cpp index 724bdce1..2760ad13 100644 --- a/src/access.cpp +++ b/src/access.cpp @@ -45,19 +45,19 @@ using mergerfs::Policy; static int -_access(const fs::SearchFunc searchFunc, +_access(const fs::find::Func searchFunc, const vector &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); } diff --git a/src/chmod.cpp b/src/chmod.cpp index 26867383..193b7464 100644 --- a/src/chmod.cpp +++ b/src/chmod.cpp @@ -39,21 +39,29 @@ using mergerfs::Policy; static int -_chmod(const fs::SearchFunc searchFunc, +_chmod(const fs::find::Func actionFunc, const vector &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 diff --git a/src/chown.cpp b/src/chown.cpp index 41dd12c4..40dbf721 100644 --- a/src/chown.cpp +++ b/src/chown.cpp @@ -40,22 +40,30 @@ using mergerfs::Policy; static int -_chown(const fs::SearchFunc searchFunc, +_chown(const fs::find::Func actionFunc, const vector &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 diff --git a/src/config.cpp b/src/config.cpp index 0b20812a..3cf4fe93 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -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); } diff --git a/src/create.cpp b/src/create.cpp index e6988b5f..01a5a10e 100644 --- a/src/create.cpp +++ b/src/create.cpp @@ -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 &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, diff --git a/src/fs.cpp b/src/fs.cpp index b8d31b4c..db99a38a 100644 --- a/src/fs.cpp +++ b/src/fs.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -519,7 +520,8 @@ namespace fs int invalid(const vector &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 &basepaths, const string &fusepath, - Path &path) + Paths &paths, + size_t count) { errno = ENOENT; for(vector::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 &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 &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 &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 &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 &basepaths, + const string &fusepath, + Paths &paths, + size_t count) + { + int rv; + struct stat st; + string fullpath; + + for(vector::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 &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; } diff --git a/src/fs.hpp b/src/fs.hpp index ac3d071e..54c01c59 100644 --- a/src/fs.hpp +++ b/src/fs.hpp @@ -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&,const string&,Path&); + typedef vector Paths; string dirname(const string &path); string basename(const string &path); @@ -112,27 +113,40 @@ namespace fs namespace find { + typedef int (*Func)(const vector&,const string&,Paths&,size_t); + int invalid(const vector &basepaths, const string &fusepath, - Path &path); + Paths &path, + size_t max); + int all(const vector &basepaths, + const string &fusepath, + Paths &path, + size_t max); int ff(const vector &basepaths, const string &fusepath, - Path &path); + Paths &path, + size_t max); int ffwp(const vector &paths, const string &fusepath, - Path &path); + Paths &path, + size_t max); int newest(const vector &paths, const string &fusepath, - Path &path); + Paths &path, + size_t max); int mfs(const vector &paths, const string &fusepath, - Path &path); + Paths &path, + size_t max); int epmfs(const vector &paths, const string &fusepath, - Path &path); + Paths &path, + size_t max); int rand(const vector &paths, const string &fusepath, - Path &path); + Paths &path, + size_t max); } }; diff --git a/src/fusefunc.cpp b/src/fusefunc.cpp index 06fbb90b..b65a8a85 100644 --- a/src/fusefunc.cpp +++ b/src/fusefunc.cpp @@ -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)) diff --git a/src/getattr.cpp b/src/getattr.cpp index baadfd38..27a1a281 100644 --- a/src/getattr.cpp +++ b/src/getattr.cpp @@ -65,19 +65,19 @@ _getattr_controlfile(struct stat &buf) static int -_getattr(const fs::SearchFunc searchFunc, +_getattr(const fs::find::Func searchFunc, const vector &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); } diff --git a/src/getxattr.cpp b/src/getxattr.cpp index 46047889..efca6527 100644 --- a/src/getxattr.cpp +++ b/src/getxattr.cpp @@ -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 &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 diff --git a/src/ioctl.cpp b/src/ioctl.cpp index a93fd772..441e4e3c 100644 --- a/src/ioctl.cpp +++ b/src/ioctl.cpp @@ -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 &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; diff --git a/src/link.cpp b/src/link.cpp index 41e3daa6..bf286942 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -41,41 +41,64 @@ using mergerfs::Policy; static int -_link(const fs::SearchFunc searchFunc, - const vector &srcmounts, - const string &from, - const string &to) +_single_link(const fs::find::Func searchFunc, + const vector &srcmounts, + const string &base, + const string &oldpath, + const string &newpath) { int rv; - fs::Path path; - - 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); + const string fulloldpath = fs::make_path(base,oldpath); + const string fullnewpath = fs::make_path(base,newpath); - 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; +} + +static +int +_link(const fs::find::Func searchFunc, + const fs::find::Func actionFunc, + const vector &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 @@ -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); diff --git a/src/listxattr.cpp b/src/listxattr.cpp index 06dc2ae4..e29b7168 100644 --- a/src/listxattr.cpp +++ b/src/listxattr.cpp @@ -69,7 +69,7 @@ _listxattr_controlfile(char *list, static int -_listxattr(const fs::SearchFunc searchFunc, +_listxattr(const fs::find::Func searchFunc, const vector &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 diff --git a/src/mkdir.cpp b/src/mkdir.cpp index 693e8613..cb9814c7 100644 --- a/src/mkdir.cpp +++ b/src/mkdir.cpp @@ -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 &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); + } - 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 diff --git a/src/mknod.cpp b/src/mknod.cpp index f99d7a6d..647b9720 100644 --- a/src/mknod.cpp +++ b/src/mknod.cpp @@ -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 &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); + } - 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 diff --git a/src/open.cpp b/src/open.cpp index 19f519c2..8a04d86c 100644 --- a/src/open.cpp +++ b/src/open.cpp @@ -43,7 +43,7 @@ using mergerfs::FileInfo; static int -_open(const fs::SearchFunc searchFunc, +_open(const fs::find::Func searchFunc, const vector &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; } diff --git a/src/policy.cpp b/src/policy.cpp index 9668750d..0cf8915a 100644 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -35,6 +35,7 @@ namespace mergerfs const std::vector Policy::_policies_ = buildvector (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]; diff --git a/src/policy.hpp b/src/policy.hpp index 1145df8b..fadfa6d5 100644 --- a/src/policy.hpp +++ b/src/policy.hpp @@ -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 _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; diff --git a/src/readlink.cpp b/src/readlink.cpp index 680b6f12..d22d5f2a 100644 --- a/src/readlink.cpp +++ b/src/readlink.cpp @@ -41,20 +41,20 @@ using mergerfs::Policy; static int -_readlink(const fs::SearchFunc searchFunc, +_readlink(const fs::find::Func searchFunc, const vector &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; diff --git a/src/removexattr.cpp b/src/removexattr.cpp index 5295498b..9066df44 100644 --- a/src/removexattr.cpp +++ b/src/removexattr.cpp @@ -41,22 +41,30 @@ using std::vector; static int -_removexattr(const fs::SearchFunc searchFunc, +_removexattr(const fs::find::Func actionFunc, const vector &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 diff --git a/src/rename.cpp b/src/rename.cpp index 3ddd5afe..f1b53093 100644 --- a/src/rename.cpp +++ b/src/rename.cpp @@ -41,26 +41,62 @@ using std::vector; static int -_rename(const fs::SearchFunc searchFunc, +_single_rename(const fs::find::Func searchFunc, + const vector &srcmounts, + const fs::Path &oldpath, + const string &newpath) +{ + int rv; + const string fullnewpath = fs::make_path(oldpath.base,newpath); + + 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 &srcmounts, - const string &from, - const string &to) + const string &oldpath, + const string &newpath) { int rv; - string pathto; - fs::Path pathfrom; + int error; + fs::Paths oldpaths; - rv = searchFunc(srcmounts,from,pathfrom); + rv = actionFunc(srcmounts,oldpath,oldpaths,-1); if(rv == -1) return -errno; - pathto = fs::make_path(pathfrom.base,to); - - rv = ::rename(pathfrom.full.c_str(),pathto.c_str()); - if(rv == -1 && errno == ENOENT) - return -EXDEV; + 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 @@ -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); } } } diff --git a/src/rmdir.cpp b/src/rmdir.cpp index 4a8ab163..2c4959fb 100644 --- a/src/rmdir.cpp +++ b/src/rmdir.cpp @@ -40,20 +40,28 @@ using mergerfs::Policy; static int -_rmdir(const fs::SearchFunc searchFunc, +_rmdir(const fs::find::Func actionFunc, const vector &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 diff --git a/src/setxattr.cpp b/src/setxattr.cpp index e4439619..a9d913ce 100644 --- a/src/setxattr.cpp +++ b/src/setxattr.cpp @@ -256,7 +256,7 @@ _setxattr_controlfile(config::Config &config, static int -_setxattr(const fs::SearchFunc searchFunc, +_setxattr(const fs::find::Func actionFunc, const vector &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 diff --git a/src/symlink.cpp b/src/symlink.cpp index 86106622..8ae96e05 100644 --- a/src/symlink.cpp +++ b/src/symlink.cpp @@ -39,22 +39,33 @@ using std::vector; static int -_symlink(const vector &srcmounts, - const string &from, - const string &to) +_symlink(const fs::find::Func createFunc, + const vector &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); } diff --git a/src/truncate.cpp b/src/truncate.cpp index 64268c7c..c4ef8cbb 100644 --- a/src/truncate.cpp +++ b/src/truncate.cpp @@ -41,21 +41,29 @@ using std::vector; static int -_truncate(const fs::SearchFunc searchFunc, +_truncate(const fs::find::Func actionFunc, const vector &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 diff --git a/src/unlink.cpp b/src/unlink.cpp index f72835a2..a2ba191b 100644 --- a/src/unlink.cpp +++ b/src/unlink.cpp @@ -40,20 +40,28 @@ using std::vector; static int -_unlink(const fs::SearchFunc searchFunc, +_unlink(const fs::find::Func actionFunc, const vector &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 diff --git a/src/utimens.cpp b/src/utimens.cpp index 26a1db46..45b3e564 100644 --- a/src/utimens.cpp +++ b/src/utimens.cpp @@ -41,21 +41,29 @@ using std::vector; static int -_utimens(const fs::SearchFunc searchFunc, +_utimens(const fs::find::Func actionFunc, const vector &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