diff options
Diffstat (limited to 'gl/dup2.c')
| -rw-r--r-- | gl/dup2.c | 68 |
1 files changed, 42 insertions, 26 deletions
| @@ -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) | |||
| 70 | static int | 70 | static int |
| 71 | ms_windows_dup2 (int fd, int desired_fd) | 71 | ms_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) | |||
| 110 | static int | 108 | static int |
| 111 | klibc_dup2dirfd (int fd, int desired_fd) | 109 | klibc_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) | |||
| 138 | static int | 155 | static int |
| 139 | klibc_dup2 (int fd, int desired_fd) | 156 | klibc_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) | |||
| 159 | int | 176 | int |
| 160 | rpl_dup2 (int fd, int desired_fd) | 177 | rpl_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; |
