1# Detect some bugs in glibc's implementation of utimes.
2# serial 3
3
4dnl Copyright (C) 2003-2005, 2009-2014 Free Software Foundation, Inc.
5dnl This file is free software; the Free Software Foundation
6dnl gives unlimited permission to copy and/or distribute it,
7dnl 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
21AC_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
37static int
38inorder (time_t a, time_t b, time_t c)
39{
40  return a <= b && b <= c;
41}
42
43int
44main ()
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 m_ok_POSIX = inorder (t0, st1.st_mtime, t2);
100            int m_ok_NFS = inorder (st0.st_mtime, st1.st_mtime, st2.st_mtime);
101            if (! (st1.st_atime == st1.st_mtime))
102              result |= 16;
103            if (! (m_ok_POSIX || m_ok_NFS))
104              result |= 32;
105          }
106        if (close (fd) != 0)
107          result |= 1;
108      }
109    if (unlink (file) != 0)
110      result |= 1;
111  }
112
113  /* Test whether utimes() with a NULL argument works on read-only files.  */
114  {
115    int fd = open (file, O_WRONLY|O_CREAT, 0444);
116    if (fd < 0)
117      result |= 1;
118    else if (close (fd) != 0)
119      result |= 1;
120    else if (utimes (file, NULL) != 0)
121      result |= 64;
122    if (unlink (file) != 0)
123      result |= 1;
124  }
125
126  return result;
127}
128  ]])],
129       [gl_cv_func_working_utimes=yes],
130       [gl_cv_func_working_utimes=no],
131       [gl_cv_func_working_utimes=no])])
132
133  if test $gl_cv_func_working_utimes = yes; then
134    AC_DEFINE([HAVE_WORKING_UTIMES], [1], [Define if utimes works properly. ])
135  fi
136])
137