diff options
Diffstat (limited to 'gl/dup2.c')
-rw-r--r-- | gl/dup2.c | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/gl/dup2.c b/gl/dup2.c new file mode 100644 index 00000000..53e55521 --- /dev/null +++ b/gl/dup2.c | |||
@@ -0,0 +1,189 @@ | |||
1 | /* Duplicate an open file descriptor to a specified file descriptor. | ||
2 | |||
3 | Copyright (C) 1999, 2004-2007, 2009-2021 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 | } | ||