X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fwrite.c;h=2d204219f2d849263f03cd6167e997b68c2b355b;hb=bbfcd2f1a92c9bdbb8d7d7d0a8a8c6665c316747;hp=4b40cd31d1e1b31b8e60ee65753ec4fe92d2fe01;hpb=836e0457064eb3b0b21bd2d4954cbc428a6b6277;p=gnulib.git diff --git a/lib/write.c b/lib/write.c index 4b40cd31d..2d204219f 100644 --- a/lib/write.c +++ b/lib/write.c @@ -1,5 +1,5 @@ /* POSIX compatible write() function. - Copyright (C) 2008-2011 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. Written by Bruno Haible , 2008. This program is free software: you can redistribute it and/or modify @@ -20,65 +20,126 @@ /* Specification. */ #include -/* Replace this function only if module 'nonblocking' or module 'sigpipe' is - requested. */ -#if GNULIB_NONBLOCKING || 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 GNULIB_NONBLOCKING - if (errno == ENOSPC) + ssize_t ret = write_nothrow (fd, buf, count); + + if (ret < 0) { - HANDLE h = (HANDLE) _get_osfhandle (fd); - if (GetFileType (h) == FILE_TYPE_PIPE) +# if GNULIB_NONBLOCKING + if (errno == ENOSPC) { - /* 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. - Change errno from ENOSPC to EAGAIN. */ - errno = EAGAIN; + 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) + else +# endif { - /* Try to raise signal SIGPIPE. */ - raise (SIGPIPE); - /* If it is currently blocked or ignored, change errno from - EINVAL to EPIPE. */ - errno = EPIPE; +# 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 } -# endif } + return ret; } - return ret; } -# endif #endif