diff --git a/src/branches.cpp b/src/branches.cpp index f2aed5dd..f779498c 100644 --- a/src/branches.cpp +++ b/src/branches.cpp @@ -34,7 +34,7 @@ #include -Branches::Impl::Impl(const u64 &default_minfreespace_) +Branches::Impl::Impl(const u64 *default_minfreespace_) : _default_minfreespace(default_minfreespace_) { } @@ -48,6 +48,12 @@ Branches::Impl::operator=(Branches::Impl &rval_) *this_base = *rval_base; + for(auto &branch : *this) + { + if(std::holds_alternative(branch._minfreespace)) + branch._minfreespace = _default_minfreespace; + } + return *this; } @@ -60,6 +66,12 @@ Branches::Impl::operator=(Branches::Impl &&rval_) *this_base = std::move(*rval_base); + for(auto &branch : *this) + { + if(std::holds_alternative(branch._minfreespace)) + branch._minfreespace = _default_minfreespace; + } + return *this; } @@ -67,7 +79,7 @@ const u64& Branches::Impl::minfreespace(void) const { - return _default_minfreespace; + return *_default_minfreespace; } namespace l @@ -148,7 +160,7 @@ namespace l case 2: *glob_ = v[0]; options = v[1]; - v = str::split(options,','); + v = str::split(options,','); switch(v.size()) { case 2: @@ -229,7 +241,7 @@ namespace l { int rv; StrVec paths; - Branches::Impl tmp_branches(branches_->minfreespace()); + Branches::Impl tmp_branches(&branches_->minfreespace()); paths = str::split(str_,':'); for(auto &path : paths) @@ -251,7 +263,7 @@ namespace l { int rv; std::vector paths; - Branches::Impl tmp_branches(branches_->minfreespace()); + Branches::Impl tmp_branches(&branches_->minfreespace()); paths = str::split(str_,':'); for(auto &path : paths) @@ -275,7 +287,7 @@ namespace l { int rv; StrVec paths; - Branches::Impl tmp_branches(branches_->minfreespace()); + Branches::Impl tmp_branches(&branches_->minfreespace()); paths = str::split(str_,':'); for(auto &path : paths) @@ -419,7 +431,7 @@ Branches::from_string(const std::string_view str_) impl = std::atomic_load(&_impl); - new_impl = std::make_shared(impl->minfreespace()); + new_impl = std::make_shared(&minfreespace); *new_impl = *impl; rv = new_impl->from_string(str_); @@ -440,7 +452,16 @@ Branches::to_string(void) const void Branches::find_and_set_mode_ro() { - for(auto &branch : *_impl) + Branches::Ptr impl; + Branches::Ptr new_impl; + + impl = std::atomic_load(&_impl); + new_impl = std::make_shared(&minfreespace); + + *new_impl = *impl; + + bool changed = false; + for(auto &branch : *new_impl) { if(branch.mode != Branch::Mode::RW) continue; @@ -452,7 +473,13 @@ Branches::find_and_set_mode_ro() branch.path.string()); branch.mode = Branch::Mode::RO; + changed = true; } + + if(not changed) + return; + + std::atomic_store(&_impl,new_impl); } SrcMounts::SrcMounts(Branches &b_) diff --git a/src/branches.hpp b/src/branches.hpp index cf4c1d11..54f85959 100644 --- a/src/branches.hpp +++ b/src/branches.hpp @@ -39,13 +39,13 @@ public: public std::vector { private: - const u64 &_default_minfreespace; + const u64 *_default_minfreespace; public: using Ptr = std::shared_ptr; public: - Impl(const u64 &default_minfreespace); + Impl(const u64 *default_minfreespace); public: int from_string(const std::string_view str) final; @@ -73,7 +73,7 @@ private: public: Branches() - : _impl(std::make_shared(minfreespace)) + : _impl(std::make_shared(&minfreespace)) { } diff --git a/src/config.hpp b/src/config.hpp index d30785bf..c20cf102 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -47,7 +47,6 @@ #include "fuse_cfg.hpp" #include "fuse_readdir.hpp" #include "policy.hpp" -#include "rwlock.hpp" #include "tofrom_ref.hpp" #include "tofrom_wrapper.hpp" #include "syslog.hpp" diff --git a/src/config_log_file.cpp b/src/config_log_file.cpp index 65271990..f37c1f6d 100644 --- a/src/config_log_file.cpp +++ b/src/config_log_file.cpp @@ -26,7 +26,8 @@ LogFile::LogFile(const std::string &s_) { - fuse_debug_set_output(s_); + if(!s_.empty()) + fuse_debug_set_output(s_); } std::string diff --git a/src/dirinfo.hpp b/src/dirinfo.hpp index 972e07c8..2355b4a5 100644 --- a/src/dirinfo.hpp +++ b/src/dirinfo.hpp @@ -27,6 +27,7 @@ class DirInfo : public FH { public: + static u64 to_fh(const DirInfo*); static DirInfo *from_fh(const u64 fh); public: @@ -39,23 +40,23 @@ public: } }; +inline +u64 +DirInfo::to_fh(const DirInfo *di_) +{ + return reinterpret_cast(di_); +} + inline u64 DirInfo::to_fh() const { - ASSERT_NOT_NULL(this); - return reinterpret_cast(this); + return to_fh(this); } inline DirInfo* DirInfo::from_fh(const u64 fh_) { - DirInfo *rv; - - rv = reinterpret_cast(fh_); - - ASSERT_NOT_NULL(rv); - - return rv; + return reinterpret_cast(fh_); } diff --git a/src/fileinfo.hpp b/src/fileinfo.hpp index e905007a..6a2866f7 100644 --- a/src/fileinfo.hpp +++ b/src/fileinfo.hpp @@ -104,7 +104,6 @@ inline u64 FileInfo::to_fh(const FileInfo *fi_) { - ASSERT_NOT_NULL(fi_); return reinterpret_cast(fi_); } @@ -112,19 +111,12 @@ inline u64 FileInfo::to_fh() const { - ASSERT_NOT_NULL(this); - return reinterpret_cast(this); + return to_fh(this); } inline FileInfo* FileInfo::from_fh(const u64 fh_) { - FileInfo *rv; - - rv = reinterpret_cast(fh_); - - ASSERT_NOT_NULL(rv); - - return rv; + return reinterpret_cast(fh_); } diff --git a/src/fs_movefile_and_open.cpp b/src/fs_movefile_and_open.cpp index 75de245a..6f3bc86a 100644 --- a/src/fs_movefile_and_open.cpp +++ b/src/fs_movefile_and_open.cpp @@ -82,6 +82,8 @@ _movefile_and_open(const Policy::Create &createFunc_, rv = createFunc_(branches_,fusepath_,dst_branch); if(rv < 0) return rv; + if(dst_branch.empty()) + return -ENOSPC; origfd_flags = fs::getfl(origfd_); if(origfd_flags < 0) diff --git a/src/fuse_access.cpp b/src/fuse_access.cpp index a98fc8bc..23e1e28c 100644 --- a/src/fuse_access.cpp +++ b/src/fuse_access.cpp @@ -30,7 +30,7 @@ static int _access(const Policy::Search &searchFunc_, - const Branches &branches_, + const Branches::Ptr branches_, const fs::path &fusepath_, const int mask_) { @@ -42,6 +42,8 @@ _access(const Policy::Search &searchFunc_, rv = searchFunc_(branches_,fusepath_,branches); if(rv < 0) return rv; + if(branches.empty()) + return -ENOENT; fullpath = branches[0]->path / fusepath_; diff --git a/src/fuse_chmod.cpp b/src/fuse_chmod.cpp index 1c2857d7..22362c8e 100644 --- a/src/fuse_chmod.cpp +++ b/src/fuse_chmod.cpp @@ -64,7 +64,7 @@ static int _chmod(const Policy::Action &actionFunc_, const Policy::Search &searchFunc_, - const Branches &branches_, + const Branches::Ptr branches_, const fs::path &fusepath_, const mode_t mode_) { @@ -75,6 +75,8 @@ _chmod(const Policy::Action &actionFunc_, rv = actionFunc_(branches_,fusepath_,branches); if(rv < 0) return rv; + if(branches.empty()) + return -ENOENT; ::_chmod_loop(branches,fusepath_,mode_,&prv); if(prv.errors.empty()) @@ -86,6 +88,8 @@ _chmod(const Policy::Action &actionFunc_, rv = searchFunc_(branches_,fusepath_,branches); if(rv < 0) return rv; + if(branches.empty()) + return -ENOENT; return prv.get_error(branches[0]->path); } diff --git a/src/fuse_chown.cpp b/src/fuse_chown.cpp index b51c4c99..466f525d 100644 --- a/src/fuse_chown.cpp +++ b/src/fuse_chown.cpp @@ -66,7 +66,7 @@ static int _chown(const Policy::Action &actionFunc_, const Policy::Search &searchFunc_, - const Branches &branches_, + const Branches::Ptr branches_, const fs::path &fusepath_, const uid_t uid_, const gid_t gid_) @@ -78,6 +78,8 @@ _chown(const Policy::Action &actionFunc_, rv = actionFunc_(branches_,fusepath_,branches); if(rv < 0) return rv; + if(branches.empty()) + return -ENOENT; ::_chown_loop(branches,fusepath_,uid_,gid_,&prv); @@ -90,6 +92,8 @@ _chown(const Policy::Action &actionFunc_, rv = searchFunc_(branches_,fusepath_,branches); if(rv < 0) return rv; + if(branches.empty()) + return -ENOENT; return prv.get_error(branches[0]->path); } diff --git a/src/fuse_create.cpp b/src/fuse_create.cpp index a05e6210..49f61b7b 100644 --- a/src/fuse_create.cpp +++ b/src/fuse_create.cpp @@ -207,7 +207,7 @@ int _create(const ugid_t ugid_, const Policy::Search &searchFunc_, const Policy::Create &createFunc_, - const Branches &branches_, + const Branches::Ptr branches_, const fs::path &fusepath_, fuse_file_info_t *ffi_, const mode_t mode_, @@ -224,10 +224,14 @@ _create(const ugid_t ugid_, rv = searchFunc_(branches_,fusedirpath,existingpaths); if(rv < 0) return rv; + if(existingpaths.empty()) + return -ENOENT; rv = createFunc_(branches_,fusedirpath,createpaths); if(rv < 0) return rv; + if(createpaths.empty()) + return -ENOENT; rv = fs::clonepath(existingpaths[0]->path, createpaths[0]->path, @@ -292,6 +296,9 @@ _create(const fuse_req_ctx_t *ctx_, FileInfo *fi = FileInfo::from_fh(ffi_->fh); int backing_id = INVALID_BACKING_ID; + if(not fi) + return -EBADF; + switch(_(cfg.passthrough_io,ffi_->flags)) { case _(PassthroughIO::ENUM::RO,O_RDONLY): diff --git a/src/fuse_fallocate.cpp b/src/fuse_fallocate.cpp index abd4e90e..be11d40f 100644 --- a/src/fuse_fallocate.cpp +++ b/src/fuse_fallocate.cpp @@ -48,22 +48,10 @@ FUSE::fallocate(const fuse_req_ctx_t *ctx_, off_t offset_, off_t len_) { - u64 fh; + FileInfo *fi = FileInfo::from_fh(fh_); - fh = fh_; - if(fh == 0) - { - state.open_files.cvisit(ctx_->nodeid, - [&](auto &val_) - { - fh = val_.second.fi->to_fh(); - }); - } - - if(fh == 0) - return -ENOENT; - - FileInfo *fi = FileInfo::from_fh(fh); + if(not fi) + return -EBADF; return ::_fallocate(fi->fd, mode_, diff --git a/src/fuse_fchmod.cpp b/src/fuse_fchmod.cpp index cc5b0c5b..f70996d0 100644 --- a/src/fuse_fchmod.cpp +++ b/src/fuse_fchmod.cpp @@ -43,22 +43,10 @@ FUSE::fchmod(const fuse_req_ctx_t *ctx_, cu64 fh_, const mode_t mode_) { - u64 fh; + FileInfo *fi = FileInfo::from_fh(fh_); - fh = fh_; - if(fh == 0) - { - state.open_files.cvisit(ctx_->nodeid, - [&](auto &val_) - { - fh = val_.second.fi->to_fh(); - }); - } - - if(fh == 0) - return -ENOENT; - - FileInfo *fi = FileInfo::from_fh(fh); + if(not fi) + return -EBADF; return ::_fchmod(fi->fd,mode_); } diff --git a/src/fuse_fchown.cpp b/src/fuse_fchown.cpp index 91b799c9..e30ec9e0 100644 --- a/src/fuse_fchown.cpp +++ b/src/fuse_fchown.cpp @@ -47,22 +47,10 @@ FUSE::fchown(const fuse_req_ctx_t *ctx_, const uid_t uid_, const gid_t gid_) { - u64 fh; + FileInfo *fi = FileInfo::from_fh(fh_); - fh = fh_; - if(fh == 0) - { - state.open_files.cvisit(ctx_->nodeid, - [&](auto &val_) - { - fh = val_.second.fi->to_fh(); - }); - } - - if(fh == 0) - return -ENOENT; - - FileInfo *fi = FileInfo::from_fh(fh); + if(not fi) + return -EBADF; return ::_fchown(fi->fd,uid_,gid_); } diff --git a/src/fuse_fgetattr.cpp b/src/fuse_fgetattr.cpp index 94f20b11..4629bc0f 100644 --- a/src/fuse_fgetattr.cpp +++ b/src/fuse_fgetattr.cpp @@ -54,26 +54,14 @@ FUSE::fgetattr(const fuse_req_ctx_t *ctx_, fuse_timeouts_t *timeout_) { int rv; - u64 fh; + FileInfo *fi = FileInfo::from_fh(fh_); - fh = fh_; - if(fh == 0) - { - state.open_files.cvisit(ctx_->nodeid, - [&](const auto &val_) - { - fh = val_.second.fi->to_fh(); - }); - } - - if(fh == 0) + if(not fi) { timeout_->entry = cfg.cache_negative_entry; - return -ENOENT; + return -EBADF; } - FileInfo *fi = FileInfo::from_fh(fh); - rv = ::_fgetattr(fi,st_); timeout_->entry = ((rv >= 0) ? diff --git a/src/fuse_flock.cpp b/src/fuse_flock.cpp index 47b22f78..c2fde1e3 100644 --- a/src/fuse_flock.cpp +++ b/src/fuse_flock.cpp @@ -43,22 +43,10 @@ FUSE::flock(const fuse_req_ctx_t *ctx_, const fuse_file_info_t *ffi_, int op_) { - u64 fh; + FileInfo* fi = FileInfo::from_fh(ffi_->fh); - fh = ffi_->fh; - if(fh == 0) - { - state.open_files.cvisit(ctx_->nodeid, - [&](const auto &val_) - { - fh = val_.second.fi->to_fh(); - }); - } - - if(fh == 0) - return -ENOENT; - - FileInfo* fi = FileInfo::from_fh(fh); + if(not fi) + return -EBADF; return ::_flock(fi->fd,op_); } diff --git a/src/fuse_ftruncate.cpp b/src/fuse_ftruncate.cpp index cf967ca4..99aca0f5 100644 --- a/src/fuse_ftruncate.cpp +++ b/src/fuse_ftruncate.cpp @@ -43,22 +43,10 @@ FUSE::ftruncate(const fuse_req_ctx_t *ctx_, cu64 fh_, off_t size_) { - u64 fh; + FileInfo *fi = FileInfo::from_fh(fh_); - fh = fh_; - if(fh == 0) - { - state.open_files.cvisit(ctx_->nodeid, - [&](auto &val_) - { - fh = val_.second.fi->to_fh(); - }); - } - - if(fh == 0) - return -ENOENT; - - FileInfo *fi = FileInfo::from_fh(fh); + if(not fi) + return -EBADF; return ::_ftruncate(fi->fd,size_); } diff --git a/src/fuse_futimens.cpp b/src/fuse_futimens.cpp index 2b4a2a21..e6b9e012 100644 --- a/src/fuse_futimens.cpp +++ b/src/fuse_futimens.cpp @@ -45,22 +45,10 @@ FUSE::futimens(const fuse_req_ctx_t *ctx_, cu64 fh_, const struct timespec ts_[2]) { - u64 fh; + FileInfo *fi = FileInfo::from_fh(fh_); - fh = fh_; - if(fh == 0) - { - state.open_files.cvisit(ctx_->nodeid, - [&](const auto &val_) - { - fh = val_.second.fi->to_fh(); - }); - } - - if(fh == 0) - return -ENOENT; - - FileInfo *fi = FileInfo::from_fh(fh); + if(not fi) + return -EBADF; return ::_futimens(fi->fd,ts_); } diff --git a/src/fuse_getattr.cpp b/src/fuse_getattr.cpp index 3bebb35e..b27c16d4 100644 --- a/src/fuse_getattr.cpp +++ b/src/fuse_getattr.cpp @@ -73,7 +73,8 @@ _set_stat_if_leads_to_reg(const fs::path &path_, static int -_getattr_fake_root(struct stat *st_) +_getattr_fake_root(struct stat *st_, + fuse_timeouts_t *timeout_) { st_->st_dev = 0; st_->st_ino = 0; @@ -89,12 +90,16 @@ _getattr_fake_root(struct stat *st_) st_->st_mtime = 0; st_->st_ctime = 0; + timeout_->entry = 0; + timeout_->attr = 0; + return 0; } static int -_getattr_controlfile(struct stat *st_) +_getattr_controlfile(struct stat *st_, + fuse_timeouts_t *timeout_) { static const uid_t uid = ::getuid(); static const gid_t gid = ::getgid(); @@ -114,13 +119,16 @@ _getattr_controlfile(struct stat *st_) st_->st_mtime = now; st_->st_ctime = now; + timeout_->entry = cfg.cache_entry; + timeout_->attr = cfg.cache_attr; + return 0; } static int _getattr(const Policy::Search &searchFunc_, - const Branches &branches_, + const Branches::Ptr branches_, const fs::path &fusepath_, struct stat *st_, const bool symlinkify_, @@ -134,6 +142,8 @@ _getattr(const Policy::Search &searchFunc_, rv = searchFunc_(branches_,fusepath_,branches); if(rv < 0) return rv; + if(branches.empty()) + return -ENOENT; fullpath = branches[0]->path / fusepath_; @@ -144,12 +154,12 @@ _getattr(const Policy::Search &searchFunc_, break; case FollowSymlinks::ENUM::DIRECTORY: rv = fs::lstat(fullpath,st_); - if(S_ISLNK(st_->st_mode)) + if((rv >= 0) && 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)) + if((rv >= 0) && S_ISLNK(st_->st_mode)) ::_set_stat_if_leads_to_reg(fullpath,st_); break; case FollowSymlinks::ENUM::ALL: @@ -187,7 +197,7 @@ _getattr(const fs::path &fusepath_, cfg.symlinkify_timeout, cfg.follow_symlinks); if((rv < 0) && Config::is_rootdir(fusepath_)) - return ::_getattr_fake_root(st_); + return ::_getattr_fake_root(st_,timeout_); timeout_->entry = ((rv >= 0) ? cfg.cache_entry : @@ -223,7 +233,7 @@ FUSE::getattr(const fs::path &fusepath_, fuse_timeouts_t *timeout_) { if(Config::is_ctrl_file(fusepath_)) - return ::_getattr_controlfile(st_); + return ::_getattr_controlfile(st_,timeout_); return ::_getattr(fusepath_,st_,timeout_); } diff --git a/src/fuse_getxattr.cpp b/src/fuse_getxattr.cpp index 55d5b43c..2a7a8a87 100644 --- a/src/fuse_getxattr.cpp +++ b/src/fuse_getxattr.cpp @@ -97,7 +97,7 @@ _getxattr_from_string(char *destbuf_, static int -_getxattr_user_mergerfs_allpaths(const Branches::Ptr &branches_, +_getxattr_user_mergerfs_allpaths(const Branches::Ptr branches_, const fs::path &fusepath_, char *buf_, const size_t count_) @@ -120,7 +120,7 @@ int _getxattr_user_mergerfs(const fs::path &basepath_, const fs::path &fusepath_, const fs::path &fullpath_, - const Branches &branches_, + const Branches::Ptr branches_, const char *attrname_, char *buf_, const size_t count_) @@ -144,7 +144,7 @@ _getxattr_user_mergerfs(const fs::path &basepath_, static int _getxattr(const Policy::Search &searchFunc_, - const Branches &branches_, + const Branches::Ptr branches_, const fs::path &fusepath_, const char *attrname_, char *buf_, @@ -157,6 +157,8 @@ _getxattr(const Policy::Search &searchFunc_, rv = searchFunc_(branches_,fusepath_,branches); if(rv < 0) return rv; + if(branches.empty()) + return -ENOENT; fullpath = branches[0]->path / fusepath_; diff --git a/src/fuse_init.cpp b/src/fuse_init.cpp index ecf58bf2..91d90893 100644 --- a/src/fuse_init.cpp +++ b/src/fuse_init.cpp @@ -45,7 +45,7 @@ _want(fuse_conn_info_t *conn_, static bool _capable(fuse_conn_info_t *conn_, - const int flag_) + const int flag_) { return !!(conn_->capable & flag_); } @@ -53,7 +53,7 @@ _capable(fuse_conn_info_t *conn_, static void _want_if_capable(fuse_conn_info_t *conn_, - const int flag_) + const int flag_) { if(::_capable(conn_,flag_)) ::_want(conn_,flag_); @@ -62,8 +62,8 @@ _want_if_capable(fuse_conn_info_t *conn_, static void _want_if_capable(fuse_conn_info_t *conn_, - const int flag_, - ConfigBOOL *want_) + const int flag_, + ConfigBOOL *want_) { if(*want_ && ::_capable(conn_,flag_)) { diff --git a/src/fuse_ioctl.cpp b/src/fuse_ioctl.cpp index 51ce85a6..eecf5ac2 100644 --- a/src/fuse_ioctl.cpp +++ b/src/fuse_ioctl.cpp @@ -32,6 +32,7 @@ #include "fs_open.hpp" #include "fs_path.hpp" #include "mergerfs_ioctl.hpp" +#include "state.hpp" #include "str.hpp" #include @@ -115,6 +116,9 @@ _ioctl_file(const fuse_req_ctx_t *ctx_, { FileInfo *fi = FileInfo::from_fh(ffi_->fh); + if(not fi) + return -EBADF; + return ::_ioctl(fi->fd,cmd_,data_,out_bufsz_); } @@ -125,7 +129,7 @@ _ioctl_file(const fuse_req_ctx_t *ctx_, static int _ioctl_dir_base(const Policy::Search &searchFunc_, - const Branches &branches_, + const Branches::Ptr branches_, const fs::path &fusepath_, const u32 cmd_, void *data_, @@ -139,6 +143,8 @@ _ioctl_dir_base(const Policy::Search &searchFunc_, rv = searchFunc_(branches_,fusepath_,branches); if(rv < 0) return rv; + if(branches.empty()) + return -ENOENT; fullpath = branches[0]->path / fusepath_; @@ -163,6 +169,9 @@ _ioctl_dir(const fuse_req_ctx_t *ctx_, { DirInfo *di = DirInfo::from_fh(ffi_->fh); + if(not di) + return -EBADF; + return ::_ioctl_dir_base(cfg.func.open.policy, cfg.branches, di->fusepath.c_str(), diff --git a/src/fuse_link.cpp b/src/fuse_link.cpp index 7cabdf78..b9b5c3da 100644 --- a/src/fuse_link.cpp +++ b/src/fuse_link.cpp @@ -74,7 +74,7 @@ static int _link_create_path(const Policy::Search &searchFunc_, const Policy::Action &actionFunc_, - const Branches &ibranches_, + const Branches::Ptr ibranches_, const fs::path &oldfusepath_, const fs::path &newfusepath_) { @@ -86,12 +86,16 @@ _link_create_path(const Policy::Search &searchFunc_, rv = actionFunc_(ibranches_,oldfusepath_,oldbranches); if(rv < 0) return rv; + if(oldbranches.empty()) + return -ENOENT; newfusedirpath = newfusepath_.parent_path(); rv = searchFunc_(ibranches_,newfusedirpath,newbranches); if(rv < 0) return rv; + if(newbranches.empty()) + return -ENOENT; return ::_link_create_path_loop(oldbranches,newbranches[0], oldfusepath_,newfusepath_, @@ -148,7 +152,7 @@ _link_preserve_path_loop(const std::vector &oldbranches_, static int _link_preserve_path(const Policy::Action &actionFunc_, - const Branches &branches_, + const Branches::Ptr branches_, const fs::path &oldfusepath_, const fs::path &newfusepath_, struct stat *st_) @@ -159,6 +163,8 @@ _link_preserve_path(const Policy::Action &actionFunc_, rv = actionFunc_(branches_,oldfusepath_,oldbranches); if(rv < 0) return rv; + if(oldbranches.empty()) + return -ENOENT; return ::_link_preserve_path_loop(oldbranches, oldfusepath_, @@ -231,8 +237,8 @@ _link_exdev_rel_symlink(const fuse_req_ctx_t *ctx_, static int _link_exdev_abs_base_symlink(const fuse_req_ctx_t *ctx_, - const Policy::Search &openPolicy_, - const Branches::Ptr &ibranches_, + const Policy::Search &openPolicy_, + const Branches::Ptr ibranches_, const fs::path &oldpath_, const fs::path &newpath_, struct stat *st_, @@ -245,6 +251,8 @@ _link_exdev_abs_base_symlink(const fuse_req_ctx_t *ctx_, rv = openPolicy_(ibranches_,oldpath_,obranches); if(rv < 0) return rv; + if(obranches.empty()) + return -ENOENT; target = obranches[0]->path / oldpath_; diff --git a/src/fuse_listxattr.cpp b/src/fuse_listxattr.cpp index d14035e3..ce84e64e 100644 --- a/src/fuse_listxattr.cpp +++ b/src/fuse_listxattr.cpp @@ -121,7 +121,7 @@ _listxattr(const std::vector &branches_, static int _listxattr(const Policy::Search &searchFunc_, - const Branches &ibranches_, + const Branches::Ptr ibranches_, const fs::path &fusepath_, char *list_, const size_t size_) diff --git a/src/fuse_mkdir.cpp b/src/fuse_mkdir.cpp index 68f732a7..bd3e9c68 100644 --- a/src/fuse_mkdir.cpp +++ b/src/fuse_mkdir.cpp @@ -103,7 +103,7 @@ int _mkdir(const ugid_t ugid_, const Policy::Search &getattrPolicy_, const Policy::Create &mkdirPolicy_, - const Branches &branches_, + const Branches::Ptr branches_, const fs::path &fusepath_, const mode_t mode_, const mode_t umask_) @@ -118,10 +118,14 @@ _mkdir(const ugid_t ugid_, rv = getattrPolicy_(branches_,fusedirpath,existingbranches); if(rv < 0) return rv; + if(existingbranches.empty()) + return -ENOENT; rv = mkdirPolicy_(branches_,fusedirpath,createbranches); if(rv < 0) return rv; + if(createbranches.empty()) + return -ENOENT; return ::_mkdir_loop(ugid_, existingbranches[0], diff --git a/src/fuse_mknod.cpp b/src/fuse_mknod.cpp index 7e3d3cf2..889f1a96 100644 --- a/src/fuse_mknod.cpp +++ b/src/fuse_mknod.cpp @@ -108,7 +108,7 @@ int _mknod(const ugid_t ugid_, const Policy::Search &searchFunc_, const Policy::Create &createFunc_, - const Branches &branches_, + const Branches::Ptr branches_, const fs::path &fusepath_, const mode_t mode_, const mode_t umask_, @@ -124,10 +124,14 @@ _mknod(const ugid_t ugid_, rv = searchFunc_(branches_,fusedirpath,existingbranches); if(rv < 0) return rv; + if(existingbranches.empty()) + return -ENOENT; rv = createFunc_(branches_,fusedirpath,createbranches); if(rv < 0) return rv; + if(createbranches.empty()) + return -ENOENT; return ::_mknod_loop(ugid_, existingbranches[0]->path, diff --git a/src/fuse_open.cpp b/src/fuse_open.cpp index 251decab..6bdc3e70 100644 --- a/src/fuse_open.cpp +++ b/src/fuse_open.cpp @@ -25,9 +25,9 @@ simultaneously attempt to open the same file (same nodeid), and we need to: - 1. Share a single canonical FileInfo entry in the open_files map for all - opens of the same file while still giving each FUSE handle its own - FileInfo object and file descriptor + 1. Share a single canonical FileInfo entry in the open_files map for + all opens of the same file while still giving each FUSE handle + its own FileInfo object and file descriptor 2. Properly reference count to know when to release resources 3. Handle race conditions without deadlocks or resource leaks 4. Support FUSE passthrough mode for performance @@ -45,8 +45,8 @@ FileInfo by re-opening the canonical file descriptor 3. If it doesn't exist, we create a new FileInfo and try to insert it 4. If insertion fails (another thread inserted first), we clean up - and retry (because to use passthrough it MUST be the same underlying - file as the backing id was created) + and retry (because to use passthrough it MUST be the same + underlying file as the backing id was created) THE RETRY LOOP -------------- @@ -308,7 +308,7 @@ _open_fd(const int fd_, static int _open(const Policy::Search &searchFunc_, - const Branches &ibranches_, + const Branches::Ptr ibranches_, const fs::path &fusepath_, fuse_file_info_t *ffi_, const bool link_cow_, @@ -321,6 +321,8 @@ _open(const Policy::Search &searchFunc_, rv = searchFunc_(ibranches_,fusepath_,obranches); if(rv < 0) return rv; + if(obranches.empty()) + return -ENOENT; filepath = obranches[0]->path / fusepath_; @@ -423,6 +425,8 @@ _open(const fuse_req_ctx_t *ctx_, return rv; fi = FileInfo::from_fh(ffi_->fh); + if(not fi) + return -EBADF; switch(_(cfg.passthrough_io,ffi_->flags)) { diff --git a/src/fuse_read.cpp b/src/fuse_read.cpp index 9847cfa6..3cd9ad35 100644 --- a/src/fuse_read.cpp +++ b/src/fuse_read.cpp @@ -67,6 +67,9 @@ FUSE::read(const fuse_req_ctx_t *ctx_, ioprio::SetFrom iop(ctx_->pid); FileInfo *fi = FileInfo::from_fh(ffi_->fh); + if(not fi) + return -EBADF; + if(fi->direct_io) return ::_read_direct_io(fi->fd,buf_,size_,offset_); diff --git a/src/fuse_readdir.cpp b/src/fuse_readdir.cpp index 614927d9..d506d3d8 100644 --- a/src/fuse_readdir.cpp +++ b/src/fuse_readdir.cpp @@ -84,18 +84,24 @@ _handle_ENOENT(const fuse_file_info_t *ffi_, dirent de; DirInfo *di = DirInfo::from_fh(ffi_->fh); + if(not di) + return -EBADF; + if(!di->fusepath.empty()) return -ENOENT; + constexpr const char msg[] = + "error: no valid mergerfs branch found, check config"; + de = {}; de.d_ino = 0; de.d_off = 0; de.d_type = DT_UNKNOWN; - strcpy(de.d_name,"error: no valid mergerfs branch found, check config"); + strncpy(de.d_name,msg,(sizeof(msg) - 1)); de.d_reclen = sizeof(de); - fuse_dirents_add(buf_,&de,::strlen(de.d_name)); + fuse_dirents_add(buf_,&de,(sizeof(msg) - 1)); return 0; } diff --git a/src/fuse_readdir.hpp b/src/fuse_readdir.hpp index 8abf8820..afcff6da 100644 --- a/src/fuse_readdir.hpp +++ b/src/fuse_readdir.hpp @@ -22,6 +22,7 @@ #include "tofrom_string.hpp" #include "fuse_readdir_base.hpp" +#include #include #include @@ -58,7 +59,7 @@ namespace FUSE void initialize(); private: - bool _initialized = false; + std::atomic _initialized = false; std::shared_ptr _str; std::shared_ptr _impl; }; diff --git a/src/fuse_readdir_cor.cpp b/src/fuse_readdir_cor.cpp index e4f60eca..596a27f4 100644 --- a/src/fuse_readdir_cor.cpp +++ b/src/fuse_readdir_cor.cpp @@ -47,7 +47,7 @@ static inline int _concurrent_readdir(ThreadPool &tp_, - const Branches::Ptr &branches_, + const Branches::Ptr branches_, const fs::path &rel_dirpath_, fuse_dirents_t *dirents_) { @@ -89,6 +89,9 @@ FUSE::ReadDirCOR::operator()(const fuse_req_ctx_t *ctx_, { DirInfo *di = DirInfo::from_fh(ffi_->fh); + if(not di) + return -EBADF; + return ::_concurrent_readdir(_tp, cfg.branches, di->fusepath, diff --git a/src/fuse_readdir_cor_getdents.icpp b/src/fuse_readdir_cor_getdents.icpp index 03fb7941..3df46a5b 100644 --- a/src/fuse_readdir_cor_getdents.icpp +++ b/src/fuse_readdir_cor_getdents.icpp @@ -53,6 +53,9 @@ _readdir(const fs::path &branch_path_, DEFER{ fs::close(fd); }; buf = msgbuf_alloc(); + if(not buf) + return -ENOMEM; + DEFER{ msgbuf_free(buf); }; fs::inode::ReaddirCalc inodecalc(branch_path_,rel_dirpath_); diff --git a/src/fuse_readdir_cosr.cpp b/src/fuse_readdir_cosr.cpp index 4943061e..6d7bb721 100644 --- a/src/fuse_readdir_cosr.cpp +++ b/src/fuse_readdir_cosr.cpp @@ -45,7 +45,7 @@ static inline int _readdir(ThreadPool &tp_, - const Branches::Ptr &branches_, + const Branches::Ptr branches_, const fs::path &rel_dirpath_, fuse_dirents_t *dirents_) { @@ -67,6 +67,9 @@ FUSE::ReadDirCOSR::operator()(const fuse_req_ctx_t *ctx_, { DirInfo *di = DirInfo::from_fh(ffi_->fh); + if(not di) + return -EBADF; + return ::_readdir(_tp, cfg.branches, di->fusepath, diff --git a/src/fuse_readdir_cosr_getdents.icpp b/src/fuse_readdir_cosr_getdents.icpp index 93b0cc18..52a48adb 100644 --- a/src/fuse_readdir_cosr_getdents.icpp +++ b/src/fuse_readdir_cosr_getdents.icpp @@ -87,6 +87,8 @@ _readdir(std::vector> &dh_futures_, fuse_msgbuf_t *buf; buf = msgbuf_alloc(); + if(not buf) + return -ENOMEM; DEFER { msgbuf_free(buf); }; for(auto &dh_future : dh_futures_) diff --git a/src/fuse_readdir_seq.cpp b/src/fuse_readdir_seq.cpp index 11663d2d..3b8335d0 100644 --- a/src/fuse_readdir_seq.cpp +++ b/src/fuse_readdir_seq.cpp @@ -36,6 +36,9 @@ FUSE::ReadDirSeq::operator()(const fuse_req_ctx_t *ctx_, { DirInfo *di = DirInfo::from_fh(ffi_->fh); + if(not di) + return -EBADF; + return ::_readdir(cfg.branches, di->fusepath, dirents_); diff --git a/src/fuse_readdir_seq_getdents.icpp b/src/fuse_readdir_seq_getdents.icpp index e190eccf..da99bb56 100644 --- a/src/fuse_readdir_seq_getdents.icpp +++ b/src/fuse_readdir_seq_getdents.icpp @@ -45,6 +45,8 @@ _readdir(const Branches::Ptr &branches_, fuse_dirents_reset(dirents_); buf = msgbuf_alloc(); + if(not buf) + return -ENOMEM; DEFER { msgbuf_free(buf); }; for(const auto &branch : *branches_) diff --git a/src/fuse_readlink.cpp b/src/fuse_readlink.cpp index 7dd12933..7bd9f91a 100644 --- a/src/fuse_readlink.cpp +++ b/src/fuse_readlink.cpp @@ -40,12 +40,11 @@ _readlink_core_standard(const fs::path &fullpath_, { int rv; - rv = fs::readlink(fullpath_,buf_,bufsize_); + rv = fs::readlink(fullpath_,buf_,(bufsize_ - 1)); if(rv < 0) return rv; - if((size_t)rv < bufsize_) - buf_[rv] = '\0'; + buf_[rv] = '\0'; return 0; } @@ -71,10 +70,9 @@ _readlink_core_symlinkify(const fs::path &fullpath_, if(!symlinkify::can_be_symlink(st,symlinkify_timeout_)) return ::_readlink_core_standard(fullpath_,buf_,bufsize_); - n = std::min(fullpath_str.size(),bufsize_); + n = std::min(fullpath_str.size(),(bufsize_ - 1)); memcpy(buf_,fullpath_str.c_str(),n); - if(n < bufsize_) - buf_[n] = '\0'; + buf_[n] = '\0'; return 0; } @@ -101,7 +99,7 @@ _readlink_core(const fs::path &basepath_, static int _readlink(const Policy::Search &searchFunc_, - const Branches &ibranches_, + const Branches::Ptr ibranches_, const fs::path &fusepath_, char *buf_, const size_t bufsize_, diff --git a/src/fuse_release.cpp b/src/fuse_release.cpp index c05f754c..17bbb0cd 100644 --- a/src/fuse_release.cpp +++ b/src/fuse_release.cpp @@ -119,6 +119,9 @@ FUSE::release(const fuse_req_ctx_t *ctx_, { FileInfo *fi = FileInfo::from_fh(ffi_->fh); + if(not fi) + return -EBADF; + return ::_release(ctx_->nodeid, fi, cfg.dropcacheonclose); diff --git a/src/fuse_releasedir.cpp b/src/fuse_releasedir.cpp index 7c755660..71226519 100644 --- a/src/fuse_releasedir.cpp +++ b/src/fuse_releasedir.cpp @@ -39,5 +39,8 @@ FUSE::releasedir(const fuse_req_ctx_t *ctx_, { DirInfo *di = DirInfo::from_fh(ffi_->fh); + if(not di) + return -EBADF; + return ::_releasedir(di); } diff --git a/src/fuse_removexattr.cpp b/src/fuse_removexattr.cpp index e9b67c8f..f43bb411 100644 --- a/src/fuse_removexattr.cpp +++ b/src/fuse_removexattr.cpp @@ -63,7 +63,7 @@ static int _removexattr(const Policy::Action &actionFunc_, const Policy::Search &searchFunc_, - const Branches &ibranches_, + const Branches::Ptr ibranches_, const fs::path &fusepath_, const char *attrname_) { @@ -74,6 +74,8 @@ _removexattr(const Policy::Action &actionFunc_, rv = actionFunc_(ibranches_,fusepath_,obranches); if(rv < 0) return rv; + if(obranches.empty()) + return -ENOENT; ::_removexattr_loop(obranches,fusepath_,attrname_,&prv); if(prv.errors.empty()) @@ -85,6 +87,8 @@ _removexattr(const Policy::Action &actionFunc_, rv = searchFunc_(ibranches_,fusepath_,obranches); if(rv < 0) return rv; + if(obranches.empty()) + return -ENOENT; return prv.get_error(obranches[0]->path); } diff --git a/src/fuse_rename.cpp b/src/fuse_rename.cpp index 36bc1e8e..ad550a2f 100644 --- a/src/fuse_rename.cpp +++ b/src/fuse_rename.cpp @@ -70,8 +70,8 @@ _remove(const StrVec &toremove_) static int _rename_create_path(const Policy::Search &searchPolicy_, - const Policy::Action &actionPolicy_, - const Branches::Ptr &branches_, + const Policy::Action &actionPolicy_, + const Branches::Ptr branches_, const fs::path &oldfusepath_, const fs::path &newfusepath_) { @@ -86,10 +86,14 @@ _rename_create_path(const Policy::Search &searchPolicy_, rv = actionPolicy_(branches_,oldfusepath_,oldbranches); if(rv < 0) return rv; + if(oldbranches.empty()) + return -ENOENT; rv = searchPolicy_(branches_,newfusepath_.parent_path(),newbranches); if(rv < 0) return rv; + if(newbranches.empty()) + return -ENOENT; for(auto &branch : *branches_) { @@ -127,7 +131,7 @@ _rename_create_path(const Policy::Search &searchPolicy_, static int _rename_preserve_path(const Policy::Action &actionPolicy_, - const Branches::Ptr &branches_, + const Branches::Ptr branches_, const fs::path &oldfusepath_, const fs::path &newfusepath_) { @@ -198,7 +202,7 @@ _rename_exdev_rename_back(const std::vector &branches_, static int _rename_exdev_rename_target(const Policy::Action &actionPolicy_, - const Branches::Ptr &ibranches_, + const Branches::Ptr ibranches_, const fs::path &oldfusepath_, std::vector &obranches_) { @@ -245,8 +249,8 @@ _rename_exdev_rename_target(const Policy::Action &actionPolicy_, static int _rename_exdev_rel_symlink(const fuse_req_ctx_t *ctx_, - const Policy::Action &actionPolicy_, - const Branches::Ptr &branches_, + const Policy::Action &actionPolicy_, + const Branches::Ptr branches_, const fs::path &oldfusepath_, const fs::path &newfusepath_) { @@ -274,8 +278,8 @@ _rename_exdev_rel_symlink(const fuse_req_ctx_t *ctx_, static int _rename_exdev_abs_symlink(const fuse_req_ctx_t *ctx_, - const Policy::Action &actionPolicy_, - const Branches::Ptr &branches_, + const Policy::Action &actionPolicy_, + const Branches::Ptr branches_, const fs::path &mount_, const fs::path &oldfusepath_, const fs::path &newfusepath_) diff --git a/src/fuse_rmdir.cpp b/src/fuse_rmdir.cpp index e2dad055..e6fcbd53 100644 --- a/src/fuse_rmdir.cpp +++ b/src/fuse_rmdir.cpp @@ -78,7 +78,7 @@ _rmdir_loop(const std::vector &branches_, static int _rmdir(const Policy::Action &actionFunc_, - const Branches &branches_, + const Branches::Ptr branches_, const FollowSymlinks followsymlinks_, const fs::path &fusepath_) { diff --git a/src/fuse_setxattr.cpp b/src/fuse_setxattr.cpp index 4f398c32..260d2beb 100644 --- a/src/fuse_setxattr.cpp +++ b/src/fuse_setxattr.cpp @@ -145,7 +145,7 @@ static int _setxattr(const Policy::Action &setxattrPolicy_, const Policy::Search &getxattrPolicy_, - const Branches &branches_, + const Branches::Ptr branches_, const fs::path &fusepath_, const char *attrname_, const char *attrval_, @@ -159,6 +159,8 @@ _setxattr(const Policy::Action &setxattrPolicy_, rv = setxattrPolicy_(branches_,fusepath_,branches); if(rv < 0) return rv; + if(branches.empty()) + return -ENOENT; ::_setxattr_loop(branches,fusepath_,attrname_,attrval_,attrvalsize_,flags_,&prv); if(prv.errors.empty()) @@ -170,6 +172,8 @@ _setxattr(const Policy::Action &setxattrPolicy_, rv = getxattrPolicy_(branches_,fusepath_,branches); if(rv < 0) return rv; + if(branches.empty()) + return -ENOENT; return prv.get_error(branches[0]->path); } diff --git a/src/fuse_statfs.cpp b/src/fuse_statfs.cpp index 68f0194d..7671883f 100644 --- a/src/fuse_statfs.cpp +++ b/src/fuse_statfs.cpp @@ -41,9 +41,13 @@ _normalize_statvfs(struct statvfs *fsstat_, const unsigned long min_frsize_, const unsigned long min_namemax_) { - fsstat_->f_blocks = (fsblkcnt_t)((fsstat_->f_blocks * fsstat_->f_frsize) / min_frsize_); - fsstat_->f_bfree = (fsblkcnt_t)((fsstat_->f_bfree * fsstat_->f_frsize) / min_frsize_); - fsstat_->f_bavail = (fsblkcnt_t)((fsstat_->f_bavail * fsstat_->f_frsize) / min_frsize_); + long double scale; + + scale = (((long double)fsstat_->f_frsize) / ((long double)min_frsize_)); + + fsstat_->f_blocks = (fsblkcnt_t)(fsstat_->f_blocks * scale); + fsstat_->f_bfree = (fsblkcnt_t)(fsstat_->f_bfree * scale); + fsstat_->f_bavail = (fsblkcnt_t)(fsstat_->f_bavail * scale); fsstat_->f_bsize = min_bsize_; fsstat_->f_frsize = min_frsize_; fsstat_->f_namemax = min_namemax_; @@ -76,7 +80,7 @@ _should_ignore(const StatFSIgnore ignore_, static int -_statfs(const Branches::Ptr &branches_, +_statfs(const Branches::Ptr branches_, const fs::path &fusepath_, const StatFS mode_, const StatFSIgnore ignore_, @@ -147,7 +151,7 @@ FUSE::statfs(const fuse_req_ctx_t *ctx_, const char *fusepath_, struct statvfs *st_) { - const fs::path fusepath{fusepath_}; + const fs::path fusepath{fusepath_}; return ::_statfs(cfg.branches, fusepath, diff --git a/src/fuse_statx_supported.icpp b/src/fuse_statx_supported.icpp index a49c75df..84a81018 100644 --- a/src/fuse_statx_supported.icpp +++ b/src/fuse_statx_supported.icpp @@ -75,7 +75,8 @@ _set_stat_if_leads_to_reg(const fs::path &path_, static int -_statx_fake_root(struct fuse_statx *st_) +_statx_fake_root(struct fuse_statx *st_, + fuse_timeouts_t *timeout_) { st_->ino = 0; st_->mode = (S_IFDIR|S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); @@ -88,12 +89,16 @@ _statx_fake_root(struct fuse_statx *st_) st_->mtime.tv_sec = 0; st_->ctime.tv_sec = 0; + timeout_->entry = cfg.cache_entry; + timeout_->attr = cfg.cache_attr; + return 0; } static int -_statx_controlfile(struct fuse_statx *st_) +_statx_controlfile(struct fuse_statx *st_, + fuse_timeouts_t *timeout_) { static const uid_t uid = ::getuid(); static const gid_t gid = ::getgid(); @@ -110,13 +115,16 @@ _statx_controlfile(struct fuse_statx *st_) st_->mtime.tv_sec = now; st_->ctime.tv_sec = now; + timeout_->entry = cfg.cache_entry; + timeout_->attr = cfg.cache_attr; + return 0; } static int _statx(const Policy::Search &searchFunc_, - const Branches &branches_, + const Branches::Ptr branches_, const fs::path &fusepath_, const uint32_t flags_, const uint32_t mask_, @@ -132,6 +140,8 @@ _statx(const Policy::Search &searchFunc_, rv = searchFunc_(branches_,fusepath_,branches); if(rv < 0) return rv; + if(branches.empty()) + return -ENOENT; fullpath = branches[0]->path / fusepath_; @@ -190,7 +200,7 @@ _statx(const fs::path &fusepath_, cfg.symlinkify_timeout, cfg.follow_symlinks); if((rv < 0) && Config::is_rootdir(fusepath_)) - return ::_statx_fake_root(st_); + return ::_statx_fake_root(st_,timeout_); timeout_->entry = ((rv >= 0) ? cfg.cache_entry : @@ -235,7 +245,7 @@ FUSE::statx(const fuse_req_ctx_t *ctx_, const fs::path fusepath{fusepath_}; if(Config::is_ctrl_file(fusepath)) - return ::_statx_controlfile(st_); + return ::_statx_controlfile(st_,timeout_); return ::_statx(fusepath, flags_|AT_STATX_DONT_SYNC, @@ -253,27 +263,15 @@ FUSE::statx_fh(const fuse_req_ctx_t *ctx_, fuse_timeouts_t *timeout_) { int rv; - uint64_t fh; + FileInfo *fi = FileInfo::from_fh(fh_); - fh = fh_; - if(fh == 0) - { - state.open_files.cvisit(ctx_->nodeid, - [&](auto &val_) - { - fh = val_.second.fi->to_fh(); - }); - } + if(not fi) + return -EBADF; - if(fh == 0) - return -ENOENT; - - FileInfo *fi = FileInfo::from_fh(fh); - - rv = ::_statx(fi, - flags_|AT_STATX_DONT_SYNC, - mask_, - st_); + rv = ::_statx(fi, + flags_|AT_STATX_DONT_SYNC, + mask_, + st_); timeout_->entry = ((rv >= 0) ? cfg.cache_entry : diff --git a/src/fuse_symlink.cpp b/src/fuse_symlink.cpp index a2cbd367..5dbc818a 100644 --- a/src/fuse_symlink.cpp +++ b/src/fuse_symlink.cpp @@ -97,7 +97,7 @@ int _symlink(const ugid_t ugid_, const Policy::Search &searchFunc_, const Policy::Create &createFunc_, - const Branches &branches_, + const Branches::Ptr branches_, const char *target_, const fs::path &linkpath_, struct stat *st_) @@ -112,10 +112,14 @@ _symlink(const ugid_t ugid_, rv = searchFunc_(branches_,newdirpath,existingbranches); if(rv < 0) return rv; + if(existingbranches.empty()) + return -ENOENT; rv = createFunc_(branches_,newdirpath,newbranches); if(rv < 0) return rv; + if(newbranches.empty()) + return -ENOENT; return ::_symlink_loop(ugid_, existingbranches[0]->path, diff --git a/src/fuse_truncate.cpp b/src/fuse_truncate.cpp index ca9a9e07..6ea0f8a1 100644 --- a/src/fuse_truncate.cpp +++ b/src/fuse_truncate.cpp @@ -64,7 +64,7 @@ static int _truncate(const Policy::Action &actionFunc_, const Policy::Search &searchFunc_, - const Branches &branches_, + const Branches::Ptr branches_, const fs::path &fusepath_, const off_t size_) { @@ -75,6 +75,8 @@ _truncate(const Policy::Action &actionFunc_, rv = actionFunc_(branches_,fusepath_,branches); if(rv < 0) return rv; + if(branches.empty()) + return -ENOENT; ::_truncate_loop(branches,fusepath_,size_,&prv); if(prv.errors.empty()) @@ -86,6 +88,8 @@ _truncate(const Policy::Action &actionFunc_, rv = searchFunc_(branches_,fusepath_,branches); if(rv < 0) return rv; + if(branches.empty()) + return -ENOENT; return prv.get_error(branches[0]->path); } diff --git a/src/fuse_unlink.cpp b/src/fuse_unlink.cpp index 8f72e1a4..abd7ee35 100644 --- a/src/fuse_unlink.cpp +++ b/src/fuse_unlink.cpp @@ -52,7 +52,7 @@ _unlink_loop(const std::vector &branches_, static int _unlink(const Policy::Action &unlinkPolicy_, - const Branches &branches_, + const Branches::Ptr branches_, const fs::path &fusepath_) { int rv; diff --git a/src/fuse_utimens.cpp b/src/fuse_utimens.cpp index 48b8f8fc..7fbec390 100644 --- a/src/fuse_utimens.cpp +++ b/src/fuse_utimens.cpp @@ -63,7 +63,7 @@ static int _utimens(const Policy::Action &utimensPolicy_, const Policy::Search &getattrPolicy_, - const Branches &branches_, + const Branches::Ptr branches_, const fs::path &fusepath_, const timespec ts_[2]) { @@ -74,6 +74,8 @@ _utimens(const Policy::Action &utimensPolicy_, rv = utimensPolicy_(branches_,fusepath_,branches); if(rv < 0) return rv; + if(branches.empty()) + return -ENOENT; ::_utimens_loop(branches,fusepath_,ts_,&prv); if(prv.errors.empty()) @@ -85,6 +87,8 @@ _utimens(const Policy::Action &utimensPolicy_, rv = getattrPolicy_(branches_,fusepath_,branches); if(rv < 0) return rv; + if(branches.empty()) + return -ENOENT; return prv.get_error(branches[0]->path); } diff --git a/src/fuse_write.cpp b/src/fuse_write.cpp index 08403ebd..4db6c397 100644 --- a/src/fuse_write.cpp +++ b/src/fuse_write.cpp @@ -168,6 +168,8 @@ _write(const fuse_file_info_t *ffi_, FileInfo *fi; fi = FileInfo::from_fh(ffi_->fh); + if(not fi) + return -EBADF; // Concurrent writes can only happen if: // 1) writeback-cache is enabled and using page caching diff --git a/src/policy_epff.cpp b/src/policy_epff.cpp index 871d8d6f..71323eeb 100644 --- a/src/policy_epff.cpp +++ b/src/policy_epff.cpp @@ -26,7 +26,6 @@ #include "fs_statvfs_cache.hpp" #include "policy.hpp" #include "policy_error.hpp" -#include "rwlock.hpp" #include #include diff --git a/src/policy_eplus.cpp b/src/policy_eplus.cpp index 5f57f351..2884de11 100644 --- a/src/policy_eplus.cpp +++ b/src/policy_eplus.cpp @@ -25,7 +25,6 @@ #include "fs_statvfs_cache.hpp" #include "policy.hpp" #include "policy_error.hpp" -#include "rwlock.hpp" #include #include diff --git a/src/policy_eppfrd.cpp b/src/policy_eppfrd.cpp index 7a1c6ce0..6220d2ea 100644 --- a/src/policy_eppfrd.cpp +++ b/src/policy_eppfrd.cpp @@ -26,7 +26,6 @@ #include "policy.hpp" #include "policy_error.hpp" #include "rnd.hpp" -#include "rwlock.hpp" #include "strvec.hpp" #include diff --git a/src/policy_lup.cpp b/src/policy_lup.cpp index f154a635..a7f13db4 100644 --- a/src/policy_lup.cpp +++ b/src/policy_lup.cpp @@ -26,7 +26,6 @@ #include "fs_statvfs_cache.hpp" #include "policy.hpp" #include "policy_error.hpp" -#include "rwlock.hpp" #include "base_types.h" diff --git a/src/policy_newest.cpp b/src/policy_newest.cpp index 357b606f..fe3a96a2 100644 --- a/src/policy_newest.cpp +++ b/src/policy_newest.cpp @@ -25,7 +25,6 @@ #include "fs_statvfs_cache.hpp" #include "policy.hpp" #include "policy_error.hpp" -#include "rwlock.hpp" #include #include diff --git a/src/rwlock.hpp b/src/rwlock.hpp deleted file mode 100644 index e72c828b..00000000 --- a/src/rwlock.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - ISC License - - Copyright (c) 2026, Antonio SJ Musumeci - - 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. -*/ - -#pragma once - -#include - -namespace rwlock -{ - class ReadGuard - { - public: - ReadGuard(pthread_rwlock_t &lock_) - : _lock(lock_) - { - pthread_rwlock_rdlock(&_lock); - } - - ~ReadGuard() - { - pthread_rwlock_unlock(&_lock); - } - - private: - ReadGuard(); - - private: - pthread_rwlock_t &_lock; - }; - - class WriteGuard - { - public: - WriteGuard(pthread_rwlock_t &lock_) - : _lock(lock_) - { - pthread_rwlock_wrlock(&_lock); - } - - ~WriteGuard() - { - pthread_rwlock_unlock(&_lock); - } - - private: - WriteGuard(); - - private: - pthread_rwlock_t &_lock; - }; -} diff --git a/src/state.hpp b/src/state.hpp index 5f36db48..b7905a51 100644 --- a/src/state.hpp +++ b/src/state.hpp @@ -79,6 +79,7 @@ #include "fuse.h" +#include #include #include #include @@ -102,7 +103,14 @@ public: { } - int ref_count; + OpenFile(OpenFile &&o_) noexcept + : ref_count(o_.ref_count.load()), + backing_id(o_.backing_id), + fi(o_.fi) + { + } + + std::atomic ref_count; int backing_id; FileInfo *fi; }; diff --git a/src/str.cpp b/src/str.cpp index 5889d92d..5d55bbba 100644 --- a/src/str.cpp +++ b/src/str.cpp @@ -300,6 +300,9 @@ bool str::eq(const char *s0_, const char *s1_) noexcept { + if((s0_ == nullptr) || (s1_ == nullptr)) + return (s0_ == s1_); + return (std::strcmp(s0_, s1_) == 0); } @@ -307,6 +310,9 @@ bool str::startswith(const char *s_, const char *p_) noexcept { + if((s_ == nullptr) || (p_ == nullptr)) + return false; + while(*p_) { if(*p_ != *s_) diff --git a/vendored/libfuse/include/fuse_lowlevel.h b/vendored/libfuse/include/fuse_lowlevel.h index f74f5050..40394b84 100644 --- a/vendored/libfuse/include/fuse_lowlevel.h +++ b/vendored/libfuse/include/fuse_lowlevel.h @@ -102,7 +102,7 @@ struct fuse_lowlevel_ops void (*bmap)(fuse_req_t *req, const struct fuse_in_header *hdr); void (*copy_file_range)(fuse_req_t *req, const struct fuse_in_header *hdr); void (*create)(fuse_req_t *req, struct fuse_in_header *hdr); - void (*destroy)(void *userdata); + void (*destroy)(); void (*fallocate)(fuse_req_t *req, const struct fuse_in_header *hdr); void (*flock)(fuse_req_t *req, uint64_t ino, fuse_file_info_t *fi, int op); void (*flush)(fuse_req_t *req, struct fuse_in_header *hdr); @@ -113,7 +113,7 @@ struct fuse_lowlevel_ops void (*getattr)(fuse_req_t *req, struct fuse_in_header *hdr); void (*getlk)(fuse_req_t *req, const struct fuse_in_header *hdr); void (*getxattr)(fuse_req_t *req, struct fuse_in_header *hdr); - void (*init)(void *userdata, fuse_conn_info_t *conn); + void (*init)(fuse_conn_info_t *conn); void (*ioctl)(fuse_req_t *req, const struct fuse_in_header *hdr); void (*link)(fuse_req_t *req, struct fuse_in_header *hdr); void (*listxattr)(fuse_req_t *req, struct fuse_in_header *hdr); @@ -383,20 +383,6 @@ int fuse_reply_ioctl_retry(fuse_req_t *req, */ int fuse_reply_ioctl(fuse_req_t *req, int result, const void *buf, uint32_t size); -/** - * Reply to finish ioctl with iov buffer - * - * Possible requests: - * ioctl - * - * @param req request handle - * @param result result to be passed to the caller - * @param iov the vector containing the data - * @param count the size of vector - */ -int fuse_reply_ioctl_iov(fuse_req_t *req, int result, const struct iovec *iov, - int count); - /** * Reply with poll result event mask * @@ -535,12 +521,11 @@ int fuse_lowlevel_is_lib_option(const char *opt); * @param args argument vector * @param op the low level filesystem operations * @param op_size sizeof(struct fuse_lowlevel_ops) - * @param userdata user data * @return the created session object, or NULL on failure */ struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, - size_t op_size, void *userdata); + size_t op_size); /* ----------------------------------------------------------- * * Session interface * diff --git a/vendored/libfuse/include/objpool.hpp b/vendored/libfuse/include/objpool.hpp index ceb3b0db..6e4facdb 100644 --- a/vendored/libfuse/include/objpool.hpp +++ b/vendored/libfuse/include/objpool.hpp @@ -214,6 +214,9 @@ private: static_cast(node) : _allocator.allocate(size_, alignof(T))); + if(not mem) + return nullptr; + try { return new(mem) T(std::forward(args_)...); @@ -242,12 +245,13 @@ public: if(not obj_) return; - bool should_pool = _should_pool(obj_); + bool should_pool = _should_pool(obj_); + Node *node = to_node(obj_); obj_->~T(); if(should_pool) - _push_node(to_node(obj_),size_); + _push_node(node,size_); else _allocator.deallocate(obj_,size_,alignof(T)); } diff --git a/vendored/libfuse/include/thread_pool.hpp b/vendored/libfuse/include/thread_pool.hpp index 4a2bffe4..d32061d5 100644 --- a/vendored/libfuse/include/thread_pool.hpp +++ b/vendored/libfuse/include/thread_pool.hpp @@ -180,14 +180,21 @@ ThreadPool::ThreadPool(const unsigned thread_count_, inline ThreadPool::~ThreadPool() { + std::vector threads; + + { + mutex_lockguard(_threads_mutex); + threads = _threads; + } + syslog(LOG_DEBUG, "threadpool (%s): destroying %zu threads", _name.c_str(), - _threads.size()); + threads.size()); - for(auto t : _threads) + for(auto t : threads) pthread_cancel(t); - for(auto t : _threads) + for(auto t : threads) pthread_join(t,NULL); } diff --git a/vendored/libfuse/lib/cpu.cpp b/vendored/libfuse/lib/cpu.cpp index c8566d0a..b16e19ec 100644 --- a/vendored/libfuse/lib/cpu.cpp +++ b/vendored/libfuse/lib/cpu.cpp @@ -136,6 +136,12 @@ CPU::cpu2core() ifs >> core_id; + if(!ifs) + { + ifs.close(); + continue; + } + c2c[i] = core_id; ifs.close(); @@ -169,6 +175,12 @@ CPU::core2cpus() ifs >> core_id; + if(!ifs) + { + ifs.close(); + continue; + } + c2c[core_id].insert(i); ifs.close(); diff --git a/vendored/libfuse/lib/debug.cpp b/vendored/libfuse/lib/debug.cpp index 57a48c2c..7dfd9027 100644 --- a/vendored/libfuse/lib/debug.cpp +++ b/vendored/libfuse/lib/debug.cpp @@ -63,7 +63,7 @@ _debug_set_output_stderr() auto new_log_file = std::shared_ptr(stderr,[](FILE*){}); fuse_cfg.log_file(new_log_file); - fuse_cfg.log_filepath("/dev/stderr"); + fuse_cfg.log_filepath(""); return 0; } diff --git a/vendored/libfuse/lib/fuse.cpp b/vendored/libfuse/lib/fuse.cpp index 79993680..51e8d600 100644 --- a/vendored/libfuse/lib/fuse.cpp +++ b/vendored/libfuse/lib/fuse.cpp @@ -6,7 +6,6 @@ See the file COPYING.LIB */ -/* For pthread_rwlock_t */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif @@ -15,9 +14,11 @@ #include "crc32b.h" #include "debug.hpp" +#include "fatal.hpp" #include "kvec.h" #include "mutex.hpp" #include "node.hpp" +#include "xalloc.hpp" #include "fuse_cfg.hpp" #include "fuse_req.hpp" @@ -188,7 +189,7 @@ id_hash(uint64_t ino) static node_t* -get_node_nocheck(uint64_t nodeid) +get_node(const uint64_t nodeid) { size_t hash = id_hash(nodeid); node_t *node; @@ -200,22 +201,6 @@ get_node_nocheck(uint64_t nodeid) return NULL; } -static -node_t* -get_node(const uint64_t nodeid) -{ - node_t *node = get_node_nocheck(nodeid); - - if(!node) - { - fprintf(stderr,"fuse internal error: node %llu not found\n", - (unsigned long long)nodeid); - abort(); - } - - return node; -} - static void remove_remembered_node(node_t *node_) @@ -290,10 +275,11 @@ node_table_reduce(struct node_table *t) return; newarray = realloc(t->array,sizeof(node_t*) * newsize); - if(newarray != NULL) - t->array = (node_t**)newarray; + if(newarray == NULL) + return; - t->size = newsize; + t->array = (node_t**)newarray; + t->size = newsize; t->split = t->size / 2; } @@ -471,33 +457,32 @@ static void unhash_name(node_t *node) { - if(node->name) + if(not (node && node->name && node->parent)) + return; + + size_t hash = name_hash(node->parent->nodeid,node->name); + node_t **nodep = &f.name_table.array[hash]; + + for(; *nodep != NULL; nodep = &(*nodep)->name_next) { - size_t hash = name_hash(node->parent->nodeid,node->name); - node_t **nodep = &f.name_table.array[hash]; + if(*nodep != node) + continue; - for(; *nodep != NULL; nodep = &(*nodep)->name_next) - if(*nodep == node) - { - *nodep = node->name_next; - node->name_next = NULL; - unref_node(node->parent); - free(node->name); - node->name = NULL; - node->parent = NULL; - f.name_table.use--; + *nodep = node->name_next; + node->name_next = NULL; + unref_node(node->parent); + free(node->name); + node->name = NULL; + node->parent = NULL; + f.name_table.use--; - if(f.name_table.use < f.name_table.size / 4) - remerge_name(); - return; - } - - fprintf(stderr, - "fuse internal error: unable to unhash node: %llu\n", - (unsigned long long)node->nodeid); - - abort(); + if(f.name_table.use < f.name_table.size / 4) + remerge_name(); + return; } + + fatal::abort("mergerfs: unable to unhash node: {}", + node->nodeid); } static @@ -517,6 +502,12 @@ rehash_name() for(nodep = &t->array[hash]; *nodep != NULL; nodep = next) { node_t *node = *nodep; + if(node->parent == NULL) + { + next = &node->name_next; + continue; + } + size_t newhash = name_hash(node->parent->nodeid,node->name); if(newhash != hash) @@ -542,8 +533,15 @@ hash_name(node_t *node, uint64_t parentid, const char *name) { - size_t hash = name_hash(parentid,name); - node_t *parent = get_node(parentid); + size_t hash; + node_t *parent; + + hash = name_hash(parentid,name); + parent = get_node(parentid); + + if(parent == NULL) + return -1; + node->name = strdup(name); if(node->name == NULL) return -1; @@ -634,12 +632,18 @@ find_node(uint64_t parent, const char *name) { node_t *node; + mutex_lockguard(f.lock); - mutex_lock(f.lock); if(!name) - node = get_node(parent); + { + node = get_node(parent); + if(node == NULL) + goto out_err; + } else - node = lookup_node(parent,name); + { + node = lookup_node(parent,name); + } if(node == NULL) { @@ -664,8 +668,8 @@ find_node(uint64_t parent, remove_remembered_node(node); } inc_nlookup(node); + out_err: - mutex_unlock(f.lock); return node; } @@ -723,8 +727,11 @@ unlock_path(uint64_t nodeid, wnode->treelock = 0; } - for(node = get_node(nodeid); - node != end && node->nodeid != FUSE_ROOT_ID; + node = get_node(nodeid); + if(node == NULL) + return; + + for(;node != end && node->nodeid != FUSE_ROOT_ID; node = node->parent) { assert(node->treelock != 0); @@ -794,7 +801,14 @@ try_get_path(uint64_t nodeid, } } - for(node = get_node(nodeid); node->nodeid != FUSE_ROOT_ID; node = node->parent) + node = get_node(nodeid); + if(node == NULL) + { + err = -ESTALE; + goto out_unlock; + } + + for(; node->nodeid != FUSE_ROOT_ID; node = node->parent) { err = -ESTALE; if(node->name == NULL || node->parent == NULL) @@ -874,7 +888,8 @@ queue_element_wakeup(struct lock_queue_element *qe) if(!qe->path1) { /* Just waiting for it to be unlocked */ - if(get_node(qe->nodeid1)->treelock == 0) + node_t *qnode = get_node(qe->nodeid1); + if(qnode && (qnode->treelock == 0)) pthread_cond_signal(&qe->cond); return; @@ -1102,8 +1117,11 @@ forget_node(const uint64_t nodeid, if(nodeid == FUSE_ROOT_ID) return; - mutex_lock(f.lock); + mutex_lockguard(f.lock); + node = get_node(nodeid); + if(node == NULL) + return; /* * Node may still be locked due to interrupt idiocy in open, @@ -1142,8 +1160,6 @@ forget_node(const uint64_t nodeid, kv_push(remembered_node_t,f.remembered_nodes,fn); } - - mutex_unlock(f.lock); } static @@ -1320,15 +1336,14 @@ reply_entry(fuse_req_t *req_, static void -fuse_lib_init(void *data, - fuse_conn_info_t *conn) +fuse_lib_init(fuse_conn_info_t *conn) { f.ops.init(conn); } static void -fuse_lib_destroy(void *data) +fuse_lib_destroy() { f.ops.destroy(); } @@ -1353,29 +1368,34 @@ fuse_lib_lookup(fuse_req_t *req_, if(name[1] == '\0') { name = NULL; - mutex_lock(f.lock); - dot = get_node_nocheck(nodeid); + mutex_lockguard(f.lock); + dot = get_node(nodeid); if(dot == NULL) { - mutex_unlock(f.lock); reply_entry(req_,&e,-ESTALE); return; } dot->refctr++; - mutex_unlock(f.lock); } else if((name[1] == '.') && (name[2] == '\0')) { - if(nodeid == 1) + if(nodeid == FUSE_ROOT_ID) { reply_entry(req_,&e,-ENOENT); return; } name = NULL; - mutex_lock(f.lock); - nodeid = get_node(nodeid)->parent->nodeid; - mutex_unlock(f.lock); + mutex_lockguard(f.lock); + { + node_t *pnode = get_node(nodeid); + if((pnode == NULL) || (pnode->parent == NULL)) + { + reply_entry(req_,&e,-ESTALE); + return; + } + nodeid = pnode->parent->nodeid; + } } } @@ -1476,19 +1496,28 @@ fuse_lib_getattr(fuse_req_t *req_, if(!err) { - err = ((fusepath != NULL) ? - f.ops.getattr(&req_->ctx,&fusepath[1],&buf,&timeouts) : - f.ops.fgetattr(&req_->ctx,fh,&buf,&timeouts)); + if(fusepath != NULL) + err = f.ops.getattr(&req_->ctx,&fusepath[1],&buf,&timeouts); + else if(fh != 0) + err = f.ops.fgetattr(&req_->ctx,fh,&buf,&timeouts); + else + err = -ENOENT; free_path(hdr_->nodeid,fusepath); } if(!err) { - mutex_lock(f.lock); - node = get_node(hdr_->nodeid); - update_stat(node,&buf); - mutex_unlock(f.lock); + { + mutex_lockguard(f.lock); + node = get_node(hdr_->nodeid); + if(node == NULL) + { + fuse_reply_err(req_,ENOMEM); + return; + } + update_stat(node,&buf); + } set_stat(hdr_->nodeid,&buf); fuse_reply_attr(req_,&buf,timeouts.attr); } @@ -1654,9 +1683,15 @@ fuse_lib_setattr(fuse_req_t *req_, if(!err) { - mutex_lock(f.lock); - update_stat(get_node(hdr_->nodeid),&stbuf); - mutex_unlock(f.lock); + { + node_t *node; + mutex_lockguard(f.lock); + + node = get_node(hdr_->nodeid); + if(node) + update_stat(node,&stbuf); + } + set_stat(hdr_->nodeid,&stbuf); fuse_reply_attr(req_,&stbuf,timeouts.attr); } @@ -1997,15 +2032,17 @@ fuse_do_release(fuse_req_ctx_t *req_ctx_, f.ops.release(req_ctx_, ffi_); - mutex_lock(f.lock); + mutex_lockguard(f.lock); { node_t *node; node = get_node(ino_); - assert(node->open_count > 0); - node->open_count--; + if(node) + { + assert(node->open_count > 0); + node->open_count--; + } } - mutex_unlock(f.lock); } static @@ -2021,8 +2058,8 @@ fuse_lib_create(fuse_req_t *req_, struct fuse_entry_param e; struct fuse_create_in *arg; - arg = (fuse_create_in*)fuse_hdr_arg(hdr_); - name = (const char*)PARAM(arg); + arg = (fuse_create_in*)fuse_hdr_arg(hdr_); + name = (const char*)PARAM(arg); ffi.flags = arg->flags; @@ -2034,7 +2071,15 @@ fuse_lib_create(fuse_req_t *req_, // opportunistically allocate a node so we have a new nodeid for // later in the actual create. Added for use with passthrough. { - node_t *node = find_node(hdr_->nodeid,name); + node_t *node; + + node = find_node(hdr_->nodeid,name); + if(node == NULL) + { + fuse_reply_err(req_,ENOMEM); + return; + } + new_nodeid = node->nodeid; req_->ctx.nodeid = new_nodeid; } @@ -2065,7 +2110,9 @@ fuse_lib_create(fuse_req_t *req_, if(!err) { mutex_lock(f.lock); - get_node(e.ino)->open_count++; + node_t *node = get_node(e.ino); + if(node) + node->open_count++; mutex_unlock(f.lock); if(fuse_reply_create(req_,&e,&ffi) == -ENOENT) @@ -2098,6 +2145,12 @@ open_auto_cache(fuse_req_ctx_t *req_ctx_, mutex_lock(f.lock); node = get_node(ino); + if(not node) + { + mutex_unlock(f.lock); + return; + } + if(node->is_stat_cache_valid) { int err; @@ -2134,7 +2187,7 @@ fuse_lib_open(fuse_req_t *req_, fuse_file_info_t ffi = {}; struct fuse_open_in *arg; - arg = (fuse_open_in*)fuse_hdr_arg(hdr_); + arg = (fuse_open_in*)fuse_hdr_arg(hdr_); ffi.flags = arg->flags; @@ -2154,7 +2207,9 @@ fuse_lib_open(fuse_req_t *req_, if(!err) { mutex_lock(f.lock); - get_node(hdr_->nodeid)->open_count++; + node_t *node = get_node(hdr_->nodeid); + if(node) + node->open_count++; mutex_unlock(f.lock); /* The open syscall was interrupted,so it must be cancelled */ if(fuse_reply_open(req_,&ffi) == -ENOENT) @@ -2187,6 +2242,11 @@ fuse_lib_read(fuse_req_t *req_, } msgbuf = msgbuf_alloc_page_aligned(); + if(msgbuf == NULL) + { + fuse_reply_err(req_,ENOMEM); + return; + } res = f.ops.read(&req_->ctx, &ffi, @@ -2260,11 +2320,17 @@ fuse_lib_fsync(fuse_req_t *req_, static struct fuse_dh* get_dirhandle(const fuse_file_info_t *llfi, - fuse_file_info_t *fi) + fuse_file_info_t *ffi) { struct fuse_dh *dh = (struct fuse_dh *)(uintptr_t)llfi->fh; - memset(fi,0,sizeof(fuse_file_info_t)); - fi->fh = dh->fh; + + if(dh == NULL) + return NULL; + + memset(ffi,0,sizeof(fuse_file_info_t)); + + ffi->fh = dh->fh; + return dh; } @@ -2283,14 +2349,21 @@ fuse_lib_opendir(fuse_req_t *req_, arg = (fuse_open_in*)fuse_hdr_arg(hdr_); llffi.flags = arg->flags; - dh = (struct fuse_dh *)calloc(1,sizeof(struct fuse_dh)); + dh = (fuse_dh*)calloc(1,sizeof(fuse_dh)); if(dh == NULL) { fuse_reply_err(req_,ENOMEM); return; } - fuse_dirents_init(&dh->d); + err = fuse_dirents_init(&dh->d); + if(err) + { + free(dh); + fuse_reply_err(req_,ENOMEM); + return; + } + mutex_init(dh->lock); llffi.fh = (uintptr_t)dh; @@ -2313,8 +2386,9 @@ fuse_lib_opendir(fuse_req_t *req_, { /* The opendir syscall was interrupted,so it must be cancelled */ - f.ops.releasedir(&req_->ctx, - &ffi); + f.ops.releasedir(&req_->ctx,&ffi); + + fuse_dirents_free(&dh->d); mutex_destroy(dh->lock); free(dh); } @@ -2322,6 +2396,7 @@ fuse_lib_opendir(fuse_req_t *req_, else { fuse_reply_err(req_,err); + fuse_dirents_free(&dh->d); mutex_destroy(dh->lock); free(dh); } @@ -2363,7 +2438,7 @@ fuse_lib_readdir(fuse_req_t *req_, size_t size; fuse_dirents_t *d; struct fuse_dh *dh; - fuse_file_info_t ffi = {}; + fuse_file_info_t ffi; fuse_file_info_t llffi = {}; struct fuse_read_in *arg; @@ -2372,9 +2447,15 @@ fuse_lib_readdir(fuse_req_t *req_, llffi.fh = arg->fh; dh = get_dirhandle(&llffi,&ffi); - d = &dh->d; + if(not dh) + { + fuse_reply_err(req_,EBADF); + return; + } - mutex_lock(dh->lock); + d = &dh->d; + + mutex_lockguard(dh->lock); rv = 0; if((arg->offset == 0) || (kv_size(d->data) == 0)) @@ -2385,17 +2466,17 @@ fuse_lib_readdir(fuse_req_t *req_, if(rv) { fuse_reply_err(req_,rv); - goto out; + return; } size = readdir_buf_size(d,size,arg->offset); - fuse_reply_buf(req_, - readdir_buf(d,arg->offset), - size); - - out: - mutex_unlock(dh->lock); + if(size == 0) + fuse_reply_buf(req_,NULL,0); + else + fuse_reply_buf(req_, + readdir_buf(d,arg->offset), + size); } static @@ -2407,7 +2488,7 @@ fuse_lib_readdir_plus(fuse_req_t *req_, size_t size; fuse_dirents_t *d; struct fuse_dh *dh; - fuse_file_info_t ffi = {}; + fuse_file_info_t ffi; fuse_file_info_t llffi = {}; struct fuse_read_in *arg; @@ -2416,9 +2497,15 @@ fuse_lib_readdir_plus(fuse_req_t *req_, llffi.fh = arg->fh; dh = get_dirhandle(&llffi,&ffi); - d = &dh->d; + if(not dh) + { + fuse_reply_err(req_,EBADF); + return; + } - mutex_lock(dh->lock); + d = &dh->d; + + mutex_lockguard(dh->lock); rv = 0; if((arg->offset == 0) || (kv_size(d->data) == 0)) @@ -2429,17 +2516,17 @@ fuse_lib_readdir_plus(fuse_req_t *req_, if(rv) { fuse_reply_err(req_,rv); - goto out; + return; } size = readdir_buf_size(d,size,arg->offset); - fuse_reply_buf(req_, - readdir_buf(d,arg->offset), - size); - - out: - mutex_unlock(dh->lock); + if(size == 0) + fuse_reply_buf(req_,NULL,0); + else + fuse_reply_buf(req_, + readdir_buf(d,arg->offset), + size); } static @@ -2457,6 +2544,11 @@ fuse_lib_releasedir(fuse_req_t *req_, llffi.flags = arg->flags; dh = get_dirhandle(&llffi,&ffi); + if(not dh) + { + fuse_reply_err(req_,EBADF); + return; + } f.ops.releasedir(&req_->ctx, &ffi); @@ -2477,6 +2569,7 @@ fuse_lib_fsyncdir(fuse_req_t *req_, { int err; int is_datasync; + fuse_dh *dh; fuse_file_info_t ffi; fuse_file_info_t llffi = {}; struct fuse_fsync_in *arg; @@ -2485,7 +2578,12 @@ fuse_lib_fsyncdir(fuse_req_t *req_, is_datasync = !!(arg->fsync_flags & FUSE_FSYNC_FDATASYNC); llffi.fh = arg->fh; - get_dirhandle(&llffi,&ffi); + dh = get_dirhandle(&llffi,&ffi); + if(not dh) + { + fuse_reply_err(req_,EBADF); + return; + } err = f.ops.fsyncdir(&req_->ctx, &ffi, @@ -2822,7 +2920,9 @@ fuse_lib_tmpfile(fuse_req_t *req_, if(!err) { mutex_lock(f.lock); - get_node(e.ino)->open_count++; + node_t *node = get_node(e.ino); + if(node) + node->open_count++; mutex_unlock(f.lock); if(fuse_reply_create(req_,&e,&ffi) == -ENOENT) @@ -3008,9 +3108,13 @@ fuse_flush_common(fuse_req_t *req_, { flock_to_lock(&lock,&l); l.owner = ffi_->lock_owner; - mutex_lock(f.lock); - locks_insert(get_node(ino_),&l); - mutex_unlock(f.lock); + + { + mutex_lockguard(f.lock); + node_t *n = get_node(ino_); + if(n) + locks_insert(n,&l); + } /* if op.lock() is defined FLUSH is needed regardless of op.flush() */ @@ -3133,11 +3237,15 @@ fuse_lib_getlk(fuse_req_t *req_, flock_to_lock(&flk,&lk); lk.owner = ffi.lock_owner; - mutex_lock(f.lock); - conflict = locks_conflict(get_node(hdr_->nodeid),&lk); - if(conflict) - lock_to_flock(conflict,&flk); - mutex_unlock(f.lock); + + { + mutex_lockguard(f.lock); + node_t *n = get_node(hdr_->nodeid); + conflict = (n ? locks_conflict(n,&lk) : NULL); + if(conflict) + lock_to_flock(conflict,&flk); + } + if(!conflict) err = fuse_lock_common(req_,hdr_->nodeid,&ffi,&flk,F_GETLK); else @@ -3157,16 +3265,26 @@ fuse_lib_setlk(fuse_req_t *req_, struct flock *lock, int sleep) { - int err = fuse_lock_common(req_,ino,fi,lock, - sleep ? F_SETLKW : F_SETLK); + int err; + + err = fuse_lock_common(req_, + ino, + fi, + lock, + sleep ? F_SETLKW : F_SETLK); if(!err) { lock_t l; + flock_to_lock(lock,&l); l.owner = fi->lock_owner; - mutex_lock(f.lock); - locks_insert(get_node(ino),&l); - mutex_unlock(f.lock); + + { + mutex_lockguard(f.lock); + node_t *n = get_node(ino); + if(n) + locks_insert(n,&l); + } } fuse_reply_err(req_,err); @@ -3224,20 +3342,20 @@ fuse_lib_ioctl(fuse_req_t *req_, { int err; char *out_buf = NULL; - fuse_file_info_t ffi; + fuse_dh *dh; + fuse_file_info_t ffi = {}; fuse_file_info_t llffi = {}; const void *in_buf; uint32_t out_size; const struct fuse_ioctl_in *arg; arg = (fuse_ioctl_in*)fuse_hdr_arg(hdr_); - if((arg->flags & FUSE_IOCTL_DIR) && !(req_->conn.want & FUSE_CAP_IOCTL_DIR)) - { - fuse_reply_err(req_,ENOTTY); - return; - } - if((sizeof(void*) == 4) && + err = -EPERM; + if(arg->flags & FUSE_IOCTL_UNRESTRICTED) + goto err; + + if((sizeof(void*) == 4) && (req_->conn.proto_minor >= 16) && !(arg->flags & FUSE_IOCTL_32BIT)) { @@ -3248,14 +3366,27 @@ fuse_lib_ioctl(fuse_req_t *req_, out_size = arg->out_size; in_buf = (arg->in_size ? PARAM(arg) : NULL); - err = -EPERM; - if(arg->flags & FUSE_IOCTL_UNRESTRICTED) - goto err; - if(arg->flags & FUSE_IOCTL_DIR) - get_dirhandle(&llffi,&ffi); + { + dh = get_dirhandle(&llffi,&ffi); + if(not dh) + { + err = -EBADF; + goto err; + } + } else - ffi = llffi; + { + ffi = llffi; + } + + if((arg->in_size > 0) && + (out_size > 0) && + (arg->in_size != out_size)) + { + err = -EINVAL; + goto err; + } if(out_size) { @@ -3263,28 +3394,27 @@ fuse_lib_ioctl(fuse_req_t *req_, out_buf = (char*)malloc(out_size); if(!out_buf) goto err; + DEFER { free(out_buf); }; } - assert(!arg->in_size || !out_size || arg->in_size == out_size); - if(out_buf && in_buf) - memcpy(out_buf,in_buf,arg->in_size); + if(in_buf && out_buf) + memcpy(out_buf,in_buf,out_size); err = f.ops.ioctl(&req_->ctx, &ffi, arg->cmd, (void*)(uintptr_t)arg->arg, arg->flags, - out_buf ?: (void *)in_buf, + out_buf ? out_buf : (void*)in_buf, &out_size); if(err < 0) goto err; fuse_reply_ioctl(req_,err,out_buf,out_size); - goto out; + return; + err: fuse_reply_err(req_,err); - out: - free(out_buf); } static @@ -3352,7 +3482,11 @@ remembered_node_cmp(const void *a_, const remembered_node_t *a = (const remembered_node_t*)a_; const remembered_node_t *b = (const remembered_node_t*)b_; - return (a->time - b->time); + if(a->time < b->time) + return -1; + if(a->time > b->time) + return 1; + return 0; } static @@ -3606,7 +3740,10 @@ metrics_log_nodes_info_to_tmp_dir(struct fuse *f_) struct stat st; char const *mode = "a"; - sprintf(filepath,"/tmp/mergerfs.%d.info",getpid()); + snprintf(filepath, + sizeof(filepath), + "/tmp/mergerfs.%d.info", + getpid()); rv = lstat(filepath,&st); if((rv == 0) && (st.st_size > INFO_FILE_MAX_SIZE)) @@ -3725,7 +3862,7 @@ fuse_new(int fd_, llop.setlk = NULL; } - f.se = fuse_lowlevel_new_common(args,&llop,sizeof(llop),&f); + f.se = fuse_lowlevel_new_common(args,&llop,sizeof(llop)); if(f.se == NULL) goto out_free_fs; @@ -3750,11 +3887,11 @@ fuse_new(int fd_, root = node_alloc(); if(root == NULL) { - fprintf(stderr,"fuse: memory allocation failed\n"); + fprintf(stderr,"mergerfs: root node alloc failed\n"); goto out_free_id_table; } - root->name = strdup("/"); + root->name = xstrdup("/"); root->parent = NULL; root->nodeid = FUSE_ROOT_ID; diff --git a/vendored/libfuse/lib/fuse_i.hpp b/vendored/libfuse/lib/fuse_i.hpp index d52b4560..8989aa07 100644 --- a/vendored/libfuse/lib/fuse_i.hpp +++ b/vendored/libfuse/lib/fuse_i.hpp @@ -56,6 +56,6 @@ EXTERN_C_BEGIN struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args, const struct fuse_lowlevel_ops *op, - size_t op_size, void *userdata); + size_t op_size); EXTERN_C_END diff --git a/vendored/libfuse/lib/fuse_loop.cpp b/vendored/libfuse/lib/fuse_loop.cpp index b2394a93..408853b9 100644 --- a/vendored/libfuse/lib/fuse_loop.cpp +++ b/vendored/libfuse/lib/fuse_loop.cpp @@ -57,6 +57,13 @@ _print_error(int rv_) -rv_); } +static +int +_nproc() +{ + return std::max(1,(int)std::thread::hardware_concurrency()); +} + struct AsyncWorker { fuse_session *_se; @@ -86,6 +93,11 @@ struct AsyncWorker fuse_msgbuf_t *msgbuf; msgbuf = msgbuf_alloc(); + if(not msgbuf) + { + fmt::println(stderr,"mergerfs: failure to allocate msgbuf, exiting"); + return; + } while(true) { @@ -141,6 +153,11 @@ struct SyncWorker fuse_msgbuf_t *msgbuf; msgbuf = msgbuf_alloc(); + if(not msgbuf) + { + fmt::println(stderr,"mergerfs: failure to allocate msgbuf, exiting"); + return; + } while(true) { @@ -166,31 +183,6 @@ struct SyncWorker } }; -int -fuse_start_thread(pthread_t *thread_id, - void *(*func)(void *), - void *arg) -{ - int res; - sigset_t oldset; - sigset_t newset; - - sigfillset(&newset); - pthread_sigmask(SIG_BLOCK,&newset,&oldset); - res = pthread_create(thread_id,NULL,func,arg); - pthread_sigmask(SIG_SETMASK,&oldset,NULL); - - if(res != 0) - { - fprintf(stderr, - "fuse: error creating thread: %s\n", - strerror(res)); - return -1; - } - - return 0; -} - static int _calculate_thread_count(const int raw_thread_count_) @@ -199,12 +191,12 @@ _calculate_thread_count(const int raw_thread_count_) if(raw_thread_count_ == 0) { - thread_count = std::thread::hardware_concurrency(); + thread_count = ::_nproc(); thread_count = std::min(8,thread_count); } else if(raw_thread_count_ < 0) { - thread_count = (std::thread::hardware_concurrency() / -raw_thread_count_); + thread_count = (::_nproc() / -raw_thread_count_); thread_count = std::max(1,thread_count); } else if(raw_thread_count_ > 0) @@ -225,14 +217,14 @@ _calculate_thread_counts(int *read_thread_count_, { int nproc; - nproc = std::thread::hardware_concurrency(); + nproc = ::_nproc(); *read_thread_count_ = std::min(8,nproc); } else if((*read_thread_count_ == 0) && (*process_thread_count_ == 0)) { int nproc; - nproc = std::thread::hardware_concurrency(); + nproc = ::_nproc(); *read_thread_count_ = 2; *process_thread_count_ = std::max(2,(nproc - 2)); *process_thread_count_ = std::min(8,*process_thread_count_); diff --git a/vendored/libfuse/lib/fuse_lowlevel.cpp b/vendored/libfuse/lib/fuse_lowlevel.cpp index 2e093ab8..411168d2 100644 --- a/vendored/libfuse/lib/fuse_lowlevel.cpp +++ b/vendored/libfuse/lib/fuse_lowlevel.cpp @@ -45,7 +45,6 @@ static size_t pagesize; struct fuse_ll { struct fuse_lowlevel_ops op; - void *userdata; uid_t owner; fuse_conn_info_t conn; mutex_t lock; @@ -361,6 +360,9 @@ int fuse_reply_readlink(fuse_req_t *req, const char *linkname) { + if(not linkname) + return fuse_reply_err(req,EIO); + if(fuse_cfg.debug) fuse_debug_readlink(req->ctx.unique,linkname); @@ -538,12 +540,12 @@ fuse_reply_ioctl_retry(fuse_req_t *req, const struct iovec *out_iov, size_t out_count) { + int res; struct fuse_ioctl_out arg = {}; struct fuse_ioctl_iovec *in_fiov = NULL; struct fuse_ioctl_iovec *out_fiov = NULL; struct iovec iov[4]; size_t count = 1; - int res; arg.flags |= FUSE_IOCTL_RETRY; arg.in_iovs = in_count; @@ -603,6 +605,7 @@ fuse_reply_ioctl_retry(fuse_req_t *req, } res = send_reply_iov(req, 0, iov, count); + out: free(in_fiov); free(out_fiov); @@ -647,36 +650,6 @@ fuse_reply_ioctl(fuse_req_t *req, return send_reply_iov(req, 0, iov, count); } -int -fuse_reply_ioctl_iov(fuse_req_t *req, - int result, - const struct iovec *iov, - int count) -{ - struct iovec *padded_iov; - struct fuse_ioctl_out arg = {}; - int res; - - padded_iov = (iovec*)malloc((count + 2) * sizeof(struct iovec)); - if(padded_iov == NULL) - return fuse_reply_err(req, ENOMEM); - - arg.result = result; - - if(fuse_cfg.debug) - fuse_debug_ioctl_out(req->ctx.unique,&arg); - - padded_iov[1].iov_base = &arg; - padded_iov[1].iov_len = sizeof(arg); - - memcpy(&padded_iov[2], iov, count * sizeof(struct iovec)); - - res = send_reply_iov(req, 0, padded_iov, count + 2); - free(padded_iov); - - return res; -} - int fuse_reply_poll(fuse_req_t *req, unsigned revents) @@ -1195,8 +1168,7 @@ do_init(fuse_req_t *req, max_write = bufsize; f.got_init = 1; - if(f.op.init) - f.op.init(f.userdata, &f.conn); + f.op.init(&f.conn); outargflags = outarg.flags; if((inargflags & FUSE_MAX_PAGES) && (f.conn.want & FUSE_CAP_MAX_PAGES)) @@ -1309,7 +1281,8 @@ do_destroy(fuse_req_t *req, struct fuse_in_header *hdr_) { f.got_destroy = 1; - f.op.destroy(f.userdata); + + f.op.destroy(); send_reply_ok(req,NULL,0); } @@ -1697,10 +1670,7 @@ void fuse_ll_destroy(void *data) { if(f.got_init && !f.got_destroy) - { - if(f.op.destroy) - f.op.destroy(f.userdata); - } + f.op.destroy(); mutex_destroy(f.lock); msgbuf_gc(); @@ -1854,8 +1824,7 @@ fuse_ll_buf_process_read_init(struct fuse_session *se_, struct fuse_session * fuse_lowlevel_new_common(struct fuse_args *args, const struct fuse_lowlevel_ops *op, - size_t op_size, - void *userdata) + size_t op_size) { struct fuse_session *se; @@ -1871,7 +1840,6 @@ fuse_lowlevel_new_common(struct fuse_args *args, memcpy(&f.op,op,op_size); f.owner = getuid(); - f.userdata = userdata; se = fuse_session_new(&f, (void*)fuse_ll_buf_receive_read, @@ -1892,8 +1860,7 @@ fuse_lowlevel_new_common(struct fuse_args *args, struct fuse_session* fuse_lowlevel_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, - size_t op_size, - void *userdata) + size_t op_size) { - return fuse_lowlevel_new_common(args, op, op_size, userdata); + return fuse_lowlevel_new_common(args, op, op_size); } diff --git a/vendored/libfuse/lib/fuse_opt.cpp b/vendored/libfuse/lib/fuse_opt.cpp index 89bd9e80..07eca268 100644 --- a/vendored/libfuse/lib/fuse_opt.cpp +++ b/vendored/libfuse/lib/fuse_opt.cpp @@ -214,23 +214,35 @@ int fuse_opt_match(const struct fuse_opt *opts, const char *opt) return find_opt(opts, opt, &dummy) ? 1 : 0; } -static int process_opt_param(void *var, const char *format, const char *param, - const char *arg) +static +int +process_opt_param(void *var, + const char *format, + const char *param, + const char *arg) { assert(format[0] == '%'); - if (format[1] == 's') + + if(format[1] == 's') { char *copy = strdup(param); - if (!copy) + if(!copy) return alloc_failed(); *static_cast(var) = copy; - } else { - if (sscanf(param, format, static_cast(var)) != 1) { - fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg); - return -1; } - } + else + { + int rv; + + rv = sscanf(param, format, static_cast(var)); + if(rv != 1) + { + fprintf(stderr,"mergerfs: invalid parameter in option `%s'\n",arg); + return -1; + } + } + return 0; } diff --git a/vendored/libfuse/lib/fuse_session.cpp b/vendored/libfuse/lib/fuse_session.cpp index e1f2a849..de356330 100644 --- a/vendored/libfuse/lib/fuse_session.cpp +++ b/vendored/libfuse/lib/fuse_session.cpp @@ -50,6 +50,9 @@ fuse_session_new(void *data, void fuse_session_destroy(struct fuse_session *se) { + if(se == nullptr) + return; + if(se->destroy) se->destroy(se->f); diff --git a/vendored/libfuse/lib/fuse_signals.cpp b/vendored/libfuse/lib/fuse_signals.cpp index ba9c70be..447d2701 100644 --- a/vendored/libfuse/lib/fuse_signals.cpp +++ b/vendored/libfuse/lib/fuse_signals.cpp @@ -8,19 +8,24 @@ #include "fuse_lowlevel.h" +#include + #include #include #include -static struct fuse_session *fuse_instance; +static std::atomic g_fuse_instance{nullptr}; static void exit_handler(int sig) { (void)sig; - if (fuse_instance) - fuse_session_exit(fuse_instance); + struct fuse_session *instance; + + instance = g_fuse_instance.load(std::memory_order_acquire); + if(instance) + fuse_session_exit(instance); } static int set_one_signal_handler(int sig, void (*handler)(int), int remove) @@ -54,20 +59,20 @@ int fuse_set_signal_handlers(struct fuse_session *se) (set_one_signal_handler(SIGPIPE, SIG_IGN, 0) == -1)) return -1; - fuse_instance = se; + g_fuse_instance.store(se,std::memory_order_release); + return 0; } void fuse_remove_signal_handlers(struct fuse_session *se) { - if (fuse_instance != se) - fprintf(stderr, - "fuse: fuse_remove_signal_handlers: unknown session\n"); - else - fuse_instance = NULL; - set_one_signal_handler(SIGINT, exit_handler, 1); set_one_signal_handler(SIGTERM, exit_handler, 1); set_one_signal_handler(SIGQUIT, exit_handler, 1); set_one_signal_handler(SIGPIPE, SIG_IGN, 1); + + if(g_fuse_instance.load(std::memory_order_acquire) != se) + fprintf(stderr,"mergerfs: fuse_remove_signal_handlers: unknown session\n"); + else + g_fuse_instance.store(nullptr,std::memory_order_release); } diff --git a/vendored/libfuse/lib/helper.cpp b/vendored/libfuse/lib/helper.cpp index 41cf1bdf..9209f78d 100644 --- a/vendored/libfuse/lib/helper.cpp +++ b/vendored/libfuse/lib/helper.cpp @@ -102,7 +102,7 @@ fuse_helper_opt_proc(void *data, default: return 1; - } + } } static int add_default_subtype(const char *progname, struct fuse_args *args) @@ -153,58 +153,66 @@ fuse_parse_cmdline(struct fuse_args *args_, err: free(hopts.mountpoint); + return -1; } -int fuse_daemonize(int foreground) +int +fuse_daemonize(int foreground) { - if (!foreground) { - int nullfd; - int waiter[2]; - char completed; + if(!foreground) + { + int nullfd; + int waiter[2]; + char completed; - if (pipe(waiter)) { - perror("fuse_daemonize: pipe"); - return -1; + if(pipe(waiter)) + { + perror("fuse_daemonize: pipe"); + return -1; + } + + /* + * demonize current process by forking it and killing the + * parent. This makes current process as a child of 'init'. + */ + switch(fork()) + { + case -1: + perror("fuse_daemonize: fork"); + return -1; + case 0: + break; + default: + read(waiter[0], &completed, sizeof(completed)); + _exit(0); + } + + if(setsid() == -1) + { + perror("fuse_daemonize: setsid"); + return -1; + } + + (void) chdir("/"); + + nullfd = open("/dev/null", O_RDWR, 0); + if(nullfd != -1) + { + (void) dup2(nullfd, 0); + (void) dup2(nullfd, 1); + (void) dup2(nullfd, 2); + if (nullfd > 2) + close(nullfd); + } + + /* Propagate completion of daemon initializatation */ + completed = 1; + write(waiter[1], &completed, sizeof(completed)); + close(waiter[0]); + close(waiter[1]); } - /* - * demonize current process by forking it and killing the - * parent. This makes current process as a child of 'init'. - */ - switch(fork()) { - case -1: - perror("fuse_daemonize: fork"); - return -1; - case 0: - break; - default: - read(waiter[0], &completed, sizeof(completed)); - _exit(0); - } - - if (setsid() == -1) { - perror("fuse_daemonize: setsid"); - return -1; - } - - (void) chdir("/"); - - nullfd = open("/dev/null", O_RDWR, 0); - if (nullfd != -1) { - (void) dup2(nullfd, 0); - (void) dup2(nullfd, 1); - (void) dup2(nullfd, 2); - if (nullfd > 2) - close(nullfd); - } - - /* Propagate completion of daemon initializatation */ - completed = 1; - write(waiter[1], &completed, sizeof(completed)); - close(waiter[0]); - close(waiter[1]); - } return 0; } diff --git a/vendored/libfuse/lib/maintenance_thread.cpp b/vendored/libfuse/lib/maintenance_thread.cpp index 0fca690d..a2be0f49 100644 --- a/vendored/libfuse/lib/maintenance_thread.cpp +++ b/vendored/libfuse/lib/maintenance_thread.cpp @@ -16,7 +16,7 @@ static void* _thread_loop(void *) { - int count; + u64 count; pthread_setname_np(pthread_self(),"fuse.maint"); diff --git a/vendored/libfuse/lib/xalloc.hpp b/vendored/libfuse/lib/xalloc.hpp new file mode 100644 index 00000000..7d962402 --- /dev/null +++ b/vendored/libfuse/lib/xalloc.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include +#include + +#define xstrdup(S) xstrdup_impl((S),__FILE__,__LINE__) +#define xmalloc(S) xmalloc_impl((S),__FILE__,__LINE__) + +static +inline +char* +xstrdup_impl(const char *s_, + const char *file_, + const unsigned line_) +{ + char *p; + + if(s_ == NULL) + { + fprintf(stderr, + "mergerfs: xstrdup called with NULL - file: %s; line: %u\n", + file_, + line_); + exit(EXIT_FAILURE); + } + + p = strdup(s_); + if(p == NULL) + { + fprintf(stderr, + "mergerfs: strdup failed - file: %s; line: %u\n", + file_, + line_); + exit(EXIT_FAILURE); + } + + return p; +} + +static +inline +void* +xmalloc_impl(const size_t size_, + const char *file_, + const unsigned line_) +{ + void *p; + + p = malloc(size_); + if(p == NULL) + { + fprintf(stderr, + "mergerfs: malloc failed - file: %s; line: %u\n", + file_, + line_); + exit(EXIT_FAILURE); + } + + return p; +} diff --git a/vendored/libfuse/util/fusermount.cpp b/vendored/libfuse/util/fusermount.cpp index 23b1be0b..7ef5d9d5 100644 --- a/vendored/libfuse/util/fusermount.cpp +++ b/vendored/libfuse/util/fusermount.cpp @@ -445,6 +445,7 @@ static int unmount_fuse_locked(const char *mnt, int quiet, int lazy) } out: + free(copy); if (res == -1) return -1; @@ -688,7 +689,7 @@ static int get_mnt_opts(int flags, char *opts, char **mnt_optsp) if (add_option(mnt_optsp, "user=", strlen(user)) == -1) return -1; - strcat(*mnt_optsp, user); + strncat(*mnt_optsp,user,strlen(user)); } return 0; } @@ -992,7 +993,7 @@ static int check_perm(const char **mntp, struct stat *stbuf, int *mountpoint_fd) return -1; } - sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd); + snprintf(procfile,sizeof(procfile),"/proc/self/fd/%i",*mountpoint_fd); *mntp = procfile; } else { fprintf(stderr,