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