Compare commits

...
5 Commits
Author SHA1 Message Date
Antonio SJ Musumeci a30f8fa953 func_getattr_combine.cpp 2025-12-07 12:32:30 -06:00
Antonio SJ Musumeci a26adb222b func_getattr_combine.cpp 2025-12-07 02:09:45 -06:00
Antonio SJ Musumeci ce07e07ab5 func_getattr_combine.cpp 2025-12-07 02:02:03 -06:00
Antonio SJ Musumeci 28c797cdc6 func_getattr_combine.cpp 2025-12-07 02:01:17 -06:00
Antonio SJ Musumeci c114211a48 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.
2025-12-06 14:10:30 -06:00
32 changed files with 1057 additions and 239 deletions
+2 -1
View File
@@ -229,7 +229,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;
@@ -242,6 +242,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;
+6
View File
@@ -16,6 +16,9 @@
#pragma once
#include "func_getattr.hpp"
#include "func_statx.hpp"
#include "branches.hpp"
#include "category.hpp"
#include "config_cachefiles.hpp"
@@ -108,6 +111,9 @@ public:
Config& operator=(const Config&);
public:
Func2::GetAttr getattr{"combine"};
Func2::Statx statx{"combine"};
ConfigBOOL allow_idmap;
ConfigBOOL async_read;
Branches branches;
+1 -7
View File
@@ -19,12 +19,6 @@
#pragma once
#include "enum.hpp"
#include "follow_symlinks_enum.hpp"
enum class FollowSymlinksEnum
{
NEVER,
DIRECTORY,
REGULAR,
ALL
};
typedef Enum<FollowSymlinksEnum> FollowSymlinks;
+9
View File
@@ -0,0 +1,9 @@
#pragma once
enum class FollowSymlinksEnum
{
NEVER,
DIRECTORY,
REGULAR,
ALL
};
+5 -14
View File
@@ -19,8 +19,7 @@
#pragma once
#include "to_neg_errno.hpp"
#include <string>
#include "to_cstr.hpp"
#include <sys/stat.h>
#include <sys/types.h>
@@ -29,25 +28,17 @@
namespace fs
{
template<typename PathType>
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_);
}
}
View File
+55 -6
View File
@@ -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 <string>
@@ -29,25 +32,71 @@
namespace fs
{
template<typename PathType>
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<typename PathType>
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;
}
}
+52 -9
View File
@@ -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<typename PathType>
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<typename PathType>
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;
}
}
+76
View File
@@ -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
View File
@@ -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;
};
}
+70
View File
@@ -0,0 +1,70 @@
#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;
}
// This upgrades the uid:gid because mergerfs now does most
// file interaction as root and relies on `default-permissions`
// to manage permissions. If the
if(tmp_st.st_uid == 0)
st_->st_uid = 0;
if(tmp_st.st_gid == 0)
st_->st_gid = 0;
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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
};
}
+5 -98
View File
@@ -34,42 +34,6 @@
#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
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<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
_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_);
+7 -104
View File
@@ -30,49 +30,11 @@
#include "symlinkify.hpp"
#include "ugid.hpp"
#include "fmt/core.h"
#include "fuse.h"
#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
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<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
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_);
+72
View File
@@ -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
View File
@@ -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;
}