utimens: fix compilation error
[gnulib.git] / lib / utimens.c
1 /* Set file access and modification times.
2
3    Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free
4    Software Foundation, Inc.
5
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
9    later version.
10
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.
15
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/>.  */
18
19 /* Written by Paul Eggert.  */
20
21 /* derived from a function in touch.c */
22
23 #include <config.h>
24
25 #include "utimens.h"
26
27 #include <assert.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <stdbool.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33 #include <unistd.h>
34
35 #include "stat-time.h"
36 #include "timespec.h"
37
38 #if HAVE_UTIME_H
39 # include <utime.h>
40 #endif
41
42 /* Some systems (even some that do have <utime.h>) don't declare this
43    structure anywhere.  */
44 #ifndef HAVE_STRUCT_UTIMBUF
45 struct utimbuf
46 {
47   long actime;
48   long modtime;
49 };
50 #endif
51
52 /* Avoid recursion with rpl_futimens or rpl_utimensat.  */
53 #undef futimens
54 #undef utimensat
55
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 */
64
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
69 #endif
70
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.  */
77 static int
78 validate_timespec (struct timespec timespec[2])
79 {
80   int result = 0;
81   assert (timespec);
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)))
88     {
89       errno = EINVAL;
90       return -1;
91     }
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
94      tv_nsec.  */
95   if (timespec[0].tv_nsec == UTIME_NOW
96       || timespec[0].tv_nsec == UTIME_OMIT)
97     {
98       timespec[0].tv_sec = 0;
99       result = 1;
100     }
101   if (timespec[1].tv_nsec == UTIME_NOW
102       || timespec[1].tv_nsec == UTIME_OMIT)
103     {
104       timespec[1].tv_sec = 0;
105       result = 1;
106     }
107   return result;
108 }
109
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.  */
116 static bool
117 update_timespec (struct stat const *statbuf, struct timespec *ts[2])
118 {
119   struct timespec *timespec = *ts;
120   if (timespec[0].tv_nsec == UTIME_OMIT
121       && timespec[1].tv_nsec == UTIME_OMIT)
122     return true;
123   if (timespec[0].tv_nsec == UTIME_NOW
124       && timespec[1].tv_nsec == UTIME_NOW)
125     {
126       *ts = NULL;
127       return false;
128     }
129
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 (&timespec[0]);
134
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 (&timespec[1]);
139
140   return false;
141 }
142
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.  */
152
153 int
154 fdutimens (char const *file, int fd, struct timespec const timespec[2])
155 {
156   struct timespec adjusted_timespec[2];
157   struct timespec *ts = timespec ? adjusted_timespec : NULL;
158   int adjustment_needed = 0;
159
160   if (ts)
161     {
162       adjusted_timespec[0] = timespec[0];
163       adjusted_timespec[1] = timespec[1];
164       adjustment_needed = validate_timespec (ts);
165     }
166   if (adjustment_needed < 0)
167     return -1;
168
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
171      than failing.  */
172   if (!file)
173     {
174       if (fd < 0)
175         {
176           errno = EBADF;
177           return -1;
178         }
179       if (dup2 (fd, fd) != fd)
180         return -1;
181     }
182
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.  */
192
193 #if HAVE_BUGGY_NFS_TIME_STAMPS
194   if (fd < 0)
195     sync ();
196   else
197     fsync (fd);
198 #endif
199
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)
207     {
208 # if HAVE_UTIMENSAT
209       if (fd < 0)
210         {
211           int result = utimensat (AT_FDCWD, file, ts, 0);
212 #  ifdef __linux__
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.  */
220           if (0 < result)
221             errno = ENOSYS;
222 #  endif /* __linux__ */
223           if (result == 0 || errno != ENOSYS)
224             {
225               utimensat_works_really = 1;
226               return result;
227             }
228         }
229 # endif /* HAVE_UTIMENSAT */
230 # if HAVE_FUTIMENS
231       {
232         int result = futimens (fd, ts);
233 #  ifdef __linux__
234         /* Work around the same bug as above.  */
235         if (0 < result)
236           errno = ENOSYS;
237 #  endif /* __linux__ */
238         if (result == 0 || errno != ENOSYS)
239           {
240             utimensat_works_really = 1;
241             return result;
242           }
243       }
244 # endif /* HAVE_FUTIMENS */
245     }
246   utimensat_works_really = -1;
247   lutimensat_works_really = -1;
248 #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
249
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.  */
253
254   if (adjustment_needed || (REPLACE_FUNC_STAT_FILE && fd < 0))
255     {
256       struct stat st;
257       if (fd < 0 ? stat (file, &st) : fstat (fd, &st))
258         return -1;
259       if (ts && update_timespec (&st, &ts))
260         return 0;
261     }
262
263   {
264 #if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
265     struct timeval timeval[2];
266     struct timeval const *t;
267     if (ts)
268       {
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;
273         t = timeval;
274       }
275     else
276       t = NULL;
277
278     if (fd < 0)
279       {
280 # if HAVE_FUTIMESAT
281         return futimesat (AT_FDCWD, file, t);
282 # endif
283       }
284     else
285       {
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
295            below.  */
296 # if HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG
297         if (futimesat (fd, NULL, t) == 0)
298           return 0;
299 # elif HAVE_FUTIMES
300         if (futimes (fd, t) == 0)
301           return 0;
302 # endif
303       }
304 #endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */
305
306     if (!file)
307       {
308 #if ! ((HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG)          \
309         || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
310         errno = ENOSYS;
311 #endif
312         return -1;
313       }
314
315 #if HAVE_WORKING_UTIMES
316     return utimes (file, t);
317 #else
318     {
319       struct utimbuf utimbuf;
320       struct utimbuf *ut;
321       if (ts)
322         {
323           utimbuf.actime = ts[0].tv_sec;
324           utimbuf.modtime = ts[1].tv_sec;
325           ut = &utimbuf;
326         }
327       else
328         ut = NULL;
329
330       return utime (file, ut);
331     }
332 #endif /* !HAVE_WORKING_UTIMES */
333   }
334 }
335
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.  */
345
346 int
347 gl_futimens (int fd, char const *file, struct timespec const timespec[2])
348 {
349   return fdutimens (file, fd, timespec);
350 }
351
352 /* Set the access and modification time stamps of FILE to be
353    TIMESPEC[0] and TIMESPEC[1], respectively.  */
354 int
355 utimens (char const *file, struct timespec const timespec[2])
356 {
357   return fdutimens (file, -1, timespec);
358 }
359
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.  */
364 int
365 lutimens (char const *file, struct timespec const timespec[2])
366 {
367   struct timespec adjusted_timespec[2];
368   struct timespec *ts = timespec ? adjusted_timespec : NULL;
369   int adjustment_needed = 0;
370   struct stat st;
371   int result;
372
373   if (ts)
374     {
375       adjusted_timespec[0] = timespec[0];
376       adjusted_timespec[1] = timespec[1];
377       adjustment_needed = validate_timespec (ts);
378     }
379   if (adjustment_needed < 0)
380     return -1;
381
382   /* The Linux kernel did not support symlink timestamps until
383      utimensat, in version 2.6.22, so we don't need to mimic
384      gl_futimens' worry about buggy NFS clients.  But we do have to
385      worry about bogus return values.  */
386
387 #if HAVE_UTIMENSAT
388   if (0 <= lutimensat_works_really)
389     {
390       result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW);
391 # ifdef __linux__
392       /* Work around a kernel bug:
393          http://bugzilla.redhat.com/442352
394          http://bugzilla.redhat.com/449910
395          It appears that utimensat can mistakenly return 280 rather
396          than -1 upon ENOSYS failure.
397          FIXME: remove in 2010 or whenever the offending kernels
398          are no longer in common use.  */
399       if (0 < result)
400         errno = ENOSYS;
401 # endif
402       if (result == 0 || errno != ENOSYS)
403         {
404           utimensat_works_really = 1;
405           lutimensat_works_really = 1;
406           return result;
407         }
408     }
409   lutimensat_works_really = -1;
410 #endif /* HAVE_UTIMENSAT */
411
412   /* The platform lacks an interface to set file timestamps with
413      nanosecond resolution, so do the best we can, discarding any
414      fractional part of the timestamp.  */
415
416   if (adjustment_needed || REPLACE_FUNC_STAT_FILE)
417     {
418       if (lstat (file, &st))
419         return -1;
420       if (ts && update_timespec (&st, &ts))
421         return 0;
422     }
423
424   /* On Linux, lutimes is a thin wrapper around utimensat, so there is
425      no point trying lutimes if utimensat failed with ENOSYS.  */
426 #if HAVE_LUTIMES && !HAVE_UTIMENSAT
427   {
428     struct timeval timeval[2];
429     struct timeval const *t;
430     if (ts)
431       {
432         timeval[0].tv_sec = ts[0].tv_sec;
433         timeval[0].tv_usec = ts[0].tv_nsec / 1000;
434         timeval[1].tv_sec = ts[1].tv_sec;
435         timeval[1].tv_usec = ts[1].tv_nsec / 1000;
436         t = timeval;
437       }
438     else
439       t = NULL;
440
441     result = lutimes (file, t);
442     if (result == 0 || errno != ENOSYS)
443       return result;
444   }
445 #endif /* HAVE_LUTIMES && !HAVE_UTIMENSAT */
446
447   /* Out of luck for symlinks, but we still handle regular files.  */
448   if (!(adjustment_needed || REPLACE_FUNC_STAT_FILE) && lstat (file, &st))
449     return -1;
450   if (!S_ISLNK (st.st_mode))
451     return fdutimens (file, -1, ts);
452   errno = ENOSYS;
453   return -1;
454 }