-/* Copyright (C) 1991,92,93,94,95,96,97,98,99,2004,2005,2006 Free Software
+/* Copyright (C) 1991,92,93,94,95,96,97,98,99,2004,2005,2006,2007 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
+ This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#if !_LIBC
# include <config.h>
-# include "getcwd.h"
+# include <unistd.h>
+# include "dirfd.h"
#endif
#include <errno.h>
# ifndef mempcpy
# define mempcpy __mempcpy
# endif
-#else
-# include "mempcpy.h"
#endif
#include <limits.h>
size_t allocated = size;
size_t used;
-#if HAVE_PARTLY_WORKING_GETCWD && !defined AT_FDCWD
+#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. */
+ suspicious.
+
+ 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. */
+
# undef getcwd
dir = getcwd (buf, size);
if (dir || (errno != ERANGE && !is_ENAMETOOLONG (errno) && errno != ENOENT))
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);
used = dir + allocated - dirp;
memmove (dir, dirp, used);
- if (buf == NULL && size == 0)
+ if (size == 0)
/* Ensure that the buffer is only as large as necessary. */
buf = realloc (dir, used);