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