From 00c814dc58ef3c957abc105659099f24abf7b24f Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Sun, 23 Oct 2016 23:54:06 -0400 Subject: [PATCH] consolidate and simplify utime --- ...s_time_futimens.icpp => fs_base_utime.hpp} | 40 ++- src/fs_base_utime_generic.hpp | 298 ++++++++++++++++++ ...mensat.hpp => fs_base_utime_utimensat.hpp} | 19 +- src/fs_clonefile.cpp | 190 +++++------ src/fs_clonepath.cpp | 38 +-- src/fs_time.cpp | 21 -- src/fs_time.hpp | 22 -- src/fs_time_futimes.icpp | 33 -- src/utimens.cpp | 4 +- 9 files changed, 456 insertions(+), 209 deletions(-) rename src/{fs_time_futimens.icpp => fs_base_utime.hpp} (56%) create mode 100644 src/fs_base_utime_generic.hpp rename src/{fs_base_utimensat.hpp => fs_base_utime_utimensat.hpp} (72%) delete mode 100644 src/fs_time.cpp delete mode 100644 src/fs_time.hpp delete mode 100644 src/fs_time_futimes.icpp diff --git a/src/fs_time_futimens.icpp b/src/fs_base_utime.hpp similarity index 56% rename from src/fs_time_futimens.icpp rename to src/fs_base_utime.hpp index 529140a0..f2d5d5d3 100644 --- a/src/fs_time_futimens.icpp +++ b/src/fs_base_utime.hpp @@ -14,20 +14,50 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include +#ifdef __linux__ +# include "fs_base_utime_utimensat.hpp" +#elif __FreeBSD__ >= 11 +# include "fs_base_utime_utimensat.hpp" +#else +# include "fs_base_utime_generic.hpp" +#endif namespace fs { + static + inline int - utimes(const int fd, - const struct stat &st) + utime(const std::string &path, + const struct stat &st) { struct timespec times[2]; times[0] = st.st_atim; times[1] = st.st_mtim; - return ::futimens(fd,times); + return fs::utime(AT_FDCWD,path,times,0); + } + + static + inline + int + utime(const int fd, + const struct stat &st) + { + struct timespec times[2]; + + times[0] = st.st_atim; + times[1] = st.st_mtim; + + return fs::utime(fd,times); + } + + static + inline + int + lutime(const std::string &path, + const struct timespec times[2]) + { + return fs::utime(AT_FDCWD,path,times,AT_SYMLINK_NOFOLLOW); } } diff --git a/src/fs_base_utime_generic.hpp b/src/fs_base_utime_generic.hpp new file mode 100644 index 00000000..99647784 --- /dev/null +++ b/src/fs_base_utime_generic.hpp @@ -0,0 +1,298 @@ +/* + ISC License + + Copyright (c) 2016, 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. +*/ + +#include + +#include +#include +#include + +#ifndef UTIME_NOW +# define UTIME_NOW ((1l << 30) - 1l) +#endif + +#ifndef UTIME_OMIT +# define UTIME_OMIT ((1l << 30) - 2l) +#endif + +static +inline +bool +_can_call_lutimes(const int dirfd, + const std::string &path, + const int flags) +{ + return ((flags == AT_SYMLINK_NOFOLLOW) && + ((dirfd == AT_FDCWD) || + (path[0] == '/'))); +} + +static +inline +bool +_should_ignore(const struct timespec ts[2]) +{ + return ((ts != NULL) && + (ts[0].tv_nsec == UTIME_OMIT) && + (ts[1].tv_nsec == UTIME_OMIT)); +} + +static +inline +bool +_should_be_set_to_now(const struct timespec ts[2]) +{ + return ((ts == NULL) || + ((ts[0].tv_nsec == UTIME_NOW) && + (ts[1].tv_nsec == UTIME_NOW))); +} + +static +inline +bool +_timespec_invalid(const struct timespec &ts) +{ + return (((ts.tv_nsec < 0) || + (ts.tv_nsec > 999999999)) && + ((ts.tv_nsec != UTIME_NOW) && + (ts.tv_nsec != UTIME_OMIT))); +} + +static +inline +bool +_timespec_invalid(const struct timespec ts[2]) +{ + return ((ts != NULL) && + (_timespec_invalid(ts[0]) || + _timespec_invalid(ts[1]))); +} + +static +inline +bool +_flags_invalid(const int flags) +{ + return ((flags & ~AT_SYMLINK_NOFOLLOW) != 0); +} + +static +inline +bool +_any_timespec_is_utime_omit(const struct timespec ts[2]) +{ + return ((ts[0].tv_nsec == UTIME_OMIT) || + (ts[1].tv_nsec == UTIME_OMIT)); +} + +static +inline +bool +_any_timespec_is_utime_now(const struct timespec ts[2]) +{ + return ((ts[0].tv_nsec == UTIME_NOW) || + (ts[1].tv_nsec == UTIME_NOW)); +} + +static +inline +int +_set_utime_omit_to_current_value(const int dirfd, + const std::string &path, + const struct timespec ts[2], + struct timeval tv[2], + const int flags) +{ + int rv; + struct stat st; + + if(!_any_timespec_is_utime_omit(ts)) + return 0; + + rv = ::fstatat(dirfd,path.c_str(),&st,flags); + if(rv == -1) + return -1; + + if(ts[0].tv_nsec == UTIME_OMIT) + TIMESPEC_TO_TIMEVAL(&tv[0],&st.st_atim); + if(ts[1].tv_nsec == UTIME_OMIT) + TIMESPEC_TO_TIMEVAL(&tv[1],&st.st_mtim); + + return 0; +} + +static +inline +int +_set_utime_omit_to_current_value(const int fd, + const struct timespec ts[2], + struct timeval tv[2]) +{ + int rv; + struct stat st; + + if(!_any_timespec_is_utime_omit(ts)) + return 0; + + rv = ::fstat(fd,&st); + if(rv == -1) + return -1; + + if(ts[0].tv_nsec == UTIME_OMIT) + TIMESPEC_TO_TIMEVAL(&tv[0],&st.st_atim); + if(ts[1].tv_nsec == UTIME_OMIT) + TIMESPEC_TO_TIMEVAL(&tv[1],&st.st_mtim); + + return 0; +} + +static +inline +int +_set_utime_now_to_now(const struct timespec ts[2], + struct timeval tv[2]) +{ + int rv; + struct timeval now; + + if(_any_timespec_is_utime_now(ts)) + return 0; + + rv = ::gettimeofday(&now,NULL); + if(rv == -1) + return -1; + + if(ts[0].tv_nsec == UTIME_NOW) + tv[0] = now; + if(ts[1].tv_nsec == UTIME_NOW) + tv[1] = now; + + return 0; +} + +static +inline +int +_convert_timespec_to_timeval(const int dirfd, + const std::string &path, + const struct timespec ts[2], + struct timeval tv[2], + struct timeval *&tvp, + const int flags) +{ + int rv; + + if(_should_be_set_to_now(ts)) + return (tvp=NULL,0); + + TIMESPEC_TO_TIMEVAL(&tv[0],&ts[0]); + TIMESPEC_TO_TIMEVAL(&tv[1],&ts[1]); + + rv = _set_utime_omit_to_current_value(dirfd,path,ts,tv,flags); + if(rv == -1) + return -1; + + rv = _set_utime_now_to_now(ts,tv); + if(rv == -1) + return -1; + + return (tvp=tv,0); +} + +static +inline +int +_convert_timespec_to_timeval(const int fd, + const struct timespec ts[2], + struct timeval tv[2], + struct timeval *&tvp) +{ + int rv; + + if(_should_be_set_to_now(ts)) + return (tvp=NULL,0); + + TIMESPEC_TO_TIMEVAL(&tv[0],&ts[0]); + TIMESPEC_TO_TIMEVAL(&tv[1],&ts[1]); + + rv = _set_utime_omit_to_current_value(fd,ts,tv); + if(rv == -1) + return -1; + + rv = _set_utime_now_to_now(ts,tv); + if(rv == -1) + return -1; + + return (tvp=tv,0); +} + +namespace fs +{ + static + inline + int + utime(const int dirfd, + const std::string &path, + const struct timespec ts[2], + const int flags) + { + int rv; + struct timeval tv[2]; + struct timeval *tvp; + + if(_flags_invalid(flags)) + return (errno=EINVAL,-1); + if(_timespec_invalid(ts)) + return (errno=EINVAL,-1); + if(_should_ignore(ts)) + return 0; + + rv = _convert_timespec_to_timeval(dirfd,path,ts,tv,tvp,flags); + if(rv == -1) + return -1; + + if((flags & AT_SYMLINK_NOFOLLOW) == 0) + return ::futimesat(dirfd,path.c_str(),tvp); + if(_can_call_lutimes(dirfd,path,flags)) + return ::lutimes(path.c_str(),tvp); + + return (errno=ENOTSUP,-1); + } + + static + inline + int + utime(const int fd, + const struct timespec ts[2]) + { + int rv; + struct timeval tv[2]; + struct timeval *tvp; + + if(_timespec_invalid(ts)) + return (errno=EINVAL,-1); + if(_should_ignore(ts)) + return 0; + + rv = _convert_timespec_to_timeval(fd,ts,tv,tvp); + if(rv == -1) + return -1; + + return ::futimes(fd,tvp); + } +} diff --git a/src/fs_base_utimensat.hpp b/src/fs_base_utime_utimensat.hpp similarity index 72% rename from src/fs_base_utimensat.hpp rename to src/fs_base_utime_utimensat.hpp index fe49e3ee..f3ab6e1d 100644 --- a/src/fs_base_utimensat.hpp +++ b/src/fs_base_utime_utimensat.hpp @@ -26,10 +26,10 @@ namespace fs static inline int - utimensat(const int dirfd, - const std::string &path, - const struct timespec times[2], - const int flags) + utime(const int dirfd, + const std::string &path, + const struct timespec times[2], + const int flags) { return ::utimensat(dirfd,path.c_str(),times,flags); } @@ -37,14 +37,9 @@ namespace fs static inline int - utimensat(const std::string &path, - const struct stat &st) + utime(const int fd, + const struct timespec times[2]) { - struct timespec times[2]; - - times[0] = st.st_atim; - times[1] = st.st_mtim; - - return fs::utimensat(AT_FDCWD,path,times,0); + return ::futimens(fd,times); } } diff --git a/src/fs_clonefile.cpp b/src/fs_clonefile.cpp index b8bac932..c81efdb4 100644 --- a/src/fs_clonefile.cpp +++ b/src/fs_clonefile.cpp @@ -30,121 +30,121 @@ #include "fs_base_open.hpp" #include "fs_base_read.hpp" #include "fs_base_stat.hpp" +#include "fs_base_utime.hpp" #include "fs_base_write.hpp" #include "fs_fadvise.hpp" #include "fs_fallocate.hpp" #include "fs_sendfile.hpp" -#include "fs_time.hpp" #include "fs_xattr.hpp" using std::string; using std::vector; -namespace fs +int +writen(const int fd, + const char *buf, + const size_t count) { - int - writen(const int fd, - const char *buf, - const size_t count) - { - size_t nleft; - ssize_t nwritten; - - nleft = count; - while(nleft > 0) - { - nwritten = fs::write(fd,buf,nleft); - if(nwritten == -1) - { - if(errno == EINTR) - continue; - return -1; - } - - nleft -= nwritten; - buf += nwritten; - } - - return count; - } + size_t nleft; + ssize_t nwritten; + + nleft = count; + while(nleft > 0) + { + nwritten = fs::write(fd,buf,nleft); + if(nwritten == -1) + { + if(errno == EINTR) + continue; + return -1; + } - static - int - copyfile_rw(const int fdin, - const int fdout, - const size_t count, - const size_t blocksize) - { - ssize_t nr; - ssize_t nw; - ssize_t bufsize; - size_t totalwritten; - vector buf; - - bufsize = (blocksize * 16); - buf.resize(bufsize); - - fs::lseek(fdin,0,SEEK_SET); - - totalwritten = 0; - while(totalwritten < count) - { - nr = fs::read(fdin,&buf[0],bufsize); - if(nr == -1) - { - if(errno == EINTR) - continue; - return -1; - } - - nw = writen(fdout,&buf[0],nr); - if(nw == -1) + nleft -= nwritten; + buf += nwritten; + } + + return count; +} + +static +int +copyfile_rw(const int fdin, + const int fdout, + const size_t count, + const size_t blocksize) +{ + ssize_t nr; + ssize_t nw; + ssize_t bufsize; + size_t totalwritten; + vector buf; + + bufsize = (blocksize * 16); + buf.resize(bufsize); + + fs::lseek(fdin,0,SEEK_SET); + + totalwritten = 0; + while(totalwritten < count) + { + nr = fs::read(fdin,&buf[0],bufsize); + if(nr == -1) + { + if(errno == EINTR) + continue; return -1; + } - totalwritten += nw; - } + nw = writen(fdout,&buf[0],nr); + if(nw == -1) + return -1; - return count; - } + totalwritten += nw; + } - static - int - copydata(const int fdin, - const int fdout, - const size_t count, - const size_t blocksize) - { - int rv; + return count; +} - fs::fadvise(fdin,0,count,POSIX_FADV_WILLNEED); - fs::fadvise(fdin,0,count,POSIX_FADV_SEQUENTIAL); +static +int +copydata(const int fdin, + const int fdout, + const size_t count, + const size_t blocksize) +{ + int rv; - fs::fallocate(fdout,0,0,count); + fs::fadvise(fdin,0,count,POSIX_FADV_WILLNEED); + fs::fadvise(fdin,0,count,POSIX_FADV_SEQUENTIAL); - rv = fs::sendfile(fdin,fdout,count); - if((rv == -1) && ((errno == EINVAL) || (errno == ENOSYS))) - return fs::copyfile_rw(fdin,fdout,count,blocksize); + fs::fallocate(fdout,0,0,count); - return rv; - } + rv = fs::sendfile(fdin,fdout,count); + if((rv == -1) && ((errno == EINVAL) || (errno == ENOSYS))) + return ::copyfile_rw(fdin,fdout,count,blocksize); - static - bool - ignorable_error(const int err) - { - switch(err) - { - case ENOTTY: - case ENOTSUP: + return rv; +} + +static +bool +ignorable_error(const int err) +{ + switch(err) + { + case ENOTTY: + case ENOTSUP: #if ENOTSUP != EOPNOTSUPP - case EOPNOTSUPP: + case EOPNOTSUPP: #endif - return true; - } + return true; + } - return false; - } + return false; +} +namespace fs +{ int clonefile(const int fdin, const int fdout) @@ -156,16 +156,16 @@ namespace fs if(rv == -1) return -1; - rv = copydata(fdin,fdout,stin.st_size,stin.st_blksize); + rv = ::copydata(fdin,fdout,stin.st_size,stin.st_blksize); if(rv == -1) return -1; rv = fs::attr::copy(fdin,fdout); - if(rv == -1 && !ignorable_error(errno)) + if((rv == -1) && !ignorable_error(errno)) return -1; rv = fs::xattr::copy(fdin,fdout); - if(rv == -1 && !ignorable_error(errno)) + if((rv == -1) && !ignorable_error(errno)) return -1; rv = fs::fchown(fdout,stin); @@ -176,7 +176,7 @@ namespace fs if(rv == -1) return -1; - rv = fs::utimes(fdout,stin); + rv = fs::utime(fdout,stin); if(rv == -1) return -1; diff --git a/src/fs_clonepath.cpp b/src/fs_clonepath.cpp index b6efcf33..68e5396d 100644 --- a/src/fs_clonepath.cpp +++ b/src/fs_clonepath.cpp @@ -22,31 +22,31 @@ #include "fs_base_chown.hpp" #include "fs_base_mkdir.hpp" #include "fs_base_stat.hpp" -#include "fs_base_utimensat.hpp" +#include "fs_base_utime.hpp" #include "fs_path.hpp" #include "fs_xattr.hpp" using std::string; -namespace fs +static +bool +ignorable_error(const int err) { - static - bool - ignorable_error(const int err) - { - switch(err) - { - case ENOTTY: - case ENOTSUP: + switch(err) + { + case ENOTTY: + case ENOTSUP: #if ENOTSUP != EOPNOTSUPP - case EOPNOTSUPP: + case EOPNOTSUPP: #endif - return true; - } + return true; + } - return false; - } + return false; +} +namespace fs +{ int clonepath(const string &fromsrc, const string &tosrc, @@ -72,7 +72,7 @@ namespace fs if(rv == -1) return -1; else if(!S_ISDIR(st.st_mode)) - return (errno = ENOTDIR,-1); + return (errno=ENOTDIR,-1); fs::path::make(&tosrc,relative,topath); rv = fs::mkdir(topath,st.st_mode); @@ -88,18 +88,18 @@ namespace fs // It may not support it... it's fine... rv = fs::attr::copy(frompath,topath); - if(rv == -1 && !ignorable_error(errno)) + if((rv == -1) && !ignorable_error(errno)) return -1; rv = fs::xattr::copy(frompath,topath); - if(rv == -1 && !ignorable_error(errno)) + if((rv == -1) && !ignorable_error(errno)) return -1; rv = fs::chown(topath,st); if(rv == -1) return -1; - rv = fs::utimensat(topath,st); + rv = fs::utime(topath,st); if(rv == -1) return -1; diff --git a/src/fs_time.cpp b/src/fs_time.cpp deleted file mode 100644 index a8267d5f..00000000 --- a/src/fs_time.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - Copyright (c) 2016, 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. -*/ - -#ifdef __linux__ -# include "fs_time_futimens.icpp" -#else -# include "fs_time_futimes.icpp" -#endif diff --git a/src/fs_time.hpp b/src/fs_time.hpp deleted file mode 100644 index d79222d5..00000000 --- a/src/fs_time.hpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - Copyright (c) 2016, 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. -*/ - -namespace fs -{ - int - utimes(const int fd, - const struct stat &st); -} diff --git a/src/fs_time_futimes.icpp b/src/fs_time_futimes.icpp deleted file mode 100644 index b241956a..00000000 --- a/src/fs_time_futimes.icpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - Copyright (c) 2016, 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. -*/ - -#include -#include - -namespace fs -{ - int - utimes(const int fd, - const struct stat &st) - { - struct timeval times[2]; - - TIMESPEC_TO_TIMEVAL(×[0],&st.st_atim); - TIMESPEC_TO_TIMEVAL(×[1],&st.st_mtim); - - return ::futimes(fd,times); - } -} diff --git a/src/utimens.cpp b/src/utimens.cpp index 455b941c..ddf57b84 100644 --- a/src/utimens.cpp +++ b/src/utimens.cpp @@ -23,7 +23,7 @@ #include "config.hpp" #include "errno.hpp" -#include "fs_base_utimensat.hpp" +#include "fs_base_utime.hpp" #include "fs_path.hpp" #include "rv.hpp" #include "rwlock.hpp" @@ -45,7 +45,7 @@ _utimens_loop_core(const string *basepath, fs::path::make(basepath,fusepath,fullpath); - rv = fs::utimensat(AT_FDCWD,fullpath,ts,AT_SYMLINK_NOFOLLOW); + rv = fs::lutime(fullpath,ts); return calc_error(rv,error,errno); }