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