diff options
Diffstat (limited to 'lib/pipe2.c')
-rw-r--r-- | lib/pipe2.c | 76 |
1 files changed, 55 insertions, 21 deletions
diff --git a/lib/pipe2.c b/lib/pipe2.c index a326754..211d755 100644 --- a/lib/pipe2.c +++ b/lib/pipe2.c @@ -1,5 +1,5 @@ /* Create a pipe, with specific opening flags. - Copyright (C) 2009-2011 Free Software Foundation, Inc. + Copyright (C) 2009-2013 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 @@ -12,8 +12,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <config.h> @@ -24,9 +23,14 @@ #include <fcntl.h> #include "binary-io.h" +#include "verify.h" + +#if GNULIB_defined_O_NONBLOCK +# include "nonblocking.h" +#endif #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ -/* Native Woe32 API. */ +/* Native Windows API. */ # include <io.h> @@ -35,6 +39,13 @@ int pipe2 (int fd[2], int flags) { + /* Mingw _pipe() corrupts fd on failure; also, if we succeed at + creating the pipe but later fail at changing fcntl, we want + to leave fd unchanged: http://austingroupbugs.net/view.php?id=467 */ + int tmp[2]; + tmp[0] = fd[0]; + tmp[1] = fd[1]; + #if HAVE_PIPE2 # undef pipe2 /* Try the system call first, if it exists. (We may be running with a glibc @@ -55,35 +66,53 @@ pipe2 (int fd[2], int flags) } #endif -#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ -/* Native Woe32 API. */ - /* Check the supported flags. */ - if ((flags & ~(O_CLOEXEC | O_BINARY | O_TEXT)) != 0) + if ((flags & ~(O_CLOEXEC | O_NONBLOCK | O_BINARY | O_TEXT)) != 0) { errno = EINVAL; return -1; } - return _pipe (fd, 4096, flags); - -#else -/* Unix API. */ +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +/* Native Windows API. */ - /* Check the supported flags. */ - if ((flags & ~(O_CLOEXEC | O_NONBLOCK | O_TEXT | O_BINARY)) != 0) + if (_pipe (fd, 4096, flags & ~O_NONBLOCK) < 0) { - errno = EINVAL; + fd[0] = tmp[0]; + fd[1] = tmp[1]; return -1; } + /* O_NONBLOCK handling. + On native Windows platforms, O_NONBLOCK is defined by gnulib. Use the + functions defined by the gnulib module 'nonblocking'. */ +# if GNULIB_defined_O_NONBLOCK + if (flags & O_NONBLOCK) + { + if (set_nonblocking_flag (fd[0], true) != 0 + || set_nonblocking_flag (fd[1], true) != 0) + goto fail; + } +# else + { + verify (O_NONBLOCK == 0); + } +# endif + + return 0; + +#else +/* Unix API. */ + if (pipe (fd) < 0) return -1; /* POSIX <http://www.opengroup.org/onlinepubs/9699919799/functions/pipe.html> says that initially, the O_NONBLOCK and FD_CLOEXEC flags are cleared on - both fd[0] amd fd[1]. */ + both fd[0] and fd[1]. */ + /* O_NONBLOCK handling. + On Unix platforms, O_NONBLOCK is defined by the system. Use fcntl(). */ if (flags & O_NONBLOCK) { int fcntl_flags; @@ -109,26 +138,31 @@ pipe2 (int fd[2], int flags) # if O_BINARY if (flags & O_BINARY) { - setmode (fd[1], O_BINARY); - setmode (fd[0], O_BINARY); + set_binary_mode (fd[1], O_BINARY); + set_binary_mode (fd[0], O_BINARY); } else if (flags & O_TEXT) { - setmode (fd[1], O_TEXT); - setmode (fd[0], O_TEXT); + set_binary_mode (fd[1], O_TEXT); + set_binary_mode (fd[0], O_TEXT); } # endif return 0; +#endif + +#if GNULIB_defined_O_NONBLOCK || \ + !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__) fail: { int saved_errno = errno; close (fd[0]); close (fd[1]); + fd[0] = tmp[0]; + fd[1] = tmp[1]; errno = saved_errno; return -1; } - #endif } |