From: Bruno Haible Date: Mon, 23 Sep 2024 14:03:07 +0000 (+0200) Subject: utimens: Fix test failure on NetBSD 10 (regression 2024-09-16). X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=2db45a0f135326fb93d2fd4e0fbf54a362a8ab4e;p=gnulib.git 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. --- diff --git a/ChangeLog b/ChangeLog index af260cc65a..d16a3f140e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2024-09-23 Bruno Haible + + 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 getopt-posix, crypto/md5-buffer: Fix __GNUC_PREREQ re clang. diff --git a/lib/utimens.c b/lib/utimens.c index cd86a44ea7..3c81b5c349 100644 --- a/lib/utimens.c +++ b/lib/utimens.c @@ -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 (×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 @@ -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 +} diff --git a/lib/utimens.h b/lib/utimens.h index e85477b849..762c3f9a85 100644 --- a/lib/utimens.h +++ b/lib/utimens.h @@ -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 } diff --git a/tests/test-utimens-common.h b/tests/test-utimens-common.h index a59e65df8c..f564323630 100644 --- a/tests/test-utimens-common.h +++ b/tests/test-utimens-common.h @@ -55,7 +55,7 @@ enum { properly tracked change time. See . */ # 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