glib/gio/gwin32inputstream.c
Matthias Clasen 35066ed6c6 Docs: Drop entities, switch away from sgml mode
Since all element markup is now gone from the doc comments,
we can turn off the gtk-doc sgml mode, which means that from
now on, docbook markup is no longer allowed in doc comments.

To make this possible, we have to replace all remaining
entities in doc comments by their replacement text, & -> &
and so on.
2014-02-09 02:07:26 -05:00

409 lines
11 KiB
C

/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2006-2010 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Alexander Larsson <alexl@redhat.com>
* Author: Tor Lillqvist <tml@iki.fi>
*/
#include "config.h"
#include <windows.h>
#include <io.h>
#include <glib.h>
#include "gioerror.h"
#include "gsimpleasyncresult.h"
#include "gwin32inputstream.h"
#include "giowin32-priv.h"
#include "gcancellable.h"
#include "gasynchelper.h"
#include "glibintl.h"
/**
* SECTION:gwin32inputstream
* @short_description: Streaming input operations for Windows file handles
* @include: gio/gwin32inputstream.h
* @see_also: #GInputStream
*
* #GWin32InputStream implements #GInputStream for reading from a
* Windows file handle.
*
* Note that `<gio/gwin32inputstream.h>` belongs to the Windows-specific GIO
* interfaces, thus you have to use the `gio-windows-2.0.pc` pkg-config file
* when using it.
*/
enum {
PROP_0,
PROP_HANDLE,
PROP_CLOSE_HANDLE
};
struct _GWin32InputStreamPrivate {
HANDLE handle;
gboolean close_handle;
gint fd;
};
G_DEFINE_TYPE_WITH_PRIVATE (GWin32InputStream, g_win32_input_stream, G_TYPE_INPUT_STREAM)
static void g_win32_input_stream_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void g_win32_input_stream_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static gssize g_win32_input_stream_read (GInputStream *stream,
void *buffer,
gsize count,
GCancellable *cancellable,
GError **error);
static gboolean g_win32_input_stream_close (GInputStream *stream,
GCancellable *cancellable,
GError **error);
static void
g_win32_input_stream_class_init (GWin32InputStreamClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
gobject_class->get_property = g_win32_input_stream_get_property;
gobject_class->set_property = g_win32_input_stream_set_property;
stream_class->read_fn = g_win32_input_stream_read;
stream_class->close_fn = g_win32_input_stream_close;
/**
* GWin32InputStream:handle:
*
* The handle that the stream reads from.
*
* Since: 2.26
*/
g_object_class_install_property (gobject_class,
PROP_HANDLE,
g_param_spec_pointer ("handle",
P_("File handle"),
P_("The file handle to read from"),
G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
/**
* GWin32InputStream:close-handle:
*
* Whether to close the file handle when the stream is closed.
*
* Since: 2.26
*/
g_object_class_install_property (gobject_class,
PROP_CLOSE_HANDLE,
g_param_spec_boolean ("close-handle",
P_("Close file handle"),
P_("Whether to close the file handle when the stream is closed"),
TRUE,
G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
}
static void
g_win32_input_stream_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GWin32InputStream *win32_stream;
win32_stream = G_WIN32_INPUT_STREAM (object);
switch (prop_id)
{
case PROP_HANDLE:
win32_stream->priv->handle = g_value_get_pointer (value);
break;
case PROP_CLOSE_HANDLE:
win32_stream->priv->close_handle = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
g_win32_input_stream_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GWin32InputStream *win32_stream;
win32_stream = G_WIN32_INPUT_STREAM (object);
switch (prop_id)
{
case PROP_HANDLE:
g_value_set_pointer (value, win32_stream->priv->handle);
break;
case PROP_CLOSE_HANDLE:
g_value_set_boolean (value, win32_stream->priv->close_handle);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
g_win32_input_stream_init (GWin32InputStream *win32_stream)
{
win32_stream->priv = g_win32_input_stream_get_instance_private (win32_stream);
win32_stream->priv->handle = NULL;
win32_stream->priv->close_handle = TRUE;
win32_stream->priv->fd = -1;
}
/**
* g_win32_input_stream_new:
* @handle: a Win32 file handle
* @close_handle: %TRUE to close the handle when done
*
* Creates a new #GWin32InputStream for the given @handle.
*
* If @close_handle is %TRUE, the handle will be closed
* when the stream is closed.
*
* Note that "handle" here means a Win32 HANDLE, not a "file descriptor"
* as used in the Windows C libraries.
*
* Returns: a new #GWin32InputStream
**/
GInputStream *
g_win32_input_stream_new (void *handle,
gboolean close_handle)
{
GWin32InputStream *stream;
g_return_val_if_fail (handle != NULL, NULL);
stream = g_object_new (G_TYPE_WIN32_INPUT_STREAM,
"handle", handle,
"close-handle", close_handle,
NULL);
return G_INPUT_STREAM (stream);
}
/**
* g_win32_input_stream_set_close_handle:
* @stream: a #GWin32InputStream
* @close_handle: %TRUE to close the handle when done
*
* Sets whether the handle of @stream shall be closed
* when the stream is closed.
*
* Since: 2.26
*/
void
g_win32_input_stream_set_close_handle (GWin32InputStream *stream,
gboolean close_handle)
{
g_return_if_fail (G_IS_WIN32_INPUT_STREAM (stream));
close_handle = close_handle != FALSE;
if (stream->priv->close_handle != close_handle)
{
stream->priv->close_handle = close_handle;
g_object_notify (G_OBJECT (stream), "close-handle");
}
}
/**
* g_win32_input_stream_get_close_handle:
* @stream: a #GWin32InputStream
*
* Returns whether the handle of @stream will be
* closed when the stream is closed.
*
* Return value: %TRUE if the handle is closed when done
*
* Since: 2.26
*/
gboolean
g_win32_input_stream_get_close_handle (GWin32InputStream *stream)
{
g_return_val_if_fail (G_IS_WIN32_INPUT_STREAM (stream), FALSE);
return stream->priv->close_handle;
}
/**
* g_win32_input_stream_get_handle:
* @stream: a #GWin32InputStream
*
* Return the Windows file handle that the stream reads from.
*
* Return value: The file handle of @stream
*
* Since: 2.26
*/
void *
g_win32_input_stream_get_handle (GWin32InputStream *stream)
{
g_return_val_if_fail (G_IS_WIN32_INPUT_STREAM (stream), NULL);
return stream->priv->handle;
}
static gssize
g_win32_input_stream_read (GInputStream *stream,
void *buffer,
gsize count,
GCancellable *cancellable,
GError **error)
{
GWin32InputStream *win32_stream;
BOOL res;
DWORD nbytes, nread;
OVERLAPPED overlap = { 0, };
gssize retval = -1;
win32_stream = G_WIN32_INPUT_STREAM (stream);
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return -1;
if (count > G_MAXINT)
nbytes = G_MAXINT;
else
nbytes = count;
overlap.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
g_return_val_if_fail (overlap.hEvent != NULL, -1);
res = ReadFile (win32_stream->priv->handle, buffer, nbytes, &nread, &overlap);
if (res)
retval = nread;
else
{
int errsv = GetLastError ();
if (errsv == ERROR_IO_PENDING &&
_g_win32_overlap_wait_result (win32_stream->priv->handle,
&overlap, &nread, cancellable))
{
retval = nread;
goto end;
}
if (g_cancellable_set_error_if_cancelled (cancellable, error))
goto end;
errsv = GetLastError ();
if (errsv == ERROR_MORE_DATA)
{
/* If a named pipe is being read in message mode and the
* next message is longer than the nNumberOfBytesToRead
* parameter specifies, ReadFile returns FALSE and
* GetLastError returns ERROR_MORE_DATA */
retval = nread;
goto end;
}
else if (errsv == ERROR_HANDLE_EOF ||
errsv == ERROR_BROKEN_PIPE)
{
/* TODO: the other end of a pipe may call the WriteFile
* function with nNumberOfBytesToWrite set to zero. In this
* case, it's not possible for the caller to know if it's
* broken pipe or a read of 0. Perhaps we should add a
* is_broken flag for this win32 case.. */
retval = 0;
}
else
{
gchar *emsg;
emsg = g_win32_error_message (errsv);
g_set_error (error, G_IO_ERROR,
g_io_error_from_win32_error (errsv),
_("Error reading from handle: %s"),
emsg);
g_free (emsg);
}
}
end:
CloseHandle (overlap.hEvent);
return retval;
}
static gboolean
g_win32_input_stream_close (GInputStream *stream,
GCancellable *cancellable,
GError **error)
{
GWin32InputStream *win32_stream;
BOOL res;
win32_stream = G_WIN32_INPUT_STREAM (stream);
if (!win32_stream->priv->close_handle)
return TRUE;
if (win32_stream->priv->fd != -1)
{
if (close (win32_stream->priv->fd) < 0)
{
g_set_error_literal (error, G_IO_ERROR,
g_io_error_from_errno (errno),
g_strerror (errno));
return FALSE;
}
}
else
{
res = CloseHandle (win32_stream->priv->handle);
if (!res)
{
int errsv = GetLastError ();
gchar *emsg = g_win32_error_message (errsv);
g_set_error (error, G_IO_ERROR,
g_io_error_from_win32_error (errsv),
_("Error closing handle: %s"),
emsg);
g_free (emsg);
return FALSE;
}
}
return TRUE;
}
GInputStream *
g_win32_input_stream_new_from_fd (gint fd,
gboolean close_fd)
{
GWin32InputStream *win32_stream;
win32_stream = G_WIN32_INPUT_STREAM (g_win32_input_stream_new ((HANDLE) _get_osfhandle (fd), close_fd));
win32_stream->priv->fd = fd;
return (GInputStream*)win32_stream;
}