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