summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2012-06-22 14:26:37 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2012-06-22 14:26:37 -0700
commitc8fff8630133fea7c4e279458d10d825e5028c62 (patch)
treef8b8261fdf3596e1306a3d072e13ec572c9e3e65 /lib
parent36cec983d4e680e28e7066fda505910cd549f509 (diff)
Add gnulib files to support higher-resolution time stamps.
Fixes: debbugs:9000
Diffstat (limited to 'lib')
-rw-r--r--lib/dtotimespec.c69
-rw-r--r--lib/gettime.c48
-rw-r--r--lib/gettimeofday.c154
-rw-r--r--lib/pselect.c76
-rw-r--r--lib/stat-time.h189
-rw-r--r--lib/sys_select.in.h298
-rw-r--r--lib/sys_time.in.h205
-rw-r--r--lib/timespec-add.c71
-rw-r--r--lib/timespec-sub.c72
-rw-r--r--lib/timespec.h82
-rw-r--r--lib/utimens.c533
-rw-r--r--lib/utimens.h19
12 files changed, 1816 insertions, 0 deletions
diff --git a/lib/dtotimespec.c b/lib/dtotimespec.c
new file mode 100644
index 0000000000..f30fa07507
--- /dev/null
+++ b/lib/dtotimespec.c
@@ -0,0 +1,69 @@
+/* Convert double to timespec.
+
+ Copyright (C) 2011-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* written by Paul Eggert */
+
+/* Convert the double value SEC to a struct timespec. Round toward
+ positive infinity. On overflow, return an extremal value. */
+
+#include <config.h>
+
+#include "timespec.h"
+
+#include "intprops.h"
+
+struct timespec
+dtotimespec (double sec)
+{
+ enum { BILLION = 1000 * 1000 * 1000 };
+ double min_representable = TYPE_MINIMUM (time_t);
+ double max_representable =
+ ((TYPE_MAXIMUM (time_t) * (double) BILLION + (BILLION - 1))
+ / BILLION);
+ struct timespec r;
+
+ if (! (min_representable < sec))
+ {
+ r.tv_sec = TYPE_MINIMUM (time_t);
+ r.tv_nsec = 0;
+ }
+ else if (! (sec < max_representable))
+ {
+ r.tv_sec = TYPE_MAXIMUM (time_t);
+ r.tv_nsec = BILLION - 1;
+ }
+ else
+ {
+ time_t s = sec;
+ double frac = BILLION * (sec - s);
+ long ns = frac;
+ ns += ns < frac;
+ s += ns / BILLION;
+ ns %= BILLION;
+
+ if (ns < 0)
+ {
+ s--;
+ ns += BILLION;
+ }
+
+ r.tv_sec = s;
+ r.tv_nsec = ns;
+ }
+
+ return r;
+}
diff --git a/lib/gettime.c b/lib/gettime.c
new file mode 100644
index 0000000000..8075bfaf99
--- /dev/null
+++ b/lib/gettime.c
@@ -0,0 +1,48 @@
+/* gettime -- get the system clock
+
+ Copyright (C) 2002, 2004-2007, 2009-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Written by Paul Eggert. */
+
+#include <config.h>
+
+#include "timespec.h"
+
+#include <sys/time.h>
+
+/* Get the system time into *TS. */
+
+void
+gettime (struct timespec *ts)
+{
+#if HAVE_NANOTIME
+ nanotime (ts);
+#else
+
+# if defined CLOCK_REALTIME && HAVE_CLOCK_GETTIME
+ if (clock_gettime (CLOCK_REALTIME, ts) == 0)
+ return;
+# endif
+
+ {
+ struct timeval tv;
+ gettimeofday (&tv, NULL);
+ ts->tv_sec = tv.tv_sec;
+ ts->tv_nsec = tv.tv_usec * 1000;
+ }
+
+#endif
+}
diff --git a/lib/gettimeofday.c b/lib/gettimeofday.c
new file mode 100644
index 0000000000..5d35060950
--- /dev/null
+++ b/lib/gettimeofday.c
@@ -0,0 +1,154 @@
+/* Provide gettimeofday for systems that don't have it or for which it's broken.
+
+ Copyright (C) 2001-2003, 2005-2007, 2009-2012 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+/* written by Jim Meyering */
+
+#include <config.h>
+
+/* Specification. */
+#include <sys/time.h>
+
+#include <time.h>
+
+#if HAVE_SYS_TIMEB_H
+# include <sys/timeb.h>
+#endif
+
+#if GETTIMEOFDAY_CLOBBERS_LOCALTIME || TZSET_CLOBBERS_LOCALTIME
+
+/* Work around the bug in some systems whereby gettimeofday clobbers
+ the static buffer that localtime uses for its return value. The
+ gettimeofday function from Mac OS X 10.0.4 (i.e., Darwin 1.3.7) has
+ this problem. The tzset replacement is necessary for at least
+ Solaris 2.5, 2.5.1, and 2.6. */
+
+static struct tm tm_zero_buffer;
+static struct tm *localtime_buffer_addr = &tm_zero_buffer;
+
+# undef localtime
+extern struct tm *localtime (time_t const *);
+
+# undef gmtime
+extern struct tm *gmtime (time_t const *);
+
+/* This is a wrapper for localtime. It is used only on systems for which
+ gettimeofday clobbers the static buffer used for localtime's result.
+
+ On the first call, record the address of the static buffer that
+ localtime uses for its result. */
+
+struct tm *
+rpl_localtime (time_t const *timep)
+{
+ struct tm *tm = localtime (timep);
+
+ if (localtime_buffer_addr == &tm_zero_buffer)
+ localtime_buffer_addr = tm;
+
+ return tm;
+}
+
+/* Same as above, since gmtime and localtime use the same buffer. */
+struct tm *
+rpl_gmtime (time_t const *timep)
+{
+ struct tm *tm = gmtime (timep);
+
+ if (localtime_buffer_addr == &tm_zero_buffer)
+ localtime_buffer_addr = tm;
+
+ return tm;
+}
+
+#endif /* GETTIMEOFDAY_CLOBBERS_LOCALTIME || TZSET_CLOBBERS_LOCALTIME */
+
+#if TZSET_CLOBBERS_LOCALTIME
+
+# undef tzset
+extern void tzset (void);
+
+/* This is a wrapper for tzset, for systems on which tzset may clobber
+ the static buffer used for localtime's result. */
+void
+rpl_tzset (void)
+{
+ /* Save and restore the contents of the buffer used for localtime's
+ result around the call to tzset. */
+ struct tm save = *localtime_buffer_addr;
+ tzset ();
+ *localtime_buffer_addr = save;
+}
+#endif
+
+/* This is a wrapper for gettimeofday. It is used only on systems
+ that lack this function, or whose implementation of this function
+ causes problems. */
+
+int
+gettimeofday (struct timeval *restrict tv, void *restrict tz)
+{
+#undef gettimeofday
+#if HAVE_GETTIMEOFDAY
+# if GETTIMEOFDAY_CLOBBERS_LOCALTIME
+ /* Save and restore the contents of the buffer used for localtime's
+ result around the call to gettimeofday. */
+ struct tm save = *localtime_buffer_addr;
+# endif
+
+# if defined timeval /* 'struct timeval' overridden by gnulib? */
+# undef timeval
+ struct timeval otv;
+ int result = gettimeofday (&otv, (struct timezone *) tz);
+ if (result == 0)
+ {
+ tv->tv_sec = otv.tv_sec;
+ tv->tv_usec = otv.tv_usec;
+ }
+# else
+ int result = gettimeofday (tv, (struct timezone *) tz);
+# endif
+
+# if GETTIMEOFDAY_CLOBBERS_LOCALTIME
+ *localtime_buffer_addr = save;
+# endif
+
+ return result;
+
+#else
+
+# if HAVE__FTIME
+
+ struct _timeb timebuf;
+ _ftime (&timebuf);
+ tv->tv_sec = timebuf.time;
+ tv->tv_usec = timebuf.millitm * 1000;
+
+# else
+
+# if !defined OK_TO_USE_1S_CLOCK
+# error "Only 1-second nominal clock resolution found. Is that intended?" \
+ "If so, compile with the -DOK_TO_USE_1S_CLOCK option."
+# endif
+ tv->tv_sec = time (NULL);
+ tv->tv_usec = 0;
+
+# endif
+
+ return 0;
+
+#endif
+}
diff --git a/lib/pselect.c b/lib/pselect.c
new file mode 100644
index 0000000000..d8ebc70f6c
--- /dev/null
+++ b/lib/pselect.c
@@ -0,0 +1,76 @@
+/* pselect - synchronous I/O multiplexing
+
+ Copyright 2011-2012 Free Software Foundation, Inc.
+
+ This file is part of gnulib.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+/* written by Paul Eggert */
+
+#include <config.h>
+
+#include <sys/select.h>
+
+#include <errno.h>
+#include <signal.h>
+
+/* Examine the size-NFDS file descriptor sets in RFDS, WFDS, and XFDS
+ to see whether some of their descriptors are ready for reading,
+ ready for writing, or have exceptions pending. Wait for at most
+ TIMEOUT seconds, and use signal mask SIGMASK while waiting. A null
+ pointer parameter stands for no descriptors, an infinite timeout,
+ or an unaffected signal mask. */
+
+int
+pselect (int nfds, fd_set *restrict rfds,
+ fd_set *restrict wfds, fd_set *restrict xfds,
+ struct timespec const *restrict timeout,
+ sigset_t const *restrict sigmask)
+{
+ int select_result;
+ sigset_t origmask;
+ struct timeval tv, *tvp;
+
+ if (timeout)
+ {
+ if (! (0 <= timeout->tv_nsec && timeout->tv_nsec < 1000000000))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ tv.tv_sec = timeout->tv_sec;
+ tv.tv_usec = (timeout->tv_nsec + 999) / 1000;
+ tvp = &tv;
+ }
+ else
+ tvp = NULL;
+
+ /* Signal mask munging should be atomic, but this is the best we can
+ do in this emulation. */
+ if (sigmask)
+ pthread_sigmask (SIG_SETMASK, sigmask, &origmask);
+
+ select_result = select (nfds, rfds, wfds, xfds, tvp);
+
+ if (sigmask)
+ {
+ int select_errno = errno;
+ pthread_sigmask (SIG_SETMASK, &origmask, NULL);
+ errno = select_errno;
+ }
+
+ return select_result;
+}
diff --git a/lib/stat-time.h b/lib/stat-time.h
new file mode 100644
index 0000000000..30c2acdab6
--- /dev/null
+++ b/lib/stat-time.h
@@ -0,0 +1,189 @@
+/* stat-related time functions.
+
+ Copyright (C) 2005, 2007, 2009-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Written by Paul Eggert. */
+
+#ifndef STAT_TIME_H
+#define STAT_TIME_H 1
+
+#include <sys/stat.h>
+#include <time.h>
+
+/* STAT_TIMESPEC (ST, ST_XTIM) is the ST_XTIM member for *ST of type
+ struct timespec, if available. If not, then STAT_TIMESPEC_NS (ST,
+ ST_XTIM) is the nanosecond component of the ST_XTIM member for *ST,
+ if available. ST_XTIM can be st_atim, st_ctim, st_mtim, or st_birthtim
+ for access, status change, data modification, or birth (creation)
+ time respectively.
+
+ These macros are private to stat-time.h. */
+#if defined HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
+# ifdef TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC
+# define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim)
+# else
+# define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.tv_nsec)
+# endif
+#elif defined HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC
+# define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim##espec)
+#elif defined HAVE_STRUCT_STAT_ST_ATIMENSEC
+# define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim##ensec)
+#elif defined HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC
+# define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.st__tim.tv_nsec)
+#endif
+
+/* Return the nanosecond component of *ST's access time. */
+static inline long int
+get_stat_atime_ns (struct stat const *st)
+{
+# if defined STAT_TIMESPEC
+ return STAT_TIMESPEC (st, st_atim).tv_nsec;
+# elif defined STAT_TIMESPEC_NS
+ return STAT_TIMESPEC_NS (st, st_atim);
+# else
+ return 0;
+# endif
+}
+
+/* Return the nanosecond component of *ST's status change time. */
+static inline long int
+get_stat_ctime_ns (struct stat const *st)
+{
+# if defined STAT_TIMESPEC
+ return STAT_TIMESPEC (st, st_ctim).tv_nsec;
+# elif defined STAT_TIMESPEC_NS
+ return STAT_TIMESPEC_NS (st, st_ctim);
+# else
+ return 0;
+# endif
+}
+
+/* Return the nanosecond component of *ST's data modification time. */
+static inline long int
+get_stat_mtime_ns (struct stat const *st)
+{
+# if defined STAT_TIMESPEC
+ return STAT_TIMESPEC (st, st_mtim).tv_nsec;
+# elif defined STAT_TIMESPEC_NS
+ return STAT_TIMESPEC_NS (st, st_mtim);
+# else
+ return 0;
+# endif
+}
+
+/* Return the nanosecond component of *ST's birth time. */
+static inline long int
+get_stat_birthtime_ns (struct stat const *st)
+{
+# if defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC
+ return STAT_TIMESPEC (st, st_birthtim).tv_nsec;
+# elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC
+ return STAT_TIMESPEC_NS (st, st_birthtim);
+# else
+ /* Avoid a "parameter unused" warning. */
+ (void) st;
+ return 0;
+# endif
+}
+
+/* Return *ST's access time. */
+static inline struct timespec
+get_stat_atime (struct stat const *st)
+{
+#ifdef STAT_TIMESPEC
+ return STAT_TIMESPEC (st, st_atim);
+#else
+ struct timespec t;
+ t.tv_sec = st->st_atime;
+ t.tv_nsec = get_stat_atime_ns (st);
+ return t;
+#endif
+}
+
+/* Return *ST's status change time. */
+static inline struct timespec
+get_stat_ctime (struct stat const *st)
+{
+#ifdef STAT_TIMESPEC
+ return STAT_TIMESPEC (st, st_ctim);
+#else
+ struct timespec t;
+ t.tv_sec = st->st_ctime;
+ t.tv_nsec = get_stat_ctime_ns (st);
+ return t;
+#endif
+}
+
+/* Return *ST's data modification time. */
+static inline struct timespec
+get_stat_mtime (struct stat const *st)
+{
+#ifdef STAT_TIMESPEC
+ return STAT_TIMESPEC (st, st_mtim);
+#else
+ struct timespec t;
+ t.tv_sec = st->st_mtime;
+ t.tv_nsec = get_stat_mtime_ns (st);
+ return t;
+#endif
+}
+
+/* Return *ST's birth time, if available; otherwise return a value
+ with tv_sec and tv_nsec both equal to -1. */
+static inline struct timespec
+get_stat_birthtime (struct stat const *st)
+{
+ struct timespec t;
+
+#if (defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC \
+ || defined HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC)
+ t = STAT_TIMESPEC (st, st_birthtim);
+#elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC
+ t.tv_sec = st->st_birthtime;
+ t.tv_nsec = st->st_birthtimensec;
+#elif (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+ /* Native Windows platforms (but not Cygwin) put the "file creation
+ time" in st_ctime (!). See
+ <http://msdn2.microsoft.com/de-de/library/14h5k7ff(VS.80).aspx>. */
+ t.tv_sec = st->st_ctime;
+ t.tv_nsec = 0;
+#else
+ /* Birth time is not supported. */
+ t.tv_sec = -1;
+ t.tv_nsec = -1;
+ /* Avoid a "parameter unused" warning. */
+ (void) st;
+#endif
+
+#if (defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC \
+ || defined HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC \
+ || defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
+ /* FreeBSD and NetBSD sometimes signal the absence of knowledge by
+ using zero. Attempt to work around this problem. Alas, this can
+ report failure even for valid time stamps. Also, NetBSD
+ sometimes returns junk in the birth time fields; work around this
+ bug if it is detected. */
+ if (! (t.tv_sec && 0 <= t.tv_nsec && t.tv_nsec < 1000000000))
+ {
+ t.tv_sec = -1;
+ t.tv_nsec = -1;
+ }
+#endif
+
+ return t;
+}
+
+#endif
diff --git a/lib/sys_select.in.h b/lib/sys_select.in.h
new file mode 100644
index 0000000000..0aee2a16cb
--- /dev/null
+++ b/lib/sys_select.in.h
@@ -0,0 +1,298 @@
+/* Substitute for <sys/select.h>.
+ Copyright (C) 2007-2012 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+# if __GNUC__ >= 3
+@PRAGMA_SYSTEM_HEADER@
+# endif
+@PRAGMA_COLUMNS@
+
+/* On OSF/1, <sys/types.h> and <sys/time.h> include <sys/select.h>.
+ Simply delegate to the system's header in this case. */
+#if @HAVE_SYS_SELECT_H@ && defined __osf__ && (defined _SYS_TYPES_H_ && !defined _GL_SYS_SELECT_H_REDIRECT_FROM_SYS_TYPES_H) && defined _OSF_SOURCE
+
+# define _GL_SYS_SELECT_H_REDIRECT_FROM_SYS_TYPES_H
+# @INCLUDE_NEXT@ @NEXT_SYS_SELECT_H@
+
+#elif @HAVE_SYS_SELECT_H@ && defined __osf__ && (defined _SYS_TIME_H_ && !defined _GL_SYS_SELECT_H_REDIRECT_FROM_SYS_TIME_H) && defined _OSF_SOURCE
+
+# define _GL_SYS_SELECT_H_REDIRECT_FROM_SYS_TIME_H
+# @INCLUDE_NEXT@ @NEXT_SYS_SELECT_H@
+
+/* On IRIX 6.5, <sys/timespec.h> includes <sys/types.h>, which includes
+ <sys/bsd_types.h>, which includes <sys/select.h>. At this point we cannot
+ include <signal.h>, because that includes <internal/signal_core.h>, which
+ gives a syntax error because <sys/timespec.h> has not been completely
+ processed. Simply delegate to the system's header in this case. */
+#elif @HAVE_SYS_SELECT_H@ && defined __sgi && (defined _SYS_BSD_TYPES_H && !defined _GL_SYS_SELECT_H_REDIRECT_FROM_SYS_BSD_TYPES_H)
+
+# define _GL_SYS_SELECT_H_REDIRECT_FROM_SYS_BSD_TYPES_H
+# @INCLUDE_NEXT@ @NEXT_SYS_SELECT_H@
+
+/* On OpenBSD 5.0, <pthread.h> includes <sys/types.h>, which includes
+ <sys/select.h>. At this point we cannot include <signal.h>, because that
+ includes gnulib's pthread.h override, which gives a syntax error because
+ /usr/include/pthread.h has not been completely processed. Simply delegate
+ to the system's header in this case. */
+#elif @HAVE_SYS_SELECT_H@ && defined __OpenBSD__ && (defined _PTHREAD_H_ && !defined PTHREAD_MUTEX_INITIALIZER)
+
+# @INCLUDE_NEXT@ @NEXT_SYS_SELECT_H@
+
+#else
+
+#ifndef _@GUARD_PREFIX@_SYS_SELECT_H
+
+/* On many platforms, <sys/select.h> assumes prior inclusion of
+ <sys/types.h>. Also, mingw defines sigset_t there, instead of
+ in <signal.h> where it belongs. */
+#include <sys/types.h>
+
+#if @HAVE_SYS_SELECT_H@
+
+/* On OSF/1 4.0, <sys/select.h> provides only a forward declaration
+ of 'struct timeval', and no definition of this type.
+ Also, Mac OS X, AIX, HP-UX, IRIX, Solaris, Interix declare select()
+ in <sys/time.h>.
+ But avoid namespace pollution on glibc systems. */
+# ifndef __GLIBC__
+# include <sys/time.h>
+# endif
+
+/* On AIX 7 and Solaris 10, <sys/select.h> provides an FD_ZERO implementation
+ that relies on memset(), but without including <string.h>.
+ But in any case avoid namespace pollution on glibc systems. */
+# if (defined __OpenBSD__ || defined _AIX || defined __sun || defined __osf__ || defined __BEOS__) \
+ && ! defined __GLIBC__
+# include <string.h>
+# endif
+
+/* The include_next requires a split double-inclusion guard. */
+# @INCLUDE_NEXT@ @NEXT_SYS_SELECT_H@
+
+#endif
+
+/* Get definition of 'sigset_t'.
+ But avoid namespace pollution on glibc systems.
+ Do this after the include_next (for the sake of OpenBSD 5.0) but before
+ the split double-inclusion guard (for the sake of Solaris). */
+#if !(defined __GLIBC__ && !defined __UCLIBC__)
+# include <signal.h>
+#endif
+
+#ifndef _@GUARD_PREFIX@_SYS_SELECT_H
+#define _@GUARD_PREFIX@_SYS_SELECT_H
+
+#if !@HAVE_SYS_SELECT_H@
+/* A platform that lacks <sys/select.h>. */
+/* Get the 'struct timeval' and 'fd_set' types and the FD_* macros
+ on most platforms. */
+# include <sys/time.h>
+/* On HP-UX 11, <sys/time.h> provides an FD_ZERO implementation
+ that relies on memset(), but without including <string.h>. */
+# if defined __hpux
+# include <string.h>
+# endif
+/* On native Windows platforms:
+ Get the 'fd_set' type.
+ Get the close() declaration before we override it. */
+# if @HAVE_WINSOCK2_H@
+# if !defined _GL_INCLUDING_WINSOCK2_H
+# define _GL_INCLUDING_WINSOCK2_H
+# include <winsock2.h>
+# undef _GL_INCLUDING_WINSOCK2_H
+# endif
+# include <io.h>
+# endif
+#endif
+
+/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
+
+/* The definition of _GL_WARN_ON_USE is copied here. */
+
+
+/* Fix some definitions from <winsock2.h>. */
+
+#if @HAVE_WINSOCK2_H@
+
+# if !GNULIB_defined_rpl_fd_isset
+
+/* Re-define FD_ISSET to avoid a WSA call while we are not using
+ network sockets. */
+static inline int
+rpl_fd_isset (SOCKET fd, fd_set * set)
+{
+ u_int i;
+ if (set == NULL)
+ return 0;
+
+ for (i = 0; i < set->fd_count; i++)
+ if (set->fd_array[i] == fd)
+ return 1;
+
+ return 0;
+}
+
+# define GNULIB_defined_rpl_fd_isset 1
+# endif
+
+# undef FD_ISSET
+# define FD_ISSET(fd, set) rpl_fd_isset(fd, set)
+
+#endif
+
+/* Hide some function declarations from <winsock2.h>. */
+
+#if @HAVE_WINSOCK2_H@
+# if !defined _@GUARD_PREFIX@_UNISTD_H
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# undef close
+# define close close_used_without_including_unistd_h
+# else
+ _GL_WARN_ON_USE (close,
+ "close() used without including <unistd.h>");
+# endif
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# undef gethostname
+# define gethostname gethostname_used_without_including_unistd_h
+# else
+ _GL_WARN_ON_USE (gethostname,
+ "gethostname() used without including <unistd.h>");
+# endif
+# endif
+# if !defined _@GUARD_PREFIX@_SYS_SOCKET_H
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# undef socket
+# define socket socket_used_without_including_sys_socket_h
+# undef connect
+# define connect connect_used_without_including_sys_socket_h
+# undef accept
+# define accept accept_used_without_including_sys_socket_h
+# undef bind
+# define bind bind_used_without_including_sys_socket_h
+# undef getpeername
+# define getpeername getpeername_used_without_including_sys_socket_h
+# undef getsockname
+# define getsockname getsockname_used_without_including_sys_socket_h
+# undef getsockopt
+# define getsockopt getsockopt_used_without_including_sys_socket_h
+# undef listen
+# define listen listen_used_without_including_sys_socket_h
+# undef recv
+# define recv recv_used_without_including_sys_socket_h
+# undef send
+# define send send_used_without_including_sys_socket_h
+# undef recvfrom
+# define recvfrom recvfrom_used_without_including_sys_socket_h
+# undef sendto
+# define sendto sendto_used_without_including_sys_socket_h
+# undef setsockopt
+# define setsockopt setsockopt_used_without_including_sys_socket_h
+# undef shutdown
+# define shutdown shutdown_used_without_including_sys_socket_h
+# else
+ _GL_WARN_ON_USE (socket,
+ "socket() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (connect,
+ "connect() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (accept,
+ "accept() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (bind,
+ "bind() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (getpeername,
+ "getpeername() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (getsockname,
+ "getsockname() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (getsockopt,
+ "getsockopt() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (listen,
+ "listen() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (recv,
+ "recv() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (send,
+ "send() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (recvfrom,
+ "recvfrom() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (sendto,
+ "sendto() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (setsockopt,
+ "setsockopt() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (shutdown,
+ "shutdown() used without including <sys/socket.h>");
+# endif
+# endif
+#endif
+
+
+#if @GNULIB_PSELECT@
+# if @REPLACE_PSELECT@
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# undef pselect
+# define pselect rpl_pselect
+# endif
+_GL_FUNCDECL_RPL (pselect, int,
+ (int, fd_set *restrict, fd_set *restrict, fd_set *restrict,
+ struct timespec const *restrict, const sigset_t *restrict));
+_GL_CXXALIAS_RPL (pselect, int,
+ (int, fd_set *restrict, fd_set *restrict, fd_set *restrict,
+ struct timespec const *restrict, const sigset_t *restrict));
+# else
+# if !@HAVE_PSELECT@
+_GL_FUNCDECL_SYS (pselect, int,
+ (int, fd_set *restrict, fd_set *restrict, fd_set *restrict,
+ struct timespec const *restrict, const sigset_t *restrict));
+# endif
+_GL_CXXALIAS_SYS (pselect, int,
+ (int, fd_set *restrict, fd_set *restrict, fd_set *restrict,
+ struct timespec const *restrict, const sigset_t *restrict));
+# endif
+_GL_CXXALIASWARN (pselect);
+#elif defined GNULIB_POSIXCHECK
+# undef pselect
+# if HAVE_RAW_DECL_PSELECT
+_GL_WARN_ON_USE (pselect, "pselect is not portable - "
+ "use gnulib module pselect for portability");
+# endif
+#endif
+
+#if @GNULIB_SELECT@
+# if @REPLACE_SELECT@
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# undef select
+# define select rpl_select
+# endif
+_GL_FUNCDECL_RPL (select, int,
+ (int, fd_set *, fd_set *, fd_set *, struct timeval *));
+_GL_CXXALIAS_RPL (select, int,
+ (int, fd_set *, fd_set *, fd_set *, struct timeval *));
+# else
+_GL_CXXALIAS_SYS (select, int,
+ (int, fd_set *, fd_set *, fd_set *, struct timeval *));
+# endif
+_GL_CXXALIASWARN (select);
+#elif @HAVE_WINSOCK2_H@
+# undef select
+# define select select_used_without_requesting_gnulib_module_select
+#elif defined GNULIB_POSIXCHECK
+# undef select
+# if HAVE_RAW_DECL_SELECT
+_GL_WARN_ON_USE (select, "select is not always POSIX compliant - "
+ "use gnulib module select for portability");
+# endif
+#endif
+
+
+#endif /* _@GUARD_PREFIX@_SYS_SELECT_H */
+#endif /* _@GUARD_PREFIX@_SYS_SELECT_H */
+#endif /* OSF/1 */
diff --git a/lib/sys_time.in.h b/lib/sys_time.in.h
new file mode 100644
index 0000000000..d915cee467
--- /dev/null
+++ b/lib/sys_time.in.h
@@ -0,0 +1,205 @@
+/* Provide a more complete sys/time.h.
+
+ Copyright (C) 2007-2012 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+/* Written by Paul Eggert. */
+
+#if __GNUC__ >= 3
+@PRAGMA_SYSTEM_HEADER@
+#endif
+@PRAGMA_COLUMNS@
+
+#if defined _@GUARD_PREFIX@_SYS_TIME_H
+
+/* Simply delegate to the system's header, without adding anything. */
+# if @HAVE_SYS_TIME_H@
+# @INCLUDE_NEXT@ @NEXT_SYS_TIME_H@
+# endif
+
+#else
+
+# define _@GUARD_PREFIX@_SYS_TIME_H
+
+# if @HAVE_SYS_TIME_H@
+# @INCLUDE_NEXT@ @NEXT_SYS_TIME_H@
+# else
+# include <time.h>
+# endif
+
+/* On native Windows with MSVC, get the 'struct timeval' type.
+ Also, on native Windows with a 64-bit time_t, where we are overriding the
+ 'struct timeval' type, get all declarations of system functions whose
+ signature contains 'struct timeval'. */
+# if (defined _MSC_VER || @REPLACE_STRUCT_TIMEVAL@) && @HAVE_WINSOCK2_H@ && !defined _GL_INCLUDING_WINSOCK2_H
+# define _GL_INCLUDING_WINSOCK2_H
+# include <winsock2.h>
+# undef _GL_INCLUDING_WINSOCK2_H
+# endif
+
+/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
+
+/* The definition of _GL_ARG_NONNULL is copied here. */
+
+/* The definition of _GL_WARN_ON_USE is copied here. */
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# if !@HAVE_STRUCT_TIMEVAL@ || @REPLACE_STRUCT_TIMEVAL@
+
+# if @REPLACE_STRUCT_TIMEVAL@
+# define timeval rpl_timeval
+# endif
+
+# if !GNULIB_defined_struct_timeval
+struct timeval
+{
+ time_t tv_sec;
+ long int tv_usec;
+};
+# define GNULIB_defined_struct_timeval 1
+# endif
+
+# endif
+
+# ifdef __cplusplus
+}
+# endif
+
+# if @GNULIB_GETTIMEOFDAY@
+# if @REPLACE_GETTIMEOFDAY@
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# undef gettimeofday
+# define gettimeofday rpl_gettimeofday
+# endif
+_GL_FUNCDECL_RPL (gettimeofday, int,
+ (struct timeval *restrict, void *restrict)
+ _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (gettimeofday, int,
+ (struct timeval *restrict, void *restrict));
+# else
+# if !@HAVE_GETTIMEOFDAY@
+_GL_FUNCDECL_SYS (gettimeofday, int,
+ (struct timeval *restrict, void *restrict)
+ _GL_ARG_NONNULL ((1)));
+# endif
+/* Need to cast, because on glibc systems, by default, the second argument is
+ struct timezone *. */
+_GL_CXXALIAS_SYS_CAST (gettimeofday, int,
+ (struct timeval *restrict, void *restrict));
+# endif
+_GL_CXXALIASWARN (gettimeofday);
+# elif defined GNULIB_POSIXCHECK
+# undef gettimeofday
+# if HAVE_RAW_DECL_GETTIMEOFDAY
+_GL_WARN_ON_USE (gettimeofday, "gettimeofday is unportable - "
+ "use gnulib module gettimeofday for portability");
+# endif
+# endif
+
+/* Hide some function declarations from <winsock2.h>. */
+
+# if defined _MSC_VER && @HAVE_WINSOCK2_H@
+# if !defined _@GUARD_PREFIX@_UNISTD_H
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# undef close
+# define close close_used_without_including_unistd_h
+# else
+ _GL_WARN_ON_USE (close,
+ "close() used without including <unistd.h>");
+# endif
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# undef gethostname
+# define gethostname gethostname_used_without_including_unistd_h
+# else
+ _GL_WARN_ON_USE (gethostname,
+ "gethostname() used without including <unistd.h>");
+# endif
+# endif
+# if !defined _@GUARD_PREFIX@_SYS_SOCKET_H
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# undef socket
+# define socket socket_used_without_including_sys_socket_h
+# undef connect
+# define connect connect_used_without_including_sys_socket_h
+# undef accept
+# define accept accept_used_without_including_sys_socket_h
+# undef bind
+# define bind bind_used_without_including_sys_socket_h
+# undef getpeername
+# define getpeername getpeername_used_without_including_sys_socket_h
+# undef getsockname
+# define getsockname getsockname_used_without_including_sys_socket_h
+# undef getsockopt
+# define getsockopt getsockopt_used_without_including_sys_socket_h
+# undef listen
+# define listen listen_used_without_including_sys_socket_h
+# undef recv
+# define recv recv_used_without_including_sys_socket_h
+# undef send
+# define send send_used_without_including_sys_socket_h
+# undef recvfrom
+# define recvfrom recvfrom_used_without_including_sys_socket_h
+# undef sendto
+# define sendto sendto_used_without_including_sys_socket_h
+# undef setsockopt
+# define setsockopt setsockopt_used_without_including_sys_socket_h
+# undef shutdown
+# define shutdown shutdown_used_without_including_sys_socket_h
+# else
+ _GL_WARN_ON_USE (socket,
+ "socket() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (connect,
+ "connect() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (accept,
+ "accept() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (bind,
+ "bind() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (getpeername,
+ "getpeername() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (getsockname,
+ "getsockname() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (getsockopt,
+ "getsockopt() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (listen,
+ "listen() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (recv,
+ "recv() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (send,
+ "send() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (recvfrom,
+ "recvfrom() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (sendto,
+ "sendto() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (setsockopt,
+ "setsockopt() used without including <sys/socket.h>");
+ _GL_WARN_ON_USE (shutdown,
+ "shutdown() used without including <sys/socket.h>");
+# endif
+# endif
+# if !defined _@GUARD_PREFIX@_SYS_SELECT_H
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# undef select
+# define select select_used_without_including_sys_select_h
+# else
+ _GL_WARN_ON_USE (select,
+ "select() used without including <sys/select.h>");
+# endif
+# endif
+# endif
+
+#endif /* _@GUARD_PREFIX@_SYS_TIME_H */
diff --git a/lib/timespec-add.c b/lib/timespec-add.c
new file mode 100644
index 0000000000..4e5c641ac1
--- /dev/null
+++ b/lib/timespec-add.c
@@ -0,0 +1,71 @@
+/* Add two struct timespec values.
+
+ Copyright (C) 2011-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Written by Paul Eggert. */
+
+/* Return the sum of two timespec values A and B. On overflow, return
+ an extremal value. This assumes 0 <= tv_nsec <= 999999999. */
+
+#include <config.h>
+#include "timespec.h"
+
+#include "intprops.h"
+
+struct timespec
+timespec_add (struct timespec a, struct timespec b)
+{
+ struct timespec r;
+ time_t rs = a.tv_sec;
+ time_t bs = b.tv_sec;
+ int ns = a.tv_nsec + b.tv_nsec;
+ int nsd = ns - 1000000000;
+ int rns = ns;
+
+ if (0 <= nsd)
+ {
+ rns = nsd;
+ if (rs == TYPE_MAXIMUM (time_t))
+ {
+ if (0 <= bs)
+ goto high_overflow;
+ bs++;
+ }
+ else
+ rs++;
+ }
+
+ if (INT_ADD_OVERFLOW (rs, bs))
+ {
+ if (rs < 0)
+ {
+ rs = TYPE_MINIMUM (time_t);
+ rns = 0;
+ }
+ else
+ {
+ high_overflow:
+ rs = TYPE_MAXIMUM (time_t);
+ rns = 999999999;
+ }
+ }
+ else
+ rs += bs;
+
+ r.tv_sec = rs;
+ r.tv_nsec = rns;
+ return r;
+}
diff --git a/lib/timespec-sub.c b/lib/timespec-sub.c
new file mode 100644
index 0000000000..0b3bb1b57e
--- /dev/null
+++ b/lib/timespec-sub.c
@@ -0,0 +1,72 @@
+/* Subtract two struct timespec values.
+
+ Copyright (C) 2011-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Written by Paul Eggert. */
+
+/* Return the difference between two timespec values A and B. On
+ overflow, return an extremal value. This assumes 0 <= tv_nsec <=
+ 999999999. */
+
+#include <config.h>
+#include <config.h>
+#include "timespec.h"
+
+#include "intprops.h"
+
+struct timespec
+timespec_sub (struct timespec a, struct timespec b)
+{
+ struct timespec r;
+ time_t rs = a.tv_sec;
+ time_t bs = b.tv_sec;
+ int ns = a.tv_nsec - b.tv_nsec;
+ int rns = ns;
+
+ if (ns < 0)
+ {
+ rns = ns + 1000000000;
+ if (rs == TYPE_MINIMUM (time_t))
+ {
+ if (bs <= 0)
+ goto low_overflow;
+ bs--;
+ }
+ else
+ rs--;
+ }
+
+ if (INT_SUBTRACT_OVERFLOW (rs, bs))
+ {
+ if (rs < 0)
+ {
+ low_overflow:
+ rs = TYPE_MINIMUM (time_t);
+ rns = 0;
+ }
+ else
+ {
+ rs = TYPE_MAXIMUM (time_t);
+ rns = 999999999;
+ }
+ }
+ else
+ rs -= bs;
+
+ r.tv_sec = rs;
+ r.tv_nsec = rns;
+ return r;
+}
diff --git a/lib/timespec.h b/lib/timespec.h
new file mode 100644
index 0000000000..388ddb83a7
--- /dev/null
+++ b/lib/timespec.h
@@ -0,0 +1,82 @@
+/* timespec -- System time interface
+
+ Copyright (C) 2000, 2002, 2004-2005, 2007, 2009-2012 Free Software
+ Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#if ! defined TIMESPEC_H
+# define TIMESPEC_H
+
+# include <time.h>
+
+/* Return negative, zero, positive if A < B, A == B, A > B, respectively.
+
+ For each time stamp T, this code assumes that either:
+
+ * T.tv_nsec is in the range 0..999999999; or
+ * T.tv_sec corresponds to a valid leap second on a host that supports
+ leap seconds, and T.tv_nsec is in the range 1000000000..1999999999; or
+ * T.tv_sec is the minimum time_t value and T.tv_nsec is -1; or
+ T.tv_sec is the maximum time_t value and T.tv_nsec is 2000000000.
+ This allows for special struct timespec values that are less or
+ greater than all possible valid time stamps.
+
+ In all these cases, it is safe to subtract two tv_nsec values and
+ convert the result to integer without worrying about overflow on
+ any platform of interest to the GNU project, since all such
+ platforms have 32-bit int or wider.
+
+ Replacing "(int) (a.tv_nsec - b.tv_nsec)" with something like
+ "a.tv_nsec < b.tv_nsec ? -1 : a.tv_nsec > b.tv_nsec" would cause
+ this function to work in some cases where the above assumption is
+ violated, but not in all cases (e.g., a.tv_sec==1, a.tv_nsec==-2,
+ b.tv_sec==0, b.tv_nsec==999999999) and is arguably not worth the
+ extra instructions. Using a subtraction has the advantage of
+ detecting some invalid cases on platforms that detect integer
+ overflow.
+
+ The (int) cast avoids a gcc -Wconversion warning. */
+
+static inline int
+timespec_cmp (struct timespec a, struct timespec b)
+{
+ return (a.tv_sec < b.tv_sec ? -1
+ : a.tv_sec > b.tv_sec ? 1
+ : (int) (a.tv_nsec - b.tv_nsec));
+}
+
+/* Return -1, 0, 1, depending on the sign of A. A.tv_nsec must be
+ nonnegative. */
+static inline int
+timespec_sign (struct timespec a)
+{
+ return a.tv_sec < 0 ? -1 : a.tv_sec || a.tv_nsec;
+}
+
+struct timespec timespec_add (struct timespec, struct timespec);
+struct timespec timespec_sub (struct timespec, struct timespec);
+struct timespec dtotimespec (double);
+
+/* Return an approximation to A, of type 'double'. */
+static inline double
+timespectod (struct timespec a)
+{
+ return a.tv_sec + a.tv_nsec / 1e9;
+}
+
+void gettime (struct timespec *);
+int settime (struct timespec const *);
+
+#endif
diff --git a/lib/utimens.c b/lib/utimens.c
new file mode 100644
index 0000000000..c126b9551a
--- /dev/null
+++ b/lib/utimens.c
@@ -0,0 +1,533 @@
+/* Set file access and modification times.
+
+ Copyright (C) 2003-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 3 of the License, or any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Written by Paul Eggert. */
+
+/* derived from a function in touch.c */
+
+#include <config.h>
+
+#include "utimens.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "stat-time.h"
+#include "timespec.h"
+
+#if HAVE_UTIME_H
+# include <utime.h>
+#endif
+
+/* Some systems (even some that do have <utime.h>) don't declare this
+ structure anywhere. */
+#ifndef HAVE_STRUCT_UTIMBUF
+struct utimbuf
+{
+ long actime;
+ long modtime;
+};
+#endif
+
+/* Avoid recursion with rpl_futimens or rpl_utimensat. */
+#undef futimens
+#undef utimensat
+
+/* Solaris 9 mistakenly succeeds when given a non-directory with a
+ trailing slash. Force the use of rpl_stat for a fix. */
+#ifndef REPLACE_FUNC_STAT_FILE
+# define REPLACE_FUNC_STAT_FILE 0
+#endif
+
+#if HAVE_UTIMENSAT || HAVE_FUTIMENS
+/* Cache variables for whether the utimensat syscall works; used to
+ avoid calling the syscall if we know it will just fail with ENOSYS,
+ and to avoid unnecessary work in massaging timestamps if the
+ syscall will work. Multiple variables are needed, to distinguish
+ between the following scenarios on Linux:
+ utimensat doesn't exist, or is in glibc but kernel 2.6.18 fails with ENOSYS
+ kernel 2.6.22 and earlier rejects AT_SYMLINK_NOFOLLOW
+ kernel 2.6.25 and earlier reject UTIME_NOW/UTIME_OMIT with non-zero tv_sec
+ kernel 2.6.32 used with xfs or ntfs-3g fail to honor UTIME_OMIT
+ utimensat completely works
+ For each cache variable: 0 = unknown, 1 = yes, -1 = no. */
+static int utimensat_works_really;
+static int lutimensat_works_really;
+#endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
+
+/* Validate the requested timestamps. Return 0 if the resulting
+ timespec can be used for utimensat (after possibly modifying it to
+ work around bugs in utimensat). Return a positive value if the
+ timespec needs further adjustment based on stat results: 1 if any
+ adjustment is needed for utimes, and 2 if any adjustment is needed
+ for Linux utimensat. Return -1, with errno set to EINVAL, if
+ timespec is out of range. */
+static int
+validate_timespec (struct timespec timespec[2])
+{
+ int result = 0;
+ int utime_omit_count = 0;
+ assert (timespec);
+ if ((timespec[0].tv_nsec != UTIME_NOW
+ && timespec[0].tv_nsec != UTIME_OMIT
+ && (timespec[0].tv_nsec < 0 || 1000000000 <= timespec[0].tv_nsec))
+ || (timespec[1].tv_nsec != UTIME_NOW
+ && timespec[1].tv_nsec != UTIME_OMIT
+ && (timespec[1].tv_nsec < 0 || 1000000000 <= timespec[1].tv_nsec)))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ /* Work around Linux kernel 2.6.25 bug, where utimensat fails with
+ EINVAL if tv_sec is not 0 when using the flag values of tv_nsec.
+ Flag a Linux kernel 2.6.32 bug, where an mtime of UTIME_OMIT
+ fails to bump ctime. */
+ if (timespec[0].tv_nsec == UTIME_NOW
+ || timespec[0].tv_nsec == UTIME_OMIT)
+ {
+ timespec[0].tv_sec = 0;
+ result = 1;
+ if (timespec[0].tv_nsec == UTIME_OMIT)
+ utime_omit_count++;
+ }
+ if (timespec[1].tv_nsec == UTIME_NOW
+ || timespec[1].tv_nsec == UTIME_OMIT)
+ {
+ timespec[1].tv_sec = 0;
+ result = 1;
+ if (timespec[1].tv_nsec == UTIME_OMIT)
+ utime_omit_count++;
+ }
+ return result + (utime_omit_count == 1);
+}
+
+/* Normalize any UTIME_NOW or UTIME_OMIT values in *TS, using stat
+ buffer STATBUF to obtain the current timestamps of the file. If
+ both times are UTIME_NOW, set *TS to NULL (as this can avoid some
+ permissions issues). If both times are UTIME_OMIT, return true
+ (nothing further beyond the prior collection of STATBUF is
+ necessary); otherwise return false. */
+static bool
+update_timespec (struct stat const *statbuf, struct timespec *ts[2])
+{
+ struct timespec *timespec = *ts;
+ if (timespec[0].tv_nsec == UTIME_OMIT
+ && timespec[1].tv_nsec == UTIME_OMIT)
+ return true;
+ if (timespec[0].tv_nsec == UTIME_NOW
+ && timespec[1].tv_nsec == UTIME_NOW)
+ {
+ *ts = NULL;
+ return false;
+ }
+
+ if (timespec[0].tv_nsec == UTIME_OMIT)
+ timespec[0] = get_stat_atime (statbuf);
+ else if (timespec[0].tv_nsec == UTIME_NOW)
+ gettime (&timespec[0]);
+
+ if (timespec[1].tv_nsec == UTIME_OMIT)
+ timespec[1] = get_stat_mtime (statbuf);
+ else if (timespec[1].tv_nsec == UTIME_NOW)
+ gettime (&timespec[1]);
+
+ return false;
+}
+
+/* Set the access and modification time stamps of FD (a.k.a. FILE) to be
+ TIMESPEC[0] and TIMESPEC[1], respectively.
+ FD must be either negative -- in which case it is ignored --
+ or a file descriptor that is open on FILE.
+ If FD is nonnegative, then FILE can be NULL, which means
+ use just futimes (or equivalent) instead of utimes (or equivalent),
+ and fail if on an old system without futimes (or equivalent).
+ If TIMESPEC is null, set the time stamps to the current time.
+ Return 0 on success, -1 (setting errno) on failure. */
+
+int
+fdutimens (int fd, char const *file, struct timespec const timespec[2])
+{
+ struct timespec adjusted_timespec[2];
+ struct timespec *ts = timespec ? adjusted_timespec : NULL;
+ int adjustment_needed = 0;
+ struct stat st;
+
+ if (ts)
+ {
+ adjusted_timespec[0] = timespec[0];
+ adjusted_timespec[1] = timespec[1];
+ adjustment_needed = validate_timespec (ts);
+ }
+ if (adjustment_needed < 0)
+ return -1;
+
+ /* Require that at least one of FD or FILE are potentially valid, to avoid
+ a Linux bug where futimens (AT_FDCWD, NULL) changes "." rather
+ than failing. */
+ if (fd < 0 && !file)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ /* Some Linux-based NFS clients are buggy, and mishandle time stamps
+ of files in NFS file systems in some cases. We have no
+ configure-time test for this, but please see
+ <http://bugs.gentoo.org/show_bug.cgi?id=132673> for references to
+ some of the problems with Linux 2.6.16. If this affects you,
+ compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to
+ help in some cases, albeit at a cost in performance. But you
+ really should upgrade your kernel to a fixed version, since the
+ problem affects many applications. */
+
+#if HAVE_BUGGY_NFS_TIME_STAMPS
+ if (fd < 0)
+ sync ();
+ else
+ fsync (fd);
+#endif
+
+ /* POSIX 2008 added two interfaces to set file timestamps with
+ nanosecond resolution; newer Linux implements both functions via
+ a single syscall. We provide a fallback for ENOSYS (for example,
+ compiling against Linux 2.6.25 kernel headers and glibc 2.7, but
+ running on Linux 2.6.18 kernel). */
+#if HAVE_UTIMENSAT || HAVE_FUTIMENS
+ if (0 <= utimensat_works_really)
+ {
+ int result;
+# if __linux__
+ /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
+ systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
+ but work if both times are either explicitly specified or
+ UTIME_NOW. Work around it with a preparatory [f]stat prior
+ to calling futimens/utimensat; fortunately, there is not much
+ timing impact due to the extra syscall even on file systems
+ where UTIME_OMIT would have worked. FIXME: Simplify this in
+ 2012, when file system bugs are no longer common. */
+ if (adjustment_needed == 2)
+ {
+ if (fd < 0 ? stat (file, &st) : fstat (fd, &st))
+ return -1;
+ if (ts[0].tv_nsec == UTIME_OMIT)
+ ts[0] = get_stat_atime (&st);
+ else if (ts[1].tv_nsec == UTIME_OMIT)
+ ts[1] = get_stat_mtime (&st);
+ /* Note that st is good, in case utimensat gives ENOSYS. */
+ adjustment_needed++;
+ }
+# endif /* __linux__ */
+# if HAVE_UTIMENSAT
+ if (fd < 0)
+ {
+ result = utimensat (AT_FDCWD, file, ts, 0);
+# ifdef __linux__
+ /* Work around a kernel bug:
+ http://bugzilla.redhat.com/442352
+ http://bugzilla.redhat.com/449910
+ It appears that utimensat can mistakenly return 280 rather
+ than -1 upon ENOSYS failure.
+ FIXME: remove in 2010 or whenever the offending kernels
+ are no longer in common use. */
+ if (0 < result)
+ errno = ENOSYS;
+# endif /* __linux__ */
+ if (result == 0 || errno != ENOSYS)
+ {
+ utimensat_works_really = 1;
+ return result;
+ }
+ }
+# endif /* HAVE_UTIMENSAT */
+# if HAVE_FUTIMENS
+ if (0 <= fd)
+ {
+ result = futimens (fd, ts);
+# ifdef __linux__
+ /* Work around the same bug as above. */
+ if (0 < result)
+ errno = ENOSYS;
+# endif /* __linux__ */
+ if (result == 0 || errno != ENOSYS)
+ {
+ utimensat_works_really = 1;
+ return result;
+ }
+ }
+# endif /* HAVE_FUTIMENS */
+ }
+ utimensat_works_really = -1;
+ lutimensat_works_really = -1;
+#endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
+
+ /* The platform lacks an interface to set file timestamps with
+ nanosecond resolution, so do the best we can, discarding any
+ fractional part of the timestamp. */
+
+ if (adjustment_needed || (REPLACE_FUNC_STAT_FILE && fd < 0))
+ {
+ if (adjustment_needed != 3
+ && (fd < 0 ? stat (file, &st) : fstat (fd, &st)))
+ return -1;
+ if (ts && update_timespec (&st, &ts))
+ return 0;
+ }
+
+ {
+#if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
+ struct timeval timeval[2];
+ struct timeval *t;
+ if (ts)
+ {
+ timeval[0].tv_sec = ts[0].tv_sec;
+ timeval[0].tv_usec = ts[0].tv_nsec / 1000;
+ timeval[1].tv_sec = ts[1].tv_sec;
+ timeval[1].tv_usec = ts[1].tv_nsec / 1000;
+ t = timeval;
+ }
+ else
+ t = NULL;
+
+ if (fd < 0)
+ {
+# if HAVE_FUTIMESAT
+ return futimesat (AT_FDCWD, file, t);
+# endif
+ }
+ else
+ {
+ /* If futimesat or futimes fails here, don't try to speed things
+ up by returning right away. glibc can incorrectly fail with
+ errno == ENOENT if /proc isn't mounted. Also, Mandrake 10.0
+ in high security mode doesn't allow ordinary users to read
+ /proc/self, so glibc incorrectly fails with errno == EACCES.
+ If errno == EIO, EPERM, or EROFS, it's probably safe to fail
+ right away, but these cases are rare enough that they're not
+ worth optimizing, and who knows what other messed-up systems
+ are out there? So play it safe and fall back on the code
+ below. */
+
+# if (HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) || HAVE_FUTIMES
+# if HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG
+# undef futimes
+# define futimes(fd, t) futimesat (fd, NULL, t)
+# endif
+ if (futimes (fd, t) == 0)
+ {
+# if __linux__ && __GLIBC__
+ /* Work around a longstanding glibc bug, still present as
+ of 2010-12-27. On older Linux kernels that lack both
+ utimensat and utimes, glibc's futimes rounds instead of
+ truncating when falling back on utime. The same bug
+ occurs in futimesat with a null 2nd arg. */
+ if (t)
+ {
+ bool abig = 500000 <= t[0].tv_usec;
+ bool mbig = 500000 <= t[1].tv_usec;
+ if ((abig | mbig) && fstat (fd, &st) == 0)
+ {
+ /* If these two subtractions overflow, they'll
+ track the overflows inside the buggy glibc. */
+ time_t adiff = st.st_atime - t[0].tv_sec;
+ time_t mdiff = st.st_mtime - t[1].tv_sec;
+
+ struct timeval *tt = NULL;
+ struct timeval truncated_timeval[2];
+ truncated_timeval[0] = t[0];
+ truncated_timeval[1] = t[1];
+ if (abig && adiff == 1 && get_stat_atime_ns (&st) == 0)
+ {
+ tt = truncated_timeval;
+ tt[0].tv_usec = 0;
+ }
+ if (mbig && mdiff == 1 && get_stat_mtime_ns (&st) == 0)
+ {
+ tt = truncated_timeval;
+ tt[1].tv_usec = 0;
+ }
+ if (tt)
+ futimes (fd, tt);
+ }
+ }
+# endif
+
+ return 0;
+ }
+# endif
+ }
+#endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */
+
+ if (!file)
+ {
+#if ! ((HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) \
+ || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
+ errno = ENOSYS;
+#endif
+ return -1;
+ }
+
+#if HAVE_WORKING_UTIMES
+ return utimes (file, t);
+#else
+ {
+ struct utimbuf utimbuf;
+ struct utimbuf *ut;
+ if (ts)
+ {
+ utimbuf.actime = ts[0].tv_sec;
+ utimbuf.modtime = ts[1].tv_sec;
+ ut = &utimbuf;
+ }
+ else
+ ut = NULL;
+
+ return utime (file, ut);
+ }
+#endif /* !HAVE_WORKING_UTIMES */
+ }
+}
+
+/* Set the access and modification time stamps of FILE to be
+ TIMESPEC[0] and TIMESPEC[1], respectively. */
+int
+utimens (char const *file, struct timespec const timespec[2])
+{
+ return fdutimens (-1, file, timespec);
+}
+
+/* Set the access and modification time stamps of FILE to be
+ TIMESPEC[0] and TIMESPEC[1], respectively, without dereferencing
+ symlinks. Fail with ENOSYS if the platform does not support
+ changing symlink timestamps, but FILE was a symlink. */
+int
+lutimens (char const *file, struct timespec const timespec[2])
+{
+ struct timespec adjusted_timespec[2];
+ struct timespec *ts = timespec ? adjusted_timespec : NULL;
+ int adjustment_needed = 0;
+ struct stat st;
+
+ if (ts)
+ {
+ adjusted_timespec[0] = timespec[0];
+ adjusted_timespec[1] = timespec[1];
+ adjustment_needed = validate_timespec (ts);
+ }
+ if (adjustment_needed < 0)
+ return -1;
+
+ /* The Linux kernel did not support symlink timestamps until
+ utimensat, in version 2.6.22, so we don't need to mimic
+ fdutimens' worry about buggy NFS clients. But we do have to
+ worry about bogus return values. */
+
+#if HAVE_UTIMENSAT
+ if (0 <= lutimensat_works_really)
+ {
+ int result;
+# if __linux__
+ /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
+ systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
+ but work if both times are either explicitly specified or
+ UTIME_NOW. Work around it with a preparatory lstat prior to
+ calling utimensat; fortunately, there is not much timing
+ impact due to the extra syscall even on file systems where
+ UTIME_OMIT would have worked. FIXME: Simplify this in 2012,
+ when file system bugs are no longer common. */
+ if (adjustment_needed == 2)
+ {
+ if (lstat (file, &st))
+ return -1;
+ if (ts[0].tv_nsec == UTIME_OMIT)
+ ts[0] = get_stat_atime (&st);
+ else if (ts[1].tv_nsec == UTIME_OMIT)
+ ts[1] = get_stat_mtime (&st);
+ /* Note that st is good, in case utimensat gives ENOSYS. */
+ adjustment_needed++;
+ }
+# endif /* __linux__ */
+ result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW);
+# ifdef __linux__
+ /* Work around a kernel bug:
+ http://bugzilla.redhat.com/442352
+ http://bugzilla.redhat.com/449910
+ It appears that utimensat can mistakenly return 280 rather
+ than -1 upon ENOSYS failure.
+ FIXME: remove in 2010 or whenever the offending kernels
+ are no longer in common use. */
+ if (0 < result)
+ errno = ENOSYS;
+# endif
+ if (result == 0 || errno != ENOSYS)
+ {
+ utimensat_works_really = 1;
+ lutimensat_works_really = 1;
+ return result;
+ }
+ }
+ lutimensat_works_really = -1;
+#endif /* HAVE_UTIMENSAT */
+
+ /* The platform lacks an interface to set file timestamps with
+ nanosecond resolution, so do the best we can, discarding any
+ fractional part of the timestamp. */
+
+ if (adjustment_needed || REPLACE_FUNC_STAT_FILE)
+ {
+ if (adjustment_needed != 3 && lstat (file, &st))
+ return -1;
+ if (ts && update_timespec (&st, &ts))
+ return 0;
+ }
+
+ /* On Linux, lutimes is a thin wrapper around utimensat, so there is
+ no point trying lutimes if utimensat failed with ENOSYS. */
+#if HAVE_LUTIMES && !HAVE_UTIMENSAT
+ {
+ struct timeval timeval[2];
+ struct timeval *t;
+ int result;
+ if (ts)
+ {
+ timeval[0].tv_sec = ts[0].tv_sec;
+ timeval[0].tv_usec = ts[0].tv_nsec / 1000;
+ timeval[1].tv_sec = ts[1].tv_sec;
+ timeval[1].tv_usec = ts[1].tv_nsec / 1000;
+ t = timeval;
+ }
+ else
+ t = NULL;
+
+ result = lutimes (file, t);
+ if (result == 0 || errno != ENOSYS)
+ return result;
+ }
+#endif /* HAVE_LUTIMES && !HAVE_UTIMENSAT */
+
+ /* Out of luck for symlinks, but we still handle regular files. */
+ if (!(adjustment_needed || REPLACE_FUNC_STAT_FILE) && lstat (file, &st))
+ return -1;
+ if (!S_ISLNK (st.st_mode))
+ return fdutimens (-1, file, ts);
+ errno = ENOSYS;
+ return -1;
+}
diff --git a/lib/utimens.h b/lib/utimens.h
new file mode 100644
index 0000000000..8c47cf93f8
--- /dev/null
+++ b/lib/utimens.h
@@ -0,0 +1,19 @@
+#include <time.h>
+int fdutimens (int, char const *, struct timespec const [2]);
+int utimens (char const *, struct timespec const [2]);
+int lutimens (char const *, struct timespec const [2]);
+
+#if GNULIB_FDUTIMENSAT
+# include <fcntl.h>
+# include <sys/stat.h>
+
+int fdutimensat (int fd, int dir, char const *name, struct timespec const [2],
+ int atflag);
+
+/* Using this function makes application code slightly more readable. */
+static inline int
+lutimensat (int dir, char const *file, struct timespec const times[2])
+{
+ return utimensat (dir, file, times, AT_SYMLINK_NOFOLLOW);
+}
+#endif