diff --git a/TODO b/TODO index af8c69cc..c046d6ee 100644 --- a/TODO +++ b/TODO @@ -7,4 +7,3 @@ * newest * unit tests * add more to ioctl -* use {list,set}xattr for setting runtime values via .mergerfs pseudofile diff --git a/src/getxattr.cpp b/src/getxattr.cpp index 0026e855..155cd9ef 100644 --- a/src/getxattr.cpp +++ b/src/getxattr.cpp @@ -27,6 +27,7 @@ #include #include +#include #include "config.hpp" #include "fs.hpp" @@ -38,6 +39,45 @@ using std::string; using std::vector; using mergerfs::Policy; +static +int +_getxattr_controlfile(const Policy &policy, + const string attrname, + char *buf, + const size_t count) +{ +#ifndef WITHOUT_XATTR + size_t len; + string attrvalue; + + if(attrname == "user.mergerfs.action") + attrvalue = policy.action.str(); + else if(attrname == "user.mergerfs.create") + attrvalue = policy.create.str(); + else if(attrname == "user.mergerfs.search") + attrvalue = policy.search.str(); + else if(attrname == "user.mergerfs.statfs") + attrvalue = policy.statfs.str(); + + if(attrvalue.empty()) + return -ENOATTR; + + len = attrvalue.size() + 1; + + if(count == 0) + return len; + + if(count < len) + return -ERANGE; + + memcpy(buf,attrvalue.c_str(),len); + + return (int)len; +#else + return -ENOTSUP; +#endif +} + static int _getxattr(const Policy::Search::Func searchFunc, @@ -77,7 +117,10 @@ namespace mergerfs const config::Config &config = config::get(); if(fusepath == config.controlfile) - return -ENOTSUP; + return _getxattr_controlfile(config.policy, + attrname, + buf, + count); return _getxattr(config.policy.search, config.srcmounts, diff --git a/src/listxattr.cpp b/src/listxattr.cpp index 94cd2229..8a6ec1c2 100644 --- a/src/listxattr.cpp +++ b/src/listxattr.cpp @@ -27,6 +27,7 @@ #include #include +#include #include "config.hpp" #include "fs.hpp" @@ -37,6 +38,33 @@ using std::string; using std::vector; using mergerfs::Policy; +using namespace mergerfs; + +static +int +_listxattr_controlfile(char *list, + const size_t size) +{ +#ifndef WITHOUT_XATTR + const char xattrs[] = + "user.mergerfs.action\0" + "user.mergerfs.create\0" + "user.mergerfs.search\0" + "user.mergerfs.statfs\0"; + + if(size == 0) + return sizeof(xattrs); + + if(size < sizeof(xattrs)) + return -ERANGE; + + memcpy(list,xattrs,sizeof(xattrs)); + + return sizeof(xattrs); +#else + return -ENOTSUP; +#endif +} static int @@ -75,7 +103,8 @@ namespace mergerfs const config::Config &config = config::get(); if(fusepath == config.controlfile) - return -ENOTSUP; + return _listxattr_controlfile(list, + size); return _listxattr(config.policy.search, config.srcmounts, diff --git a/src/setxattr.cpp b/src/setxattr.cpp index 3fd93b9b..0fb53190 100644 --- a/src/setxattr.cpp +++ b/src/setxattr.cpp @@ -37,6 +37,65 @@ using std::string; using std::vector; using mergerfs::Policy; +using namespace mergerfs; + +static +int +_setxattr_controlfile(config::Config &config, + const string attrname, + const string attrval, + const size_t attrvalsize, + const int flags) +{ +#ifndef WITHOUT_XATTR + if(attrname == "user.mergerfs.action") + { + if((flags & XATTR_CREATE) == XATTR_CREATE) + return -EEXIST; + if(Policy::Action::fromString(attrval) != -1) + config.policy.action = attrval; + else + return -ENOSPC; + } + else if(attrname == "user.mergerfs.create") + { + if((flags & XATTR_CREATE) == XATTR_CREATE) + return -EEXIST; + if(Policy::Create::fromString(attrval) != -1) + config.policy.create = attrval; + else + return -ENOSPC; + } + else if(attrname == "user.mergerfs.search") + { + if((flags & XATTR_CREATE) == XATTR_CREATE) + return -EEXIST; + if(Policy::Search::fromString(attrval) != -1) + config.policy.search = attrval; + else + return -ENOSPC; + } + else if(attrname == "user.mergerfs.statfs") + { + if((flags & XATTR_CREATE) == XATTR_CREATE) + return -EEXIST; + if(Policy::StatFS::fromString(attrval) != -1) + config.policy.statfs = attrval; + else + return -ENOSPC; + } + else + { + return -ENOATTR; + } + + config.updateReadStr(); + + return 0; +#else + return -ENOTSUP; +#endif +} static int @@ -87,7 +146,11 @@ namespace mergerfs const config::Config &config = config::get(); if(fusepath == config.controlfile) - return -ENOTSUP; + return _setxattr_controlfile(config::get_writable(), + attrname, + string(attrval,attrvalsize), + attrvalsize, + flags); return _setxattr(config.policy.action, config.srcmounts,