added missing dependencies to fix failing unistr/ tests
[gnulib.git] / lib / fdopendir.c
index 7095156..f7b29af 100644 (file)
@@ -1,5 +1,5 @@
 /* provide a replacement fdopendir function
-   Copyright (C) 2004-2009 Free Software Foundation, Inc.
+   Copyright (C) 2004-2010 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
 #include <stdlib.h>
 #include <unistd.h>
 
-#include "openat.h"
-#include "openat-priv.h"
-#include "save-cwd.h"
+#if !HAVE_FDOPENDIR
+
+# 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>
    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.
@@ -45,7 +52,6 @@
 DIR *
 fdopendir (int fd)
 {
-  struct saved_cwd saved_cwd;
   int saved_errno;
   DIR *dir;
 
@@ -66,24 +72,32 @@ fdopendir (int fd)
      save_cwd/restore_cwd.  */
   if (! dir && EXPECTED_ERRNO (saved_errno))
     {
+# if REPLACE_FCHDIR
+      const char *name = _gl_directory_name (fd);
+      if (name)
+        dir = opendir (name);
+      saved_errno = errno;
+# else /* !REPLACE_FCHDIR */
+      struct saved_cwd saved_cwd;
       if (save_cwd (&saved_cwd) != 0)
-       openat_save_fail (errno);
+        openat_save_fail (errno);
 
       if (fchdir (fd) != 0)
-       {
-         dir = NULL;
-         saved_errno = errno;
-       }
+        {
+          dir = NULL;
+          saved_errno = errno;
+        }
       else
-       {
-         dir = opendir (".");
-         saved_errno = errno;
+        {
+          dir = opendir (".");
+          saved_errno = errno;
 
-         if (restore_cwd (&saved_cwd) != 0)
-           openat_restore_fail (errno);
-       }
+          if (restore_cwd (&saved_cwd) != 0)
+            openat_restore_fail (errno);
+        }
 
       free_cwd (&saved_cwd);
+# endif /* !REPLACE_FCHDIR */
     }
 
   if (dir)
@@ -93,3 +107,28 @@ fdopendir (int fd)
   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 */