summaryrefslogtreecommitdiffstats
path: root/gl/stat-time.h
diff options
context:
space:
mode:
Diffstat (limited to 'gl/stat-time.h')
-rw-r--r--gl/stat-time.h81
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. */
135static 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
117get_stat_atime (struct stat const *st) 147get_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
210stat_time_normalize (int result, _GL_UNUSED struct stat *st) 225stat_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;