1# serial 19 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-2007, 2009-2017 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([AC_CANONICAL_HOST]) dnl for cross-compiles 20 AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) 21 AC_CHECK_HEADERS_ONCE([unistd.h]) 22 AC_REQUIRE([gl_PATHMAX_SNIPPET_PREREQ]) 23 AC_CACHE_CHECK([whether getcwd handles long file names properly], 24 gl_cv_func_getcwd_path_max, 25 [# Arrange for deletion of the temporary directory this test creates. 26 ac_clean_files="$ac_clean_files confdir3" 27 dnl Please keep this in sync with tests/test-getcwd.c. 28 AC_RUN_IFELSE( 29 [AC_LANG_SOURCE( 30 [[ 31#include <errno.h> 32#include <stdlib.h> 33#if HAVE_UNISTD_H 34# include <unistd.h> 35#else 36# include <direct.h> 37#endif 38#include <string.h> 39#include <limits.h> 40#include <sys/stat.h> 41#include <sys/types.h> 42#include <fcntl.h> 43 44]gl_PATHMAX_SNIPPET[ 45 46#ifndef AT_FDCWD 47# define AT_FDCWD 0 48#endif 49#ifdef ENAMETOOLONG 50# define is_ENAMETOOLONG(x) ((x) == ENAMETOOLONG) 51#else 52# define is_ENAMETOOLONG(x) 0 53#endif 54 55/* Use the getcwd function, not any macro. */ 56#undef getcwd 57 58/* Don't get link errors because mkdir is redefined to rpl_mkdir. */ 59#undef mkdir 60 61#ifndef S_IRWXU 62# define S_IRWXU 0700 63#endif 64 65/* The length of this name must be 8. */ 66#define DIR_NAME "confdir3" 67#define DIR_NAME_LEN 8 68#define DIR_NAME_SIZE (DIR_NAME_LEN + 1) 69 70/* The length of "../". */ 71#define DOTDOTSLASH_LEN 3 72 73/* Leftover bytes in the buffer, to work around library or OS bugs. */ 74#define BUF_SLOP 20 75 76int 77main () 78{ 79#ifndef PATH_MAX 80 /* The Hurd doesn't define this, so getcwd can't exhibit the bug -- 81 at least not on a local file system. And if we were to start worrying 82 about remote file systems, we'd have to enable the wrapper function 83 all of the time, just to be safe. That's not worth the cost. */ 84 exit (0); 85#elif ((INT_MAX / (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1) \ 86 - DIR_NAME_SIZE - BUF_SLOP) \ 87 <= PATH_MAX) 88 /* FIXME: Assuming there's a system for which this is true, 89 this should be done in a compile test. */ 90 exit (0); 91#else 92 char buf[PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1) 93 + DIR_NAME_SIZE + BUF_SLOP]; 94 char *cwd = getcwd (buf, PATH_MAX); 95 size_t initial_cwd_len; 96 size_t cwd_len; 97 int fail = 0; 98 size_t n_chdirs = 0; 99 100 if (cwd == NULL) 101 exit (10); 102 103 cwd_len = initial_cwd_len = strlen (cwd); 104 105 while (1) 106 { 107 size_t dotdot_max = PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN); 108 char *c = NULL; 109 110 cwd_len += DIR_NAME_SIZE; 111 /* If mkdir or chdir fails, it could be that this system cannot create 112 any file with an absolute name longer than PATH_MAX, such as cygwin. 113 If so, leave fail as 0, because the current working directory can't 114 be too long for getcwd if it can't even be created. For other 115 errors, be pessimistic and consider that as a failure, too. */ 116 if (mkdir (DIR_NAME, S_IRWXU) < 0 || chdir (DIR_NAME) < 0) 117 { 118 if (! (errno == ERANGE || is_ENAMETOOLONG (errno))) 119 fail = 20; 120 break; 121 } 122 123 if (PATH_MAX <= cwd_len && cwd_len < PATH_MAX + DIR_NAME_SIZE) 124 { 125 struct stat sb; 126 127 c = getcwd (buf, PATH_MAX); 128 if (!c && errno == ENOENT) 129 { 130 fail = 11; 131 break; 132 } 133 if (c) 134 { 135 fail = 31; 136 break; 137 } 138 if (! (errno == ERANGE || is_ENAMETOOLONG (errno))) 139 { 140 fail = 21; 141 break; 142 } 143 144 /* Our replacement needs to be able to stat() long ../../paths, 145 so generate a path larger than PATH_MAX to check, 146 avoiding the replacement if we can't stat(). */ 147 c = getcwd (buf, cwd_len + 1); 148 if (c && !AT_FDCWD && stat (c, &sb) != 0 && is_ENAMETOOLONG (errno)) 149 { 150 fail = 32; 151 break; 152 } 153 } 154 155 if (dotdot_max <= cwd_len - initial_cwd_len) 156 { 157 if (dotdot_max + DIR_NAME_SIZE < cwd_len - initial_cwd_len) 158 break; 159 c = getcwd (buf, cwd_len + 1); 160 if (!c) 161 { 162 if (! (errno == ERANGE || errno == ENOENT 163 || is_ENAMETOOLONG (errno))) 164 { 165 fail = 22; 166 break; 167 } 168 if (AT_FDCWD || errno == ERANGE || errno == ENOENT) 169 { 170 fail = 12; 171 break; 172 } 173 } 174 } 175 176 if (c && strlen (c) != cwd_len) 177 { 178 fail = 23; 179 break; 180 } 181 ++n_chdirs; 182 } 183 184 /* Leaving behind such a deep directory is not polite. 185 So clean up here, right away, even though the driving 186 shell script would also clean up. */ 187 { 188 size_t i; 189 190 /* Try rmdir first, in case the chdir failed. */ 191 rmdir (DIR_NAME); 192 for (i = 0; i <= n_chdirs; i++) 193 { 194 if (chdir ("..") < 0) 195 break; 196 if (rmdir (DIR_NAME) != 0) 197 break; 198 } 199 } 200 201 exit (fail); 202#endif 203} 204 ]])], 205 [gl_cv_func_getcwd_path_max=yes], 206 [case $? in 207 10|11|12) gl_cv_func_getcwd_path_max='no, but it is partly working';; 208 31) gl_cv_func_getcwd_path_max='no, it has the AIX bug';; 209 32) gl_cv_func_getcwd_path_max='yes, but with shorter paths';; 210 *) gl_cv_func_getcwd_path_max=no;; 211 esac], 212 [case "$host_os" in 213 aix*) gl_cv_func_getcwd_path_max='no, it has the AIX bug';; 214 *) gl_cv_func_getcwd_path_max=no;; 215 esac]) 216 ]) 217]) 218