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 /* Validate the requested timestamps. Return 0 if the resulting
53 timespec can be used for utimensat (after possibly modifying it to
54 work around bugs in utimensat). Return 1 if the timespec needs
55 further adjustment based on stat results for utimes or other less
56 powerful interfaces. Return -1, with errno set to EINVAL, if
57 timespec is out of range. */
59 validate_timespec (struct timespec timespec[2])
63 if ((timespec[0].tv_nsec != UTIME_NOW
64 && timespec[0].tv_nsec != UTIME_OMIT
65 && (timespec[0].tv_nsec < 0 || 1000000000 <= timespec[0].tv_nsec))
66 || (timespec[1].tv_nsec != UTIME_NOW
67 && timespec[1].tv_nsec != UTIME_OMIT
68 && (timespec[1].tv_nsec < 0 || 1000000000 <= timespec[1].tv_nsec)))
73 /* Work around Linux kernel 2.6.25 bug, where utimensat fails with
74 EINVAL if tv_sec is not 0 when using the flag values of
76 if (timespec[0].tv_nsec == UTIME_NOW
77 || timespec[0].tv_nsec == UTIME_OMIT)
79 timespec[0].tv_sec = 0;
82 if (timespec[1].tv_nsec == UTIME_NOW
83 || timespec[1].tv_nsec == UTIME_OMIT)
85 timespec[1].tv_sec = 0;
91 /* Normalize any UTIME_NOW or UTIME_OMIT values in *TS, using stat
92 buffer STATBUF to obtain the current timestamps of the file. If
93 both times are UTIME_NOW, set *TS to NULL (as this can avoid some
94 permissions issues). If both times are UTIME_OMIT, return true
95 (nothing further beyond the prior collection of STATBUF is
96 necessary); otherwise return false. */
98 update_timespec (struct stat const *statbuf, struct timespec *ts[2])
100 struct timespec *timespec = *ts;
101 if (timespec[0].tv_nsec == UTIME_OMIT
102 && timespec[1].tv_nsec == UTIME_OMIT)
104 if (timespec[0].tv_nsec == UTIME_NOW
105 && timespec[1].tv_nsec == UTIME_NOW)
111 if (timespec[0].tv_nsec == UTIME_OMIT)
112 timespec[0] = get_stat_atime (statbuf);
113 else if (timespec[0].tv_nsec == UTIME_NOW)
114 gettime (×pec[0]);
116 if (timespec[1].tv_nsec == UTIME_OMIT)
117 timespec[1] = get_stat_mtime (statbuf);
118 else if (timespec[1].tv_nsec == UTIME_NOW)
119 gettime (×pec[1]);
124 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
125 TIMESPEC[0] and TIMESPEC[1], respectively.
126 FD must be either negative -- in which case it is ignored --
127 or a file descriptor that is open on FILE.
128 If FD is nonnegative, then FILE can be NULL, which means
129 use just futimes (or equivalent) instead of utimes (or equivalent),
130 and fail if on an old system without futimes (or equivalent).
131 If TIMESPEC is null, set the time stamps to the current time.
132 Return 0 on success, -1 (setting errno) on failure. */
135 fdutimens (char const *file, int fd, struct timespec const timespec[2])
137 struct timespec adjusted_timespec[2];
138 struct timespec *ts = timespec ? adjusted_timespec : NULL;
139 int adjustment_needed = 0;
143 adjusted_timespec[0] = timespec[0];
144 adjusted_timespec[1] = timespec[1];
145 adjustment_needed = validate_timespec (ts);
147 if (adjustment_needed < 0)
150 /* Require that at least one of FD or FILE are valid. Works around
151 a Linux bug where futimens (AT_FDCWD, NULL) changes "." rather
160 if (dup2 (fd, fd) != fd)
164 /* Some Linux-based NFS clients are buggy, and mishandle time stamps
165 of files in NFS file systems in some cases. We have no
166 configure-time test for this, but please see
167 <http://bugs.gentoo.org/show_bug.cgi?id=132673> for references to
168 some of the problems with Linux 2.6.16. If this affects you,
169 compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to
170 help in some cases, albeit at a cost in performance. But you
171 really should upgrade your kernel to a fixed version, since the
172 problem affects many applications. */
174 #if HAVE_BUGGY_NFS_TIME_STAMPS
181 /* POSIX 2008 added two interfaces to set file timestamps with
182 nanosecond resolution. We provide a fallback for ENOSYS (for
183 example, compiling against Linux 2.6.25 kernel headers and glibc
184 2.7, but running on Linux 2.6.18 kernel). */
188 int result = utimensat (AT_FDCWD, file, ts, 0);
190 /* Work around a kernel bug:
191 http://bugzilla.redhat.com/442352
192 http://bugzilla.redhat.com/449910
193 It appears that utimensat can mistakenly return 280 rather
194 than -1 upon failure.
195 FIXME: remove in 2010 or whenever the offending kernels
196 are no longer in common use. */
201 if (result == 0 || errno != ENOSYS)
207 int result = futimens (fd, timespec);
209 /* Work around the same bug as above. */
213 if (result == 0 || errno != ENOSYS)
218 /* The platform lacks an interface to set file timestamps with
219 nanosecond resolution, so do the best we can, discarding any
220 fractional part of the timestamp. */
222 if (adjustment_needed)
225 if (fd < 0 ? stat (file, &st) : fstat (fd, &st))
227 if (update_timespec (&st, &ts))
232 #if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
233 struct timeval timeval[2];
234 struct timeval const *t;
237 timeval[0].tv_sec = ts[0].tv_sec;
238 timeval[0].tv_usec = ts[0].tv_nsec / 1000;
239 timeval[1].tv_sec = ts[1].tv_sec;
240 timeval[1].tv_usec = ts[1].tv_nsec / 1000;
249 return futimesat (AT_FDCWD, file, t);
254 /* If futimesat or futimes fails here, don't try to speed things
255 up by returning right away. glibc can incorrectly fail with
256 errno == ENOENT if /proc isn't mounted. Also, Mandrake 10.0
257 in high security mode doesn't allow ordinary users to read
258 /proc/self, so glibc incorrectly fails with errno == EACCES.
259 If errno == EIO, EPERM, or EROFS, it's probably safe to fail
260 right away, but these cases are rare enough that they're not
261 worth optimizing, and who knows what other messed-up systems
262 are out there? So play it safe and fall back on the code
265 if (futimesat (fd, NULL, t) == 0)
268 if (futimes (fd, t) == 0)
272 #endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */
276 #if ! (HAVE_FUTIMESAT || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
282 #if HAVE_WORKING_UTIMES
283 return utimes (file, t);
286 struct utimbuf utimbuf;
290 utimbuf.actime = ts[0].tv_sec;
291 utimbuf.modtime = ts[1].tv_sec;
297 return utime (file, ut);
299 #endif /* !HAVE_WORKING_UTIMES */
303 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
304 TIMESPEC[0] and TIMESPEC[1], respectively.
305 FD must be either negative -- in which case it is ignored --
306 or a file descriptor that is open on FILE.
307 If FD is nonnegative, then FILE can be NULL, which means
308 use just futimes (or equivalent) instead of utimes (or equivalent),
309 and fail if on an old system without futimes (or equivalent).
310 If TIMESPEC is null, set the time stamps to the current time.
311 Return 0 on success, -1 (setting errno) on failure. */
314 gl_futimens (int fd, char const *file, struct timespec const timespec[2])
316 return fdutimens (file, fd, timespec);
319 /* Set the access and modification time stamps of FILE to be
320 TIMESPEC[0] and TIMESPEC[1], respectively. */
322 utimens (char const *file, struct timespec const timespec[2])
324 return gl_futimens (-1, file, timespec);
327 /* Set the access and modification time stamps of the symlink FILE to
328 be TIMESPEC[0] and TIMESPEC[1], respectively. Fail with ENOSYS if
329 the platform does not support changing symlink timestamps. */
331 lutimens (char const *file, struct timespec const timespec[2])
333 struct timespec adjusted_timespec[2];
334 struct timespec *ts = timespec ? adjusted_timespec : NULL;
335 int adjustment_needed = 0;
339 adjusted_timespec[0] = timespec[0];
340 adjusted_timespec[1] = timespec[1];
341 adjustment_needed = validate_timespec (ts);
343 if (adjustment_needed < 0)
346 /* The Linux kernel did not support symlink timestamps until
347 utimensat, in version 2.6.22, so we don't need to mimic
348 gl_futimens' worry about buggy NFS clients. But we do have to
349 worry about bogus return values. */
353 int result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW);
355 /* Work around a kernel bug:
356 http://bugzilla.redhat.com/442352
357 http://bugzilla.redhat.com/449910
358 It appears that utimensat can mistakenly return 280 rather
359 than -1 upon ENOSYS failure.
360 FIXME: remove in 2010 or whenever the offending kernels
361 are no longer in common use. */
366 if (result == 0 || errno != ENOSYS)
369 #endif /* HAVE_UTIMENSAT */
371 /* The platform lacks an interface to set file timestamps with
372 nanosecond resolution, so do the best we can, discarding any
373 fractional part of the timestamp. */
375 if (adjustment_needed)
378 if (lstat (file, &st))
380 if (update_timespec (&st, &ts))
386 struct timeval timeval[2];
387 struct timeval const *t;
390 timeval[0].tv_sec = ts[0].tv_sec;
391 timeval[0].tv_usec = ts[0].tv_nsec / 1000;
392 timeval[1].tv_sec = ts[1].tv_sec;
393 timeval[1].tv_usec = ts[1].tv_nsec / 1000;
399 return lutimes (file, t);
401 #endif /* HAVE_LUTIMES */
403 /* Out of luck. Symlink timestamps can't be changed. We won't
404 bother changing the timestamps if FILE was not a symlink. */