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. */
55 /* Validate the requested timestamps. Return 0 if the resulting
56 timespec can be used for utimensat (after possibly modifying it to
57 work around bugs in utimensat). Return 1 if the timespec needs
58 further adjustment based on stat results for utimes or other less
59 powerful interfaces. Return -1, with errno set to EINVAL, if
60 timespec is out of range. */
62 validate_timespec (struct timespec timespec[2])
66 if ((timespec[0].tv_nsec != UTIME_NOW
67 && timespec[0].tv_nsec != UTIME_OMIT
68 && (timespec[0].tv_nsec < 0 || 1000000000 <= timespec[0].tv_nsec))
69 || (timespec[1].tv_nsec != UTIME_NOW
70 && timespec[1].tv_nsec != UTIME_OMIT
71 && (timespec[1].tv_nsec < 0 || 1000000000 <= timespec[1].tv_nsec)))
76 /* Work around Linux kernel 2.6.25 bug, where utimensat fails with
77 EINVAL if tv_sec is not 0 when using the flag values of
79 if (timespec[0].tv_nsec == UTIME_NOW
80 || timespec[0].tv_nsec == UTIME_OMIT)
82 timespec[0].tv_sec = 0;
85 if (timespec[1].tv_nsec == UTIME_NOW
86 || timespec[1].tv_nsec == UTIME_OMIT)
88 timespec[1].tv_sec = 0;
94 /* Normalize any UTIME_NOW or UTIME_OMIT values in *TS, using stat
95 buffer STATBUF to obtain the current timestamps of the file. If
96 both times are UTIME_NOW, set *TS to NULL (as this can avoid some
97 permissions issues). If both times are UTIME_OMIT, return true
98 (nothing further beyond the prior collection of STATBUF is
99 necessary); otherwise return false. */
101 update_timespec (struct stat const *statbuf, struct timespec *ts[2])
103 struct timespec *timespec = *ts;
104 if (timespec[0].tv_nsec == UTIME_OMIT
105 && timespec[1].tv_nsec == UTIME_OMIT)
107 if (timespec[0].tv_nsec == UTIME_NOW
108 && timespec[1].tv_nsec == UTIME_NOW)
114 if (timespec[0].tv_nsec == UTIME_OMIT)
115 timespec[0] = get_stat_atime (statbuf);
116 else if (timespec[0].tv_nsec == UTIME_NOW)
117 gettime (×pec[0]);
119 if (timespec[1].tv_nsec == UTIME_OMIT)
120 timespec[1] = get_stat_mtime (statbuf);
121 else if (timespec[1].tv_nsec == UTIME_NOW)
122 gettime (×pec[1]);
127 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
128 TIMESPEC[0] and TIMESPEC[1], respectively.
129 FD must be either negative -- in which case it is ignored --
130 or a file descriptor that is open on FILE.
131 If FD is nonnegative, then FILE can be NULL, which means
132 use just futimes (or equivalent) instead of utimes (or equivalent),
133 and fail if on an old system without futimes (or equivalent).
134 If TIMESPEC is null, set the time stamps to the current time.
135 Return 0 on success, -1 (setting errno) on failure. */
138 fdutimens (char const *file, int fd, struct timespec const timespec[2])
140 struct timespec adjusted_timespec[2];
141 struct timespec *ts = timespec ? adjusted_timespec : NULL;
142 int adjustment_needed = 0;
146 adjusted_timespec[0] = timespec[0];
147 adjusted_timespec[1] = timespec[1];
148 adjustment_needed = validate_timespec (ts);
150 if (adjustment_needed < 0)
153 /* Require that at least one of FD or FILE are valid. Works around
154 a Linux bug where futimens (AT_FDCWD, NULL) changes "." rather
163 if (dup2 (fd, fd) != fd)
167 /* Some Linux-based NFS clients are buggy, and mishandle time stamps
168 of files in NFS file systems in some cases. We have no
169 configure-time test for this, but please see
170 <http://bugs.gentoo.org/show_bug.cgi?id=132673> for references to
171 some of the problems with Linux 2.6.16. If this affects you,
172 compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to
173 help in some cases, albeit at a cost in performance. But you
174 really should upgrade your kernel to a fixed version, since the
175 problem affects many applications. */
177 #if HAVE_BUGGY_NFS_TIME_STAMPS
184 /* POSIX 2008 added two interfaces to set file timestamps with
185 nanosecond resolution. We provide a fallback for ENOSYS (for
186 example, compiling against Linux 2.6.25 kernel headers and glibc
187 2.7, but running on Linux 2.6.18 kernel). */
191 int result = utimensat (AT_FDCWD, file, ts, 0);
193 /* Work around a kernel bug:
194 http://bugzilla.redhat.com/442352
195 http://bugzilla.redhat.com/449910
196 It appears that utimensat can mistakenly return 280 rather
197 than -1 upon failure.
198 FIXME: remove in 2010 or whenever the offending kernels
199 are no longer in common use. */
204 if (result == 0 || errno != ENOSYS)
210 int result = futimens (fd, timespec);
212 /* Work around the same bug as above. */
216 if (result == 0 || errno != ENOSYS)
221 /* The platform lacks an interface to set file timestamps with
222 nanosecond resolution, so do the best we can, discarding any
223 fractional part of the timestamp. */
225 if (adjustment_needed)
228 if (fd < 0 ? stat (file, &st) : fstat (fd, &st))
230 if (update_timespec (&st, &ts))
235 #if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
236 struct timeval timeval[2];
237 struct timeval const *t;
240 timeval[0].tv_sec = ts[0].tv_sec;
241 timeval[0].tv_usec = ts[0].tv_nsec / 1000;
242 timeval[1].tv_sec = ts[1].tv_sec;
243 timeval[1].tv_usec = ts[1].tv_nsec / 1000;
252 return futimesat (AT_FDCWD, file, t);
257 /* If futimesat or futimes fails here, don't try to speed things
258 up by returning right away. glibc can incorrectly fail with
259 errno == ENOENT if /proc isn't mounted. Also, Mandrake 10.0
260 in high security mode doesn't allow ordinary users to read
261 /proc/self, so glibc incorrectly fails with errno == EACCES.
262 If errno == EIO, EPERM, or EROFS, it's probably safe to fail
263 right away, but these cases are rare enough that they're not
264 worth optimizing, and who knows what other messed-up systems
265 are out there? So play it safe and fall back on the code
268 if (futimesat (fd, NULL, t) == 0)
271 if (futimes (fd, t) == 0)
275 #endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */
279 #if ! (HAVE_FUTIMESAT || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
285 #if HAVE_WORKING_UTIMES
286 return utimes (file, t);
289 struct utimbuf utimbuf;
293 utimbuf.actime = ts[0].tv_sec;
294 utimbuf.modtime = ts[1].tv_sec;
300 return utime (file, ut);
302 #endif /* !HAVE_WORKING_UTIMES */
306 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
307 TIMESPEC[0] and TIMESPEC[1], respectively.
308 FD must be either negative -- in which case it is ignored --
309 or a file descriptor that is open on FILE.
310 If FD is nonnegative, then FILE can be NULL, which means
311 use just futimes (or equivalent) instead of utimes (or equivalent),
312 and fail if on an old system without futimes (or equivalent).
313 If TIMESPEC is null, set the time stamps to the current time.
314 Return 0 on success, -1 (setting errno) on failure. */
317 gl_futimens (int fd, char const *file, struct timespec const timespec[2])
319 return fdutimens (file, fd, timespec);
322 /* Set the access and modification time stamps of FILE to be
323 TIMESPEC[0] and TIMESPEC[1], respectively. */
325 utimens (char const *file, struct timespec const timespec[2])
327 return gl_futimens (-1, file, timespec);
330 /* Set the access and modification time stamps of the symlink FILE to
331 be TIMESPEC[0] and TIMESPEC[1], respectively. Fail with ENOSYS if
332 the platform does not support changing symlink timestamps. */
334 lutimens (char const *file, struct timespec const timespec[2])
336 struct timespec adjusted_timespec[2];
337 struct timespec *ts = timespec ? adjusted_timespec : NULL;
338 int adjustment_needed = 0;
342 adjusted_timespec[0] = timespec[0];
343 adjusted_timespec[1] = timespec[1];
344 adjustment_needed = validate_timespec (ts);
346 if (adjustment_needed < 0)
349 /* The Linux kernel did not support symlink timestamps until
350 utimensat, in version 2.6.22, so we don't need to mimic
351 gl_futimens' worry about buggy NFS clients. But we do have to
352 worry about bogus return values. */
356 int result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW);
358 /* Work around a kernel bug:
359 http://bugzilla.redhat.com/442352
360 http://bugzilla.redhat.com/449910
361 It appears that utimensat can mistakenly return 280 rather
362 than -1 upon ENOSYS failure.
363 FIXME: remove in 2010 or whenever the offending kernels
364 are no longer in common use. */
369 if (result == 0 || errno != ENOSYS)
372 #endif /* HAVE_UTIMENSAT */
374 /* The platform lacks an interface to set file timestamps with
375 nanosecond resolution, so do the best we can, discarding any
376 fractional part of the timestamp. */
378 if (adjustment_needed)
381 if (lstat (file, &st))
383 if (update_timespec (&st, &ts))
389 struct timeval timeval[2];
390 struct timeval const *t;
393 timeval[0].tv_sec = ts[0].tv_sec;
394 timeval[0].tv_usec = ts[0].tv_nsec / 1000;
395 timeval[1].tv_sec = ts[1].tv_sec;
396 timeval[1].tv_usec = ts[1].tv_nsec / 1000;
402 return lutimes (file, t);
404 #endif /* HAVE_LUTIMES */
406 /* Out of luck. Symlink timestamps can't be changed. We won't
407 bother changing the timestamps if FILE was not a symlink. */