utimecmp: new function utimecmpat
authorPaul Eggert <eggert@cs.ucla.edu>
Tue, 20 Feb 2018 17:06:51 +0000 (09:06 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Tue, 20 Feb 2018 17:08:15 +0000 (09:08 -0800)
* 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
lib/utimecmp.c
lib/utimecmp.h
modules/utimecmp

index 3d9335f80d3a63a53c31172390f96977bb959535..15fad2bb5ee8119883496d0dd31edaccc7c784be 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2018-02-20  Paul Eggert  <eggert@cs.ucla.edu>
 
+       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.
index be9b32364c86033fd810af472ce0d0bdaf8b8187..b92797a6b6460ee4aaa71ae5f365c430095e971a 100644 (file)
 
 #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.
 
@@ -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)
index 65003ff0782cb5b075d3a85108698a89fd473314..ef05a57cba37beb4bdf4ab019d0daf45b5f68515 100644 (file)
@@ -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
index c7eee89ce053ebdf4b122a5ff5543fdbaa548a1c..8a3303cc06bf21ecead5e6ec3abb83e75e6b7093 100644 (file)
@@ -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