fchmod-tests, fchmodat tests, lchmod tests: Add more tests.
[gnulib.git] / lib / utimens.c
blob44d1ea003e233905011317091d352f7e2e4bfc74
1 /* Set file access and modification times.
3 Copyright (C) 2003-2021 Free Software Foundation, Inc.
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.
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.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 /* Written by Paul Eggert. */
20 /* derived from a function in touch.c */
22 #include <config.h>
24 #define _GL_UTIMENS_INLINE _GL_EXTERN_INLINE
25 #include "utimens.h"
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <stdbool.h>
30 #include <string.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33 #include <unistd.h>
34 #include <utime.h>
36 #include "stat-time.h"
37 #include "timespec.h"
39 /* On native Windows, use SetFileTime; but avoid this when compiling
40 GNU Emacs, which arranges for this in some other way and which
41 defines WIN32_LEAN_AND_MEAN itself. */
43 #if defined _WIN32 && ! defined __CYGWIN__ && ! defined EMACS_CONFIGURATION
44 # define USE_SETFILETIME
45 # define WIN32_LEAN_AND_MEAN
46 # include <windows.h>
47 # if GNULIB_MSVC_NOTHROW
48 # include "msvc-nothrow.h"
49 # else
50 # include <io.h>
51 # endif
52 #endif
54 /* Avoid recursion with rpl_futimens or rpl_utimensat. */
55 #undef futimens
56 #if !HAVE_NEARLY_WORKING_UTIMENSAT
57 # undef utimensat
58 #endif
60 /* Solaris 9 mistakenly succeeds when given a non-directory with a
61 trailing slash. Force the use of rpl_stat for a fix. */
62 #ifndef REPLACE_FUNC_STAT_FILE
63 # define REPLACE_FUNC_STAT_FILE 0
64 #endif
66 #if HAVE_UTIMENSAT || HAVE_FUTIMENS
67 /* Cache variables for whether the utimensat syscall works; used to
68 avoid calling the syscall if we know it will just fail with ENOSYS,
69 and to avoid unnecessary work in massaging timestamps if the
70 syscall will work. Multiple variables are needed, to distinguish
71 between the following scenarios on Linux:
72 utimensat doesn't exist, or is in glibc but kernel 2.6.18 fails with ENOSYS
73 kernel 2.6.22 and earlier rejects AT_SYMLINK_NOFOLLOW
74 kernel 2.6.25 and earlier reject UTIME_NOW/UTIME_OMIT with non-zero tv_sec
75 kernel 2.6.32 used with xfs or ntfs-3g fail to honor UTIME_OMIT
76 utimensat completely works
77 For each cache variable: 0 = unknown, 1 = yes, -1 = no. */
78 static int utimensat_works_really;
79 static int lutimensat_works_really;
80 #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
82 /* Validate the requested timestamps. Return 0 if the resulting
83 timespec can be used for utimensat (after possibly modifying it to
84 work around bugs in utimensat). Return a positive value if the
85 timespec needs further adjustment based on stat results: 1 if any
86 adjustment is needed for utimes, and 2 if any adjustment is needed
87 for Linux utimensat. Return -1, with errno set to EINVAL, if
88 timespec is out of range. */
89 static int
90 validate_timespec (struct timespec timespec[2])
92 int result = 0;
93 int utime_omit_count = 0;
94 if ((timespec[0].tv_nsec != UTIME_NOW
95 && timespec[0].tv_nsec != UTIME_OMIT
96 && ! (0 <= timespec[0].tv_nsec
97 && timespec[0].tv_nsec < TIMESPEC_HZ))
98 || (timespec[1].tv_nsec != UTIME_NOW
99 && timespec[1].tv_nsec != UTIME_OMIT
100 && ! (0 <= timespec[1].tv_nsec
101 && timespec[1].tv_nsec < TIMESPEC_HZ)))
103 errno = EINVAL;
104 return -1;
106 /* Work around Linux kernel 2.6.25 bug, where utimensat fails with
107 EINVAL if tv_sec is not 0 when using the flag values of tv_nsec.
108 Flag a Linux kernel 2.6.32 bug, where an mtime of UTIME_OMIT
109 fails to bump ctime. */
110 if (timespec[0].tv_nsec == UTIME_NOW
111 || timespec[0].tv_nsec == UTIME_OMIT)
113 timespec[0].tv_sec = 0;
114 result = 1;
115 if (timespec[0].tv_nsec == UTIME_OMIT)
116 utime_omit_count++;
118 if (timespec[1].tv_nsec == UTIME_NOW
119 || timespec[1].tv_nsec == UTIME_OMIT)
121 timespec[1].tv_sec = 0;
122 result = 1;
123 if (timespec[1].tv_nsec == UTIME_OMIT)
124 utime_omit_count++;
126 return result + (utime_omit_count == 1);
129 /* Normalize any UTIME_NOW or UTIME_OMIT values in *TS, using stat
130 buffer STATBUF to obtain the current timestamps of the file. If
131 both times are UTIME_NOW, set *TS to NULL (as this can avoid some
132 permissions issues). If both times are UTIME_OMIT, return true
133 (nothing further beyond the prior collection of STATBUF is
134 necessary); otherwise return false. */
135 static bool
136 update_timespec (struct stat const *statbuf, struct timespec *ts[2])
138 struct timespec *timespec = *ts;
139 if (timespec[0].tv_nsec == UTIME_OMIT
140 && timespec[1].tv_nsec == UTIME_OMIT)
141 return true;
142 if (timespec[0].tv_nsec == UTIME_NOW
143 && timespec[1].tv_nsec == UTIME_NOW)
145 *ts = NULL;
146 return false;
149 if (timespec[0].tv_nsec == UTIME_OMIT)
150 timespec[0] = get_stat_atime (statbuf);
151 else if (timespec[0].tv_nsec == UTIME_NOW)
152 gettime (&timespec[0]);
154 if (timespec[1].tv_nsec == UTIME_OMIT)
155 timespec[1] = get_stat_mtime (statbuf);
156 else if (timespec[1].tv_nsec == UTIME_NOW)
157 gettime (&timespec[1]);
159 return false;
162 /* Set the access and modification timestamps of FD (a.k.a. FILE) to be
163 TIMESPEC[0] and TIMESPEC[1], respectively.
164 FD must be either negative -- in which case it is ignored --
165 or a file descriptor that is open on FILE.
166 If FD is nonnegative, then FILE can be NULL, which means
167 use just futimes (or equivalent) instead of utimes (or equivalent),
168 and fail if on an old system without futimes (or equivalent).
169 If TIMESPEC is null, set the timestamps to the current time.
170 Return 0 on success, -1 (setting errno) on failure. */
173 fdutimens (int fd, char const *file, struct timespec const timespec[2])
175 struct timespec adjusted_timespec[2];
176 struct timespec *ts = timespec ? adjusted_timespec : NULL;
177 int adjustment_needed = 0;
178 struct stat st;
180 if (ts)
182 adjusted_timespec[0] = timespec[0];
183 adjusted_timespec[1] = timespec[1];
184 adjustment_needed = validate_timespec (ts);
186 if (adjustment_needed < 0)
187 return -1;
189 /* Require that at least one of FD or FILE are potentially valid, to avoid
190 a Linux bug where futimens (AT_FDCWD, NULL) changes "." rather
191 than failing. */
192 if (fd < 0 && !file)
194 errno = EBADF;
195 return -1;
198 /* Some Linux-based NFS clients are buggy, and mishandle timestamps
199 of files in NFS file systems in some cases. We have no
200 configure-time test for this, but please see
201 <https://bugs.gentoo.org/show_bug.cgi?id=132673> for references to
202 some of the problems with Linux 2.6.16. If this affects you,
203 compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to
204 help in some cases, albeit at a cost in performance. But you
205 really should upgrade your kernel to a fixed version, since the
206 problem affects many applications. */
208 #if HAVE_BUGGY_NFS_TIME_STAMPS
209 if (fd < 0)
210 sync ();
211 else
212 fsync (fd);
213 #endif
215 /* POSIX 2008 added two interfaces to set file timestamps with
216 nanosecond resolution; newer Linux implements both functions via
217 a single syscall. We provide a fallback for ENOSYS (for example,
218 compiling against Linux 2.6.25 kernel headers and glibc 2.7, but
219 running on Linux 2.6.18 kernel). */
220 #if HAVE_UTIMENSAT || HAVE_FUTIMENS
221 if (0 <= utimensat_works_really)
223 int result;
224 # if __linux__ || __sun
225 /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
226 systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
227 but work if both times are either explicitly specified or
228 UTIME_NOW. Work around it with a preparatory [f]stat prior
229 to calling futimens/utimensat; fortunately, there is not much
230 timing impact due to the extra syscall even on file systems
231 where UTIME_OMIT would have worked.
233 The same bug occurs in Solaris 11.1 (Apr 2013).
235 FIXME: Simplify this for Linux in 2016 and for Solaris in
236 2024, when file system bugs are no longer common. */
237 if (adjustment_needed == 2)
239 if (fd < 0 ? stat (file, &st) : fstat (fd, &st))
240 return -1;
241 if (ts[0].tv_nsec == UTIME_OMIT)
242 ts[0] = get_stat_atime (&st);
243 else if (ts[1].tv_nsec == UTIME_OMIT)
244 ts[1] = get_stat_mtime (&st);
245 /* Note that st is good, in case utimensat gives ENOSYS. */
246 adjustment_needed++;
248 # endif
249 # if HAVE_UTIMENSAT
250 if (fd < 0)
252 # if defined __APPLE__ && defined __MACH__
253 size_t len = strlen (file);
254 if (len > 0 && file[len - 1] == '/')
256 struct stat statbuf;
257 if (stat (file, &statbuf) < 0)
258 return -1;
259 if (!S_ISDIR (statbuf.st_mode))
261 errno = ENOTDIR;
262 return -1;
265 # endif
266 result = utimensat (AT_FDCWD, file, ts, 0);
267 # ifdef __linux__
268 /* Work around a kernel bug:
269 https://bugzilla.redhat.com/show_bug.cgi?id=442352
270 https://bugzilla.redhat.com/show_bug.cgi?id=449910
271 It appears that utimensat can mistakenly return 280 rather
272 than -1 upon ENOSYS failure.
273 FIXME: remove in 2010 or whenever the offending kernels
274 are no longer in common use. */
275 if (0 < result)
276 errno = ENOSYS;
277 # endif /* __linux__ */
278 if (result == 0 || errno != ENOSYS)
280 utimensat_works_really = 1;
281 return result;
284 # endif /* HAVE_UTIMENSAT */
285 # if HAVE_FUTIMENS
286 if (0 <= fd)
288 result = futimens (fd, ts);
289 # ifdef __linux__
290 /* Work around the same bug as above. */
291 if (0 < result)
292 errno = ENOSYS;
293 # endif /* __linux__ */
294 if (result == 0 || errno != ENOSYS)
296 utimensat_works_really = 1;
297 return result;
300 # endif /* HAVE_FUTIMENS */
302 utimensat_works_really = -1;
303 lutimensat_works_really = -1;
304 #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
306 #ifdef USE_SETFILETIME
307 /* On native Windows, use SetFileTime(). See
308 <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-setfiletime>
309 <https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ns-minwinbase-filetime> */
310 if (0 <= fd)
312 HANDLE handle;
313 FILETIME current_time;
314 FILETIME last_access_time;
315 FILETIME last_write_time;
317 handle = (HANDLE) _get_osfhandle (fd);
318 if (handle == INVALID_HANDLE_VALUE)
320 errno = EBADF;
321 return -1;
324 if (ts == NULL || ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW)
326 /* GetSystemTimeAsFileTime
327 <https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime>.
328 It would be overkill to use
329 GetSystemTimePreciseAsFileTime
330 <https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime>. */
331 GetSystemTimeAsFileTime (&current_time);
334 if (ts == NULL || ts[0].tv_nsec == UTIME_NOW)
336 last_access_time = current_time;
338 else if (ts[0].tv_nsec == UTIME_OMIT)
340 last_access_time.dwLowDateTime = 0;
341 last_access_time.dwHighDateTime = 0;
343 else
345 ULONGLONG time_since_16010101 =
346 (ULONGLONG) ts[0].tv_sec * 10000000 + ts[0].tv_nsec / 100 + 116444736000000000LL;
347 last_access_time.dwLowDateTime = (DWORD) time_since_16010101;
348 last_access_time.dwHighDateTime = time_since_16010101 >> 32;
351 if (ts == NULL || ts[1].tv_nsec == UTIME_NOW)
353 last_write_time = current_time;
355 else if (ts[1].tv_nsec == UTIME_OMIT)
357 last_write_time.dwLowDateTime = 0;
358 last_write_time.dwHighDateTime = 0;
360 else
362 ULONGLONG time_since_16010101 =
363 (ULONGLONG) ts[1].tv_sec * 10000000 + ts[1].tv_nsec / 100 + 116444736000000000LL;
364 last_write_time.dwLowDateTime = (DWORD) time_since_16010101;
365 last_write_time.dwHighDateTime = time_since_16010101 >> 32;
368 if (SetFileTime (handle, NULL, &last_access_time, &last_write_time))
369 return 0;
370 else
372 DWORD sft_error = GetLastError ();
373 #if 0
374 fprintf (stderr, "fdutimens SetFileTime error 0x%x\n", (unsigned int) sft_error);
375 #endif
376 switch (sft_error)
378 case ERROR_ACCESS_DENIED: /* fd was opened without O_RDWR */
379 errno = EACCES; /* not specified by POSIX */
380 break;
381 default:
382 errno = EINVAL;
383 break;
385 return -1;
388 #endif
390 /* The platform lacks an interface to set file timestamps with
391 nanosecond resolution, so do the best we can, discarding any
392 fractional part of the timestamp. */
394 if (adjustment_needed || (REPLACE_FUNC_STAT_FILE && fd < 0))
396 if (adjustment_needed != 3
397 && (fd < 0 ? stat (file, &st) : fstat (fd, &st)))
398 return -1;
399 if (ts && update_timespec (&st, &ts))
400 return 0;
404 #if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
405 struct timeval timeval[2];
406 struct timeval *t;
407 if (ts)
409 timeval[0].tv_sec = ts[0].tv_sec;
410 timeval[0].tv_usec = ts[0].tv_nsec / 1000;
411 timeval[1].tv_sec = ts[1].tv_sec;
412 timeval[1].tv_usec = ts[1].tv_nsec / 1000;
413 t = timeval;
415 else
416 t = NULL;
418 if (fd < 0)
420 # if HAVE_FUTIMESAT
421 return futimesat (AT_FDCWD, file, t);
422 # endif
424 else
426 /* If futimesat or futimes fails here, don't try to speed things
427 up by returning right away. glibc can incorrectly fail with
428 errno == ENOENT if /proc isn't mounted. Also, Mandrake 10.0
429 in high security mode doesn't allow ordinary users to read
430 /proc/self, so glibc incorrectly fails with errno == EACCES.
431 If errno == EIO, EPERM, or EROFS, it's probably safe to fail
432 right away, but these cases are rare enough that they're not
433 worth optimizing, and who knows what other messed-up systems
434 are out there? So play it safe and fall back on the code
435 below. */
437 # if (HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) || HAVE_FUTIMES
438 # if HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG
439 # undef futimes
440 # define futimes(fd, t) futimesat (fd, NULL, t)
441 # endif
442 if (futimes (fd, t) == 0)
444 # if __linux__ && __GLIBC__
445 /* Work around a longstanding glibc bug, still present as
446 of 2010-12-27. On older Linux kernels that lack both
447 utimensat and utimes, glibc's futimes rounds instead of
448 truncating when falling back on utime. The same bug
449 occurs in futimesat with a null 2nd arg. */
450 if (t)
452 bool abig = 500000 <= t[0].tv_usec;
453 bool mbig = 500000 <= t[1].tv_usec;
454 if ((abig | mbig) && fstat (fd, &st) == 0)
456 /* If these two subtractions overflow, they'll
457 track the overflows inside the buggy glibc. */
458 time_t adiff = st.st_atime - t[0].tv_sec;
459 time_t mdiff = st.st_mtime - t[1].tv_sec;
461 struct timeval *tt = NULL;
462 struct timeval truncated_timeval[2];
463 truncated_timeval[0] = t[0];
464 truncated_timeval[1] = t[1];
465 if (abig && adiff == 1 && get_stat_atime_ns (&st) == 0)
467 tt = truncated_timeval;
468 tt[0].tv_usec = 0;
470 if (mbig && mdiff == 1 && get_stat_mtime_ns (&st) == 0)
472 tt = truncated_timeval;
473 tt[1].tv_usec = 0;
475 if (tt)
476 futimes (fd, tt);
479 # endif
481 return 0;
483 # endif
485 #endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */
487 if (!file)
489 #if ! ((HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) \
490 || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
491 errno = ENOSYS;
492 #endif
493 return -1;
496 #ifdef USE_SETFILETIME
497 return _gl_utimens_windows (file, ts);
498 #elif HAVE_WORKING_UTIMES
499 return utimes (file, t);
500 #else
502 struct utimbuf utimbuf;
503 struct utimbuf *ut;
504 if (ts)
506 utimbuf.actime = ts[0].tv_sec;
507 utimbuf.modtime = ts[1].tv_sec;
508 ut = &utimbuf;
510 else
511 ut = NULL;
513 return utime (file, ut);
515 #endif /* !HAVE_WORKING_UTIMES */
519 /* Set the access and modification timestamps of FILE to be
520 TIMESPEC[0] and TIMESPEC[1], respectively. */
522 utimens (char const *file, struct timespec const timespec[2])
524 return fdutimens (-1, file, timespec);
527 /* Set the access and modification timestamps of FILE to be
528 TIMESPEC[0] and TIMESPEC[1], respectively, without dereferencing
529 symlinks. Fail with ENOSYS if the platform does not support
530 changing symlink timestamps, but FILE was a symlink. */
532 lutimens (char const *file, struct timespec const timespec[2])
534 struct timespec adjusted_timespec[2];
535 struct timespec *ts = timespec ? adjusted_timespec : NULL;
536 int adjustment_needed = 0;
537 struct stat st;
539 if (ts)
541 adjusted_timespec[0] = timespec[0];
542 adjusted_timespec[1] = timespec[1];
543 adjustment_needed = validate_timespec (ts);
545 if (adjustment_needed < 0)
546 return -1;
548 /* The Linux kernel did not support symlink timestamps until
549 utimensat, in version 2.6.22, so we don't need to mimic
550 fdutimens' worry about buggy NFS clients. But we do have to
551 worry about bogus return values. */
553 #if HAVE_UTIMENSAT
554 if (0 <= lutimensat_works_really)
556 int result;
557 # if __linux__ || __sun
558 /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
559 systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
560 but work if both times are either explicitly specified or
561 UTIME_NOW. Work around it with a preparatory lstat prior to
562 calling utimensat; fortunately, there is not much timing
563 impact due to the extra syscall even on file systems where
564 UTIME_OMIT would have worked.
566 The same bug occurs in Solaris 11.1 (Apr 2013).
568 FIXME: Simplify this for Linux in 2016 and for Solaris in
569 2024, when file system bugs are no longer common. */
570 if (adjustment_needed == 2)
572 if (lstat (file, &st))
573 return -1;
574 if (ts[0].tv_nsec == UTIME_OMIT)
575 ts[0] = get_stat_atime (&st);
576 else if (ts[1].tv_nsec == UTIME_OMIT)
577 ts[1] = get_stat_mtime (&st);
578 /* Note that st is good, in case utimensat gives ENOSYS. */
579 adjustment_needed++;
581 # endif
582 result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW);
583 # ifdef __linux__
584 /* Work around a kernel bug:
585 https://bugzilla.redhat.com/show_bug.cgi?id=442352
586 https://bugzilla.redhat.com/show_bug.cgi?id=449910
587 It appears that utimensat can mistakenly return 280 rather
588 than -1 upon ENOSYS failure.
589 FIXME: remove in 2010 or whenever the offending kernels
590 are no longer in common use. */
591 if (0 < result)
592 errno = ENOSYS;
593 # endif
594 if (result == 0 || errno != ENOSYS)
596 utimensat_works_really = 1;
597 lutimensat_works_really = 1;
598 return result;
601 lutimensat_works_really = -1;
602 #endif /* HAVE_UTIMENSAT */
604 /* The platform lacks an interface to set file timestamps with
605 nanosecond resolution, so do the best we can, discarding any
606 fractional part of the timestamp. */
608 if (adjustment_needed || REPLACE_FUNC_STAT_FILE)
610 if (adjustment_needed != 3 && lstat (file, &st))
611 return -1;
612 if (ts && update_timespec (&st, &ts))
613 return 0;
616 /* On Linux, lutimes is a thin wrapper around utimensat, so there is
617 no point trying lutimes if utimensat failed with ENOSYS. */
618 #if HAVE_LUTIMES && !HAVE_UTIMENSAT
620 struct timeval timeval[2];
621 struct timeval *t;
622 int result;
623 if (ts)
625 timeval[0].tv_sec = ts[0].tv_sec;
626 timeval[0].tv_usec = ts[0].tv_nsec / 1000;
627 timeval[1].tv_sec = ts[1].tv_sec;
628 timeval[1].tv_usec = ts[1].tv_nsec / 1000;
629 t = timeval;
631 else
632 t = NULL;
634 result = lutimes (file, t);
635 if (result == 0 || errno != ENOSYS)
636 return result;
638 #endif /* HAVE_LUTIMES && !HAVE_UTIMENSAT */
640 /* Out of luck for symlinks, but we still handle regular files. */
641 if (!(adjustment_needed || REPLACE_FUNC_STAT_FILE) && lstat (file, &st))
642 return -1;
643 if (!S_ISLNK (st.st_mode))
644 return fdutimens (-1, file, ts);
645 errno = ENOSYS;
646 return -1;