Blame lib/stat-time.h

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