X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fdup2.c;h=790c98a2e846c7ccd823b98c5ed2e816a3a5705c;hb=f16415c07025fdec551dfc1dc7275c2a88819d44;hp=6d6182934308b4b65ba88be71a6dc242dcd1c613;hpb=80cb44fa0b094ad965f7bd88ad7e46e83df418d5;p=gnulib.git diff --git a/lib/dup2.c b/lib/dup2.c index 6d6182934..790c98a2e 100644 --- a/lib/dup2.c +++ b/lib/dup2.c @@ -1,7 +1,6 @@ /* Duplicate an open file descriptor to a specified file descriptor. - Copyright (C) 1999, 2004, 2005, 2006, 2007, 2009 Free Software - Foundation, Inc. + Copyright (C) 1999, 2004-2007, 2009-2011 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,21 +25,26 @@ #include #include -#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +#if HAVE_DUP2 + +# undef dup2 + +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + /* Get declarations of the Win32 API functions. */ -# define WIN32_LEAN_AND_MEAN -# include -#endif +# define WIN32_LEAN_AND_MEAN +# include -#if REPLACE_DUP2 +# include "msvc-inval.h" -# undef dup2 +/* Get _get_osfhandle. */ +# include "msvc-nothrow.h" -int -rpl_dup2 (int fd, int desired_fd) +static int +ms_windows_dup2 (int fd, int desired_fd) { int result; -# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + /* 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. */ @@ -53,14 +57,62 @@ rpl_dup2 (int fd, int desired_fd) } return fd; } -# endif - result = dup2 (fd, desired_fd); + + /* Wine 1.0.1 return 0 when desired_fd is negative but not -1: + http://bugs.winehq.org/show_bug.cgi?id=21289 */ + if (desired_fd < 0) + { + errno = EBADF; + return -1; + } + + TRY_MSVC_INVAL + { + result = dup2 (fd, desired_fd); + } + CATCH_MSVC_INVAL + { + errno = EBADF; + result = -1; + } + DONE_MSVC_INVAL; + if (result == 0) result = desired_fd; + return result; } -#else /* !REPLACE_DUP2 */ +# define dup2 ms_windows_dup2 + +# endif + +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. + On Haiku, dup2 (fd, fd) mistakenly clears FD_CLOEXEC. */ + if (fd == desired_fd) + return fcntl (fd, F_GETFL) == -1 ? -1 : fd; +# endif + + result = dup2 (fd, desired_fd); + + /* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x. */ + if (result == -1 && errno == EMFILE) + errno = EBADF; +# if REPLACE_FCHDIR + if (fd != desired_fd && result != -1) + result = _gl_register_dup (fd, result); +# endif + return result; +} + +#else /* !HAVE_DUP2 */ /* On older platforms, dup2 did not exist. */ @@ -85,13 +137,21 @@ dupfd (int fd, int desired_fd) int dup2 (int fd, int desired_fd) { - if (fd == desired_fd) - return fd; + int result = fcntl (fd, F_GETFL) < 0 ? -1 : fd; + if (result == -1 || fd == desired_fd) + return result; close (desired_fd); # ifdef F_DUPFD - return fcntl (fd, F_DUPFD, desired_fd); + result = fcntl (fd, F_DUPFD, desired_fd); +# if REPLACE_FCHDIR + if (0 <= result) + result = _gl_register_dup (fd, result); +# endif # else - return dupfd (fd, desired_fd); + result = dupfd (fd, desired_fd); # endif + if (result == -1 && (errno == EMFILE || errno == EINVAL)) + errno = EBADF; + return result; } -#endif /* !REPLACE_DUP2 */ +#endif /* !HAVE_DUP2 */