| 1 | # Detect some bugs in glibc's implementation of utimes. |
| 2 | # serial 3 |
| 3 | |
| 4 | dnl Copyright (C) 2003-2005, 2009-2014 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 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 | ]) |