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 variables for whether the utimensat syscall works; used to
58 avoid calling the syscall if we know it will just fail with ENOSYS.
59 There are some Linux kernel versions where a flag of 0 passes, but
60 not AT_SYMLINK_NOFOLLOW. 0 = unknown, 1 = yes, -1 = no. */
61 static int utimensat_works_really;
62 static int lutimensat_works_really;
63 #endif /* HAVE_UTIMENSAT || HAVE_UTIMENSAT */
65 /* Solaris 9 mistakenly succeeds when given a non-directory with a
66 trailing slash. Force the use of rpl_stat for a fix. */
67 #ifndef REPLACE_FUNC_STAT_FILE
68 # define REPLACE_FUNC_STAT_FILE 0
71 /* Validate the requested timestamps. Return 0 if the resulting
72 timespec can be used for utimensat (after possibly modifying it to
73 work around bugs in utimensat). Return 1 if the timespec needs
74 further adjustment based on stat results for utimes or other less
75 powerful interfaces. Return -1, with errno set to EINVAL, if
76 timespec is out of range. */
78 validate_timespec (struct timespec timespec[2])
82 if ((timespec[0].tv_nsec != UTIME_NOW
83 && timespec[0].tv_nsec != UTIME_OMIT
84 && (timespec[0].tv_nsec < 0 || 1000000000 <= timespec[0].tv_nsec))
85 || (timespec[1].tv_nsec != UTIME_NOW
86 && timespec[1].tv_nsec != UTIME_OMIT
87 && (timespec[1].tv_nsec < 0 || 1000000000 <= timespec[1].tv_nsec)))
92 /* Work around Linux kernel 2.6.25 bug, where utimensat fails with
93 EINVAL if tv_sec is not 0 when using the flag values of
95 if (timespec[0].tv_nsec == UTIME_NOW
96 || timespec[0].tv_nsec == UTIME_OMIT)
98 timespec[0].tv_sec = 0;
101 if (timespec[1].tv_nsec == UTIME_NOW
102 || timespec[1].tv_nsec == UTIME_OMIT)
104 timespec[1].tv_sec = 0;
110 /* Normalize any UTIME_NOW or UTIME_OMIT values in *TS, using stat
111 buffer STATBUF to obtain the current timestamps of the file. If
112 both times are UTIME_NOW, set *TS to NULL (as this can avoid some
113 permissions issues). If both times are UTIME_OMIT, return true
114 (nothing further beyond the prior collection of STATBUF is
115 necessary); otherwise return false. */
117 update_timespec (struct stat const *statbuf, struct timespec *ts[2])
119 struct timespec *timespec = *ts;
120 if (timespec[0].tv_nsec == UTIME_OMIT
121 && timespec[1].tv_nsec == UTIME_OMIT)
123 if (timespec[0].tv_nsec == UTIME_NOW
124 && timespec[1].tv_nsec == UTIME_NOW)
130 if (timespec[0].tv_nsec == UTIME_OMIT)
131 timespec[0] = get_stat_atime (statbuf);
132 else if (timespec[0].tv_nsec == UTIME_NOW)
133 gettime (×pec[0]);
135 if (timespec[1].tv_nsec == UTIME_OMIT)
136 timespec[1] = get_stat_mtime (statbuf);
137 else if (timespec[1].tv_nsec == UTIME_NOW)
138 gettime (×pec[1]);
143 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
144 TIMESPEC[0] and TIMESPEC[1], respectively.
145 FD must be either negative -- in which case it is ignored --
146 or a file descriptor that is open on FILE.
147 If FD is nonnegative, then FILE can be NULL, which means
148 use just futimes (or equivalent) instead of utimes (or equivalent),
149 and fail if on an old system without futimes (or equivalent).
150 If TIMESPEC is null, set the time stamps to the current time.
151 Return 0 on success, -1 (setting errno) on failure. */
154 fdutimens (char const *file, int fd, struct timespec const timespec[2])
156 struct timespec adjusted_timespec[2];
157 struct timespec *ts = timespec ? adjusted_timespec : NULL;
158 int adjustment_needed = 0;
162 adjusted_timespec[0] = timespec[0];
163 adjusted_timespec[1] = timespec[1];
164 adjustment_needed = validate_timespec (ts);
166 if (adjustment_needed < 0)
169 /* Require that at least one of FD or FILE are valid. Works around
170 a Linux bug where futimens (AT_FDCWD, NULL) changes "." rather
179 if (dup2 (fd, fd) != fd)
183 /* Some Linux-based NFS clients are buggy, and mishandle time stamps
184 of files in NFS file systems in some cases. We have no
185 configure-time test for this, but please see
186 <http://bugs.gentoo.org/show_bug.cgi?id=132673> for references to
187 some of the problems with Linux 2.6.16. If this affects you,
188 compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to
189 help in some cases, albeit at a cost in performance. But you
190 really should upgrade your kernel to a fixed version, since the
191 problem affects many applications. */
193 #if HAVE_BUGGY_NFS_TIME_STAMPS
200 /* POSIX 2008 added two interfaces to set file timestamps with
201 nanosecond resolution; newer Linux implements both functions via
202 a single syscall. We provide a fallback for ENOSYS (for example,
203 compiling against Linux 2.6.25 kernel headers and glibc 2.7, but
204 running on Linux 2.6.18 kernel). */
205 #if HAVE_UTIMENSAT || HAVE_FUTIMENS
206 if (0 <= utimensat_works_really)
211 int result = utimensat (AT_FDCWD, file, ts, 0);
213 /* Work around a kernel bug:
214 http://bugzilla.redhat.com/442352
215 http://bugzilla.redhat.com/449910
216 It appears that utimensat can mistakenly return 280 rather
217 than -1 upon ENOSYS failure.
218 FIXME: remove in 2010 or whenever the offending kernels
219 are no longer in common use. */
222 # endif /* __linux__ */
223 if (result == 0 || errno != ENOSYS)
225 utimensat_works_really = 1;
229 # endif /* HAVE_UTIMENSAT */
232 int result = futimens (fd, ts);
234 /* Work around the same bug as above. */
237 # endif /* __linux__ */
238 if (result == 0 || errno != ENOSYS)
240 utimensat_works_really = 1;
244 # endif /* HAVE_FUTIMENS */
246 utimensat_works_really = -1;
247 lutimensat_works_really = -1;
248 #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
250 /* The platform lacks an interface to set file timestamps with
251 nanosecond resolution, so do the best we can, discarding any
252 fractional part of the timestamp. */
254 if (adjustment_needed || (REPLACE_FUNC_STAT_FILE && fd < 0))
257 if (fd < 0 ? stat (file, &st) : fstat (fd, &st))
259 if (ts && update_timespec (&st, &ts))
264 #if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
265 struct timeval timeval[2];
266 struct timeval const *t;
269 timeval[0].tv_sec = ts[0].tv_sec;
270 timeval[0].tv_usec = ts[0].tv_nsec / 1000;
271 timeval[1].tv_sec = ts[1].tv_sec;
272 timeval[1].tv_usec = ts[1].tv_nsec / 1000;
281 return futimesat (AT_FDCWD, file, t);
286 /* If futimesat or futimes fails here, don't try to speed things
287 up by returning right away. glibc can incorrectly fail with
288 errno == ENOENT if /proc isn't mounted. Also, Mandrake 10.0
289 in high security mode doesn't allow ordinary users to read
290 /proc/self, so glibc incorrectly fails with errno == EACCES.
291 If errno == EIO, EPERM, or EROFS, it's probably safe to fail
292 right away, but these cases are rare enough that they're not
293 worth optimizing, and who knows what other messed-up systems
294 are out there? So play it safe and fall back on the code
296 # if HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG
297 if (futimesat (fd, NULL, t) == 0)
300 if (futimes (fd, t) == 0)
304 #endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */
308 #if ! ((HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) \
309 || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
315 #if HAVE_WORKING_UTIMES
316 return utimes (file, t);
319 struct utimbuf utimbuf;
323 utimbuf.actime = ts[0].tv_sec;
324 utimbuf.modtime = ts[1].tv_sec;
330 return utime (file, ut);
332 #endif /* !HAVE_WORKING_UTIMES */
336 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
337 TIMESPEC[0] and TIMESPEC[1], respectively.
338 FD must be either negative -- in which case it is ignored --
339 or a file descriptor that is open on FILE.
340 If FD is nonnegative, then FILE can be NULL, which means
341 use just futimes (or equivalent) instead of utimes (or equivalent),
342 and fail if on an old system without futimes (or equivalent).
343 If TIMESPEC is null, set the time stamps to the current time.
344 Return 0 on success, -1 (setting errno) on failure. */
347 gl_futimens (int fd, char const *file, struct timespec const timespec[2])
349 return fdutimens (file, fd, timespec);
352 /* Set the access and modification time stamps of FILE to be
353 TIMESPEC[0] and TIMESPEC[1], respectively. */
355 utimens (char const *file, struct timespec const timespec[2])
357 return fdutimens (file, -1, timespec);
360 /* Set the access and modification time stamps of FILE to be
361 TIMESPEC[0] and TIMESPEC[1], respectively, without dereferencing
362 symlinks. Fail with ENOSYS if the platform does not support
363 changing symlink timestamps, but FILE was a symlink. */
365 lutimens (char const *file, struct timespec const timespec[2])
367 struct timespec adjusted_timespec[2];
368 struct timespec *ts = timespec ? adjusted_timespec : NULL;
369 int adjustment_needed = 0;
374 adjusted_timespec[0] = timespec[0];
375 adjusted_timespec[1] = timespec[1];
376 adjustment_needed = validate_timespec (ts);
378 if (adjustment_needed < 0)
381 /* The Linux kernel did not support symlink timestamps until
382 utimensat, in version 2.6.22, so we don't need to mimic
383 gl_futimens' worry about buggy NFS clients. But we do have to
384 worry about bogus return values. */
387 if (0 <= lutimensat_works_really)
389 int result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW);
391 /* Work around a kernel bug:
392 http://bugzilla.redhat.com/442352
393 http://bugzilla.redhat.com/449910
394 It appears that utimensat can mistakenly return 280 rather
395 than -1 upon ENOSYS failure.
396 FIXME: remove in 2010 or whenever the offending kernels
397 are no longer in common use. */
401 if (result == 0 || errno != ENOSYS)
403 utimensat_works_really = 1;
404 lutimensat_works_really = 1;
408 lutimensat_works_really = -1;
409 #endif /* HAVE_UTIMENSAT */
411 /* The platform lacks an interface to set file timestamps with
412 nanosecond resolution, so do the best we can, discarding any
413 fractional part of the timestamp. */
415 if (adjustment_needed || REPLACE_FUNC_STAT_FILE)
417 if (lstat (file, &st))
419 if (ts && update_timespec (&st, &ts))
423 /* On Linux, lutimes is a thin wrapper around utimensat, so there is
424 no point trying lutimes if utimensat failed with ENOSYS. */
425 #if HAVE_LUTIMES && !HAVE_UTIMENSAT
427 struct timeval timeval[2];
428 struct timeval const *t;
431 timeval[0].tv_sec = ts[0].tv_sec;
432 timeval[0].tv_usec = ts[0].tv_nsec / 1000;
433 timeval[1].tv_sec = ts[1].tv_sec;
434 timeval[1].tv_usec = ts[1].tv_nsec / 1000;
440 result = lutimes (file, t);
441 if (result == 0 || errno != ENOSYS)
444 #endif /* HAVE_LUTIMES && !HAVE_UTIMENSAT */
446 /* Out of luck for symlinks, but we still handle regular files. */
447 if (!(adjustment_needed || REPLACE_FUNC_STAT_FILE) && lstat (file, &st))
449 if (!S_ISLNK (st.st_mode))
450 return fdutimens (file, -1, ts);