[kdbus] KDBUS_ITEM_PAYLOAD_OFF items are (once again) relative to msg header
[platform/upstream/glib.git] / gio / gwin32inputstream.c
index a545981..179e139 100644 (file)
@@ -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>
@@ -31,6 +29,7 @@
 #include "gioerror.h"
 #include "gsimpleasyncresult.h"
 #include "gwin32inputstream.h"
+#include "giowin32-priv.h"
 #include "gcancellable.h"
 #include "gasynchelper.h"
 #include "glibintl.h"
@@ -45,9 +44,9 @@
  * #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 {
@@ -56,13 +55,14 @@ enum {
   PROP_CLOSE_HANDLE
 };
 
-G_DEFINE_TYPE (GWin32InputStream, g_win32_input_stream, G_TYPE_INPUT_STREAM);
-
 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,
@@ -81,22 +81,13 @@ static gboolean g_win32_input_stream_close        (GInputStream         *stream,
                                                   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;
@@ -181,20 +172,18 @@ g_win32_input_stream_get_property (GObject    *object,
 static void
 g_win32_input_stream_init (GWin32InputStream *win32_stream)
 {
-  win32_stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (win32_stream,
-                                                   G_TYPE_WIN32_INPUT_STREAM,
-                                                   GWin32InputStreamPrivate);
-
+  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.
@@ -251,7 +240,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
  */
@@ -269,7 +258,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
  */
@@ -291,6 +280,8 @@ g_win32_input_stream_read (GInputStream  *stream,
   GWin32InputStream *win32_stream;
   BOOL res;
   DWORD nbytes, nread;
+  OVERLAPPED overlap = { 0, };
+  gssize retval = -1;
 
   win32_stream = G_WIN32_INPUT_STREAM (stream);
 
@@ -302,26 +293,63 @@ g_win32_input_stream_read (GInputStream  *stream,
   else
     nbytes = count;
 
-  res = ReadFile (win32_stream->priv->handle, buffer, nbytes, &nread, NULL);
-  if (!res)
+  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 ();
-      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;
+
+      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);
+        }
     }
 
-  return nread;
+end:
+  CloseHandle (overlap.hEvent);
+  return retval;
 }
 
 static gboolean
@@ -337,19 +365,44 @@ g_win32_input_stream_close (GInputStream  *stream,
   if (!win32_stream->priv->close_handle)
     return TRUE;
 
-  res = CloseHandle (win32_stream->priv->handle);
-  if (!res)
+  if (win32_stream->priv->fd != -1)
     {
-      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;
+      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;
+}