Compare commits

...
1 Commits
Author SHA1 Message Date
Antonio SJ Musumeci 7a5e94be74 fs_stat.hpp 2025-07-27 18:34:03 -05:00
30 changed files with 862 additions and 87 deletions
+1
View File
@@ -74,6 +74,7 @@ CXXFLAGS ?= ${OPT_FLAGS}
CXXFLAGS := \
${CXXFLAGS} \
-std=c++17 \
-fno-rtti \
$(STATIC_FLAGS) \
$(LTO_FLAGS) \
-Isrc \
+11
View File
@@ -0,0 +1,11 @@
struct ffi
{
uint64_t nodeid;
uint64_t gen;
uid_t uid;
gid_t gid;
pid_t pid;
uint64_t fh;
char *name;
char path[0];
};
+9
View File
@@ -1567,6 +1567,9 @@ fuse_lib_lookup(fuse_req_t req,
nodeid = hdr_->nodeid;
f = req_fuse_prepare(req);
fmt::print("lookup: {}\n",
nodeid);
if(name[0] == '.')
{
if(name[1] == '\0')
@@ -1685,6 +1688,9 @@ fuse_lib_getattr(fuse_req_t req,
arg = (fuse_getattr_in*)fuse_hdr_arg(hdr_);
f = req_fuse_prepare(req);
fmt::print("getattr: {}\n",
hdr_->nodeid);
fh = 0;
if(arg->getattr_flags & FUSE_GETATTR_FH)
fh = arg->fh;
@@ -1789,6 +1795,9 @@ fuse_lib_statx(fuse_req_t req_,
struct fuse *f = req_fuse_prepare(req_);
fuse_statx_in *inarg;
fmt::print("statx: {}\n",
hdr_->nodeid);
inarg = (fuse_statx_in*)fuse_hdr_arg(hdr_);
if(inarg->getattr_flags & FUSE_GETATTR_FH)
+7
View File
@@ -80,6 +80,13 @@ public:
operator Ptr() const { std::lock_guard<std::mutex> lg(_mutex); return _impl; }
Ptr operator->() const { std::lock_guard<std::mutex> lg(_mutex); return _impl; }
public:
Impl::iterator begin() { return _impl->begin(); }
Impl::iterator end() { return _impl->end(); }
Impl::const_iterator begin() const { return _impl->begin(); }
Impl::const_iterator end() const { return _impl->end(); }
public:
void find_and_set_mode_ro();
};
+2
View File
@@ -223,6 +223,8 @@ Config::Config()
_map["process-thread-queue-depth"] = &fuse_process_thread_queue_depth;
_map["version"] = &version;
_map["xattr"] = &xattr;
_map["func2.getattr"] = &getattr;
}
Config&
+6 -1
View File
@@ -16,6 +16,8 @@
#pragma once
#include "func_getattr.hpp"
#include "branches.hpp"
#include "category.hpp"
#include "config_cachefiles.hpp"
@@ -56,6 +58,7 @@
typedef ToFromWrapper<bool> ConfigBOOL;
typedef ToFromWrapper<uint64_t> ConfigUINT64;
typedef ToFromWrapper<int64_t> ConfigS64;
typedef ToFromWrapper<int> ConfigINT;
typedef ToFromWrapper<std::string> ConfigSTR;
typedef ToFromWrapper<std::filesystem::path> ConfigPath;
@@ -161,7 +164,7 @@ public:
StatFS statfs;
StatFSIgnore statfs_ignore;
ConfigBOOL symlinkify;
ConfigUINT64 symlinkify_timeout;
ConfigS64 symlinkify_timeout;
ConfigINT fuse_read_thread_count;
ConfigINT fuse_process_thread_count;
ConfigINT fuse_process_thread_queue_depth;
@@ -170,6 +173,8 @@ public:
ConfigBOOL writeback_cache;
XAttr xattr;
Func2::GetAttr getattr{"combine"};
private:
bool _initialized;
+1 -7
View File
@@ -18,13 +18,7 @@
#pragma once
#include "follow_symlinks_enum.hpp"
#include "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
};
+47
View File
@@ -65,6 +65,53 @@ namespace str
return 0;
}
int
from(const std::string &value_,
int64_t *int64_)
{
char *endptr;
int64_t tmp;
tmp = ::strtoll(value_.c_str(),&endptr,10);
switch(*endptr)
{
case 'b':
case 'B':
tmp *= 1ULL;
break;
case 'k':
case 'K':
tmp *= 1024ULL;
break;
case 'm':
case 'M':
tmp *= (1024ULL * 1024ULL);
break;
case 'g':
case 'G':
tmp *= (1024ULL * 1024ULL * 1024ULL);
break;
case 't':
case 'T':
tmp *= (1024ULL * 1024ULL * 1024ULL * 1024ULL);
break;
case '\0':
break;
default:
return -EINVAL;
}
*int64_ = tmp;
return 0;
}
int
from(const std::string &value_,
uint64_t *uint64_)
+1
View File
@@ -29,6 +29,7 @@ namespace str
int from(const std::string &, bool *);
int from(const std::string &, int *);
int from(const std::string &, uint64_t *);
int from(const std::string &, int64_t *);
int from(const std::string &, std::string *);
int from(const std::string &, const std::string *);
int from(const std::string &, fs::Path *);
+70
View File
@@ -0,0 +1,70 @@
#include "fs_stat.hpp"
#include "fs_lstat.hpp"
static
void
_set_stat_if_leads_to_dir(const char *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 char *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;
}
int
fs::stat(const char *path_,
struct stat *st_,
FollowSymlinksEnum follow_)
{
int rv;
switch(follow_)
{
case FollowSymlinksEnum::NEVER:
rv = fs::lstat(path_,st_);
break;
case FollowSymlinksEnum::DIRECTORY:
rv = fs::lstat(path_,st_);
if(S_ISLNK(st_->st_mode))
_set_stat_if_leads_to_dir(path_,st_);
break;
case FollowSymlinksEnum::REGULAR:
rv = fs::lstat(path_,st_);
if(S_ISLNK(st_->st_mode))
_set_stat_if_leads_to_reg(path_,st_);
break;
case FollowSymlinksEnum::ALL:
rv = fs::stat(path_,st_);
if(rv != 0)
rv = fs::lstat(path_,st_);
break;
}
return rv;
}
+18
View File
@@ -18,6 +18,7 @@
#pragma once
#include "follow_symlinks_enum.hpp"
#include "to_neg_errno.hpp"
#include <string>
@@ -50,4 +51,21 @@ namespace fs
{
return fs::stat(path_.c_str(),st_);
}
int
stat(const char *path,
struct stat *st,
FollowSymlinksEnum follow);
static
inline
int
stat(const std::string &path_,
struct stat *st_,
FollowSymlinksEnum follow_)
{
return fs::stat(path_.c_str(),
st_,
follow_);
}
}
+90
View File
@@ -0,0 +1,90 @@
/*
ISC License
Copyright (c) 2025, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "fs_statx.hpp"
static
void
_set_stat_if_leads_to_dir(const std::string &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 std::string &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;
}
int
fs::statx(const int dirfd_,
const char *pathname_,
const int flags_,
const unsigned int mask_,
struct fuse_statx *st_,
FollowSymlinksEnum follow_)
{
int rv;
switch(follow_)
{
case FollowSymlinksEnum::NEVER:
rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_);
break;
case FollowSymlinksEnum::DIRECTORY:
rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_);
if((rv >= 0) && S_ISLNK(st_->mode))
::_set_stat_if_leads_to_dir(pathname_,st_);
break;
case FollowSymlinksEnum::REGULAR:
rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_);
if((rv >= 0) && S_ISLNK(st_->mode))
::_set_stat_if_leads_to_reg(pathname_,st_);
break;
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_);
break;
}
return rv;
}
+61 -1
View File
@@ -1,6 +1,7 @@
#pragma once
#include "to_neg_errno.hpp"
#include "follow_symlinks_enum.hpp"
#include "fuse_kernel.h"
@@ -14,7 +15,7 @@
#include <sys/stat.h>
#ifdef STATX_TYPE
#define MERGERFS_STATX_SUPPORTED
//#define MERGERFS_STATX_SUPPORTED
#endif
namespace fs
@@ -54,4 +55,63 @@ namespace fs
{
return fs::statx(dirfd_,pathname_.c_str(),flags_,mask_,st_);
}
int
statx(const int dirfd,
const char *pathname,
const int flags,
const unsigned int mask,
struct fuse_statx *st,
FollowSymlinksEnum follow);
static
inline
int
statx(const int dirfd_,
const std::string &pathname_,
const int flags_,
const unsigned int mask_,
struct fuse_statx *st_,
FollowSymlinksEnum follow_)
{
return fs::statx(dirfd_,
pathname_.c_str(),
flags_,
mask_,
st_,
follow_);
}
static
inline
int
statx(const char *pathname_,
const int flags_,
const unsigned int mask_,
struct fuse_statx *st_,
FollowSymlinksEnum follow_)
{
return fs::statx(AT_FDCWD,
pathname_,
flags_,
mask_,
st_,
follow_);
}
static
inline
int
statx(const std::string &pathname_,
const int flags_,
const unsigned int mask_,
struct fuse_statx *st_,
FollowSymlinksEnum follow_)
{
return fs::statx(pathname_.c_str(),
flags_,
mask_,
st_,
follow_);
}
}
+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 &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;
};
}
+64
View File
@@ -0,0 +1,64 @@
#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 st;
fullpath = branch.path;
fullpath += fusepath_;
rv = fs::stat(fullpath.c_str(),&st,follow_symlinks_);
if(rv == -1)
continue;
if(!first_branch)
{
*st_ = st;
first_branch = &branch;
continue;
}
st_->st_atim = TimeSpec::newest(st_->st_atim,st.st_atim);
st_->st_ctim = TimeSpec::newest(st_->st_ctim,st.st_ctim);
st_->st_mtim = TimeSpec::newest(st_->st_mtim,st.st_mtim);
st_->st_nlink += st.st_nlink;
}
if(!first_branch)
return -ENOENT;
if(symlinkify_timeout_ >= 0)
{
fullpath = fs::path::make(first_branch->path,fusepath_);
symlinkify::convert_if_can_be_symlink(fullpath,
st_,
symlinkify_timeout_);
}
fs::inode::calc(first_branch->path,fusepath_.string(),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 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 str);
};
}
+42
View File
@@ -0,0 +1,42 @@
#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;
fullpath += fusepath_;
rv = fs::stat(fullpath.string(),st_,follow_symlinks_);
if(rv != 0)
continue;
symlinkify::convert_if_can_be_symlink(fullpath,
st_,
symlinkify_timeout_);
fs::inode::calc(branch.path,fusepath_.string(),st_);
return 0;
}
return -ENOENT;
}
+21
View File
@@ -0,0 +1,21 @@
#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);
};
}
+58
View File
@@ -0,0 +1,58 @@
#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;
fullpath += fusepath_;
rv = fs::stat(fullpath,&tmp_st,follow_symlinks_);
if(rv == -1)
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 = fs::path::make(newest_branch->path,fusepath_);
symlinkify::convert_if_can_be_symlink(fullpath,
st_,
symlinkify_timeout_);
}
fs::inode::calc(newest_branch->path,fusepath_.string(),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);
};
}
+11 -59
View File
@@ -36,41 +36,6 @@
#include <string>
static
void
_set_stat_if_leads_to_dir(const std::string &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 std::string &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
@@ -134,28 +99,7 @@ _statx(const Policy::Search &searchFunc_,
fullpath = fs::path::make(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;
}
rv = fs::statx(fullpath,flags_,mask_,st_,followsymlinks_);
if(rv < 0)
return rv;
@@ -210,7 +154,11 @@ FUSE::statx(const char *fusepath_,
if(Config::is_ctrl_file(fusepath_))
return ::_statx_controlfile(st_);
return ::_statx(fusepath_,flags_|AT_STATX_DONT_SYNC,mask_,st_,timeout_);
return ::_statx(fusepath_,
flags_|AT_STATX_DONT_SYNC,
mask_,
st_,
timeout_);
}
int
@@ -222,5 +170,9 @@ FUSE::statx_fh(const uint64_t fh_,
{
FileInfo *fi = reinterpret_cast<FileInfo*>(fh_);
return ::_statx(fi->fusepath.c_str(),flags_,mask_,st_,timeout_);
return ::_statx(fi->fusepath.c_str(),
flags_|AT_STATX_DONT_SYNC,
mask_,
st_,
timeout_);
}
+48 -12
View File
@@ -56,7 +56,6 @@ enum
MERGERFS_OPT_VERSION
};
static
void
_set_option(const std::string &option_,
@@ -204,7 +203,7 @@ _parse_and_process_kv_arg(Config::Write &cfg_,
static
int
process_opt(Config::Write &cfg_,
_process_opt(Config::Write &cfg_,
Config::ErrVec *errs_,
const std::string &arg_)
{
@@ -220,7 +219,7 @@ process_opt(Config::Write &cfg_,
static
int
process_branches(Config::Write &cfg_,
_process_branches(Config::Write &cfg_,
Config::ErrVec *errs_,
const char *arg_)
{
@@ -237,7 +236,7 @@ process_branches(Config::Write &cfg_,
static
int
process_mount(Config::Write &cfg_,
_process_mount(Config::Write &cfg_,
Config::ErrVec *errs_,
const char *arg_)
{
@@ -290,10 +289,10 @@ _usage(void)
static
int
option_processor(void *data_,
const char *arg_,
int key_,
fuse_args *outargs_)
_option_processor(void *data_,
const char *arg_,
int key_,
fuse_args *outargs_)
{
Config::Write cfg;
Config::ErrVec *errs = (Config::ErrVec*)data_;
@@ -301,13 +300,13 @@ option_processor(void *data_,
switch(key_)
{
case FUSE_OPT_KEY_OPT:
return process_opt(cfg,errs,arg_);
return ::_process_opt(cfg,errs,arg_);
case FUSE_OPT_KEY_NONOPT:
if(cfg->branches->empty())
return process_branches(cfg,errs,arg_);
return ::_process_branches(cfg,errs,arg_);
else
return process_mount(cfg,errs,arg_);
return ::_process_mount(cfg,errs,arg_);
case MERGERFS_OPT_HELP:
::_usage();
@@ -367,6 +366,41 @@ _check_for_mount_loop(Config::Write &cfg_,
}
}
static
void
_print_warnings(Config::Write &cfg_)
{
if(cfg_->passthrough != Passthrough::ENUM::OFF)
{
if(cfg_->cache_files == CacheFiles::ENUM::OFF)
{
SysLog::warning("'cache.files' can not be 'off' when using 'passthrough'."
" Setting 'cache.files=auto-full'");
cfg_->cache_files = CacheFiles::ENUM::AUTO_FULL;
}
if(cfg_->writeback_cache == true)
{
SysLog::warning("'cache.writeback' can not be enabled when using 'passthrough'."
" Setting 'cache.writeback=false'");
cfg_->writeback_cache = false;
}
if(cfg_->moveonenospc.enabled == true)
{
SysLog::warning("`moveonenospc` will not function when `passthrough` is enabled");
}
}
}
static
void
_cleanup_options(Config::Write &cfg_)
{
if(!cfg_->symlinkify)
cfg_->symlinkify_timeout = -1;
}
namespace options
{
void
@@ -387,7 +421,7 @@ namespace options
fuse_opt_parse(args_,
errs_,
opts,
::option_processor);
::_option_processor);
if(cfg->branches->empty())
errs_->push_back({0,"branches not set"});
@@ -400,6 +434,8 @@ namespace options
::_set_fsname(cfg,args_);
::_set_subtype(args_);
::_set_fuse_threads(cfg);
::_print_warnings(cfg);
::_cleanup_options(cfg);
cfg->finish_initializing();
}
+35 -7
View File
@@ -19,9 +19,7 @@
#pragma once
#include "fuse_kernel.h"
#include <sys/stat.h>
#include <time.h>
#include "int_types.h"
#include <string>
@@ -32,13 +30,13 @@ namespace symlinkify
inline
bool
can_be_symlink(const struct stat &st_,
const time_t timeout_)
const s64 timeout_)
{
if(S_ISDIR(st_.st_mode) ||
(st_.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)))
return false;
const time_t now = ::time(NULL);
const s64 now = ::time(NULL);
return (((now - st_.st_mtime) > timeout_) &&
((now - st_.st_ctime) > timeout_));
@@ -48,13 +46,13 @@ namespace symlinkify
inline
bool
can_be_symlink(const struct fuse_statx &st_,
const time_t timeout_)
const s64 timeout_)
{
if(S_ISDIR(st_.mode) ||
(st_.mode & (S_IWUSR|S_IWGRP|S_IWOTH)))
return false;
const time_t now = ::time(NULL);
const s64 now = ::time(NULL);
return (((now - st_.mtime.tv_sec) > timeout_) &&
((now - st_.ctime.tv_sec) > timeout_));
@@ -81,4 +79,34 @@ namespace symlinkify
st_->size = target_.size();
st_->blocks = 0;
}
static
inline
void
convert_if_can_be_symlink(const std::string &target_,
struct stat *st_,
const s64 timeout_)
{
if(timeout_ < 0)
return;
if(!symlinkify::can_be_symlink(*st_,timeout_))
return;
symlinkify::convert(target_,st_);
}
static
inline
void
convert_if_can_be_symlink(const std::string &target_,
fuse_statx *st_,
const s64 timeout_)
{
if(timeout_ < 0)
return;
if(!symlinkify::can_be_symlink(*st_,timeout_))
return;
symlinkify::convert(target_,st_);
}
}
+38
View File
@@ -0,0 +1,38 @@
#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_;
}
}
+6
View File
@@ -46,6 +46,12 @@ namespace str
return fmt::format("{}",uint64_);
}
std::string
to(const int64_t int64_)
{
return fmt::format("{}",int64_);
}
std::string
to(const std::string &s_)
{
+1
View File
@@ -29,6 +29,7 @@ namespace str
std::string to(const bool);
std::string to(const int);
std::string to(const uint64_t);
std::string to(const int64_t);
std::string to(const std::string&);
std::string to(const fs::Path&);
}