X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=gnu%2Fwrite.c;h=ed2d3b7bf49fc8317010883bf4ac93dfaaa6ada9;hb=HEAD;hp=1eee7bdbb76a9d96eefa16ee7f00617f68711de7;hpb=1a44d77d50f4fb37c0410eed04b82303624ea2ec;p=debian%2Ftar diff --git a/gnu/write.c b/gnu/write.c index 1eee7bdb..ed2d3b7b 100644 --- a/gnu/write.c +++ b/gnu/write.c @@ -1,7 +1,5 @@ -/* -*- buffer-read-only: t -*- vi: set ro: */ -/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ /* POSIX compatible write() function. - Copyright (C) 2008-2011 Free Software Foundation, Inc. + Copyright (C) 2008-2015 Free Software Foundation, Inc. Written by Bruno Haible , 2008. This program is free software: you can redistribute it and/or modify @@ -22,43 +20,126 @@ /* Specification. */ #include -/* Replace this function only if module 'sigpipe' is requested. */ -#if GNULIB_SIGPIPE - /* On native Windows platforms, SIGPIPE does not exist. When write() is called on a pipe with no readers, WriteFile() fails with error GetLastError() = ERROR_NO_DATA, and write() in consequence fails with error EINVAL. */ -# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + +# include +# include +# include + +# define WIN32_LEAN_AND_MEAN /* avoid including junk */ +# include + +# include "msvc-inval.h" +# include "msvc-nothrow.h" + +# undef write -# include -# include -# include +# if HAVE_MSVC_INVALID_PARAMETER_HANDLER +static ssize_t +write_nothrow (int fd, const void *buf, size_t count) +{ + ssize_t result; + + TRY_MSVC_INVAL + { + result = write (fd, buf, count); + } + CATCH_MSVC_INVAL + { + result = -1; + errno = EBADF; + } + DONE_MSVC_INVAL; -# define WIN32_LEAN_AND_MEAN /* avoid including junk */ -# include + return result; +} +# else +# define write_nothrow write +# endif ssize_t rpl_write (int fd, const void *buf, size_t count) -#undef write { - ssize_t ret = write (fd, buf, count); - - if (ret < 0) + for (;;) { - if (GetLastError () == ERROR_NO_DATA - && GetFileType ((HANDLE) _get_osfhandle (fd)) == FILE_TYPE_PIPE) + ssize_t ret = write_nothrow (fd, buf, count); + + if (ret < 0) { - /* Try to raise signal SIGPIPE. */ - raise (SIGPIPE); - /* If it is currently blocked or ignored, change errno from EINVAL - to EPIPE. */ - errno = EPIPE; +# if GNULIB_NONBLOCKING + if (errno == ENOSPC) + { + HANDLE h = (HANDLE) _get_osfhandle (fd); + if (GetFileType (h) == FILE_TYPE_PIPE) + { + /* h is a pipe or socket. */ + DWORD state; + if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL, + NULL, 0) + && (state & PIPE_NOWAIT) != 0) + { + /* h is a pipe in non-blocking mode. + We can get here in four situations: + 1. When the pipe buffer is full. + 2. When count <= pipe_buf_size and the number of + free bytes in the pipe buffer is < count. + 3. When count > pipe_buf_size and the number of free + bytes in the pipe buffer is > 0, < pipe_buf_size. + 4. When count > pipe_buf_size and the pipe buffer is + entirely empty. + The cases 1 and 2 are POSIX compliant. In cases 3 and + 4 POSIX specifies that write() must split the request + and succeed with a partial write. We fix case 4. + We don't fix case 3 because it is not essential for + programs. */ + DWORD out_size; /* size of the buffer for outgoing data */ + DWORD in_size; /* size of the buffer for incoming data */ + if (GetNamedPipeInfo (h, NULL, &out_size, &in_size, NULL)) + { + size_t reduced_count = count; + /* In theory we need only one of out_size, in_size. + But I don't know which of the two. The description + is ambiguous. */ + if (out_size != 0 && out_size < reduced_count) + reduced_count = out_size; + if (in_size != 0 && in_size < reduced_count) + reduced_count = in_size; + if (reduced_count < count) + { + /* Attempt to write only the first part. */ + count = reduced_count; + continue; + } + } + /* Change errno from ENOSPC to EAGAIN. */ + errno = EAGAIN; + } + } + } + else +# endif + { +# if GNULIB_SIGPIPE + if (GetLastError () == ERROR_NO_DATA + && GetFileType ((HANDLE) _get_osfhandle (fd)) + == FILE_TYPE_PIPE) + { + /* Try to raise signal SIGPIPE. */ + raise (SIGPIPE); + /* If it is currently blocked or ignored, change errno from + EINVAL to EPIPE. */ + errno = EPIPE; + } +# endif + } } + return ret; } - return ret; } -# endif #endif