(root)/
glib-2.79.0/
gio/
gwin32inputstream.c
       1  /* GIO - GLib Input, Output and Streaming Library
       2   *
       3   * Copyright (C) 2006-2010 Red Hat, Inc.
       4   *
       5   * SPDX-License-Identifier: LGPL-2.1-or-later
       6   *
       7   * This library is free software; you can redistribute it and/or
       8   * modify it under the terms of the GNU Lesser General Public
       9   * License as published by the Free Software Foundation; either
      10   * version 2.1 of the License, or (at your option) any later version.
      11   *
      12   * This library is distributed in the hope that it will be useful,
      13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15   * Lesser General Public License for more details.
      16   *
      17   * You should have received a copy of the GNU Lesser General
      18   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      19   *
      20   * Author: Alexander Larsson <alexl@redhat.com>
      21   * Author: Tor Lillqvist <tml@iki.fi>
      22   */
      23  
      24  #include "config.h"
      25  
      26  #include <windows.h>
      27  
      28  #include <io.h>
      29  
      30  #include <glib.h>
      31  #include "gioerror.h"
      32  #include "gwin32inputstream.h"
      33  #include "giowin32-priv.h"
      34  #include "gcancellable.h"
      35  #include "gasynchelper.h"
      36  #include "glibintl.h"
      37  
      38  /**
      39   * GWin32InputStream:
      40   *
      41   * `GWin32InputStream` implements [class@Gio.InputStream] for reading from a
      42   * Windows file handle.
      43   *
      44   * Note that `<gio/gwin32inputstream.h>` belongs to the Windows-specific GIO
      45   * interfaces, thus you have to use the `gio-windows-2.0.pc` pkg-config file
      46   * when using it.
      47   */
      48  
      49  struct _GWin32InputStreamPrivate {
      50    HANDLE handle;
      51    gboolean close_handle;
      52    gint fd;
      53  };
      54  
      55  enum {
      56    PROP_0,
      57    PROP_HANDLE,
      58    PROP_CLOSE_HANDLE,
      59    LAST_PROP
      60  };
      61  
      62  static GParamSpec *props[LAST_PROP];
      63  
      64  G_DEFINE_TYPE_WITH_PRIVATE (GWin32InputStream, g_win32_input_stream, G_TYPE_INPUT_STREAM)
      65  
      66  static void
      67  g_win32_input_stream_set_property (GObject         *object,
      68  				   guint            prop_id,
      69  				   const GValue    *value,
      70  				   GParamSpec      *pspec)
      71  {
      72    GWin32InputStream *win32_stream;
      73  
      74    win32_stream = G_WIN32_INPUT_STREAM (object);
      75  
      76    switch (prop_id)
      77      {
      78      case PROP_HANDLE:
      79        win32_stream->priv->handle = g_value_get_pointer (value);
      80        break;
      81      case PROP_CLOSE_HANDLE:
      82        win32_stream->priv->close_handle = g_value_get_boolean (value);
      83        break;
      84      default:
      85        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      86        break;
      87      }
      88  }
      89  
      90  static void
      91  g_win32_input_stream_get_property (GObject    *object,
      92  				   guint       prop_id,
      93  				   GValue     *value,
      94  				   GParamSpec *pspec)
      95  {
      96    GWin32InputStream *win32_stream;
      97  
      98    win32_stream = G_WIN32_INPUT_STREAM (object);
      99  
     100    switch (prop_id)
     101      {
     102      case PROP_HANDLE:
     103        g_value_set_pointer (value, win32_stream->priv->handle);
     104        break;
     105      case PROP_CLOSE_HANDLE:
     106        g_value_set_boolean (value, win32_stream->priv->close_handle);
     107        break;
     108      default:
     109        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     110      }
     111  }
     112  
     113  static gssize
     114  g_win32_input_stream_read (GInputStream  *stream,
     115  			   void          *buffer,
     116  			   gsize          count,
     117  			   GCancellable  *cancellable,
     118  			   GError       **error)
     119  {
     120    GWin32InputStream *win32_stream;
     121    BOOL res;
     122    DWORD nbytes, nread;
     123    OVERLAPPED overlap = { 0, };
     124    gssize retval = -1;
     125  
     126    win32_stream = G_WIN32_INPUT_STREAM (stream);
     127  
     128    if (g_cancellable_set_error_if_cancelled (cancellable, error))
     129      return -1;
     130  
     131    if (count > G_MAXINT)
     132      nbytes = G_MAXINT;
     133    else
     134      nbytes = count;
     135  
     136    overlap.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
     137    g_return_val_if_fail (overlap.hEvent != NULL, -1);
     138  
     139    res = ReadFile (win32_stream->priv->handle, buffer, nbytes, &nread, &overlap);
     140    if (res)
     141      retval = nread;
     142    else
     143      {
     144        int errsv = GetLastError ();
     145  
     146        if (errsv == ERROR_IO_PENDING &&
     147            _g_win32_overlap_wait_result (win32_stream->priv->handle,
     148                                          &overlap, &nread, cancellable))
     149          {
     150            retval = nread;
     151            goto end;
     152          }
     153  
     154        if (g_cancellable_set_error_if_cancelled (cancellable, error))
     155          goto end;
     156  
     157        errsv = GetLastError ();
     158        if (errsv == ERROR_MORE_DATA)
     159          {
     160            /* If a named pipe is being read in message mode and the
     161             * next message is longer than the nNumberOfBytesToRead
     162             * parameter specifies, ReadFile returns FALSE and
     163             * GetLastError returns ERROR_MORE_DATA */
     164            retval = nread;
     165            goto end;
     166          }
     167        else if (errsv == ERROR_HANDLE_EOF ||
     168                 errsv == ERROR_BROKEN_PIPE)
     169          {
     170            /* TODO: the other end of a pipe may call the WriteFile
     171             * function with nNumberOfBytesToWrite set to zero. In this
     172             * case, it's not possible for the caller to know if it's
     173             * broken pipe or a read of 0. Perhaps we should add a
     174             * is_broken flag for this win32 case.. */
     175            retval = 0;
     176          }
     177        else
     178          {
     179            gchar *emsg;
     180  
     181            emsg = g_win32_error_message (errsv);
     182            g_set_error (error, G_IO_ERROR,
     183                         g_io_error_from_win32_error (errsv),
     184                         _("Error reading from handle: %s"),
     185                         emsg);
     186            g_free (emsg);
     187          }
     188      }
     189  
     190  end:
     191    CloseHandle (overlap.hEvent);
     192    return retval;
     193  }
     194  
     195  static gboolean
     196  g_win32_input_stream_close (GInputStream  *stream,
     197  			   GCancellable  *cancellable,
     198  			   GError       **error)
     199  {
     200    GWin32InputStream *win32_stream;
     201    BOOL res;
     202  
     203    win32_stream = G_WIN32_INPUT_STREAM (stream);
     204  
     205    if (!win32_stream->priv->close_handle)
     206      return TRUE;
     207  
     208    if (win32_stream->priv->fd != -1)
     209      {
     210        if (close (win32_stream->priv->fd) < 0)
     211  	{
     212  	  int errsv = errno;
     213  
     214  	  g_set_error (error, G_IO_ERROR,
     215  	               g_io_error_from_errno (errsv),
     216  	               _("Error closing file descriptor: %s"),
     217  	               g_strerror (errsv));
     218  	  return FALSE;
     219  	}
     220      }
     221    else
     222      {
     223        res = CloseHandle (win32_stream->priv->handle);
     224        if (!res)
     225  	{
     226  	  int errsv = GetLastError ();
     227  	  gchar *emsg = g_win32_error_message (errsv);
     228  
     229  	  g_set_error (error, G_IO_ERROR,
     230  		       g_io_error_from_win32_error (errsv),
     231  		       _("Error closing handle: %s"),
     232  		       emsg);
     233  	  g_free (emsg);
     234  	  return FALSE;
     235  	}
     236      }
     237  
     238    return TRUE;
     239  }
     240  
     241  static void
     242  g_win32_input_stream_class_init (GWin32InputStreamClass *klass)
     243  {
     244    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     245    GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
     246  
     247    gobject_class->get_property = g_win32_input_stream_get_property;
     248    gobject_class->set_property = g_win32_input_stream_set_property;
     249  
     250    stream_class->read_fn = g_win32_input_stream_read;
     251    stream_class->close_fn = g_win32_input_stream_close;
     252  
     253    /**
     254     * GWin32InputStream:handle:
     255     *
     256     * The handle that the stream reads from.
     257     *
     258     * Since: 2.26
     259     */
     260    props[PROP_HANDLE] =
     261      g_param_spec_pointer ("handle", NULL, NULL,
     262                            G_PARAM_READABLE |
     263                            G_PARAM_WRITABLE |
     264                            G_PARAM_CONSTRUCT_ONLY |
     265                            G_PARAM_STATIC_STRINGS);
     266  
     267    /**
     268     * GWin32InputStream:close-handle:
     269     *
     270     * Whether to close the file handle when the stream is closed.
     271     *
     272     * Since: 2.26
     273     */
     274    props[PROP_CLOSE_HANDLE] =
     275      g_param_spec_boolean ("close-handle", NULL, NULL,
     276                            TRUE,
     277                            G_PARAM_READABLE |
     278                            G_PARAM_WRITABLE |
     279                            G_PARAM_STATIC_STRINGS);
     280  
     281    g_object_class_install_properties (gobject_class, LAST_PROP, props);
     282  }
     283  
     284  static void
     285  g_win32_input_stream_init (GWin32InputStream *win32_stream)
     286  {
     287    win32_stream->priv = g_win32_input_stream_get_instance_private (win32_stream);
     288    win32_stream->priv->handle = NULL;
     289    win32_stream->priv->close_handle = TRUE;
     290    win32_stream->priv->fd = -1;
     291  }
     292  
     293  /**
     294   * g_win32_input_stream_new:
     295   * @handle: a Win32 file handle
     296   * @close_handle: %TRUE to close the handle when done
     297   *
     298   * Creates a new #GWin32InputStream for the given @handle.
     299   *
     300   * If @close_handle is %TRUE, the handle will be closed
     301   * when the stream is closed.
     302   *
     303   * Note that "handle" here means a Win32 HANDLE, not a "file descriptor"
     304   * as used in the Windows C libraries.
     305   *
     306   * Returns: a new #GWin32InputStream
     307   **/
     308  GInputStream *
     309  g_win32_input_stream_new (void     *handle,
     310  			  gboolean close_handle)
     311  {
     312    GWin32InputStream *stream;
     313  
     314    g_return_val_if_fail (handle != NULL, NULL);
     315  
     316    stream = g_object_new (G_TYPE_WIN32_INPUT_STREAM,
     317  			 "handle", handle,
     318  			 "close-handle", close_handle,
     319  			 NULL);
     320  
     321    return G_INPUT_STREAM (stream);
     322  }
     323  
     324  /**
     325   * g_win32_input_stream_set_close_handle:
     326   * @stream: a #GWin32InputStream
     327   * @close_handle: %TRUE to close the handle when done
     328   *
     329   * Sets whether the handle of @stream shall be closed
     330   * when the stream is closed.
     331   *
     332   * Since: 2.26
     333   */
     334  void
     335  g_win32_input_stream_set_close_handle (GWin32InputStream *stream,
     336  				       gboolean          close_handle)
     337  {
     338    g_return_if_fail (G_IS_WIN32_INPUT_STREAM (stream));
     339  
     340    close_handle = close_handle != FALSE;
     341    if (stream->priv->close_handle != close_handle)
     342      {
     343        stream->priv->close_handle = close_handle;
     344        g_object_notify (G_OBJECT (stream), "close-handle");
     345      }
     346  }
     347  
     348  /**
     349   * g_win32_input_stream_get_close_handle:
     350   * @stream: a #GWin32InputStream
     351   *
     352   * Returns whether the handle of @stream will be
     353   * closed when the stream is closed.
     354   *
     355   * Returns: %TRUE if the handle is closed when done
     356   *
     357   * Since: 2.26
     358   */
     359  gboolean
     360  g_win32_input_stream_get_close_handle (GWin32InputStream *stream)
     361  {
     362    g_return_val_if_fail (G_IS_WIN32_INPUT_STREAM (stream), FALSE);
     363  
     364    return stream->priv->close_handle;
     365  }
     366  
     367  /**
     368   * g_win32_input_stream_get_handle:
     369   * @stream: a #GWin32InputStream
     370   *
     371   * Return the Windows file handle that the stream reads from.
     372   *
     373   * Returns: The file handle of @stream
     374   *
     375   * Since: 2.26
     376   */
     377  void *
     378  g_win32_input_stream_get_handle (GWin32InputStream *stream)
     379  {
     380    g_return_val_if_fail (G_IS_WIN32_INPUT_STREAM (stream), NULL);
     381  
     382    return stream->priv->handle;
     383  }
     384  
     385  GInputStream *
     386  g_win32_input_stream_new_from_fd (gint      fd,
     387  				  gboolean  close_fd)
     388  {
     389    GWin32InputStream *win32_stream;
     390  
     391    win32_stream = G_WIN32_INPUT_STREAM (g_win32_input_stream_new ((HANDLE) _get_osfhandle (fd), close_fd));
     392    win32_stream->priv->fd = fd;
     393  
     394    return (GInputStream*)win32_stream;
     395  }