2007-07-10 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;
353   int j;
354   int n = 0;
355   char *buf;
356   char *p;
357   
358   /* We have to quote some things because under Windows the program
359      parses the commandline and does some unquoting.  We enclose the
360      whole argument in double-quotes, and escape literal double-quotes
361      as well as backslashes with a backslash.  We end up with a
362      trailing space at the end of the line, but that is harmless.  */
363   for (i = 0; argv[i]; i++)
364     {
365       p = argv[i];
366       /* The leading double-quote.  */
367       n++;
368       while (*p)
369         {
370           /* An extra one for each literal that must be escaped.  */
371           if (*p == '\\' || *p == '"')
372             n++;
373           n++;
374           p++;
375         }
376       /* The trailing double-quote and the delimiter.  */
377       n += 2;
378     }
379   /* And a trailing zero.  */
380   n++;
381
382   buf = p = malloc (n);
383   if (!buf)
384     return NULL;
385   for (i = 0; argv[i]; i++)
386     {
387       char *argvp = argv[i];
388
389       *(p++) = '"';
390       while (*argvp)
391         {
392           if (*argvp == '\\' || *argvp == '"')
393             *(p++) = '\\';
394           *(p++) = *(argvp++);
395         }
396       *(p++) = '"';
397       *(p++) = ' ';
398     }
399   *(p++) = 0;
400
401   return buf;
402 }
403
404
405 int
406 _gpgme_io_spawn ( const char *path, char **argv,
407                   struct spawn_fd_item_s *fd_child_list,
408                   struct spawn_fd_item_s *fd_parent_list )
409 {
410     SECURITY_ATTRIBUTES sec_attr;
411     PROCESS_INFORMATION pi = {
412         NULL,      /* returns process handle */
413         0,         /* returns primary thread handle */
414         0,         /* returns pid */
415         0         /* returns tid */
416     };
417     STARTUPINFO si;
418     char *envblock = NULL;
419     int cr_flags = CREATE_DEFAULT_ERROR_MODE
420                  | GetPriorityClass (GetCurrentProcess ());
421     int i;
422     char *arg_string;
423     int duped_stdin = 0;
424     int duped_stderr = 0;
425     HANDLE hnul = INVALID_HANDLE_VALUE;
426     /* FIXME.  */
427     int debug_me = 0;
428
429     memset (&sec_attr, 0, sizeof sec_attr);
430     sec_attr.nLength = sizeof sec_attr;
431     sec_attr.bInheritHandle = FALSE;
432
433     arg_string = build_commandline (argv);
434     if (!arg_string )
435         return -1; 
436
437     memset (&si, 0, sizeof si);
438     si.cb = sizeof (si);
439     si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
440     si.wShowWindow = debug_me? SW_SHOW : SW_HIDE;
441     si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
442     si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
443     si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
444
445     for (i=0; fd_child_list[i].fd != -1; i++ ) {
446         if (fd_child_list[i].dup_to == 0 ) {
447             si.hStdInput = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
448             DEBUG2 ("using %d (%p) for stdin", fd_child_list[i].fd,
449                     _get_osfhandle (fd_child_list[i].fd));
450             duped_stdin=1;
451         }
452         else if (fd_child_list[i].dup_to == 1 ) {
453             si.hStdOutput = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
454             DEBUG2 ("using %d (%p) for stdout", fd_child_list[i].fd,
455                     _get_osfhandle (fd_child_list[i].fd));
456         }
457         else if (fd_child_list[i].dup_to == 2 ) {
458             si.hStdError = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
459             DEBUG2 ("using %d (%p) for stderr", fd_child_list[i].fd,
460                     _get_osfhandle (fd_child_list[i].fd));
461             duped_stderr = 1;
462         }
463     }
464
465     if( !duped_stdin || !duped_stderr ) {
466         SECURITY_ATTRIBUTES sa;
467
468         memset (&sa, 0, sizeof sa );
469         sa.nLength = sizeof sa;
470         sa.bInheritHandle = TRUE;
471         hnul = CreateFile ( "nul",
472                             GENERIC_READ|GENERIC_WRITE,
473                             FILE_SHARE_READ|FILE_SHARE_WRITE,
474                             &sa,
475                             OPEN_EXISTING,
476                             FILE_ATTRIBUTE_NORMAL,
477                             NULL );
478         if ( hnul == INVALID_HANDLE_VALUE ) {
479             DEBUG1 ("can't open `nul': ec=%d\n", (int)GetLastError ());
480             free (arg_string);
481             return -1;
482         }
483         /* Make sure that the process has a connected stdin */
484         if ( !duped_stdin ) {
485             si.hStdInput = hnul;
486             DEBUG1 ("using %d for dummy stdin", (int)hnul );
487         }
488         /* We normally don't want all the normal output */
489         if ( !duped_stderr ) {
490             si.hStdError = hnul;
491             DEBUG1 ("using %d for dummy stderr", (int)hnul );
492         }
493     }
494
495     DEBUG2 ("CreateProcess, path=`%s' args=`%s'", path, arg_string);
496     cr_flags |= CREATE_SUSPENDED; 
497     if ( !CreateProcessA (path,
498                           arg_string,
499                           &sec_attr,     /* process security attributes */
500                           &sec_attr,     /* thread security attributes */
501                           TRUE,          /* inherit handles */
502                           cr_flags,      /* creation flags */
503                           envblock,      /* environment */
504                           NULL,          /* use current drive/directory */
505                           &si,           /* startup information */
506                           &pi            /* returns process information */
507         ) ) {
508         DEBUG1 ("CreateProcess failed: ec=%d\n", (int) GetLastError ());
509         free (arg_string);
510         return -1;
511     }
512
513     /* Close the /dev/nul handle if used. */
514     if (hnul != INVALID_HANDLE_VALUE ) {
515         if ( !CloseHandle ( hnul ) )
516             DEBUG1 ("CloseHandle(hnul) failed: ec=%d\n", (int)GetLastError());
517     }
518
519     /* Close the other ends of the pipes. */
520     for (i = 0; fd_parent_list[i].fd != -1; i++)
521       _gpgme_io_close (fd_parent_list[i].fd);
522
523     DEBUG4 ("CreateProcess ready\n"
524             "-   hProcess=%p  hThread=%p\n"
525             "-   dwProcessID=%d dwThreadId=%d\n",
526             pi.hProcess, pi.hThread, 
527             (int) pi.dwProcessId, (int) pi.dwThreadId);
528
529     if ( ResumeThread ( pi.hThread ) < 0 ) {
530         DEBUG1 ("ResumeThread failed: ec=%d\n", (int)GetLastError ());
531     }
532
533     if ( !CloseHandle (pi.hThread) ) { 
534         DEBUG1 ("CloseHandle of thread failed: ec=%d\n",
535                  (int)GetLastError ());
536     }
537
538     return 0;
539 }
540
541
542 /*
543  * Select on the list of fds.
544  * Returns: -1 = error
545  *           0 = timeout or nothing to select
546  *          >0 = number of signaled fds
547  */
548 int
549 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
550 {
551   int     npollfds;
552   GPollFD *pollfds;
553   int     *pollfds_map; 
554   int i, j;
555   int any, n, count;
556   int timeout = 1000;  /* Use a 1s timeout.  */
557   void *dbg_help = NULL;
558
559   if (nonblock)
560     timeout = 0;
561
562   pollfds = calloc (nfds, sizeof *pollfds);
563   if (!pollfds)
564     return -1;
565   pollfds_map = calloc (nfds, sizeof *pollfds_map);
566   if (!pollfds_map)
567     {
568       free (pollfds);
569       return -1;
570     }
571   npollfds = 0;
572
573   DEBUG_BEGIN (dbg_help, 3, "gpgme:select on [ ");
574   any = 0;
575   for (i = 0; i < nfds; i++)
576     {
577       if (fds[i].fd == -1) 
578         continue;
579       if (fds[i].frozen)
580         DEBUG_ADD1 (dbg_help, "f%d ", fds[i].fd);
581       else if (fds[i].for_read )
582         {
583           GIOChannel *chan = find_channel (fds[i].fd, 0);
584           assert (chan);
585           g_io_channel_win32_make_pollfd (chan, G_IO_IN, pollfds + npollfds);
586           pollfds_map[npollfds] = i;
587           DEBUG_ADD2 (dbg_help, "r%d<%d> ", fds[i].fd, pollfds[npollfds].fd);
588           npollfds++;
589           any = 1;
590         }
591       else if (fds[i].for_write)
592         {
593           GIOChannel *chan = find_channel (fds[i].fd, 0);
594           assert (chan);
595           g_io_channel_win32_make_pollfd (chan, G_IO_OUT, pollfds + npollfds);
596           pollfds_map[npollfds] = i;
597           DEBUG_ADD2 (dbg_help, "w%d<%d> ", fds[i].fd, pollfds[npollfds].fd);
598           npollfds++;
599           any = 1;
600         }
601       fds[i].signaled = 0;
602     }
603   DEBUG_END (dbg_help, "]"); 
604   if (!any)
605     {
606       count = 0;
607       goto leave;
608     }
609
610
611   count = g_io_channel_win32_poll (pollfds, npollfds, timeout);
612   if (count < 0)
613     {
614       int saved_errno = errno;
615       DEBUG1 ("_gpgme_io_select failed: %s\n", strerror (errno));
616       errno = saved_errno;
617       goto leave;
618     }
619
620   DEBUG_BEGIN (dbg_help, 3, "select OK [ ");
621   if (DEBUG_ENABLED (dbg_help))
622     {
623       for (i = 0; i < npollfds; i++)
624         {
625           if ((pollfds[i].revents & G_IO_IN))
626             DEBUG_ADD1 (dbg_help, "r%d ", fds[pollfds_map[i]].fd);
627           if ((pollfds[i].revents & G_IO_OUT))
628             DEBUG_ADD1 (dbg_help, "w%d ", fds[pollfds_map[i]].fd);
629         }
630       DEBUG_END (dbg_help, "]");
631     }
632     
633   /* COUNT is used to stop the lop as soon as possible.  */
634   for (n = count, i = 0; i < npollfds && n; i++)
635     {
636       j = pollfds_map[i];
637       assert (j >= 0 && j < nfds);
638       if (fds[j].fd == -1)
639         ;
640       else if (fds[j].for_read)
641         {
642           if ((pollfds[i].revents & G_IO_IN))
643             {
644               fds[j].signaled = 1;
645               n--;
646             }
647         }
648       else if (fds[j].for_write)
649         {
650           if ((pollfds[i].revents & G_IO_OUT))
651             {
652               fds[j].signaled = 1;
653               n--;
654             }
655         }
656     }
657
658 leave:
659   free (pollfds);
660   free (pollfds_map);
661   return count;
662 }
663
664
665 int
666 _gpgme_io_dup (int fd)
667 {
668   return _dup (fd);
669 }  
670