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