+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
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:
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:
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
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:
above. */
#include "sys/stat.h"
+#include "stat-time.h"
+
#include <errno.h>
#include <unistd.h>
#ifdef WINDOWS_NATIVE
}
return _gl_fstat_by_handle (h, NULL, buf);
#else
- return orig_fstat (fd, buf);
+ return stat_time_normalize (orig_fstat (fd, buf), buf);
#endif
}
above. */
#include "sys/stat.h"
+#include "stat-time.h"
+
#include <errno.h>
#include <fcntl.h>
#include <string.h>
# 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.
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)
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] == '/')
above. */
# include "sys/stat.h"
+# include "stat-time.h"
+
# include <string.h>
# include <errno.h>
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 */
#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>
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
}
#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);
+ }
return result;
#endif
}
-# 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,
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
-# 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,
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
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
])
-# serial 29
+# serial 30
# Copyright (C) 1997-2001, 2003-2017 Free Software Foundation, Inc.
#
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
-# serial 12
+# serial 13
# Copyright (C) 2009-2017 Free Software Foundation, Inc.
#
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
])
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]
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
Depends-on:
time
+errno
extensions
extern-inline
+intprops
configure.ac:
gl_STAT_TIME