diff --git a/src/config.cpp b/src/config.cpp index 46a2e894..1d51bd6e 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -231,7 +231,7 @@ Config::Config() _map["func.chmod"] = &func.chmod; _map["func.chown"] = &func.chown; _map["func.create"] = &func.create; - _map["func.getattr"] = &func.getattr; + _map["func.getattr"] = &getattr; _map["func.getxattr"] = &func.getxattr; _map["func.link"] = &func.link; _map["func.listxattr"] = &func.listxattr; @@ -244,6 +244,7 @@ Config::Config() _map["func.rename"] = &func.rename; _map["func.rmdir"] = &func.rmdir; _map["func.setxattr"] = &func.setxattr; + _map["func.statx"] = &statx; _map["func.symlink"] = &func.symlink; _map["func.truncate"] = &func.truncate; _map["func.unlink"] = &func.unlink; diff --git a/src/config.hpp b/src/config.hpp index a6335c97..9609334a 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -16,6 +16,9 @@ #pragma once +#include "func_getattr.hpp" +#include "func_statx.hpp" + #include "branches.hpp" #include "category.hpp" #include "config_cachefiles.hpp" @@ -109,6 +112,9 @@ public: Config& operator=(const Config&); public: + Func2::GetAttr getattr{"combine"}; + Func2::Statx statx{"combine"}; + ConfigBOOL allow_idmap; ConfigBOOL async_read; Branches branches; diff --git a/src/config_follow_symlinks.hpp b/src/config_follow_symlinks.hpp index 1ebbdecf..a6df2bce 100644 --- a/src/config_follow_symlinks.hpp +++ b/src/config_follow_symlinks.hpp @@ -19,12 +19,6 @@ #pragma once #include "enum.hpp" +#include "follow_symlinks_enum.hpp" -enum class FollowSymlinksEnum - { - NEVER, - DIRECTORY, - REGULAR, - ALL - }; typedef Enum FollowSymlinks; diff --git a/src/follow_symlinks_enum.hpp b/src/follow_symlinks_enum.hpp new file mode 100644 index 00000000..c708b898 --- /dev/null +++ b/src/follow_symlinks_enum.hpp @@ -0,0 +1,9 @@ +#pragma once + +enum class FollowSymlinksEnum + { + NEVER, + DIRECTORY, + REGULAR, + ALL + }; diff --git a/src/fs_lstat.hpp b/src/fs_lstat.hpp index 574fd80b..ece50c9c 100644 --- a/src/fs_lstat.hpp +++ b/src/fs_lstat.hpp @@ -19,8 +19,7 @@ #pragma once #include "to_neg_errno.hpp" - -#include +#include "to_cstr.hpp" #include #include @@ -29,25 +28,17 @@ namespace fs { + template static inline int - lstat(const char *path_, - struct stat *st_) + lstat(const PathType &path_, + struct stat *st_) { int rv; - rv = ::lstat(path_,st_); + rv = ::lstat(to_cstr(path_),st_); return ::to_neg_errno(rv); } - - static - inline - int - lstat(const std::string &path_, - struct stat *st_) - { - return fs::lstat(path_.c_str(),st_); - } } diff --git a/src/fs_stat.cpp b/src/fs_stat.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/fs_stat.hpp b/src/fs_stat.hpp index 0e85f7f3..c3e60c98 100644 --- a/src/fs_stat.hpp +++ b/src/fs_stat.hpp @@ -18,7 +18,10 @@ #pragma once +#include "follow_symlinks_enum.hpp" #include "to_neg_errno.hpp" +#include "to_cstr.hpp" +#include "fs_lstat.hpp" #include @@ -29,25 +32,71 @@ namespace fs { + template static inline int - stat(const char *path_, - struct stat *st_) + stat(const PathType &path_, + struct stat *st_) { int rv; - rv = ::stat(path_,st_); + rv = ::stat(to_cstr(path_),st_); return ::to_neg_errno(rv); } + template static inline int - stat(const std::string &path_, - struct stat *st_) + stat(const PathType &path_, + struct stat *st_, + FollowSymlinksEnum follow_) { - return fs::stat(path_.c_str(),st_); + int rv; + + switch(follow_) + { + default: + case FollowSymlinksEnum::NEVER: + rv = fs::lstat(path_,st_); + return rv; + case FollowSymlinksEnum::DIRECTORY: + rv = fs::lstat(path_,st_); + if((rv >= 0) && S_ISLNK(st_->st_mode)) + { + struct stat st; + + rv = fs::stat(path_,&st); + if(rv < 0) + return rv; + + if(S_ISDIR(st.st_mode)) + *st_ = st; + } + return rv; + case FollowSymlinksEnum::REGULAR: + rv = fs::lstat(path_,st_); + if((rv >= 0) && S_ISLNK(st_->st_mode)) + { + struct stat st; + + rv = fs::stat(path_,&st); + if(rv < 0) + return rv; + + if(S_ISREG(st.st_mode)) + *st_ = st; + } + return rv; + case FollowSymlinksEnum::ALL: + rv = fs::stat(path_,st_); + if(rv < 0) + rv = fs::lstat(path_,st_); + return rv; + } + + return -ENOENT; } } diff --git a/src/fs_statx.hpp b/src/fs_statx.hpp index 6c0365b0..8ad3b443 100644 --- a/src/fs_statx.hpp +++ b/src/fs_statx.hpp @@ -1,5 +1,7 @@ #pragma once +#include "follow_symlinks_enum.hpp" +#include "to_cstr.hpp" #include "to_neg_errno.hpp" #include "fuse_kernel.h" @@ -17,11 +19,12 @@ namespace fs { + template static inline int statx(const int dirfd_, - const char *pathname_, + const PathType &pathname_, const int flags_, const unsigned int mask_, struct fuse_statx *st_) @@ -30,7 +33,7 @@ namespace fs int rv; rv = ::statx(dirfd_, - pathname_, + to_cstr(pathname_), flags_, mask_, (struct statx*)st_); @@ -41,19 +44,59 @@ namespace fs #endif } + template static inline int statx(const int dirfd_, - const std::string &pathname_, + const PathType &pathname_, const int flags_, const unsigned int mask_, - struct fuse_statx *st_) + struct fuse_statx *st_, + FollowSymlinksEnum followsymlinks_) { - return fs::statx(dirfd_, - pathname_.c_str(), - flags_, - mask_, - st_); + int rv; + + switch(followsymlinks_) + { + case FollowSymlinksEnum::NEVER: + rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_); + return rv; + case FollowSymlinksEnum::DIRECTORY: + rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_); + if((rv >= 0) && S_ISLNK(st_->mode)) + { + struct fuse_statx st; + + rv = fs::statx(AT_FDCWD,pathname_,AT_SYMLINK_FOLLOW,STATX_TYPE,&st); + if(rv < 0) + return rv; + + if(S_ISDIR(st.mode)) + *st_ = st; + } + return rv; + case FollowSymlinksEnum::REGULAR: + rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_); + if((rv >= 0) && S_ISLNK(st_->mode)) + { + struct fuse_statx st; + + rv = fs::statx(AT_FDCWD,pathname_,AT_SYMLINK_FOLLOW,STATX_TYPE,&st); + if(rv < 0) + return rv; + + if(S_ISREG(st.mode)) + *st_ = st; + } + return rv; + case FollowSymlinksEnum::ALL: + rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_FOLLOW,mask_,st_); + if(rv < 0) + rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_); + return rv; + } + + return -ENOENT; } } diff --git a/src/func_getattr.hpp b/src/func_getattr.hpp new file mode 100644 index 00000000..d3687960 --- /dev/null +++ b/src/func_getattr.hpp @@ -0,0 +1,76 @@ +#pragma once + +#include "func_getattr_base.hpp" +#include "func_getattr_factory.hpp" + +#include "tofrom_string.hpp" + +#include "fmt/core.h" + +#include + +#include + +namespace Func2 +{ + class GetAttr : public ToFromString + { + private: + std::shared_ptr _impl; + + public: + GetAttr() + { + } + + GetAttr(const std::string &name_) + { + _impl = Func2::GetAttrFactory::make(name_); + assert(_impl); + } + + public: + int + operator()(const Branches &branches_, + const fs::path &fusepath_, + struct stat *st_, + const FollowSymlinksEnum follow_symlinks_, + const s64 symlinkify_timeout_) + { + std::shared_ptr p; + + p = std::atomic_load(&_impl); + + return (*p)(branches_, + fusepath_, + st_, + follow_symlinks_, + symlinkify_timeout_); + } + + public: + std::string + to_string() const + { + std::shared_ptr p; + + p = std::atomic_load(&_impl); + + return std::string(p->name()); + } + + int + from_string(const std::string_view str_) + { + std::shared_ptr p; + + p = Func2::GetAttrFactory::make(str_); + if(!p) + return -EINVAL; + + _impl = std::atomic_load(&p); + + return 0; + } + }; +} diff --git a/src/func_getattr_base.hpp b/src/func_getattr_base.hpp new file mode 100644 index 00000000..6f89b750 --- /dev/null +++ b/src/func_getattr_base.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include "follow_symlinks_enum.hpp" + +#include "fs_path.hpp" +#include "branches.hpp" +#include "int_types.h" + +#include "fuse.h" + +#include + +#include +#include +#include + +namespace Func2 +{ + class GetAttrBase + { + public: + GetAttrBase() {} + ~GetAttrBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual int operator()(const Branches &branches, + const fs::path &fusepath, + struct stat *st, + const FollowSymlinksEnum follow_symlinks, + const s64 symlinkify_timeout) = 0; + }; +} diff --git a/src/func_getattr_combine.cpp b/src/func_getattr_combine.cpp new file mode 100644 index 00000000..c75410c0 --- /dev/null +++ b/src/func_getattr_combine.cpp @@ -0,0 +1,63 @@ +#include "func_getattr_combine.hpp" + +#include "fs_inode.hpp" +#include "fs_stat.hpp" +#include "symlinkify.hpp" +#include "timespec_utils.hpp" + + +std::string_view +Func2::GetAttrCombine::name() const +{ + return "combine"; +} + +int +Func2::GetAttrCombine::operator()(const Branches &branches_, + const fs::path &fusepath_, + struct stat *st_, + const FollowSymlinksEnum follow_symlinks_, + const s64 symlinkify_timeout_) +{ + int rv; + fs::path fullpath; + const Branch *first_branch; + + first_branch = nullptr; + for(const auto &branch : branches_) + { + struct stat tmp_st; + + fullpath = branch.path / fusepath_; + rv = fs::stat(fullpath,&tmp_st,follow_symlinks_); + if(rv < 0) + continue; + + if(!first_branch) + { + *st_ = tmp_st; + first_branch = &branch; + continue; + } + + st_->st_atim = TimeSpec::newest(st_->st_atim,tmp_st.st_atim); + st_->st_ctim = TimeSpec::newest(st_->st_ctim,tmp_st.st_ctim); + st_->st_mtim = TimeSpec::newest(st_->st_mtim,tmp_st.st_mtim); + st_->st_nlink += tmp_st.st_nlink; + } + + if(!first_branch) + return -ENOENT; + + if(symlinkify_timeout_ >= 0) + { + fullpath = first_branch->path / fusepath_; + symlinkify::convert_if_can_be_symlink(fullpath, + st_, + symlinkify_timeout_); + } + + fs::inode::calc(first_branch->path,fusepath_,st_); + + return 0; +} diff --git a/src/func_getattr_combine.hpp b/src/func_getattr_combine.hpp new file mode 100644 index 00000000..2a97bdf4 --- /dev/null +++ b/src/func_getattr_combine.hpp @@ -0,0 +1,21 @@ +#include "func_getattr_base.hpp" + +namespace Func2 +{ + class GetAttrCombine : public GetAttrBase + { + public: + GetAttrCombine() {} + ~GetAttrCombine() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + struct stat *st, + const FollowSymlinksEnum follow_symlinks, + const s64 symlinkify_timeout); + }; +} diff --git a/src/func_getattr_factory.cpp b/src/func_getattr_factory.cpp new file mode 100644 index 00000000..e6ee3576 --- /dev/null +++ b/src/func_getattr_factory.cpp @@ -0,0 +1,39 @@ +#include "func_getattr_factory.hpp" + +#include "func_getattr_combine.hpp" +#include "func_getattr_ff.hpp" +#include "func_getattr_newest.hpp" + +#include "policies.hpp" + +bool +Func2::GetAttrFactory::valid(const std::string str_) +{ + if(str_ == "combined") + return true; + if(str_ == "ff") + return true; + if(str_ == "newest") + return true; + + if(Policies::Search::find(str_)) + return true; + + return false; +} + +std::shared_ptr +Func2::GetAttrFactory::make(const std::string_view str_) +{ + if(str_ == "combine") + return std::make_shared(); + if(str_ == "ff") + return std::make_shared(); + if(str_ == "newest") + return std::make_shared(); + + if(Policies::Search::find(str_)) + return std::make_shared(); + + return {}; +} diff --git a/src/func_getattr_factory.hpp b/src/func_getattr_factory.hpp new file mode 100644 index 00000000..1e085980 --- /dev/null +++ b/src/func_getattr_factory.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "func_getattr_base.hpp" + +namespace Func2 +{ + class GetAttrFactory + { + public: + static bool valid(const std::string str); + static std::shared_ptr make(const std::string_view str); + }; +} diff --git a/src/func_getattr_ff.cpp b/src/func_getattr_ff.cpp new file mode 100644 index 00000000..4a94f69c --- /dev/null +++ b/src/func_getattr_ff.cpp @@ -0,0 +1,41 @@ +#include "func_getattr_ff.hpp" + +#include "fs_stat.hpp" +#include "fs_inode.hpp" +#include "symlinkify.hpp" + + +std::string_view +Func2::GetAttrFF::name() const +{ + return "ff"; +} + +int +Func2::GetAttrFF::operator()(const Branches &branches_, + const fs::path &fusepath_, + struct stat *st_, + const FollowSymlinksEnum follow_symlinks_, + const s64 symlinkify_timeout_) +{ + int rv; + fs::path fullpath; + + for(const auto &branch : branches_) + { + fullpath = branch.path / fusepath_; + rv = fs::stat(fullpath,st_,follow_symlinks_); + if(rv < 0) + continue; + + symlinkify::convert_if_can_be_symlink(fullpath, + st_, + symlinkify_timeout_); + + fs::inode::calc(branch.path,fusepath_,st_); + + return rv; + } + + return -ENOENT; +} diff --git a/src/func_getattr_ff.hpp b/src/func_getattr_ff.hpp new file mode 100644 index 00000000..e3d4b18f --- /dev/null +++ b/src/func_getattr_ff.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "func_getattr_base.hpp" + +namespace Func2 +{ + class GetAttrFF : public GetAttrBase + { + public: + GetAttrFF() {} + ~GetAttrFF() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + struct stat *st, + const FollowSymlinksEnum follow_symlinks, + const s64 symlinkify_timeout); + }; +} diff --git a/src/func_getattr_newest.cpp b/src/func_getattr_newest.cpp new file mode 100644 index 00000000..32a03b78 --- /dev/null +++ b/src/func_getattr_newest.cpp @@ -0,0 +1,57 @@ +#include "func_getattr_newest.hpp" + +#include "fs_stat.hpp" +#include "fs_inode.hpp" +#include "timespec_utils.hpp" +#include "symlinkify.hpp" + + +std::string_view +Func2::GetAttrNewest::name() const +{ + return "newest"; +} + +int +Func2::GetAttrNewest::operator()(const Branches &branches_, + const fs::path &fusepath_, + struct stat *st_, + const FollowSymlinksEnum follow_symlinks_, + const s64 symlinkify_timeout_) +{ + int rv; + fs::path fullpath; + const Branch *newest_branch; + + newest_branch = nullptr; + for(const auto &branch : branches_) + { + struct stat tmp_st; + + fullpath = branch.path / fusepath_; + rv = fs::stat(fullpath,&tmp_st,follow_symlinks_); + if(rv < 0) + continue; + + if(!TimeSpec::is_newer(tmp_st.st_mtim,st_->st_mtim)) + continue; + + *st_ = tmp_st; + newest_branch = &branch; + } + + if(!newest_branch) + return -ENOENT; + + if(symlinkify_timeout_ >= 0) + { + fullpath = newest_branch->path / fusepath_; + symlinkify::convert_if_can_be_symlink(fullpath, + st_, + symlinkify_timeout_); + } + + fs::inode::calc(newest_branch->path,fusepath_,st_); + + return 0; +} diff --git a/src/func_getattr_newest.hpp b/src/func_getattr_newest.hpp new file mode 100644 index 00000000..b08d0a67 --- /dev/null +++ b/src/func_getattr_newest.hpp @@ -0,0 +1,21 @@ +#include "func_getattr_base.hpp" + +namespace Func2 +{ + class GetAttrNewest : public GetAttrBase + { + public: + GetAttrNewest() {} + ~GetAttrNewest() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + struct stat *st, + const FollowSymlinksEnum follow_symlinks, + const s64 symlinkify_timeout); + }; +} diff --git a/src/func_statx.hpp b/src/func_statx.hpp new file mode 100644 index 00000000..a3a0b87f --- /dev/null +++ b/src/func_statx.hpp @@ -0,0 +1,81 @@ +#pragma once + +#include "func_statx_base.hpp" +#include "func_statx_factory.hpp" + +#include "tofrom_string.hpp" + +#include "fmt/core.h" + +#include + +#include + + +namespace Func2 +{ + class Statx : public ToFromString + { + private: + std::shared_ptr _impl; + + public: + Statx() + { + } + + Statx(const std::string &name_) + { + _impl = Func2::StatxFactory::make(name_); + assert(_impl); + } + + public: + int + operator()(const Branches &branches_, + const fs::path &fusepath_, + const u32 flags_, + const u32 mask_, + struct fuse_statx *st_, + const FollowSymlinksEnum follow_symlinks_, + const s64 symlinkify_timeout_) + { + std::shared_ptr p; + + p = std::atomic_load(&_impl); + + return (*p)(branches_, + fusepath_, + flags_, + mask_, + st_, + follow_symlinks_, + symlinkify_timeout_); + } + + public: + std::string + to_string() const + { + std::shared_ptr p; + + p = std::atomic_load(&_impl); + + return std::string(p->name()); + } + + int + from_string(const std::string_view str_) + { + std::shared_ptr p; + + p = Func2::StatxFactory::make(str_); + if(!p) + return -EINVAL; + + _impl = std::atomic_load(&p); + + return 0; + } + }; +} diff --git a/src/func_statx_base.hpp b/src/func_statx_base.hpp new file mode 100644 index 00000000..872ba349 --- /dev/null +++ b/src/func_statx_base.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "follow_symlinks_enum.hpp" + +#include "fs_path.hpp" +#include "branches.hpp" +#include "int_types.h" + +#include "fuse.h" + +#include + +#include +#include +#include + + +namespace Func2 +{ + class StatxBase + { + public: + StatxBase() {} + ~StatxBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual int operator()(const Branches &branches, + const fs::path &fusepath, + const u32 flags_, + const u32 mask_, + struct fuse_statx *st, + const FollowSymlinksEnum follow_symlinks, + const s64 symlinkify_timeout) = 0; + }; +} diff --git a/src/func_statx_combine.cpp b/src/func_statx_combine.cpp new file mode 100644 index 00000000..2df957e8 --- /dev/null +++ b/src/func_statx_combine.cpp @@ -0,0 +1,71 @@ +#include "func_statx_combine.hpp" + +#include "fs_inode.hpp" +#include "fs_statx.hpp" +#include "symlinkify.hpp" +#include "timespec_utils.hpp" + + +std::string_view +Func2::StatxCombine::name() const +{ + return "combine"; +} + +int +Func2::StatxCombine::operator()(const Branches &branches_, + const fs::path &fusepath_, + const u32 flags_, + const u32 mask_, + struct fuse_statx *st_, + const FollowSymlinksEnum follow_symlinks_, + const s64 symlinkify_timeout_) +{ + int rv; + fs::path fullpath; + const Branch *first_branch; + + first_branch = nullptr; + for(const auto &branch : branches_) + { + struct fuse_statx tmp_st; + + fullpath = branch.path / fusepath_; + rv = fs::statx(AT_FDCWD, + fullpath, + flags_|AT_SYMLINK_NOFOLLOW, + mask_, + &tmp_st, + follow_symlinks_); + if(rv < 0) + continue; + + if(!first_branch) + { + *st_ = tmp_st; + first_branch = &branch; + continue; + } + + st_->atime = TimeSpec::newest(st_->atime,tmp_st.atime); + st_->ctime = TimeSpec::newest(st_->ctime,tmp_st.ctime); + st_->mtime = TimeSpec::newest(st_->mtime,tmp_st.mtime); + st_->btime = TimeSpec::newest(st_->btime,tmp_st.btime); + st_->nlink += tmp_st.nlink; + } + + if(!first_branch) + return -ENOENT; + + if(symlinkify_timeout_ >= 0) + { + fullpath = first_branch->path / fusepath_; + symlinkify::convert_if_can_be_symlink(fullpath, + st_, + symlinkify_timeout_); + } + + fs::inode::calc(first_branch->path,fusepath_,st_); + + return 0; +} diff --git a/src/func_statx_combine.hpp b/src/func_statx_combine.hpp new file mode 100644 index 00000000..ef81fc69 --- /dev/null +++ b/src/func_statx_combine.hpp @@ -0,0 +1,23 @@ +#include "func_statx_base.hpp" + +namespace Func2 +{ + class StatxCombine : public StatxBase + { + public: + StatxCombine() {} + ~StatxCombine() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + const u32 flags_, + const u32 mask_, + struct fuse_statx *st, + const FollowSymlinksEnum follow_symlinks, + const s64 symlinkify_timeout); + }; +} diff --git a/src/func_statx_factory.cpp b/src/func_statx_factory.cpp new file mode 100644 index 00000000..5d9397f5 --- /dev/null +++ b/src/func_statx_factory.cpp @@ -0,0 +1,39 @@ +#include "func_statx_factory.hpp" + +#include "func_statx_combine.hpp" +#include "func_statx_ff.hpp" +#include "func_statx_newest.hpp" + +#include "policies.hpp" + +bool +Func2::StatxFactory::valid(const std::string str_) +{ + if(str_ == "combined") + return true; + if(str_ == "ff") + return true; + if(str_ == "newest") + return true; + + if(Policies::Search::find(str_)) + return true; + + return false; +} + +std::shared_ptr +Func2::StatxFactory::make(const std::string_view str_) +{ + if(str_ == "combine") + return std::make_shared(); + if(str_ == "ff") + return std::make_shared(); + if(str_ == "newest") + return std::make_shared(); + + if(Policies::Search::find(str_)) + return std::make_shared(); + + return {}; +} diff --git a/src/func_statx_factory.hpp b/src/func_statx_factory.hpp new file mode 100644 index 00000000..50ae11e6 --- /dev/null +++ b/src/func_statx_factory.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "func_statx_base.hpp" + +namespace Func2 +{ + class StatxFactory + { + public: + static bool valid(const std::string str); + static std::shared_ptr make(const std::string_view str); + }; +} diff --git a/src/func_statx_ff.cpp b/src/func_statx_ff.cpp new file mode 100644 index 00000000..f28170b9 --- /dev/null +++ b/src/func_statx_ff.cpp @@ -0,0 +1,48 @@ +#include "func_statx_ff.hpp" + +#include "fs_statx.hpp" +#include "fs_inode.hpp" +#include "symlinkify.hpp" + + +std::string_view +Func2::StatxFF::name() const +{ + return "ff"; +} + +int +Func2::StatxFF::operator()(const Branches &branches_, + const fs::path &fusepath_, + const u32 flags_, + const u32 mask_, + struct fuse_statx *st_, + const FollowSymlinksEnum follow_symlinks_, + const s64 symlinkify_timeout_) +{ + int rv; + fs::path fullpath; + + for(const auto &branch : branches_) + { + fullpath = branch.path / fusepath_; + rv = fs::statx(AT_FDCWD, + fullpath, + flags_|AT_SYMLINK_NOFOLLOW, + mask_, + st_, + follow_symlinks_); + if(rv < 0) + continue; + + symlinkify::convert_if_can_be_symlink(fullpath, + st_, + symlinkify_timeout_); + + fs::inode::calc(branch.path,fusepath_,st_); + + return rv; + } + + return -ENOENT; +} diff --git a/src/func_statx_ff.hpp b/src/func_statx_ff.hpp new file mode 100644 index 00000000..f216a3bf --- /dev/null +++ b/src/func_statx_ff.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "func_statx_base.hpp" + +namespace Func2 +{ + class StatxFF : public StatxBase + { + public: + StatxFF() {} + ~StatxFF() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + const u32 flags_, + const u32 mask_, + struct fuse_statx *st, + const FollowSymlinksEnum follow_symlinks, + const s64 symlinkify_timeout); + }; +} diff --git a/src/func_statx_newest.cpp b/src/func_statx_newest.cpp new file mode 100644 index 00000000..57a650cc --- /dev/null +++ b/src/func_statx_newest.cpp @@ -0,0 +1,64 @@ +#include "func_statx_newest.hpp" + +#include "fs_statx.hpp" +#include "fs_inode.hpp" +#include "symlinkify.hpp" +#include "timespec_utils.hpp" + + +std::string_view +Func2::StatxNewest::name() const +{ + return "newest"; +} + +int +Func2::StatxNewest::operator()(const Branches &branches_, + const fs::path &fusepath_, + const u32 flags_, + const u32 mask_, + struct fuse_statx *st_, + const FollowSymlinksEnum follow_symlinks_, + const s64 symlinkify_timeout_) +{ + int rv; + fs::path fullpath; + const Branch *newest_branch; + + newest_branch = nullptr; + for(const auto &branch : branches_) + { + struct fuse_statx tmp_st; + + fullpath = branch.path / fusepath_; + rv = fs::statx(AT_FDCWD, + fullpath, + flags_|AT_SYMLINK_NOFOLLOW, + mask_, + &tmp_st, + follow_symlinks_); + if(rv < 0) + continue; + + if(not TimeSpec::is_newer(tmp_st.mtime,st_->mtime)) + continue; + + *st_ = tmp_st; + newest_branch = &branch; + } + + if(!newest_branch) + return -ENOENT; + + if(symlinkify_timeout_ >= 0) + { + fullpath = newest_branch->path / fusepath_; + symlinkify::convert_if_can_be_symlink(fullpath, + st_, + symlinkify_timeout_); + } + + fs::inode::calc(newest_branch->path,fusepath_,st_); + + return 0; +} diff --git a/src/func_statx_newest.hpp b/src/func_statx_newest.hpp new file mode 100644 index 00000000..220ed7bf --- /dev/null +++ b/src/func_statx_newest.hpp @@ -0,0 +1,23 @@ +#include "func_statx_base.hpp" + +namespace Func2 +{ + class StatxNewest : public StatxBase + { + public: + StatxNewest() {} + ~StatxNewest() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + const u32 flags_, + const u32 mask_, + struct fuse_statx *st, + const FollowSymlinksEnum follow_symlinks, + const s64 symlinkify_timeout); + }; +} diff --git a/src/fuse_getattr.cpp b/src/fuse_getattr.cpp index 2dfe0096..c31f373f 100644 --- a/src/fuse_getattr.cpp +++ b/src/fuse_getattr.cpp @@ -34,42 +34,6 @@ #include -static -void -_set_stat_if_leads_to_dir(const fs::path &path_, - struct stat *st_) -{ - int rv; - struct stat st; - - rv = fs::stat(path_,&st); - if(rv < 0) - return; - - if(S_ISDIR(st.st_mode)) - *st_ = st; - - return; -} - -static -void -_set_stat_if_leads_to_reg(const fs::path &path_, - struct stat *st_) -{ - int rv; - struct stat st; - - rv = fs::stat(path_,&st); - if(rv < 0) - return; - - if(S_ISREG(st.st_mode)) - *st_ = st; - - return; -} - static int _getattr_fake_root(struct stat *st_) @@ -116,61 +80,6 @@ _getattr_controlfile(struct stat *st_) return 0; } -static -int -_getattr(const Policy::Search &searchFunc_, - const Branches &branches_, - const fs::path &fusepath_, - struct stat *st_, - const bool symlinkify_, - const time_t symlinkify_timeout_, - FollowSymlinks followsymlinks_) -{ - int rv; - fs::path fullpath; - std::vector branches; - - rv = searchFunc_(branches_,fusepath_,branches); - if(rv < 0) - return rv; - - fullpath = branches[0]->path / fusepath_; - - switch(followsymlinks_) - { - case FollowSymlinks::ENUM::NEVER: - rv = fs::lstat(fullpath,st_); - break; - case FollowSymlinks::ENUM::DIRECTORY: - rv = fs::lstat(fullpath,st_); - if(S_ISLNK(st_->st_mode)) - ::_set_stat_if_leads_to_dir(fullpath,st_); - break; - case FollowSymlinks::ENUM::REGULAR: - rv = fs::lstat(fullpath,st_); - if(S_ISLNK(st_->st_mode)) - ::_set_stat_if_leads_to_reg(fullpath,st_); - break; - case FollowSymlinks::ENUM::ALL: - rv = fs::stat(fullpath,st_); - if(rv < 0) - rv = fs::lstat(fullpath,st_); - break; - } - - if(rv < 0) - return rv; - - if(symlinkify_ && symlinkify::can_be_symlink(*st_,symlinkify_timeout_)) - symlinkify::convert(fullpath,st_); - - fs::inode::calc(branches[0]->path, - fusepath_, - st_); - - return 0; -} - int _getattr(const fs::path &fusepath_, struct stat *st_, @@ -178,13 +87,11 @@ _getattr(const fs::path &fusepath_, { int rv; - rv = ::_getattr(cfg.func.getattr.policy, - cfg.branches, - fusepath_, - st_, - cfg.symlinkify, - cfg.symlinkify_timeout, - cfg.follow_symlinks); + rv = cfg.getattr(cfg.branches, + fusepath_, + st_, + cfg.follow_symlinks, + cfg.symlinkify_timeout); if((rv < 0) && Config::is_rootdir(fusepath_)) return ::_getattr_fake_root(st_); diff --git a/src/fuse_statx_supported.icpp b/src/fuse_statx_supported.icpp index 32089583..8c64288f 100644 --- a/src/fuse_statx_supported.icpp +++ b/src/fuse_statx_supported.icpp @@ -30,49 +30,11 @@ #include "symlinkify.hpp" #include "ugid.hpp" -#include "fmt/core.h" - #include "fuse.h" #include -static -void -_set_stat_if_leads_to_dir(const fs::path &path_, - struct fuse_statx *st_) -{ - int rv; - struct fuse_statx st; - - rv = fs::statx(AT_FDCWD,path_,AT_SYMLINK_FOLLOW,STATX_TYPE,&st); - if(rv < 0) - return; - - if(S_ISDIR(st.mode)) - *st_ = st; - - return; -} - -static -void -_set_stat_if_leads_to_reg(const fs::path &path_, - struct fuse_statx *st_) -{ - int rv; - struct fuse_statx st; - - rv = fs::statx(AT_FDCWD,path_,AT_SYMLINK_FOLLOW,STATX_TYPE,&st); - if(rv < 0) - return; - - if(S_ISREG(st.mode)) - *st_ = st; - - return; -} - static int _statx_fake_root(struct fuse_statx *st_) @@ -113,63 +75,6 @@ _statx_controlfile(struct fuse_statx *st_) return 0; } -static -int -_statx(const Policy::Search &searchFunc_, - const Branches &branches_, - const fs::path &fusepath_, - const uint32_t flags_, - const uint32_t mask_, - struct fuse_statx *st_, - const bool symlinkify_, - const time_t symlinkify_timeout_, - FollowSymlinks followsymlinks_) -{ - int rv; - fs::path fullpath; - std::vector branches; - - rv = searchFunc_(branches_,fusepath_,branches); - if(rv < 0) - return rv; - - fullpath = branches[0]->path / fusepath_; - - switch(followsymlinks_) - { - case FollowSymlinks::ENUM::NEVER: - rv = fs::statx(AT_FDCWD,fullpath,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_); - break; - case FollowSymlinks::ENUM::DIRECTORY: - rv = fs::statx(AT_FDCWD,fullpath,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_); - if((rv >= 0) && S_ISLNK(st_->mode)) - ::_set_stat_if_leads_to_dir(fullpath,st_); - break; - case FollowSymlinks::ENUM::REGULAR: - rv = fs::statx(AT_FDCWD,fullpath,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_); - if((rv >= 0) && S_ISLNK(st_->mode)) - ::_set_stat_if_leads_to_reg(fullpath,st_); - break; - case FollowSymlinks::ENUM::ALL: - rv = fs::statx(AT_FDCWD,fullpath,flags_|AT_SYMLINK_FOLLOW,mask_,st_); - if(rv < 0) - rv = fs::statx(AT_FDCWD,fullpath,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_); - break; - } - - if(rv < 0) - return rv; - - if(symlinkify_ && symlinkify::can_be_symlink(*st_,symlinkify_timeout_)) - symlinkify::convert(fullpath,st_); - - fs::inode::calc(branches[0]->path, - fusepath_, - st_); - - return 0; -} - static int _statx(const fs::path &fusepath_, @@ -180,15 +85,13 @@ _statx(const fs::path &fusepath_, { int rv; - rv = ::_statx(cfg.func.getattr.policy, - cfg.branches, - fusepath_, - flags_, - mask_, - st_, - cfg.symlinkify, - cfg.symlinkify_timeout, - cfg.follow_symlinks); + rv = cfg.statx(cfg.branches, + fusepath_, + flags_, + mask_, + st_, + cfg.follow_symlinks, + cfg.symlinkify_timeout); if((rv < 0) && Config::is_rootdir(fusepath_)) return ::_statx_fake_root(st_); diff --git a/src/timespec_utils.hpp b/src/timespec_utils.hpp new file mode 100644 index 00000000..24fbbd05 --- /dev/null +++ b/src/timespec_utils.hpp @@ -0,0 +1,72 @@ +#pragma once + +namespace TimeSpec +{ + static + inline + bool + is_newer(const timespec &t0_, + const timespec &t1_) + { + if(t0_.tv_sec > t1_.tv_sec) + return true; + if(t0_.tv_sec == t1_.tv_sec) + { + if(t0_.tv_nsec > t1_.tv_nsec) + return true; + } + + return false; + } + + static + inline + timespec + newest(const timespec &t0_, + const timespec &t1_) + { + if(t0_.tv_sec > t1_.tv_sec) + return t0_; + if(t0_.tv_sec == t1_.tv_sec) + { + if(t0_.tv_nsec > t1_.tv_nsec) + return t0_; + } + + return t1_; + } + + static + inline + bool + is_newer(const fuse_sx_time &t0_, + const fuse_sx_time &t1_) + { + if(t0_.tv_sec > t1_.tv_sec) + return true; + if(t0_.tv_sec == t1_.tv_sec) + { + if(t0_.tv_nsec > t1_.tv_nsec) + return true; + } + + return false; + } + + static + inline + fuse_sx_time + newest(const fuse_sx_time &t0_, + const fuse_sx_time &t1_) + { + if(t0_.tv_sec > t1_.tv_sec) + return t0_; + if(t0_.tv_sec == t1_.tv_sec) + { + if(t0_.tv_nsec > t1_.tv_nsec) + return t0_; + } + + return t1_; + } +} diff --git a/src/to_cstr.hpp b/src/to_cstr.hpp new file mode 100644 index 00000000..85da6ff4 --- /dev/null +++ b/src/to_cstr.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include + + +template +const char* +to_cstr(const PathType &p_) +{ + if constexpr (std::is_same_v, std::filesystem::path>) + return p_.c_str(); + if constexpr (std::is_same_v, std::string>) + return p_.c_str(); + if constexpr (std::is_same_v, const char*> || + std::is_same_v, char*>) + return p_; + + abort(); + return NULL; +}