From a4d64c0060225a40ce7ac12803edd27fdab1e8a8 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 20 Feb 2018 09:06:51 -0800 Subject: [PATCH] utimecmp: new function utimecmpat * lib/utimecmp.c: Include fcntl.h, sys/stat.h and dirname.h. Do not include utimens.h. (utimecmpat): New function, generalizing utimecmp. (utimecmp): Now a thin layer around utimecmpat. * modules/utimecmp (Depends-on): Depend on dirname-lgpl, fstatat, utimensat instead of on lstat and utimens. --- ChangeLog | 8 ++++++++ lib/utimecmp.c | 52 +++++++++++++++++++++++++++++++++--------------- lib/utimecmp.h | 2 ++ modules/utimecmp | 5 +++-- 4 files changed, 49 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3d9335f80d..15fad2bb5e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 2018-02-20 Paul Eggert + utimecmp: new function utimecmpat + * lib/utimecmp.c: Include fcntl.h, sys/stat.h and dirname.h. + Do not include utimens.h. + (utimecmpat): New function, generalizing utimecmp. + (utimecmp): Now a thin layer around utimecmpat. + * modules/utimecmp (Depends-on): Depend on dirname-lgpl, fstatat, + utimensat instead of on lstat and utimens. + same: new function same_nameat * lib/same.c: Include fcntl.h. * lib/same.c (same_nameat): New function, generalizing same_name. diff --git a/lib/utimecmp.c b/lib/utimecmp.c index be9b32364c..b92797a6b6 100644 --- a/lib/utimecmp.c +++ b/lib/utimecmp.c @@ -21,17 +21,19 @@ #include "utimecmp.h" +#include #include #include #include #include +#include #include #include +#include "dirname.h" #include "hash.h" #include "intprops.h" #include "stat-time.h" -#include "utimens.h" #include "verify.h" #ifndef MAX @@ -103,7 +105,8 @@ dev_info_compare (void const *x, void const *y) return a->dev == b->dev; } -/* Return -1, 0, 1 based on whether the destination file (with name +/* Return -1, 0, 1 based on whether the destination file (relative + to openat-like directory file descriptor DFD with name DST_NAME and status DST_STAT) is older than SRC_STAT, the same age as SRC_STAT, or newer than SRC_STAT, respectively. @@ -121,6 +124,15 @@ utimecmp (char const *dst_name, struct stat const *dst_stat, struct stat const *src_stat, int options) +{ + return utimecmpat (AT_FDCWD, dst_name, dst_stat, src_stat, options); +} + +int +utimecmpat (int dfd, char const *dst_name, + struct stat const *dst_stat, + struct stat const *src_stat, + int options) { /* Things to watch out for: @@ -216,7 +228,24 @@ utimecmp (char const *dst_name, /* If the system will tell us the resolution, we're set! */ if (! dst_res->exact) { - res = pathconf (dst_name, _PC_TIMESTAMP_RESOLUTION); + res = -1; + if (dfd == AT_FDCWD) + res = pathconf (dst_name, _PC_TIMESTAMP_RESOLUTION); + else + { + char *dstdir = mdir_name (dst_name); + if (dstdir) + { + int destdirfd = openat (dfd, dstdir, + O_SEARCH | O_CLOEXEC | O_DIRECTORY); + if (0 <= destdirfd) + { + res = fpathconf (destdirfd, _PC_TIMESTAMP_RESOLUTION); + close (destdirfd); + } + free (dstdir); + } + } if (0 < res) { dst_res->resolution = res; @@ -311,19 +340,13 @@ utimecmp (char const *dst_name, timespec[1].tv_sec = dst_m_s | (res == 2 * BILLION); timespec[1].tv_nsec = dst_m_ns + res / 9; - /* Set the modification time. But don't try to set the - modification time of symbolic links; on many hosts this sets - the time of the pointed-to file. */ - if ((S_ISLNK (dst_stat->st_mode) - ? lutimens (dst_name, timespec) - : utimens (dst_name, timespec)) != 0) + if (utimensat (dfd, dst_name, timespec, AT_SYMLINK_NOFOLLOW)) return -2; /* Read the modification time that was set. */ { - int stat_result = (S_ISLNK (dst_stat->st_mode) - ? lstat (dst_name, &dst_status) - : stat (dst_name, &dst_status)); + int stat_result + = fstatat (dfd, dst_name, &dst_status, AT_SYMLINK_NOFOLLOW); if (stat_result | (dst_status.st_mtime ^ dst_m_s) @@ -333,10 +356,7 @@ utimecmp (char const *dst_name, it changed. Change it back as best we can. */ timespec[1].tv_sec = dst_m_s; timespec[1].tv_nsec = dst_m_ns; - if (S_ISLNK (dst_stat->st_mode)) - lutimens (dst_name, timespec); - else - utimens (dst_name, timespec); + utimensat (dfd, dst_name, timespec, AT_SYMLINK_NOFOLLOW); } if (stat_result != 0) diff --git a/lib/utimecmp.h b/lib/utimecmp.h index 65003ff078..ef05a57cba 100644 --- a/lib/utimecmp.h +++ b/lib/utimecmp.h @@ -33,5 +33,7 @@ enum }; int utimecmp (char const *, struct stat const *, struct stat const *, int); +int utimecmpat (int, char const *, struct stat const *, struct stat const *, + int); #endif diff --git a/modules/utimecmp b/modules/utimecmp index c7eee89ce0..8a3303cc06 100644 --- a/modules/utimecmp +++ b/modules/utimecmp @@ -7,12 +7,13 @@ lib/utimecmp.c m4/utimecmp.m4 Depends-on: +dirname-lgpl +fstatat hash stat-time time -utimens +utimensat intprops -lstat stdbool stdint verify -- 2.39.5