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