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