summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog20
-rwxr-xr-xMODULES.html.sh1
-rw-r--r--doc/posix-functions/fdopendir.texi7
-rw-r--r--lib/dirent.in.h17
-rw-r--r--lib/fdopendir.c95
-rw-r--r--lib/openat.c68
-rw-r--r--lib/openat.h6
-rw-r--r--lib/savedir.c3
-rw-r--r--m4/dirent_h.m410
-rw-r--r--m4/fdopendir.m421
-rw-r--r--m4/openat.m43
-rw-r--r--modules/dirent2
-rw-r--r--modules/fdopendir30
-rw-r--r--modules/fdopendir-tests13
-rw-r--r--modules/openat1
-rw-r--r--modules/savedir2
-rw-r--r--tests/test-fdopendir.c76
17 files changed, 291 insertions, 84 deletions
diff --git a/ChangeLog b/ChangeLog
index 3205ba8d71..0cd6e20963 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/MODULES.html.sh b/MODULES.html.sh
index 3c54cec985..027a0bca1b 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 1d9827c532..20db12cfe1 100644
--- a/doc/posix-functions/fdopendir.texi
+++ b/doc/posix-functions/fdopendir.texi
@@ -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 @@ Portability problems fixed by Gnulib:
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:
diff --git a/lib/dirent.in.h b/lib/dirent.in.h
index 15f0245b09..8930765672 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 0000000000..70951562f4
--- /dev/null
+++ b/lib/fdopendir.c
@@ -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;
+}
diff --git a/lib/openat.c b/lib/openat.c
index 77a85bffe8..7a68cba60d 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 68c7df0b7d..4072c94ed0 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 b837414335..8400145ad8 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 e507e3de8c..06fffefc15 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 0000000000..09670bb43e
--- /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 daa6a539e1..c8403a15f5 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 8df7c354aa..3eb7411f1a 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 0000000000..7a90aa367f
--- /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 0000000000..9df5e293ad
--- /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 561687d9d0..5c326a07d5 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 e781af76b2..4171b802c1 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 0000000000..003a279725
--- /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 <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;
+}