dup2: fix more mingw problems
authorEric Blake <ebb9@byu.net>
Tue, 21 Jul 2009 15:00:57 +0000 (09:00 -0600)
committerEric Blake <ebb9@byu.net>
Tue, 21 Jul 2009 19:12:25 +0000 (13:12 -0600)
* 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>
ChangeLog
doc/posix-functions/dup2.texi
lib/dup2.c
lib/fchdir.c
lib/unistd.in.h

index b471369..2bb96cf 100644 (file)
--- 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
index bfaff38..c8f2ca1 100644 (file)
@@ -13,6 +13,10 @@ This function always returns 0 for success on some platforms:
 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.
 
index e5d3de4..6d61829 100644 (file)
 #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
index cc2fa63..d51d963 100644 (file)
@@ -172,18 +172,19 @@ rpl_dup (int oldfd)
   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)
index 47d3096..93edb48 100644 (file)
@@ -217,10 +217,12 @@ extern int fchdir (int /*fd*/);
 
 #  define dup rpl_dup
 extern int dup (int);
-#  if !@REPLACE_DUP2@
-#   define dup2 rpl_dup2
-extern int dup2 (int, int);
+
+#  if @REPLACE_DUP2@
+#   undef dup2
 #  endif
+#  define dup2 rpl_dup2_fchdir
+extern int dup2 (int, int);
 
 # endif
 #elif defined GNULIB_POSIXCHECK