diff options
-rw-r--r-- | m4/getcwd-path-max.m4 | 116 |
1 files changed, 69 insertions, 47 deletions
diff --git a/m4/getcwd-path-max.m4 b/m4/getcwd-path-max.m4 index a1e123976..ec2063d65 100644 --- a/m4/getcwd-path-max.m4 +++ b/m4/getcwd-path-max.m4 @@ -1,6 +1,5 @@ -#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 5 +# Check for several getcwd bugs with long paths. # 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. @@ -25,46 +24,57 @@ # 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, + AC_CHECK_DECLS_ONCE(getcwd) + AC_CHECK_HEADERS_ONCE(fcntl.h) + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + AC_CACHE_CHECK([whether getcwd handles long paths 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 <errno.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <limits.h> #include <sys/stat.h> #include <sys/types.h> +#if HAVE_FCNTL_H +# include <fcntl.h> +#endif -/* 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 () +main (void) { #ifndef PATH_MAX /* The Hurd doesn't define this, so getcwd can't exhibit the bug -- @@ -72,14 +82,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 +100,50 @@ main () if (cwd == NULL) exit (1); - cwd_len = strlen (cwd); + cwd_len = initial_cwd_len = strlen (cwd); while (1) { - char *c; - size_t len; + size_t dotdot_max = PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN); + char *c = NULL; - cwd_len += 1 + strlen (DIR_NAME); + cwd_len += DIR_NAME_SIZE; /* If mkdir or chdir fails, be pessimistic and consider that as a failure, too. */ - if (mkdir (DIR_NAME, 0700) < 0 || chdir (DIR_NAME) < 0) + if (mkdir (DIR_NAME, S_IRWXU) < 0 || chdir (DIR_NAME) < 0) { fail = 1; 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 != ERANGE) + { + fail = 1; + break; + } } - if ((len = strlen (c)) != cwd_len) + + 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 && (AT_FDCWD || !is_ENAMETOOLONG (errno))) + { + fail = 1; + break; + } + } + + if (c && strlen (c) != cwd_len) { fail = 1; break; } ++n_chdirs; - if (PATH_MAX < len) - break; } /* Leaving behind such a deep directory is not polite. @@ -138,13 +166,7 @@ main () #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], + [gl_cv_func_getcwd_path_max=no], + [gl_cv_func_getcwd_path_max=no])]) ]) |