1*09d4459fSDaniel Fojt /* stat-related time functions.
2*09d4459fSDaniel Fojt
3*09d4459fSDaniel Fojt Copyright (C) 2005, 2007, 2009-2020 Free Software Foundation, Inc.
4*09d4459fSDaniel Fojt
5*09d4459fSDaniel Fojt This program is free software: you can redistribute it and/or modify
6*09d4459fSDaniel Fojt it under the terms of the GNU General Public License as published by
7*09d4459fSDaniel Fojt the Free Software Foundation; either version 3 of the License, or
8*09d4459fSDaniel Fojt (at your option) any later version.
9*09d4459fSDaniel Fojt
10*09d4459fSDaniel Fojt This program is distributed in the hope that it will be useful,
11*09d4459fSDaniel Fojt but WITHOUT ANY WARRANTY; without even the implied warranty of
12*09d4459fSDaniel Fojt MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*09d4459fSDaniel Fojt GNU General Public License for more details.
14*09d4459fSDaniel Fojt
15*09d4459fSDaniel Fojt You should have received a copy of the GNU General Public License
16*09d4459fSDaniel Fojt along with this program. If not, see <https://www.gnu.org/licenses/>. */
17*09d4459fSDaniel Fojt
18*09d4459fSDaniel Fojt /* Written by Paul Eggert. */
19*09d4459fSDaniel Fojt
20*09d4459fSDaniel Fojt #ifndef STAT_TIME_H
21*09d4459fSDaniel Fojt #define STAT_TIME_H 1
22*09d4459fSDaniel Fojt
23*09d4459fSDaniel Fojt #include "intprops.h"
24*09d4459fSDaniel Fojt
25*09d4459fSDaniel Fojt #include <errno.h>
26*09d4459fSDaniel Fojt #include <stddef.h>
27*09d4459fSDaniel Fojt #include <sys/stat.h>
28*09d4459fSDaniel Fojt #include <time.h>
29*09d4459fSDaniel Fojt
30*09d4459fSDaniel Fojt #ifndef _GL_INLINE_HEADER_BEGIN
31*09d4459fSDaniel Fojt #error "Please include config.h first."
32*09d4459fSDaniel Fojt #endif
33*09d4459fSDaniel Fojt _GL_INLINE_HEADER_BEGIN
34*09d4459fSDaniel Fojt #ifndef _GL_STAT_TIME_INLINE
35*09d4459fSDaniel Fojt # define _GL_STAT_TIME_INLINE _GL_INLINE
36*09d4459fSDaniel Fojt #endif
37*09d4459fSDaniel Fojt
38*09d4459fSDaniel Fojt #ifdef __cplusplus
39*09d4459fSDaniel Fojt extern "C" {
40*09d4459fSDaniel Fojt #endif
41*09d4459fSDaniel Fojt
42*09d4459fSDaniel Fojt /* STAT_TIMESPEC (ST, ST_XTIM) is the ST_XTIM member for *ST of type
43*09d4459fSDaniel Fojt struct timespec, if available. If not, then STAT_TIMESPEC_NS (ST,
44*09d4459fSDaniel Fojt ST_XTIM) is the nanosecond component of the ST_XTIM member for *ST,
45*09d4459fSDaniel Fojt if available. ST_XTIM can be st_atim, st_ctim, st_mtim, or st_birthtim
46*09d4459fSDaniel Fojt for access, status change, data modification, or birth (creation)
47*09d4459fSDaniel Fojt time respectively.
48*09d4459fSDaniel Fojt
49*09d4459fSDaniel Fojt These macros are private to stat-time.h. */
50*09d4459fSDaniel Fojt #if _GL_WINDOWS_STAT_TIMESPEC || defined HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
51*09d4459fSDaniel Fojt # if _GL_WINDOWS_STAT_TIMESPEC || defined TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC
52*09d4459fSDaniel Fojt # define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim)
53*09d4459fSDaniel Fojt # else
54*09d4459fSDaniel Fojt # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.tv_nsec)
55*09d4459fSDaniel Fojt # endif
56*09d4459fSDaniel Fojt #elif defined HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC
57*09d4459fSDaniel Fojt # define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim##espec)
58*09d4459fSDaniel Fojt #elif defined HAVE_STRUCT_STAT_ST_ATIMENSEC
59*09d4459fSDaniel Fojt # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim##ensec)
60*09d4459fSDaniel Fojt #elif defined HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC
61*09d4459fSDaniel Fojt # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.st__tim.tv_nsec)
62*09d4459fSDaniel Fojt #endif
63*09d4459fSDaniel Fojt
64*09d4459fSDaniel Fojt /* Return the nanosecond component of *ST's access time. */
65*09d4459fSDaniel Fojt _GL_STAT_TIME_INLINE long int _GL_ATTRIBUTE_PURE
get_stat_atime_ns(struct stat const * st)66*09d4459fSDaniel Fojt get_stat_atime_ns (struct stat const *st)
67*09d4459fSDaniel Fojt {
68*09d4459fSDaniel Fojt # if defined STAT_TIMESPEC
69*09d4459fSDaniel Fojt return STAT_TIMESPEC (st, st_atim).tv_nsec;
70*09d4459fSDaniel Fojt # elif defined STAT_TIMESPEC_NS
71*09d4459fSDaniel Fojt return STAT_TIMESPEC_NS (st, st_atim);
72*09d4459fSDaniel Fojt # else
73*09d4459fSDaniel Fojt return 0;
74*09d4459fSDaniel Fojt # endif
75*09d4459fSDaniel Fojt }
76*09d4459fSDaniel Fojt
77*09d4459fSDaniel Fojt /* Return the nanosecond component of *ST's status change time. */
78*09d4459fSDaniel Fojt _GL_STAT_TIME_INLINE long int _GL_ATTRIBUTE_PURE
get_stat_ctime_ns(struct stat const * st)79*09d4459fSDaniel Fojt get_stat_ctime_ns (struct stat const *st)
80*09d4459fSDaniel Fojt {
81*09d4459fSDaniel Fojt # if defined STAT_TIMESPEC
82*09d4459fSDaniel Fojt return STAT_TIMESPEC (st, st_ctim).tv_nsec;
83*09d4459fSDaniel Fojt # elif defined STAT_TIMESPEC_NS
84*09d4459fSDaniel Fojt return STAT_TIMESPEC_NS (st, st_ctim);
85*09d4459fSDaniel Fojt # else
86*09d4459fSDaniel Fojt return 0;
87*09d4459fSDaniel Fojt # endif
88*09d4459fSDaniel Fojt }
89*09d4459fSDaniel Fojt
90*09d4459fSDaniel Fojt /* Return the nanosecond component of *ST's data modification time. */
91*09d4459fSDaniel Fojt _GL_STAT_TIME_INLINE long int _GL_ATTRIBUTE_PURE
get_stat_mtime_ns(struct stat const * st)92*09d4459fSDaniel Fojt get_stat_mtime_ns (struct stat const *st)
93*09d4459fSDaniel Fojt {
94*09d4459fSDaniel Fojt # if defined STAT_TIMESPEC
95*09d4459fSDaniel Fojt return STAT_TIMESPEC (st, st_mtim).tv_nsec;
96*09d4459fSDaniel Fojt # elif defined STAT_TIMESPEC_NS
97*09d4459fSDaniel Fojt return STAT_TIMESPEC_NS (st, st_mtim);
98*09d4459fSDaniel Fojt # else
99*09d4459fSDaniel Fojt return 0;
100*09d4459fSDaniel Fojt # endif
101*09d4459fSDaniel Fojt }
102*09d4459fSDaniel Fojt
103*09d4459fSDaniel Fojt /* Return the nanosecond component of *ST's birth time. */
104*09d4459fSDaniel Fojt _GL_STAT_TIME_INLINE long int _GL_ATTRIBUTE_PURE
get_stat_birthtime_ns(struct stat const * st _GL_UNUSED)105*09d4459fSDaniel Fojt get_stat_birthtime_ns (struct stat const *st _GL_UNUSED)
106*09d4459fSDaniel Fojt {
107*09d4459fSDaniel Fojt # if defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC
108*09d4459fSDaniel Fojt return STAT_TIMESPEC (st, st_birthtim).tv_nsec;
109*09d4459fSDaniel Fojt # elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC
110*09d4459fSDaniel Fojt return STAT_TIMESPEC_NS (st, st_birthtim);
111*09d4459fSDaniel Fojt # else
112*09d4459fSDaniel Fojt return 0;
113*09d4459fSDaniel Fojt # endif
114*09d4459fSDaniel Fojt }
115*09d4459fSDaniel Fojt
116*09d4459fSDaniel Fojt /* Return *ST's access time. */
117*09d4459fSDaniel Fojt _GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE
get_stat_atime(struct stat const * st)118*09d4459fSDaniel Fojt get_stat_atime (struct stat const *st)
119*09d4459fSDaniel Fojt {
120*09d4459fSDaniel Fojt #ifdef STAT_TIMESPEC
121*09d4459fSDaniel Fojt return STAT_TIMESPEC (st, st_atim);
122*09d4459fSDaniel Fojt #else
123*09d4459fSDaniel Fojt struct timespec t;
124*09d4459fSDaniel Fojt t.tv_sec = st->st_atime;
125*09d4459fSDaniel Fojt t.tv_nsec = get_stat_atime_ns (st);
126*09d4459fSDaniel Fojt return t;
127*09d4459fSDaniel Fojt #endif
128*09d4459fSDaniel Fojt }
129*09d4459fSDaniel Fojt
130*09d4459fSDaniel Fojt /* Return *ST's status change time. */
131*09d4459fSDaniel Fojt _GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE
get_stat_ctime(struct stat const * st)132*09d4459fSDaniel Fojt get_stat_ctime (struct stat const *st)
133*09d4459fSDaniel Fojt {
134*09d4459fSDaniel Fojt #ifdef STAT_TIMESPEC
135*09d4459fSDaniel Fojt return STAT_TIMESPEC (st, st_ctim);
136*09d4459fSDaniel Fojt #else
137*09d4459fSDaniel Fojt struct timespec t;
138*09d4459fSDaniel Fojt t.tv_sec = st->st_ctime;
139*09d4459fSDaniel Fojt t.tv_nsec = get_stat_ctime_ns (st);
140*09d4459fSDaniel Fojt return t;
141*09d4459fSDaniel Fojt #endif
142*09d4459fSDaniel Fojt }
143*09d4459fSDaniel Fojt
144*09d4459fSDaniel Fojt /* Return *ST's data modification time. */
145*09d4459fSDaniel Fojt _GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE
get_stat_mtime(struct stat const * st)146*09d4459fSDaniel Fojt get_stat_mtime (struct stat const *st)
147*09d4459fSDaniel Fojt {
148*09d4459fSDaniel Fojt #ifdef STAT_TIMESPEC
149*09d4459fSDaniel Fojt return STAT_TIMESPEC (st, st_mtim);
150*09d4459fSDaniel Fojt #else
151*09d4459fSDaniel Fojt struct timespec t;
152*09d4459fSDaniel Fojt t.tv_sec = st->st_mtime;
153*09d4459fSDaniel Fojt t.tv_nsec = get_stat_mtime_ns (st);
154*09d4459fSDaniel Fojt return t;
155*09d4459fSDaniel Fojt #endif
156*09d4459fSDaniel Fojt }
157*09d4459fSDaniel Fojt
158*09d4459fSDaniel Fojt /* Return *ST's birth time, if available; otherwise return a value
159*09d4459fSDaniel Fojt with tv_sec and tv_nsec both equal to -1. */
160*09d4459fSDaniel Fojt _GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE
get_stat_birthtime(struct stat const * st _GL_UNUSED)161*09d4459fSDaniel Fojt get_stat_birthtime (struct stat const *st _GL_UNUSED)
162*09d4459fSDaniel Fojt {
163*09d4459fSDaniel Fojt struct timespec t;
164*09d4459fSDaniel Fojt
165*09d4459fSDaniel Fojt #if (defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC \
166*09d4459fSDaniel Fojt || defined HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC)
167*09d4459fSDaniel Fojt t = STAT_TIMESPEC (st, st_birthtim);
168*09d4459fSDaniel Fojt #elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC
169*09d4459fSDaniel Fojt t.tv_sec = st->st_birthtime;
170*09d4459fSDaniel Fojt t.tv_nsec = st->st_birthtimensec;
171*09d4459fSDaniel Fojt #elif defined _WIN32 && ! defined __CYGWIN__
172*09d4459fSDaniel Fojt /* Native Windows platforms (but not Cygwin) put the "file creation
173*09d4459fSDaniel Fojt time" in st_ctime (!). See
174*09d4459fSDaniel Fojt <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/stat-functions>. */
175*09d4459fSDaniel Fojt # if _GL_WINDOWS_STAT_TIMESPEC
176*09d4459fSDaniel Fojt t = st->st_ctim;
177*09d4459fSDaniel Fojt # else
178*09d4459fSDaniel Fojt t.tv_sec = st->st_ctime;
179*09d4459fSDaniel Fojt t.tv_nsec = 0;
180*09d4459fSDaniel Fojt # endif
181*09d4459fSDaniel Fojt #else
182*09d4459fSDaniel Fojt /* Birth time is not supported. */
183*09d4459fSDaniel Fojt t.tv_sec = -1;
184*09d4459fSDaniel Fojt t.tv_nsec = -1;
185*09d4459fSDaniel Fojt #endif
186*09d4459fSDaniel Fojt
187*09d4459fSDaniel Fojt #if (defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC \
188*09d4459fSDaniel Fojt || defined HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC \
189*09d4459fSDaniel Fojt || defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
190*09d4459fSDaniel Fojt /* FreeBSD and NetBSD sometimes signal the absence of knowledge by
191*09d4459fSDaniel Fojt using zero. Attempt to work around this problem. Alas, this can
192*09d4459fSDaniel Fojt report failure even for valid timestamps. Also, NetBSD
193*09d4459fSDaniel Fojt sometimes returns junk in the birth time fields; work around this
194*09d4459fSDaniel Fojt bug if it is detected. */
195*09d4459fSDaniel Fojt if (! (t.tv_sec && 0 <= t.tv_nsec && t.tv_nsec < 1000000000))
196*09d4459fSDaniel Fojt {
197*09d4459fSDaniel Fojt t.tv_sec = -1;
198*09d4459fSDaniel Fojt t.tv_nsec = -1;
199*09d4459fSDaniel Fojt }
200*09d4459fSDaniel Fojt #endif
201*09d4459fSDaniel Fojt
202*09d4459fSDaniel Fojt return t;
203*09d4459fSDaniel Fojt }
204*09d4459fSDaniel Fojt
205*09d4459fSDaniel Fojt /* If a stat-like function returned RESULT, normalize the timestamps
206*09d4459fSDaniel Fojt in *ST, in case this platform suffers from the Solaris 11 bug where
207*09d4459fSDaniel Fojt tv_nsec might be negative. Return the adjusted RESULT, setting
208*09d4459fSDaniel Fojt errno to EOVERFLOW if normalization overflowed. This function
209*09d4459fSDaniel Fojt is intended to be private to this .h file. */
210*09d4459fSDaniel Fojt _GL_STAT_TIME_INLINE int
stat_time_normalize(int result,struct stat * st _GL_UNUSED)211*09d4459fSDaniel Fojt stat_time_normalize (int result, struct stat *st _GL_UNUSED)
212*09d4459fSDaniel Fojt {
213*09d4459fSDaniel Fojt #if defined __sun && defined STAT_TIMESPEC
214*09d4459fSDaniel Fojt if (result == 0)
215*09d4459fSDaniel Fojt {
216*09d4459fSDaniel Fojt long int timespec_hz = 1000000000;
217*09d4459fSDaniel Fojt short int const ts_off[] = { offsetof (struct stat, st_atim),
218*09d4459fSDaniel Fojt offsetof (struct stat, st_mtim),
219*09d4459fSDaniel Fojt offsetof (struct stat, st_ctim) };
220*09d4459fSDaniel Fojt int i;
221*09d4459fSDaniel Fojt for (i = 0; i < sizeof ts_off / sizeof *ts_off; i++)
222*09d4459fSDaniel Fojt {
223*09d4459fSDaniel Fojt struct timespec *ts = (struct timespec *) ((char *) st + ts_off[i]);
224*09d4459fSDaniel Fojt long int q = ts->tv_nsec / timespec_hz;
225*09d4459fSDaniel Fojt long int r = ts->tv_nsec % timespec_hz;
226*09d4459fSDaniel Fojt if (r < 0)
227*09d4459fSDaniel Fojt {
228*09d4459fSDaniel Fojt r += timespec_hz;
229*09d4459fSDaniel Fojt q--;
230*09d4459fSDaniel Fojt }
231*09d4459fSDaniel Fojt ts->tv_nsec = r;
232*09d4459fSDaniel Fojt /* Overflow is possible, as Solaris 11 stat can yield
233*09d4459fSDaniel Fojt tv_sec == TYPE_MINIMUM (time_t) && tv_nsec == -1000000000.
234*09d4459fSDaniel Fojt INT_ADD_WRAPV is OK, since time_t is signed on Solaris. */
235*09d4459fSDaniel Fojt if (INT_ADD_WRAPV (q, ts->tv_sec, &ts->tv_sec))
236*09d4459fSDaniel Fojt {
237*09d4459fSDaniel Fojt errno = EOVERFLOW;
238*09d4459fSDaniel Fojt return -1;
239*09d4459fSDaniel Fojt }
240*09d4459fSDaniel Fojt }
241*09d4459fSDaniel Fojt }
242*09d4459fSDaniel Fojt #endif
243*09d4459fSDaniel Fojt return result;
244*09d4459fSDaniel Fojt }
245*09d4459fSDaniel Fojt
246*09d4459fSDaniel Fojt #ifdef __cplusplus
247*09d4459fSDaniel Fojt }
248*09d4459fSDaniel Fojt #endif
249*09d4459fSDaniel Fojt
250*09d4459fSDaniel Fojt _GL_INLINE_HEADER_END
251*09d4459fSDaniel Fojt
252*09d4459fSDaniel Fojt #endif
253