mirror of https://github.com/trapexit/mergerfs.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
186 lines
4.3 KiB
186 lines
4.3 KiB
#include "fuse_statx.hpp"
|
|
|
|
#include "config.hpp"
|
|
#include "errno.hpp"
|
|
#include "fileinfo.hpp"
|
|
#include "fs_inode.hpp"
|
|
#include "fs_path.hpp"
|
|
#include "fs_statx.hpp"
|
|
#include "symlinkify.hpp"
|
|
#include "ugid.hpp"
|
|
|
|
#include "fmt/core.h"
|
|
|
|
#include "fuse.h"
|
|
|
|
#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
|
|
_statx_controlfile(struct fuse_statx *st_)
|
|
{
|
|
static const uid_t uid = ::getuid();
|
|
static const gid_t gid = ::getgid();
|
|
static const time_t now = ::time(NULL);
|
|
|
|
st_->ino = 0;
|
|
st_->mode = (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
|
|
st_->nlink = 1;
|
|
st_->uid = uid;
|
|
st_->gid = gid;
|
|
st_->size = 0;
|
|
st_->blocks = 0;
|
|
st_->atime.tv_sec = now;
|
|
st_->mtime.tv_sec = now;
|
|
st_->ctime.tv_sec = now;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
int
|
|
_statx(const Policy::Search &searchFunc_,
|
|
const Branches &branches_,
|
|
const char *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;
|
|
std::string fullpath;
|
|
StrVec basepaths;
|
|
|
|
rv = searchFunc_(branches_,fusepath_,&basepaths);
|
|
if(rv == -1)
|
|
return -errno;
|
|
|
|
fullpath = fs::path::make(basepaths[0],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(basepaths[0],fusepath_,st_);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
int
|
|
_statx(const char *fusepath_,
|
|
const uint32_t flags_,
|
|
const uint32_t mask_,
|
|
struct fuse_statx *st_,
|
|
fuse_timeouts_t *timeout_)
|
|
{
|
|
int rv;
|
|
Config::Read cfg;
|
|
const fuse_context *fc = fuse_get_context();
|
|
const ugid::Set ugid(fc->uid,fc->gid);
|
|
|
|
rv = ::_statx(cfg->func.getattr.policy,
|
|
cfg->branches,
|
|
fusepath_,
|
|
flags_,
|
|
mask_,
|
|
st_,
|
|
cfg->symlinkify,
|
|
cfg->symlinkify_timeout,
|
|
cfg->follow_symlinks);
|
|
|
|
timeout_->entry = ((rv >= 0) ?
|
|
cfg->cache_entry :
|
|
cfg->cache_negative_entry);
|
|
timeout_->attr = cfg->cache_attr;
|
|
|
|
return rv;
|
|
}
|
|
|
|
int
|
|
FUSE::statx(const char *fusepath_,
|
|
const uint32_t flags_,
|
|
const uint32_t mask_,
|
|
struct fuse_statx *st_,
|
|
fuse_timeouts_t *timeout_)
|
|
{
|
|
if(fusepath_ == CONTROLFILE)
|
|
return ::_statx_controlfile(st_);
|
|
|
|
return ::_statx(fusepath_,flags_|AT_STATX_DONT_SYNC,mask_,st_,timeout_);
|
|
}
|
|
|
|
int
|
|
FUSE::statx_fh(const uint64_t fh_,
|
|
const uint32_t flags_,
|
|
const uint32_t mask_,
|
|
struct fuse_statx *st_,
|
|
fuse_timeouts_t *timeout_)
|
|
{
|
|
FileInfo *fi = reinterpret_cast<FileInfo*>(fh_);
|
|
|
|
return ::_statx(fi->fusepath.c_str(),flags_,mask_,st_,timeout_);
|
|
}
|