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