diff options
| author | Paul Eggert | 2012-06-22 14:26:37 -0700 |
|---|---|---|
| committer | Paul Eggert | 2012-06-22 14:26:37 -0700 |
| commit | c8fff8630133fea7c4e279458d10d825e5028c62 (patch) | |
| tree | f8b8261fdf3596e1306a3d072e13ec572c9e3e65 /lib | |
| parent | 36cec983d4e680e28e7066fda505910cd549f509 (diff) | |
| download | emacs-c8fff8630133fea7c4e279458d10d825e5028c62.tar.gz emacs-c8fff8630133fea7c4e279458d10d825e5028c62.zip | |
Add gnulib files to support higher-resolution time stamps.
Fixes: debbugs:9000
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/dtotimespec.c | 69 | ||||
| -rw-r--r-- | lib/gettime.c | 48 | ||||
| -rw-r--r-- | lib/gettimeofday.c | 154 | ||||
| -rw-r--r-- | lib/pselect.c | 76 | ||||
| -rw-r--r-- | lib/stat-time.h | 189 | ||||
| -rw-r--r-- | lib/sys_select.in.h | 298 | ||||
| -rw-r--r-- | lib/sys_time.in.h | 205 | ||||
| -rw-r--r-- | lib/timespec-add.c | 71 | ||||
| -rw-r--r-- | lib/timespec-sub.c | 72 | ||||
| -rw-r--r-- | lib/timespec.h | 82 | ||||
| -rw-r--r-- | lib/utimens.c | 533 | ||||
| -rw-r--r-- | lib/utimens.h | 19 |
12 files changed, 1816 insertions, 0 deletions
diff --git a/lib/dtotimespec.c b/lib/dtotimespec.c new file mode 100644 index 00000000000..f30fa075077 --- /dev/null +++ b/lib/dtotimespec.c | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | /* Convert double to timespec. | ||
| 2 | |||
| 3 | Copyright (C) 2011-2012 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This program is free software: you can redistribute it and/or modify | ||
| 6 | it under the terms of the GNU General Public License as published by | ||
| 7 | the Free Software Foundation; either version 3 of the License, or | ||
| 8 | (at your option) any later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 17 | |||
| 18 | /* written by Paul Eggert */ | ||
| 19 | |||
| 20 | /* Convert the double value SEC to a struct timespec. Round toward | ||
| 21 | positive infinity. On overflow, return an extremal value. */ | ||
| 22 | |||
| 23 | #include <config.h> | ||
| 24 | |||
| 25 | #include "timespec.h" | ||
| 26 | |||
| 27 | #include "intprops.h" | ||
| 28 | |||
| 29 | struct timespec | ||
| 30 | dtotimespec (double sec) | ||
| 31 | { | ||
| 32 | enum { BILLION = 1000 * 1000 * 1000 }; | ||
| 33 | double min_representable = TYPE_MINIMUM (time_t); | ||
| 34 | double max_representable = | ||
| 35 | ((TYPE_MAXIMUM (time_t) * (double) BILLION + (BILLION - 1)) | ||
| 36 | / BILLION); | ||
| 37 | struct timespec r; | ||
| 38 | |||
| 39 | if (! (min_representable < sec)) | ||
| 40 | { | ||
| 41 | r.tv_sec = TYPE_MINIMUM (time_t); | ||
| 42 | r.tv_nsec = 0; | ||
| 43 | } | ||
| 44 | else if (! (sec < max_representable)) | ||
| 45 | { | ||
| 46 | r.tv_sec = TYPE_MAXIMUM (time_t); | ||
| 47 | r.tv_nsec = BILLION - 1; | ||
| 48 | } | ||
| 49 | else | ||
| 50 | { | ||
| 51 | time_t s = sec; | ||
| 52 | double frac = BILLION * (sec - s); | ||
| 53 | long ns = frac; | ||
| 54 | ns += ns < frac; | ||
| 55 | s += ns / BILLION; | ||
| 56 | ns %= BILLION; | ||
| 57 | |||
| 58 | if (ns < 0) | ||
| 59 | { | ||
| 60 | s--; | ||
| 61 | ns += BILLION; | ||
| 62 | } | ||
| 63 | |||
| 64 | r.tv_sec = s; | ||
| 65 | r.tv_nsec = ns; | ||
| 66 | } | ||
| 67 | |||
| 68 | return r; | ||
| 69 | } | ||
diff --git a/lib/gettime.c b/lib/gettime.c new file mode 100644 index 00000000000..8075bfaf999 --- /dev/null +++ b/lib/gettime.c | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | /* gettime -- get the system clock | ||
| 2 | |||
| 3 | Copyright (C) 2002, 2004-2007, 2009-2012 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This program is free software: you can redistribute it and/or modify | ||
| 6 | it under the terms of the GNU General Public License as published by | ||
| 7 | the Free Software Foundation; either version 3 of the License, or | ||
| 8 | (at your option) any later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 17 | |||
| 18 | /* Written by Paul Eggert. */ | ||
| 19 | |||
| 20 | #include <config.h> | ||
| 21 | |||
| 22 | #include "timespec.h" | ||
| 23 | |||
| 24 | #include <sys/time.h> | ||
| 25 | |||
| 26 | /* Get the system time into *TS. */ | ||
| 27 | |||
| 28 | void | ||
| 29 | gettime (struct timespec *ts) | ||
| 30 | { | ||
| 31 | #if HAVE_NANOTIME | ||
| 32 | nanotime (ts); | ||
| 33 | #else | ||
| 34 | |||
| 35 | # if defined CLOCK_REALTIME && HAVE_CLOCK_GETTIME | ||
| 36 | if (clock_gettime (CLOCK_REALTIME, ts) == 0) | ||
| 37 | return; | ||
| 38 | # endif | ||
| 39 | |||
| 40 | { | ||
| 41 | struct timeval tv; | ||
| 42 | gettimeofday (&tv, NULL); | ||
| 43 | ts->tv_sec = tv.tv_sec; | ||
| 44 | ts->tv_nsec = tv.tv_usec * 1000; | ||
| 45 | } | ||
| 46 | |||
| 47 | #endif | ||
| 48 | } | ||
diff --git a/lib/gettimeofday.c b/lib/gettimeofday.c new file mode 100644 index 00000000000..5d35060950a --- /dev/null +++ b/lib/gettimeofday.c | |||
| @@ -0,0 +1,154 @@ | |||
| 1 | /* Provide gettimeofday for systems that don't have it or for which it's broken. | ||
| 2 | |||
| 3 | Copyright (C) 2001-2003, 2005-2007, 2009-2012 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This program is free software; you can redistribute it and/or modify | ||
| 6 | it under the terms of the GNU General Public License as published by | ||
| 7 | the Free Software Foundation; either version 3, or (at your option) | ||
| 8 | any later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program; if not, see <http://www.gnu.org/licenses/>. */ | ||
| 17 | |||
| 18 | /* written by Jim Meyering */ | ||
| 19 | |||
| 20 | #include <config.h> | ||
| 21 | |||
| 22 | /* Specification. */ | ||
| 23 | #include <sys/time.h> | ||
| 24 | |||
| 25 | #include <time.h> | ||
| 26 | |||
| 27 | #if HAVE_SYS_TIMEB_H | ||
| 28 | # include <sys/timeb.h> | ||
| 29 | #endif | ||
| 30 | |||
| 31 | #if GETTIMEOFDAY_CLOBBERS_LOCALTIME || TZSET_CLOBBERS_LOCALTIME | ||
| 32 | |||
| 33 | /* Work around the bug in some systems whereby gettimeofday clobbers | ||
| 34 | the static buffer that localtime uses for its return value. The | ||
| 35 | gettimeofday function from Mac OS X 10.0.4 (i.e., Darwin 1.3.7) has | ||
| 36 | this problem. The tzset replacement is necessary for at least | ||
| 37 | Solaris 2.5, 2.5.1, and 2.6. */ | ||
| 38 | |||
| 39 | static struct tm tm_zero_buffer; | ||
| 40 | static struct tm *localtime_buffer_addr = &tm_zero_buffer; | ||
| 41 | |||
| 42 | # undef localtime | ||
| 43 | extern struct tm *localtime (time_t const *); | ||
| 44 | |||
| 45 | # undef gmtime | ||
| 46 | extern struct tm *gmtime (time_t const *); | ||
| 47 | |||
| 48 | /* This is a wrapper for localtime. It is used only on systems for which | ||
| 49 | gettimeofday clobbers the static buffer used for localtime's result. | ||
| 50 | |||
| 51 | On the first call, record the address of the static buffer that | ||
| 52 | localtime uses for its result. */ | ||
| 53 | |||
| 54 | struct tm * | ||
| 55 | rpl_localtime (time_t const *timep) | ||
| 56 | { | ||
| 57 | struct tm *tm = localtime (timep); | ||
| 58 | |||
| 59 | if (localtime_buffer_addr == &tm_zero_buffer) | ||
| 60 | localtime_buffer_addr = tm; | ||
| 61 | |||
| 62 | return tm; | ||
| 63 | } | ||
| 64 | |||
| 65 | /* Same as above, since gmtime and localtime use the same buffer. */ | ||
| 66 | struct tm * | ||
| 67 | rpl_gmtime (time_t const *timep) | ||
| 68 | { | ||
| 69 | struct tm *tm = gmtime (timep); | ||
| 70 | |||
| 71 | if (localtime_buffer_addr == &tm_zero_buffer) | ||
| 72 | localtime_buffer_addr = tm; | ||
| 73 | |||
| 74 | return tm; | ||
| 75 | } | ||
| 76 | |||
| 77 | #endif /* GETTIMEOFDAY_CLOBBERS_LOCALTIME || TZSET_CLOBBERS_LOCALTIME */ | ||
| 78 | |||
| 79 | #if TZSET_CLOBBERS_LOCALTIME | ||
| 80 | |||
| 81 | # undef tzset | ||
| 82 | extern void tzset (void); | ||
| 83 | |||
| 84 | /* This is a wrapper for tzset, for systems on which tzset may clobber | ||
| 85 | the static buffer used for localtime's result. */ | ||
| 86 | void | ||
| 87 | rpl_tzset (void) | ||
| 88 | { | ||
| 89 | /* Save and restore the contents of the buffer used for localtime's | ||
| 90 | result around the call to tzset. */ | ||
| 91 | struct tm save = *localtime_buffer_addr; | ||
| 92 | tzset (); | ||
| 93 | *localtime_buffer_addr = save; | ||
| 94 | } | ||
| 95 | #endif | ||
| 96 | |||
| 97 | /* This is a wrapper for gettimeofday. It is used only on systems | ||
| 98 | that lack this function, or whose implementation of this function | ||
| 99 | causes problems. */ | ||
| 100 | |||
| 101 | int | ||
| 102 | gettimeofday (struct timeval *restrict tv, void *restrict tz) | ||
| 103 | { | ||
| 104 | #undef gettimeofday | ||
| 105 | #if HAVE_GETTIMEOFDAY | ||
| 106 | # if GETTIMEOFDAY_CLOBBERS_LOCALTIME | ||
| 107 | /* Save and restore the contents of the buffer used for localtime's | ||
| 108 | result around the call to gettimeofday. */ | ||
| 109 | struct tm save = *localtime_buffer_addr; | ||
| 110 | # endif | ||
| 111 | |||
| 112 | # if defined timeval /* 'struct timeval' overridden by gnulib? */ | ||
| 113 | # undef timeval | ||
| 114 | struct timeval otv; | ||
| 115 | int result = gettimeofday (&otv, (struct timezone *) tz); | ||
| 116 | if (result == 0) | ||
| 117 | { | ||
| 118 | tv->tv_sec = otv.tv_sec; | ||
| 119 | tv->tv_usec = otv.tv_usec; | ||
| 120 | } | ||
| 121 | # else | ||
| 122 | int result = gettimeofday (tv, (struct timezone *) tz); | ||
| 123 | # endif | ||
| 124 | |||
| 125 | # if GETTIMEOFDAY_CLOBBERS_LOCALTIME | ||
| 126 | *localtime_buffer_addr = save; | ||
| 127 | # endif | ||
| 128 | |||
| 129 | return result; | ||
| 130 | |||
| 131 | #else | ||
| 132 | |||
| 133 | # if HAVE__FTIME | ||
| 134 | |||
| 135 | struct _timeb timebuf; | ||
| 136 | _ftime (&timebuf); | ||
| 137 | tv->tv_sec = timebuf.time; | ||
| 138 | tv->tv_usec = timebuf.millitm * 1000; | ||
| 139 | |||
| 140 | # else | ||
| 141 | |||
| 142 | # if !defined OK_TO_USE_1S_CLOCK | ||
| 143 | # error "Only 1-second nominal clock resolution found. Is that intended?" \ | ||
| 144 | "If so, compile with the -DOK_TO_USE_1S_CLOCK option." | ||
| 145 | # endif | ||
| 146 | tv->tv_sec = time (NULL); | ||
| 147 | tv->tv_usec = 0; | ||
| 148 | |||
| 149 | # endif | ||
| 150 | |||
| 151 | return 0; | ||
| 152 | |||
| 153 | #endif | ||
| 154 | } | ||
diff --git a/lib/pselect.c b/lib/pselect.c new file mode 100644 index 00000000000..d8ebc70f6c6 --- /dev/null +++ b/lib/pselect.c | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | /* pselect - synchronous I/O multiplexing | ||
| 2 | |||
| 3 | Copyright 2011-2012 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of gnulib. | ||
| 6 | |||
| 7 | This program is free software; you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation; either version 3, or (at your option) | ||
| 10 | any later version. | ||
| 11 | |||
| 12 | This program is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License along | ||
| 18 | with this program; if not, see <http://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | /* written by Paul Eggert */ | ||
| 21 | |||
| 22 | #include <config.h> | ||
| 23 | |||
| 24 | #include <sys/select.h> | ||
| 25 | |||
| 26 | #include <errno.h> | ||
| 27 | #include <signal.h> | ||
| 28 | |||
| 29 | /* Examine the size-NFDS file descriptor sets in RFDS, WFDS, and XFDS | ||
| 30 | to see whether some of their descriptors are ready for reading, | ||
| 31 | ready for writing, or have exceptions pending. Wait for at most | ||
| 32 | TIMEOUT seconds, and use signal mask SIGMASK while waiting. A null | ||
| 33 | pointer parameter stands for no descriptors, an infinite timeout, | ||
| 34 | or an unaffected signal mask. */ | ||
| 35 | |||
| 36 | int | ||
| 37 | pselect (int nfds, fd_set *restrict rfds, | ||
| 38 | fd_set *restrict wfds, fd_set *restrict xfds, | ||
| 39 | struct timespec const *restrict timeout, | ||
| 40 | sigset_t const *restrict sigmask) | ||
| 41 | { | ||
| 42 | int select_result; | ||
| 43 | sigset_t origmask; | ||
| 44 | struct timeval tv, *tvp; | ||
| 45 | |||
| 46 | if (timeout) | ||
| 47 | { | ||
| 48 | if (! (0 <= timeout->tv_nsec && timeout->tv_nsec < 1000000000)) | ||
| 49 | { | ||
| 50 | errno = EINVAL; | ||
| 51 | return -1; | ||
| 52 | } | ||
| 53 | |||
| 54 | tv.tv_sec = timeout->tv_sec; | ||
| 55 | tv.tv_usec = (timeout->tv_nsec + 999) / 1000; | ||
| 56 | tvp = &tv; | ||
| 57 | } | ||
| 58 | else | ||
| 59 | tvp = NULL; | ||
| 60 | |||
| 61 | /* Signal mask munging should be atomic, but this is the best we can | ||
| 62 | do in this emulation. */ | ||
| 63 | if (sigmask) | ||
| 64 | pthread_sigmask (SIG_SETMASK, sigmask, &origmask); | ||
| 65 | |||
| 66 | select_result = select (nfds, rfds, wfds, xfds, tvp); | ||
| 67 | |||
| 68 | if (sigmask) | ||
| 69 | { | ||
| 70 | int select_errno = errno; | ||
| 71 | pthread_sigmask (SIG_SETMASK, &origmask, NULL); | ||
| 72 | errno = select_errno; | ||
| 73 | } | ||
| 74 | |||
| 75 | return select_result; | ||
| 76 | } | ||
diff --git a/lib/stat-time.h b/lib/stat-time.h new file mode 100644 index 00000000000..30c2acdab63 --- /dev/null +++ b/lib/stat-time.h | |||
| @@ -0,0 +1,189 @@ | |||
| 1 | /* stat-related time functions. | ||
| 2 | |||
| 3 | Copyright (C) 2005, 2007, 2009-2012 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This program is free software: you can redistribute it and/or modify | ||
| 6 | it under the terms of the GNU General Public License as published by | ||
| 7 | the Free Software Foundation; either version 3 of the License, or | ||
| 8 | (at your option) any later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 17 | |||
| 18 | /* Written by Paul Eggert. */ | ||
| 19 | |||
| 20 | #ifndef STAT_TIME_H | ||
| 21 | #define STAT_TIME_H 1 | ||
| 22 | |||
| 23 | #include <sys/stat.h> | ||
| 24 | #include <time.h> | ||
| 25 | |||
| 26 | /* STAT_TIMESPEC (ST, ST_XTIM) is the ST_XTIM member for *ST of type | ||
| 27 | struct timespec, if available. If not, then STAT_TIMESPEC_NS (ST, | ||
| 28 | ST_XTIM) is the nanosecond component of the ST_XTIM member for *ST, | ||
| 29 | if available. ST_XTIM can be st_atim, st_ctim, st_mtim, or st_birthtim | ||
| 30 | for access, status change, data modification, or birth (creation) | ||
| 31 | time respectively. | ||
| 32 | |||
| 33 | These macros are private to stat-time.h. */ | ||
| 34 | #if defined HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC | ||
| 35 | # ifdef TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC | ||
| 36 | # define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim) | ||
| 37 | # else | ||
| 38 | # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.tv_nsec) | ||
| 39 | # endif | ||
| 40 | #elif defined HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC | ||
| 41 | # define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim##espec) | ||
| 42 | #elif defined HAVE_STRUCT_STAT_ST_ATIMENSEC | ||
| 43 | # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim##ensec) | ||
| 44 | #elif defined HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC | ||
| 45 | # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.st__tim.tv_nsec) | ||
| 46 | #endif | ||
| 47 | |||
| 48 | /* Return the nanosecond component of *ST's access time. */ | ||
| 49 | static inline long int | ||
| 50 | get_stat_atime_ns (struct stat const *st) | ||
| 51 | { | ||
| 52 | # if defined STAT_TIMESPEC | ||
| 53 | return STAT_TIMESPEC (st, st_atim).tv_nsec; | ||
| 54 | # elif defined STAT_TIMESPEC_NS | ||
| 55 | return STAT_TIMESPEC_NS (st, st_atim); | ||
| 56 | # else | ||
| 57 | return 0; | ||
| 58 | # endif | ||
| 59 | } | ||
| 60 | |||
| 61 | /* Return the nanosecond component of *ST's status change time. */ | ||
| 62 | static inline long int | ||
| 63 | get_stat_ctime_ns (struct stat const *st) | ||
| 64 | { | ||
| 65 | # if defined STAT_TIMESPEC | ||
| 66 | return STAT_TIMESPEC (st, st_ctim).tv_nsec; | ||
| 67 | # elif defined STAT_TIMESPEC_NS | ||
| 68 | return STAT_TIMESPEC_NS (st, st_ctim); | ||
| 69 | # else | ||
| 70 | return 0; | ||
| 71 | # endif | ||
| 72 | } | ||
| 73 | |||
| 74 | /* Return the nanosecond component of *ST's data modification time. */ | ||
| 75 | static inline long int | ||
| 76 | get_stat_mtime_ns (struct stat const *st) | ||
| 77 | { | ||
| 78 | # if defined STAT_TIMESPEC | ||
| 79 | return STAT_TIMESPEC (st, st_mtim).tv_nsec; | ||
| 80 | # elif defined STAT_TIMESPEC_NS | ||
| 81 | return STAT_TIMESPEC_NS (st, st_mtim); | ||
| 82 | # else | ||
| 83 | return 0; | ||
| 84 | # endif | ||
| 85 | } | ||
| 86 | |||
| 87 | /* Return the nanosecond component of *ST's birth time. */ | ||
| 88 | static inline long int | ||
| 89 | get_stat_birthtime_ns (struct stat const *st) | ||
| 90 | { | ||
| 91 | # if defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC | ||
| 92 | return STAT_TIMESPEC (st, st_birthtim).tv_nsec; | ||
| 93 | # elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC | ||
| 94 | return STAT_TIMESPEC_NS (st, st_birthtim); | ||
| 95 | # else | ||
| 96 | /* Avoid a "parameter unused" warning. */ | ||
| 97 | (void) st; | ||
| 98 | return 0; | ||
| 99 | # endif | ||
| 100 | } | ||
| 101 | |||
| 102 | /* Return *ST's access time. */ | ||
| 103 | static inline struct timespec | ||
| 104 | get_stat_atime (struct stat const *st) | ||
| 105 | { | ||
| 106 | #ifdef STAT_TIMESPEC | ||
| 107 | return STAT_TIMESPEC (st, st_atim); | ||
| 108 | #else | ||
| 109 | struct timespec t; | ||
| 110 | t.tv_sec = st->st_atime; | ||
| 111 | t.tv_nsec = get_stat_atime_ns (st); | ||
| 112 | return t; | ||
| 113 | #endif | ||
| 114 | } | ||
| 115 | |||
| 116 | /* Return *ST's status change time. */ | ||
| 117 | static inline struct timespec | ||
| 118 | get_stat_ctime (struct stat const *st) | ||
| 119 | { | ||
| 120 | #ifdef STAT_TIMESPEC | ||
| 121 | return STAT_TIMESPEC (st, st_ctim); | ||
| 122 | #else | ||
| 123 | struct timespec t; | ||
| 124 | t.tv_sec = st->st_ctime; | ||
| 125 | t.tv_nsec = get_stat_ctime_ns (st); | ||
| 126 | return t; | ||
| 127 | #endif | ||
| 128 | } | ||
| 129 | |||
| 130 | /* Return *ST's data modification time. */ | ||
| 131 | static inline struct timespec | ||
| 132 | get_stat_mtime (struct stat const *st) | ||
| 133 | { | ||
| 134 | #ifdef STAT_TIMESPEC | ||
| 135 | return STAT_TIMESPEC (st, st_mtim); | ||
| 136 | #else | ||
| 137 | struct timespec t; | ||
| 138 | t.tv_sec = st->st_mtime; | ||
| 139 | t.tv_nsec = get_stat_mtime_ns (st); | ||
| 140 | return t; | ||
| 141 | #endif | ||
| 142 | } | ||
| 143 | |||
| 144 | /* Return *ST's birth time, if available; otherwise return a value | ||
| 145 | with tv_sec and tv_nsec both equal to -1. */ | ||
| 146 | static inline struct timespec | ||
| 147 | get_stat_birthtime (struct stat const *st) | ||
| 148 | { | ||
| 149 | struct timespec t; | ||
| 150 | |||
| 151 | #if (defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC \ | ||
| 152 | || defined HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC) | ||
| 153 | t = STAT_TIMESPEC (st, st_birthtim); | ||
| 154 | #elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC | ||
| 155 | t.tv_sec = st->st_birthtime; | ||
| 156 | t.tv_nsec = st->st_birthtimensec; | ||
| 157 | #elif (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ | ||
| 158 | /* Native Windows platforms (but not Cygwin) put the "file creation | ||
| 159 | time" in st_ctime (!). See | ||
| 160 | <http://msdn2.microsoft.com/de-de/library/14h5k7ff(VS.80).aspx>. */ | ||
| 161 | t.tv_sec = st->st_ctime; | ||
| 162 | t.tv_nsec = 0; | ||
| 163 | #else | ||
| 164 | /* Birth time is not supported. */ | ||
| 165 | t.tv_sec = -1; | ||
| 166 | t.tv_nsec = -1; | ||
| 167 | /* Avoid a "parameter unused" warning. */ | ||
| 168 | (void) st; | ||
| 169 | #endif | ||
| 170 | |||
| 171 | #if (defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC \ | ||
| 172 | || defined HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC \ | ||
| 173 | || defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC) | ||
| 174 | /* FreeBSD and NetBSD sometimes signal the absence of knowledge by | ||
| 175 | using zero. Attempt to work around this problem. Alas, this can | ||
| 176 | report failure even for valid time stamps. Also, NetBSD | ||
| 177 | sometimes returns junk in the birth time fields; work around this | ||
| 178 | bug if it is detected. */ | ||
| 179 | if (! (t.tv_sec && 0 <= t.tv_nsec && t.tv_nsec < 1000000000)) | ||
| 180 | { | ||
| 181 | t.tv_sec = -1; | ||
| 182 | t.tv_nsec = -1; | ||
| 183 | } | ||
| 184 | #endif | ||
| 185 | |||
| 186 | return t; | ||
| 187 | } | ||
| 188 | |||
| 189 | #endif | ||
diff --git a/lib/sys_select.in.h b/lib/sys_select.in.h new file mode 100644 index 00000000000..0aee2a16cbf --- /dev/null +++ b/lib/sys_select.in.h | |||
| @@ -0,0 +1,298 @@ | |||
| 1 | /* Substitute for <sys/select.h>. | ||
| 2 | Copyright (C) 2007-2012 Free Software Foundation, Inc. | ||
| 3 | |||
| 4 | This program is free software; you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation; either version 3, or (at your option) | ||
| 7 | any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program; if not, see <http://www.gnu.org/licenses/>. */ | ||
| 16 | |||
| 17 | # if __GNUC__ >= 3 | ||
| 18 | @PRAGMA_SYSTEM_HEADER@ | ||
| 19 | # endif | ||
| 20 | @PRAGMA_COLUMNS@ | ||
| 21 | |||
| 22 | /* On OSF/1, <sys/types.h> and <sys/time.h> include <sys/select.h>. | ||
| 23 | Simply delegate to the system's header in this case. */ | ||
| 24 | #if @HAVE_SYS_SELECT_H@ && defined __osf__ && (defined _SYS_TYPES_H_ && !defined _GL_SYS_SELECT_H_REDIRECT_FROM_SYS_TYPES_H) && defined _OSF_SOURCE | ||
| 25 | |||
| 26 | # define _GL_SYS_SELECT_H_REDIRECT_FROM_SYS_TYPES_H | ||
| 27 | # @INCLUDE_NEXT@ @NEXT_SYS_SELECT_H@ | ||
| 28 | |||
| 29 | #elif @HAVE_SYS_SELECT_H@ && defined __osf__ && (defined _SYS_TIME_H_ && !defined _GL_SYS_SELECT_H_REDIRECT_FROM_SYS_TIME_H) && defined _OSF_SOURCE | ||
| 30 | |||
| 31 | # define _GL_SYS_SELECT_H_REDIRECT_FROM_SYS_TIME_H | ||
| 32 | # @INCLUDE_NEXT@ @NEXT_SYS_SELECT_H@ | ||
| 33 | |||
| 34 | /* On IRIX 6.5, <sys/timespec.h> includes <sys/types.h>, which includes | ||
| 35 | <sys/bsd_types.h>, which includes <sys/select.h>. At this point we cannot | ||
| 36 | include <signal.h>, because that includes <internal/signal_core.h>, which | ||
| 37 | gives a syntax error because <sys/timespec.h> has not been completely | ||
| 38 | processed. Simply delegate to the system's header in this case. */ | ||
| 39 | #elif @HAVE_SYS_SELECT_H@ && defined __sgi && (defined _SYS_BSD_TYPES_H && !defined _GL_SYS_SELECT_H_REDIRECT_FROM_SYS_BSD_TYPES_H) | ||
| 40 | |||
| 41 | # define _GL_SYS_SELECT_H_REDIRECT_FROM_SYS_BSD_TYPES_H | ||
| 42 | # @INCLUDE_NEXT@ @NEXT_SYS_SELECT_H@ | ||
| 43 | |||
| 44 | /* On OpenBSD 5.0, <pthread.h> includes <sys/types.h>, which includes | ||
| 45 | <sys/select.h>. At this point we cannot include <signal.h>, because that | ||
| 46 | includes gnulib's pthread.h override, which gives a syntax error because | ||
| 47 | /usr/include/pthread.h has not been completely processed. Simply delegate | ||
| 48 | to the system's header in this case. */ | ||
| 49 | #elif @HAVE_SYS_SELECT_H@ && defined __OpenBSD__ && (defined _PTHREAD_H_ && !defined PTHREAD_MUTEX_INITIALIZER) | ||
| 50 | |||
| 51 | # @INCLUDE_NEXT@ @NEXT_SYS_SELECT_H@ | ||
| 52 | |||
| 53 | #else | ||
| 54 | |||
| 55 | #ifndef _@GUARD_PREFIX@_SYS_SELECT_H | ||
| 56 | |||
| 57 | /* On many platforms, <sys/select.h> assumes prior inclusion of | ||
| 58 | <sys/types.h>. Also, mingw defines sigset_t there, instead of | ||
| 59 | in <signal.h> where it belongs. */ | ||
| 60 | #include <sys/types.h> | ||
| 61 | |||
| 62 | #if @HAVE_SYS_SELECT_H@ | ||
| 63 | |||
| 64 | /* On OSF/1 4.0, <sys/select.h> provides only a forward declaration | ||
| 65 | of 'struct timeval', and no definition of this type. | ||
| 66 | Also, Mac OS X, AIX, HP-UX, IRIX, Solaris, Interix declare select() | ||
| 67 | in <sys/time.h>. | ||
| 68 | But avoid namespace pollution on glibc systems. */ | ||
| 69 | # ifndef __GLIBC__ | ||
| 70 | # include <sys/time.h> | ||
| 71 | # endif | ||
| 72 | |||
| 73 | /* On AIX 7 and Solaris 10, <sys/select.h> provides an FD_ZERO implementation | ||
| 74 | that relies on memset(), but without including <string.h>. | ||
| 75 | But in any case avoid namespace pollution on glibc systems. */ | ||
| 76 | # if (defined __OpenBSD__ || defined _AIX || defined __sun || defined __osf__ || defined __BEOS__) \ | ||
| 77 | && ! defined __GLIBC__ | ||
| 78 | # include <string.h> | ||
| 79 | # endif | ||
| 80 | |||
| 81 | /* The include_next requires a split double-inclusion guard. */ | ||
| 82 | # @INCLUDE_NEXT@ @NEXT_SYS_SELECT_H@ | ||
| 83 | |||
| 84 | #endif | ||
| 85 | |||
| 86 | /* Get definition of 'sigset_t'. | ||
| 87 | But avoid namespace pollution on glibc systems. | ||
| 88 | Do this after the include_next (for the sake of OpenBSD 5.0) but before | ||
| 89 | the split double-inclusion guard (for the sake of Solaris). */ | ||
| 90 | #if !(defined __GLIBC__ && !defined __UCLIBC__) | ||
| 91 | # include <signal.h> | ||
| 92 | #endif | ||
| 93 | |||
| 94 | #ifndef _@GUARD_PREFIX@_SYS_SELECT_H | ||
| 95 | #define _@GUARD_PREFIX@_SYS_SELECT_H | ||
| 96 | |||
| 97 | #if !@HAVE_SYS_SELECT_H@ | ||
| 98 | /* A platform that lacks <sys/select.h>. */ | ||
| 99 | /* Get the 'struct timeval' and 'fd_set' types and the FD_* macros | ||
| 100 | on most platforms. */ | ||
| 101 | # include <sys/time.h> | ||
| 102 | /* On HP-UX 11, <sys/time.h> provides an FD_ZERO implementation | ||
| 103 | that relies on memset(), but without including <string.h>. */ | ||
| 104 | # if defined __hpux | ||
| 105 | # include <string.h> | ||
| 106 | # endif | ||
| 107 | /* On native Windows platforms: | ||
| 108 | Get the 'fd_set' type. | ||
| 109 | Get the close() declaration before we override it. */ | ||
| 110 | # if @HAVE_WINSOCK2_H@ | ||
| 111 | # if !defined _GL_INCLUDING_WINSOCK2_H | ||
| 112 | # define _GL_INCLUDING_WINSOCK2_H | ||
| 113 | # include <winsock2.h> | ||
| 114 | # undef _GL_INCLUDING_WINSOCK2_H | ||
| 115 | # endif | ||
| 116 | # include <io.h> | ||
| 117 | # endif | ||
| 118 | #endif | ||
| 119 | |||
| 120 | /* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ | ||
| 121 | |||
| 122 | /* The definition of _GL_WARN_ON_USE is copied here. */ | ||
| 123 | |||
| 124 | |||
| 125 | /* Fix some definitions from <winsock2.h>. */ | ||
| 126 | |||
| 127 | #if @HAVE_WINSOCK2_H@ | ||
| 128 | |||
| 129 | # if !GNULIB_defined_rpl_fd_isset | ||
| 130 | |||
| 131 | /* Re-define FD_ISSET to avoid a WSA call while we are not using | ||
| 132 | network sockets. */ | ||
| 133 | static inline int | ||
| 134 | rpl_fd_isset (SOCKET fd, fd_set * set) | ||
| 135 | { | ||
| 136 | u_int i; | ||
| 137 | if (set == NULL) | ||
| 138 | return 0; | ||
| 139 | |||
| 140 | for (i = 0; i < set->fd_count; i++) | ||
| 141 | if (set->fd_array[i] == fd) | ||
| 142 | return 1; | ||
| 143 | |||
| 144 | return 0; | ||
| 145 | } | ||
| 146 | |||
| 147 | # define GNULIB_defined_rpl_fd_isset 1 | ||
| 148 | # endif | ||
| 149 | |||
| 150 | # undef FD_ISSET | ||
| 151 | # define FD_ISSET(fd, set) rpl_fd_isset(fd, set) | ||
| 152 | |||
| 153 | #endif | ||
| 154 | |||
| 155 | /* Hide some function declarations from <winsock2.h>. */ | ||
| 156 | |||
| 157 | #if @HAVE_WINSOCK2_H@ | ||
| 158 | # if !defined _@GUARD_PREFIX@_UNISTD_H | ||
| 159 | # if !(defined __cplusplus && defined GNULIB_NAMESPACE) | ||
| 160 | # undef close | ||
| 161 | # define close close_used_without_including_unistd_h | ||
| 162 | # else | ||
| 163 | _GL_WARN_ON_USE (close, | ||
| 164 | "close() used without including <unistd.h>"); | ||
| 165 | # endif | ||
| 166 | # if !(defined __cplusplus && defined GNULIB_NAMESPACE) | ||
| 167 | # undef gethostname | ||
| 168 | # define gethostname gethostname_used_without_including_unistd_h | ||
| 169 | # else | ||
| 170 | _GL_WARN_ON_USE (gethostname, | ||
| 171 | "gethostname() used without including <unistd.h>"); | ||
| 172 | # endif | ||
| 173 | # endif | ||
| 174 | # if !defined _@GUARD_PREFIX@_SYS_SOCKET_H | ||
| 175 | # if !(defined __cplusplus && defined GNULIB_NAMESPACE) | ||
| 176 | # undef socket | ||
| 177 | # define socket socket_used_without_including_sys_socket_h | ||
| 178 | # undef connect | ||
| 179 | # define connect connect_used_without_including_sys_socket_h | ||
| 180 | # undef accept | ||
| 181 | # define accept accept_used_without_including_sys_socket_h | ||
| 182 | # undef bind | ||
| 183 | # define bind bind_used_without_including_sys_socket_h | ||
| 184 | # undef getpeername | ||
| 185 | # define getpeername getpeername_used_without_including_sys_socket_h | ||
| 186 | # undef getsockname | ||
| 187 | # define getsockname getsockname_used_without_including_sys_socket_h | ||
| 188 | # undef getsockopt | ||
| 189 | # define getsockopt getsockopt_used_without_including_sys_socket_h | ||
| 190 | # undef listen | ||
| 191 | # define listen listen_used_without_including_sys_socket_h | ||
| 192 | # undef recv | ||
| 193 | # define recv recv_used_without_including_sys_socket_h | ||
| 194 | # undef send | ||
| 195 | # define send send_used_without_including_sys_socket_h | ||
| 196 | # undef recvfrom | ||
| 197 | # define recvfrom recvfrom_used_without_including_sys_socket_h | ||
| 198 | # undef sendto | ||
| 199 | # define sendto sendto_used_without_including_sys_socket_h | ||
| 200 | # undef setsockopt | ||
| 201 | # define setsockopt setsockopt_used_without_including_sys_socket_h | ||
| 202 | # undef shutdown | ||
| 203 | # define shutdown shutdown_used_without_including_sys_socket_h | ||
| 204 | # else | ||
| 205 | _GL_WARN_ON_USE (socket, | ||
| 206 | "socket() used without including <sys/socket.h>"); | ||
| 207 | _GL_WARN_ON_USE (connect, | ||
| 208 | "connect() used without including <sys/socket.h>"); | ||
| 209 | _GL_WARN_ON_USE (accept, | ||
| 210 | "accept() used without including <sys/socket.h>"); | ||
| 211 | _GL_WARN_ON_USE (bind, | ||
| 212 | "bind() used without including <sys/socket.h>"); | ||
| 213 | _GL_WARN_ON_USE (getpeername, | ||
| 214 | "getpeername() used without including <sys/socket.h>"); | ||
| 215 | _GL_WARN_ON_USE (getsockname, | ||
| 216 | "getsockname() used without including <sys/socket.h>"); | ||
| 217 | _GL_WARN_ON_USE (getsockopt, | ||
| 218 | "getsockopt() used without including <sys/socket.h>"); | ||
| 219 | _GL_WARN_ON_USE (listen, | ||
| 220 | "listen() used without including <sys/socket.h>"); | ||
| 221 | _GL_WARN_ON_USE (recv, | ||
| 222 | "recv() used without including <sys/socket.h>"); | ||
| 223 | _GL_WARN_ON_USE (send, | ||
| 224 | "send() used without including <sys/socket.h>"); | ||
| 225 | _GL_WARN_ON_USE (recvfrom, | ||
| 226 | "recvfrom() used without including <sys/socket.h>"); | ||
| 227 | _GL_WARN_ON_USE (sendto, | ||
| 228 | "sendto() used without including <sys/socket.h>"); | ||
| 229 | _GL_WARN_ON_USE (setsockopt, | ||
| 230 | "setsockopt() used without including <sys/socket.h>"); | ||
| 231 | _GL_WARN_ON_USE (shutdown, | ||
| 232 | "shutdown() used without including <sys/socket.h>"); | ||
| 233 | # endif | ||
| 234 | # endif | ||
| 235 | #endif | ||
| 236 | |||
| 237 | |||
| 238 | #if @GNULIB_PSELECT@ | ||
| 239 | # if @REPLACE_PSELECT@ | ||
| 240 | # if !(defined __cplusplus && defined GNULIB_NAMESPACE) | ||
| 241 | # undef pselect | ||
| 242 | # define pselect rpl_pselect | ||
| 243 | # endif | ||
| 244 | _GL_FUNCDECL_RPL (pselect, int, | ||
| 245 | (int, fd_set *restrict, fd_set *restrict, fd_set *restrict, | ||
| 246 | struct timespec const *restrict, const sigset_t *restrict)); | ||
| 247 | _GL_CXXALIAS_RPL (pselect, int, | ||
| 248 | (int, fd_set *restrict, fd_set *restrict, fd_set *restrict, | ||
| 249 | struct timespec const *restrict, const sigset_t *restrict)); | ||
| 250 | # else | ||
| 251 | # if !@HAVE_PSELECT@ | ||
| 252 | _GL_FUNCDECL_SYS (pselect, int, | ||
| 253 | (int, fd_set *restrict, fd_set *restrict, fd_set *restrict, | ||
| 254 | struct timespec const *restrict, const sigset_t *restrict)); | ||
| 255 | # endif | ||
| 256 | _GL_CXXALIAS_SYS (pselect, int, | ||
| 257 | (int, fd_set *restrict, fd_set *restrict, fd_set *restrict, | ||
| 258 | struct timespec const *restrict, const sigset_t *restrict)); | ||
| 259 | # endif | ||
| 260 | _GL_CXXALIASWARN (pselect); | ||
| 261 | #elif defined GNULIB_POSIXCHECK | ||
| 262 | # undef pselect | ||
| 263 | # if HAVE_RAW_DECL_PSELECT | ||
| 264 | _GL_WARN_ON_USE (pselect, "pselect is not portable - " | ||
| 265 | "use gnulib module pselect for portability"); | ||
| 266 | # endif | ||
| 267 | #endif | ||
| 268 | |||
| 269 | #if @GNULIB_SELECT@ | ||
| 270 | # if @REPLACE_SELECT@ | ||
| 271 | # if !(defined __cplusplus && defined GNULIB_NAMESPACE) | ||
| 272 | # undef select | ||
| 273 | # define select rpl_select | ||
| 274 | # endif | ||
| 275 | _GL_FUNCDECL_RPL (select, int, | ||
| 276 | (int, fd_set *, fd_set *, fd_set *, struct timeval *)); | ||
| 277 | _GL_CXXALIAS_RPL (select, int, | ||
| 278 | (int, fd_set *, fd_set *, fd_set *, struct timeval *)); | ||
| 279 | # else | ||
| 280 | _GL_CXXALIAS_SYS (select, int, | ||
| 281 | (int, fd_set *, fd_set *, fd_set *, struct timeval *)); | ||
| 282 | # endif | ||
| 283 | _GL_CXXALIASWARN (select); | ||
| 284 | #elif @HAVE_WINSOCK2_H@ | ||
| 285 | # undef select | ||
| 286 | # define select select_used_without_requesting_gnulib_module_select | ||
| 287 | #elif defined GNULIB_POSIXCHECK | ||
| 288 | # undef select | ||
| 289 | # if HAVE_RAW_DECL_SELECT | ||
| 290 | _GL_WARN_ON_USE (select, "select is not always POSIX compliant - " | ||
| 291 | "use gnulib module select for portability"); | ||
| 292 | # endif | ||
| 293 | #endif | ||
| 294 | |||
| 295 | |||
| 296 | #endif /* _@GUARD_PREFIX@_SYS_SELECT_H */ | ||
| 297 | #endif /* _@GUARD_PREFIX@_SYS_SELECT_H */ | ||
| 298 | #endif /* OSF/1 */ | ||
diff --git a/lib/sys_time.in.h b/lib/sys_time.in.h new file mode 100644 index 00000000000..d915cee467a --- /dev/null +++ b/lib/sys_time.in.h | |||
| @@ -0,0 +1,205 @@ | |||
| 1 | /* Provide a more complete sys/time.h. | ||
| 2 | |||
| 3 | Copyright (C) 2007-2012 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This program is free software; you can redistribute it and/or modify | ||
| 6 | it under the terms of the GNU General Public License as published by | ||
| 7 | the Free Software Foundation; either version 3, or (at your option) | ||
| 8 | any later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program; if not, see <http://www.gnu.org/licenses/>. */ | ||
| 17 | |||
| 18 | /* Written by Paul Eggert. */ | ||
| 19 | |||
| 20 | #if __GNUC__ >= 3 | ||
| 21 | @PRAGMA_SYSTEM_HEADER@ | ||
| 22 | #endif | ||
| 23 | @PRAGMA_COLUMNS@ | ||
| 24 | |||
| 25 | #if defined _@GUARD_PREFIX@_SYS_TIME_H | ||
| 26 | |||
| 27 | /* Simply delegate to the system's header, without adding anything. */ | ||
| 28 | # if @HAVE_SYS_TIME_H@ | ||
| 29 | # @INCLUDE_NEXT@ @NEXT_SYS_TIME_H@ | ||
| 30 | # endif | ||
| 31 | |||
| 32 | #else | ||
| 33 | |||
| 34 | # define _@GUARD_PREFIX@_SYS_TIME_H | ||
| 35 | |||
| 36 | # if @HAVE_SYS_TIME_H@ | ||
| 37 | # @INCLUDE_NEXT@ @NEXT_SYS_TIME_H@ | ||
| 38 | # else | ||
| 39 | # include <time.h> | ||
| 40 | # endif | ||
| 41 | |||
| 42 | /* On native Windows with MSVC, get the 'struct timeval' type. | ||
| 43 | Also, on native Windows with a 64-bit time_t, where we are overriding the | ||
| 44 | 'struct timeval' type, get all declarations of system functions whose | ||
| 45 | signature contains 'struct timeval'. */ | ||
| 46 | # if (defined _MSC_VER || @REPLACE_STRUCT_TIMEVAL@) && @HAVE_WINSOCK2_H@ && !defined _GL_INCLUDING_WINSOCK2_H | ||
| 47 | # define _GL_INCLUDING_WINSOCK2_H | ||
| 48 | # include <winsock2.h> | ||
| 49 | # undef _GL_INCLUDING_WINSOCK2_H | ||
| 50 | # endif | ||
| 51 | |||
| 52 | /* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ | ||
| 53 | |||
| 54 | /* The definition of _GL_ARG_NONNULL is copied here. */ | ||
| 55 | |||
| 56 | /* The definition of _GL_WARN_ON_USE is copied here. */ | ||
| 57 | |||
| 58 | # ifdef __cplusplus | ||
| 59 | extern "C" { | ||
| 60 | # endif | ||
| 61 | |||
| 62 | # if !@HAVE_STRUCT_TIMEVAL@ || @REPLACE_STRUCT_TIMEVAL@ | ||
| 63 | |||
| 64 | # if @REPLACE_STRUCT_TIMEVAL@ | ||
| 65 | # define timeval rpl_timeval | ||
| 66 | # endif | ||
| 67 | |||
| 68 | # if !GNULIB_defined_struct_timeval | ||
| 69 | struct timeval | ||
| 70 | { | ||
| 71 | time_t tv_sec; | ||
| 72 | long int tv_usec; | ||
| 73 | }; | ||
| 74 | # define GNULIB_defined_struct_timeval 1 | ||
| 75 | # endif | ||
| 76 | |||
| 77 | # endif | ||
| 78 | |||
| 79 | # ifdef __cplusplus | ||
| 80 | } | ||
| 81 | # endif | ||
| 82 | |||
| 83 | # if @GNULIB_GETTIMEOFDAY@ | ||
| 84 | # if @REPLACE_GETTIMEOFDAY@ | ||
| 85 | # if !(defined __cplusplus && defined GNULIB_NAMESPACE) | ||
| 86 | # undef gettimeofday | ||
| 87 | # define gettimeofday rpl_gettimeofday | ||
| 88 | # endif | ||
| 89 | _GL_FUNCDECL_RPL (gettimeofday, int, | ||
| 90 | (struct timeval *restrict, void *restrict) | ||
| 91 | _GL_ARG_NONNULL ((1))); | ||
| 92 | _GL_CXXALIAS_RPL (gettimeofday, int, | ||
| 93 | (struct timeval *restrict, void *restrict)); | ||
| 94 | # else | ||
| 95 | # if !@HAVE_GETTIMEOFDAY@ | ||
| 96 | _GL_FUNCDECL_SYS (gettimeofday, int, | ||
| 97 | (struct timeval *restrict, void *restrict) | ||
| 98 | _GL_ARG_NONNULL ((1))); | ||
| 99 | # endif | ||
| 100 | /* Need to cast, because on glibc systems, by default, the second argument is | ||
| 101 | struct timezone *. */ | ||
| 102 | _GL_CXXALIAS_SYS_CAST (gettimeofday, int, | ||
| 103 | (struct timeval *restrict, void *restrict)); | ||
| 104 | # endif | ||
| 105 | _GL_CXXALIASWARN (gettimeofday); | ||
| 106 | # elif defined GNULIB_POSIXCHECK | ||
| 107 | # undef gettimeofday | ||
| 108 | # if HAVE_RAW_DECL_GETTIMEOFDAY | ||
| 109 | _GL_WARN_ON_USE (gettimeofday, "gettimeofday is unportable - " | ||
| 110 | "use gnulib module gettimeofday for portability"); | ||
| 111 | # endif | ||
| 112 | # endif | ||
| 113 | |||
| 114 | /* Hide some function declarations from <winsock2.h>. */ | ||
| 115 | |||
| 116 | # if defined _MSC_VER && @HAVE_WINSOCK2_H@ | ||
| 117 | # if !defined _@GUARD_PREFIX@_UNISTD_H | ||
| 118 | # if !(defined __cplusplus && defined GNULIB_NAMESPACE) | ||
| 119 | # undef close | ||
| 120 | # define close close_used_without_including_unistd_h | ||
| 121 | # else | ||
| 122 | _GL_WARN_ON_USE (close, | ||
| 123 | "close() used without including <unistd.h>"); | ||
| 124 | # endif | ||
| 125 | # if !(defined __cplusplus && defined GNULIB_NAMESPACE) | ||
| 126 | # undef gethostname | ||
| 127 | # define gethostname gethostname_used_without_including_unistd_h | ||
| 128 | # else | ||
| 129 | _GL_WARN_ON_USE (gethostname, | ||
| 130 | "gethostname() used without including <unistd.h>"); | ||
| 131 | # endif | ||
| 132 | # endif | ||
| 133 | # if !defined _@GUARD_PREFIX@_SYS_SOCKET_H | ||
| 134 | # if !(defined __cplusplus && defined GNULIB_NAMESPACE) | ||
| 135 | # undef socket | ||
| 136 | # define socket socket_used_without_including_sys_socket_h | ||
| 137 | # undef connect | ||
| 138 | # define connect connect_used_without_including_sys_socket_h | ||
| 139 | # undef accept | ||
| 140 | # define accept accept_used_without_including_sys_socket_h | ||
| 141 | # undef bind | ||
| 142 | # define bind bind_used_without_including_sys_socket_h | ||
| 143 | # undef getpeername | ||
| 144 | # define getpeername getpeername_used_without_including_sys_socket_h | ||
| 145 | # undef getsockname | ||
| 146 | # define getsockname getsockname_used_without_including_sys_socket_h | ||
| 147 | # undef getsockopt | ||
| 148 | # define getsockopt getsockopt_used_without_including_sys_socket_h | ||
| 149 | # undef listen | ||
| 150 | # define listen listen_used_without_including_sys_socket_h | ||
| 151 | # undef recv | ||
| 152 | # define recv recv_used_without_including_sys_socket_h | ||
| 153 | # undef send | ||
| 154 | # define send send_used_without_including_sys_socket_h | ||
| 155 | # undef recvfrom | ||
| 156 | # define recvfrom recvfrom_used_without_including_sys_socket_h | ||
| 157 | # undef sendto | ||
| 158 | # define sendto sendto_used_without_including_sys_socket_h | ||
| 159 | # undef setsockopt | ||
| 160 | # define setsockopt setsockopt_used_without_including_sys_socket_h | ||
| 161 | # undef shutdown | ||
| 162 | # define shutdown shutdown_used_without_including_sys_socket_h | ||
| 163 | # else | ||
| 164 | _GL_WARN_ON_USE (socket, | ||
| 165 | "socket() used without including <sys/socket.h>"); | ||
| 166 | _GL_WARN_ON_USE (connect, | ||
| 167 | "connect() used without including <sys/socket.h>"); | ||
| 168 | _GL_WARN_ON_USE (accept, | ||
| 169 | "accept() used without including <sys/socket.h>"); | ||
| 170 | _GL_WARN_ON_USE (bind, | ||
| 171 | "bind() used without including <sys/socket.h>"); | ||
| 172 | _GL_WARN_ON_USE (getpeername, | ||
| 173 | "getpeername() used without including <sys/socket.h>"); | ||
| 174 | _GL_WARN_ON_USE (getsockname, | ||
| 175 | "getsockname() used without including <sys/socket.h>"); | ||
| 176 | _GL_WARN_ON_USE (getsockopt, | ||
| 177 | "getsockopt() used without including <sys/socket.h>"); | ||
| 178 | _GL_WARN_ON_USE (listen, | ||
| 179 | "listen() used without including <sys/socket.h>"); | ||
| 180 | _GL_WARN_ON_USE (recv, | ||
| 181 | "recv() used without including <sys/socket.h>"); | ||
| 182 | _GL_WARN_ON_USE (send, | ||
| 183 | "send() used without including <sys/socket.h>"); | ||
| 184 | _GL_WARN_ON_USE (recvfrom, | ||
| 185 | "recvfrom() used without including <sys/socket.h>"); | ||
| 186 | _GL_WARN_ON_USE (sendto, | ||
| 187 | "sendto() used without including <sys/socket.h>"); | ||
| 188 | _GL_WARN_ON_USE (setsockopt, | ||
| 189 | "setsockopt() used without including <sys/socket.h>"); | ||
| 190 | _GL_WARN_ON_USE (shutdown, | ||
| 191 | "shutdown() used without including <sys/socket.h>"); | ||
| 192 | # endif | ||
| 193 | # endif | ||
| 194 | # if !defined _@GUARD_PREFIX@_SYS_SELECT_H | ||
| 195 | # if !(defined __cplusplus && defined GNULIB_NAMESPACE) | ||
| 196 | # undef select | ||
| 197 | # define select select_used_without_including_sys_select_h | ||
| 198 | # else | ||
| 199 | _GL_WARN_ON_USE (select, | ||
| 200 | "select() used without including <sys/select.h>"); | ||
| 201 | # endif | ||
| 202 | # endif | ||
| 203 | # endif | ||
| 204 | |||
| 205 | #endif /* _@GUARD_PREFIX@_SYS_TIME_H */ | ||
diff --git a/lib/timespec-add.c b/lib/timespec-add.c new file mode 100644 index 00000000000..4e5c641ac12 --- /dev/null +++ b/lib/timespec-add.c | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | /* Add two struct timespec values. | ||
| 2 | |||
| 3 | Copyright (C) 2011-2012 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This program is free software: you can redistribute it and/or modify | ||
| 6 | it under the terms of the GNU General Public License as published by | ||
| 7 | the Free Software Foundation; either version 3 of the License, or | ||
| 8 | (at your option) any later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 17 | |||
| 18 | /* Written by Paul Eggert. */ | ||
| 19 | |||
| 20 | /* Return the sum of two timespec values A and B. On overflow, return | ||
| 21 | an extremal value. This assumes 0 <= tv_nsec <= 999999999. */ | ||
| 22 | |||
| 23 | #include <config.h> | ||
| 24 | #include "timespec.h" | ||
| 25 | |||
| 26 | #include "intprops.h" | ||
| 27 | |||
| 28 | struct timespec | ||
| 29 | timespec_add (struct timespec a, struct timespec b) | ||
| 30 | { | ||
| 31 | struct timespec r; | ||
| 32 | time_t rs = a.tv_sec; | ||
| 33 | time_t bs = b.tv_sec; | ||
| 34 | int ns = a.tv_nsec + b.tv_nsec; | ||
| 35 | int nsd = ns - 1000000000; | ||
| 36 | int rns = ns; | ||
| 37 | |||
| 38 | if (0 <= nsd) | ||
| 39 | { | ||
| 40 | rns = nsd; | ||
| 41 | if (rs == TYPE_MAXIMUM (time_t)) | ||
| 42 | { | ||
| 43 | if (0 <= bs) | ||
| 44 | goto high_overflow; | ||
| 45 | bs++; | ||
| 46 | } | ||
| 47 | else | ||
| 48 | rs++; | ||
| 49 | } | ||
| 50 | |||
| 51 | if (INT_ADD_OVERFLOW (rs, bs)) | ||
| 52 | { | ||
| 53 | if (rs < 0) | ||
| 54 | { | ||
| 55 | rs = TYPE_MINIMUM (time_t); | ||
| 56 | rns = 0; | ||
| 57 | } | ||
| 58 | else | ||
| 59 | { | ||
| 60 | high_overflow: | ||
| 61 | rs = TYPE_MAXIMUM (time_t); | ||
| 62 | rns = 999999999; | ||
| 63 | } | ||
| 64 | } | ||
| 65 | else | ||
| 66 | rs += bs; | ||
| 67 | |||
| 68 | r.tv_sec = rs; | ||
| 69 | r.tv_nsec = rns; | ||
| 70 | return r; | ||
| 71 | } | ||
diff --git a/lib/timespec-sub.c b/lib/timespec-sub.c new file mode 100644 index 00000000000..0b3bb1b57e1 --- /dev/null +++ b/lib/timespec-sub.c | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | /* Subtract two struct timespec values. | ||
| 2 | |||
| 3 | Copyright (C) 2011-2012 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This program is free software: you can redistribute it and/or modify | ||
| 6 | it under the terms of the GNU General Public License as published by | ||
| 7 | the Free Software Foundation; either version 3 of the License, or | ||
| 8 | (at your option) any later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 17 | |||
| 18 | /* Written by Paul Eggert. */ | ||
| 19 | |||
| 20 | /* Return the difference between two timespec values A and B. On | ||
| 21 | overflow, return an extremal value. This assumes 0 <= tv_nsec <= | ||
| 22 | 999999999. */ | ||
| 23 | |||
| 24 | #include <config.h> | ||
| 25 | #include <config.h> | ||
| 26 | #include "timespec.h" | ||
| 27 | |||
| 28 | #include "intprops.h" | ||
| 29 | |||
| 30 | struct timespec | ||
| 31 | timespec_sub (struct timespec a, struct timespec b) | ||
| 32 | { | ||
| 33 | struct timespec r; | ||
| 34 | time_t rs = a.tv_sec; | ||
| 35 | time_t bs = b.tv_sec; | ||
| 36 | int ns = a.tv_nsec - b.tv_nsec; | ||
| 37 | int rns = ns; | ||
| 38 | |||
| 39 | if (ns < 0) | ||
| 40 | { | ||
| 41 | rns = ns + 1000000000; | ||
| 42 | if (rs == TYPE_MINIMUM (time_t)) | ||
| 43 | { | ||
| 44 | if (bs <= 0) | ||
| 45 | goto low_overflow; | ||
| 46 | bs--; | ||
| 47 | } | ||
| 48 | else | ||
| 49 | rs--; | ||
| 50 | } | ||
| 51 | |||
| 52 | if (INT_SUBTRACT_OVERFLOW (rs, bs)) | ||
| 53 | { | ||
| 54 | if (rs < 0) | ||
| 55 | { | ||
| 56 | low_overflow: | ||
| 57 | rs = TYPE_MINIMUM (time_t); | ||
| 58 | rns = 0; | ||
| 59 | } | ||
| 60 | else | ||
| 61 | { | ||
| 62 | rs = TYPE_MAXIMUM (time_t); | ||
| 63 | rns = 999999999; | ||
| 64 | } | ||
| 65 | } | ||
| 66 | else | ||
| 67 | rs -= bs; | ||
| 68 | |||
| 69 | r.tv_sec = rs; | ||
| 70 | r.tv_nsec = rns; | ||
| 71 | return r; | ||
| 72 | } | ||
diff --git a/lib/timespec.h b/lib/timespec.h new file mode 100644 index 00000000000..388ddb83a76 --- /dev/null +++ b/lib/timespec.h | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | /* timespec -- System time interface | ||
| 2 | |||
| 3 | Copyright (C) 2000, 2002, 2004-2005, 2007, 2009-2012 Free Software | ||
| 4 | Foundation, Inc. | ||
| 5 | |||
| 6 | This program is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 3 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 18 | |||
| 19 | #if ! defined TIMESPEC_H | ||
| 20 | # define TIMESPEC_H | ||
| 21 | |||
| 22 | # include <time.h> | ||
| 23 | |||
| 24 | /* Return negative, zero, positive if A < B, A == B, A > B, respectively. | ||
| 25 | |||
| 26 | For each time stamp T, this code assumes that either: | ||
| 27 | |||
| 28 | * T.tv_nsec is in the range 0..999999999; or | ||
| 29 | * T.tv_sec corresponds to a valid leap second on a host that supports | ||
| 30 | leap seconds, and T.tv_nsec is in the range 1000000000..1999999999; or | ||
| 31 | * T.tv_sec is the minimum time_t value and T.tv_nsec is -1; or | ||
| 32 | T.tv_sec is the maximum time_t value and T.tv_nsec is 2000000000. | ||
| 33 | This allows for special struct timespec values that are less or | ||
| 34 | greater than all possible valid time stamps. | ||
| 35 | |||
| 36 | In all these cases, it is safe to subtract two tv_nsec values and | ||
| 37 | convert the result to integer without worrying about overflow on | ||
| 38 | any platform of interest to the GNU project, since all such | ||
| 39 | platforms have 32-bit int or wider. | ||
| 40 | |||
| 41 | Replacing "(int) (a.tv_nsec - b.tv_nsec)" with something like | ||
| 42 | "a.tv_nsec < b.tv_nsec ? -1 : a.tv_nsec > b.tv_nsec" would cause | ||
| 43 | this function to work in some cases where the above assumption is | ||
| 44 | violated, but not in all cases (e.g., a.tv_sec==1, a.tv_nsec==-2, | ||
| 45 | b.tv_sec==0, b.tv_nsec==999999999) and is arguably not worth the | ||
| 46 | extra instructions. Using a subtraction has the advantage of | ||
| 47 | detecting some invalid cases on platforms that detect integer | ||
| 48 | overflow. | ||
| 49 | |||
| 50 | The (int) cast avoids a gcc -Wconversion warning. */ | ||
| 51 | |||
| 52 | static inline int | ||
| 53 | timespec_cmp (struct timespec a, struct timespec b) | ||
| 54 | { | ||
| 55 | return (a.tv_sec < b.tv_sec ? -1 | ||
| 56 | : a.tv_sec > b.tv_sec ? 1 | ||
| 57 | : (int) (a.tv_nsec - b.tv_nsec)); | ||
| 58 | } | ||
| 59 | |||
| 60 | /* Return -1, 0, 1, depending on the sign of A. A.tv_nsec must be | ||
| 61 | nonnegative. */ | ||
| 62 | static inline int | ||
| 63 | timespec_sign (struct timespec a) | ||
| 64 | { | ||
| 65 | return a.tv_sec < 0 ? -1 : a.tv_sec || a.tv_nsec; | ||
| 66 | } | ||
| 67 | |||
| 68 | struct timespec timespec_add (struct timespec, struct timespec); | ||
| 69 | struct timespec timespec_sub (struct timespec, struct timespec); | ||
| 70 | struct timespec dtotimespec (double); | ||
| 71 | |||
| 72 | /* Return an approximation to A, of type 'double'. */ | ||
| 73 | static inline double | ||
| 74 | timespectod (struct timespec a) | ||
| 75 | { | ||
| 76 | return a.tv_sec + a.tv_nsec / 1e9; | ||
| 77 | } | ||
| 78 | |||
| 79 | void gettime (struct timespec *); | ||
| 80 | int settime (struct timespec const *); | ||
| 81 | |||
| 82 | #endif | ||
diff --git a/lib/utimens.c b/lib/utimens.c new file mode 100644 index 00000000000..c126b9551a6 --- /dev/null +++ b/lib/utimens.c | |||
| @@ -0,0 +1,533 @@ | |||
| 1 | /* Set file access and modification times. | ||
| 2 | |||
| 3 | Copyright (C) 2003-2012 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This program is free software: you can redistribute it and/or modify it | ||
| 6 | under the terms of the GNU General Public License as published by the | ||
| 7 | Free Software Foundation; either version 3 of the License, or any | ||
| 8 | later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 17 | |||
| 18 | /* Written by Paul Eggert. */ | ||
| 19 | |||
| 20 | /* derived from a function in touch.c */ | ||
| 21 | |||
| 22 | #include <config.h> | ||
| 23 | |||
| 24 | #include "utimens.h" | ||
| 25 | |||
| 26 | #include <assert.h> | ||
| 27 | #include <errno.h> | ||
| 28 | #include <fcntl.h> | ||
| 29 | #include <stdbool.h> | ||
| 30 | #include <sys/stat.h> | ||
| 31 | #include <sys/time.h> | ||
| 32 | #include <unistd.h> | ||
| 33 | |||
| 34 | #include "stat-time.h" | ||
| 35 | #include "timespec.h" | ||
| 36 | |||
| 37 | #if HAVE_UTIME_H | ||
| 38 | # include <utime.h> | ||
| 39 | #endif | ||
| 40 | |||
| 41 | /* Some systems (even some that do have <utime.h>) don't declare this | ||
| 42 | structure anywhere. */ | ||
| 43 | #ifndef HAVE_STRUCT_UTIMBUF | ||
| 44 | struct utimbuf | ||
| 45 | { | ||
| 46 | long actime; | ||
| 47 | long modtime; | ||
| 48 | }; | ||
| 49 | #endif | ||
| 50 | |||
| 51 | /* Avoid recursion with rpl_futimens or rpl_utimensat. */ | ||
| 52 | #undef futimens | ||
| 53 | #undef utimensat | ||
| 54 | |||
| 55 | /* Solaris 9 mistakenly succeeds when given a non-directory with a | ||
| 56 | trailing slash. Force the use of rpl_stat for a fix. */ | ||
| 57 | #ifndef REPLACE_FUNC_STAT_FILE | ||
| 58 | # define REPLACE_FUNC_STAT_FILE 0 | ||
| 59 | #endif | ||
| 60 | |||
| 61 | #if HAVE_UTIMENSAT || HAVE_FUTIMENS | ||
| 62 | /* Cache variables for whether the utimensat syscall works; used to | ||
| 63 | avoid calling the syscall if we know it will just fail with ENOSYS, | ||
| 64 | and to avoid unnecessary work in massaging timestamps if the | ||
| 65 | syscall will work. Multiple variables are needed, to distinguish | ||
| 66 | between the following scenarios on Linux: | ||
| 67 | utimensat doesn't exist, or is in glibc but kernel 2.6.18 fails with ENOSYS | ||
| 68 | kernel 2.6.22 and earlier rejects AT_SYMLINK_NOFOLLOW | ||
| 69 | kernel 2.6.25 and earlier reject UTIME_NOW/UTIME_OMIT with non-zero tv_sec | ||
| 70 | kernel 2.6.32 used with xfs or ntfs-3g fail to honor UTIME_OMIT | ||
| 71 | utimensat completely works | ||
| 72 | For each cache variable: 0 = unknown, 1 = yes, -1 = no. */ | ||
| 73 | static int utimensat_works_really; | ||
| 74 | static int lutimensat_works_really; | ||
| 75 | #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */ | ||
| 76 | |||
| 77 | /* Validate the requested timestamps. Return 0 if the resulting | ||
| 78 | timespec can be used for utimensat (after possibly modifying it to | ||
| 79 | work around bugs in utimensat). Return a positive value if the | ||
| 80 | timespec needs further adjustment based on stat results: 1 if any | ||
| 81 | adjustment is needed for utimes, and 2 if any adjustment is needed | ||
| 82 | for Linux utimensat. Return -1, with errno set to EINVAL, if | ||
| 83 | timespec is out of range. */ | ||
| 84 | static int | ||
| 85 | validate_timespec (struct timespec timespec[2]) | ||
| 86 | { | ||
| 87 | int result = 0; | ||
| 88 | int utime_omit_count = 0; | ||
| 89 | assert (timespec); | ||
| 90 | if ((timespec[0].tv_nsec != UTIME_NOW | ||
| 91 | && timespec[0].tv_nsec != UTIME_OMIT | ||
| 92 | && (timespec[0].tv_nsec < 0 || 1000000000 <= timespec[0].tv_nsec)) | ||
| 93 | || (timespec[1].tv_nsec != UTIME_NOW | ||
| 94 | && timespec[1].tv_nsec != UTIME_OMIT | ||
| 95 | && (timespec[1].tv_nsec < 0 || 1000000000 <= timespec[1].tv_nsec))) | ||
| 96 | { | ||
| 97 | errno = EINVAL; | ||
| 98 | return -1; | ||
| 99 | } | ||
| 100 | /* Work around Linux kernel 2.6.25 bug, where utimensat fails with | ||
| 101 | EINVAL if tv_sec is not 0 when using the flag values of tv_nsec. | ||
| 102 | Flag a Linux kernel 2.6.32 bug, where an mtime of UTIME_OMIT | ||
| 103 | fails to bump ctime. */ | ||
| 104 | if (timespec[0].tv_nsec == UTIME_NOW | ||
| 105 | || timespec[0].tv_nsec == UTIME_OMIT) | ||
| 106 | { | ||
| 107 | timespec[0].tv_sec = 0; | ||
| 108 | result = 1; | ||
| 109 | if (timespec[0].tv_nsec == UTIME_OMIT) | ||
| 110 | utime_omit_count++; | ||
| 111 | } | ||
| 112 | if (timespec[1].tv_nsec == UTIME_NOW | ||
| 113 | || timespec[1].tv_nsec == UTIME_OMIT) | ||
| 114 | { | ||
| 115 | timespec[1].tv_sec = 0; | ||
| 116 | result = 1; | ||
| 117 | if (timespec[1].tv_nsec == UTIME_OMIT) | ||
| 118 | utime_omit_count++; | ||
| 119 | } | ||
| 120 | return result + (utime_omit_count == 1); | ||
| 121 | } | ||
| 122 | |||
| 123 | /* Normalize any UTIME_NOW or UTIME_OMIT values in *TS, using stat | ||
| 124 | buffer STATBUF to obtain the current timestamps of the file. If | ||
| 125 | both times are UTIME_NOW, set *TS to NULL (as this can avoid some | ||
| 126 | permissions issues). If both times are UTIME_OMIT, return true | ||
| 127 | (nothing further beyond the prior collection of STATBUF is | ||
| 128 | necessary); otherwise return false. */ | ||
| 129 | static bool | ||
| 130 | update_timespec (struct stat const *statbuf, struct timespec *ts[2]) | ||
| 131 | { | ||
| 132 | struct timespec *timespec = *ts; | ||
| 133 | if (timespec[0].tv_nsec == UTIME_OMIT | ||
| 134 | && timespec[1].tv_nsec == UTIME_OMIT) | ||
| 135 | return true; | ||
| 136 | if (timespec[0].tv_nsec == UTIME_NOW | ||
| 137 | && timespec[1].tv_nsec == UTIME_NOW) | ||
| 138 | { | ||
| 139 | *ts = NULL; | ||
| 140 | return false; | ||
| 141 | } | ||
| 142 | |||
| 143 | if (timespec[0].tv_nsec == UTIME_OMIT) | ||
| 144 | timespec[0] = get_stat_atime (statbuf); | ||
| 145 | else if (timespec[0].tv_nsec == UTIME_NOW) | ||
| 146 | gettime (×pec[0]); | ||
| 147 | |||
| 148 | if (timespec[1].tv_nsec == UTIME_OMIT) | ||
| 149 | timespec[1] = get_stat_mtime (statbuf); | ||
| 150 | else if (timespec[1].tv_nsec == UTIME_NOW) | ||
| 151 | gettime (×pec[1]); | ||
| 152 | |||
| 153 | return false; | ||
| 154 | } | ||
| 155 | |||
| 156 | /* Set the access and modification time stamps of FD (a.k.a. FILE) to be | ||
| 157 | TIMESPEC[0] and TIMESPEC[1], respectively. | ||
| 158 | FD must be either negative -- in which case it is ignored -- | ||
| 159 | or a file descriptor that is open on FILE. | ||
| 160 | If FD is nonnegative, then FILE can be NULL, which means | ||
| 161 | use just futimes (or equivalent) instead of utimes (or equivalent), | ||
| 162 | and fail if on an old system without futimes (or equivalent). | ||
| 163 | If TIMESPEC is null, set the time stamps to the current time. | ||
| 164 | Return 0 on success, -1 (setting errno) on failure. */ | ||
| 165 | |||
| 166 | int | ||
| 167 | fdutimens (int fd, char const *file, struct timespec const timespec[2]) | ||
| 168 | { | ||
| 169 | struct timespec adjusted_timespec[2]; | ||
| 170 | struct timespec *ts = timespec ? adjusted_timespec : NULL; | ||
| 171 | int adjustment_needed = 0; | ||
| 172 | struct stat st; | ||
| 173 | |||
| 174 | if (ts) | ||
| 175 | { | ||
| 176 | adjusted_timespec[0] = timespec[0]; | ||
| 177 | adjusted_timespec[1] = timespec[1]; | ||
| 178 | adjustment_needed = validate_timespec (ts); | ||
| 179 | } | ||
| 180 | if (adjustment_needed < 0) | ||
| 181 | return -1; | ||
| 182 | |||
| 183 | /* Require that at least one of FD or FILE are potentially valid, to avoid | ||
| 184 | a Linux bug where futimens (AT_FDCWD, NULL) changes "." rather | ||
| 185 | than failing. */ | ||
| 186 | if (fd < 0 && !file) | ||
| 187 | { | ||
| 188 | errno = EBADF; | ||
| 189 | return -1; | ||
| 190 | } | ||
| 191 | |||
| 192 | /* Some Linux-based NFS clients are buggy, and mishandle time stamps | ||
| 193 | of files in NFS file systems in some cases. We have no | ||
| 194 | configure-time test for this, but please see | ||
| 195 | <http://bugs.gentoo.org/show_bug.cgi?id=132673> for references to | ||
| 196 | some of the problems with Linux 2.6.16. If this affects you, | ||
| 197 | compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to | ||
| 198 | help in some cases, albeit at a cost in performance. But you | ||
| 199 | really should upgrade your kernel to a fixed version, since the | ||
| 200 | problem affects many applications. */ | ||
| 201 | |||
| 202 | #if HAVE_BUGGY_NFS_TIME_STAMPS | ||
| 203 | if (fd < 0) | ||
| 204 | sync (); | ||
| 205 | else | ||
| 206 | fsync (fd); | ||
| 207 | #endif | ||
| 208 | |||
| 209 | /* POSIX 2008 added two interfaces to set file timestamps with | ||
| 210 | nanosecond resolution; newer Linux implements both functions via | ||
| 211 | a single syscall. We provide a fallback for ENOSYS (for example, | ||
| 212 | compiling against Linux 2.6.25 kernel headers and glibc 2.7, but | ||
| 213 | running on Linux 2.6.18 kernel). */ | ||
| 214 | #if HAVE_UTIMENSAT || HAVE_FUTIMENS | ||
| 215 | if (0 <= utimensat_works_really) | ||
| 216 | { | ||
| 217 | int result; | ||
| 218 | # if __linux__ | ||
| 219 | /* As recently as Linux kernel 2.6.32 (Dec 2009), several file | ||
| 220 | systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT, | ||
| 221 | but work if both times are either explicitly specified or | ||
| 222 | UTIME_NOW. Work around it with a preparatory [f]stat prior | ||
| 223 | to calling futimens/utimensat; fortunately, there is not much | ||
| 224 | timing impact due to the extra syscall even on file systems | ||
| 225 | where UTIME_OMIT would have worked. FIXME: Simplify this in | ||
| 226 | 2012, when file system bugs are no longer common. */ | ||
| 227 | if (adjustment_needed == 2) | ||
| 228 | { | ||
| 229 | if (fd < 0 ? stat (file, &st) : fstat (fd, &st)) | ||
| 230 | return -1; | ||
| 231 | if (ts[0].tv_nsec == UTIME_OMIT) | ||
| 232 | ts[0] = get_stat_atime (&st); | ||
| 233 | else if (ts[1].tv_nsec == UTIME_OMIT) | ||
| 234 | ts[1] = get_stat_mtime (&st); | ||
| 235 | /* Note that st is good, in case utimensat gives ENOSYS. */ | ||
| 236 | adjustment_needed++; | ||
| 237 | } | ||
| 238 | # endif /* __linux__ */ | ||
| 239 | # if HAVE_UTIMENSAT | ||
| 240 | if (fd < 0) | ||
| 241 | { | ||
| 242 | result = utimensat (AT_FDCWD, file, ts, 0); | ||
| 243 | # ifdef __linux__ | ||
| 244 | /* Work around a kernel bug: | ||
| 245 | http://bugzilla.redhat.com/442352 | ||
| 246 | http://bugzilla.redhat.com/449910 | ||
| 247 | It appears that utimensat can mistakenly return 280 rather | ||
| 248 | than -1 upon ENOSYS failure. | ||
| 249 | FIXME: remove in 2010 or whenever the offending kernels | ||
| 250 | are no longer in common use. */ | ||
| 251 | if (0 < result) | ||
| 252 | errno = ENOSYS; | ||
| 253 | # endif /* __linux__ */ | ||
| 254 | if (result == 0 || errno != ENOSYS) | ||
| 255 | { | ||
| 256 | utimensat_works_really = 1; | ||
| 257 | return result; | ||
| 258 | } | ||
| 259 | } | ||
| 260 | # endif /* HAVE_UTIMENSAT */ | ||
| 261 | # if HAVE_FUTIMENS | ||
| 262 | if (0 <= fd) | ||
| 263 | { | ||
| 264 | result = futimens (fd, ts); | ||
| 265 | # ifdef __linux__ | ||
| 266 | /* Work around the same bug as above. */ | ||
| 267 | if (0 < result) | ||
| 268 | errno = ENOSYS; | ||
| 269 | # endif /* __linux__ */ | ||
| 270 | if (result == 0 || errno != ENOSYS) | ||
| 271 | { | ||
| 272 | utimensat_works_really = 1; | ||
| 273 | return result; | ||
| 274 | } | ||
| 275 | } | ||
| 276 | # endif /* HAVE_FUTIMENS */ | ||
| 277 | } | ||
| 278 | utimensat_works_really = -1; | ||
| 279 | lutimensat_works_really = -1; | ||
| 280 | #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */ | ||
| 281 | |||
| 282 | /* The platform lacks an interface to set file timestamps with | ||
| 283 | nanosecond resolution, so do the best we can, discarding any | ||
| 284 | fractional part of the timestamp. */ | ||
| 285 | |||
| 286 | if (adjustment_needed || (REPLACE_FUNC_STAT_FILE && fd < 0)) | ||
| 287 | { | ||
| 288 | if (adjustment_needed != 3 | ||
| 289 | && (fd < 0 ? stat (file, &st) : fstat (fd, &st))) | ||
| 290 | return -1; | ||
| 291 | if (ts && update_timespec (&st, &ts)) | ||
| 292 | return 0; | ||
| 293 | } | ||
| 294 | |||
| 295 | { | ||
| 296 | #if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES | ||
| 297 | struct timeval timeval[2]; | ||
| 298 | struct timeval *t; | ||
| 299 | if (ts) | ||
| 300 | { | ||
| 301 | timeval[0].tv_sec = ts[0].tv_sec; | ||
| 302 | timeval[0].tv_usec = ts[0].tv_nsec / 1000; | ||
| 303 | timeval[1].tv_sec = ts[1].tv_sec; | ||
| 304 | timeval[1].tv_usec = ts[1].tv_nsec / 1000; | ||
| 305 | t = timeval; | ||
| 306 | } | ||
| 307 | else | ||
| 308 | t = NULL; | ||
| 309 | |||
| 310 | if (fd < 0) | ||
| 311 | { | ||
| 312 | # if HAVE_FUTIMESAT | ||
| 313 | return futimesat (AT_FDCWD, file, t); | ||
| 314 | # endif | ||
| 315 | } | ||
| 316 | else | ||
| 317 | { | ||
| 318 | /* If futimesat or futimes fails here, don't try to speed things | ||
| 319 | up by returning right away. glibc can incorrectly fail with | ||
| 320 | errno == ENOENT if /proc isn't mounted. Also, Mandrake 10.0 | ||
| 321 | in high security mode doesn't allow ordinary users to read | ||
| 322 | /proc/self, so glibc incorrectly fails with errno == EACCES. | ||
| 323 | If errno == EIO, EPERM, or EROFS, it's probably safe to fail | ||
| 324 | right away, but these cases are rare enough that they're not | ||
| 325 | worth optimizing, and who knows what other messed-up systems | ||
| 326 | are out there? So play it safe and fall back on the code | ||
| 327 | below. */ | ||
| 328 | |||
| 329 | # if (HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) || HAVE_FUTIMES | ||
| 330 | # if HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG | ||
| 331 | # undef futimes | ||
| 332 | # define futimes(fd, t) futimesat (fd, NULL, t) | ||
| 333 | # endif | ||
| 334 | if (futimes (fd, t) == 0) | ||
| 335 | { | ||
| 336 | # if __linux__ && __GLIBC__ | ||
| 337 | /* Work around a longstanding glibc bug, still present as | ||
| 338 | of 2010-12-27. On older Linux kernels that lack both | ||
| 339 | utimensat and utimes, glibc's futimes rounds instead of | ||
| 340 | truncating when falling back on utime. The same bug | ||
| 341 | occurs in futimesat with a null 2nd arg. */ | ||
| 342 | if (t) | ||
| 343 | { | ||
| 344 | bool abig = 500000 <= t[0].tv_usec; | ||
| 345 | bool mbig = 500000 <= t[1].tv_usec; | ||
| 346 | if ((abig | mbig) && fstat (fd, &st) == 0) | ||
| 347 | { | ||
| 348 | /* If these two subtractions overflow, they'll | ||
| 349 | track the overflows inside the buggy glibc. */ | ||
| 350 | time_t adiff = st.st_atime - t[0].tv_sec; | ||
| 351 | time_t mdiff = st.st_mtime - t[1].tv_sec; | ||
| 352 | |||
| 353 | struct timeval *tt = NULL; | ||
| 354 | struct timeval truncated_timeval[2]; | ||
| 355 | truncated_timeval[0] = t[0]; | ||
| 356 | truncated_timeval[1] = t[1]; | ||
| 357 | if (abig && adiff == 1 && get_stat_atime_ns (&st) == 0) | ||
| 358 | { | ||
| 359 | tt = truncated_timeval; | ||
| 360 | tt[0].tv_usec = 0; | ||
| 361 | } | ||
| 362 | if (mbig && mdiff == 1 && get_stat_mtime_ns (&st) == 0) | ||
| 363 | { | ||
| 364 | tt = truncated_timeval; | ||
| 365 | tt[1].tv_usec = 0; | ||
| 366 | } | ||
| 367 | if (tt) | ||
| 368 | futimes (fd, tt); | ||
| 369 | } | ||
| 370 | } | ||
| 371 | # endif | ||
| 372 | |||
| 373 | return 0; | ||
| 374 | } | ||
| 375 | # endif | ||
| 376 | } | ||
| 377 | #endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */ | ||
| 378 | |||
| 379 | if (!file) | ||
| 380 | { | ||
| 381 | #if ! ((HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) \ | ||
| 382 | || (HAVE_WORKING_UTIMES && HAVE_FUTIMES)) | ||
| 383 | errno = ENOSYS; | ||
| 384 | #endif | ||
| 385 | return -1; | ||
| 386 | } | ||
| 387 | |||
| 388 | #if HAVE_WORKING_UTIMES | ||
| 389 | return utimes (file, t); | ||
| 390 | #else | ||
| 391 | { | ||
| 392 | struct utimbuf utimbuf; | ||
| 393 | struct utimbuf *ut; | ||
| 394 | if (ts) | ||
| 395 | { | ||
| 396 | utimbuf.actime = ts[0].tv_sec; | ||
| 397 | utimbuf.modtime = ts[1].tv_sec; | ||
| 398 | ut = &utimbuf; | ||
| 399 | } | ||
| 400 | else | ||
| 401 | ut = NULL; | ||
| 402 | |||
| 403 | return utime (file, ut); | ||
| 404 | } | ||
| 405 | #endif /* !HAVE_WORKING_UTIMES */ | ||
| 406 | } | ||
| 407 | } | ||
| 408 | |||
| 409 | /* Set the access and modification time stamps of FILE to be | ||
| 410 | TIMESPEC[0] and TIMESPEC[1], respectively. */ | ||
| 411 | int | ||
| 412 | utimens (char const *file, struct timespec const timespec[2]) | ||
| 413 | { | ||
| 414 | return fdutimens (-1, file, timespec); | ||
| 415 | } | ||
| 416 | |||
| 417 | /* Set the access and modification time stamps of FILE to be | ||
| 418 | TIMESPEC[0] and TIMESPEC[1], respectively, without dereferencing | ||
| 419 | symlinks. Fail with ENOSYS if the platform does not support | ||
| 420 | changing symlink timestamps, but FILE was a symlink. */ | ||
| 421 | int | ||
| 422 | lutimens (char const *file, struct timespec const timespec[2]) | ||
| 423 | { | ||
| 424 | struct timespec adjusted_timespec[2]; | ||
| 425 | struct timespec *ts = timespec ? adjusted_timespec : NULL; | ||
| 426 | int adjustment_needed = 0; | ||
| 427 | struct stat st; | ||
| 428 | |||
| 429 | if (ts) | ||
| 430 | { | ||
| 431 | adjusted_timespec[0] = timespec[0]; | ||
| 432 | adjusted_timespec[1] = timespec[1]; | ||
| 433 | adjustment_needed = validate_timespec (ts); | ||
| 434 | } | ||
| 435 | if (adjustment_needed < 0) | ||
| 436 | return -1; | ||
| 437 | |||
| 438 | /* The Linux kernel did not support symlink timestamps until | ||
| 439 | utimensat, in version 2.6.22, so we don't need to mimic | ||
| 440 | fdutimens' worry about buggy NFS clients. But we do have to | ||
| 441 | worry about bogus return values. */ | ||
| 442 | |||
| 443 | #if HAVE_UTIMENSAT | ||
| 444 | if (0 <= lutimensat_works_really) | ||
| 445 | { | ||
| 446 | int result; | ||
| 447 | # if __linux__ | ||
| 448 | /* As recently as Linux kernel 2.6.32 (Dec 2009), several file | ||
| 449 | systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT, | ||
| 450 | but work if both times are either explicitly specified or | ||
| 451 | UTIME_NOW. Work around it with a preparatory lstat prior to | ||
| 452 | calling utimensat; fortunately, there is not much timing | ||
| 453 | impact due to the extra syscall even on file systems where | ||
| 454 | UTIME_OMIT would have worked. FIXME: Simplify this in 2012, | ||
| 455 | when file system bugs are no longer common. */ | ||
| 456 | if (adjustment_needed == 2) | ||
| 457 | { | ||
| 458 | if (lstat (file, &st)) | ||
| 459 | return -1; | ||
| 460 | if (ts[0].tv_nsec == UTIME_OMIT) | ||
| 461 | ts[0] = get_stat_atime (&st); | ||
| 462 | else if (ts[1].tv_nsec == UTIME_OMIT) | ||
| 463 | ts[1] = get_stat_mtime (&st); | ||
| 464 | /* Note that st is good, in case utimensat gives ENOSYS. */ | ||
| 465 | adjustment_needed++; | ||
| 466 | } | ||
| 467 | # endif /* __linux__ */ | ||
| 468 | result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW); | ||
| 469 | # ifdef __linux__ | ||
| 470 | /* Work around a kernel bug: | ||
| 471 | http://bugzilla.redhat.com/442352 | ||
| 472 | http://bugzilla.redhat.com/449910 | ||
| 473 | It appears that utimensat can mistakenly return 280 rather | ||
| 474 | than -1 upon ENOSYS failure. | ||
| 475 | FIXME: remove in 2010 or whenever the offending kernels | ||
| 476 | are no longer in common use. */ | ||
| 477 | if (0 < result) | ||
| 478 | errno = ENOSYS; | ||
| 479 | # endif | ||
| 480 | if (result == 0 || errno != ENOSYS) | ||
| 481 | { | ||
| 482 | utimensat_works_really = 1; | ||
| 483 | lutimensat_works_really = 1; | ||
| 484 | return result; | ||
| 485 | } | ||
| 486 | } | ||
| 487 | lutimensat_works_really = -1; | ||
| 488 | #endif /* HAVE_UTIMENSAT */ | ||
| 489 | |||
| 490 | /* The platform lacks an interface to set file timestamps with | ||
| 491 | nanosecond resolution, so do the best we can, discarding any | ||
| 492 | fractional part of the timestamp. */ | ||
| 493 | |||
| 494 | if (adjustment_needed || REPLACE_FUNC_STAT_FILE) | ||
| 495 | { | ||
| 496 | if (adjustment_needed != 3 && lstat (file, &st)) | ||
| 497 | return -1; | ||
| 498 | if (ts && update_timespec (&st, &ts)) | ||
| 499 | return 0; | ||
| 500 | } | ||
| 501 | |||
| 502 | /* On Linux, lutimes is a thin wrapper around utimensat, so there is | ||
| 503 | no point trying lutimes if utimensat failed with ENOSYS. */ | ||
| 504 | #if HAVE_LUTIMES && !HAVE_UTIMENSAT | ||
| 505 | { | ||
| 506 | struct timeval timeval[2]; | ||
| 507 | struct timeval *t; | ||
| 508 | int result; | ||
| 509 | if (ts) | ||
| 510 | { | ||
| 511 | timeval[0].tv_sec = ts[0].tv_sec; | ||
| 512 | timeval[0].tv_usec = ts[0].tv_nsec / 1000; | ||
| 513 | timeval[1].tv_sec = ts[1].tv_sec; | ||
| 514 | timeval[1].tv_usec = ts[1].tv_nsec / 1000; | ||
| 515 | t = timeval; | ||
| 516 | } | ||
| 517 | else | ||
| 518 | t = NULL; | ||
| 519 | |||
| 520 | result = lutimes (file, t); | ||
| 521 | if (result == 0 || errno != ENOSYS) | ||
| 522 | return result; | ||
| 523 | } | ||
| 524 | #endif /* HAVE_LUTIMES && !HAVE_UTIMENSAT */ | ||
| 525 | |||
| 526 | /* Out of luck for symlinks, but we still handle regular files. */ | ||
| 527 | if (!(adjustment_needed || REPLACE_FUNC_STAT_FILE) && lstat (file, &st)) | ||
| 528 | return -1; | ||
| 529 | if (!S_ISLNK (st.st_mode)) | ||
| 530 | return fdutimens (-1, file, ts); | ||
| 531 | errno = ENOSYS; | ||
| 532 | return -1; | ||
| 533 | } | ||
diff --git a/lib/utimens.h b/lib/utimens.h new file mode 100644 index 00000000000..8c47cf93f88 --- /dev/null +++ b/lib/utimens.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | #include <time.h> | ||
| 2 | int fdutimens (int, char const *, struct timespec const [2]); | ||
| 3 | int utimens (char const *, struct timespec const [2]); | ||
| 4 | int lutimens (char const *, struct timespec const [2]); | ||
| 5 | |||
| 6 | #if GNULIB_FDUTIMENSAT | ||
| 7 | # include <fcntl.h> | ||
| 8 | # include <sys/stat.h> | ||
| 9 | |||
| 10 | int fdutimensat (int fd, int dir, char const *name, struct timespec const [2], | ||
| 11 | int atflag); | ||
| 12 | |||
| 13 | /* Using this function makes application code slightly more readable. */ | ||
| 14 | static inline int | ||
| 15 | lutimensat (int dir, char const *file, struct timespec const times[2]) | ||
| 16 | { | ||
| 17 | return utimensat (dir, file, times, AT_SYMLINK_NOFOLLOW); | ||
| 18 | } | ||
| 19 | #endif | ||