[git] GPG-ERROR - branch, master, updated. libgpg-error-1.20-6-gc09997b

by Werner Koch cvs at cvs.gnupg.org
Mon Sep 28 19:33:23 CEST 2015


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  c09997bc50f3fffaf76d60d2e571b1d85536571e (commit)
       via  d3e9514ff82ff767fc78ce485aef71ba56f3c0d5 (commit)
       via  071c2170479869f4c6694ae85d2b113e84482a01 (commit)
       via  61d832c53b7db5367a5542347e3454c882d0bf28 (commit)
      from  9decdd7bd105ff6a0973cc1f6652e0eb0625d640 (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 c09997bc50f3fffaf76d60d2e571b1d85536571e
Author: Werner Koch <wk at gnupg.org>
Date:   Mon Sep 28 17:41:33 2015 +0200

    estream: Keep track of EPIPE.
    
    * src/estream.c (_gpgrt_stream_internal): Add indicators.hup.
    (init_stream_obj): Init it.
    (es_fill, es_flush, es_seek): Set that.
    (_gpgrt_poll): Set event.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/estream.c b/src/estream.c
index 58f069c..21694a3 100644
--- a/src/estream.c
+++ b/src/estream.c
@@ -195,6 +195,7 @@ struct _gpgrt_stream_internal
   {
     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.  */
@@ -1713,7 +1714,11 @@ es_fill (estream_t stream)
   if (err)
     {
       if (errno != EAGAIN)
-        stream->intern->indicators.err = 1;
+        {
+          if (errno == EPIPE)
+            stream->intern->indicators.hup = 1;
+          stream->intern->indicators.err = 1;
+        }
     }
   else if (!bytes_read)
     stream->intern->indicators.eof = 1;
@@ -1793,8 +1798,12 @@ es_flush (estream_t stream)
 
  out:
 
-  if (err)
-    stream->intern->indicators.err = 1;
+  if (err && errno != EAGAIN)
+    {
+      if (errno == EPIPE)
+        stream->intern->indicators.hup = 1;
+      stream->intern->indicators.err = 1;
+    }
 
   return err;
 }
@@ -1829,6 +1838,7 @@ init_stream_obj (estream_t stream,
   stream->intern->print_ntotal = 0;
   stream->intern->indicators.err = 0;
   stream->intern->indicators.eof = 0;
+  stream->intern->indicators.hup = 0;
   stream->intern->is_stdstream = 0;
   stream->intern->stdstream_fd = 0;
   stream->intern->deallocate_buffer = 0;
@@ -2310,7 +2320,11 @@ es_seek (estream_t _GPGRT__RESTRICT stream, gpgrt_off_t offset, int whence,
  out:
 
   if (err)
-    stream->intern->indicators.err = 1;
+    {
+      if (errno == EPIPE)
+        stream->intern->indicators.hup = 1;
+      stream->intern->indicators.err = 1;
+    }
 
   return err;
 }
@@ -3624,6 +3638,8 @@ _gpgrt_clearerr_unlocked (estream_t stream)
 {
   stream->intern->indicators.eof = 0;
   stream->intern->indicators.err = 0;
+  /* We do not reset the HUP indicator because there is no way to
+     get out of this state.  */
 }
 
 
@@ -4609,6 +4625,11 @@ _gpgrt_poll (gpgrt_poll_t *fds, unsigned int nfds, int timeout)
         }
 
       any = 0;
+      if (item->stream->intern->indicators.hup)
+        {
+          item->got_hup = 1;
+          any = 1;
+        }
       if (item->want_read && FD_ISSET (fd, &readfds))
         {
           item->got_read = 1;

commit d3e9514ff82ff767fc78ce485aef71ba56f3c0d5
Author: Werner Koch <wk at gnupg.org>
Date:   Mon Sep 28 09:59:53 2015 +0200

    Add GPG_ERR_FALSE and GPG_ERR_TRUE error codes.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/NEWS b/NEWS
index 9bfc5b3..8df0a14 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,8 @@ Noteworthy changes in version 1.21 (unreleased) [C17/A17/R0]
  es_set_nonblock                  NEW macro.
  es_get_nonblock                  NEW macro.
  es_poll                          NEW macro.
+ GPG_ERR_TRUE                     NEW.
+ GPG_ERR_FALSE                    NEW.
 
 
 Noteworthy changes in version 1.20 (2015-08-26) [C16/A16/R0]
diff --git a/doc/errorref.txt b/doc/errorref.txt
index a369fbf..268454f 100644
--- a/doc/errorref.txt
+++ b/doc/errorref.txt
@@ -768,8 +768,14 @@ GPG_ERR_INV_LOCK_OBJ		Invalid lock object
              internal problem in libgpg-error or more likely a
              programming error.
 
+GPG_ERR_TRUE			True
 
+    Used to retrun the boolena value True.  Note that GPG_ERR_NO_ERROR
+    (with the value 0) is also often used to indicate the value true.
 
+GPG_ERR_FALSE			False
+
+    Used to return the boolean value False.
 
 GPG_ERR_LDAP_GENERAL		LDAP General error
 
diff --git a/src/err-codes.h.in b/src/err-codes.h.in
index a8846e4..e05d41f 100644
--- a/src/err-codes.h.in
+++ b/src/err-codes.h.in
@@ -283,7 +283,8 @@
 253	GPG_ERR_KEY_ON_CARD		Not possible with a card based key
 254	GPG_ERR_INV_LOCK_OBJ		Invalid lock object
 
-# 255 and 256 are RFU.
+255	GPG_ERR_TRUE			True
+256	GPG_ERR_FALSE			False
 
 # Error codes pertaining to the Assuan IPC interface
 257	GPG_ERR_ASS_GENERAL		General IPC error

commit 071c2170479869f4c6694ae85d2b113e84482a01
Author: Werner Koch <wk at gnupg.org>
Date:   Fri Sep 25 10:45:22 2015 +0200

    estream: Add gpgrt_set_nonblock and gpgrt_poll.
    
    * configure.ac (AC_CHECK_HEADERS): Add sys/select.h and sys/time.h.
    * src/estream.c: Include both header if available.
    (COOKIE_IOCTL_NONBLOCK): New.
    (struct estream_cookie_fd): Add field nonblock.
    (func_fd_create): Set nonblock from MODEFLAGS.
    (es_func_fd_ioctl): New.
    (parse_mode): Add modeflag "nonblock".
    (es_fill): Map EWOULDBLOCK to EAGAIN.  Do not set error indicator for
    EAGAIN.
    (es_flush, es_seek, es_write_nbf): Map EWOULDBLOCK to EAGAIN.
    (do_fdopen): Call COOKIE_IOCTL_NONBLOCK.
    (_gpgrt_set_nonblock): New.
    (_gpgrt_get_nonblock): New.
    (_gpgrt_poll): New.
    
    * src/gpg-error.h.in (struct _gpgrt_poll_s): New.
    (gpgrt_poll_t, es_poll_t): New.
    (es_set_nonblock, es_get_nonblock, es_poll): New.
    
    * src/gpg-error.vers, src/gpg-error.def.in: Add gpgrt_set_nonblock,
    gpgrt_get_nonblock, and gpgrt_poll.
    * src/visibility.c (gpgrt_set_nonblock, gpgrt_get_nonblock): New.
    (gpgrt_poll): New.
    
    * tests/t-common.h (DIM): New.
    * tests/t-poll.c: New.
    * tests/Makefile.am (TESTS): Add t-poll.
    (t_poll_LDADD): New.
    --
    
    The poll interface uses select(2) internally because that is more
    portable than poll(2).
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/NEWS b/NEWS
index ad19b1b..9bfc5b3 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,20 @@
-Noteworthy changes in version 1.21 (unreleased) [C16/A16/R_]
+Noteworthy changes in version 1.21 (unreleased) [C17/A17/R0]
 -----------------------------------------------
 
+ * New functions gpgrt_poll and gpgrt_set_nonblock.  For now only
+   pipes and sockets on Unix are supported.
+
+ * Interface changes relative to the 1.20 release:
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ gpgrt_set_nonblock               NEW.
+ gpgrt_get_nonblock               NEW.
+ gpgrt_poll                       NEW.
+ gpgrt_poll_t                     NEW type.
+ es_poll_t                        NEW type.
+ es_set_nonblock                  NEW macro.
+ es_get_nonblock                  NEW macro.
+ es_poll                          NEW macro.
+
 
 Noteworthy changes in version 1.20 (2015-08-26) [C16/A16/R0]
 -----------------------------------------------
diff --git a/configure.ac b/configure.ac
index 8946ffa..39b57d8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -160,7 +160,7 @@ AM_GNU_GETTEXT([external])
 
 # Checks for header files.
 AC_HEADER_STDC
-AC_CHECK_HEADERS([stdlib.h locale.h stdint.h])
+AC_CHECK_HEADERS([stdlib.h locale.h stdint.h sys/select.h sys/time.h])
 AC_FUNC_STRERROR_R
 case "${host_os}" in
      solaris*)
diff --git a/doc/errorref.txt b/doc/errorref.txt
index f9dbf59..a369fbf 100644
--- a/doc/errorref.txt
+++ b/doc/errorref.txt
@@ -750,7 +750,7 @@ GPG_ERR_BOGUS_STRING            Bogus string
 
 GPG_ERR_FORBIDDEN		Forbidden
 
-    The use of a features is not allowed due to insuffcient rights.
+    The use of a features is not allowed due to insufficient rights.
     Use by gpg-agent as an error codes for restricted commands.
 
 GPG_ERR_KEY_DISABLED            Key disabled
diff --git a/src/estream.c b/src/estream.c
index 7d12e36..58f069c 100644
--- a/src/estream.c
+++ b/src/estream.c
@@ -1,6 +1,6 @@
 /* estream.c - Extended Stream I/O Library
  * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011,
- *               2014 g10 Code GmbH
+ *               2014, 2015 g10 Code GmbH
  *
  * This file is part of Libestream.
  *
@@ -67,6 +67,12 @@
 # endif
 #endif
 
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
 #include <sys/types.h>
 #include <sys/file.h>
 #include <sys/stat.h>
@@ -108,6 +114,11 @@
 # define S_IWOTH S_IWUSR
 # define S_IXGRP S_IXUSR
 # define S_IXOTH S_IXUSR
+# define O_NONBLOCK  0  /* FIXME: Not yet supported.  */
+#endif
+
+#ifndef EAGAIN
+# define EAGAIN  EWOULDBLOCK
 #endif
 
 
@@ -157,6 +168,7 @@ typedef int (*cookie_ioctl_function_t) (void *cookie, int cmd,
 					void *ptr, size_t *len);
 /* IOCTL commands for the private cookie function.  */
 #define COOKIE_IOCTL_SNATCH_BUFFER 1
+#define COOKIE_IOCTL_NONBLOCK      2
 
 
 /* The internal stream object.  */
@@ -869,6 +881,7 @@ typedef struct estream_cookie_fd
 {
   int fd;        /* The file descriptor we are using for actual output.  */
   int no_close;  /* If set we won't close the file descriptor.  */
+  int nonblock;  /* Non-blocking mode is enabled.  */
 } *estream_cookie_fd_t;
 
 /* Create function for objects indentified by a libc file descriptor.  */
@@ -887,11 +900,10 @@ func_fd_create (void **cookie, int fd, unsigned int modeflags, int no_close)
       /* Make sure it is in binary mode if requested.  */
       if ( (modeflags & O_BINARY) )
         setmode (fd, O_BINARY);
-#else
-      (void)modeflags;
 #endif
       fd_cookie->fd = fd;
       fd_cookie->no_close = no_close;
+      fd_cookie->nonblock = !!(modeflags & O_NONBLOCK);
       *cookie = fd_cookie;
       err = 0;
     }
@@ -990,6 +1002,47 @@ es_func_fd_seek (void *cookie, gpgrt_off_t *offset, int whence)
   return err;
 }
 
+/* An IOCTL function for fd objects.  */
+static int
+es_func_fd_ioctl (void *cookie, int cmd, void *ptr, size_t *len)
+{
+  estream_cookie_fd_t fd_cookie = cookie;
+  int ret;
+
+  if (cmd == COOKIE_IOCTL_NONBLOCK && !len)
+    {
+      fd_cookie->nonblock = !!ptr;
+      if (IS_INVALID_FD (fd_cookie->fd))
+        {
+          _set_errno (EINVAL);
+          ret = -1;
+        }
+      else
+        {
+#ifdef _WIN32
+          _set_errno (EOPNOTSUPP); /* FIXME: Implement for Windows.  */
+          ret = -1;
+#else
+          _set_errno (0);
+          ret = fcntl (fd_cookie->fd, F_GETFL, 0);
+          if (ret == -1 && errno)
+            ;
+          else if (fd_cookie->nonblock)
+            ret = fcntl (fd_cookie->fd, F_SETFL, (ret | O_NONBLOCK));
+          else
+            ret = fcntl (fd_cookie->fd, F_SETFL, (ret & ~O_NONBLOCK));
+#endif
+        }
+    }
+  else
+    {
+      _set_errno (EINVAL);
+      ret = -1;
+    }
+
+  return ret;
+}
+
 /* Destroy function for fd objects.  */
 static int
 es_func_fd_destroy (void *cookie)
@@ -1496,6 +1549,10 @@ func_file_create (void **cookie, int *filedes,
       disables any internal locking.  This keyword is also found on
       IBM systems.
 
+   nonblock
+
+      The object is opened in non-blocking mode.  This is the same as
+      calling gpgrt_set_nonblock on the file.
 
    Note: R_CMODE is optional because is only required by functions
    which are able to creat a file.  */
@@ -1591,6 +1648,16 @@ parse_mode (const char *modestr,
             }
           *samethread = 1;
         }
+      else if (!strncmp (modestr, "nonblock", 8))
+        {
+          modestr += 8;
+          if (*modestr && !strchr (" \t,", *modestr))
+            {
+              _set_errno (EINVAL);
+              return -1;
+            }
+          oflags |= O_NONBLOCK;
+        }
     }
   if (!got_cmode)
     cmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
@@ -1631,6 +1698,10 @@ es_fill (estream_t stream)
 	{
 	  bytes_read = 0;
 	  err = -1;
+#if EWOULDBLOCK != EAGAIN
+          if (errno == EWOULDBLOCK)
+            _set_errno (EAGAIN);
+#endif
 	}
       else
 	{
@@ -1640,7 +1711,10 @@ es_fill (estream_t stream)
     }
 
   if (err)
-    stream->intern->indicators.err = 1;
+    {
+      if (errno != EAGAIN)
+        stream->intern->indicators.err = 1;
+    }
   else if (!bytes_read)
     stream->intern->indicators.eof = 1;
 
@@ -1690,6 +1764,10 @@ es_flush (estream_t stream)
 	    {
 	      bytes_written = 0;
 	      err = -1;
+#if EWOULDBLOCK != EAGAIN
+              if (errno == EWOULDBLOCK)
+                _set_errno (EAGAIN);
+#endif
 	    }
 	  else
 	    bytes_written = ret;
@@ -1941,6 +2019,10 @@ es_read_nbf (estream_t _GPGRT__RESTRICT stream,
       if (ret == -1)
 	{
 	  err = -1;
+#if EWOULDBLOCK != EAGAIN
+          if (errno == EWOULDBLOCK)
+            _set_errno (EAGAIN);
+#endif
 	  break;
 	}
       else if (ret)
@@ -2209,6 +2291,10 @@ es_seek (estream_t _GPGRT__RESTRICT stream, gpgrt_off_t offset, int whence,
   if (ret == -1)
     {
       err = -1;
+#if EWOULDBLOCK != EAGAIN
+      if (errno == EWOULDBLOCK)
+        _set_errno (EAGAIN);
+#endif
       goto out;
     }
 
@@ -2259,6 +2345,10 @@ es_write_nbf (estream_t _GPGRT__RESTRICT stream,
       if (ret == -1)
 	{
 	  err = -1;
+#if EWOULDBLOCK != EAGAIN
+          if (errno == EWOULDBLOCK)
+            _set_errno (EAGAIN);
+#endif
 	  break;
 	}
       else
@@ -2941,6 +3031,13 @@ do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list)
   err = es_create (&stream, cookie, &syshd, estream_functions_fd,
                    modeflags, samethread, with_locked_list);
 
+  if (!err && stream)
+    {
+      stream->intern->func_ioctl = es_func_fd_ioctl;
+      if ((modeflags & O_NONBLOCK))
+        err = es_func_fd_ioctl (cookie, COOKIE_IOCTL_NONBLOCK, "", NULL);
+    }
+
  out:
   if (err && create_called)
     (*estream_functions_fd.func_close) (cookie);
@@ -4293,6 +4390,249 @@ _gpgrt_set_binary (estream_t stream)
 }
 
 
+/* Set non-blocking mode for STREAM.  Use true for ONOFF to enable and
+   false to disable non-blocking mode.  Returns 0 on success or -1 on
+   error and sets ERRNO.  Note that not all backends support
+   non-blocking mode.
+
+   In non-blocking mode a system call will not block but return an
+   error and set errno to EAGAIN.  The estream API always uses EAGAIN
+   and not EWOULDBLOCK.  If a buffered function like es_fgetc() or
+   es_fgets() returns an error and both, feof() and ferror() return
+   false the caller may assume that the error condition was EAGAIN.
+
+   Switching back from non-blocking to blocking may raise problems
+   with buffering, thus care should be taken.  Although read+write
+   sockets are supported in theory, switching from write to read may
+   result into problems because estream may first flush the write
+   buffers and there is no way to handle that non-blocking (EAGAIN)
+   case.  Explicit flushing should thus be done before before
+   switching to read.  */
+int
+_gpgrt_set_nonblock (estream_t stream, int onoff)
+{
+  cookie_ioctl_function_t func_ioctl;
+  int ret;
+
+  lock_stream (stream);
+  func_ioctl = stream->intern->func_ioctl;
+  if (!func_ioctl)
+    {
+      _set_errno (EOPNOTSUPP);
+      ret = -1;
+    }
+  else
+    {
+      unsigned int save_flags = stream->intern->modeflags;
+
+      if (onoff)
+        stream->intern->modeflags |= O_NONBLOCK;
+      else
+        stream->intern->modeflags &= ~O_NONBLOCK;
+
+      ret = func_ioctl (stream->intern->cookie, COOKIE_IOCTL_NONBLOCK,
+                        onoff?"":NULL, NULL);
+      if (ret)
+        stream->intern->modeflags = save_flags;
+    }
+  unlock_stream (stream);
+  return ret;
+}
+
+
+/* Return true if STREAM is in non-blocking mode.  */
+int
+_gpgrt_get_nonblock (estream_t stream)
+{
+  int ret;
+
+  lock_stream (stream);
+  ret = !!(stream->intern->modeflags & O_NONBLOCK);
+  unlock_stream (stream);
+  return ret;
+}
+
+
+/* A version of poll(2) working on estream handles.  Note that not all
+   estream types work with this function.  In contrast to the standard
+   poll function the gpgrt_poll_t object uses a set of names bit flags
+   instead of the EVENTS and REVENTS members.  An item with the IGNORE
+   flag set is entirely ignored.  The TIMEOUT values is given in
+   milliseconds, a value of -1 waits indefinitely, and a value of 0
+   returns immediately.
+
+   A positive return value gives the number of fds with new
+   information.  A return value of 0 indicates a timeout and -1
+   indicates an error in which case ERRNO is set.  */
+int
+_gpgrt_poll (gpgrt_poll_t *fds, unsigned int nfds, int timeout)
+{
+  gpgrt_poll_t *item;
+  int count = 0;
+  fd_set readfds, writefds, exceptfds;
+  int any_readfd, any_writefd, any_exceptfd;
+  int idx;
+  int max_fd;
+  int fd, ret, any;
+
+  if (!fds)
+    {
+      _set_errno (EINVAL);
+      return -1;
+    }
+
+  /* Clear all response fields (even for ignored items).  */
+  for (item = fds, idx = 0; idx < nfds; item++, idx++)
+    {
+      item->got_read = 0;
+      item->got_write = 0;
+      item->got_oob = 0;
+      item->got_rdhup = 0;
+      item->got_err = 0;
+      item->got_hup = 0;
+      item->got_nval = 0;
+    }
+
+  /* Check for pending reads.  */
+  for (item = fds, idx = 0; idx < nfds; item++, idx++)
+    {
+      if (item->ignore)
+        continue;
+      if (!item->want_read)
+        continue;
+      if (_gpgrt__pending (item->stream))
+        {
+          item->got_read = 1;
+          count++;
+        }
+    }
+
+  /* Check for space in the write buffers.  */
+  for (item = fds, idx = 0; idx < nfds; item++, idx++)
+    {
+      if (item->ignore)
+        continue;
+      if (!item->want_write)
+        continue;
+      /* FIXME */
+    }
+
+  if (count)
+    return count;  /* Early return without waiting.  */
+
+  /* Now do the real select.  */
+  any_readfd = any_writefd = any_exceptfd = 0;
+  max_fd = 0;
+  for (item = fds, idx = 0; idx < nfds; item++, idx++)
+    {
+      if (item->ignore)
+        continue;
+      fd = _gpgrt_fileno (item->stream);
+      if (fd == -1)
+        continue;  /* Stream does not support polling.  */
+
+      if (item->want_read)
+        {
+          if (!any_readfd)
+            {
+              FD_ZERO (&readfds);
+              any_readfd = 1;
+            }
+          FD_SET (fd, &readfds);
+          if (fd > max_fd)
+            max_fd = fd;
+        }
+      if (item->want_write)
+        {
+          if (!any_writefd)
+            {
+              FD_ZERO (&writefds);
+              any_writefd = 1;
+            }
+          FD_SET (fd, &writefds);
+          if (fd > max_fd)
+            max_fd = fd;
+        }
+      if (item->want_oob)
+        {
+          if (!any_exceptfd)
+            {
+              FD_ZERO (&exceptfds);
+              any_exceptfd = 1;
+            }
+          FD_SET (fd, &exceptfds);
+          if (fd > max_fd)
+            max_fd = fd;
+        }
+    }
+
+#ifdef _WIN32
+  (void)timeout;
+  ret = -1;
+  _set_errno (EOPNOTSUPP);
+#else
+  if (pre_syscall_func)
+    pre_syscall_func ();
+  do
+    {
+      struct timeval timeout_val;
+
+      timeout_val.tv_sec = timeout / 1000;
+      timeout_val.tv_usec = (timeout % 1000) * 1000;
+      ret = select (max_fd+1,
+                    any_readfd?   &readfds   : NULL,
+                    any_writefd?  &writefds  : NULL,
+                    any_exceptfd? &exceptfds : NULL,
+                    timeout == -1 ? NULL : &timeout_val);
+    }
+  while (ret == -1 && errno == EINTR);
+  if (post_syscall_func)
+    post_syscall_func ();
+#endif
+
+  if (ret == -1)
+    return -1;
+  if (!ret)
+    return 0; /* Timeout.  Note that in this case we can't return
+                 got_err for an invalid stream.  */
+
+  for (item = fds, idx = 0; idx < nfds; item++, idx++)
+    {
+      if (item->ignore)
+        continue;
+      fd = _gpgrt_fileno (item->stream);
+      if (fd == -1)
+        {
+          item->got_err = 1;  /* Stream does not support polling.  */
+          count++;
+          continue;
+        }
+
+      any = 0;
+      if (item->want_read && FD_ISSET (fd, &readfds))
+        {
+          item->got_read = 1;
+          any = 1;
+        }
+      if (item->want_write && FD_ISSET (fd, &writefds))
+        {
+          item->got_write = 1;
+          any = 1;
+        }
+      if (item->want_oob && FD_ISSET (fd, &exceptfds))
+        {
+          item->got_oob = 1;
+          any = 1;
+        }
+
+      if (any)
+        count++;
+    }
+
+  return count;
+}
+
+
 void
 _gpgrt_opaque_set (estream_t stream, void *opaque)
 {
@@ -4373,6 +4713,7 @@ _gpgrt_fname_get (estream_t stream)
 }
 
 
+

 /* Print a BUFFER to STREAM while replacing all control characters and
    the characters in DELIMITERS by standard C escape sequences.
    Returns 0 on success or -1 on error.  If BYTES_WRITTEN is not NULL
diff --git a/src/gpg-error.def.in b/src/gpg-error.def.in
index cba973d..16de809 100644
--- a/src/gpg-error.def.in
+++ b/src/gpg-error.def.in
@@ -140,4 +140,8 @@ EXPORTS
  _gpgrt_pending               @104
  _gpgrt_pending_unlocked      @105
 
+ gpgrt_set_nonblock           @106
+ gpgrt_get_nonblock           @107
+ gpgrt_poll                   @108
+
 ;; end of file with public symbols for Windows.
diff --git a/src/gpg-error.h.in b/src/gpg-error.h.in
index ad5d470..61b57fc 100644
--- a/src/gpg-error.h.in
+++ b/src/gpg-error.h.in
@@ -525,6 +525,32 @@ typedef struct _gpgrt_syshd es_syshd_t;
 #define ES_SYSHD_HANDLE GPGRT_SYSHD_HANDLE
 #endif
 
+/* The object used with gpgrt_poll.  */
+struct _gpgrt_poll_s
+{
+  gpgrt_stream_t stream;
+  unsigned int want_read:1;
+  unsigned int want_write:1;
+  unsigned int want_oob:1;
+  unsigned int want_rdhup:1;
+  unsigned int _reserv1:4;
+  unsigned int got_read:1;
+  unsigned int got_write:1;
+  unsigned int got_oob:1;
+  unsigned int got_rdhup:1;
+  unsigned int _reserv2:4;
+  unsigned int got_err:1;
+  unsigned int got_hup:1;
+  unsigned int got_nval:1;
+  unsigned int _reserv3:4;
+  unsigned int ignore:1;
+  unsigned int user:8;       /* For application use.  */
+};
+typedef struct _gpgrt_poll_s gpgrt_poll_t;
+#ifdef GPGRT_ENABLE_ES_MACROS
+typedef struct _gpgrt_poll_s es_poll_t;
+#endif
+
 gpgrt_stream_t gpgrt_fopen (const char *_GPGRT__RESTRICT path,
                             const char *_GPGRT__RESTRICT mode);
 gpgrt_stream_t gpgrt_mopen (void *_GPGRT__RESTRICT data,
@@ -682,6 +708,10 @@ void gpgrt_setbuf (gpgrt_stream_t _GPGRT__RESTRICT stream,
                    char *_GPGRT__RESTRICT buf);
 
 void gpgrt_set_binary (gpgrt_stream_t stream);
+int  gpgrt_set_nonblock (gpgrt_stream_t stream, int onoff);
+int  gpgrt_get_nonblock (gpgrt_stream_t stream);
+
+int gpgrt_poll (gpgrt_poll_t *fdlist, unsigned int nfds, int timeout);
 
 gpgrt_stream_t gpgrt_tmpfile (void);
 
@@ -777,6 +807,9 @@ int gpgrt_vsnprintf (char *buf,size_t bufsize,
 # define es_setvbuf           gpgrt_setvbuf
 # define es_setbuf            gpgrt_setbuf
 # define es_set_binary        gpgrt_set_binary
+# define es_set_nonblock      gpgrt_set_nonblock
+# define es_get_nonblock      gpgrt_get_nonblock
+# define es_poll              gpgrt_poll
 # define es_tmpfile           gpgrt_tmpfile
 # define es_opaque_set        gpgrt_opaque_set
 # define es_opaque_get        gpgrt_opaque_get
diff --git a/src/gpg-error.vers b/src/gpg-error.vers
index 758e549..067bb29 100644
--- a/src/gpg-error.vers
+++ b/src/gpg-error.vers
@@ -104,6 +104,9 @@ GPG_ERROR_1.0 {
     gpgrt_setvbuf;
     gpgrt_setbuf;
     gpgrt_set_binary;
+    gpgrt_set_nonblock;
+    gpgrt_get_nonblock;
+    gpgrt_poll;
     gpgrt_tmpfile;
     gpgrt_opaque_set;
     gpgrt_opaque_get;
diff --git a/src/gpgrt-int.h b/src/gpgrt-int.h
index 34e5d72..0f7b29b 100644
--- a/src/gpgrt-int.h
+++ b/src/gpgrt-int.h
@@ -189,6 +189,10 @@ int _gpgrt_setvbuf (gpgrt_stream_t _GPGRT__RESTRICT stream,
                     char *_GPGRT__RESTRICT buf, int mode, size_t size);
 
 void _gpgrt_set_binary (gpgrt_stream_t stream);
+int  _gpgrt_set_nonblock (gpgrt_stream_t stream, int onoff);
+int  _gpgrt_get_nonblock (gpgrt_stream_t stream);
+
+int _gpgrt_poll (gpgrt_poll_t *fds, unsigned int nfds, int timeout);
 
 gpgrt_stream_t _gpgrt_tmpfile (void);
 
diff --git a/src/visibility.c b/src/visibility.c
index 9213ce9..4750685 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -592,6 +592,24 @@ gpgrt_set_binary (estream_t stream)
   _gpgrt_set_binary (stream);
 }
 
+int
+gpgrt_set_nonblock (estream_t stream, int onoff)
+{
+  return _gpgrt_set_nonblock (stream, onoff);
+}
+
+int
+gpgrt_get_nonblock (estream_t stream)
+{
+  return _gpgrt_get_nonblock (stream);
+}
+
+int
+gpgrt_poll (gpgrt_poll_t *fds, unsigned int nfds, int timeout)
+{
+  return _gpgrt_poll (fds, nfds, timeout);
+}
+
 estream_t
 gpgrt_tmpfile (void)
 {
diff --git a/src/visibility.h b/src/visibility.h
index 6f7de84..ec3a124 100644
--- a/src/visibility.h
+++ b/src/visibility.h
@@ -127,6 +127,9 @@ MARK_VISIBLE (gpgrt_vfprintf_unlocked)
 MARK_VISIBLE (gpgrt_setvbuf)
 MARK_VISIBLE (gpgrt_setbuf)
 MARK_VISIBLE (gpgrt_set_binary)
+MARK_VISIBLE (gpgrt_set_nonblock)
+MARK_VISIBLE (gpgrt_get_nonblock)
+MARK_VISIBLE (gpgrt_poll)
 MARK_VISIBLE (gpgrt_tmpfile)
 MARK_VISIBLE (gpgrt_opaque_set)
 MARK_VISIBLE (gpgrt_opaque_get)
@@ -232,6 +235,9 @@ MARK_VISIBLE (gpgrt_set_alloc_func)
 #define gpgrt_setvbuf               _gpgrt_USE_UNDERSCORED_FUNCTION
 #define gpgrt_setbuf                _gpgrt_USE_UNDERSCORED_FUNCTION
 #define gpgrt_set_binary            _gpgrt_USE_UNDERSCORED_FUNCTION
+#define gpgrt_set_nonblock          _gpgrt_USE_UNDERSCORED_FUNCTION
+#define gpgrt_get_nonblock          _gpgrt_USE_UNDERSCORED_FUNCTION
+#define gpgrt_poll                  _gpgrt_USE_UNDERSCORED_FUNCTION
 #define gpgrt_tmpfile               _gpgrt_USE_UNDERSCORED_FUNCTION
 #define gpgrt_opaque_set            _gpgrt_USE_UNDERSCORED_FUNCTION
 #define gpgrt_opaque_get            _gpgrt_USE_UNDERSCORED_FUNCTION
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 5cbd9f4..92b97f2 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -27,7 +27,7 @@ endif
 
 gpg_error_lib = ../src/libgpg-error.la
 
-TESTS = t-version t-strerror t-syserror t-lock t-printf
+TESTS = t-version t-strerror t-syserror t-lock t-printf t-poll
 
 AM_CPPFLAGS = -I$(top_builddir)/src $(extra_includes)
 
@@ -38,3 +38,4 @@ noinst_PROGRAMS = $(TESTS)
 noinst_HEADERS = t-common.h
 
 t_lock_LDADD = $(gpg_error_lib) $(LIBMULTITHREAD)
+t_poll_LDADD = $(gpg_error_lib) $(LIBMULTITHREAD)
diff --git a/tests/t-common.h b/tests/t-common.h
index 85bcd51..c6dcd12 100644
--- a/tests/t-common.h
+++ b/tests/t-common.h
@@ -24,6 +24,9 @@
 #ifndef PGM
 # error Macro PGM not defined.
 #endif
+#ifndef DIM
+# define DIM(array) (sizeof (array) / sizeof (*array))
+#endif
 
 
 static int verbose;
diff --git a/tests/t-poll.c b/tests/t-poll.c
new file mode 100644
index 0000000..5955d50
--- /dev/null
+++ b/tests/t-poll.c
@@ -0,0 +1,383 @@
+/* t-poll.c - Check the poll function
+ * Copyright (C) 2015 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 <http://www.gnu.org/licenses/>.
+ */
+
+/* FIXME: We need much better tests that this very basic one.  */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#ifdef _WIN32
+# include <windows.h>
+# include <time.h>
+#else
+# include <pthread.h>
+#endif
+
+#define PGM "t-lock"
+
+#include "t-common.h"
+
+#ifdef _WIN32
+# define THREAD_RET_TYPE  DWORD WINAPI
+# define THREAD_RET_VALUE 0
+#else
+# define THREAD_RET_TYPE  void *
+# define THREAD_RET_VALUE NULL
+#endif
+
+
+/* Object to convey data to a thread.  */
+struct thread_arg
+{
+  const char *name;
+  estream_t stream;
+  volatile int stop_me;
+#ifdef USE_POSIX_THREADS
+  pthread_t thread;
+#elif _WIN32
+  HANDLE thread;
+#endif
+};
+
+
+static struct thread_arg peer_stdin;  /* Thread to feed the stdin.  */
+static struct thread_arg peer_stdout; /* Thread to feed the stdout. */
+static struct thread_arg peer_stderr; /* Thread to feed the stderr. */
+
+static estream_t test_stdin;
+static estream_t test_stdout;
+static estream_t test_stderr;
+
+#if defined(_WIN32) || defined(USE_POSIX_THREADS)
+
+/* This thread feeds data to the given stream.  */
+static THREAD_RET_TYPE
+producer_thread (void *argaddr)
+{
+  struct thread_arg *arg = argaddr;
+  int i = 0;
+
+  (void)arg;
+
+  while (!arg->stop_me && i++ < 3)
+    {
+      show ("thread '%s' about to write\n", arg->name);
+      es_fprintf (arg->stream, "This is '%s' count=%d\n", arg->name, i);
+      es_fflush (arg->stream);
+    }
+  es_fclose (arg->stream);
+  return THREAD_RET_VALUE;
+}
+
+/* This thread eats data from the given stream.  */
+static THREAD_RET_TYPE
+consumer_thread (void *argaddr)
+{
+  struct thread_arg *arg = argaddr;
+  char buf[15];
+
+  (void)arg;
+
+  while (!arg->stop_me)
+    {
+      show ("thread '%s' ready to read\n", arg->name);
+      if (!es_fgets (buf, sizeof buf, arg->stream))
+        {
+          show ("Thread '%s' received EOF or error\n", arg->name);
+          break;
+        }
+      show ("Thread '%s' got: '%s'\n", arg->name, buf);
+    }
+  es_fclose (arg->stream);
+  return THREAD_RET_VALUE;
+}
+
+#endif /*_WIN32 || USE_POSIX_THREADS */
+
+
+static void
+launch_thread (THREAD_RET_TYPE (*fnc)(void *), struct thread_arg *th)
+{
+#ifdef _WIN32
+
+  th->thread = CreateThread (NULL, 0, fnc, th, 0, NULL);
+  if (!th->thread)
+    die ("creating thread '%s' failed: rc=%d", th->name, (int)GetLastError ());
+  show ("thread '%s' launched (fd=%d)\n", th->name, es_fileno (th->stream));
+
+#elif USE_POSIX_THREADS
+
+  th->stop_me = 0;
+  if (pthread_create (&th->thread, NULL, fnc, th))
+    die ("creating thread '%s' failed: %s\n", th->name, strerror (errno));
+  show ("thread '%s' launched (fd=%d)\n", th->name, es_fileno (th->stream));
+
+# else /* no thread support */
+
+  verbose++;
+  show ("no thread support - skipping test\n", PGM);
+  verbose--;
+
+#endif /* no thread support */
+}
+
+
+static void
+join_thread (struct thread_arg *th)
+{
+#ifdef _WIN32
+  int rc;
+
+  rc = WaitForSingleObject (th->thread, INFINITE);
+  if (rc == WAIT_OBJECT_0)
+    show ("thread '%s' has terminated\n", th->name);
+  else
+    fail ("waiting for thread '%s' failed: %d", th->name, (int)GetLastError ());
+  CloseHandle (th->thread);
+
+#elif USE_POSIX_THREADS
+
+  pthread_join (th->thread, NULL);
+  show ("thread '%s' has terminated\n", th->name);
+
+#endif
+}
+
+
+static void
+create_pipe (estream_t *r_in, estream_t *r_out)
+{
+  gpg_error_t err;
+  int filedes[2];
+
+#ifdef _WIN32
+  if (_pipe (filedes, 512, 0) == -1)
+#else
+  if (pipe (filedes) == -1)
+#endif
+    {
+      err = gpg_error_from_syserror ();
+      die ("error creating a pipe: %s\n", gpg_strerror (err));
+    }
+
+  show ("created pipe [%d, %d]\n", filedes[0], filedes[1]);
+
+  *r_in = es_fdopen (filedes[0], "r");
+  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");
+  if (!*r_out)
+    {
+      err = gpg_error_from_syserror ();
+      die ("error creating a stream for a pipe: %s\n", gpg_strerror (err));
+    }
+}
+
+
+static void
+test_poll (void)
+{
+  int ret;
+  gpgrt_poll_t fds[3];
+  char buffer[16];
+  size_t used, nwritten;
+  int c;
+
+  memset (fds, 0, sizeof fds);
+  fds[0].stream = test_stdin;
+  fds[0].want_read = 1;
+  fds[1].stream = test_stdout;
+  fds[1].want_write = 1;
+  /* FIXME: We don't use the next stream at all.  */
+  fds[2].stream = test_stderr;
+  fds[2].want_write = 1;
+  fds[2].ignore = 1;
+
+
+  used = 0;
+  while (used || !fds[0].ignore)
+    {
+      ret = gpgrt_poll (fds, DIM(fds), -1);
+      if (ret == -1)
+        {
+          fail ("gpgrt_poll failed: %s\n", strerror (errno));
+          continue;
+        }
+      if (!ret)
+        {
+          fail ("gpgrt_poll unexpectedly timed out\n");
+          continue;
+        }
+      show ("gpgrt_poll detected %d events\n", ret);
+      if (fds[0].got_read)
+        {
+          /* Read from the producer.  */
+          for (;;)
+            {
+              c = es_fgetc (fds[0].stream);
+              if (c == EOF)
+                {
+                  if (es_feof (fds[0].stream))
+                    {
+                      show ("reading '%s': EOF\n", peer_stdin.name);
+                      fds[0].ignore = 1; /* Not anymore needed.  */
+                      peer_stdin.stop_me = 1; /* Tell the thread to stop.  */
+                    }
+                  else if (es_ferror (fds[0].stream))
+                    {
+                      fail ("error reading '%s': %s\n",
+                            peer_stdin.name, strerror (errno));
+                      fds[0].ignore = 1;    /* Disable.  */
+                      peer_stdin.stop_me = 1; /* Tell the thread to stop.  */
+                    }
+                  else
+                    show ("reading '%s': EAGAIN\n", peer_stdin.name);
+                  break;
+                }
+              else
+                {
+                  if (used <= sizeof buffer -1)
+                    buffer[used++] = c;
+                  if (used == sizeof buffer)
+                    {
+                      show ("throttling reading from '%s'\n", peer_stdin.name);
+                      fds[0].ignore = 1;
+                      break;
+                    }
+                }
+            }
+          show ("read from '%s': %zu bytes\n", peer_stdin.name, used);
+          if (used)
+            fds[1].ignore = 0; /* Data to send.  */
+        }
+      if (fds[1].got_write)
+        {
+          if (used)
+            {
+              ret = es_write (fds[1].stream, buffer, used, &nwritten);
+              show ("result for writing to '%s': ret=%d, n=%zu, nwritten=%zu\n",
+                    peer_stdout.name, ret, used, nwritten);
+              if (!ret)
+                {
+                  assert (nwritten <= used);
+                  memmove (buffer, buffer + nwritten, nwritten);
+                  used -= nwritten;
+                }
+              ret = es_fflush (fds[1].stream);
+              if (ret)
+                fail ("Flushing for '%s' failed: %s\n",
+                      peer_stdout.name, strerror (errno));
+            }
+          if (!used)
+            fds[1].ignore = 1; /* No need to send data.  */
+        }
+
+      if (used < sizeof buffer / 2 && !peer_stdin.stop_me && fds[0].ignore)
+        {
+          show ("accelerate reading from '%s'\n", peer_stdin.name);
+          fds[0].ignore = 0;
+        }
+    }
+}
+
+
+int
+main (int argc, char **argv)
+{
+  int last_argc = -1;
+
+  if (argc)
+    {
+      argc--; argv++;
+    }
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--help"))
+        {
+          puts (
+"usage: ./t-poll [options]\n"
+"\n"
+"Options:\n"
+"  --verbose      Show what is going on\n"
+"  --debug        Flyswatter\n"
+);
+          exit (0);
+        }
+      if (!strcmp (*argv, "--verbose"))
+        {
+          verbose = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--debug"))
+        {
+          verbose = debug = 1;
+          argc--; argv++;
+        }
+    }
+
+  if (!gpg_error_check_version (GPG_ERROR_VERSION))
+    {
+      die ("gpg_error_check_version returned an error");
+      errorcount++;
+    }
+
+  peer_stdin.name  = "stdin producer";
+  create_pipe (&test_stdin, &peer_stdin.stream);
+  peer_stdout.name = "stdout consumer";
+  create_pipe (&peer_stdout.stream, &test_stdout);
+  peer_stderr.name = "stderr consumer";
+  create_pipe (&peer_stderr.stream, &test_stderr);
+
+  if (es_set_nonblock (test_stdin, 1))
+    fail ("error setting test_stdin to nonblock: %s\n", strerror (errno));
+  if (es_set_nonblock (test_stdout, 1))
+    fail ("error setting test_stdout to nonblock: %s\n", strerror (errno));
+  if (es_set_nonblock (test_stderr, 1))
+    fail ("error setting test_stderr to nonblock: %s\n", strerror (errno));
+
+  launch_thread (producer_thread, &peer_stdin );
+  launch_thread (consumer_thread, &peer_stdout);
+  launch_thread (consumer_thread, &peer_stderr);
+  test_poll ();
+  show ("Waiting for threads to terminate...\n");
+  es_fclose (test_stdin);
+  es_fclose (test_stdout);
+  es_fclose (test_stderr);
+  peer_stdin.stop_me = 1;
+  peer_stdout.stop_me = 1;
+  peer_stderr.stop_me = 1;
+  join_thread (&peer_stdin);
+  join_thread (&peer_stdout);
+  join_thread (&peer_stderr);
+
+  return errorcount ? 1 : 0;
+}

commit 61d832c53b7db5367a5542347e3454c882d0bf28
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Sep 24 12:22:22 2015 +0200

    estream: Replace indicator help functions to ease code reading.
    
    * src/estream.c (es_set_indicators, es_get_indicator): Remove and
    change callers to set/get indicators directly.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/estream.c b/src/estream.c
index 1175ac8..7d12e36 100644
--- a/src/estream.c
+++ b/src/estream.c
@@ -2026,7 +2026,7 @@ check_pending_fbf (estream_t _GPGRT__RESTRICT stream)
 
   if (stream->data_offset == stream->data_len)
     {
-      /* Nothing more to read in current container, check whetehr it
+      /* Nothing more to read in current container, check whether it
          would be possible to fill the container with new data.  */
       if (!(*func_read) (stream->intern->cookie, buffer, 0))
         return 1; /* Pending bytes.  */
@@ -2596,7 +2596,7 @@ doreadline (estream_t _GPGRT__RESTRICT stream, size_t max_length,
 }
 
 
-/* Output fucntion used for estream_format.  */
+/* Output function used by estream_format.  */
 static int
 print_writer (void *outfncarg, const char *buf, size_t buflen)
 {
@@ -2626,30 +2626,6 @@ es_print (estream_t _GPGRT__RESTRICT stream,
 }
 
 
-static void
-es_set_indicators (estream_t stream, int ind_err, int ind_eof)
-{
-  if (ind_err != -1)
-    stream->intern->indicators.err = ind_err ? 1 : 0;
-  if (ind_eof != -1)
-    stream->intern->indicators.eof = ind_eof ? 1 : 0;
-}
-
-
-static int
-es_get_indicator (estream_t stream, int ind_err, int ind_eof)
-{
-  int ret = 0;
-
-  if (ind_err)
-    ret = stream->intern->indicators.err;
-  else if (ind_eof)
-    ret = stream->intern->indicators.eof;
-
-  return ret;
-}
-
-
 static int
 es_set_buffering (estream_t _GPGRT__RESTRICT stream,
 		  char *_GPGRT__RESTRICT buffer, int mode, size_t size)
@@ -2666,7 +2642,7 @@ es_set_buffering (estream_t _GPGRT__RESTRICT stream,
   else
     es_empty (stream);
 
-  es_set_indicators (stream, -1, 0);
+  stream->intern->indicators.eof = 0;
 
   /* Free old buffer in case that was allocated by this function.  */
   if (stream->intern->deallocate_buffer)
@@ -2727,7 +2703,8 @@ es_offset_calculate (estream_t stream)
 
 
 static void
-es_opaque_ctrl (estream_t _GPGRT__RESTRICT stream, void *_GPGRT__RESTRICT opaque_new,
+es_opaque_ctrl (estream_t _GPGRT__RESTRICT stream,
+                void *_GPGRT__RESTRICT opaque_new,
 		void **_GPGRT__RESTRICT opaque_old)
 {
   if (opaque_old)
@@ -2897,7 +2874,8 @@ _gpgrt_fopenmem_init (size_t memlimit, const char *_GPGRT__RESTRICT mode,
       else
         {
           es_seek (stream, 0L, SEEK_SET, NULL);
-          es_set_indicators (stream, 0, 0);
+          stream->intern->indicators.eof = 0;
+          stream->intern->indicators.err = 0;
         }
     }
   return stream;
@@ -3507,7 +3485,7 @@ _gpgrt__pending (estream_t stream)
 int
 _gpgrt_feof_unlocked (estream_t stream)
 {
-  return es_get_indicator (stream, 0, 1);
+  return stream->intern->indicators.eof;
 }
 
 
@@ -3527,7 +3505,7 @@ _gpgrt_feof (estream_t stream)
 int
 _gpgrt_ferror_unlocked (estream_t stream)
 {
-  return es_get_indicator (stream, 1, 0);
+  return stream->intern->indicators.err;
 }
 
 
@@ -3547,7 +3525,8 @@ _gpgrt_ferror (estream_t stream)
 void
 _gpgrt_clearerr_unlocked (estream_t stream)
 {
-  es_set_indicators (stream, 0, 0);
+  stream->intern->indicators.eof = 0;
+  stream->intern->indicators.err = 0;
 }
 
 
@@ -3664,7 +3643,8 @@ _gpgrt_rewind (estream_t stream)
 {
   lock_stream (stream);
   es_seek (stream, 0L, SEEK_SET, NULL);
-  es_set_indicators (stream, 0, -1);
+  /* Note that es_seek already cleared the EOF flag.  */
+  stream->intern->indicators.err = 0;
   unlock_stream (stream);
 }
 

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

Summary of changes:
 NEWS                 |  18 ++-
 configure.ac         |   2 +-
 doc/errorref.txt     |   8 +-
 src/err-codes.h.in   |   3 +-
 src/estream.c        | 422 ++++++++++++++++++++++++++++++++++++++++++++++-----
 src/gpg-error.def.in |   4 +
 src/gpg-error.h.in   |  33 ++++
 src/gpg-error.vers   |   3 +
 src/gpgrt-int.h      |   4 +
 src/visibility.c     |  18 +++
 src/visibility.h     |   6 +
 tests/Makefile.am    |   3 +-
 tests/t-common.h     |   3 +
 tests/t-poll.c       | 383 ++++++++++++++++++++++++++++++++++++++++++++++
 14 files changed, 865 insertions(+), 45 deletions(-)
 create mode 100644 tests/t-poll.c


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




More information about the Gnupg-commits mailing list