summaryrefslogtreecommitdiff
path: root/lib/utimecmp.c
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2018-02-20 09:06:51 -0800
committerPaul Eggert <eggert@cs.ucla.edu>2018-02-20 09:08:15 -0800
commita4d64c0060225a40ce7ac12803edd27fdab1e8a8 (patch)
tree6e7b381b83cf32beaa9be90f08789e99f2129614 /lib/utimecmp.c
parentd50980ddfe6d3b25287725048abba2c65f753686 (diff)
downloadgnulib-a4d64c0060225a40ce7ac12803edd27fdab1e8a8.tar.gz
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.
Diffstat (limited to 'lib/utimecmp.c')
-rw-r--r--lib/utimecmp.c52
1 files changed, 36 insertions, 16 deletions
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 <fcntl.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
+#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
+#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.
@@ -122,6 +125,15 @@ utimecmp (char const *dst_name,
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:
The code uses a static hash table internally and is not safe in the
@@ -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)