Don't modify errno. (#116617, Balazs Scheidler)
[platform/upstream/glib.git] / glib / giowin32.c
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  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
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 /* Define this to get (very) verbose logging of all channels */
33 /* #define G_IO_WIN32_DEBUG */
34
35 #include "config.h"
36
37 #include "glib.h"
38
39 #include <stdlib.h>
40 #include <windows.h>
41 #include <winsock.h>          /* Not everybody has winsock2 */
42 #include <fcntl.h>
43 #include <io.h>
44 #include <process.h>
45 #include <errno.h>
46 #include <sys/stat.h>
47
48 #include "glibintl.h"
49
50 typedef struct _GIOWin32Channel GIOWin32Channel;
51 typedef struct _GIOWin32Watch GIOWin32Watch;
52
53 #define BUFFER_SIZE 4096
54
55 typedef enum {
56   G_IO_WIN32_WINDOWS_MESSAGES,  /* Windows messages */
57   G_IO_WIN32_FILE_DESC,         /* Unix-like file descriptors from
58                                  * _open() or _pipe(). Read with read().
59                                  * Have to create separate thread to read.
60                                  */
61   G_IO_WIN32_SOCKET             /* Sockets. A separate thread is blocked
62                                  * in select() most of the time.
63                                  */
64 } GIOWin32ChannelType;
65
66 struct _GIOWin32Channel {
67   GIOChannel channel;
68   gint fd;                      /* Either a Unix-like file handle as provided
69                                  * by the Microsoft C runtime, or a SOCKET
70                                  * as provided by WinSock.
71                                  */
72   GIOWin32ChannelType type;
73   
74   gboolean debug;
75
76   CRITICAL_SECTION mutex;
77
78   /* This is used by G_IO_WIN32_WINDOWS_MESSAGES channels */
79   HWND hwnd;                    /* handle of window, or NULL */
80   
81   /* Following fields are used by both fd and socket channels. */
82   gboolean running;             /* Is reader thread running. FALSE if
83                                  * EOF has been reached.
84                                  */
85   gboolean needs_close;         /* If the channel has been closed while
86                                  * the reader thread was still running.
87                                  */
88   guint thread_id;              /* If non-NULL has a reader thread, or has
89                                  * had.*/
90   HANDLE data_avail_event;
91
92   gushort revents;
93
94   /* Following fields used by fd channels for input */
95   
96   /* Data is kept in a circular buffer. To be able to distinguish between
97    * empty and full buffer, we cannot fill it completely, but have to
98    * leave a one character gap.
99    *
100    * Data available is between indexes rdp and wrp-1 (modulo BUFFER_SIZE).
101    *
102    * Empty:    wrp == rdp
103    * Full:     (wrp + 1) % BUFFER_SIZE == rdp
104    * Partial:  otherwise
105    */
106   guchar *buffer;               /* (Circular) buffer */
107   gint wrp, rdp;                /* Buffer indices for writing and reading */
108   HANDLE space_avail_event;
109
110   /* Following fields used by socket channels */
111   GSList *watches;
112   HANDLE data_avail_noticed_event;
113   gint reset_send; /* socket used to send data so select_thread() can reset/re-loop */
114   gint reset_recv; /* socket used to recv data so select_thread() can reset/re-loop */
115 };
116
117 #define LOCK(mutex) EnterCriticalSection (&mutex)
118 #define UNLOCK(mutex) LeaveCriticalSection (&mutex)
119
120 struct _GIOWin32Watch {
121   GSource       source;
122   GPollFD       pollfd;
123   GIOChannel   *channel;
124   GIOCondition  condition;
125 };
126
127 static void
128 g_win32_print_access_mode (int flags)
129 {
130   g_print ("%s%s%s%s%s%s%s%s%s%s",
131            ((flags & 0x3) == _O_RDWR ? "O_RDWR" :
132             ((flags & 0x3) == _O_RDONLY ? "O_RDONLY" :
133              ((flags & 0x3) == _O_WRONLY ? "O_WRONLY" : "0"))),
134            (flags & _O_APPEND ? "|O_APPEND" : ""),
135            (flags & _O_RANDOM ? "|O_RANDOM" : ""),
136            (flags & _O_SEQUENTIAL ? "|O_SEQUENTIAL" : ""),
137            (flags & _O_TEMPORARY ? "|O_TEMPORARY" : ""),
138            (flags & _O_CREAT ? "|O_CREAT" : ""),
139            (flags & _O_TRUNC ? "|O_TRUNC" : ""),
140            (flags & _O_EXCL ? "|O_EXCL" : ""),
141            (flags & _O_TEXT ? "|O_TEXT" : ""),
142            (flags & _O_BINARY ? "|O_BINARY" : ""));
143 }
144
145 static void
146 g_win32_print_gioflags (GIOFlags flags)
147 {
148   char *bar = "";
149
150   if (flags & G_IO_FLAG_APPEND)
151     bar = "|", g_print ("APPEND");
152   if (flags & G_IO_FLAG_NONBLOCK)
153     g_print ("%sNONBLOCK", bar), bar = "|";
154   if (flags & G_IO_FLAG_IS_READABLE)
155     g_print ("%sREADABLE", bar), bar = "|";
156   if (flags & G_IO_FLAG_IS_WRITEABLE)
157     g_print ("%sWRITEABLE", bar), bar = "|";
158   if (flags & G_IO_FLAG_IS_WRITEABLE)
159     g_print ("%sWRITEABLE", bar), bar = "|";
160   if (flags & G_IO_FLAG_IS_SEEKABLE)
161     g_print ("%sSEEKABLE", bar), bar = "|";
162 }
163
164 static gboolean
165 g_io_win32_get_debug_flag (void)
166 {
167 #ifdef G_IO_WIN32_DEBUG
168   return TRUE;
169 #else
170   if (getenv ("G_IO_WIN32_DEBUG") != NULL)
171     return TRUE;
172   else
173     return FALSE;
174 #endif
175 }  
176
177 static void
178 g_io_channel_win32_init (GIOWin32Channel *channel)
179 {
180   channel->debug = g_io_win32_get_debug_flag ();
181   channel->buffer = NULL;
182   channel->running = FALSE;
183   channel->needs_close = FALSE;
184   channel->thread_id = 0;
185   channel->data_avail_event = NULL;
186   channel->revents = 0;
187   channel->space_avail_event = NULL;
188   channel->data_avail_noticed_event = NULL;
189   channel->watches = NULL;
190   InitializeCriticalSection (&channel->mutex);
191 }
192
193 static void
194 create_events (GIOWin32Channel *channel)
195 {
196   SECURITY_ATTRIBUTES sec_attrs;
197   
198   sec_attrs.nLength = sizeof (SECURITY_ATTRIBUTES);
199   sec_attrs.lpSecurityDescriptor = NULL;
200   sec_attrs.bInheritHandle = FALSE;
201
202   /* The data available event is manual reset, the space available event
203    * is automatic reset.
204    */
205   if (!(channel->data_avail_event = CreateEvent (&sec_attrs, TRUE, FALSE, NULL))
206       || !(channel->space_avail_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL))
207       || !(channel->data_avail_noticed_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL)))
208     {
209       gchar *emsg = g_win32_error_message (GetLastError ());
210       g_error ("Error creating event: %s", emsg);
211       g_free (emsg);
212     }
213 }
214
215 static unsigned __stdcall
216 read_thread (void *parameter)
217 {
218   GIOWin32Channel *channel = parameter;
219   guchar *buffer;
220   guint nbytes;
221
222   g_io_channel_ref ((GIOChannel *)channel);
223
224   if (channel->debug)
225     g_print ("read_thread %#x: start fd:%d, data_avail:%#x space_avail:%#x\n",
226              channel->thread_id,
227              channel->fd,
228              (guint) channel->data_avail_event,
229              (guint) channel->space_avail_event);
230   
231   channel->buffer = g_malloc (BUFFER_SIZE);
232   channel->rdp = channel->wrp = 0;
233   channel->running = TRUE;
234
235   SetEvent (channel->space_avail_event);
236   
237   LOCK (channel->mutex);
238   while (channel->running)
239     {
240       if (channel->debug)
241         g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
242                  channel->thread_id, channel->rdp, channel->wrp);
243       if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
244         {
245           /* Buffer is full */
246           if (channel->debug)
247             g_print ("read_thread %#x: resetting space_avail\n",
248                      channel->thread_id);
249           ResetEvent (channel->space_avail_event);
250           if (channel->debug)
251             g_print ("read_thread %#x: waiting for space\n",
252                      channel->thread_id);
253           UNLOCK (channel->mutex);
254           WaitForSingleObject (channel->space_avail_event, INFINITE);
255           LOCK (channel->mutex);
256           if (channel->debug)
257             g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
258                      channel->thread_id, channel->rdp, channel->wrp);
259         }
260       
261       buffer = channel->buffer + channel->wrp;
262       
263       /* Always leave at least one byte unused gap to be able to
264        * distinguish between the full and empty condition...
265        */
266       nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE,
267                     BUFFER_SIZE - channel->wrp);
268
269       if (channel->debug)
270         g_print ("read_thread %#x: calling read() for %d bytes\n",
271                  channel->thread_id, nbytes);
272
273       UNLOCK (channel->mutex);
274
275       nbytes = read (channel->fd, buffer, nbytes);
276       
277       LOCK (channel->mutex);
278
279       channel->revents = G_IO_IN;
280       if (nbytes == 0)
281         channel->revents |= G_IO_HUP;
282       else if (nbytes < 0)
283         channel->revents |= G_IO_ERR;
284
285       if (channel->debug)
286         g_print ("read_thread %#x: read() returned %d, rdp=%d, wrp=%d\n",
287                  channel->thread_id, nbytes, channel->rdp, channel->wrp);
288
289       if (nbytes <= 0)
290         break;
291
292       channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE;
293       if (channel->debug)
294         g_print ("read_thread %#x: rdp=%d, wrp=%d, setting data_avail\n",
295                  channel->thread_id, channel->rdp, channel->wrp);
296       SetEvent (channel->data_avail_event);
297     }
298   
299   channel->running = FALSE;
300   if (channel->needs_close)
301     {
302       if (channel->debug)
303         g_print ("read_thread %#x: channel fd %d needs closing\n",
304                  channel->thread_id, channel->fd);
305       close (channel->fd);
306       channel->fd = -1;
307     }
308
309   if (channel->debug)
310     g_print ("read_thread %#x: EOF, rdp=%d, wrp=%d, setting data_avail\n",
311              channel->thread_id, channel->rdp, channel->wrp);
312   SetEvent (channel->data_avail_event);
313   UNLOCK (channel->mutex);
314   
315   g_io_channel_unref ((GIOChannel *)channel);
316   
317   /* No need to call _endthreadex(), the actual thread starter routine
318    * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
319    * _endthreadex() for us.
320    */
321
322   return 0;
323 }
324
325 static void
326 create_thread (GIOWin32Channel     *channel,
327                GIOCondition         condition,
328                unsigned (__stdcall *thread) (void *parameter))
329 {
330   HANDLE thread_handle;
331
332   thread_handle = (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0,
333                                            &channel->thread_id);
334   if (thread_handle == 0)
335     g_warning (G_STRLOC ": Error creating reader thread: %s",
336                g_strerror (errno));
337   else if (!CloseHandle (thread_handle))
338     g_warning (G_STRLOC ": Error closing thread handle: %s\n",
339                g_win32_error_message (GetLastError ()));
340
341   WaitForSingleObject (channel->space_avail_event, INFINITE);
342 }
343
344 static void
345 init_reset_sockets (GIOWin32Channel *channel)
346 {
347   struct sockaddr_in local, local2, server;
348   int len;
349
350   channel->reset_send = (gint) socket (AF_INET, SOCK_DGRAM, 0);
351   if (channel->reset_send == INVALID_SOCKET)
352     {
353       g_warning (G_STRLOC ": Error creating reset_send socket: %s\n",
354                  g_win32_error_message (WSAGetLastError ()));
355     }
356
357   local.sin_family = AF_INET;
358   local.sin_port = 0;
359   local.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
360
361   if (bind (channel->reset_send, (struct sockaddr *)&local, sizeof (local)) == SOCKET_ERROR)
362     {
363       g_warning (G_STRLOC ": Error binding to reset_send socket: %s\n",
364                  g_win32_error_message (WSAGetLastError ()));
365   }
366
367   local2.sin_family = AF_INET;
368   local2.sin_port = 0;
369   local2.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
370
371   channel->reset_recv = (gint) socket (AF_INET, SOCK_DGRAM, 0);
372   if (channel->reset_recv == INVALID_SOCKET)
373     {
374       g_warning (G_STRLOC ": Error creating reset_recv socket: %s\n",
375                  g_win32_error_message (WSAGetLastError ()));
376   }
377
378   if (bind (channel->reset_recv, (struct sockaddr *)&local2, sizeof (local)) == SOCKET_ERROR)
379     {
380       g_warning (G_STRLOC ": Error binding to reset_recv socket: %s\n",
381                  g_win32_error_message (WSAGetLastError ()));
382     }
383   
384   len = sizeof (local2);
385   if (getsockname (channel->reset_recv, (struct sockaddr *)&local2, &len) == SOCKET_ERROR)
386     {
387       g_warning (G_STRLOC ": Error getsockname with reset_recv socket: %s\n",
388                  g_win32_error_message (WSAGetLastError ()));
389     }
390
391   memset (&server, 0, sizeof (server));
392   server.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
393   server.sin_family = AF_INET;
394   server.sin_port = local2.sin_port;
395
396   if (connect (channel->reset_send, (struct sockaddr  *)&server, sizeof (server)) == SOCKET_ERROR)
397     {
398       g_warning (G_STRLOC ": connect to reset_recv socket: %s\n",
399                  g_win32_error_message (WSAGetLastError ()));
400   }
401
402 }
403
404 static GIOStatus
405 buffer_read (GIOWin32Channel *channel,
406              guchar          *dest,
407              gsize            count,
408              gsize           *bytes_read,
409              GError         **err)
410 {
411   guint nbytes;
412   guint left = count;
413   
414   LOCK (channel->mutex);
415   if (channel->debug)
416     g_print ("reading from thread %#x %d bytes, rdp=%d, wrp=%d\n",
417              channel->thread_id, count, channel->rdp, channel->wrp);
418   
419   if (channel->wrp == channel->rdp)
420     {
421       UNLOCK (channel->mutex);
422       if (channel->debug)
423         g_print ("waiting for data from thread %#x\n", channel->thread_id);
424       WaitForSingleObject (channel->data_avail_event, INFINITE);
425       if (channel->debug)
426         g_print ("done waiting for data from thread %#x\n", channel->thread_id);
427       LOCK (channel->mutex);
428       if (channel->wrp == channel->rdp && !channel->running)
429         {
430           if (channel->debug)
431             g_print ("wrp==rdp, !running\n");
432           UNLOCK (channel->mutex);
433           *bytes_read = 0;
434           return G_IO_STATUS_EOF;
435         }
436     }
437   
438   if (channel->rdp < channel->wrp)
439     nbytes = channel->wrp - channel->rdp;
440   else
441     nbytes = BUFFER_SIZE - channel->rdp;
442   UNLOCK (channel->mutex);
443   nbytes = MIN (left, nbytes);
444   if (channel->debug)
445     g_print ("moving %d bytes from thread %#x\n",
446              nbytes, channel->thread_id);
447   memcpy (dest, channel->buffer + channel->rdp, nbytes);
448   dest += nbytes;
449   left -= nbytes;
450   LOCK (channel->mutex);
451   channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE;
452   if (channel->debug)
453     g_print ("setting space_avail for thread %#x\n", channel->thread_id);
454   SetEvent (channel->space_avail_event);
455   if (channel->debug)
456     g_print ("for thread %#x: rdp=%d, wrp=%d\n",
457              channel->thread_id, channel->rdp, channel->wrp);
458   if (channel->running && channel->wrp == channel->rdp)
459     {
460       if (channel->debug)
461         g_print ("resetting data_avail of thread %#x\n",
462                  channel->thread_id);
463       ResetEvent (channel->data_avail_event);
464     };
465   UNLOCK (channel->mutex);
466   
467   /* We have no way to indicate any errors form the actual
468    * read() or recv() call in the reader thread. Should we have?
469    */
470   *bytes_read = count - left;
471   return (*bytes_read > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
472 }
473
474 static unsigned __stdcall
475 select_thread (void *parameter)
476 {
477   GIOWin32Channel *channel = parameter;
478   fd_set read_fds, write_fds, except_fds;
479   GSList *tmp;
480   int n;
481   char buffer[8];
482
483   g_io_channel_ref ((GIOChannel *)channel);
484
485   if (channel->debug)
486     g_print ("select_thread %#x: start fd:%d data_avail:%#x data_avail_noticed:%#x\n",
487              channel->thread_id,
488              channel->fd,
489              (guint) channel->data_avail_event,
490              (guint) channel->data_avail_noticed_event);
491   
492   channel->rdp = channel->wrp = 0;
493   channel->running = TRUE;
494
495   SetEvent (channel->space_avail_event);
496   
497   while (channel->running)
498     {
499       FD_ZERO (&read_fds);
500       FD_ZERO (&write_fds);
501       FD_ZERO (&except_fds);
502       FD_SET (channel->reset_recv, &read_fds);
503
504       LOCK (channel->mutex);
505       tmp = channel->watches;
506       while (tmp)
507         {
508           GIOWin32Watch *watch = (GIOWin32Watch *)tmp->data;
509
510           if (watch->condition & (G_IO_IN | G_IO_HUP))
511             FD_SET (channel->fd, &read_fds);
512           if (watch->condition & G_IO_OUT)
513             FD_SET (channel->fd, &write_fds);
514           if (watch->condition & G_IO_ERR)
515             FD_SET (channel->fd, &except_fds);
516           
517           tmp = tmp->next;
518         }
519       UNLOCK (channel->mutex);
520
521       if (channel->debug)
522         g_print ("select_thread %#x: calling select() for%s%s%s\n",
523                  channel->thread_id,
524                  (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
525                  (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
526                  (FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
527       
528       n = select (1, &read_fds, &write_fds, &except_fds, NULL);
529       
530       LOCK (channel->mutex);
531       if (channel->needs_close)
532         {
533           UNLOCK (channel->mutex);
534           break;
535         }
536       UNLOCK (channel->mutex);
537
538       if (n == SOCKET_ERROR)
539         {
540           if (channel->debug)
541             g_print ("select_thread %#x: select returned SOCKET_ERROR\n",
542                      channel->thread_id);
543           break;
544         }
545
546     if (FD_ISSET (channel->reset_recv, &read_fds))
547     {
548       if (channel->debug)
549         g_print ("select_thread %#x: re-looping\n",
550             channel->thread_id);
551       recv (channel->reset_recv,  (char *)&buffer, (int) sizeof (buffer), 0);
552       continue;
553     }
554
555     if (channel->debug)
556       g_print ("select_thread %#x: got%s%s%s\n",
557                channel->thread_id,
558                (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
559                (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
560                (FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
561     
562     if (FD_ISSET (channel->fd, &read_fds))
563       channel->revents |= G_IO_IN;
564     if (FD_ISSET (channel->fd, &write_fds))
565       channel->revents |= G_IO_OUT;
566     if (FD_ISSET (channel->fd, &except_fds))
567       channel->revents |= G_IO_ERR;
568
569     if (channel->debug)
570       g_print ("select_thread %#x: resetting data_avail_noticed, setting data_avail\n",
571                channel->thread_id);
572
573     LOCK (channel->mutex);
574     ResetEvent (channel->data_avail_noticed_event);
575     SetEvent (channel->data_avail_event);
576     if (channel->needs_close)
577       {
578         UNLOCK (channel->mutex);
579         break;
580       }
581     UNLOCK (channel->mutex);
582
583     if (channel->debug)
584       g_print ("select_thread %#x: waiting for data_avail_noticed\n",
585         channel->thread_id);
586
587     WaitForSingleObject (channel->data_avail_noticed_event, INFINITE);
588     if (channel->debug)
589       g_print ("select_thread %#x: got data_avail_noticed\n",
590                  channel->thread_id);
591     }
592
593   LOCK (channel->mutex);
594   channel->running = FALSE;
595   if (channel->debug)
596     g_print ("select_thread %#x: got error, setting data_avail\n",
597              channel->thread_id);
598   SetEvent (channel->data_avail_event);
599   g_io_channel_unref ((GIOChannel *)channel);
600   UNLOCK (channel->mutex);
601
602   /* No need to call _endthreadex(), the actual thread starter routine
603    * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
604    * _endthreadex() for us.
605    */
606
607   return 0;
608 }
609
610 static gboolean
611 g_io_win32_prepare (GSource *source,
612                     gint    *timeout)
613 {
614   GIOWin32Watch *watch = (GIOWin32Watch *)source;
615   GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
616   GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
617   
618   *timeout = -1;
619   
620   if (channel->debug)
621     g_print ("g_io_win32_prepare: for thread %#x buffer_condition:%#x\n"
622              "  watch->pollfd.events:%#x watch->pollfd.revents:%#x channel->revents:%#x\n",
623              channel->thread_id, buffer_condition,
624              watch->pollfd.events, watch->pollfd.revents, channel->revents);
625
626   if (channel->type == G_IO_WIN32_FILE_DESC)
627     {
628       LOCK (channel->mutex);
629       if (channel->running && channel->wrp == channel->rdp)
630         {
631           if (channel->debug)
632             g_print ("g_io_win32_prepare: for thread %#x, setting channel->revents = 0\n",
633                      channel->thread_id);
634           channel->revents = 0;
635         }
636       UNLOCK (channel->mutex);
637     }
638   else if (channel->type == G_IO_WIN32_SOCKET)
639     {
640       LOCK (channel->mutex);
641       channel->revents = 0;
642       if (channel->debug)
643         g_print ("g_io_win32_prepare: for thread %#x, setting data_avail_noticed\n",
644                  channel->thread_id);
645       SetEvent (channel->data_avail_noticed_event);
646       if (channel->debug)
647         g_print ("g_io_win32_prepare: thread %#x, there.\n",
648                  channel->thread_id);
649       UNLOCK (channel->mutex);
650     }
651
652   return ((watch->condition & buffer_condition) == watch->condition);
653 }
654
655 static gboolean
656 g_io_win32_check (GSource *source)
657 {
658   MSG msg;
659   GIOWin32Watch *watch = (GIOWin32Watch *)source;
660   GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
661   GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
662
663   if (channel->debug)
664     g_print ("g_io_win32_check: for thread %#x buffer_condition:%#x\n"
665              "  watch->pollfd.events:%#x watch->pollfd.revents:%#x channel->revents:%#x\n",
666              channel->thread_id, buffer_condition,
667              watch->pollfd.events, watch->pollfd.revents, channel->revents);
668
669   if (channel->type != G_IO_WIN32_WINDOWS_MESSAGES)
670     {
671       watch->pollfd.revents = (watch->pollfd.events & channel->revents);
672     }
673   else
674     {
675       return (PeekMessage (&msg, channel->hwnd, 0, 0, PM_NOREMOVE));
676     }
677   
678   if (channel->type == G_IO_WIN32_SOCKET)
679     {
680       LOCK (channel->mutex);
681       if (channel->debug)
682         g_print ("g_io_win32_check: thread %#x, resetting data_avail\n",
683                  channel->thread_id);
684       ResetEvent (channel->data_avail_event);
685       if (channel->debug)
686         g_print ("g_io_win32_check: thread %#x, there.\n",
687                  channel->thread_id);
688       UNLOCK (channel->mutex);
689     }
690
691   return ((watch->pollfd.revents | buffer_condition) & watch->condition);
692 }
693
694 static gboolean
695 g_io_win32_dispatch (GSource     *source,
696                      GSourceFunc  callback,
697                      gpointer     user_data)
698 {
699   GIOFunc func = (GIOFunc)callback;
700   GIOWin32Watch *watch = (GIOWin32Watch *)source;
701   GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
702   
703   if (!func)
704     {
705       g_warning (G_STRLOC ": GIOWin32Watch dispatched without callback\n"
706                  "You must call g_source_connect().");
707       return FALSE;
708     }
709   
710   return (*func) (watch->channel,
711                   (watch->pollfd.revents | buffer_condition) & watch->condition,
712                   user_data);
713 }
714
715 static void
716 g_io_win32_finalize (GSource *source)
717 {
718   GIOWin32Watch *watch = (GIOWin32Watch *)source;
719   GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
720   char send_buffer[] = "f";
721   
722   LOCK (channel->mutex);
723   if (channel->debug)
724     g_print ("g_io_win32_finalize: channel with thread %#x\n",
725              channel->thread_id);
726
727   channel->watches = g_slist_remove (channel->watches, watch);
728
729   SetEvent (channel->data_avail_noticed_event);
730   if (channel->type == G_IO_WIN32_SOCKET)
731     send (channel->reset_send, send_buffer, sizeof (send_buffer), 0);
732
733   g_io_channel_unref (watch->channel);
734   UNLOCK (channel->mutex);
735 }
736
737 #if defined(G_PLATFORM_WIN32) && defined(__GNUC__)
738 __declspec(dllexport)
739 #endif
740 GSourceFuncs g_io_watch_funcs = {
741   g_io_win32_prepare,
742   g_io_win32_check,
743   g_io_win32_dispatch,
744   g_io_win32_finalize
745 };
746
747 static GSource *
748 g_io_win32_create_watch (GIOChannel    *channel,
749                          GIOCondition   condition,
750                          unsigned (__stdcall *thread) (void *parameter))
751 {
752   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
753   GIOWin32Watch *watch;
754   GSource *source;
755   char send_buffer[] = "c";
756
757   source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
758   watch = (GIOWin32Watch *)source;
759   
760   watch->channel = channel;
761   g_io_channel_ref (channel);
762   
763   watch->condition = condition;
764   
765   if (win32_channel->data_avail_event == NULL)
766     create_events (win32_channel);
767
768   watch->pollfd.fd = (gint) win32_channel->data_avail_event;
769   watch->pollfd.events = condition;
770   
771   if (win32_channel->debug)
772     g_print ("g_io_win32_create_watch: fd:%d condition:%#x handle:%#x\n",
773              win32_channel->fd, condition, watch->pollfd.fd);
774
775   LOCK (win32_channel->mutex);
776   win32_channel->watches = g_slist_append (win32_channel->watches, watch);
777
778   if (win32_channel->thread_id == 0)
779     create_thread (win32_channel, condition, thread);
780   else
781     send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0);
782
783   g_source_add_poll (source, &watch->pollfd);
784   UNLOCK (win32_channel->mutex);
785
786   return source;
787 }
788
789 static GIOStatus
790 g_io_win32_msg_read (GIOChannel *channel,
791                      gchar      *buf,
792                      gsize       count,
793                      gsize      *bytes_read,
794                      GError    **err)
795 {
796   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
797   MSG msg;               /* In case of alignment problems */
798   
799   if (count < sizeof (MSG))
800     {
801       g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
802                    "Incorrect message size"); /* Informative enough error message? */
803       return G_IO_STATUS_ERROR;
804     }
805   
806   if (win32_channel->debug)
807     g_print ("g_io_win32_msg_read: for %#x\n",
808              (guint) win32_channel->hwnd);
809   if (!PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_REMOVE))
810     return G_IO_STATUS_AGAIN;
811
812   memmove (buf, &msg, sizeof (MSG));
813   *bytes_read = sizeof (MSG);
814
815   return G_IO_STATUS_NORMAL;
816 }
817
818 static GIOStatus
819 g_io_win32_msg_write (GIOChannel  *channel,
820                       const gchar *buf,
821                       gsize        count,
822                       gsize       *bytes_written,
823                       GError     **err)
824 {
825   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
826   MSG msg;
827   
828   if (count != sizeof (MSG))
829     {
830       g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
831                    "Incorrect message size"); /* Informative enough error message? */
832       return G_IO_STATUS_ERROR;
833     }
834   
835   /* In case of alignment problems */
836   memmove (&msg, buf, sizeof (MSG));
837   if (!PostMessage (win32_channel->hwnd, msg.message, msg.wParam, msg.lParam))
838     {
839       gchar *emsg = g_win32_error_message (GetLastError ());
840       g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, emsg);
841       g_free (emsg);
842       return G_IO_STATUS_ERROR;
843     }
844
845   *bytes_written = sizeof (MSG);
846
847   return G_IO_STATUS_NORMAL;
848 }
849
850 static GIOStatus
851 g_io_win32_msg_close (GIOChannel *channel,
852                       GError    **err)
853 {
854   /* Nothing to be done. Or should we set hwnd to some invalid value? */
855
856   return G_IO_STATUS_NORMAL;
857 }
858
859 static void
860 g_io_win32_free (GIOChannel *channel)
861 {
862   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
863   
864   if (win32_channel->debug)
865     g_print ("thread %#x: freeing channel, fd: %d\n",
866              win32_channel->thread_id,
867              win32_channel->fd);
868
869   if (win32_channel->reset_send)
870     closesocket (win32_channel->reset_send);
871   if (win32_channel->reset_recv)
872     closesocket (win32_channel->reset_recv);
873   if (win32_channel->data_avail_event)
874     CloseHandle (win32_channel->data_avail_event);
875   if (win32_channel->space_avail_event)
876     CloseHandle (win32_channel->space_avail_event);
877   if (win32_channel->data_avail_noticed_event)
878     CloseHandle (win32_channel->data_avail_noticed_event);
879   DeleteCriticalSection (&win32_channel->mutex);
880
881   g_free (win32_channel->buffer);
882   g_slist_free (win32_channel->watches);
883   g_free (win32_channel);
884 }
885
886 static GSource *
887 g_io_win32_msg_create_watch (GIOChannel    *channel,
888                              GIOCondition   condition)
889 {
890   GIOWin32Watch *watch;
891   GSource *source;
892
893   source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
894   watch = (GIOWin32Watch *)source;
895   
896   watch->channel = channel;
897   g_io_channel_ref (channel);
898   
899   watch->condition = condition;
900   
901   watch->pollfd.fd = G_WIN32_MSG_HANDLE;
902   watch->pollfd.events = condition;
903   
904   g_source_add_poll (source, &watch->pollfd);
905   
906   return source;
907 }
908
909 static GIOStatus
910 g_io_win32_fd_read (GIOChannel *channel,
911                     gchar      *buf,
912                     gsize       count,
913                     gsize      *bytes_read,
914                     GError    **err)
915 {
916   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
917   gint result;
918   
919   if (win32_channel->debug)
920     g_print ("g_io_win32_fd_read: fd:%d count:%d\n",
921              win32_channel->fd, count);
922   
923   if (win32_channel->thread_id)
924     {
925       return buffer_read (win32_channel, buf, count, bytes_read, err);
926     }
927
928   result = read (win32_channel->fd, buf, count);
929
930   if (win32_channel->debug)
931     g_print ("g_io_win32_fd_read: read() = %d\n", result);
932
933   if (result < 0)
934     {
935       *bytes_read = 0;
936
937       switch (errno)
938         {
939 #ifdef EAGAIN
940         case EAGAIN:
941           return G_IO_STATUS_AGAIN;
942 #endif
943         default:
944           g_set_error (err, G_IO_CHANNEL_ERROR,
945                        g_io_channel_error_from_errno (errno),
946                        g_strerror (errno));
947           return G_IO_STATUS_ERROR;
948         }
949     }
950
951   *bytes_read = result;
952
953   return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
954 }
955
956 static GIOStatus
957 g_io_win32_fd_write (GIOChannel  *channel,
958                      const gchar *buf,
959                      gsize        count,
960                      gsize       *bytes_written,
961                      GError     **err)
962 {
963   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
964   gint result;
965   
966   result = write (win32_channel->fd, buf, count);
967   if (win32_channel->debug)
968     g_print ("g_io_win32_fd_write: fd:%d count:%d = %d\n",
969              win32_channel->fd, count, result);
970
971   if (result < 0)
972     {
973       *bytes_written = 0;
974
975       switch (errno)
976         {
977 #ifdef EAGAIN
978         case EAGAIN:
979           return G_IO_STATUS_AGAIN;
980 #endif
981         default:
982           g_set_error (err, G_IO_CHANNEL_ERROR,
983                        g_io_channel_error_from_errno (errno),
984                        g_strerror (errno));
985           return G_IO_STATUS_ERROR;
986         }
987     }
988
989   *bytes_written = result;
990
991   return G_IO_STATUS_NORMAL;
992 }
993
994 static GIOStatus
995 g_io_win32_fd_seek (GIOChannel *channel,
996                     gint64      offset,
997                     GSeekType   type,
998                     GError    **err)
999 {
1000   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1001   int whence;
1002   off_t tmp_offset;
1003   off_t result;
1004   
1005   switch (type)
1006     {
1007     case G_SEEK_SET:
1008       whence = SEEK_SET;
1009       break;
1010     case G_SEEK_CUR:
1011       whence = SEEK_CUR;
1012       break;
1013     case G_SEEK_END:
1014       whence = SEEK_END;
1015       break;
1016     default:
1017       whence = -1; /* Keep the compiler quiet */
1018       g_assert_not_reached ();
1019     }
1020
1021   tmp_offset = offset;
1022   if (tmp_offset != offset)
1023     {
1024       g_set_error (err, G_IO_CHANNEL_ERROR,
1025                    g_io_channel_error_from_errno (EINVAL),
1026                    g_strerror (EINVAL));
1027       return G_IO_STATUS_ERROR;
1028     }
1029   
1030   result = lseek (win32_channel->fd, tmp_offset, whence);
1031   
1032   if (result < 0)
1033     {
1034       g_set_error (err, G_IO_CHANNEL_ERROR,
1035                    g_io_channel_error_from_errno (errno),
1036                    g_strerror (errno));
1037       return G_IO_STATUS_ERROR;
1038     }
1039
1040   return G_IO_STATUS_NORMAL;
1041 }
1042
1043 static GIOStatus
1044 g_io_win32_fd_close (GIOChannel *channel,
1045                      GError    **err)
1046 {
1047   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1048   
1049   if (win32_channel->debug)
1050     g_print ("thread %#x: closing fd %d\n",
1051              win32_channel->thread_id,
1052              win32_channel->fd);
1053   LOCK (win32_channel->mutex);
1054   if (win32_channel->running)
1055     {
1056       if (win32_channel->debug)
1057         g_print ("thread %#x: running, marking fd %d for later close\n",
1058                  win32_channel->thread_id, win32_channel->fd);
1059       win32_channel->running = FALSE;
1060       win32_channel->needs_close = TRUE;
1061       SetEvent (win32_channel->data_avail_event);
1062     }
1063   else
1064     {
1065       if (win32_channel->debug)
1066         g_print ("closing fd %d\n", win32_channel->fd);
1067       close (win32_channel->fd);
1068       if (win32_channel->debug)
1069         g_print ("closed fd %d, setting to -1\n",
1070                  win32_channel->fd);
1071       win32_channel->fd = -1;
1072     }
1073   UNLOCK (win32_channel->mutex);
1074
1075   /* FIXME error detection? */
1076
1077   return G_IO_STATUS_NORMAL;
1078 }
1079
1080 static GSource *
1081 g_io_win32_fd_create_watch (GIOChannel    *channel,
1082                             GIOCondition   condition)
1083 {
1084   return g_io_win32_create_watch (channel, condition, read_thread);
1085 }
1086
1087 static GIOStatus
1088 g_io_win32_sock_read (GIOChannel *channel,
1089                       gchar      *buf,
1090                       gsize       count,
1091                       gsize      *bytes_read,
1092                       GError    **err)
1093 {
1094   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1095   gint result;
1096   GIOChannelError error = G_IO_STATUS_NORMAL;
1097   GIOStatus internal_status = G_IO_STATUS_NORMAL;
1098   char send_buffer[] = "sr";
1099
1100   if (win32_channel->debug)
1101     g_print ("g_io_win32_sock_read: sockfd:%d count:%d\n",
1102              win32_channel->fd, count);
1103 #ifdef WE_NEED_TO_HANDLE_WSAEINTR
1104 repeat:
1105 #endif
1106   result = recv (win32_channel->fd, buf, count, 0);
1107
1108   if (win32_channel->debug)
1109     g_print ("g_io_win32_sock_read: recv:%d\n", result);
1110   
1111   if (result == SOCKET_ERROR)
1112     {
1113       *bytes_read = 0;
1114
1115       switch (WSAGetLastError ())
1116         {
1117         case WSAEINVAL:
1118           error = G_IO_CHANNEL_ERROR_INVAL;
1119           break;
1120         case WSAEWOULDBLOCK:
1121           return G_IO_STATUS_AGAIN;
1122 #ifdef WE_NEED_TO_HANDLE_WSAEINTR /* not anymore with wsock2 ? */
1123         case WSAEINTR:
1124           goto repeat;
1125 #endif
1126         default:
1127           error = G_IO_CHANNEL_ERROR_FAILED;
1128           break;
1129         }
1130       g_set_error (err, G_IO_CHANNEL_ERROR, error, "Socket read error");
1131       internal_status = G_IO_STATUS_ERROR;
1132       /* FIXME get all errors, better error messages */
1133     }
1134   else
1135     {
1136       *bytes_read = result;
1137       if (result == 0)
1138         internal_status = G_IO_STATUS_EOF;
1139     }
1140
1141   if ((internal_status == G_IO_STATUS_EOF) || 
1142       (internal_status == G_IO_STATUS_ERROR))
1143     {
1144       LOCK (win32_channel->mutex);
1145       SetEvent (win32_channel->data_avail_noticed_event);
1146       win32_channel->needs_close = 1;
1147       send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0);
1148       UNLOCK (win32_channel->mutex);
1149     }
1150   return internal_status;
1151 }
1152
1153 static GIOStatus
1154 g_io_win32_sock_write (GIOChannel  *channel,
1155                        const gchar *buf,
1156                        gsize        count,
1157                        gsize       *bytes_written,
1158                        GError     **err)
1159 {
1160   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1161   gint result;
1162   GIOChannelError error = G_IO_STATUS_NORMAL;
1163   char send_buffer[] = "sw";
1164   
1165   if (win32_channel->debug)
1166     g_print ("g_io_win32_sock_write: sockfd:%d count:%d\n",
1167              win32_channel->fd, count);
1168 #ifdef WE_NEED_TO_HANDLE_WSAEINTR
1169 repeat:
1170 #endif
1171   result = send (win32_channel->fd, buf, count, 0);
1172   
1173   if (win32_channel->debug)
1174     g_print ("g_io_win32_sock_write: send:%d\n", result);
1175   
1176   if (result == SOCKET_ERROR)
1177     {
1178       *bytes_written = 0;
1179
1180       switch (WSAGetLastError ())
1181         {
1182         case WSAEINVAL:
1183           error = G_IO_CHANNEL_ERROR_INVAL;
1184           break;
1185         case WSAEWOULDBLOCK:
1186           return G_IO_STATUS_AGAIN;
1187 #ifdef WE_NEED_TO_HANDLE_WSAEINTR /* not anymore with wsock2 ? */
1188         case WSAEINTR:
1189           goto repeat;
1190 #endif
1191         default:
1192           error = G_IO_CHANNEL_ERROR_FAILED;
1193           break;
1194         }
1195       g_set_error (err, G_IO_CHANNEL_ERROR, error, "Socket write error");
1196       LOCK (win32_channel->mutex);
1197       SetEvent (win32_channel->data_avail_noticed_event);
1198       win32_channel->needs_close = 1;
1199       send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0);
1200       UNLOCK (win32_channel->mutex);
1201       return G_IO_STATUS_ERROR;
1202       /* FIXME get all errors, better error messages */
1203     }
1204   else
1205     {
1206       *bytes_written = result;
1207
1208       return G_IO_STATUS_NORMAL;
1209     }
1210 }
1211
1212 static GIOStatus
1213 g_io_win32_sock_close (GIOChannel *channel,
1214                        GError    **err)
1215 {
1216   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1217
1218   LOCK (win32_channel->mutex);
1219   if (win32_channel->running)
1220     {
1221       if (win32_channel->debug)
1222         g_print ("thread %#x: running, marking for later close\n",
1223                  win32_channel->thread_id);
1224       win32_channel->running = FALSE;
1225       win32_channel->needs_close = TRUE;
1226       SetEvent(win32_channel->data_avail_noticed_event);
1227     }
1228   if (win32_channel->fd != -1)
1229     {
1230       if (win32_channel->debug)
1231         g_print ("thread %#x: closing socket %d\n",
1232                  win32_channel->thread_id,
1233                  win32_channel->fd);
1234       
1235       closesocket (win32_channel->fd);
1236       win32_channel->fd = -1;
1237     }
1238   UNLOCK (win32_channel->mutex);
1239
1240   /* FIXME error detection? */
1241
1242   return G_IO_STATUS_NORMAL;
1243 }
1244
1245 static GSource *
1246 g_io_win32_sock_create_watch (GIOChannel    *channel,
1247                               GIOCondition   condition)
1248 {
1249   return g_io_win32_create_watch (channel, condition, select_thread);
1250 }
1251
1252 GIOChannel *
1253 g_io_channel_new_file (const gchar  *filename,
1254                        const gchar  *mode,
1255                        GError      **error)
1256 {
1257   int fid, flags, pmode;
1258   GIOChannel *channel;
1259
1260   enum { /* Cheesy hack */
1261     MODE_R = 1 << 0,
1262     MODE_W = 1 << 1,
1263     MODE_A = 1 << 2,
1264     MODE_PLUS = 1 << 3,
1265   } mode_num;
1266
1267   g_return_val_if_fail (filename != NULL, NULL);
1268   g_return_val_if_fail (mode != NULL, NULL);
1269   g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL);
1270
1271   switch (mode[0])
1272     {
1273       case 'r':
1274         mode_num = MODE_R;
1275         break;
1276       case 'w':
1277         mode_num = MODE_W;
1278         break;
1279       case 'a':
1280         mode_num = MODE_A;
1281         break;
1282       default:
1283         g_warning ("Invalid GIOFileMode %s.\n", mode);
1284         return NULL;
1285     }
1286
1287   switch (mode[1])
1288     {
1289       case '\0':
1290         break;
1291       case '+':
1292         if (mode[2] == '\0')
1293           {
1294             mode_num |= MODE_PLUS;
1295             break;
1296           }
1297         /* Fall through */
1298       default:
1299         g_warning ("Invalid GIOFileMode %s.\n", mode);
1300         return NULL;
1301     }
1302
1303   switch (mode_num)
1304     {
1305       case MODE_R:
1306         flags = O_RDONLY;
1307         pmode = _S_IREAD;
1308         break;
1309       case MODE_W:
1310         flags = O_WRONLY | O_TRUNC | O_CREAT;
1311         pmode = _S_IWRITE;
1312         break;
1313       case MODE_A:
1314         flags = O_WRONLY | O_APPEND | O_CREAT;
1315         pmode = _S_IWRITE;
1316         break;
1317       case MODE_R | MODE_PLUS:
1318         flags = O_RDWR;
1319         pmode = _S_IREAD | _S_IWRITE;
1320         break;
1321       case MODE_W | MODE_PLUS:
1322         flags = O_RDWR | O_TRUNC | O_CREAT;
1323         pmode = _S_IREAD | _S_IWRITE;
1324         break;
1325       case MODE_A | MODE_PLUS:
1326         flags = O_RDWR | O_APPEND | O_CREAT;
1327         pmode = _S_IREAD | _S_IWRITE;
1328         break;
1329       default:
1330         g_assert_not_reached ();
1331         flags = 0;
1332         pmode = 0;
1333     }
1334
1335   /* always open 'untranslated' */
1336   fid = open (filename, flags | _O_BINARY, pmode);
1337
1338   if (g_io_win32_get_debug_flag ())
1339     {
1340       g_print ("g_io_channel_win32_new_file: open(\"%s\", ", filename);
1341       g_win32_print_access_mode (flags|_O_BINARY);
1342       g_print (",%#o)=%d\n", pmode, fid);
1343     }
1344
1345   if (fid < 0)
1346     {
1347       g_set_error (error, G_FILE_ERROR,
1348                    g_file_error_from_errno (errno),
1349                    g_strerror (errno));
1350       return (GIOChannel *)NULL;
1351     }
1352
1353   channel = g_io_channel_win32_new_fd (fid);
1354
1355   /* XXX: move this to g_io_channel_win32_new_fd () */
1356   channel->close_on_unref = TRUE;
1357   channel->is_seekable = TRUE;
1358
1359   /* g_io_channel_win32_new_fd sets is_readable and is_writeable to
1360    * correspond to actual readability/writeability. Set to FALSE those
1361    * that mode doesn't allow
1362    */
1363   switch (mode_num)
1364     {
1365       case MODE_R:
1366         channel->is_writeable = FALSE;
1367         break;
1368       case MODE_W:
1369       case MODE_A:
1370         channel->is_readable = FALSE;
1371         break;
1372       case MODE_R | MODE_PLUS:
1373       case MODE_W | MODE_PLUS:
1374       case MODE_A | MODE_PLUS:
1375         break;
1376       default:
1377         g_assert_not_reached ();
1378     }
1379
1380   return channel;
1381 }
1382
1383 static GIOStatus
1384 g_io_win32_set_flags (GIOChannel *channel,
1385                       GIOFlags    flags,
1386                       GError    **err)
1387 {
1388   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1389
1390   if (win32_channel->debug)
1391     {
1392       g_print ("g_io_win32_set_flags: ");
1393       g_win32_print_gioflags (flags);
1394       g_print ("\n");
1395     }
1396
1397   g_warning ("g_io_win32_set_flags () not implemented.\n");
1398
1399   return G_IO_STATUS_NORMAL;
1400 }
1401
1402 static GIOFlags
1403 g_io_win32_fd_get_flags_internal (GIOChannel  *channel,
1404                                   struct stat *st)
1405 {
1406   GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
1407   gchar c;
1408   DWORD count;
1409
1410   if (st->st_mode & _S_IFIFO)
1411     {
1412       channel->is_readable =
1413         (PeekNamedPipe ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL, NULL) != 0) || GetLastError () == ERROR_BROKEN_PIPE;
1414       channel->is_writeable =
1415         (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1416       channel->is_seekable  = FALSE;
1417     }
1418   else if (st->st_mode & _S_IFCHR)
1419     {
1420       /* XXX Seems there is no way to find out the readability of file
1421        * handles to device files (consoles, mostly) without doing a
1422        * blocking read. So punt, use st->st_mode.
1423        */
1424       channel->is_readable  = !!(st->st_mode & _S_IREAD);
1425
1426       channel->is_writeable =
1427         (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1428
1429       /* XXX What about devices that actually *are* seekable? But
1430        * those would probably not be handled using the C runtime
1431        * anyway, but using Windows-specific code.
1432        */
1433       channel->is_seekable = FALSE;
1434     }
1435   else
1436     {
1437       channel->is_readable =
1438         (ReadFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1439       channel->is_writeable =
1440         (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1441       channel->is_seekable = TRUE;
1442     }
1443
1444   /* XXX: G_IO_FLAG_APPEND */
1445   /* XXX: G_IO_FLAG_NONBLOCK */
1446
1447   return 0;
1448 }
1449
1450 static GIOFlags
1451 g_io_win32_fd_get_flags (GIOChannel *channel)
1452 {
1453   struct stat st;
1454   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1455
1456   g_return_val_if_fail (win32_channel != NULL, 0);
1457   g_return_val_if_fail (win32_channel->type == G_IO_WIN32_FILE_DESC, 0);
1458
1459   if (0 == fstat (win32_channel->fd, &st))
1460     return g_io_win32_fd_get_flags_internal (channel, &st);
1461   else
1462     return 0;
1463 }
1464
1465 static GIOFlags
1466 g_io_win32_msg_get_flags (GIOChannel *channel)
1467 {
1468   return 0;
1469 }
1470
1471 static GIOFlags
1472 g_io_win32_sock_get_flags (GIOChannel *channel)
1473 {
1474   /* XXX Could do something here. */
1475   return 0;
1476 }
1477
1478 static GIOFuncs win32_channel_msg_funcs = {
1479   g_io_win32_msg_read,
1480   g_io_win32_msg_write,
1481   NULL,
1482   g_io_win32_msg_close,
1483   g_io_win32_msg_create_watch,
1484   g_io_win32_free,
1485   g_io_win32_set_flags,
1486   g_io_win32_msg_get_flags,
1487 };
1488
1489 static GIOFuncs win32_channel_fd_funcs = {
1490   g_io_win32_fd_read,
1491   g_io_win32_fd_write,
1492   g_io_win32_fd_seek,
1493   g_io_win32_fd_close,
1494   g_io_win32_fd_create_watch,
1495   g_io_win32_free,
1496   g_io_win32_set_flags,
1497   g_io_win32_fd_get_flags,
1498 };
1499
1500 static GIOFuncs win32_channel_sock_funcs = {
1501   g_io_win32_sock_read,
1502   g_io_win32_sock_write,
1503   NULL,
1504   g_io_win32_sock_close,
1505   g_io_win32_sock_create_watch,
1506   g_io_win32_free,
1507   g_io_win32_set_flags,
1508   g_io_win32_sock_get_flags,
1509 };
1510
1511 GIOChannel *
1512 g_io_channel_win32_new_messages (guint hwnd)
1513 {
1514   GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1515   GIOChannel *channel = (GIOChannel *)win32_channel;
1516
1517   g_io_channel_init (channel);
1518   g_io_channel_win32_init (win32_channel);
1519   if (win32_channel->debug)
1520     g_print ("g_io_channel_win32_new_messages: hwnd = %ud\n", hwnd);
1521   channel->funcs = &win32_channel_msg_funcs;
1522   win32_channel->type = G_IO_WIN32_WINDOWS_MESSAGES;
1523   win32_channel->hwnd = (HWND) hwnd;
1524
1525   /* XXX: check this. */
1526   channel->is_readable = IsWindow (win32_channel->hwnd);
1527   channel->is_writeable = IsWindow (win32_channel->hwnd);
1528
1529   channel->is_seekable = FALSE;
1530
1531   return channel;
1532 }
1533
1534 static GIOChannel *
1535 g_io_channel_win32_new_fd_internal (gint         fd,
1536                                     struct stat *st)
1537 {
1538   GIOWin32Channel *win32_channel;
1539   GIOChannel *channel;
1540
1541   win32_channel = g_new (GIOWin32Channel, 1);
1542   channel = (GIOChannel *)win32_channel;
1543
1544   g_io_channel_init (channel);
1545   g_io_channel_win32_init (win32_channel);
1546   if (win32_channel->debug)
1547     g_print ("g_io_channel_win32_new_fd: %u\n", fd);
1548   channel->funcs = &win32_channel_fd_funcs;
1549   win32_channel->type = G_IO_WIN32_FILE_DESC;
1550   win32_channel->fd = fd;
1551
1552   g_io_win32_fd_get_flags_internal (channel, st);
1553   
1554   return channel;
1555 }
1556
1557 GIOChannel *
1558 g_io_channel_win32_new_fd (gint fd)
1559 {
1560   struct stat st;
1561
1562   if (fstat (fd, &st) == -1)
1563     {
1564       g_warning (G_STRLOC ": %d isn't a C library file descriptor", fd);
1565       return NULL;
1566     }
1567
1568   return g_io_channel_win32_new_fd_internal (fd, &st);
1569 }
1570
1571 gint
1572 g_io_channel_win32_get_fd (GIOChannel *channel)
1573 {
1574   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1575
1576   return win32_channel->fd;
1577 }
1578
1579 GIOChannel *
1580 g_io_channel_win32_new_socket (int socket)
1581 {
1582   GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1583   GIOChannel *channel = (GIOChannel *)win32_channel;
1584
1585   g_io_channel_init (channel);
1586   g_io_channel_win32_init (win32_channel);
1587   init_reset_sockets (win32_channel);
1588   if (win32_channel->debug)
1589     g_print ("g_io_channel_win32_new_socket: sockfd:%d\n", socket);
1590   channel->funcs = &win32_channel_sock_funcs;
1591   win32_channel->type = G_IO_WIN32_SOCKET;
1592   win32_channel->fd = socket;
1593
1594   /* XXX: check this */
1595   channel->is_readable = TRUE;
1596   channel->is_writeable = TRUE;
1597
1598   channel->is_seekable = FALSE;
1599
1600   return channel;
1601 }
1602
1603 GIOChannel *
1604 g_io_channel_unix_new (gint fd)
1605 {
1606   gboolean is_fd, is_socket;
1607   struct stat st;
1608   int optval, optlen;
1609
1610   is_fd = (fstat (fd, &st) == 0);
1611
1612   optlen = sizeof (optval);
1613   is_socket = (getsockopt (fd, SOL_SOCKET, SO_TYPE, (char *) &optval, &optlen) != SOCKET_ERROR);
1614
1615   if (is_fd && is_socket)
1616     g_warning (G_STRLOC ": %d is both a file descriptor and a socket, file descriptor interpretation assumed.", fd);
1617
1618   if (is_fd)
1619     return g_io_channel_win32_new_fd_internal (fd, &st);
1620
1621   if (is_socket)
1622     return g_io_channel_win32_new_socket(fd);
1623
1624   g_warning (G_STRLOC ": %d is neither a file descriptor or a socket", fd);
1625
1626   return NULL;
1627 }
1628
1629 gint
1630 g_io_channel_unix_get_fd (GIOChannel *channel)
1631 {
1632   return g_io_channel_win32_get_fd (channel);
1633 }
1634
1635 void
1636 g_io_channel_win32_set_debug (GIOChannel *channel,
1637                               gboolean    flag)
1638 {
1639   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1640
1641   win32_channel->debug = flag;
1642 }
1643
1644 gint
1645 g_io_channel_win32_poll (GPollFD *fds,
1646                          gint     n_fds,
1647                          gint     timeout)
1648 {
1649   int result;
1650
1651   g_return_val_if_fail (n_fds >= 0, 0);
1652
1653   result = (*g_main_context_get_poll_func (NULL)) (fds, n_fds, timeout);
1654
1655   return result;
1656 }
1657
1658 void
1659 g_io_channel_win32_make_pollfd (GIOChannel   *channel,
1660                                 GIOCondition  condition,
1661                                 GPollFD      *fd)
1662 {
1663   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1664
1665   if (win32_channel->data_avail_event == NULL)
1666     create_events (win32_channel);
1667   
1668   fd->fd = (gint) win32_channel->data_avail_event;
1669   fd->events = condition;
1670
1671   if (win32_channel->thread_id == 0)
1672     {
1673       if ((condition & G_IO_IN) && win32_channel->type == G_IO_WIN32_FILE_DESC)
1674         create_thread (win32_channel, condition, read_thread);
1675       else if (win32_channel->type == G_IO_WIN32_SOCKET)
1676         create_thread (win32_channel, condition, select_thread);
1677     }
1678 }
1679
1680 /* Binary compatibility */
1681 GIOChannel *
1682 g_io_channel_win32_new_stream_socket (int socket)
1683 {
1684   return g_io_channel_win32_new_socket (socket);
1685 }