diff options
Diffstat (limited to 'gl/stat-time.h')
| -rw-r--r-- | gl/stat-time.h | 81 |
1 files changed, 48 insertions, 33 deletions
diff --git a/gl/stat-time.h b/gl/stat-time.h index 92aa1e64..38315b9f 100644 --- a/gl/stat-time.h +++ b/gl/stat-time.h | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* stat-related time functions. | 1 | /* stat-related time functions. |
| 2 | 2 | ||
| 3 | Copyright (C) 2005, 2007, 2009-2023 Free Software Foundation, Inc. | 3 | Copyright (C) 2005, 2007, 2009-2025 Free Software Foundation, Inc. |
| 4 | 4 | ||
| 5 | This file is free software: you can redistribute it and/or modify | 5 | This file is free software: you can redistribute it and/or modify |
| 6 | it under the terms of the GNU Lesser General Public License as | 6 | it under the terms of the GNU Lesser General Public License as |
| @@ -20,15 +20,18 @@ | |||
| 20 | #ifndef STAT_TIME_H | 20 | #ifndef STAT_TIME_H |
| 21 | #define STAT_TIME_H 1 | 21 | #define STAT_TIME_H 1 |
| 22 | 22 | ||
| 23 | /* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE, _GL_UNUSED, | ||
| 24 | _GL_ATTRIBUTE_PURE, HAVE_STRUCT_STAT_*. */ | ||
| 25 | #if !_GL_CONFIG_H_INCLUDED | ||
| 26 | #error "Please include config.h first." | ||
| 27 | #endif | ||
| 28 | |||
| 23 | #include <errno.h> | 29 | #include <errno.h> |
| 24 | #include <stdckdint.h> | 30 | #include <stdckdint.h> |
| 25 | #include <stddef.h> | 31 | #include <stddef.h> |
| 26 | #include <sys/stat.h> | 32 | #include <sys/stat.h> |
| 27 | #include <time.h> | 33 | #include <time.h> |
| 28 | 34 | ||
| 29 | #ifndef _GL_INLINE_HEADER_BEGIN | ||
| 30 | #error "Please include config.h first." | ||
| 31 | #endif | ||
| 32 | _GL_INLINE_HEADER_BEGIN | 35 | _GL_INLINE_HEADER_BEGIN |
| 33 | #ifndef _GL_STAT_TIME_INLINE | 36 | #ifndef _GL_STAT_TIME_INLINE |
| 34 | # define _GL_STAT_TIME_INLINE _GL_INLINE | 37 | # define _GL_STAT_TIME_INLINE _GL_INLINE |
| @@ -49,11 +52,13 @@ extern "C" { | |||
| 49 | #if _GL_WINDOWS_STAT_TIMESPEC || defined HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC | 52 | #if _GL_WINDOWS_STAT_TIMESPEC || defined HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC |
| 50 | # if _GL_WINDOWS_STAT_TIMESPEC || defined TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC | 53 | # if _GL_WINDOWS_STAT_TIMESPEC || defined TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC |
| 51 | # define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim) | 54 | # define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim) |
| 55 | # define STAT_TIMESPEC_OFFSETOF(st_xtim) offsetof (struct stat, st_xtim) | ||
| 52 | # else | 56 | # else |
| 53 | # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.tv_nsec) | 57 | # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.tv_nsec) |
| 54 | # endif | 58 | # endif |
| 55 | #elif defined HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC | 59 | #elif defined HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC |
| 56 | # define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim##espec) | 60 | # define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim##espec) |
| 61 | # define STAT_TIMESPEC_OFFSETOF(st_xtim) offsetof (struct stat, st_xtim##espec) | ||
| 57 | #elif defined HAVE_STRUCT_STAT_ST_ATIMENSEC | 62 | #elif defined HAVE_STRUCT_STAT_ST_ATIMENSEC |
| 58 | # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim##ensec) | 63 | # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim##ensec) |
| 59 | #elif defined HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC | 64 | #elif defined HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC |
| @@ -112,6 +117,31 @@ get_stat_birthtime_ns (_GL_UNUSED struct stat const *st) | |||
| 112 | # endif | 117 | # endif |
| 113 | } | 118 | } |
| 114 | 119 | ||
| 120 | /* Constructs a 'struct timespec' with the given contents. | ||
| 121 | This macro / function is private to stat-time.h. */ | ||
| 122 | #if !defined __cplusplus | ||
| 123 | /* Use a C99 compound literal. | ||
| 124 | This is guaranteed to initialize also the padding bits, for example on | ||
| 125 | platforms where tv_sec is 64 bits and tv_nsec is 32 bits, thus avoiding | ||
| 126 | gcc -Wuse-of-uninitialized-value warnings. */ | ||
| 127 | # define _gl_make_timespec(sec,nsec) \ | ||
| 128 | (struct timespec) { .tv_sec = (sec), .tv_nsec = (nsec) } | ||
| 129 | #else | ||
| 130 | /* C++ does not have C99 compound literals. | ||
| 131 | A constructor invocation | ||
| 132 | timespec { (sec), (nsec) } | ||
| 133 | would make assumptions about the order of the fields of 'struct timespec', | ||
| 134 | which are not guaranteed by POSIX. So, use an inline function. */ | ||
| 135 | static inline struct timespec | ||
| 136 | _gl_make_timespec (time_t sec, long nsec) | ||
| 137 | { | ||
| 138 | struct timespec ts; | ||
| 139 | ts.tv_sec = sec; | ||
| 140 | ts.tv_nsec = nsec; | ||
| 141 | return ts; | ||
| 142 | } | ||
| 143 | #endif | ||
| 144 | |||
| 115 | /* Return *ST's access time. */ | 145 | /* Return *ST's access time. */ |
| 116 | _GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE | 146 | _GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE |
| 117 | get_stat_atime (struct stat const *st) | 147 | get_stat_atime (struct stat const *st) |
| @@ -119,10 +149,7 @@ get_stat_atime (struct stat const *st) | |||
| 119 | #ifdef STAT_TIMESPEC | 149 | #ifdef STAT_TIMESPEC |
| 120 | return STAT_TIMESPEC (st, st_atim); | 150 | return STAT_TIMESPEC (st, st_atim); |
| 121 | #else | 151 | #else |
| 122 | struct timespec t; | 152 | return _gl_make_timespec (st->st_atime, get_stat_atime_ns (st)); |
| 123 | t.tv_sec = st->st_atime; | ||
| 124 | t.tv_nsec = get_stat_atime_ns (st); | ||
| 125 | return t; | ||
| 126 | #endif | 153 | #endif |
| 127 | } | 154 | } |
| 128 | 155 | ||
| @@ -133,10 +160,7 @@ get_stat_ctime (struct stat const *st) | |||
| 133 | #ifdef STAT_TIMESPEC | 160 | #ifdef STAT_TIMESPEC |
| 134 | return STAT_TIMESPEC (st, st_ctim); | 161 | return STAT_TIMESPEC (st, st_ctim); |
| 135 | #else | 162 | #else |
| 136 | struct timespec t; | 163 | return _gl_make_timespec (st->st_ctime, get_stat_ctime_ns (st)); |
| 137 | t.tv_sec = st->st_ctime; | ||
| 138 | t.tv_nsec = get_stat_ctime_ns (st); | ||
| 139 | return t; | ||
| 140 | #endif | 164 | #endif |
| 141 | } | 165 | } |
| 142 | 166 | ||
| @@ -147,10 +171,7 @@ get_stat_mtime (struct stat const *st) | |||
| 147 | #ifdef STAT_TIMESPEC | 171 | #ifdef STAT_TIMESPEC |
| 148 | return STAT_TIMESPEC (st, st_mtim); | 172 | return STAT_TIMESPEC (st, st_mtim); |
| 149 | #else | 173 | #else |
| 150 | struct timespec t; | 174 | return _gl_make_timespec (st->st_mtime, get_stat_mtime_ns (st)); |
| 151 | t.tv_sec = st->st_mtime; | ||
| 152 | t.tv_nsec = get_stat_mtime_ns (st); | ||
| 153 | return t; | ||
| 154 | #endif | 175 | #endif |
| 155 | } | 176 | } |
| 156 | 177 | ||
| @@ -165,8 +186,7 @@ get_stat_birthtime (_GL_UNUSED struct stat const *st) | |||
| 165 | || defined HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC) | 186 | || defined HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC) |
| 166 | t = STAT_TIMESPEC (st, st_birthtim); | 187 | t = STAT_TIMESPEC (st, st_birthtim); |
| 167 | #elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC | 188 | #elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC |
| 168 | t.tv_sec = st->st_birthtime; | 189 | t = _gl_make_timespec (st->st_birthtime, st->st_birthtimensec); |
| 169 | t.tv_nsec = st->st_birthtimensec; | ||
| 170 | #elif defined _WIN32 && ! defined __CYGWIN__ | 190 | #elif defined _WIN32 && ! defined __CYGWIN__ |
| 171 | /* Native Windows platforms (but not Cygwin) put the "file creation | 191 | /* Native Windows platforms (but not Cygwin) put the "file creation |
| 172 | time" in st_ctime (!). See | 192 | time" in st_ctime (!). See |
| @@ -174,13 +194,11 @@ get_stat_birthtime (_GL_UNUSED struct stat const *st) | |||
| 174 | # if _GL_WINDOWS_STAT_TIMESPEC | 194 | # if _GL_WINDOWS_STAT_TIMESPEC |
| 175 | t = st->st_ctim; | 195 | t = st->st_ctim; |
| 176 | # else | 196 | # else |
| 177 | t.tv_sec = st->st_ctime; | 197 | t = _gl_make_timespec (st->st_ctime, 0); |
| 178 | t.tv_nsec = 0; | ||
| 179 | # endif | 198 | # endif |
| 180 | #else | 199 | #else |
| 181 | /* Birth time is not supported. */ | 200 | /* Birth time is not supported. */ |
| 182 | t.tv_sec = -1; | 201 | t = _gl_make_timespec (-1, -1); |
| 183 | t.tv_nsec = -1; | ||
| 184 | #endif | 202 | #endif |
| 185 | 203 | ||
| 186 | #if (defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC \ | 204 | #if (defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC \ |
| @@ -192,30 +210,28 @@ get_stat_birthtime (_GL_UNUSED struct stat const *st) | |||
| 192 | sometimes returns junk in the birth time fields; work around this | 210 | sometimes returns junk in the birth time fields; work around this |
| 193 | bug if it is detected. */ | 211 | bug if it is detected. */ |
| 194 | if (! (t.tv_sec && 0 <= t.tv_nsec && t.tv_nsec < 1000000000)) | 212 | if (! (t.tv_sec && 0 <= t.tv_nsec && t.tv_nsec < 1000000000)) |
| 195 | { | 213 | t = _gl_make_timespec (-1, -1); |
| 196 | t.tv_sec = -1; | ||
| 197 | t.tv_nsec = -1; | ||
| 198 | } | ||
| 199 | #endif | 214 | #endif |
| 200 | 215 | ||
| 201 | return t; | 216 | return t; |
| 202 | } | 217 | } |
| 203 | 218 | ||
| 204 | /* If a stat-like function returned RESULT, normalize the timestamps | 219 | /* If a stat-like function returned RESULT, normalize the timestamps |
| 205 | in *ST, in case this platform suffers from the Solaris 11 bug where | 220 | in *ST, if this platform suffers from a macOS and Solaris bug where |
| 206 | tv_nsec might be negative. Return the adjusted RESULT, setting | 221 | tv_nsec might be negative. Return the adjusted RESULT, setting |
| 207 | errno to EOVERFLOW if normalization overflowed. This function | 222 | errno to EOVERFLOW if normalization overflowed. This function |
| 208 | is intended to be private to this .h file. */ | 223 | is intended to be private to this .h file. */ |
| 209 | _GL_STAT_TIME_INLINE int | 224 | _GL_STAT_TIME_INLINE int |
| 210 | stat_time_normalize (int result, _GL_UNUSED struct stat *st) | 225 | stat_time_normalize (int result, _GL_UNUSED struct stat *st) |
| 211 | { | 226 | { |
| 212 | #if defined __sun && defined STAT_TIMESPEC | 227 | #if (((defined __APPLE__ && defined __MACH__) || defined __sun) \ |
| 228 | && defined STAT_TIMESPEC_OFFSETOF) | ||
| 213 | if (result == 0) | 229 | if (result == 0) |
| 214 | { | 230 | { |
| 215 | long int timespec_hz = 1000000000; | 231 | long int timespec_hz = 1000000000; |
| 216 | short int const ts_off[] = { offsetof (struct stat, st_atim), | 232 | short int const ts_off[] = { STAT_TIMESPEC_OFFSETOF (st_atim), |
| 217 | offsetof (struct stat, st_mtim), | 233 | STAT_TIMESPEC_OFFSETOF (st_mtim), |
| 218 | offsetof (struct stat, st_ctim) }; | 234 | STAT_TIMESPEC_OFFSETOF (st_ctim) }; |
| 219 | int i; | 235 | int i; |
| 220 | for (i = 0; i < sizeof ts_off / sizeof *ts_off; i++) | 236 | for (i = 0; i < sizeof ts_off / sizeof *ts_off; i++) |
| 221 | { | 237 | { |
| @@ -229,8 +245,7 @@ stat_time_normalize (int result, _GL_UNUSED struct stat *st) | |||
| 229 | } | 245 | } |
| 230 | ts->tv_nsec = r; | 246 | ts->tv_nsec = r; |
| 231 | /* Overflow is possible, as Solaris 11 stat can yield | 247 | /* Overflow is possible, as Solaris 11 stat can yield |
| 232 | tv_sec == TYPE_MINIMUM (time_t) && tv_nsec == -1000000000. | 248 | tv_sec == TYPE_MINIMUM (time_t) && tv_nsec == -1000000000. */ |
| 233 | INT_ADD_WRAPV is OK, since time_t is signed on Solaris. */ | ||
| 234 | if (ckd_add (&ts->tv_sec, q, ts->tv_sec)) | 249 | if (ckd_add (&ts->tv_sec, q, ts->tv_sec)) |
| 235 | { | 250 | { |
| 236 | errno = EOVERFLOW; | 251 | errno = EOVERFLOW; |
