diff options
author | Anas Nashif <anas.nashif@intel.com> | 2012-12-20 20:15:32 -0800 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2012-12-20 20:15:32 -0800 |
commit | 81f1c64e30d2ea59604a628bca9f1d04b1f82afb (patch) | |
tree | 24fef6ba91ee63db41bbf6940dd2e8bdc348ac89 /lib/write.c | |
download | wget-81f1c64e30d2ea59604a628bca9f1d04b1f82afb.tar.gz wget-81f1c64e30d2ea59604a628bca9f1d04b1f82afb.tar.bz2 wget-81f1c64e30d2ea59604a628bca9f1d04b1f82afb.zip |
Imported Upstream version 1.13.4upstream/1.13.4
Diffstat (limited to 'lib/write.c')
-rw-r--r-- | lib/write.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/lib/write.c b/lib/write.c new file mode 100644 index 0000000..b0ffa94 --- /dev/null +++ b/lib/write.c @@ -0,0 +1,123 @@ +/* POSIX compatible write() function. + Copyright (C) 2008-2011 Free Software Foundation, Inc. + Written by Bruno Haible <bruno@clisp.org>, 2008. + + 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 + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +/* Specification. */ +#include <unistd.h> + +/* 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__ + +# include <errno.h> +# include <signal.h> +# include <io.h> + +# define WIN32_LEAN_AND_MEAN /* avoid including junk */ +# include <windows.h> + +ssize_t +rpl_write (int fd, const void *buf, size_t count) +#undef write +{ + for (;;) + { + ssize_t ret = write (fd, buf, count); + + if (ret < 0) + { +# 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; + } +} + +# endif +#endif |