maint: update copyright
[gnulib.git] / lib / dup3.c
index 906594e..5af40b2 100644 (file)
@@ -1,5 +1,5 @@
 /* Copy a file descriptor, applying specific flags.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009-2014 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
@@ -12,8 +12,7 @@
    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, write to the Free Software Foundation,
-   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+   with this program; if not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
 
 #include "binary-io.h"
 
-#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-/* Native Woe32 API.  */
-
-/* Get declarations of the Win32 API functions.  */
-# define WIN32_LEAN_AND_MEAN
-# include <windows.h>
-
-/* Upper bound on getdtablesize().  See lib/getdtablesize.c.  */
-# define OPEN_MAX_MAX 0x10000
-
-#else
-/* Unix API.  */
-
-# ifndef O_CLOEXEC
-#  define O_CLOEXEC 0
-# endif
-
-#endif
-
 int
 dup3 (int oldfd, int newfd, int flags)
 {
 #if HAVE_DUP3
 # undef dup3
+# if HAVE_SETDTABLESIZE
+  /* Avoid a cygwin crasher. */
+  setdtablesize (newfd + 1);
+# endif
   /* Try the system call first, if it exists.  (We may be running with a glibc
      that has the function but with an older kernel that lacks it.)  */
   {
@@ -57,18 +41,22 @@ dup3 (int oldfd, int newfd, int flags)
     static int have_dup3_really; /* 0 = unknown, 1 = yes, -1 = no */
     if (have_dup3_really >= 0)
       {
-       int result = dup3 (oldfd, newfd, flags);
-       if (!(result < 0 && errno == ENOSYS))
-         {
-           have_dup3_really = 1;
-           return result;
-         }
-       have_dup3_really = -1;
+        int result = dup3 (oldfd, newfd, flags);
+        if (!(result < 0 && errno == ENOSYS))
+          {
+            have_dup3_really = 1;
+# if REPLACE_FCHDIR
+            if (0 <= result)
+              result = _gl_register_dup (oldfd, newfd);
+# endif
+            return result;
+          }
+        have_dup3_really = -1;
       }
   }
 #endif
 
-  if (oldfd < 0 || newfd < 0 || newfd >= getdtablesize ())
+  if (newfd < 0 || newfd >= getdtablesize () || fcntl (oldfd, F_GETFD) == -1)
     {
       errno = EBADF;
       return -1;
@@ -89,131 +77,28 @@ dup3 (int oldfd, int newfd, int flags)
       return -1;
     }
 
-#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-/* Native Woe32 API.  */
-
   if (flags & O_CLOEXEC)
     {
-      /* Neither dup() nor dup2() can create a file descriptor with
-        O_CLOEXEC = O_NOINHERIT set.  We need to use the low-level function
-        _open_osfhandle for this.  Iterate until all file descriptors less
-        than newfd are filled up.  */
-      HANDLE curr_process = GetCurrentProcess ();
-      HANDLE old_handle = (HANDLE) _get_osfhandle (oldfd);
-      unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT];
-      unsigned int fds_to_close_bound = 0;
       int result;
-
-      if (old_handle == INVALID_HANDLE_VALUE)
-       {
-         /* oldfd is not open, or is an unassigned standard file
-            descriptor.  */
-         errno = EBADF;
-         return -1;
-       }
-
       close (newfd);
-
-      for (;;)
-       {
-         HANDLE new_handle;
-         int duplicated_fd;
-         unsigned int index;
-
-         if (!DuplicateHandle (curr_process,         /* SourceProcessHandle */
-                               old_handle,           /* SourceHandle */
-                               curr_process,         /* TargetProcessHandle */
-                               (PHANDLE) &new_handle, /* TargetHandle */
-                               (DWORD) 0,            /* DesiredAccess */
-                               FALSE,                /* InheritHandle */
-                               DUPLICATE_SAME_ACCESS)) /* Options */
-           {
-             errno = EBADF; /* arbitrary */
-             result = -1;
-             break;
-           }
-         duplicated_fd = _open_osfhandle ((long) new_handle, flags);
-         if (duplicated_fd < 0)
-           {
-             CloseHandle (new_handle);
-             result = -1;
-             break;
-           }
-         if (duplicated_fd > newfd)
-           /* Shouldn't happen, since newfd is still closed.  */
-           abort ();
-         if (duplicated_fd == newfd)
-           {
-             result = newfd;
-             break;
-           }
-
-         /* Set the bit duplicated_fd in fds_to_close[].  */
-         index = (unsigned int) duplicated_fd / CHAR_BIT;
-         if (index >= fds_to_close_bound)
-           {
-             if (index >= sizeof (fds_to_close))
-               /* Need to increase OPEN_MAX_MAX.  */
-               abort ();
-             memset (fds_to_close + fds_to_close_bound, '\0',
-                     index + 1 - fds_to_close_bound);
-             fds_to_close_bound = index + 1;
-           }
-         fds_to_close[index] |= 1 << ((unsigned int) duplicated_fd % CHAR_BIT);
-       }
-
-      /* Close the previous fds that turned out to be too small.  */
-      {
-       int saved_errno = errno;
-       unsigned int duplicated_fd;
-
-       for (duplicated_fd = 0;
-            duplicated_fd < fds_to_close_bound * CHAR_BIT;
-            duplicated_fd++)
-         if ((fds_to_close[duplicated_fd / CHAR_BIT]
-              >> (duplicated_fd % CHAR_BIT))
-             & 1)
-           close (duplicated_fd);
-
-       errno = saved_errno;
-      }
-
-      return result;
+      result = fcntl (oldfd, F_DUPFD_CLOEXEC, newfd);
+      if (newfd < result)
+        {
+          close (result);
+          errno = EIO;
+          result = -1;
+        }
+      if (result < 0)
+        return -1;
     }
-
-  if (dup2 (oldfd, newfd) < 0)
-    return -1;
-
-#else
-/* Unix API.  */
-
-  if (dup2 (oldfd, newfd) < 0)
+  else if (dup2 (oldfd, newfd) < 0)
     return -1;
 
-  /* POSIX <http://www.opengroup.org/onlinepubs/9699919799/functions/dup.html>
-     says that initially, the FD_CLOEXEC flag is cleared on newfd.  */
-
-  if (flags & O_CLOEXEC)
-    {
-      int fcntl_flags;
-
-      if ((fcntl_flags = fcntl (newfd, F_GETFD, 0)) < 0
-         || fcntl (newfd, F_SETFD, fcntl_flags | FD_CLOEXEC) == -1)
-       {
-         int saved_errno = errno;
-         close (newfd);
-         errno = saved_errno;
-         return -1;
-       }
-    }
-
-#endif
-
 #if O_BINARY
   if (flags & O_BINARY)
-    setmode (newfd, O_BINARY);
+    set_binary_mode (newfd, O_BINARY);
   else if (flags & O_TEXT)
-    setmode (newfd, O_TEXT);
+    set_binary_mode (newfd, O_TEXT);
 #endif
 
   return newfd;