Really add file.
[gpgme.git] / src / w32-qt-io.cpp
1 /* w32-qt-io.c - W32 Glib I/O functions
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2004, 2005, 2007 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 <windows.h>
36 #include <io.h>
37
38 #include "kdpipeiodevice.h"
39
40 extern "C"
41 {
42 #include "util.h"
43 #include "priv-io.h"
44 #include "sema.h"
45 #include "debug.h"
46 }
47
48 #ifndef O_BINARY
49 #ifdef _O_BINARY
50 #define O_BINARY        _O_BINARY
51 #else
52 #define O_BINARY        0
53 #endif
54 #endif
55
56 using _gpgme_::KDPipeIODevice;
57
58 \f
59 /* This file is an ugly hack to get GPGME working with Qt on Windows
60    targets.  On Windows, you can not select() on file descriptors.
61 \f
62    The only way to check if there is something to read is to read
63    something.  This means that GPGME can not let Qt check for data
64    without letting Qt also handle the data on Windows targets.
65
66    The ugly consequence is that we need to work on QIODevices in
67    GPGME, creating a Qt dependency.  Also, we need to export an
68    interface for the application to get at GPGME's QIODevices.  There
69    is no good way to abstract all this with callbacks, because the
70    whole thing is also interconnected with the creation of pipes and
71    child processes.
72
73    The following rule applies only to this I/O backend:
74
75    * ALL operations must use the user defined event loop.  GPGME can
76    not anymore provide its own event loop.  This is mostly a sanity
77    requirement: Although we have in theory all information we need to
78    make the GPGME W32 code for select still work, it would be a big
79    complication and require changes throughout GPGME.
80
81    Eventually, we probably have to bite the bullet and make some
82    really nice callback interfaces to let the user control all this at
83    a per-context level.  */
84
85 #define MAX_SLAFD 1024
86
87 struct DeviceEntry {
88   DeviceEntry() : iodev( 0 ), refCount( 1 ), blocking( true ) {}
89     KDPipeIODevice* iodev;
90     bool blocking;
91     mutable int refCount;
92     void ref() const { ++refCount; }
93     int unref() const { assert( refCount > 0 ); return --refCount; }
94 };
95
96 DeviceEntry* iodevice_table[MAX_SLAFD];
97
98
99 static KDPipeIODevice *
100 find_channel (int fd, int create)
101 {
102   assert( fd < MAX_SLAFD );
103   if (fd < 0 || fd >= MAX_SLAFD)
104     return NULL;
105
106   if (create && !iodevice_table[fd])
107   {
108     DeviceEntry* entry = new DeviceEntry;
109     entry->iodev = new KDPipeIODevice
110       (fd, QIODevice::ReadWrite|QIODevice::Unbuffered);
111     iodevice_table[fd] = entry; 
112   }
113   return iodevice_table[fd] ? iodevice_table[fd]->iodev : 0;
114 }
115
116 /* Write the printable version of FD to the buffer BUF of length
117    BUFLEN.  The printable version is the representation on the command
118    line that the child process expects.  */
119 int
120 _gpgme_io_fd2str (char *buf, int buflen, int fd)
121 {
122   return snprintf (buf, buflen, "%d", (long)_get_osfhandle( fd ) );
123 }
124
125 \f
126 void
127 _gpgme_io_subsystem_init (void)
128 {
129 }
130
131 \f
132 static struct
133 {
134   _gpgme_close_notify_handler_t handler;
135   void *value;
136 } notify_table[MAX_SLAFD];
137
138
139 int
140 _gpgme_io_read (int fd, void *buffer, size_t count)
141 {
142   int saved_errno = 0;
143   qint64 nread;
144   KDPipeIODevice *chan;
145   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
146               "buffer=%p, count=%u", buffer, count);
147
148   chan = find_channel (fd, 0);
149   if (!chan)
150     {
151       TRACE_LOG ("no channel registered");
152       errno = EINVAL;
153       return TRACE_SYSRES (-1);
154     }
155   TRACE_LOG1 ("channel %p", chan);
156   if ( iodevice_table[fd] && !iodevice_table[fd]->blocking && chan->readWouldBlock() ) {
157       errno = EAGAIN;
158       return TRACE_SYSRES( -1 );
159   }
160  
161   nread = chan->read ((char *) buffer, count);
162   if (nread < 0)
163     {
164       TRACE_LOG1 ("err %s", qPrintable (chan->errorString ()));
165       saved_errno = EIO;
166       nread = -1;
167     }
168
169   TRACE_LOGBUF ((char *) buffer, nread);
170
171   errno = saved_errno;
172   return TRACE_SYSRES (nread);
173 }
174
175
176 int
177 _gpgme_io_write (int fd, const void *buffer, size_t count)
178 {
179   qint64 nwritten;
180   KDPipeIODevice *chan;
181   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
182               "buffer=%p, count=%u", buffer, count);
183   TRACE_LOGBUF ((char *) buffer, count);
184
185   chan = find_channel (fd, 0);
186   if (!chan)
187     {
188       TRACE_LOG ("fd %d: no channel registered");
189       errno = EINVAL;
190       return -1;
191     }
192
193   if ( iodevice_table[fd] && !iodevice_table[fd]->blocking && chan->writeWouldBlock() )
194   {
195       errno = EAGAIN;
196       return TRACE_SYSRES( -1 );
197   }
198   nwritten = chan->write ((char *) buffer, count);
199
200   if (nwritten < 0)
201     {
202       nwritten = -1;
203       errno = EIO;
204       return TRACE_SYSRES(-1);
205     }
206   errno = 0;
207   return TRACE_SYSRES (nwritten);
208 }
209
210
211 int
212 _gpgme_io_pipe (int filedes[2], int inherit_idx)
213 {
214   KDPipeIODevice *chan;
215   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
216               "inherit_idx=%i (GPGME uses it for %s)",
217               inherit_idx, inherit_idx ? "reading" : "writing");
218
219 #define PIPEBUF_SIZE  4096
220   if (_pipe (filedes, PIPEBUF_SIZE, O_NOINHERIT | O_BINARY) == -1)
221     return TRACE_SYSRES (-1);
222
223   /* Make one end inheritable. */
224   if (inherit_idx == 0)
225     {
226       int new_read;
227
228       new_read = _dup (filedes[0]);
229       _close (filedes[0]);
230       filedes[0] = new_read;
231
232       if (new_read < 0)
233         {
234           _close (filedes[1]);
235           return TRACE_SYSRES (-1);
236         }
237     }
238   else if (inherit_idx == 1)
239     {
240       int new_write;
241
242       new_write = _dup (filedes[1]);
243       _close (filedes[1]);
244       filedes[1] = new_write;
245
246       if (new_write < 0)
247         {
248           _close (filedes[0]);
249           return TRACE_SYSRES (-1);
250         }
251     }
252
253   /* Now we have a pipe with the right end inheritable.  The other end
254      should have a giochannel.  */
255
256   chan = find_channel (filedes[1 - inherit_idx], 1);
257
258   if (!chan)
259     {
260       int saved_errno = errno;
261       _close (filedes[0]);
262       _close (filedes[1]);
263       errno = saved_errno;
264       return TRACE_SYSRES (-1);
265     }
266
267   return TRACE_SUC5 ("read=0x%x/%p, write=0x%x/%p, channel=%p",
268           filedes[0], (HANDLE) _get_osfhandle (filedes[0]),
269           filedes[1], (HANDLE) _get_osfhandle (filedes[1]),
270           chan);
271 }
272
273 int
274 _gpgme_io_close (int fd)
275 {
276   KDPipeIODevice *chan;
277   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
278
279   if (fd < 0 || fd >= MAX_SLAFD)
280     {
281       errno = EBADF;
282       return TRACE_SYSRES (-1);
283     }
284
285   /* First call the notify handler.  */
286   if (notify_table[fd].handler)
287     {
288       notify_table[fd].handler (fd, notify_table[fd].value);
289       notify_table[fd].handler = NULL;
290       notify_table[fd].value = NULL;
291     }
292
293   /* Then do the close.  */    
294   
295   DeviceEntry* const entry = iodevice_table[fd];
296   if ( entry ) {
297       if ( entry->unref() == 0 ) {
298           entry->iodev->close();
299           delete entry->iodev;
300           delete entry;
301           iodevice_table[fd] = 0;
302       }
303   } else {
304       _close( fd );
305   }
306
307   
308
309   return 0;
310 }
311
312
313 int
314 _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
315                             void *value)
316 {
317   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
318               "close_handler=%p/%p", handler, value);
319
320   assert (fd != -1);
321
322   if (fd < 0 || fd >= (int) DIM (notify_table))
323     {
324       errno = EINVAL;
325       return TRACE_SYSRES (-1);
326     }
327   notify_table[fd].handler = handler;
328   notify_table[fd].value = value;
329   return TRACE_SYSRES (0);
330 }
331
332
333 int
334 _gpgme_io_set_nonblocking (int fd)
335 {
336   DeviceEntry* const entry = iodevice_table[fd];
337   assert( entry );
338   entry->blocking = false; 
339   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
340   return TRACE_SYSRES (0);
341 }
342
343
344 static char *
345 build_commandline (char **argv)
346 {
347   int i;
348   int n = 0;
349   char *buf;
350   char *p;
351   
352   /* We have to quote some things because under Windows the program
353      parses the commandline and does some unquoting.  We enclose the
354      whole argument in double-quotes, and escape literal double-quotes
355      as well as backslashes with a backslash.  We end up with a
356      trailing space at the end of the line, but that is harmless.  */
357   for (i = 0; argv[i]; i++)
358     {
359       p = argv[i];
360       /* The leading double-quote.  */
361       n++;
362       while (*p)
363       {
364           /* An extra one for each literal that must be escaped.  */
365           if (*p == '\\' || *p == '"')
366             n++;
367           n++;
368           p++;
369         }
370       /* The trailing double-quote and the delimiter.  */
371       n += 2;
372     }
373   /* And a trailing zero.  */
374   n++;
375
376   buf = p = (char *) malloc (n);
377   if (!buf)
378     return NULL;
379   for (i = 0; argv[i]; i++)
380     {
381       char *argvp = argv[i];
382
383       *(p++) = '"';
384       while (*argvp)
385         {
386           if (*argvp == '\\' || *argvp == '"')
387             *(p++) = '\\';
388           *(p++) = *(argvp++);
389         }
390       *(p++) = '"';
391       *(p++) = ' ';
392     }
393   *(p++) = 0;
394
395   return buf;
396 }
397
398
399 int
400 _gpgme_io_spawn (const char *path, char * const argv[], unsigned int flags,
401                  struct spawn_fd_item_s *fd_list, pid_t *r_pid)
402 {
403   SECURITY_ATTRIBUTES sec_attr;
404   PROCESS_INFORMATION pi =
405     {
406       NULL,      /* returns process handle */
407       0,         /* returns primary thread handle */
408       0,         /* returns pid */
409       0         /* returns tid */
410     };
411   STARTUPINFO si;
412   int cr_flags = CREATE_DEFAULT_ERROR_MODE
413     | GetPriorityClass (GetCurrentProcess ());
414   int i;
415   char **args;
416   char *arg_string;
417   /* FIXME.  */
418   int debug_me = 0;
419   int tmp_fd;
420   char *tmp_name;
421
422   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
423               "path=%s", path);
424   i = 0;
425   while (argv[i])
426     {
427       TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
428       i++;
429     }
430   
431   /* We do not inherit any handles by default, and just insert those
432      handles we want the child to have afterwards.  But some handle
433      values occur on the command line, and we need to move
434      stdin/out/err to the right location.  So we use a wrapper program
435      which gets the information from a temporary file.  */
436   if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0)
437     {
438       TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno));
439       return TRACE_SYSRES (-1);
440     }
441   TRACE_LOG1 ("tmp_name = %s", tmp_name);
442
443   args = (char **) calloc (2 + i + 1, sizeof (*args));
444   args[0] = (char *) _gpgme_get_w32spawn_path ();
445   args[1] = tmp_name;
446   args[2] = const_cast<char *>(path);
447   memcpy (&args[3], &argv[1], i * sizeof (*args));
448
449   memset (&sec_attr, 0, sizeof sec_attr);
450   sec_attr.nLength = sizeof sec_attr;
451   sec_attr.bInheritHandle = FALSE;
452   
453   arg_string = build_commandline (args);
454   free (args);
455   if (!arg_string)
456     {
457       close (tmp_fd);
458       DeleteFile (tmp_name);
459       return TRACE_SYSRES (-1);
460     }
461   
462   memset (&si, 0, sizeof si);
463   si.cb = sizeof (si);
464   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
465   si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
466   si.hStdInput = INVALID_HANDLE_VALUE;
467   si.hStdOutput = INVALID_HANDLE_VALUE;
468   si.hStdError = INVALID_HANDLE_VALUE;
469
470   cr_flags |= CREATE_SUSPENDED;
471   cr_flags |= DETACHED_PROCESS;
472   if (!CreateProcessA (_gpgme_get_w32spawn_path (),
473                        arg_string,
474                        &sec_attr,     /* process security attributes */
475                        &sec_attr,     /* thread security attributes */
476                        FALSE,         /* inherit handles */
477                        cr_flags,      /* creation flags */
478                        NULL,          /* environment */
479                        NULL,          /* use current drive/directory */
480                        &si,           /* startup information */
481                        &pi))          /* returns process information */
482     {
483       TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
484       free (arg_string);
485       close (tmp_fd);
486       DeleteFile (tmp_name);
487
488       /* FIXME: Should translate the error code.  */
489       errno = EIO;
490       return TRACE_SYSRES (-1);
491     }
492
493   free (arg_string);
494
495   if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
496     _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
497
498   /* Insert the inherited handles.  */
499   for (i = 0; fd_list[i].fd != -1; i++)
500     {
501       HANDLE hd;
502
503       if (!DuplicateHandle (GetCurrentProcess(),
504                             (HANDLE) _get_osfhandle (fd_list[i].fd),
505                             pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
506         {
507           TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
508           TerminateProcess (pi.hProcess, 0);
509           /* Just in case TerminateProcess didn't work, let the
510              process fail on its own.  */
511           ResumeThread (pi.hThread);
512           CloseHandle (pi.hThread);
513           CloseHandle (pi.hProcess);
514
515           close (tmp_fd);
516           DeleteFile (tmp_name);
517
518           /* FIXME: Should translate the error code.  */
519           errno = EIO;
520           return TRACE_SYSRES (-1);
521         }
522       /* Return the child name of this handle.  */
523       fd_list[i].peer_name = (int) hd;
524     }
525     
526   /* Write the handle translation information to the temporary
527      file.  */
528   {
529     /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
530        notation: "0xFEDCBA9876543210" with an extra white space after
531        every quadruplet.  10*(19*4 + 1) - 1 = 769.  This plans ahead
532        for a time when a HANDLE is 64 bit.  */
533 #define BUFFER_MAX 800
534     char line[BUFFER_MAX + 1];
535     int res;
536     int written;
537     size_t len;
538
539     if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
540       strcpy (line, "~1 \n");
541     else
542       strcpy (line, "\n");
543     for (i = 0; fd_list[i].fd != -1; i++)
544       {
545         /* Strip the newline.  */
546         len = strlen (line) - 1;
547         
548         /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx.  */
549         snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d  \n",
550                   fd_list[i].fd, fd_list[i].dup_to,
551                   fd_list[i].peer_name, fd_list[i].arg_loc);
552         /* Rather safe than sorry.  */
553         line[BUFFER_MAX - 1] = '\n';
554         line[BUFFER_MAX] = '\0';
555       }
556     len = strlen (line);
557     written = 0;
558     do
559       {
560         res = write (tmp_fd, &line[written], len - written);
561         if (res > 0)
562           written += res;
563       }
564     while (res > 0 || (res < 0 && errno == EAGAIN));
565   }
566   close (tmp_fd);
567   /* The temporary file is deleted by the gpgme-w32spawn process
568      (hopefully).  */
569   
570   TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
571               "dwProcessID=%d, dwThreadId=%d",
572               pi.hProcess, pi.hThread, 
573               (int) pi.dwProcessId, (int) pi.dwThreadId);
574
575   if (r_pid)
576     *r_pid = (pid_t)pi.dwProcessId;
577   
578   if (ResumeThread (pi.hThread) < 0)
579     TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
580   
581   if (!CloseHandle (pi.hThread))
582     TRACE_LOG1 ("CloseHandle of thread failed: ec=%d",
583                 (int) GetLastError ());
584
585   TRACE_LOG1 ("process=%p", pi.hProcess);
586
587   /* We don't need to wait for the process.  */
588   if (!CloseHandle (pi.hProcess))
589     TRACE_LOG1 ("CloseHandle of process failed: ec=%d",
590                 (int) GetLastError ());
591
592   for (i = 0; fd_list[i].fd != -1; i++)
593     _gpgme_io_close (fd_list[i].fd);
594
595   for (i = 0; fd_list[i].fd != -1; i++)
596     if (fd_list[i].dup_to == -1)
597       TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
598                   fd_list[i].peer_name);
599     else
600       TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
601                   fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
602                   ((fd_list[i].dup_to == 1) ? "out" : "err"));
603
604   return TRACE_SYSRES (0);
605 }
606
607
608 /* Select on the list of fds.  Returns: -1 = error, 0 = timeout or
609    nothing to select, > 0 = number of signaled fds.  */
610 int
611 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
612 {
613   /* Use a 1s timeout.  */
614
615   void *dbg_help = NULL;
616   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
617               "nfds=%u, nonblock=%u", nfds, nonblock);
618
619   int count = 0;
620
621   TRACE_SEQ (dbg_help, "select on [ ");
622   for (int i = 0; i < nfds; i++)
623     {
624       if (fds[i].fd == -1)
625         {
626           fds[i].signaled = 0;
627         }
628       else if (fds[i].for_read )
629       {
630           KDPipeIODevice * const chan = find_channel (fds[i].fd, 0);
631           assert (chan);
632           if ( nonblock )
633               fds[i].signaled = chan->readWouldBlock() ? 0 : 1;
634           else
635               fds[i].signaled = chan->waitForReadyRead( 1000 ) ? 1 : 0;
636           TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
637           if ( fds[i].signaled ) 
638               count++;
639         }
640       else if (fds[i].for_write)
641         {
642           const KDPipeIODevice * const chan = find_channel (fds[i].fd, 0);
643           assert (chan);
644           fds[i].signaled = nonblock ? ( chan->writeWouldBlock() ? 0 : 1 ) : 1;
645           TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
646           if ( fds[i].signaled ) 
647               count++;
648         }
649     }
650   TRACE_END (dbg_help, "]"); 
651
652   return TRACE_SYSRES (count);
653 }
654
655
656 /* Look up the qiodevice for file descriptor FD.  */
657 extern "C"
658 void *
659 gpgme_get_fdptr (int fd)
660 {
661   return find_channel (fd, 0);
662 }
663
664
665 /* Obsolete compatibility interface.  */
666 extern "C"
667 void *
668 gpgme_get_giochannel (int fd)
669 {
670   return NULL;
671 }
672
673
674 int
675 _gpgme_io_dup (int fd)
676 {
677     assert( iodevice_table[fd] );
678     iodevice_table[fd]->ref();
679     return fd;
680 }
681
682 \f
683 extern "C"
684 int
685 _gpgme_io_socket (int domain, int type, int proto)
686 {
687   errno = EIO;
688   return -1;
689 }
690
691
692 extern "C"
693 int
694 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
695 {
696   errno = EIO;
697   return -1;
698 }