X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=m4%2Fgetcwd-path-max.m4;h=14784999d454a312d08a637dc3cb59489eb12919;hb=05a96e0bca75d5b01c337cd7dacd04507d6e6497;hp=a1e123976b02a057803f61b41a2fe2458e31151c;hpb=7c232d6b1cfc23376954f517f6d6773aa3f52eda;p=gnulib.git diff --git a/m4/getcwd-path-max.m4 b/m4/getcwd-path-max.m4 index a1e123976..14784999d 100644 --- a/m4/getcwd-path-max.m4 +++ b/m4/getcwd-path-max.m4 @@ -1,67 +1,64 @@ -#serial 4 -# Check whether getcwd has the bug that it succeeds for a working directory -# longer than PATH_MAX, yet returns a truncated directory name. +# serial 14 +# Check for several getcwd bugs with long file names. # If so, arrange to compile the wrapper function. # This is necessary for at least GNU libc on linux-2.4.19 and 2.4.20. # I've heard that this is due to a Linux kernel bug, and that it has # been fixed between 2.4.21-pre3 and 2.4.21-pre4. */ -# Copyright (C) 2003, 2004 Free Software Foundation, Inc. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Copyright (C) 2003-2007, 2009 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. # From Jim Meyering -AC_DEFUN([GL_FUNC_GETCWD_PATH_MAX], +AC_DEFUN([gl_FUNC_GETCWD_PATH_MAX], [ - AC_CHECK_DECLS([getcwd]) - AC_CACHE_CHECK([whether getcwd properly handles paths longer than PATH_MAX], - gl_cv_func_getcwd_vs_path_max, - [ - # Arrange for deletion of the temporary directory this test creates. - ac_clean_files="$ac_clean_files confdir3" - AC_RUN_IFELSE([AC_LANG_SOURCE([[ + 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, + [# Arrange for deletion of the temporary directory this test creates. + ac_clean_files="$ac_clean_files confdir3" + AC_RUN_IFELSE( + [AC_LANG_SOURCE( + [[ +#include #include #include #include #include #include #include +#include -/* Don't get link errors because mkdir is redefined to rpl_mkdir. */ -#undef mkdir - -#ifndef CHAR_BIT -# define CHAR_BIT 8 +#ifndef AT_FDCWD +# define AT_FDCWD 0 +#endif +#ifdef ENAMETOOLONG +# define is_ENAMETOOLONG(x) ((x) == ENAMETOOLONG) +#else +# define is_ENAMETOOLONG(x) 0 #endif -/* The extra casts work around common compiler bugs. */ -#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) -/* The outer cast is needed to work around a bug in Cray C 5.0.3.0. - It is necessary at least when t == time_t. */ -#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \ - ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0)) -#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t))) +/* Don't get link errors because mkdir is redefined to rpl_mkdir. */ +#undef mkdir -#ifndef INT_MAX -# define INT_MAX TYPE_MAXIMUM (int) +#ifndef S_IRWXU +# define S_IRWXU 0700 #endif /* The length of this name must be 8. */ #define DIR_NAME "confdir3" +#define DIR_NAME_LEN 8 +#define DIR_NAME_SIZE (DIR_NAME_LEN + 1) + +/* The length of "../". */ +#define DOTDOTSLASH_LEN 3 + +/* Leftover bytes in the buffer, to work around library or OS bugs. */ +#define BUF_SLOP 20 int main () @@ -72,14 +69,17 @@ main () 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); -#elif INT_MAX - 9 <= PATH_MAX - /* The '9', above, comes from strlen (DIR_NAME) + 1. */ +#elif ((INT_MAX / (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1) \ + - 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); #else - char buf[PATH_MAX + 20]; + 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; @@ -87,35 +87,68 @@ main () if (cwd == NULL) exit (1); - cwd_len = strlen (cwd); + cwd_len = initial_cwd_len = strlen (cwd); while (1) { - char *c; - size_t len; - - cwd_len += 1 + strlen (DIR_NAME); - /* If mkdir or chdir fails, be pessimistic and consider that - as a failure, too. */ - if (mkdir (DIR_NAME, 0700) < 0 || chdir (DIR_NAME) < 0) + 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) { - fail = 1; + if (! (errno == ERANGE || is_ENAMETOOLONG (errno))) + fail = 2; break; } - if ((c = getcwd (buf, PATH_MAX)) == NULL) - { - /* This allows any failure to indicate there is no bug. - FIXME: check errno? */ - 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 ((len = strlen (c)) != cwd_len) + + if (dotdot_max <= cwd_len - initial_cwd_len) { - fail = 1; + 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; - if (PATH_MAX < len) - break; } /* Leaving behind such a deep directory is not polite. @@ -124,27 +157,34 @@ main () { size_t i; - /* Unlink first, in case the chdir failed. */ - unlink (DIR_NAME); + /* Try rmdir first, in case the chdir failed. */ + rmdir (DIR_NAME); for (i = 0; i <= n_chdirs; i++) { if (chdir ("..") < 0) break; - rmdir (DIR_NAME); + if (rmdir (DIR_NAME) != 0) + break; } } exit (fail); #endif } - ]])], - [gl_cv_func_getcwd_vs_path_max=yes], - [gl_cv_func_getcwd_vs_path_max=no], - [gl_cv_func_getcwd_vs_path_max=no])]) - - if test $gl_cv_func_getcwd_vs_path_max = no; then - AC_LIBOBJ(getcwd) - AC_DEFINE(getcwd, rpl_getcwd, - [Define to rpl_getcwd if the wrapper function should be used.]) - fi + ]])], + [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 ])