textsec: handle email address without domain part
[emacs.git] / lib / utimens.c
blob4bfb9c91a7bb786a8c2e4089d3b4d90569ab780c
1 /* Set file access and modification times.
3 Copyright (C) 2003-2024 Free Software Foundation, Inc.
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation, either version 3 of the
8 License, or (at your option) any later version.
10 This file 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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser 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 <string.h>
30 #include <sys/stat.h>
31 #include <sys/time.h>
32 #include <unistd.h>
33 #include <utime.h>
35 #include "stat-time.h"
36 #include "timespec.h"
38 /* On native Windows, use SetFileTime; but avoid this when compiling
39 GNU Emacs, which arranges for this in some other way and which
40 defines WIN32_LEAN_AND_MEAN itself. */
42 #if defined _WIN32 && ! defined __CYGWIN__ && ! defined EMACS_CONFIGURATION
43 # define USE_SETFILETIME
44 # define WIN32_LEAN_AND_MEAN
45 # include <windows.h>
46 # if GNULIB_MSVC_NOTHROW
47 # include "msvc-nothrow.h"
48 # else
49 # include <io.h>
50 # endif
51 #endif
53 /* Avoid recursion with rpl_futimens or rpl_utimensat. */
54 #undef futimens
55 #if !HAVE_NEARLY_WORKING_UTIMENSAT
56 # undef utimensat
57 #endif
59 /* Solaris 9 mistakenly succeeds when given a non-directory with a
60 trailing slash. Force the use of rpl_stat for a fix. */
61 #ifndef REPLACE_FUNC_STAT_FILE
62 # define REPLACE_FUNC_STAT_FILE 0
63 #endif
65 #if HAVE_UTIMENSAT || HAVE_FUTIMENS
66 /* Cache variables for whether the utimensat syscall works; used to
67 avoid calling the syscall if we know it will just fail with ENOSYS,
68 and to avoid unnecessary work in massaging timestamps if the
69 syscall will work. Multiple variables are needed, to distinguish
70 between the following scenarios on Linux:
71 utimensat doesn't exist, or is in glibc but kernel 2.6.18 fails with ENOSYS
72 kernel 2.6.22 and earlier rejects AT_SYMLINK_NOFOLLOW
73 kernel 2.6.25 and earlier reject UTIME_NOW/UTIME_OMIT with non-zero tv_sec
74 kernel 2.6.32 used with xfs or ntfs-3g fail to honor UTIME_OMIT
75 utimensat completely works
76 For each cache variable: 0 = unknown, 1 = yes, -1 = no. */
77 static int utimensat_works_really;
78 static int lutimensat_works_really;
79 #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
81 /* Validate the requested timestamps. Return 0 if the resulting
82 timespec can be used for utimensat (after possibly modifying it to
83 work around bugs in utimensat). Return a positive value if the
84 timespec needs further adjustment based on stat results: 1 if any
85 adjustment is needed for utimes, and 2 if any adjustment is needed
86 for Linux utimensat. Return -1, with errno set to EINVAL, if
87 timespec is out of range. */
88 static int
89 validate_timespec (struct timespec timespec[2])
91 int result = 0;
92 int utime_omit_count = 0;
93 if ((timespec[0].tv_nsec != UTIME_NOW
94 && timespec[0].tv_nsec != UTIME_OMIT
95 && ! (0 <= timespec[0].tv_nsec
96 && timespec[0].tv_nsec < TIMESPEC_HZ))
97 || (timespec[1].tv_nsec != UTIME_NOW
98 && timespec[1].tv_nsec != UTIME_OMIT
99 && ! (0 <= timespec[1].tv_nsec
100 && timespec[1].tv_nsec < TIMESPEC_HZ)))
102 errno = EINVAL;
103 return -1;
105 /* Work around Linux kernel 2.6.25 bug, where utimensat fails with
106 EINVAL if tv_sec is not 0 when using the flag values of tv_nsec.
107 Flag a Linux kernel 2.6.32 bug, where an mtime of UTIME_OMIT
108 fails to bump ctime. */
109 if (timespec[0].tv_nsec == UTIME_NOW
110 || timespec[0].tv_nsec == UTIME_OMIT)
112 timespec[0].tv_sec = 0;
113 result = 1;
114 if (timespec[0].tv_nsec == UTIME_OMIT)
115 utime_omit_count++;
117 if (timespec[1].tv_nsec == UTIME_NOW
118 || timespec[1].tv_nsec == UTIME_OMIT)
120 timespec[1].tv_sec = 0;
121 result = 1;
122 if (timespec[1].tv_nsec == UTIME_OMIT)
123 utime_omit_count++;
125 return result + (utime_omit_count == 1);
128 /* Normalize any UTIME_NOW or UTIME_OMIT values in (*TS)[0] and (*TS)[1],
129 using STATBUF to obtain the current timestamps of the file. If
130 both times are UTIME_NOW, set *TS to NULL (as this can avoid some
131 permissions issues). If both times are UTIME_OMIT, return true
132 (nothing further beyond the prior collection of STATBUF is
133 necessary); otherwise return false. */
134 static bool
135 update_timespec (struct stat const *statbuf, struct timespec **ts)
137 struct timespec *timespec = *ts;
138 if (timespec[0].tv_nsec == UTIME_OMIT
139 && timespec[1].tv_nsec == UTIME_OMIT)
140 return true;
141 if (timespec[0].tv_nsec == UTIME_NOW
142 && timespec[1].tv_nsec == UTIME_NOW)
144 *ts = NULL;
145 return false;
148 if (timespec[0].tv_nsec == UTIME_OMIT)
149 timespec[0] = get_stat_atime (statbuf);
150 else if (timespec[0].tv_nsec == UTIME_NOW)
151 gettime (&timespec[0]);
153 if (timespec[1].tv_nsec == UTIME_OMIT)
154 timespec[1] = get_stat_mtime (statbuf);
155 else if (timespec[1].tv_nsec == UTIME_NOW)
156 gettime (&timespec[1]);
158 return false;
161 /* Set the access and modification timestamps of FD (a.k.a. FILE) to be
162 TIMESPEC[0] and TIMESPEC[1], respectively.
163 FD must be either negative -- in which case it is ignored --
164 or a file descriptor that is open on FILE.
165 If FD is nonnegative, then FILE can be NULL, which means
166 use just futimes (or equivalent) instead of utimes (or equivalent),
167 and fail if on an old system without futimes (or equivalent).
168 If TIMESPEC is null, set the timestamps to the current time.
169 Return 0 on success, -1 (setting errno) on failure. */
172 fdutimens (int fd, char const *file, struct timespec const timespec[2])
174 struct timespec adjusted_timespec[2];
175 struct timespec *ts = timespec ? adjusted_timespec : NULL;
176 int adjustment_needed = 0;
177 struct stat st;
179 if (ts)
181 adjusted_timespec[0] = timespec[0];
182 adjusted_timespec[1] = timespec[1];
183 adjustment_needed = validate_timespec (ts);
185 if (adjustment_needed < 0)
186 return -1;
188 /* Require that at least one of FD or FILE are potentially valid, to avoid
189 a Linux bug where futimens (AT_FDCWD, NULL) changes "." rather
190 than failing. */
191 if (fd < 0 && !file)
193 errno = EBADF;
194 return -1;
197 /* Some Linux-based NFS clients are buggy, and mishandle timestamps
198 of files in NFS file systems in some cases. We have no
199 configure-time test for this, but please see
200 <https://bugs.gentoo.org/show_bug.cgi?id=132673> for references to
201 some of the problems with Linux 2.6.16. If this affects you,
202 compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to
203 help in some cases, albeit at a cost in performance. But you
204 really should upgrade your kernel to a fixed version, since the
205 problem affects many applications. */
207 #if HAVE_BUGGY_NFS_TIME_STAMPS
208 if (fd < 0)
209 sync ();
210 else
211 fsync (fd);
212 #endif
214 /* POSIX 2008 added two interfaces to set file timestamps with
215 nanosecond resolution; newer Linux implements both functions via
216 a single syscall. We provide a fallback for ENOSYS (for example,
217 compiling against Linux 2.6.25 kernel headers and glibc 2.7, but
218 running on Linux 2.6.18 kernel). */
219 #if HAVE_UTIMENSAT || HAVE_FUTIMENS
220 if (0 <= utimensat_works_really)
222 int result;
223 # if __linux__ || __sun
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.
232 The same bug occurs in Solaris 11.1 (Apr 2013).
234 FIXME: Simplify this in 2024, when these file system bugs are
235 no longer common on Gnulib target platforms. */
236 if (adjustment_needed == 2)
238 if (fd < 0 ? stat (file, &st) : fstat (fd, &st))
239 return -1;
240 if (ts[0].tv_nsec == UTIME_OMIT)
241 ts[0] = get_stat_atime (&st);
242 else if (ts[1].tv_nsec == UTIME_OMIT)
243 ts[1] = get_stat_mtime (&st);
244 /* Note that st is good, in case utimensat gives ENOSYS. */
245 adjustment_needed++;
247 # endif
248 # if HAVE_UTIMENSAT
249 if (fd < 0)
251 # if defined __APPLE__ && defined __MACH__
252 size_t len = strlen (file);
253 if (len > 0 && file[len - 1] == '/')
255 struct stat statbuf;
256 if (stat (file, &statbuf) < 0)
257 return -1;
258 if (!S_ISDIR (statbuf.st_mode))
260 errno = ENOTDIR;
261 return -1;
264 # endif
265 result = utimensat (AT_FDCWD, file, ts, 0);
266 # ifdef __linux__
267 /* Work around a kernel bug:
268 https://bugzilla.redhat.com/show_bug.cgi?id=442352
269 https://bugzilla.redhat.com/show_bug.cgi?id=449910
270 It appears that utimensat can mistakenly return 280 rather
271 than -1 upon ENOSYS failure.
272 FIXME: remove in 2010 or whenever the offending kernels
273 are no longer in common use. */
274 if (0 < result)
275 errno = ENOSYS;
276 # endif /* __linux__ */
277 if (result == 0 || errno != ENOSYS)
279 utimensat_works_really = 1;
280 return result;
283 # endif /* HAVE_UTIMENSAT */
284 # if HAVE_FUTIMENS
285 if (0 <= fd)
287 result = futimens (fd, ts);
288 # ifdef __linux__
289 /* Work around the same bug as above. */
290 if (0 < result)
291 errno = ENOSYS;
292 # endif /* __linux__ */
293 if (result == 0 || errno != ENOSYS)
295 utimensat_works_really = 1;
296 return result;
299 # endif /* HAVE_FUTIMENS */
301 utimensat_works_really = -1;
302 lutimensat_works_really = -1;
303 #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
305 #ifdef USE_SETFILETIME
306 /* On native Windows, use SetFileTime(). See
307 <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-setfiletime>
308 <https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ns-minwinbase-filetime> */
309 if (0 <= fd)
311 HANDLE handle;
312 FILETIME current_time;
313 FILETIME last_access_time;
314 FILETIME last_write_time;
316 handle = (HANDLE) _get_osfhandle (fd);
317 if (handle == INVALID_HANDLE_VALUE)
319 errno = EBADF;
320 return -1;
323 if (ts == NULL || ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW)
325 /* GetSystemTimeAsFileTime
326 <https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime>.
327 It would be overkill to use
328 GetSystemTimePreciseAsFileTime
329 <https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime>. */
330 GetSystemTimeAsFileTime (&current_time);
333 if (ts == NULL || ts[0].tv_nsec == UTIME_NOW)
335 last_access_time = current_time;
337 else if (ts[0].tv_nsec == UTIME_OMIT)
339 last_access_time.dwLowDateTime = 0;
340 last_access_time.dwHighDateTime = 0;
342 else
344 ULONGLONG time_since_16010101 =
345 (ULONGLONG) ts[0].tv_sec * 10000000 + ts[0].tv_nsec / 100 + 116444736000000000LL;
346 last_access_time.dwLowDateTime = (DWORD) time_since_16010101;
347 last_access_time.dwHighDateTime = time_since_16010101 >> 32;
350 if (ts == NULL || ts[1].tv_nsec == UTIME_NOW)
352 last_write_time = current_time;
354 else if (ts[1].tv_nsec == UTIME_OMIT)
356 last_write_time.dwLowDateTime = 0;
357 last_write_time.dwHighDateTime = 0;
359 else
361 ULONGLONG time_since_16010101 =
362 (ULONGLONG) ts[1].tv_sec * 10000000 + ts[1].tv_nsec / 100 + 116444736000000000LL;
363 last_write_time.dwLowDateTime = (DWORD) time_since_16010101;
364 last_write_time.dwHighDateTime = time_since_16010101 >> 32;
367 if (SetFileTime (handle, NULL, &last_access_time, &last_write_time))
368 return 0;
369 else
371 DWORD sft_error = GetLastError ();
372 #if 0
373 fprintf (stderr, "fdutimens SetFileTime error 0x%x\n", (unsigned int) sft_error);
374 #endif
375 switch (sft_error)
377 case ERROR_ACCESS_DENIED: /* fd was opened without O_RDWR */
378 errno = EACCES; /* not specified by POSIX */
379 break;
380 default:
381 errno = EINVAL;
382 break;
384 return -1;
387 #endif
389 /* The platform lacks an interface to set file timestamps with
390 nanosecond resolution, so do the best we can, discarding any
391 fractional part of the timestamp. */
393 if (adjustment_needed || (REPLACE_FUNC_STAT_FILE && fd < 0))
395 if (adjustment_needed != 3
396 && (fd < 0 ? stat (file, &st) : fstat (fd, &st)))
397 return -1;
398 if (ts && update_timespec (&st, &ts))
399 return 0;
403 #if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
404 struct timeval timeval[2];
405 struct timeval *t;
406 if (ts)
408 timeval[0] = (struct timeval) { .tv_sec = ts[0].tv_sec,
409 .tv_usec = ts[0].tv_nsec / 1000 };
410 timeval[1] = (struct timeval) { .tv_sec = ts[1].tv_sec,
411 .tv_usec = ts[1].tv_nsec / 1000 };
412 t = timeval;
414 else
415 t = NULL;
417 if (fd < 0)
419 # if HAVE_FUTIMESAT
420 return futimesat (AT_FDCWD, file, t);
421 # endif
423 else
425 /* If futimesat or futimes fails here, don't try to speed things
426 up by returning right away. glibc can incorrectly fail with
427 errno == ENOENT if /proc isn't mounted. Also, Mandrake 10.0
428 in high security mode doesn't allow ordinary users to read
429 /proc/self, so glibc incorrectly fails with errno == EACCES.
430 If errno == EIO, EPERM, or EROFS, it's probably safe to fail
431 right away, but these cases are rare enough that they're not
432 worth optimizing, and who knows what other messed-up systems
433 are out there? So play it safe and fall back on the code
434 below. */
436 # if (HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) || HAVE_FUTIMES
437 # if HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG
438 # undef futimes
439 # define futimes(fd, t) futimesat (fd, NULL, t)
440 # endif
441 if (futimes (fd, t) == 0)
443 # if __linux__ && __GLIBC__
444 /* Work around a longstanding glibc bug, still present as
445 of 2010-12-27. On older Linux kernels that lack both
446 utimensat and utimes, glibc's futimes rounds instead of
447 truncating when falling back on utime. The same bug
448 occurs in futimesat with a null 2nd arg. */
449 if (t)
451 bool abig = 500000 <= t[0].tv_usec;
452 bool mbig = 500000 <= t[1].tv_usec;
453 if ((abig | mbig) && fstat (fd, &st) == 0)
455 /* If these two subtractions overflow, they'll
456 track the overflows inside the buggy glibc. */
457 time_t adiff = st.st_atime - t[0].tv_sec;
458 time_t mdiff = st.st_mtime - t[1].tv_sec;
460 struct timeval *tt = NULL;
461 struct timeval truncated_timeval[2];
462 truncated_timeval[0] = t[0];
463 truncated_timeval[1] = t[1];
464 if (abig && adiff == 1 && get_stat_atime_ns (&st) == 0)
466 tt = truncated_timeval;
467 tt[0].tv_usec = 0;
469 if (mbig && mdiff == 1 && get_stat_mtime_ns (&st) == 0)
471 tt = truncated_timeval;
472 tt[1].tv_usec = 0;
474 if (tt)
475 futimes (fd, tt);
478 # endif
480 return 0;
482 # endif
484 #endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */
486 if (!file)
488 #if ! ((HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) \
489 || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
490 errno = ENOSYS;
491 #endif
492 return -1;
495 #ifdef USE_SETFILETIME
496 return _gl_utimens_windows (file, ts);
497 #elif HAVE_WORKING_UTIMES
498 return utimes (file, t);
499 #else
501 struct utimbuf utimbuf;
502 struct utimbuf *ut;
503 if (ts)
505 utimbuf = (struct utimbuf) { .actime = ts[0].tv_sec,
506 .modtime = ts[1].tv_sec };
507 ut = &utimbuf;
509 else
510 ut = NULL;
512 return utime (file, ut);
514 #endif /* !HAVE_WORKING_UTIMES */
518 /* Set the access and modification timestamps of FILE to be
519 TIMESPEC[0] and TIMESPEC[1], respectively. */
521 utimens (char const *file, struct timespec const timespec[2])
523 return fdutimens (-1, file, timespec);
526 /* Set the access and modification timestamps of FILE to be
527 TIMESPEC[0] and TIMESPEC[1], respectively, without dereferencing
528 symlinks. Fail with ENOSYS if the platform does not support
529 changing symlink timestamps, but FILE was a symlink. */
531 lutimens (char const *file, struct timespec const timespec[2])
533 struct timespec adjusted_timespec[2];
534 struct timespec *ts = timespec ? adjusted_timespec : NULL;
535 int adjustment_needed = 0;
536 struct stat st;
538 if (ts)
540 adjusted_timespec[0] = timespec[0];
541 adjusted_timespec[1] = timespec[1];
542 adjustment_needed = validate_timespec (ts);
544 if (adjustment_needed < 0)
545 return -1;
547 /* The Linux kernel did not support symlink timestamps until
548 utimensat, in version 2.6.22, so we don't need to mimic
549 fdutimens' worry about buggy NFS clients. But we do have to
550 worry about bogus return values. */
552 #if HAVE_UTIMENSAT
553 if (0 <= lutimensat_works_really)
555 int result;
556 # if __linux__ || __sun
557 /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
558 systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
559 but work if both times are either explicitly specified or
560 UTIME_NOW. Work around it with a preparatory lstat prior to
561 calling utimensat; fortunately, there is not much timing
562 impact due to the extra syscall even on file systems where
563 UTIME_OMIT would have worked.
565 The same bug occurs in Solaris 11.1 (Apr 2013).
567 FIXME: Simplify this for Linux in 2016 and for Solaris in
568 2024, when file system bugs are no longer common. */
569 if (adjustment_needed == 2)
571 if (lstat (file, &st))
572 return -1;
573 if (ts[0].tv_nsec == UTIME_OMIT)
574 ts[0] = get_stat_atime (&st);
575 else if (ts[1].tv_nsec == UTIME_OMIT)
576 ts[1] = get_stat_mtime (&st);
577 /* Note that st is good, in case utimensat gives ENOSYS. */
578 adjustment_needed++;
580 # endif
581 result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW);
582 # ifdef __linux__
583 /* Work around a kernel bug:
584 https://bugzilla.redhat.com/show_bug.cgi?id=442352
585 https://bugzilla.redhat.com/show_bug.cgi?id=449910
586 It appears that utimensat can mistakenly return 280 rather
587 than -1 upon ENOSYS failure.
588 FIXME: remove in 2010 or whenever the offending kernels
589 are no longer in common use. */
590 if (0 < result)
591 errno = ENOSYS;
592 # endif
593 if (result == 0 || errno != ENOSYS)
595 utimensat_works_really = 1;
596 lutimensat_works_really = 1;
597 return result;
600 lutimensat_works_really = -1;
601 #endif /* HAVE_UTIMENSAT */
603 /* The platform lacks an interface to set file timestamps with
604 nanosecond resolution, so do the best we can, discarding any
605 fractional part of the timestamp. */
607 if (adjustment_needed || REPLACE_FUNC_STAT_FILE)
609 if (adjustment_needed != 3 && lstat (file, &st))
610 return -1;
611 if (ts && update_timespec (&st, &ts))
612 return 0;
615 /* On Linux, lutimes is a thin wrapper around utimensat, so there is
616 no point trying lutimes if utimensat failed with ENOSYS. */
617 #if HAVE_LUTIMES && !HAVE_UTIMENSAT
619 struct timeval timeval[2];
620 struct timeval *t;
621 int result;
622 if (ts)
624 timeval[0] = (struct timeval) { .tv_sec = ts[0].tv_sec,
625 .tv_usec = ts[0].tv_nsec / 1000 };
626 timeval[1] = (struct timeval) { .tv_sec = ts[1].tv_sec,
627 .tv_usec = ts[1].tv_nsec / 1000 };
628 t = timeval;
630 else
631 t = NULL;
633 result = lutimes (file, t);
634 if (result == 0 || errno != ENOSYS)
635 return result;
637 #endif /* HAVE_LUTIMES && !HAVE_UTIMENSAT */
639 /* Out of luck for symlinks, but we still handle regular files. */
640 if (!(adjustment_needed || REPLACE_FUNC_STAT_FILE) && lstat (file, &st))
641 return -1;
642 if (!S_ISLNK (st.st_mode))
643 return fdutimens (-1, file, ts);
644 errno = ENOSYS;
645 return -1;