stat-time.h 7.5 KB

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