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 */
37 /* Some systems (even some that do have <utime.h>) don't declare this
38 structure anywhere. */
39 #ifndef HAVE_STRUCT_UTIMBUF
47 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
48 TIMESPEC[0] and TIMESPEC[1], respectively.
49 FD must be either negative -- in which case it is ignored --
50 or a file descriptor that is open on FILE.
51 If FD is nonnegative, then FILE can be NULL, which means
52 use just futimes (or equivalent) instead of utimes (or equivalent),
53 and fail if on an old system without futimes (or equivalent).
54 If TIMESPEC is null, set the time stamps to the current time.
55 Return 0 on success, -1 (setting errno) on failure. */
58 gl_futimens (int fd, char const *file, struct timespec const timespec[2])
60 /* Require that at least one of FD or FILE are valid. Works around
61 a Linux bug where futimens (AT_FDCWD, NULL) changes "." rather
70 if (dup2 (fd, fd) != fd)
74 /* Some Linux-based NFS clients are buggy, and mishandle time stamps
75 of files in NFS file systems in some cases. We have no
76 configure-time test for this, but please see
77 <http://bugs.gentoo.org/show_bug.cgi?id=132673> for references to
78 some of the problems with Linux 2.6.16. If this affects you,
79 compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to
80 help in some cases, albeit at a cost in performance. But you
81 really should upgrade your kernel to a fixed version, since the
82 problem affects many applications. */
84 #if HAVE_BUGGY_NFS_TIME_STAMPS
91 /* POSIX 200x added two interfaces to set file timestamps with
92 nanosecond resolution. We provide a fallback for ENOSYS (for
93 example, compiling against Linux 2.6.25 kernel headers and glibc
94 2.7, but running on Linux 2.6.18 kernel). */
98 int result = utimensat (AT_FDCWD, file, timespec, 0);
100 /* Work around what might be a kernel bug:
101 http://bugzilla.redhat.com/442352
102 http://bugzilla.redhat.com/449910
103 It appears that utimensat can mistakenly return 280 rather
104 than -1 upon failure.
105 FIXME: remove in 2010 or whenever the offending kernels
106 are no longer in common use. */
111 if (result == 0 || errno != ENOSYS)
117 int result = futimens (fd, timespec);
119 /* Work around the same bug as above. */
123 if (result == 0 || errno != ENOSYS)
128 /* The platform lacks an interface to set file timestamps with
129 nanosecond resolution, so do the best we can, discarding any
130 fractional part of the timestamp. */
132 #if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
133 struct timeval timeval[2];
134 struct timeval const *t;
137 timeval[0].tv_sec = timespec[0].tv_sec;
138 timeval[0].tv_usec = timespec[0].tv_nsec / 1000;
139 timeval[1].tv_sec = timespec[1].tv_sec;
140 timeval[1].tv_usec = timespec[1].tv_nsec / 1000;
149 return futimesat (AT_FDCWD, file, t);
154 /* If futimesat or futimes fails here, don't try to speed things
155 up by returning right away. glibc can incorrectly fail with
156 errno == ENOENT if /proc isn't mounted. Also, Mandrake 10.0
157 in high security mode doesn't allow ordinary users to read
158 /proc/self, so glibc incorrectly fails with errno == EACCES.
159 If errno == EIO, EPERM, or EROFS, it's probably safe to fail
160 right away, but these cases are rare enough that they're not
161 worth optimizing, and who knows what other messed-up systems
162 are out there? So play it safe and fall back on the code
165 if (futimesat (fd, NULL, t) == 0)
168 if (futimes (fd, t) == 0)
172 #endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */
176 #if ! (HAVE_FUTIMESAT || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
182 #if HAVE_WORKING_UTIMES
183 return utimes (file, t);
186 struct utimbuf utimbuf;
190 utimbuf.actime = timespec[0].tv_sec;
191 utimbuf.modtime = timespec[1].tv_sec;
197 return utime (file, ut);
199 #endif /* !HAVE_WORKING_UTIMES */
203 /* Set the access and modification time stamps of FILE to be
204 TIMESPEC[0] and TIMESPEC[1], respectively. */
206 utimens (char const *file, struct timespec const timespec[2])
208 return gl_futimens (-1, file, timespec);
211 /* Set the access and modification time stamps of the symlink FILE to
212 be TIMESPEC[0] and TIMESPEC[1], respectively. Fail with ENOSYS if
213 the platform does not support changing symlink timestamps. */
215 lutimens (char const *file _UNUSED_PARAMETER_,
216 struct timespec const timespec[2] _UNUSED_PARAMETER_)
218 /* The Linux kernel did not support symlink timestamps until
219 utimensat, in version 2.6.22, so we don't need to mimic
220 gl_futimens' worry about buggy NFS clients. But we do have to
221 worry about bogus return values. */
225 int result = utimensat (AT_FDCWD, file, timespec, AT_SYMLINK_NOFOLLOW);
227 /* Work around a kernel bug:
228 http://bugzilla.redhat.com/442352
229 http://bugzilla.redhat.com/449910
230 It appears that utimensat can mistakenly return 280 rather
231 than -1 upon ENOSYS failure.
232 FIXME: remove in 2010 or whenever the offending kernels
233 are no longer in common use. */
238 if (result == 0 || errno != ENOSYS)
241 #endif /* HAVE_UTIMENSAT */
243 /* The platform lacks an interface to set file timestamps with
244 nanosecond resolution, so do the best we can, discarding any
245 fractional part of the timestamp. */
248 struct timeval timeval[2];
249 struct timeval const *t;
252 timeval[0].tv_sec = timespec[0].tv_sec;
253 timeval[0].tv_usec = timespec[0].tv_nsec / 1000;
254 timeval[1].tv_sec = timespec[1].tv_sec;
255 timeval[1].tv_usec = timespec[1].tv_nsec / 1000;
261 return lutimes (file, t);
263 #endif /* HAVE_LUTIMES */
265 /* Out of luck. Symlink timestamps can't be changed. We won't
266 bother changing the timestamps if FILE was not a symlink. */