X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=lib%2Fgetcwd.c;h=2397c08c839e82e781c5837df6baa48a97dbf1a6;hb=679b14d8851a364efdffbdf50d4aa43921762076;hp=978c5383737da0672fa98a1c71a7f2b377360095;hpb=1e4ece4ab9850fbfa88c9ec43ea518c7bc266792;p=gnulib.git
diff --git a/lib/getcwd.c b/lib/getcwd.c
index 978c53837..2397c08c8 100644
--- a/lib/getcwd.c
+++ b/lib/getcwd.c
@@ -2,23 +2,23 @@
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 . */
#if !_LIBC
# include
-# include "getcwd.h"
+# include
+# include "dirfd.h"
#endif
#include
@@ -29,6 +29,14 @@
#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
+# define HAVE_OPENAT_SUPPORT 1
+#else
+# define HAVE_OPENAT_SUPPORT 0
+#endif
+
#ifndef __set_errno
# define __set_errno(val) (errno = (val))
#endif
@@ -89,7 +97,7 @@
#endif
#if !_LIBC
-# define __getcwd getcwd
+# define __getcwd rpl_getcwd
# define __lstat lstat
# define __closedir closedir
# define __opendir opendir
@@ -122,7 +130,7 @@ __getcwd (char *buf, size_t size)
DEEP_NESTING = 100
};
-#ifdef AT_FDCWD
+#if HAVE_OPENAT_SUPPORT
int fd = AT_FDCWD;
bool fd_needs_closing = false;
#else
@@ -140,13 +148,18 @@ __getcwd (char *buf, size_t size)
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))
@@ -198,7 +211,7 @@ __getcwd (char *buf, size_t size)
bool use_d_ino = true;
/* Look at the parent directory. */
-#ifdef AT_FDCWD
+#if HAVE_OPENAT_SUPPORT
fd = openat (fd, "..", O_RDONLY);
if (fd < 0)
goto lose;
@@ -225,10 +238,12 @@ __getcwd (char *buf, size_t size)
mount_point = dotdev != thisdev;
/* Search for the last directory. */
-#ifdef AT_FDCWD
+#if HAVE_OPENAT_SUPPORT
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);
@@ -279,7 +294,7 @@ __getcwd (char *buf, size_t size)
{
int entry_status;
-#ifdef AT_FDCWD
+#if HAVE_OPENAT_SUPPORT
entry_status = fstatat (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW);
#else
/* Compute size needed for this file name, or for the file
@@ -375,7 +390,7 @@ __getcwd (char *buf, size_t size)
if (dirp == &dir[allocated - 1])
*--dirp = '/';
-#ifndef AT_FDCWD
+#if ! HAVE_OPENAT_SUPPORT
if (dotlist != dots)
free (dotlist);
#endif
@@ -383,7 +398,7 @@ __getcwd (char *buf, size_t size)
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);
@@ -401,7 +416,7 @@ __getcwd (char *buf, size_t size)
int save = errno;
if (dirstream)
__closedir (dirstream);
-#ifdef AT_FDCWD
+#if HAVE_OPENAT_SUPPORT
if (fd_needs_closing)
close (fd);
#else