getcwd-path-max.m4 [plain text]
AC_DEFUN([gl_FUNC_GETCWD_PATH_MAX],
[
AC_CHECK_DECLS_ONCE(getcwd)
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
AC_CACHE_CHECK([whether getcwd handles long file names properly],
gl_cv_func_getcwd_path_max,
[ ac_clean_files="$ac_clean_files confdir3"
AC_RUN_IFELSE(
[AC_LANG_SOURCE(
[[
/* Don't get link errors because mkdir is redefined to rpl_mkdir. */
/* The length of this name must be 8. */
/* The length of "../". */
/* Leftover bytes in the buffer, to work around library or OS bugs. */
int
main (void)
{
/* The Hurd doesn't define this, so getcwd can't exhibit the bug --
at least not on a local file system. And if we were to start worrying
about remote file systems, we'd have to enable the wrapper function
all of the time, just to be safe. That's not worth the cost. */
exit (0);
- DIR_NAME_SIZE - BUF_SLOP) \
<= PATH_MAX)
/* FIXME: Assuming there's a system for which this is true,
this should be done in a compile test. */
exit (0);
char buf[PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1)
+ DIR_NAME_SIZE + BUF_SLOP];
char *cwd = getcwd (buf, PATH_MAX);
size_t initial_cwd_len;
size_t cwd_len;
int fail = 0;
size_t n_chdirs = 0;
if (cwd == NULL)
exit (1);
cwd_len = initial_cwd_len = strlen (cwd);
while (1)
{
size_t dotdot_max = PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN);
char *c = NULL;
cwd_len += DIR_NAME_SIZE;
/* If mkdir or chdir fails, it could be that this system cannot create
any file with an absolute name longer than PATH_MAX, such as cygwin.
If so, leave fail as 0, because the current working directory can't
be too long for getcwd if it can't even be created. For other
errors, be pessimistic and consider that as a failure, too. */
if (mkdir (DIR_NAME, S_IRWXU) < 0 || chdir (DIR_NAME) < 0)
{
if (! (errno == ERANGE || is_ENAMETOOLONG (errno)))
fail = 2;
break;
}
if (PATH_MAX <= cwd_len && cwd_len < PATH_MAX + DIR_NAME_SIZE)
{
c = getcwd (buf, PATH_MAX);
if (!c && errno == ENOENT)
{
fail = 1;
break;
}
if (c || ! (errno == ERANGE || is_ENAMETOOLONG (errno)))
{
fail = 2;
break;
}
}
if (dotdot_max <= cwd_len - initial_cwd_len)
{
if (dotdot_max + DIR_NAME_SIZE < cwd_len - initial_cwd_len)
break;
c = getcwd (buf, cwd_len + 1);
if (!c)
{
if (! (errno == ERANGE || errno == ENOENT
|| is_ENAMETOOLONG (errno)))
{
fail = 2;
break;
}
if (AT_FDCWD || errno == ERANGE || errno == ENOENT)
{
fail = 1;
break;
}
}
}
if (c && strlen (c) != cwd_len)
{
fail = 2;
break;
}
++n_chdirs;
}
/* Leaving behind such a deep directory is not polite.
So clean up here, right away, even though the driving
shell script would also clean up. */
{
size_t i;
/* Unlink first, in case the chdir failed. */
unlink (DIR_NAME);
for (i = 0; i <= n_chdirs; i++)
{
if (chdir ("..") < 0)
break;
rmdir (DIR_NAME);
}
}
exit (fail);
}
]])],
[gl_cv_func_getcwd_path_max=yes],
[case $? in
1) gl_cv_func_getcwd_path_max='no, but it is partly working';;
*) gl_cv_func_getcwd_path_max=no;;
esac],
[gl_cv_func_getcwd_path_max=no])
])
case $gl_cv_func_getcwd_path_max in
no,*)
AC_DEFINE([HAVE_PARTLY_WORKING_GETCWD], 1,
[Define to 1 if getcwd works, except it sometimes fails when it shouldn't,
setting errno to ERANGE, ENAMETOOLONG, or ENOENT. If __GETCWD_PREFIX
is not defined, it doesn't matter whether HAVE_PARTLY_WORKING_GETCWD
is defined.]);;
esac
])