write.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /* POSIX compatible write() function.
  2. Copyright (C) 2008-2023 Free Software Foundation, Inc.
  3. Written by Bruno Haible <bruno@clisp.org>, 2008.
  4. This file is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as
  6. published by the Free Software Foundation; either version 2.1 of the
  7. License, or (at your option) any later version.
  8. This file is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License
  13. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  14. #include <config.h>
  15. /* Specification. */
  16. #include <unistd.h>
  17. /* On native Windows platforms, SIGPIPE does not exist. When write() is
  18. called on a pipe with no readers, WriteFile() fails with error
  19. GetLastError() = ERROR_NO_DATA, and write() in consequence fails with
  20. error EINVAL. */
  21. #if defined _WIN32 && ! defined __CYGWIN__
  22. # include <errno.h>
  23. # include <signal.h>
  24. # include <io.h>
  25. # define WIN32_LEAN_AND_MEAN /* avoid including junk */
  26. # include <windows.h>
  27. # if HAVE_MSVC_INVALID_PARAMETER_HANDLER
  28. # include "msvc-inval.h"
  29. # endif
  30. # if GNULIB_MSVC_NOTHROW
  31. # include "msvc-nothrow.h"
  32. # else
  33. # include <io.h>
  34. # endif
  35. /* Don't assume that UNICODE is not defined. */
  36. # undef GetNamedPipeHandleState
  37. # define GetNamedPipeHandleState GetNamedPipeHandleStateA
  38. # undef write
  39. # if HAVE_MSVC_INVALID_PARAMETER_HANDLER
  40. static ssize_t
  41. write_nothrow (int fd, const void *buf, size_t count)
  42. {
  43. ssize_t result;
  44. TRY_MSVC_INVAL
  45. {
  46. result = _write (fd, buf, count);
  47. }
  48. CATCH_MSVC_INVAL
  49. {
  50. result = -1;
  51. errno = EBADF;
  52. }
  53. DONE_MSVC_INVAL;
  54. return result;
  55. }
  56. # else
  57. # define write_nothrow _write
  58. # endif
  59. ssize_t
  60. rpl_write (int fd, const void *buf, size_t count)
  61. {
  62. for (;;)
  63. {
  64. ssize_t ret = write_nothrow (fd, buf, count);
  65. if (ret < 0)
  66. {
  67. # if GNULIB_NONBLOCKING
  68. if (errno == ENOSPC)
  69. {
  70. HANDLE h = (HANDLE) _get_osfhandle (fd);
  71. if (GetFileType (h) == FILE_TYPE_PIPE)
  72. {
  73. /* h is a pipe or socket. */
  74. DWORD state;
  75. if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL,
  76. NULL, 0)
  77. && (state & PIPE_NOWAIT) != 0)
  78. {
  79. /* h is a pipe in non-blocking mode.
  80. We can get here in four situations:
  81. 1. When the pipe buffer is full.
  82. 2. When count <= pipe_buf_size and the number of
  83. free bytes in the pipe buffer is < count.
  84. 3. When count > pipe_buf_size and the number of free
  85. bytes in the pipe buffer is > 0, < pipe_buf_size.
  86. 4. When count > pipe_buf_size and the pipe buffer is
  87. entirely empty.
  88. The cases 1 and 2 are POSIX compliant. In cases 3 and
  89. 4 POSIX specifies that write() must split the request
  90. and succeed with a partial write. We fix case 4.
  91. We don't fix case 3 because it is not essential for
  92. programs. */
  93. DWORD out_size; /* size of the buffer for outgoing data */
  94. DWORD in_size; /* size of the buffer for incoming data */
  95. if (GetNamedPipeInfo (h, NULL, &out_size, &in_size, NULL))
  96. {
  97. size_t reduced_count = count;
  98. /* In theory we need only one of out_size, in_size.
  99. But I don't know which of the two. The description
  100. is ambiguous. */
  101. if (out_size != 0 && out_size < reduced_count)
  102. reduced_count = out_size;
  103. if (in_size != 0 && in_size < reduced_count)
  104. reduced_count = in_size;
  105. if (reduced_count < count)
  106. {
  107. /* Attempt to write only the first part. */
  108. count = reduced_count;
  109. continue;
  110. }
  111. }
  112. /* Change errno from ENOSPC to EAGAIN. */
  113. errno = EAGAIN;
  114. }
  115. }
  116. }
  117. else
  118. # endif
  119. {
  120. # if GNULIB_SIGPIPE
  121. if (GetLastError () == ERROR_NO_DATA
  122. && GetFileType ((HANDLE) _get_osfhandle (fd))
  123. == FILE_TYPE_PIPE)
  124. {
  125. /* Try to raise signal SIGPIPE. */
  126. raise (SIGPIPE);
  127. /* If it is currently blocked or ignored, change errno from
  128. EINVAL to EPIPE. */
  129. errno = EPIPE;
  130. }
  131. # endif
  132. }
  133. }
  134. return ret;
  135. }
  136. }
  137. #endif