xref: /dflybsd-src/contrib/grep/lib/stat-time.h (revision 91b9ed38d3db6a8a8ac5b66da1d43e6e331e259a)
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