diff options
Diffstat (limited to 'lib/dup2.c')
| -rw-r--r-- | lib/dup2.c | 71 |
1 files changed, 48 insertions, 23 deletions
diff --git a/lib/dup2.c b/lib/dup2.c index e00dc7b2e3c..790c98a2e84 100644 --- a/lib/dup2.c +++ b/lib/dup2.c | |||
| @@ -25,21 +25,26 @@ | |||
| 25 | #include <errno.h> | 25 | #include <errno.h> |
| 26 | #include <fcntl.h> | 26 | #include <fcntl.h> |
| 27 | 27 | ||
| 28 | #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ | ||
| 29 | /* Get declarations of the Win32 API functions. */ | ||
| 30 | # define WIN32_LEAN_AND_MEAN | ||
| 31 | # include <windows.h> | ||
| 32 | #endif | ||
| 33 | |||
| 34 | #if HAVE_DUP2 | 28 | #if HAVE_DUP2 |
| 35 | 29 | ||
| 36 | # undef dup2 | 30 | # undef dup2 |
| 37 | 31 | ||
| 38 | int | 32 | # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ |
| 39 | rpl_dup2 (int fd, int desired_fd) | 33 | |
| 34 | /* Get declarations of the Win32 API functions. */ | ||
| 35 | # define WIN32_LEAN_AND_MEAN | ||
| 36 | # include <windows.h> | ||
| 37 | |||
| 38 | # include "msvc-inval.h" | ||
| 39 | |||
| 40 | /* Get _get_osfhandle. */ | ||
| 41 | # include "msvc-nothrow.h" | ||
| 42 | |||
| 43 | static int | ||
| 44 | ms_windows_dup2 (int fd, int desired_fd) | ||
| 40 | { | 45 | { |
| 41 | int result; | 46 | int result; |
| 42 | # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ | 47 | |
| 43 | /* If fd is closed, mingw hangs on dup2 (fd, fd). If fd is open, | 48 | /* If fd is closed, mingw hangs on dup2 (fd, fd). If fd is open, |
| 44 | dup2 (fd, fd) returns 0, but all further attempts to use fd in | 49 | dup2 (fd, fd) returns 0, but all further attempts to use fd in |
| 45 | future dup2 calls will hang. */ | 50 | future dup2 calls will hang. */ |
| @@ -52,6 +57,7 @@ rpl_dup2 (int fd, int desired_fd) | |||
| 52 | } | 57 | } |
| 53 | return fd; | 58 | return fd; |
| 54 | } | 59 | } |
| 60 | |||
| 55 | /* Wine 1.0.1 return 0 when desired_fd is negative but not -1: | 61 | /* Wine 1.0.1 return 0 when desired_fd is negative but not -1: |
| 56 | http://bugs.winehq.org/show_bug.cgi?id=21289 */ | 62 | http://bugs.winehq.org/show_bug.cgi?id=21289 */ |
| 57 | if (desired_fd < 0) | 63 | if (desired_fd < 0) |
| @@ -59,26 +65,45 @@ rpl_dup2 (int fd, int desired_fd) | |||
| 59 | errno = EBADF; | 65 | errno = EBADF; |
| 60 | return -1; | 66 | return -1; |
| 61 | } | 67 | } |
| 62 | # elif !defined __linux__ | 68 | |
| 63 | /* On Haiku, dup2 (fd, fd) mistakenly clears FD_CLOEXEC. */ | 69 | TRY_MSVC_INVAL |
| 64 | if (fd == desired_fd) | 70 | { |
| 65 | return fcntl (fd, F_GETFL) == -1 ? -1 : fd; | 71 | result = dup2 (fd, desired_fd); |
| 66 | # endif | 72 | } |
| 67 | result = dup2 (fd, desired_fd); | 73 | CATCH_MSVC_INVAL |
| 68 | # ifdef __linux__ | ||
| 69 | /* Correct a Linux return value. | ||
| 70 | <http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.30.y.git;a=commitdiff;h=2b79bc4f7ebbd5af3c8b867968f9f15602d5f802> | ||
| 71 | */ | ||
| 72 | if (fd == desired_fd && result == (unsigned int) -EBADF) | ||
| 73 | { | 74 | { |
| 74 | errno = EBADF; | 75 | errno = EBADF; |
| 75 | result = -1; | 76 | result = -1; |
| 76 | } | 77 | } |
| 77 | # endif | 78 | DONE_MSVC_INVAL; |
| 79 | |||
| 78 | if (result == 0) | 80 | if (result == 0) |
| 79 | result = desired_fd; | 81 | result = desired_fd; |
| 80 | /* Correct a cygwin 1.5.x errno value. */ | 82 | |
| 81 | else if (result == -1 && errno == EMFILE) | 83 | return result; |
| 84 | } | ||
| 85 | |||
| 86 | # define dup2 ms_windows_dup2 | ||
| 87 | |||
| 88 | # endif | ||
| 89 | |||
| 90 | int | ||
| 91 | rpl_dup2 (int fd, int desired_fd) | ||
| 92 | { | ||
| 93 | int result; | ||
| 94 | |||
| 95 | # ifdef F_GETFL | ||
| 96 | /* On Linux kernels 2.6.26-2.6.29, dup2 (fd, fd) returns -EBADF. | ||
| 97 | On Cygwin 1.5.x, dup2 (1, 1) returns 0. | ||
| 98 | On Haiku, dup2 (fd, fd) mistakenly clears FD_CLOEXEC. */ | ||
| 99 | if (fd == desired_fd) | ||
| 100 | return fcntl (fd, F_GETFL) == -1 ? -1 : fd; | ||
| 101 | # endif | ||
| 102 | |||
| 103 | result = dup2 (fd, desired_fd); | ||
| 104 | |||
| 105 | /* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x. */ | ||
| 106 | if (result == -1 && errno == EMFILE) | ||
| 82 | errno = EBADF; | 107 | errno = EBADF; |
| 83 | # if REPLACE_FCHDIR | 108 | # if REPLACE_FCHDIR |
| 84 | if (fd != desired_fd && result != -1) | 109 | if (fd != desired_fd && result != -1) |