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