Imported Upstream version 2.66.6
[platform/upstream/glib.git] / gio / gwin32inputstream.c
index 3cfe5cc..5649af1 100644 (file)
@@ -5,7 +5,7 @@
  * 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.
+ * version 2.1 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
@@ -13,9 +13,7 @@
  * 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, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
+ * 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 <glib.h>
 #include "gioerror.h"
-#include "gsimpleasyncresult.h"
 #include "gwin32inputstream.h"
+#include "giowin32-priv.h"
 #include "gcancellable.h"
 #include "gasynchelper.h"
 #include "glibintl.h"
 
-#include "gioalias.h"
-
 /**
  * SECTION:gwin32inputstream
  * @short_description: Streaming input operations for Windows file handles
  * #GWin32InputStream implements #GInputStream for reading from a
  * Windows file handle.
  *
- * Note that <filename>&lt;gio/gwin32inputstream.h&gt;</filename> belongs
- * to the Windows-specific GIO interfaces, thus you have to use the
- * <filename>gio-windows-2.0.pc</filename> pkg-config file when using it.
+ * 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
-};
-
-G_DEFINE_TYPE (GWin32InputStream, g_win32_input_stream, G_TYPE_INPUT_STREAM);
-
 struct _GWin32InputStreamPrivate {
   HANDLE handle;
   gboolean close_handle;
+  gint fd;
 };
 
-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_finalize (GObject *object)
-{
-  G_OBJECT_CLASS (g_win32_input_stream_parent_class)->finalize (object);
-}
-
-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);
-
-  g_type_class_add_private (klass, sizeof (GWin32InputStreamPrivate));
-
-  gobject_class->get_property = g_win32_input_stream_get_property;
-  gobject_class->set_property = g_win32_input_stream_set_property;
-  gobject_class->finalize = g_win32_input_stream_finalize;
-
-  stream_class->read_fn = g_win32_input_stream_read;
-  stream_class->close_fn = g_win32_input_stream_close;
+enum {
+  PROP_0,
+  PROP_HANDLE,
+  PROP_CLOSE_HANDLE,
+  LAST_PROP
+};
 
-  /**
-   * 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));
+static GParamSpec *props[LAST_PROP];
 
-  /**
-   * 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));
-}
+G_DEFINE_TYPE_WITH_PRIVATE (GWin32InputStream, g_win32_input_stream, G_TYPE_INPUT_STREAM)
 
 static void
 g_win32_input_stream_set_property (GObject         *object,
@@ -179,23 +111,196 @@ g_win32_input_stream_get_property (GObject    *object,
     }
 }
 
+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)
+       {
+         int errsv = errno;
+
+         g_set_error (error, G_IO_ERROR,
+                      g_io_error_from_errno (errsv),
+                      _("Error closing file descriptor: %s"),
+                      g_strerror (errsv));
+         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;
+}
+
 static void
-g_win32_input_stream_init (GWin32InputStream *win32_stream)
+g_win32_input_stream_class_init (GWin32InputStreamClass *klass)
 {
-  win32_stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (win32_stream,
-                                                   G_TYPE_WIN32_INPUT_STREAM,
-                                                   GWin32InputStreamPrivate);
+  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
+   */
+  props[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_STRINGS);
 
+  /**
+   * GWin32InputStream:close-handle:
+   *
+   * Whether to close the file handle when the stream is closed.
+   *
+   * Since: 2.26
+   */
+  props[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_STRINGS);
+
+  g_object_class_install_properties (gobject_class, LAST_PROP, props);
+}
+
+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_fd: %TRUE to close the handle when done
+ * @close_handle: %TRUE to close the handle when done
  *
- * Creates a new #GWin32InputStream for the given @fd.
+ * Creates a new #GWin32InputStream for the given @handle.
  *
  * If @close_handle is %TRUE, the handle will be closed
  * when the stream is closed.
@@ -252,7 +357,7 @@ g_win32_input_stream_set_close_handle (GWin32InputStream *stream,
  * Returns whether the handle of @stream will be
  * closed when the stream is closed.
  *
- * Return value: %TRUE if the handle is closed when done
+ * Returns: %TRUE if the handle is closed when done
  *
  * Since: 2.26
  */
@@ -270,7 +375,7 @@ g_win32_input_stream_get_close_handle (GWin32InputStream *stream)
  *
  * Return the Windows file handle that the stream reads from.
  *
- * Return value: The file handle of @stream
+ * Returns: The file handle of @stream
  *
  * Since: 2.26
  */
@@ -282,78 +387,14 @@ g_win32_input_stream_get_handle (GWin32InputStream *stream)
   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;
-
-  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;
-
-  res = ReadFile (win32_stream->priv->handle, buffer, nbytes, &nread, NULL);
-  if (!res)
-    {
-      int errsv = GetLastError ();
-      gchar *emsg;
-
-      if (errsv == ERROR_HANDLE_EOF ||
-         errsv == ERROR_BROKEN_PIPE)
-       return 0;
-
-      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);
-      return -1;
-    }
-
-  return nread;
-}
-
-static gboolean
-g_win32_input_stream_close (GInputStream  *stream,
-                          GCancellable  *cancellable,
-                          GError       **error)
+GInputStream *
+g_win32_input_stream_new_from_fd (gint      fd,
+                                 gboolean  close_fd)
 {
   GWin32InputStream *win32_stream;
-  BOOL res;
 
-  win32_stream = G_WIN32_INPUT_STREAM (stream);
-
-  if (!win32_stream->priv->close_handle)
-    return TRUE;
-
-  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;
-    }
+  win32_stream = G_WIN32_INPUT_STREAM (g_win32_input_stream_new ((HANDLE) _get_osfhandle (fd), close_fd));
+  win32_stream->priv->fd = fd;
 
-  return TRUE;
+  return (GInputStream*)win32_stream;
 }
-
-#define __G_WIN32_INPUT_STREAM_C__
-#include "gioaliasdef.c"