~ubuntu-branches/ubuntu/lucid/gpgme1.0/lucid

« back to all changes in this revision

Viewing changes to src/w32-glib-io.c

  • Committer: Bazaar Package Importer
  • Author(s): Scott Kitterman, Bhavani Shankar, Scott Kitterman
  • Date: 2008-12-31 02:39:33 UTC
  • mfrom: (1.1.6 upstream) (3.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20081231023933-zi5r2w9vf7fdz0x9
Tags: 1.1.8-1ubuntu1
[ Bhavani Shankar ]
* Merge from debian unstable, remaining changes: LP: #311666
  - debian/rules: enable tests

[ Scott Kitterman ]
* Re-enable testsuite on armel since it's no longer a first build 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
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
 
 
79
#define MAX_SLAFD 256
 
80
 
 
81
static struct 
 
82
{
 
83
  GIOChannel *chan;
 
84
  /* The boolean PRIMARY is true if this file descriptor caused the
 
85
     allocation of CHAN.  Only then should CHAN be destroyed when this
 
86
     FD is closed.  This, together with the fact that dup'ed file
 
87
     descriptors are closed before the file descriptors from which
 
88
     they are dup'ed are closed, ensures that CHAN is always valid,
 
89
     and shared among all file descriptors refering to the same
 
90
     underlying object.
 
91
 
 
92
     The logic behind this is that there is only one reason for us to
 
93
     dup file descriptors anyway: to allow simpler book-keeping of
 
94
     file descriptors shared between GPGME and libassuan, which both
 
95
     want to close something.  Using the same channel for these
 
96
     duplicates works just fine (and in fact, using different channels
 
97
     does not work because the W32 backend in glib does not support
 
98
     that: One would end up with several competing reader/writer
 
99
     threads.  */
 
100
  int primary;
 
101
} giochannel_table[MAX_SLAFD];
 
102
 
 
103
 
 
104
static GIOChannel *
 
105
find_channel (int fd, int create)
 
106
{
 
107
  if (fd < 0 || fd >= MAX_SLAFD)
 
108
    return NULL;
 
109
 
 
110
  if (create && !giochannel_table[fd].chan)
 
111
    {
 
112
      giochannel_table[fd].chan = g_io_channel_win32_new_fd (fd);
 
113
      giochannel_table[fd].primary = 1;
 
114
      g_io_channel_set_encoding (giochannel_table[fd].chan, NULL, NULL);
 
115
      g_io_channel_set_buffered (giochannel_table[fd].chan, FALSE);
 
116
    }
 
117
 
 
118
  return giochannel_table[fd].chan;
 
119
}
 
120
 
 
121
 
 
122
/* Compatibility interface.  Obsolete.  */
 
123
void *
 
124
gpgme_get_giochannel (int fd)
 
125
{
 
126
  return find_channel (fd, 0);
 
127
}
 
128
 
 
129
 
 
130
/* Look up the giochannel for "file descriptor" FD.  */
 
131
void *
 
132
gpgme_get_fdptr (int fd)
 
133
{
 
134
  return find_channel (fd, 0);
 
135
}
 
136
 
 
137
 
 
138
/* Write the printable version of FD to the buffer BUF of length
 
139
   BUFLEN.  The printable version is the representation on the command
 
140
   line that the child process expects.  */
 
141
int
 
142
_gpgme_io_fd2str (char *buf, int buflen, int fd)
 
143
{
 
144
  TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_fd2str", fd, "fd=%d", fd);
 
145
  TRACE_SUC1 ("syshd=%p", _get_osfhandle (fd));
 
146
  return snprintf (buf, buflen, "%d", (int) _get_osfhandle (fd));
 
147
}
 
148
 
 
149
 
 
150
void
 
151
_gpgme_io_subsystem_init (void)
 
152
{
 
153
}
 
154
 
 
155
 
 
156
static struct
 
157
{
 
158
  _gpgme_close_notify_handler_t handler;
 
159
  void *value;
 
160
} notify_table[MAX_SLAFD];
 
161
 
 
162
 
 
163
int
 
164
_gpgme_io_read (int fd, void *buffer, size_t count)
 
165
{
 
166
  int saved_errno = 0;
 
167
  gsize nread;
 
168
  GIOChannel *chan;
 
169
  GIOStatus status;
 
170
  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
 
171
              "buffer=%p, count=%u", buffer, count);
 
172
 
 
173
  chan = find_channel (fd, 0);
 
174
  if (!chan)
 
175
    {
 
176
      TRACE_LOG ("no channel registered");
 
177
      errno = EINVAL;
 
178
      return TRACE_SYSRES (-1);
 
179
    }
 
180
  TRACE_LOG1 ("channel %p", chan);
 
181
 
 
182
  {
 
183
    GError *err = NULL;
 
184
    status = g_io_channel_read_chars (chan, (gchar *) buffer,
 
185
                                      count, &nread, &err);
 
186
    if (err)
 
187
      {
 
188
        TRACE_LOG2 ("status %i, err %s", status, err->message);
 
189
        g_error_free (err);
 
190
      }
 
191
  }
 
192
 
 
193
  if (status == G_IO_STATUS_EOF)
 
194
    nread = 0;
 
195
  else if (status != G_IO_STATUS_NORMAL)
 
196
    {
 
197
      TRACE_LOG1 ("status %d", status);
 
198
      nread = -1;
 
199
      saved_errno = EIO;
 
200
    }
 
201
 
 
202
  TRACE_LOGBUF (buffer, nread);
 
203
 
 
204
  errno = saved_errno;
 
205
  return TRACE_SYSRES (nread);
 
206
}
 
207
 
 
208
 
 
209
int
 
210
_gpgme_io_write (int fd, const void *buffer, size_t count)
 
211
{
 
212
  int saved_errno = 0;
 
213
  gsize nwritten;
 
214
  GIOChannel *chan;
 
215
  GIOStatus status;
 
216
  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
 
217
              "buffer=%p, count=%u", buffer, count);
 
218
  TRACE_LOGBUF (buffer, count);
 
219
 
 
220
  chan = find_channel (fd, 0);
 
221
  if (!chan)
 
222
    {
 
223
      TRACE_LOG ("fd %d: no channel registered");
 
224
      errno = EINVAL;
 
225
      return -1;
 
226
    }
 
227
 
 
228
  status = g_io_channel_write_chars (chan, (gchar *) buffer, count,
 
229
                                     &nwritten, NULL);
 
230
  if (status != G_IO_STATUS_NORMAL)
 
231
    {
 
232
      nwritten = -1;
 
233
      saved_errno = EIO;
 
234
    }
 
235
  errno = saved_errno;
 
236
 
 
237
  return TRACE_SYSRES (nwritten);
 
238
}
 
239
 
 
240
 
 
241
int
 
242
_gpgme_io_pipe (int filedes[2], int inherit_idx)
 
243
{
 
244
  GIOChannel *chan;
 
245
  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
 
246
              "inherit_idx=%i (GPGME uses it for %s)",
 
247
              inherit_idx, inherit_idx ? "reading" : "writing");
 
248
 
 
249
#define PIPEBUF_SIZE  4096
 
250
  if (_pipe (filedes, PIPEBUF_SIZE, O_NOINHERIT | O_BINARY) == -1)
 
251
    return TRACE_SYSRES (-1);
 
252
 
 
253
  /* Make one end inheritable. */
 
254
  if (inherit_idx == 0)
 
255
    {
 
256
      int new_read;
 
257
 
 
258
      new_read = _dup (filedes[0]);
 
259
      _close (filedes[0]);
 
260
      filedes[0] = new_read;
 
261
 
 
262
      if (new_read < 0)
 
263
        {
 
264
          _close (filedes[1]);
 
265
          return TRACE_SYSRES (-1);
 
266
        }
 
267
    }
 
268
  else if (inherit_idx == 1)
 
269
    {
 
270
      int new_write;
 
271
 
 
272
      new_write = _dup (filedes[1]);
 
273
      _close (filedes[1]);
 
274
      filedes[1] = new_write;
 
275
 
 
276
      if (new_write < 0)
 
277
        {
 
278
          _close (filedes[0]);
 
279
          return TRACE_SYSRES (-1);
 
280
        }
 
281
    }
 
282
 
 
283
  /* Now we have a pipe with the right end inheritable.  The other end
 
284
     should have a giochannel.  */
 
285
  chan = find_channel (filedes[1 - inherit_idx], 1);
 
286
  if (!chan)
 
287
    {
 
288
      int saved_errno = errno;
 
289
      _close (filedes[0]);
 
290
      _close (filedes[1]);
 
291
      errno = saved_errno;
 
292
      return TRACE_SYSRES (-1);
 
293
    }
 
294
 
 
295
  return TRACE_SUC5 ("read=0x%x/%p, write=0x%x/%p, channel=%p",
 
296
          filedes[0], (HANDLE) _get_osfhandle (filedes[0]),
 
297
          filedes[1], (HANDLE) _get_osfhandle (filedes[1]),
 
298
          chan);
 
299
}
 
300
 
 
301
 
 
302
int
 
303
_gpgme_io_close (int fd)
 
304
{
 
305
  TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
 
306
 
 
307
  if (fd < 0 || fd >= MAX_SLAFD)
 
308
    {
 
309
      errno = EBADF;
 
310
      return TRACE_SYSRES (-1);
 
311
    }
 
312
 
 
313
  /* First call the notify handler.  */
 
314
  if (notify_table[fd].handler)
 
315
    {
 
316
      notify_table[fd].handler (fd, notify_table[fd].value);
 
317
      notify_table[fd].handler = NULL;
 
318
      notify_table[fd].value = NULL;
 
319
    }
 
320
 
 
321
  /* Then do the close.  */    
 
322
  if (giochannel_table[fd].chan)
 
323
    {
 
324
      if (giochannel_table[fd].primary)
 
325
        g_io_channel_shutdown (giochannel_table[fd].chan, 1, NULL);
 
326
      else
 
327
        _close (fd);
 
328
 
 
329
      g_io_channel_unref (giochannel_table[fd].chan);
 
330
      giochannel_table[fd].chan = NULL;
 
331
    }
 
332
  else
 
333
    _close (fd);
 
334
 
 
335
  TRACE_SUC ();
 
336
  return 0;
 
337
}
 
338
 
 
339
 
 
340
int
 
341
_gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
 
342
                            void *value)
 
343
{
 
344
  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
 
345
              "close_handler=%p/%p", handler, value);
 
346
 
 
347
  assert (fd != -1);
 
348
 
 
349
  if (fd < 0 || fd >= (int) DIM (notify_table))
 
350
    {
 
351
      errno = EINVAL;
 
352
      return TRACE_SYSRES (-1);
 
353
    }
 
354
  notify_table[fd].handler = handler;
 
355
  notify_table[fd].value = value;
 
356
  return TRACE_SYSRES (0);
 
357
}
 
358
 
 
359
 
 
360
int
 
361
_gpgme_io_set_nonblocking (int fd)
 
362
{
 
363
  GIOChannel *chan;
 
364
  GIOStatus status;
 
365
 
 
366
  TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
 
367
 
 
368
  chan = find_channel (fd, 0);
 
369
  if (!chan)
 
370
    {
 
371
      errno = EIO;
 
372
      return TRACE_SYSRES (-1);
 
373
    }
 
374
 
 
375
   status = g_io_channel_set_flags (chan,
 
376
                                   g_io_channel_get_flags (chan) |
 
377
                                   G_IO_FLAG_NONBLOCK, NULL);
 
378
  if (status != G_IO_STATUS_NORMAL)
 
379
    {
 
380
#if 0
 
381
      /* glib 1.9.2 does not implement set_flags and returns an
 
382
         error.  */
 
383
      errno = EIO;
 
384
      return TRACE_SYSRES (-1);
 
385
#else
 
386
      TRACE_LOG1 ("g_io_channel_set_flags failed: status=%d (ignored)",
 
387
                  status);
 
388
#endif
 
389
    }
 
390
 
 
391
  return TRACE_SYSRES (0);
 
392
}
 
393
 
 
394
 
 
395
static char *
 
396
build_commandline (char **argv)
 
397
{
 
398
  int i;
 
399
  int n = 0;
 
400
  char *buf;
 
401
  char *p;
 
402
  
 
403
  /* We have to quote some things because under Windows the program
 
404
     parses the commandline and does some unquoting.  We enclose the
 
405
     whole argument in double-quotes, and escape literal double-quotes
 
406
     as well as backslashes with a backslash.  We end up with a
 
407
     trailing space at the end of the line, but that is harmless.  */
 
408
  for (i = 0; argv[i]; i++)
 
409
    {
 
410
      p = argv[i];
 
411
      /* The leading double-quote.  */
 
412
      n++;
 
413
      while (*p)
 
414
        {
 
415
          /* An extra one for each literal that must be escaped.  */
 
416
          if (*p == '\\' || *p == '"')
 
417
            n++;
 
418
          n++;
 
419
          p++;
 
420
        }
 
421
      /* The trailing double-quote and the delimiter.  */
 
422
      n += 2;
 
423
    }
 
424
  /* And a trailing zero.  */
 
425
  n++;
 
426
 
 
427
  buf = p = malloc (n);
 
428
  if (!buf)
 
429
    return NULL;
 
430
  for (i = 0; argv[i]; i++)
 
431
    {
 
432
      char *argvp = argv[i];
 
433
 
 
434
      *(p++) = '"';
 
435
      while (*argvp)
 
436
        {
 
437
          if (*argvp == '\\' || *argvp == '"')
 
438
            *(p++) = '\\';
 
439
          *(p++) = *(argvp++);
 
440
        }
 
441
      *(p++) = '"';
 
442
      *(p++) = ' ';
 
443
    }
 
444
  *(p++) = 0;
 
445
 
 
446
  return buf;
 
447
}
 
448
 
 
449
 
 
450
int
 
451
_gpgme_io_spawn (const char *path, char **argv,
 
452
                 struct spawn_fd_item_s *fd_list, pid_t *r_pid)
 
453
{
 
454
  SECURITY_ATTRIBUTES sec_attr;
 
455
  PROCESS_INFORMATION pi =
 
456
    {
 
457
      NULL,      /* returns process handle */
 
458
      0,         /* returns primary thread handle */
 
459
      0,         /* returns pid */
 
460
      0          /* returns tid */
 
461
    };
 
462
  STARTUPINFO si;
 
463
  int cr_flags = CREATE_DEFAULT_ERROR_MODE
 
464
    | GetPriorityClass (GetCurrentProcess ());
 
465
  int i;
 
466
  char **args;
 
467
  char *arg_string;
 
468
  /* FIXME.  */
 
469
  int debug_me = 0;
 
470
  int tmp_fd;
 
471
  char *tmp_name;
 
472
 
 
473
  TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
 
474
              "path=%s", path);
 
475
  i = 0;
 
476
  while (argv[i])
 
477
    {
 
478
      TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
 
479
      i++;
 
480
    }
 
481
  
 
482
  /* We do not inherit any handles by default, and just insert those
 
483
     handles we want the child to have afterwards.  But some handle
 
484
     values occur on the command line, and we need to move
 
485
     stdin/out/err to the right location.  So we use a wrapper program
 
486
     which gets the information from a temporary file.  */
 
487
  if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0)
 
488
    {
 
489
      TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno));
 
490
      return TRACE_SYSRES (-1);
 
491
    }
 
492
  TRACE_LOG1 ("tmp_name = %s", tmp_name);
 
493
 
 
494
  args = calloc (2 + i + 1, sizeof (*args));
 
495
  args[0] = (char *) _gpgme_get_w32spawn_path ();
 
496
  args[1] = tmp_name;
 
497
  args[2] = path;
 
498
  memcpy (&args[3], &argv[1], i * sizeof (*args));
 
499
 
 
500
  memset (&sec_attr, 0, sizeof sec_attr);
 
501
  sec_attr.nLength = sizeof sec_attr;
 
502
  sec_attr.bInheritHandle = FALSE;
 
503
  
 
504
  arg_string = build_commandline (args);
 
505
  free (args);
 
506
  if (!arg_string)
 
507
    {
 
508
      close (tmp_fd);
 
509
      DeleteFile (tmp_name);
 
510
      return TRACE_SYSRES (-1);
 
511
    }
 
512
 
 
513
  memset (&si, 0, sizeof si);
 
514
  si.cb = sizeof (si);
 
515
  si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
 
516
  si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
 
517
  si.hStdInput = INVALID_HANDLE_VALUE;
 
518
  si.hStdOutput = INVALID_HANDLE_VALUE;
 
519
  si.hStdError = INVALID_HANDLE_VALUE;
 
520
 
 
521
  cr_flags |= CREATE_SUSPENDED;
 
522
  cr_flags |= DETACHED_PROCESS;
 
523
  if (!CreateProcessA (_gpgme_get_w32spawn_path (),
 
524
                       arg_string,
 
525
                       &sec_attr,     /* process security attributes */
 
526
                       &sec_attr,     /* thread security attributes */
 
527
                       FALSE,         /* inherit handles */
 
528
                       cr_flags,      /* creation flags */
 
529
                       NULL,          /* environment */
 
530
                       NULL,          /* use current drive/directory */
 
531
                       &si,           /* startup information */
 
532
                       &pi))          /* returns process information */
 
533
    {
 
534
      TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
 
535
      free (arg_string);
 
536
      close (tmp_fd);
 
537
      DeleteFile (tmp_name);
 
538
 
 
539
      /* FIXME: Should translate the error code.  */
 
540
      errno = EIO;
 
541
      return TRACE_SYSRES (-1);
 
542
    }
 
543
 
 
544
  free (arg_string);
 
545
  
 
546
  /* Insert the inherited handles.  */
 
547
  for (i = 0; fd_list[i].fd != -1; i++)
 
548
    {
 
549
      HANDLE hd;
 
550
 
 
551
      /* Make it inheritable for the wrapper process.  */
 
552
      if (!DuplicateHandle (GetCurrentProcess(), _get_osfhandle (fd_list[i].fd),
 
553
                            pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
 
554
        {
 
555
          TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
 
556
          TerminateProcess (pi.hProcess, 0);
 
557
          /* Just in case TerminateProcess didn't work, let the
 
558
             process fail on its own.  */
 
559
          ResumeThread (pi.hThread);
 
560
          CloseHandle (pi.hThread);
 
561
          CloseHandle (pi.hProcess);
 
562
 
 
563
          close (tmp_fd);
 
564
          DeleteFile (tmp_name);
 
565
 
 
566
          /* FIXME: Should translate the error code.  */
 
567
          errno = EIO;
 
568
          return TRACE_SYSRES (-1);
 
569
        }
 
570
      /* Return the child name of this handle.  */
 
571
      fd_list[i].peer_name = (int) hd;
 
572
    }
 
573
 
 
574
  /* Write the handle translation information to the temporary
 
575
     file.  */
 
576
  {
 
577
    /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
 
578
       notation: "0xFEDCBA9876543210" with an extra white space after
 
579
       every quadruplet.  10*(19*4 + 1) - 1 = 769.  This plans ahead
 
580
       for a time when a HANDLE is 64 bit.  */
 
581
#define BUFFER_MAX 800
 
582
    char line[BUFFER_MAX + 1];
 
583
    int res;
 
584
    int written;
 
585
    size_t len;
 
586
 
 
587
    line[0] = '\n';
 
588
    line[1] = '\0';
 
589
    for (i = 0; fd_list[i].fd != -1; i++)
 
590
      {
 
591
        /* Strip the newline.  */
 
592
        len = strlen (line) - 1;
 
593
        
 
594
        /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx.  */
 
595
        snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d  \n",
 
596
                  fd_list[i].fd, fd_list[i].dup_to,
 
597
                  fd_list[i].peer_name, fd_list[i].arg_loc);
 
598
        /* Rather safe than sorry.  */
 
599
        line[BUFFER_MAX - 1] = '\n';
 
600
        line[BUFFER_MAX] = '\0';
 
601
      }
 
602
    len = strlen (line);
 
603
    written = 0;
 
604
    do
 
605
      {
 
606
        res = write (tmp_fd, &line[written], len - written);
 
607
        if (res > 0)
 
608
          written += res;
 
609
      }
 
610
    while (res > 0 || (res < 0 && errno == EAGAIN));
 
611
  }
 
612
  close (tmp_fd);
 
613
  /* The temporary file is deleted by the gpgme-w32spawn process
 
614
     (hopefully).  */
 
615
    
 
616
  TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
 
617
              "dwProcessID=%d, dwThreadId=%d",
 
618
              pi.hProcess, pi.hThread, 
 
619
              (int) pi.dwProcessId, (int) pi.dwThreadId);
 
620
  
 
621
  if (r_pid)
 
622
    *r_pid = (pid_t)pi.dwProcessId;
 
623
 
 
624
  if (ResumeThread (pi.hThread) < 0)
 
625
    TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
 
626
  
 
627
  if (!CloseHandle (pi.hThread))
 
628
    TRACE_LOG1 ("CloseHandle of thread failed: ec=%d",
 
629
                (int) GetLastError ());
 
630
 
 
631
  TRACE_LOG1 ("process=%p", pi.hProcess);
 
632
 
 
633
  /* We don't need to wait for the process.  */
 
634
  if (!CloseHandle (pi.hProcess))
 
635
    TRACE_LOG1 ("CloseHandle of process failed: ec=%d",
 
636
                (int) GetLastError ());
 
637
 
 
638
  for (i = 0; fd_list[i].fd != -1; i++)
 
639
    _gpgme_io_close (fd_list[i].fd);
 
640
 
 
641
  for (i = 0; fd_list[i].fd != -1; i++)
 
642
    if (fd_list[i].dup_to == -1)
 
643
      TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
 
644
                  fd_list[i].peer_name);
 
645
    else
 
646
      TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
 
647
                  fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
 
648
                  ((fd_list[i].dup_to == 1) ? "out" : "err"));
 
649
 
 
650
  return TRACE_SYSRES (0);
 
651
}
 
652
 
 
653
 
 
654
/* Select on the list of fds.  Returns: -1 = error, 0 = timeout or
 
655
   nothing to select, > 0 = number of signaled fds.  */
 
656
int
 
657
_gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
 
658
{
 
659
  int npollfds;
 
660
  GPollFD *pollfds;
 
661
  int *pollfds_map; 
 
662
  int i;
 
663
  int j;
 
664
  int any;
 
665
  int n;
 
666
  int count;
 
667
  /* Use a 1s timeout.  */
 
668
  int timeout = 1000;
 
669
  void *dbg_help = NULL;
 
670
  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
 
671
              "nfds=%u, nonblock=%u", nfds, nonblock);
 
672
 
 
673
  if (nonblock)
 
674
    timeout = 0;
 
675
 
 
676
  pollfds = calloc (nfds, sizeof *pollfds);
 
677
  if (!pollfds)
 
678
    return -1;
 
679
  pollfds_map = calloc (nfds, sizeof *pollfds_map);
 
680
  if (!pollfds_map)
 
681
    {
 
682
      free (pollfds);
 
683
      return -1;
 
684
    }
 
685
  npollfds = 0;
 
686
 
 
687
  TRACE_SEQ (dbg_help, "select on [ ");
 
688
  any = 0;
 
689
  for (i = 0; i < nfds; i++)
 
690
    {
 
691
      GIOChannel *chan = NULL;
 
692
 
 
693
      if (fds[i].fd == -1) 
 
694
        continue;
 
695
 
 
696
      if ((fds[i].for_read || fds[i].for_write)
 
697
          && !(chan = find_channel (fds[i].fd, 0)))
 
698
        {
 
699
          TRACE_ADD1 (dbg_help, "[BAD0x%x ", fds[i].fd);
 
700
          TRACE_END (dbg_help, "]"); 
 
701
          assert (!"see log file");
 
702
        }
 
703
      else if (fds[i].for_read )
 
704
        {
 
705
          assert(chan);
 
706
          g_io_channel_win32_make_pollfd (chan, G_IO_IN, pollfds + npollfds);
 
707
          pollfds_map[npollfds] = i;
 
708
          TRACE_ADD2 (dbg_help, "r0x%x<%d> ", fds[i].fd, pollfds[npollfds].fd);
 
709
          npollfds++;
 
710
          any = 1;
 
711
        }
 
712
      else if (fds[i].for_write)
 
713
        {
 
714
          assert(chan);
 
715
          g_io_channel_win32_make_pollfd (chan, G_IO_OUT, pollfds + npollfds);
 
716
          pollfds_map[npollfds] = i;
 
717
          TRACE_ADD2 (dbg_help, "w0x%x<%d> ", fds[i].fd, pollfds[npollfds].fd);
 
718
          npollfds++;
 
719
          any = 1;
 
720
        }
 
721
      fds[i].signaled = 0;
 
722
    }
 
723
  TRACE_END (dbg_help, "]"); 
 
724
  if (!any)
 
725
    {
 
726
      count = 0;
 
727
      goto leave;
 
728
    }
 
729
 
 
730
 
 
731
  count = g_io_channel_win32_poll (pollfds, npollfds, timeout);
 
732
  if (count < 0)
 
733
    {
 
734
      int saved_errno = errno;
 
735
      errno = saved_errno;
 
736
      goto leave;
 
737
    }
 
738
 
 
739
  TRACE_SEQ (dbg_help, "select OK [ ");
 
740
  if (TRACE_ENABLED (dbg_help))
 
741
    {
 
742
      for (i = 0; i < npollfds; i++)
 
743
        {
 
744
          if ((pollfds[i].revents & G_IO_IN))
 
745
            TRACE_ADD1 (dbg_help, "r0x%x ", fds[pollfds_map[i]].fd);
 
746
          if ((pollfds[i].revents & G_IO_OUT))
 
747
            TRACE_ADD1 (dbg_help, "w0x%x ", fds[pollfds_map[i]].fd);
 
748
        }
 
749
      TRACE_END (dbg_help, "]");
 
750
    }
 
751
    
 
752
  /* COUNT is used to stop the lop as soon as possible.  */
 
753
  for (n = count, i = 0; i < npollfds && n; i++)
 
754
    {
 
755
      j = pollfds_map[i];
 
756
      assert (j >= 0 && j < nfds);
 
757
      if (fds[j].fd == -1)
 
758
        ;
 
759
      else if (fds[j].for_read)
 
760
        {
 
761
          if ((pollfds[i].revents & G_IO_IN))
 
762
            {
 
763
              fds[j].signaled = 1;
 
764
              n--;
 
765
            }
 
766
        }
 
767
      else if (fds[j].for_write)
 
768
        {
 
769
          if ((pollfds[i].revents & G_IO_OUT))
 
770
            {
 
771
              fds[j].signaled = 1;
 
772
              n--;
 
773
            }
 
774
        }
 
775
    }
 
776
 
 
777
leave:
 
778
  free (pollfds);
 
779
  free (pollfds_map);
 
780
  return TRACE_SYSRES (count);
 
781
}
 
782
 
 
783
 
 
784
int
 
785
_gpgme_io_dup (int fd)
 
786
{
 
787
  int newfd;
 
788
  GIOChannel *chan;
 
789
  
 
790
  TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_dup", fd, "dup (%d)", fd);
 
791
 
 
792
  newfd = _dup (fd);
 
793
  if (newfd == -1)
 
794
    return TRACE_SYSRES (-1);
 
795
  if (newfd < 0 || newfd >= MAX_SLAFD)
 
796
    {
 
797
      /* New FD won't fit into our table.  */
 
798
      _close (newfd);
 
799
      errno = EIO; 
 
800
      return TRACE_SYSRES (-1);
 
801
    }
 
802
  assert (giochannel_table[newfd].chan == NULL);
 
803
 
 
804
  chan = find_channel (fd, 0);
 
805
  assert (chan);
 
806
 
 
807
  g_io_channel_ref (chan);
 
808
  giochannel_table[newfd].chan = chan;
 
809
  giochannel_table[newfd].primary = 0;
 
810
 
 
811
  return TRACE_SYSRES (newfd);
 
812
}