1 /* Set file access and modification times.
3 Copyright (C) 2003-2012 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 <http://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"
42 /* Some systems (even some that do have <utime.h>) don't declare this
43 structure anywhere. */
44 #ifndef HAVE_STRUCT_UTIMBUF
52 /* Avoid recursion with rpl_futimens or rpl_utimensat. */
56 /* Solaris 9 mistakenly succeeds when given a non-directory with a
57 trailing slash. Force the use of rpl_stat for a fix. */
58 #ifndef REPLACE_FUNC_STAT_FILE
59 # define REPLACE_FUNC_STAT_FILE 0
62 #if HAVE_UTIMENSAT || HAVE_FUTIMENS
63 /* Cache variables for whether the utimensat syscall works; used to
64 avoid calling the syscall if we know it will just fail with ENOSYS,
65 and to avoid unnecessary work in massaging timestamps if the
66 syscall will work. Multiple variables are needed, to distinguish
67 between the following scenarios on Linux:
68 utimensat doesn't exist, or is in glibc but kernel 2.6.18 fails with ENOSYS
69 kernel 2.6.22 and earlier rejects AT_SYMLINK_NOFOLLOW
70 kernel 2.6.25 and earlier reject UTIME_NOW/UTIME_OMIT with non-zero tv_sec
71 kernel 2.6.32 used with xfs or ntfs-3g fail to honor UTIME_OMIT
72 utimensat completely works
73 For each cache variable: 0 = unknown, 1 = yes, -1 = no. */
74 static int utimensat_works_really
;
75 static int lutimensat_works_really
;
76 #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
78 /* Validate the requested timestamps. Return 0 if the resulting
79 timespec can be used for utimensat (after possibly modifying it to
80 work around bugs in utimensat). Return a positive value if the
81 timespec needs further adjustment based on stat results: 1 if any
82 adjustment is needed for utimes, and 2 if any adjustment is needed
83 for Linux utimensat. Return -1, with errno set to EINVAL, if
84 timespec is out of range. */
86 validate_timespec (struct timespec timespec
[2])
89 int utime_omit_count
= 0;
91 if ((timespec
[0].tv_nsec
!= UTIME_NOW
92 && timespec
[0].tv_nsec
!= UTIME_OMIT
93 && (timespec
[0].tv_nsec
< 0 || 1000000000 <= timespec
[0].tv_nsec
))
94 || (timespec
[1].tv_nsec
!= UTIME_NOW
95 && timespec
[1].tv_nsec
!= UTIME_OMIT
96 && (timespec
[1].tv_nsec
< 0 || 1000000000 <= timespec
[1].tv_nsec
)))
101 /* Work around Linux kernel 2.6.25 bug, where utimensat fails with
102 EINVAL if tv_sec is not 0 when using the flag values of tv_nsec.
103 Flag a Linux kernel 2.6.32 bug, where an mtime of UTIME_OMIT
104 fails to bump ctime. */
105 if (timespec
[0].tv_nsec
== UTIME_NOW
106 || timespec
[0].tv_nsec
== UTIME_OMIT
)
108 timespec
[0].tv_sec
= 0;
110 if (timespec
[0].tv_nsec
== UTIME_OMIT
)
113 if (timespec
[1].tv_nsec
== UTIME_NOW
114 || timespec
[1].tv_nsec
== UTIME_OMIT
)
116 timespec
[1].tv_sec
= 0;
118 if (timespec
[1].tv_nsec
== UTIME_OMIT
)
121 return result
+ (utime_omit_count
== 1);
124 /* Normalize any UTIME_NOW or UTIME_OMIT values in *TS, using stat
125 buffer STATBUF to obtain the current timestamps of the file. If
126 both times are UTIME_NOW, set *TS to NULL (as this can avoid some
127 permissions issues). If both times are UTIME_OMIT, return true
128 (nothing further beyond the prior collection of STATBUF is
129 necessary); otherwise return false. */
131 update_timespec (struct stat
const *statbuf
, struct timespec
*ts
[2])
133 struct timespec
*timespec
= *ts
;
134 if (timespec
[0].tv_nsec
== UTIME_OMIT
135 && timespec
[1].tv_nsec
== UTIME_OMIT
)
137 if (timespec
[0].tv_nsec
== UTIME_NOW
138 && timespec
[1].tv_nsec
== UTIME_NOW
)
144 if (timespec
[0].tv_nsec
== UTIME_OMIT
)
145 timespec
[0] = get_stat_atime (statbuf
);
146 else if (timespec
[0].tv_nsec
== UTIME_NOW
)
147 gettime (×pec
[0]);
149 if (timespec
[1].tv_nsec
== UTIME_OMIT
)
150 timespec
[1] = get_stat_mtime (statbuf
);
151 else if (timespec
[1].tv_nsec
== UTIME_NOW
)
152 gettime (×pec
[1]);
157 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
158 TIMESPEC[0] and TIMESPEC[1], respectively.
159 FD must be either negative -- in which case it is ignored --
160 or a file descriptor that is open on FILE.
161 If FD is nonnegative, then FILE can be NULL, which means
162 use just futimes (or equivalent) instead of utimes (or equivalent),
163 and fail if on an old system without futimes (or equivalent).
164 If TIMESPEC is null, set the time stamps to the current time.
165 Return 0 on success, -1 (setting errno) on failure. */
168 fdutimens (int fd
, char const *file
, struct timespec
const timespec
[2])
170 struct timespec adjusted_timespec
[2];
171 struct timespec
*ts
= timespec
? adjusted_timespec
: NULL
;
172 int adjustment_needed
= 0;
177 adjusted_timespec
[0] = timespec
[0];
178 adjusted_timespec
[1] = timespec
[1];
179 adjustment_needed
= validate_timespec (ts
);
181 if (adjustment_needed
< 0)
184 /* Require that at least one of FD or FILE are potentially valid, to avoid
185 a Linux bug where futimens (AT_FDCWD, NULL) changes "." rather
193 /* Some Linux-based NFS clients are buggy, and mishandle time stamps
194 of files in NFS file systems in some cases. We have no
195 configure-time test for this, but please see
196 <http://bugs.gentoo.org/show_bug.cgi?id=132673> for references to
197 some of the problems with Linux 2.6.16. If this affects you,
198 compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to
199 help in some cases, albeit at a cost in performance. But you
200 really should upgrade your kernel to a fixed version, since the
201 problem affects many applications. */
203 #if HAVE_BUGGY_NFS_TIME_STAMPS
210 /* POSIX 2008 added two interfaces to set file timestamps with
211 nanosecond resolution; newer Linux implements both functions via
212 a single syscall. We provide a fallback for ENOSYS (for example,
213 compiling against Linux 2.6.25 kernel headers and glibc 2.7, but
214 running on Linux 2.6.18 kernel). */
215 #if HAVE_UTIMENSAT || HAVE_FUTIMENS
216 if (0 <= utimensat_works_really
)
220 /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
221 systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
222 but work if both times are either explicitly specified or
223 UTIME_NOW. Work around it with a preparatory [f]stat prior
224 to calling futimens/utimensat; fortunately, there is not much
225 timing impact due to the extra syscall even on file systems
226 where UTIME_OMIT would have worked. FIXME: Simplify this in
227 2012, when file system bugs are no longer common. */
228 if (adjustment_needed
== 2)
230 if (fd
< 0 ? stat (file
, &st
) : fstat (fd
, &st
))
232 if (ts
[0].tv_nsec
== UTIME_OMIT
)
233 ts
[0] = get_stat_atime (&st
);
234 else if (ts
[1].tv_nsec
== UTIME_OMIT
)
235 ts
[1] = get_stat_mtime (&st
);
236 /* Note that st is good, in case utimensat gives ENOSYS. */
239 # endif /* __linux__ */
243 result
= utimensat (AT_FDCWD
, file
, ts
, 0);
245 /* Work around a kernel bug:
246 http://bugzilla.redhat.com/442352
247 http://bugzilla.redhat.com/449910
248 It appears that utimensat can mistakenly return 280 rather
249 than -1 upon ENOSYS failure.
250 FIXME: remove in 2010 or whenever the offending kernels
251 are no longer in common use. */
254 # endif /* __linux__ */
255 if (result
== 0 || errno
!= ENOSYS
)
257 utimensat_works_really
= 1;
261 # endif /* HAVE_UTIMENSAT */
265 result
= futimens (fd
, ts
);
267 /* Work around the same bug as above. */
270 # endif /* __linux__ */
271 if (result
== 0 || errno
!= ENOSYS
)
273 utimensat_works_really
= 1;
277 # endif /* HAVE_FUTIMENS */
279 utimensat_works_really
= -1;
280 lutimensat_works_really
= -1;
281 #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
283 /* The platform lacks an interface to set file timestamps with
284 nanosecond resolution, so do the best we can, discarding any
285 fractional part of the timestamp. */
287 if (adjustment_needed
|| (REPLACE_FUNC_STAT_FILE
&& fd
< 0))
289 if (adjustment_needed
!= 3
290 && (fd
< 0 ? stat (file
, &st
) : fstat (fd
, &st
)))
292 if (ts
&& update_timespec (&st
, &ts
))
297 #if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
298 struct timeval timeval
[2];
302 timeval
[0].tv_sec
= ts
[0].tv_sec
;
303 timeval
[0].tv_usec
= ts
[0].tv_nsec
/ 1000;
304 timeval
[1].tv_sec
= ts
[1].tv_sec
;
305 timeval
[1].tv_usec
= ts
[1].tv_nsec
/ 1000;
314 return futimesat (AT_FDCWD
, file
, t
);
319 /* If futimesat or futimes fails here, don't try to speed things
320 up by returning right away. glibc can incorrectly fail with
321 errno == ENOENT if /proc isn't mounted. Also, Mandrake 10.0
322 in high security mode doesn't allow ordinary users to read
323 /proc/self, so glibc incorrectly fails with errno == EACCES.
324 If errno == EIO, EPERM, or EROFS, it's probably safe to fail
325 right away, but these cases are rare enough that they're not
326 worth optimizing, and who knows what other messed-up systems
327 are out there? So play it safe and fall back on the code
330 # if (HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) || HAVE_FUTIMES
331 # if HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG
333 # define futimes(fd, t) futimesat (fd, NULL, t)
335 if (futimes (fd
, t
) == 0)
337 # if __linux__ && __GLIBC__
338 /* Work around a longstanding glibc bug, still present as
339 of 2010-12-27. On older Linux kernels that lack both
340 utimensat and utimes, glibc's futimes rounds instead of
341 truncating when falling back on utime. The same bug
342 occurs in futimesat with a null 2nd arg. */
345 bool abig
= 500000 <= t
[0].tv_usec
;
346 bool mbig
= 500000 <= t
[1].tv_usec
;
347 if ((abig
| mbig
) && fstat (fd
, &st
) == 0)
349 /* If these two subtractions overflow, they'll
350 track the overflows inside the buggy glibc. */
351 time_t adiff
= st
.st_atime
- t
[0].tv_sec
;
352 time_t mdiff
= st
.st_mtime
- t
[1].tv_sec
;
354 struct timeval
*tt
= NULL
;
355 struct timeval truncated_timeval
[2];
356 truncated_timeval
[0] = t
[0];
357 truncated_timeval
[1] = t
[1];
358 if (abig
&& adiff
== 1 && get_stat_atime_ns (&st
) == 0)
360 tt
= truncated_timeval
;
363 if (mbig
&& mdiff
== 1 && get_stat_mtime_ns (&st
) == 0)
365 tt
= truncated_timeval
;
378 #endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */
382 #if ! ((HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) \
383 || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
389 #if HAVE_WORKING_UTIMES
390 return utimes (file
, t
);
393 struct utimbuf utimbuf
;
397 utimbuf
.actime
= ts
[0].tv_sec
;
398 utimbuf
.modtime
= ts
[1].tv_sec
;
404 return utime (file
, ut
);
406 #endif /* !HAVE_WORKING_UTIMES */
410 /* Set the access and modification time stamps of FILE to be
411 TIMESPEC[0] and TIMESPEC[1], respectively. */
413 utimens (char const *file
, struct timespec
const timespec
[2])
415 return fdutimens (-1, file
, timespec
);
418 /* Set the access and modification time stamps of FILE to be
419 TIMESPEC[0] and TIMESPEC[1], respectively, without dereferencing
420 symlinks. Fail with ENOSYS if the platform does not support
421 changing symlink timestamps, but FILE was a symlink. */
423 lutimens (char const *file
, struct timespec
const timespec
[2])
425 struct timespec adjusted_timespec
[2];
426 struct timespec
*ts
= timespec
? adjusted_timespec
: NULL
;
427 int adjustment_needed
= 0;
432 adjusted_timespec
[0] = timespec
[0];
433 adjusted_timespec
[1] = timespec
[1];
434 adjustment_needed
= validate_timespec (ts
);
436 if (adjustment_needed
< 0)
439 /* The Linux kernel did not support symlink timestamps until
440 utimensat, in version 2.6.22, so we don't need to mimic
441 fdutimens' worry about buggy NFS clients. But we do have to
442 worry about bogus return values. */
445 if (0 <= lutimensat_works_really
)
449 /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
450 systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
451 but work if both times are either explicitly specified or
452 UTIME_NOW. Work around it with a preparatory lstat prior to
453 calling utimensat; fortunately, there is not much timing
454 impact due to the extra syscall even on file systems where
455 UTIME_OMIT would have worked. FIXME: Simplify this in 2012,
456 when file system bugs are no longer common. */
457 if (adjustment_needed
== 2)
459 if (lstat (file
, &st
))
461 if (ts
[0].tv_nsec
== UTIME_OMIT
)
462 ts
[0] = get_stat_atime (&st
);
463 else if (ts
[1].tv_nsec
== UTIME_OMIT
)
464 ts
[1] = get_stat_mtime (&st
);
465 /* Note that st is good, in case utimensat gives ENOSYS. */
468 # endif /* __linux__ */
469 result
= utimensat (AT_FDCWD
, file
, ts
, AT_SYMLINK_NOFOLLOW
);
471 /* Work around a kernel bug:
472 http://bugzilla.redhat.com/442352
473 http://bugzilla.redhat.com/449910
474 It appears that utimensat can mistakenly return 280 rather
475 than -1 upon ENOSYS failure.
476 FIXME: remove in 2010 or whenever the offending kernels
477 are no longer in common use. */
481 if (result
== 0 || errno
!= ENOSYS
)
483 utimensat_works_really
= 1;
484 lutimensat_works_really
= 1;
488 lutimensat_works_really
= -1;
489 #endif /* HAVE_UTIMENSAT */
491 /* The platform lacks an interface to set file timestamps with
492 nanosecond resolution, so do the best we can, discarding any
493 fractional part of the timestamp. */
495 if (adjustment_needed
|| REPLACE_FUNC_STAT_FILE
)
497 if (adjustment_needed
!= 3 && lstat (file
, &st
))
499 if (ts
&& update_timespec (&st
, &ts
))
503 /* On Linux, lutimes is a thin wrapper around utimensat, so there is
504 no point trying lutimes if utimensat failed with ENOSYS. */
505 #if HAVE_LUTIMES && !HAVE_UTIMENSAT
507 struct timeval timeval
[2];
512 timeval
[0].tv_sec
= ts
[0].tv_sec
;
513 timeval
[0].tv_usec
= ts
[0].tv_nsec
/ 1000;
514 timeval
[1].tv_sec
= ts
[1].tv_sec
;
515 timeval
[1].tv_usec
= ts
[1].tv_nsec
/ 1000;
521 result
= lutimes (file
, t
);
522 if (result
== 0 || errno
!= ENOSYS
)
525 #endif /* HAVE_LUTIMES && !HAVE_UTIMENSAT */
527 /* Out of luck for symlinks, but we still handle regular files. */
528 if (!(adjustment_needed
|| REPLACE_FUNC_STAT_FILE
) && lstat (file
, &st
))
530 if (!S_ISLNK (st
.st_mode
))
531 return fdutimens (-1, file
, ts
);