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