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
# undef getcwd
dir = getcwd (buf, size);
- if (dir || (errno != ERANGE && errno != ENAMETOOLONG && errno != ENOENT))
+ if (dir)
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)
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);