Blame gl/dup2.c

Packit Service 4684c1
/* Duplicate an open file descriptor to a specified file descriptor.
Packit Service 4684c1
Packit Service 4684c1
   Copyright (C) 1999, 2004-2007, 2009-2020 Free Software Foundation, Inc.
Packit Service 4684c1
Packit Service 4684c1
   This program is free software: you can redistribute it and/or modify
Packit Service 4684c1
   it under the terms of the GNU Lesser General Public License as published by
Packit Service 4684c1
   the Free Software Foundation; either version 2.1 of the License, or
Packit Service 4684c1
   (at your option) any later version.
Packit Service 4684c1
Packit Service 4684c1
   This program is distributed in the hope that it will be useful,
Packit Service 4684c1
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 4684c1
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 4684c1
   GNU Lesser General Public License for more details.
Packit Service 4684c1
Packit Service 4684c1
   You should have received a copy of the GNU Lesser General Public License
Packit Service 4684c1
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit Service 4684c1
Packit Service 4684c1
/* written by Paul Eggert */
Packit Service 4684c1
Packit Service 4684c1
#include <config.h>
Packit Service 4684c1
Packit Service 4684c1
/* Specification.  */
Packit Service 4684c1
#include <unistd.h>
Packit Service 4684c1
Packit Service 4684c1
#include <errno.h>
Packit Service 4684c1
#include <fcntl.h>
Packit Service 4684c1
Packit Service 4684c1
#if HAVE_DUP2
Packit Service 4684c1
Packit Service 4684c1
# undef dup2
Packit Service 4684c1
Packit Service 4684c1
# if defined _WIN32 && ! defined __CYGWIN__
Packit Service 4684c1
Packit Service 4684c1
/* Get declarations of the native Windows API functions.  */
Packit Service 4684c1
#  define WIN32_LEAN_AND_MEAN
Packit Service 4684c1
#  include <windows.h>
Packit Service 4684c1
Packit Service 4684c1
#  if HAVE_MSVC_INVALID_PARAMETER_HANDLER
Packit Service 4684c1
#   include "msvc-inval.h"
Packit Service 4684c1
#  endif
Packit Service 4684c1
Packit Service 4684c1
/* Get _get_osfhandle.  */
Packit Service 4684c1
#  if GNULIB_MSVC_NOTHROW
Packit Service 4684c1
#   include "msvc-nothrow.h"
Packit Service 4684c1
#  else
Packit Service 4684c1
#   include <io.h>
Packit Service 4684c1
#  endif
Packit Service 4684c1
Packit Service 4684c1
#  if HAVE_MSVC_INVALID_PARAMETER_HANDLER
Packit Service 4684c1
static int
Packit Service 4684c1
dup2_nothrow (int fd, int desired_fd)
Packit Service 4684c1
{
Packit Service 4684c1
  int result;
Packit Service 4684c1
Packit Service 4684c1
  TRY_MSVC_INVAL
Packit Service 4684c1
    {
Packit Service 4684c1
      result = dup2 (fd, desired_fd);
Packit Service 4684c1
    }
Packit Service 4684c1
  CATCH_MSVC_INVAL
Packit Service 4684c1
    {
Packit Service 4684c1
      errno = EBADF;
Packit Service 4684c1
      result = -1;
Packit Service 4684c1
    }
Packit Service 4684c1
  DONE_MSVC_INVAL;
Packit Service 4684c1
Packit Service 4684c1
  return result;
Packit Service 4684c1
}
Packit Service 4684c1
#  else
Packit Service 4684c1
#   define dup2_nothrow dup2
Packit Service 4684c1
#  endif
Packit Service 4684c1
Packit Service 4684c1
static int
Packit Service 4684c1
ms_windows_dup2 (int fd, int desired_fd)
Packit Service 4684c1
{
Packit Service 4684c1
  int result;
Packit Service 4684c1
Packit Service 4684c1
  /* If fd is closed, mingw hangs on dup2 (fd, fd).  If fd is open,
Packit Service 4684c1
     dup2 (fd, fd) returns 0, but all further attempts to use fd in
Packit Service 4684c1
     future dup2 calls will hang.  */
Packit Service 4684c1
  if (fd == desired_fd)
Packit Service 4684c1
    {
Packit Service 4684c1
      if ((HANDLE) _get_osfhandle (fd) == INVALID_HANDLE_VALUE)
Packit Service 4684c1
        {
Packit Service 4684c1
          errno = EBADF;
Packit Service 4684c1
          return -1;
Packit Service 4684c1
        }
Packit Service 4684c1
      return fd;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  /* Wine 1.0.1 return 0 when desired_fd is negative but not -1:
Packit Service 4684c1
     https://bugs.winehq.org/show_bug.cgi?id=21289 */
Packit Service 4684c1
  if (desired_fd < 0)
Packit Service 4684c1
    {
Packit Service 4684c1
      errno = EBADF;
Packit Service 4684c1
      return -1;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  result = dup2_nothrow (fd, desired_fd);
Packit Service 4684c1
Packit Service 4684c1
  if (result == 0)
Packit Service 4684c1
    result = desired_fd;
Packit Service 4684c1
Packit Service 4684c1
  return result;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
#  define dup2 ms_windows_dup2
Packit Service 4684c1
Packit Service 4684c1
# elif defined __KLIBC__
Packit Service 4684c1
Packit Service 4684c1
#  include <InnoTekLIBC/backend.h>
Packit Service 4684c1
Packit Service 4684c1
static int
Packit Service 4684c1
klibc_dup2dirfd (int fd, int desired_fd)
Packit Service 4684c1
{
Packit Service 4684c1
  int tempfd;
Packit Service 4684c1
  int dupfd;
Packit Service 4684c1
Packit Service 4684c1
  tempfd = open ("NUL", O_RDONLY);
Packit Service 4684c1
  if (tempfd == -1)
Packit Service 4684c1
    return -1;
Packit Service 4684c1
Packit Service 4684c1
  if (tempfd == desired_fd)
Packit Service 4684c1
    {
Packit Service 4684c1
      close (tempfd);
Packit Service 4684c1
Packit Service 4684c1
      char path[_MAX_PATH];
Packit Service 4684c1
      if (__libc_Back_ioFHToPath (fd, path, sizeof (path)))
Packit Service 4684c1
        return -1;
Packit Service 4684c1
Packit Service 4684c1
      return open(path, O_RDONLY);
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  dupfd = klibc_dup2dirfd (fd, desired_fd);
Packit Service 4684c1
Packit Service 4684c1
  close (tempfd);
Packit Service 4684c1
Packit Service 4684c1
  return dupfd;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static int
Packit Service 4684c1
klibc_dup2 (int fd, int desired_fd)
Packit Service 4684c1
{
Packit Service 4684c1
  int dupfd;
Packit Service 4684c1
  struct stat sbuf;
Packit Service 4684c1
Packit Service 4684c1
  dupfd = dup2 (fd, desired_fd);
Packit Service 4684c1
  if (dupfd == -1 && errno == ENOTSUP \
Packit Service 4684c1
      && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
Packit Service 4684c1
    {
Packit Service 4684c1
      close (desired_fd);
Packit Service 4684c1
Packit Service 4684c1
      return klibc_dup2dirfd (fd, desired_fd);
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  return dupfd;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
#  define dup2 klibc_dup2
Packit Service 4684c1
# endif
Packit Service 4684c1
Packit Service 4684c1
int
Packit Service 4684c1
rpl_dup2 (int fd, int desired_fd)
Packit Service 4684c1
{
Packit Service 4684c1
  int result;
Packit Service 4684c1
Packit Service 4684c1
# ifdef F_GETFL
Packit Service 4684c1
  /* On Linux kernels 2.6.26-2.6.29, dup2 (fd, fd) returns -EBADF.
Packit Service 4684c1
     On Cygwin 1.5.x, dup2 (1, 1) returns 0.
Packit Service 4684c1
     On Cygwin 1.7.17, dup2 (1, -1) dumps core.
Packit Service 4684c1
     On Cygwin 1.7.25, dup2 (1, 256) can dump core.
Packit Service 4684c1
     On Haiku, dup2 (fd, fd) mistakenly clears FD_CLOEXEC.  */
Packit Service 4684c1
#  if HAVE_SETDTABLESIZE
Packit Service 4684c1
  setdtablesize (desired_fd + 1);
Packit Service 4684c1
#  endif
Packit Service 4684c1
  if (desired_fd < 0)
Packit Service 4684c1
    fd = desired_fd;
Packit Service 4684c1
  if (fd == desired_fd)
Packit Service 4684c1
    return fcntl (fd, F_GETFL) == -1 ? -1 : fd;
Packit Service 4684c1
# endif
Packit Service 4684c1
Packit Service 4684c1
  result = dup2 (fd, desired_fd);
Packit Service 4684c1
Packit Service 4684c1
  /* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x.  */
Packit Service 4684c1
  if (result == -1 && errno == EMFILE)
Packit Service 4684c1
    errno = EBADF;
Packit Service 4684c1
# if REPLACE_FCHDIR
Packit Service 4684c1
  if (fd != desired_fd && result != -1)
Packit Service 4684c1
    result = _gl_register_dup (fd, result);
Packit Service 4684c1
# endif
Packit Service 4684c1
  return result;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
#else /* !HAVE_DUP2 */
Packit Service 4684c1
Packit Service 4684c1
/* On older platforms, dup2 did not exist.  */
Packit Service 4684c1
Packit Service 4684c1
# ifndef F_DUPFD
Packit Service 4684c1
static int
Packit Service 4684c1
dupfd (int fd, int desired_fd)
Packit Service 4684c1
{
Packit Service 4684c1
  int duplicated_fd = dup (fd);
Packit Service 4684c1
  if (duplicated_fd < 0 || duplicated_fd == desired_fd)
Packit Service 4684c1
    return duplicated_fd;
Packit Service 4684c1
  else
Packit Service 4684c1
    {
Packit Service 4684c1
      int r = dupfd (fd, desired_fd);
Packit Service 4684c1
      int e = errno;
Packit Service 4684c1
      close (duplicated_fd);
Packit Service 4684c1
      errno = e;
Packit Service 4684c1
      return r;
Packit Service 4684c1
    }
Packit Service 4684c1
}
Packit Service 4684c1
# endif
Packit Service 4684c1
Packit Service 4684c1
int
Packit Service 4684c1
dup2 (int fd, int desired_fd)
Packit Service 4684c1
{
Packit Service 4684c1
  int result = fcntl (fd, F_GETFL) < 0 ? -1 : fd;
Packit Service 4684c1
  if (result == -1 || fd == desired_fd)
Packit Service 4684c1
    return result;
Packit Service 4684c1
  close (desired_fd);
Packit Service 4684c1
# ifdef F_DUPFD
Packit Service 4684c1
  result = fcntl (fd, F_DUPFD, desired_fd);
Packit Service 4684c1
#  if REPLACE_FCHDIR
Packit Service 4684c1
  if (0 <= result)
Packit Service 4684c1
    result = _gl_register_dup (fd, result);
Packit Service 4684c1
#  endif
Packit Service 4684c1
# else
Packit Service 4684c1
  result = dupfd (fd, desired_fd);
Packit Service 4684c1
# endif
Packit Service 4684c1
  if (result == -1 && (errno == EMFILE || errno == EINVAL))
Packit Service 4684c1
    errno = EBADF;
Packit Service 4684c1
  return result;
Packit Service 4684c1
}
Packit Service 4684c1
#endif /* !HAVE_DUP2 */