Commit | Line | Data |
---|---|---|
c8fff863 PE |
1 | # Detect some bugs in glibc's implementation of utimes. |
2 | # serial 3 | |
3 | ||
ba318903 | 4 | dnl Copyright (C) 2003-2005, 2009-2014 Free Software Foundation, Inc. |
c8fff863 PE |
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 | ]) |