(root)/
tar-1.35/
gnu/
dup2.c
       1  /* Duplicate an open file descriptor to a specified file descriptor.
       2  
       3     Copyright (C) 1999, 2004-2007, 2009-2023 Free Software Foundation, Inc.
       4  
       5     This file is free software: you can redistribute it and/or modify
       6     it under the terms of the GNU Lesser General Public License as
       7     published by the Free Software Foundation; either version 2.1 of the
       8     License, or (at your option) any later version.
       9  
      10     This file is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13     GNU Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public License
      16     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  /* written by Paul Eggert */
      19  
      20  #include <config.h>
      21  
      22  /* Specification.  */
      23  #include <unistd.h>
      24  
      25  #include <errno.h>
      26  #include <fcntl.h>
      27  
      28  #undef dup2
      29  
      30  #if defined _WIN32 && ! defined __CYGWIN__
      31  
      32  /* Get declarations of the native Windows API functions.  */
      33  # define WIN32_LEAN_AND_MEAN
      34  # include <windows.h>
      35  
      36  # if HAVE_MSVC_INVALID_PARAMETER_HANDLER
      37  #  include "msvc-inval.h"
      38  # endif
      39  
      40  /* Get _get_osfhandle.  */
      41  # if GNULIB_MSVC_NOTHROW
      42  #  include "msvc-nothrow.h"
      43  # else
      44  #  include <io.h>
      45  # endif
      46  
      47  # if HAVE_MSVC_INVALID_PARAMETER_HANDLER
      48  static int
      49  dup2_nothrow (int fd, int desired_fd)
      50  {
      51    int result;
      52  
      53    TRY_MSVC_INVAL
      54      {
      55        result = _dup2 (fd, desired_fd);
      56      }
      57    CATCH_MSVC_INVAL
      58      {
      59        errno = EBADF;
      60        result = -1;
      61      }
      62    DONE_MSVC_INVAL;
      63  
      64    return result;
      65  }
      66  # else
      67  #  define dup2_nothrow _dup2
      68  # endif
      69  
      70  static int
      71  ms_windows_dup2 (int fd, int desired_fd)
      72  {
      73    int result;
      74  
      75    /* If fd is closed, mingw hangs on dup2 (fd, fd).  If fd is open,
      76       dup2 (fd, fd) returns 0, but all further attempts to use fd in
      77       future dup2 calls will hang.  */
      78    if (fd == desired_fd)
      79      {
      80        if ((HANDLE) _get_osfhandle (fd) == INVALID_HANDLE_VALUE)
      81          {
      82            errno = EBADF;
      83            return -1;
      84          }
      85        return fd;
      86      }
      87  
      88    /* Wine 1.0.1 return 0 when desired_fd is negative but not -1:
      89       https://bugs.winehq.org/show_bug.cgi?id=21289 */
      90    if (desired_fd < 0)
      91      {
      92        errno = EBADF;
      93        return -1;
      94      }
      95  
      96    result = dup2_nothrow (fd, desired_fd);
      97  
      98    if (result == 0)
      99      result = desired_fd;
     100  
     101    return result;
     102  }
     103  
     104  # define dup2 ms_windows_dup2
     105  
     106  #elif defined __KLIBC__
     107  
     108  # include <InnoTekLIBC/backend.h>
     109  
     110  static int
     111  klibc_dup2dirfd (int fd, int desired_fd)
     112  {
     113    int tempfd;
     114    int dupfd;
     115  
     116    tempfd = open ("NUL", O_RDONLY);
     117    if (tempfd == -1)
     118      return -1;
     119  
     120    if (tempfd == desired_fd)
     121      {
     122        close (tempfd);
     123  
     124        char path[_MAX_PATH];
     125        if (__libc_Back_ioFHToPath (fd, path, sizeof (path)))
     126          return -1;
     127  
     128        return open(path, O_RDONLY);
     129      }
     130  
     131    dupfd = klibc_dup2dirfd (fd, desired_fd);
     132  
     133    close (tempfd);
     134  
     135    return dupfd;
     136  }
     137  
     138  static int
     139  klibc_dup2 (int fd, int desired_fd)
     140  {
     141    int dupfd;
     142    struct stat sbuf;
     143  
     144    dupfd = dup2 (fd, desired_fd);
     145    if (dupfd == -1 && errno == ENOTSUP \
     146        && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
     147      {
     148        close (desired_fd);
     149  
     150        return klibc_dup2dirfd (fd, desired_fd);
     151      }
     152  
     153    return dupfd;
     154  }
     155  
     156  # define dup2 klibc_dup2
     157  #endif
     158  
     159  int
     160  rpl_dup2 (int fd, int desired_fd)
     161  {
     162    int result;
     163  
     164  #ifdef F_GETFL
     165    /* On Linux kernels 2.6.26-2.6.29, dup2 (fd, fd) returns -EBADF.
     166       On Cygwin 1.5.x, dup2 (1, 1) returns 0.
     167       On Cygwin 1.7.17, dup2 (1, -1) dumps core.
     168       On Cygwin 1.7.25, dup2 (1, 256) can dump core.
     169       On Haiku, dup2 (fd, fd) mistakenly clears FD_CLOEXEC.  */
     170  # if HAVE_SETDTABLESIZE
     171    setdtablesize (desired_fd + 1);
     172  # endif
     173    if (desired_fd < 0)
     174      fd = desired_fd;
     175    if (fd == desired_fd)
     176      return fcntl (fd, F_GETFL) == -1 ? -1 : fd;
     177  #endif
     178  
     179    result = dup2 (fd, desired_fd);
     180  
     181    /* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x.  */
     182    if (result == -1 && errno == EMFILE)
     183      errno = EBADF;
     184  #if REPLACE_FCHDIR
     185    if (fd != desired_fd && result != -1)
     186      result = _gl_register_dup (fd, result);
     187  #endif
     188    return result;
     189  }