2006-02-28 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / 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 GIOChannel *giochannel_table[MAX_SLAFD];
82
83
84 static GIOChannel *
85 find_channel (int fd, int create)
86 {
87   if (fd < 0 || fd >= MAX_SLAFD)
88     return NULL;
89
90   if (create && !giochannel_table[fd])
91     {
92       giochannel_table[fd] = g_io_channel_win32_new_fd (fd);
93       g_io_channel_set_encoding (giochannel_table[fd], NULL, NULL);
94       g_io_channel_set_buffered (giochannel_table[fd], FALSE);
95     }
96
97   return giochannel_table[fd];
98 }
99
100 /* Look up the giochannel for "file descriptor" FD.  */
101 GIOChannel *
102 gpgme_get_giochannel (int fd)
103 {
104   return find_channel (fd, 0);
105 }
106
107
108 /* Write the printable version of FD to the buffer BUF of length
109    BUFLEN.  The printable version is the representation on the command
110    line that the child process expects.  */
111 int
112 _gpgme_io_fd2str (char *buf, int buflen, int fd)
113 {
114   return snprintf (buf, buflen, "%ld", (long) _get_osfhandle (fd));
115 }
116
117 \f
118 void
119 _gpgme_io_subsystem_init (void)
120 {
121 }
122
123 \f
124 static struct
125 {
126   void (*handler) (int,void*);
127   void *value;
128 } notify_table[MAX_SLAFD];
129
130 int
131 _gpgme_io_read (int fd, void *buffer, size_t count)
132 {
133   int saved_errno = 0;
134   gsize nread;
135   GIOChannel *chan;
136   GIOStatus status;
137
138   DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int) count);
139
140   chan = find_channel (fd, 0);
141   if (!chan)
142     {
143       DEBUG1 ("fd %d: no channel registered\n", fd);
144       errno = EINVAL;
145       return -1;
146     }
147   DEBUG2 ("fd %d: channel %p\n", fd, chan);
148
149   {
150     GError *err = NULL;
151     status = g_io_channel_read_chars (chan, (gchar *) buffer,
152                                       count, &nread, &err);
153     if (err)
154       {
155         DEBUG3 ("fd %d: status %i, err %s\n", fd, status, err->message);
156         g_error_free (err);
157       }
158   }
159
160   if (status == G_IO_STATUS_EOF)
161     nread = 0;
162   else if (status != G_IO_STATUS_NORMAL)
163     {
164       DEBUG2 ("fd %d: status %d\n", fd, status);
165       nread = -1;
166       saved_errno = EIO;
167     }
168
169   DEBUG2 ("fd %d: got %d bytes\n", fd, nread);
170   if (nread > 0)
171     _gpgme_debug (2, "fd %d: got `%.*s'\n", fd, nread, buffer);
172
173   errno = saved_errno;
174   return nread;
175 }
176
177
178 int
179 _gpgme_io_write (int fd, const void *buffer, size_t count)
180 {
181   int saved_errno = 0;
182   gsize nwritten;
183   GIOChannel *chan;
184   GIOStatus status;
185
186   DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int) count);
187   _gpgme_debug (2, "fd %d: write `%.*s'\n", fd, (int) count, buffer);
188
189   chan = find_channel (fd, 0);
190   if (!chan)
191     {
192       DEBUG1 ("fd %d: no channel registered\n", fd);
193       errno = EINVAL;
194       return -1;
195     }
196
197   status = g_io_channel_write_chars (chan, (gchar *) buffer, count,
198                                      &nwritten, NULL);
199   if (status != G_IO_STATUS_NORMAL)
200     {
201       nwritten = -1;
202       saved_errno = EIO;
203     }
204   DEBUG2 ("fd %d:          wrote %d bytes\n", fd, (int) nwritten);
205   errno = saved_errno;
206   return nwritten;
207 }
208
209
210 int
211 _gpgme_io_pipe (int filedes[2], int inherit_idx)
212 {
213   GIOChannel *chan;
214
215 #define PIPEBUF_SIZE  4096
216   if (_pipe (filedes, PIPEBUF_SIZE, O_NOINHERIT | O_BINARY) == -1)
217     return -1;
218
219   /* Make one end inheritable. */
220   if (inherit_idx == 0)
221     {
222       int new_read;
223
224       new_read = _dup (filedes[0]);
225       _close (filedes[0]);
226       filedes[0] = new_read;
227
228       if (new_read < 0)
229         {
230           _close (filedes[1]);
231           return -1;
232         }
233     }
234   else if (inherit_idx == 1)
235     {
236       int new_write;
237
238       new_write = _dup (filedes[1]);
239       _close (filedes[1]);
240       filedes[1] = new_write;
241
242       if (new_write < 0)
243         {
244           _close (filedes[0]);
245           return -1;
246         }
247     }
248
249   /* Now we have a pipe with the right end inheritable.  The other end
250      should have a giochannel.  */
251   chan = find_channel (filedes[1 - inherit_idx], 1);
252   if (!chan)
253     {
254       DEBUG2 ("channel creation for %d failed: ec=%d\n",
255               filedes[1 - inherit_idx], errno);
256       _close (filedes[0]);
257       _close (filedes[1]);
258       return -1;
259     }
260
261   DEBUG5 ("CreatePipe %d (%p) %d (%p) inherit=%p\n",
262           filedes[0], (HANDLE) _get_osfhandle (filedes[0]),
263           filedes[1], (HANDLE) _get_osfhandle (filedes[1]),
264           chan);
265   return 0;
266 }
267
268
269 int
270 _gpgme_io_close (int fd)
271 {
272   GIOChannel *chan;
273
274   if (fd < 0 || fd >= MAX_SLAFD)
275     {
276       errno = EBADF;
277       return -1;
278     }
279
280   /* First call the notify handler.  */
281   DEBUG1 ("closing fd %d", fd);
282   if (notify_table[fd].handler)
283     {
284       notify_table[fd].handler (fd, notify_table[fd].value);
285       notify_table[fd].handler = NULL;
286       notify_table[fd].value = NULL;
287     }
288
289   /* Then do the close.  */    
290   chan = giochannel_table[fd];
291   if (chan)
292     {
293       g_io_channel_shutdown (chan, 1, NULL);
294       g_io_channel_unref (chan);
295       giochannel_table[fd] = NULL;
296     }
297   else
298     _close (fd);
299
300
301   return 0;
302 }
303
304
305 int
306 _gpgme_io_set_close_notify (int fd, void (*handler)(int, void*), void *value)
307 {
308   assert (fd != -1);
309
310   if (fd < 0 || fd >= (int) DIM (notify_table))
311     return -1;
312   DEBUG1 ("set notification for fd %d", fd);
313   notify_table[fd].handler = handler;
314   notify_table[fd].value = value;
315   return 0;
316 }
317
318
319 int
320 _gpgme_io_set_nonblocking (int fd)
321 {
322   GIOChannel *chan;
323   GIOStatus status;
324  
325   chan = find_channel (fd, 0);
326   if (!chan)
327     {
328       DEBUG1 ("set nonblocking for fd %d failed: channel not found", fd);
329       errno = EIO;
330       return -1;
331     }
332
333    status = g_io_channel_set_flags (chan,
334                                    g_io_channel_get_flags (chan) |
335                                    G_IO_FLAG_NONBLOCK, NULL);
336   if (status != G_IO_STATUS_NORMAL)
337     {
338       /* glib 1.9.2 does not implement set_flags and returns an error. */
339       DEBUG2 ("set nonblocking for fd %d failed: status=%d - ignored",
340               fd, status);
341 /*       errno = EIO; */
342 /*       return -1; */
343     }
344
345   return 0;
346 }
347
348
349 static char *
350 build_commandline ( char **argv )
351 {
352   int i, n = 0;
353   char *buf, *p;
354   
355   /* FIXME: we have to quote some things because under Windows the
356    * program parses the commandline and does some unquoting.  For now
357    * we only do very basic quoting to the first argument because this
358    * one often contains a space (e.g. C:\\Program Files\GNU\GnuPG\gpg.exe) 
359    * and we would produce an invalid line in that case.  */
360   for (i=0; argv[i]; i++)
361     n += strlen (argv[i]) + 2 + 1; /* 2 extra bytes for possible quoting */
362   buf = p = malloc (n);
363   if ( !buf )
364     return NULL;
365   *buf = 0;
366   if ( argv[0] )
367     {
368       if (strpbrk (argv[0], " \t"))
369         p = stpcpy (stpcpy (stpcpy (p, "\""), argv[0]), "\"");
370       else
371         p = stpcpy (p, argv[0]);
372       for (i = 1; argv[i]; i++)
373         {
374           if (!*argv[i])
375             p = stpcpy (p, " \"\"");
376           else
377             p = stpcpy (stpcpy (p, " "), argv[i]);
378         }
379     }
380   
381   return buf;
382 }
383
384
385 int
386 _gpgme_io_spawn ( const char *path, char **argv,
387                   struct spawn_fd_item_s *fd_child_list,
388                   struct spawn_fd_item_s *fd_parent_list )
389 {
390     SECURITY_ATTRIBUTES sec_attr;
391     PROCESS_INFORMATION pi = {
392         NULL,      /* returns process handle */
393         0,         /* returns primary thread handle */
394         0,         /* returns pid */
395         0         /* returns tid */
396     };
397     STARTUPINFO si;
398     char *envblock = NULL;
399     int cr_flags = CREATE_DEFAULT_ERROR_MODE
400                  | GetPriorityClass (GetCurrentProcess ());
401     int i;
402     char *arg_string;
403     int duped_stdin = 0;
404     int duped_stderr = 0;
405     HANDLE hnul = INVALID_HANDLE_VALUE;
406     /* FIXME.  */
407     int debug_me = 0;
408
409     memset (&sec_attr, 0, sizeof sec_attr);
410     sec_attr.nLength = sizeof sec_attr;
411     sec_attr.bInheritHandle = FALSE;
412
413     arg_string = build_commandline (argv);
414     if (!arg_string )
415         return -1; 
416
417     memset (&si, 0, sizeof si);
418     si.cb = sizeof (si);
419     si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
420     si.wShowWindow = debug_me? SW_SHOW : SW_HIDE;
421     si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
422     si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
423     si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
424
425     for (i=0; fd_child_list[i].fd != -1; i++ ) {
426         if (fd_child_list[i].dup_to == 0 ) {
427             si.hStdInput = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
428             DEBUG2 ("using %d (%p) for stdin", fd_child_list[i].fd,
429                     _get_osfhandle (fd_child_list[i].fd));
430             duped_stdin=1;
431         }
432         else if (fd_child_list[i].dup_to == 1 ) {
433             si.hStdOutput = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
434             DEBUG2 ("using %d (%p) for stdout", fd_child_list[i].fd,
435                     _get_osfhandle (fd_child_list[i].fd));
436         }
437         else if (fd_child_list[i].dup_to == 2 ) {
438             si.hStdError = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
439             DEBUG2 ("using %d (%p) for stderr", fd_child_list[i].fd,
440                     _get_osfhandle (fd_child_list[i].fd));
441             duped_stderr = 1;
442         }
443     }
444
445     if( !duped_stdin || !duped_stderr ) {
446         SECURITY_ATTRIBUTES sa;
447
448         memset (&sa, 0, sizeof sa );
449         sa.nLength = sizeof sa;
450         sa.bInheritHandle = TRUE;
451         hnul = CreateFile ( "nul",
452                             GENERIC_READ|GENERIC_WRITE,
453                             FILE_SHARE_READ|FILE_SHARE_WRITE,
454                             &sa,
455                             OPEN_EXISTING,
456                             FILE_ATTRIBUTE_NORMAL,
457                             NULL );
458         if ( hnul == INVALID_HANDLE_VALUE ) {
459             DEBUG1 ("can't open `nul': ec=%d\n", (int)GetLastError ());
460             free (arg_string);
461             return -1;
462         }
463         /* Make sure that the process has a connected stdin */
464         if ( !duped_stdin ) {
465             si.hStdInput = hnul;
466             DEBUG1 ("using %d for dummy stdin", (int)hnul );
467         }
468         /* We normally don't want all the normal output */
469         if ( !duped_stderr ) {
470             si.hStdError = hnul;
471             DEBUG1 ("using %d for dummy stderr", (int)hnul );
472         }
473     }
474
475     DEBUG2 ("CreateProcess, path=`%s' args=`%s'", path, arg_string);
476     cr_flags |= CREATE_SUSPENDED; 
477     if ( !CreateProcessA (path,
478                           arg_string,
479                           &sec_attr,     /* process security attributes */
480                           &sec_attr,     /* thread security attributes */
481                           TRUE,          /* inherit handles */
482                           cr_flags,      /* creation flags */
483                           envblock,      /* environment */
484                           NULL,          /* use current drive/directory */
485                           &si,           /* startup information */
486                           &pi            /* returns process information */
487         ) ) {
488         DEBUG1 ("CreateProcess failed: ec=%d\n", (int) GetLastError ());
489         free (arg_string);
490         return -1;
491     }
492
493     /* Close the /dev/nul handle if used. */
494     if (hnul != INVALID_HANDLE_VALUE ) {
495         if ( !CloseHandle ( hnul ) )
496             DEBUG1 ("CloseHandle(hnul) failed: ec=%d\n", (int)GetLastError());
497     }
498
499     /* Close the other ends of the pipes. */
500     for (i = 0; fd_parent_list[i].fd != -1; i++)
501       _gpgme_io_close (fd_parent_list[i].fd);
502
503     DEBUG4 ("CreateProcess ready\n"
504             "-   hProcess=%p  hThread=%p\n"
505             "-   dwProcessID=%d dwThreadId=%d\n",
506             pi.hProcess, pi.hThread, 
507             (int) pi.dwProcessId, (int) pi.dwThreadId);
508
509     if ( ResumeThread ( pi.hThread ) < 0 ) {
510         DEBUG1 ("ResumeThread failed: ec=%d\n", (int)GetLastError ());
511     }
512
513     if ( !CloseHandle (pi.hThread) ) { 
514         DEBUG1 ("CloseHandle of thread failed: ec=%d\n",
515                  (int)GetLastError ());
516     }
517
518     return 0;
519 }
520
521
522 /*
523  * Select on the list of fds.
524  * Returns: -1 = error
525  *           0 = timeout or nothing to select
526  *          >0 = number of signaled fds
527  */
528 int
529 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
530 {
531   int     npollfds;
532   GPollFD *pollfds;
533   int     *pollfds_map; 
534   int i, j;
535   int any, n, count;
536   int timeout = 1000;  /* Use a 1s timeout.  */
537   void *dbg_help = NULL;
538
539   if (nonblock)
540     timeout = 0;
541
542   pollfds = calloc (nfds, sizeof *pollfds);
543   if (!pollfds)
544     return -1;
545   pollfds_map = calloc (nfds, sizeof *pollfds_map);
546   if (!pollfds_map)
547     {
548       free (pollfds);
549       return -1;
550     }
551   npollfds = 0;
552
553   DEBUG_BEGIN (dbg_help, 3, "gpgme:select on [ ");
554   any = 0;
555   for (i = 0; i < nfds; i++)
556     {
557       if (fds[i].fd == -1) 
558         continue;
559       if (fds[i].frozen)
560         DEBUG_ADD1 (dbg_help, "f%d ", fds[i].fd);
561       else if (fds[i].for_read )
562         {
563           GIOChannel *chan = find_channel (fds[i].fd, 0);
564           assert (chan);
565           g_io_channel_win32_make_pollfd (chan, G_IO_IN, pollfds + npollfds);
566           pollfds_map[npollfds] = i;
567           DEBUG_ADD2 (dbg_help, "r%d<%d> ", fds[i].fd, pollfds[npollfds].fd);
568           npollfds++;
569           any = 1;
570         }
571       else if (fds[i].for_write)
572         {
573           GIOChannel *chan = find_channel (fds[i].fd, 0);
574           assert (chan);
575           g_io_channel_win32_make_pollfd (chan, G_IO_OUT, pollfds + npollfds);
576           pollfds_map[npollfds] = i;
577           DEBUG_ADD2 (dbg_help, "w%d<%d> ", fds[i].fd, pollfds[npollfds].fd);
578           npollfds++;
579           any = 1;
580         }
581       fds[i].signaled = 0;
582     }
583   DEBUG_END (dbg_help, "]"); 
584   if (!any)
585     {
586       count = 0;
587       goto leave;
588     }
589
590
591   count = g_io_channel_win32_poll (pollfds, npollfds, timeout);
592   if (count < 0)
593     {
594       int saved_errno = errno;
595       DEBUG1 ("_gpgme_io_select failed: %s\n", strerror (errno));
596       errno = saved_errno;
597       goto leave;
598     }
599
600   DEBUG_BEGIN (dbg_help, 3, "select OK [ ");
601   if (DEBUG_ENABLED (dbg_help))
602     {
603       for (i = 0; i < npollfds; i++)
604         {
605           if ((pollfds[i].revents & G_IO_IN))
606             DEBUG_ADD1 (dbg_help, "r%d ", fds[pollfds_map[i]].fd);
607           if ((pollfds[i].revents & G_IO_OUT))
608             DEBUG_ADD1 (dbg_help, "w%d ", fds[pollfds_map[i]].fd);
609         }
610       DEBUG_END (dbg_help, "]");
611     }
612     
613   /* COUNT is used to stop the lop as soon as possible.  */
614   for (n = count, i = 0; i < npollfds && n; i++)
615     {
616       j = pollfds_map[i];
617       assert (j >= 0 && j < nfds);
618       if (fds[j].fd == -1)
619         ;
620       else if (fds[j].for_read)
621         {
622           if ((pollfds[i].revents & G_IO_IN))
623             {
624               fds[j].signaled = 1;
625               n--;
626             }
627         }
628       else if (fds[j].for_write)
629         {
630           if ((pollfds[i].revents & G_IO_OUT))
631             {
632               fds[j].signaled = 1;
633               n--;
634             }
635         }
636     }
637
638 leave:
639   free (pollfds);
640   free (pollfds_map);
641   return count;
642 }