1 /* Test of getcwd() function.
2 Copyright (C) 2009-2011 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
32 #if ! HAVE_GETPAGESIZE
33 # define getpagesize() 0
36 /* This size is chosen to be larger than PATH_MAX (4k), yet smaller than
37 the 16kB pagesize on ia64 linux. Those conditions make the code below
38 trigger a bug in glibc's getcwd implementation before 2.4.90-10. */
39 #define TARGET_LEN (5 * 1024)
41 /* Keep this test in sync with m4/getcwd-abort-bug.m4. */
45 char const *dir_name = "confdir-14B---";
47 size_t initial_cwd_len;
53 /* The bug is triggered when PATH_MAX < getpagesize (), so skip
54 this relatively expensive and invasive test if that's not true. */
55 if (getpagesize () <= PATH_MAX)
59 cwd = getcwd (NULL, 0);
63 initial_cwd_len = strlen (cwd);
65 desired_depth = ((TARGET_LEN - 1 - initial_cwd_len)
66 / (1 + strlen (dir_name)));
67 for (d = 0; d < desired_depth; d++)
69 if (mkdir (dir_name, S_IRWXU) < 0 || chdir (dir_name) < 0)
71 if (! (errno == ERANGE || errno == ENAMETOOLONG || errno == ENOENT))
72 fail = 3; /* Unable to construct deep hierarchy. */
77 /* If libc has the bug in question, this invocation of getcwd
78 results in a failed assertion. */
79 cwd = getcwd (NULL, 0);
81 fail = 4; /* getcwd didn't assert, but it failed for a long name
82 where the answer could have been learned. */
85 /* Call rmdir first, in case the above chdir failed. */
100 /* The length of this name must be 8. */
101 #define DIR_NAME "confdir3"
102 #define DIR_NAME_LEN 8
103 #define DIR_NAME_SIZE (DIR_NAME_LEN + 1)
105 /* The length of "../". */
106 #define DOTDOTSLASH_LEN 3
108 /* Leftover bytes in the buffer, to work around library or OS bugs. */
111 /* Keep this test in sync with m4/getcwd-path-max.m4. */
113 test_long_name (void)
116 /* The Hurd doesn't define this, so getcwd can't exhibit the bug --
117 at least not on a local file system. And if we were to start worrying
118 about remote file systems, we'd have to enable the wrapper function
119 all of the time, just to be safe. That's not worth the cost. */
121 #elif ((INT_MAX / (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1) \
122 - DIR_NAME_SIZE - BUF_SLOP) \
124 /* FIXME: Assuming there's a system for which this is true,
125 this should be done in a compile test. */
128 char buf[PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1)
129 + DIR_NAME_SIZE + BUF_SLOP];
130 char *cwd = getcwd (buf, PATH_MAX);
131 size_t initial_cwd_len;
139 cwd_len = initial_cwd_len = strlen (cwd);
143 size_t dotdot_max = PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN);
146 cwd_len += DIR_NAME_SIZE;
147 /* If mkdir or chdir fails, it could be that this system cannot create
148 any file with an absolute name longer than PATH_MAX, such as cygwin.
149 If so, leave fail as 0, because the current working directory can't
150 be too long for getcwd if it can't even be created. For other
151 errors, be pessimistic and consider that as a failure, too. */
152 if (mkdir (DIR_NAME, S_IRWXU) < 0 || chdir (DIR_NAME) < 0)
154 if (! (errno == ERANGE || errno == ENAMETOOLONG || errno == ENOENT))
159 if (PATH_MAX <= cwd_len && cwd_len < PATH_MAX + DIR_NAME_SIZE)
161 c = getcwd (buf, PATH_MAX);
162 if (!c && errno == ENOENT)
167 if (c || ! (errno == ERANGE || errno == ENAMETOOLONG))
174 if (dotdot_max <= cwd_len - initial_cwd_len)
176 if (dotdot_max + DIR_NAME_SIZE < cwd_len - initial_cwd_len)
178 c = getcwd (buf, cwd_len + 1);
181 if (! (errno == ERANGE || errno == ENOENT
182 || errno == ENAMETOOLONG))
187 if (AT_FDCWD || errno == ERANGE || errno == ENOENT)
195 if (c && strlen (c) != cwd_len)
203 /* Leaving behind such a deep directory is not polite.
204 So clean up here, right away, even though the driving
205 shell script would also clean up. */
209 /* Try rmdir first, in case the chdir failed. */
211 for (i = 0; i <= n_chdirs; i++)
213 if (chdir ("..") < 0)
215 if (rmdir (DIR_NAME) != 0)
225 main (int argc, char **argv)
227 return test_abort_bug () + test_long_name ();