X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fgetcwd.c;h=2397c08c839e82e781c5837df6baa48a97dbf1a6;hb=679b14d8851a364efdffbdf50d4aa43921762076;hp=ba226799d384c1f799dfd49e966435d1202b8a89;hpb=79c0a43808d9ca85acd04600149fc1a9b75bd1b9;p=gnulib.git diff --git a/lib/getcwd.c b/lib/getcwd.c index ba226799d..2397c08c8 100644 --- a/lib/getcwd.c +++ b/lib/getcwd.c @@ -1,27 +1,24 @@ -/* 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. */ - -#ifdef HAVE_CONFIG_H -# include -#endif + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #if !_LIBC -# include "getcwd.h" +# include +# include +# include "dirfd.h" #endif #include @@ -32,29 +29,21 @@ #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 -#if HAVE_DIRENT_H || _LIBC -# include -# ifndef _D_EXACT_NAMLEN -# define _D_EXACT_NAMLEN(d) strlen ((d)->d_name) -# endif -#else -# define dirent direct -# if HAVE_SYS_NDIR_H -# include -# endif -# if HAVE_SYS_DIR_H -# include -# endif -# if HAVE_NDIR_H -# include -# endif -#endif +#include #ifndef _D_EXACT_NAMLEN -# define _D_EXACT_NAMLEN(d) ((d)->d_namlen) +# define _D_EXACT_NAMLEN(d) strlen ((d)->d_name) #endif #ifndef _D_ALLOC_NAMLEN # define _D_ALLOC_NAMLEN(d) (_D_EXACT_NAMLEN (d) + 1) @@ -68,8 +57,6 @@ # ifndef mempcpy # define mempcpy __mempcpy # endif -#else -# include "mempcpy.h" #endif #include @@ -110,12 +97,17 @@ #endif #if !_LIBC -# define __getcwd getcwd +# define __getcwd rpl_getcwd # define __lstat lstat # define __closedir closedir # define __opendir opendir # define __readdir readdir #endif + +/* The results of opendir() in this file are not used with dirfd and fchdir, + therefore save some unnecessary recursion in fchdir.c. */ +#undef opendir +#undef closedir /* Get the name of the current working directory, and put it in SIZE bytes of BUF. Returns NULL if the directory couldn't be determined or @@ -138,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 @@ -156,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)) @@ -214,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; @@ -241,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); @@ -295,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 @@ -391,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 @@ -399,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); @@ -417,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