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 (×pec[0])
+ && is_valid_timespec (×pec[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
{
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;
}
}
-#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;
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
/* 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
are no longer in common use. */
if (0 < result)
errno = ENOSYS;
-# endif
+# endif
if (result == 0 || errno != ENOSYS)
{
utimensat_works_really = 1;
}
}
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
/* 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;
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))
return fdutimens (-1, file, ts);
errno = ENOSYS;
return -1;
-}
#endif
+}