bug-gnulib
[Top][All Lists]
Advanced

[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








reply via email to

[Prev in Thread] Current Thread [Next in Thread]