Blame src/gl/stat-time.h

Packit aea12f
/* stat-related time functions.
Packit aea12f
Packit Service 991b93
   Copyright (C) 2005, 2007, 2009-2020 Free Software Foundation, Inc.
Packit aea12f
Packit aea12f
   This program is free software: you can redistribute it and/or modify
Packit aea12f
   it under the terms of the GNU General Public License as published by
Packit aea12f
   the Free Software Foundation; either version 3 of the License, or
Packit aea12f
   (at your option) any later version.
Packit aea12f
Packit aea12f
   This program is distributed in the hope that it will be useful,
Packit aea12f
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit aea12f
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit aea12f
   GNU General Public License for more details.
Packit aea12f
Packit aea12f
   You should have received a copy of the GNU General Public License
Packit aea12f
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit aea12f
Packit aea12f
/* Written by Paul Eggert.  */
Packit aea12f
Packit aea12f
#ifndef STAT_TIME_H
Packit aea12f
#define STAT_TIME_H 1
Packit aea12f
Packit aea12f
#include "intprops.h"
Packit aea12f
Packit aea12f
#include <errno.h>
Packit aea12f
#include <stddef.h>
Packit aea12f
#include <sys/stat.h>
Packit aea12f
#include <time.h>
Packit aea12f
Packit aea12f
#ifndef _GL_INLINE_HEADER_BEGIN
Packit aea12f
 #error "Please include config.h first."
Packit aea12f
#endif
Packit aea12f
_GL_INLINE_HEADER_BEGIN
Packit aea12f
#ifndef _GL_STAT_TIME_INLINE
Packit aea12f
# define _GL_STAT_TIME_INLINE _GL_INLINE
Packit aea12f
#endif
Packit aea12f
Packit aea12f
#ifdef __cplusplus
Packit aea12f
extern "C" {
Packit aea12f
#endif
Packit aea12f
Packit aea12f
/* STAT_TIMESPEC (ST, ST_XTIM) is the ST_XTIM member for *ST of type
Packit aea12f
   struct timespec, if available.  If not, then STAT_TIMESPEC_NS (ST,
Packit aea12f
   ST_XTIM) is the nanosecond component of the ST_XTIM member for *ST,
Packit aea12f
   if available.  ST_XTIM can be st_atim, st_ctim, st_mtim, or st_birthtim
Packit aea12f
   for access, status change, data modification, or birth (creation)
Packit aea12f
   time respectively.
Packit aea12f
Packit aea12f
   These macros are private to stat-time.h.  */
Packit aea12f
#if _GL_WINDOWS_STAT_TIMESPEC || defined HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
Packit aea12f
# if _GL_WINDOWS_STAT_TIMESPEC || defined TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC
Packit aea12f
#  define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim)
Packit aea12f
# else
Packit aea12f
#  define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.tv_nsec)
Packit aea12f
# endif
Packit aea12f
#elif defined HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC
Packit aea12f
# define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim##espec)
Packit aea12f
#elif defined HAVE_STRUCT_STAT_ST_ATIMENSEC
Packit aea12f
# define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim##ensec)
Packit aea12f
#elif defined HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC
Packit aea12f
# define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.st__tim.tv_nsec)
Packit aea12f
#endif
Packit aea12f
Packit aea12f
/* Return the nanosecond component of *ST's access time.  */
Packit aea12f
_GL_STAT_TIME_INLINE long int _GL_ATTRIBUTE_PURE
Packit aea12f
get_stat_atime_ns (struct stat const *st)
Packit aea12f
{
Packit aea12f
# if defined STAT_TIMESPEC
Packit aea12f
  return STAT_TIMESPEC (st, st_atim).tv_nsec;
Packit aea12f
# elif defined STAT_TIMESPEC_NS
Packit aea12f
  return STAT_TIMESPEC_NS (st, st_atim);
Packit aea12f
# else
Packit aea12f
  return 0;
Packit aea12f
# endif
Packit aea12f
}
Packit aea12f
Packit aea12f
/* Return the nanosecond component of *ST's status change time.  */
Packit aea12f
_GL_STAT_TIME_INLINE long int _GL_ATTRIBUTE_PURE
Packit aea12f
get_stat_ctime_ns (struct stat const *st)
Packit aea12f
{
Packit aea12f
# if defined STAT_TIMESPEC
Packit aea12f
  return STAT_TIMESPEC (st, st_ctim).tv_nsec;
Packit aea12f
# elif defined STAT_TIMESPEC_NS
Packit aea12f
  return STAT_TIMESPEC_NS (st, st_ctim);
Packit aea12f
# else
Packit aea12f
  return 0;
Packit aea12f
# endif
Packit aea12f
}
Packit aea12f
Packit aea12f
/* Return the nanosecond component of *ST's data modification time.  */
Packit aea12f
_GL_STAT_TIME_INLINE long int _GL_ATTRIBUTE_PURE
Packit aea12f
get_stat_mtime_ns (struct stat const *st)
Packit aea12f
{
Packit aea12f
# if defined STAT_TIMESPEC
Packit aea12f
  return STAT_TIMESPEC (st, st_mtim).tv_nsec;
Packit aea12f
# elif defined STAT_TIMESPEC_NS
Packit aea12f
  return STAT_TIMESPEC_NS (st, st_mtim);
Packit aea12f
# else
Packit aea12f
  return 0;
Packit aea12f
# endif
Packit aea12f
}
Packit aea12f
Packit aea12f
/* Return the nanosecond component of *ST's birth time.  */
Packit aea12f
_GL_STAT_TIME_INLINE long int _GL_ATTRIBUTE_PURE
Packit aea12f
get_stat_birthtime_ns (struct stat const *st _GL_UNUSED)
Packit aea12f
{
Packit aea12f
# if defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC
Packit aea12f
  return STAT_TIMESPEC (st, st_birthtim).tv_nsec;
Packit aea12f
# elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC
Packit aea12f
  return STAT_TIMESPEC_NS (st, st_birthtim);
Packit aea12f
# else
Packit aea12f
  return 0;
Packit aea12f
# endif
Packit aea12f
}
Packit aea12f
Packit aea12f
/* Return *ST's access time.  */
Packit aea12f
_GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE
Packit aea12f
get_stat_atime (struct stat const *st)
Packit aea12f
{
Packit aea12f
#ifdef STAT_TIMESPEC
Packit aea12f
  return STAT_TIMESPEC (st, st_atim);
Packit aea12f
#else
Packit aea12f
  struct timespec t;
Packit aea12f
  t.tv_sec = st->st_atime;
Packit aea12f
  t.tv_nsec = get_stat_atime_ns (st);
Packit aea12f
  return t;
Packit aea12f
#endif
Packit aea12f
}
Packit aea12f
Packit aea12f
/* Return *ST's status change time.  */
Packit aea12f
_GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE
Packit aea12f
get_stat_ctime (struct stat const *st)
Packit aea12f
{
Packit aea12f
#ifdef STAT_TIMESPEC
Packit aea12f
  return STAT_TIMESPEC (st, st_ctim);
Packit aea12f
#else
Packit aea12f
  struct timespec t;
Packit aea12f
  t.tv_sec = st->st_ctime;
Packit aea12f
  t.tv_nsec = get_stat_ctime_ns (st);
Packit aea12f
  return t;
Packit aea12f
#endif
Packit aea12f
}
Packit aea12f
Packit aea12f
/* Return *ST's data modification time.  */
Packit aea12f
_GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE
Packit aea12f
get_stat_mtime (struct stat const *st)
Packit aea12f
{
Packit aea12f
#ifdef STAT_TIMESPEC
Packit aea12f
  return STAT_TIMESPEC (st, st_mtim);
Packit aea12f
#else
Packit aea12f
  struct timespec t;
Packit aea12f
  t.tv_sec = st->st_mtime;
Packit aea12f
  t.tv_nsec = get_stat_mtime_ns (st);
Packit aea12f
  return t;
Packit aea12f
#endif
Packit aea12f
}
Packit aea12f
Packit aea12f
/* Return *ST's birth time, if available; otherwise return a value
Packit aea12f
   with tv_sec and tv_nsec both equal to -1.  */
Packit aea12f
_GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE
Packit aea12f
get_stat_birthtime (struct stat const *st _GL_UNUSED)
Packit aea12f
{
Packit aea12f
  struct timespec t;
Packit aea12f
Packit aea12f
#if (defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC \
Packit aea12f
     || defined HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC)
Packit aea12f
  t = STAT_TIMESPEC (st, st_birthtim);
Packit aea12f
#elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC
Packit aea12f
  t.tv_sec = st->st_birthtime;
Packit aea12f
  t.tv_nsec = st->st_birthtimensec;
Packit aea12f
#elif defined _WIN32 && ! defined __CYGWIN__
Packit aea12f
  /* Native Windows platforms (but not Cygwin) put the "file creation
Packit aea12f
     time" in st_ctime (!).  See
Packit aea12f
     <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/stat-functions>.  */
Packit aea12f
# if _GL_WINDOWS_STAT_TIMESPEC
Packit aea12f
  t = st->st_ctim;
Packit aea12f
# else
Packit aea12f
  t.tv_sec = st->st_ctime;
Packit aea12f
  t.tv_nsec = 0;
Packit aea12f
# endif
Packit aea12f
#else
Packit aea12f
  /* Birth time is not supported.  */
Packit aea12f
  t.tv_sec = -1;
Packit aea12f
  t.tv_nsec = -1;
Packit aea12f
#endif
Packit aea12f
Packit aea12f
#if (defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC \
Packit aea12f
     || defined HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC \
Packit aea12f
     || defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
Packit aea12f
  /* FreeBSD and NetBSD sometimes signal the absence of knowledge by
Packit aea12f
     using zero.  Attempt to work around this problem.  Alas, this can
Packit aea12f
     report failure even for valid timestamps.  Also, NetBSD
Packit aea12f
     sometimes returns junk in the birth time fields; work around this
Packit aea12f
     bug if it is detected.  */
Packit aea12f
  if (! (t.tv_sec && 0 <= t.tv_nsec && t.tv_nsec < 1000000000))
Packit aea12f
    {
Packit aea12f
      t.tv_sec = -1;
Packit aea12f
      t.tv_nsec = -1;
Packit aea12f
    }
Packit aea12f
#endif
Packit aea12f
Packit aea12f
  return t;
Packit aea12f
}
Packit aea12f
Packit aea12f
/* If a stat-like function returned RESULT, normalize the timestamps
Packit aea12f
   in *ST, in case this platform suffers from the Solaris 11 bug where
Packit aea12f
   tv_nsec might be negative.  Return the adjusted RESULT, setting
Packit aea12f
   errno to EOVERFLOW if normalization overflowed.  This function
Packit aea12f
   is intended to be private to this .h file.  */
Packit aea12f
_GL_STAT_TIME_INLINE int
Packit aea12f
stat_time_normalize (int result, struct stat *st _GL_UNUSED)
Packit aea12f
{
Packit aea12f
#if defined __sun && defined STAT_TIMESPEC
Packit aea12f
  if (result == 0)
Packit aea12f
    {
Packit aea12f
      long int timespec_hz = 1000000000;
Packit aea12f
      short int const ts_off[] = { offsetof (struct stat, st_atim),
Packit aea12f
                                   offsetof (struct stat, st_mtim),
Packit aea12f
                                   offsetof (struct stat, st_ctim) };
Packit aea12f
      int i;
Packit aea12f
      for (i = 0; i < sizeof ts_off / sizeof *ts_off; i++)
Packit aea12f
        {
Packit aea12f
          struct timespec *ts = (struct timespec *) ((char *) st + ts_off[i]);
Packit aea12f
          long int q = ts->tv_nsec / timespec_hz;
Packit aea12f
          long int r = ts->tv_nsec % timespec_hz;
Packit aea12f
          if (r < 0)
Packit aea12f
            {
Packit aea12f
              r += timespec_hz;
Packit aea12f
              q--;
Packit aea12f
            }
Packit aea12f
          ts->tv_nsec = r;
Packit aea12f
          /* Overflow is possible, as Solaris 11 stat can yield
Packit aea12f
             tv_sec == TYPE_MINIMUM (time_t) && tv_nsec == -1000000000.
Packit aea12f
             INT_ADD_WRAPV is OK, since time_t is signed on Solaris.  */
Packit aea12f
          if (INT_ADD_WRAPV (q, ts->tv_sec, &ts->tv_sec))
Packit aea12f
            {
Packit aea12f
              errno = EOVERFLOW;
Packit aea12f
              return -1;
Packit aea12f
            }
Packit aea12f
        }
Packit aea12f
    }
Packit aea12f
#endif
Packit aea12f
  return result;
Packit aea12f
}
Packit aea12f
Packit aea12f
#ifdef __cplusplus
Packit aea12f
}
Packit aea12f
#endif
Packit aea12f
Packit aea12f
_GL_INLINE_HEADER_END
Packit aea12f
Packit aea12f
#endif