mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-20 00:17:43 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a30f8fa953 | ||
|
|
a26adb222b | ||
|
|
ce07e07ab5 | ||
|
|
28c797cdc6 | ||
|
|
c114211a48 |
+2
-1
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
enum class FollowSymlinksEnum
|
||||
{
|
||||
NEVER,
|
||||
DIRECTORY,
|
||||
REGULAR,
|
||||
ALL
|
||||
};
|
||||
+5
-14
@@ -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_);
|
||||
}
|
||||
}
|
||||
|
||||
+55
-6
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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 {};
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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 {};
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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_);
|
||||
|
||||
|
||||
@@ -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_);
|
||||
|
||||
|
||||
@@ -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_;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user