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