Jim Meyering wrote: > Is there an advantage to using the system getcwd for names > shorter than PATH_MAX, as there is on Solaris and systems with > a linux kernel? (i.e., ability to function in spite of restricted > permissions on a parent directory)
Paul Eggert wrote: > The first patch is simpler and easier to maintain, so I'd go with it > unless there's a performance or correctness reason to go with the > second patch. > > In Solaris, the system getcwd has some internal magic that > makes it better than our replacement when it works; if the > same is true for AIX that'd argue for the second patch. On both AIX 5.1 and 7.1, I can see with a "truss" run of my test program that getcwd() does the usual search through ../, ../../, ../../../, etc., like gnulib/lib/getcwd.c also does: statx("./../../../../../../../../../../../../", 0x2FF20E50, 76, 0) = 0 open("./../../../../../../../../../../../../", O_RDONLY) = 3 getdirent(3, 0x20000998, 4096) = 124 lseek(3, 0, 0) = 0 kfcntl(3, F_GETFD, 0x2FF22FFC) = 0 kfcntl(3, F_SETFD, 0x00000001) = 0 fstatx(3, 0x2FF20FB8, 76, 0) = 0 getdirent(3, 0x20000998, 4096) = 124 close(3) = 0 When run in a directory with an unreadable parent dir, the test program shows that getcwd() fails, and /bin/pwd as well: $ /bin/pwd pwd: The file access permissions do not allow the specified action. So, I'm going with the first approach. I'm not writing 'defined _AIX' but instead using an autoconf test. My new autoconf test is not needed; Jim's old one in m4/getcwd-path-max.m4 also recognizes the bug. Only two modifications are needed: to actually run the test on this platform (previously it was only run on platforms where getcwd(NULL,0) works), and a new exit code. 2011-11-20 Bruno Haible <br...@clisp.org> getcwd: Work around getcwd bug on AIX 5..7. * m4/getcwd-path-max.m4 (gl_FUNC_GETCWD_PATH_MAX): Require AC_CANONICAL_HOST. Assign exit code 31 to the bug seen on AIX 5.1..7.1. Use a different value for gl_cv_func_getcwd_path_max. Move the definition of HAVE_PARTLY_WORKING_GETCWD from here... * m4/getcwd.m4 (gl_FUNC_GETCWD): ... to here. Invoke gl_FUNC_GETCWD_PATH_MAX also when $gl_cv_func_getcwd_null is 'no'. Define HAVE_MINIMALLY_WORKING_GETCWD. * lib/getcwd.c (__getcwd): Don't use the system's getcwd on platforms where it is not even minimally working, that is, on AIX. * tests/test-getcwd.c (test_long_name): Distinguish the same cases as m4/getcwd-path-max.m4. (main): Update exit code computation. * doc/posix-functions/getcwd.texi: Mention list of platforms where getcwd does not handle long file names. --- doc/posix-functions/getcwd.texi.orig Mon Nov 21 00:44:38 2011 +++ doc/posix-functions/getcwd.texi Mon Nov 21 00:35:22 2011 @@ -33,7 +33,8 @@ This function is missing on some older platforms. @item This function does not handle long file names (greater than @code{PATH_MAX}) -correctly on some platforms. +correctly on some platforms: +glibc on Linux 2.4.20, MacOS X 10.5, FreeBSD 6.4, NetBSD 5.1, OpenBSD 4.9, AIX 7.1. @end itemize Portability problems not fixed by Gnulib: --- lib/getcwd.c.orig Mon Nov 21 00:44:38 2011 +++ lib/getcwd.c Mon Nov 21 00:24:42 2011 @@ -135,7 +135,7 @@ size_t allocated = size; size_t used; -#if HAVE_RAW_DECL_GETCWD +#if HAVE_RAW_DECL_GETCWD && HAVE_MINIMALLY_WORKING_GETCWD /* If AT_FDCWD is not defined, the algorithm below is O(N**2) and this is much slower than the system getcwd (at least on GNU/Linux). So trust the system getcwd's results unless they @@ -143,7 +143,12 @@ Use the system getcwd even if we have openat support, since the system getcwd works even when a parent is unreadable, while the - openat-based approach does not. */ + openat-based approach does not. + + But on AIX 5.1..7.1, the system getcwd is not even minimally + working: If the current directory name is slightly longer than + PATH_MAX, it omits the first directory component and returns + this wrong result with errno = 0. */ # undef getcwd dir = getcwd (buf, size); --- m4/getcwd-path-max.m4.orig Mon Nov 21 00:44:38 2011 +++ m4/getcwd-path-max.m4 Mon Nov 21 00:29:53 2011 @@ -1,4 +1,4 @@ -# serial 18 +# serial 19 # Check for several getcwd bugs with long file names. # If so, arrange to compile the wrapper function. @@ -16,6 +16,7 @@ AC_DEFUN([gl_FUNC_GETCWD_PATH_MAX], [ AC_CHECK_DECLS_ONCE([getcwd]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) AC_CHECK_HEADERS_ONCE([unistd.h]) AC_REQUIRE([gl_PATHMAX_SNIPPET_PREREQ]) @@ -124,7 +125,12 @@ fail = 11; break; } - if (c || ! (errno == ERANGE || is_ENAMETOOLONG (errno))) + if (c) + { + fail = 31; + break; + } + if (! (errno == ERANGE || is_ENAMETOOLONG (errno))) { fail = 21; break; @@ -184,14 +190,12 @@ [gl_cv_func_getcwd_path_max=yes], [case $? in 10|11|12) gl_cv_func_getcwd_path_max='no, but it is partly working';; + 31) gl_cv_func_getcwd_path_max='no, it has the AIX bug';; *) gl_cv_func_getcwd_path_max=no;; esac], - [gl_cv_func_getcwd_path_max=no]) + [case "$host_os" in + aix*) gl_cv_func_getcwd_path_max='no, it has the AIX bug';; + *) gl_cv_func_getcwd_path_max=no;; + esac]) ]) - 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.]);; - esac ]) --- m4/getcwd.m4.orig Mon Nov 21 00:44:38 2011 +++ m4/getcwd.m4 Mon Nov 21 00:30:45 2011 @@ -113,14 +113,31 @@ gl_cv_func_getcwd_path_max=yes ;; *) + gl_FUNC_GETCWD_PATH_MAX case "$gl_cv_func_getcwd_null" in *yes) - gl_FUNC_GETCWD_PATH_MAX gl_FUNC_GETCWD_ABORT_BUG([gl_abort_bug=yes]) ;; esac ;; esac + dnl Define HAVE_MINIMALLY_WORKING_GETCWD and HAVE_PARTLY_WORKING_GETCWD + dnl if appropriate. + case "$gl_cv_func_getcwd_path_max" in + "no, it has the AIX bug") ;; + *) + AC_DEFINE([HAVE_MINIMALLY_WORKING_GETCWD], [1], + [Define to 1 if getcwd minimally works, that is, its result can be + trusted when it succeeds.]) + ;; + esac + case "$gl_cv_func_getcwd_path_max" in + "no, but it is partly working") + 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.]) + ;; + esac case $gl_cv_func_getcwd_null,$gl_cv_func_getcwd_posix_signature$gl_cv_func_getcwd_path_max,$gl_abort_bug in *yes,yes,yes,no) ;; --- tests/test-getcwd.c.orig Mon Nov 21 00:44:38 2011 +++ tests/test-getcwd.c Mon Nov 21 00:36:56 2011 @@ -164,11 +164,16 @@ fail = 3; break; } - if (c || ! (errno == ERANGE || errno == ENAMETOOLONG)) + if (c) { fail = 4; break; } + if (! (errno == ERANGE || errno == ENAMETOOLONG)) + { + fail = 5; + break; + } } if (dotdot_max <= cwd_len - initial_cwd_len) @@ -181,12 +186,12 @@ if (! (errno == ERANGE || errno == ENOENT || errno == ENAMETOOLONG)) { - fail = 5; + fail = 6; break; } if (AT_FDCWD || errno == ERANGE || errno == ENOENT) { - fail = 6; + fail = 7; break; } } @@ -194,7 +199,7 @@ if (c && strlen (c) != cwd_len) { - fail = 7; + fail = 8; break; } ++n_chdirs; @@ -224,5 +229,5 @@ int main (int argc, char **argv) { - return test_abort_bug () * 8 + test_long_name (); + return test_abort_bug () * 10 + test_long_name (); } -- In memoriam Kerem Yılmazer <http://en.wikipedia.org/wiki/Kerem_Yılmazer>