changeset 11729:96bc5f7886d1

dup2: fix more mingw problems * lib/dup2.c (rpl_dup2) [_WIN32]: Avoid hanging when duplicating fd to itself. * doc/posix-functions/dup2.texi (dup2): Document the bug. * lib/unistd.in.h (dup2) [REPLACE_FCHDIR]: Avoid name collision. * lib/fchdir.c (dup2): Manage preprocessor macros correctly. (rpl_dup2_fchdir): Rename from rpl_dup2, and let dup2 module take care of mingw bugs. Signed-off-by: Eric Blake <ebb9@byu.net>
author Eric Blake <ebb9@byu.net>
date Tue, 21 Jul 2009 09:00:57 -0600
parents 91887b0a2a0f
children 1bd4d344ee8d
files ChangeLog doc/posix-functions/dup2.texi lib/dup2.c lib/fchdir.c lib/unistd.in.h
diffstat 5 files changed, 56 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2009-07-21  Eric Blake  <ebb9@byu.net>
+
+	dup2: fix more mingw problems
+	* lib/dup2.c (rpl_dup2) [_WIN32]: Avoid hanging when duplicating
+	fd to itself.
+	* doc/posix-functions/dup2.texi (dup2): Document the bug.
+	* lib/unistd.in.h (dup2) [REPLACE_FCHDIR]: Avoid name collision.
+	* lib/fchdir.c (dup2): Manage preprocessor macros correctly.
+	(rpl_dup2_fchdir): Rename from rpl_dup2, and let dup2 module take
+	care of mingw bugs.
+
 2009-07-21  Jim Meyering  <meyering@redhat.com>
 
 	vc-list-files: avoid failure when /bin/sh is dash
--- a/doc/posix-functions/dup2.texi
+++ b/doc/posix-functions/dup2.texi
@@ -13,6 +13,10 @@
 mingw.
 
 @item
+This function can hang when duplicating an fd to itself on some platforms:
+mingw.
+
+@item
 This function returns 0 for dup2 (1, 1) on some platforms:
 Cygwin 1.5.x.
 
--- a/lib/dup2.c
+++ b/lib/dup2.c
@@ -26,19 +26,42 @@
 #include <errno.h>
 #include <fcntl.h>
 
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+/* Get declarations of the Win32 API functions.  */
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#endif
+
 #if REPLACE_DUP2
-/* On mingw, dup2 exists, but always returns 0 for success.  */
+
+# undef dup2
+
 int
-dup2 (int fd, int desired_fd)
-#undef dup2
+rpl_dup2 (int fd, int desired_fd)
 {
-  int result = dup2 (fd, desired_fd);
+  int result;
+# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+  /* If fd is closed, mingw hangs on dup2 (fd, fd).  If fd is open,
+     dup2 (fd, fd) returns 0, but all further attempts to use fd in
+     future dup2 calls will hang.  */
+  if (fd == desired_fd)
+    {
+      if ((HANDLE) _get_osfhandle (fd) == INVALID_HANDLE_VALUE)
+        {
+          errno = EBADF;
+          return -1;
+        }
+      return fd;
+    }
+# endif
+  result = dup2 (fd, desired_fd);
   if (result == 0)
     result = desired_fd;
   return result;
 }
 
 #else /* !REPLACE_DUP2 */
+
 /* On older platforms, dup2 did not exist.  */
 
 # ifndef F_DUPFD
--- a/lib/fchdir.c
+++ b/lib/fchdir.c
@@ -172,18 +172,19 @@
   return newfd;
 }
 
+/* Our <unistd.h> replacement overrides dup2 twice; be sure to pick
+   the one we want.  */
+#if REPLACE_DUP2
+# undef dup2
+# define dup2 rpl_dup2
+#endif
+
 int
-rpl_dup2 (int oldfd, int newfd)
-#undef dup2
+rpl_dup2_fchdir (int oldfd, int newfd)
 {
   int retval = dup2 (oldfd, newfd);
-#if REPLACE_DUP2
-  /* Inline mingw replacement from dup2.c.  */
-  if (retval == 0)
-    retval = newfd;
-#endif
 
-  if (retval >= 0 && oldfd >= 0 && newfd >= 0 && newfd != oldfd)
+  if (retval >= 0 && newfd != oldfd)
     {
       ensure_dirs_slot (newfd);
       if (newfd < dirs_allocated)
--- a/lib/unistd.in.h
+++ b/lib/unistd.in.h
@@ -217,10 +217,12 @@
 
 #  define dup rpl_dup
 extern int dup (int);
-#  if !@REPLACE_DUP2@
-#   define dup2 rpl_dup2
+
+#  if @REPLACE_DUP2@
+#   undef dup2
+#  endif
+#  define dup2 rpl_dup2_fchdir
 extern int dup2 (int, int);
-#  endif
 
 # endif
 #elif defined GNULIB_POSIXCHECK