changeset 11934:80567a8f98f8

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 <ebb9@byu.net>
author Eric Blake <ebb9@byu.net>
date Mon, 31 Aug 2009 20:37:59 -0600
parents 1ffad224c413
children d233b3d8efbf
files ChangeLog MODULES.html.sh doc/posix-functions/fdopendir.texi lib/dirent.in.h lib/fdopendir.c lib/openat.c lib/openat.h lib/savedir.c m4/dirent_h.m4 m4/fdopendir.m4 m4/openat.m4 modules/dirent modules/fdopendir modules/fdopendir-tests modules/openat modules/savedir tests/test-fdopendir.c
diffstat 17 files changed, 291 insertions(+), 84 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Sep 01 09:18:16 2009 -0600
+++ b/ChangeLog	Mon Aug 31 20:37:59 2009 -0600
@@ -1,5 +1,25 @@
 2009-09-02  Eric Blake  <ebb9@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: use more consistent macro convention
 	* lib/fcntl.in.h (_gl_register_fd): Move declaration to unistd.
 	* lib/sys_stat.in.h (rpl_fstat): Declare via make-time
--- a/MODULES.html.sh	Tue Sep 01 09:18:16 2009 -0600
+++ b/MODULES.html.sh	Mon Aug 31 20:37:59 2009 -0600
@@ -2451,6 +2451,7 @@
   func_module dirfd
   func_module double-slash-root
   func_module euidaccess
+  func_module fdopendir
   func_module file-type
   func_module fileblocks
   func_module filemode
--- a/doc/posix-functions/fdopendir.texi	Tue Sep 01 09:18:16 2009 -0600
+++ b/doc/posix-functions/fdopendir.texi	Mon Aug 31 20:37:59 2009 -0600
@@ -4,7 +4,7 @@
 
 POSIX specification: @url{http://www.opengroup.org/onlinepubs/9699919799/functions/fdopendir.html}
 
-Gnulib module: openat
+Gnulib module: fdopendir
 
 Portability problems fixed by Gnulib:
 @itemize
@@ -12,7 +12,10 @@
 This function is missing on some platforms:
 glibc 2.3.6, MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, AIX
 5.1, HP-UX 11, IRIX 6.5, OSF/1 5.1, Cygwin 1.5.x, mingw, Interix 3.5, BeOS.
-But the replacement function is not safe to be used in libraries and is not multithread-safe.
+But the replacement function is not safe to be used in libraries and
+is not multithread-safe.  Also, the replacement does not guarantee
+that @samp{dirfd(fdopendir(n))==n} (dirfd might fail, or return a
+different file descriptor than n).
 @end itemize
 
 Portability problems not fixed by Gnulib:
--- a/lib/dirent.in.h	Tue Sep 01 09:18:16 2009 -0600
+++ b/lib/dirent.in.h	Mon Aug 31 20:37:59 2009 -0600
@@ -58,6 +58,23 @@
      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,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/fdopendir.c	Mon Aug 31 20:37:59 2009 -0600
@@ -0,0 +1,95 @@
+/* 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"
+
+/* 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.  Also, this
+   implementation does not guarantee that dirfd(fdopendir(n))==n;
+   the open directory stream may use a clone of FD, or have no
+   associated fd at all.  */
+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;
+}
--- a/lib/openat.c	Tue Sep 01 09:18:16 2009 -0600
+++ b/lib/openat.c	Mon Aug 31 20:37:59 2009 -0600
@@ -152,74 +152,6 @@
   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").
--- a/lib/openat.h	Tue Sep 01 09:18:16 2009 -0600
+++ b/lib/openat.h	Mon Aug 31 20:37:59 2009 -0600
@@ -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)
--- a/lib/savedir.c	Tue Sep 01 09:18:16 2009 -0600
+++ b/lib/savedir.c	Mon Aug 31 20:37:59 2009 -0600
@@ -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
--- a/m4/dirent_h.m4	Tue Sep 01 09:18:16 2009 -0600
+++ b/m4/dirent_h.m4	Mon Aug 31 20:37:59 2009 -0600
@@ -33,11 +33,13 @@
 [
   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])
 ])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m4/fdopendir.m4	Mon Aug 31 20:37:59 2009 -0600
@@ -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
+])
--- a/m4/openat.m4	Tue Sep 01 09:18:16 2009 -0600
+++ b/m4/openat.m4	Mon Aug 31 20:37:59 2009 -0600
@@ -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_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
--- a/modules/dirent	Tue Sep 01 09:18:16 2009 -0600
+++ b/modules/dirent	Mon Aug 31 20:37:59 2009 -0600
@@ -25,9 +25,11 @@
 	      -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' \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fdopendir	Mon Aug 31 20:37:59 2009 -0600
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fdopendir-tests	Mon Aug 31 20:37:59 2009 -0600
@@ -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@
--- a/modules/openat	Tue Sep 01 09:18:16 2009 -0600
+++ b/modules/openat	Mon Aug 31 20:37:59 2009 -0600
@@ -18,6 +18,7 @@
 dirname
 extensions
 fchdir
+fdopendir
 gettext-h
 intprops
 lchown
--- a/modules/savedir	Tue Sep 01 09:18:16 2009 -0600
+++ b/modules/savedir	Mon Aug 31 20:37:59 2009 -0600
@@ -7,7 +7,7 @@
 m4/savedir.m4
 
 Depends-on:
-openat
+fdopendir
 xalloc
 
 configure.ac:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-fdopendir.c	Mon Aug 31 20:37:59 2009 -0600
@@ -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 <ebb9@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;
+}