summaryrefslogtreecommitdiffstats
path: root/gl/dup2.c
diff options
context:
space:
mode:
Diffstat (limited to 'gl/dup2.c')
-rw-r--r--gl/dup2.c68
1 files changed, 42 insertions, 26 deletions
diff --git a/gl/dup2.c b/gl/dup2.c
index 69b37196..b9a55263 100644
--- a/gl/dup2.c
+++ b/gl/dup2.c
@@ -1,6 +1,6 @@
1/* Duplicate an open file descriptor to a specified file descriptor. 1/* Duplicate an open file descriptor to a specified file descriptor.
2 2
3 Copyright (C) 1999, 2004-2007, 2009-2025 Free Software Foundation, Inc. 3 Copyright (C) 1999, 2004-2007, 2009-2026 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 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 6 it under the terms of the GNU Lesser General Public License as
@@ -70,8 +70,6 @@ dup2_nothrow (int fd, int desired_fd)
70static int 70static int
71ms_windows_dup2 (int fd, int desired_fd) 71ms_windows_dup2 (int fd, int desired_fd)
72{ 72{
73 int result;
74
75 /* If fd is closed, mingw hangs on dup2 (fd, fd). If fd is open, 73 /* 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 74 dup2 (fd, fd) returns 0, but all further attempts to use fd in
77 future dup2 calls will hang. */ 75 future dup2 calls will hang. */
@@ -93,7 +91,7 @@ ms_windows_dup2 (int fd, int desired_fd)
93 return -1; 91 return -1;
94 } 92 }
95 93
96 result = dup2_nothrow (fd, desired_fd); 94 int result = dup2_nothrow (fd, desired_fd);
97 95
98 if (result == 0) 96 if (result == 0)
99 result = desired_fd; 97 result = desired_fd;
@@ -110,14 +108,11 @@ ms_windows_dup2 (int fd, int desired_fd)
110static int 108static int
111klibc_dup2dirfd (int fd, int desired_fd) 109klibc_dup2dirfd (int fd, int desired_fd)
112{ 110{
113 int tempfd; 111 int tempfd = open ("NUL", O_RDONLY);
114 int dupfd; 112 if (tempfd < 0)
115 113 return tempfd;
116 tempfd = open ("NUL", O_RDONLY);
117 if (tempfd == -1)
118 return -1;
119 114
120 if (tempfd == desired_fd) 115 if (tempfd >= desired_fd)
121 { 116 {
122 close (tempfd); 117 close (tempfd);
123 118
@@ -125,10 +120,32 @@ klibc_dup2dirfd (int fd, int desired_fd)
125 if (__libc_Back_ioFHToPath (fd, path, sizeof (path))) 120 if (__libc_Back_ioFHToPath (fd, path, sizeof (path)))
126 return -1; 121 return -1;
127 122
128 return open(path, O_RDONLY); 123 for (;;)
124 {
125 close (desired_fd);
126
127 int dupfd = open (path, O_RDONLY);
128 if (dupfd < 0)
129 return dupfd;
130
131 if (dupfd == desired_fd)
132 return dupfd;
133
134 /* If lower FD was closed by other threads, fill again. */
135 if (dupfd < desired_fd)
136 {
137 tempfd = dupfd;
138 break;
139 }
140
141 /* desired_fd was opened by other threads. Try again. */
142 /* FIXME: Closing desired_fd opened by other threads may lead to
143 unexpected behavior. */
144 close (dupfd);
145 }
129 } 146 }
130 147
131 dupfd = klibc_dup2dirfd (fd, desired_fd); 148 int dupfd = klibc_dup2dirfd (fd, desired_fd);
132 149
133 close (tempfd); 150 close (tempfd);
134 151
@@ -138,16 +155,16 @@ klibc_dup2dirfd (int fd, int desired_fd)
138static int 155static int
139klibc_dup2 (int fd, int desired_fd) 156klibc_dup2 (int fd, int desired_fd)
140{ 157{
141 int dupfd; 158 int dupfd = dup2 (fd, desired_fd);
142 struct stat sbuf; 159 if (dupfd < 0 && errno == ENOTSUP)
143
144 dupfd = dup2 (fd, desired_fd);
145 if (dupfd == -1 && errno == ENOTSUP \
146 && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
147 { 160 {
148 close (desired_fd); 161 struct stat sbuf;
162 if (!fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
163 {
164 close (desired_fd);
149 165
150 return klibc_dup2dirfd (fd, desired_fd); 166 return klibc_dup2dirfd (fd, desired_fd);
167 }
151 } 168 }
152 169
153 return dupfd; 170 return dupfd;
@@ -159,8 +176,6 @@ klibc_dup2 (int fd, int desired_fd)
159int 176int
160rpl_dup2 (int fd, int desired_fd) 177rpl_dup2 (int fd, int desired_fd)
161{ 178{
162 int result;
163
164#ifdef F_GETFL 179#ifdef F_GETFL
165 /* On Linux kernels 2.6.26-2.6.29, dup2 (fd, fd) returns -EBADF. 180 /* 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. 181 On Cygwin 1.5.x, dup2 (1, 1) returns 0.
@@ -176,13 +191,14 @@ rpl_dup2 (int fd, int desired_fd)
176 return fcntl (fd, F_GETFL) == -1 ? -1 : fd; 191 return fcntl (fd, F_GETFL) == -1 ? -1 : fd;
177#endif 192#endif
178 193
179 result = dup2 (fd, desired_fd); 194 int result = dup2 (fd, desired_fd);
180 195
181 /* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x. */ 196 /* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x. */
182 if (result == -1 && errno == EMFILE) 197 if (result < 0 && errno == EMFILE)
183 errno = EBADF; 198 errno = EBADF;
199
184#if REPLACE_FCHDIR 200#if REPLACE_FCHDIR
185 if (fd != desired_fd && result != -1) 201 if (! (result < 0 || fd == desired_fd))
186 result = _gl_register_dup (fd, result); 202 result = _gl_register_dup (fd, result);
187#endif 203#endif
188 return result; 204 return result;