Merge from gnulib
[emacs.git] / m4 / utimes.m4
blob847b2eba78fd0edcf96f560936791e8dad6b497b
1 # Detect some bugs in glibc's implementation of utimes.
2 # serial 5
4 dnl Copyright (C) 2003-2005, 2009-2017 Free Software Foundation, Inc.
5 dnl This file is free software; the Free Software Foundation
6 dnl gives unlimited permission to copy and/or distribute it,
7 dnl with or without modifications, as long as this notice is preserved.
9 # See if we need to work around bugs in glibc's implementation of
10 # utimes from 2003-07-12 to 2003-09-17.
11 # First, there was a bug that would make utimes set mtime
12 # and atime to zero (1970-01-01) unconditionally.
13 # Then, there was code to round rather than truncate.
14 # Then, there was an implementation (sparc64, Linux-2.4.28, glibc-2.3.3)
15 # that didn't honor the NULL-means-set-to-current-time semantics.
16 # Finally, there was also a version of utimes that failed on read-only
17 # files, while utime worked fine (linux-2.2.20, glibc-2.2.5).
19 # From Jim Meyering, with suggestions from Paul Eggert.
21 AC_DEFUN([gl_FUNC_UTIMES],
23   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
24   AC_CACHE_CHECK([whether the utimes function works],
25                  [gl_cv_func_working_utimes],
26     [AC_RUN_IFELSE([AC_LANG_SOURCE([[
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <sys/time.h>
31 #include <time.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <utime.h>
36 #include <errno.h>
38 static int
39 inorder (time_t a, time_t b, time_t c)
41   return a <= b && b <= c;
44 int
45 main ()
47   int result = 0;
48   char const *file = "conftest.utimes";
49   /* On OS/2, file timestamps must be on or after 1980 in local time,
50      with an even number of seconds.  */
51   static struct timeval timeval[2] = {{315620000 + 10, 10},
52                                       {315620000 + 1000000, 999998}};
54   /* Test whether utimes() essentially works.  */
55   {
56     struct stat sbuf;
57     FILE *f = fopen (file, "w");
58     if (f == NULL)
59       result |= 1;
60     else if (fclose (f) != 0)
61       result |= 1;
62     else if (utimes (file, timeval) != 0)
63       result |= 2;
64     else if (lstat (file, &sbuf) != 0)
65       result |= 1;
66     else if (!(sbuf.st_atime == timeval[0].tv_sec
67                && sbuf.st_mtime == timeval[1].tv_sec))
68       result |= 4;
69     if (unlink (file) != 0)
70       result |= 1;
71   }
73   /* Test whether utimes() with a NULL argument sets the file's timestamp
74      to the current time.  Use 'fstat' as well as 'time' to
75      determine the "current" time, to accommodate NFS file systems
76      if there is a time skew between the host and the NFS server.  */
77   {
78     int fd = open (file, O_WRONLY|O_CREAT, 0644);
79     if (fd < 0)
80       result |= 1;
81     else
82       {
83         time_t t0, t2;
84         struct stat st0, st1, st2;
85         if (time (&t0) == (time_t) -1)
86           result |= 1;
87         else if (fstat (fd, &st0) != 0)
88           result |= 1;
89         else if (utimes (file, timeval) != 0
90                  && (errno != EACCES
91                      /* OS/2 kLIBC utimes fails on opened files.  */
92                      || close (fd) != 0
93                      || utimes (file, timeval) != 0
94                      || (fd = open (file, O_WRONLY)) < 0))
95           result |= 2;
96         else if (utimes (file, NULL) != 0
97                  && (errno != EACCES
98                      /* OS/2 kLIBC utimes fails on opened files.  */
99                      || close (fd) != 0
100                      || utimes (file, NULL) != 0
101                      || (fd = open (file, O_WRONLY)) < 0))
102           result |= 8;
103         else if (fstat (fd, &st1) != 0)
104           result |= 1;
105         else if (write (fd, "\n", 1) != 1)
106           result |= 1;
107         else if (fstat (fd, &st2) != 0)
108           result |= 1;
109         else if (time (&t2) == (time_t) -1)
110           result |= 1;
111         else
112           {
113             int m_ok_POSIX = inorder (t0, st1.st_mtime, t2);
114             int m_ok_NFS = inorder (st0.st_mtime, st1.st_mtime, st2.st_mtime);
115             if (! (st1.st_atime == st1.st_mtime))
116               result |= 16;
117             if (! (m_ok_POSIX || m_ok_NFS))
118               result |= 32;
119           }
120         if (close (fd) != 0)
121           result |= 1;
122       }
123     if (unlink (file) != 0)
124       result |= 1;
125   }
127   /* Test whether utimes() with a NULL argument works on read-only files.  */
128   {
129     int fd = open (file, O_WRONLY|O_CREAT, 0444);
130     if (fd < 0)
131       result |= 1;
132     else if (close (fd) != 0)
133       result |= 1;
134     else if (utimes (file, NULL) != 0)
135       result |= 64;
136     if (unlink (file) != 0)
137       result |= 1;
138   }
140   return result;
142   ]])],
143        [gl_cv_func_working_utimes=yes],
144        [gl_cv_func_working_utimes=no],
145        [case "$host_os" in
146                   # Guess no on native Windows.
147           mingw*) gl_cv_func_working_utimes="guessing no" ;;
148           *)      gl_cv_func_working_utimes="guessing no" ;;
149         esac
150        ])
151     ])
153   case "$gl_cv_func_working_utimes" in
154     *yes)
155       AC_DEFINE([HAVE_WORKING_UTIMES], [1], [Define if utimes works properly.])
156       ;;
157   esac