summaryrefslogtreecommitdiff
path: root/tests/dup2.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/dup2.c')
-rw-r--r--tests/dup2.c68
1 files changed, 42 insertions, 26 deletions
diff --git a/tests/dup2.c b/tests/dup2.c
index 69b37196..b9a55263 100644
--- a/tests/dup2.c
+++ b/tests/dup2.c
@@ -1,6 +1,6 @@
/* Duplicate an open file descriptor to a specified file descriptor.
- Copyright (C) 1999, 2004-2007, 2009-2025 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2004-2007, 2009-2026 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
@@ -70,8 +70,6 @@ dup2_nothrow (int fd, int desired_fd)
static int
ms_windows_dup2 (int fd, int desired_fd)
{
- int result;
-
/* If fd is closed, mingw hangs on dup2 (fd, fd). If fd is open,
dup2 (fd, fd) returns 0, but all further attempts to use fd in
future dup2 calls will hang. */
@@ -93,7 +91,7 @@ ms_windows_dup2 (int fd, int desired_fd)
return -1;
}
- result = dup2_nothrow (fd, desired_fd);
+ int result = dup2_nothrow (fd, desired_fd);
if (result == 0)
result = desired_fd;
@@ -110,14 +108,11 @@ ms_windows_dup2 (int fd, int desired_fd)
static int
klibc_dup2dirfd (int fd, int desired_fd)
{
- int tempfd;
- int dupfd;
-
- tempfd = open ("NUL", O_RDONLY);
- if (tempfd == -1)
- return -1;
+ int tempfd = open ("NUL", O_RDONLY);
+ if (tempfd < 0)
+ return tempfd;
- if (tempfd == desired_fd)
+ if (tempfd >= desired_fd)
{
close (tempfd);
@@ -125,10 +120,32 @@ klibc_dup2dirfd (int fd, int desired_fd)
if (__libc_Back_ioFHToPath (fd, path, sizeof (path)))
return -1;
- return open(path, O_RDONLY);
+ for (;;)
+ {
+ close (desired_fd);
+
+ int dupfd = open (path, O_RDONLY);
+ if (dupfd < 0)
+ return dupfd;
+
+ if (dupfd == desired_fd)
+ return dupfd;
+
+ /* If lower FD was closed by other threads, fill again. */
+ if (dupfd < desired_fd)
+ {
+ tempfd = dupfd;
+ break;
+ }
+
+ /* desired_fd was opened by other threads. Try again. */
+ /* FIXME: Closing desired_fd opened by other threads may lead to
+ unexpected behavior. */
+ close (dupfd);
+ }
}
- dupfd = klibc_dup2dirfd (fd, desired_fd);
+ int dupfd = klibc_dup2dirfd (fd, desired_fd);
close (tempfd);
@@ -138,16 +155,16 @@ klibc_dup2dirfd (int fd, int desired_fd)
static int
klibc_dup2 (int fd, int desired_fd)
{
- int dupfd;
- struct stat sbuf;
-
- dupfd = dup2 (fd, desired_fd);
- if (dupfd == -1 && errno == ENOTSUP \
- && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
+ int dupfd = dup2 (fd, desired_fd);
+ if (dupfd < 0 && errno == ENOTSUP)
{
- close (desired_fd);
+ struct stat sbuf;
+ if (!fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
+ {
+ close (desired_fd);
- return klibc_dup2dirfd (fd, desired_fd);
+ return klibc_dup2dirfd (fd, desired_fd);
+ }
}
return dupfd;
@@ -159,8 +176,6 @@ klibc_dup2 (int fd, int desired_fd)
int
rpl_dup2 (int fd, int desired_fd)
{
- int result;
-
#ifdef F_GETFL
/* On Linux kernels 2.6.26-2.6.29, dup2 (fd, fd) returns -EBADF.
On Cygwin 1.5.x, dup2 (1, 1) returns 0.
@@ -176,13 +191,14 @@ rpl_dup2 (int fd, int desired_fd)
return fcntl (fd, F_GETFL) == -1 ? -1 : fd;
#endif
- result = dup2 (fd, desired_fd);
+ int result = dup2 (fd, desired_fd);
/* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x. */
- if (result == -1 && errno == EMFILE)
+ if (result < 0 && errno == EMFILE)
errno = EBADF;
+
#if REPLACE_FCHDIR
- if (fd != desired_fd && result != -1)
+ if (! (result < 0 || fd == desired_fd))
result = _gl_register_dup (fd, result);
#endif
return result;