1 | #serial 12
|
---|
2 | # Check for several getcwd bugs with long file names.
|
---|
3 | # If so, arrange to compile the wrapper function.
|
---|
4 |
|
---|
5 | # This is necessary for at least GNU libc on linux-2.4.19 and 2.4.20.
|
---|
6 | # I've heard that this is due to a Linux kernel bug, and that it has
|
---|
7 | # been fixed between 2.4.21-pre3 and 2.4.21-pre4. */
|
---|
8 |
|
---|
9 | # Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
---|
10 | # This file is free software; the Free Software Foundation
|
---|
11 | # gives unlimited permission to copy and/or distribute it,
|
---|
12 | # with or without modifications, as long as this notice is preserved.
|
---|
13 |
|
---|
14 | # From Jim Meyering
|
---|
15 |
|
---|
16 | AC_DEFUN([gl_FUNC_GETCWD_PATH_MAX],
|
---|
17 | [
|
---|
18 | AC_CHECK_DECLS_ONCE(getcwd)
|
---|
19 | AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
|
---|
20 | AC_CACHE_CHECK([whether getcwd handles long file names properly],
|
---|
21 | gl_cv_func_getcwd_path_max,
|
---|
22 | [# Arrange for deletion of the temporary directory this test creates.
|
---|
23 | ac_clean_files="$ac_clean_files confdir3"
|
---|
24 | AC_RUN_IFELSE(
|
---|
25 | [AC_LANG_SOURCE(
|
---|
26 | [[
|
---|
27 | #include <errno.h>
|
---|
28 | #include <stdlib.h>
|
---|
29 | #include <unistd.h>
|
---|
30 | #include <string.h>
|
---|
31 | #include <limits.h>
|
---|
32 | #include <sys/stat.h>
|
---|
33 | #include <sys/types.h>
|
---|
34 | #include <fcntl.h>
|
---|
35 |
|
---|
36 | #ifndef AT_FDCWD
|
---|
37 | # define AT_FDCWD 0
|
---|
38 | #endif
|
---|
39 | #ifdef ENAMETOOLONG
|
---|
40 | # define is_ENAMETOOLONG(x) ((x) == ENAMETOOLONG)
|
---|
41 | #else
|
---|
42 | # define is_ENAMETOOLONG(x) 0
|
---|
43 | #endif
|
---|
44 |
|
---|
45 | /* Don't get link errors because mkdir is redefined to rpl_mkdir. */
|
---|
46 | #undef mkdir
|
---|
47 |
|
---|
48 | #ifndef S_IRWXU
|
---|
49 | # define S_IRWXU 0700
|
---|
50 | #endif
|
---|
51 |
|
---|
52 | /* The length of this name must be 8. */
|
---|
53 | #define DIR_NAME "confdir3"
|
---|
54 | #define DIR_NAME_LEN 8
|
---|
55 | #define DIR_NAME_SIZE (DIR_NAME_LEN + 1)
|
---|
56 |
|
---|
57 | /* The length of "../". */
|
---|
58 | #define DOTDOTSLASH_LEN 3
|
---|
59 |
|
---|
60 | /* Leftover bytes in the buffer, to work around library or OS bugs. */
|
---|
61 | #define BUF_SLOP 20
|
---|
62 |
|
---|
63 | int
|
---|
64 | main ()
|
---|
65 | {
|
---|
66 | #ifndef PATH_MAX
|
---|
67 | /* The Hurd doesn't define this, so getcwd can't exhibit the bug --
|
---|
68 | at least not on a local file system. And if we were to start worrying
|
---|
69 | about remote file systems, we'd have to enable the wrapper function
|
---|
70 | all of the time, just to be safe. That's not worth the cost. */
|
---|
71 | exit (0);
|
---|
72 | #elif ((INT_MAX / (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1) \
|
---|
73 | - DIR_NAME_SIZE - BUF_SLOP) \
|
---|
74 | <= PATH_MAX)
|
---|
75 | /* FIXME: Assuming there's a system for which this is true,
|
---|
76 | this should be done in a compile test. */
|
---|
77 | exit (0);
|
---|
78 | #else
|
---|
79 | char buf[PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1)
|
---|
80 | + DIR_NAME_SIZE + BUF_SLOP];
|
---|
81 | char *cwd = getcwd (buf, PATH_MAX);
|
---|
82 | size_t initial_cwd_len;
|
---|
83 | size_t cwd_len;
|
---|
84 | int fail = 0;
|
---|
85 | size_t n_chdirs = 0;
|
---|
86 |
|
---|
87 | if (cwd == NULL)
|
---|
88 | exit (1);
|
---|
89 |
|
---|
90 | cwd_len = initial_cwd_len = strlen (cwd);
|
---|
91 |
|
---|
92 | while (1)
|
---|
93 | {
|
---|
94 | size_t dotdot_max = PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN);
|
---|
95 | char *c = NULL;
|
---|
96 |
|
---|
97 | cwd_len += DIR_NAME_SIZE;
|
---|
98 | /* If mkdir or chdir fails, it could be that this system cannot create
|
---|
99 | any file with an absolute name longer than PATH_MAX, such as cygwin.
|
---|
100 | If so, leave fail as 0, because the current working directory can't
|
---|
101 | be too long for getcwd if it can't even be created. For other
|
---|
102 | errors, be pessimistic and consider that as a failure, too. */
|
---|
103 | if (mkdir (DIR_NAME, S_IRWXU) < 0 || chdir (DIR_NAME) < 0)
|
---|
104 | {
|
---|
105 | if (! (errno == ERANGE || is_ENAMETOOLONG (errno)))
|
---|
106 | fail = 2;
|
---|
107 | break;
|
---|
108 | }
|
---|
109 |
|
---|
110 | if (PATH_MAX <= cwd_len && cwd_len < PATH_MAX + DIR_NAME_SIZE)
|
---|
111 | {
|
---|
112 | c = getcwd (buf, PATH_MAX);
|
---|
113 | if (!c && errno == ENOENT)
|
---|
114 | {
|
---|
115 | fail = 1;
|
---|
116 | break;
|
---|
117 | }
|
---|
118 | if (c || ! (errno == ERANGE || is_ENAMETOOLONG (errno)))
|
---|
119 | {
|
---|
120 | fail = 2;
|
---|
121 | break;
|
---|
122 | }
|
---|
123 | }
|
---|
124 |
|
---|
125 | if (dotdot_max <= cwd_len - initial_cwd_len)
|
---|
126 | {
|
---|
127 | if (dotdot_max + DIR_NAME_SIZE < cwd_len - initial_cwd_len)
|
---|
128 | break;
|
---|
129 | c = getcwd (buf, cwd_len + 1);
|
---|
130 | if (!c)
|
---|
131 | {
|
---|
132 | if (! (errno == ERANGE || errno == ENOENT
|
---|
133 | || is_ENAMETOOLONG (errno)))
|
---|
134 | {
|
---|
135 | fail = 2;
|
---|
136 | break;
|
---|
137 | }
|
---|
138 | if (AT_FDCWD || errno == ERANGE || errno == ENOENT)
|
---|
139 | {
|
---|
140 | fail = 1;
|
---|
141 | break;
|
---|
142 | }
|
---|
143 | }
|
---|
144 | }
|
---|
145 |
|
---|
146 | if (c && strlen (c) != cwd_len)
|
---|
147 | {
|
---|
148 | fail = 2;
|
---|
149 | break;
|
---|
150 | }
|
---|
151 | ++n_chdirs;
|
---|
152 | }
|
---|
153 |
|
---|
154 | /* Leaving behind such a deep directory is not polite.
|
---|
155 | So clean up here, right away, even though the driving
|
---|
156 | shell script would also clean up. */
|
---|
157 | {
|
---|
158 | size_t i;
|
---|
159 |
|
---|
160 | /* Try rmdir first, in case the chdir failed. */
|
---|
161 | rmdir (DIR_NAME);
|
---|
162 | for (i = 0; i <= n_chdirs; i++)
|
---|
163 | {
|
---|
164 | if (chdir ("..") < 0)
|
---|
165 | break;
|
---|
166 | rmdir (DIR_NAME);
|
---|
167 | }
|
---|
168 | }
|
---|
169 |
|
---|
170 | exit (fail);
|
---|
171 | #endif
|
---|
172 | }
|
---|
173 | ]])],
|
---|
174 | [gl_cv_func_getcwd_path_max=yes],
|
---|
175 | [case $? in
|
---|
176 | 1) gl_cv_func_getcwd_path_max='no, but it is partly working';;
|
---|
177 | *) gl_cv_func_getcwd_path_max=no;;
|
---|
178 | esac],
|
---|
179 | [gl_cv_func_getcwd_path_max=no])
|
---|
180 | ])
|
---|
181 | case $gl_cv_func_getcwd_path_max in
|
---|
182 | no,*)
|
---|
183 | AC_DEFINE([HAVE_PARTLY_WORKING_GETCWD], 1,
|
---|
184 | [Define to 1 if getcwd works, except it sometimes fails when it shouldn't,
|
---|
185 | setting errno to ERANGE, ENAMETOOLONG, or ENOENT. If __GETCWD_PREFIX
|
---|
186 | is not defined, it doesn't matter whether HAVE_PARTLY_WORKING_GETCWD
|
---|
187 | is defined.]);;
|
---|
188 | esac
|
---|
189 | ])
|
---|