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