Branch data Line data Source code
1 : : /* GLIB - Library of useful routines for C programming
2 : : * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 : : *
4 : : * giowin32.c: IO Channels for Win32.
5 : : * Copyright 1998 Owen Taylor and Tor Lillqvist
6 : : * Copyright 1999-2000 Tor Lillqvist and Craig Setera
7 : : * Copyright 2001-2003 Andrew Lanoix
8 : : *
9 : : * SPDX-License-Identifier: LGPL-2.1-or-later
10 : : *
11 : : * This library is free software; you can redistribute it and/or
12 : : * modify it under the terms of the GNU Lesser General Public
13 : : * License as published by the Free Software Foundation; either
14 : : * version 2.1 of the License, or (at your option) any later version.
15 : : *
16 : : * This library is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 : : * Lesser General Public License for more details.
20 : : *
21 : : * You should have received a copy of the GNU Lesser General Public
22 : : * License along with this library; if not, see <http://www.gnu.org/licenses/>.
23 : : */
24 : :
25 : : /*
26 : : * Modified by the GLib Team and others 1997-2000. See the AUTHORS
27 : : * file for a list of people on the GLib Team. See the ChangeLog
28 : : * files for a list of changes. These files are distributed with
29 : : * GLib at ftp://ftp.gtk.org/pub/gtk/.
30 : : */
31 : :
32 : : /*
33 : : * Bugs that are related to the code in this file:
34 : : *
35 : : * Bug 137968 - Sometimes a GIOFunc on Win32 is called with zero condition
36 : : * http://bugzilla.gnome.org/show_bug.cgi?id=137968
37 : : *
38 : : * Bug 324234 - Using g_io_add_watch_full() to wait for connect() to return on a non-blocking socket returns prematurely
39 : : * http://bugzilla.gnome.org/show_bug.cgi?id=324234
40 : : *
41 : : * Bug 331214 - g_io_channel async socket io stalls
42 : : * http://bugzilla.gnome.org/show_bug.cgi?id=331214
43 : : *
44 : : * Bug 338943 - Multiple watches on the same socket
45 : : * http://bugzilla.gnome.org/show_bug.cgi?id=338943
46 : : *
47 : : * Bug 357674 - 2 serious bugs in giowin32.c making glib iochannels useless
48 : : * http://bugzilla.gnome.org/show_bug.cgi?id=357674
49 : : *
50 : : * Bug 425156 - GIOChannel deadlocks on a win32 socket
51 : : * http://bugzilla.gnome.org/show_bug.cgi?id=425156
52 : : *
53 : : * Bug 468910 - giofunc condition=0
54 : : * http://bugzilla.gnome.org/show_bug.cgi?id=468910
55 : : *
56 : : * Bug 500246 - Bug fixes for giowin32
57 : : * http://bugzilla.gnome.org/show_bug.cgi?id=500246
58 : : *
59 : : * Bug 548278 - Async GETs connections are always terminated unexpectedly on windows
60 : : * http://bugzilla.gnome.org/show_bug.cgi?id=548278
61 : : *
62 : : * Bug 548536 - giowin32 problem when adding and removing watches
63 : : * http://bugzilla.gnome.org/show_bug.cgi?id=548536
64 : : *
65 : : * When fixing bugs related to the code in this file, either the above
66 : : * bugs or others, make sure that the test programs attached to the
67 : : * above bugs continue to work.
68 : : */
69 : :
70 : : #include "config.h"
71 : :
72 : : #include "glib.h"
73 : :
74 : : #include <stdlib.h>
75 : : #include <winsock2.h>
76 : : #include <windows.h>
77 : : #include <conio.h>
78 : : #include <fcntl.h>
79 : : #include <io.h>
80 : : #include <process.h>
81 : : #include <errno.h>
82 : : #include <sys/stat.h>
83 : :
84 : : #include "gstdio.h"
85 : : #include "glibintl.h"
86 : :
87 : :
88 : : typedef struct _GIOWin32Channel GIOWin32Channel;
89 : : typedef struct _GIOWin32Watch GIOWin32Watch;
90 : :
91 : : #define BUFFER_SIZE 4096
92 : :
93 : : typedef enum {
94 : : G_IO_WIN32_WINDOWS_MESSAGES, /* Windows messages */
95 : :
96 : : G_IO_WIN32_FILE_DESC, /* Unix-like file descriptors from
97 : : * _open() or _pipe(), except for
98 : : * console IO. Separate thread to read
99 : : * or write.
100 : : */
101 : :
102 : : G_IO_WIN32_CONSOLE, /* Console IO (usually stdin, stdout, stderr) */
103 : :
104 : : G_IO_WIN32_SOCKET /* Sockets. No separate thread. */
105 : : } GIOWin32ChannelType;
106 : :
107 : : struct _GIOWin32Channel {
108 : : GIOChannel channel;
109 : : gint fd; /* Either a Unix-like file handle as provided
110 : : * by the Microsoft C runtime, or a SOCKET
111 : : * as provided by WinSock.
112 : : */
113 : : GIOWin32ChannelType type;
114 : :
115 : : gboolean debug;
116 : :
117 : : /* Field used by G_IO_WIN32_WINDOWS_MESSAGES channels */
118 : : HWND hwnd; /* Handle of window, or NULL */
119 : :
120 : : /* Fields used by G_IO_WIN32_FILE_DESC channels. */
121 : : CRITICAL_SECTION mutex;
122 : :
123 : : int direction; /* 0 means we read from it,
124 : : * 1 means we write to it.
125 : : */
126 : :
127 : : gboolean running; /* Is reader or writer thread
128 : : * running. FALSE if EOF has been
129 : : * reached by the reader thread.
130 : : */
131 : :
132 : : gboolean needs_close; /* If the channel has been closed while
133 : : * the reader thread was still running.
134 : : */
135 : :
136 : : guint thread_id; /* If non-NULL the channel has or has
137 : : * had a reader or writer thread.
138 : : */
139 : : HANDLE data_avail_event;
140 : :
141 : : gushort revents;
142 : :
143 : : /* Data is kept in a circular buffer. To be able to distinguish between
144 : : * empty and full buffers, we cannot fill it completely, but have to
145 : : * leave a one character gap.
146 : : *
147 : : * Data available is between indexes rdp and wrp-1 (modulo BUFFER_SIZE).
148 : : *
149 : : * Empty: wrp == rdp
150 : : * Full: (wrp + 1) % BUFFER_SIZE == rdp
151 : : * Partial: otherwise
152 : : */
153 : : guchar *buffer; /* (Circular) buffer */
154 : : gint wrp, rdp; /* Buffer indices for writing and reading */
155 : : HANDLE space_avail_event;
156 : :
157 : : /* Fields used by G_IO_WIN32_SOCKET channels */
158 : : int event_mask;
159 : : int last_events;
160 : : HANDLE event;
161 : : gboolean write_would_have_blocked;
162 : : gboolean ever_writable;
163 : : };
164 : :
165 : : struct _GIOWin32Watch {
166 : : GSource source;
167 : : GPollFD pollfd;
168 : : GIOChannel *channel;
169 : : GIOCondition condition;
170 : : };
171 : :
172 : : static void
173 : 0 : g_win32_print_access_mode (int flags)
174 : : {
175 : 0 : g_print ("%s%s%s%s%s%s%s%s%s%s",
176 : 0 : ((flags & 0x3) == _O_RDWR ? "O_RDWR" :
177 : 0 : ((flags & 0x3) == _O_RDONLY ? "O_RDONLY" :
178 : 0 : ((flags & 0x3) == _O_WRONLY ? "O_WRONLY" : "0"))),
179 : 0 : (flags & _O_APPEND ? "|O_APPEND" : ""),
180 : 0 : (flags & _O_RANDOM ? "|O_RANDOM" : ""),
181 : 0 : (flags & _O_SEQUENTIAL ? "|O_SEQUENTIAL" : ""),
182 : 0 : (flags & _O_TEMPORARY ? "|O_TEMPORARY" : ""),
183 : 0 : (flags & _O_CREAT ? "|O_CREAT" : ""),
184 : 0 : (flags & _O_TRUNC ? "|O_TRUNC" : ""),
185 : 0 : (flags & _O_EXCL ? "|O_EXCL" : ""),
186 : 0 : (flags & _O_TEXT ? "|O_TEXT" : ""),
187 : 0 : (flags & _O_BINARY ? "|O_BINARY" : ""));
188 : 0 : }
189 : :
190 : : static void
191 : 0 : g_win32_print_gioflags (GIOFlags flags)
192 : : {
193 : 0 : char *bar = "";
194 : :
195 : 0 : if (flags & G_IO_FLAG_APPEND)
196 : 0 : bar = "|", g_print ("APPEND");
197 : 0 : if (flags & G_IO_FLAG_NONBLOCK)
198 : 0 : g_print ("%sNONBLOCK", bar), bar = "|";
199 : 0 : if (flags & G_IO_FLAG_IS_READABLE)
200 : 0 : g_print ("%sREADABLE", bar), bar = "|";
201 : 0 : if (flags & G_IO_FLAG_IS_WRITABLE)
202 : 0 : g_print ("%sWRITABLE", bar), bar = "|";
203 : 0 : if (flags & G_IO_FLAG_IS_SEEKABLE)
204 : 0 : g_print ("%sSEEKABLE", bar), bar = "|";
205 : 0 : }
206 : :
207 : : static const char *
208 : 0 : event_mask_to_string (int mask)
209 : : {
210 : : char buf[100];
211 : 0 : int checked_bits = 0;
212 : 0 : char *bufp = buf;
213 : :
214 : 0 : if (mask == 0)
215 : 0 : return "";
216 : :
217 : : #define BIT(n) checked_bits |= FD_##n; if (mask & FD_##n) bufp += sprintf (bufp, "%s" #n, (bufp>buf ? "|" : ""))
218 : :
219 : 0 : BIT (READ);
220 : 0 : BIT (WRITE);
221 : 0 : BIT (OOB);
222 : 0 : BIT (ACCEPT);
223 : 0 : BIT (CONNECT);
224 : 0 : BIT (CLOSE);
225 : 0 : BIT (QOS);
226 : 0 : BIT (GROUP_QOS);
227 : 0 : BIT (ROUTING_INTERFACE_CHANGE);
228 : 0 : BIT (ADDRESS_LIST_CHANGE);
229 : :
230 : : #undef BIT
231 : :
232 : 0 : if ((mask & ~checked_bits) != 0)
233 : 0 : bufp += sprintf (bufp, "|%#x", mask & ~checked_bits);
234 : :
235 : 0 : return g_quark_to_string (g_quark_from_string (buf));
236 : 0 : }
237 : :
238 : : static const char *
239 : 0 : condition_to_string (GIOCondition condition)
240 : : {
241 : : char buf[100];
242 : 0 : int checked_bits = 0;
243 : 0 : char *bufp = buf;
244 : :
245 : 0 : if (condition == 0)
246 : 0 : return "";
247 : :
248 : : #define BIT(n) checked_bits |= G_IO_##n; if (condition & G_IO_##n) bufp += sprintf (bufp, "%s" #n, (bufp>buf ? "|" : ""))
249 : :
250 : 0 : BIT (IN);
251 : 0 : BIT (OUT);
252 : 0 : BIT (PRI);
253 : 0 : BIT (ERR);
254 : 0 : BIT (HUP);
255 : 0 : BIT (NVAL);
256 : :
257 : : #undef BIT
258 : :
259 : 0 : if ((condition & ~checked_bits) != 0)
260 : 0 : bufp += sprintf (bufp, "|%#x", condition & ~checked_bits);
261 : :
262 : 0 : return g_quark_to_string (g_quark_from_string (buf));
263 : 0 : }
264 : :
265 : : static gboolean
266 : 721 : g_io_win32_get_debug_flag (void)
267 : : {
268 : 721 : return (g_getenv ("G_IO_WIN32_DEBUG") != NULL);
269 : : }
270 : :
271 : : static void
272 : 713 : g_io_channel_win32_init (GIOWin32Channel *channel)
273 : : {
274 : 713 : channel->debug = g_io_win32_get_debug_flag ();
275 : :
276 : 713 : InitializeCriticalSection (&channel->mutex);
277 : 713 : channel->running = FALSE;
278 : 713 : channel->needs_close = FALSE;
279 : 713 : channel->thread_id = 0;
280 : 713 : channel->data_avail_event = NULL;
281 : 713 : channel->revents = 0;
282 : 713 : channel->buffer = NULL;
283 : 713 : channel->space_avail_event = NULL;
284 : :
285 : 713 : channel->event_mask = 0;
286 : 713 : channel->last_events = 0;
287 : 713 : channel->event = NULL;
288 : 713 : channel->write_would_have_blocked = FALSE;
289 : 713 : channel->ever_writable = FALSE;
290 : 713 : }
291 : :
292 : : static void
293 : 594 : create_events (GIOWin32Channel *channel)
294 : : {
295 : : SECURITY_ATTRIBUTES sec_attrs;
296 : :
297 : 594 : sec_attrs.nLength = sizeof (SECURITY_ATTRIBUTES);
298 : 594 : sec_attrs.lpSecurityDescriptor = NULL;
299 : 594 : sec_attrs.bInheritHandle = FALSE;
300 : :
301 : : /* The data available event is manual reset, the space available event
302 : : * is automatic reset.
303 : : */
304 : 594 : if (!(channel->data_avail_event = CreateEvent (&sec_attrs, TRUE, FALSE, NULL))
305 : 594 : || !(channel->space_avail_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL)))
306 : : {
307 : 0 : gchar *emsg = g_win32_error_message (GetLastError ());
308 : :
309 : 0 : g_error ("Error creating event: %s", emsg);
310 : 0 : g_free (emsg);
311 : 0 : }
312 : 594 : }
313 : :
314 : : static unsigned __stdcall
315 : 594 : read_thread (void *parameter)
316 : : {
317 : 594 : GIOWin32Channel *channel = parameter;
318 : : guchar *buffer;
319 : : gint nbytes;
320 : :
321 : 594 : g_io_channel_ref ((GIOChannel *)channel);
322 : :
323 : 594 : if (channel->debug)
324 : 0 : g_print ("read_thread %#x: start fd=%d, data_avail=%p space_avail=%p\n",
325 : 0 : channel->thread_id,
326 : 0 : channel->fd,
327 : 0 : channel->data_avail_event,
328 : 0 : channel->space_avail_event);
329 : :
330 : 594 : channel->direction = 0;
331 : 594 : channel->buffer = g_malloc (BUFFER_SIZE);
332 : 594 : channel->rdp = channel->wrp = 0;
333 : 594 : channel->running = TRUE;
334 : :
335 : 594 : SetEvent (channel->space_avail_event);
336 : :
337 : 594 : EnterCriticalSection (&channel->mutex);
338 : 1682 : while (channel->running)
339 : : {
340 : 1679 : if (channel->debug)
341 : 0 : g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
342 : 0 : channel->thread_id, channel->rdp, channel->wrp);
343 : 1679 : if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
344 : : {
345 : : /* Buffer is full */
346 : 4 : if (channel->debug)
347 : 0 : g_print ("read_thread %#x: resetting space_avail\n",
348 : 0 : channel->thread_id);
349 : 4 : ResetEvent (channel->space_avail_event);
350 : 4 : if (channel->debug)
351 : 0 : g_print ("read_thread %#x: waiting for space\n",
352 : 0 : channel->thread_id);
353 : 4 : LeaveCriticalSection (&channel->mutex);
354 : 4 : WaitForSingleObject (channel->space_avail_event, INFINITE);
355 : 4 : EnterCriticalSection (&channel->mutex);
356 : 4 : if (channel->debug)
357 : 0 : g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
358 : 0 : channel->thread_id, channel->rdp, channel->wrp);
359 : 4 : }
360 : :
361 : 1679 : buffer = channel->buffer + channel->wrp;
362 : :
363 : : /* Always leave at least one byte unused gap to be able to
364 : : * distinguish between the full and empty condition...
365 : : */
366 : 3358 : nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE,
367 : 1679 : BUFFER_SIZE - channel->wrp);
368 : :
369 : 1679 : if (channel->debug)
370 : 0 : g_print ("read_thread %#x: calling read() for %d bytes\n",
371 : 0 : channel->thread_id, nbytes);
372 : :
373 : 1679 : LeaveCriticalSection (&channel->mutex);
374 : :
375 : 1679 : nbytes = read (channel->fd, buffer, nbytes);
376 : :
377 : 1679 : EnterCriticalSection (&channel->mutex);
378 : :
379 : 1679 : channel->revents = G_IO_IN;
380 : 1679 : if (nbytes == 0)
381 : 591 : channel->revents |= G_IO_HUP;
382 : 1088 : else if (nbytes < 0)
383 : 0 : channel->revents |= G_IO_ERR;
384 : :
385 : 1679 : if (channel->debug)
386 : 0 : g_print ("read_thread %#x: read() returned %d, rdp=%d, wrp=%d\n",
387 : 0 : channel->thread_id, nbytes, channel->rdp, channel->wrp);
388 : :
389 : 1679 : if (nbytes <= 0)
390 : 591 : break;
391 : :
392 : 1088 : channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE;
393 : 1088 : if (channel->debug)
394 : 0 : g_print ("read_thread %#x: rdp=%d, wrp=%d, setting data_avail\n",
395 : 0 : channel->thread_id, channel->rdp, channel->wrp);
396 : 1088 : SetEvent (channel->data_avail_event);
397 : : }
398 : :
399 : 594 : channel->running = FALSE;
400 : 594 : if (channel->needs_close)
401 : : {
402 : 0 : if (channel->debug)
403 : 0 : g_print ("read_thread %#x: channel fd %d needs closing\n",
404 : 0 : channel->thread_id, channel->fd);
405 : 0 : close (channel->fd);
406 : 0 : channel->fd = -1;
407 : 0 : }
408 : :
409 : 594 : if (channel->debug)
410 : 0 : g_print ("read_thread %#x: EOF, rdp=%d, wrp=%d, setting data_avail\n",
411 : 0 : channel->thread_id, channel->rdp, channel->wrp);
412 : 594 : SetEvent (channel->data_avail_event);
413 : 594 : LeaveCriticalSection (&channel->mutex);
414 : :
415 : 594 : g_io_channel_unref ((GIOChannel *)channel);
416 : :
417 : : /* No need to call _endthreadex(), the actual thread starter routine
418 : : * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
419 : : * _endthreadex() for us.
420 : : */
421 : :
422 : 594 : return 0;
423 : : }
424 : :
425 : : static unsigned __stdcall
426 : 0 : write_thread (void *parameter)
427 : : {
428 : 0 : GIOWin32Channel *channel = parameter;
429 : : guchar *buffer;
430 : : gint nbytes;
431 : :
432 : 0 : g_io_channel_ref ((GIOChannel *)channel);
433 : :
434 : 0 : if (channel->debug)
435 : 0 : g_print ("write_thread %#x: start fd=%d, data_avail=%p space_avail=%p\n",
436 : 0 : channel->thread_id,
437 : 0 : channel->fd,
438 : 0 : channel->data_avail_event,
439 : 0 : channel->space_avail_event);
440 : :
441 : 0 : channel->direction = 1;
442 : 0 : channel->buffer = g_malloc (BUFFER_SIZE);
443 : 0 : channel->rdp = channel->wrp = 0;
444 : 0 : channel->running = TRUE;
445 : :
446 : 0 : SetEvent (channel->space_avail_event);
447 : :
448 : : /* We use the same event objects as for a reader thread, but with
449 : : * reversed meaning. So, space_avail is used if data is available
450 : : * for writing, and data_avail is used if space is available in the
451 : : * write buffer.
452 : : */
453 : :
454 : 0 : EnterCriticalSection (&channel->mutex);
455 : 0 : while (channel->running || channel->rdp != channel->wrp)
456 : : {
457 : 0 : if (channel->debug)
458 : 0 : g_print ("write_thread %#x: rdp=%d, wrp=%d\n",
459 : 0 : channel->thread_id, channel->rdp, channel->wrp);
460 : 0 : if (channel->wrp == channel->rdp)
461 : : {
462 : : /* Buffer is empty. */
463 : 0 : if (channel->debug)
464 : 0 : g_print ("write_thread %#x: resetting space_avail\n",
465 : 0 : channel->thread_id);
466 : 0 : ResetEvent (channel->space_avail_event);
467 : 0 : if (channel->debug)
468 : 0 : g_print ("write_thread %#x: waiting for data\n",
469 : 0 : channel->thread_id);
470 : 0 : channel->revents = G_IO_OUT;
471 : 0 : SetEvent (channel->data_avail_event);
472 : 0 : LeaveCriticalSection (&channel->mutex);
473 : 0 : WaitForSingleObject (channel->space_avail_event, INFINITE);
474 : :
475 : 0 : EnterCriticalSection (&channel->mutex);
476 : 0 : if (channel->rdp == channel->wrp)
477 : 0 : break;
478 : :
479 : 0 : if (channel->debug)
480 : 0 : g_print ("write_thread %#x: rdp=%d, wrp=%d\n",
481 : 0 : channel->thread_id, channel->rdp, channel->wrp);
482 : 0 : }
483 : :
484 : 0 : buffer = channel->buffer + channel->rdp;
485 : 0 : if (channel->rdp < channel->wrp)
486 : 0 : nbytes = channel->wrp - channel->rdp;
487 : : else
488 : 0 : nbytes = BUFFER_SIZE - channel->rdp;
489 : :
490 : 0 : if (channel->debug)
491 : 0 : g_print ("write_thread %#x: calling write() for %d bytes\n",
492 : 0 : channel->thread_id, nbytes);
493 : :
494 : 0 : LeaveCriticalSection (&channel->mutex);
495 : 0 : nbytes = write (channel->fd, buffer, nbytes);
496 : 0 : EnterCriticalSection (&channel->mutex);
497 : :
498 : 0 : if (channel->debug)
499 : 0 : g_print ("write_thread %#x: write(%i) returned %d, rdp=%d, wrp=%d\n",
500 : 0 : channel->thread_id, channel->fd, nbytes, channel->rdp, channel->wrp);
501 : :
502 : 0 : channel->revents = 0;
503 : 0 : if (nbytes > 0)
504 : 0 : channel->revents |= G_IO_OUT;
505 : 0 : else if (nbytes <= 0)
506 : 0 : channel->revents |= G_IO_ERR;
507 : :
508 : 0 : channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE;
509 : :
510 : 0 : if (nbytes <= 0)
511 : 0 : break;
512 : :
513 : 0 : if (channel->debug)
514 : 0 : g_print ("write_thread: setting data_avail for thread %#x\n",
515 : 0 : channel->thread_id);
516 : 0 : SetEvent (channel->data_avail_event);
517 : : }
518 : :
519 : 0 : channel->running = FALSE;
520 : 0 : if (channel->needs_close)
521 : : {
522 : 0 : if (channel->debug)
523 : 0 : g_print ("write_thread %#x: channel fd %d needs closing\n",
524 : 0 : channel->thread_id, channel->fd);
525 : 0 : close (channel->fd);
526 : 0 : channel->fd = -1;
527 : 0 : }
528 : :
529 : 0 : LeaveCriticalSection (&channel->mutex);
530 : :
531 : 0 : g_io_channel_unref ((GIOChannel *)channel);
532 : :
533 : 0 : return 0;
534 : : }
535 : :
536 : : static void
537 : 594 : create_thread (GIOWin32Channel *channel,
538 : : GIOCondition condition,
539 : : unsigned (__stdcall *thread) (void *parameter))
540 : : {
541 : : HANDLE thread_handle;
542 : : int errsv;
543 : :
544 : 1188 : thread_handle = (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0,
545 : 594 : &channel->thread_id);
546 : 594 : errsv = errno;
547 : 594 : if (thread_handle == 0)
548 : 0 : g_warning ("Error creating thread: %s.",
549 : 0 : g_strerror (errsv));
550 : 594 : else if (!CloseHandle (thread_handle))
551 : : {
552 : 0 : gchar *emsg = g_win32_error_message (GetLastError ());
553 : :
554 : 0 : g_warning ("Error closing thread handle: %s.", emsg);
555 : 0 : g_free (emsg);
556 : 0 : }
557 : :
558 : 594 : WaitForSingleObject (channel->space_avail_event, INFINITE);
559 : 594 : }
560 : :
561 : : static GIOStatus
562 : 1300 : buffer_read (GIOWin32Channel *channel,
563 : : gchar *dest,
564 : : gsize count,
565 : : gsize *bytes_read,
566 : : GError **err)
567 : : {
568 : : guint nbytes;
569 : 1300 : guint left = count;
570 : :
571 : 1300 : EnterCriticalSection (&channel->mutex);
572 : 1300 : if (channel->debug)
573 : 0 : g_print ("reading from thread %#x %" G_GSIZE_FORMAT " bytes, rdp=%d, wrp=%d\n",
574 : 0 : channel->thread_id, count, channel->rdp, channel->wrp);
575 : :
576 : 1300 : if (channel->wrp == channel->rdp)
577 : : {
578 : 659 : LeaveCriticalSection (&channel->mutex);
579 : 659 : if (channel->debug)
580 : 0 : g_print ("waiting for data from thread %#x\n", channel->thread_id);
581 : 659 : WaitForSingleObject (channel->data_avail_event, INFINITE);
582 : 659 : if (channel->debug)
583 : 0 : g_print ("done waiting for data from thread %#x\n", channel->thread_id);
584 : 659 : EnterCriticalSection (&channel->mutex);
585 : 659 : if (channel->wrp == channel->rdp && !channel->running)
586 : : {
587 : 607 : if (channel->debug)
588 : 0 : g_print ("wrp==rdp, !running\n");
589 : 607 : LeaveCriticalSection (&channel->mutex);
590 : 607 : *bytes_read = 0;
591 : 607 : return G_IO_STATUS_EOF;
592 : : }
593 : 52 : }
594 : :
595 : 693 : if (channel->rdp < channel->wrp)
596 : 674 : nbytes = channel->wrp - channel->rdp;
597 : : else
598 : 19 : nbytes = BUFFER_SIZE - channel->rdp;
599 : 693 : LeaveCriticalSection (&channel->mutex);
600 : 693 : nbytes = MIN (left, nbytes);
601 : 693 : if (channel->debug)
602 : 0 : g_print ("moving %d bytes from thread %#x\n",
603 : 0 : nbytes, channel->thread_id);
604 : 693 : memcpy (dest, channel->buffer + channel->rdp, nbytes);
605 : 693 : dest += nbytes;
606 : 693 : left -= nbytes;
607 : 693 : EnterCriticalSection (&channel->mutex);
608 : 693 : channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE;
609 : 693 : if (channel->debug)
610 : 0 : g_print ("setting space_avail for thread %#x\n", channel->thread_id);
611 : 693 : SetEvent (channel->space_avail_event);
612 : 693 : if (channel->debug)
613 : 0 : g_print ("for thread %#x: rdp=%d, wrp=%d\n",
614 : 0 : channel->thread_id, channel->rdp, channel->wrp);
615 : 693 : if (channel->running && channel->wrp == channel->rdp)
616 : : {
617 : 656 : if (channel->debug)
618 : 0 : g_print ("resetting data_avail of thread %#x\n",
619 : 0 : channel->thread_id);
620 : 656 : ResetEvent (channel->data_avail_event);
621 : 656 : };
622 : 693 : LeaveCriticalSection (&channel->mutex);
623 : :
624 : : /* We have no way to indicate any errors form the actual
625 : : * read() or recv() call in the reader thread. Should we have?
626 : : */
627 : 693 : *bytes_read = count - left;
628 : 693 : return (*bytes_read > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
629 : 1300 : }
630 : :
631 : :
632 : : static GIOStatus
633 : 0 : buffer_write (GIOWin32Channel *channel,
634 : : const gchar *dest,
635 : : gsize count,
636 : : gsize *bytes_written,
637 : : GError **err)
638 : : {
639 : : guint nbytes;
640 : 0 : guint left = count;
641 : :
642 : 0 : EnterCriticalSection (&channel->mutex);
643 : 0 : if (channel->debug)
644 : 0 : g_print ("buffer_write: writing to thread %#x %" G_GSIZE_FORMAT " bytes, rdp=%d, wrp=%d\n",
645 : 0 : channel->thread_id, count, channel->rdp, channel->wrp);
646 : :
647 : 0 : if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
648 : : {
649 : : /* Buffer is full */
650 : 0 : if (channel->debug)
651 : 0 : g_print ("buffer_write: tid %#x: resetting data_avail\n",
652 : 0 : channel->thread_id);
653 : 0 : ResetEvent (channel->data_avail_event);
654 : 0 : if (channel->debug)
655 : 0 : g_print ("buffer_write: tid %#x: waiting for space\n",
656 : 0 : channel->thread_id);
657 : 0 : LeaveCriticalSection (&channel->mutex);
658 : 0 : WaitForSingleObject (channel->data_avail_event, INFINITE);
659 : 0 : EnterCriticalSection (&channel->mutex);
660 : 0 : if (channel->debug)
661 : 0 : g_print ("buffer_write: tid %#x: rdp=%d, wrp=%d\n",
662 : 0 : channel->thread_id, channel->rdp, channel->wrp);
663 : 0 : }
664 : :
665 : 0 : nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE,
666 : 0 : BUFFER_SIZE - channel->wrp);
667 : :
668 : 0 : LeaveCriticalSection (&channel->mutex);
669 : 0 : nbytes = MIN (left, nbytes);
670 : 0 : if (channel->debug)
671 : 0 : g_print ("buffer_write: tid %#x: writing %d bytes\n",
672 : 0 : channel->thread_id, nbytes);
673 : 0 : memcpy (channel->buffer + channel->wrp, dest, nbytes);
674 : 0 : dest += nbytes;
675 : 0 : left -= nbytes;
676 : 0 : EnterCriticalSection (&channel->mutex);
677 : :
678 : 0 : channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE;
679 : 0 : if (channel->debug)
680 : 0 : g_print ("buffer_write: tid %#x: rdp=%d, wrp=%d, setting space_avail\n",
681 : 0 : channel->thread_id, channel->rdp, channel->wrp);
682 : 0 : SetEvent (channel->space_avail_event);
683 : :
684 : 0 : if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
685 : : {
686 : : /* Buffer is full */
687 : 0 : if (channel->debug)
688 : 0 : g_print ("buffer_write: tid %#x: resetting data_avail\n",
689 : 0 : channel->thread_id);
690 : 0 : ResetEvent (channel->data_avail_event);
691 : 0 : }
692 : :
693 : 0 : LeaveCriticalSection (&channel->mutex);
694 : :
695 : : /* We have no way to indicate any errors form the actual
696 : : * write() call in the writer thread. Should we have?
697 : : */
698 : 0 : *bytes_written = count - left;
699 : 0 : return (*bytes_written > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
700 : : }
701 : :
702 : :
703 : : static gboolean
704 : 2679 : g_io_win32_prepare (GSource *source,
705 : : gint *timeout)
706 : : {
707 : 2679 : GIOWin32Watch *watch = (GIOWin32Watch *)source;
708 : 2679 : GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
709 : 2679 : GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
710 : : int event_mask;
711 : :
712 : 2679 : if (channel->debug)
713 : 0 : g_print ("g_io_win32_prepare: source=%p channel=%p", source, channel);
714 : :
715 : 2679 : switch (channel->type)
716 : : {
717 : : case G_IO_WIN32_WINDOWS_MESSAGES:
718 : 53 : if (channel->debug)
719 : 0 : g_print (" MSG");
720 : 53 : break;
721 : :
722 : : case G_IO_WIN32_CONSOLE:
723 : 0 : if (channel->debug)
724 : 0 : g_print (" CON");
725 : 0 : break;
726 : :
727 : : case G_IO_WIN32_FILE_DESC:
728 : 2626 : if (channel->debug)
729 : 0 : g_print (" FD thread=%#x buffer_condition:{%s}"
730 : : "\n watch->pollfd.events:{%s} watch->pollfd.revents:{%s} channel->revents:{%s}",
731 : 0 : channel->thread_id, condition_to_string (buffer_condition),
732 : 0 : condition_to_string (watch->pollfd.events),
733 : 0 : condition_to_string (watch->pollfd.revents),
734 : 0 : condition_to_string (channel->revents));
735 : :
736 : 2626 : EnterCriticalSection (&channel->mutex);
737 : 2626 : if (channel->running)
738 : : {
739 : 2561 : if (channel->direction == 0 && channel->wrp == channel->rdp)
740 : : {
741 : 2523 : if (channel->debug)
742 : 0 : g_print ("\n setting revents=0");
743 : 2523 : channel->revents = 0;
744 : 2523 : }
745 : 2561 : }
746 : : else
747 : : {
748 : 65 : if (channel->direction == 1
749 : 65 : && (channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
750 : : {
751 : 0 : if (channel->debug)
752 : 0 : g_print ("\n setting revents=0");
753 : 0 : channel->revents = 0;
754 : 0 : }
755 : : }
756 : 2626 : LeaveCriticalSection (&channel->mutex);
757 : 2626 : break;
758 : :
759 : : case G_IO_WIN32_SOCKET:
760 : 0 : if (channel->debug)
761 : 0 : g_print (" SOCK");
762 : 0 : event_mask = 0;
763 : 0 : if (watch->condition & G_IO_IN)
764 : 0 : event_mask |= (FD_READ | FD_ACCEPT);
765 : 0 : if (watch->condition & G_IO_OUT)
766 : 0 : event_mask |= (FD_WRITE | FD_CONNECT);
767 : 0 : event_mask |= FD_CLOSE;
768 : :
769 : 0 : if (channel->event_mask != event_mask)
770 : : {
771 : 0 : if (channel->debug)
772 : 0 : g_print ("\n WSAEventSelect(%d,%p,{%s})",
773 : 0 : channel->fd, (HANDLE) watch->pollfd.fd,
774 : 0 : event_mask_to_string (event_mask));
775 : 0 : if (WSAEventSelect (channel->fd, (HANDLE) watch->pollfd.fd,
776 : 0 : event_mask) == SOCKET_ERROR)
777 : 0 : if (channel->debug)
778 : : {
779 : 0 : gchar *emsg = g_win32_error_message (WSAGetLastError ());
780 : :
781 : 0 : g_print (" failed: %s", emsg);
782 : 0 : g_free (emsg);
783 : 0 : }
784 : 0 : channel->event_mask = event_mask;
785 : :
786 : 0 : if (channel->debug)
787 : 0 : g_print ("\n setting last_events=0");
788 : 0 : channel->last_events = 0;
789 : :
790 : 0 : if ((event_mask & FD_WRITE) &&
791 : 0 : channel->ever_writable &&
792 : 0 : !channel->write_would_have_blocked)
793 : : {
794 : 0 : if (channel->debug)
795 : 0 : g_print (" WSASetEvent(%p)", (WSAEVENT) watch->pollfd.fd);
796 : 0 : WSASetEvent ((WSAEVENT) watch->pollfd.fd);
797 : 0 : }
798 : 0 : }
799 : 0 : break;
800 : :
801 : : default:
802 : : g_assert_not_reached ();
803 : 0 : g_abort ();
804 : : }
805 : 2679 : if (channel->debug)
806 : 0 : g_print ("\n");
807 : :
808 : 2679 : return ((watch->condition & buffer_condition) == watch->condition);
809 : : }
810 : :
811 : : static gboolean
812 : 2678 : g_io_win32_check (GSource *source)
813 : : {
814 : : MSG msg;
815 : 2678 : GIOWin32Watch *watch = (GIOWin32Watch *)source;
816 : 2678 : GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
817 : 2678 : GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
818 : 2678 : WSANETWORKEVENTS events = { 0 };
819 : :
820 : 2678 : if (channel->debug)
821 : 0 : g_print ("g_io_win32_check: source=%p channel=%p", source, channel);
822 : :
823 : 2678 : switch (channel->type)
824 : : {
825 : : case G_IO_WIN32_WINDOWS_MESSAGES:
826 : 53 : if (channel->debug)
827 : 0 : g_print (" MSG\n");
828 : 53 : return (PeekMessage (&msg, channel->hwnd, 0, 0, PM_NOREMOVE));
829 : :
830 : : case G_IO_WIN32_FILE_DESC:
831 : 2625 : if (channel->debug)
832 : 0 : g_print (" FD thread=%#x buffer_condition=%s\n"
833 : : " watch->pollfd.events={%s} watch->pollfd.revents={%s} channel->revents={%s}\n",
834 : 0 : channel->thread_id, condition_to_string (buffer_condition),
835 : 0 : condition_to_string (watch->pollfd.events),
836 : 0 : condition_to_string (watch->pollfd.revents),
837 : 0 : condition_to_string (channel->revents));
838 : :
839 : 2625 : watch->pollfd.revents = (watch->pollfd.events & channel->revents);
840 : :
841 : 2625 : return ((watch->pollfd.revents | buffer_condition) & watch->condition);
842 : :
843 : : case G_IO_WIN32_CONSOLE:
844 : 0 : if (channel->debug)
845 : 0 : g_print (" CON\n");
846 : 0 : if (watch->channel->is_writeable)
847 : 0 : return TRUE;
848 : 0 : else if (watch->channel->is_readable)
849 : : {
850 : : INPUT_RECORD buffer;
851 : : DWORD n;
852 : 0 : if (PeekConsoleInput ((HANDLE) watch->pollfd.fd, &buffer, 1, &n) &&
853 : 0 : n == 1)
854 : : {
855 : : /* _kbhit() does quite complex processing to find out
856 : : * whether at least one of the key events pending corresponds
857 : : * to a "real" character that can be read.
858 : : */
859 : 0 : if (_kbhit ())
860 : 0 : return TRUE;
861 : :
862 : : /* Discard all other kinds of events */
863 : 0 : ReadConsoleInput ((HANDLE) watch->pollfd.fd, &buffer, 1, &n);
864 : 0 : }
865 : 0 : }
866 : 0 : return FALSE;
867 : :
868 : : case G_IO_WIN32_SOCKET:
869 : 0 : if (channel->debug)
870 : 0 : g_print (" SOCK");
871 : 0 : if (channel->last_events & FD_WRITE)
872 : : {
873 : 0 : if (channel->debug)
874 : 0 : g_print (" sock=%d event=%p last_events has FD_WRITE",
875 : 0 : channel->fd, (HANDLE) watch->pollfd.fd);
876 : 0 : }
877 : : else
878 : : {
879 : 0 : WSAEnumNetworkEvents (channel->fd, 0, &events);
880 : :
881 : 0 : if (channel->debug)
882 : 0 : g_print ("\n revents={%s} condition={%s}"
883 : : "\n WSAEnumNetworkEvents(%d,0) sets events={%s}",
884 : 0 : condition_to_string (watch->pollfd.revents),
885 : 0 : condition_to_string (watch->condition),
886 : 0 : channel->fd,
887 : 0 : event_mask_to_string (events.lNetworkEvents));
888 : :
889 : 0 : if (watch->pollfd.revents != 0 &&
890 : 0 : events.lNetworkEvents == 0 &&
891 : 0 : !(channel->event_mask & FD_WRITE))
892 : : {
893 : 0 : channel->event_mask = 0;
894 : 0 : if (channel->debug)
895 : 0 : g_print ("\n WSAEventSelect(%d,%p,{})",
896 : 0 : channel->fd, (HANDLE) watch->pollfd.fd);
897 : 0 : WSAEventSelect (channel->fd, (HANDLE) watch->pollfd.fd, 0);
898 : 0 : if (channel->debug)
899 : 0 : g_print (" ResetEvent(%p)",
900 : 0 : (HANDLE) watch->pollfd.fd);
901 : 0 : ResetEvent ((HANDLE) watch->pollfd.fd);
902 : 0 : }
903 : 0 : else if (events.lNetworkEvents & FD_WRITE)
904 : 0 : channel->ever_writable = TRUE;
905 : 0 : channel->last_events = events.lNetworkEvents;
906 : : }
907 : :
908 : 0 : watch->pollfd.revents = 0;
909 : 0 : if (channel->last_events & (FD_READ | FD_ACCEPT))
910 : 0 : watch->pollfd.revents |= G_IO_IN;
911 : :
912 : 0 : if (channel->last_events & FD_WRITE)
913 : 0 : watch->pollfd.revents |= G_IO_OUT;
914 : : else
915 : : {
916 : : /* We have called WSAEnumNetworkEvents() above but it didn't
917 : : * set FD_WRITE.
918 : : */
919 : 0 : if (events.lNetworkEvents & FD_CONNECT)
920 : : {
921 : 0 : if (events.iErrorCode[FD_CONNECT_BIT] == 0)
922 : 0 : watch->pollfd.revents |= G_IO_OUT;
923 : : else
924 : 0 : watch->pollfd.revents |= (G_IO_HUP | G_IO_ERR);
925 : 0 : }
926 : 0 : if (watch->pollfd.revents == 0 && (channel->last_events & (FD_CLOSE)))
927 : 0 : watch->pollfd.revents |= G_IO_HUP;
928 : : }
929 : :
930 : : /* Regardless of WSAEnumNetworkEvents() result, if watching for
931 : : * writability, and if we have ever got a FD_WRITE event, and
932 : : * unless last write would have blocked, set G_IO_OUT. But never
933 : : * set both G_IO_OUT and G_IO_HUP.
934 : : */
935 : 0 : if (!(watch->pollfd.revents & G_IO_HUP) &&
936 : 0 : channel->ever_writable &&
937 : 0 : !channel->write_would_have_blocked &&
938 : 0 : (channel->event_mask & FD_WRITE))
939 : 0 : watch->pollfd.revents |= G_IO_OUT;
940 : :
941 : 0 : if (channel->debug)
942 : 0 : g_print ("\n revents={%s} retval={%s}\n",
943 : 0 : condition_to_string (watch->pollfd.revents),
944 : 0 : condition_to_string ((watch->pollfd.revents | buffer_condition) & watch->condition));
945 : :
946 : 0 : return ((watch->pollfd.revents | buffer_condition) & watch->condition);
947 : :
948 : : default:
949 : : g_assert_not_reached ();
950 : 0 : g_abort ();
951 : : }
952 : 2678 : }
953 : :
954 : : static gboolean
955 : 950 : g_io_win32_dispatch (GSource *source,
956 : : GSourceFunc callback,
957 : : gpointer user_data)
958 : : {
959 : 950 : GIOFunc func = (GIOFunc)callback;
960 : 950 : GIOWin32Watch *watch = (GIOWin32Watch *)source;
961 : 950 : GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
962 : 950 : GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
963 : :
964 : 950 : if (!func)
965 : : {
966 : 0 : g_warning ("IO Watch dispatched without callback. "
967 : : "You must call g_source_connect().");
968 : 0 : return FALSE;
969 : : }
970 : :
971 : 950 : if (channel->debug)
972 : 0 : g_print ("g_io_win32_dispatch: pollfd.revents=%s condition=%s result=%s\n",
973 : 0 : condition_to_string (watch->pollfd.revents),
974 : 0 : condition_to_string (watch->condition),
975 : 0 : condition_to_string ((watch->pollfd.revents | buffer_condition) & watch->condition));
976 : :
977 : 1900 : return (*func) (watch->channel,
978 : 950 : (watch->pollfd.revents | buffer_condition) & watch->condition,
979 : 950 : user_data);
980 : 950 : }
981 : :
982 : : static void
983 : 533 : g_io_win32_finalize (GSource *source)
984 : : {
985 : 533 : GIOWin32Watch *watch = (GIOWin32Watch *)source;
986 : 533 : GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
987 : :
988 : 533 : if (channel->debug)
989 : 0 : g_print ("g_io_win32_finalize: source=%p channel=%p", source, channel);
990 : :
991 : 533 : switch (channel->type)
992 : : {
993 : : case G_IO_WIN32_WINDOWS_MESSAGES:
994 : 0 : if (channel->debug)
995 : 0 : g_print (" MSG");
996 : 0 : break;
997 : :
998 : : case G_IO_WIN32_CONSOLE:
999 : 1 : if (channel->debug)
1000 : 0 : g_print (" CON");
1001 : 1 : break;
1002 : :
1003 : : case G_IO_WIN32_FILE_DESC:
1004 : 532 : if (channel->debug)
1005 : 0 : g_print (" FD thread=%#x", channel->thread_id);
1006 : 532 : break;
1007 : :
1008 : : case G_IO_WIN32_SOCKET:
1009 : 0 : if (channel->debug)
1010 : 0 : g_print (" SOCK sock=%d", channel->fd);
1011 : 0 : break;
1012 : :
1013 : : default:
1014 : : g_assert_not_reached ();
1015 : 0 : g_abort ();
1016 : : }
1017 : 533 : if (channel->debug)
1018 : 0 : g_print ("\n");
1019 : 533 : g_io_channel_unref (watch->channel);
1020 : 533 : }
1021 : :
1022 : : GSourceFuncs g_io_watch_funcs = {
1023 : : g_io_win32_prepare,
1024 : : g_io_win32_check,
1025 : : g_io_win32_dispatch,
1026 : : g_io_win32_finalize,
1027 : : NULL,
1028 : : NULL
1029 : : };
1030 : :
1031 : : static GIOStatus
1032 : 4 : g_io_win32_msg_read (GIOChannel *channel,
1033 : : gchar *buf,
1034 : : gsize count,
1035 : : gsize *bytes_read,
1036 : : GError **err)
1037 : : {
1038 : 4 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1039 : : MSG msg; /* In case of alignment problems */
1040 : :
1041 : 4 : *bytes_read = 0;
1042 : :
1043 : 4 : if (count < sizeof (MSG))
1044 : : {
1045 : 0 : g_set_error_literal (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
1046 : : "Incorrect message size"); /* Informative enough error message? */
1047 : 0 : return G_IO_STATUS_ERROR;
1048 : : }
1049 : :
1050 : 4 : if (win32_channel->debug)
1051 : 0 : g_print ("g_io_win32_msg_read: channel=%p hwnd=%p\n",
1052 : 0 : channel, win32_channel->hwnd);
1053 : 4 : if (!PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_REMOVE))
1054 : 0 : return G_IO_STATUS_AGAIN;
1055 : :
1056 : 4 : memmove (buf, &msg, sizeof (MSG));
1057 : 4 : *bytes_read = sizeof (MSG);
1058 : :
1059 : 4 : return G_IO_STATUS_NORMAL;
1060 : 4 : }
1061 : :
1062 : : static GIOStatus
1063 : 0 : g_io_win32_msg_write (GIOChannel *channel,
1064 : : const gchar *buf,
1065 : : gsize count,
1066 : : gsize *bytes_written,
1067 : : GError **err)
1068 : : {
1069 : 0 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1070 : : MSG msg;
1071 : :
1072 : 0 : *bytes_written = 0;
1073 : :
1074 : 0 : if (count != sizeof (MSG))
1075 : : {
1076 : 0 : g_set_error_literal (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
1077 : : "Incorrect message size"); /* Informative enough error message? */
1078 : 0 : return G_IO_STATUS_ERROR;
1079 : : }
1080 : :
1081 : : /* In case of alignment problems */
1082 : 0 : memmove (&msg, buf, sizeof (MSG));
1083 : 0 : if (!PostMessage (win32_channel->hwnd, msg.message, msg.wParam, msg.lParam))
1084 : : {
1085 : 0 : gchar *emsg = g_win32_error_message (GetLastError ());
1086 : :
1087 : 0 : g_set_error_literal (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, emsg);
1088 : 0 : g_free (emsg);
1089 : :
1090 : 0 : return G_IO_STATUS_ERROR;
1091 : : }
1092 : :
1093 : 0 : *bytes_written = sizeof (MSG);
1094 : :
1095 : 0 : return G_IO_STATUS_NORMAL;
1096 : 0 : }
1097 : :
1098 : : static GIOStatus
1099 : 0 : g_io_win32_msg_close (GIOChannel *channel,
1100 : : GError **err)
1101 : : {
1102 : : /* Nothing to be done. Or should we set hwnd to some invalid value? */
1103 : :
1104 : 0 : return G_IO_STATUS_NORMAL;
1105 : : }
1106 : :
1107 : : static void
1108 : 711 : g_io_win32_free (GIOChannel *channel)
1109 : : {
1110 : 711 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1111 : :
1112 : 711 : if (win32_channel->debug)
1113 : 0 : g_print ("g_io_win32_free channel=%p fd=%d\n", channel, win32_channel->fd);
1114 : :
1115 : 711 : DeleteCriticalSection (&win32_channel->mutex);
1116 : :
1117 : 711 : if (win32_channel->data_avail_event)
1118 : 593 : if (!CloseHandle (win32_channel->data_avail_event))
1119 : 0 : if (win32_channel->debug)
1120 : : {
1121 : 0 : gchar *emsg = g_win32_error_message (GetLastError ());
1122 : :
1123 : 0 : g_print (" CloseHandle(%p) failed: %s\n",
1124 : 0 : win32_channel->data_avail_event, emsg);
1125 : 0 : g_free (emsg);
1126 : 0 : }
1127 : :
1128 : 711 : g_free (win32_channel->buffer);
1129 : :
1130 : 711 : if (win32_channel->space_avail_event)
1131 : 593 : if (!CloseHandle (win32_channel->space_avail_event))
1132 : 0 : if (win32_channel->debug)
1133 : : {
1134 : 0 : gchar *emsg = g_win32_error_message (GetLastError ());
1135 : :
1136 : 0 : g_print (" CloseHandle(%p) failed: %s\n",
1137 : 0 : win32_channel->space_avail_event, emsg);
1138 : 0 : g_free (emsg);
1139 : 0 : }
1140 : :
1141 : 711 : if (win32_channel->type == G_IO_WIN32_SOCKET &&
1142 : 0 : win32_channel->fd != -1)
1143 : 0 : if (WSAEventSelect (win32_channel->fd, NULL, 0) == SOCKET_ERROR)
1144 : 0 : if (win32_channel->debug)
1145 : : {
1146 : 0 : gchar *emsg = g_win32_error_message (WSAGetLastError ());
1147 : :
1148 : 0 : g_print (" WSAEventSelect(%d,NULL,{}) failed: %s\n",
1149 : 0 : win32_channel->fd, emsg);
1150 : 0 : g_free (emsg);
1151 : 0 : }
1152 : :
1153 : 711 : if (win32_channel->event)
1154 : 0 : if (!WSACloseEvent (win32_channel->event))
1155 : 0 : if (win32_channel->debug)
1156 : : {
1157 : 0 : gchar *emsg = g_win32_error_message (WSAGetLastError ());
1158 : :
1159 : 0 : g_print (" WSACloseEvent(%p) failed: %s\n",
1160 : 0 : win32_channel->event, emsg);
1161 : 0 : g_free (emsg);
1162 : 0 : }
1163 : :
1164 : 711 : g_free (win32_channel);
1165 : 711 : }
1166 : :
1167 : : static GSource *
1168 : 1 : g_io_win32_msg_create_watch (GIOChannel *channel,
1169 : : GIOCondition condition)
1170 : : {
1171 : : GIOWin32Watch *watch;
1172 : : GSource *source;
1173 : :
1174 : 1 : source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
1175 : 1 : g_source_set_static_name (source, "GIOChannel (Win32)");
1176 : 1 : watch = (GIOWin32Watch *)source;
1177 : :
1178 : 1 : watch->channel = channel;
1179 : 1 : g_io_channel_ref (channel);
1180 : :
1181 : 1 : watch->condition = condition;
1182 : :
1183 : 1 : watch->pollfd.fd = (gintptr) G_WIN32_MSG_HANDLE;
1184 : 1 : watch->pollfd.events = condition;
1185 : :
1186 : 1 : g_source_add_poll (source, &watch->pollfd);
1187 : :
1188 : 1 : return source;
1189 : : }
1190 : :
1191 : : static GIOStatus
1192 : 5301 : g_io_win32_fd_and_console_read (GIOChannel *channel,
1193 : : gchar *buf,
1194 : : gsize count,
1195 : : gsize *bytes_read,
1196 : : GError **err)
1197 : : {
1198 : 5301 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1199 : : gint result;
1200 : : int errsv;
1201 : :
1202 : 5301 : if (win32_channel->debug)
1203 : 0 : g_print ("g_io_win32_fd_read: fd=%d count=%" G_GSIZE_FORMAT "\n",
1204 : 0 : win32_channel->fd, count);
1205 : :
1206 : 5301 : if (win32_channel->thread_id)
1207 : : {
1208 : 1300 : return buffer_read (win32_channel, buf, count, bytes_read, err);
1209 : : }
1210 : :
1211 : 4001 : result = read (win32_channel->fd, buf, count);
1212 : 4001 : errsv = errno;
1213 : :
1214 : 4001 : if (win32_channel->debug)
1215 : 0 : g_print ("g_io_win32_fd_read: read() => %d\n", result);
1216 : :
1217 : 4001 : if (result < 0)
1218 : : {
1219 : 0 : *bytes_read = 0;
1220 : :
1221 : 0 : switch (errsv)
1222 : : {
1223 : : #ifdef EAGAIN
1224 : : case EAGAIN:
1225 : 0 : return G_IO_STATUS_AGAIN;
1226 : : #endif
1227 : : default:
1228 : 0 : g_set_error_literal (err, G_IO_CHANNEL_ERROR,
1229 : 0 : g_io_channel_error_from_errno (errsv),
1230 : 0 : g_strerror (errsv));
1231 : 0 : return G_IO_STATUS_ERROR;
1232 : : }
1233 : : }
1234 : :
1235 : 4001 : *bytes_read = result;
1236 : :
1237 : 4001 : return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
1238 : 5301 : }
1239 : :
1240 : : static GIOStatus
1241 : 109 : g_io_win32_fd_and_console_write (GIOChannel *channel,
1242 : : const gchar *buf,
1243 : : gsize count,
1244 : : gsize *bytes_written,
1245 : : GError **err)
1246 : : {
1247 : 109 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1248 : : gint result;
1249 : : int errsv;
1250 : :
1251 : 109 : if (win32_channel->thread_id)
1252 : : {
1253 : 0 : return buffer_write (win32_channel, buf, count, bytes_written, err);
1254 : : }
1255 : :
1256 : 109 : result = write (win32_channel->fd, buf, count);
1257 : 109 : errsv = errno;
1258 : :
1259 : 109 : if (win32_channel->debug)
1260 : 0 : g_print ("g_io_win32_fd_write: fd=%d count=%" G_GSIZE_FORMAT " => %d\n",
1261 : 0 : win32_channel->fd, count, result);
1262 : :
1263 : 109 : if (result < 0)
1264 : : {
1265 : 0 : *bytes_written = 0;
1266 : :
1267 : 0 : switch (errsv)
1268 : : {
1269 : : #ifdef EAGAIN
1270 : : case EAGAIN:
1271 : 0 : return G_IO_STATUS_AGAIN;
1272 : : #endif
1273 : : default:
1274 : 0 : g_set_error_literal (err, G_IO_CHANNEL_ERROR,
1275 : 0 : g_io_channel_error_from_errno (errsv),
1276 : 0 : g_strerror (errsv));
1277 : 0 : return G_IO_STATUS_ERROR;
1278 : : }
1279 : : }
1280 : :
1281 : 109 : *bytes_written = result;
1282 : :
1283 : 109 : return G_IO_STATUS_NORMAL;
1284 : 109 : }
1285 : :
1286 : : static GIOStatus
1287 : 0 : g_io_win32_fd_seek (GIOChannel *channel,
1288 : : gint64 offset,
1289 : : GSeekType type,
1290 : : GError **err)
1291 : : {
1292 : 0 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1293 : : int whence, errsv;
1294 : : gint64 result;
1295 : :
1296 : 0 : switch (type)
1297 : : {
1298 : : case G_SEEK_SET:
1299 : 0 : whence = SEEK_SET;
1300 : 0 : break;
1301 : : case G_SEEK_CUR:
1302 : 0 : whence = SEEK_CUR;
1303 : 0 : break;
1304 : : case G_SEEK_END:
1305 : 0 : whence = SEEK_END;
1306 : 0 : break;
1307 : : default:
1308 : 0 : whence = -1; /* Keep the compiler quiet */
1309 : : g_assert_not_reached ();
1310 : 0 : g_abort ();
1311 : : }
1312 : :
1313 : 0 : result = _lseeki64 (win32_channel->fd, offset, whence);
1314 : 0 : errsv = errno;
1315 : :
1316 : 0 : if (result < 0)
1317 : : {
1318 : 0 : g_set_error_literal (err, G_IO_CHANNEL_ERROR,
1319 : 0 : g_io_channel_error_from_errno (errsv),
1320 : 0 : g_strerror (errsv));
1321 : 0 : return G_IO_STATUS_ERROR;
1322 : : }
1323 : :
1324 : 0 : return G_IO_STATUS_NORMAL;
1325 : 0 : }
1326 : :
1327 : : static GIOStatus
1328 : 522 : g_io_win32_fd_close (GIOChannel *channel,
1329 : : GError **err)
1330 : : {
1331 : 522 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1332 : :
1333 : 522 : if (win32_channel->debug)
1334 : 0 : g_print ("g_io_win32_fd_close: thread=%#x: fd=%d\n",
1335 : 0 : win32_channel->thread_id,
1336 : 0 : win32_channel->fd);
1337 : 522 : EnterCriticalSection (&win32_channel->mutex);
1338 : 522 : if (win32_channel->running)
1339 : : {
1340 : 0 : if (win32_channel->debug)
1341 : 0 : g_print ("thread %#x: running, marking fd %d for later close\n",
1342 : 0 : win32_channel->thread_id, win32_channel->fd);
1343 : 0 : win32_channel->running = FALSE;
1344 : 0 : win32_channel->needs_close = TRUE;
1345 : 0 : if (win32_channel->direction == 0)
1346 : 0 : SetEvent (win32_channel->data_avail_event);
1347 : : else
1348 : 0 : SetEvent (win32_channel->space_avail_event);
1349 : 0 : }
1350 : : else
1351 : : {
1352 : 522 : if (win32_channel->debug)
1353 : 0 : g_print ("closing fd %d\n", win32_channel->fd);
1354 : 522 : close (win32_channel->fd);
1355 : 522 : if (win32_channel->debug)
1356 : 0 : g_print ("closed fd %d, setting to -1\n",
1357 : 0 : win32_channel->fd);
1358 : 522 : win32_channel->fd = -1;
1359 : : }
1360 : 522 : LeaveCriticalSection (&win32_channel->mutex);
1361 : :
1362 : : /* FIXME error detection? */
1363 : :
1364 : 522 : return G_IO_STATUS_NORMAL;
1365 : : }
1366 : :
1367 : : static GSource *
1368 : 532 : g_io_win32_fd_create_watch (GIOChannel *channel,
1369 : : GIOCondition condition)
1370 : : {
1371 : 532 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1372 : 532 : GSource *source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
1373 : 532 : GIOWin32Watch *watch = (GIOWin32Watch *)source;
1374 : :
1375 : 532 : watch->channel = channel;
1376 : 532 : g_io_channel_ref (channel);
1377 : :
1378 : 532 : watch->condition = condition;
1379 : :
1380 : 532 : if (win32_channel->data_avail_event == NULL)
1381 : 529 : create_events (win32_channel);
1382 : :
1383 : 532 : watch->pollfd.fd = (gintptr) win32_channel->data_avail_event;
1384 : 532 : watch->pollfd.events = condition;
1385 : :
1386 : 532 : if (win32_channel->debug)
1387 : 0 : g_print ("g_io_win32_fd_create_watch: channel=%p fd=%d condition={%s} event=%p\n",
1388 : 0 : channel, win32_channel->fd,
1389 : 0 : condition_to_string (condition), (HANDLE) watch->pollfd.fd);
1390 : :
1391 : 532 : EnterCriticalSection (&win32_channel->mutex);
1392 : 532 : if (win32_channel->thread_id == 0)
1393 : : {
1394 : 529 : if (condition & G_IO_IN)
1395 : 529 : create_thread (win32_channel, condition, read_thread);
1396 : 0 : else if (condition & G_IO_OUT)
1397 : 0 : create_thread (win32_channel, condition, write_thread);
1398 : 529 : }
1399 : :
1400 : 532 : g_source_add_poll (source, &watch->pollfd);
1401 : 532 : LeaveCriticalSection (&win32_channel->mutex);
1402 : :
1403 : 532 : return source;
1404 : : }
1405 : :
1406 : : static GIOStatus
1407 : 1 : g_io_win32_console_close (GIOChannel *channel,
1408 : : GError **err)
1409 : : {
1410 : 1 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1411 : :
1412 : 1 : if (close (win32_channel->fd) < 0)
1413 : : {
1414 : 0 : int errsv = errno;
1415 : 0 : g_set_error_literal (err, G_IO_CHANNEL_ERROR,
1416 : 0 : g_io_channel_error_from_errno (errsv),
1417 : 0 : g_strerror (errsv));
1418 : 0 : return G_IO_STATUS_ERROR;
1419 : : }
1420 : :
1421 : 1 : return G_IO_STATUS_NORMAL;
1422 : 1 : }
1423 : :
1424 : : static GSource *
1425 : 1 : g_io_win32_console_create_watch (GIOChannel *channel,
1426 : : GIOCondition condition)
1427 : : {
1428 : 1 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1429 : 1 : GSource *source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
1430 : 1 : GIOWin32Watch *watch = (GIOWin32Watch *)source;
1431 : :
1432 : 1 : watch->channel = channel;
1433 : 1 : g_io_channel_ref (channel);
1434 : :
1435 : 1 : watch->condition = condition;
1436 : :
1437 : 1 : watch->pollfd.fd = _get_osfhandle (win32_channel->fd);
1438 : 1 : watch->pollfd.events = condition;
1439 : :
1440 : 1 : g_source_add_poll (source, &watch->pollfd);
1441 : :
1442 : 1 : return source;
1443 : : }
1444 : :
1445 : : static GIOStatus
1446 : 0 : g_io_win32_sock_read (GIOChannel *channel,
1447 : : gchar *buf,
1448 : : gsize count,
1449 : : gsize *bytes_read,
1450 : : GError **err)
1451 : : {
1452 : 0 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1453 : : gint result;
1454 : : GIOChannelError error;
1455 : 0 : int winsock_error = 0;
1456 : :
1457 : 0 : if (win32_channel->debug)
1458 : 0 : g_print ("g_io_win32_sock_read: channel=%p sock=%d count=%" G_GSIZE_FORMAT,
1459 : 0 : channel, win32_channel->fd, count);
1460 : :
1461 : 0 : result = recv (win32_channel->fd, buf, count, 0);
1462 : 0 : if (result == SOCKET_ERROR)
1463 : 0 : winsock_error = WSAGetLastError ();
1464 : :
1465 : 0 : if (win32_channel->debug)
1466 : 0 : g_print (" recv=%d", result);
1467 : :
1468 : 0 : if (result == SOCKET_ERROR)
1469 : : {
1470 : 0 : gchar *emsg = g_win32_error_message (winsock_error);
1471 : :
1472 : 0 : if (win32_channel->debug)
1473 : 0 : g_print (" %s\n", emsg);
1474 : :
1475 : 0 : *bytes_read = 0;
1476 : :
1477 : 0 : switch (winsock_error)
1478 : : {
1479 : : case WSAEINVAL:
1480 : 0 : error = G_IO_CHANNEL_ERROR_INVAL;
1481 : 0 : break;
1482 : : case WSAEWOULDBLOCK:
1483 : 0 : g_free (emsg);
1484 : 0 : return G_IO_STATUS_AGAIN;
1485 : : default:
1486 : 0 : error = G_IO_CHANNEL_ERROR_FAILED;
1487 : 0 : break;
1488 : : }
1489 : 0 : g_set_error_literal (err, G_IO_CHANNEL_ERROR, error, emsg);
1490 : 0 : g_free (emsg);
1491 : :
1492 : 0 : return G_IO_STATUS_ERROR;
1493 : : }
1494 : : else
1495 : : {
1496 : 0 : if (win32_channel->debug)
1497 : 0 : g_print ("\n");
1498 : 0 : *bytes_read = result;
1499 : 0 : if (result == 0)
1500 : 0 : return G_IO_STATUS_EOF;
1501 : : else
1502 : 0 : return G_IO_STATUS_NORMAL;
1503 : : }
1504 : 0 : }
1505 : :
1506 : : static GIOStatus
1507 : 0 : g_io_win32_sock_write (GIOChannel *channel,
1508 : : const gchar *buf,
1509 : : gsize count,
1510 : : gsize *bytes_written,
1511 : : GError **err)
1512 : : {
1513 : 0 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1514 : : gint result;
1515 : : GIOChannelError error;
1516 : 0 : int winsock_error = 0;
1517 : :
1518 : 0 : if (win32_channel->debug)
1519 : 0 : g_print ("g_io_win32_sock_write: channel=%p sock=%d count=%" G_GSIZE_FORMAT,
1520 : 0 : channel, win32_channel->fd, count);
1521 : :
1522 : 0 : result = send (win32_channel->fd, buf, count, 0);
1523 : 0 : if (result == SOCKET_ERROR)
1524 : 0 : winsock_error = WSAGetLastError ();
1525 : :
1526 : 0 : if (win32_channel->debug)
1527 : 0 : g_print (" send=%d", result);
1528 : :
1529 : 0 : if (result == SOCKET_ERROR)
1530 : : {
1531 : 0 : gchar *emsg = g_win32_error_message (winsock_error);
1532 : :
1533 : 0 : if (win32_channel->debug)
1534 : 0 : g_print (" %s\n", emsg);
1535 : :
1536 : 0 : *bytes_written = 0;
1537 : :
1538 : 0 : switch (winsock_error)
1539 : : {
1540 : : case WSAEINVAL:
1541 : 0 : error = G_IO_CHANNEL_ERROR_INVAL;
1542 : 0 : break;
1543 : : case WSAEWOULDBLOCK:
1544 : 0 : win32_channel->write_would_have_blocked = TRUE;
1545 : 0 : win32_channel->last_events = 0;
1546 : 0 : g_free (emsg);
1547 : 0 : return G_IO_STATUS_AGAIN;
1548 : : default:
1549 : 0 : error = G_IO_CHANNEL_ERROR_FAILED;
1550 : 0 : break;
1551 : : }
1552 : 0 : g_set_error_literal (err, G_IO_CHANNEL_ERROR, error, emsg);
1553 : 0 : g_free (emsg);
1554 : :
1555 : 0 : return G_IO_STATUS_ERROR;
1556 : : }
1557 : : else
1558 : : {
1559 : 0 : if (win32_channel->debug)
1560 : 0 : g_print ("\n");
1561 : 0 : *bytes_written = result;
1562 : 0 : win32_channel->write_would_have_blocked = FALSE;
1563 : :
1564 : 0 : return G_IO_STATUS_NORMAL;
1565 : : }
1566 : 0 : }
1567 : :
1568 : : static GIOStatus
1569 : 0 : g_io_win32_sock_close (GIOChannel *channel,
1570 : : GError **err)
1571 : : {
1572 : 0 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1573 : :
1574 : 0 : if (win32_channel->fd != -1)
1575 : : {
1576 : 0 : if (win32_channel->debug)
1577 : 0 : g_print ("g_io_win32_sock_close: channel=%p sock=%d\n",
1578 : 0 : channel, win32_channel->fd);
1579 : :
1580 : 0 : closesocket (win32_channel->fd);
1581 : 0 : win32_channel->fd = -1;
1582 : 0 : }
1583 : :
1584 : : /* FIXME error detection? */
1585 : :
1586 : 0 : return G_IO_STATUS_NORMAL;
1587 : : }
1588 : :
1589 : : static GSource *
1590 : 0 : g_io_win32_sock_create_watch (GIOChannel *channel,
1591 : : GIOCondition condition)
1592 : : {
1593 : 0 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1594 : 0 : GSource *source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
1595 : 0 : GIOWin32Watch *watch = (GIOWin32Watch *)source;
1596 : :
1597 : 0 : watch->channel = channel;
1598 : 0 : g_io_channel_ref (channel);
1599 : :
1600 : 0 : watch->condition = condition;
1601 : :
1602 : 0 : if (win32_channel->event == 0)
1603 : 0 : win32_channel->event = WSACreateEvent ();
1604 : :
1605 : 0 : watch->pollfd.fd = (gintptr) win32_channel->event;
1606 : 0 : watch->pollfd.events = condition;
1607 : :
1608 : 0 : if (win32_channel->debug)
1609 : 0 : g_print ("g_io_win32_sock_create_watch: channel=%p sock=%d event=%p condition={%s}\n",
1610 : 0 : channel, win32_channel->fd, (HANDLE) watch->pollfd.fd,
1611 : 0 : condition_to_string (watch->condition));
1612 : :
1613 : 0 : g_source_add_poll (source, &watch->pollfd);
1614 : :
1615 : 0 : return source;
1616 : : }
1617 : :
1618 : : GIOChannel *
1619 : 8 : g_io_channel_new_file (const gchar *filename,
1620 : : const gchar *mode,
1621 : : GError **error)
1622 : : {
1623 : : int fid, flags, pmode;
1624 : : GIOChannel *channel;
1625 : :
1626 : : enum { /* Cheesy hack */
1627 : : MODE_R = 1 << 0,
1628 : : MODE_W = 1 << 1,
1629 : : MODE_A = 1 << 2,
1630 : : MODE_PLUS = 1 << 3,
1631 : : } G_GNUC_FLAG_ENUM;
1632 : : int mode_num, errsv;
1633 : :
1634 : 8 : g_return_val_if_fail (filename != NULL, NULL);
1635 : 8 : g_return_val_if_fail (mode != NULL, NULL);
1636 : 8 : g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL);
1637 : :
1638 : 8 : switch (mode[0])
1639 : : {
1640 : : case 'r':
1641 : 6 : mode_num = MODE_R;
1642 : 6 : break;
1643 : : case 'w':
1644 : 2 : mode_num = MODE_W;
1645 : 2 : break;
1646 : : case 'a':
1647 : 0 : mode_num = MODE_A;
1648 : 0 : break;
1649 : : default:
1650 : 0 : g_warning ("Invalid GIOFileMode %s.", mode);
1651 : 0 : return NULL;
1652 : : }
1653 : :
1654 : 8 : switch (mode[1])
1655 : : {
1656 : : case '\0':
1657 : 8 : break;
1658 : : case '+':
1659 : 0 : if (mode[2] == '\0')
1660 : : {
1661 : 0 : mode_num |= MODE_PLUS;
1662 : 0 : break;
1663 : : }
1664 : : G_GNUC_FALLTHROUGH;
1665 : : default:
1666 : 0 : g_warning ("Invalid GIOFileMode %s.", mode);
1667 : 0 : return NULL;
1668 : : }
1669 : :
1670 : 8 : switch (mode_num)
1671 : : {
1672 : : case MODE_R:
1673 : 6 : flags = O_RDONLY;
1674 : 6 : pmode = _S_IREAD;
1675 : 6 : break;
1676 : : case MODE_W:
1677 : 2 : flags = O_WRONLY | O_TRUNC | O_CREAT;
1678 : 2 : pmode = _S_IWRITE;
1679 : 2 : break;
1680 : : case MODE_A:
1681 : 0 : flags = O_WRONLY | O_APPEND | O_CREAT;
1682 : 0 : pmode = _S_IWRITE;
1683 : 0 : break;
1684 : : case MODE_R | MODE_PLUS:
1685 : 0 : flags = O_RDWR;
1686 : 0 : pmode = _S_IREAD | _S_IWRITE;
1687 : 0 : break;
1688 : : case MODE_W | MODE_PLUS:
1689 : 0 : flags = O_RDWR | O_TRUNC | O_CREAT;
1690 : 0 : pmode = _S_IREAD | _S_IWRITE;
1691 : 0 : break;
1692 : : case MODE_A | MODE_PLUS:
1693 : 0 : flags = O_RDWR | O_APPEND | O_CREAT;
1694 : 0 : pmode = _S_IREAD | _S_IWRITE;
1695 : 0 : break;
1696 : : default:
1697 : : g_assert_not_reached ();
1698 : 0 : g_abort ();
1699 : : }
1700 : :
1701 : : /* always open 'untranslated' */
1702 : 8 : fid = g_open (filename, flags | _O_BINARY, pmode);
1703 : 8 : errsv = errno;
1704 : :
1705 : 8 : if (g_io_win32_get_debug_flag ())
1706 : : {
1707 : 0 : g_print ("g_io_channel_win32_new_file: open(\"%s\",", filename);
1708 : 0 : g_win32_print_access_mode (flags|_O_BINARY);
1709 : 0 : g_print (",%#o)=%d\n", pmode, fid);
1710 : 0 : }
1711 : :
1712 : 8 : if (fid < 0)
1713 : : {
1714 : 0 : g_set_error_literal (error, G_FILE_ERROR,
1715 : 0 : g_file_error_from_errno (errsv),
1716 : 0 : g_strerror (errsv));
1717 : 0 : return (GIOChannel *)NULL;
1718 : : }
1719 : :
1720 : 8 : channel = g_io_channel_win32_new_fd (fid);
1721 : :
1722 : : /* XXX: move this to g_io_channel_win32_new_fd () */
1723 : 8 : channel->close_on_unref = TRUE;
1724 : 8 : channel->is_seekable = TRUE;
1725 : :
1726 : : /* g_io_channel_win32_new_fd sets is_readable and is_writeable to
1727 : : * correspond to actual readability/writeability. Set to FALSE those
1728 : : * that mode doesn't allow
1729 : : */
1730 : 8 : switch (mode_num)
1731 : : {
1732 : : case MODE_R:
1733 : 6 : channel->is_writeable = FALSE;
1734 : 6 : break;
1735 : : case MODE_W:
1736 : : case MODE_A:
1737 : 2 : channel->is_readable = FALSE;
1738 : 2 : break;
1739 : : case MODE_R | MODE_PLUS:
1740 : : case MODE_W | MODE_PLUS:
1741 : : case MODE_A | MODE_PLUS:
1742 : 0 : break;
1743 : : default:
1744 : : g_assert_not_reached ();
1745 : 0 : g_abort ();
1746 : : }
1747 : :
1748 : 8 : return channel;
1749 : 8 : }
1750 : :
1751 : : static GIOStatus
1752 : 36 : g_io_win32_unimpl_set_flags (GIOChannel *channel,
1753 : : GIOFlags flags,
1754 : : GError **err)
1755 : : {
1756 : 36 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1757 : :
1758 : 36 : if (win32_channel->debug)
1759 : : {
1760 : 0 : g_print ("g_io_win32_unimpl_set_flags: ");
1761 : 0 : g_win32_print_gioflags (flags);
1762 : 0 : g_print ("\n");
1763 : 0 : }
1764 : :
1765 : 36 : g_set_error_literal (err, G_IO_CHANNEL_ERROR,
1766 : : G_IO_CHANNEL_ERROR_FAILED,
1767 : : "Not implemented on Win32");
1768 : :
1769 : 36 : return G_IO_STATUS_ERROR;
1770 : : }
1771 : :
1772 : : static GIOFlags
1773 : 729 : g_io_win32_fd_get_flags_internal (GIOChannel *channel,
1774 : : struct _stati64 *st)
1775 : : {
1776 : 729 : GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
1777 : : gchar c;
1778 : : DWORD count;
1779 : :
1780 : 729 : if (st->st_mode & _S_IFIFO)
1781 : : {
1782 : 720 : channel->is_readable =
1783 : 720 : (PeekNamedPipe ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL, NULL) != 0) || GetLastError () == ERROR_BROKEN_PIPE;
1784 : 720 : channel->is_writeable =
1785 : 720 : (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1786 : 720 : channel->is_seekable = FALSE;
1787 : 720 : }
1788 : : else
1789 : : {
1790 : 9 : channel->is_readable =
1791 : 9 : (ReadFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1792 : 9 : channel->is_writeable =
1793 : 9 : (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1794 : 9 : channel->is_seekable = TRUE;
1795 : : }
1796 : :
1797 : : /* XXX: G_IO_FLAG_APPEND */
1798 : : /* XXX: G_IO_FLAG_NONBLOCK */
1799 : :
1800 : 729 : return 0;
1801 : : }
1802 : :
1803 : : static GIOFlags
1804 : 27 : g_io_win32_fd_get_flags (GIOChannel *channel)
1805 : : {
1806 : : struct _stati64 st;
1807 : 27 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1808 : :
1809 : 27 : g_return_val_if_fail (win32_channel != NULL, 0);
1810 : 27 : g_return_val_if_fail (win32_channel->type == G_IO_WIN32_FILE_DESC, 0);
1811 : :
1812 : 27 : if (0 == _fstati64 (win32_channel->fd, &st))
1813 : 27 : return g_io_win32_fd_get_flags_internal (channel, &st);
1814 : : else
1815 : 0 : return 0;
1816 : 27 : }
1817 : :
1818 : : static GIOFlags
1819 : 14 : g_io_win32_console_get_flags_internal (GIOChannel *channel)
1820 : : {
1821 : 14 : GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
1822 : 14 : HANDLE handle = (HANDLE) _get_osfhandle (win32_channel->fd);
1823 : 14 : gchar c = 0;
1824 : : DWORD count;
1825 : : INPUT_RECORD record;
1826 : :
1827 : 14 : channel->is_readable = PeekConsoleInput (handle, &record, 1, &count);
1828 : 14 : channel->is_writeable = WriteFile (handle, &c, 0, &count, NULL);
1829 : 14 : channel->is_seekable = FALSE;
1830 : :
1831 : 14 : return 0;
1832 : : }
1833 : :
1834 : : static GIOFlags
1835 : 4 : g_io_win32_console_get_flags (GIOChannel *channel)
1836 : : {
1837 : 4 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1838 : :
1839 : 4 : g_return_val_if_fail (win32_channel != NULL, 0);
1840 : 4 : g_return_val_if_fail (win32_channel->type == G_IO_WIN32_CONSOLE, 0);
1841 : :
1842 : 4 : return g_io_win32_console_get_flags_internal (channel);
1843 : 4 : }
1844 : :
1845 : : static GIOFlags
1846 : 0 : g_io_win32_msg_get_flags (GIOChannel *channel)
1847 : : {
1848 : 0 : return 0;
1849 : : }
1850 : :
1851 : : static GIOStatus
1852 : 0 : g_io_win32_sock_set_flags (GIOChannel *channel,
1853 : : GIOFlags flags,
1854 : : GError **err)
1855 : : {
1856 : 0 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1857 : : u_long arg;
1858 : :
1859 : 0 : if (win32_channel->debug)
1860 : : {
1861 : 0 : g_print ("g_io_win32_sock_set_flags: ");
1862 : 0 : g_win32_print_gioflags (flags);
1863 : 0 : g_print ("\n");
1864 : 0 : }
1865 : :
1866 : 0 : if (flags & G_IO_FLAG_NONBLOCK)
1867 : : {
1868 : 0 : arg = 1;
1869 : 0 : if (ioctlsocket (win32_channel->fd, FIONBIO, &arg) == SOCKET_ERROR)
1870 : : {
1871 : 0 : gchar *emsg = g_win32_error_message (WSAGetLastError ());
1872 : :
1873 : 0 : g_set_error_literal (err, G_IO_CHANNEL_ERROR,
1874 : : G_IO_CHANNEL_ERROR_FAILED,
1875 : 0 : emsg);
1876 : 0 : g_free (emsg);
1877 : :
1878 : 0 : return G_IO_STATUS_ERROR;
1879 : : }
1880 : 0 : }
1881 : : else
1882 : : {
1883 : 0 : arg = 0;
1884 : 0 : if (ioctlsocket (win32_channel->fd, FIONBIO, &arg) == SOCKET_ERROR)
1885 : : {
1886 : 0 : gchar *emsg = g_win32_error_message (WSAGetLastError ());
1887 : :
1888 : 0 : g_set_error_literal (err, G_IO_CHANNEL_ERROR,
1889 : : G_IO_CHANNEL_ERROR_FAILED,
1890 : 0 : emsg);
1891 : 0 : g_free (emsg);
1892 : :
1893 : 0 : return G_IO_STATUS_ERROR;
1894 : : }
1895 : : }
1896 : :
1897 : 0 : return G_IO_STATUS_NORMAL;
1898 : 0 : }
1899 : :
1900 : : static GIOFlags
1901 : 0 : g_io_win32_sock_get_flags (GIOChannel *channel)
1902 : : {
1903 : : /* Could we do something here? */
1904 : 0 : return 0;
1905 : : }
1906 : :
1907 : : static GIOFuncs win32_channel_msg_funcs = {
1908 : : g_io_win32_msg_read,
1909 : : g_io_win32_msg_write,
1910 : : NULL,
1911 : : g_io_win32_msg_close,
1912 : : g_io_win32_msg_create_watch,
1913 : : g_io_win32_free,
1914 : : g_io_win32_unimpl_set_flags,
1915 : : g_io_win32_msg_get_flags,
1916 : : };
1917 : :
1918 : : static GIOFuncs win32_channel_fd_funcs = {
1919 : : g_io_win32_fd_and_console_read,
1920 : : g_io_win32_fd_and_console_write,
1921 : : g_io_win32_fd_seek,
1922 : : g_io_win32_fd_close,
1923 : : g_io_win32_fd_create_watch,
1924 : : g_io_win32_free,
1925 : : g_io_win32_unimpl_set_flags,
1926 : : g_io_win32_fd_get_flags,
1927 : : };
1928 : :
1929 : : static GIOFuncs win32_channel_console_funcs = {
1930 : : g_io_win32_fd_and_console_read,
1931 : : g_io_win32_fd_and_console_write,
1932 : : NULL,
1933 : : g_io_win32_console_close,
1934 : : g_io_win32_console_create_watch,
1935 : : g_io_win32_free,
1936 : : g_io_win32_unimpl_set_flags,
1937 : : g_io_win32_console_get_flags,
1938 : : };
1939 : :
1940 : : static GIOFuncs win32_channel_sock_funcs = {
1941 : : g_io_win32_sock_read,
1942 : : g_io_win32_sock_write,
1943 : : NULL,
1944 : : g_io_win32_sock_close,
1945 : : g_io_win32_sock_create_watch,
1946 : : g_io_win32_free,
1947 : : g_io_win32_sock_set_flags,
1948 : : g_io_win32_sock_get_flags,
1949 : : };
1950 : :
1951 : : /**
1952 : : * g_io_channel_win32_new_messages:
1953 : : * @hwnd: a window handle.
1954 : : *
1955 : : * Creates a new #GIOChannel given a window handle on Windows.
1956 : : *
1957 : : * This function creates a #GIOChannel that can be used to poll for
1958 : : * Windows messages for the window in question.
1959 : : *
1960 : : * Returns: a new #GIOChannel.
1961 : : **/
1962 : : GIOChannel *
1963 : : #if GLIB_SIZEOF_VOID_P == 8
1964 : 1 : g_io_channel_win32_new_messages (gsize hwnd)
1965 : : #else
1966 : : g_io_channel_win32_new_messages (guint hwnd)
1967 : : #endif
1968 : : {
1969 : 1 : GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1970 : 1 : GIOChannel *channel = (GIOChannel *)win32_channel;
1971 : :
1972 : 1 : g_io_channel_init (channel);
1973 : 1 : g_io_channel_win32_init (win32_channel);
1974 : 1 : if (win32_channel->debug)
1975 : 0 : g_print ("g_io_channel_win32_new_messages: channel=%p hwnd=%p\n",
1976 : 0 : channel, (HWND) hwnd);
1977 : 1 : channel->funcs = &win32_channel_msg_funcs;
1978 : 1 : win32_channel->type = G_IO_WIN32_WINDOWS_MESSAGES;
1979 : 1 : win32_channel->hwnd = (HWND) hwnd;
1980 : :
1981 : : /* XXX: check this. */
1982 : 1 : channel->is_readable = IsWindow (win32_channel->hwnd);
1983 : 1 : channel->is_writeable = IsWindow (win32_channel->hwnd);
1984 : :
1985 : 1 : channel->is_seekable = FALSE;
1986 : :
1987 : 1 : return channel;
1988 : : }
1989 : :
1990 : : static GIOChannel *
1991 : 712 : g_io_channel_win32_new_fd_internal (gint fd,
1992 : : struct _stati64 *st)
1993 : : {
1994 : : GIOWin32Channel *win32_channel;
1995 : : GIOChannel *channel;
1996 : :
1997 : 712 : win32_channel = g_new (GIOWin32Channel, 1);
1998 : 712 : channel = (GIOChannel *)win32_channel;
1999 : :
2000 : 712 : g_io_channel_init (channel);
2001 : 712 : g_io_channel_win32_init (win32_channel);
2002 : :
2003 : 712 : win32_channel->fd = fd;
2004 : :
2005 : 712 : if (win32_channel->debug)
2006 : 0 : g_print ("g_io_channel_win32_new_fd: channel=%p fd=%u\n",
2007 : 0 : channel, fd);
2008 : :
2009 : 712 : if (st->st_mode & _S_IFCHR) /* console */
2010 : : {
2011 : 10 : channel->funcs = &win32_channel_console_funcs;
2012 : 10 : win32_channel->type = G_IO_WIN32_CONSOLE;
2013 : 10 : g_io_win32_console_get_flags_internal (channel);
2014 : 10 : }
2015 : : else
2016 : : {
2017 : 702 : channel->funcs = &win32_channel_fd_funcs;
2018 : 702 : win32_channel->type = G_IO_WIN32_FILE_DESC;
2019 : 702 : g_io_win32_fd_get_flags_internal (channel, st);
2020 : : }
2021 : :
2022 : 712 : return channel;
2023 : : }
2024 : :
2025 : : /**
2026 : : * g_io_channel_win32_new_fd:
2027 : : * @fd: a C library file descriptor.
2028 : : *
2029 : : * Creates a new #GIOChannel given a file descriptor on Windows. This
2030 : : * works for file descriptors from the C runtime.
2031 : : *
2032 : : * This function works for file descriptors as returned by the open(),
2033 : : * creat(), pipe() and fileno() calls in the Microsoft C runtime. In
2034 : : * order to meaningfully use this function your code should use the
2035 : : * same C runtime as GLib uses, which is msvcrt.dll. Note that in
2036 : : * current Microsoft compilers it is near impossible to convince it to
2037 : : * build code that would use msvcrt.dll. The last Microsoft compiler
2038 : : * version that supported using msvcrt.dll as the C runtime was version 6.
2039 : : * The GNU compiler and toolchain for Windows, also known as Mingw,
2040 : : * fully supports msvcrt.dll.
2041 : : *
2042 : : * If you have created a #GIOChannel for a file descriptor and started
2043 : : * watching (polling) it, you shouldn't call read() on the file
2044 : : * descriptor. This is because adding polling for a file descriptor is
2045 : : * implemented in GLib on Windows by starting a thread that sits
2046 : : * blocked in a read() from the file descriptor most of the time. All
2047 : : * reads from the file descriptor should be done by this internal GLib
2048 : : * thread. Your code should call only g_io_channel_read().
2049 : : *
2050 : : * This function is available only in GLib on Windows.
2051 : : *
2052 : : * Returns: a new #GIOChannel.
2053 : : **/
2054 : : GIOChannel *
2055 : 76 : g_io_channel_win32_new_fd (gint fd)
2056 : : {
2057 : : struct _stati64 st;
2058 : :
2059 : 76 : if (_fstati64 (fd, &st) == -1)
2060 : : {
2061 : 0 : g_warning ("g_io_channel_win32_new_fd: %d isn't an open file descriptor in the C library GLib uses.", fd);
2062 : 0 : return NULL;
2063 : : }
2064 : :
2065 : 76 : return g_io_channel_win32_new_fd_internal (fd, &st);
2066 : 76 : }
2067 : :
2068 : : gint
2069 : 24 : g_io_channel_win32_get_fd (GIOChannel *channel)
2070 : : {
2071 : 24 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
2072 : :
2073 : 24 : return win32_channel->fd;
2074 : : }
2075 : :
2076 : : /**
2077 : : * g_io_channel_win32_new_socket:
2078 : : * @socket: a Winsock socket
2079 : : *
2080 : : * Creates a new #GIOChannel given a socket on Windows.
2081 : : *
2082 : : * This function works for sockets created by Winsock. It's available
2083 : : * only in GLib on Windows.
2084 : : *
2085 : : * Polling a #GSource created to watch a channel for a socket puts the
2086 : : * socket in non-blocking mode. This is a side-effect of the
2087 : : * implementation and unavoidable.
2088 : : *
2089 : : * Returns: a new #GIOChannel
2090 : : **/
2091 : : GIOChannel *
2092 : 0 : g_io_channel_win32_new_socket (int socket)
2093 : : {
2094 : 0 : GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
2095 : 0 : GIOChannel *channel = (GIOChannel *)win32_channel;
2096 : :
2097 : 0 : g_io_channel_init (channel);
2098 : 0 : g_io_channel_win32_init (win32_channel);
2099 : 0 : if (win32_channel->debug)
2100 : 0 : g_print ("g_io_channel_win32_new_socket: channel=%p sock=%d\n",
2101 : 0 : channel, socket);
2102 : 0 : channel->funcs = &win32_channel_sock_funcs;
2103 : 0 : win32_channel->type = G_IO_WIN32_SOCKET;
2104 : 0 : win32_channel->fd = socket;
2105 : :
2106 : 0 : channel->is_readable = TRUE;
2107 : 0 : channel->is_writeable = TRUE;
2108 : 0 : channel->is_seekable = FALSE;
2109 : :
2110 : 0 : return channel;
2111 : : }
2112 : :
2113 : : GIOChannel *
2114 : 636 : g_io_channel_unix_new (gint fd)
2115 : : {
2116 : : gboolean is_fd, is_socket;
2117 : : struct _stati64 st;
2118 : : int optval, optlen;
2119 : :
2120 : 636 : is_fd = (_fstati64 (fd, &st) == 0);
2121 : :
2122 : 636 : optlen = sizeof (optval);
2123 : 636 : is_socket = (getsockopt (fd, SOL_SOCKET, SO_TYPE, (char *) &optval, &optlen) != SOCKET_ERROR);
2124 : :
2125 : 636 : if (is_fd && is_socket)
2126 : 0 : g_warning ("g_io_channel_unix_new: %d is both a file descriptor and a socket. File descriptor interpretation assumed. To avoid ambiguity, call either g_io_channel_win32_new_fd() or g_io_channel_win32_new_socket() instead.", fd);
2127 : :
2128 : 636 : if (is_fd)
2129 : 636 : return g_io_channel_win32_new_fd_internal (fd, &st);
2130 : :
2131 : 0 : if (is_socket)
2132 : 0 : return g_io_channel_win32_new_socket(fd);
2133 : :
2134 : 0 : g_warning ("g_io_channel_unix_new: %d is neither a file descriptor or a socket.", fd);
2135 : :
2136 : 0 : return NULL;
2137 : 636 : }
2138 : :
2139 : : gint
2140 : 24 : g_io_channel_unix_get_fd (GIOChannel *channel)
2141 : : {
2142 : 24 : return g_io_channel_win32_get_fd (channel);
2143 : : }
2144 : :
2145 : : void
2146 : 0 : g_io_channel_win32_set_debug (GIOChannel *channel,
2147 : : gboolean flag)
2148 : : {
2149 : 0 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
2150 : :
2151 : 0 : win32_channel->debug = flag;
2152 : 0 : }
2153 : :
2154 : : gint
2155 : 254 : g_io_channel_win32_poll (GPollFD *fds,
2156 : : gint n_fds,
2157 : : gint timeout)
2158 : : {
2159 : 254 : g_return_val_if_fail (n_fds >= 0, 0);
2160 : :
2161 : 254 : return g_poll (fds, n_fds, timeout);
2162 : 254 : }
2163 : :
2164 : : void
2165 : 66 : g_io_channel_win32_make_pollfd (GIOChannel *channel,
2166 : : GIOCondition condition,
2167 : : GPollFD *fd)
2168 : : {
2169 : 66 : GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
2170 : :
2171 : 66 : switch (win32_channel->type)
2172 : : {
2173 : : case G_IO_WIN32_FILE_DESC:
2174 : 66 : if (win32_channel->data_avail_event == NULL)
2175 : 65 : create_events (win32_channel);
2176 : :
2177 : 66 : fd->fd = (gintptr) win32_channel->data_avail_event;
2178 : :
2179 : 66 : if (win32_channel->thread_id == 0)
2180 : : {
2181 : : /* Is it meaningful for a file descriptor to be polled for
2182 : : * both IN and OUT? For what kind of file descriptor would
2183 : : * that be? Doesn't seem to make sense, in practise the file
2184 : : * descriptors handled here are always read or write ends of
2185 : : * pipes surely, and thus unidirectional.
2186 : : */
2187 : 65 : if (condition & G_IO_IN)
2188 : 65 : create_thread (win32_channel, condition, read_thread);
2189 : 0 : else if (condition & G_IO_OUT)
2190 : 0 : create_thread (win32_channel, condition, write_thread);
2191 : 65 : }
2192 : 66 : break;
2193 : :
2194 : : case G_IO_WIN32_CONSOLE:
2195 : 0 : fd->fd = _get_osfhandle (win32_channel->fd);
2196 : 0 : break;
2197 : :
2198 : : case G_IO_WIN32_SOCKET:
2199 : 0 : fd->fd = (gintptr) WSACreateEvent ();
2200 : 0 : break;
2201 : :
2202 : : case G_IO_WIN32_WINDOWS_MESSAGES:
2203 : 0 : fd->fd = G_WIN32_MSG_HANDLE;
2204 : 0 : break;
2205 : :
2206 : : default:
2207 : : g_assert_not_reached ();
2208 : 0 : g_abort ();
2209 : : }
2210 : :
2211 : 66 : fd->events = condition;
2212 : 66 : }
2213 : :
2214 : : #ifndef _WIN64
2215 : :
2216 : : /* Binary compatibility */
2217 : : GIOChannel *
2218 : : g_io_channel_win32_new_stream_socket (int socket)
2219 : : {
2220 : : return g_io_channel_win32_new_socket (socket);
2221 : : }
2222 : :
2223 : : #endif
2224 : :
2225 : : #ifdef G_OS_WIN32
2226 : :
2227 : : /* Binary compatibility versions. Not for newly compiled code. */
2228 : :
2229 : : _GLIB_EXTERN GIOChannel *g_io_channel_new_file_utf8 (const gchar *filename,
2230 : : const gchar *mode,
2231 : : GError **error);
2232 : :
2233 : : GIOChannel *
2234 : 0 : g_io_channel_new_file_utf8 (const gchar *filename,
2235 : : const gchar *mode,
2236 : : GError **error)
2237 : : {
2238 : 0 : return g_io_channel_new_file (filename, mode, error);
2239 : : }
2240 : :
2241 : : #endif
|