xfreopen need not depend on freopen-safer
[gnulib.git] / lib / utimens.c
blob34689bcd65566958e35e7fe3d759b86ed158ac80
1 /* Set file access and modification times.
3 Copyright (C) 2003-2019 Free Software Foundation, Inc.
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.
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.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 /* Written by Paul Eggert. */
20 /* derived from a function in touch.c */
22 #include <config.h>
24 #define _GL_UTIMENS_INLINE _GL_EXTERN_INLINE
25 #include "utimens.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 #include <utime.h>
35 #include "stat-time.h"
36 #include "timespec.h"
38 /* On native Windows, use SetFileTime; but avoid this when compiling
39 GNU Emacs, which arranges for this in some other way and which
40 defines WIN32_LEAN_AND_MEAN itself. */
42 #if defined _WIN32 && ! defined __CYGWIN__ && ! defined EMACS_CONFIGURATION
43 # define USE_SETFILETIME
44 # define WIN32_LEAN_AND_MEAN
45 # include <windows.h>
46 # if GNULIB_MSVC_NOTHROW
47 # include "msvc-nothrow.h"
48 # else
49 # include <io.h>
50 # endif
51 #endif
53 /* Avoid recursion with rpl_futimens or rpl_utimensat. */
54 #undef futimens
55 #undef utimensat
57 /* Solaris 9 mistakenly succeeds when given a non-directory with a
58 trailing slash. Force the use of rpl_stat for a fix. */
59 #ifndef REPLACE_FUNC_STAT_FILE
60 # define REPLACE_FUNC_STAT_FILE 0
61 #endif
63 #if HAVE_UTIMENSAT || HAVE_FUTIMENS
64 /* Cache variables for whether the utimensat syscall works; used to
65 avoid calling the syscall if we know it will just fail with ENOSYS,
66 and to avoid unnecessary work in massaging timestamps if the
67 syscall will work. Multiple variables are needed, to distinguish
68 between the following scenarios on Linux:
69 utimensat doesn't exist, or is in glibc but kernel 2.6.18 fails with ENOSYS
70 kernel 2.6.22 and earlier rejects AT_SYMLINK_NOFOLLOW
71 kernel 2.6.25 and earlier reject UTIME_NOW/UTIME_OMIT with non-zero tv_sec
72 kernel 2.6.32 used with xfs or ntfs-3g fail to honor UTIME_OMIT
73 utimensat completely works
74 For each cache variable: 0 = unknown, 1 = yes, -1 = no. */
75 static int utimensat_works_really;
76 static int lutimensat_works_really;
77 #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
79 /* Validate the requested timestamps. Return 0 if the resulting
80 timespec can be used for utimensat (after possibly modifying it to
81 work around bugs in utimensat). Return a positive value if the
82 timespec needs further adjustment based on stat results: 1 if any
83 adjustment is needed for utimes, and 2 if any adjustment is needed
84 for Linux utimensat. Return -1, with errno set to EINVAL, if
85 timespec is out of range. */
86 static int
87 validate_timespec (struct timespec timespec[2])
89 int result = 0;
90 int utime_omit_count = 0;
91 if ((timespec[0].tv_nsec != UTIME_NOW
92 && timespec[0].tv_nsec != UTIME_OMIT
93 && ! (0 <= timespec[0].tv_nsec
94 && timespec[0].tv_nsec < TIMESPEC_HZ))
95 || (timespec[1].tv_nsec != UTIME_NOW
96 && timespec[1].tv_nsec != UTIME_OMIT
97 && ! (0 <= timespec[1].tv_nsec
98 && timespec[1].tv_nsec < TIMESPEC_HZ)))
100 errno = EINVAL;
101 return -1;
103 /* Work around Linux kernel 2.6.25 bug, where utimensat fails with
104 EINVAL if tv_sec is not 0 when using the flag values of tv_nsec.
105 Flag a Linux kernel 2.6.32 bug, where an mtime of UTIME_OMIT
106 fails to bump ctime. */
107 if (timespec[0].tv_nsec == UTIME_NOW
108 || timespec[0].tv_nsec == UTIME_OMIT)
110 timespec[0].tv_sec = 0;
111 result = 1;
112 if (timespec[0].tv_nsec == UTIME_OMIT)
113 utime_omit_count++;
115 if (timespec[1].tv_nsec == UTIME_NOW
116 || timespec[1].tv_nsec == UTIME_OMIT)
118 timespec[1].tv_sec = 0;
119 result = 1;
120 if (timespec[1].tv_nsec == UTIME_OMIT)
121 utime_omit_count++;
123 return result + (utime_omit_count == 1);
126 /* Normalize any UTIME_NOW or UTIME_OMIT values in *TS, using stat
127 buffer STATBUF to obtain the current timestamps of the file. If
128 both times are UTIME_NOW, set *TS to NULL (as this can avoid some
129 permissions issues). If both times are UTIME_OMIT, return true
130 (nothing further beyond the prior collection of STATBUF is
131 necessary); otherwise return false. */
132 static bool
133 update_timespec (struct stat const *statbuf, struct timespec *ts[2])
135 struct timespec *timespec = *ts;
136 if (timespec[0].tv_nsec == UTIME_OMIT
137 && timespec[1].tv_nsec == UTIME_OMIT)
138 return true;
139 if (timespec[0].tv_nsec == UTIME_NOW
140 && timespec[1].tv_nsec == UTIME_NOW)
142 *ts = NULL;
143 return false;
146 if (timespec[0].tv_nsec == UTIME_OMIT)
147 timespec[0] = get_stat_atime (statbuf);
148 else if (timespec[0].tv_nsec == UTIME_NOW)
149 gettime (&timespec[0]);
151 if (timespec[1].tv_nsec == UTIME_OMIT)
152 timespec[1] = get_stat_mtime (statbuf);
153 else if (timespec[1].tv_nsec == UTIME_NOW)
154 gettime (&timespec[1]);
156 return false;
159 /* Set the access and modification timestamps of FD (a.k.a. FILE) to be
160 TIMESPEC[0] and TIMESPEC[1], respectively.
161 FD must be either negative -- in which case it is ignored --
162 or a file descriptor that is open on FILE.
163 If FD is nonnegative, then FILE can be NULL, which means
164 use just futimes (or equivalent) instead of utimes (or equivalent),
165 and fail if on an old system without futimes (or equivalent).
166 If TIMESPEC is null, set the timestamps to the current time.
167 Return 0 on success, -1 (setting errno) on failure. */
170 fdutimens (int fd, char const *file, struct timespec const timespec[2])
172 struct timespec adjusted_timespec[2];
173 struct timespec *ts = timespec ? adjusted_timespec : NULL;
174 int adjustment_needed = 0;
175 struct stat st;
177 if (ts)
179 adjusted_timespec[0] = timespec[0];
180 adjusted_timespec[1] = timespec[1];
181 adjustment_needed = validate_timespec (ts);
183 if (adjustment_needed < 0)
184 return -1;
186 /* Require that at least one of FD or FILE are potentially valid, to avoid
187 a Linux bug where futimens (AT_FDCWD, NULL) changes "." rather
188 than failing. */
189 if (fd < 0 && !file)
191 errno = EBADF;
192 return -1;
195 /* Some Linux-based NFS clients are buggy, and mishandle timestamps
196 of files in NFS file systems in some cases. We have no
197 configure-time test for this, but please see
198 <https://bugs.gentoo.org/show_bug.cgi?id=132673> for references to
199 some of the problems with Linux 2.6.16. If this affects you,
200 compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to
201 help in some cases, albeit at a cost in performance. But you
202 really should upgrade your kernel to a fixed version, since the
203 problem affects many applications. */
205 #if HAVE_BUGGY_NFS_TIME_STAMPS
206 if (fd < 0)
207 sync ();
208 else
209 fsync (fd);
210 #endif
212 /* POSIX 2008 added two interfaces to set file timestamps with
213 nanosecond resolution; newer Linux implements both functions via
214 a single syscall. We provide a fallback for ENOSYS (for example,
215 compiling against Linux 2.6.25 kernel headers and glibc 2.7, but
216 running on Linux 2.6.18 kernel). */
217 #if HAVE_UTIMENSAT || HAVE_FUTIMENS
218 if (0 <= utimensat_works_really)
220 int result;
221 # if __linux__ || __sun
222 /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
223 systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
224 but work if both times are either explicitly specified or
225 UTIME_NOW. Work around it with a preparatory [f]stat prior
226 to calling futimens/utimensat; fortunately, there is not much
227 timing impact due to the extra syscall even on file systems
228 where UTIME_OMIT would have worked.
230 The same bug occurs in Solaris 11.1 (Apr 2013).
232 FIXME: Simplify this for Linux in 2016 and for Solaris in
233 2024, when file system bugs are no longer common. */
234 if (adjustment_needed == 2)
236 if (fd < 0 ? stat (file, &st) : fstat (fd, &st))
237 return -1;
238 if (ts[0].tv_nsec == UTIME_OMIT)
239 ts[0] = get_stat_atime (&st);
240 else if (ts[1].tv_nsec == UTIME_OMIT)
241 ts[1] = get_stat_mtime (&st);
242 /* Note that st is good, in case utimensat gives ENOSYS. */
243 adjustment_needed++;
245 # endif
246 # if HAVE_UTIMENSAT
247 if (fd < 0)
249 result = utimensat (AT_FDCWD, file, ts, 0);
250 # ifdef __linux__
251 /* Work around a kernel bug:
252 https://bugzilla.redhat.com/show_bug.cgi?id=442352
253 https://bugzilla.redhat.com/show_bug.cgi?id=449910
254 It appears that utimensat can mistakenly return 280 rather
255 than -1 upon ENOSYS failure.
256 FIXME: remove in 2010 or whenever the offending kernels
257 are no longer in common use. */
258 if (0 < result)
259 errno = ENOSYS;
260 # endif /* __linux__ */
261 if (result == 0 || errno != ENOSYS)
263 utimensat_works_really = 1;
264 return result;
267 # endif /* HAVE_UTIMENSAT */
268 # if HAVE_FUTIMENS
269 if (0 <= fd)
271 result = futimens (fd, ts);
272 # ifdef __linux__
273 /* Work around the same bug as above. */
274 if (0 < result)
275 errno = ENOSYS;
276 # endif /* __linux__ */
277 if (result == 0 || errno != ENOSYS)
279 utimensat_works_really = 1;
280 return result;
283 # endif /* HAVE_FUTIMENS */
285 utimensat_works_really = -1;
286 lutimensat_works_really = -1;
287 #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
289 #ifdef USE_SETFILETIME
290 /* On native Windows, use SetFileTime(). See
291 <https://msdn.microsoft.com/en-us/library/ms724933.aspx>
292 <https://msdn.microsoft.com/en-us/library/ms724284.aspx> */
293 if (0 <= fd)
295 HANDLE handle;
296 FILETIME current_time;
297 FILETIME last_access_time;
298 FILETIME last_write_time;
300 handle = (HANDLE) _get_osfhandle (fd);
301 if (handle == INVALID_HANDLE_VALUE)
303 errno = EBADF;
304 return -1;
307 if (ts == NULL || ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW)
309 /* GetSystemTimeAsFileTime
310 <https://msdn.microsoft.com/en-us/library/ms724397.aspx>.
311 It would be overkill to use
312 GetSystemTimePreciseAsFileTime
313 <https://msdn.microsoft.com/en-us/library/hh706895.aspx>. */
314 GetSystemTimeAsFileTime (&current_time);
317 if (ts == NULL || ts[0].tv_nsec == UTIME_NOW)
319 last_access_time = current_time;
321 else if (ts[0].tv_nsec == UTIME_OMIT)
323 last_access_time.dwLowDateTime = 0;
324 last_access_time.dwHighDateTime = 0;
326 else
328 ULONGLONG time_since_16010101 =
329 (ULONGLONG) ts[0].tv_sec * 10000000 + ts[0].tv_nsec / 100 + 116444736000000000LL;
330 last_access_time.dwLowDateTime = (DWORD) time_since_16010101;
331 last_access_time.dwHighDateTime = time_since_16010101 >> 32;
334 if (ts == NULL || ts[1].tv_nsec == UTIME_NOW)
336 last_write_time = current_time;
338 else if (ts[1].tv_nsec == UTIME_OMIT)
340 last_write_time.dwLowDateTime = 0;
341 last_write_time.dwHighDateTime = 0;
343 else
345 ULONGLONG time_since_16010101 =
346 (ULONGLONG) ts[1].tv_sec * 10000000 + ts[1].tv_nsec / 100 + 116444736000000000LL;
347 last_write_time.dwLowDateTime = (DWORD) time_since_16010101;
348 last_write_time.dwHighDateTime = time_since_16010101 >> 32;
351 if (SetFileTime (handle, NULL, &last_access_time, &last_write_time))
352 return 0;
353 else
355 DWORD sft_error = GetLastError ();
356 #if 0
357 fprintf (stderr, "fdutimens SetFileTime error 0x%x\n", (unsigned int) sft_error);
358 #endif
359 switch (sft_error)
361 case ERROR_ACCESS_DENIED: /* fd was opened without O_RDWR */
362 errno = EACCES; /* not specified by POSIX */
363 break;
364 default:
365 errno = EINVAL;
366 break;
368 return -1;
371 #endif
373 /* The platform lacks an interface to set file timestamps with
374 nanosecond resolution, so do the best we can, discarding any
375 fractional part of the timestamp. */
377 if (adjustment_needed || (REPLACE_FUNC_STAT_FILE && fd < 0))
379 if (adjustment_needed != 3
380 && (fd < 0 ? stat (file, &st) : fstat (fd, &st)))
381 return -1;
382 if (ts && update_timespec (&st, &ts))
383 return 0;
387 #if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
388 struct timeval timeval[2];
389 struct timeval *t;
390 if (ts)
392 timeval[0].tv_sec = ts[0].tv_sec;
393 timeval[0].tv_usec = ts[0].tv_nsec / 1000;
394 timeval[1].tv_sec = ts[1].tv_sec;
395 timeval[1].tv_usec = ts[1].tv_nsec / 1000;
396 t = timeval;
398 else
399 t = NULL;
401 if (fd < 0)
403 # if HAVE_FUTIMESAT
404 return futimesat (AT_FDCWD, file, t);
405 # endif
407 else
409 /* If futimesat or futimes fails here, don't try to speed things
410 up by returning right away. glibc can incorrectly fail with
411 errno == ENOENT if /proc isn't mounted. Also, Mandrake 10.0
412 in high security mode doesn't allow ordinary users to read
413 /proc/self, so glibc incorrectly fails with errno == EACCES.
414 If errno == EIO, EPERM, or EROFS, it's probably safe to fail
415 right away, but these cases are rare enough that they're not
416 worth optimizing, and who knows what other messed-up systems
417 are out there? So play it safe and fall back on the code
418 below. */
420 # if (HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) || HAVE_FUTIMES
421 # if HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG
422 # undef futimes
423 # define futimes(fd, t) futimesat (fd, NULL, t)
424 # endif
425 if (futimes (fd, t) == 0)
427 # if __linux__ && __GLIBC__
428 /* Work around a longstanding glibc bug, still present as
429 of 2010-12-27. On older Linux kernels that lack both
430 utimensat and utimes, glibc's futimes rounds instead of
431 truncating when falling back on utime. The same bug
432 occurs in futimesat with a null 2nd arg. */
433 if (t)
435 bool abig = 500000 <= t[0].tv_usec;
436 bool mbig = 500000 <= t[1].tv_usec;
437 if ((abig | mbig) && fstat (fd, &st) == 0)
439 /* If these two subtractions overflow, they'll
440 track the overflows inside the buggy glibc. */
441 time_t adiff = st.st_atime - t[0].tv_sec;
442 time_t mdiff = st.st_mtime - t[1].tv_sec;
444 struct timeval *tt = NULL;
445 struct timeval truncated_timeval[2];
446 truncated_timeval[0] = t[0];
447 truncated_timeval[1] = t[1];
448 if (abig && adiff == 1 && get_stat_atime_ns (&st) == 0)
450 tt = truncated_timeval;
451 tt[0].tv_usec = 0;
453 if (mbig && mdiff == 1 && get_stat_mtime_ns (&st) == 0)
455 tt = truncated_timeval;
456 tt[1].tv_usec = 0;
458 if (tt)
459 futimes (fd, tt);
462 # endif
464 return 0;
466 # endif
468 #endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */
470 if (!file)
472 #if ! ((HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) \
473 || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
474 errno = ENOSYS;
475 #endif
476 return -1;
479 #ifdef USE_SETFILETIME
480 return _gl_utimens_windows (file, ts);
481 #elif HAVE_WORKING_UTIMES
482 return utimes (file, t);
483 #else
485 struct utimbuf utimbuf;
486 struct utimbuf *ut;
487 if (ts)
489 utimbuf.actime = ts[0].tv_sec;
490 utimbuf.modtime = ts[1].tv_sec;
491 ut = &utimbuf;
493 else
494 ut = NULL;
496 return utime (file, ut);
498 #endif /* !HAVE_WORKING_UTIMES */
502 /* Set the access and modification timestamps of FILE to be
503 TIMESPEC[0] and TIMESPEC[1], respectively. */
505 utimens (char const *file, struct timespec const timespec[2])
507 return fdutimens (-1, file, timespec);
510 /* Set the access and modification timestamps of FILE to be
511 TIMESPEC[0] and TIMESPEC[1], respectively, without dereferencing
512 symlinks. Fail with ENOSYS if the platform does not support
513 changing symlink timestamps, but FILE was a symlink. */
515 lutimens (char const *file, struct timespec const timespec[2])
517 struct timespec adjusted_timespec[2];
518 struct timespec *ts = timespec ? adjusted_timespec : NULL;
519 int adjustment_needed = 0;
520 struct stat st;
522 if (ts)
524 adjusted_timespec[0] = timespec[0];
525 adjusted_timespec[1] = timespec[1];
526 adjustment_needed = validate_timespec (ts);
528 if (adjustment_needed < 0)
529 return -1;
531 /* The Linux kernel did not support symlink timestamps until
532 utimensat, in version 2.6.22, so we don't need to mimic
533 fdutimens' worry about buggy NFS clients. But we do have to
534 worry about bogus return values. */
536 #if HAVE_UTIMENSAT
537 if (0 <= lutimensat_works_really)
539 int result;
540 # if __linux__ || __sun
541 /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
542 systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
543 but work if both times are either explicitly specified or
544 UTIME_NOW. Work around it with a preparatory lstat prior to
545 calling utimensat; fortunately, there is not much timing
546 impact due to the extra syscall even on file systems where
547 UTIME_OMIT would have worked.
549 The same bug occurs in Solaris 11.1 (Apr 2013).
551 FIXME: Simplify this for Linux in 2016 and for Solaris in
552 2024, when file system bugs are no longer common. */
553 if (adjustment_needed == 2)
555 if (lstat (file, &st))
556 return -1;
557 if (ts[0].tv_nsec == UTIME_OMIT)
558 ts[0] = get_stat_atime (&st);
559 else if (ts[1].tv_nsec == UTIME_OMIT)
560 ts[1] = get_stat_mtime (&st);
561 /* Note that st is good, in case utimensat gives ENOSYS. */
562 adjustment_needed++;
564 # endif
565 result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW);
566 # ifdef __linux__
567 /* Work around a kernel bug:
568 https://bugzilla.redhat.com/show_bug.cgi?id=442352
569 https://bugzilla.redhat.com/show_bug.cgi?id=449910
570 It appears that utimensat can mistakenly return 280 rather
571 than -1 upon ENOSYS failure.
572 FIXME: remove in 2010 or whenever the offending kernels
573 are no longer in common use. */
574 if (0 < result)
575 errno = ENOSYS;
576 # endif
577 if (result == 0 || errno != ENOSYS)
579 utimensat_works_really = 1;
580 lutimensat_works_really = 1;
581 return result;
584 lutimensat_works_really = -1;
585 #endif /* HAVE_UTIMENSAT */
587 /* The platform lacks an interface to set file timestamps with
588 nanosecond resolution, so do the best we can, discarding any
589 fractional part of the timestamp. */
591 if (adjustment_needed || REPLACE_FUNC_STAT_FILE)
593 if (adjustment_needed != 3 && lstat (file, &st))
594 return -1;
595 if (ts && update_timespec (&st, &ts))
596 return 0;
599 /* On Linux, lutimes is a thin wrapper around utimensat, so there is
600 no point trying lutimes if utimensat failed with ENOSYS. */
601 #if HAVE_LUTIMES && !HAVE_UTIMENSAT
603 struct timeval timeval[2];
604 struct timeval *t;
605 int result;
606 if (ts)
608 timeval[0].tv_sec = ts[0].tv_sec;
609 timeval[0].tv_usec = ts[0].tv_nsec / 1000;
610 timeval[1].tv_sec = ts[1].tv_sec;
611 timeval[1].tv_usec = ts[1].tv_nsec / 1000;
612 t = timeval;
614 else
615 t = NULL;
617 result = lutimes (file, t);
618 if (result == 0 || errno != ENOSYS)
619 return result;
621 #endif /* HAVE_LUTIMES && !HAVE_UTIMENSAT */
623 /* Out of luck for symlinks, but we still handle regular files. */
624 if (!(adjustment_needed || REPLACE_FUNC_STAT_FILE) && lstat (file, &st))
625 return -1;
626 if (!S_ISLNK (st.st_mode))
627 return fdutimens (-1, file, ts);
628 errno = ENOSYS;
629 return -1;