2010-09-01 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / iobuf.c
index 32b9e18..b9bed32 100644 (file)
@@ -1,11 +1,12 @@
-/* iobuf.c  -  file handling
- * Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+/* iobuf.c  -  File Handling for OpenPGP.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2006, 2007, 2008,
+ *               2009, 2010  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 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -14,8 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
-#ifdef HAVE_DOSISH_SYSTEM
-#include <windows.h>
+#ifdef HAVE_W32_SYSTEM
+# include <windows.h>
 #endif
 #ifdef __riscos__
-#include <kernel.h>
-#include <swis.h>
+# include <kernel.h>
+# include <swis.h>
 #endif /* __riscos__ */
 
-#include "memory.h"
+#include <assuan.h>
+
 #include "util.h"
+#include "sysutils.h"
 #include "iobuf.h"
 
-#undef FILE_FILTER_USES_STDIO
+/*-- Begin configurable part.  --*/
 
-#ifdef HAVE_DOSISH_SYSTEM
-#define USE_SETMODE 1
-#endif
+/* 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
 
-#ifdef FILE_FILTER_USES_STDIO
-#define my_fileno(a)  fileno ((a))
-#define my_fopen_ro(a,b) fopen ((a),(b))
-#define my_fopen(a,b)    fopen ((a),(b))
-typedef FILE *FILEP_OR_FD;
-#define INVALID_FP    NULL
-#define FILEP_OR_FD_FOR_STDIN  (stdin)
-#define FILEP_OR_FD_FOR_STDOUT  (stdout)
-typedef struct
-{
-  FILE *fp;                    /* open file handle */
-  int keep_open;
-  int no_cache;
-  int print_only_name;         /* flags indicating that fname is not a real file */
-  char fname[1];               /* name of the file */
-}
-file_filter_ctx_t;
-#else
-#define my_fileno(a)  (a)
-#define my_fopen_ro(a,b) fd_cache_open ((a),(b))
-#define my_fopen(a,b) direct_open ((a),(b))
-#ifdef HAVE_DOSISH_SYSTEM
-typedef HANDLE FILEP_OR_FD;
-#define INVALID_FP  ((HANDLE)-1)
-#define FILEP_OR_FD_FOR_STDIN  (GetStdHandle (STD_INPUT_HANDLE))
-#define FILEP_OR_FD_FOR_STDOUT (GetStdHandle (STD_OUTPUT_HANDLE))
-#undef USE_SETMODE
-#else
-typedef int FILEP_OR_FD;
-#define INVALID_FP  (-1)
-#define FILEP_OR_FD_FOR_STDIN  (0)
-#define FILEP_OR_FD_FOR_STDOUT (1)
-#endif
+/*-- End configurable part.  --*/
+
+
+#ifdef HAVE_W32_SYSTEM
+# 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)
+#endif /*!HAVE_W32_SYSTEM*/
+
+
+/* The context used by the file filter.  */
 typedef struct
 {
-  FILEP_OR_FD fp;              /* open file handle */
-  int keep_open;
+  gnupg_fd_t fp;       /* Open file pointer or 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_filter_ctx_t;
+  int print_only_name; /* Flags indicating that fname is not a real file.  */
+  char fname[1];       /* Name of the file.  */
+} file_filter_ctx_t;
+
 
+/* Object to control the "close cache".  */
 struct close_cache_s
 {
   struct close_cache_s *next;
-  FILEP_OR_FD fp;
+  gnupg_fd_t fp;
   char fname[1];
 };
-typedef struct close_cache_s *CLOSE_CACHE;
-static CLOSE_CACHE close_cache;
-#endif
+typedef struct close_cache_s *close_cache_t;
+static close_cache_t close_cache;
+
+
 
-#ifdef _WIN32
+#ifdef HAVE_W32_SYSTEM
 typedef struct
 {
   int sock;
   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 */
-}
-sock_filter_ctx_t;
-#endif /*_WIN32*/
+  int print_only_name; /* Flag indicating that fname is not a real file.  */
+  char fname[1];       /* Name of the file */
+
+sock_filter_ctx_t;
+#endif /*HAVE_W32_SYSTEM*/
 
 /* The first partial length header block must be of size 512
  * to make it easier (and efficienter) we use a min. block size of 512
@@ -120,33 +110,59 @@ sock_filter_ctx_t;
 #define OP_MIN_PARTIAL_CHUNK     512
 #define OP_MIN_PARTIAL_CHUNK_2POW 9
 
+/* The context we use for the block filter (used to handle OpenPGP
+   length information header).  */
 typedef struct
 {
   int use;
   size_t size;
   size_t count;
-  int partial;                 /* 1 = partial header, 2 in last partial packet */
-  char *buffer;                        /* used for partial header */
-  size_t buflen;               /* used size of buffer */
-  int first_c;                 /* of partial header (which is > 0) */
+  int partial;    /* 1 = partial header, 2 in last partial packet.  */
+  char *buffer;           /* Used for partial header.  */
+  size_t buflen;   /* Used size of buffer.  */
+  int first_c;    /* First character of a partial header (which is > 0).  */
   int eof;
 }
 block_filter_ctx_t;
 
+
+/* Global flag to tell whether special file names are enabled.  See
+   gpg.c for an explanation of these file names.  FIXME: it does not
+   belong into the iobuf subsystem. */
 static int special_names_enabled;
 
+/* Local prototypes.  */
 static int underflow (iobuf_t a);
 static int translate_file_handle (int fd, int for_write);
 
-#ifndef FILE_FILTER_USES_STDIO
+
+\f
+/* This is a replacement for strcmp.  Under W32 it does not
+   distinguish between backslash and slash.  */
+static int
+fd_cache_strcmp (const char *a, const char *b)
+{
+#ifdef HAVE_DOSISH_SYSTEM
+  for (; *a && *b; a++, b++)
+    {
+      if (*a != *b && !((*a == '/' && *b == '\\') 
+                        || (*a == '\\' && *b == '/')) )
+        break;
+    }
+  return *(const unsigned char *)a - *(const unsigned char *)b;
+#else
+  return strcmp (a, b);
+#endif
+}
 
 /*
  * Invalidate (i.e. close) a cached iobuf
  */
-static void
+static int
 fd_cache_invalidate (const char *fname)
 {
-  CLOSE_CACHE cc;
+  close_cache_t cc;
+  int rc = 0;
 
   assert (fname);
   if (DBG_IOBUF)
@@ -154,45 +170,80 @@ fd_cache_invalidate (const char *fname)
 
   for (cc = close_cache; cc; cc = cc->next)
     {
-      if (cc->fp != INVALID_FP && !strcmp (cc->fname, fname))
+      if (cc->fp != GNUPG_INVALID_FD && !fd_cache_strcmp (cc->fname, fname))
        {
          if (DBG_IOBUF)
            log_debug ("                did (%s)\n", cc->fname);
-#ifdef HAVE_DOSISH_SYSTEM
-         CloseHandle (cc->fp);
+#ifdef HAVE_W32_SYSTEM
+         if (!CloseHandle (cc->fp))
+            rc = -1;
 #else
-         close (cc->fp);
+         rc = close (cc->fp);
 #endif
-         cc->fp = INVALID_FP;
+         cc->fp = GNUPG_INVALID_FD;
        }
     }
+  return rc;
 }
 
 
+/* Try to sync changes to the disk.  This is to avoid data loss during
+   a system crash in write/close/rename cycle on some file
+   systems.  */
+static int
+fd_cache_synchronize (const char *fname)
+{
+  int err = 0;
+
+#ifdef HAVE_FSYNC
+  close_cache_t cc;
+
+  if (DBG_IOBUF)
+    log_debug ("fd_cache_synchronize (%s)\n", fname);
+
+  for (cc=close_cache; cc; cc = cc->next )
+    {
+      if (cc->fp != GNUPG_INVALID_FD && !fd_cache_strcmp (cc->fname, fname))
+       {
+         if (DBG_IOBUF)
+           log_debug ("                 did (%s)\n", cc->fname);
+
+         err = fsync (cc->fp);
+       }
+    }
+#else
+  (void)fname;
+#endif /*HAVE_FSYNC*/
+
+  return err;
+}
 
-static FILEP_OR_FD
+
+static gnupg_fd_t
 direct_open (const char *fname, const char *mode)
 {
-#ifdef HAVE_DOSISH_SYSTEM
+#ifdef HAVE_W32_SYSTEM
   unsigned long da, cd, sm;
   HANDLE hfile;
 
   /* Note, that we do not handle all mode combinations */
 
   /* According to the ReactOS source it seems that open() of the
-   * standard MSW32 crt does open the file in share mode which is
+   * standard MSW32 crt does open the file in shared mode which is
    * something new for MS applications ;-)
    */
   if (strchr (mode, '+'))
     {
-      fd_cache_invalidate (fname);
+      if (fd_cache_invalidate (fname))
+        return GNUPG_INVALID_FD;
       da = GENERIC_READ | GENERIC_WRITE;
       cd = OPEN_EXISTING;
       sm = FILE_SHARE_READ | FILE_SHARE_WRITE;
     }
   else if (strchr (mode, 'w'))
     {
-      fd_cache_invalidate (fname);
+      if (fd_cache_invalidate (fname))
+        return GNUPG_INVALID_FD;
       da = GENERIC_WRITE;
       cd = CREATE_ALWAYS;
       sm = FILE_SHARE_WRITE;
@@ -204,21 +255,37 @@ direct_open (const char *fname, const char *mode)
       sm = FILE_SHARE_READ;
     }
 
+#ifdef HAVE_W32CE_SYSTEM
+  {
+    wchar_t *wfname = utf8_to_wchar (fname);
+    if (wfname)
+      {
+        hfile = CreateFile (wfname, da, sm, NULL, cd,
+                            FILE_ATTRIBUTE_NORMAL, NULL);
+        xfree (wfname);
+      }
+    else
+      hfile = INVALID_HANDLE_VALUE;
+  }
+#else
   hfile = CreateFile (fname, da, sm, NULL, cd, FILE_ATTRIBUTE_NORMAL, NULL);
+#endif
   return hfile;
-#else
+#else /*!HAVE_W32_SYSTEM*/
   int oflag;
   int cflag = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
 
   /* Note, that we do not handle all mode combinations */
   if (strchr (mode, '+'))
     {
-      fd_cache_invalidate (fname);
+      if (fd_cache_invalidate (fname))
+        return GNUPG_INVALID_FD;
       oflag = O_RDWR;
     }
   else if (strchr (mode, 'w'))
     {
-      fd_cache_invalidate (fname);
+      if (fd_cache_invalidate (fname))
+        return GNUPG_INVALID_FD;
       oflag = O_WRONLY | O_CREAT | O_TRUNC;
     }
   else
@@ -229,6 +296,7 @@ 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
@@ -243,7 +311,7 @@ direct_open (const char *fname, const char *mode)
       return open (fname, oflag, cflag);
   }
 #endif
-#endif
+#endif /*!HAVE_W32_SYSTEM*/
 }
 
 
@@ -252,26 +320,26 @@ direct_open (const char *fname, const char *mode)
  * Note that this caching strategy only works if the process does not chdir.
  */
 static void
-fd_cache_close (const char *fname, FILEP_OR_FD fp)
+fd_cache_close (const char *fname, gnupg_fd_t fp)
 {
-  CLOSE_CACHE cc;
+  close_cache_t cc;
 
   assert (fp);
   if (!fname || !*fname)
     {
-#ifdef HAVE_DOSISH_SYSTEM
+#ifdef HAVE_W32_SYSTEM
       CloseHandle (fp);
 #else
       close (fp);
 #endif
       if (DBG_IOBUF)
-       log_debug ("fd_cache_close (%p) real\n", (void *) fp);
+       log_debug ("fd_cache_close (%d) real\n", (int)fp);
       return;
     }
   /* try to reuse a slot */
   for (cc = close_cache; cc; cc = cc->next)
     {
-      if (cc->fp == INVALID_FP && !strcmp (cc->fname, fname))
+      if (cc->fp == GNUPG_INVALID_FD && !fd_cache_strcmp (cc->fname, fname))
        {
          cc->fp = fp;
          if (DBG_IOBUF)
@@ -292,32 +360,32 @@ fd_cache_close (const char *fname, FILEP_OR_FD fp)
 /*
  * Do an direct_open on FNAME but first try to reuse one from the fd_cache
  */
-static FILEP_OR_FD
+static gnupg_fd_t
 fd_cache_open (const char *fname, const char *mode)
 {
-  CLOSE_CACHE cc;
+  close_cache_t cc;
 
   assert (fname);
   for (cc = close_cache; cc; cc = cc->next)
     {
-      if (cc->fp != INVALID_FP && !strcmp (cc->fname, fname))
+      if (cc->fp != GNUPG_INVALID_FD && !fd_cache_strcmp (cc->fname, fname))
        {
-         FILEP_OR_FD fp = cc->fp;
-         cc->fp = INVALID_FP;
+         gnupg_fd_t fp = cc->fp;
+         cc->fp = GNUPG_INVALID_FD;
          if (DBG_IOBUF)
            log_debug ("fd_cache_open (%s) using cached fp\n", fname);
-#ifdef HAVE_DOSISH_SYSTEM
+#ifdef HAVE_W32_SYSTEM
          if (SetFilePointer (fp, 0, NULL, FILE_BEGIN) == 0xffffffff)
            {
              log_error ("rewind file failed on handle %p: ec=%d\n",
                         fp, (int) GetLastError ());
-             fp = INVALID_FP;
+             fp = GNUPG_INVALID_FD;
            }
 #else
          if (lseek (fp, 0, SEEK_SET) == (off_t) - 1)
            {
              log_error ("can't rewind fd %d: %s\n", fp, strerror (errno));
-             fp = INVALID_FP;
+             fp = GNUPG_INVALID_FD;
            }
 #endif
          return fp;
@@ -329,9 +397,6 @@ fd_cache_open (const char *fname, const char *mode)
 }
 
 
-#endif /*FILE_FILTER_USES_STDIO */
-
-
 /****************
  * Read data from a file into buf which has an allocated length of *LEN.
  * return the number of read bytes in *LEN. OPAQUE is the FILE * of
@@ -361,75 +426,16 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
             size_t * ret_len)
 {
   file_filter_ctx_t *a = opaque;
-  FILEP_OR_FD f = a->fp;
+  gnupg_fd_t f = a->fp;
   size_t size = *ret_len;
   size_t nbytes = 0;
   int rc = 0;
 
-#ifdef FILE_FILTER_USES_STDIO
-  if (control == IOBUFCTRL_UNDERFLOW)
-    {
-      assert (size);           /* need a buffer */
-      if (feof (f))
-       {                       /* On terminals you could easiely read as many EOFs as you call         */
-         rc = -1;              /* fread() or fgetc() repeatly. Every call will block until you press   */
-         *ret_len = 0;         /* CTRL-D. So we catch this case before we call fread() again.          */
-       }
-      else
-       {
-         clearerr (f);
-         nbytes = fread (buf, 1, size, f);
-         if (feof (f) && !nbytes)
-           {
-             rc = -1;          /* okay: we can return EOF now. */
-           }
-         else if (ferror (f) && errno != EPIPE)
-           {
-             rc = gpg_error_from_errno (errno);
-             log_error ("%s: read error: %s\n", a->fname, strerror (errno));
-           }
-         *ret_len = nbytes;
-       }
-    }
-  else if (control == IOBUFCTRL_FLUSH)
-    {
-      if (size)
-       {
-         clearerr (f);
-         nbytes = fwrite (buf, 1, size, f);
-         if (ferror (f))
-           {
-             rc = gpg_error_from_errno (errno);
-             log_error ("%s: write error: %s\n", a->fname, strerror (errno));
-           }
-       }
-      *ret_len = nbytes;
-    }
-  else if (control == IOBUFCTRL_INIT)
-    {
-      a->keep_open = a->no_cache = 0;
-    }
-  else if (control == IOBUFCTRL_DESC)
-    {
-      *(char **) buf = "file_filter";
-    }
-  else if (control == IOBUFCTRL_FREE)
-    {
-      if (f != stdin && f != stdout)
-       {
-         if (DBG_IOBUF)
-           log_debug ("%s: close fd %d\n", a->fname, fileno (f));
-         if (!a->keep_open)
-           fclose (f);
-       }
-      f = NULL;
-      xfree (a);               /* we can free our context now */
-    }
-#else /* !stdio implementation */
+  (void)chain; /* Not used.  */
 
   if (control == IOBUFCTRL_UNDERFLOW)
     {
-      assert (size);           /* need a buffer */
+      assert (size); /* We need a buffer.  */
       if (a->eof_seen)
        {
          rc = -1;
@@ -437,7 +443,7 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
        }
       else
        {
-#ifdef HAVE_DOSISH_SYSTEM
+#ifdef HAVE_W32_SYSTEM
          unsigned long nread;
 
          nbytes = 0;
@@ -474,7 +480,7 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
            {                   /* error */
              if (errno != EPIPE)
                {
-                 rc = gpg_error_from_errno (errno);
+                 rc = gpg_error_from_syserror ();
                  log_error ("%s: read error: %s\n",
                             a->fname, strerror (errno));
                }
@@ -496,7 +502,7 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
     {
       if (size)
        {
-#ifdef HAVE_DOSISH_SYSTEM
+#ifdef HAVE_W32_SYSTEM
          byte *p = buf;
          unsigned long n;
 
@@ -536,7 +542,7 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
          while (n != -1 && nbytes);
          if (n == -1)
            {
-             rc = gpg_error_from_errno (errno);
+             rc = gpg_error_from_syserror ();
              log_error ("%s: write error: %s\n", a->fname, strerror (errno));
            }
          nbytes = p - buf;
@@ -556,33 +562,24 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
     }
   else if (control == IOBUFCTRL_FREE)
     {
-#ifdef HAVE_DOSISH_SYSTEM
-      if (f != FILEP_OR_FD_FOR_STDIN && f != FILEP_OR_FD_FOR_STDOUT)
+      if (f != FD_FOR_STDIN && f != FD_FOR_STDOUT)
        {
          if (DBG_IOBUF)
-           log_debug ("%s: close handle %p\n", a->fname, f);
+           log_debug ("%s: close fd/handle %d\n", a->fname, FD2INT (f));
          if (!a->keep_open)
            fd_cache_close (a->no_cache ? NULL : a->fname, f);
        }
-#else
-      if ((int) f != 0 && (int) f != 1)
-       {
-         if (DBG_IOBUF)
-           log_debug ("%s: close fd %d\n", a->fname, f);
-         if (!a->keep_open)
-           fd_cache_close (a->no_cache ? NULL : a->fname, f);
-       }
-      f = INVALID_FP;
-#endif
-      xfree (a);               /* we can free our context now */
+      f = GNUPG_INVALID_FD;
+      xfree (a); /* We can free our context now. */
     }
-#endif /* !stdio implementation */
+
   return rc;
 }
 
-#ifdef _WIN32
-/* Becuase sockets are an special object under Lose32 we have to
- * use a special filter */
+
+#ifdef HAVE_W32_SYSTEM
+/* Because network sockets are special objects under Lose32 we have to
+   use a dedicated filter for them. */
 static int
 sock_filter (void *opaque, int control, iobuf_t chain, byte * buf,
             size_t * ret_len)
@@ -592,6 +589,8 @@ sock_filter (void *opaque, int control, iobuf_t chain, byte * buf,
   size_t nbytes = 0;
   int rc = 0;
 
+  (void)chain;
+
   if (control == IOBUFCTRL_UNDERFLOW)
     {
       assert (size);           /* need a buffer */
@@ -667,7 +666,7 @@ sock_filter (void *opaque, int control, iobuf_t chain, byte * buf,
     }
   return rc;
 }
-#endif /*_WIN32*/
+#endif /*HAVE_W32_SYSTEM*/
 
 /****************
  * This is used to implement the block write mode.
@@ -762,32 +761,23 @@ block_filter (void *opaque, int control, iobuf_t chain, byte * buffer,
                          break;
                        }
                      a->size |= c;
+                      a->partial = 2;
+                      if (!a->size)
+                        {
+                          a->eof = 1;
+                          if (!n)
+                            rc = -1;
+                          break;
+                       }
                    }
                  else
-                   {           /* next partial body length */
+                   { /* Next partial body length. */
                      a->size = 1 << (c & 0x1f);
                    }
                  /*  log_debug("partial: ctx=%p c=%02x size=%u\n", a, c, a->size); */
                }
              else
-               {               /* the gnupg partial length scheme - much better :-) */
-                 c = iobuf_get (chain);
-                 a->size = c << 8;
-                 c = iobuf_get (chain);
-                 a->size |= c;
-                 if (c == -1)
-                   {
-                     log_error ("block_filter: error reading length info\n");
-                     rc = GPG_ERR_BAD_DATA;
-                   }
-                 if (!a->size)
-                   {
-                     a->eof = 1;
-                     if (!n)
-                       rc = -1;
-                     break;
-                   }
-               }
+               BUG (); 
            }
 
          while (!rc && size && a->size)
@@ -851,14 +841,14 @@ block_filter (void *opaque, int control, iobuf_t chain, byte * buffer,
                    {           /* write stuff from the buffer */
                      assert (n == OP_MIN_PARTIAL_CHUNK);
                      if (iobuf_write (chain, a->buffer, n))
-                       rc = gpg_error_from_errno (errno);
+                       rc = gpg_error_from_syserror ();
                      a->buflen = 0;
                      nbytes -= n;
                    }
                  if ((n = nbytes) > blen)
                    n = blen;
                  if (n && iobuf_write (chain, p, n))
-                   rc = gpg_error_from_errno (errno);
+                   rc = gpg_error_from_syserror ();
                  p += n;
                  nbytes -= n;
                }
@@ -876,39 +866,7 @@ block_filter (void *opaque, int control, iobuf_t chain, byte * buffer,
            }
        }
       else
-       {                       /* the gnupg scheme (which is not openpgp compliant) */
-         size_t avail, n;
-
-         for (p = buf; !rc && size;)
-           {
-             n = size;
-             avail = a->size - a->count;
-             if (!avail)
-               {
-                 if (n > a->size)
-                   {
-                     iobuf_put (chain, (a->size >> 8) & 0xff);
-                     iobuf_put (chain, a->size & 0xff);
-                     avail = a->size;
-                     a->count = 0;
-                   }
-                 else
-                   {
-                     iobuf_put (chain, (n >> 8) & 0xff);
-                     iobuf_put (chain, n & 0xff);
-                     avail = n;
-                     a->count = a->size - n;
-                   }
-               }
-             if (n > avail)
-               n = avail;
-             if (iobuf_write (chain, p, n))
-               rc = gpg_error_from_errno (errno);
-             a->count += n;
-             p += n;
-             size -= n;
-           }
-       }
+       BUG ();
     }
   else if (control == IOBUFCTRL_INIT)
     {
@@ -969,17 +927,14 @@ block_filter (void *opaque, int control, iobuf_t chain, byte * buffer,
                {
                  log_error ("block_filter: write error: %s\n",
                             strerror (errno));
-                 rc = gpg_error_from_errno (errno);
+                 rc = gpg_error_from_syserror ();
                }
              xfree (a->buffer);
              a->buffer = NULL;
              a->buflen = 0;
            }
          else
-           {
-             iobuf_writebyte (chain, 0);
-             iobuf_writebyte (chain, 0);
-           }
+           BUG ();
        }
       else if (a->size)
        {
@@ -1009,7 +964,7 @@ print_chain (iobuf_t a)
                   (byte *) & desc, &dummy_len);
 
       log_debug ("iobuf chain: %d.%d `%s' filter_eof=%d start=%d len=%d\n",
-                a->no, a->subno, desc, a->filter_eof,
+                a->no, a->subno, desc?desc:"?", a->filter_eof,
                 (int) a->d.start, (int) a->d.len);
     }
 }
@@ -1066,7 +1021,8 @@ 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, a->desc);
+       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)))
        log_error ("IOBUFCTRL_FREE failed on close: %s\n", gpg_strerror (rc));
@@ -1087,7 +1043,7 @@ iobuf_cancel (iobuf_t a)
   const char *s;
   iobuf_t a2;
   int rc;
-#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
+#if defined(HAVE_W32_SYSTEM) || defined(__riscos__)
   char *remove_name = NULL;
 #endif
 
@@ -1096,7 +1052,7 @@ iobuf_cancel (iobuf_t a)
       s = iobuf_get_real_fname (a);
       if (s && *s)
        {
-#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
+#if defined(HAVE_W32_SYSTEM) || defined(__riscos__)
          remove_name = xstrdup (s);
 #else
          remove (s);
@@ -1113,12 +1069,19 @@ iobuf_cancel (iobuf_t a)
     }
 
   rc = iobuf_close (a);
-#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
+#if defined(HAVE_W32_SYSTEM) || defined(__riscos__)
   if (remove_name)
     {
       /* Argg, MSDOS does not allow to remove open files.  So
        * we have to do it here */
+#ifdef HAVE_W32CE_SYSTEM
+      wchar_t *wtmp = utf8_to_wchar (remove_name);
+      if (wtmp)
+        DeleteFile (wtmp);
+      xfree (wtmp);
+#else
       remove (remove_name);
+#endif
       xfree (remove_name);
     }
 #endif
@@ -1136,7 +1099,7 @@ iobuf_temp ()
 {
   iobuf_t a;
 
-  a = iobuf_alloc (3, 8192);
+  a = iobuf_alloc (3, IOBUF_BUFFER_SIZE);
 
   return a;
 }
@@ -1159,11 +1122,10 @@ iobuf_enable_special_filenames (int yes)
   special_names_enabled = yes;
 }
 
-/*
- * see whether the filename has the for "-&nnnn", where n is a
- * non-zero number.
- * Returns this number or -1 if it is not the case.
- */
+
+/* See whether the filename has the form "-&nnnn", where n is a
+   non-zero number.  Returns this number or -1 if it is not the
+   case.  */
 static int
 check_special_filename (const char *fname)
 {
@@ -1180,6 +1142,35 @@ check_special_filename (const char *fname)
   return -1;
 }
 
+
+/* This fucntion returns true if FNAME indicates a PIPE (stdout or
+   stderr) or a special file name if those are enabled. */
+int
+iobuf_is_pipe_filename (const char *fname)
+{
+  if (!fname || (*fname=='-' && !fname[1]) )
+    return 1;
+  return check_special_filename (fname) != -1;
+}
+
+
+/* Either open the file specified by the file descriptor FD or - if FD
+   is -1, the file with name FNAME.  As of now MODE is assumed to be
+   "rb" if FNAME is used.  In contrast to iobuf_fdopen the file
+   descriptor FD will not be closed during an iobuf_close.  */
+iobuf_t
+iobuf_open_fd_or_name (gnupg_fd_t fd, const char *fname, const char *mode)
+{
+  iobuf_t a;
+
+  if (fd == GNUPG_INVALID_FD)
+    a = iobuf_open (fname);
+  else
+    a = iobuf_fdopen_nc (FD2INT(fd), mode);
+  return a;
+}
+
+
 /****************
  * Create a head iobuf for reading from a file
  * returns: NULL if an error occures and sets errno
@@ -1188,7 +1179,7 @@ iobuf_t
 iobuf_open (const char *fname)
 {
   iobuf_t a;
-  FILEP_OR_FD fp;
+  gnupg_fd_t fp;
   file_filter_ctx_t *fcx;
   size_t len;
   int print_only = 0;
@@ -1196,18 +1187,15 @@ iobuf_open (const char *fname)
 
   if (!fname || (*fname == '-' && !fname[1]))
     {
-      fp = FILEP_OR_FD_FOR_STDIN;
-#ifdef USE_SETMODE
-      setmode (my_fileno (fp), O_BINARY);
-#endif
+      fp = FD_FOR_STDIN;
       fname = "[stdin]";
       print_only = 1;
     }
   else if ((fd = check_special_filename (fname)) != -1)
     return iobuf_fdopen (translate_file_handle (fd, 0), "rb");
-  else if ((fp = my_fopen_ro (fname, "rb")) == INVALID_FP)
+  else if ((fp = fd_cache_open (fname, "rb")) == GNUPG_INVALID_FD)
     return NULL;
-  a = iobuf_alloc (1, 8192);
+  a = iobuf_alloc (1, IOBUF_BUFFER_SIZE);
   fcx = xmalloc (sizeof *fcx + strlen (fname));
   fcx->fp = fp;
   fcx->print_only_name = print_only;
@@ -1220,54 +1208,64 @@ iobuf_open (const char *fname)
   file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
   if (DBG_IOBUF)
     log_debug ("iobuf-%d.%d: open `%s' fd=%d\n",
-              a->no, a->subno, fname, (int) my_fileno (fcx->fp));
+              a->no, a->subno, fname, FD2INT (fcx->fp));
 
   return a;
 }
 
-/****************
- * Create a head iobuf for reading from 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;
-  FILEP_OR_FD fp;
+  gnupg_fd_t fp;
   file_filter_ctx_t *fcx;
   size_t len;
 
-#ifdef FILE_FILTER_USES_STDIO
-  if (!(fp = fdopen (fd, mode)))
-    return NULL;
-#else
-  fp = (FILEP_OR_FD) fd;
-#endif
-  a = iobuf_alloc (strchr (mode, 'w') ? 2 : 1, 8192);
+  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_sockopen (int fd, const char *mode)
 {
   iobuf_t a;
-#ifdef _WIN32
+#ifdef HAVE_W32_SYSTEM
   sock_filter_ctx_t *scx;
   size_t len;
 
-  a = iobuf_alloc (strchr (mode, 'w') ? 2 : 1, 8192);
+  a = iobuf_alloc (strchr (mode, 'w') ? 2 : 1, IOBUF_BUFFER_SIZE);
   scx = xmalloc (sizeof *scx + 25);
   scx->sock = fd;
   scx->print_only_name = 1;
@@ -1278,7 +1276,7 @@ iobuf_sockopen (int fd, const char *mode)
   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 */
+  iobuf_ioctl (a, IOBUF_IOCTL_NO_CACHE, 1, NULL);
 #else
   a = iobuf_fdopen (fd, mode);
 #endif
@@ -1292,7 +1290,7 @@ iobuf_t
 iobuf_create (const char *fname)
 {
   iobuf_t a;
-  FILEP_OR_FD fp;
+  gnupg_fd_t fp;
   file_filter_ctx_t *fcx;
   size_t len;
   int print_only = 0;
@@ -1300,18 +1298,15 @@ iobuf_create (const char *fname)
 
   if (!fname || (*fname == '-' && !fname[1]))
     {
-      fp = FILEP_OR_FD_FOR_STDOUT;
-#ifdef USE_SETMODE
-      setmode (my_fileno (fp), O_BINARY);
-#endif
+      fp = FD_FOR_STDOUT;
       fname = "[stdout]";
       print_only = 1;
     }
   else if ((fd = check_special_filename (fname)) != -1)
     return iobuf_fdopen (translate_file_handle (fd, 1), "wb");
-  else if ((fp = my_fopen (fname, "wb")) == INVALID_FP)
+  else if ((fp = direct_open (fname, "wb")) == GNUPG_INVALID_FD)
     return NULL;
-  a = iobuf_alloc (2, 8192);
+  a = iobuf_alloc (2, IOBUF_BUFFER_SIZE);
   fcx = xmalloc (sizeof *fcx + strlen (fname));
   fcx->fp = fp;
   fcx->print_only_name = print_only;
@@ -1323,58 +1318,26 @@ 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, a->desc);
+    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 = my_fopen (fname, "ab")))
-    return NULL;
-  a = iobuf_alloc (2, 8192);
-  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);
-
-  return a;
-}
-#endif
 
 iobuf_t
 iobuf_openrw (const char *fname)
 {
   iobuf_t a;
-  FILEP_OR_FD fp;
+  gnupg_fd_t fp;
   file_filter_ctx_t *fcx;
   size_t len;
 
   if (!fname)
     return NULL;
-  else if ((fp = my_fopen (fname, "r+b")) == INVALID_FP)
+  else if ((fp = direct_open (fname, "r+b")) == GNUPG_INVALID_FD)
     return NULL;
-  a = iobuf_alloc (2, 8192);
+  a = iobuf_alloc (2, IOBUF_BUFFER_SIZE);
   fcx = xmalloc (sizeof *fcx + strlen (fname));
   fcx->fp = fp;
   strcpy (fcx->fname, fname);
@@ -1384,20 +1347,25 @@ 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, a->desc);
+    log_debug ("iobuf-%d.%d: openrw `%s'\n", a->no, a->subno,
+               a->desc?a->desc:"?");
 
   return a;
 }
 
 
 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, a ? a->desc : "?",
+       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)
        if (!a->chain && a->filter == file_filter)
@@ -1406,7 +1374,7 @@ iobuf_ioctl (iobuf_t a, int cmd, int intval, void *ptrval)
            b->keep_open = intval;
            return 0;
          }
-#ifdef _WIN32
+#ifdef HAVE_W32_SYSTEM
        else if (!a->chain && a->filter == sock_filter)
          {
            sock_filter_ctx_t *b = a->filter_ov;
@@ -1415,24 +1383,24 @@ 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",
                   ptrval ? (char *) ptrval : "?");
       if (!a && !intval && ptrval)
        {
-#ifndef FILE_FILTER_USES_STDIO
-         fd_cache_invalidate (ptrval);
-#endif
+         if (fd_cache_invalidate (ptrval))
+            return -1;
          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, a ? a->desc : "?",
+                  a ? a->no : -1, a ? a->subno : -1, 
+                   a && a->desc? a->desc : "?",
                   intval);
       for (; a; a = a->chain)
        if (!a->chain && a->filter == file_filter)
@@ -1441,7 +1409,7 @@ iobuf_ioctl (iobuf_t a, int cmd, int intval, void *ptrval)
            b->no_cache = intval;
            return 0;
          }
-#ifdef _WIN32
+#ifdef HAVE_W32_SYSTEM
        else if (!a->chain && a->filter == sock_filter)
          {
            sock_filter_ctx_t *b = a->filter_ov;
@@ -1450,6 +1418,20 @@ iobuf_ioctl (iobuf_t a, int cmd, int intval, void *ptrval)
          }
 #endif
     }
+  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",
+                   ptrval? (const char*)ptrval:"<null>");
+
+       if (!a && !intval && ptrval)
+         {
+           return fd_cache_synchronize (ptrval);
+         }
+      }
+
 
   return -1;
 }
@@ -1533,7 +1515,8 @@ iobuf_push_filter2 (iobuf_t a,
 
   if (DBG_IOBUF)
     {
-      log_debug ("iobuf-%d.%d: push `%s'\n", a->no, a->subno, a->desc);
+      log_debug ("iobuf-%d.%d: push `%s'\n", a->no, a->subno, 
+                 a->desc?a->desc:"?");
       print_chain (a);
     }
 
@@ -1547,7 +1530,7 @@ iobuf_push_filter2 (iobuf_t a,
 /****************
  * Remove an i/o filter.
  */
-int
+static int
 pop_filter (iobuf_t a, int (*f) (void *opaque, int control,
                               iobuf_t chain, byte * buf, size_t * len),
            void *ov)
@@ -1560,7 +1543,8 @@ 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, a->desc);
+    log_debug ("iobuf-%d.%d: pop `%s'\n", a->no, a->subno,
+               a->desc?a->desc:"?");
   if (!a->filter)
     {                          /* this is simple */
       b = a->chain;
@@ -1647,7 +1631,7 @@ underflow (iobuf_t a)
          iobuf_t b = a->chain;
          if (DBG_IOBUF)
            log_debug ("iobuf-%d.%d: pop `%s' in underflow\n",
-                      a->no, a->subno, a->desc);
+                      a->no, a->subno, a->desc?a->desc:"?");
          xfree (a->d.buf);
          xfree (a->real_fname);
          memcpy (a, b, sizeof *a);
@@ -1676,7 +1660,7 @@ underflow (iobuf_t a)
       if (len < a->d.size)
        {
          if (ferror (fp))
-           a->error = gpg_error_from_errno (errno);
+           a->error = gpg_error_from_syserror ();
        }
       a->d.len = len;
       a->d.start = 0;
@@ -1720,8 +1704,8 @@ underflow (iobuf_t a)
            {
              iobuf_t b = a->chain;
              if (DBG_IOBUF)
-               log_debug ("iobuf-%d.%d: pop `%s' in underflow (!len)\n",
-                          a->no, a->subno, a->desc);
+               log_debug ("iobuf-%d.%d: pop in underflow (!len)\n",
+                          a->no, a->subno);
              xfree (a->d.buf);
              xfree (a->real_fname);
              memcpy (a, b, sizeof *a);
@@ -1764,7 +1748,7 @@ iobuf_flush (iobuf_t a)
   if (a->use == 3)
     {                          /* increase the temp buffer */
       unsigned char *newbuf;
-      size_t newsize = a->d.size + 8192;
+      size_t newsize = a->d.size + IOBUF_BUFFER_SIZE;
 
       if (DBG_IOBUF)
        log_debug ("increasing temp iobuf from %lu to %lu\n",
@@ -1803,17 +1787,6 @@ iobuf_readbyte (iobuf_t a)
 {
   int c;
 
-  /* nlimit does not work together with unget */
-  /* nbytes is also not valid! */
-  if (a->unget.buf)
-    {
-      if (a->unget.start < a->unget.len)
-       return a->unget.buf[a->unget.start++];
-      xfree (a->unget.buf);
-      a->unget.buf = NULL;
-      a->nofast &= ~2;
-    }
-
   if (a->nlimit && a->nbytes >= a->nlimit)
     return -1;                 /* forced EOF */
 
@@ -1835,9 +1808,9 @@ iobuf_read (iobuf_t a, void *buffer, unsigned int buflen)
   unsigned char *buf = (unsigned char *)buffer;
   int c, n;
 
-  if (a->unget.buf || a->nlimit)
+  if (a->nlimit)
     {
-      /* handle special cases */
+      /* Handle special cases. */
       for (n = 0; n < buflen; n++)
        {
          if ((c = iobuf_readbyte (a)) == -1)
@@ -1887,6 +1860,7 @@ iobuf_read (iobuf_t a, void *buffer, unsigned int buflen)
 }
 
 
+
 /****************
  * Have a look at the iobuf.
  * NOTE: This only works in special cases.
@@ -1903,7 +1877,7 @@ iobuf_peek (iobuf_t a, byte * buf, unsigned buflen)
     {
       if (underflow (a) == -1)
        return -1;
-      /* and unget this character */
+      /* And unget this character. */
       assert (a->d.start == 1);
       a->d.start = 0;
     }
@@ -2038,49 +2012,111 @@ iobuf_set_limit (iobuf_t a, off_t nlimit)
 
 
 
-/****************
* Return the length of an open file
- */
+/* Return the length of an open file A.  IF OVERFLOW is not NULL it
  will be set to true if the file is larger than what off_t can cope
  with.  The function return 0 on error or on overflow condition.  */
 off_t
-iobuf_get_filelength (iobuf_t a)
+iobuf_get_filelength (iobuf_t a, int *overflow)
 {
   struct stat st;
 
-  if (a->directfp)
+  if (overflow)
+    *overflow = 0;
+  
+  if ( a->directfp )  
     {
       FILE *fp = a->directfp;
-
-      if (!fstat (fileno (fp), &st))
-       return st.st_size;
-      log_error ("fstat() failed: %s\n", strerror (errno));
+      
+      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)
+  for ( ; a; a = a->chain )
+    if ( !a->chain && a->filter == file_filter )
       {
-       file_filter_ctx_t *b = a->filter_ov;
-       FILEP_OR_FD fp = b->fp;
-
-#if defined(HAVE_DOSISH_SYSTEM) && !defined(FILE_FILTER_USES_STDIO)
-       ulong size;
-
-       if ((size = GetFileSize (fp, NULL)) != 0xffffffff)
-         return size;
-       log_error ("GetFileSize for handle %p failed: ec=%d\n",
-                  fp, (int) GetLastError ());
+        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 (my_fileno (fp), &st))
-         return st.st_size;
-       log_error ("fstat() failed: %s\n", strerror (errno));
+        if ( !fstat (FD2INT (fp), &st) )
+          return st.st_size;
+        log_error("fstat() failed: %s\n", strerror(errno) );
 #endif
-       break;
+        break/*the for loop*/;
       }
+  
+    return 0;
+}
 
-  return 0;
+
+/* Return the file descriptor of the underlying file or -1 if it is
+   not available.  */
+int 
+iobuf_get_fd (iobuf_t a)
+{
+  if (a->directfp)
+    return fileno ( (FILE*)a->directfp );
+
+  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;
+
+        return FD2INT (fp);
+      }
+
+  return -1;
 }
 
+
+
 /****************
  * Tell the file position, where the next read will take place
  */
@@ -2152,14 +2188,7 @@ iobuf_seek (iobuf_t a, off_t newpos)
        }
       if (!a)
        return -1;
-#ifdef FILE_FILTER_USES_STDIO
-      if (fseeko (b->fp, newpos, SEEK_SET))
-       {
-         log_error ("can't fseek: %s\n", strerror (errno));
-         return -1;
-       }
-#else
-#ifdef HAVE_DOSISH_SYSTEM
+#ifdef HAVE_W32_SYSTEM
       if (SetFilePointer (b->fp, newpos, NULL, FILE_BEGIN) == 0xffffffff)
        {
          log_error ("SetFilePointer failed on handle %p: ec=%d\n",
@@ -2173,7 +2202,6 @@ iobuf_seek (iobuf_t a, off_t newpos)
          return -1;
        }
 #endif
-#endif
     }
   a->d.len = 0;                        /* discard buffer */
   a->d.start = 0;
@@ -2197,7 +2225,9 @@ iobuf_seek (iobuf_t a, off_t newpos)
 
 
 /****************
- * Retrieve the real filename
+ * Retrieve the real filename.  This is the filename actually used on
+ * disk and not a made up one.  Returns NULL if no real filename is
+ * available.
  */
 const char *
 iobuf_get_real_fname (iobuf_t a)
@@ -2218,7 +2248,7 @@ iobuf_get_real_fname (iobuf_t a)
 
 
 /****************
- * Retrieve the filename
+ * Retrieve the filename.  This name should only be used in diagnostics.
  */
 const char *
 iobuf_get_fname (iobuf_t a)
@@ -2229,35 +2259,20 @@ iobuf_get_fname (iobuf_t a)
        file_filter_ctx_t *b = a->filter_ov;
        return b->fname;
       }
-
   return NULL;
 }
 
-/****************
- * Start the block write mode, see rfc1991.new for details.
- * A value of 0 for N stops this mode (flushes and writes
- * the end marker)
- */
-void
-iobuf_set_block_mode (iobuf_t a, size_t n)
+/* Same as iobuf_get_fname but never returns NULL.  */
+const char *
+iobuf_get_fname_nonnull (iobuf_t a)
 {
-  block_filter_ctx_t *ctx = xcalloc (1, sizeof *ctx);
+  const char *fname;
 
-  assert (a->use == 1 || a->use == 2);
-  ctx->use = a->use;
-  if (!n)
-    {
-      if (a->use == 1)
-       log_debug ("pop_filter called in set_block_mode - please report\n");
-      pop_filter (a, block_filter, NULL);
-    }
-  else
-    {
-      ctx->size = n;           /* only needed for use 2 */
-      iobuf_push_filter (a, block_filter, ctx);
-    }
+  fname = iobuf_get_fname (a);
+  return fname? fname : "[?]";
 }
 
+
 /****************
  * enable partial block mode as described in the OpenPGP draft.
  * LEN is the first length byte on read, but ignored on writes.
@@ -2286,18 +2301,6 @@ iobuf_set_partial_block_mode (iobuf_t a, size_t len)
 }
 
 
-/****************
- * Checks whether the stream is in block mode
- * Note: This does not work if other filters are pushed on the stream.
- */
-int
-iobuf_in_block_mode (iobuf_t a)
-{
-  if (a && a->filter == block_filter)
-    return 1;                  /* yes */
-  return 0;                    /* no */
-}
-
 
 /****************
  * Same as fgets() but if the buffer is too short a larger one will
@@ -2362,40 +2365,19 @@ iobuf_read_line (iobuf_t a, byte ** addr_of_buffer,
   return nbytes;
 }
 
-/* This is the non iobuf specific function */
-int
-iobuf_translate_file_handle (int fd, int for_write)
-{
-#ifdef _WIN32
-  {
-    int x;
-
-    if (fd <= 2)
-      return fd;               /* do not do this for error, stdin, stdout, stderr */
-
-    x = _open_osfhandle (fd, for_write ? 1 : 0);
-    if (x == -1)
-      log_error ("failed to translate osfhandle %p\n", (void *) fd);
-    else
-      {
-       /*log_info ("_open_osfhandle %p yields %d%s\n",
-          (void*)fd, x, for_write? " for writing":"" ); */
-       fd = x;
-      }
-  }
-#endif
-  return fd;
-}
-
 static int
 translate_file_handle (int fd, int for_write)
 {
-#ifdef _WIN32
-#ifdef FILE_FILTER_USES_STDIO
-  fd = iobuf_translate_file_handle (fd, for_write);
-#else
+#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)
       x = (int) GetStdHandle (STD_INPUT_HANDLE);
@@ -2412,7 +2394,59 @@ translate_file_handle (int fd, int for_write)
 
     fd = x;
   }
-#endif
+#else
+  (void)for_write;
 #endif
   return fd;
 }
+
+
+void
+iobuf_skip_rest (iobuf_t a, unsigned long n, int partial)
+{
+  if ( partial )
+    {
+      for (;;)
+        {
+          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;
+              a->nbytes += count;
+              a->d.start = a->d.len;
+           }
+       }
+    } 
+  else
+    {
+      unsigned long remaining = n;
+      while (remaining > 0) 
+        {
+          if (a->nofast || a->d.start >= a->d.len)
+            {
+              if (iobuf_readbyte (a) == -1)
+                {
+                  break;
+               }
+              --remaining;
+           } 
+          else 
+            {
+              unsigned long count = a->d.len - a->d.start;
+              if (count > remaining) 
+                {
+                  count = remaining;
+               }
+              a->nbytes += count;
+              a->d.start += count;
+              remaining -= count;
+           }
+       }
+    }
+}