diff --git a/src/config.cpp b/src/config.cpp index 2eb6cb30..375c2eac 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -235,7 +235,7 @@ Config::Config() _map["func.link"] = &func.link; _map["func.listxattr"] = &listxattr; _map["func.mkdir"] = &func.mkdir; - _map["func.mknod"] = &func.mknod; + _map["func.mknod"] = &mknod; _map["func.open"] = &func.open; _map["func.readdir"] = &readdir; _map["func.readlink"] = &readlink; diff --git a/src/config.hpp b/src/config.hpp index 938fe7fd..68c092cb 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -22,6 +22,7 @@ #include "func_getattr.hpp" #include "func_getxattr.hpp" #include "func_listxattr.hpp" +#include "func_mknod.hpp" #include "func_readlink.hpp" #include "func_removexattr.hpp" #include "func_rmdir.hpp" @@ -130,6 +131,7 @@ public: Func2::GetAttr getattr{"cdfo"}; Func2::Getxattr getxattr{"ff"}; Func2::Listxattr listxattr{"ff"}; + Func2::Mknod mknod{"ff"}; Func2::Readlink readlink{"ff"}; Func2::Removexattr removexattr{"all"}; Func2::Rmdir rmdir{"all"}; diff --git a/src/func_mknod.hpp b/src/func_mknod.hpp new file mode 100644 index 00000000..d0bbb694 --- /dev/null +++ b/src/func_mknod.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "func_mknod_base.hpp" +#include "func_mknod_factory.hpp" + +#include "func_wrapper.hpp" + +namespace Func2 +{ + using Mknod = FuncWrapper; +} \ No newline at end of file diff --git a/src/func_mknod_base.hpp b/src/func_mknod_base.hpp new file mode 100644 index 00000000..1406392f --- /dev/null +++ b/src/func_mknod_base.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "branches.hpp" +#include "fs_path.hpp" +#include "ugid.hpp" + +#include + +namespace Func2 +{ + class MknodBase + { + public: + MknodBase() {} + ~MknodBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual int operator()(const ugid_t &ugid, + const Branches &branches, + const fs::path &fusepath, + const mode_t mode, + const mode_t umask, + const dev_t dev) = 0; + }; +} \ No newline at end of file diff --git a/src/func_mknod_factory.cpp b/src/func_mknod_factory.cpp new file mode 100644 index 00000000..d09fef05 --- /dev/null +++ b/src/func_mknod_factory.cpp @@ -0,0 +1,26 @@ +#include "func_mknod_factory.hpp" + +#include "func_mknod_ff.hpp" +#include "func_mknod_mfs.hpp" + +bool +Func2::MknodFactory::valid(const std::string str_) +{ + if(str_ == "ff") + return true; + if(str_ == "mfs") + return true; + + return false; +} + +std::shared_ptr +Func2::MknodFactory::make(const std::string_view str_) +{ + if(str_ == "ff") + return std::make_shared(); + if(str_ == "mfs") + return std::make_shared(); + + return {}; +} \ No newline at end of file diff --git a/src/func_mknod_factory.hpp b/src/func_mknod_factory.hpp new file mode 100644 index 00000000..53be363d --- /dev/null +++ b/src/func_mknod_factory.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +namespace Func2 +{ + class MknodBase; + + class MknodFactory + { + public: + static bool valid(const std::string str_); + + static std::shared_ptr make(const std::string_view str_); + }; +} \ No newline at end of file diff --git a/src/func_mknod_ff.cpp b/src/func_mknod_ff.cpp new file mode 100644 index 00000000..f976b467 --- /dev/null +++ b/src/func_mknod_ff.cpp @@ -0,0 +1,94 @@ +#include "func_mknod_ff.hpp" + +#include "errno.hpp" +#include "error.hpp" +#include "fs_acl.hpp" +#include "fs_clonepath.hpp" +#include "fs_exists.hpp" +#include "fs_info.hpp" +#include "fs_mknod_as.hpp" +#include "fs_path.hpp" +#include "ugid.hpp" + +std::string_view +Func2::MknodFF::name() const +{ + return "ff"; +} + +int +Func2::MknodFF::operator()(const ugid_t &ugid_, + const Branches &branches_, + const fs::path &fusepath_, + const mode_t mode_, + const mode_t umask_, + const dev_t dev_) +{ + int rv; + fs::path fusedirpath; + mode_t umask; + + fusedirpath = fusepath_.parent_path(); + umask = 0; // TODO: get actual umask + + // Find first branch with the directory + const Branch *existing_branch = nullptr; + for(const auto &branch : branches_) + { + if(fs::exists(branch.path / fusedirpath)) + { + existing_branch = &branch; + break; + } + } + + if(!existing_branch) + return -ENOENT; + + // Find first branch for creation + const Branch *create_branch = nullptr; + for(const auto &branch : branches_) + { + if(branch.ro_or_nc()) + continue; + + fs::info_t info; + rv = fs::info(branch.path, &info); + if(rv < 0) + continue; + + if(info.readonly) + continue; + + if(info.spaceavail < branch.minfreespace()) + continue; + + create_branch = &branch; + break; + } + + if(!create_branch) + return -ENOSPC; + + // Clone path if needed + if(existing_branch != create_branch) + { + rv = fs::clonepath(existing_branch->path, + create_branch->path, + fusedirpath); + if(rv < 0) + return rv; + } + + // Create the node + fs::path fullpath = create_branch->path / fusepath_; + if(!fs::acl::dir_has_defaults(fullpath)) + { + mode_t mode = mode_ & ~umask_; + return fs::mknod_as(ugid_, fullpath, mode, dev_); + } + else + { + return fs::mknod_as(ugid_, fullpath, mode_, dev_); + } +} \ No newline at end of file diff --git a/src/func_mknod_ff.hpp b/src/func_mknod_ff.hpp new file mode 100644 index 00000000..737c41c0 --- /dev/null +++ b/src/func_mknod_ff.hpp @@ -0,0 +1,24 @@ +#include "func_mknod_base.hpp" + +#include + +namespace Func2 +{ + class MknodFF : public MknodBase + { + public: + MknodFF() {} + ~MknodFF() {} + + public: + std::string_view name() const; + + public: + int operator()(const ugid_t &ugid, + const Branches &branches, + const fs::path &fusepath, + const mode_t mode, + const mode_t umask, + const dev_t dev); + }; +} \ No newline at end of file diff --git a/src/func_mknod_mfs.cpp b/src/func_mknod_mfs.cpp new file mode 100644 index 00000000..212ae97f --- /dev/null +++ b/src/func_mknod_mfs.cpp @@ -0,0 +1,99 @@ +#include "func_mknod_mfs.hpp" + +#include "errno.hpp" +#include "error.hpp" +#include "fs_acl.hpp" +#include "fs_clonepath.hpp" +#include "fs_exists.hpp" +#include "fs_info.hpp" +#include "fs_mknod_as.hpp" +#include "fs_path.hpp" +#include "ugid.hpp" + +std::string_view +Func2::MknodMFS::name() const +{ + return "mfs"; +} + +int +Func2::MknodMFS::operator()(const ugid_t &ugid_, + const Branches &branches_, + const fs::path &fusepath_, + const mode_t mode_, + const mode_t umask_, + const dev_t dev_) +{ + int rv; + fs::path fusedirpath; + mode_t umask; + + fusedirpath = fusepath_.parent_path(); + umask = 0; // TODO: get actual umask + + // Find first branch with the directory + const Branch *existing_branch = nullptr; + for(const auto &branch : branches_) + { + if(fs::exists(branch.path / fusedirpath)) + { + existing_branch = &branch; + break; + } + } + + if(!existing_branch) + return -ENOENT; + + // Find branch with most free space for creation + const Branch *create_branch = nullptr; + uint64_t max_space = 0; + + for(const auto &branch : branches_) + { + if(branch.ro_or_nc()) + continue; + + fs::info_t info; + rv = fs::info(branch.path, &info); + if(rv < 0) + continue; + + if(info.readonly) + continue; + + if(info.spaceavail < branch.minfreespace()) + continue; + + if(info.spaceavail > max_space) + { + max_space = info.spaceavail; + create_branch = &branch; + } + } + + if(!create_branch) + return -ENOSPC; + + // Clone path if needed + if(existing_branch != create_branch) + { + rv = fs::clonepath(existing_branch->path, + create_branch->path, + fusedirpath); + if(rv < 0) + return rv; + } + + // Create the node + fs::path fullpath = create_branch->path / fusepath_; + if(!fs::acl::dir_has_defaults(fullpath)) + { + mode_t mode = mode_ & ~umask_; + return fs::mknod_as(ugid_, fullpath, mode, dev_); + } + else + { + return fs::mknod_as(ugid_, fullpath, mode_, dev_); + } +} \ No newline at end of file diff --git a/src/func_mknod_mfs.hpp b/src/func_mknod_mfs.hpp new file mode 100644 index 00000000..c465d5b3 --- /dev/null +++ b/src/func_mknod_mfs.hpp @@ -0,0 +1,24 @@ +#include "func_mknod_base.hpp" + +#include + +namespace Func2 +{ + class MknodMFS : public MknodBase + { + public: + MknodMFS() {} + ~MknodMFS() {} + + public: + std::string_view name() const; + + public: + int operator()(const ugid_t &ugid, + const Branches &branches, + const fs::path &fusepath, + const mode_t mode, + const mode_t umask, + const dev_t dev); + }; +} \ No newline at end of file diff --git a/src/fuse_mknod.cpp b/src/fuse_mknod.cpp index a1df63f1..6a4b8d95 100644 --- a/src/fuse_mknod.cpp +++ b/src/fuse_mknod.cpp @@ -145,26 +145,23 @@ FUSE::mknod(const fuse_req_ctx_t *ctx_, { int rv; const fs::path fusepath{fusepath_}; - - rv = ::_mknod(ctx_, - cfg.func.getattr.policy, - cfg.func.mknod.policy, - cfg.branches, - fusepath, - mode_, - ctx_->umask, - rdev_); + const ugid_t ugid(ctx_); + + rv = cfg.mknod(ugid, + cfg.branches, + fusepath, + mode_, + ctx_->umask, + rdev_); if(rv == -EROFS) { cfg.branches.find_and_set_mode_ro(); - rv = ::_mknod(ctx_, - cfg.func.getattr.policy, - cfg.func.mknod.policy, - cfg.branches, - fusepath, - mode_, - ctx_->umask, - rdev_); + rv = cfg.mknod(ugid, + cfg.branches, + fusepath, + mode_, + ctx_->umask, + rdev_); } return rv;