From c9a935835f7854083d715004b1ab8764da515856 Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Sat, 19 Mar 2022 15:15:34 -0400 Subject: [PATCH] Fix query of attr during symlink Using getattr when follow-symlink is enabled causes invalid type to the kernel if symlink pointed to non-symlink. --- src/fuse_link.cpp | 15 ++++++---- src/fuse_symlink.cpp | 66 +++++++++++++++++++++++++++++--------------- src/fuse_symlink.hpp | 8 ++---- 3 files changed, 54 insertions(+), 35 deletions(-) diff --git a/src/fuse_link.cpp b/src/fuse_link.cpp index 29966a36..7547b264 100644 --- a/src/fuse_link.cpp +++ b/src/fuse_link.cpp @@ -239,8 +239,9 @@ namespace l if(rv == 0) rv = FUSE::getattr(oldpath_,st_,timeouts_); - // Disable attr caching since we created a symlink but should be a regular. - timeouts_->attr = 0; + // Disable caching since we created a symlink but should be a regular. + timeouts_->attr = 0; + timeouts_->entry = 0; return rv; } @@ -268,8 +269,9 @@ namespace l if(rv == 0) rv = FUSE::getattr(oldpath_,st_,timeouts_); - // Disable attr caching since we created a symlink but should be a regular. - timeouts_->attr = 0; + // Disable caching since we created a symlink but should be a regular. + timeouts_->attr = 0; + timeouts_->entry = 0; return rv; } @@ -292,8 +294,9 @@ namespace l if(rv == 0) rv = FUSE::getattr(oldpath_,st_,timeouts_); - // Disable attr caching since we created a symlink but should be a regular. - timeouts_->attr = 0; + // Disable caching since we created a symlink but should be a regular. + timeouts_->attr = 0; + timeouts_->entry = 0; return rv; } diff --git a/src/fuse_symlink.cpp b/src/fuse_symlink.cpp index 30f53a86..e413f6b6 100644 --- a/src/fuse_symlink.cpp +++ b/src/fuse_symlink.cpp @@ -17,7 +17,9 @@ #include "config.hpp" #include "errno.hpp" #include "fs_clonepath.hpp" +#include "fs_lstat.hpp" #include "fs_path.hpp" +#include "fs_inode.hpp" #include "fs_symlink.hpp" #include "fuse_getattr.hpp" #include "ugid.hpp" @@ -59,6 +61,7 @@ namespace l symlink_loop_core(const string &newbasepath_, const char *target_, const char *linkpath_, + struct stat *st_, const int error_) { int rv; @@ -67,6 +70,12 @@ namespace l fullnewpath = fs::path::make(newbasepath_,linkpath_); rv = fs::symlink(target_,fullnewpath); + if((rv != -1) && (st_ != NULL) && (st_->st_ino == 0)) + { + fs::lstat(fullnewpath,st_); + if(st_->st_ino != 0) + fs::inode::calc(linkpath_,st_); + } return error::calc(rv,error_,errno); } @@ -77,7 +86,8 @@ namespace l const StrVec &newbasepaths_, const char *target_, const char *linkpath_, - const string &newdirpath_) + const string &newdirpath_, + struct stat *st_) { int rv; int error; @@ -92,6 +102,7 @@ namespace l error = l::symlink_loop_core(newbasepaths_[i], target_, linkpath_, + st_, error); } @@ -104,7 +115,8 @@ namespace l const Policy::Create &createFunc_, const Branches &branches_, const char *target_, - const char *linkpath_) + const char *linkpath_, + struct stat *st_) { int rv; string newdirpath; @@ -122,39 +134,47 @@ namespace l return -errno; return l::symlink_loop(existingpaths[0],newbasepaths, - target_,linkpath_,newdirpath); + target_,linkpath_,newdirpath,st_); } } namespace FUSE { - int - symlink(const char *target_, - const char *linkpath_) - { - Config::Read cfg; - const fuse_context *fc = fuse_get_context(); - const ugid::Set ugid(fc->uid,fc->gid); - - return l::symlink(cfg->func.getattr.policy, - cfg->func.symlink.policy, - cfg->branches, - target_, - linkpath_); - } - int symlink(const char *target_, const char *linkpath_, struct stat *st_, - fuse_timeouts_t *timeout_) + fuse_timeouts_t *timeouts_) { int rv; + Config::Read cfg; + const fuse_context *fc = fuse_get_context(); + const ugid::Set ugid(fc->uid,fc->gid); + + rv = l::symlink(cfg->func.getattr.policy, + cfg->func.symlink.policy, + cfg->branches, + target_, + linkpath_, + st_); - rv = FUSE::symlink(target_,linkpath_); - if(rv < 0) - return rv; + if(timeouts_ != NULL) + { + switch(cfg->follow_symlinks) + { + case FollowSymlinks::ENUM::NEVER: + timeouts_->entry = ((rv >= 0) ? + cfg->cache_entry : + cfg->cache_negative_entry); + timeouts_->attr = cfg->cache_attr; + break; + default: + timeouts_->entry = 0; + timeouts_->attr = 0; + break; + } + } - return FUSE::getattr(linkpath_,st_,timeout_); + return rv; } } diff --git a/src/fuse_symlink.hpp b/src/fuse_symlink.hpp index 68988a9d..ba568633 100644 --- a/src/fuse_symlink.hpp +++ b/src/fuse_symlink.hpp @@ -22,13 +22,9 @@ namespace FUSE { - int - symlink(const char *target, - const char *linkpath); - int symlink(const char *target, const char *linkpath, - struct stat *st, - fuse_timeouts_t *timeouts); + struct stat *st = NULL, + fuse_timeouts_t *timeouts = NULL); }