stat-time.h 7.9 KB

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