Browse Source

fs_stat.hpp

getattr
Antonio SJ Musumeci 2 months ago
parent
commit
7a5e94be74
  1. 1
      Makefile
  2. 11
      libfuse/lib/ffi.h
  3. 9
      libfuse/lib/fuse.cpp
  4. 7
      src/branches.hpp
  5. 2
      src/config.cpp
  6. 7
      src/config.hpp
  7. 8
      src/config_follow_symlinks.hpp
  8. 9
      src/follow_symlinks_enum.hpp
  9. 47
      src/from_string.cpp
  10. 1
      src/from_string.hpp
  11. 70
      src/fs_stat.cpp
  12. 18
      src/fs_stat.hpp
  13. 90
      src/fs_statx.cpp
  14. 62
      src/fs_statx.hpp
  15. 76
      src/func_getattr.hpp
  16. 35
      src/func_getattr_base.hpp
  17. 64
      src/func_getattr_combine.cpp
  18. 21
      src/func_getattr_combine.hpp
  19. 39
      src/func_getattr_factory.cpp
  20. 13
      src/func_getattr_factory.hpp
  21. 42
      src/func_getattr_ff.cpp
  22. 21
      src/func_getattr_ff.hpp
  23. 58
      src/func_getattr_newest.cpp
  24. 21
      src/func_getattr_newest.hpp
  25. 70
      src/fuse_statx_supported.icpp
  26. 60
      src/option_parser.cpp
  27. 42
      src/symlinkify.hpp
  28. 38
      src/timespec_utils.hpp
  29. 6
      src/to_string.cpp
  30. 1
      src/to_string.hpp

1
Makefile

@ -74,6 +74,7 @@ CXXFLAGS ?= ${OPT_FLAGS}
CXXFLAGS := \
${CXXFLAGS} \
-std=c++17 \
-fno-rtti \
$(STATIC_FLAGS) \
$(LTO_FLAGS) \
-Isrc \

11
libfuse/lib/ffi.h

@ -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
libfuse/lib/fuse.cpp

@ -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
src/branches.hpp

@ -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
src/config.cpp

@ -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&

7
src/config.hpp

@ -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;

8
src/config_follow_symlinks.hpp

@ -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
src/follow_symlinks_enum.hpp

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

47
src/from_string.cpp

@ -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
src/from_string.hpp

@ -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
src/fs_stat.cpp

@ -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
src/fs_stat.hpp

@ -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
src/fs_statx.cpp

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

62
src/fs_statx.hpp

@ -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
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 &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;
};
}

64
src/func_getattr_combine.cpp

@ -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
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 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 str);
};
}

42
src/func_getattr_ff.cpp

@ -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
src/func_getattr_ff.hpp

@ -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
src/func_getattr_newest.cpp

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

70
src/fuse_statx_supported.icpp

@ -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_);
}

60
src/option_parser.cpp

@ -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();
}

42
src/symlinkify.hpp

@ -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
src/timespec_utils.hpp

@ -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
src/to_string.cpp

@ -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
src/to_string.hpp

@ -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&);
}
Loading…
Cancel
Save