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