xref: /netbsd-src/external/gpl3/gdb/dist/gnulib/import/stat-time.h (revision 4b169a6ba595ae283ca507b26b15fdff40495b1c)
18dffb485Schristos /* stat-related time functions.
28dffb485Schristos 
3*4b169a6bSchristos    Copyright (C) 2005, 2007, 2009-2022 Free Software Foundation, Inc.
48dffb485Schristos 
5*4b169a6bSchristos    This file is free software: you can redistribute it and/or modify
6*4b169a6bSchristos    it under the terms of the GNU Lesser General Public License as
7*4b169a6bSchristos    published by the Free Software Foundation; either version 2.1 of the
8*4b169a6bSchristos    License, or (at your option) any later version.
98dffb485Schristos 
10*4b169a6bSchristos    This file is distributed in the hope that it will be useful,
118dffb485Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
128dffb485Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*4b169a6bSchristos    GNU Lesser General Public License for more details.
148dffb485Schristos 
15*4b169a6bSchristos    You should have received a copy of the GNU Lesser General Public License
168dffb485Schristos    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
178dffb485Schristos 
188dffb485Schristos /* Written by Paul Eggert.  */
198dffb485Schristos 
208dffb485Schristos #ifndef STAT_TIME_H
218dffb485Schristos #define STAT_TIME_H 1
228dffb485Schristos 
238dffb485Schristos #include "intprops.h"
248dffb485Schristos 
258dffb485Schristos #include <errno.h>
268dffb485Schristos #include <stddef.h>
278dffb485Schristos #include <sys/stat.h>
288dffb485Schristos #include <time.h>
298dffb485Schristos 
308dffb485Schristos #ifndef _GL_INLINE_HEADER_BEGIN
318dffb485Schristos  #error "Please include config.h first."
328dffb485Schristos #endif
338dffb485Schristos _GL_INLINE_HEADER_BEGIN
348dffb485Schristos #ifndef _GL_STAT_TIME_INLINE
358dffb485Schristos # define _GL_STAT_TIME_INLINE _GL_INLINE
368dffb485Schristos #endif
378dffb485Schristos 
388dffb485Schristos #ifdef __cplusplus
398dffb485Schristos extern "C" {
408dffb485Schristos #endif
418dffb485Schristos 
428dffb485Schristos /* STAT_TIMESPEC (ST, ST_XTIM) is the ST_XTIM member for *ST of type
438dffb485Schristos    struct timespec, if available.  If not, then STAT_TIMESPEC_NS (ST,
448dffb485Schristos    ST_XTIM) is the nanosecond component of the ST_XTIM member for *ST,
458dffb485Schristos    if available.  ST_XTIM can be st_atim, st_ctim, st_mtim, or st_birthtim
468dffb485Schristos    for access, status change, data modification, or birth (creation)
478dffb485Schristos    time respectively.
488dffb485Schristos 
498dffb485Schristos    These macros are private to stat-time.h.  */
508dffb485Schristos #if _GL_WINDOWS_STAT_TIMESPEC || defined HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
518dffb485Schristos # if _GL_WINDOWS_STAT_TIMESPEC || defined TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC
528dffb485Schristos #  define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim)
538dffb485Schristos # else
548dffb485Schristos #  define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.tv_nsec)
558dffb485Schristos # endif
568dffb485Schristos #elif defined HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC
578dffb485Schristos # define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim##espec)
588dffb485Schristos #elif defined HAVE_STRUCT_STAT_ST_ATIMENSEC
598dffb485Schristos # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim##ensec)
608dffb485Schristos #elif defined HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC
618dffb485Schristos # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.st__tim.tv_nsec)
628dffb485Schristos #endif
638dffb485Schristos 
648dffb485Schristos /* Return the nanosecond component of *ST's access time.  */
658dffb485Schristos _GL_STAT_TIME_INLINE long int _GL_ATTRIBUTE_PURE
get_stat_atime_ns(struct stat const * st)668dffb485Schristos get_stat_atime_ns (struct stat const *st)
678dffb485Schristos {
688dffb485Schristos # if defined STAT_TIMESPEC
698dffb485Schristos   return STAT_TIMESPEC (st, st_atim).tv_nsec;
708dffb485Schristos # elif defined STAT_TIMESPEC_NS
718dffb485Schristos   return STAT_TIMESPEC_NS (st, st_atim);
728dffb485Schristos # else
738dffb485Schristos   return 0;
748dffb485Schristos # endif
758dffb485Schristos }
768dffb485Schristos 
778dffb485Schristos /* Return the nanosecond component of *ST's status change time.  */
788dffb485Schristos _GL_STAT_TIME_INLINE long int _GL_ATTRIBUTE_PURE
get_stat_ctime_ns(struct stat const * st)798dffb485Schristos get_stat_ctime_ns (struct stat const *st)
808dffb485Schristos {
818dffb485Schristos # if defined STAT_TIMESPEC
828dffb485Schristos   return STAT_TIMESPEC (st, st_ctim).tv_nsec;
838dffb485Schristos # elif defined STAT_TIMESPEC_NS
848dffb485Schristos   return STAT_TIMESPEC_NS (st, st_ctim);
858dffb485Schristos # else
868dffb485Schristos   return 0;
878dffb485Schristos # endif
888dffb485Schristos }
898dffb485Schristos 
908dffb485Schristos /* Return the nanosecond component of *ST's data modification time.  */
918dffb485Schristos _GL_STAT_TIME_INLINE long int _GL_ATTRIBUTE_PURE
get_stat_mtime_ns(struct stat const * st)928dffb485Schristos get_stat_mtime_ns (struct stat const *st)
938dffb485Schristos {
948dffb485Schristos # if defined STAT_TIMESPEC
958dffb485Schristos   return STAT_TIMESPEC (st, st_mtim).tv_nsec;
968dffb485Schristos # elif defined STAT_TIMESPEC_NS
978dffb485Schristos   return STAT_TIMESPEC_NS (st, st_mtim);
988dffb485Schristos # else
998dffb485Schristos   return 0;
1008dffb485Schristos # endif
1018dffb485Schristos }
1028dffb485Schristos 
1038dffb485Schristos /* Return the nanosecond component of *ST's birth time.  */
1048dffb485Schristos _GL_STAT_TIME_INLINE long int _GL_ATTRIBUTE_PURE
get_stat_birthtime_ns(_GL_UNUSED struct stat const * st)105*4b169a6bSchristos get_stat_birthtime_ns (_GL_UNUSED struct stat const *st)
1068dffb485Schristos {
1078dffb485Schristos # if defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC
1088dffb485Schristos   return STAT_TIMESPEC (st, st_birthtim).tv_nsec;
1098dffb485Schristos # elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC
1108dffb485Schristos   return STAT_TIMESPEC_NS (st, st_birthtim);
1118dffb485Schristos # else
1128dffb485Schristos   return 0;
1138dffb485Schristos # endif
1148dffb485Schristos }
1158dffb485Schristos 
1168dffb485Schristos /* Return *ST's access time.  */
1178dffb485Schristos _GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE
get_stat_atime(struct stat const * st)1188dffb485Schristos get_stat_atime (struct stat const *st)
1198dffb485Schristos {
1208dffb485Schristos #ifdef STAT_TIMESPEC
1218dffb485Schristos   return STAT_TIMESPEC (st, st_atim);
1228dffb485Schristos #else
1238dffb485Schristos   struct timespec t;
1248dffb485Schristos   t.tv_sec = st->st_atime;
1258dffb485Schristos   t.tv_nsec = get_stat_atime_ns (st);
1268dffb485Schristos   return t;
1278dffb485Schristos #endif
1288dffb485Schristos }
1298dffb485Schristos 
1308dffb485Schristos /* Return *ST's status change time.  */
1318dffb485Schristos _GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE
get_stat_ctime(struct stat const * st)1328dffb485Schristos get_stat_ctime (struct stat const *st)
1338dffb485Schristos {
1348dffb485Schristos #ifdef STAT_TIMESPEC
1358dffb485Schristos   return STAT_TIMESPEC (st, st_ctim);
1368dffb485Schristos #else
1378dffb485Schristos   struct timespec t;
1388dffb485Schristos   t.tv_sec = st->st_ctime;
1398dffb485Schristos   t.tv_nsec = get_stat_ctime_ns (st);
1408dffb485Schristos   return t;
1418dffb485Schristos #endif
1428dffb485Schristos }
1438dffb485Schristos 
1448dffb485Schristos /* Return *ST's data modification time.  */
1458dffb485Schristos _GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE
get_stat_mtime(struct stat const * st)1468dffb485Schristos get_stat_mtime (struct stat const *st)
1478dffb485Schristos {
1488dffb485Schristos #ifdef STAT_TIMESPEC
1498dffb485Schristos   return STAT_TIMESPEC (st, st_mtim);
1508dffb485Schristos #else
1518dffb485Schristos   struct timespec t;
1528dffb485Schristos   t.tv_sec = st->st_mtime;
1538dffb485Schristos   t.tv_nsec = get_stat_mtime_ns (st);
1548dffb485Schristos   return t;
1558dffb485Schristos #endif
1568dffb485Schristos }
1578dffb485Schristos 
1588dffb485Schristos /* Return *ST's birth time, if available; otherwise return a value
1598dffb485Schristos    with tv_sec and tv_nsec both equal to -1.  */
1608dffb485Schristos _GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE
get_stat_birthtime(_GL_UNUSED struct stat const * st)161*4b169a6bSchristos get_stat_birthtime (_GL_UNUSED struct stat const *st)
1628dffb485Schristos {
1638dffb485Schristos   struct timespec t;
1648dffb485Schristos 
1658dffb485Schristos #if (defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC \
1668dffb485Schristos      || defined HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC)
1678dffb485Schristos   t = STAT_TIMESPEC (st, st_birthtim);
1688dffb485Schristos #elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC
1698dffb485Schristos   t.tv_sec = st->st_birthtime;
1708dffb485Schristos   t.tv_nsec = st->st_birthtimensec;
1718dffb485Schristos #elif defined _WIN32 && ! defined __CYGWIN__
1728dffb485Schristos   /* Native Windows platforms (but not Cygwin) put the "file creation
1738dffb485Schristos      time" in st_ctime (!).  See
1748dffb485Schristos      <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/stat-functions>.  */
1758dffb485Schristos # if _GL_WINDOWS_STAT_TIMESPEC
1768dffb485Schristos   t = st->st_ctim;
1778dffb485Schristos # else
1788dffb485Schristos   t.tv_sec = st->st_ctime;
1798dffb485Schristos   t.tv_nsec = 0;
1808dffb485Schristos # endif
1818dffb485Schristos #else
1828dffb485Schristos   /* Birth time is not supported.  */
1838dffb485Schristos   t.tv_sec = -1;
1848dffb485Schristos   t.tv_nsec = -1;
1858dffb485Schristos #endif
1868dffb485Schristos 
1878dffb485Schristos #if (defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC \
1888dffb485Schristos      || defined HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC \
1898dffb485Schristos      || defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
1908dffb485Schristos   /* FreeBSD and NetBSD sometimes signal the absence of knowledge by
1918dffb485Schristos      using zero.  Attempt to work around this problem.  Alas, this can
1928dffb485Schristos      report failure even for valid timestamps.  Also, NetBSD
1938dffb485Schristos      sometimes returns junk in the birth time fields; work around this
1948dffb485Schristos      bug if it is detected.  */
1958dffb485Schristos   if (! (t.tv_sec && 0 <= t.tv_nsec && t.tv_nsec < 1000000000))
1968dffb485Schristos     {
1978dffb485Schristos       t.tv_sec = -1;
1988dffb485Schristos       t.tv_nsec = -1;
1998dffb485Schristos     }
2008dffb485Schristos #endif
2018dffb485Schristos 
2028dffb485Schristos   return t;
2038dffb485Schristos }
2048dffb485Schristos 
2058dffb485Schristos /* If a stat-like function returned RESULT, normalize the timestamps
2068dffb485Schristos    in *ST, in case this platform suffers from the Solaris 11 bug where
2078dffb485Schristos    tv_nsec might be negative.  Return the adjusted RESULT, setting
2088dffb485Schristos    errno to EOVERFLOW if normalization overflowed.  This function
2098dffb485Schristos    is intended to be private to this .h file.  */
2108dffb485Schristos _GL_STAT_TIME_INLINE int
stat_time_normalize(int result,_GL_UNUSED struct stat * st)211*4b169a6bSchristos stat_time_normalize (int result, _GL_UNUSED struct stat *st)
2128dffb485Schristos {
2138dffb485Schristos #if defined __sun && defined STAT_TIMESPEC
2148dffb485Schristos   if (result == 0)
2158dffb485Schristos     {
2168dffb485Schristos       long int timespec_hz = 1000000000;
2178dffb485Schristos       short int const ts_off[] = { offsetof (struct stat, st_atim),
2188dffb485Schristos                                    offsetof (struct stat, st_mtim),
2198dffb485Schristos                                    offsetof (struct stat, st_ctim) };
2208dffb485Schristos       int i;
2218dffb485Schristos       for (i = 0; i < sizeof ts_off / sizeof *ts_off; i++)
2228dffb485Schristos         {
2238dffb485Schristos           struct timespec *ts = (struct timespec *) ((char *) st + ts_off[i]);
2248dffb485Schristos           long int q = ts->tv_nsec / timespec_hz;
2258dffb485Schristos           long int r = ts->tv_nsec % timespec_hz;
2268dffb485Schristos           if (r < 0)
2278dffb485Schristos             {
2288dffb485Schristos               r += timespec_hz;
2298dffb485Schristos               q--;
2308dffb485Schristos             }
2318dffb485Schristos           ts->tv_nsec = r;
2328dffb485Schristos           /* Overflow is possible, as Solaris 11 stat can yield
2338dffb485Schristos              tv_sec == TYPE_MINIMUM (time_t) && tv_nsec == -1000000000.
2348dffb485Schristos              INT_ADD_WRAPV is OK, since time_t is signed on Solaris.  */
2358dffb485Schristos           if (INT_ADD_WRAPV (q, ts->tv_sec, &ts->tv_sec))
2368dffb485Schristos             {
2378dffb485Schristos               errno = EOVERFLOW;
2388dffb485Schristos               return -1;
2398dffb485Schristos             }
2408dffb485Schristos         }
2418dffb485Schristos     }
2428dffb485Schristos #endif
2438dffb485Schristos   return result;
2448dffb485Schristos }
2458dffb485Schristos 
2468dffb485Schristos #ifdef __cplusplus
2478dffb485Schristos }
2488dffb485Schristos #endif
2498dffb485Schristos 
2508dffb485Schristos _GL_INLINE_HEADER_END
2518dffb485Schristos 
2528dffb485Schristos #endif
253