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
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 */
24 #define _GL_UTIMENS_INLINE _GL_EXTERN_INLINE
35 #include "stat-time.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
46 # if GNULIB_MSVC_NOTHROW
47 # include "msvc-nothrow.h"
53 /* Avoid recursion with rpl_futimens or rpl_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
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. */
87 validate_timespec (struct timespec timespec
[2])
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
)))
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;
112 if (timespec
[0].tv_nsec
== UTIME_OMIT
)
115 if (timespec
[1].tv_nsec
== UTIME_NOW
116 || timespec
[1].tv_nsec
== UTIME_OMIT
)
118 timespec
[1].tv_sec
= 0;
120 if (timespec
[1].tv_nsec
== UTIME_OMIT
)
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. */
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
)
139 if (timespec
[0].tv_nsec
== UTIME_NOW
140 && timespec
[1].tv_nsec
== UTIME_NOW
)
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 (×pec
[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 (×pec
[1]);
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;
179 adjusted_timespec
[0] = timespec
[0];
180 adjusted_timespec
[1] = timespec
[1];
181 adjustment_needed
= validate_timespec (ts
);
183 if (adjustment_needed
< 0)
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
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
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
)
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
))
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. */
249 result
= utimensat (AT_FDCWD
, file
, ts
, 0);
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. */
260 # endif /* __linux__ */
261 if (result
== 0 || errno
!= ENOSYS
)
263 utimensat_works_really
= 1;
267 # endif /* HAVE_UTIMENSAT */
271 result
= futimens (fd
, ts
);
273 /* Work around the same bug as above. */
276 # endif /* __linux__ */
277 if (result
== 0 || errno
!= ENOSYS
)
279 utimensat_works_really
= 1;
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> */
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
)
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 (¤t_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;
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;
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
))
355 DWORD sft_error
= GetLastError ();
357 fprintf (stderr
, "fdutimens SetFileTime error 0x%x\n", (unsigned int) sft_error
);
361 case ERROR_ACCESS_DENIED
: /* fd was opened without O_RDWR */
362 errno
= EACCES
; /* not specified by POSIX */
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
)))
382 if (ts
&& update_timespec (&st
, &ts
))
387 #if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
388 struct timeval timeval
[2];
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;
404 return futimesat (AT_FDCWD
, file
, t
);
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
420 # if (HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) || HAVE_FUTIMES
421 # if HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG
423 # define futimes(fd, t) futimesat (fd, NULL, t)
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. */
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
;
453 if (mbig
&& mdiff
== 1 && get_stat_mtime_ns (&st
) == 0)
455 tt
= truncated_timeval
;
468 #endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */
472 #if ! ((HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) \
473 || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
479 #ifdef USE_SETFILETIME
480 return _gl_utimens_windows (file
, ts
);
481 #elif HAVE_WORKING_UTIMES
482 return utimes (file
, t
);
485 struct utimbuf utimbuf
;
489 utimbuf
.actime
= ts
[0].tv_sec
;
490 utimbuf
.modtime
= ts
[1].tv_sec
;
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;
524 adjusted_timespec
[0] = timespec
[0];
525 adjusted_timespec
[1] = timespec
[1];
526 adjustment_needed
= validate_timespec (ts
);
528 if (adjustment_needed
< 0)
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. */
537 if (0 <= lutimensat_works_really
)
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
))
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. */
565 result
= utimensat (AT_FDCWD
, file
, ts
, AT_SYMLINK_NOFOLLOW
);
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. */
577 if (result
== 0 || errno
!= ENOSYS
)
579 utimensat_works_really
= 1;
580 lutimensat_works_really
= 1;
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
))
595 if (ts
&& update_timespec (&st
, &ts
))
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];
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;
617 result
= lutimes (file
, t
);
618 if (result
== 0 || errno
!= ENOSYS
)
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
))
626 if (!S_ISLNK (st
.st_mode
))
627 return fdutimens (-1, file
, ts
);