Browse Source

Change getattr and statx to bespoke policies

* Provides: slight improvement in performance as it no longer will
need to find and then act on the files.
* It doesn't make sense to support all original policy types. Most
people used 'newest' or 'ff' and 'combine' is a better default which
has same runtime as 'newest' but with better output.
getattr2
Antonio SJ Musumeci 1 week ago
parent
commit
a61b587aed
  1. 3
      src/config.cpp
  2. 6
      src/config.hpp
  3. 8
      src/config_follow_symlinks.hpp
  4. 9
      src/follow_symlinks_enum.hpp
  5. 19
      src/fs_lstat.hpp
  6. 0
      src/fs_stat.cpp
  7. 61
      src/fs_stat.hpp
  8. 61
      src/fs_statx.hpp
  9. 76
      src/func_getattr.hpp
  10. 35
      src/func_getattr_base.hpp
  11. 63
      src/func_getattr_combine.cpp
  12. 21
      src/func_getattr_combine.hpp
  13. 39
      src/func_getattr_factory.cpp
  14. 13
      src/func_getattr_factory.hpp
  15. 41
      src/func_getattr_ff.cpp
  16. 23
      src/func_getattr_ff.hpp
  17. 57
      src/func_getattr_newest.cpp
  18. 21
      src/func_getattr_newest.hpp
  19. 81
      src/func_statx.hpp
  20. 38
      src/func_statx_base.hpp
  21. 71
      src/func_statx_combine.cpp
  22. 23
      src/func_statx_combine.hpp
  23. 39
      src/func_statx_factory.cpp
  24. 13
      src/func_statx_factory.hpp
  25. 48
      src/func_statx_ff.cpp
  26. 25
      src/func_statx_ff.hpp
  27. 64
      src/func_statx_newest.cpp
  28. 23
      src/func_statx_newest.hpp
  29. 103
      src/fuse_getattr.cpp
  30. 111
      src/fuse_statx_supported.icpp
  31. 72
      src/timespec_utils.hpp
  32. 22
      src/to_cstr.hpp

3
src/config.cpp

@ -231,7 +231,7 @@ Config::Config()
_map["func.chmod"] = &func.chmod; _map["func.chmod"] = &func.chmod;
_map["func.chown"] = &func.chown; _map["func.chown"] = &func.chown;
_map["func.create"] = &func.create; _map["func.create"] = &func.create;
_map["func.getattr"] = &func.getattr;
_map["func.getattr"] = &getattr;
_map["func.getxattr"] = &func.getxattr; _map["func.getxattr"] = &func.getxattr;
_map["func.link"] = &func.link; _map["func.link"] = &func.link;
_map["func.listxattr"] = &func.listxattr; _map["func.listxattr"] = &func.listxattr;
@ -244,6 +244,7 @@ Config::Config()
_map["func.rename"] = &func.rename; _map["func.rename"] = &func.rename;
_map["func.rmdir"] = &func.rmdir; _map["func.rmdir"] = &func.rmdir;
_map["func.setxattr"] = &func.setxattr; _map["func.setxattr"] = &func.setxattr;
_map["func.statx"] = &statx;
_map["func.symlink"] = &func.symlink; _map["func.symlink"] = &func.symlink;
_map["func.truncate"] = &func.truncate; _map["func.truncate"] = &func.truncate;
_map["func.unlink"] = &func.unlink; _map["func.unlink"] = &func.unlink;

6
src/config.hpp

@ -16,6 +16,9 @@
#pragma once #pragma once
#include "func_getattr.hpp"
#include "func_statx.hpp"
#include "branches.hpp" #include "branches.hpp"
#include "category.hpp" #include "category.hpp"
#include "config_cachefiles.hpp" #include "config_cachefiles.hpp"
@ -109,6 +112,9 @@ public:
Config& operator=(const Config&); Config& operator=(const Config&);
public: public:
Func2::GetAttr getattr{"combine"};
Func2::Statx statx{"combine"};
ConfigBOOL allow_idmap; ConfigBOOL allow_idmap;
ConfigBOOL async_read; ConfigBOOL async_read;
Branches branches; Branches branches;

8
src/config_follow_symlinks.hpp

@ -19,12 +19,6 @@
#pragma once #pragma once
#include "enum.hpp" #include "enum.hpp"
#include "follow_symlinks_enum.hpp"
enum class FollowSymlinksEnum
{
NEVER,
DIRECTORY,
REGULAR,
ALL
};
typedef Enum<FollowSymlinksEnum> FollowSymlinks; typedef Enum<FollowSymlinksEnum> FollowSymlinks;

9
src/follow_symlinks_enum.hpp

@ -0,0 +1,9 @@
#pragma once
enum class FollowSymlinksEnum
{
NEVER,
DIRECTORY,
REGULAR,
ALL
};

19
src/fs_lstat.hpp

@ -19,8 +19,7 @@
#pragma once #pragma once
#include "to_neg_errno.hpp" #include "to_neg_errno.hpp"
#include <string>
#include "to_cstr.hpp"
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
@ -29,25 +28,17 @@
namespace fs namespace fs
{ {
template<typename PathType>
static static
inline inline
int int
lstat(const char *path_,
struct stat *st_)
lstat(const PathType &path_,
struct stat *st_)
{ {
int rv; int rv;
rv = ::lstat(path_,st_);
rv = ::lstat(to_cstr(path_),st_);
return ::to_neg_errno(rv); return ::to_neg_errno(rv);
} }
static
inline
int
lstat(const std::string &path_,
struct stat *st_)
{
return fs::lstat(path_.c_str(),st_);
}
} }

0
src/fs_stat.cpp

61
src/fs_stat.hpp

@ -18,7 +18,10 @@
#pragma once #pragma once
#include "follow_symlinks_enum.hpp"
#include "to_neg_errno.hpp" #include "to_neg_errno.hpp"
#include "to_cstr.hpp"
#include "fs_lstat.hpp"
#include <string> #include <string>
@ -29,25 +32,71 @@
namespace fs namespace fs
{ {
template<typename PathType>
static static
inline inline
int int
stat(const char *path_,
struct stat *st_)
stat(const PathType &path_,
struct stat *st_)
{ {
int rv; int rv;
rv = ::stat(path_,st_);
rv = ::stat(to_cstr(path_),st_);
return ::to_neg_errno(rv); return ::to_neg_errno(rv);
} }
template<typename PathType>
static static
inline inline
int 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;
} }
} }

61
src/fs_statx.hpp

@ -1,5 +1,7 @@
#pragma once #pragma once
#include "follow_symlinks_enum.hpp"
#include "to_cstr.hpp"
#include "to_neg_errno.hpp" #include "to_neg_errno.hpp"
#include "fuse_kernel.h" #include "fuse_kernel.h"
@ -17,11 +19,12 @@
namespace fs namespace fs
{ {
template<typename PathType>
static static
inline inline
int int
statx(const int dirfd_, statx(const int dirfd_,
const char *pathname_,
const PathType &pathname_,
const int flags_, const int flags_,
const unsigned int mask_, const unsigned int mask_,
struct fuse_statx *st_) struct fuse_statx *st_)
@ -30,7 +33,7 @@ namespace fs
int rv; int rv;
rv = ::statx(dirfd_, rv = ::statx(dirfd_,
pathname_,
to_cstr(pathname_),
flags_, flags_,
mask_, mask_,
(struct statx*)st_); (struct statx*)st_);
@ -41,19 +44,59 @@ namespace fs
#endif #endif
} }
template<typename PathType>
static static
inline inline
int int
statx(const int dirfd_, statx(const int dirfd_,
const std::string &pathname_,
const PathType &pathname_,
const int flags_, const int flags_,
const unsigned int mask_, 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;
} }
} }

76
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 <atomic>
#include <cassert>
namespace Func2
{
class GetAttr : public ToFromString
{
private:
std::shared_ptr<Func2::GetAttrBase> _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<Func2::GetAttrBase> p;
p = std::atomic_load(&_impl);
return (*p)(branches_,
fusepath_,
st_,
follow_symlinks_,
symlinkify_timeout_);
}
public:
std::string
to_string() const
{
std::shared_ptr<Func2::GetAttrBase> p;
p = std::atomic_load(&_impl);
return std::string(p->name());
}
int
from_string(const std::string_view str_)
{
std::shared_ptr<Func2::GetAttrBase> p;
p = Func2::GetAttrFactory::make(str_);
if(!p)
return -EINVAL;
_impl = std::atomic_load(&p);
return 0;
}
};
}

35
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 <string_view>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
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;
};
}

63
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;
}

21
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);
};
}

39
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::GetAttrBase>
Func2::GetAttrFactory::make(const std::string_view str_)
{
if(str_ == "combine")
return std::make_shared<Func2::GetAttrCombine>();
if(str_ == "ff")
return std::make_shared<Func2::GetAttrFF>();
if(str_ == "newest")
return std::make_shared<Func2::GetAttrNewest>();
if(Policies::Search::find(str_))
return std::make_shared<Func2::GetAttrCombine>();
return {};
}

13
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<GetAttrBase> make(const std::string_view str);
};
}

41
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;
}

23
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);
};
}

57
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;
}

21
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);
};
}

81
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 <atomic>
#include <assert.h>
namespace Func2
{
class Statx : public ToFromString
{
private:
std::shared_ptr<Func2::StatxBase> _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<Func2::StatxBase> 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<Func2::StatxBase> p;
p = std::atomic_load(&_impl);
return std::string(p->name());
}
int
from_string(const std::string_view str_)
{
std::shared_ptr<Func2::StatxBase> p;
p = Func2::StatxFactory::make(str_);
if(!p)
return -EINVAL;
_impl = std::atomic_load(&p);
return 0;
}
};
}

38
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 <string_view>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
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;
};
}

71
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;
}

23
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);
};
}

39
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::StatxBase>
Func2::StatxFactory::make(const std::string_view str_)
{
if(str_ == "combine")
return std::make_shared<Func2::StatxCombine>();
if(str_ == "ff")
return std::make_shared<Func2::StatxFF>();
if(str_ == "newest")
return std::make_shared<Func2::StatxNewest>();
if(Policies::Search::find(str_))
return std::make_shared<Func2::StatxCombine>();
return {};
}

13
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<StatxBase> make(const std::string_view str);
};
}

48
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;
}

25
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);
};
}

64
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;
}

23
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);
};
}

103
src/fuse_getattr.cpp

@ -34,42 +34,6 @@
#include <string> #include <string>
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 static
int int
_getattr_fake_root(struct stat *st_) _getattr_fake_root(struct stat *st_)
@ -116,61 +80,6 @@ _getattr_controlfile(struct stat *st_)
return 0; 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<Branch*> 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 int
_getattr(const fs::path &fusepath_, _getattr(const fs::path &fusepath_,
struct stat *st_, struct stat *st_,
@ -178,13 +87,11 @@ _getattr(const fs::path &fusepath_,
{ {
int rv; 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_)) if((rv < 0) && Config::is_rootdir(fusepath_))
return ::_getattr_fake_root(st_); return ::_getattr_fake_root(st_);

111
src/fuse_statx_supported.icpp

@ -30,49 +30,11 @@
#include "symlinkify.hpp" #include "symlinkify.hpp"
#include "ugid.hpp" #include "ugid.hpp"
#include "fmt/core.h"
#include "fuse.h" #include "fuse.h"
#include <string> #include <string>
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 static
int int
_statx_fake_root(struct fuse_statx *st_) _statx_fake_root(struct fuse_statx *st_)
@ -113,63 +75,6 @@ _statx_controlfile(struct fuse_statx *st_)
return 0; 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<Branch*> 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 static
int int
_statx(const fs::path &fusepath_, _statx(const fs::path &fusepath_,
@ -180,15 +85,13 @@ _statx(const fs::path &fusepath_,
{ {
int rv; 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_)) if((rv < 0) && Config::is_rootdir(fusepath_))
return ::_statx_fake_root(st_); return ::_statx_fake_root(st_);

72
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_;
}
}

22
src/to_cstr.hpp

@ -0,0 +1,22 @@
#pragma once
#include <filesystem>
#include <string>
#include <type_traits>
template<typename PathType>
const char*
to_cstr(const PathType &p_)
{
if constexpr (std::is_same_v<std::decay_t<PathType>, std::filesystem::path>)
return p_.c_str();
if constexpr (std::is_same_v<std::decay_t<PathType>, std::string>)
return p_.c_str();
if constexpr (std::is_same_v<std::decay_t<PathType>, const char*> ||
std::is_same_v<std::decay_t<PathType>, char*>)
return p_;
abort();
return NULL;
}
Loading…
Cancel
Save