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