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 #if HAVE_UTIMENSAT || HAVE_FUTIMENS
56 /* Cache variable for whether syscall works; used to avoid calling the
57 syscall if we know it will just fail with ENOSYS. 0 = unknown, 1 =
59 static int utimensat_works_really;
60 #endif /* HAVE_UTIMENSAT || HAVE_UTIMENSAT */
62 /* Validate the requested timestamps. Return 0 if the resulting
63 timespec can be used for utimensat (after possibly modifying it to
64 work around bugs in utimensat). Return 1 if the timespec needs
65 further adjustment based on stat results for utimes or other less
66 powerful interfaces. Return -1, with errno set to EINVAL, if
67 timespec is out of range. */
69 validate_timespec (struct timespec timespec[2])
73 if ((timespec[0].tv_nsec != UTIME_NOW
74 && timespec[0].tv_nsec != UTIME_OMIT
75 && (timespec[0].tv_nsec < 0 || 1000000000 <= timespec[0].tv_nsec))
76 || (timespec[1].tv_nsec != UTIME_NOW
77 && timespec[1].tv_nsec != UTIME_OMIT
78 && (timespec[1].tv_nsec < 0 || 1000000000 <= timespec[1].tv_nsec)))
83 /* Work around Linux kernel 2.6.25 bug, where utimensat fails with
84 EINVAL if tv_sec is not 0 when using the flag values of
86 if (timespec[0].tv_nsec == UTIME_NOW
87 || timespec[0].tv_nsec == UTIME_OMIT)
89 timespec[0].tv_sec = 0;
92 if (timespec[1].tv_nsec == UTIME_NOW
93 || timespec[1].tv_nsec == UTIME_OMIT)
95 timespec[1].tv_sec = 0;
101 /* Normalize any UTIME_NOW or UTIME_OMIT values in *TS, using stat
102 buffer STATBUF to obtain the current timestamps of the file. If
103 both times are UTIME_NOW, set *TS to NULL (as this can avoid some
104 permissions issues). If both times are UTIME_OMIT, return true
105 (nothing further beyond the prior collection of STATBUF is
106 necessary); otherwise return false. */
108 update_timespec (struct stat const *statbuf, struct timespec *ts[2])
110 struct timespec *timespec = *ts;
111 if (timespec[0].tv_nsec == UTIME_OMIT
112 && timespec[1].tv_nsec == UTIME_OMIT)
114 if (timespec[0].tv_nsec == UTIME_NOW
115 && timespec[1].tv_nsec == UTIME_NOW)
121 if (timespec[0].tv_nsec == UTIME_OMIT)
122 timespec[0] = get_stat_atime (statbuf);
123 else if (timespec[0].tv_nsec == UTIME_NOW)
124 gettime (×pec[0]);
126 if (timespec[1].tv_nsec == UTIME_OMIT)
127 timespec[1] = get_stat_mtime (statbuf);
128 else if (timespec[1].tv_nsec == UTIME_NOW)
129 gettime (×pec[1]);
134 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
135 TIMESPEC[0] and TIMESPEC[1], respectively.
136 FD must be either negative -- in which case it is ignored --
137 or a file descriptor that is open on FILE.
138 If FD is nonnegative, then FILE can be NULL, which means
139 use just futimes (or equivalent) instead of utimes (or equivalent),
140 and fail if on an old system without futimes (or equivalent).
141 If TIMESPEC is null, set the time stamps to the current time.
142 Return 0 on success, -1 (setting errno) on failure. */
145 fdutimens (char const *file, int fd, struct timespec const timespec[2])
147 struct timespec adjusted_timespec[2];
148 struct timespec *ts = timespec ? adjusted_timespec : NULL;
149 int adjustment_needed = 0;
153 adjusted_timespec[0] = timespec[0];
154 adjusted_timespec[1] = timespec[1];
155 adjustment_needed = validate_timespec (ts);
157 if (adjustment_needed < 0)
160 /* Require that at least one of FD or FILE are valid. Works around
161 a Linux bug where futimens (AT_FDCWD, NULL) changes "." rather
170 if (dup2 (fd, fd) != fd)
174 /* Some Linux-based NFS clients are buggy, and mishandle time stamps
175 of files in NFS file systems in some cases. We have no
176 configure-time test for this, but please see
177 <http://bugs.gentoo.org/show_bug.cgi?id=132673> for references to
178 some of the problems with Linux 2.6.16. If this affects you,
179 compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to
180 help in some cases, albeit at a cost in performance. But you
181 really should upgrade your kernel to a fixed version, since the
182 problem affects many applications. */
184 #if HAVE_BUGGY_NFS_TIME_STAMPS
191 /* POSIX 2008 added two interfaces to set file timestamps with
192 nanosecond resolution; newer Linux implements both functions via
193 a single syscall. We provide a fallback for ENOSYS (for example,
194 compiling against Linux 2.6.25 kernel headers and glibc 2.7, but
195 running on Linux 2.6.18 kernel). */
196 #if HAVE_UTIMENSAT || HAVE_FUTIMENS
197 if (0 <= utimensat_works_really)
202 int result = utimensat (AT_FDCWD, file, ts, 0);
204 /* Work around a kernel bug:
205 http://bugzilla.redhat.com/442352
206 http://bugzilla.redhat.com/449910
207 It appears that utimensat can mistakenly return 280 rather
208 than -1 upon ENOSYS failure.
209 FIXME: remove in 2010 or whenever the offending kernels
210 are no longer in common use. */
213 # endif /* __linux__ */
214 if (result == 0 || errno != ENOSYS)
216 utimensat_works_really = 1;
220 # endif /* HAVE_UTIMENSAT */
223 int result = futimens (fd, timespec);
225 /* Work around the same bug as above. */
228 # endif /* __linux__ */
229 if (result == 0 || errno != ENOSYS)
231 utimensat_works_really = 1;
235 # endif /* HAVE_FUTIMENS */
237 utimensat_works_really = -1;
238 #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
240 /* The platform lacks an interface to set file timestamps with
241 nanosecond resolution, so do the best we can, discarding any
242 fractional part of the timestamp. */
244 if (adjustment_needed)
247 if (fd < 0 ? stat (file, &st) : fstat (fd, &st))
249 if (update_timespec (&st, &ts))
254 #if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
255 struct timeval timeval[2];
256 struct timeval const *t;
259 timeval[0].tv_sec = ts[0].tv_sec;
260 timeval[0].tv_usec = ts[0].tv_nsec / 1000;
261 timeval[1].tv_sec = ts[1].tv_sec;
262 timeval[1].tv_usec = ts[1].tv_nsec / 1000;
271 return futimesat (AT_FDCWD, file, t);
276 /* If futimesat or futimes fails here, don't try to speed things
277 up by returning right away. glibc can incorrectly fail with
278 errno == ENOENT if /proc isn't mounted. Also, Mandrake 10.0
279 in high security mode doesn't allow ordinary users to read
280 /proc/self, so glibc incorrectly fails with errno == EACCES.
281 If errno == EIO, EPERM, or EROFS, it's probably safe to fail
282 right away, but these cases are rare enough that they're not
283 worth optimizing, and who knows what other messed-up systems
284 are out there? So play it safe and fall back on the code
287 if (futimesat (fd, NULL, t) == 0)
290 if (futimes (fd, t) == 0)
294 #endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */
298 #if ! (HAVE_FUTIMESAT || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
304 #if HAVE_WORKING_UTIMES
305 return utimes (file, t);
308 struct utimbuf utimbuf;
312 utimbuf.actime = ts[0].tv_sec;
313 utimbuf.modtime = ts[1].tv_sec;
319 return utime (file, ut);
321 #endif /* !HAVE_WORKING_UTIMES */
325 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
326 TIMESPEC[0] and TIMESPEC[1], respectively.
327 FD must be either negative -- in which case it is ignored --
328 or a file descriptor that is open on FILE.
329 If FD is nonnegative, then FILE can be NULL, which means
330 use just futimes (or equivalent) instead of utimes (or equivalent),
331 and fail if on an old system without futimes (or equivalent).
332 If TIMESPEC is null, set the time stamps to the current time.
333 Return 0 on success, -1 (setting errno) on failure. */
336 gl_futimens (int fd, char const *file, struct timespec const timespec[2])
338 return fdutimens (file, fd, timespec);
341 /* Set the access and modification time stamps of FILE to be
342 TIMESPEC[0] and TIMESPEC[1], respectively. */
344 utimens (char const *file, struct timespec const timespec[2])
346 return gl_futimens (-1, file, timespec);
349 /* Set the access and modification time stamps of the symlink FILE to
350 be TIMESPEC[0] and TIMESPEC[1], respectively. Fail with ENOSYS if
351 the platform does not support changing symlink timestamps. */
353 lutimens (char const *file, struct timespec const timespec[2])
355 struct timespec adjusted_timespec[2];
356 struct timespec *ts = timespec ? adjusted_timespec : NULL;
357 int adjustment_needed = 0;
361 adjusted_timespec[0] = timespec[0];
362 adjusted_timespec[1] = timespec[1];
363 adjustment_needed = validate_timespec (ts);
365 if (adjustment_needed < 0)
368 /* The Linux kernel did not support symlink timestamps until
369 utimensat, in version 2.6.22, so we don't need to mimic
370 gl_futimens' worry about buggy NFS clients. But we do have to
371 worry about bogus return values. */
374 if (0 <= utimensat_works_really)
376 int result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW);
378 /* Work around a kernel bug:
379 http://bugzilla.redhat.com/442352
380 http://bugzilla.redhat.com/449910
381 It appears that utimensat can mistakenly return 280 rather
382 than -1 upon ENOSYS failure.
383 FIXME: remove in 2010 or whenever the offending kernels
384 are no longer in common use. */
388 if (result == 0 || errno != ENOSYS)
390 utimensat_works_really = 1;
394 utimensat_works_really = -1;
395 #endif /* HAVE_UTIMENSAT */
397 /* The platform lacks an interface to set file timestamps with
398 nanosecond resolution, so do the best we can, discarding any
399 fractional part of the timestamp. */
401 if (adjustment_needed)
404 if (lstat (file, &st))
406 if (update_timespec (&st, &ts))
412 struct timeval timeval[2];
413 struct timeval const *t;
416 timeval[0].tv_sec = ts[0].tv_sec;
417 timeval[0].tv_usec = ts[0].tv_nsec / 1000;
418 timeval[1].tv_sec = ts[1].tv_sec;
419 timeval[1].tv_usec = ts[1].tv_nsec / 1000;
425 return lutimes (file, t);
427 #endif /* HAVE_LUTIMES */
429 /* Out of luck. Symlink timestamps can't be changed. We won't
430 bother changing the timestamps if FILE was not a symlink. */