]> git.cworth.org Git - tar/blob - gnu/utimens.c
Imported Upstream version 1.24
[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 (int fd, char const *file, 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 *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 FILE to be
376    TIMESPEC[0] and TIMESPEC[1], respectively.  */
377 int
378 utimens (char const *file, struct timespec const timespec[2])
379 {
380   return fdutimens (-1, file, timespec);
381 }
382
383 /* Set the access and modification time stamps of FILE to be
384    TIMESPEC[0] and TIMESPEC[1], respectively, without dereferencing
385    symlinks.  Fail with ENOSYS if the platform does not support
386    changing symlink timestamps, but FILE was a symlink.  */
387 int
388 lutimens (char const *file, struct timespec const timespec[2])
389 {
390   struct timespec adjusted_timespec[2];
391   struct timespec *ts = timespec ? adjusted_timespec : NULL;
392   int adjustment_needed = 0;
393   struct stat st;
394
395   if (ts)
396     {
397       adjusted_timespec[0] = timespec[0];
398       adjusted_timespec[1] = timespec[1];
399       adjustment_needed = validate_timespec (ts);
400     }
401   if (adjustment_needed < 0)
402     return -1;
403
404   /* The Linux kernel did not support symlink timestamps until
405      utimensat, in version 2.6.22, so we don't need to mimic
406      fdutimens' worry about buggy NFS clients.  But we do have to
407      worry about bogus return values.  */
408
409 #if HAVE_UTIMENSAT
410   if (0 <= lutimensat_works_really)
411     {
412       int result;
413 # if __linux__
414       /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
415          systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
416          but work if both times are either explicitly specified or
417          UTIME_NOW.  Work around it with a preparatory lstat prior to
418          calling utimensat; fortunately, there is not much timing
419          impact due to the extra syscall even on file systems where
420          UTIME_OMIT would have worked.  FIXME: Simplify this in 2012,
421          when file system bugs are no longer common.  */
422       if (adjustment_needed == 2)
423         {
424           if (lstat (file, &st))
425             return -1;
426           if (ts[0].tv_nsec == UTIME_OMIT)
427             ts[0] = get_stat_atime (&st);
428           else if (ts[1].tv_nsec == UTIME_OMIT)
429             ts[1] = get_stat_mtime (&st);
430           /* Note that st is good, in case utimensat gives ENOSYS.  */
431           adjustment_needed++;
432         }
433 # endif /* __linux__ */
434       result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW);
435 # ifdef __linux__
436       /* Work around a kernel bug:
437          http://bugzilla.redhat.com/442352
438          http://bugzilla.redhat.com/449910
439          It appears that utimensat can mistakenly return 280 rather
440          than -1 upon ENOSYS failure.
441          FIXME: remove in 2010 or whenever the offending kernels
442          are no longer in common use.  */
443       if (0 < result)
444         errno = ENOSYS;
445 # endif
446       if (result == 0 || errno != ENOSYS)
447         {
448           utimensat_works_really = 1;
449           lutimensat_works_really = 1;
450           return result;
451         }
452     }
453   lutimensat_works_really = -1;
454 #endif /* HAVE_UTIMENSAT */
455
456   /* The platform lacks an interface to set file timestamps with
457      nanosecond resolution, so do the best we can, discarding any
458      fractional part of the timestamp.  */
459
460   if (adjustment_needed || REPLACE_FUNC_STAT_FILE)
461     {
462       if (adjustment_needed != 3 && lstat (file, &st))
463         return -1;
464       if (ts && update_timespec (&st, &ts))
465         return 0;
466     }
467
468   /* On Linux, lutimes is a thin wrapper around utimensat, so there is
469      no point trying lutimes if utimensat failed with ENOSYS.  */
470 #if HAVE_LUTIMES && !HAVE_UTIMENSAT
471   {
472     struct timeval timeval[2];
473     struct timeval *t;
474     int result;
475     if (ts)
476       {
477         timeval[0].tv_sec = ts[0].tv_sec;
478         timeval[0].tv_usec = ts[0].tv_nsec / 1000;
479         timeval[1].tv_sec = ts[1].tv_sec;
480         timeval[1].tv_usec = ts[1].tv_nsec / 1000;
481         t = timeval;
482       }
483     else
484       t = NULL;
485
486     result = lutimes (file, t);
487     if (result == 0 || errno != ENOSYS)
488       return result;
489   }
490 #endif /* HAVE_LUTIMES && !HAVE_UTIMENSAT */
491
492   /* Out of luck for symlinks, but we still handle regular files.  */
493   if (!(adjustment_needed || REPLACE_FUNC_STAT_FILE) && lstat (file, &st))
494     return -1;
495   if (!S_ISLNK (st.st_mode))
496     return fdutimens (-1, file, ts);
497   errno = ENOSYS;
498   return -1;
499 }