]> Savannah Git Hosting - gnulib.git/commitdiff
utimens: Fix test failure on NetBSD 10 (regression 2024-09-16).
authorBruno Haible <bruno@clisp.org>
Mon, 23 Sep 2024 14:03:07 +0000 (16:03 +0200)
committerBruno Haible <bruno@clisp.org>
Mon, 23 Sep 2024 14:03:07 +0000 (16:03 +0200)
* lib/utimens.h (utimens): Declare as an override if utimens exists in
libc.
(lutimens): Declare as an override if lutimens exists in libc.
* lib/utimens.c (is_valid_timespec, is_valid_timespecs): New functions,
extracted from validate_timespec.
(validate_timespec): Call is_valid_timespecs.
(utimens, lutimens): On NetBSD, validate the argument before calling
NetBSD's libc function.
* tests/test-utimens-common.h (check_ctime): Set to -1 on NetBSD.

ChangeLog
lib/utimens.c
lib/utimens.h
tests/test-utimens-common.h

index af260cc65a14cf62a18d66d660d7124cb3805407..d16a3f140e7ce54e6d85e3133fd1b20135d265fb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2024-09-23  Bruno Haible  <bruno@clisp.org>
+
+       utimens: Fix test failure on NetBSD 10 (regression 2024-09-16).
+       * lib/utimens.h (utimens): Declare as an override if utimens exists in
+       libc.
+       (lutimens): Declare as an override if lutimens exists in libc.
+       * lib/utimens.c (is_valid_timespec, is_valid_timespecs): New functions,
+       extracted from validate_timespec.
+       (validate_timespec): Call is_valid_timespecs.
+       (utimens, lutimens): On NetBSD, validate the argument before calling
+       NetBSD's libc function.
+       * tests/test-utimens-common.h (check_ctime): Set to -1 on NetBSD.
+
 2024-09-21  Bruno Haible  <bruno@clisp.org>
 
        getopt-posix, crypto/md5-buffer: Fix __GNUC_PREREQ re clang.
index cd86a44ea7653506777d71dc8e7e43bea9e0af9a..3c81b5c34926e6bc20f2c01dbec8987a360a6f7a 100644 (file)
@@ -78,6 +78,21 @@ static int utimensat_works_really;
 static int lutimensat_works_really;
 #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
 
+static bool
+is_valid_timespec (struct timespec const *timespec)
+{
+  return (timespec->tv_nsec == UTIME_NOW
+          || timespec->tv_nsec == UTIME_OMIT
+          || (0 <= timespec->tv_nsec && timespec->tv_nsec < TIMESPEC_HZ));
+}
+
+static bool
+is_valid_timespecs (struct timespec const timespec[2])
+{
+  return (is_valid_timespec (&timespec[0])
+          && is_valid_timespec (&timespec[1]));
+}
+
 /* Validate the requested timestamps.  Return 0 if the resulting
    timespec can be used for utimensat (after possibly modifying it to
    work around bugs in utimensat).  Return a positive value if the
@@ -90,14 +105,7 @@ validate_timespec (struct timespec timespec[2])
 {
   int result = 0;
   int utime_omit_count = 0;
-  if ((timespec[0].tv_nsec != UTIME_NOW
-       && timespec[0].tv_nsec != UTIME_OMIT
-       && ! (0 <= timespec[0].tv_nsec
-             && timespec[0].tv_nsec < TIMESPEC_HZ))
-      || (timespec[1].tv_nsec != UTIME_NOW
-          && timespec[1].tv_nsec != UTIME_OMIT
-          && ! (0 <= timespec[1].tv_nsec
-                && timespec[1].tv_nsec < TIMESPEC_HZ)))
+  if (!is_valid_timespecs (timespec))
     {
       errno = EINVAL;
       return -1;
@@ -516,24 +524,44 @@ fdutimens (int fd, char const *file, struct timespec const timespec[2])
   }
 }
 
-#if !HAVE_UTIMENS
 /* Set the access and modification timestamps of FILE to be
    TIMESPEC[0] and TIMESPEC[1], respectively.  */
 int
 utimens (char const *file, struct timespec const timespec[2])
+#undef utimens
 {
+#if HAVE_UTIMENS
+  /* NetBSD's native utimens() does not fulfil the Gnulib expectations:
+     At least in NetBSD 10.0, it does not validate the timespec argument.  */
+  if (timespec != NULL && !is_valid_timespecs (timespec))
+    {
+      errno = EINVAL;
+      return -1;
+    }
+  return utimens (file, timespec);
+#else
   return fdutimens (-1, file, timespec);
-}
 #endif
+}
 
-#if !HAVE_LUTIMENS
 /* Set the access and modification timestamps of FILE to be
    TIMESPEC[0] and TIMESPEC[1], respectively, without dereferencing
    symlinks.  Fail with ENOSYS if the platform does not support
    changing symlink timestamps, but FILE was a symlink.  */
 int
 lutimens (char const *file, struct timespec const timespec[2])
+#undef lutimens
 {
+#if HAVE_LUTIMENS
+  /* NetBSD's native lutimens() does not fulfil the Gnulib expectations:
+     At least in NetBSD 10.0, it does not validate the timespec argument.  */
+  if (timespec != NULL && !is_valid_timespecs (timespec))
+    {
+      errno = EINVAL;
+      return -1;
+    }
+  return lutimens (file, timespec);
+#else
   struct timespec adjusted_timespec[2];
   struct timespec *ts = timespec ? adjusted_timespec : NULL;
   int adjustment_needed = 0;
@@ -553,11 +581,11 @@ lutimens (char const *file, struct timespec const timespec[2])
      fdutimens' worry about buggy NFS clients.  But we do have to
      worry about bogus return values.  */
 
-#if HAVE_UTIMENSAT
+# if HAVE_UTIMENSAT
   if (0 <= lutimensat_works_really)
     {
       int result;
-# if defined __linux__ || defined __sun || defined __NetBSD__
+#  if defined __linux__ || defined __sun || defined __NetBSD__
       /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
          systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
          but work if both times are either explicitly specified or
@@ -582,9 +610,9 @@ lutimens (char const *file, struct timespec const timespec[2])
           /* Note that st is good, in case utimensat gives ENOSYS.  */
           adjustment_needed++;
         }
-# endif
+#  endif
       result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW);
-# ifdef __linux__
+#  ifdef __linux__
       /* Work around a kernel bug:
          https://bugzilla.redhat.com/show_bug.cgi?id=442352
          https://bugzilla.redhat.com/show_bug.cgi?id=449910
@@ -594,7 +622,7 @@ lutimens (char const *file, struct timespec const timespec[2])
          are no longer in common use.  */
       if (0 < result)
         errno = ENOSYS;
-# endif
+#  endif
       if (result == 0 || errno != ENOSYS)
         {
           utimensat_works_really = 1;
@@ -603,7 +631,7 @@ lutimens (char const *file, struct timespec const timespec[2])
         }
     }
   lutimensat_works_really = -1;
-#endif /* HAVE_UTIMENSAT */
+# endif /* HAVE_UTIMENSAT */
 
   /* The platform lacks an interface to set file timestamps with
      nanosecond resolution, so do the best we can, discarding any
@@ -619,7 +647,7 @@ lutimens (char const *file, struct timespec const timespec[2])
 
   /* On Linux, lutimes is a thin wrapper around utimensat, so there is
      no point trying lutimes if utimensat failed with ENOSYS.  */
-#if HAVE_LUTIMES && !HAVE_UTIMENSAT
+# if HAVE_LUTIMES && !HAVE_UTIMENSAT
   {
     struct timeval timeval[2];
     struct timeval *t;
@@ -639,7 +667,7 @@ lutimens (char const *file, struct timespec const timespec[2])
     if (result == 0 || errno != ENOSYS)
       return result;
   }
-#endif /* HAVE_LUTIMES && !HAVE_UTIMENSAT */
+# endif /* HAVE_LUTIMES && !HAVE_UTIMENSAT */
 
   /* Out of luck for symlinks, but we still handle regular files.  */
   if (!(adjustment_needed || REPLACE_FUNC_STAT_FILE) && lstat (file, &st))
@@ -648,5 +676,5 @@ lutimens (char const *file, struct timespec const timespec[2])
     return fdutimens (-1, file, ts);
   errno = ENOSYS;
   return -1;
-}
 #endif
+}
index e85477b84936844b25454b32efb9beb2f770a056..762c3f9a858b66cf0176f7e877aa4b53f77efc7b 100644 (file)
@@ -33,12 +33,16 @@ extern "C" {
 #endif
 
 int fdutimens (int, char const *, struct timespec const [2]);
-#if !HAVE_UTIMENS
+
+#if HAVE_UTIMENS
+# define utimens rpl_utimens
+#endif
 int utimens (char const *, struct timespec const [2]);
+
+#if HAVE_LUTIMENS
+# define lutimens rpl_lutimens
 #endif
-#if !HAVE_LUTIMENS
 int lutimens (char const *, struct timespec const [2]);
-#endif
 
 #ifdef __cplusplus
 }
index a59e65df8c10c169aba95a209f475654757d1fba..f564323630d933c1f26d6df136e200f9924fb56e 100644 (file)
@@ -55,7 +55,7 @@ enum {
    properly tracked change time.  See
    <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/stat-functions>.  */
 #  define check_ctime 0
-# elif defined __APPLE__ && defined __MACH__
+# elif (defined __APPLE__ && defined __MACH__) || defined __NetBSD__
 /* On macOS, the ctime is not updated when only the st_atime changes.  */
 #  define check_ctime -1
 # else