diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2017-11-23 00:05:57 -0800 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2017-11-23 00:06:42 -0800 |
commit | 2c5d5587453d18cf83bdf67b4914db5e5db684b1 (patch) | |
tree | b2b1f2682c97bc7a9087651aee6f3a9db05fe9e9 /lib/stat-time.h | |
parent | 6245cd45374f0db1e832ed81b1b7c60ef8f5784f (diff) | |
download | gnulib-2c5d5587453d18cf83bdf67b4914db5e5db684b1.tar.gz |
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.
Diffstat (limited to 'lib/stat-time.h')
-rw-r--r-- | lib/stat-time.h | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/lib/stat-time.h b/lib/stat-time.h index 47a3bf8f21..1cf821992e 100644 --- a/lib/stat-time.h +++ b/lib/stat-time.h @@ -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 @@ get_stat_birthtime (struct stat const *st) 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 |