build: Require latest released libraries
[gnupg.git] / common / iobuf.c
index 41b9d18..f3d67b4 100644 (file)
@@ -170,10 +170,10 @@ static int translate_file_handle (int fd, int for_write);
    underlying file; it just causes any data buffered at the filter A
    to be sent to A's filter function.
 
-   If A is a IOBUF_TEMP filter, then this also enlarges the buffer by
-   IOBUF_BUFFER_SIZE.
+   If A is a IOBUF_OUTPUT_TEMP filter, then this also enlarges the
+   buffer by IOBUF_BUFFER_SIZE.
 
-   May only be called on an IOBUF_OUTPUT or IOBUF_TEMP filters.  */
+   May only be called on an IOBUF_OUTPUT or IOBUF_OUTPUT_TEMP filters.  */
 static int filter_flush (iobuf_t a);
 
 
@@ -267,6 +267,7 @@ direct_open (const char *fname, const char *mode, int mode700)
   unsigned long da, cd, sm;
   HANDLE hfile;
 
+  (void)mode700;
   /* Note, that we do not handle all mode combinations */
 
   /* According to the ReactOS source it seems that open() of the
@@ -577,7 +578,7 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
     }
   else if (control == IOBUFCTRL_DESC)
     {
-      *(char **) buf = "file_filter(fd)";
+      mem2str (buf, "file_filter(fd)", *ret_len);
     }
   else if (control == IOBUFCTRL_FREE)
     {
@@ -588,7 +589,6 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
          if (!a->keep_open)
            fd_cache_close (a->no_cache ? NULL : a->fname, f);
        }
-      f = GNUPG_INVALID_FD;
       xfree (a); /* We can free our context now. */
     }
 
@@ -667,7 +667,7 @@ file_es_filter (void *opaque, int control, iobuf_t chain, byte * buf,
     }
   else if (control == IOBUFCTRL_DESC)
     {
-      *(char **) buf = "estream_filter";
+      mem2str (buf, "estream_filter", *ret_len);
     }
   else if (control == IOBUFCTRL_FREE)
     {
@@ -765,7 +765,7 @@ sock_filter (void *opaque, int control, iobuf_t chain, byte * buf,
     }
   else if (control == IOBUFCTRL_DESC)
     {
-      *(char **) buf = "sock_filter";
+      mem2str (buf, "sock_filter", *ret_len);
     }
   else if (control == IOBUFCTRL_FREE)
     {
@@ -993,7 +993,7 @@ block_filter (void *opaque, int control, iobuf_t chain, byte * buffer,
     }
   else if (control == IOBUFCTRL_DESC)
     {
-      *(char **) buf = "block_filter";
+      mem2str (buf, "block_filter", *ret_len);
     }
   else if (control == IOBUFCTRL_FREE)
     {
@@ -1057,19 +1057,23 @@ block_filter (void *opaque, int control, iobuf_t chain, byte * buffer,
   return rc;
 }
 
+#define MAX_IOBUF_DESC 32
+/*
+ * Fill the buffer by the description of iobuf A.
+ * The buffer size should be MAX_IOBUF_DESC (or larger).
+ * Returns BUF as (const char *).
+ */
 static const char *
-iobuf_desc (iobuf_t a)
+iobuf_desc (iobuf_t a, byte *buf)
 {
-  size_t dummy_len = 0;
-  const char *desc = "?";
+  size_t len = MAX_IOBUF_DESC;
 
   if (! a || ! a->filter)
-    return desc;
-
-  a->filter (a->filter_ov, IOBUFCTRL_DESC, NULL,
-            (byte *) & desc, &dummy_len);
+    memcpy (buf, "?", 2);
+  else
+    a->filter (a->filter_ov, IOBUFCTRL_DESC, NULL, buf, &len);
 
-  return desc;
+  return buf;
 }
 
 static void
@@ -1079,9 +1083,10 @@ print_chain (iobuf_t a)
     return;
   for (; a; a = a->chain)
     {
+      byte desc[MAX_IOBUF_DESC];
 
       log_debug ("iobuf chain: %d.%d '%s' filter_eof=%d start=%d len=%d\n",
-                a->no, a->subno, iobuf_desc (a), a->filter_eof,
+                a->no, a->subno, iobuf_desc (a, desc), a->filter_eof,
                 (int) a->d.start, (int) a->d.len);
     }
 }
@@ -1099,7 +1104,8 @@ iobuf_alloc (int use, size_t bufsize)
   iobuf_t a;
   static int number = 0;
 
-  assert (use == IOBUF_INPUT || use == IOBUF_OUTPUT || use == IOBUF_TEMP);
+  assert (use == IOBUF_INPUT || use == IOBUF_INPUT_TEMP
+         || use == IOBUF_OUTPUT || use == IOBUF_OUTPUT_TEMP);
   if (bufsize == 0)
     {
       log_bug ("iobuf_alloc() passed a bufsize of 0!\n");
@@ -1125,6 +1131,7 @@ iobuf_close (iobuf_t a)
 
   for (; a; a = a_chain)
     {
+      byte desc[MAX_IOBUF_DESC];
       int rc2 = 0;
 
       a_chain = a->chain;
@@ -1134,13 +1141,13 @@ iobuf_close (iobuf_t a)
 
       if (DBG_IOBUF)
        log_debug ("iobuf-%d.%d: close '%s'\n",
-                  a->no, a->subno, iobuf_desc (a));
+                  a->no, a->subno, iobuf_desc (a, desc));
 
       if (a->filter && (rc2 = a->filter (a->filter_ov, IOBUFCTRL_FREE,
                                         a->chain, NULL, &dummy_len)))
        log_error ("IOBUFCTRL_FREE failed on close: %s\n", gpg_strerror (rc));
       if (! rc && rc2)
-       /* Whoops!  An error occured.  Save it in RC if we haven't
+       /* Whoops!  An error occurred.  Save it in RC if we haven't
           already recorded an error.  */
        rc = rc2;
 
@@ -1210,7 +1217,7 @@ iobuf_cancel (iobuf_t a)
 iobuf_t
 iobuf_temp (void)
 {
-  return iobuf_alloc (IOBUF_TEMP, IOBUF_BUFFER_SIZE);
+  return iobuf_alloc (IOBUF_OUTPUT_TEMP, IOBUF_BUFFER_SIZE);
 }
 
 iobuf_t
@@ -1219,7 +1226,8 @@ iobuf_temp_with_content (const char *buffer, size_t length)
   iobuf_t a;
   int i;
 
-  a = iobuf_alloc (IOBUF_INPUT, length);
+  a = iobuf_alloc (IOBUF_INPUT_TEMP, length);
+  assert (length == a->d.size);
   /* memcpy (a->d.buf, buffer, length); */
   for (i=0; i < length; i++)
     a->d.buf[i] = buffer[i];
@@ -1273,6 +1281,9 @@ do_open (const char *fname, int special_filenames,
   size_t len = 0;
   int print_only = 0;
   int fd;
+  byte desc[MAX_IOBUF_DESC];
+
+  assert (use == IOBUF_INPUT || use == IOBUF_OUTPUT);
 
   if (special_filenames
       /* NULL or '-'.  */
@@ -1317,7 +1328,7 @@ do_open (const char *fname, int special_filenames,
   file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
   if (DBG_IOBUF)
     log_debug ("iobuf-%d.%d: open '%s' desc=%s fd=%d\n",
-              a->no, a->subno, fname, iobuf_desc (a), FD2INT (fcx->fp));
+              a->no, a->subno, fname, iobuf_desc (a, desc), FD2INT (fcx->fp));
 
   return a;
 }
@@ -1387,7 +1398,7 @@ iobuf_esopen (estream_t estream, const char *mode, int keep_open)
 {
   iobuf_t a;
   file_es_filter_ctx_t *fcx;
-  size_t len;
+  size_t len = 0;
 
   a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT,
                   IOBUF_BUFFER_SIZE);
@@ -1435,6 +1446,8 @@ iobuf_sockopen (int fd, const char *mode)
 int
 iobuf_ioctl (iobuf_t a, iobuf_ioctl_t cmd, int intval, void *ptrval)
 {
+  byte desc[MAX_IOBUF_DESC];
+
   if (cmd == IOBUF_IOCTL_KEEP_OPEN)
     {
       /* Keep system filepointer/descriptor open.  This was used in
@@ -1442,7 +1455,7 @@ iobuf_ioctl (iobuf_t a, iobuf_ioctl_t cmd, int intval, void *ptrval)
          anymore.  */
       if (DBG_IOBUF)
        log_debug ("iobuf-%d.%d: ioctl '%s' keep_open=%d\n",
-                  a ? a->no : -1, a ? a->subno : -1, iobuf_desc (a),
+                  a ? a->no : -1, a ? a->subno : -1, iobuf_desc (a, desc),
                   intval);
       for (; a; a = a->chain)
        if (!a->chain && a->filter == file_filter)
@@ -1476,7 +1489,7 @@ iobuf_ioctl (iobuf_t a, iobuf_ioctl_t cmd, int intval, void *ptrval)
     {
       if (DBG_IOBUF)
        log_debug ("iobuf-%d.%d: ioctl '%s' no_cache=%d\n",
-                  a ? a->no : -1, a ? a->subno : -1, iobuf_desc (a),
+                  a ? a->no : -1, a ? a->subno : -1, iobuf_desc (a, desc),
                   intval);
       for (; a; a = a->chain)
        if (!a->chain && a->filter == file_filter)
@@ -1502,11 +1515,11 @@ iobuf_ioctl (iobuf_t a, iobuf_ioctl_t cmd, int intval, void *ptrval)
         log_debug ("iobuf-*.*: ioctl '%s' fsync\n",
                    ptrval? (const char*)ptrval:"<null>");
 
-       if (!a && !intval && ptrval)
-         {
-           return fd_cache_synchronize (ptrval);
-         }
-      }
+      if (!a && !intval && ptrval)
+        {
+          return fd_cache_synchronize (ptrval);
+        }
+    }
 
 
   return -1;
@@ -1600,13 +1613,13 @@ iobuf_push_filter2 (iobuf_t a,
   a->filter_ov = NULL;
   a->filter_ov_owner = 0;
   a->filter_eof = 0;
-  if (a->use == IOBUF_TEMP)
+  if (a->use == IOBUF_OUTPUT_TEMP)
     /* A TEMP filter buffers any data sent to it; it does not forward
        any data down the pipeline.  If we add a new filter to the
        pipeline, it shouldn't also buffer data.  It should send it
        downstream to be buffered.  Thus, the correct type for a filter
-       added in front of an IOBUF_TEMP filter is IOBUF_OUPUT, not
-       IOBUF_TEMP.  */
+       added in front of an IOBUF_OUTPUT_TEMP filter is IOBUF_OUPUT, not
+       IOBUF_OUTPUT_TEMP.  */
     {
       a->use = IOBUF_OUTPUT;
 
@@ -1616,6 +1629,12 @@ iobuf_push_filter2 (iobuf_t a,
         size.  */
       a->d.size = IOBUF_BUFFER_SIZE;
     }
+  else if (a->use == IOBUF_INPUT_TEMP)
+    /* Same idea as above.  */
+    {
+      a->use = IOBUF_INPUT;
+      a->d.size = IOBUF_BUFFER_SIZE;
+    }
 
   /* The new filter (A) gets a new buffer.
 
@@ -1648,8 +1667,9 @@ iobuf_push_filter2 (iobuf_t a,
 
   if (DBG_IOBUF)
     {
+      byte desc[MAX_IOBUF_DESC];
       log_debug ("iobuf-%d.%d: push '%s'\n",
-                a->no, a->subno, iobuf_desc (a));
+                a->no, a->subno, iobuf_desc (a, desc));
       print_chain (a);
     }
 
@@ -1663,18 +1683,25 @@ iobuf_push_filter2 (iobuf_t a,
 /****************
  * Remove an i/o filter.
  */
-static int
-pop_filter (iobuf_t a, int (*f) (void *opaque, int control,
-                              iobuf_t chain, byte * buf, size_t * len),
-           void *ov)
+int
+iobuf_pop_filter (iobuf_t a, int (*f) (void *opaque, int control,
+                                       iobuf_t chain, byte * buf, size_t * len),
+                  void *ov)
 {
   iobuf_t b;
   size_t dummy_len = 0;
   int rc = 0;
+  byte desc[MAX_IOBUF_DESC];
 
   if (DBG_IOBUF)
     log_debug ("iobuf-%d.%d: pop '%s'\n",
-              a->no, a->subno, iobuf_desc (a));
+              a->no, a->subno, iobuf_desc (a, desc));
+  if (a->use == IOBUF_INPUT_TEMP || a->use == IOBUF_OUTPUT_TEMP)
+    {
+      /* This should be the last filter in the pipeline.  */
+      assert (! a->chain);
+      return 0;
+    }
   if (!a->filter)
     {                          /* this is simple */
       b = a->chain;
@@ -1689,12 +1716,13 @@ pop_filter (iobuf_t a, int (*f) (void *opaque, int control,
     if (b->filter == f && (!ov || b->filter_ov == ov))
       break;
   if (!b)
-    log_bug ("pop_filter(): filter function not found\n");
+    log_bug ("iobuf_pop_filter(): filter function not found\n");
 
   /* flush this stream if it is an output stream */
   if (a->use == IOBUF_OUTPUT && (rc = filter_flush (b)))
     {
-      log_error ("filter_flush failed in pop_filter: %s\n", gpg_strerror (rc));
+      log_error ("filter_flush failed in iobuf_pop_filter: %s\n",
+                 gpg_strerror (rc));
       return rc;
     }
   /* and tell the filter to free it self */
@@ -1756,6 +1784,11 @@ underflow (iobuf_t a, int clear_pending_eof)
               (int) a->d.size, (int) (a->d.len - a->d.start),
               (int) (a->d.size - (a->d.len - a->d.start)));
 
+  if (a->use == IOBUF_INPUT_TEMP)
+    /* By definition, there isn't more data to read into the
+       buffer.  */
+    return -1;
+
   assert (a->use == IOBUF_INPUT);
 
   /* If there is still some buffered data, then move it to the start
@@ -1904,7 +1937,7 @@ filter_flush (iobuf_t a)
   size_t len;
   int rc;
 
-  if (a->use == IOBUF_TEMP)
+  if (a->use == IOBUF_OUTPUT_TEMP)
     {                          /* increase the temp buffer */
       size_t newsize = a->d.size + IOBUF_BUFFER_SIZE;
 
@@ -1940,7 +1973,7 @@ iobuf_readbyte (iobuf_t a)
 {
   int c;
 
-  if (a->use != IOBUF_INPUT)
+  if (a->use == IOBUF_OUTPUT || a->use == IOBUF_OUTPUT_TEMP)
     {
       log_bug ("iobuf_readbyte called on a non-INPUT pipeline!\n");
       return -1;
@@ -1974,12 +2007,11 @@ iobuf_read (iobuf_t a, void *buffer, unsigned int buflen)
   unsigned char *buf = (unsigned char *)buffer;
   int c, n;
 
-  if (a->use != IOBUF_INPUT)
+  if (a->use == IOBUF_OUTPUT || a->use == IOBUF_OUTPUT_TEMP)
     {
       log_bug ("iobuf_read called on a non-INPUT pipeline!\n");
       return -1;
     }
-  assert (a->use == IOBUF_INPUT);
 
   if (a->nlimit)
     {
@@ -1992,10 +2024,12 @@ iobuf_read (iobuf_t a, void *buffer, unsigned int buflen)
                return -1;      /* eof */
              break;
            }
-         else if (buf)
-           *buf = c;
+
          if (buf)
-           buf++;
+           {
+             *buf = c;
+             buf++;
+           }
        }
       return n;
     }
@@ -2046,7 +2080,7 @@ iobuf_peek (iobuf_t a, byte * buf, unsigned buflen)
   int n = 0;
 
   assert (buflen > 0);
-  assert (a->use == IOBUF_INPUT);
+  assert (a->use == IOBUF_INPUT || a->use == IOBUF_INPUT_TEMP);
 
   if (buflen > a->d.size)
     /* We can't peek more than we can buffer.  */
@@ -2087,7 +2121,7 @@ iobuf_writebyte (iobuf_t a, unsigned int c)
 {
   int rc;
 
-  if (a->use == IOBUF_INPUT)
+  if (a->use == IOBUF_INPUT || a->use == IOBUF_INPUT_TEMP)
     {
       log_bug ("iobuf_writebyte called on an input pipeline!\n");
       return -1;
@@ -2109,7 +2143,7 @@ iobuf_write (iobuf_t a, const void *buffer, unsigned int buflen)
   const unsigned char *buf = (const unsigned char *)buffer;
   int rc;
 
-  if (a->use == IOBUF_INPUT)
+  if (a->use == IOBUF_INPUT || a->use == IOBUF_INPUT_TEMP)
     {
       log_bug ("iobuf_write called on an input pipeline!\n");
       return -1;
@@ -2142,7 +2176,7 @@ iobuf_write (iobuf_t a, const void *buffer, unsigned int buflen)
 int
 iobuf_writestr (iobuf_t a, const char *buf)
 {
-  if (a->use == IOBUF_INPUT)
+  if (a->use == IOBUF_INPUT || a->use == IOBUF_INPUT_TEMP)
     {
       log_bug ("iobuf_writestr called on an input pipeline!\n");
       return -1;
@@ -2156,8 +2190,8 @@ iobuf_writestr (iobuf_t a, const char *buf)
 int
 iobuf_write_temp (iobuf_t dest, iobuf_t source)
 {
-  assert (source->use == IOBUF_OUTPUT || source->use == IOBUF_TEMP);
-  assert (dest->use == IOBUF_OUTPUT || dest->use == IOBUF_TEMP);
+  assert (source->use == IOBUF_OUTPUT || source->use == IOBUF_OUTPUT_TEMP);
+  assert (dest->use == IOBUF_OUTPUT || dest->use == IOBUF_OUTPUT_TEMP);
 
   iobuf_flush_temp (source);
   return iobuf_write (dest, source->d.buf, source->d.len);
@@ -2166,6 +2200,7 @@ iobuf_write_temp (iobuf_t dest, iobuf_t source)
 size_t
 iobuf_temp_to_buffer (iobuf_t a, byte * buffer, size_t buflen)
 {
+  byte desc[MAX_IOBUF_DESC];
   size_t n;
 
   while (1)
@@ -2173,7 +2208,7 @@ iobuf_temp_to_buffer (iobuf_t a, byte * buffer, size_t buflen)
       int rc = filter_flush (a);
       if (rc)
        log_bug ("Flushing iobuf %d.%d (%s) from iobuf_temp_to_buffer failed.  Ignoring.\n",
-                a->no, a->subno, iobuf_desc (a));
+                a->no, a->subno, iobuf_desc (a, desc));
       if (! a->chain)
        break;
       a = a->chain;
@@ -2186,14 +2221,55 @@ iobuf_temp_to_buffer (iobuf_t a, byte * buffer, size_t buflen)
   return n;
 }
 
+/* Copies the data from the input iobuf SOURCE to the output iobuf
+   DEST until either an error is encountered or EOF is reached.
+   Returns the number of bytes copies.  */
+size_t
+iobuf_copy (iobuf_t dest, iobuf_t source)
+{
+  char *temp;
+  /* Use a 32 KB buffer.  */
+  const size_t temp_size = 32 * 1024;
+
+  size_t nread;
+  size_t nwrote = 0;
+  int err;
+
+  assert (source->use == IOBUF_INPUT || source->use == IOBUF_INPUT_TEMP);
+  assert (dest->use == IOBUF_OUTPUT || source->use == IOBUF_OUTPUT_TEMP);
+
+  if (iobuf_error (dest))
+    return -1;
+
+  temp = xmalloc (temp_size);
+  while (1)
+    {
+      nread = iobuf_read (source, temp, temp_size);
+      if (nread == -1)
+        /* EOF.  */
+        break;
+
+      err = iobuf_write (dest, temp, nread);
+      if (err)
+        break;
+      nwrote += nread;
+    }
+
+  /* Burn the buffer.  */
+  wipememory (temp, sizeof (temp));
+  xfree (temp);
+
+  return nwrote;
+}
+
 
 void
 iobuf_flush_temp (iobuf_t temp)
 {
-  if (temp->use == IOBUF_INPUT)
-    log_bug ("iobuf_writestr called on an input pipeline!\n");
+  if (temp->use == IOBUF_INPUT || temp->use == IOBUF_INPUT_TEMP)
+    log_bug ("iobuf_flush_temp called on an input pipeline!\n");
   while (temp->chain)
-    pop_filter (temp, temp->filter, NULL);
+    iobuf_pop_filter (temp, temp->filter, NULL);
 }
 
 
@@ -2214,86 +2290,93 @@ iobuf_set_limit (iobuf_t a, off_t nlimit)
 off_t
 iobuf_get_filelength (iobuf_t a, int *overflow)
 {
-  struct stat st;
-
   if (overflow)
     *overflow = 0;
 
   /* Hmmm: file_filter may have already been removed */
-  for ( ; a; a = a->chain )
-    if ( !a->chain && a->filter == file_filter )
-      {
-        file_filter_ctx_t *b = a->filter_ov;
-        gnupg_fd_t fp = b->fp;
+  for ( ; a->chain; a = a->chain )
+    ;
+
+  if (a->filter != file_filter)
+    return 0;
+
+  {
+    file_filter_ctx_t *b = a->filter_ov;
+    gnupg_fd_t fp = b->fp;
 
 #if defined(HAVE_W32_SYSTEM)
-        ulong size;
-        static int (* __stdcall get_file_size_ex) (void *handle,
-                                                   LARGE_INTEGER *r_size);
-        static int get_file_size_ex_initialized;
-
-        if (!get_file_size_ex_initialized)
-          {
-            void *handle;
-
-            handle = dlopen ("kernel32.dll", RTLD_LAZY);
-            if (handle)
-              {
-                get_file_size_ex = dlsym (handle, "GetFileSizeEx");
-                if (!get_file_size_ex)
-                  dlclose (handle);
-              }
-            get_file_size_ex_initialized = 1;
-          }
-
-        if (get_file_size_ex)
-          {
-            /* This is a newer system with GetFileSizeEx; we use this
-               then because it seem that GetFileSize won't return a
-               proper error in case a file is larger than 4GB. */
-            LARGE_INTEGER exsize;
-
-            if (get_file_size_ex (fp, &exsize))
-              {
-                if (!exsize.u.HighPart)
-                  return exsize.u.LowPart;
-                if (overflow)
-                  *overflow = 1;
-                return 0;
-              }
-          }
-        else
-          {
-            if ((size=GetFileSize (fp, NULL)) != 0xffffffff)
-              return size;
-          }
-        log_error ("GetFileSize for handle %p failed: %s\n",
-                   fp, w32_strerror (0));
-#else
-        if ( !fstat (FD2INT (fp), &st) )
-          return st.st_size;
-        log_error("fstat() failed: %s\n", strerror(errno) );
-#endif
-        break/*the for loop*/;
+    ulong size;
+    static int (* __stdcall get_file_size_ex) (void *handle,
+                                              LARGE_INTEGER *r_size);
+    static int get_file_size_ex_initialized;
+
+    if (!get_file_size_ex_initialized)
+      {
+       void *handle;
+
+       handle = dlopen ("kernel32.dll", RTLD_LAZY);
+       if (handle)
+         {
+           get_file_size_ex = dlsym (handle, "GetFileSizeEx");
+           if (!get_file_size_ex)
+             dlclose (handle);
+         }
+       get_file_size_ex_initialized = 1;
       }
 
-    return 0;
+    if (get_file_size_ex)
+      {
+       /* This is a newer system with GetFileSizeEx; we use this
+          then because it seem that GetFileSize won't return a
+          proper error in case a file is larger than 4GB. */
+       LARGE_INTEGER exsize;
+
+       if (get_file_size_ex (fp, &exsize))
+         {
+           if (!exsize.u.HighPart)
+             return exsize.u.LowPart;
+           if (overflow)
+             *overflow = 1;
+           return 0;
+         }
+      }
+    else
+      {
+       if ((size=GetFileSize (fp, NULL)) != 0xffffffff)
+         return size;
+      }
+    log_error ("GetFileSize for handle %p failed: %s\n",
+              fp, w32_strerror (0));
+#else /*!HAVE_W32_SYSTEM*/
+    {
+      struct stat st;
+
+      if ( !fstat (FD2INT (fp), &st) )
+        return st.st_size;
+      log_error("fstat() failed: %s\n", strerror(errno) );
+    }
+#endif /*!HAVE_W32_SYSTEM*/
+  }
+
+  return 0;
 }
 
 
 int
 iobuf_get_fd (iobuf_t a)
 {
-  for ( ; a; a = a->chain )
-    if (!a->chain && a->filter == file_filter)
-      {
-        file_filter_ctx_t *b = a->filter_ov;
-        gnupg_fd_t fp = b->fp;
+  for (; a->chain; a = a->chain)
+    ;
 
-        return FD2INT (fp);
-      }
+  if (a->filter != file_filter)
+    return -1;
 
-  return -1;
+  {
+    file_filter_ctx_t *b = a->filter_ov;
+    gnupg_fd_t fp = b->fp;
+
+    return FD2INT (fp);
+  }
 }
 
 
@@ -2339,18 +2422,17 @@ iobuf_seek (iobuf_t a, off_t newpos)
 {
   file_filter_ctx_t *b = NULL;
 
-  if (a->use != IOBUF_TEMP)
+  if (a->use == IOBUF_OUTPUT || a->use == IOBUF_INPUT)
     {
-      for (; a; a = a->chain)
-       {
-         if (!a->chain && a->filter == file_filter)
-           {
-             b = a->filter_ov;
-             break;
-           }
-       }
-      if (!a)
+      /* Find the last filter in the pipeline.  */
+      for (; a->chain; a = a->chain)
+       ;
+
+      if (a->filter != file_filter)
        return -1;
+
+      b = a->filter_ov;
+
 #ifdef HAVE_W32_SYSTEM
       if (SetFilePointer (b->fp, newpos, NULL, FILE_BEGIN) == 0xffffffff)
        {
@@ -2365,10 +2447,9 @@ iobuf_seek (iobuf_t a, off_t newpos)
          return -1;
        }
 #endif
+      /* Discard the buffer it is not a temp stream.  */
+      a->d.len = 0;
     }
-  /* Discard the buffer unless it is a temp stream.  */
-  if (a->use != IOBUF_TEMP)
-    a->d.len = 0;
   a->d.start = 0;
   a->nbytes = 0;
   a->nlimit = 0;
@@ -2387,18 +2468,14 @@ iobuf_seek (iobuf_t a, off_t newpos)
 
   /* remove filters, but the last */
   if (a->chain)
-    log_debug ("pop_filter called in iobuf_seek - please report\n");
+    log_debug ("iobuf_pop_filter called in iobuf_seek - please report\n");
   while (a->chain)
-    pop_filter (a, a->filter, NULL);
+    iobuf_pop_filter (a, a->filter, NULL);
 
   return 0;
 }
 
 
-
-
-
-
 const char *
 iobuf_get_real_fname (iobuf_t a)
 {
@@ -2416,7 +2493,6 @@ iobuf_get_real_fname (iobuf_t a)
   return NULL;
 }
 
-
 const char *
 iobuf_get_fname (iobuf_t a)
 {
@@ -2440,33 +2516,35 @@ iobuf_get_fname_nonnull (iobuf_t a)
 
 
 /****************
- * enable partial block mode as described in the OpenPGP draft.
- * LEN is the first length byte on read, but ignored on writes.
+ * Enable or disable partial body length mode (RFC 4880 4.2.2.4).
+ *
+ * If LEN is 0, this disables partial block mode by popping the
+ * partial body length filter, which which must be the most recently
+ * added filter.
+ *
+ * If LEN is non-zero, it pushes a partial body length filter.  If
+ * this is a read filter, LEN must be the length byte from the first
+ * chunk and A should be position just after this first partial body
+ * length header.
  */
 void
-iobuf_set_partial_block_mode (iobuf_t a, size_t len)
+iobuf_set_partial_body_length_mode (iobuf_t a, size_t len)
 {
-  block_filter_ctx_t *ctx = xcalloc (1, sizeof *ctx);
-
-  assert (a->use == IOBUF_INPUT || a->use == IOBUF_OUTPUT);
-  ctx->use = a->use;
   if (!len)
+    /* Disable partial body length mode.  */
     {
       if (a->use == IOBUF_INPUT)
-       log_debug ("pop_filter called in set_partial_block_mode"
+       log_debug ("iobuf_pop_filter called in set_partial_block_mode"
                   " - please report\n");
-      /* XXX: This pop_filter doesn't make sense.  Since we haven't
-        actually added the filter to the pipeline yet, why are we
-        popping anything?  Moreover, since we don't report an error,
-        the caller won't directly see an error.  I think that it
-        would be better to push the filter and set a->error to
-        GPG_ERR_BAD_DATA, but Werner thinks it's impossible for len
-        to be 0 (but he doesn't want to remove the check just in
-        case).  */
-      pop_filter (a, block_filter, NULL);
+
+      log_assert (a->filter == block_filter);
+      iobuf_pop_filter (a, block_filter, NULL);
     }
   else
+    /* Enabled partial body length mode.  */
     {
+      block_filter_ctx_t *ctx = xcalloc (1, sizeof *ctx);
+      ctx->use = a->use;
       ctx->partial = 1;
       ctx->size = 0;
       ctx->first_c = len;