[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: fchdir on mingw
From: |
Eric Blake |
Subject: |
Re: fchdir on mingw |
Date: |
Mon, 31 Aug 2009 23:27:10 +0000 (UTC) |
User-agent: |
Loom/3.14 (http://gmane.org/) |
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 <address@hidden>
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 <address@hidden>
---
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 <address@hidden>
+ 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 address@hidden@
+/* 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 <address@hidden>, 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 <address@hidden>
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 <address@hidden>
---
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 <address@hidden>
+ 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