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

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