Blame src/w32-glib-io.c

Packit d7e8d0
/* w32-glib-io.c - W32 Glib I/O functions
Packit Service 30b792
 * Copyright (C) 2000 Werner Koch (dd9jn)
Packit Service 30b792
 * Copyright (C) 2001, 2002, 2004, 2005 g10 Code GmbH
Packit Service 30b792
 *
Packit Service 30b792
 * This file is part of GPGME.
Packit Service 30b792
 *
Packit Service 30b792
 * GPGME is free software; you can redistribute it and/or modify it
Packit Service 30b792
 * under the terms of the GNU Lesser General Public License as
Packit Service 30b792
 * published by the Free Software Foundation; either version 2.1 of
Packit Service 30b792
 * the License, or (at your option) any later version.
Packit Service 30b792
 *
Packit Service 30b792
 * GPGME is distributed in the hope that it will be useful, but
Packit Service 30b792
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 30b792
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 30b792
 * Lesser General Public License for more details.
Packit Service 30b792
 *
Packit Service 30b792
 * You should have received a copy of the GNU Lesser General Public
Packit Service 30b792
 * License along with this program; if not, see <https://gnu.org/licenses/>.
Packit Service 30b792
 * SPDX-License-Identifier: LGPL-2.1-or-later
Packit Service 30b792
 */
Packit d7e8d0
Packit d7e8d0
#ifdef HAVE_CONFIG_H
Packit d7e8d0
#include <config.h>
Packit d7e8d0
#endif
Packit d7e8d0
#include <stdio.h>
Packit d7e8d0
#include <stdlib.h>
Packit d7e8d0
#include <string.h>
Packit d7e8d0
#include <assert.h>
Packit d7e8d0
#include <errno.h>
Packit d7e8d0
#include <fcntl.h>
Packit d7e8d0
#ifdef HAVE_UNISTD_H
Packit d7e8d0
# include <unistd.h>
Packit d7e8d0
#endif
Packit d7e8d0
#ifdef HAVE_SYS_TIME_H
Packit d7e8d0
# include <sys/time.h>
Packit d7e8d0
#endif
Packit d7e8d0
#ifdef HAVE_SYS_TYPES_H
Packit d7e8d0
# include <sys/types.h>
Packit d7e8d0
#endif
Packit d7e8d0
#include <glib.h>
Packit d7e8d0
#include <windows.h>
Packit d7e8d0
#include <io.h>
Packit d7e8d0
Packit d7e8d0
#include "util.h"
Packit d7e8d0
#include "priv-io.h"
Packit d7e8d0
#include "sema.h"
Packit d7e8d0
#include "debug.h"
Packit d7e8d0
Packit d7e8d0
#ifndef O_BINARY
Packit d7e8d0
#ifdef _O_BINARY
Packit d7e8d0
#define O_BINARY	_O_BINARY
Packit d7e8d0
#else
Packit d7e8d0
#define O_BINARY	0
Packit d7e8d0
#endif
Packit d7e8d0
#endif
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
/* This file is an ugly hack to get GPGME working with glib on Windows
Packit d7e8d0
   targets.  On Windows, you can not select() on file descriptors.
Packit d7e8d0
   The only way to check if there is something to read is to read
Packit d7e8d0
   something.  This means that GPGME can not let glib check for data
Packit d7e8d0
   without letting glib also handle the data on Windows targets.
Packit d7e8d0
Packit d7e8d0
   The ugly consequence is that we need to work on GIOChannels in
Packit d7e8d0
   GPGME, creating a glib dependency.  Also, we need to export an
Packit d7e8d0
   interface for the application to get at GPGME's GIOChannel.  There
Packit d7e8d0
   is no good way to abstract all this with callbacks, because the
Packit d7e8d0
   whole thing is also interconnected with the creation of pipes and
Packit d7e8d0
   child processes.
Packit d7e8d0
Packit d7e8d0
   The following rule applies only to this I/O backend:
Packit d7e8d0
Packit d7e8d0
   * ALL operations must use the user defined event loop.  GPGME can
Packit d7e8d0
   not anymore provide its own event loop.  This is mostly a sanity
Packit d7e8d0
   requirement: Although we have in theory all information we need to
Packit d7e8d0
   make the GPGME W32 code for select still work, it would be a big
Packit d7e8d0
   complication and require changes throughout GPGME.
Packit d7e8d0
Packit d7e8d0
   Eventually, we probably have to bite the bullet and make some
Packit d7e8d0
   really nice callback interfaces to let the user control all this at
Packit d7e8d0
   a per-context level.  */
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
#define MAX_SLAFD 256
Packit d7e8d0
Packit d7e8d0
static struct
Packit d7e8d0
{
Packit d7e8d0
  int used;
Packit d7e8d0
Packit d7e8d0
  /* If this is not -1, then it's a libc file descriptor.  */
Packit d7e8d0
  int fd;
Packit d7e8d0
  /* If fd is -1, this is the Windows socket handle.  */
Packit d7e8d0
  int socket;
Packit d7e8d0
Packit d7e8d0
  GIOChannel *chan;
Packit d7e8d0
  /* The boolean PRIMARY is true if this file descriptor caused the
Packit d7e8d0
     allocation of CHAN.  Only then should CHAN be destroyed when this
Packit d7e8d0
     FD is closed.  This, together with the fact that dup'ed file
Packit d7e8d0
     descriptors are closed before the file descriptors from which
Packit d7e8d0
     they are dup'ed are closed, ensures that CHAN is always valid,
Packit d7e8d0
     and shared among all file descriptors referring to the same
Packit d7e8d0
     underlying object.
Packit d7e8d0
Packit d7e8d0
     The logic behind this is that there is only one reason for us to
Packit d7e8d0
     dup file descriptors anyway: to allow simpler book-keeping of
Packit d7e8d0
     file descriptors shared between GPGME and libassuan, which both
Packit d7e8d0
     want to close something.  Using the same channel for these
Packit d7e8d0
     duplicates works just fine (and in fact, using different channels
Packit d7e8d0
     does not work because the W32 backend in glib does not support
Packit d7e8d0
     that: One would end up with several competing reader/writer
Packit d7e8d0
     threads.  */
Packit d7e8d0
  int primary;
Packit d7e8d0
} giochannel_table[MAX_SLAFD];
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static GIOChannel *
Packit d7e8d0
find_channel (int fd)
Packit d7e8d0
{
Packit d7e8d0
  if (fd < 0 || fd >= MAX_SLAFD || !giochannel_table[fd].used)
Packit d7e8d0
    return NULL;
Packit d7e8d0
Packit d7e8d0
  return giochannel_table[fd].chan;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Returns the FD or -1 on resource limit.  */
Packit d7e8d0
int
Packit d7e8d0
new_dummy_channel_from_fd (int cfd)
Packit d7e8d0
{
Packit d7e8d0
  int idx;
Packit d7e8d0
Packit d7e8d0
  for (idx = 0; idx < MAX_SLAFD; idx++)
Packit d7e8d0
    if (! giochannel_table[idx].used)
Packit d7e8d0
      break;
Packit d7e8d0
Packit d7e8d0
  if (idx == MAX_SLAFD)
Packit d7e8d0
    {
Packit d7e8d0
      errno = EIO;
Packit d7e8d0
      return -1;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  giochannel_table[idx].used = 1;
Packit d7e8d0
  giochannel_table[idx].chan = NULL;
Packit d7e8d0
  giochannel_table[idx].fd = cfd;
Packit d7e8d0
  giochannel_table[idx].socket = INVALID_SOCKET;
Packit d7e8d0
  giochannel_table[idx].primary = 1;
Packit d7e8d0
Packit d7e8d0
  return idx;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Returns the FD or -1 on resource limit.  */
Packit d7e8d0
int
Packit d7e8d0
new_channel_from_fd (int cfd)
Packit d7e8d0
{
Packit d7e8d0
  int idx;
Packit d7e8d0
Packit d7e8d0
  for (idx = 0; idx < MAX_SLAFD; idx++)
Packit d7e8d0
    if (! giochannel_table[idx].used)
Packit d7e8d0
      break;
Packit d7e8d0
Packit d7e8d0
  if (idx == MAX_SLAFD)
Packit d7e8d0
    {
Packit d7e8d0
      errno = EIO;
Packit d7e8d0
      return -1;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  giochannel_table[idx].used = 1;
Packit d7e8d0
  giochannel_table[idx].chan = g_io_channel_win32_new_fd (cfd);
Packit d7e8d0
  giochannel_table[idx].fd = cfd;
Packit d7e8d0
  giochannel_table[idx].socket = INVALID_SOCKET;
Packit d7e8d0
  giochannel_table[idx].primary = 1;
Packit d7e8d0
Packit d7e8d0
  g_io_channel_set_encoding (giochannel_table[idx].chan, NULL, NULL);
Packit d7e8d0
  g_io_channel_set_buffered (giochannel_table[idx].chan, FALSE);
Packit d7e8d0
Packit d7e8d0
  return idx;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Returns the FD or -1 on resource limit.  */
Packit d7e8d0
int
Packit d7e8d0
new_channel_from_socket (int sock)
Packit d7e8d0
{
Packit d7e8d0
  int idx;
Packit d7e8d0
Packit d7e8d0
  for (idx = 0; idx < MAX_SLAFD; idx++)
Packit d7e8d0
    if (! giochannel_table[idx].used)
Packit d7e8d0
      break;
Packit d7e8d0
Packit d7e8d0
  if (idx == MAX_SLAFD)
Packit d7e8d0
    {
Packit d7e8d0
      errno = EIO;
Packit d7e8d0
      return -1;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  giochannel_table[idx].used = 1;
Packit d7e8d0
  giochannel_table[idx].chan = g_io_channel_win32_new_socket (sock);
Packit d7e8d0
  giochannel_table[idx].fd = -1;
Packit d7e8d0
  giochannel_table[idx].socket = sock;
Packit d7e8d0
  giochannel_table[idx].primary = 1;
Packit d7e8d0
Packit d7e8d0
  g_io_channel_set_encoding (giochannel_table[idx].chan, NULL, NULL);
Packit d7e8d0
  g_io_channel_set_buffered (giochannel_table[idx].chan, FALSE);
Packit d7e8d0
Packit d7e8d0
  return idx;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Compatibility interface.  Obsolete.  */
Packit d7e8d0
void *
Packit d7e8d0
gpgme_get_giochannel (int fd)
Packit d7e8d0
{
Packit d7e8d0
  return find_channel (fd);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Look up the giochannel for "file descriptor" FD.  */
Packit d7e8d0
void *
Packit d7e8d0
gpgme_get_fdptr (int fd)
Packit d7e8d0
{
Packit d7e8d0
  return find_channel (fd);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Write the printable version of FD to the buffer BUF of length
Packit d7e8d0
   BUFLEN.  The printable version is the representation on the command
Packit d7e8d0
   line that the child process expects.  */
Packit d7e8d0
int
Packit d7e8d0
_gpgme_io_fd2str (char *buf, int buflen, int fd)
Packit d7e8d0
{
Packit d7e8d0
  HANDLE hndl;
Packit d7e8d0
Packit Service 30b792
  TRACE_BEG  (DEBUG_SYSIO, "_gpgme_io_fd2str", fd, "fd=%d", fd);
Packit d7e8d0
  if (giochannel_table[fd].fd != -1)
Packit d7e8d0
    hndl = (HANDLE) _get_osfhandle (giochannel_table[fd].fd);
Packit d7e8d0
  else
Packit d7e8d0
    hndl = (HANDLE) giochannel_table[fd].socket;
Packit d7e8d0
Packit Service 30b792
  TRACE_SUC ("syshd=%p", hndl);
Packit d7e8d0
Packit d7e8d0
  return snprintf (buf, buflen, "%d", (int) hndl);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
void
Packit d7e8d0
_gpgme_io_subsystem_init (void)
Packit d7e8d0
{
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
static struct
Packit d7e8d0
{
Packit d7e8d0
  _gpgme_close_notify_handler_t handler;
Packit d7e8d0
  void *value;
Packit d7e8d0
} notify_table[MAX_SLAFD];
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
int
Packit d7e8d0
_gpgme_io_read (int fd, void *buffer, size_t count)
Packit d7e8d0
{
Packit d7e8d0
  int saved_errno = 0;
Packit d7e8d0
  gsize nread;
Packit d7e8d0
  GIOChannel *chan;
Packit d7e8d0
  GIOStatus status;
Packit Service 30b792
  TRACE_BEG  (DEBUG_SYSIO, "_gpgme_io_read", fd,
Packit d7e8d0
	      "buffer=%p, count=%u", buffer, count);
Packit d7e8d0
Packit d7e8d0
  chan = find_channel (fd);
Packit d7e8d0
  if (!chan)
Packit d7e8d0
    {
Packit d7e8d0
      TRACE_LOG ("no channel registered");
Packit d7e8d0
      errno = EINVAL;
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit Service 30b792
  TRACE_LOG  ("channel %p", chan);
Packit d7e8d0
Packit d7e8d0
  {
Packit d7e8d0
    GError *err = NULL;
Packit d7e8d0
    status = g_io_channel_read_chars (chan, (gchar *) buffer,
Packit d7e8d0
				      count, &nread, &err;;
Packit d7e8d0
    if (err)
Packit d7e8d0
      {
Packit Service 30b792
	TRACE_LOG  ("status %i, err %s", status, err->message);
Packit d7e8d0
	g_error_free (err);
Packit d7e8d0
      }
Packit d7e8d0
  }
Packit d7e8d0
Packit d7e8d0
  if (status == G_IO_STATUS_EOF)
Packit d7e8d0
    nread = 0;
Packit d7e8d0
  else if (status == G_IO_STATUS_AGAIN)
Packit d7e8d0
    {
Packit d7e8d0
      nread = -1;
Packit d7e8d0
      saved_errno = EAGAIN;
Packit d7e8d0
    }
Packit d7e8d0
  else if (status != G_IO_STATUS_NORMAL)
Packit d7e8d0
    {
Packit Service 30b792
      TRACE_LOG  ("status %d", status);
Packit d7e8d0
      nread = -1;
Packit d7e8d0
      saved_errno = EIO;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  if (nread != 0 && nread != -1)
Packit Service 30b792
    TRACE_LOGBUFX (buffer, nread);
Packit d7e8d0
Packit d7e8d0
  errno = saved_errno;
Packit d7e8d0
  return TRACE_SYSRES (nread);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
int
Packit d7e8d0
_gpgme_io_write (int fd, const void *buffer, size_t count)
Packit d7e8d0
{
Packit d7e8d0
  int saved_errno = 0;
Packit d7e8d0
  gsize nwritten;
Packit d7e8d0
  GIOChannel *chan;
Packit d7e8d0
  GIOStatus status;
Packit d7e8d0
  GError *err = NULL;
Packit d7e8d0
Packit Service 30b792
  TRACE_BEG  (DEBUG_SYSIO, "_gpgme_io_write", fd,
Packit d7e8d0
	      "buffer=%p, count=%u", buffer, count);
Packit Service 30b792
  TRACE_LOGBUFX (buffer, count);
Packit d7e8d0
Packit d7e8d0
  chan = find_channel (fd);
Packit d7e8d0
  if (!chan)
Packit d7e8d0
    {
Packit Service 30b792
      TRACE_LOG ("fd=%d: no channel registered");
Packit d7e8d0
      errno = EINVAL;
Packit d7e8d0
      return -1;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  status = g_io_channel_write_chars (chan, (gchar *) buffer, count,
Packit d7e8d0
				     &nwritten, &err;;
Packit d7e8d0
  if (err)
Packit d7e8d0
    {
Packit Service 30b792
      TRACE_LOG  ("write error: %s", err->message);
Packit d7e8d0
      g_error_free (err);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  if (status == G_IO_STATUS_AGAIN)
Packit d7e8d0
    {
Packit d7e8d0
      nwritten = -1;
Packit d7e8d0
      saved_errno = EAGAIN;
Packit d7e8d0
    }
Packit d7e8d0
  else if (status != G_IO_STATUS_NORMAL)
Packit d7e8d0
    {
Packit d7e8d0
      nwritten = -1;
Packit d7e8d0
      saved_errno = EIO;
Packit d7e8d0
    }
Packit d7e8d0
  errno = saved_errno;
Packit d7e8d0
Packit d7e8d0
  return TRACE_SYSRES (nwritten);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
int
Packit d7e8d0
_gpgme_io_pipe (int filedes[2], int inherit_idx)
Packit d7e8d0
{
Packit d7e8d0
  int fds[2];
Packit d7e8d0
Packit Service 30b792
  TRACE_BEG  (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
Packit d7e8d0
	      "inherit_idx=%i (GPGME uses it for %s)",
Packit d7e8d0
	      inherit_idx, inherit_idx ? "reading" : "writing");
Packit d7e8d0
Packit d7e8d0
#define PIPEBUF_SIZE  4096
Packit d7e8d0
  if (_pipe (fds, PIPEBUF_SIZE, O_NOINHERIT | O_BINARY) == -1)
Packit d7e8d0
    return TRACE_SYSRES (-1);
Packit d7e8d0
Packit d7e8d0
  /* Make one end inheritable. */
Packit d7e8d0
  if (inherit_idx == 0)
Packit d7e8d0
    {
Packit d7e8d0
      int new_read;
Packit d7e8d0
Packit d7e8d0
      new_read = _dup (fds[0]);
Packit d7e8d0
      _close (fds[0]);
Packit d7e8d0
      fds[0] = new_read;
Packit d7e8d0
Packit d7e8d0
      if (new_read < 0)
Packit d7e8d0
	{
Packit d7e8d0
	  _close (fds[1]);
Packit d7e8d0
	  return TRACE_SYSRES (-1);
Packit d7e8d0
	}
Packit d7e8d0
    }
Packit d7e8d0
  else if (inherit_idx == 1)
Packit d7e8d0
    {
Packit d7e8d0
      int new_write;
Packit d7e8d0
Packit d7e8d0
      new_write = _dup (fds[1]);
Packit d7e8d0
      _close (fds[1]);
Packit d7e8d0
      fds[1] = new_write;
Packit d7e8d0
Packit d7e8d0
      if (new_write < 0)
Packit d7e8d0
	{
Packit d7e8d0
	  _close (fds[0]);
Packit d7e8d0
	  return TRACE_SYSRES (-1);
Packit d7e8d0
	}
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* For _gpgme_io_close.  */
Packit d7e8d0
  filedes[inherit_idx] = new_dummy_channel_from_fd (fds[inherit_idx]);
Packit d7e8d0
  if (filedes[inherit_idx] < 0)
Packit d7e8d0
    {
Packit d7e8d0
      int saved_errno = errno;
Packit d7e8d0
Packit d7e8d0
      _close (fds[0]);
Packit d7e8d0
      _close (fds[1]);
Packit d7e8d0
      errno = saved_errno;
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* Now we have a pipe with the correct end inheritable.  The other end
Packit d7e8d0
     should have a giochannel.  */
Packit d7e8d0
  filedes[1 - inherit_idx] = new_channel_from_fd (fds[1 - inherit_idx]);
Packit d7e8d0
  if (filedes[1 - inherit_idx] < 0)
Packit d7e8d0
    {
Packit d7e8d0
      int saved_errno = errno;
Packit d7e8d0
Packit d7e8d0
      _gpgme_io_close (fds[inherit_idx]);
Packit d7e8d0
      _close (fds[1 - inherit_idx]);
Packit d7e8d0
      errno = saved_errno;
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
Packit Service 30b792
  TRACE_SUC ("read=0x%x/%p, write=0x%x/%p, channel=%p",
Packit Service 30b792
	     filedes[0],
Packit Service 30b792
	     (HANDLE) _get_osfhandle (giochannel_table[filedes[0]].fd),
Packit Service 30b792
	     filedes[1],
Packit Service 30b792
	     (HANDLE) _get_osfhandle (giochannel_table[filedes[1]].fd),
Packit Service 30b792
	     giochannel_table[1 - inherit_idx].chan);
Packit Service 30b792
  return 0;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
int
Packit d7e8d0
_gpgme_io_close (int fd)
Packit d7e8d0
{
Packit Service 30b792
  TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd, "");
Packit d7e8d0
Packit d7e8d0
  if (fd < 0 || fd >= MAX_SLAFD)
Packit d7e8d0
    {
Packit d7e8d0
      errno = EBADF;
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  assert (giochannel_table[fd].used);
Packit d7e8d0
Packit d7e8d0
  /* First call the notify handler.  */
Packit d7e8d0
  if (notify_table[fd].handler)
Packit d7e8d0
    {
Packit d7e8d0
      notify_table[fd].handler (fd, notify_table[fd].value);
Packit d7e8d0
      notify_table[fd].handler = NULL;
Packit d7e8d0
      notify_table[fd].value = NULL;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* Then do the close.  */
Packit d7e8d0
  if (giochannel_table[fd].chan)
Packit d7e8d0
    {
Packit d7e8d0
      if (giochannel_table[fd].primary)
Packit d7e8d0
	g_io_channel_shutdown (giochannel_table[fd].chan, 1, NULL);
Packit d7e8d0
Packit d7e8d0
      g_io_channel_unref (giochannel_table[fd].chan);
Packit d7e8d0
    }
Packit d7e8d0
  else
Packit d7e8d0
    {
Packit d7e8d0
      /* Dummy entry, just close.  */
Packit d7e8d0
      assert (giochannel_table[fd].fd != -1);
Packit d7e8d0
      _close (giochannel_table[fd].fd);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  giochannel_table[fd].used = 0;
Packit d7e8d0
  giochannel_table[fd].fd = -1;
Packit d7e8d0
  giochannel_table[fd].socket = INVALID_SOCKET;
Packit d7e8d0
  giochannel_table[fd].chan = NULL;
Packit d7e8d0
  giochannel_table[fd].primary = 0;
Packit d7e8d0
Packit Service 30b792
  TRACE_SUC ("");
Packit d7e8d0
  return 0;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
int
Packit d7e8d0
_gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
Packit d7e8d0
			    void *value)
Packit d7e8d0
{
Packit Service 30b792
  TRACE_BEG  (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
Packit d7e8d0
	      "close_handler=%p/%p", handler, value);
Packit d7e8d0
Packit d7e8d0
  assert (fd != -1);
Packit d7e8d0
Packit d7e8d0
  if (fd < 0 || fd >= (int) DIM (notify_table))
Packit d7e8d0
    {
Packit d7e8d0
      errno = EINVAL;
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
  notify_table[fd].handler = handler;
Packit d7e8d0
  notify_table[fd].value = value;
Packit d7e8d0
  return TRACE_SYSRES (0);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
int
Packit d7e8d0
_gpgme_io_set_nonblocking (int fd)
Packit d7e8d0
{
Packit d7e8d0
  GIOChannel *chan;
Packit d7e8d0
  GIOStatus status;
Packit d7e8d0
Packit Service 30b792
  TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd, "");
Packit d7e8d0
Packit d7e8d0
  chan = find_channel (fd);
Packit d7e8d0
  if (!chan)
Packit d7e8d0
    {
Packit d7e8d0
      errno = EIO;
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  status = g_io_channel_set_flags (chan,
Packit d7e8d0
				   g_io_channel_get_flags (chan) |
Packit d7e8d0
				   G_IO_FLAG_NONBLOCK, NULL);
Packit d7e8d0
Packit d7e8d0
  if (status != G_IO_STATUS_NORMAL)
Packit d7e8d0
    {
Packit d7e8d0
#if 0
Packit d7e8d0
      /* glib 1.9.2 does not implement set_flags and returns an
Packit d7e8d0
	 error.  */
Packit d7e8d0
      errno = EIO;
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
#else
Packit Service 30b792
      TRACE_LOG  ("g_io_channel_set_flags failed: status=%d (ignored)",
Packit d7e8d0
		  status);
Packit d7e8d0
#endif
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  return TRACE_SYSRES (0);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static char *
Packit d7e8d0
build_commandline (char **argv)
Packit d7e8d0
{
Packit d7e8d0
  int i;
Packit d7e8d0
  int n = 0;
Packit d7e8d0
  char *buf;
Packit d7e8d0
  char *p;
Packit d7e8d0
Packit d7e8d0
  /* We have to quote some things because under Windows the program
Packit d7e8d0
     parses the commandline and does some unquoting.  We enclose the
Packit d7e8d0
     whole argument in double-quotes, and escape literal double-quotes
Packit d7e8d0
     as well as backslashes with a backslash.  We end up with a
Packit d7e8d0
     trailing space at the end of the line, but that is harmless.  */
Packit d7e8d0
  for (i = 0; argv[i]; i++)
Packit d7e8d0
    {
Packit d7e8d0
      p = argv[i];
Packit d7e8d0
      /* The leading double-quote.  */
Packit d7e8d0
      n++;
Packit d7e8d0
      while (*p)
Packit d7e8d0
	{
Packit d7e8d0
	  /* An extra one for each literal that must be escaped.  */
Packit d7e8d0
	  if (*p == '\\' || *p == '"')
Packit d7e8d0
	    n++;
Packit d7e8d0
	  n++;
Packit d7e8d0
	  p++;
Packit d7e8d0
	}
Packit d7e8d0
      /* The trailing double-quote and the delimiter.  */
Packit d7e8d0
      n += 2;
Packit d7e8d0
    }
Packit d7e8d0
  /* And a trailing zero.  */
Packit d7e8d0
  n++;
Packit d7e8d0
Packit d7e8d0
  buf = p = malloc (n);
Packit d7e8d0
  if (!buf)
Packit d7e8d0
    return NULL;
Packit d7e8d0
  for (i = 0; argv[i]; i++)
Packit d7e8d0
    {
Packit d7e8d0
      char *argvp = argv[i];
Packit d7e8d0
Packit d7e8d0
      *(p++) = '"';
Packit d7e8d0
      while (*argvp)
Packit d7e8d0
	{
Packit d7e8d0
	  if (*argvp == '\\' || *argvp == '"')
Packit d7e8d0
	    *(p++) = '\\';
Packit d7e8d0
	  *(p++) = *(argvp++);
Packit d7e8d0
	}
Packit d7e8d0
      *(p++) = '"';
Packit d7e8d0
      *(p++) = ' ';
Packit d7e8d0
    }
Packit d7e8d0
  *(p++) = 0;
Packit d7e8d0
Packit d7e8d0
  return buf;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
int
Packit d7e8d0
_gpgme_io_spawn (const char *path, char * const argv[], unsigned int flags,
Packit d7e8d0
		 struct spawn_fd_item_s *fd_list,
Packit d7e8d0
		 void (*atfork) (void *opaque, int reserved),
Packit d7e8d0
		 void *atforkvalue, pid_t *r_pid)
Packit d7e8d0
{
Packit d7e8d0
  SECURITY_ATTRIBUTES sec_attr;
Packit d7e8d0
  PROCESS_INFORMATION pi =
Packit d7e8d0
    {
Packit d7e8d0
      NULL,      /* returns process handle */
Packit d7e8d0
      0,         /* returns primary thread handle */
Packit d7e8d0
      0,         /* returns pid */
Packit d7e8d0
      0          /* returns tid */
Packit d7e8d0
    };
Packit d7e8d0
  STARTUPINFO si;
Packit d7e8d0
  int cr_flags = (CREATE_DEFAULT_ERROR_MODE
Packit d7e8d0
                  | GetPriorityClass (GetCurrentProcess ()));
Packit d7e8d0
  int i;
Packit d7e8d0
  char **args;
Packit d7e8d0
  char *arg_string;
Packit d7e8d0
  /* FIXME.  */
Packit d7e8d0
  int debug_me = 0;
Packit d7e8d0
  int tmp_fd;
Packit d7e8d0
  char *tmp_name;
Packit d7e8d0
Packit Service 30b792
  TRACE_BEG  (DEBUG_SYSIO, "_gpgme_io_spawn", path,
Packit d7e8d0
	      "path=%s", path);
Packit d7e8d0
  i = 0;
Packit d7e8d0
  while (argv[i])
Packit d7e8d0
    {
Packit Service 30b792
      TRACE_LOG  ("argv[%2i] = %s", i, argv[i]);
Packit d7e8d0
      i++;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* We do not inherit any handles by default, and just insert those
Packit d7e8d0
     handles we want the child to have afterwards.  But some handle
Packit d7e8d0
     values occur on the command line, and we need to move
Packit d7e8d0
     stdin/out/err to the right location.  So we use a wrapper program
Packit d7e8d0
     which gets the information from a temporary file.  */
Packit d7e8d0
  if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0)
Packit d7e8d0
    {
Packit Service 30b792
      TRACE_LOG  ("_gpgme_mkstemp failed: %s", strerror (errno));
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit Service 30b792
  TRACE_LOG  ("tmp_name = %s", tmp_name);
Packit d7e8d0
Packit d7e8d0
  args = calloc (2 + i + 1, sizeof (*args));
Packit d7e8d0
  args[0] = (char *) _gpgme_get_w32spawn_path ();
Packit d7e8d0
  args[1] = tmp_name;
Packit d7e8d0
  args[2] = path;
Packit d7e8d0
  memcpy (&args[3], &argv[1], i * sizeof (*args));
Packit d7e8d0
Packit d7e8d0
  memset (&sec_attr, 0, sizeof sec_attr);
Packit d7e8d0
  sec_attr.nLength = sizeof sec_attr;
Packit d7e8d0
  sec_attr.bInheritHandle = FALSE;
Packit d7e8d0
Packit d7e8d0
  arg_string = build_commandline (args);
Packit d7e8d0
  free (args);
Packit d7e8d0
  if (!arg_string)
Packit d7e8d0
    {
Packit d7e8d0
      close (tmp_fd);
Packit d7e8d0
      DeleteFile (tmp_name);
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  memset (&si, 0, sizeof si);
Packit d7e8d0
  si.cb = sizeof (si);
Packit d7e8d0
  si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
Packit d7e8d0
  si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
Packit d7e8d0
  si.hStdInput = INVALID_HANDLE_VALUE;
Packit d7e8d0
  si.hStdOutput = INVALID_HANDLE_VALUE;
Packit d7e8d0
  si.hStdError = INVALID_HANDLE_VALUE;
Packit d7e8d0
Packit d7e8d0
  cr_flags |= CREATE_SUSPENDED;
Packit d7e8d0
  if ((flags & IOSPAWN_FLAG_DETACHED))
Packit d7e8d0
    cr_flags |= DETACHED_PROCESS;
Packit d7e8d0
  if (!CreateProcessA (_gpgme_get_w32spawn_path (),
Packit d7e8d0
		       arg_string,
Packit d7e8d0
		       &sec_attr,     /* process security attributes */
Packit d7e8d0
		       &sec_attr,     /* thread security attributes */
Packit d7e8d0
		       FALSE,         /* inherit handles */
Packit d7e8d0
		       cr_flags,      /* creation flags */
Packit d7e8d0
		       NULL,          /* environment */
Packit d7e8d0
		       NULL,          /* use current drive/directory */
Packit d7e8d0
		       &si,           /* startup information */
Packit d7e8d0
		       &pi))          /* returns process information */
Packit d7e8d0
    {
Packit Service 30b792
      TRACE_LOG  ("CreateProcess failed: ec=%d", (int) GetLastError ());
Packit d7e8d0
      free (arg_string);
Packit d7e8d0
      close (tmp_fd);
Packit d7e8d0
      DeleteFile (tmp_name);
Packit d7e8d0
Packit d7e8d0
      /* FIXME: Should translate the error code.  */
Packit d7e8d0
      errno = EIO;
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  free (arg_string);
Packit d7e8d0
Packit d7e8d0
  if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
Packit d7e8d0
    _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
Packit d7e8d0
Packit d7e8d0
  /* Insert the inherited handles.  */
Packit d7e8d0
  for (i = 0; fd_list[i].fd != -1; i++)
Packit d7e8d0
    {
Packit d7e8d0
      HANDLE hd;
Packit d7e8d0
Packit d7e8d0
      /* Make it inheritable for the wrapper process.  */
Packit d7e8d0
      if (!DuplicateHandle (GetCurrentProcess(),
Packit d7e8d0
			    _get_osfhandle (giochannel_table[fd_list[i].fd].fd),
Packit d7e8d0
			    pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
Packit d7e8d0
	{
Packit Service 30b792
	  TRACE_LOG  ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
Packit d7e8d0
	  TerminateProcess (pi.hProcess, 0);
Packit d7e8d0
	  /* Just in case TerminateProcess didn't work, let the
Packit d7e8d0
	     process fail on its own.  */
Packit d7e8d0
	  ResumeThread (pi.hThread);
Packit d7e8d0
	  CloseHandle (pi.hThread);
Packit d7e8d0
	  CloseHandle (pi.hProcess);
Packit d7e8d0
Packit d7e8d0
	  close (tmp_fd);
Packit d7e8d0
	  DeleteFile (tmp_name);
Packit d7e8d0
Packit d7e8d0
	  /* FIXME: Should translate the error code.  */
Packit d7e8d0
	  errno = EIO;
Packit d7e8d0
	  return TRACE_SYSRES (-1);
Packit d7e8d0
        }
Packit d7e8d0
      /* Return the child name of this handle.  */
Packit d7e8d0
      fd_list[i].peer_name = (int) hd;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* Write the handle translation information to the temporary
Packit d7e8d0
     file.  */
Packit d7e8d0
  {
Packit d7e8d0
    /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
Packit d7e8d0
       notation: "0xFEDCBA9876543210" with an extra white space after
Packit d7e8d0
       every quadruplet.  10*(19*4 + 1) - 1 = 769.  This plans ahead
Packit d7e8d0
       for a time when a HANDLE is 64 bit.  */
Packit d7e8d0
#define BUFFER_MAX 800
Packit d7e8d0
    char line[BUFFER_MAX + 1];
Packit d7e8d0
    int res;
Packit d7e8d0
    int written;
Packit d7e8d0
    size_t len;
Packit d7e8d0
Packit d7e8d0
    if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
Packit d7e8d0
      strcpy (line, "~1 \n");
Packit d7e8d0
    else
Packit d7e8d0
      strcpy (line, "\n");
Packit d7e8d0
    for (i = 0; fd_list[i].fd != -1; i++)
Packit d7e8d0
      {
Packit d7e8d0
	/* Strip the newline.  */
Packit d7e8d0
	len = strlen (line) - 1;
Packit d7e8d0
Packit d7e8d0
	/* Format is: Local name, stdin/stdout/stderr, peer name, argv idx.  */
Packit d7e8d0
	snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d  \n",
Packit d7e8d0
		  fd_list[i].fd, fd_list[i].dup_to,
Packit d7e8d0
		  fd_list[i].peer_name, fd_list[i].arg_loc);
Packit d7e8d0
	/* Rather safe than sorry.  */
Packit d7e8d0
	line[BUFFER_MAX - 1] = '\n';
Packit d7e8d0
	line[BUFFER_MAX] = '\0';
Packit d7e8d0
      }
Packit d7e8d0
    len = strlen (line);
Packit d7e8d0
    written = 0;
Packit d7e8d0
    do
Packit d7e8d0
      {
Packit d7e8d0
	res = write (tmp_fd, &line[written], len - written);
Packit d7e8d0
	if (res > 0)
Packit d7e8d0
	  written += res;
Packit d7e8d0
      }
Packit d7e8d0
    while (res > 0 || (res < 0 && errno == EAGAIN));
Packit d7e8d0
  }
Packit d7e8d0
  close (tmp_fd);
Packit d7e8d0
  /* The temporary file is deleted by the gpgme-w32spawn process
Packit d7e8d0
     (hopefully).  */
Packit d7e8d0
Packit Service 30b792
  TRACE_LOG  ("CreateProcess ready: hProcess=%p, hThread=%p, "
Packit d7e8d0
	      "dwProcessID=%d, dwThreadId=%d",
Packit d7e8d0
	      pi.hProcess, pi.hThread,
Packit d7e8d0
	      (int) pi.dwProcessId, (int) pi.dwThreadId);
Packit d7e8d0
Packit d7e8d0
  if (r_pid)
Packit d7e8d0
    *r_pid = (pid_t)pi.dwProcessId;
Packit d7e8d0
Packit d7e8d0
  if (ResumeThread (pi.hThread) < 0)
Packit Service 30b792
    TRACE_LOG  ("ResumeThread failed: ec=%d", (int) GetLastError ());
Packit d7e8d0
Packit d7e8d0
  if (!CloseHandle (pi.hThread))
Packit Service 30b792
    TRACE_LOG  ("CloseHandle of thread failed: ec=%d",
Packit d7e8d0
		(int) GetLastError ());
Packit d7e8d0
Packit Service 30b792
  TRACE_LOG  ("process=%p", pi.hProcess);
Packit d7e8d0
Packit d7e8d0
  /* We don't need to wait for the process.  */
Packit d7e8d0
  if (!CloseHandle (pi.hProcess))
Packit Service 30b792
    TRACE_LOG  ("CloseHandle of process failed: ec=%d",
Packit d7e8d0
		(int) GetLastError ());
Packit d7e8d0
Packit d7e8d0
  if (! (flags & IOSPAWN_FLAG_NOCLOSE))
Packit d7e8d0
    {
Packit d7e8d0
      for (i = 0; fd_list[i].fd != -1; i++)
Packit d7e8d0
	_gpgme_io_close (fd_list[i].fd);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  for (i = 0; fd_list[i].fd != -1; i++)
Packit d7e8d0
    if (fd_list[i].dup_to == -1)
Packit Service 30b792
      TRACE_LOG  ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
Packit d7e8d0
		  fd_list[i].peer_name);
Packit d7e8d0
    else
Packit Service 30b792
      TRACE_LOG  ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
Packit d7e8d0
		  fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
Packit d7e8d0
		  ((fd_list[i].dup_to == 1) ? "out" : "err"));
Packit d7e8d0
Packit d7e8d0
  return TRACE_SYSRES (0);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Select on the list of fds.  Returns: -1 = error, 0 = timeout or
Packit d7e8d0
   nothing to select, > 0 = number of signaled fds.  */
Packit d7e8d0
int
Packit d7e8d0
_gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
Packit d7e8d0
{
Packit d7e8d0
  int npollfds;
Packit d7e8d0
  GPollFD *pollfds;
Packit d7e8d0
  int *pollfds_map;
Packit d7e8d0
  int i;
Packit d7e8d0
  int j;
Packit d7e8d0
  int any;
Packit d7e8d0
  int n;
Packit d7e8d0
  int count;
Packit d7e8d0
  /* Use a 1s timeout.  */
Packit d7e8d0
  int timeout = 1000;
Packit d7e8d0
  void *dbg_help = NULL;
Packit Service 30b792
  TRACE_BEG  (DEBUG_SYSIO, "_gpgme_io_select", fds,
Packit d7e8d0
	      "nfds=%u, nonblock=%u", nfds, nonblock);
Packit d7e8d0
Packit d7e8d0
  if (nonblock)
Packit d7e8d0
    timeout = 0;
Packit d7e8d0
Packit d7e8d0
  pollfds = calloc (nfds, sizeof *pollfds);
Packit d7e8d0
  if (!pollfds)
Packit d7e8d0
    return -1;
Packit d7e8d0
  pollfds_map = calloc (nfds, sizeof *pollfds_map);
Packit d7e8d0
  if (!pollfds_map)
Packit d7e8d0
    {
Packit d7e8d0
      free (pollfds);
Packit d7e8d0
      return -1;
Packit d7e8d0
    }
Packit d7e8d0
  npollfds = 0;
Packit d7e8d0
Packit d7e8d0
  TRACE_SEQ (dbg_help, "select on [ ");
Packit d7e8d0
  any = 0;
Packit d7e8d0
  for (i = 0; i < nfds; i++)
Packit d7e8d0
    {
Packit d7e8d0
      GIOChannel *chan = NULL;
Packit d7e8d0
Packit d7e8d0
      if (fds[i].fd == -1)
Packit d7e8d0
	continue;
Packit d7e8d0
Packit d7e8d0
      if ((fds[i].for_read || fds[i].for_write)
Packit d7e8d0
          && !(chan = find_channel (fds[i].fd)))
Packit d7e8d0
        {
Packit d7e8d0
          TRACE_ADD1 (dbg_help, "[BAD0x%x ", fds[i].fd);
Packit d7e8d0
          TRACE_END (dbg_help, "]");
Packit d7e8d0
          assert (!"see log file");
Packit d7e8d0
        }
Packit d7e8d0
      else if (fds[i].for_read )
Packit d7e8d0
	{
Packit d7e8d0
          assert(chan);
Packit d7e8d0
          g_io_channel_win32_make_pollfd (chan, G_IO_IN, pollfds + npollfds);
Packit d7e8d0
          pollfds_map[npollfds] = i;
Packit d7e8d0
	  TRACE_ADD2 (dbg_help, "r0x%x<%d> ", fds[i].fd, pollfds[npollfds].fd);
Packit d7e8d0
          npollfds++;
Packit d7e8d0
	  any = 1;
Packit d7e8d0
        }
Packit d7e8d0
      else if (fds[i].for_write)
Packit d7e8d0
	{
Packit d7e8d0
          assert(chan);
Packit d7e8d0
          g_io_channel_win32_make_pollfd (chan, G_IO_OUT, pollfds + npollfds);
Packit d7e8d0
          pollfds_map[npollfds] = i;
Packit d7e8d0
	  TRACE_ADD2 (dbg_help, "w0x%x<%d> ", fds[i].fd, pollfds[npollfds].fd);
Packit d7e8d0
          npollfds++;
Packit d7e8d0
	  any = 1;
Packit d7e8d0
        }
Packit d7e8d0
      fds[i].signaled = 0;
Packit d7e8d0
    }
Packit d7e8d0
  TRACE_END (dbg_help, "]");
Packit d7e8d0
  if (!any)
Packit d7e8d0
    {
Packit d7e8d0
      count = 0;
Packit d7e8d0
      goto leave;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
  count = g_io_channel_win32_poll (pollfds, npollfds, timeout);
Packit d7e8d0
  if (count < 0)
Packit d7e8d0
    {
Packit d7e8d0
      int saved_errno = errno;
Packit d7e8d0
      errno = saved_errno;
Packit d7e8d0
      goto leave;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  TRACE_SEQ (dbg_help, "select OK [ ");
Packit d7e8d0
  if (TRACE_ENABLED (dbg_help))
Packit d7e8d0
    {
Packit d7e8d0
      for (i = 0; i < npollfds; i++)
Packit d7e8d0
	{
Packit d7e8d0
	  if ((pollfds[i].revents & G_IO_IN))
Packit d7e8d0
	    TRACE_ADD1 (dbg_help, "r0x%x ", fds[pollfds_map[i]].fd);
Packit d7e8d0
          if ((pollfds[i].revents & G_IO_OUT))
Packit d7e8d0
            TRACE_ADD1 (dbg_help, "w0x%x ", fds[pollfds_map[i]].fd);
Packit d7e8d0
        }
Packit d7e8d0
      TRACE_END (dbg_help, "]");
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* COUNT is used to stop the lop as soon as possible.  */
Packit d7e8d0
  for (n = count, i = 0; i < npollfds && n; i++)
Packit d7e8d0
    {
Packit d7e8d0
      j = pollfds_map[i];
Packit d7e8d0
      assert (j >= 0 && j < nfds);
Packit d7e8d0
      if (fds[j].fd == -1)
Packit d7e8d0
	;
Packit d7e8d0
      else if (fds[j].for_read)
Packit d7e8d0
	{
Packit d7e8d0
	  if ((pollfds[i].revents & G_IO_IN))
Packit d7e8d0
	    {
Packit d7e8d0
	      fds[j].signaled = 1;
Packit d7e8d0
	      n--;
Packit d7e8d0
            }
Packit d7e8d0
        }
Packit d7e8d0
      else if (fds[j].for_write)
Packit d7e8d0
	{
Packit d7e8d0
	  if ((pollfds[i].revents & G_IO_OUT))
Packit d7e8d0
	    {
Packit d7e8d0
	      fds[j].signaled = 1;
Packit d7e8d0
	      n--;
Packit d7e8d0
            }
Packit d7e8d0
        }
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
leave:
Packit d7e8d0
  free (pollfds);
Packit d7e8d0
  free (pollfds_map);
Packit d7e8d0
  return TRACE_SYSRES (count);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
int
Packit d7e8d0
_gpgme_io_dup (int fd)
Packit d7e8d0
{
Packit d7e8d0
  int newfd;
Packit d7e8d0
  GIOChannel *chan;
Packit d7e8d0
Packit Service 30b792
  TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd, "");
Packit d7e8d0
Packit d7e8d0
  if (fd < 0 || fd >= MAX_SLAFD || !giochannel_table[fd].used)
Packit d7e8d0
    {
Packit d7e8d0
      errno = EINVAL;
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  for (newfd = 0; newfd < MAX_SLAFD; newfd++)
Packit d7e8d0
    if (! giochannel_table[newfd].used)
Packit d7e8d0
      break;
Packit d7e8d0
  if (newfd == MAX_SLAFD)
Packit d7e8d0
    {
Packit d7e8d0
      errno = EIO;
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  chan = giochannel_table[fd].chan;
Packit d7e8d0
  g_io_channel_ref (chan);
Packit d7e8d0
  giochannel_table[newfd].used = 1;
Packit d7e8d0
  giochannel_table[newfd].chan = chan;
Packit d7e8d0
  giochannel_table[newfd].fd = -1;
Packit d7e8d0
  giochannel_table[newfd].socket = INVALID_SOCKET;
Packit d7e8d0
  giochannel_table[newfd].primary = 0;
Packit d7e8d0
Packit d7e8d0
  return TRACE_SYSRES (newfd);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
static int
Packit d7e8d0
wsa2errno (int err)
Packit d7e8d0
{
Packit d7e8d0
  switch (err)
Packit d7e8d0
    {
Packit d7e8d0
    case WSAENOTSOCK:
Packit d7e8d0
      return EINVAL;
Packit d7e8d0
    case WSAEWOULDBLOCK:
Packit d7e8d0
      return EAGAIN;
Packit d7e8d0
    case ERROR_BROKEN_PIPE:
Packit d7e8d0
      return EPIPE;
Packit d7e8d0
    case WSANOTINITIALISED:
Packit d7e8d0
      return ENOSYS;
Packit d7e8d0
    default:
Packit d7e8d0
      return EIO;
Packit d7e8d0
    }
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
int
Packit d7e8d0
_gpgme_io_socket (int domain, int type, int proto)
Packit d7e8d0
{
Packit d7e8d0
  int res;
Packit d7e8d0
  int fd;
Packit d7e8d0
Packit Service 30b792
  TRACE_BEG  (DEBUG_SYSIO, "_gpgme_io_socket", domain,
Packit d7e8d0
	      "type=%i, protp=%i", type, proto);
Packit d7e8d0
Packit d7e8d0
  res = socket (domain, type, proto);
Packit d7e8d0
  if (res == INVALID_SOCKET)
Packit d7e8d0
    {
Packit d7e8d0
      errno = wsa2errno (WSAGetLastError ());
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  fd = new_channel_from_socket (res);
Packit d7e8d0
  if (fd < 0)
Packit d7e8d0
    {
Packit d7e8d0
      int saved_errno = errno;
Packit d7e8d0
      closesocket (res);
Packit d7e8d0
      errno = saved_errno;
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
Packit Service 30b792
  TRACE_SUC ("fd=%i, socket=0x%x", fd, res);
Packit d7e8d0
Packit d7e8d0
  return fd;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
int
Packit d7e8d0
_gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
Packit d7e8d0
{
Packit d7e8d0
  GIOChannel *chan;
Packit d7e8d0
  int sockfd;
Packit d7e8d0
  int res;
Packit d7e8d0
  GIOFlags flags;
Packit d7e8d0
  GIOStatus status;
Packit d7e8d0
  GError *err = NULL;
Packit d7e8d0
Packit Service 30b792
  TRACE_BEG  (DEBUG_SYSIO, "_gpgme_io_connect", fd,
Packit d7e8d0
	      "addr=%p, addrlen=%i", addr, addrlen);
Packit d7e8d0
Packit d7e8d0
  chan = find_channel (fd);
Packit d7e8d0
  if (! chan)
Packit d7e8d0
    {
Packit d7e8d0
      errno = EINVAL;
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  flags = g_io_channel_get_flags (chan);
Packit d7e8d0
  if (flags & G_IO_FLAG_NONBLOCK)
Packit d7e8d0
    {
Packit d7e8d0
      status = g_io_channel_set_flags (chan, flags & ~G_IO_FLAG_NONBLOCK, &err;;
Packit d7e8d0
      if (err)
Packit d7e8d0
	{
Packit Service 30b792
	  TRACE_LOG  ("setting flags error: %s", err->message);
Packit d7e8d0
	  g_error_free (err);
Packit d7e8d0
	  err = NULL;
Packit d7e8d0
	}
Packit d7e8d0
      if (status != G_IO_STATUS_NORMAL)
Packit d7e8d0
	{
Packit d7e8d0
	  errno = EIO;
Packit d7e8d0
	  return TRACE_SYSRES (-1);
Packit d7e8d0
	}
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  sockfd = giochannel_table[fd].socket;
Packit d7e8d0
  if (sockfd == INVALID_SOCKET)
Packit d7e8d0
    {
Packit d7e8d0
      errno = EINVAL;
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
Packit Service 30b792
  TRACE_LOG  ("connect socket fd=%d", sockfd);
Packit d7e8d0
  res = connect (sockfd, addr, addrlen);
Packit d7e8d0
Packit d7e8d0
  /* FIXME: Error ignored here.  */
Packit d7e8d0
  if (! (flags & G_IO_FLAG_NONBLOCK))
Packit d7e8d0
    g_io_channel_set_flags (chan, flags, NULL);
Packit d7e8d0
Packit d7e8d0
  if (res)
Packit d7e8d0
    {
Packit Service 30b792
      TRACE_LOG  ("connect failed: %i %i", res, WSAGetLastError ());
Packit d7e8d0
Packit d7e8d0
      errno = wsa2errno (WSAGetLastError ());
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
Packit Service 30b792
  TRACE_SUC ("");
Packit Service 30b792
Packit Service 30b792
  return 0;
Packit d7e8d0
}