(root)/
glib-2.79.0/
gio/
gwin32outputstream.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 <glib/gstdio.h>
      32  #include "gioerror.h"
      33  #include "gwin32outputstream.h"
      34  #include "giowin32-priv.h"
      35  #include "gcancellable.h"
      36  #include "gasynchelper.h"
      37  #include "glibintl.h"
      38  
      39  /**
      40   * GWin32OutputStream:
      41   *
      42   * `GWin32OutputStream` implements [class@Gio.OutputStream] for writing to a
      43   * Windows file handle.
      44   *
      45   * Note that `<gio/gwin32outputstream.h>` belongs to the Windows-specific GIO
      46   * interfaces, thus you have to use the `gio-windows-2.0.pc` pkg-config file
      47   * when using it.
      48   */
      49  
      50  struct _GWin32OutputStreamPrivate {
      51    HANDLE handle;
      52    gboolean close_handle;
      53    gint fd;
      54  };
      55  
      56  enum {
      57    PROP_0,
      58    PROP_HANDLE,
      59    PROP_CLOSE_HANDLE,
      60    LAST_PROP
      61  };
      62  
      63  static GParamSpec *props[LAST_PROP];
      64  
      65  G_DEFINE_TYPE_WITH_PRIVATE (GWin32OutputStream, g_win32_output_stream, G_TYPE_OUTPUT_STREAM)
      66  
      67  static void
      68  g_win32_output_stream_set_property (GObject         *object,
      69  				    guint            prop_id,
      70  				    const GValue    *value,
      71  				    GParamSpec      *pspec)
      72  {
      73    GWin32OutputStream *win32_stream;
      74  
      75    win32_stream = G_WIN32_OUTPUT_STREAM (object);
      76  
      77    switch (prop_id)
      78      {
      79      case PROP_HANDLE:
      80        win32_stream->priv->handle = g_value_get_pointer (value);
      81        break;
      82      case PROP_CLOSE_HANDLE:
      83        win32_stream->priv->close_handle = g_value_get_boolean (value);
      84        break;
      85      default:
      86        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      87        break;
      88      }
      89  }
      90  
      91  static void
      92  g_win32_output_stream_get_property (GObject    *object,
      93  				    guint       prop_id,
      94  				    GValue     *value,
      95  				    GParamSpec *pspec)
      96  {
      97    GWin32OutputStream *win32_stream;
      98  
      99    win32_stream = G_WIN32_OUTPUT_STREAM (object);
     100  
     101    switch (prop_id)
     102      {
     103      case PROP_HANDLE:
     104        g_value_set_pointer (value, win32_stream->priv->handle);
     105        break;
     106      case PROP_CLOSE_HANDLE:
     107        g_value_set_boolean (value, win32_stream->priv->close_handle);
     108        break;
     109      default:
     110        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     111      }
     112  }
     113  
     114  static gssize
     115  g_win32_output_stream_write (GOutputStream  *stream,
     116  			    const void     *buffer,
     117  			    gsize           count,
     118  			    GCancellable   *cancellable,
     119  			    GError        **error)
     120  {
     121    GWin32OutputStream *win32_stream;
     122    BOOL res;
     123    DWORD nbytes, nwritten;
     124    OVERLAPPED overlap = { 0, };
     125    gssize retval = -1;
     126  
     127    win32_stream = G_WIN32_OUTPUT_STREAM (stream);
     128  
     129    if (g_cancellable_set_error_if_cancelled (cancellable, error))
     130      return -1;
     131  
     132    if (count > G_MAXINT)
     133      nbytes = G_MAXINT;
     134    else
     135      nbytes = count;
     136  
     137    overlap.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
     138    g_return_val_if_fail (overlap.hEvent != NULL, -1);
     139  
     140    res = WriteFile (win32_stream->priv->handle, buffer, nbytes, &nwritten, &overlap);
     141    if (res)
     142      retval = nwritten;
     143    else
     144      {
     145        int errsv = GetLastError ();
     146  
     147        if (errsv == ERROR_IO_PENDING &&
     148            _g_win32_overlap_wait_result (win32_stream->priv->handle,
     149                                          &overlap, &nwritten, cancellable))
     150          {
     151            retval = nwritten;
     152            goto end;
     153          }
     154  
     155        if (g_cancellable_set_error_if_cancelled (cancellable, error))
     156          goto end;
     157  
     158        errsv = GetLastError ();
     159        if (errsv == ERROR_HANDLE_EOF ||
     160            errsv == ERROR_BROKEN_PIPE)
     161          {
     162            retval = 0;
     163          }
     164        else
     165          {
     166            gchar *emsg;
     167  
     168            emsg = g_win32_error_message (errsv);
     169            g_set_error (error, G_IO_ERROR,
     170                         g_io_error_from_win32_error (errsv),
     171                         _("Error writing to handle: %s"),
     172                         emsg);
     173            g_free (emsg);
     174          }
     175      }
     176  
     177  end:
     178    CloseHandle (overlap.hEvent);
     179    return retval;
     180  }
     181  
     182  static gboolean
     183  g_win32_output_stream_close (GOutputStream  *stream,
     184  			     GCancellable   *cancellable,
     185  			     GError        **error)
     186  {
     187    GWin32OutputStream *win32_stream;
     188    BOOL res;
     189  
     190    win32_stream = G_WIN32_OUTPUT_STREAM (stream);
     191  
     192    if (!win32_stream->priv->close_handle)
     193      return TRUE;
     194  
     195    if (win32_stream->priv->fd != -1)
     196      {
     197        if (close (win32_stream->priv->fd) < 0)
     198  	{
     199  	  int errsv = errno;
     200  
     201  	  g_set_error (error, G_IO_ERROR,
     202  	               g_io_error_from_errno (errsv),
     203  	               _("Error closing file descriptor: %s"),
     204  	               g_strerror (errsv));
     205  	  return FALSE;
     206  	}
     207      }
     208    else
     209      {
     210        res = CloseHandle (win32_stream->priv->handle);
     211        if (!res)
     212  	{
     213  	  int errsv = GetLastError ();
     214  	  gchar *emsg = g_win32_error_message (errsv);
     215  
     216  	  g_set_error (error, G_IO_ERROR,
     217  		       g_io_error_from_win32_error (errsv),
     218  		       _("Error closing handle: %s"),
     219  		       emsg);
     220  	  g_free (emsg);
     221  	  return FALSE;
     222  	}
     223      }
     224  
     225    return TRUE;
     226  }
     227  
     228  static void
     229  g_win32_output_stream_class_init (GWin32OutputStreamClass *klass)
     230  {
     231    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     232    GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);
     233  
     234    gobject_class->get_property = g_win32_output_stream_get_property;
     235    gobject_class->set_property = g_win32_output_stream_set_property;
     236  
     237    stream_class->write_fn = g_win32_output_stream_write;
     238    stream_class->close_fn = g_win32_output_stream_close;
     239  
     240     /**
     241     * GWin32OutputStream:handle:
     242     *
     243     * The file handle that the stream writes to.
     244     *
     245     * Since: 2.26
     246     */
     247    props[PROP_HANDLE] =
     248      g_param_spec_pointer ("handle", NULL, NULL,
     249                            G_PARAM_READABLE |
     250                            G_PARAM_WRITABLE |
     251                            G_PARAM_CONSTRUCT_ONLY |
     252                            G_PARAM_STATIC_STRINGS);
     253  
     254    /**
     255     * GWin32OutputStream:close-handle:
     256     *
     257     * Whether to close the file handle when the stream is closed.
     258     *
     259     * Since: 2.26
     260     */
     261    props[PROP_CLOSE_HANDLE] =
     262      g_param_spec_boolean ("close-handle", NULL, NULL,
     263                            TRUE,
     264                            G_PARAM_READABLE |
     265                            G_PARAM_WRITABLE |
     266                            G_PARAM_STATIC_STRINGS);
     267  
     268    g_object_class_install_properties (gobject_class, LAST_PROP, props);
     269  }
     270  
     271  static void
     272  g_win32_output_stream_init (GWin32OutputStream *win32_stream)
     273  {
     274    win32_stream->priv = g_win32_output_stream_get_instance_private (win32_stream);
     275    win32_stream->priv->handle = NULL;
     276    win32_stream->priv->close_handle = TRUE;
     277    win32_stream->priv->fd = -1;
     278  }
     279  
     280  /**
     281   * g_win32_output_stream_new:
     282   * @handle: a Win32 file handle
     283   * @close_handle: %TRUE to close the handle when done
     284   *
     285   * Creates a new #GWin32OutputStream for the given @handle.
     286   *
     287   * If @close_handle, is %TRUE, the handle will be closed when the
     288   * output stream is destroyed.
     289   *
     290   * Returns: a new #GOutputStream
     291   *
     292   * Since: 2.26
     293  **/
     294  GOutputStream *
     295  g_win32_output_stream_new (void    *handle,
     296  			   gboolean close_handle)
     297  {
     298    GWin32OutputStream *stream;
     299  
     300    g_return_val_if_fail (handle != NULL, NULL);
     301  
     302    stream = g_object_new (G_TYPE_WIN32_OUTPUT_STREAM,
     303  			 "handle", handle,
     304  			 "close-handle", close_handle,
     305  			 NULL);
     306  
     307    return G_OUTPUT_STREAM (stream);
     308  }
     309  
     310  /**
     311   * g_win32_output_stream_set_close_handle:
     312   * @stream: a #GWin32OutputStream
     313   * @close_handle: %TRUE to close the handle when done
     314   *
     315   * Sets whether the handle of @stream shall be closed when the stream
     316   * is closed.
     317   *
     318   * Since: 2.26
     319   */
     320  void
     321  g_win32_output_stream_set_close_handle (GWin32OutputStream *stream,
     322  					gboolean           close_handle)
     323  {
     324    g_return_if_fail (G_IS_WIN32_OUTPUT_STREAM (stream));
     325  
     326    close_handle = close_handle != FALSE;
     327    if (stream->priv->close_handle != close_handle)
     328      {
     329        stream->priv->close_handle = close_handle;
     330        g_object_notify (G_OBJECT (stream), "close-handle");
     331      }
     332  }
     333  
     334  /**
     335   * g_win32_output_stream_get_close_handle:
     336   * @stream: a #GWin32OutputStream
     337   *
     338   * Returns whether the handle of @stream will be closed when the
     339   * stream is closed.
     340   *
     341   * Returns: %TRUE if the handle is closed when done
     342   *
     343   * Since: 2.26
     344   */
     345  gboolean
     346  g_win32_output_stream_get_close_handle (GWin32OutputStream *stream)
     347  {
     348    g_return_val_if_fail (G_IS_WIN32_OUTPUT_STREAM (stream), FALSE);
     349  
     350    return stream->priv->close_handle;
     351  }
     352  
     353  /**
     354   * g_win32_output_stream_get_handle:
     355   * @stream: a #GWin32OutputStream
     356   *
     357   * Return the Windows handle that the stream writes to.
     358   *
     359   * Returns: The handle descriptor of @stream
     360   *
     361   * Since: 2.26
     362   */
     363  void *
     364  g_win32_output_stream_get_handle (GWin32OutputStream *stream)
     365  {
     366    g_return_val_if_fail (G_IS_WIN32_OUTPUT_STREAM (stream), NULL);
     367  
     368    return stream->priv->handle;
     369  }
     370  
     371  GOutputStream *
     372  g_win32_output_stream_new_from_fd (gint      fd,
     373                                     gboolean  close_fd)
     374  {
     375    GWin32OutputStream *win32_stream;
     376  
     377    win32_stream = G_WIN32_OUTPUT_STREAM (g_win32_output_stream_new ((HANDLE) _get_osfhandle (fd), close_fd));
     378    win32_stream->priv->fd = fd;
     379  
     380    return (GOutputStream*)win32_stream;
     381  }