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 16AC_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 63int 64main () 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]) 190