]> git.cworth.org Git - tar/blob - gnu/utimens.c
8ce10d104874144165ba7a1b8d446431352a177a
[tar] / gnu / utimens.c
1 /* -*- buffer-read-only: t -*- vi: set ro: */
2 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
3 /* Set file access and modification times.
4
5    Copyright (C) 2003-2010 Free Software Foundation, Inc.
6
7    This program is free software: you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by the
9    Free Software Foundation; either version 3 of the License, or any
10    later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20 /* Written by Paul Eggert.  */
21
22 /* derived from a function in touch.c */
23
24 #include <config.h>
25
26 #include "utimens.h"
27
28 #include <assert.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <stdbool.h>
32 #include <sys/stat.h>
33 #include <sys/time.h>
34 #include <unistd.h>
35
36 #include "stat-time.h"
37 #include "timespec.h"
38
39 #if HAVE_UTIME_H
40 # include <utime.h>
41 #endif
42
43 /* Some systems (even some that do have <utime.h>) don't declare this
44    structure anywhere.  */
45 #ifndef HAVE_STRUCT_UTIMBUF
46 struct utimbuf
47 {
48   long actime;
49   long modtime;
50 };
51 #endif
52
53 /* Avoid recursion with rpl_futimens or rpl_utimensat.  */
54 #undef futimens
55 #undef utimensat
56
57 /* Solaris 9 mistakenly succeeds when given a non-directory with a
58    trailing slash.  Force the use of rpl_stat for a fix.  */
59 #ifndef REPLACE_FUNC_STAT_FILE
60 # define REPLACE_FUNC_STAT_FILE 0
61 #endif
62
63 #if HAVE_UTIMENSAT || HAVE_FUTIMENS
64 /* Cache variables for whether the utimensat syscall works; used to
65    avoid calling the syscall if we know it will just fail with ENOSYS,
66    and to avoid unnecessary work in massaging timestamps if the
67    syscall will work.  Multiple variables are needed, to distinguish
68    between the following scenarios on Linux:
69    utimensat doesn't exist, or is in glibc but kernel 2.6.18 fails with ENOSYS
70    kernel 2.6.22 and earlier rejects AT_SYMLINK_NOFOLLOW
71    kernel 2.6.25 and earlier reject UTIME_NOW/UTIME_OMIT with non-zero tv_sec
72    kernel 2.6.32 used with xfs or ntfs-3g fail to honor UTIME_OMIT
73    utimensat completely works
74    For each cache variable: 0 = unknown, 1 = yes, -1 = no.  */
75 static int utimensat_works_really;
76 static int lutimensat_works_really;
77 #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
78
79 /* Validate the requested timestamps.  Return 0 if the resulting
80    timespec can be used for utimensat (after possibly modifying it to
81    work around bugs in utimensat).  Return a positive value if the
82    timespec needs further adjustment based on stat results: 1 if any
83    adjustment is needed for utimes, and 2 if any adjustment is needed
84    for Linux utimensat.  Return -1, with errno set to EINVAL, if
85    timespec is out of range.  */
86 static int
87 validate_timespec (struct timespec timespec[2])
88 {
89   int result = 0;
90   int utime_omit_count = 0;
91   assert (timespec);
92   if ((timespec[0].tv_nsec != UTIME_NOW
93        && timespec[0].tv_nsec != UTIME_OMIT
94        && (timespec[0].tv_nsec < 0 || 1000000000 <= timespec[0].tv_nsec))
95       || (timespec[1].tv_nsec != UTIME_NOW
96           && timespec[1].tv_nsec != UTIME_OMIT
97           && (timespec[1].tv_nsec < 0 || 1000000000 <= timespec[1].tv_nsec)))
98     {
99       errno = EINVAL;
100       return -1;
101     }
102   /* Work around Linux kernel 2.6.25 bug, where utimensat fails with
103      EINVAL if tv_sec is not 0 when using the flag values of tv_nsec.
104      Flag a Linux kernel 2.6.32 bug, where an mtime of UTIME_OMIT
105      fails to bump ctime.  */
106   if (timespec[0].tv_nsec == UTIME_NOW
107       || timespec[0].tv_nsec == UTIME_OMIT)
108     {
109       timespec[0].tv_sec = 0;
110       result = 1;
111       if (timespec[0].tv_nsec == UTIME_OMIT)
112         utime_omit_count++;
113     }
114   if (timespec[1].tv_nsec == UTIME_NOW
115       || timespec[1].tv_nsec == UTIME_OMIT)
116     {
117       timespec[1].tv_sec = 0;
118       result = 1;
119       if (timespec[1].tv_nsec == UTIME_OMIT)
120         utime_omit_count++;
121     }
122   return result + (utime_omit_count == 1);
123 }
124
125 /* Normalize any UTIME_NOW or UTIME_OMIT values in *TS, using stat
126    buffer STATBUF to obtain the current timestamps of the file.  If
127    both times are UTIME_NOW, set *TS to NULL (as this can avoid some
128    permissions issues).  If both times are UTIME_OMIT, return true
129    (nothing further beyond the prior collection of STATBUF is
130    necessary); otherwise return false.  */
131 static bool
132 update_timespec (struct stat const *statbuf, struct timespec *ts[2])
133 {
134   struct timespec *timespec = *ts;
135   if (timespec[0].tv_nsec == UTIME_OMIT
136       && timespec[1].tv_nsec == UTIME_OMIT)
137     return true;
138   if (timespec[0].tv_nsec == UTIME_NOW
139       && timespec[1].tv_nsec == UTIME_NOW)
140     {
141       *ts = NULL;
142       return false;
143     }
144
145   if (timespec[0].tv_nsec == UTIME_OMIT)
146     timespec[0] = get_stat_atime (statbuf);
147   else if (timespec[0].tv_nsec == UTIME_NOW)
148     gettime (&timespec[0]);
149
150   if (timespec[1].tv_nsec == UTIME_OMIT)
151     timespec[1] = get_stat_mtime (statbuf);
152   else if (timespec[1].tv_nsec == UTIME_NOW)
153     gettime (&timespec[1]);
154
155   return false;
156 }
157
158 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
159    TIMESPEC[0] and TIMESPEC[1], respectively.
160    FD must be either negative -- in which case it is ignored --
161    or a file descriptor that is open on FILE.
162    If FD is nonnegative, then FILE can be NULL, which means
163    use just futimes (or equivalent) instead of utimes (or equivalent),
164    and fail if on an old system without futimes (or equivalent).
165    If TIMESPEC is null, set the time stamps to the current time.
166    Return 0 on success, -1 (setting errno) on failure.  */
167
168 int
169 fdutimens (char const *file, int fd, struct timespec const timespec[2])
170 {
171   struct timespec adjusted_timespec[2];
172   struct timespec *ts = timespec ? adjusted_timespec : NULL;
173   int adjustment_needed = 0;
174   struct stat st;
175
176   if (ts)
177     {
178       adjusted_timespec[0] = timespec[0];
179       adjusted_timespec[1] = timespec[1];
180       adjustment_needed = validate_timespec (ts);
181     }
182   if (adjustment_needed < 0)
183     return -1;
184
185   /* Require that at least one of FD or FILE are valid.  Works around
186      a Linux bug where futimens (AT_FDCWD, NULL) changes "." rather
187      than failing.  */
188   if (!file)
189     {
190       if (fd < 0)
191         {
192           errno = EBADF;
193           return -1;
194         }
195       if (dup2 (fd, fd) != fd)
196         return -1;
197     }
198
199   /* Some Linux-based NFS clients are buggy, and mishandle time stamps
200      of files in NFS file systems in some cases.  We have no
201      configure-time test for this, but please see
202      <http://bugs.gentoo.org/show_bug.cgi?id=132673> for references to
203      some of the problems with Linux 2.6.16.  If this affects you,
204      compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to
205      help in some cases, albeit at a cost in performance.  But you
206      really should upgrade your kernel to a fixed version, since the
207      problem affects many applications.  */
208
209 #if HAVE_BUGGY_NFS_TIME_STAMPS
210   if (fd < 0)
211     sync ();
212   else
213     fsync (fd);
214 #endif
215
216   /* POSIX 2008 added two interfaces to set file timestamps with
217      nanosecond resolution; newer Linux implements both functions via
218      a single syscall.  We provide a fallback for ENOSYS (for example,
219      compiling against Linux 2.6.25 kernel headers and glibc 2.7, but
220      running on Linux 2.6.18 kernel).  */
221 #if HAVE_UTIMENSAT || HAVE_FUTIMENS
222   if (0 <= utimensat_works_really)
223     {
224       int result;
225 # if __linux__
226       /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
227          systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
228          but work if both times are either explicitly specified or
229          UTIME_NOW.  Work around it with a preparatory [f]stat prior
230          to calling futimens/utimensat; fortunately, there is not much
231          timing impact due to the extra syscall even on file systems
232          where UTIME_OMIT would have worked.  FIXME: Simplify this in
233          2012, when file system bugs are no longer common.  */
234       if (adjustment_needed == 2)
235         {
236           if (fd < 0 ? stat (file, &st) : fstat (fd, &st))
237             return -1;
238           if (ts[0].tv_nsec == UTIME_OMIT)
239             ts[0] = get_stat_atime (&st);
240           else if (ts[1].tv_nsec == UTIME_OMIT)
241             ts[1] = get_stat_mtime (&st);
242           /* Note that st is good, in case utimensat gives ENOSYS.  */
243           adjustment_needed++;
244         }
245 # endif /* __linux__ */
246 # if HAVE_UTIMENSAT
247       if (fd < 0)
248         {
249           result = utimensat (AT_FDCWD, file, ts, 0);
250 #  ifdef __linux__
251           /* Work around a kernel bug:
252              http://bugzilla.redhat.com/442352
253              http://bugzilla.redhat.com/449910
254              It appears that utimensat can mistakenly return 280 rather
255              than -1 upon ENOSYS failure.
256              FIXME: remove in 2010 or whenever the offending kernels
257              are no longer in common use.  */
258           if (0 < result)
259             errno = ENOSYS;
260 #  endif /* __linux__ */
261           if (result == 0 || errno != ENOSYS)
262             {
263               utimensat_works_really = 1;
264               return result;
265             }
266         }
267 # endif /* HAVE_UTIMENSAT */
268 # if HAVE_FUTIMENS
269       if (0 <= fd)
270         {
271           result = futimens (fd, ts);
272 #  ifdef __linux__
273           /* Work around the same bug as above.  */
274           if (0 < result)
275             errno = ENOSYS;
276 #  endif /* __linux__ */
277           if (result == 0 || errno != ENOSYS)
278             {
279               utimensat_works_really = 1;
280               return result;
281             }
282         }
283 # endif /* HAVE_FUTIMENS */
284     }
285   utimensat_works_really = -1;
286   lutimensat_works_really = -1;
287 #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
288
289   /* The platform lacks an interface to set file timestamps with
290      nanosecond resolution, so do the best we can, discarding any
291      fractional part of the timestamp.  */
292
293   if (adjustment_needed || (REPLACE_FUNC_STAT_FILE && fd < 0))
294     {
295       if (adjustment_needed != 3
296           && (fd < 0 ? stat (file, &st) : fstat (fd, &st)))
297         return -1;
298       if (ts && update_timespec (&st, &ts))
299         return 0;
300     }
301
302   {
303 #if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
304     struct timeval timeval[2];
305     struct timeval const *t;
306     if (ts)
307       {
308         timeval[0].tv_sec = ts[0].tv_sec;
309         timeval[0].tv_usec = ts[0].tv_nsec / 1000;
310         timeval[1].tv_sec = ts[1].tv_sec;
311         timeval[1].tv_usec = ts[1].tv_nsec / 1000;
312         t = timeval;
313       }
314     else
315       t = NULL;
316
317     if (fd < 0)
318       {
319 # if HAVE_FUTIMESAT
320         return futimesat (AT_FDCWD, file, t);
321 # endif
322       }
323     else
324       {
325         /* If futimesat or futimes fails here, don't try to speed things
326            up by returning right away.  glibc can incorrectly fail with
327            errno == ENOENT if /proc isn't mounted.  Also, Mandrake 10.0
328            in high security mode doesn't allow ordinary users to read
329            /proc/self, so glibc incorrectly fails with errno == EACCES.
330            If errno == EIO, EPERM, or EROFS, it's probably safe to fail
331            right away, but these cases are rare enough that they're not
332            worth optimizing, and who knows what other messed-up systems
333            are out there?  So play it safe and fall back on the code
334            below.  */
335 # if HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG
336         if (futimesat (fd, NULL, t) == 0)
337           return 0;
338 # elif HAVE_FUTIMES
339         if (futimes (fd, t) == 0)
340           return 0;
341 # endif
342       }
343 #endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */
344
345     if (!file)
346       {
347 #if ! ((HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG)          \
348         || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
349         errno = ENOSYS;
350 #endif
351         return -1;
352       }
353
354 #if HAVE_WORKING_UTIMES
355     return utimes (file, t);
356 #else
357     {
358       struct utimbuf utimbuf;
359       struct utimbuf *ut;
360       if (ts)
361         {
362           utimbuf.actime = ts[0].tv_sec;
363           utimbuf.modtime = ts[1].tv_sec;
364           ut = &utimbuf;
365         }
366       else
367         ut = NULL;
368
369       return utime (file, ut);
370     }
371 #endif /* !HAVE_WORKING_UTIMES */
372   }
373 }
374
375 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
376    TIMESPEC[0] and TIMESPEC[1], respectively.
377    FD must be either negative -- in which case it is ignored --
378    or a file descriptor that is open on FILE.
379    If FD is nonnegative, then FILE can be NULL, which means
380    use just futimes (or equivalent) instead of utimes (or equivalent),
381    and fail if on an old system without futimes (or equivalent).
382    If TIMESPEC is null, set the time stamps to the current time.
383    Return 0 on success, -1 (setting errno) on failure.  */
384
385 int
386 gl_futimens (int fd, char const *file, struct timespec const timespec[2])
387 {
388   return fdutimens (file, fd, timespec);
389 }
390
391 /* Set the access and modification time stamps of FILE to be
392    TIMESPEC[0] and TIMESPEC[1], respectively.  */
393 int
394 utimens (char const *file, struct timespec const timespec[2])
395 {
396   return fdutimens (file, -1, timespec);
397 }
398
399 /* Set the access and modification time stamps of FILE to be
400    TIMESPEC[0] and TIMESPEC[1], respectively, without dereferencing
401    symlinks.  Fail with ENOSYS if the platform does not support
402    changing symlink timestamps, but FILE was a symlink.  */
403 int
404 lutimens (char const *file, struct timespec const timespec[2])
405 {
406   struct timespec adjusted_timespec[2];
407   struct timespec *ts = timespec ? adjusted_timespec : NULL;
408   int adjustment_needed = 0;
409   struct stat st;
410
411   if (ts)
412     {
413       adjusted_timespec[0] = timespec[0];
414       adjusted_timespec[1] = timespec[1];
415       adjustment_needed = validate_timespec (ts);
416     }
417   if (adjustment_needed < 0)
418     return -1;
419
420   /* The Linux kernel did not support symlink timestamps until
421      utimensat, in version 2.6.22, so we don't need to mimic
422      gl_futimens' worry about buggy NFS clients.  But we do have to
423      worry about bogus return values.  */
424
425 #if HAVE_UTIMENSAT
426   if (0 <= lutimensat_works_really)
427     {
428       int result;
429 # if __linux__
430       /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
431          systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
432          but work if both times are either explicitly specified or
433          UTIME_NOW.  Work around it with a preparatory lstat prior to
434          calling utimensat; fortunately, there is not much timing
435          impact due to the extra syscall even on file systems where
436          UTIME_OMIT would have worked.  FIXME: Simplify this in 2012,
437          when file system bugs are no longer common.  */
438       if (adjustment_needed == 2)
439         {
440           if (lstat (file, &st))
441             return -1;
442           if (ts[0].tv_nsec == UTIME_OMIT)
443             ts[0] = get_stat_atime (&st);
444           else if (ts[1].tv_nsec == UTIME_OMIT)
445             ts[1] = get_stat_mtime (&st);
446           /* Note that st is good, in case utimensat gives ENOSYS.  */
447           adjustment_needed++;
448         }
449 # endif /* __linux__ */
450       result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW);
451 # ifdef __linux__
452       /* Work around a kernel bug:
453          http://bugzilla.redhat.com/442352
454          http://bugzilla.redhat.com/449910
455          It appears that utimensat can mistakenly return 280 rather
456          than -1 upon ENOSYS failure.
457          FIXME: remove in 2010 or whenever the offending kernels
458          are no longer in common use.  */
459       if (0 < result)
460         errno = ENOSYS;
461 # endif
462       if (result == 0 || errno != ENOSYS)
463         {
464           utimensat_works_really = 1;
465           lutimensat_works_really = 1;
466           return result;
467         }
468     }
469   lutimensat_works_really = -1;
470 #endif /* HAVE_UTIMENSAT */
471
472   /* The platform lacks an interface to set file timestamps with
473      nanosecond resolution, so do the best we can, discarding any
474      fractional part of the timestamp.  */
475
476   if (adjustment_needed || REPLACE_FUNC_STAT_FILE)
477     {
478       if (adjustment_needed != 3 && lstat (file, &st))
479         return -1;
480       if (ts && update_timespec (&st, &ts))
481         return 0;
482     }
483
484   /* On Linux, lutimes is a thin wrapper around utimensat, so there is
485      no point trying lutimes if utimensat failed with ENOSYS.  */
486 #if HAVE_LUTIMES && !HAVE_UTIMENSAT
487   {
488     struct timeval timeval[2];
489     struct timeval const *t;
490     int result;
491     if (ts)
492       {
493         timeval[0].tv_sec = ts[0].tv_sec;
494         timeval[0].tv_usec = ts[0].tv_nsec / 1000;
495         timeval[1].tv_sec = ts[1].tv_sec;
496         timeval[1].tv_usec = ts[1].tv_nsec / 1000;
497         t = timeval;
498       }
499     else
500       t = NULL;
501
502     result = lutimes (file, t);
503     if (result == 0 || errno != ENOSYS)
504       return result;
505   }
506 #endif /* HAVE_LUTIMES && !HAVE_UTIMENSAT */
507
508   /* Out of luck for symlinks, but we still handle regular files.  */
509   if (!(adjustment_needed || REPLACE_FUNC_STAT_FILE) && lstat (file, &st))
510     return -1;
511   if (!S_ISLNK (st.st_mode))
512     return fdutimens (file, -1, ts);
513   errno = ENOSYS;
514   return -1;
515 }