From 97f636ccd01ea7f89e93ca52a8ab582cb3789f95 Mon Sep 17 00:00:00 2001 From: Paul Eggert <eggert@cs.ucla.edu> 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 4516b008b5..a58ad00ce1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2023-12-28 Paul Eggert <eggert@cs.ucla.edu> + + 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-10 Pádraig Brady <P@draigBrady.com> bootstrap: fix option propagation with --bootstrap-sync 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 7cb2edb001..eb55bcd2a8 100644 --- a/m4/fstat.m4 +++ b/m4/fstat.m4 @@ -1,4 +1,4 @@ -# fstat.m4 serial 8 +# fstat.m4 serial 8.1 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* | solaris*) + darwin* | mingw* | 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 2bc4669793..8184901926 100644 --- a/m4/lstat.m4 +++ b/m4/lstat.m4 @@ -1,4 +1,4 @@ -# serial 34 +# serial 34.1 # 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 6d1628c217..99f3a395f9 100644 --- a/m4/stat.m4 +++ b/m4/stat.m4 @@ -1,4 +1,4 @@ -# serial 19 +# serial 19.1 # 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.39.5