Blame src/gl/dup2.c

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