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 /* Solaris 9 mistakenly succeeds when given a non-directory with a
64 trailing slash. Force the use of rpl_stat for a fix. */
65 #ifndef REPLACE_FUNC_STAT_FILE
66 # define REPLACE_FUNC_STAT_FILE 0
69 /* Validate the requested timestamps. Return 0 if the resulting
70 timespec can be used for utimensat (after possibly modifying it to
71 work around bugs in utimensat). Return 1 if the timespec needs
72 further adjustment based on stat results for utimes or other less
73 powerful interfaces. Return -1, with errno set to EINVAL, if
74 timespec is out of range. */
76 validate_timespec (struct timespec timespec[2])
80 if ((timespec[0].tv_nsec != UTIME_NOW
81 && timespec[0].tv_nsec != UTIME_OMIT
82 && (timespec[0].tv_nsec < 0 || 1000000000 <= timespec[0].tv_nsec))
83 || (timespec[1].tv_nsec != UTIME_NOW
84 && timespec[1].tv_nsec != UTIME_OMIT
85 && (timespec[1].tv_nsec < 0 || 1000000000 <= timespec[1].tv_nsec)))
90 /* Work around Linux kernel 2.6.25 bug, where utimensat fails with
91 EINVAL if tv_sec is not 0 when using the flag values of
93 if (timespec[0].tv_nsec == UTIME_NOW
94 || timespec[0].tv_nsec == UTIME_OMIT)
96 timespec[0].tv_sec = 0;
99 if (timespec[1].tv_nsec == UTIME_NOW
100 || timespec[1].tv_nsec == UTIME_OMIT)
102 timespec[1].tv_sec = 0;
108 /* Normalize any UTIME_NOW or UTIME_OMIT values in *TS, using stat
109 buffer STATBUF to obtain the current timestamps of the file. If
110 both times are UTIME_NOW, set *TS to NULL (as this can avoid some
111 permissions issues). If both times are UTIME_OMIT, return true
112 (nothing further beyond the prior collection of STATBUF is
113 necessary); otherwise return false. */
115 update_timespec (struct stat const *statbuf, struct timespec *ts[2])
117 struct timespec *timespec = *ts;
118 if (timespec[0].tv_nsec == UTIME_OMIT
119 && timespec[1].tv_nsec == UTIME_OMIT)
121 if (timespec[0].tv_nsec == UTIME_NOW
122 && timespec[1].tv_nsec == UTIME_NOW)
128 if (timespec[0].tv_nsec == UTIME_OMIT)
129 timespec[0] = get_stat_atime (statbuf);
130 else if (timespec[0].tv_nsec == UTIME_NOW)
131 gettime (×pec[0]);
133 if (timespec[1].tv_nsec == UTIME_OMIT)
134 timespec[1] = get_stat_mtime (statbuf);
135 else if (timespec[1].tv_nsec == UTIME_NOW)
136 gettime (×pec[1]);
141 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
142 TIMESPEC[0] and TIMESPEC[1], respectively.
143 FD must be either negative -- in which case it is ignored --
144 or a file descriptor that is open on FILE.
145 If FD is nonnegative, then FILE can be NULL, which means
146 use just futimes (or equivalent) instead of utimes (or equivalent),
147 and fail if on an old system without futimes (or equivalent).
148 If TIMESPEC is null, set the time stamps to the current time.
149 Return 0 on success, -1 (setting errno) on failure. */
152 fdutimens (char const *file, int fd, struct timespec const timespec[2])
154 struct timespec adjusted_timespec[2];
155 struct timespec *ts = timespec ? adjusted_timespec : NULL;
156 int adjustment_needed = 0;
160 adjusted_timespec[0] = timespec[0];
161 adjusted_timespec[1] = timespec[1];
162 adjustment_needed = validate_timespec (ts);
164 if (adjustment_needed < 0)
167 /* Require that at least one of FD or FILE are valid. Works around
168 a Linux bug where futimens (AT_FDCWD, NULL) changes "." rather
177 if (dup2 (fd, fd) != fd)
181 /* Some Linux-based NFS clients are buggy, and mishandle time stamps
182 of files in NFS file systems in some cases. We have no
183 configure-time test for this, but please see
184 <http://bugs.gentoo.org/show_bug.cgi?id=132673> for references to
185 some of the problems with Linux 2.6.16. If this affects you,
186 compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to
187 help in some cases, albeit at a cost in performance. But you
188 really should upgrade your kernel to a fixed version, since the
189 problem affects many applications. */
191 #if HAVE_BUGGY_NFS_TIME_STAMPS
198 /* POSIX 2008 added two interfaces to set file timestamps with
199 nanosecond resolution; newer Linux implements both functions via
200 a single syscall. We provide a fallback for ENOSYS (for example,
201 compiling against Linux 2.6.25 kernel headers and glibc 2.7, but
202 running on Linux 2.6.18 kernel). */
203 #if HAVE_UTIMENSAT || HAVE_FUTIMENS
204 if (0 <= utimensat_works_really)
209 int result = utimensat (AT_FDCWD, file, ts, 0);
211 /* Work around a kernel bug:
212 http://bugzilla.redhat.com/442352
213 http://bugzilla.redhat.com/449910
214 It appears that utimensat can mistakenly return 280 rather
215 than -1 upon ENOSYS failure.
216 FIXME: remove in 2010 or whenever the offending kernels
217 are no longer in common use. */
220 # endif /* __linux__ */
221 if (result == 0 || errno != ENOSYS)
223 utimensat_works_really = 1;
227 # endif /* HAVE_UTIMENSAT */
230 int result = futimens (fd, ts);
232 /* Work around the same bug as above. */
235 # endif /* __linux__ */
236 if (result == 0 || errno != ENOSYS)
238 utimensat_works_really = 1;
242 # endif /* HAVE_FUTIMENS */
244 utimensat_works_really = -1;
245 #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
247 /* The platform lacks an interface to set file timestamps with
248 nanosecond resolution, so do the best we can, discarding any
249 fractional part of the timestamp. */
251 if (adjustment_needed || (REPLACE_FUNC_STAT_FILE && fd < 0))
254 if (fd < 0 ? stat (file, &st) : fstat (fd, &st))
256 if (ts && update_timespec (&st, &ts))
261 #if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
262 struct timeval timeval[2];
263 struct timeval const *t;
266 timeval[0].tv_sec = ts[0].tv_sec;
267 timeval[0].tv_usec = ts[0].tv_nsec / 1000;
268 timeval[1].tv_sec = ts[1].tv_sec;
269 timeval[1].tv_usec = ts[1].tv_nsec / 1000;
278 return futimesat (AT_FDCWD, file, t);
283 /* If futimesat (above) or futimes fails here, don't try to speed
284 things up by returning right away. glibc can incorrectly fail
285 with errno == ENOENT if /proc isn't mounted. Also, Mandrake 10.0
286 in high security mode doesn't allow ordinary users to read
287 /proc/self, so glibc incorrectly fails with errno == EACCES.
288 If errno == EIO, EPERM, or EROFS, it's probably safe to fail
289 right away, but these cases are rare enough that they're not
290 worth optimizing, and who knows what other messed-up systems
291 are out there? So play it safe and fall back on the code
294 if (futimes (fd, t) == 0)
298 #endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */
302 #if ! (HAVE_FUTIMESAT || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
308 #if HAVE_WORKING_UTIMES
309 return utimes (file, t);
312 struct utimbuf utimbuf;
316 utimbuf.actime = ts[0].tv_sec;
317 utimbuf.modtime = ts[1].tv_sec;
323 return utime (file, ut);
325 #endif /* !HAVE_WORKING_UTIMES */
329 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
330 TIMESPEC[0] and TIMESPEC[1], respectively.
331 FD must be either negative -- in which case it is ignored --
332 or a file descriptor that is open on FILE.
333 If FD is nonnegative, then FILE can be NULL, which means
334 use just futimes (or equivalent) instead of utimes (or equivalent),
335 and fail if on an old system without futimes (or equivalent).
336 If TIMESPEC is null, set the time stamps to the current time.
337 Return 0 on success, -1 (setting errno) on failure. */
340 gl_futimens (int fd, char const *file, struct timespec const timespec[2])
342 return fdutimens (file, fd, timespec);
345 /* Set the access and modification time stamps of FILE to be
346 TIMESPEC[0] and TIMESPEC[1], respectively. */
348 utimens (char const *file, struct timespec const timespec[2])
350 return fdutimens (file, -1, timespec);
353 /* Set the access and modification time stamps of FILE to be
354 TIMESPEC[0] and TIMESPEC[1], respectively, without dereferencing
355 symlinks. Fail with ENOSYS if the platform does not support
356 changing symlink timestamps, but FILE was a symlink. */
358 lutimens (char const *file, struct timespec const timespec[2])
360 struct timespec adjusted_timespec[2];
361 struct timespec *ts = timespec ? adjusted_timespec : NULL;
362 int adjustment_needed = 0;
367 adjusted_timespec[0] = timespec[0];
368 adjusted_timespec[1] = timespec[1];
369 adjustment_needed = validate_timespec (ts);
371 if (adjustment_needed < 0)
374 /* The Linux kernel did not support symlink timestamps until
375 utimensat, in version 2.6.22, so we don't need to mimic
376 gl_futimens' worry about buggy NFS clients. But we do have to
377 worry about bogus return values. */
380 if (0 <= utimensat_works_really)
382 int result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW);
384 /* Work around a kernel bug:
385 http://bugzilla.redhat.com/442352
386 http://bugzilla.redhat.com/449910
387 It appears that utimensat can mistakenly return 280 rather
388 than -1 upon ENOSYS failure.
389 FIXME: remove in 2010 or whenever the offending kernels
390 are no longer in common use. */
394 if (result == 0 || errno != ENOSYS)
396 utimensat_works_really = 1;
400 utimensat_works_really = -1;
401 #endif /* HAVE_UTIMENSAT */
403 /* The platform lacks an interface to set file timestamps with
404 nanosecond resolution, so do the best we can, discarding any
405 fractional part of the timestamp. */
407 if (adjustment_needed || REPLACE_FUNC_STAT_FILE)
409 if (lstat (file, &st))
411 if (ts && update_timespec (&st, &ts))
417 struct timeval timeval[2];
418 struct timeval const *t;
421 timeval[0].tv_sec = ts[0].tv_sec;
422 timeval[0].tv_usec = ts[0].tv_nsec / 1000;
423 timeval[1].tv_sec = ts[1].tv_sec;
424 timeval[1].tv_usec = ts[1].tv_nsec / 1000;
430 return lutimes (file, t);
432 #endif /* HAVE_LUTIMES */
434 /* Out of luck for symlinks, but we still handle regular files. */
435 if (!(adjustment_needed || REPLACE_FUNC_STAT_FILE) && lstat (file, &st))
437 if (!S_ISLNK (st.st_mode))
438 return fdutimens (file, -1, ts);