utimens: configure better on hosts with NFS clock skew
[pspp] / m4 / utimes.m4
1 # Detect some bugs in glibc's implementation of utimes.
2 # serial 3
3
4 dnl Copyright (C) 2003-2005, 2009-2010 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.
8
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).
18 #
19 # From Jim Meyering, with suggestions from Paul Eggert.
20
21 AC_DEFUN([gl_FUNC_UTIMES],
22 [
23   AC_CACHE_CHECK([whether the utimes function works],
24                  [gl_cv_func_working_utimes],
25   [
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
37 static int
38 inorder (time_t a, time_t b, time_t c)
39 {
40   return a <= b && b <= c;
41 }
42
43 int
44 main ()
45 {
46   int result = 0;
47   char const *file = "conftest.utimes";
48   static struct timeval timeval[2] = {{9, 10}, {999999, 999999}};
49
50   /* Test whether utimes() essentially works.  */
51   {
52     struct stat sbuf;
53     FILE *f = fopen (file, "w");
54     if (f == NULL)
55       result |= 1;
56     else if (fclose (f) != 0)
57       result |= 1;
58     else if (utimes (file, timeval) != 0)
59       result |= 2;
60     else if (lstat (file, &sbuf) != 0)
61       result |= 1;
62     else if (!(sbuf.st_atime == timeval[0].tv_sec
63                && sbuf.st_mtime == timeval[1].tv_sec))
64       result |= 4;
65     if (unlink (file) != 0)
66       result |= 1;
67   }
68
69   /* Test whether utimes() with a NULL argument sets the file's timestamp
70      to the current time.  Use 'fstat' as well as 'time' to
71      determine the "current" time, to accommodate NFS file systems
72      if there is a time skew between the host and the NFS server.  */
73   {
74     int fd = open (file, O_WRONLY|O_CREAT, 0644);
75     if (fd < 0)
76       result |= 1;
77     else
78       {
79         time_t t0, t2;
80         struct stat st0, st1, st2;
81         if (time (&t0) == (time_t) -1)
82           result |= 1;
83         else if (fstat (fd, &st0) != 0)
84           result |= 1;
85         else if (utimes (file, timeval) != 0)
86           result |= 2;
87         else if (utimes (file, NULL) != 0)
88           result |= 8;
89         else if (fstat (fd, &st1) != 0)
90           result |= 1;
91         else if (write (fd, "\n", 1) != 1)
92           result |= 1;
93         else if (fstat (fd, &st2) != 0)
94           result |= 1;
95         else if (time (&t2) == (time_t) -1)
96           result |= 1;
97         else
98           {
99             int a_ok_POSIX = inorder (t0, st1.st_atime, t2);
100             int m_ok_POSIX = inorder (t0, st1.st_mtime, t2);
101             int a_ok_NFS = inorder (st0.st_mtime, st1.st_atime, st2.st_mtime);
102             int m_ok_NFS = inorder (st0.st_mtime, st1.st_mtime, st2.st_mtime);
103             if (! ((a_ok_POSIX || a_ok_NFS) && st1.st_atime == st1.st_mtime))
104               result |= 16;
105             if (! (a_ok_POSIX ? m_ok_POSIX : m_ok_NFS))
106               result |= 32;
107           }
108         if (close (fd) != 0)
109           result |= 1;
110       }
111     if (unlink (file) != 0)
112       result |= 1;
113   }
114
115   /* Test whether utimes() with a NULL argument works on read-only files.  */
116   {
117     int fd = open (file, O_WRONLY|O_CREAT, 0444);
118     if (fd < 0)
119       result |= 1;
120     else if (close (fd) != 0)
121       result |= 1;
122     else if (utimes (file, NULL) != 0)
123       result |= 64;
124     if (unlink (file) != 0)
125       result |= 1;
126   }
127
128   return result;
129 }
130   ]])],
131        [gl_cv_func_working_utimes=yes],
132        [gl_cv_func_working_utimes=no],
133        [gl_cv_func_working_utimes=no])])
134
135   if test $gl_cv_func_working_utimes = yes; then
136     AC_DEFINE([HAVE_WORKING_UTIMES], [1], [Define if utimes works properly. ])
137   fi
138 ])