1 /* Set file access and modification times.
3 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free
4 Software Foundation, Inc.
6 This program is free software: you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 3 of the License, or any
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.
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/>. */
19 /* Written by Paul Eggert. */
21 /* derived from a function in touch.c */
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 #if HAVE_UTIMENSAT || HAVE_FUTIMENS
57 /* Cache variable for whether syscall works; used to avoid calling the
58 syscall if we know it will just fail with ENOSYS. 0 = unknown, 1 =
60 static int utimensat_works_really;
61 #endif /* HAVE_UTIMENSAT || HAVE_UTIMENSAT */
63 /* Validate the requested timestamps. Return 0 if the resulting
64 timespec can be used for utimensat (after possibly modifying it to
65 work around bugs in utimensat). Return 1 if the timespec needs
66 further adjustment based on stat results for utimes or other less
67 powerful interfaces. Return -1, with errno set to EINVAL, if
68 timespec is out of range. */
70 validate_timespec (struct timespec timespec[2])
74 if ((timespec[0].tv_nsec != UTIME_NOW
75 && timespec[0].tv_nsec != UTIME_OMIT
76 && (timespec[0].tv_nsec < 0 || 1000000000 <= timespec[0].tv_nsec))
77 || (timespec[1].tv_nsec != UTIME_NOW
78 && timespec[1].tv_nsec != UTIME_OMIT
79 && (timespec[1].tv_nsec < 0 || 1000000000 <= timespec[1].tv_nsec)))
84 /* Work around Linux kernel 2.6.25 bug, where utimensat fails with
85 EINVAL if tv_sec is not 0 when using the flag values of
87 if (timespec[0].tv_nsec == UTIME_NOW
88 || timespec[0].tv_nsec == UTIME_OMIT)
90 timespec[0].tv_sec = 0;
93 if (timespec[1].tv_nsec == UTIME_NOW
94 || timespec[1].tv_nsec == UTIME_OMIT)
96 timespec[1].tv_sec = 0;
102 /* Normalize any UTIME_NOW or UTIME_OMIT values in *TS, using stat
103 buffer STATBUF to obtain the current timestamps of the file. If
104 both times are UTIME_NOW, set *TS to NULL (as this can avoid some
105 permissions issues). If both times are UTIME_OMIT, return true
106 (nothing further beyond the prior collection of STATBUF is
107 necessary); otherwise return false. */
109 update_timespec (struct stat const *statbuf, struct timespec *ts[2])
111 struct timespec *timespec = *ts;
112 if (timespec[0].tv_nsec == UTIME_OMIT
113 && timespec[1].tv_nsec == UTIME_OMIT)
115 if (timespec[0].tv_nsec == UTIME_NOW
116 && timespec[1].tv_nsec == UTIME_NOW)
122 if (timespec[0].tv_nsec == UTIME_OMIT)
123 timespec[0] = get_stat_atime (statbuf);
124 else if (timespec[0].tv_nsec == UTIME_NOW)
125 gettime (×pec[0]);
127 if (timespec[1].tv_nsec == UTIME_OMIT)
128 timespec[1] = get_stat_mtime (statbuf);
129 else if (timespec[1].tv_nsec == UTIME_NOW)
130 gettime (×pec[1]);
135 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
136 TIMESPEC[0] and TIMESPEC[1], respectively.
137 FD must be either negative -- in which case it is ignored --
138 or a file descriptor that is open on FILE.
139 If FD is nonnegative, then FILE can be NULL, which means
140 use just futimes (or equivalent) instead of utimes (or equivalent),
141 and fail if on an old system without futimes (or equivalent).
142 If TIMESPEC is null, set the time stamps to the current time.
143 Return 0 on success, -1 (setting errno) on failure. */
146 fdutimens (char const *file, int fd, struct timespec const timespec[2])
148 struct timespec adjusted_timespec[2];
149 struct timespec *ts = timespec ? adjusted_timespec : NULL;
150 int adjustment_needed = 0;
154 adjusted_timespec[0] = timespec[0];
155 adjusted_timespec[1] = timespec[1];
156 adjustment_needed = validate_timespec (ts);
158 if (adjustment_needed < 0)
161 /* Require that at least one of FD or FILE are valid. Works around
162 a Linux bug where futimens (AT_FDCWD, NULL) changes "." rather
171 if (dup2 (fd, fd) != fd)
175 /* Some Linux-based NFS clients are buggy, and mishandle time stamps
176 of files in NFS file systems in some cases. We have no
177 configure-time test for this, but please see
178 <http://bugs.gentoo.org/show_bug.cgi?id=132673> for references to
179 some of the problems with Linux 2.6.16. If this affects you,
180 compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to
181 help in some cases, albeit at a cost in performance. But you
182 really should upgrade your kernel to a fixed version, since the
183 problem affects many applications. */
185 #if HAVE_BUGGY_NFS_TIME_STAMPS
192 /* POSIX 2008 added two interfaces to set file timestamps with
193 nanosecond resolution; newer Linux implements both functions via
194 a single syscall. We provide a fallback for ENOSYS (for example,
195 compiling against Linux 2.6.25 kernel headers and glibc 2.7, but
196 running on Linux 2.6.18 kernel). */
197 #if HAVE_UTIMENSAT || HAVE_FUTIMENS
198 if (0 <= utimensat_works_really)
203 int result = utimensat (AT_FDCWD, file, ts, 0);
205 /* Work around a kernel bug:
206 http://bugzilla.redhat.com/442352
207 http://bugzilla.redhat.com/449910
208 It appears that utimensat can mistakenly return 280 rather
209 than -1 upon ENOSYS failure.
210 FIXME: remove in 2010 or whenever the offending kernels
211 are no longer in common use. */
214 # endif /* __linux__ */
215 if (result == 0 || errno != ENOSYS)
217 utimensat_works_really = 1;
221 # endif /* HAVE_UTIMENSAT */
224 int result = futimens (fd, timespec);
226 /* Work around the same bug as above. */
229 # endif /* __linux__ */
230 if (result == 0 || errno != ENOSYS)
232 utimensat_works_really = 1;
236 # endif /* HAVE_FUTIMENS */
238 utimensat_works_really = -1;
239 #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
241 /* The platform lacks an interface to set file timestamps with
242 nanosecond resolution, so do the best we can, discarding any
243 fractional part of the timestamp. */
245 if (adjustment_needed)
248 if (fd < 0 ? stat (file, &st) : fstat (fd, &st))
250 if (update_timespec (&st, &ts))
255 #if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
256 struct timeval timeval[2];
257 struct timeval const *t;
260 timeval[0].tv_sec = ts[0].tv_sec;
261 timeval[0].tv_usec = ts[0].tv_nsec / 1000;
262 timeval[1].tv_sec = ts[1].tv_sec;
263 timeval[1].tv_usec = ts[1].tv_nsec / 1000;
272 return futimesat (AT_FDCWD, file, t);
277 /* If futimesat or futimes fails here, don't try to speed things
278 up by returning right away. glibc can incorrectly fail with
279 errno == ENOENT if /proc isn't mounted. Also, Mandrake 10.0
280 in high security mode doesn't allow ordinary users to read
281 /proc/self, so glibc incorrectly fails with errno == EACCES.
282 If errno == EIO, EPERM, or EROFS, it's probably safe to fail
283 right away, but these cases are rare enough that they're not
284 worth optimizing, and who knows what other messed-up systems
285 are out there? So play it safe and fall back on the code
288 if (futimesat (fd, NULL, t) == 0)
291 if (futimes (fd, t) == 0)
295 #endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */
299 #if ! (HAVE_FUTIMESAT || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
305 #if HAVE_WORKING_UTIMES
306 return utimes (file, t);
309 struct utimbuf utimbuf;
313 utimbuf.actime = ts[0].tv_sec;
314 utimbuf.modtime = ts[1].tv_sec;
320 return utime (file, ut);
322 #endif /* !HAVE_WORKING_UTIMES */
326 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
327 TIMESPEC[0] and TIMESPEC[1], respectively.
328 FD must be either negative -- in which case it is ignored --
329 or a file descriptor that is open on FILE.
330 If FD is nonnegative, then FILE can be NULL, which means
331 use just futimes (or equivalent) instead of utimes (or equivalent),
332 and fail if on an old system without futimes (or equivalent).
333 If TIMESPEC is null, set the time stamps to the current time.
334 Return 0 on success, -1 (setting errno) on failure. */
337 gl_futimens (int fd, char const *file, struct timespec const timespec[2])
339 return fdutimens (file, fd, timespec);
342 /* Set the access and modification time stamps of FILE to be
343 TIMESPEC[0] and TIMESPEC[1], respectively. */
345 utimens (char const *file, struct timespec const timespec[2])
347 return fdutimens (file, -1, timespec);
350 /* Set the access and modification time stamps of FILE to be
351 TIMESPEC[0] and TIMESPEC[1], respectively, without dereferencing
352 symlinks. Fail with ENOSYS if the platform does not support
353 changing symlink timestamps, but FILE was a symlink. */
355 lutimens (char const *file, struct timespec const timespec[2])
357 struct timespec adjusted_timespec[2];
358 struct timespec *ts = timespec ? adjusted_timespec : NULL;
359 int adjustment_needed = 0;
364 adjusted_timespec[0] = timespec[0];
365 adjusted_timespec[1] = timespec[1];
366 adjustment_needed = validate_timespec (ts);
368 if (adjustment_needed < 0)
371 /* The Linux kernel did not support symlink timestamps until
372 utimensat, in version 2.6.22, so we don't need to mimic
373 gl_futimens' worry about buggy NFS clients. But we do have to
374 worry about bogus return values. */
377 if (0 <= utimensat_works_really)
379 int result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW);
381 /* Work around a kernel bug:
382 http://bugzilla.redhat.com/442352
383 http://bugzilla.redhat.com/449910
384 It appears that utimensat can mistakenly return 280 rather
385 than -1 upon ENOSYS failure.
386 FIXME: remove in 2010 or whenever the offending kernels
387 are no longer in common use. */
391 if (result == 0 || errno != ENOSYS)
393 utimensat_works_really = 1;
397 utimensat_works_really = -1;
398 #endif /* HAVE_UTIMENSAT */
400 /* The platform lacks an interface to set file timestamps with
401 nanosecond resolution, so do the best we can, discarding any
402 fractional part of the timestamp. */
404 if (adjustment_needed)
406 if (lstat (file, &st))
408 if (update_timespec (&st, &ts))
414 struct timeval timeval[2];
415 struct timeval const *t;
418 timeval[0].tv_sec = ts[0].tv_sec;
419 timeval[0].tv_usec = ts[0].tv_nsec / 1000;
420 timeval[1].tv_sec = ts[1].tv_sec;
421 timeval[1].tv_usec = ts[1].tv_nsec / 1000;
427 return lutimes (file, t);
429 #endif /* HAVE_LUTIMES */
431 /* Out of luck for symlinks, but we still handle regular files. */
432 if (!adjustment_needed && lstat (file, &st))
434 if (!S_ISLNK (st.st_mode))
435 return fdutimens (file, -1, ts);