From 00cf42bb77bb69f680f38e278155a425875cf37b Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Dec 2023 11:15:56 -0800 Subject: [PATCH] stat-time: fix macOS bug with negative file times macOS has a bug similar (but not identical) to Solaris when file timestamps are negative: tv_nsec might go negative. Problem reported on Darwin 8.11.0 for GNU Tar by Gordon Steemson in: https://lists.gnu.org/r/bug-tar/2023-12/msg00001.html This was evidently Mac OS X 10.4.11; I reproduced it on Darwin 21.6.0 (macOS 12.5). * lib/stat-time.h (STAT_TIMESPEC_OFFSETOF): New macro. (stat_time_normalize): Also normalize timestamps on macOS. * m4/fstat.m4 (gl_FUNC_FSTAT): * m4/fstatat.m4 (gl_FUNC_FSTATAT): * m4/lstat.m4 (gl_FUNC_LSTAT): * m4/stat.m4 (gl_FUNC_STAT): Also replace on macOS. --- ChangeLog | 17 +++++++++++++++++ doc/posix-functions/fstat.texi | 7 ++++--- doc/posix-functions/fstatat.texi | 7 ++++--- doc/posix-functions/lstat.texi | 7 ++++--- doc/posix-functions/stat.texi | 7 ++++--- lib/stat-time.h | 13 ++++++++----- m4/fstat.m4 | 6 +++--- m4/fstatat.m4 | 4 ++-- m4/lstat.m4 | 4 ++-- m4/stat.m4 | 6 +++--- 10 files changed, 51 insertions(+), 27 deletions(-) diff --git a/ChangeLog b/ChangeLog index 46c2f77242..746a1ea70f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2023-12-28 Paul Eggert + + stat-time: fix macOS bug with negative file times + macOS has a bug similar (but not identical) to Solaris when + file timestamps are negative: tv_nsec might go negative. + Problem reported on Darwin 8.11.0 for GNU Tar by Gordon Steemson in: + https://lists.gnu.org/r/bug-tar/2023-12/msg00001.html + This was evidently Mac OS X 10.4.11; I reproduced it on + Darwin 21.6.0 (macOS 12.5). + * lib/stat-time.h (STAT_TIMESPEC_OFFSETOF): New macro. + (stat_time_normalize): Also normalize timestamps on macOS. + * m4/fstat.m4 (gl_FUNC_FSTAT): + * m4/fstatat.m4 (gl_FUNC_FSTATAT): + * m4/lstat.m4 (gl_FUNC_LSTAT): + * m4/stat.m4 (gl_FUNC_STAT): + Also replace on macOS. + 2023-12-19 Bruno Haible jit/cache: Fix compilation error on m68k, sparc, etc. diff --git a/doc/posix-functions/fstat.texi b/doc/posix-functions/fstat.texi index b4c2431ff4..e8ef324553 100644 --- a/doc/posix-functions/fstat.texi +++ b/doc/posix-functions/fstat.texi @@ -21,10 +21,11 @@ access files that happen to have a 64-bit inode number. This can occur with file systems such as XFS (typically on large disks) and NFS. @xref{Large File Support}. @item -On Solaris 11.4, when this function yields a timestamp with a +On macOS 12.6, when this function yields a timestamp with a nonpositive @code{tv_sec} value, @code{tv_nsec} might be in the range -@minus{}1000000000..@minus{}1, representing a negative nanoseconds -offset from @code{tv_sec}. +@minus{}999999999..@minus{}1, representing a negative nanoseconds +offset from @code{tv_sec}. Solaris 11.4 is similar, except that +@code{tv_sec} might also be @minus{}1000000000. @item The @code{st_atime}, @code{st_ctime}, @code{st_mtime} fields are affected by the current time zone and by the DST flag of the current time zone on some diff --git a/doc/posix-functions/fstatat.texi b/doc/posix-functions/fstatat.texi index 49d394addf..e959a5cc73 100644 --- a/doc/posix-functions/fstatat.texi +++ b/doc/posix-functions/fstatat.texi @@ -26,10 +26,11 @@ For symlinks, when the argument ends in a slash, some platforms don't dereference the argument: Solaris 9. @item -On Solaris 11.4, when this function yields a timestamp with a +On macOS 12.6, when this function yields a timestamp with a nonpositive @code{tv_sec} value, @code{tv_nsec} might be in the range -@minus{}1000000000..@minus{}1, representing a negative nanoseconds -offset from @code{tv_sec}. +@minus{}999999999..@minus{}1, representing a negative nanoseconds +offset from @code{tv_sec}. Solaris 11.4 is similar, except that +@code{tv_sec} might also be @minus{}1000000000. @end itemize Portability problems not fixed by Gnulib: diff --git a/doc/posix-functions/lstat.texi b/doc/posix-functions/lstat.texi index f0a6ffb572..95f740ce09 100644 --- a/doc/posix-functions/lstat.texi +++ b/doc/posix-functions/lstat.texi @@ -26,10 +26,11 @@ On some platforms, @code{lstat("file/",buf)} succeeds instead of failing with @code{ENOTDIR}. macOS 11.1, Solaris 9. @item -On Solaris 11.4, when this function yields a timestamp with a +On macOS 12.6, when this function yields a timestamp with a nonpositive @code{tv_sec} value, @code{tv_nsec} might be in the range -@minus{}1000000000..@minus{}1, representing a negative nanoseconds -offset from @code{tv_sec}. +@minus{}999999999..@minus{}1, representing a negative nanoseconds +offset from @code{tv_sec}. Solaris 11.4 is similar, except that +@code{tv_sec} might also be @minus{}1000000000. @item On Windows platforms (excluding Cygwin), symlinks are not supported, so @code{lstat} does not exist. diff --git a/doc/posix-functions/stat.texi b/doc/posix-functions/stat.texi index b64bdd3a01..f655451392 100644 --- a/doc/posix-functions/stat.texi +++ b/doc/posix-functions/stat.texi @@ -35,10 +35,11 @@ On some platforms, @code{stat(".",buf)} and @code{stat("./",buf)} give different results: mingw, MSVC 14. @item -On Solaris 11.4, when this function yields a timestamp with a +On macOS 12.6, when this function yields a timestamp with a nonpositive @code{tv_sec} value, @code{tv_nsec} might be in the range -@minus{}1000000000..@minus{}1, representing a negative nanoseconds -offset from @code{tv_sec}. +@minus{}999999999..@minus{}1, representing a negative nanoseconds +offset from @code{tv_sec}. Solaris 11.4 is similar, except that +@code{tv_sec} might also be @minus{}1000000000. @end itemize Portability problems not fixed by Gnulib: diff --git a/lib/stat-time.h b/lib/stat-time.h index 75eb27e549..1488182163 100644 --- a/lib/stat-time.h +++ b/lib/stat-time.h @@ -52,11 +52,13 @@ extern "C" { #if _GL_WINDOWS_STAT_TIMESPEC || defined HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC # if _GL_WINDOWS_STAT_TIMESPEC || defined TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC # define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim) +# define STAT_TIMESPEC_OFFSETOF(st_xtim) offsetof (struct stat, st_xtim) # else # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.tv_nsec) # endif #elif defined HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC # define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim##espec) +# define STAT_TIMESPEC_OFFSETOF(st_xtim) offsetof (struct stat, st_xtim##espec) #elif defined HAVE_STRUCT_STAT_ST_ATIMENSEC # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim##ensec) #elif defined HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC @@ -194,20 +196,21 @@ get_stat_birthtime (_GL_UNUSED struct stat const *st) } /* If a stat-like function returned RESULT, normalize the timestamps - in *ST, in case this platform suffers from the Solaris 11 bug where + in *ST, if this platform suffers from a macOS and Solaris bug where tv_nsec might be negative. Return the adjusted RESULT, setting errno to EOVERFLOW if normalization overflowed. This function is intended to be private to this .h file. */ _GL_STAT_TIME_INLINE int stat_time_normalize (int result, _GL_UNUSED struct stat *st) { -#if defined __sun && defined STAT_TIMESPEC +#if (((defined __APPLE__ && defined __MACH__) || defined __sun) \ + && defined STAT_TIMESPEC_OFFSETOF) if (result == 0) { long int timespec_hz = 1000000000; - short int const ts_off[] = { offsetof (struct stat, st_atim), - offsetof (struct stat, st_mtim), - offsetof (struct stat, st_ctim) }; + short int const ts_off[] = { STAT_TIMESPEC_OFFSETOF (st_atim), + STAT_TIMESPEC_OFFSETOF (st_mtim), + STAT_TIMESPEC_OFFSETOF (st_ctim) }; int i; for (i = 0; i < sizeof ts_off / sizeof *ts_off; i++) { diff --git a/m4/fstat.m4 b/m4/fstat.m4 index 382741f412..769e7d6e58 100644 --- a/m4/fstat.m4 +++ b/m4/fstat.m4 @@ -1,4 +1,4 @@ -# fstat.m4 serial 9 +# fstat.m4 serial 10 dnl Copyright (C) 2011-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -10,10 +10,10 @@ AC_DEFUN([gl_FUNC_FSTAT], AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS]) case "$host_os" in - mingw* | windows* | solaris*) + darwin* | mingw* | windows* | solaris*) + dnl macOS and Solaris stat can return a negative tv_nsec. dnl On MinGW, the original stat() returns st_atime, st_mtime, dnl st_ctime values that are affected by the time zone. - dnl Solaris stat can return a negative tv_nsec. REPLACE_FSTAT=1 ;; esac diff --git a/m4/fstatat.m4 b/m4/fstatat.m4 index 083076911f..84f82a2a69 100644 --- a/m4/fstatat.m4 +++ b/m4/fstatat.m4 @@ -1,4 +1,4 @@ -# fstatat.m4 serial 4 +# fstatat.m4 serial 5 dnl Copyright (C) 2004-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -50,7 +50,7 @@ AC_DEFUN([gl_FUNC_FSTATAT], esac case $host_os in - solaris*) + darwin* | solaris*) REPLACE_FSTATAT=1 ;; esac diff --git a/m4/lstat.m4 b/m4/lstat.m4 index 977386348a..76932d55a8 100644 --- a/m4/lstat.m4 +++ b/m4/lstat.m4 @@ -1,4 +1,4 @@ -# serial 35 +# serial 36 # Copyright (C) 1997-2001, 2003-2023 Free Software Foundation, Inc. # @@ -18,7 +18,7 @@ AC_DEFUN([gl_FUNC_LSTAT], if test $ac_cv_func_lstat = yes; then AC_REQUIRE([gl_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK]) case $host_os,$gl_cv_func_lstat_dereferences_slashed_symlink in - solaris* | *no) + darwin* | solaris* | *no) REPLACE_LSTAT=1 ;; esac diff --git a/m4/stat.m4 b/m4/stat.m4 index 81bd16a8f4..6e7be3d1c5 100644 --- a/m4/stat.m4 +++ b/m4/stat.m4 @@ -1,4 +1,4 @@ -# serial 20 +# serial 21 # Copyright (C) 2009-2023 Free Software Foundation, Inc. # @@ -61,8 +61,8 @@ AC_DEFUN([gl_FUNC_STAT], help when passed a file name with a trailing slash]);; esac case $host_os in - dnl Solaris stat can return a negative tv_nsec. - solaris*) + dnl macOS and Solaris stat can return a negative tv_nsec. + darwin* | solaris*) REPLACE_FSTAT=1 ;; esac ;; -- 2.40.1