Support gpgme_op_apsswd for GPG.
[gpgme.git] / src / w32-glib-io.c
1 /* w32-glib-io.c - W32 Glib I/O functions
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2004, 2005 g10 Code GmbH
4
5    This file is part of GPGME.
6  
7    GPGME is free software; you can redistribute it and/or modify it
8    under the terms of the GNU Lesser General Public License as
9    published by the Free Software Foundation; either version 2.1 of
10    the License, or (at your option) any later version.
11    
12    GPGME is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16    
17    You should have received a copy of the GNU Lesser General Public
18    License along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <signal.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #include <glib.h>
36 #include <windows.h>
37 #include <io.h>
38
39 #include "util.h"
40 #include "priv-io.h"
41 #include "sema.h"
42 #include "debug.h"
43
44 #ifndef O_BINARY
45 #ifdef _O_BINARY
46 #define O_BINARY        _O_BINARY
47 #else
48 #define O_BINARY        0
49 #endif
50 #endif
51
52 \f
53 /* This file is an ugly hack to get GPGME working with glib on Windows
54    targets.  On Windows, you can not select() on file descriptors.
55    The only way to check if there is something to read is to read
56    something.  This means that GPGME can not let glib check for data
57    without letting glib also handle the data on Windows targets.
58
59    The ugly consequence is that we need to work on GIOChannels in
60    GPGME, creating a glib dependency.  Also, we need to export an
61    interface for the application to get at GPGME's GIOChannel.  There
62    is no good way to abstract all this with callbacks, because the
63    whole thing is also interconnected with the creation of pipes and
64    child processes.
65
66    The following rule applies only to this I/O backend:
67
68    * ALL operations must use the user defined event loop.  GPGME can
69    not anymore provide its own event loop.  This is mostly a sanity
70    requirement: Although we have in theory all information we need to
71    make the GPGME W32 code for select still work, it would be a big
72    complication and require changes throughout GPGME.
73
74    Eventually, we probably have to bite the bullet and make some
75    really nice callback interfaces to let the user control all this at
76    a per-context level.  */
77
78 \f
79 #define MAX_SLAFD 256
80
81 static struct 
82 {
83   int used;
84
85   /* If this is not -1, then it's a libc file descriptor.  */
86   int fd;
87   /* If fd is -1, this is the Windows socket handle.  */
88   int socket;
89
90   GIOChannel *chan;
91   /* The boolean PRIMARY is true if this file descriptor caused the
92      allocation of CHAN.  Only then should CHAN be destroyed when this
93      FD is closed.  This, together with the fact that dup'ed file
94      descriptors are closed before the file descriptors from which
95      they are dup'ed are closed, ensures that CHAN is always valid,
96      and shared among all file descriptors refering to the same
97      underlying object.
98
99      The logic behind this is that there is only one reason for us to
100      dup file descriptors anyway: to allow simpler book-keeping of
101      file descriptors shared between GPGME and libassuan, which both
102      want to close something.  Using the same channel for these
103      duplicates works just fine (and in fact, using different channels
104      does not work because the W32 backend in glib does not support
105      that: One would end up with several competing reader/writer
106      threads.  */
107   int primary;
108 } giochannel_table[MAX_SLAFD];
109
110
111 static GIOChannel *
112 find_channel (int fd)
113 {
114   if (fd < 0 || fd >= MAX_SLAFD)
115     return NULL;
116
117   return giochannel_table[fd].chan;
118 }
119
120
121 /* Returns the FD or -1 on resource limit.  */
122 int
123 new_dummy_channel_from_fd (int cfd)
124 {
125   int idx;
126
127   for (idx = 0; idx < MAX_SLAFD; idx++)
128     if (! giochannel_table[idx].used)
129       break;
130
131   if (idx == MAX_SLAFD)
132     {
133       errno = EIO;
134       return -1;
135     }
136
137   giochannel_table[idx].used = 1;
138   giochannel_table[idx].chan = NULL;
139   giochannel_table[idx].fd = cfd;
140   giochannel_table[idx].socket = INVALID_SOCKET;
141   giochannel_table[idx].primary = 1;
142
143   return idx;
144 }
145
146
147 /* Returns the FD or -1 on resource limit.  */
148 int
149 new_channel_from_fd (int cfd)
150 {
151   int idx;
152
153   for (idx = 0; idx < MAX_SLAFD; idx++)
154     if (! giochannel_table[idx].used)
155       break;
156
157   if (idx == MAX_SLAFD)
158     {
159       errno = EIO;
160       return -1;
161     }
162
163   giochannel_table[idx].used = 1;
164   giochannel_table[idx].chan = g_io_channel_win32_new_fd (cfd);
165   giochannel_table[idx].fd = cfd;
166   giochannel_table[idx].socket = INVALID_SOCKET;
167   giochannel_table[idx].primary = 1;
168
169   g_io_channel_set_encoding (giochannel_table[idx].chan, NULL, NULL);
170   g_io_channel_set_buffered (giochannel_table[idx].chan, FALSE);
171
172   return idx;
173 }
174
175
176 /* Returns the FD or -1 on resource limit.  */
177 int
178 new_channel_from_socket (int sock)
179 {
180   int idx;
181
182   for (idx = 0; idx < MAX_SLAFD; idx++)
183     if (! giochannel_table[idx].used)
184       break;
185
186   if (idx == MAX_SLAFD)
187     {
188       errno = EIO;
189       return -1;
190     }
191
192   giochannel_table[idx].used = 1;
193   giochannel_table[idx].chan = g_io_channel_win32_new_socket (sock);
194   giochannel_table[idx].fd = -1;
195   giochannel_table[idx].socket = sock;
196   giochannel_table[idx].primary = 1;
197
198   g_io_channel_set_encoding (giochannel_table[idx].chan, NULL, NULL);
199   g_io_channel_set_buffered (giochannel_table[idx].chan, FALSE);
200
201   return idx;
202 }
203
204
205 /* Compatibility interface.  Obsolete.  */
206 void *
207 gpgme_get_giochannel (int fd)
208 {
209   return find_channel (fd);
210 }
211
212
213 /* Look up the giochannel for "file descriptor" FD.  */
214 void *
215 gpgme_get_fdptr (int fd)
216 {
217   return find_channel (fd);
218 }
219
220
221 /* Write the printable version of FD to the buffer BUF of length
222    BUFLEN.  The printable version is the representation on the command
223    line that the child process expects.  */
224 int
225 _gpgme_io_fd2str (char *buf, int buflen, int fd)
226 {
227   HANDLE hndl;
228     
229   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_fd2str", fd, "fd=%d", fd);
230   if (giochannel_table[fd].fd != -1)
231     hndl = (HANDLE) _get_osfhandle (giochannel_table[fd].fd);
232   else
233     hndl = (HANDLE) giochannel_table[fd].socket;
234
235   TRACE_SUC1 ("syshd=%p", hndl);
236   
237   return snprintf (buf, buflen, "%d", (int) hndl);
238 }
239
240 \f
241 void
242 _gpgme_io_subsystem_init (void)
243 {
244 }
245
246 \f
247 static struct
248 {
249   _gpgme_close_notify_handler_t handler;
250   void *value;
251 } notify_table[MAX_SLAFD];
252
253
254 int
255 _gpgme_io_read (int fd, void *buffer, size_t count)
256 {
257   int saved_errno = 0;
258   gsize nread;
259   GIOChannel *chan;
260   GIOStatus status;
261   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
262               "buffer=%p, count=%u", buffer, count);
263
264   chan = find_channel (fd);
265   if (!chan)
266     {
267       TRACE_LOG ("no channel registered");
268       errno = EINVAL;
269       return TRACE_SYSRES (-1);
270     }
271   TRACE_LOG1 ("channel %p", chan);
272
273   {
274     GError *err = NULL;
275     status = g_io_channel_read_chars (chan, (gchar *) buffer,
276                                       count, &nread, &err);
277     if (err)
278       {
279         TRACE_LOG2 ("status %i, err %s", status, err->message);
280         g_error_free (err);
281       }
282   }
283
284   if (status == G_IO_STATUS_EOF)
285     nread = 0;
286   else if (status == G_IO_STATUS_AGAIN)
287     {
288       nread = -1;
289       saved_errno = EAGAIN;
290     }
291   else if (status != G_IO_STATUS_NORMAL)
292     {
293       TRACE_LOG1 ("status %d", status);
294       nread = -1;
295       saved_errno = EIO;
296     }
297   
298   if (nread != 0 && nread != -1)
299     TRACE_LOGBUF (buffer, nread);
300
301   errno = saved_errno;
302   return TRACE_SYSRES (nread);
303 }
304
305
306 int
307 _gpgme_io_write (int fd, const void *buffer, size_t count)
308 {
309   int saved_errno = 0;
310   gsize nwritten;
311   GIOChannel *chan;
312   GIOStatus status;
313   GError *err = NULL;
314
315   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
316               "buffer=%p, count=%u", buffer, count);
317   TRACE_LOGBUF (buffer, count);
318
319   chan = find_channel (fd);
320   if (!chan)
321     {
322       TRACE_LOG ("fd %d: no channel registered");
323       errno = EINVAL;
324       return -1;
325     }
326
327   status = g_io_channel_write_chars (chan, (gchar *) buffer, count,
328                                      &nwritten, &err);
329   if (err)
330     {
331       TRACE_LOG1 ("write error: %s", err->message);
332       g_error_free (err);
333     }
334
335   if (status == G_IO_STATUS_AGAIN)
336     {
337       nwritten = -1;
338       saved_errno = EAGAIN;
339     }
340   else if (status != G_IO_STATUS_NORMAL)
341     {
342       nwritten = -1;
343       saved_errno = EIO;
344     }
345   errno = saved_errno;
346
347   return TRACE_SYSRES (nwritten);
348 }
349
350
351 int
352 _gpgme_io_pipe (int filedes[2], int inherit_idx)
353 {
354   int fds[2];
355
356   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
357               "inherit_idx=%i (GPGME uses it for %s)",
358               inherit_idx, inherit_idx ? "reading" : "writing");
359
360 #define PIPEBUF_SIZE  4096
361   if (_pipe (fds, PIPEBUF_SIZE, O_NOINHERIT | O_BINARY) == -1)
362     return TRACE_SYSRES (-1);
363
364   /* Make one end inheritable. */
365   if (inherit_idx == 0)
366     {
367       int new_read;
368
369       new_read = _dup (fds[0]);
370       _close (fds[0]);
371       fds[0] = new_read;
372
373       if (new_read < 0)
374         {
375           _close (fds[1]);
376           return TRACE_SYSRES (-1);
377         }
378     }
379   else if (inherit_idx == 1)
380     {
381       int new_write;
382
383       new_write = _dup (fds[1]);
384       _close (fds[1]);
385       fds[1] = new_write;
386
387       if (new_write < 0)
388         {
389           _close (fds[0]);
390           return TRACE_SYSRES (-1);
391         }
392     }
393
394   /* For _gpgme_io_close.  */
395   filedes[inherit_idx] = new_dummy_channel_from_fd (fds[inherit_idx]);
396   if (filedes[inherit_idx] < 0)
397     {
398       int saved_errno = errno;
399       
400       _close (fds[0]);
401       _close (fds[1]);
402       errno = saved_errno;
403       return TRACE_SYSRES (-1);
404     }
405
406   /* Now we have a pipe with the correct end inheritable.  The other end
407      should have a giochannel.  */
408   filedes[1 - inherit_idx] = new_channel_from_fd (fds[1 - inherit_idx]);
409   if (filedes[1 - inherit_idx] < 0)
410     {
411       int saved_errno = errno;
412       
413       _gpgme_io_close (fds[inherit_idx]);
414       _close (fds[1 - inherit_idx]);
415       errno = saved_errno;
416       return TRACE_SYSRES (-1);
417     }
418   
419   return TRACE_SUC5 ("read=0x%x/%p, write=0x%x/%p, channel=%p",
420                      filedes[0],
421                      (HANDLE) _get_osfhandle (giochannel_table[filedes[0]].fd),
422                      filedes[1],
423                      (HANDLE) _get_osfhandle (giochannel_table[filedes[1]].fd),
424                      giochannel_table[1 - inherit_idx].chan);
425 }
426
427
428 int
429 _gpgme_io_close (int fd)
430 {
431   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
432
433   if (fd < 0 || fd >= MAX_SLAFD)
434     {
435       errno = EBADF;
436       return TRACE_SYSRES (-1);
437     }
438
439   assert (giochannel_table[fd].used);
440
441   /* First call the notify handler.  */
442   if (notify_table[fd].handler)
443     {
444       notify_table[fd].handler (fd, notify_table[fd].value);
445       notify_table[fd].handler = NULL;
446       notify_table[fd].value = NULL;
447     }
448
449   /* Then do the close.  */
450   if (giochannel_table[fd].chan)
451     {
452       if (giochannel_table[fd].primary)
453         g_io_channel_shutdown (giochannel_table[fd].chan, 1, NULL);
454       
455       g_io_channel_unref (giochannel_table[fd].chan);
456     }
457   else
458     {
459       /* Dummy entry, just close.  */
460       assert (giochannel_table[fd].fd != -1);
461       _close (giochannel_table[fd].fd);
462     }
463         
464   giochannel_table[fd].used = 0;
465   giochannel_table[fd].fd = -1;
466   giochannel_table[fd].socket = INVALID_SOCKET;
467   giochannel_table[fd].chan = NULL;
468   giochannel_table[fd].primary = 0;
469
470   TRACE_SUC ();
471   return 0;
472 }
473
474
475 int
476 _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
477                             void *value)
478 {
479   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
480               "close_handler=%p/%p", handler, value);
481
482   assert (fd != -1);
483
484   if (fd < 0 || fd >= (int) DIM (notify_table))
485     {
486       errno = EINVAL;
487       return TRACE_SYSRES (-1);
488     }
489   notify_table[fd].handler = handler;
490   notify_table[fd].value = value;
491   return TRACE_SYSRES (0);
492 }
493
494
495 int
496 _gpgme_io_set_nonblocking (int fd)
497 {
498   GIOChannel *chan;
499   GIOStatus status;
500  
501   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
502
503   chan = find_channel (fd);
504   if (!chan)
505     {
506       errno = EIO;
507       return TRACE_SYSRES (-1);
508     }
509
510   status = g_io_channel_set_flags (chan,
511                                    g_io_channel_get_flags (chan) |
512                                    G_IO_FLAG_NONBLOCK, NULL);
513
514   if (status != G_IO_STATUS_NORMAL)
515     {
516 #if 0
517       /* glib 1.9.2 does not implement set_flags and returns an
518          error.  */
519       errno = EIO;
520       return TRACE_SYSRES (-1);
521 #else
522       TRACE_LOG1 ("g_io_channel_set_flags failed: status=%d (ignored)",
523                   status);
524 #endif
525     }
526
527   return TRACE_SYSRES (0);
528 }
529
530
531 static char *
532 build_commandline (char **argv)
533 {
534   int i;
535   int n = 0;
536   char *buf;
537   char *p;
538   
539   /* We have to quote some things because under Windows the program
540      parses the commandline and does some unquoting.  We enclose the
541      whole argument in double-quotes, and escape literal double-quotes
542      as well as backslashes with a backslash.  We end up with a
543      trailing space at the end of the line, but that is harmless.  */
544   for (i = 0; argv[i]; i++)
545     {
546       p = argv[i];
547       /* The leading double-quote.  */
548       n++;
549       while (*p)
550         {
551           /* An extra one for each literal that must be escaped.  */
552           if (*p == '\\' || *p == '"')
553             n++;
554           n++;
555           p++;
556         }
557       /* The trailing double-quote and the delimiter.  */
558       n += 2;
559     }
560   /* And a trailing zero.  */
561   n++;
562
563   buf = p = malloc (n);
564   if (!buf)
565     return NULL;
566   for (i = 0; argv[i]; i++)
567     {
568       char *argvp = argv[i];
569
570       *(p++) = '"';
571       while (*argvp)
572         {
573           if (*argvp == '\\' || *argvp == '"')
574             *(p++) = '\\';
575           *(p++) = *(argvp++);
576         }
577       *(p++) = '"';
578       *(p++) = ' ';
579     }
580   *(p++) = 0;
581
582   return buf;
583 }
584
585
586 int
587 _gpgme_io_spawn (const char *path, char * const argv[], unsigned int flags,
588                  struct spawn_fd_item_s *fd_list,
589                  void (*atfork) (void *opaque, int reserved),
590                  void *atforkvalue, pid_t *r_pid)
591 {
592   SECURITY_ATTRIBUTES sec_attr;
593   PROCESS_INFORMATION pi =
594     {
595       NULL,      /* returns process handle */
596       0,         /* returns primary thread handle */
597       0,         /* returns pid */
598       0          /* returns tid */
599     };
600   STARTUPINFO si;
601   int cr_flags = (CREATE_DEFAULT_ERROR_MODE
602                   | GetPriorityClass (GetCurrentProcess ()));
603   int i;
604   char **args;
605   char *arg_string;
606   /* FIXME.  */
607   int debug_me = 0;
608   int tmp_fd;
609   char *tmp_name;
610
611   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
612               "path=%s", path);
613   i = 0;
614   while (argv[i])
615     {
616       TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
617       i++;
618     }
619   
620   /* We do not inherit any handles by default, and just insert those
621      handles we want the child to have afterwards.  But some handle
622      values occur on the command line, and we need to move
623      stdin/out/err to the right location.  So we use a wrapper program
624      which gets the information from a temporary file.  */
625   if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0)
626     {
627       TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno));
628       return TRACE_SYSRES (-1);
629     }
630   TRACE_LOG1 ("tmp_name = %s", tmp_name);
631
632   args = calloc (2 + i + 1, sizeof (*args));
633   args[0] = (char *) _gpgme_get_w32spawn_path ();
634   args[1] = tmp_name;
635   args[2] = path;
636   memcpy (&args[3], &argv[1], i * sizeof (*args));
637
638   memset (&sec_attr, 0, sizeof sec_attr);
639   sec_attr.nLength = sizeof sec_attr;
640   sec_attr.bInheritHandle = FALSE;
641   
642   arg_string = build_commandline (args);
643   free (args);
644   if (!arg_string)
645     {
646       close (tmp_fd);
647       DeleteFile (tmp_name);
648       return TRACE_SYSRES (-1);
649     }
650
651   memset (&si, 0, sizeof si);
652   si.cb = sizeof (si);
653   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
654   si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
655   si.hStdInput = INVALID_HANDLE_VALUE;
656   si.hStdOutput = INVALID_HANDLE_VALUE;
657   si.hStdError = INVALID_HANDLE_VALUE;
658
659   cr_flags |= CREATE_SUSPENDED;
660   cr_flags |= DETACHED_PROCESS;
661   if (!CreateProcessA (_gpgme_get_w32spawn_path (),
662                        arg_string,
663                        &sec_attr,     /* process security attributes */
664                        &sec_attr,     /* thread security attributes */
665                        FALSE,         /* inherit handles */
666                        cr_flags,      /* creation flags */
667                        NULL,          /* environment */
668                        NULL,          /* use current drive/directory */
669                        &si,           /* startup information */
670                        &pi))          /* returns process information */
671     {
672       TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
673       free (arg_string);
674       close (tmp_fd);
675       DeleteFile (tmp_name);
676
677       /* FIXME: Should translate the error code.  */
678       errno = EIO;
679       return TRACE_SYSRES (-1);
680     }
681
682   free (arg_string);
683   
684   if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
685     _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
686
687   /* Insert the inherited handles.  */
688   for (i = 0; fd_list[i].fd != -1; i++)
689     {
690       HANDLE hd;
691
692       /* Make it inheritable for the wrapper process.  */
693       if (!DuplicateHandle (GetCurrentProcess(),
694                             _get_osfhandle (giochannel_table[fd_list[i].fd].fd),
695                             pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
696         {
697           TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
698           TerminateProcess (pi.hProcess, 0);
699           /* Just in case TerminateProcess didn't work, let the
700              process fail on its own.  */
701           ResumeThread (pi.hThread);
702           CloseHandle (pi.hThread);
703           CloseHandle (pi.hProcess);
704
705           close (tmp_fd);
706           DeleteFile (tmp_name);
707
708           /* FIXME: Should translate the error code.  */
709           errno = EIO;
710           return TRACE_SYSRES (-1);
711         }
712       /* Return the child name of this handle.  */
713       fd_list[i].peer_name = (int) hd;
714     }
715
716   /* Write the handle translation information to the temporary
717      file.  */
718   {
719     /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
720        notation: "0xFEDCBA9876543210" with an extra white space after
721        every quadruplet.  10*(19*4 + 1) - 1 = 769.  This plans ahead
722        for a time when a HANDLE is 64 bit.  */
723 #define BUFFER_MAX 800
724     char line[BUFFER_MAX + 1];
725     int res;
726     int written;
727     size_t len;
728
729     if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
730       strcpy (line, "~1 \n");
731     else
732       strcpy (line, "\n");
733     for (i = 0; fd_list[i].fd != -1; i++)
734       {
735         /* Strip the newline.  */
736         len = strlen (line) - 1;
737         
738         /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx.  */
739         snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d  \n",
740                   fd_list[i].fd, fd_list[i].dup_to,
741                   fd_list[i].peer_name, fd_list[i].arg_loc);
742         /* Rather safe than sorry.  */
743         line[BUFFER_MAX - 1] = '\n';
744         line[BUFFER_MAX] = '\0';
745       }
746     len = strlen (line);
747     written = 0;
748     do
749       {
750         res = write (tmp_fd, &line[written], len - written);
751         if (res > 0)
752           written += res;
753       }
754     while (res > 0 || (res < 0 && errno == EAGAIN));
755   }
756   close (tmp_fd);
757   /* The temporary file is deleted by the gpgme-w32spawn process
758      (hopefully).  */
759     
760   TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
761               "dwProcessID=%d, dwThreadId=%d",
762               pi.hProcess, pi.hThread, 
763               (int) pi.dwProcessId, (int) pi.dwThreadId);
764   
765   if (r_pid)
766     *r_pid = (pid_t)pi.dwProcessId;
767
768   if (ResumeThread (pi.hThread) < 0)
769     TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
770   
771   if (!CloseHandle (pi.hThread))
772     TRACE_LOG1 ("CloseHandle of thread failed: ec=%d",
773                 (int) GetLastError ());
774
775   TRACE_LOG1 ("process=%p", pi.hProcess);
776
777   /* We don't need to wait for the process.  */
778   if (!CloseHandle (pi.hProcess))
779     TRACE_LOG1 ("CloseHandle of process failed: ec=%d",
780                 (int) GetLastError ());
781
782   if (! (flags & IOSPAWN_FLAG_NOCLOSE))
783     {
784       for (i = 0; fd_list[i].fd != -1; i++)
785         _gpgme_io_close (fd_list[i].fd);
786     }
787
788   for (i = 0; fd_list[i].fd != -1; i++)
789     if (fd_list[i].dup_to == -1)
790       TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
791                   fd_list[i].peer_name);
792     else
793       TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
794                   fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
795                   ((fd_list[i].dup_to == 1) ? "out" : "err"));
796
797   return TRACE_SYSRES (0);
798 }
799
800
801 /* Select on the list of fds.  Returns: -1 = error, 0 = timeout or
802    nothing to select, > 0 = number of signaled fds.  */
803 int
804 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
805 {
806   int npollfds;
807   GPollFD *pollfds;
808   int *pollfds_map; 
809   int i;
810   int j;
811   int any;
812   int n;
813   int count;
814   /* Use a 1s timeout.  */
815   int timeout = 1000;
816   void *dbg_help = NULL;
817   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
818               "nfds=%u, nonblock=%u", nfds, nonblock);
819
820   if (nonblock)
821     timeout = 0;
822
823   pollfds = calloc (nfds, sizeof *pollfds);
824   if (!pollfds)
825     return -1;
826   pollfds_map = calloc (nfds, sizeof *pollfds_map);
827   if (!pollfds_map)
828     {
829       free (pollfds);
830       return -1;
831     }
832   npollfds = 0;
833
834   TRACE_SEQ (dbg_help, "select on [ ");
835   any = 0;
836   for (i = 0; i < nfds; i++)
837     {
838       GIOChannel *chan = NULL;
839
840       if (fds[i].fd == -1) 
841         continue;
842
843       if ((fds[i].for_read || fds[i].for_write)
844           && !(chan = find_channel (fds[i].fd)))
845         {
846           TRACE_ADD1 (dbg_help, "[BAD0x%x ", fds[i].fd);
847           TRACE_END (dbg_help, "]"); 
848           assert (!"see log file");
849         }
850       else if (fds[i].for_read )
851         {
852           assert(chan);
853           g_io_channel_win32_make_pollfd (chan, G_IO_IN, pollfds + npollfds);
854           pollfds_map[npollfds] = i;
855           TRACE_ADD2 (dbg_help, "r0x%x<%d> ", fds[i].fd, pollfds[npollfds].fd);
856           npollfds++;
857           any = 1;
858         }
859       else if (fds[i].for_write)
860         {
861           assert(chan);
862           g_io_channel_win32_make_pollfd (chan, G_IO_OUT, pollfds + npollfds);
863           pollfds_map[npollfds] = i;
864           TRACE_ADD2 (dbg_help, "w0x%x<%d> ", fds[i].fd, pollfds[npollfds].fd);
865           npollfds++;
866           any = 1;
867         }
868       fds[i].signaled = 0;
869     }
870   TRACE_END (dbg_help, "]"); 
871   if (!any)
872     {
873       count = 0;
874       goto leave;
875     }
876
877
878   count = g_io_channel_win32_poll (pollfds, npollfds, timeout);
879   if (count < 0)
880     {
881       int saved_errno = errno;
882       errno = saved_errno;
883       goto leave;
884     }
885
886   TRACE_SEQ (dbg_help, "select OK [ ");
887   if (TRACE_ENABLED (dbg_help))
888     {
889       for (i = 0; i < npollfds; i++)
890         {
891           if ((pollfds[i].revents & G_IO_IN))
892             TRACE_ADD1 (dbg_help, "r0x%x ", fds[pollfds_map[i]].fd);
893           if ((pollfds[i].revents & G_IO_OUT))
894             TRACE_ADD1 (dbg_help, "w0x%x ", fds[pollfds_map[i]].fd);
895         }
896       TRACE_END (dbg_help, "]");
897     }
898     
899   /* COUNT is used to stop the lop as soon as possible.  */
900   for (n = count, i = 0; i < npollfds && n; i++)
901     {
902       j = pollfds_map[i];
903       assert (j >= 0 && j < nfds);
904       if (fds[j].fd == -1)
905         ;
906       else if (fds[j].for_read)
907         {
908           if ((pollfds[i].revents & G_IO_IN))
909             {
910               fds[j].signaled = 1;
911               n--;
912             }
913         }
914       else if (fds[j].for_write)
915         {
916           if ((pollfds[i].revents & G_IO_OUT))
917             {
918               fds[j].signaled = 1;
919               n--;
920             }
921         }
922     }
923
924 leave:
925   free (pollfds);
926   free (pollfds_map);
927   return TRACE_SYSRES (count);
928 }
929
930
931 int
932 _gpgme_io_dup (int fd)
933 {
934   int newfd;
935   GIOChannel *chan;
936
937   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd);
938
939   if (fd < 0 || fd >= MAX_SLAFD || !giochannel_table[fd].used)
940     {
941       errno = EINVAL;
942       return TRACE_SYSRES (-1);
943     }
944
945   for (newfd = 0; newfd < MAX_SLAFD; newfd++)
946     if (! giochannel_table[newfd].used)
947       break;
948   if (newfd == MAX_SLAFD)
949     {
950       errno = EIO;
951       return TRACE_SYSRES (-1);
952     }
953   
954   chan = giochannel_table[fd].chan;
955   g_io_channel_ref (chan);
956   giochannel_table[newfd].used = 1;
957   giochannel_table[newfd].chan = chan;
958   giochannel_table[newfd].fd = -1;
959   giochannel_table[newfd].socket = INVALID_SOCKET;
960   giochannel_table[newfd].primary = 0;
961
962   return TRACE_SYSRES (newfd);
963 }
964
965 \f
966
967
968 \f
969 static int
970 wsa2errno (int err)
971 {
972   switch (err)
973     {
974     case WSAENOTSOCK:
975       return EINVAL;
976     case WSAEWOULDBLOCK:
977       return EAGAIN;
978     case ERROR_BROKEN_PIPE:
979       return EPIPE;
980     case WSANOTINITIALISED:
981       return ENOSYS;
982     default:
983       return EIO;
984     }
985 }
986
987
988 int
989 _gpgme_io_socket (int domain, int type, int proto)
990 {
991   int res;
992   int fd;
993
994   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
995               "type=%i, protp=%i", type, proto);
996
997   res = socket (domain, type, proto);
998   if (res == INVALID_SOCKET)
999     {
1000       errno = wsa2errno (WSAGetLastError ());
1001       return TRACE_SYSRES (-1);
1002     }
1003
1004   fd = new_channel_from_socket (res);
1005   if (fd < 0)
1006     {
1007       int saved_errno = errno;
1008       closesocket (res);
1009       errno = saved_errno;
1010       return TRACE_SYSRES (-1);
1011     }
1012
1013   TRACE_SUC2 ("fd=%i, socket=0x%x", fd, res);
1014   
1015   return fd;
1016 }
1017
1018
1019 int
1020 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
1021 {
1022   GIOChannel *chan; 
1023   int sockfd;
1024   int res;
1025   GIOFlags flags;
1026   GIOStatus status;
1027   GError *err = NULL;
1028
1029   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
1030               "addr=%p, addrlen=%i", addr, addrlen);
1031
1032   chan = find_channel (fd);
1033   if (! chan)
1034     {
1035       errno = EINVAL;
1036       return TRACE_SYSRES (-1);
1037     }
1038
1039   flags = g_io_channel_get_flags (chan);
1040   if (flags & G_IO_FLAG_NONBLOCK)
1041     {
1042       status = g_io_channel_set_flags (chan, flags & ~G_IO_FLAG_NONBLOCK, &err);
1043       if (err)
1044         {
1045           TRACE_LOG1 ("setting flags error: %s", err->message);
1046           g_error_free (err);
1047           err = NULL;
1048         }
1049       if (status != G_IO_STATUS_NORMAL)
1050         {
1051           errno = EIO;
1052           return TRACE_SYSRES (-1);
1053         }
1054     }
1055
1056   sockfd = giochannel_table[fd].socket;
1057   if (sockfd == INVALID_SOCKET)
1058     {
1059       errno = EINVAL;
1060       return TRACE_SYSRES (-1);
1061     }
1062
1063   TRACE_LOG1 ("connect sockfd=0x%x", sockfd);
1064   res = connect (sockfd, addr, addrlen);
1065
1066   /* FIXME: Error ignored here.  */
1067   if (! (flags & G_IO_FLAG_NONBLOCK))
1068     g_io_channel_set_flags (chan, flags, NULL);
1069
1070   if (res)
1071     {
1072       TRACE_LOG2 ("connect failed: %i %i", res, WSAGetLastError ());
1073
1074       errno = wsa2errno (WSAGetLastError ());
1075       return TRACE_SYSRES (-1);
1076     }
1077
1078   return TRACE_SUC ();
1079 }