diff --git a/src/fs_base_chmod.hpp b/src/fs_base_chmod.hpp index 39692d2f..2334def1 100644 --- a/src/fs_base_chmod.hpp +++ b/src/fs_base_chmod.hpp @@ -21,6 +21,10 @@ #include +#include "fs_base_stat.hpp" + +#define MODE_BITS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) + namespace fs { static @@ -49,6 +53,58 @@ namespace fs { return ::fchmod(fd,st.st_mode); } + + static + inline + int + chmod_check_on_error(const std::string &path, + const mode_t mode) + { + int rv; + + rv = fs::chmod(path,mode); + if(rv == -1) + { + int error; + struct stat st; + + error = errno; + rv = fs::stat(path,st); + if(rv == -1) + return -1; + + if((st.st_mode & MODE_BITS) != (mode & MODE_BITS)) + return (errno=error,-1); + } + + return 0; + } + + static + inline + int + fchmod_check_on_error(const int fd, + const struct stat &st) + { + int rv; + + rv = fs::fchmod(fd,st); + if(rv == -1) + { + int error; + struct stat tmpst; + + error = errno; + rv = fs::fstat(fd,tmpst); + if(rv == -1) + return -1; + + if((st.st_mode & MODE_BITS) != (tmpst.st_mode & MODE_BITS)) + return (errno=error,-1); + } + + return 0; + } } #endif diff --git a/src/fs_base_chown.hpp b/src/fs_base_chown.hpp index 47b01741..a17fb60b 100644 --- a/src/fs_base_chown.hpp +++ b/src/fs_base_chown.hpp @@ -25,6 +25,8 @@ #include #include +#include "fs_base_stat.hpp" + namespace fs { static @@ -56,6 +58,15 @@ namespace fs return ::lchown(path.c_str(),uid,gid); } + static + inline + int + lchown(const std::string &path, + const struct stat &st) + { + return fs::lchown(path,st.st_uid,st.st_gid); + } + static inline int @@ -74,6 +85,60 @@ namespace fs { return fs::fchown(fd,st.st_uid,st.st_gid); } + + static + inline + int + lchown_check_on_error(const std::string &path, + const struct stat &st) + { + int rv; + + rv = fs::lchown(path,st); + if(rv == -1) + { + int error; + struct stat tmpst; + + error = errno; + rv = fs::lstat(path,tmpst); + if(rv == -1) + return -1; + + if((st.st_uid != tmpst.st_uid) || + (st.st_gid != tmpst.st_gid)) + return (errno=error,-1); + } + + return 0; + } + + static + inline + int + fchown_check_on_error(const int fd, + const struct stat &st) + { + int rv; + + rv = fs::fchown(fd,st); + if(rv == -1) + { + int error; + struct stat tmpst; + + error = errno; + rv = fs::fstat(fd,tmpst); + if(rv == -1) + return -1; + + if((st.st_uid != tmpst.st_uid) || + (st.st_gid != tmpst.st_gid)) + return (errno=error,-1); + } + + return 0; + } } #endif diff --git a/src/fs_clonefile.cpp b/src/fs_clonefile.cpp index a933536e..826790b9 100644 --- a/src/fs_clonefile.cpp +++ b/src/fs_clonefile.cpp @@ -176,11 +176,11 @@ namespace fs if((rv == -1) && !ignorable_error(errno)) return -1; - rv = fs::fchown(fdout,stin); + rv = fs::fchown_check_on_error(fdout,stin); if(rv == -1) return -1; - rv = fs::fchmod(fdout,stin); + rv = fs::fchmod_check_on_error(fdout,stin); if(rv == -1) return -1; diff --git a/src/fs_clonepath.cpp b/src/fs_clonepath.cpp index c81e6432..f4fb32ce 100644 --- a/src/fs_clonepath.cpp +++ b/src/fs_clonepath.cpp @@ -82,7 +82,7 @@ namespace fs if(errno != EEXIST) return -1; - rv = fs::chmod(topath,st.st_mode); + rv = fs::chmod_check_on_error(topath,st.st_mode); if(rv == -1) return -1; } @@ -96,7 +96,7 @@ namespace fs if((rv == -1) && !ignorable_error(errno)) return -1; - rv = fs::chown(topath,st); + rv = fs::lchown_check_on_error(topath,st); if(rv == -1) return -1;