Blame gnulib/lib/stat-time.h

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