X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fgetcwd.c;h=f8101613f2c8eb01f50364eb87176039160be5d4;hb=b781b33a9eee9f2bdb70f8fc51f6d1ec5ebbbd02;hp=37968df42abe67d68032cc2fca18f99ae083678d;hpb=441aa3044f43e5572f58c354f01e6bc070acd5c7;p=gnulib.git diff --git a/lib/getcwd.c b/lib/getcwd.c index 37968df42..f8101613f 100644 --- a/lib/getcwd.c +++ b/lib/getcwd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991-1999, 2004-2009 Free Software Foundation, Inc. +/* Copyright (C) 1991-1999, 2004-2011 Free Software Foundation, Inc. This file is part of the GNU C Library. This program is free software: you can redistribute it and/or modify @@ -27,9 +27,10 @@ #include /* For AT_FDCWD on Solaris 9. */ -/* If this host provides the openat function, then enable - code below to make getcwd more efficient and robust. */ -#ifdef HAVE_OPENAT +/* If this host provides the openat function or if we're using the + gnulib replacement function, then enable code below to make getcwd + more efficient and robust. */ +#if defined HAVE_OPENAT || defined GNULIB_OPENAT # define HAVE_OPENAT_SUPPORT 1 #else # define HAVE_OPENAT_SUPPORT 0 @@ -57,8 +58,6 @@ # endif #endif -#include - #ifndef MAX # define MAX(a, b) ((a) < (b) ? (b) : (a)) #endif @@ -66,12 +65,12 @@ # define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif +#include "pathmax.h" + +/* In this file, PATH_MAX only serves as a threshold for choosing among two + algorithms. */ #ifndef PATH_MAX -# ifdef MAXPATHLEN -# define PATH_MAX MAXPATHLEN -# else -# define PATH_MAX 1024 -# endif +# define PATH_MAX 8192 #endif #if D_INO_IN_DIRENT @@ -136,13 +135,11 @@ __getcwd (char *buf, size_t size) size_t allocated = size; size_t used; -#if HAVE_PARTLY_WORKING_GETCWD - /* The system getcwd works, except it sometimes fails when it - shouldn't, setting errno to ERANGE, ENAMETOOLONG, or ENOENT. 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 look - suspicious. +#if HAVE_RAW_DECL_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 + look suspicious. Use the system getcwd even if we have openat support, since the system getcwd works even when a parent is unreadable, while the @@ -150,8 +147,27 @@ __getcwd (char *buf, size_t size) # undef getcwd dir = getcwd (buf, size); - if (dir || (errno != ERANGE && errno != ENAMETOOLONG && errno != ENOENT)) + if (dir || (size && errno == ERANGE)) return dir; + + /* Solaris getcwd (NULL, 0) fails with errno == EINVAL, but it has + internal magic that lets it work even if an ancestor directory is + inaccessible, which is better in many cases. So in this case try + again with a buffer that's almost always big enough. */ + if (errno == EINVAL && buf == NULL && size == 0) + { + char big_buffer[BIG_FILE_NAME_LENGTH + 1]; + dir = getcwd (big_buffer, sizeof big_buffer); + if (dir) + return strdup (dir); + } + +# if HAVE_PARTLY_WORKING_GETCWD + /* The system getcwd works, except it sometimes fails when it + shouldn't, setting errno to ERANGE, ENAMETOOLONG, or ENOENT. */ + if (errno != ERANGE && errno != ENAMETOOLONG && errno != ENOENT) + return NULL; +# endif #endif if (size == 0) @@ -230,8 +246,6 @@ __getcwd (char *buf, size_t size) dirstream = fdopendir (fd); if (dirstream == NULL) goto lose; - /* Reset fd. It may have been closed by fdopendir. */ - fd = dirfd (dirstream); fd_needs_closing = false; #else dirstream = __opendir (dotlist);