Mercurial > gnulib
changeset 39162:efff996688b8
stat: work around Solaris bug with tv_nsec < 0
* doc/posix-functions/fstat.texi (fstat):
* doc/posix-functions/fstatat.texi (fstatat):
* doc/posix-functions/lstat.texi (lstat):
* doc/posix-functions/stat.texi (stat):
Mention Solaris 11 bug.
* lib/fstat.c, lib/fstatat.c, lib/lstat.c: Include stat-time.h.
* lib/fstat.c (rpl_fstat) [!WINDOWS_NATIVE]:
* lib/lstat.c (rpl_lstat):
* lib/stat.c (rpl_stat):
Normalize resulting timestamps.
* lib/fstatat.c (normal_fstatat): New function.
(rpl_fstatat): Use it.
* lib/stat-time.h: Include intprops.h, errno.h, stddef.h.
(stat_time_normalize): New function.
* m4/fstat.m4 (gl_FUNC_FSTAT):
* m4/fstatat.m4 (gl_FUNC_FSTATAT):
* m4/lstat.m4 (gl_FUNC_LSTAT):
* m4/stat.m4 (gl_FUNC_STAT):
Replace on Solaris.
* modules/fstat (Depends-on):
* modules/fstatat (Depends-on):
Add stat-time.
* modules/stat-time (Depends-on): Add errno, intprops.
author | Paul Eggert <eggert@cs.ucla.edu> |
---|---|
date | Thu, 23 Nov 2017 00:05:57 -0800 |
parents | 73a94829c5ff |
children | b1b5c9418ec5 |
files | ChangeLog doc/posix-functions/fstat.texi doc/posix-functions/fstatat.texi doc/posix-functions/lstat.texi doc/posix-functions/stat.texi lib/fstat.c lib/fstatat.c lib/lstat.c lib/stat-time.h lib/stat.c m4/fstat.m4 m4/fstatat.m4 m4/lstat.m4 m4/stat.m4 modules/fstat modules/fstatat modules/stat-time |
diffstat | 17 files changed, 169 insertions(+), 44 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Wed Nov 22 11:23:01 2017 -0800 +++ b/ChangeLog Thu Nov 23 00:05:57 2017 -0800 @@ -1,3 +1,30 @@ +2017-11-23 Paul Eggert <eggert@cs.ucla.edu> + + stat: work around Solaris bug with tv_nsec < 0 + * doc/posix-functions/fstat.texi (fstat): + * doc/posix-functions/fstatat.texi (fstatat): + * doc/posix-functions/lstat.texi (lstat): + * doc/posix-functions/stat.texi (stat): + Mention Solaris 11 bug. + * lib/fstat.c, lib/fstatat.c, lib/lstat.c: Include stat-time.h. + * lib/fstat.c (rpl_fstat) [!WINDOWS_NATIVE]: + * lib/lstat.c (rpl_lstat): + * lib/stat.c (rpl_stat): + Normalize resulting timestamps. + * lib/fstatat.c (normal_fstatat): New function. + (rpl_fstatat): Use it. + * lib/stat-time.h: Include intprops.h, errno.h, stddef.h. + (stat_time_normalize): New function. + * m4/fstat.m4 (gl_FUNC_FSTAT): + * m4/fstatat.m4 (gl_FUNC_FSTATAT): + * m4/lstat.m4 (gl_FUNC_LSTAT): + * m4/stat.m4 (gl_FUNC_STAT): + Replace on Solaris. + * modules/fstat (Depends-on): + * modules/fstatat (Depends-on): + Add stat-time. + * modules/stat-time (Depends-on): Add errno, intprops. + 2017-11-22 Paul Eggert <eggert@cs.ucla.edu> regex: merge from glibc
--- a/doc/posix-functions/fstat.texi Wed Nov 22 11:23:01 2017 -0800 +++ b/doc/posix-functions/fstat.texi Thu Nov 23 00:05:57 2017 -0800 @@ -16,6 +16,11 @@ report the size of files or block devices larger than 2 GB. (Cf. @code{AC_SYS_LARGEFILE}.) @item +On Solaris 11.3, when this function yields a timestamp with a +nonpositive @code{tv_sec} value, @code{tv_nsec} might in the range +@minus{}1000000000..@minus{}1, representing a negative nanoseconds +offset from @code{tv_sec}. +@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 platforms:
--- a/doc/posix-functions/fstatat.texi Wed Nov 22 11:23:01 2017 -0800 +++ b/doc/posix-functions/fstatat.texi Thu Nov 23 00:05:57 2017 -0800 @@ -25,6 +25,11 @@ For symlinks, when the argument ends in a slash, some platforms don't dereference the argument: Solaris 9. +@item +On Solaris 11.3, when this function yields a timestamp with a +nonpositive @code{tv_sec} value, @code{tv_nsec} might in the range +@minus{}1000000000..@minus{}1, representing a negative nanoseconds +offset from @code{tv_sec}. @end itemize Portability problems not fixed by Gnulib:
--- a/doc/posix-functions/lstat.texi Wed Nov 22 11:23:01 2017 -0800 +++ b/doc/posix-functions/lstat.texi Thu Nov 23 00:05:57 2017 -0800 @@ -21,6 +21,11 @@ failing with @code{ENOTDIR}. Solaris 9. @item +On Solaris 11.3, when this function yields a timestamp with a +nonpositive @code{tv_sec} value, @code{tv_nsec} might in the range +@minus{}1000000000..@minus{}1, representing a negative nanoseconds +offset from @code{tv_sec}. +@item On Windows platforms (excluding Cygwin), symlinks are not supported, so @code{lstat} does not exist. @end itemize
--- a/doc/posix-functions/stat.texi Wed Nov 22 11:23:01 2017 -0800 +++ b/doc/posix-functions/stat.texi Thu Nov 23 00:05:57 2017 -0800 @@ -29,6 +29,11 @@ On some platforms, @code{stat(".",buf)} and @code{stat("./",buf)} give different results: mingw, MSVC 14. +@item +On Solaris 11.3, when this function yields a timestamp with a +nonpositive @code{tv_sec} value, @code{tv_nsec} might in the range +@minus{}1000000000..@minus{}1, representing a negative nanoseconds +offset from @code{tv_sec}. @end itemize Portability problems not fixed by Gnulib:
--- a/lib/fstat.c Wed Nov 22 11:23:01 2017 -0800 +++ b/lib/fstat.c Thu Nov 23 00:05:57 2017 -0800 @@ -45,6 +45,8 @@ above. */ #include "sys/stat.h" +#include "stat-time.h" + #include <errno.h> #include <unistd.h> #ifdef WINDOWS_NATIVE @@ -83,6 +85,6 @@ } return _gl_fstat_by_handle (h, NULL, buf); #else - return orig_fstat (fd, buf); + return stat_time_normalize (orig_fstat (fd, buf), buf); #endif }
--- a/lib/fstatat.c Wed Nov 22 11:23:01 2017 -0800 +++ b/lib/fstatat.c Thu Nov 23 00:05:57 2017 -0800 @@ -41,6 +41,8 @@ above. */ #include "sys/stat.h" +#include "stat-time.h" + #include <errno.h> #include <fcntl.h> #include <string.h> @@ -51,6 +53,12 @@ # define LSTAT_FOLLOWS_SLASHED_SYMLINK 0 # endif +static int +normal_fstatat (int fd, char const *file, struct stat *st, int flag) +{ + return stat_time_normalize (orig_fstatat (fd, file, st, flag), st); +} + /* fstatat should always follow symbolic links that end in /, but on Solaris 9 it doesn't if AT_SYMLINK_NOFOLLOW is specified. Likewise, trailing slash on a non-directory should be an error. @@ -63,7 +71,7 @@ int rpl_fstatat (int fd, char const *file, struct stat *st, int flag) { - int result = orig_fstatat (fd, file, st, flag); + int result = normal_fstatat (fd, file, st, flag); size_t len; if (LSTAT_FOLLOWS_SLASHED_SYMLINK || result != 0) @@ -79,7 +87,7 @@ errno = ENOTDIR; return -1; } - result = orig_fstatat (fd, file, st, flag & ~AT_SYMLINK_NOFOLLOW); + result = normal_fstatat (fd, file, st, flag & ~AT_SYMLINK_NOFOLLOW); } /* Fix stat behavior. */ if (result == 0 && !S_ISDIR (st->st_mode) && file[len - 1] == '/')
--- a/lib/lstat.c Wed Nov 22 11:23:01 2017 -0800 +++ b/lib/lstat.c Thu Nov 23 00:05:57 2017 -0800 @@ -47,6 +47,8 @@ above. */ # include "sys/stat.h" +# include "stat-time.h" + # include <string.h> # include <errno.h> @@ -66,32 +68,33 @@ int rpl_lstat (const char *file, struct stat *sbuf) { - size_t len; - int lstat_result = orig_lstat (file, sbuf); - - if (lstat_result != 0) - return lstat_result; + int result = orig_lstat (file, sbuf); /* This replacement file can blindly check against '/' rather than using the ISSLASH macro, because all platforms with '\\' either lack symlinks (mingw) or have working lstat (cygwin) and thus do not compile this file. 0 len should have already been filtered out above, with a failure return of ENOENT. */ - len = strlen (file); - if (file[len - 1] != '/' || S_ISDIR (sbuf->st_mode)) - return 0; - - /* At this point, a trailing slash is only permitted on - symlink-to-dir; but it should have found information on the - directory, not the symlink. Call stat() to get info about the - link's referent. Our replacement stat guarantees valid results, - even if the symlink is not pointing to a directory. */ - if (!S_ISLNK (sbuf->st_mode)) + if (result == 0) { - errno = ENOTDIR; - return -1; + if (S_ISDIR (sbuf->st_mode) || file[strlen (file) - 1] != '/') + result = stat_time_normalize (result, sbuf); + else + { + /* At this point, a trailing slash is permitted only on + symlink-to-dir; but it should have found information on the + directory, not the symlink. Call 'stat' to get info about the + link's referent. Our replacement stat guarantees valid results, + even if the symlink is not pointing to a directory. */ + if (!S_ISLNK (sbuf->st_mode)) + { + errno = ENOTDIR; + return -1; + } + result = stat (file, sbuf); + } } - return stat (file, sbuf); + return result; } #endif /* HAVE_LSTAT */
--- a/lib/stat-time.h Wed Nov 22 11:23:01 2017 -0800 +++ b/lib/stat-time.h Thu Nov 23 00:05:57 2017 -0800 @@ -20,6 +20,10 @@ #ifndef STAT_TIME_H #define STAT_TIME_H 1 +#include "intprops.h" + +#include <errno.h> +#include <stddef.h> #include <sys/stat.h> #include <time.h> @@ -202,6 +206,47 @@ return t; } +/* If a stat-like function returned RESULT, normalize the timestamps + in *ST, in case this platform suffers from the Solaris 11 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, struct stat *st) +{ +#if defined __sun && defined STAT_TIMESPEC + if (result == 0) + { + long int timespec_resolution = 1000000000; + short int const ts_off[] = { offsetof (struct stat, st_atim), + offsetof (struct stat, st_mtim), + offsetof (struct stat, st_ctim) }; + int i; + for (i = 0; i < sizeof ts_off / sizeof *ts_off; i++) + { + struct timespec *ts = (struct timespec *) ((char *) st + ts_off[i]); + long int q = ts->tv_nsec / timespec_resolution; + long int r = ts->tv_nsec % timespec_resolution; + if (r < 0) + { + r += timespec_resolution; + q--; + } + ts->tv_nsec = r; + /* Overflow is possible, as Solaris 11 stat can yield + tv_sec == TYPE_MINIMUM (time_t) && tv_nsec == -1000000000. + INT_ADD_WRAPV is OK, since time_t is signed on Solaris. */ + if (INT_ADD_WRAPV (q, ts->tv_sec, &ts->tv_sec)) + { + errno = EOVERFLOW; + return -1; + } + } + } +#endif + return result; +} + #ifdef __cplusplus } #endif
--- a/lib/stat.c Wed Nov 22 11:23:01 2017 -0800 +++ b/lib/stat.c Thu Nov 23 00:05:57 2017 -0800 @@ -405,19 +405,23 @@ } #else int result = orig_stat (name, buf); -# if REPLACE_FUNC_STAT_FILE - /* Solaris 9 mistakenly succeeds when given a non-directory with a - trailing slash. */ - if (result == 0 && !S_ISDIR (buf->st_mode)) + if (result == 0) { - size_t len = strlen (name); - if (ISSLASH (name[len - 1])) +# if REPLACE_FUNC_STAT_FILE + /* Solaris 9 mistakenly succeeds when given a non-directory with a + trailing slash. */ + if (!S_ISDIR (buf->st_mode)) { - errno = ENOTDIR; - return -1; + size_t len = strlen (name); + if (ISSLASH (name[len - 1])) + { + errno = ENOTDIR; + return -1; + } } +# endif /* REPLACE_FUNC_STAT_FILE */ + result = stat_time_normalize (result, buf); } -# endif /* REPLACE_FUNC_STAT_FILE */ return result; #endif }
--- a/m4/fstat.m4 Wed Nov 22 11:23:01 2017 -0800 +++ b/m4/fstat.m4 Thu Nov 23 00:05:57 2017 -0800 @@ -1,4 +1,4 @@ -# fstat.m4 serial 5 +# fstat.m4 serial 6 dnl Copyright (C) 2011-2017 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,9 +10,10 @@ AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS]) case "$host_os" in - mingw*) - dnl On this platform, the original stat() returns st_atime, st_mtime, + mingw* | solaris*) + 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
--- a/m4/fstatat.m4 Wed Nov 22 11:23:01 2017 -0800 +++ b/m4/fstatat.m4 Thu Nov 23 00:05:57 2017 -0800 @@ -1,4 +1,4 @@ -# fstatat.m4 serial 3 +# fstatat.m4 serial 4 dnl Copyright (C) 2004-2017 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -13,7 +13,7 @@ AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS]) AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) AC_REQUIRE([gl_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK]) - AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_REQUIRE([AC_CANONICAL_HOST]) AC_CHECK_FUNCS_ONCE([fstatat]) if test $ac_cv_func_fstatat = no; then @@ -46,15 +46,20 @@ case $gl_cv_func_fstatat_zero_flag+$gl_cv_func_lstat_dereferences_slashed_symlink in *yes+*yes) ;; - *) REPLACE_FSTATAT=1 - case $gl_cv_func_fstatat_zero_flag in - *yes) + *) REPLACE_FSTATAT=1 ;; + esac + + case $host_os in + solaris*) + REPLACE_FSTATAT=1 ;; + esac + + case $REPLACE_FSTATAT,$gl_cv_func_fstatat_zero_flag in + 1,*yes) AC_DEFINE([HAVE_WORKING_FSTATAT_ZERO_FLAG], [1], [Define to 1 if fstatat (..., 0) works. For example, it does not work in AIX 7.1.]) ;; - esac - ;; esac fi ])
--- a/m4/lstat.m4 Wed Nov 22 11:23:01 2017 -0800 +++ b/m4/lstat.m4 Thu Nov 23 00:05:57 2017 -0800 @@ -1,4 +1,4 @@ -# serial 29 +# serial 30 # Copyright (C) 1997-2001, 2003-2017 Free Software Foundation, Inc. # @@ -10,14 +10,15 @@ AC_DEFUN([gl_FUNC_LSTAT], [ + AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS]) dnl If lstat does not exist, the replacement <sys/stat.h> does dnl "#define lstat stat", and lstat.c is a no-op. AC_CHECK_FUNCS_ONCE([lstat]) if test $ac_cv_func_lstat = yes; then AC_REQUIRE([gl_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK]) - case "$gl_cv_func_lstat_dereferences_slashed_symlink" in - *no) + case $host_os,$gl_cv_func_lstat_dereferences_slashed_symlink in + solaris* | *no) REPLACE_LSTAT=1 ;; esac
--- a/m4/stat.m4 Wed Nov 22 11:23:01 2017 -0800 +++ b/m4/stat.m4 Thu Nov 23 00:05:57 2017 -0800 @@ -1,4 +1,4 @@ -# serial 12 +# serial 13 # Copyright (C) 2009-2017 Free Software Foundation, Inc. # @@ -56,6 +56,11 @@ AC_DEFINE([REPLACE_FUNC_STAT_FILE], [1], [Define to 1 if stat needs 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*) + REPLACE_FSTAT=1 ;; + esac ;; esac ])
--- a/modules/fstat Wed Nov 22 11:23:01 2017 -0800 +++ b/modules/fstat Thu Nov 23 00:05:57 2017 -0800 @@ -11,6 +11,7 @@ sys_stat largefile pathmax [test $REPLACE_FSTAT = 1] +stat-time [test $REPLACE_FSTAT = 1] unistd [test $REPLACE_FSTAT = 1] verify [test $REPLACE_FSTAT = 1] msvc-nothrow [test $REPLACE_FSTAT = 1]
--- a/modules/fstatat Wed Nov 22 11:23:01 2017 -0800 +++ b/modules/fstatat Thu Nov 23 00:05:57 2017 -0800 @@ -20,6 +20,7 @@ openat-die [test $HAVE_FSTATAT = 0 || test $REPLACE_FSTATAT = 1] openat-h [test $HAVE_FSTATAT = 0 || test $REPLACE_FSTATAT = 1] save-cwd [test $HAVE_FSTATAT = 0 || test $REPLACE_FSTATAT = 1] +stat-time [test $HAVE_FSTATAT = 0 || test $REPLACE_FSTATAT = 1] configure.ac: gl_FUNC_FSTATAT