[git] GPG-ERROR - branch, master, updated. libgpg-error-1.24-18-gc26117b

by Werner Koch cvs at cvs.gnupg.org
Sat Nov 12 20:06:08 CET 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Error codes used by GnuPG et al.".

The branch, master has been updated
       via  c26117b2eda43258d4e3e8fd3ed602b2eaaa51f4 (commit)
       via  40e5ff0a0084c0d9521b401db4f38885bfdae233 (commit)
       via  e15416d3668ea9dcc6a64cbb98140a99be8a7865 (commit)
       via  a0651e910f962a49b0b7f7942512f17a5fe39a7d (commit)
       via  135319b5d1f9a88187687646c762759cfa05a7ec (commit)
      from  b7972767513c8748096ebed78d1e1621bd2bd459 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit c26117b2eda43258d4e3e8fd3ed602b2eaaa51f4
Author: Werner Koch <wk at gnupg.org>
Date:   Sat Nov 12 20:00:06 2016 +0100

    estream: Minor portability fix.
    
    --
    
    A trailing comma in an enum is not groked by all compilers.
    Binary operation should have their own parentheses to make it clear
    that a binary operator was meant.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/estream.c b/src/estream.c
index c46bc61..58d5d03 100644
--- a/src/estream.c
+++ b/src/estream.c
@@ -2087,7 +2087,7 @@ es_create (estream_t *stream, void *cookie, es_syshd_t *syshd,
   stream_new->intern = stream_internal_new;
 
 #if _WIN32
-  if (xmode & X_POLLABLE)
+  if ((xmode & X_POLLABLE))
     {
       void *new_cookie;
 
@@ -3243,7 +3243,7 @@ do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list)
   err = parse_mode (mode, &modeflags, &xmode, NULL);
   if (err)
     goto out;
-  if (xmode & X_SYSOPEN)
+  if ((xmode & X_SYSOPEN))
     {
       /* Not allowed for fdopen.  */
       _set_errno (EINVAL);
@@ -3307,7 +3307,7 @@ do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list)
   err = parse_mode (mode, &modeflags, &xmode, &cmode);
   if (err)
     goto out;
-  if (xmode & X_SYSOPEN)
+  if ((xmode & X_SYSOPEN))
     {
       /* Not allowed for fpopen.  */
       _set_errno (EINVAL);
diff --git a/src/gpgrt-int.h b/src/gpgrt-int.h
index a6e6036..fba2585 100644
--- a/src/gpgrt-int.h
+++ b/src/gpgrt-int.h
@@ -82,7 +82,7 @@ typedef enum
     BACKEND_W32,
     BACKEND_FP,
     BACKEND_USER,
-    BACKEND_W32_POLLABLE,
+    BACKEND_W32_POLLABLE
   } gpgrt_stream_backend_kind_t;
 
 

commit 40e5ff0a0084c0d9521b401db4f38885bfdae233
Author: Justus Winter <justus at g10code.com>
Date:   Wed Oct 19 12:20:44 2016 +0200

    estream: Support 'es_poll' on Windows.
    
    * src/Makefile.am (arch_sources): Add new file.
    * src/estream.c (O_NONBLOCK): Move to 'gpgrt-int.h'.
    (BUFFER_BLOCK_SIZE): Likewise.
    (BUFFER_UNREAD_SIZE): Likewise.
    (struct notify_list_s, notify_list_t): Likewise.
    (struct _gpgrt_stream_internal, estream_internal_t): Likewise.
    (X_POLLABLE): New macro.
    (parse_mode): Parse keyword 'pollable', emulate O_NONBLOCK using the
    same mechanism on Windows.
    (_gpgrt_poll): Use the new '_gpgrt_w32_poll' on Windows.
    * src/gpgrt-int.h (_gpgrt_functions_w32_pollable): New declaration.
    (_gpgrt_w32_pollable_create): New prototype.
    (_gpgrt_w32_poll): Likewise.
    * src/w32-estream.c: New file.  This code is adapted from GPGME.
    * tests/t-poll.c (create_pipe): Create pollable streams.
    
    GnuPG-bug-id: 2731
    Signed-off-by: Justus Winter <justus at g10code.com>

diff --git a/src/Makefile.am b/src/Makefile.am
index c1e86a7..0c18252 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -109,7 +109,8 @@ CLEANFILES = err-sources.h err-codes.h code-to-errno.h code-from-errno.h \
 # {{{ Begin Windows part
 #
 if HAVE_W32_SYSTEM
-arch_sources = w32-gettext.c w32-lock.c w32-lock-obj.h w32-thread.c w32-iconv.c
+arch_sources = w32-gettext.c w32-lock.c w32-lock-obj.h w32-thread.c \
+	       w32-iconv.c w32-estream.c
 RCCOMPILE = $(RC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
             -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS) $(CPPFLAGS)
 LTRCCOMPILE = $(LIBTOOL) --mode=compile --tag=RC $(RCCOMPILE)
diff --git a/src/estream.c b/src/estream.c
index aca7db7..c46bc61 100644
--- a/src/estream.c
+++ b/src/estream.c
@@ -127,8 +127,6 @@
 # ifndef  S_IXOTH
 #  define S_IXOTH S_IXUSR
 # endif
-# undef  O_NONBLOCK
-# define O_NONBLOCK  0  /* FIXME: Not yet supported.  */
 #endif
 
 #if !defined (EWOULDBLOCK) && defined (HAVE_W32_SYSTEM)
@@ -174,66 +172,6 @@ typedef void (*func_free_t) (void *mem);
 

 
 /*
- * Buffer management layer.
- */
-
-#define BUFFER_BLOCK_SIZE  BUFSIZ
-#define BUFFER_UNREAD_SIZE 16
-
-

-/*
- * A type to hold notification functions.
- */
-struct notify_list_s
-{
-  struct notify_list_s *next;
-  void (*fnc) (estream_t, void*); /* The notification function.  */
-  void *fnc_value;                /* The value to be passed to FNC.  */
-};
-typedef struct notify_list_s *notify_list_t;
-
-
-/*
- * The private object describing a stream.
- */
-struct _gpgrt_stream_internal
-{
-  unsigned char buffer[BUFFER_BLOCK_SIZE];
-  unsigned char unread_buffer[BUFFER_UNREAD_SIZE];
-
-  gpgrt_lock_t lock;		 /* Lock.  Used by *_stream_lock(). */
-
-  gpgrt_stream_backend_kind_t kind;
-  void *cookie;			 /* Cookie.                */
-  void *opaque;			 /* Opaque data.           */
-  unsigned int modeflags;	 /* Flags for the backend. */
-  char *printable_fname;         /* Malloced filename for es_fname_get.  */
-  gpgrt_off_t offset;
-  gpgrt_cookie_read_function_t  func_read;
-  gpgrt_cookie_write_function_t func_write;
-  gpgrt_cookie_seek_function_t  func_seek;
-  gpgrt_cookie_close_function_t func_close;
-  cookie_ioctl_function_t func_ioctl;
-  int strategy;
-  es_syshd_t syshd;              /* A copy of the system handle.  */
-  struct
-  {
-    unsigned int err: 1;
-    unsigned int eof: 1;
-    unsigned int hup: 1;
-  } indicators;
-  unsigned int deallocate_buffer: 1;
-  unsigned int is_stdstream:1;   /* This is a standard stream.  */
-  unsigned int stdstream_fd:2;   /* 0, 1 or 2 for a standard stream.  */
-  unsigned int printable_fname_inuse: 1;  /* es_fname_get has been used.  */
-  unsigned int samethread: 1;    /* The "samethread" mode keyword.  */
-  size_t print_ntotal;           /* Bytes written from in print_writer. */
-  notify_list_t onclose;         /* On close notify function list.  */
-};
-typedef struct _gpgrt_stream_internal *estream_internal_t;
-
-
-/*
  * A linked list to hold active stream objects.
  * Protected by ESTREAM_LIST_LOCK.
  */
@@ -1686,6 +1624,7 @@ func_file_create (void **cookie, int *filedes,
 /* Flags used by parse_mode and friends.  */
 #define X_SAMETHREAD	(1 << 0)
 #define X_SYSOPEN	(1 << 1)
+#define X_POLLABLE	(1 << 2)
 
 /* Parse the mode flags of fopen et al.  In addition to the POSIX
  * defined mode flags keyword parameters are supported.  These are
@@ -1723,6 +1662,13 @@ func_file_create (void **cookie, int *filedes,
  *    under Windows the direct W32 API functions (HANDLE) are used
  *    instead of their libc counterparts (fd).
  *
+ * pollable
+ *
+ *    The object is opened in a way suitable for use with es_poll.  On
+ *    POSIX this is a NOP but under Windows we create up to two
+ *    threads, one for reading and one for writing, do any I/O there,
+ *    and synchronize with them in order to support es_poll.
+ *
  * Note: R_CMODE is optional because is only required by functions
  * which are able to creat a file.
  */
@@ -1828,6 +1774,10 @@ parse_mode (const char *modestr,
               return -1;
             }
           oflags |= O_NONBLOCK;
+#if HAVE_W32_SYSTEM
+          /* Currently, nonblock implies pollable on Windows.  */
+          *r_xmode |= X_POLLABLE;
+#endif
         }
       else if (!strncmp (modestr, "sysopen", 7))
         {
@@ -1839,6 +1789,16 @@ parse_mode (const char *modestr,
             }
           *r_xmode |= X_SYSOPEN;
         }
+      else if (!strncmp (modestr, "pollable", 8))
+        {
+          modestr += 8;
+          if (*modestr && !strchr (" \t,", *modestr))
+            {
+              _set_errno (EINVAL);
+              return -1;
+            }
+          *r_xmode |= X_POLLABLE;
+        }
     }
   if (!got_cmode)
     cmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
@@ -2126,6 +2086,23 @@ es_create (estream_t *stream, void *cookie, es_syshd_t *syshd,
   stream_new->unread_buffer_size = sizeof (stream_internal_new->unread_buffer);
   stream_new->intern = stream_internal_new;
 
+#if _WIN32
+  if (xmode & X_POLLABLE)
+    {
+      void *new_cookie;
+
+      err = _gpgrt_w32_pollable_create (&new_cookie, modeflags,
+                                        functions, cookie);
+      if (err)
+        goto out;
+
+      modeflags &= ~O_NONBLOCK;
+      cookie = new_cookie;
+      kind = BACKEND_W32_POLLABLE;
+      functions = _gpgrt_functions_w32_pollable;
+    }
+#endif
+
   init_stream_obj (stream_new, cookie, syshd, kind, functions, modeflags,
                    xmode);
   init_stream_lock (stream_new);
@@ -4731,11 +4708,13 @@ _gpgrt_poll (gpgrt_poll_t *fds, unsigned int nfds, int timeout)
 {
   gpgrt_poll_t *item;
   int count = 0;
+#ifndef _WIN32
   fd_set readfds, writefds, exceptfds;
   int any_readfd, any_writefd, any_exceptfd;
-  int idx;
   int max_fd;
   int fd, ret, any;
+#endif
+  int idx;
 
   if (!fds)
     {
@@ -4783,6 +4762,15 @@ _gpgrt_poll (gpgrt_poll_t *fds, unsigned int nfds, int timeout)
     return count;  /* Early return without waiting.  */
 
   /* Now do the real select.  */
+#ifdef _WIN32
+  if (pre_syscall_func)
+    pre_syscall_func ();
+
+  count = _gpgrt_w32_poll (fds, nfds, timeout);
+
+  if (post_syscall_func)
+    post_syscall_func ();
+#else
   any_readfd = any_writefd = any_exceptfd = 0;
   max_fd = 0;
   for (item = fds, idx = 0; idx < nfds; item++, idx++)
@@ -4828,11 +4816,6 @@ _gpgrt_poll (gpgrt_poll_t *fds, unsigned int nfds, int timeout)
         }
     }
 
-#ifdef _WIN32
-  (void)timeout;
-  ret = -1;
-  _set_errno (EOPNOTSUPP);
-#else
   if (pre_syscall_func)
     pre_syscall_func ();
   do
@@ -4850,7 +4833,6 @@ _gpgrt_poll (gpgrt_poll_t *fds, unsigned int nfds, int timeout)
   while (ret == -1 && errno == EINTR);
   if (post_syscall_func)
     post_syscall_func ();
-#endif
 
   if (ret == -1)
     return -1;
@@ -4876,9 +4858,6 @@ _gpgrt_poll (gpgrt_poll_t *fds, unsigned int nfds, int timeout)
           item->got_hup = 1;
           any = 1;
         }
-#ifndef _WIN32
-      /* NB.: We can't use FD_ISSET under windows - but we don't have
-       * support for it anyway.  */
       if (item->want_read && FD_ISSET (fd, &readfds))
         {
           item->got_read = 1;
@@ -4894,11 +4873,11 @@ _gpgrt_poll (gpgrt_poll_t *fds, unsigned int nfds, int timeout)
           item->got_oob = 1;
           any = 1;
         }
-#endif /*!_WIN32*/
 
       if (any)
         count++;
     }
+#endif
 
   return count;
 }
diff --git a/src/gpgrt-int.h b/src/gpgrt-int.h
index a517cc6..a6e6036 100644
--- a/src/gpgrt-int.h
+++ b/src/gpgrt-int.h
@@ -52,6 +52,12 @@ gpg_err_code_t _gpgrt_yield (void);
 
 /* Local definitions for estream.  */
 
+#if HAVE_W32_SYSTEM
+# ifndef  O_NONBLOCK
+#  define O_NONBLOCK  0x40000000	/* FIXME: Is that safe?  */
+# endif
+#endif
+
 /*
  * A private cookie function to implement an internal IOCTL service.
  * and ist IOCTL numbers.
@@ -80,6 +86,65 @@ typedef enum
   } gpgrt_stream_backend_kind_t;
 
 
+/*
+ * A type to hold notification functions.
+ */
+struct notify_list_s
+{
+  struct notify_list_s *next;
+  void (*fnc) (estream_t, void*); /* The notification function.  */
+  void *fnc_value;                /* The value to be passed to FNC.  */
+};
+typedef struct notify_list_s *notify_list_t;
+
+
+/*
+ * Buffer management layer.
+ */
+
+#define BUFFER_BLOCK_SIZE  BUFSIZ
+#define BUFFER_UNREAD_SIZE 16
+
+
+/*
+ * The private object describing a stream.
+ */
+struct _gpgrt_stream_internal
+{
+  unsigned char buffer[BUFFER_BLOCK_SIZE];
+  unsigned char unread_buffer[BUFFER_UNREAD_SIZE];
+
+  gpgrt_lock_t lock;		 /* Lock.  Used by *_stream_lock(). */
+
+  gpgrt_stream_backend_kind_t kind;
+  void *cookie;			 /* Cookie.                */
+  void *opaque;			 /* Opaque data.           */
+  unsigned int modeflags;	 /* Flags for the backend. */
+  char *printable_fname;         /* Malloced filename for es_fname_get.  */
+  gpgrt_off_t offset;
+  gpgrt_cookie_read_function_t  func_read;
+  gpgrt_cookie_write_function_t func_write;
+  gpgrt_cookie_seek_function_t  func_seek;
+  gpgrt_cookie_close_function_t func_close;
+  cookie_ioctl_function_t func_ioctl;
+  int strategy;
+  es_syshd_t syshd;              /* A copy of the system handle.  */
+  struct
+  {
+    unsigned int err: 1;
+    unsigned int eof: 1;
+    unsigned int hup: 1;
+  } indicators;
+  unsigned int deallocate_buffer: 1;
+  unsigned int is_stdstream:1;   /* This is a standard stream.  */
+  unsigned int stdstream_fd:2;   /* 0, 1 or 2 for a standard stream.  */
+  unsigned int printable_fname_inuse: 1;  /* es_fname_get has been used.  */
+  unsigned int samethread: 1;    /* The "samethread" mode keyword.  */
+  size_t print_ntotal;           /* Bytes written from in print_writer. */
+  notify_list_t onclose;         /* On close notify function list.  */
+};
+typedef struct _gpgrt_stream_internal *estream_internal_t;
+
 
 /* Local prototypes for estream.  */
 int _gpgrt_es_init (void);
@@ -237,5 +302,14 @@ const char *_gpgrt_fname_get (gpgrt_stream_t stream);
 
 #include "estream-printf.h"
 
+#if _WIN32
+/* Prototypes for w32-estream.c.  */
+struct cookie_io_functions_s _gpgrt_functions_w32_pollable;
+int _gpgrt_w32_pollable_create (void *_GPGRT__RESTRICT *_GPGRT__RESTRICT cookie,
+                                unsigned int modeflags,
+                                struct cookie_io_functions_s next_functions,
+                                void *next_cookie);
+int _gpgrt_w32_poll (gpgrt_poll_t *fds, size_t nfds, int timeout);
+#endif
 
 #endif /*_GPGRT_GPGRT_INT_H*/
diff --git a/src/w32-estream.c b/src/w32-estream.c
new file mode 100644
index 0000000..516b238
--- /dev/null
+++ b/src/w32-estream.c
@@ -0,0 +1,1047 @@
+/* w32-estream.c - es_poll support on W32.
+ * Copyright (C) 2000 Werner Koch (dd9jn)
+ * Copyright (C) 2001, 2002, 2003, 2004, 2007, 2010, 2016 g10 Code GmbH
+ *
+ * This file is part of libgpg-error.
+ *
+ * libgpg-error is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * libgpg-error is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This file is based on GPGME's w32-io.c started in 2001.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#include <io.h>
+#include <windows.h>
+
+#include "gpgrt-int.h"
+
+/*
+ * In order to support es_poll on Windows, we create a proxy shim that
+ * we use as the estream I/O functions.  This shim creates reader and
+ * writer threads that use the original I/O functions.
+ */
+
+

+
+/* Tracing/debugging support.  */
+#if 0
+#define TRACE(msg, ...)                                         \
+  fprintf (stderr, msg, ## __VA_ARGS__)
+#define TRACE_CTX(ctx, msg, ...)                                \
+  fprintf (stderr, "%p: " msg "\n", ctx, ## __VA_ARGS__)
+#define TRACE_ERR(ctx, err, msg, ...)	do {                    \
+    char error_message[128];                                    \
+    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM                    \
+                  | FORMAT_MESSAGE_IGNORE_INSERTS,              \
+                  NULL,                                         \
+                  err,                                          \
+                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),    \
+                  (LPTSTR) &error_message,                      \
+                  sizeof error_message, NULL );                 \
+    fprintf (stderr, "%p: " msg ": %s\n", ctx,                  \
+             ## __VA_ARGS__, error_message);                    \
+  } while (0)
+#else
+#define TRACE(msg, ...)			(void) 0
+#define TRACE_CTX(ctx, msg, ...)	(void) 0
+#define TRACE_ERR(ctx, err, msg, ...)	(void) 0
+#endif
+
+

+
+/* Calculate array dimension.  */
+#ifndef DIM
+#define DIM(array) (sizeof (array) / sizeof (*array))
+#endif
+
+#define READBUF_SIZE 4096
+#define WRITEBUF_SIZE 4096
+
+
+typedef struct estream_cookie_w32_pollable *estream_cookie_w32_pollable_t;
+
+struct reader_context_s
+{
+  estream_cookie_w32_pollable_t pcookie;
+  HANDLE thread_hd;
+
+  gpgrt_lock_t mutex;
+
+  int stop_me;
+  int eof;
+  int eof_shortcut;
+  int error;
+  int error_code;
+
+  /* This is manually reset.  */
+  HANDLE have_data_ev;
+  /* This is automatically reset.  */
+  HANDLE have_space_ev;
+  /* This is manually reset but actually only triggered once.  */
+  HANDLE close_ev;
+
+  size_t readpos, writepos;
+  char buffer[READBUF_SIZE];
+};
+
+struct writer_context_s
+{
+  estream_cookie_w32_pollable_t pcookie;
+  HANDLE thread_hd;
+
+  gpgrt_lock_t mutex;
+
+  int stop_me;
+  int error;
+  int error_code;
+
+  /* This is manually reset.  */
+  HANDLE have_data;
+  HANDLE is_empty;
+  HANDLE close_ev;
+  size_t nbytes;
+  char buffer[WRITEBUF_SIZE];
+};
+
+/* Cookie for pollable objects.  */
+struct estream_cookie_w32_pollable
+{
+  unsigned int modeflags;
+
+  struct cookie_io_functions_s next_functions;
+  void *next_cookie;
+
+  struct reader_context_s *reader;
+  struct writer_context_s *writer;
+};
+
+
+static HANDLE
+set_synchronize (HANDLE hd)
+{
+#ifdef HAVE_W32CE_SYSTEM
+  return hd;
+#else
+  HANDLE new_hd;
+
+  /* For NT we have to set the sync flag.  It seems that the only way
+     to do it is by duplicating the handle.  Tsss...  */
+  if (!DuplicateHandle (GetCurrentProcess (), hd,
+			GetCurrentProcess (), &new_hd,
+			EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, 0))
+    {
+      TRACE_ERR (NULL, GetLastError (), "DuplicateHandle failed");
+      /* FIXME: Should translate the error code.  */
+      _gpg_err_set_errno (EIO);
+      return INVALID_HANDLE_VALUE;
+    }
+
+  CloseHandle (hd);
+  return new_hd;
+#endif
+}
+
+
+static DWORD CALLBACK
+reader (void *arg)
+{
+  struct reader_context_s *ctx = arg;
+  int nbytes;
+  ssize_t nread;
+  TRACE_CTX (ctx, "reader starting");
+
+  for (;;)
+    {
+      _gpgrt_lock_lock (&ctx->mutex);
+      /* Leave a 1 byte gap so that we can see whether it is empty or
+	 full.  */
+      while ((ctx->writepos + 1) % READBUF_SIZE == ctx->readpos)
+	{
+	  /* Wait for space.  */
+	  if (!ResetEvent (ctx->have_space_ev))
+	    TRACE_ERR (ctx, GetLastError (), "ResetEvent failed");
+	  _gpgrt_lock_unlock (&ctx->mutex);
+	  TRACE_CTX (ctx, "waiting for space");
+	  WaitForSingleObject (ctx->have_space_ev, INFINITE);
+	  TRACE_CTX (ctx, "got space");
+	  _gpgrt_lock_lock (&ctx->mutex);
+        }
+      assert (((ctx->writepos + 1) % READBUF_SIZE != ctx->readpos));
+      if (ctx->stop_me)
+	{
+	  _gpgrt_lock_unlock (&ctx->mutex);
+	  break;
+        }
+      nbytes = (ctx->readpos + READBUF_SIZE
+		- ctx->writepos - 1) % READBUF_SIZE;
+      assert (nbytes);
+      if (nbytes > READBUF_SIZE - ctx->writepos)
+	nbytes = READBUF_SIZE - ctx->writepos;
+      _gpgrt_lock_unlock (&ctx->mutex);
+
+      TRACE_CTX (ctx, "reading up to %d bytes", nbytes);
+
+      nread = ctx->pcookie->next_functions.public.func_read
+        (ctx->pcookie->next_cookie, ctx->buffer + ctx->writepos, nbytes);
+      TRACE_CTX (ctx, "got %d bytes", nread);
+      if (nread < 0)
+        {
+          ctx->error_code = (int) errno;
+          /* NOTE (W32CE): Do not ignore ERROR_BUSY!  Check at
+             least stop_me if that happens.  */
+          if (ctx->error_code == ERROR_BROKEN_PIPE)
+            {
+              ctx->eof = 1;
+              TRACE_CTX (ctx, "got EOF (broken pipe)");
+            }
+          else
+            {
+              ctx->error = 1;
+              TRACE_ERR (ctx, ctx->error_code, "read error");
+            }
+          break;
+        }
+
+      _gpgrt_lock_lock (&ctx->mutex);
+      if (ctx->stop_me)
+	{
+	  _gpgrt_lock_unlock (&ctx->mutex);
+	  break;
+        }
+      if (!nread)
+	{
+	  ctx->eof = 1;
+	  TRACE_CTX (ctx, "got eof");
+	  _gpgrt_lock_unlock (&ctx->mutex);
+	  break;
+        }
+
+      ctx->writepos = (ctx->writepos + nread) % READBUF_SIZE;
+      if (!SetEvent (ctx->have_data_ev))
+	TRACE_ERR (ctx, GetLastError (), "SetEvent (%p) failed",
+                   ctx->have_data_ev);
+      _gpgrt_lock_unlock (&ctx->mutex);
+    }
+  /* Indicate that we have an error or EOF.  */
+  if (!SetEvent (ctx->have_data_ev))
+    TRACE_ERR (ctx, GetLastError (), "SetEvent (%p) failed",
+               ctx->have_data_ev);
+
+  TRACE_CTX (ctx, "waiting for close");
+  WaitForSingleObject (ctx->close_ev, INFINITE);
+
+  CloseHandle (ctx->close_ev);
+  CloseHandle (ctx->have_data_ev);
+  CloseHandle (ctx->have_space_ev);
+  CloseHandle (ctx->thread_hd);
+  _gpgrt_lock_destroy (&ctx->mutex);
+  _gpgrt_free (ctx);
+
+  return 0;
+}
+
+
+static struct reader_context_s *
+create_reader (estream_cookie_w32_pollable_t pcookie)
+{
+  struct reader_context_s *ctx;
+  SECURITY_ATTRIBUTES sec_attr;
+  DWORD tid;
+
+  memset (&sec_attr, 0, sizeof sec_attr);
+  sec_attr.nLength = sizeof sec_attr;
+  sec_attr.bInheritHandle = FALSE;
+
+  ctx = calloc (1, sizeof *ctx);
+  if (!ctx)
+    {
+      return NULL;
+    }
+
+  ctx->pcookie = pcookie;
+
+  ctx->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
+  if (ctx->have_data_ev)
+    ctx->have_space_ev = CreateEvent (&sec_attr, FALSE, TRUE, NULL);
+  if (ctx->have_space_ev)
+    ctx->close_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
+  if (!ctx->have_data_ev || !ctx->have_space_ev || !ctx->close_ev)
+    {
+      TRACE_ERR (ctx, GetLastError (), "CreateEvent failed");
+      if (ctx->have_data_ev)
+	CloseHandle (ctx->have_data_ev);
+      if (ctx->have_space_ev)
+	CloseHandle (ctx->have_space_ev);
+      if (ctx->close_ev)
+	CloseHandle (ctx->close_ev);
+      _gpgrt_free (ctx);
+      return NULL;
+    }
+
+  ctx->have_data_ev = set_synchronize (ctx->have_data_ev);
+  _gpgrt_lock_init (&ctx->mutex);
+
+#ifdef HAVE_W32CE_SYSTEM
+  ctx->thread_hd = CreateThread (&sec_attr, 64 * 1024, reader, ctx,
+				 STACK_SIZE_PARAM_IS_A_RESERVATION, &tid);
+#else
+  ctx->thread_hd = CreateThread (&sec_attr, 0, reader, ctx, 0, &tid);
+#endif
+
+  if (!ctx->thread_hd)
+    {
+      TRACE_ERR (ctx, GetLastError (), "CreateThread failed");
+      _gpgrt_lock_destroy (&ctx->mutex);
+      if (ctx->have_data_ev)
+	CloseHandle (ctx->have_data_ev);
+      if (ctx->have_space_ev)
+	CloseHandle (ctx->have_space_ev);
+      if (ctx->close_ev)
+	CloseHandle (ctx->close_ev);
+      _gpgrt_free (ctx);
+      return NULL;
+    }
+  else
+    {
+#if 0
+      /* We set the priority of the thread higher because we know that
+         it only runs for a short time.  This greatly helps to
+         increase the performance of the I/O.  */
+      SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
+#endif
+    }
+
+  return ctx;
+}
+
+
+/* Prepare destruction of the reader thread for CTX.  Returns 0 if a
+   call to this function is sufficient and destroy_reader_finish shall
+   not be called.  */
+static void
+destroy_reader (struct reader_context_s *ctx)
+{
+  _gpgrt_lock_lock (&ctx->mutex);
+  ctx->stop_me = 1;
+  if (ctx->have_space_ev)
+    SetEvent (ctx->have_space_ev);
+  _gpgrt_lock_unlock (&ctx->mutex);
+
+#ifdef HAVE_W32CE_SYSTEM
+  /* Scenario: We never create a full pipe, but already started
+     reading.  Then we need to unblock the reader in the pipe driver
+     to make our reader thread notice that we want it to go away.  */
+
+  if (ctx->file_hd != INVALID_HANDLE_VALUE)
+    {
+      if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK,
+			NULL, 0, NULL, 0, NULL, NULL))
+	{
+	  TRACE_ERR (ctx, GetLastError (), "unblock control call failed");
+	}
+    }
+#endif
+
+  /* XXX is it feasible to unblock the thread?  */
+
+  /* After setting this event CTX is void. */
+  SetEvent (ctx->close_ev);
+}
+
+
+/*
+ * Read function for pollable objects.
+ */
+static gpgrt_ssize_t
+func_w32_pollable_read (void *cookie, void *buffer, size_t count)
+{
+  estream_cookie_w32_pollable_t pcookie = cookie;
+  gpgrt_ssize_t nread;
+  struct reader_context_s *ctx;
+
+  ctx = pcookie->reader;
+  if (ctx == NULL)
+    {
+      pcookie->reader = ctx = create_reader (pcookie);
+      if (!ctx)
+        {
+          _gpg_err_set_errno (EBADF);
+          return -1;
+        }
+    }
+
+  TRACE_CTX (ctx, "pollable read buffer=%p, count=%u", buffer, count);
+
+  if (ctx->eof_shortcut)
+    return 0;
+
+  _gpgrt_lock_lock (&ctx->mutex);
+  TRACE_CTX (ctx, "readpos: %d, writepos %d", ctx->readpos, ctx->writepos);
+  if (ctx->readpos == ctx->writepos && !ctx->error)
+    {
+      /* No data available.  */
+      int eof = ctx->eof;
+      _gpgrt_lock_unlock (&ctx->mutex);
+
+      if (pcookie->modeflags & O_NONBLOCK && ! eof)
+        {
+          _gpg_err_set_errno (EAGAIN);
+          return -1;
+        }
+
+      TRACE_CTX (ctx, "waiting for data");
+      WaitForSingleObject (ctx->have_data_ev, INFINITE);
+      TRACE_CTX (ctx, "data available");
+      _gpgrt_lock_lock (&ctx->mutex);
+    }
+
+  if (ctx->readpos == ctx->writepos || ctx->error)
+    {
+      _gpgrt_lock_unlock (&ctx->mutex);
+      ctx->eof_shortcut = 1;
+      if (ctx->eof)
+	return 0;
+      if (!ctx->error)
+	{
+	  TRACE_CTX (ctx, "EOF but ctx->eof flag not set");
+	  return 0;
+	}
+      _gpg_err_set_errno (ctx->error_code);
+      return -1;
+    }
+
+  nread = ctx->readpos < ctx->writepos
+    ? ctx->writepos - ctx->readpos
+    : READBUF_SIZE - ctx->readpos;
+  if (nread > count)
+    nread = count;
+  memcpy (buffer, ctx->buffer + ctx->readpos, nread);
+  ctx->readpos = (ctx->readpos + nread) % READBUF_SIZE;
+  if (ctx->readpos == ctx->writepos && !ctx->eof)
+    {
+      if (!ResetEvent (ctx->have_data_ev))
+	{
+	  TRACE_ERR (ctx, GetLastError (), "ResetEvent failed");
+	  _gpgrt_lock_unlock (&ctx->mutex);
+	  /* FIXME: Should translate the error code.  */
+	  _gpg_err_set_errno (EIO);
+	  return -1;
+	}
+    }
+  if (!SetEvent (ctx->have_space_ev))
+    {
+      TRACE_ERR (ctx, GetLastError (), "SetEvent (%p) failed",
+                 ctx->have_space_ev);
+      _gpgrt_lock_unlock (&ctx->mutex);
+      /* FIXME: Should translate the error code.  */
+      _gpg_err_set_errno (EIO);
+      return -1;
+    }
+  _gpgrt_lock_unlock (&ctx->mutex);
+
+  return nread;
+}
+
+
+/* The writer does use a simple buffering strategy so that we are
+   informed about write errors as soon as possible (i. e. with the the
+   next call to the write function.  */
+static DWORD CALLBACK
+writer (void *arg)
+{
+  struct writer_context_s *ctx = arg;
+  ssize_t nwritten;
+
+  TRACE_CTX (ctx, "writer starting");
+
+  for (;;)
+    {
+      _gpgrt_lock_lock (&ctx->mutex);
+      if (ctx->stop_me && !ctx->nbytes)
+	{
+	  _gpgrt_lock_unlock (&ctx->mutex);
+	  break;
+        }
+      if (!ctx->nbytes)
+	{
+	  if (!SetEvent (ctx->is_empty))
+	    TRACE_ERR (ctx, GetLastError (), "SetEvent failed");
+	  if (!ResetEvent (ctx->have_data))
+	    TRACE_ERR (ctx, GetLastError (), "ResetEvent failed");
+	  _gpgrt_lock_unlock (&ctx->mutex);
+	  TRACE_CTX (ctx, "idle");
+	  WaitForSingleObject (ctx->have_data, INFINITE);
+	  TRACE_CTX (ctx, "got data to write");
+	  _gpgrt_lock_lock (&ctx->mutex);
+        }
+      if (ctx->stop_me && !ctx->nbytes)
+	{
+	  _gpgrt_lock_unlock (&ctx->mutex);
+	  break;
+        }
+      _gpgrt_lock_unlock (&ctx->mutex);
+
+      TRACE_CTX (ctx, "writing up to %d bytes", ctx->nbytes);
+
+      nwritten = ctx->pcookie->next_functions.public.func_write
+        (ctx->pcookie->next_cookie, ctx->buffer, ctx->nbytes);
+      TRACE_CTX (ctx, "wrote %d bytes", nwritten);
+      if (nwritten < 1)
+        {
+          /* XXX */
+          if (errno == ERROR_BUSY)
+            {
+              /* Probably stop_me is set now.  */
+              TRACE_CTX (ctx, "pipe busy (unblocked?)");
+              continue;
+            }
+
+          ctx->error_code = errno;
+          ctx->error = 1;
+          TRACE_ERR (ctx, ctx->error_code, "write error");
+          break;
+        }
+
+      _gpgrt_lock_lock (&ctx->mutex);
+      ctx->nbytes -= nwritten;
+      _gpgrt_lock_unlock (&ctx->mutex);
+    }
+  /* Indicate that we have an error.  */
+  if (!SetEvent (ctx->is_empty))
+    TRACE_ERR (ctx, GetLastError (), "SetEvent failed");
+
+  TRACE_CTX (ctx, "waiting for close");
+  WaitForSingleObject (ctx->close_ev, INFINITE);
+
+  if (ctx->nbytes)
+    TRACE_CTX (ctx, "still %d bytes in buffer at close time", ctx->nbytes);
+
+  CloseHandle (ctx->close_ev);
+  CloseHandle (ctx->have_data);
+  CloseHandle (ctx->is_empty);
+  CloseHandle (ctx->thread_hd);
+  _gpgrt_lock_destroy (&ctx->mutex);
+  _gpgrt_free (ctx);
+
+  return 0;
+}
+
+
+static struct writer_context_s *
+create_writer (estream_cookie_w32_pollable_t pcookie)
+{
+  struct writer_context_s *ctx;
+  SECURITY_ATTRIBUTES sec_attr;
+  DWORD tid;
+
+  memset (&sec_attr, 0, sizeof sec_attr);
+  sec_attr.nLength = sizeof sec_attr;
+  sec_attr.bInheritHandle = FALSE;
+
+  ctx = calloc (1, sizeof *ctx);
+  if (!ctx)
+    {
+      return NULL;
+    }
+
+  ctx->pcookie = pcookie;
+
+  ctx->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
+  if (ctx->have_data)
+    ctx->is_empty  = CreateEvent (&sec_attr, TRUE, TRUE, NULL);
+  if (ctx->is_empty)
+    ctx->close_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
+  if (!ctx->have_data || !ctx->is_empty || !ctx->close_ev)
+    {
+      TRACE_ERR (ctx, GetLastError (), "CreateEvent failed");
+      if (ctx->have_data)
+	CloseHandle (ctx->have_data);
+      if (ctx->is_empty)
+	CloseHandle (ctx->is_empty);
+      if (ctx->close_ev)
+	CloseHandle (ctx->close_ev);
+      _gpgrt_free (ctx);
+      return NULL;
+    }
+
+  ctx->is_empty = set_synchronize (ctx->is_empty);
+  _gpgrt_lock_init (&ctx->mutex);
+
+#ifdef HAVE_W32CE_SYSTEM
+  ctx->thread_hd = CreateThread (&sec_attr, 64 * 1024, writer, ctx,
+				 STACK_SIZE_PARAM_IS_A_RESERVATION, &tid);
+#else
+  ctx->thread_hd = CreateThread (&sec_attr, 0, writer, ctx, 0, &tid );
+#endif
+
+  if (!ctx->thread_hd)
+    {
+      TRACE_ERR (ctx, GetLastError (), "CreateThread failed");
+      _gpgrt_lock_destroy (&ctx->mutex);
+      if (ctx->have_data)
+	CloseHandle (ctx->have_data);
+      if (ctx->is_empty)
+	CloseHandle (ctx->is_empty);
+      if (ctx->close_ev)
+	CloseHandle (ctx->close_ev);
+      _gpgrt_free (ctx);
+      return NULL;
+    }
+  else
+    {
+#if 0
+      /* We set the priority of the thread higher because we know
+	 that it only runs for a short time.  This greatly helps to
+	 increase the performance of the I/O.  */
+      SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
+#endif
+    }
+
+  return ctx;
+}
+
+
+static void
+destroy_writer (struct writer_context_s *ctx)
+{
+  _gpgrt_lock_lock (&ctx->mutex);
+  ctx->stop_me = 1;
+  if (ctx->have_data)
+    SetEvent (ctx->have_data);
+  _gpgrt_lock_unlock (&ctx->mutex);
+
+  /* Give the writer a chance to flush the buffer.  */
+  WaitForSingleObject (ctx->is_empty, INFINITE);
+
+#ifdef HAVE_W32CE_SYSTEM
+  /* Scenario: We never create a full pipe, but already started
+     writing more than the pipe buffer.  Then we need to unblock the
+     writer in the pipe driver to make our writer thread notice that
+     we want it to go away.  */
+
+  if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK,
+			NULL, 0, NULL, 0, NULL, NULL))
+    {
+      TRACE_ERR (ctx, GetLastError (), "unblock control call failed");
+    }
+#endif
+
+  /* After setting this event CTX is void.  */
+  SetEvent (ctx->close_ev);
+}
+
+
+/*
+ * Write function for pollable objects.
+ */
+static gpgrt_ssize_t
+func_w32_pollable_write (void *cookie, const void *buffer, size_t count)
+{
+  estream_cookie_w32_pollable_t pcookie = cookie;
+  struct writer_context_s *ctx;
+
+  if (count == 0)
+    return 0;
+
+  ctx = pcookie->writer;
+  if (ctx == NULL)
+    {
+      pcookie->writer = ctx = create_writer (pcookie);
+      if (!ctx)
+        return -1;
+    }
+
+  _gpgrt_lock_lock (&ctx->mutex);
+  TRACE_CTX (ctx, "pollable write buffer: %p, count: %d, nbytes: %d",
+         buffer, count, ctx->nbytes);
+  if (!ctx->error && ctx->nbytes)
+    {
+      /* Bytes are pending for send.  */
+
+      /* Reset the is_empty event.  Better safe than sorry.  */
+      if (!ResetEvent (ctx->is_empty))
+	{
+	  TRACE_ERR (ctx, GetLastError (), "ResetEvent failed");
+	  _gpgrt_lock_unlock (&ctx->mutex);
+	  /* FIXME: Should translate the error code.  */
+	  _gpg_err_set_errno (EIO);
+	  return -1;
+	}
+      _gpgrt_lock_unlock (&ctx->mutex);
+
+      if (pcookie->modeflags & O_NONBLOCK)
+        {
+          TRACE_CTX (ctx, "would block");
+          _gpg_err_set_errno (EAGAIN);
+          return -1;
+        }
+
+      TRACE_CTX (ctx, "waiting for empty buffer");
+      WaitForSingleObject (ctx->is_empty, INFINITE);
+      TRACE_CTX (ctx, "buffer is empty");
+      _gpgrt_lock_lock (&ctx->mutex);
+    }
+
+  if (ctx->error)
+    {
+      _gpgrt_lock_unlock (&ctx->mutex);
+      if (ctx->error_code == ERROR_NO_DATA)
+        _gpg_err_set_errno (EPIPE);
+      else
+        _gpg_err_set_errno (EIO);
+      return -1;
+    }
+
+  /* If no error occurred, the number of bytes in the buffer must be
+     zero.  */
+  assert (!ctx->nbytes);
+
+  if (count > WRITEBUF_SIZE)
+    count = WRITEBUF_SIZE;
+  memcpy (ctx->buffer, buffer, count);
+  ctx->nbytes = count;
+
+  /* We have to reset the is_empty event early, because it is also
+     used by the select() implementation to probe the channel.  */
+  if (!ResetEvent (ctx->is_empty))
+    {
+      TRACE_ERR (ctx, GetLastError (), "ResetEvent failed");
+      _gpgrt_lock_unlock (&ctx->mutex);
+      /* FIXME: Should translate the error code.  */
+      _gpg_err_set_errno (EIO);
+      return -1;
+    }
+  if (!SetEvent (ctx->have_data))
+    {
+      TRACE_ERR (ctx, GetLastError (), "SetEvent failed");
+      _gpgrt_lock_unlock (&ctx->mutex);
+      /* FIXME: Should translate the error code.  */
+      _gpg_err_set_errno (EIO);
+      return -1;
+    }
+  _gpgrt_lock_unlock (&ctx->mutex);
+
+  return (int) count;
+}
+
+
+int
+_gpgrt_w32_poll (gpgrt_poll_t *fds, size_t nfds, int timeout)
+{
+  HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
+  int waitidx[MAXIMUM_WAIT_OBJECTS];
+  int code;
+  int nwait;
+  int i;
+  int any;
+  int count;
+
+#if 0
+ restart:
+#endif
+
+  TRACE ("poll on [ ");
+  any = 0;
+  nwait = 0;
+  count = 0;
+  for (i = 0; i < nfds; i++)
+    {
+      struct estream_cookie_w32_pollable *pcookie;
+
+      if (fds[i].ignore)
+	continue;
+
+      if (fds[i].stream->intern->kind != BACKEND_W32_POLLABLE)
+        {
+          /* This stream does not support polling.  */
+          fds[i].got_err = 1;
+          continue;
+        }
+
+      pcookie = fds[i].stream->intern->cookie;
+
+      if (fds[i].want_read || fds[i].want_write)
+	{
+          /* XXX: What if one wants read and write, is that supported?  */
+	  if (fds[i].want_read)
+	    {
+	      struct reader_context_s *ctx = pcookie->reader;
+              TRACE ("%d/read ", i);
+              if (ctx == NULL)
+                {
+                  pcookie->reader = ctx = create_reader (pcookie);
+                  if (!ctx)
+                    {
+                      /* FIXME:  Is the error code appropriate?  */
+                      _gpg_err_set_errno (EBADF);
+                      return -1;
+                    }
+                }
+
+              if (nwait >= DIM (waitbuf))
+                {
+                  TRACE ("oops ]: Too many objects for WFMO!\n");
+                  /* FIXME: Should translate the error code.  */
+                  _gpg_err_set_errno (EIO);
+                  return -1;
+                }
+              waitidx[nwait] = i;
+              waitbuf[nwait++] = ctx->have_data_ev;
+	      any = 1;
+            }
+	  else if (fds[i].want_write)
+	    {
+	      struct writer_context_s *ctx = pcookie->writer;
+              TRACE ("%d/write ", i);
+              if (ctx == NULL)
+                {
+                  pcookie->writer = ctx = create_writer (pcookie);
+                  if (!ctx)
+                    {
+                      /* FIXME:  Is the error code appropriate?  */
+                      _gpg_err_set_errno (EBADF);
+                      return -1;
+                    }
+                }
+
+              if (nwait >= DIM (waitbuf))
+                {
+                  TRACE ("oops ]: Too many objects for WFMO!");
+                  /* FIXME: Should translate the error code.  */
+                  _gpg_err_set_errno (EIO);
+                  return -1;
+                }
+              waitidx[nwait] = i;
+              waitbuf[nwait++] = ctx->is_empty;
+	      any = 1;
+            }
+        }
+    }
+  TRACE ("]\n");
+  if (!any)
+    return 0;
+
+  code = WaitForMultipleObjects (nwait, waitbuf, 0,
+                                 timeout == -1 ? INFINITE : timeout);
+  if (code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait)
+    {
+      /* This WFMO is a really silly function: It does return either
+	 the index of the signaled object or if 2 objects have been
+	 signalled at the same time, the index of the object with the
+	 lowest object is returned - so and how do we find out how
+	 many objects have been signaled???.  The only solution I can
+	 imagine is to test each object starting with the returned
+	 index individually - how dull.  */
+      any = 0;
+      for (i = code - WAIT_OBJECT_0; i < nwait; i++)
+	{
+	  if (WaitForSingleObject (waitbuf[i], 0) == WAIT_OBJECT_0)
+	    {
+	      assert (waitidx[i] >=0 && waitidx[i] < nfds);
+              /* XXX: What if one wants read and write, is that
+                 supported?  */
+              if (fds[waitidx[i]].want_read)
+                fds[waitidx[i]].got_read = 1;
+              else if (fds[waitidx[i]].want_write)
+                fds[waitidx[i]].got_write = 1;
+	      any = 1;
+	      count++;
+	    }
+	}
+      if (!any)
+	{
+	  TRACE ("no signaled objects found after WFMO\n");
+	  count = -1;
+	}
+    }
+  else if (code == WAIT_TIMEOUT)
+    TRACE ("WFMO timed out\n");
+  else if (code == WAIT_FAILED)
+    {
+      TRACE_ERR (NULL, GetLastError (), "WFMO failed");
+#if 0
+      if (GetLastError () == ERROR_INVALID_HANDLE)
+	{
+	  int k;
+	  int j = handle_to_fd (waitbuf[i]);
+
+	  TRACE ("WFMO invalid handle %d removed\n", j);
+	  for (k = 0 ; k < nfds; k++)
+	    {
+	      if (fds[k].fd == j)
+		{
+		  fds[k].want_read = fds[k].want_write = 0;
+		  goto restart;
+                }
+            }
+	  TRACE (" oops, or not???\n");
+        }
+#endif
+      count = -1;
+    }
+  else
+    {
+      TRACE ("WFMO returned %d\n", code);
+      count = -1;
+    }
+
+  if (count > 0)
+    {
+      TRACE ("poll OK [ ");
+      for (i = 0; i < nfds; i++)
+	{
+	  if (fds[i].ignore)
+	    continue;
+	  if (fds[i].got_read || fds[i].got_write)
+	    TRACE ("%c%d ", fds[i].want_read ? 'r' : 'w', i);
+        }
+      TRACE ("]\n");
+    }
+
+  if (count < 0)
+    {
+      /* FIXME: Should determine a proper error code.  */
+      _gpg_err_set_errno (EIO);
+    }
+
+  return count;
+}
+
+

+
+/*
+ * Implementation of pollable I/O on Windows.
+ */
+
+/*
+ * Constructor for pollable objects.
+ */
+int
+_gpgrt_w32_pollable_create (void *_GPGRT__RESTRICT *_GPGRT__RESTRICT cookie,
+                            unsigned int modeflags,
+                            struct cookie_io_functions_s next_functions,
+                            void *next_cookie)
+{
+  estream_cookie_w32_pollable_t pcookie;
+  int err;
+
+  pcookie = _gpgrt_malloc (sizeof *pcookie);
+  if (!pcookie)
+    err = -1;
+  else
+    {
+      pcookie->modeflags = modeflags;
+      pcookie->next_functions = next_functions;
+      pcookie->next_cookie = next_cookie;
+      pcookie->reader = NULL;
+      pcookie->writer = NULL;
+      *cookie = pcookie;
+      err = 0;
+    }
+
+  return err;
+}
+
+
+/*
+ * Seek function for pollable objects.
+ */
+static int
+func_w32_pollable_seek (void *cookie, gpgrt_off_t *offset, int whence)
+{
+  estream_cookie_w32_pollable_t pcookie = cookie;
+  (void) pcookie;
+  (void) offset;
+  (void) whence;
+  /* XXX */
+  _gpg_err_set_errno (EOPNOTSUPP);
+  return -1;
+}
+
+
+/*
+ * The IOCTL function for pollable objects.
+ */
+static int
+func_w32_pollable_ioctl (void *cookie, int cmd, void *ptr, size_t *len)
+{
+  estream_cookie_w32_pollable_t pcookie = cookie;
+  cookie_ioctl_function_t func_ioctl = pcookie->next_functions.func_ioctl;
+
+  if (cmd == COOKIE_IOCTL_NONBLOCK)
+    {
+      if (ptr)
+        pcookie->modeflags |= O_NONBLOCK;
+      else
+        pcookie->modeflags &= ~O_NONBLOCK;
+      return 0;
+    }
+
+  if (func_ioctl)
+    return func_ioctl (pcookie->next_cookie, cmd, ptr, len);
+
+  _gpg_err_set_errno (EOPNOTSUPP);
+  return -1;
+}
+
+
+/*
+ * The destroy function for pollable objects.
+ */
+static int
+func_w32_pollable_destroy (void *cookie)
+{
+  estream_cookie_w32_pollable_t pcookie = cookie;
+
+  if (cookie)
+    {
+      if (pcookie->reader)
+        destroy_reader (pcookie->reader);
+      if (pcookie->writer)
+        destroy_writer (pcookie->writer);
+      pcookie->next_functions.public.func_close (pcookie->next_cookie);
+      _gpgrt_free (pcookie);
+    }
+  return 0;
+}
+
+/*
+ * Access object for the pollable functions.
+ */
+struct cookie_io_functions_s _gpgrt_functions_w32_pollable =
+  {
+    {
+      func_w32_pollable_read,
+      func_w32_pollable_write,
+      func_w32_pollable_seek,
+      func_w32_pollable_destroy,
+    },
+    func_w32_pollable_ioctl,
+  };
diff --git a/tests/t-poll.c b/tests/t-poll.c
index 026bb88..d39797a 100644
--- a/tests/t-poll.c
+++ b/tests/t-poll.c
@@ -191,14 +191,14 @@ create_pipe (estream_t *r_in, estream_t *r_out)
 
   show ("created pipe [%d, %d]\n", filedes[0], filedes[1]);
 
-  *r_in = es_fdopen (filedes[0], "r");
+  *r_in = es_fdopen (filedes[0], "r,pollable");
   if (!*r_in)
     {
       err = gpg_error_from_syserror ();
       die ("error creating a stream for a pipe: %s\n", gpg_strerror (err));
     }
 
-  *r_out = es_fdopen (filedes[1], "w");
+  *r_out = es_fdopen (filedes[1], "w,pollable");
   if (!*r_out)
     {
       err = gpg_error_from_syserror ();

commit e15416d3668ea9dcc6a64cbb98140a99be8a7865
Author: Justus Winter <justus at g10code.com>
Date:   Wed Oct 19 12:20:43 2016 +0200

    estream: Track the kind of backend used.
    
    * src/estream.c (struct _gpgrt_stream_internal): Add 'kind'.
    (init_stream_obj): New parameter 'kind', initialize field.
    (es_create): New parameter 'kind'.  Update all callers.
    * src/gpgrt-int.h (gpgrt_stream_backend_kind_t): New type.
    
    Signed-off-by: Justus Winter <justus at g10code.com>

diff --git a/src/estream.c b/src/estream.c
index 696e1e3..aca7db7 100644
--- a/src/estream.c
+++ b/src/estream.c
@@ -203,6 +203,7 @@ struct _gpgrt_stream_internal
 
   gpgrt_lock_t lock;		 /* Lock.  Used by *_stream_lock(). */
 
+  gpgrt_stream_backend_kind_t kind;
   void *cookie;			 /* Cookie.                */
   void *opaque;			 /* Opaque data.           */
   unsigned int modeflags;	 /* Flags for the backend. */
@@ -2007,9 +2008,11 @@ es_empty (estream_t stream)
 static void
 init_stream_obj (estream_t stream,
                  void *cookie, es_syshd_t *syshd,
+                 gpgrt_stream_backend_kind_t kind,
                  struct cookie_io_functions_s functions,
                  unsigned int modeflags, unsigned int xmode)
 {
+  stream->intern->kind = kind;
   stream->intern->cookie = cookie;
   stream->intern->opaque = NULL;
   stream->intern->offset = 0;
@@ -2092,6 +2095,7 @@ es_deinitialize (estream_t stream)
  */
 static int
 es_create (estream_t *stream, void *cookie, es_syshd_t *syshd,
+           gpgrt_stream_backend_kind_t kind,
 	   struct cookie_io_functions_s functions, unsigned int modeflags,
            unsigned int xmode, int with_locked_list)
 {
@@ -2122,7 +2126,8 @@ es_create (estream_t *stream, void *cookie, es_syshd_t *syshd,
   stream_new->unread_buffer_size = sizeof (stream_internal_new->unread_buffer);
   stream_new->intern = stream_internal_new;
 
-  init_stream_obj (stream_new, cookie, syshd, functions, modeflags, xmode);
+  init_stream_obj (stream_new, cookie, syshd, kind, functions, modeflags,
+                   xmode);
   init_stream_lock (stream_new);
 
   err = do_list_add (stream_new, with_locked_list);
@@ -2829,7 +2834,7 @@ doreadline (estream_t _GPGRT__RESTRICT stream, size_t max_length,
     goto out;
 
   memset (&syshd, 0, sizeof syshd);
-  err = es_create (&line_stream, line_stream_cookie, &syshd,
+  err = es_create (&line_stream, line_stream_cookie, &syshd, BACKEND_MEM,
 		   estream_functions_mem, O_RDWR, 1, 0);
   if (err)
     goto out;
@@ -3080,8 +3085,8 @@ _gpgrt_fopen (const char *_GPGRT__RESTRICT path,
   syshd.type = ES_SYSHD_FD;
   syshd.u.fd = fd;
   create_called = 1;
-  err = es_create (&stream, cookie, &syshd, estream_functions_fd, modeflags,
-                   xmode, 0);
+  err = es_create (&stream, cookie, &syshd, BACKEND_FD,
+                   estream_functions_fd, modeflags, xmode, 0);
   if (err)
     goto out;
 
@@ -3137,7 +3142,7 @@ _gpgrt_mopen (void *_GPGRT__RESTRICT data, size_t data_n, size_t data_len,
 
   memset (&syshd, 0, sizeof syshd);
   create_called = 1;
-  err = es_create (&stream, cookie, &syshd,
+  err = es_create (&stream, cookie, &syshd, BACKEND_MEM,
                    estream_functions_mem, modeflags, xmode, 0);
 
  out:
@@ -3171,8 +3176,8 @@ _gpgrt_fopenmem (size_t memlimit, const char *_GPGRT__RESTRICT mode)
     return NULL;
 
   memset (&syshd, 0, sizeof syshd);
-  if (es_create (&stream, cookie, &syshd, estream_functions_mem, modeflags,
-                 xmode, 0))
+  if (es_create (&stream, cookie, &syshd, BACKEND_MEM,
+                 estream_functions_mem, modeflags, xmode, 0))
     (*estream_functions_mem.public.func_close) (cookie);
 
   return stream;
@@ -3233,8 +3238,8 @@ _gpgrt_fopencookie (void *_GPGRT__RESTRICT cookie,
     goto out;
 
   memset (&syshd, 0, sizeof syshd);
-  err = es_create (&stream, cookie, &syshd, io_functions, modeflags,
-                   xmode, 0);
+  err = es_create (&stream, cookie, &syshd, BACKEND_USER, io_functions,
+                   modeflags, xmode, 0);
   if (err)
     goto out;
 
@@ -3276,7 +3281,7 @@ do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list)
   syshd.type = ES_SYSHD_FD;
   syshd.u.fd = filedes;
   create_called = 1;
-  err = es_create (&stream, cookie, &syshd, estream_functions_fd,
+  err = es_create (&stream, cookie, &syshd, BACKEND_FD, estream_functions_fd,
                    modeflags, xmode, with_locked_list);
 
   if (!err && stream)
@@ -3342,7 +3347,7 @@ do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list)
   syshd.type = ES_SYSHD_FD;
   syshd.u.fd = fp? fileno (fp): -1;
   create_called = 1;
-  err = es_create (&stream, cookie, &syshd, estream_functions_fp,
+  err = es_create (&stream, cookie, &syshd, BACKEND_FP, estream_functions_fp,
                    modeflags, xmode, with_locked_list);
 
  out:
@@ -3402,8 +3407,8 @@ do_w32open (HANDLE hd, const char *mode,
   syshd.type = ES_SYSHD_HANDLE;
   syshd.u.handle = hd;
   create_called = 1;
-  err = es_create (&stream, cookie, &syshd, estream_functions_w32,
-                   modeflags, xmode, with_locked_list);
+  err = es_create (&stream, cookie, &syshd, BACKEND_W32,
+                   estream_functions_w32, modeflags, xmode, with_locked_list);
 
  leave:
   if (err && create_called)
@@ -3581,8 +3586,8 @@ _gpgrt_freopen (const char *_GPGRT__RESTRICT path,
       syshd.type = ES_SYSHD_FD;
       syshd.u.fd = fd;
       create_called = 1;
-      init_stream_obj (stream, cookie, &syshd, estream_functions_fd,
-                       modeflags, xmode);
+      init_stream_obj (stream, cookie, &syshd, BACKEND_FD,
+                       estream_functions_fd, modeflags, xmode);
 
     leave:
 
@@ -4575,8 +4580,8 @@ _gpgrt_tmpfile (void)
   syshd.type = ES_SYSHD_FD;
   syshd.u.fd = fd;
   create_called = 1;
-  err = es_create (&stream, cookie, &syshd, estream_functions_fd, modeflags,
-                   0, 0);
+  err = es_create (&stream, cookie, &syshd, BACKEND_FD, estream_functions_fd,
+                   modeflags, 0, 0);
 
  out:
   if (err)
diff --git a/src/gpgrt-int.h b/src/gpgrt-int.h
index 475d38a..a517cc6 100644
--- a/src/gpgrt-int.h
+++ b/src/gpgrt-int.h
@@ -69,6 +69,17 @@ struct cookie_io_functions_s
   cookie_ioctl_function_t func_ioctl;
 };
 
+typedef enum
+  {
+    BACKEND_MEM,
+    BACKEND_FD,
+    BACKEND_W32,
+    BACKEND_FP,
+    BACKEND_USER,
+    BACKEND_W32_POLLABLE,
+  } gpgrt_stream_backend_kind_t;
+
+
 
 /* Local prototypes for estream.  */
 int _gpgrt_es_init (void);

commit a0651e910f962a49b0b7f7942512f17a5fe39a7d
Author: Justus Winter <justus at g10code.com>
Date:   Wed Oct 19 12:20:42 2016 +0200

    estream: Rework how the cookie functions are handled.
    
    * src/estream.c (cookie_ioctl_function_t): Move to 'gpgrt-int.h',
    along with the macros for the IOCTL numbers.
    (estream_functions_mem): Use the new type and add the ioctl function.
    (estream_functions_fd): Likewise.
    (estream_functions_w32): Likewise.
    (estream_functions_fp): Likewise.
    (init_stream_object): Use the new type, and also initialize
    'func_ioctl'.
    (es_create): Use the new type.
    (_gpgrt_fopen): Adapt.
    (_gpgrt_mopen): Likewise.
    (_gpgrt_fopenmem): Likewise.
    (_gpgrt_fopencookie): Likewise.
    (_gpgrt_fdopen): Likewise.
    (_gpgrt_fpopen): Likewise.
    (do_w32open): Likewise.
    * src/gpgrt-int.h (struct cookie_io_functions_s): New type.
    
    Signed-off-by: Justus Winter <justus at g10code.com>

diff --git a/src/estream.c b/src/estream.c
index 6e3b985..696e1e3 100644
--- a/src/estream.c
+++ b/src/estream.c
@@ -194,16 +194,6 @@ typedef struct notify_list_s *notify_list_t;
 
 
 /*
- * A private cookie function to implement an internal IOCTL service.
- * and ist IOCTL numbers.
- */
-typedef int (*cookie_ioctl_function_t) (void *cookie, int cmd,
-					void *ptr, size_t *len);
-#define COOKIE_IOCTL_SNATCH_BUFFER 1
-#define COOKIE_IOCTL_NONBLOCK      2
-
-
-/*
  * The private object describing a stream.
  */
 struct _gpgrt_stream_internal
@@ -946,12 +936,15 @@ func_mem_destroy (void *cookie)
 /*
  * Access object for the memory functions.
  */
-static gpgrt_cookie_io_functions_t estream_functions_mem =
+static struct cookie_io_functions_s estream_functions_mem =
   {
-    func_mem_read,
-    func_mem_write,
-    func_mem_seek,
-    func_mem_destroy
+    {
+      func_mem_read,
+      func_mem_write,
+      func_mem_seek,
+      func_mem_destroy,
+    },
+    func_mem_ioctl,
   };
 
 
@@ -1171,12 +1164,15 @@ func_fd_destroy (void *cookie)
 /*
  * Access object for the fd functions.
  */
-static gpgrt_cookie_io_functions_t estream_functions_fd =
+static struct cookie_io_functions_s estream_functions_fd =
   {
-    func_fd_read,
-    func_fd_write,
-    func_fd_seek,
-    func_fd_destroy
+    {
+      func_fd_read,
+      func_fd_write,
+      func_fd_seek,
+      func_fd_destroy,
+    },
+    func_fd_ioctl,
   };
 
 
@@ -1406,12 +1402,15 @@ func_w32_destroy (void *cookie)
 /*
  * Access object for the W32 handle based objects.
  */
-static gpgrt_cookie_io_functions_t estream_functions_w32 =
+static struct cookie_io_functions_s estream_functions_w32 =
   {
-    func_w32_read,
-    func_w32_write,
-    func_w32_seek,
-    func_w32_destroy
+    {
+      func_w32_read,
+      func_w32_write,
+      func_w32_seek,
+      func_w32_destroy,
+    },
+    NULL,
   };
 #endif /*HAVE_W32_SYSTEM*/
 
@@ -1617,12 +1616,15 @@ func_fp_destroy (void *cookie)
 /*
  * Access object for stdio based objects.
  */
-static gpgrt_cookie_io_functions_t estream_functions_fp =
+static struct cookie_io_functions_s estream_functions_fp =
   {
-    func_fp_read,
-    func_fp_write,
-    func_fp_seek,
-    func_fp_destroy
+    {
+      func_fp_read,
+      func_fp_write,
+      func_fp_seek,
+      func_fp_destroy,
+    },
+    NULL,
   };
 
 
@@ -2005,17 +2007,17 @@ es_empty (estream_t stream)
 static void
 init_stream_obj (estream_t stream,
                  void *cookie, es_syshd_t *syshd,
-                 gpgrt_cookie_io_functions_t functions,
+                 struct cookie_io_functions_s functions,
                  unsigned int modeflags, unsigned int xmode)
 {
   stream->intern->cookie = cookie;
   stream->intern->opaque = NULL;
   stream->intern->offset = 0;
-  stream->intern->func_read = functions.func_read;
-  stream->intern->func_write = functions.func_write;
-  stream->intern->func_seek = functions.func_seek;
-  stream->intern->func_ioctl = NULL;
-  stream->intern->func_close = functions.func_close;
+  stream->intern->func_read = functions.public.func_read;
+  stream->intern->func_write = functions.public.func_write;
+  stream->intern->func_seek = functions.public.func_seek;
+  stream->intern->func_ioctl = functions.func_ioctl;
+  stream->intern->func_close = functions.public.func_close;
   stream->intern->strategy = _IOFBF;
   stream->intern->syshd = *syshd;
   stream->intern->print_ntotal = 0;
@@ -2090,7 +2092,7 @@ es_deinitialize (estream_t stream)
  */
 static int
 es_create (estream_t *stream, void *cookie, es_syshd_t *syshd,
-	   gpgrt_cookie_io_functions_t functions, unsigned int modeflags,
+	   struct cookie_io_functions_s functions, unsigned int modeflags,
            unsigned int xmode, int with_locked_list)
 {
   estream_internal_t stream_internal_new;
@@ -3089,7 +3091,7 @@ _gpgrt_fopen (const char *_GPGRT__RESTRICT path,
  out:
 
   if (err && create_called)
-    (*estream_functions_fd.func_close) (cookie);
+    (*estream_functions_fd.public.func_close) (cookie);
 
   return stream;
 }
@@ -3141,7 +3143,7 @@ _gpgrt_mopen (void *_GPGRT__RESTRICT data, size_t data_n, size_t data_len,
  out:
 
   if (err && create_called)
-    (*estream_functions_mem.func_close) (cookie);
+    (*estream_functions_mem.public.func_close) (cookie);
 
   return stream;
 }
@@ -3171,10 +3173,7 @@ _gpgrt_fopenmem (size_t memlimit, const char *_GPGRT__RESTRICT mode)
   memset (&syshd, 0, sizeof syshd);
   if (es_create (&stream, cookie, &syshd, estream_functions_mem, modeflags,
                  xmode, 0))
-    (*estream_functions_mem.func_close) (cookie);
-
-  if (stream)
-    stream->intern->func_ioctl = func_mem_ioctl;
+    (*estream_functions_mem.public.func_close) (cookie);
 
   return stream;
 }
@@ -3224,6 +3223,7 @@ _gpgrt_fopencookie (void *_GPGRT__RESTRICT cookie,
   estream_t stream;
   int err;
   es_syshd_t syshd;
+  struct cookie_io_functions_s io_functions = { functions, NULL, };
 
   stream = NULL;
   modeflags = 0;
@@ -3233,7 +3233,7 @@ _gpgrt_fopencookie (void *_GPGRT__RESTRICT cookie,
     goto out;
 
   memset (&syshd, 0, sizeof syshd);
-  err = es_create (&stream, cookie, &syshd, functions, modeflags,
+  err = es_create (&stream, cookie, &syshd, io_functions, modeflags,
                    xmode, 0);
   if (err)
     goto out;
@@ -3281,14 +3281,14 @@ do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list)
 
   if (!err && stream)
     {
-      stream->intern->func_ioctl = func_fd_ioctl;
       if ((modeflags & O_NONBLOCK))
-        err = func_fd_ioctl (cookie, COOKIE_IOCTL_NONBLOCK, "", NULL);
+        err = stream->intern->func_ioctl (cookie, COOKIE_IOCTL_NONBLOCK,
+                                          "", NULL);
     }
 
  out:
   if (err && create_called)
-    (*estream_functions_fd.func_close) (cookie);
+    (*estream_functions_fd.public.func_close) (cookie);
 
   return stream;
 }
@@ -3348,7 +3348,7 @@ do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list)
  out:
 
   if (err && create_called)
-    (*estream_functions_fp.func_close) (cookie);
+    (*estream_functions_fp.public.func_close) (cookie);
 
   return stream;
 }
@@ -3407,7 +3407,7 @@ do_w32open (HANDLE hd, const char *mode,
 
  leave:
   if (err && create_called)
-    (*estream_functions_w32.func_close) (cookie);
+    (*estream_functions_w32.public.func_close) (cookie);
 
   return stream;
 }
diff --git a/src/gpgrt-int.h b/src/gpgrt-int.h
index b2b553b..475d38a 100644
--- a/src/gpgrt-int.h
+++ b/src/gpgrt-int.h
@@ -50,6 +50,26 @@ gpg_err_code_t _gpgrt_lock_destroy (gpgrt_lock_t *lockhd);
 gpg_err_code_t _gpgrt_yield (void);
 
 
+/* Local definitions for estream.  */
+
+/*
+ * A private cookie function to implement an internal IOCTL service.
+ * and ist IOCTL numbers.
+ */
+typedef int (*cookie_ioctl_function_t) (void *cookie, int cmd,
+					void *ptr, size_t *len);
+#define COOKIE_IOCTL_SNATCH_BUFFER 1
+#define COOKIE_IOCTL_NONBLOCK      2
+
+/* An internal variant of gpgrt_cookie_close_function_t with a slot
+   for the ioctl function.  */
+struct cookie_io_functions_s
+{
+  struct _gpgrt_cookie_io_functions public;
+  cookie_ioctl_function_t func_ioctl;
+};
+
+
 /* Local prototypes for estream.  */
 int _gpgrt_es_init (void);
 void _gpgrt_set_syscall_clamp (void (*pre)(void), void (*post)(void));

commit 135319b5d1f9a88187687646c762759cfa05a7ec
Author: Justus Winter <justus at g10code.com>
Date:   Wed Oct 19 12:20:41 2016 +0200

    estream: Rework modestring handling.
    
    * src/estream.c (X_SAMETHREAD, X_SYSOPEN): New macros.
    (parse_mode): Rework how information flows from here to 'es_create'.
    Instead of using an integer flag per mode, use flags.
    (init_stream_obj): Adapt accordingly.
    (es_create): Likewise.
    (_gpgrt_fopen): Likewise.
    (_gpgrt_mopen): Likewise.
    (_gpgrt_fopenmem): Likewise.
    (_gpgrt_fopencookie): Likewise.
    (_gpgrt_fdopen): Likewise.
    (_gpgrt_fpopen): Likewise.
    (do_w32open): Likewise.
    (_gpgrt_freopen): Likewise.
    
    Signed-off-by: Justus Winter <justus at g10code.com>

diff --git a/src/estream.c b/src/estream.c
index 752d22e..6e3b985 100644
--- a/src/estream.c
+++ b/src/estream.c
@@ -1680,6 +1680,10 @@ func_file_create (void **cookie, int *filedes,
 
 
 

+/* Flags used by parse_mode and friends.  */
+#define X_SAMETHREAD	(1 << 0)
+#define X_SYSOPEN	(1 << 1)
+
 /* Parse the mode flags of fopen et al.  In addition to the POSIX
  * defined mode flags keyword parameters are supported.  These are
  * key/value pairs delimited by comma and optional white spaces.
@@ -1721,15 +1725,14 @@ func_file_create (void **cookie, int *filedes,
  */
 static int
 parse_mode (const char *modestr,
-            unsigned int *modeflags, int *samethread, int *sysopen,
+            unsigned int *modeflags,
+            unsigned int *r_xmode,
             unsigned int *r_cmode)
 {
   unsigned int omode, oflags, cmode;
   int got_cmode = 0;
 
-  *samethread = 0;
-  if (sysopen)
-    *sysopen = 0;
+  *r_xmode = 0;
 
   switch (*modestr)
     {
@@ -1811,7 +1814,7 @@ parse_mode (const char *modestr,
               _set_errno (EINVAL);
               return -1;
             }
-          *samethread = 1;
+          *r_xmode |= X_SAMETHREAD;
         }
       else if (!strncmp (modestr, "nonblock", 8))
         {
@@ -1831,8 +1834,7 @@ parse_mode (const char *modestr,
               _set_errno (EINVAL);
               return -1;
             }
-          if (sysopen)
-            *sysopen = 1;
+          *r_xmode |= X_SYSOPEN;
         }
     }
   if (!got_cmode)
@@ -2004,7 +2006,7 @@ static void
 init_stream_obj (estream_t stream,
                  void *cookie, es_syshd_t *syshd,
                  gpgrt_cookie_io_functions_t functions,
-                 unsigned int modeflags, int samethread)
+                 unsigned int modeflags, unsigned int xmode)
 {
   stream->intern->cookie = cookie;
   stream->intern->opaque = NULL;
@@ -2025,7 +2027,7 @@ init_stream_obj (estream_t stream,
   stream->intern->deallocate_buffer = 0;
   stream->intern->printable_fname = NULL;
   stream->intern->printable_fname_inuse = 0;
-  stream->intern->samethread = !!samethread;
+  stream->intern->samethread = !! (xmode & X_SAMETHREAD);
   stream->intern->onclose = NULL;
 
   stream->data_len = 0;
@@ -2089,7 +2091,7 @@ es_deinitialize (estream_t stream)
 static int
 es_create (estream_t *stream, void *cookie, es_syshd_t *syshd,
 	   gpgrt_cookie_io_functions_t functions, unsigned int modeflags,
-           int samethread, int with_locked_list)
+           unsigned int xmode, int with_locked_list)
 {
   estream_internal_t stream_internal_new;
   estream_t stream_new;
@@ -2118,7 +2120,7 @@ es_create (estream_t *stream, void *cookie, es_syshd_t *syshd,
   stream_new->unread_buffer_size = sizeof (stream_internal_new->unread_buffer);
   stream_new->intern = stream_internal_new;
 
-  init_stream_obj (stream_new, cookie, syshd, functions, modeflags, samethread);
+  init_stream_obj (stream_new, cookie, syshd, functions, modeflags, xmode);
   init_stream_lock (stream_new);
 
   err = do_list_add (stream_new, with_locked_list);
@@ -3053,8 +3055,8 @@ estream_t
 _gpgrt_fopen (const char *_GPGRT__RESTRICT path,
               const char *_GPGRT__RESTRICT mode)
 {
-  unsigned int modeflags, cmode;
-  int samethread, sysopen, create_called;
+  unsigned int modeflags, cmode, xmode;
+  int create_called;
   estream_t stream;
   void *cookie;
   int err;
@@ -3065,7 +3067,7 @@ _gpgrt_fopen (const char *_GPGRT__RESTRICT path,
   cookie = NULL;
   create_called = 0;
 
-  err = parse_mode (mode, &modeflags, &samethread, &sysopen, &cmode);
+  err = parse_mode (mode, &modeflags, &xmode, &cmode);
   if (err)
     goto out;
 
@@ -3077,7 +3079,7 @@ _gpgrt_fopen (const char *_GPGRT__RESTRICT path,
   syshd.u.fd = fd;
   create_called = 1;
   err = es_create (&stream, cookie, &syshd, estream_functions_fd, modeflags,
-                   samethread, 0);
+                   xmode, 0);
   if (err)
     goto out;
 
@@ -3117,12 +3119,11 @@ _gpgrt_mopen (void *_GPGRT__RESTRICT data, size_t data_n, size_t data_len,
   int create_called = 0;
   estream_t stream = NULL;
   void *cookie = NULL;
-  unsigned int modeflags;
-  int samethread;
+  unsigned int modeflags, xmode;
   int err;
   es_syshd_t syshd;
 
-  err = parse_mode (mode, &modeflags, &samethread, NULL, NULL);
+  err = parse_mode (mode, &modeflags, &xmode, NULL);
   if (err)
     goto out;
 
@@ -3135,7 +3136,7 @@ _gpgrt_mopen (void *_GPGRT__RESTRICT data, size_t data_n, size_t data_len,
   memset (&syshd, 0, sizeof syshd);
   create_called = 1;
   err = es_create (&stream, cookie, &syshd,
-                   estream_functions_mem, modeflags, samethread, 0);
+                   estream_functions_mem, modeflags, xmode, 0);
 
  out:
 
@@ -3150,15 +3151,14 @@ _gpgrt_mopen (void *_GPGRT__RESTRICT data, size_t data_n, size_t data_len,
 estream_t
 _gpgrt_fopenmem (size_t memlimit, const char *_GPGRT__RESTRICT mode)
 {
-  unsigned int modeflags;
-  int samethread;
+  unsigned int modeflags, xmode;
   estream_t stream = NULL;
   void *cookie = NULL;
   es_syshd_t syshd;
 
   /* Memory streams are always read/write.  We use MODE only to get
      the append flag.  */
-  if (parse_mode (mode, &modeflags, &samethread, NULL, NULL))
+  if (parse_mode (mode, &modeflags, &xmode, NULL))
     return NULL;
   modeflags |= O_RDWR;
 
@@ -3170,7 +3170,7 @@ _gpgrt_fopenmem (size_t memlimit, const char *_GPGRT__RESTRICT mode)
 
   memset (&syshd, 0, sizeof syshd);
   if (es_create (&stream, cookie, &syshd, estream_functions_mem, modeflags,
-                 samethread, 0))
+                 xmode, 0))
     (*estream_functions_mem.func_close) (cookie);
 
   if (stream)
@@ -3220,8 +3220,7 @@ _gpgrt_fopencookie (void *_GPGRT__RESTRICT cookie,
                     const char *_GPGRT__RESTRICT mode,
                     gpgrt_cookie_io_functions_t functions)
 {
-  unsigned int modeflags;
-  int samethread;
+  unsigned int modeflags, xmode;
   estream_t stream;
   int err;
   es_syshd_t syshd;
@@ -3229,13 +3228,13 @@ _gpgrt_fopencookie (void *_GPGRT__RESTRICT cookie,
   stream = NULL;
   modeflags = 0;
 
-  err = parse_mode (mode, &modeflags, &samethread, NULL, NULL);
+  err = parse_mode (mode, &modeflags, &xmode, NULL);
   if (err)
     goto out;
 
   memset (&syshd, 0, sizeof syshd);
   err = es_create (&stream, cookie, &syshd, functions, modeflags,
-                   samethread, 0);
+                   xmode, 0);
   if (err)
     goto out;
 
@@ -3248,8 +3247,8 @@ _gpgrt_fopencookie (void *_GPGRT__RESTRICT cookie,
 static estream_t
 do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list)
 {
-  unsigned int modeflags;
-  int samethread, sysopen, create_called;
+  unsigned int modeflags, xmode;
+  int create_called;
   estream_t stream;
   void *cookie;
   int err;
@@ -3259,10 +3258,10 @@ do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list)
   cookie = NULL;
   create_called = 0;
 
-  err = parse_mode (mode, &modeflags, &samethread, &sysopen, NULL);
+  err = parse_mode (mode, &modeflags, &xmode, NULL);
   if (err)
     goto out;
-  if (sysopen)
+  if (xmode & X_SYSOPEN)
     {
       /* Not allowed for fdopen.  */
       _set_errno (EINVAL);
@@ -3278,7 +3277,7 @@ do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list)
   syshd.u.fd = filedes;
   create_called = 1;
   err = es_create (&stream, cookie, &syshd, estream_functions_fd,
-                   modeflags, samethread, with_locked_list);
+                   modeflags, xmode, with_locked_list);
 
   if (!err && stream)
     {
@@ -3312,8 +3311,8 @@ _gpgrt_fdopen_nc (int filedes, const char *mode)
 static estream_t
 do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list)
 {
-  unsigned int modeflags, cmode;
-  int samethread, sysopen, create_called;
+  unsigned int modeflags, cmode, xmode;
+  int create_called;
   estream_t stream;
   void *cookie;
   int err;
@@ -3323,10 +3322,10 @@ do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list)
   cookie = NULL;
   create_called = 0;
 
-  err = parse_mode (mode, &modeflags, &samethread, &sysopen, &cmode);
+  err = parse_mode (mode, &modeflags, &xmode, &cmode);
   if (err)
     goto out;
-  if (sysopen)
+  if (xmode & X_SYSOPEN)
     {
       /* Not allowed for fpopen.  */
       _set_errno (EINVAL);
@@ -3344,7 +3343,7 @@ do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list)
   syshd.u.fd = fp? fileno (fp): -1;
   create_called = 1;
   err = es_create (&stream, cookie, &syshd, estream_functions_fp,
-                   modeflags, samethread, with_locked_list);
+                   modeflags, xmode, with_locked_list);
 
  out:
 
@@ -3384,8 +3383,7 @@ estream_t
 do_w32open (HANDLE hd, const char *mode,
             int no_close, int with_locked_list)
 {
-  unsigned int modeflags, cmode;
-  int samethread;
+  unsigned int modeflags, cmode, xmode;
   int create_called = 0;
   estream_t stream = NULL;
   void *cookie = NULL;
@@ -3393,7 +3391,7 @@ do_w32open (HANDLE hd, const char *mode,
   es_syshd_t syshd;
 
   /* For obvious reasons we ignore sysmode here.  */
-  err = parse_mode (mode, &modeflags, &samethread, NULL, &cmode);
+  err = parse_mode (mode, &modeflags, &xmode, &cmode);
   if (err)
     goto leave;
 
@@ -3405,7 +3403,7 @@ do_w32open (HANDLE hd, const char *mode,
   syshd.u.handle = hd;
   create_called = 1;
   err = es_create (&stream, cookie, &syshd, estream_functions_w32,
-                   modeflags, samethread, with_locked_list);
+                   modeflags, xmode, with_locked_list);
 
  leave:
   if (err && create_called)
@@ -3556,8 +3554,8 @@ _gpgrt_freopen (const char *_GPGRT__RESTRICT path,
 
   if (path)
     {
-      unsigned int modeflags, cmode;
-      int dummy, samethread, create_called;
+      unsigned int modeflags, cmode, xmode, dummy;
+      int create_called;
       void *cookie;
       int fd;
       es_syshd_t syshd;
@@ -3565,13 +3563,13 @@ _gpgrt_freopen (const char *_GPGRT__RESTRICT path,
       cookie = NULL;
       create_called = 0;
 
-      samethread = stream->intern->samethread;
+      xmode = stream->intern->samethread ? X_SAMETHREAD : 0;
 
       lock_stream (stream);
 
       es_deinitialize (stream);
 
-      err = parse_mode (mode, &modeflags, &dummy, NULL, &cmode);
+      err = parse_mode (mode, &modeflags, &dummy, &cmode);
       if (err)
 	goto leave;
       (void)dummy;
@@ -3584,7 +3582,7 @@ _gpgrt_freopen (const char *_GPGRT__RESTRICT path,
       syshd.u.fd = fd;
       create_called = 1;
       init_stream_obj (stream, cookie, &syshd, estream_functions_fd,
-                       modeflags, samethread);
+                       modeflags, xmode);
 
     leave:
 

-----------------------------------------------------------------------

Summary of changes:
 src/Makefile.am   |    3 +-
 src/estream.c     |  336 ++++++++---------
 src/gpgrt-int.h   |  105 ++++++
 src/w32-estream.c | 1047 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/t-poll.c    |    4 +-
 5 files changed, 1315 insertions(+), 180 deletions(-)
 create mode 100644 src/w32-estream.c


hooks/post-receive
-- 
Error codes used by GnuPG et al.
http://git.gnupg.org




More information about the Gnupg-commits mailing list