common: Add new function gnupg_gmtime.
[gnupg.git] / common / iobuf.c
index 759a498..ca74bd7 100644 (file)
@@ -1,15 +1,25 @@
 /* iobuf.c  -  File Handling for OpenPGP.
  * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2006, 2007, 2008,
- *               2009, 2010  Free Software Foundation, Inc.
+ *               2009, 2010, 2011  Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
  *
- * GnuPG is distributed in the hope that it will be useful,
+ *   - the GNU Lesser General Public License as published by the Free
+ *     Software Foundation; either version 3 of the License, or (at
+ *     your option) any later version.
+ *
+ * or
+ *
+ *   - the GNU General Public License as published by the Free
+ *     Software Foundation; either version 2 of the License, or (at
+ *     your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * This file 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 General Public License for more details.
@@ -30,6 +40,9 @@
 #include <fcntl.h>
 #include <unistd.h>
 #ifdef HAVE_W32_SYSTEM
+# ifdef HAVE_WINSOCK2_H
+#  include <winsock2.h>
+# endif
 # include <windows.h>
 #endif
 #ifdef __riscos__
 # include <swis.h>
 #endif /* __riscos__ */
 
+#include <assuan.h>
+
 #include "util.h"
 #include "sysutils.h"
 #include "iobuf.h"
 
 /*-- Begin configurable part.  --*/
 
-/* The size of the internal buffers. 
+/* The size of the internal buffers.
    NOTE: If you change this value you MUST also adjust the regression
    test "armored_key_8192" in armor.test! */
 #define IOBUF_BUFFER_SIZE  8192
 
+/* To avoid a potential DoS with compression packets we better limit
+   the number of filters in a chain.  */
+#define MAX_NESTING_FILTER 64
+
 /*-- End configurable part.  --*/
 
 
 #ifdef HAVE_W32_SYSTEM
-# define FD_FOR_STDIN  (GetStdHandle (STD_INPUT_HANDLE))
-# define FD_FOR_STDOUT (GetStdHandle (STD_OUTPUT_HANDLE))
+# ifdef HAVE_W32CE_SYSTEM
+#  define FD_FOR_STDIN  (es_fileno (es_stdin))
+#  define FD_FOR_STDOUT (es_fileno (es_stdout))
+# else
+#  define FD_FOR_STDIN  (GetStdHandle (STD_INPUT_HANDLE))
+#  define FD_FOR_STDOUT (GetStdHandle (STD_OUTPUT_HANDLE))
+# endif
 #else /*!HAVE_W32_SYSTEM*/
 # define FD_FOR_STDIN  (0)
 # define FD_FOR_STDOUT (1)
 typedef struct
 {
   gnupg_fd_t fp;       /* Open file pointer or handle.  */
-  int keep_open; 
+  int keep_open;
   int no_cache;
   int eof_seen;
   int print_only_name; /* Flags indicating that fname is not a real file.  */
   char fname[1];       /* Name of the file.  */
 } file_filter_ctx_t;
 
+/* The context used by the estream filter.  */
+typedef struct
+{
+  estream_t fp;        /* Open estream handle.  */
+  int keep_open;
+  int no_cache;
+  int eof_seen;
+  int print_only_name; /* Flags indicating that fname is not a real file.  */
+  char fname[1];       /* Name of the file.  */
+} file_es_filter_ctx_t;
+
 
 /* Object to control the "close cache".  */
 struct close_cache_s
@@ -138,7 +173,7 @@ fd_cache_strcmp (const char *a, const char *b)
 #ifdef HAVE_DOSISH_SYSTEM
   for (; *a && *b; a++, b++)
     {
-      if (*a != *b && !((*a == '/' && *b == '\\') 
+      if (*a != *b && !((*a == '/' && *b == '\\')
                         || (*a == '\\' && *b == '/')) )
         break;
     }
@@ -213,7 +248,7 @@ fd_cache_synchronize (const char *fname)
 
 
 static gnupg_fd_t
-direct_open (const char *fname, const char *mode)
+direct_open (const char *fname, const char *mode, int mode700)
 {
 #ifdef HAVE_W32_SYSTEM
   unsigned long da, cd, sm;
@@ -264,9 +299,14 @@ direct_open (const char *fname, const char *mode)
   hfile = CreateFile (fname, da, sm, NULL, cd, FILE_ATTRIBUTE_NORMAL, NULL);
 #endif
   return hfile;
+
 #else /*!HAVE_W32_SYSTEM*/
+
   int oflag;
-  int cflag = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+  int cflag = S_IRUSR | S_IWUSR;
+
+  if (!mode700)
+    cflag |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
 
   /* Note, that we do not handle all mode combinations */
   if (strchr (mode, '+'))
@@ -289,27 +329,24 @@ direct_open (const char *fname, const char *mode)
   if (strchr (mode, 'b'))
     oflag |= O_BINARY;
 #endif
-  /* No we need to distinguish between POSIX and RISC OS.  */
-#ifndef __riscos__
-  return open (fname, oflag, cflag);
-#else
+
+#ifdef __riscos__
   {
     struct stat buf;
-    int rc = stat (fname, &buf);
 
     /* Don't allow iobufs on directories */
-    if (!rc && S_ISDIR (buf.st_mode) && !S_ISREG (buf.st_mode))
+    if (!stat (fname, &buf) && S_ISDIR (buf.st_mode) && !S_ISREG (buf.st_mode))
       return __set_errno (EISDIR);
-    else
-      return open (fname, oflag, cflag);
   }
 #endif
+  return open (fname, oflag, cflag);
+
 #endif /*!HAVE_W32_SYSTEM*/
 }
 
 
 /*
- * Instead of closing an FD we keep it open and cache it for later reuse 
+ * Instead of closing an FD we keep it open and cache it for later reuse
  * Note that this caching strategy only works if the process does not chdir.
  */
 static void
@@ -386,7 +423,7 @@ fd_cache_open (const char *fname, const char *mode)
     }
   if (DBG_IOBUF)
     log_debug ("fd_cache_open (%s) not cached\n", fname);
-  return direct_open (fname, mode);
+  return direct_open (fname, mode, 0);
 }
 
 
@@ -570,6 +607,96 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
 }
 
 
+/* Similar to file_filter but using the estream system.  */
+static int
+file_es_filter (void *opaque, int control, iobuf_t chain, byte * buf,
+                size_t * ret_len)
+{
+  file_es_filter_ctx_t *a = opaque;
+  estream_t f = a->fp;
+  size_t size = *ret_len;
+  size_t nbytes = 0;
+  int rc = 0;
+
+  (void)chain; /* Not used.  */
+
+  if (control == IOBUFCTRL_UNDERFLOW)
+    {
+      assert (size); /* We need a buffer.  */
+      if (a->eof_seen)
+       {
+         rc = -1;
+         *ret_len = 0;
+       }
+      else
+       {
+          nbytes = 0;
+          rc = es_read (f, buf, size, &nbytes);
+         if (rc == -1)
+           {                   /* error */
+              rc = gpg_error_from_syserror ();
+              log_error ("%s: read error: %s\n", a->fname, strerror (errno));
+           }
+         else if (!nbytes)
+           {                   /* eof */
+             a->eof_seen = 1;
+             rc = -1;
+           }
+         *ret_len = nbytes;
+       }
+    }
+  else if (control == IOBUFCTRL_FLUSH)
+    {
+      if (size)
+       {
+         byte *p = buf;
+         size_t nwritten;
+
+         nbytes = size;
+         do
+           {
+              nwritten = 0;
+              if (es_write (f, p, nbytes, &nwritten))
+                {
+                  rc = gpg_error_from_syserror ();
+                  log_error ("%s: write error: %s\n",
+                             a->fname, strerror (errno));
+                  break;
+                }
+              p += nwritten;
+              nbytes -= nwritten;
+           }
+         while (nbytes);
+         nbytes = p - buf;
+       }
+      *ret_len = nbytes;
+    }
+  else if (control == IOBUFCTRL_INIT)
+    {
+      a->eof_seen = 0;
+      a->no_cache = 0;
+    }
+  else if (control == IOBUFCTRL_DESC)
+    {
+      *(char **) buf = "estream_filter";
+    }
+  else if (control == IOBUFCTRL_FREE)
+    {
+      if (f != es_stdin && f != es_stdout)
+       {
+         if (DBG_IOBUF)
+           log_debug ("%s: es_fclose %p\n", a->fname, f);
+         if (!a->keep_open)
+           es_fclose (f);
+       }
+      f = NULL;
+      xfree (a); /* We can free our context now. */
+    }
+
+  return rc;
+}
+
+
 #ifdef HAVE_W32_SYSTEM
 /* Because network sockets are special objects under Lose32 we have to
    use a dedicated filter for them. */
@@ -744,7 +871,7 @@ block_filter (void *opaque, int control, iobuf_t chain, byte * buffer,
                    }
                  else if (c == 255)
                    {
-                     a->size = iobuf_get (chain) << 24;
+                     a->size = (size_t)iobuf_get (chain) << 24;
                      a->size |= iobuf_get (chain) << 16;
                      a->size |= iobuf_get (chain) << 8;
                      if ((c = iobuf_get (chain)) == -1)
@@ -770,7 +897,7 @@ block_filter (void *opaque, int control, iobuf_t chain, byte * buffer,
                  /*  log_debug("partial: ctx=%p c=%02x size=%u\n", a, c, a->size); */
                }
              else
-               BUG (); 
+               BUG ();
            }
 
          while (!rc && size && a->size)
@@ -956,7 +1083,7 @@ print_chain (iobuf_t a)
        a->filter (a->filter_ov, IOBUFCTRL_DESC, NULL,
                   (byte *) & desc, &dummy_len);
 
-      log_debug ("iobuf chain: %d.%d `%s' filter_eof=%d start=%d len=%d\n",
+      log_debug ("iobuf chain: %d.%d '%s' filter_eof=%d start=%d len=%d\n",
                 a->no, a->subno, desc?desc:"?", a->filter_eof,
                 (int) a->d.start, (int) a->d.len);
     }
@@ -1014,7 +1141,7 @@ iobuf_close (iobuf_t a)
        log_error ("iobuf_flush failed on close: %s\n", gpg_strerror (rc));
 
       if (DBG_IOBUF)
-       log_debug ("iobuf-%d.%d: close `%s'\n", a->no, a->subno,
+       log_debug ("iobuf-%d.%d: close '%s'\n", a->no, a->subno,
                    a->desc?a->desc:"?");
       if (a->filter && (rc = a->filter (a->filter_ov, IOBUFCTRL_FREE,
                                        a->chain, NULL, &dummy_len)))
@@ -1101,9 +1228,12 @@ iobuf_t
 iobuf_temp_with_content (const char *buffer, size_t length)
 {
   iobuf_t a;
+  int i;
 
   a = iobuf_alloc (3, length);
-  memcpy (a->d.buf, buffer, length);
+  /* memcpy (a->d.buf, buffer, length); */
+  for (i=0; i < length; i++)
+    a->d.buf[i] = buffer[i];
   a->d.len = length;
 
   return a;
@@ -1156,18 +1286,10 @@ iobuf_open_fd_or_name (gnupg_fd_t fd, const char *fname, const char *mode)
 {
   iobuf_t a;
 
-  if (fd == -1)
+  if (fd == GNUPG_INVALID_FD)
     a = iobuf_open (fname);
   else
-    {
-      int fd2;
-
-      fd2 = dup (fd);
-      if (fd2 == -1)
-        a = NULL;
-      else
-        a = iobuf_fdopen (fd2, mode);
-    }
+    a = iobuf_fdopen_nc (FD2INT(fd), mode);
   return a;
 }
 
@@ -1182,7 +1304,7 @@ iobuf_open (const char *fname)
   iobuf_t a;
   gnupg_fd_t fp;
   file_filter_ctx_t *fcx;
-  size_t len;
+  size_t len = 0;
   int print_only = 0;
   int fd;
 
@@ -1208,38 +1330,76 @@ iobuf_open (const char *fname)
   file_filter (fcx, IOBUFCTRL_DESC, NULL, (byte *) & a->desc, &len);
   file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
   if (DBG_IOBUF)
-    log_debug ("iobuf-%d.%d: open `%s' fd=%d\n",
+    log_debug ("iobuf-%d.%d: open '%s' fd=%d\n",
               a->no, a->subno, fname, FD2INT (fcx->fp));
 
   return a;
 }
 
-/****************
- * Create a head iobuf for reading or writing from/to a file
- * Returns: NULL if an error occures and sets ERRNO.
- */
-iobuf_t
-iobuf_fdopen (int fd, const char *mode)
+
+static iobuf_t
+do_iobuf_fdopen (int fd, const char *mode, int keep_open)
 {
   iobuf_t a;
   gnupg_fd_t fp;
   file_filter_ctx_t *fcx;
   size_t len;
 
-  fp = (gnupg_fd_t) fd;
+  fp = INT2FD (fd);
 
   a = iobuf_alloc (strchr (mode, 'w') ? 2 : 1, IOBUF_BUFFER_SIZE);
   fcx = xmalloc (sizeof *fcx + 20);
   fcx->fp = fp;
   fcx->print_only_name = 1;
+  fcx->keep_open = keep_open;
   sprintf (fcx->fname, "[fd %d]", fd);
   a->filter = file_filter;
   a->filter_ov = fcx;
   file_filter (fcx, IOBUFCTRL_DESC, NULL, (byte *) & a->desc, &len);
   file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
   if (DBG_IOBUF)
-    log_debug ("iobuf-%d.%d: fdopen `%s'\n", a->no, a->subno, fcx->fname);
-  iobuf_ioctl (a, 3, 1, NULL); /* disable fd caching */
+    log_debug ("iobuf-%d.%d: fdopen%s '%s'\n",
+               a->no, a->subno, keep_open? "_nc":"", fcx->fname);
+  iobuf_ioctl (a, IOBUF_IOCTL_NO_CACHE, 1, NULL);
+  return a;
+}
+
+
+/* Create a head iobuf for reading or writing from/to a file Returns:
+ * NULL and sets ERRNO if an error occured.  */
+iobuf_t
+iobuf_fdopen (int fd, const char *mode)
+{
+  return do_iobuf_fdopen (fd, mode, 0);
+}
+
+iobuf_t
+iobuf_fdopen_nc (int fd, const char *mode)
+{
+  return do_iobuf_fdopen (fd, mode, 1);
+}
+
+
+iobuf_t
+iobuf_esopen (estream_t estream, const char *mode, int keep_open)
+{
+  iobuf_t a;
+  file_es_filter_ctx_t *fcx;
+  size_t len;
+
+  a = iobuf_alloc (strchr (mode, 'w') ? 2 : 1, IOBUF_BUFFER_SIZE);
+  fcx = xtrymalloc (sizeof *fcx + 30);
+  fcx->fp = estream;
+  fcx->print_only_name = 1;
+  fcx->keep_open = keep_open;
+  sprintf (fcx->fname, "[fd %p]", estream);
+  a->filter = file_es_filter;
+  a->filter_ov = fcx;
+  file_es_filter (fcx, IOBUFCTRL_DESC, NULL, (byte *) & a->desc, &len);
+  file_es_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
+  if (DBG_IOBUF)
+    log_debug ("iobuf-%d.%d: esopen%s '%s'\n",
+               a->no, a->subno, keep_open? "_nc":"", fcx->fname);
   return a;
 }
 
@@ -1262,8 +1422,8 @@ iobuf_sockopen (int fd, const char *mode)
   sock_filter (scx, IOBUFCTRL_DESC, NULL, (byte *) & a->desc, &len);
   sock_filter (scx, IOBUFCTRL_INIT, NULL, NULL, &len);
   if (DBG_IOBUF)
-    log_debug ("iobuf-%d.%d: sockopen `%s'\n", a->no, a->subno, scx->fname);
-  iobuf_ioctl (a, 3, 1, NULL); /* disable fd caching */
+    log_debug ("iobuf-%d.%d: sockopen '%s'\n", a->no, a->subno, scx->fname);
+  iobuf_ioctl (a, IOBUF_IOCTL_NO_CACHE, 1, NULL);
 #else
   a = iobuf_fdopen (fd, mode);
 #endif
@@ -1271,10 +1431,11 @@ iobuf_sockopen (int fd, const char *mode)
 }
 
 /****************
- * create an iobuf for writing to a file; the file will be created.
+ * Create an iobuf for writing to a file; the file will be created.
+ * With MODE700 set the file is created with that mode (Unix only).
  */
 iobuf_t
-iobuf_create (const char *fname)
+iobuf_create (const char *fname, int mode700)
 {
   iobuf_t a;
   gnupg_fd_t fp;
@@ -1291,7 +1452,7 @@ iobuf_create (const char *fname)
     }
   else if ((fd = check_special_filename (fname)) != -1)
     return iobuf_fdopen (translate_file_handle (fd, 1), "wb");
-  else if ((fp = direct_open (fname, "wb")) == GNUPG_INVALID_FD)
+  else if ((fp = direct_open (fname, "wb", mode700)) == GNUPG_INVALID_FD)
     return NULL;
   a = iobuf_alloc (2, IOBUF_BUFFER_SIZE);
   fcx = xmalloc (sizeof *fcx + strlen (fname));
@@ -1305,46 +1466,12 @@ iobuf_create (const char *fname)
   file_filter (fcx, IOBUFCTRL_DESC, NULL, (byte *) & a->desc, &len);
   file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
   if (DBG_IOBUF)
-    log_debug ("iobuf-%d.%d: create `%s'\n", a->no, a->subno,
+    log_debug ("iobuf-%d.%d: create '%s'\n", a->no, a->subno,
                a->desc?a->desc:"?");
 
   return a;
 }
 
-/****************
- * append to an iobuf; if the file does not exist, create it.
- * cannot be used for stdout.
- * Note: This is not used.
- */
-#if 0                          /* not used */
-iobuf_t
-iobuf_append (const char *fname)
-{
-  iobuf_t a;
-  FILE *fp;
-  file_filter_ctx_t *fcx;
-  size_t len;
-
-  if (!fname)
-    return NULL;
-  else if (!(fp = direct_open (fname, "ab")))
-    return NULL;
-  a = iobuf_alloc (2, IOBUF_BUFFER_SIZE);
-  fcx = m_alloc (sizeof *fcx + strlen (fname));
-  fcx->fp = fp;
-  strcpy (fcx->fname, fname);
-  a->real_fname = m_strdup (fname);
-  a->filter = file_filter;
-  a->filter_ov = fcx;
-  file_filter (fcx, IOBUFCTRL_DESC, NULL, (byte *) & a->desc, &len);
-  file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
-  if (DBG_IOBUF)
-    log_debug ("iobuf-%d.%d: append `%s'\n", a->no, a->subno,
-               a->desc?a->desc:"?");
-
-  return a;
-}
-#endif
 
 iobuf_t
 iobuf_openrw (const char *fname)
@@ -1356,7 +1483,7 @@ iobuf_openrw (const char *fname)
 
   if (!fname)
     return NULL;
-  else if ((fp = direct_open (fname, "r+b")) == GNUPG_INVALID_FD)
+  else if ((fp = direct_open (fname, "r+b", 0)) == GNUPG_INVALID_FD)
     return NULL;
   a = iobuf_alloc (2, IOBUF_BUFFER_SIZE);
   fcx = xmalloc (sizeof *fcx + strlen (fname));
@@ -1368,7 +1495,7 @@ iobuf_openrw (const char *fname)
   file_filter (fcx, IOBUFCTRL_DESC, NULL, (byte *) & a->desc, &len);
   file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
   if (DBG_IOBUF)
-    log_debug ("iobuf-%d.%d: openrw `%s'\n", a->no, a->subno,
+    log_debug ("iobuf-%d.%d: openrw '%s'\n", a->no, a->subno,
                a->desc?a->desc:"?");
 
   return a;
@@ -1376,13 +1503,16 @@ iobuf_openrw (const char *fname)
 
 
 int
-iobuf_ioctl (iobuf_t a, int cmd, int intval, void *ptrval)
+iobuf_ioctl (iobuf_t a, iobuf_ioctl_t cmd, int intval, void *ptrval)
 {
-  if (cmd == 1)
-    {                          /* keep system filepointer/descriptor open */
+  if (cmd == IOBUF_IOCTL_KEEP_OPEN)
+    {
+      /* Keep system filepointer/descriptor open.  This was used in
+         the past by http.c; this ioctl is not directly used
+         anymore.  */
       if (DBG_IOBUF)
-       log_debug ("iobuf-%d.%d: ioctl `%s' keep=%d\n",
-                  a ? a->no : -1, a ? a->subno : -1, 
+       log_debug ("iobuf-%d.%d: ioctl '%s' keep_open=%d\n",
+                  a ? a->no : -1, a ? a->subno : -1,
                    a && a->desc ? a->desc : "?",
                   intval);
       for (; a; a = a->chain)
@@ -1401,10 +1531,10 @@ iobuf_ioctl (iobuf_t a, int cmd, int intval, void *ptrval)
          }
 #endif
     }
-  else if (cmd == 2)
-    {                          /* invalidate cache */
+  else if (cmd == IOBUF_IOCTL_INVALIDATE_CACHE)
+    {
       if (DBG_IOBUF)
-       log_debug ("iobuf-*.*: ioctl `%s' invalidate\n",
+       log_debug ("iobuf-*.*: ioctl '%s' invalidate\n",
                   ptrval ? (char *) ptrval : "?");
       if (!a && !intval && ptrval)
        {
@@ -1413,11 +1543,11 @@ iobuf_ioctl (iobuf_t a, int cmd, int intval, void *ptrval)
          return 0;
        }
     }
-  else if (cmd == 3)
-    {                          /* disallow/allow caching */
+  else if (cmd == IOBUF_IOCTL_NO_CACHE)
+    {
       if (DBG_IOBUF)
-       log_debug ("iobuf-%d.%d: ioctl `%s' no_cache=%d\n",
-                  a ? a->no : -1, a ? a->subno : -1, 
+       log_debug ("iobuf-%d.%d: ioctl '%s' no_cache=%d\n",
+                  a ? a->no : -1, a ? a->subno : -1,
                    a && a->desc? a->desc : "?",
                   intval);
       for (; a; a = a->chain)
@@ -1436,12 +1566,12 @@ iobuf_ioctl (iobuf_t a, int cmd, int intval, void *ptrval)
          }
 #endif
     }
-  else if (cmd == 4)
+  else if (cmd == IOBUF_IOCTL_FSYNC)
     {
       /* Do a fsync on the open fd and return any errors to the caller
          of iobuf_ioctl.  Note that we work on a file name here. */
       if (DBG_IOBUF)
-        log_debug ("iobuf-*.*: ioctl `%s' fsync\n",
+        log_debug ("iobuf-*.*: ioctl '%s' fsync\n",
                    ptrval? (const char*)ptrval:"<null>");
 
        if (!a && !intval && ptrval)
@@ -1482,6 +1612,13 @@ iobuf_push_filter2 (iobuf_t a,
 
   if (a->use == 2 && (rc = iobuf_flush (a)))
     return rc;
+
+  if (a->subno >= MAX_NESTING_FILTER)
+    {
+      log_error ("i/o filter too deeply nested - corrupted data?\n");
+      return GPG_ERR_BAD_DATA;
+    }
+
   /* make a copy of the current stream, so that
    * A is the new stream and B the original one.
    * The contents of the buffers are transferred to the
@@ -1533,7 +1670,7 @@ iobuf_push_filter2 (iobuf_t a,
 
   if (DBG_IOBUF)
     {
-      log_debug ("iobuf-%d.%d: push `%s'\n", a->no, a->subno, 
+      log_debug ("iobuf-%d.%d: push '%s'\n", a->no, a->subno,
                  a->desc?a->desc:"?");
       print_chain (a);
     }
@@ -1561,7 +1698,7 @@ pop_filter (iobuf_t a, int (*f) (void *opaque, int control,
     BUG ();
 
   if (DBG_IOBUF)
-    log_debug ("iobuf-%d.%d: pop `%s'\n", a->no, a->subno,
+    log_debug ("iobuf-%d.%d: pop '%s'\n", a->no, a->subno,
                a->desc?a->desc:"?");
   if (!a->filter)
     {                          /* this is simple */
@@ -1648,7 +1785,7 @@ underflow (iobuf_t a)
        {
          iobuf_t b = a->chain;
          if (DBG_IOBUF)
-           log_debug ("iobuf-%d.%d: pop `%s' in underflow\n",
+           log_debug ("iobuf-%d.%d: pop '%s' in underflow\n",
                       a->no, a->subno, a->desc?a->desc:"?");
          xfree (a->d.buf);
          xfree (a->real_fname);
@@ -2040,24 +2177,24 @@ iobuf_get_filelength (iobuf_t a, int *overflow)
 
   if (overflow)
     *overflow = 0;
-  
-  if ( a->directfp )  
+
+  if ( a->directfp )
     {
       FILE *fp = a->directfp;
-      
+
       if ( !fstat(fileno(fp), &st) )
         return st.st_size;
       log_error("fstat() failed: %s\n", strerror(errno) );
       return 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;
-        
+
 #if defined(HAVE_W32_SYSTEM)
         ulong size;
         static int (* __stdcall get_file_size_ex) (void *handle,
@@ -2067,7 +2204,7 @@ iobuf_get_filelength (iobuf_t a, int *overflow)
         if (!get_file_size_ex_initialized)
           {
             void *handle;
-            
+
             handle = dlopen ("kernel32.dll", RTLD_LAZY);
             if (handle)
               {
@@ -2077,21 +2214,21 @@ iobuf_get_filelength (iobuf_t a, int *overflow)
               }
             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; 
+                return 0;
               }
           }
         else
@@ -2108,14 +2245,14 @@ iobuf_get_filelength (iobuf_t a, int *overflow)
 #endif
         break/*the for loop*/;
       }
-  
+
     return 0;
 }
 
 
 /* Return the file descriptor of the underlying file or -1 if it is
    not available.  */
-int 
+int
 iobuf_get_fd (iobuf_t a)
 {
   if (a->directfp)
@@ -2194,7 +2331,7 @@ iobuf_seek (iobuf_t a, off_t newpos)
        }
       clearerr (fp);
     }
-  else
+  else if (a->use != 3)  /* Not a temp stream.  */
     {
       for (; a; a = a->chain)
        {
@@ -2221,7 +2358,8 @@ iobuf_seek (iobuf_t a, off_t newpos)
        }
 #endif
     }
-  a->d.len = 0;                        /* discard buffer */
+  if (a->use != 3)
+    a->d.len = 0;      /* Discard the buffer  unless it is a temp stream.  */
   a->d.start = 0;
   a->nbytes = 0;
   a->nlimit = 0;
@@ -2386,10 +2524,15 @@ iobuf_read_line (iobuf_t a, byte ** addr_of_buffer,
 static int
 translate_file_handle (int fd, int for_write)
 {
-#ifdef HAVE_W32_SYSTEM
+#if defined(HAVE_W32CE_SYSTEM)
+  /* This is called only with one of the special filenames.  Under
+     W32CE the FD here is not a file descriptor but a rendezvous id,
+     thus we need to finish the pipe first.  */
+  fd = _assuan_w32ce_finish_pipe (fd, for_write);
+#elif defined(HAVE_W32_SYSTEM)
   {
     int x;
-    
+
     (void)for_write;
 
     if (fd == 0)
@@ -2421,13 +2564,13 @@ iobuf_skip_rest (iobuf_t a, unsigned long n, int partial)
     {
       for (;;)
         {
-          if (a->nofast || a->d.start >= a->d.len) 
+          if (a->nofast || a->d.start >= a->d.len)
             {
               if (iobuf_readbyte (a) == -1)
                 {
                   break;
                 }
-           } 
+           }
           else
             {
               unsigned long count = a->d.len - a->d.start;
@@ -2435,11 +2578,11 @@ iobuf_skip_rest (iobuf_t a, unsigned long n, int partial)
               a->d.start = a->d.len;
            }
        }
-    } 
+    }
   else
     {
       unsigned long remaining = n;
-      while (remaining > 0) 
+      while (remaining > 0)
         {
           if (a->nofast || a->d.start >= a->d.len)
             {
@@ -2448,11 +2591,11 @@ iobuf_skip_rest (iobuf_t a, unsigned long n, int partial)
                   break;
                }
               --remaining;
-           } 
-          else 
+           }
+          else
             {
               unsigned long count = a->d.len - a->d.start;
-              if (count > remaining) 
+              if (count > remaining)
                 {
                   count = remaining;
                }