2009-10-06 Eric Blake <ebb9@byu.net>
+ fdopendir: fix GNU/Hurd bug
+ * m4/fdopendir.m4 (gl_FUNC_FDOPENDIR): Check for Hurd bug in
+ allowing non-directory fds.
+ * lib/fdopendir.c (rpl_fdopendir): Work around it.
+ * m4/dirent_h.m4 (gl_DIRENT_H_DEFAULTS): New witness.
+ * modules/dirent (Makefile.am): Substitute it.
+ * lib/dirent.in.h (fdopendir): Declare replacement.
+ * doc/posix-functions/fdopendir.texi (fdopendir): Document this.
+ * tests/test-fdopendir.c (main): Test something other than
+ /dev/null, since on Hurd that behaves like a directory.
+
test-symlink: port to GNU/Hurd
* tests/test-symlink.h (test_symlink): Relax expected errno.
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).
+@item
+This function does not reject non-directory file descriptors on some
+platforms:
+GNU/Hurd.
@end itemize
Portability problems not fixed by Gnulib:
#endif
#if @GNULIB_FDOPENDIR@
-# if !@HAVE_FDOPENDIR@
+# if @REPLACE_FDOPENDIR@
+# undef fdopendir
+# define fdopendir rpl_fdopendir
+# endif
+# if !@HAVE_FDOPENDIR@ || @REPLACE_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
#include <stdlib.h>
#include <unistd.h>
-#include "openat.h"
-#include "openat-priv.h"
-#include "save-cwd.h"
+#if !HAVE_FDOPENDIR
-#if GNULIB_DIRENT_SAFER
-# include "dirent--.h"
-#endif
+# include "openat.h"
+# include "openat-priv.h"
+# include "save-cwd.h"
+
+# if GNULIB_DIRENT_SAFER
+# include "dirent--.h"
+# endif
/* Replacement for Solaris' function by the same name.
<http://www.google.com/search?q=fdopendir+site:docs.sun.com>
save_cwd/restore_cwd. */
if (! dir && EXPECTED_ERRNO (saved_errno))
{
-#if REPLACE_FCHDIR
+# if REPLACE_FCHDIR
const char *name = _gl_directory_name (fd);
if (name)
dir = opendir (name);
saved_errno = errno;
-#else /* !REPLACE_FCHDIR */
+# else /* !REPLACE_FCHDIR */
struct saved_cwd saved_cwd;
if (save_cwd (&saved_cwd) != 0)
openat_save_fail (errno);
}
free_cwd (&saved_cwd);
-#endif /* !REPLACE_FCHDIR */
+# endif /* !REPLACE_FCHDIR */
}
if (dir)
errno = saved_errno;
return dir;
}
+
+#else /* HAVE_FDOPENDIR */
+
+# include <errno.h>
+# include <sys/stat.h>
+
+# undef fdopendir
+
+/* Like fdopendir, but work around GNU/Hurd bug by validating FD. */
+
+DIR *
+rpl_fdopendir (int fd)
+{
+ struct stat st;
+ if (fstat (fd, &st))
+ return NULL;
+ if (!S_ISDIR (st.st_mode))
+ {
+ errno = ENOTDIR;
+ return NULL;
+ }
+ return fdopendir (fd);
+}
+
+#endif /* HAVE_FDOPENDIR */
-# dirent_h.m4 serial 5
+# dirent_h.m4 serial 6
dnl Copyright (C) 2008-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,
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])
+ 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_FDOPENDIR=1; AC_SUBST([HAVE_FDOPENDIR])
- HAVE_SCANDIR=1; AC_SUBST([HAVE_SCANDIR])
- HAVE_ALPHASORT=1; AC_SUBST([HAVE_ALPHASORT])
- REPLACE_CLOSEDIR=0; AC_SUBST([REPLACE_CLOSEDIR])
- REPLACE_OPENDIR=0; AC_SUBST([REPLACE_OPENDIR])
- 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])
+ REPLACE_CLOSEDIR=0; AC_SUBST([REPLACE_CLOSEDIR])
+ REPLACE_FDOPENDIR=0; AC_SUBST([REPLACE_FDOPENDIR])
+ REPLACE_OPENDIR=0; AC_SUBST([REPLACE_OPENDIR])
+ DIRENT_H=''; AC_SUBST([DIRENT_H])
])
-# serial 1
+# serial 2
# See if we need to provide fdopendir.
dnl Copyright (C) 2009 Free Software Foundation, Inc.
AC_LIBOBJ([fdopendir])
gl_REPLACE_DIRENT_H
HAVE_FDOPENDIR=0
+ else
+ AC_CACHE_CHECK([whether fdopendir works],
+ [gl_cv_func_fdopendir_works],
+ [AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <dirent.h>
+#include <fcntl.h>
+]], [int fd = open ("conftest.h", O_RDONLY);
+ if (fd < 0) return 2;
+ return !!fdopendir (fd);])],
+ [gl_cv_func_fdopendir_works=yes],
+ [gl_cv_func_fdopendir_works=no],
+ [gl_cv_func_fdopendir_works="guessing no"])])
+ if test "$gl_cv_func_fdopendir_works" != yes; then
+ REPLACE_FDOPENDIR=1
+ gl_REPLACE_DIRENT_H
+ AC_LIBOBJ([fdopendir])
+ fi
fi
])
-e 's|@''HAVE_SCANDIR''@|$(HAVE_SCANDIR)|g' \
-e 's|@''HAVE_ALPHASORT''@|$(HAVE_ALPHASORT)|g' \
-e 's|@''REPLACE_CLOSEDIR''@|$(REPLACE_CLOSEDIR)|g' \
+ -e 's|@''REPLACE_FDOPENDIR''@|$(REPLACE_FDOPENDIR)|g' \
-e 's|@''REPLACE_OPENDIR''@|$(REPLACE_OPENDIR)|g' \
-e '/definition of GL_LINK_WARNING/r $(LINK_WARNING_H)' \
< $(srcdir)/dirent.in.h; \
int fd;
/* A non-directory cannot be turned into a directory stream. */
- fd = open ("/dev/null", O_RDONLY);
+ fd = open ("test-fdopendir.tmp", O_RDONLY | O_CREAT, 0600);
ASSERT (0 <= fd);
errno = 0;
ASSERT (fdopendir (fd) == NULL);
ASSERT (errno == ENOTDIR);
ASSERT (close (fd) == 0);
+ ASSERT (unlink ("test-fdopendir.tmp") == 0);
/* A bad fd cannot be turned into a stream. */
errno = 0;