Blame lib/stat-time.h

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