Eric Blake <ebb9 <at> byu.net> writes: > One improvement possible for fdopendir is that > if fchdir is being emulated by gnulib, we can do a query into the fchdir > metadata table to retrieve the directory name associated with an fd, rather > than having to go through save_cwd/fchdir/opendir/restore_cwd.
Here's two patches for that, to be applied on top of fchdir. From: Eric Blake <e...@byu.net> Date: Sun, 30 Aug 2009 18:48:20 -0600 Subject: [PATCH 1/2] fdopendir: split into its own module * lib/openat.c (fdopendir): Move... * lib/fdopendir.c: ...into new file. * modules/fdopendir: New module. * m4/fdopendir.m4 (gl_FUNC_FDOPENDIR): New file. * modules/openat (Depends-on): Add fdopendir. * m4/openat.m4 (gl_FUNC_OPENAT): No longer need to check for fdopendir here. * modules/savedir (Depends-on): Only need fdopendir, not full openat. * lib/savedir.c (include): Use <dirent.h>, not "openat.h". * lib/openat.h (fdopendir): Drop prototype. * lib/dirent.in.h (fdopendir): Provide prototype. * m4/dirent_h.m4 (gl_DIRENT_H_DEFAULTS): Add replacements. * modules/dirent (Makefile.am): Substitute them. * MODULES.html.sh (File system functions): Mention it. * doc/posix-functions/fdopendir.texi (fdopendir): Likewise. * modules/fdopendir-tests: New file. * tests/test-fdopendir.c: Likewise. Signed-off-by: Eric Blake <e...@byu.net> --- ChangeLog | 20 ++++++++ MODULES.html.sh | 1 + doc/posix-functions/fdopendir.texi | 2 +- lib/dirent.in.h | 17 ++++++ lib/fdopendir.c | 96 ++++++++++++++++++++++++++++++++++++ lib/openat.c | 68 ------------------------- lib/openat.h | 6 +-- lib/savedir.c | 3 +- m4/dirent_h.m4 | 10 ++-- m4/fdopendir.m4 | 21 ++++++++ m4/openat.m4 | 3 +- modules/dirent | 2 + modules/fdopendir | 30 +++++++++++ modules/fdopendir-tests | 13 +++++ modules/openat | 1 + modules/savedir | 2 +- tests/test-fdopendir.c | 76 ++++++++++++++++++++++++++++ 17 files changed, 288 insertions(+), 83 deletions(-) create mode 100644 lib/fdopendir.c create mode 100644 m4/fdopendir.m4 create mode 100644 modules/fdopendir create mode 100644 modules/fdopendir-tests create mode 100644 tests/test-fdopendir.c diff --git a/ChangeLog b/ChangeLog index 869567e..b9b3041 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,25 @@ 2009-08-31 Eric Blake <e...@byu.net> + fdopendir: split into its own module + * lib/openat.c (fdopendir): Move... + * lib/fdopendir.c: ...into new file. + * modules/fdopendir: New module. + * m4/fdopendir.m4 (gl_FUNC_FDOPENDIR): New file. + * modules/openat (Depends-on): Add fdopendir. + * m4/openat.m4 (gl_FUNC_OPENAT): No longer need to check for + fdopendir here. + * modules/savedir (Depends-on): Only need fdopendir, not full + openat. + * lib/savedir.c (include): Use <dirent.h>, not "openat.h". + * lib/openat.h (fdopendir): Drop prototype. + * lib/dirent.in.h (fdopendir): Provide prototype. + * m4/dirent_h.m4 (gl_DIRENT_H_DEFAULTS): Add replacements. + * modules/dirent (Makefile.am): Substitute them. + * MODULES.html.sh (File system functions): Mention it. + * doc/posix-functions/fdopendir.texi (fdopendir): Likewise. + * modules/fdopendir-tests: New file. + * tests/test-fdopendir.c: Likewise. + fchdir: simplify error handling, and support dup3 * modules/fchdir (Depends-on): Use strdup-posix, not strdup. Add stdbool, malloc-posix, realloc-posix. diff --git a/MODULES.html.sh b/MODULES.html.sh index 3c54cec..027a0bc 100755 --- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -2451,6 +2451,7 @@ func_all_modules () func_module dirfd func_module double-slash-root func_module euidaccess + func_module fdopendir func_module file-type func_module fileblocks func_module filemode diff --git a/doc/posix-functions/fdopendir.texi b/doc/posix- functions/fdopendir.texi index 1d9827c..81b6991 100644 --- a/doc/posix-functions/fdopendir.texi +++ b/doc/posix-functions/fdopendir.texi @@ -4,7 +4,7 @@ fdopendir POSIX specification: @url {http://www.opengroup.org/onlinepubs/9699919799/functions/fdopendir.html} -Gnulib module: openat +Gnulib module: fdopendir Portability problems fixed by Gnulib: @itemize diff --git a/lib/dirent.in.h b/lib/dirent.in.h index 15f0245..8930765 100644 --- a/lib/dirent.in.h +++ b/lib/dirent.in.h @@ -58,6 +58,23 @@ extern int dirfd (DIR const *dir); dirfd (d)) #endif +#if @GNULIB_FDOPENDIR@ +# if !...@have_fdopendir@ +/* Open a directory stream visiting the given directory file + descriptor. Return NULL and set errno if fd is not visiting a + directory. On success, this function consumes fd (it will be + implicitly closed either by this function or by a subsequent + closedir). */ +extern DIR *fdopendir (int fd); +# endif +#elif defined GNULIB_POSIXCHECK +# undef fdopendir +# define fdopendir(f) \ + (GL_LINK_WARNING ("fdopendir is unportable - " \ + "use gnulib module fdopendir for portability"), \ + fdopendir (f)) +#endif + #if @GNULIB_SCANDIR@ /* Scan the directory DIR, calling FILTER on each directory entry. Entries for which FILTER returns nonzero are individually malloc'd, diff --git a/lib/fdopendir.c b/lib/fdopendir.c new file mode 100644 index 0000000..a536db7 --- /dev/null +++ b/lib/fdopendir.c @@ -0,0 +1,96 @@ +/* provide a replacement fdopendir function + Copyright (C) 2004-2009 Free Software Foundation, Inc. + + 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 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, see <http://www.gnu.org/licenses/>. */ + +/* written by Jim Meyering */ + +#include <config.h> + +#include <dirent.h> + +#include <stdlib.h> +#include <unistd.h> + +#include "openat.h" +#include "openat-priv.h" +#include "save-cwd.h" + +#if !HAVE_FDOPENDIR + +/* Replacement for Solaris' function by the same name. + <http://www.google.com/search?q=fdopendir+site:docs.sun.com> + First, try to simulate it via opendir ("/proc/self/fd/FD"). Failing + that, simulate it by doing save_cwd/fchdir/opendir(".")/restore_cwd. + If either the save_cwd or the restore_cwd fails (relatively unlikely), + then give a diagnostic and exit nonzero. + Otherwise, this function works just like Solaris' fdopendir. + + W A R N I N G: + Unlike other fd-related functions, this one effectively consumes + its FD parameter. The caller should not close or otherwise + manipulate FD if this function returns successfully. */ +DIR * +fdopendir (int fd) +{ + struct saved_cwd saved_cwd; + int saved_errno; + DIR *dir; + + char buf[OPENAT_BUFFER_SIZE]; + char *proc_file = openat_proc_name (buf, fd, "."); + if (proc_file) + { + dir = opendir (proc_file); + saved_errno = errno; + } + else + { + dir = NULL; + saved_errno = EOPNOTSUPP; + } + + /* If the syscall fails with an expected errno value, resort to + save_cwd/restore_cwd. */ + if (! dir && EXPECTED_ERRNO (saved_errno)) + { + if (save_cwd (&saved_cwd) != 0) + openat_save_fail (errno); + + if (fchdir (fd) != 0) + { + dir = NULL; + saved_errno = errno; + } + else + { + dir = opendir ("."); + saved_errno = errno; + + if (restore_cwd (&saved_cwd) != 0) + openat_restore_fail (errno); + } + + free_cwd (&saved_cwd); + } + + if (dir) + close (fd); + if (proc_file != buf) + free (proc_file); + errno = saved_errno; + return dir; +} + +#endif diff --git a/lib/openat.c b/lib/openat.c index 77a85bf..7a68cba 100644 --- a/lib/openat.c +++ b/lib/openat.c @@ -152,74 +152,6 @@ openat_needs_fchdir (void) return needs_fchdir; } -#if !HAVE_FDOPENDIR - -/* Replacement for Solaris' function by the same name. - <http://www.google.com/search?q=fdopendir+site:docs.sun.com> - First, try to simulate it via opendir ("/proc/self/fd/FD"). Failing - that, simulate it by doing save_cwd/fchdir/opendir(".")/restore_cwd. - If either the save_cwd or the restore_cwd fails (relatively unlikely), - then give a diagnostic and exit nonzero. - Otherwise, this function works just like Solaris' fdopendir. - - W A R N I N G: - Unlike the other fd-related functions here, this one - effectively consumes its FD parameter. The caller should not - close or otherwise manipulate FD if this function returns successfully. */ -DIR * -fdopendir (int fd) -{ - struct saved_cwd saved_cwd; - int saved_errno; - DIR *dir; - - char buf[OPENAT_BUFFER_SIZE]; - char *proc_file = openat_proc_name (buf, fd, "."); - if (proc_file) - { - dir = opendir (proc_file); - saved_errno = errno; - } - else - { - dir = NULL; - saved_errno = EOPNOTSUPP; - } - - /* If the syscall fails with an expected errno value, resort to - save_cwd/restore_cwd. */ - if (! dir && EXPECTED_ERRNO (saved_errno)) - { - if (save_cwd (&saved_cwd) != 0) - openat_save_fail (errno); - - if (fchdir (fd) != 0) - { - dir = NULL; - saved_errno = errno; - } - else - { - dir = opendir ("."); - saved_errno = errno; - - if (restore_cwd (&saved_cwd) != 0) - openat_restore_fail (errno); - } - - free_cwd (&saved_cwd); - } - - if (dir) - close (fd); - if (proc_file != buf) - free (proc_file); - errno = saved_errno; - return dir; -} - -#endif - /* Replacement for Solaris' function by the same name. <http://www.google.com/search?q=fstatat+site:docs.sun.com> First, try to simulate it via l?stat ("/proc/self/fd/FD/FILE"). diff --git a/lib/openat.h b/lib/openat.h index 68c7df0..4072c94 100644 --- a/lib/openat.h +++ b/lib/openat.h @@ -1,5 +1,5 @@ /* provide a replacement openat function - Copyright (C) 2004, 2005, 2006, 2008 Free Software Foundation, Inc. + Copyright (C) 2004-2006, 2008-2009 Free Software Foundation, Inc. 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 @@ -66,10 +66,6 @@ int openat (int fd, char const *file, int flags, /* mode_t mode */ ...); int openat_permissive (int fd, char const *file, int flags, mode_t mode, int *cwd_errno); -# if ! HAVE_FDOPENDIR -# define fdopendir __OPENAT_ID (fdopendir) -# endif -DIR *fdopendir (int fd); # define fstatat __OPENAT_ID (fstatat) int fstatat (int fd, char const *file, struct stat *st, int flag); # define unlinkat __OPENAT_ID (unlinkat) diff --git a/lib/savedir.c b/lib/savedir.c index b837414..8400145 100644 --- a/lib/savedir.c +++ b/lib/savedir.c @@ -1,7 +1,7 @@ /* savedir.c -- save the list of files in a directory in a string Copyright (C) 1990, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, - 2006 Free Software Foundation, Inc. + 2006, 2009 Free Software Foundation, Inc. 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 @@ -35,7 +35,6 @@ #include <stdlib.h> #include <string.h> -#include "openat.h" #include "xalloc.h" #ifndef NAME_SIZE_DEFAULT diff --git a/m4/dirent_h.m4 b/m4/dirent_h.m4 index e507e3d..06fffef 100644 --- a/m4/dirent_h.m4 +++ b/m4/dirent_h.m4 @@ -33,11 +33,13 @@ AC_DEFUN([gl_DIRENT_H_DEFAULTS], [ AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) dnl for REPLACE_FCHDIR GNULIB_DIRFD=0; AC_SUBST([GNULIB_DIRFD]) + GNULIB_FDOPENDIR=0; AC_SUBST([GNULIB_FDOPENDIR]) GNULIB_SCANDIR=0; AC_SUBST([GNULIB_SCANDIR]) GNULIB_ALPHASORT=0; AC_SUBST([GNULIB_ALPHASORT]) dnl Assume proper GNU behavior unless another module says otherwise. - HAVE_DECL_DIRFD=1; AC_SUBST([HAVE_DECL_DIRFD]) - HAVE_SCANDIR=1; AC_SUBST([HAVE_SCANDIR]) - HAVE_ALPHASORT=1; AC_SUBST([HAVE_ALPHASORT]) - DIRENT_H=''; AC_SUBST([DIRENT_H]) + HAVE_DECL_DIRFD=1; AC_SUBST([HAVE_DECL_DIRFD]) + HAVE_FDOPENDIR=1; AC_SUBST([HAVE_FDOPENDIR]) + HAVE_SCANDIR=1; AC_SUBST([HAVE_SCANDIR]) + HAVE_ALPHASORT=1; AC_SUBST([HAVE_ALPHASORT]) + DIRENT_H=''; AC_SUBST([DIRENT_H]) ]) diff --git a/m4/fdopendir.m4 b/m4/fdopendir.m4 new file mode 100644 index 0000000..09670bb --- /dev/null +++ b/m4/fdopendir.m4 @@ -0,0 +1,21 @@ +# serial 1 +# See if we need to provide fdopendir. + +dnl Copyright (C) 2009 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +# Written by Eric Blake. + +AC_DEFUN([gl_FUNC_FDOPENDIR], +[ + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + AC_CHECK_FUNCS_ONCE([fdopendir]) + if test $ac_cv_func_fdopendir = no; then + AC_LIBOBJ([openat-proc]) + AC_LIBOBJ([fdopendir]) + gl_REPLACE_DIRENT_H + HAVE_FDOPENDIR=0 + fi +]) diff --git a/m4/openat.m4 b/m4/openat.m4 index daa6a53..c8403a1 100644 --- a/m4/openat.m4 +++ b/m4/openat.m4 @@ -1,4 +1,4 @@ -# serial 18 +# serial 19 # See if we need to use our replacement for Solaris' openat et al functions. dnl Copyright (C) 2004-2009 Free Software Foundation, Inc. @@ -13,7 +13,6 @@ AC_DEFUN([gl_FUNC_OPENAT], AC_LIBOBJ([openat-proc]) AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) AC_CHECK_FUNCS_ONCE([lchmod]) - AC_CHECK_FUNCS_ONCE([fdopendir]) AC_REPLACE_FUNCS([fchmodat mkdirat openat]) AC_REQUIRE([AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK]) case $ac_cv_func_openat+$ac_cv_func_lstat_dereferences_slashed_symlink in diff --git a/modules/dirent b/modules/dirent index 8df7c35..3eb7411 100644 --- a/modules/dirent +++ b/modules/dirent @@ -25,9 +25,11 @@ dirent.h: dirent.in.h -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \ -e 's|@''NEXT_DIRENT_H''@|$(NEXT_DIRENT_H)|g' \ -e 's|@''GNULIB_DIRFD''@|$(GNULIB_DIRFD)|g' \ + -e 's|@''GNULIB_FDOPENDIR''@|$(GNULIB_FDOPENDIR)|g' \ -e 's|@''GNULIB_SCANDIR''@|$(GNULIB_SCANDIR)|g' \ -e 's|@''GNULIB_ALPHASORT''@|$(GNULIB_ALPHASORT)|g' \ -e 's|@''HAVE_DECL_DIRFD''@|$(HAVE_DECL_DIRFD)|g' \ + -e 's|@''HAVE_FDOPENDIR''@|$(HAVE_FDOPENDIR)|g' \ -e 's|@''HAVE_SCANDIR''@|$(HAVE_SCANDIR)|g' \ -e 's|@''HAVE_ALPHASORT''@|$(HAVE_ALPHASORT)|g' \ -e 's|@''REPLACE_FCHDIR''@|$(REPLACE_FCHDIR)|g' \ diff --git a/modules/fdopendir b/modules/fdopendir new file mode 100644 index 0000000..7a90aa3 --- /dev/null +++ b/modules/fdopendir @@ -0,0 +1,30 @@ +Description: +Open a directory stream from a file descriptor. + +Files: +lib/fdopendir.c +lib/openat-priv.h +lib/openat-proc.c +m4/fdopendir.m4 + +Depends-on: +extensions +dirent +fchdir +openat-die +save-cwd + +configure.ac: +gl_FUNC_FDOPENDIR +gl_DIRENT_MODULE_INDICATOR([fdopendir]) + +Makefile.am: + +Include: +<dirent.h> + +License: +GPL + +Maintainer: +Jim Meyering, Eric Blake diff --git a/modules/fdopendir-tests b/modules/fdopendir-tests new file mode 100644 index 0000000..9df5e29 --- /dev/null +++ b/modules/fdopendir-tests @@ -0,0 +1,13 @@ +Files: +tests/test-fdopendir.c + +Depends-on: +open +progname + +configure.ac: + +Makefile.am: +TESTS += test-fdopendir +check_PROGRAMS += test-fdopendir +test_fdopendir_LDADD = $(LDADD) @LIBINTL@ diff --git a/modules/openat b/modules/openat index 561687d..5c326a0 100644 --- a/modules/openat +++ b/modules/openat @@ -18,6 +18,7 @@ Depends-on: dirname extensions fchdir +fdopendir gettext-h intprops lchown diff --git a/modules/savedir b/modules/savedir index e781af7..4171b80 100644 --- a/modules/savedir +++ b/modules/savedir @@ -7,7 +7,7 @@ lib/savedir.c m4/savedir.m4 Depends-on: -openat +fdopendir xalloc configure.ac: diff --git a/tests/test-fdopendir.c b/tests/test-fdopendir.c new file mode 100644 index 0000000..003a279 --- /dev/null +++ b/tests/test-fdopendir.c @@ -0,0 +1,76 @@ +/* Test opening a directory stream from a file descriptor. + Copyright (C) 2009 Free Software Foundation, Inc. + + 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 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Eric Blake <e...@byu.net>, 2009. */ + +#include <config.h> + +#include <dirent.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#define ASSERT(expr) \ + do \ + { \ + if (!(expr)) \ + { \ + fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \ + fflush (stderr); \ + abort (); \ + } \ + } \ + while (0) + +int +main () +{ + DIR *d; + int fd; + + /* A non-directory cannot be turned into a directory stream. */ + fd = open ("/dev/null", O_RDONLY); + ASSERT (0 <= fd); + errno = 0; + ASSERT (fdopendir (fd) == NULL); + ASSERT (errno == ENOTDIR); + ASSERT (close (fd) == 0); + + /* A bad fd cannot be turned into a stream. */ + errno = 0; + ASSERT (fdopendir (-1) == NULL); + ASSERT (errno == EBADF); + + /* This should work. */ + fd = open (".", O_RDONLY); + ASSERT (0 <= fd); + d = fdopendir (fd); + /* We know that fd is now out of our reach, but it is not specified + whether it is closed now or at the closedir. We also can't + guarantee whether dirfd returns fd, some other descriptor, or + -1. */ + ASSERT (d); + ASSERT (closedir (d) == 0); + /* Now we can guarantee that fd must be closed. */ + errno = 0; + ASSERT (dup2 (fd, fd) == -1); + ASSERT (errno == EBADF); + + return 0; +} -- 1.6.3.2 From: Eric Blake <e...@byu.net> Date: Mon, 31 Aug 2009 17:24:42 -0600 Subject: [PATCH 2/2] fdopendir: optimize on mingw * lib/unistd.in.h (_gl_retrieve_fd_name): New prototype. * lib/fchdir.c (_gl_retrieve_fd_name): Implement it. * lib/fdopendir.c (fdopendir) [FCHDIR_REPLACEMENT]: Use metadata from fchdir, when available, to avoid calling [f]chdir(). Signed-off-by: Eric Blake <e...@byu.net> --- ChangeLog | 6 ++++++ lib/fchdir.c | 19 +++++++++++++++++++ lib/fdopendir.c | 12 ++++++++++-- lib/unistd.in.h | 2 ++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index b9b3041..48a1877 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2009-08-31 Eric Blake <e...@byu.net> + fdopendir: optimize on mingw + * lib/unistd.in.h (_gl_retrieve_fd_name): New prototype. + * lib/fchdir.c (_gl_retrieve_fd_name): Implement it. + * lib/fdopendir.c (fdopendir) [FCHDIR_REPLACEMENT]: Use metadata + from fchdir, when available, to avoid calling [f]chdir(). + fdopendir: split into its own module * lib/openat.c (fdopendir): Move... * lib/fdopendir.c: ...into new file. diff --git a/lib/fchdir.c b/lib/fchdir.c index 523d0a3..5dec13b 100644 --- a/lib/fchdir.c +++ b/lib/fchdir.c @@ -155,6 +155,25 @@ _gl_register_dup (int oldfd, int newfd) return newfd; } +/* If FD is currently visiting a directory, then return the name of + that directory. Otherwise, return NULL and set errno. */ +const char * +_gl_retrieve_fd_name (int fd) +{ + if (0 <= fd && fd <= dirs_allocated && dirs[fd].name != NULL) + return dirs[fd].name; + /* At this point, fd is either invalid, or open but not a directory. + If dup2 fails, errno is correctly EBADF. */ + if (0 <= fd) + { + if (dup2 (fd, fd) == fd) + errno = ENOTDIR; + } + else + errno = EBADF; + return NULL; +} + /* Return stat information about FD in STATBUF. Needed when rpl_open() used a dummy file to work around an open() that can't normally visit directories. */ diff --git a/lib/fdopendir.c b/lib/fdopendir.c index a536db7..cacf633 100644 --- a/lib/fdopendir.c +++ b/lib/fdopendir.c @@ -32,7 +32,8 @@ /* Replacement for Solaris' function by the same name. <http://www.google.com/search?q=fdopendir+site:docs.sun.com> First, try to simulate it via opendir ("/proc/self/fd/FD"). Failing - that, simulate it by doing save_cwd/fchdir/opendir(".")/restore_cwd. + that, simulate it by using fchdir metadata, or by doing + save_cwd/fchdir/opendir(".")/restore_cwd. If either the save_cwd or the restore_cwd fails (relatively unlikely), then give a diagnostic and exit nonzero. Otherwise, this function works just like Solaris' fdopendir. @@ -44,7 +45,6 @@ DIR * fdopendir (int fd) { - struct saved_cwd saved_cwd; int saved_errno; DIR *dir; @@ -65,6 +65,13 @@ fdopendir (int fd) save_cwd/restore_cwd. */ if (! dir && EXPECTED_ERRNO (saved_errno)) { +#if FCHDIR_REPLACEMENT + const char *name = _gl_retrieve_fd_name (fd); + if (name) + dir = opendir (name); + saved_errno = errno; +#else /* !FCHDIR_REPLACEMENT */ + struct saved_cwd saved_cwd; if (save_cwd (&saved_cwd) != 0) openat_save_fail (errno); @@ -83,6 +90,7 @@ fdopendir (int fd) } free_cwd (&saved_cwd); +#endif /* !FCHDIR_REPLACEMENT */ } if (dir) diff --git a/lib/unistd.in.h b/lib/unistd.in.h index f0b5cc4..d30e4fa 100644 --- a/lib/unistd.in.h +++ b/lib/unistd.in.h @@ -620,6 +620,8 @@ extern ssize_t write (int fd, const void *buf, size_t count); extern void _gl_unregister_fd (int fd); /* gnulib internal function. */ extern int _gl_register_dup (int oldfd, int newfd); +/* gnulib internal function. */ +extern const char *_gl_retrieve_fd_name (int fd); #endif -- 1.6.3.2