Updated FSF's address.
[gnupg.git] / common / iobuf.c
index 773e299..8f7374f 100644 (file)
@@ -1,5 +1,6 @@
 /* iobuf.c  -  file handling
- * Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003,
+ *               2004, 2006  Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -15,7 +16,8 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
  */
 
 #include <config.h>
 #include "util.h"
 #include "iobuf.h"
 
+/* 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
+
 #undef FILE_FILTER_USES_STDIO
 
 #ifdef HAVE_DOSISH_SYSTEM
@@ -101,7 +108,7 @@ typedef struct close_cache_s *CLOSE_CACHE;
 static CLOSE_CACHE close_cache;
 #endif
 
-#ifdef __MINGW32__
+#ifdef _WIN32
 typedef struct
 {
   int sock;
@@ -112,7 +119,7 @@ typedef struct
   char fname[1];               /* name of the file */
 }
 sock_filter_ctx_t;
-#endif /*__MINGW32__*/
+#endif /*_WIN32*/
 
 /* 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
@@ -580,7 +587,7 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
   return rc;
 }
 
-#ifdef __MINGW32__
+#ifdef _WIN32
 /* Becuase sockets are an special object under Lose32 we have to
  * use a special filter */
 static int
@@ -667,7 +674,7 @@ sock_filter (void *opaque, int control, iobuf_t chain, byte * buf,
     }
   return rc;
 }
-#endif /*__MINGW32__*/
+#endif /*_WIN32*/
 
 /****************
  * This is used to implement the block write mode.
@@ -675,10 +682,11 @@ sock_filter (void *opaque, int control, iobuf_t chain, byte * buf,
  * without a filter
  */
 static int
-block_filter (void *opaque, int control, iobuf_t chain, byte * buf,
+block_filter (void *opaque, int control, iobuf_t chain, byte * buffer,
              size_t * ret_len)
 {
   block_filter_ctx_t *a = opaque;
+  char *buf = (char *)buffer;
   size_t size = *ret_len;
   int c, needed, rc = 0;
   char *p;
@@ -761,32 +769,23 @@ block_filter (void *opaque, int control, iobuf_t chain, byte * buf,
                          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)
@@ -875,39 +874,7 @@ block_filter (void *opaque, int control, iobuf_t chain, byte * buf,
            }
        }
       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)
     {
@@ -975,10 +942,7 @@ block_filter (void *opaque, int control, iobuf_t chain, byte * buf,
              a->buflen = 0;
            }
          else
-           {
-             iobuf_writebyte (chain, 0);
-             iobuf_writebyte (chain, 0);
-           }
+           BUG ();
        }
       else if (a->size)
        {
@@ -1096,7 +1060,7 @@ iobuf_cancel (iobuf_t a)
       if (s && *s)
        {
 #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
-         remove_name = m_strdup (s);
+         remove_name = xstrdup (s);
 #else
          remove (s);
 #endif
@@ -1158,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)
 {
@@ -1171,7 +1134,7 @@ check_special_filename (const char *fname)
       int i;
 
       fname += 2;
-      for (i = 0; isdigit (fname[i]); i++)
+      for (i = 0; digitp (fname+i); i++)
        ;
       if (!fname[i])
        return atoi (fname);
@@ -1179,6 +1142,17 @@ 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;
+}
+
 /****************
  * Create a head iobuf for reading from a file
  * returns: NULL if an error occures and sets errno
@@ -1262,12 +1236,12 @@ iobuf_t
 iobuf_sockopen (int fd, const char *mode)
 {
   iobuf_t a;
-#ifdef __MINGW32__
+#ifdef _WIN32
   sock_filter_ctx_t *scx;
   size_t len;
 
   a = iobuf_alloc (strchr (mode, 'w') ? 2 : 1, 8192);
-  scx = m_alloc (sizeof *scx + 25);
+  scx = xmalloc (sizeof *scx + 25);
   scx->sock = fd;
   scx->print_only_name = 1;
   sprintf (scx->fname, "[sock %d]", fd);
@@ -1405,7 +1379,7 @@ iobuf_ioctl (iobuf_t a, int cmd, int intval, void *ptrval)
            b->keep_open = intval;
            return 0;
          }
-#ifdef __MINGW32__
+#ifdef _WIN32
        else if (!a->chain && a->filter == sock_filter)
          {
            sock_filter_ctx_t *b = a->filter_ov;
@@ -1440,7 +1414,7 @@ iobuf_ioctl (iobuf_t a, int cmd, int intval, void *ptrval)
            b->no_cache = intval;
            return 0;
          }
-#ifdef __MINGW32__
+#ifdef _WIN32
        else if (!a->chain && a->filter == sock_filter)
          {
            sock_filter_ctx_t *b = a->filter_ov;
@@ -1546,7 +1520,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)
@@ -1762,7 +1736,7 @@ iobuf_flush (iobuf_t a)
 
   if (a->use == 3)
     {                          /* increase the temp buffer */
-      char *newbuf;
+      unsigned char *newbuf;
       size_t newsize = a->d.size + 8192;
 
       if (DBG_IOBUF)
@@ -1829,8 +1803,9 @@ iobuf_readbyte (iobuf_t a)
 
 
 int
-iobuf_read (iobuf_t a, byte * buf, unsigned buflen)
+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)
@@ -1915,7 +1890,7 @@ iobuf_peek (iobuf_t a, byte * buf, unsigned buflen)
 
 
 int
-iobuf_writebyte (iobuf_t a, unsigned c)
+iobuf_writebyte (iobuf_t a, unsigned int c)
 {
   int rc;
 
@@ -1933,8 +1908,9 @@ iobuf_writebyte (iobuf_t a, unsigned c)
 
 
 int
-iobuf_write (iobuf_t a, byte * buf, unsigned buflen)
+iobuf_write (iobuf_t a, const void *buffer, unsigned int buflen)
 {
+  const unsigned char *buf = (const unsigned char *)buffer;
   int rc;
 
   if (a->directfp)
@@ -2035,49 +2011,110 @@ 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;
+    struct stat st;
 
-  if (a->directfp)
-    {
-      FILE *fp = a->directfp;
+    if (overflow)
+      *overflow = 0;
 
-      if (!fstat (fileno (fp), &st))
-       return st.st_size;
-      log_error ("fstat() failed: %s\n", strerror (errno));
-      return 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) );
+       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;
-       FILEP_OR_FD fp = b->fp;
+    /* 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;
+           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 ());
+            ulong size;
+            static int (* __stdcall get_file_size_ex) 
+              (void *handle, LARGE_INTEGER *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 becuase it seem that GetFileSize won't
+                   return a proper error in case a file is larger than
+                   4GB. */
+                LARGE_INTEGER size;
+                
+                if (get_file_size_ex (fp, &size))
+                  {
+                    if (!size.u.HighPart)
+                      return size.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(my_fileno(fp), &st) )
+               return st.st_size;
+           log_error("fstat() failed: %s\n", strerror(errno) );
 #endif
-       break;
+           break;
+       }
+
+    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;
+        FILEP_OR_FD fp = b->fp;
+
+        return my_fileno (fp);
       }
 
-  return 0;
+  return -1;
 }
 
+
+
 /****************
  * Tell the file position, where the next read will take place
  */
@@ -2230,30 +2267,6 @@ iobuf_get_fname (iobuf_t a)
   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)
-{
-  block_filter_ctx_t *ctx = xcalloc (1, sizeof *ctx);
-
-  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);
-    }
-}
 
 /****************
  * enable partial block mode as described in the OpenPGP draft.
@@ -2283,18 +2296,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
@@ -2311,7 +2312,7 @@ iobuf_read_line (iobuf_t a, byte ** addr_of_buffer,
                 unsigned *length_of_buffer, unsigned *max_length)
 {
   int c;
-  char *buffer = *addr_of_buffer;
+  char *buffer = (char *)*addr_of_buffer;
   unsigned length = *length_of_buffer;
   unsigned nbytes = 0;
   unsigned maxlen = *max_length;
@@ -2321,7 +2322,7 @@ iobuf_read_line (iobuf_t a, byte ** addr_of_buffer,
     {                          /* must allocate a new buffer */
       length = 256;
       buffer = xmalloc (length);
-      *addr_of_buffer = buffer;
+      *addr_of_buffer = (unsigned char *)buffer;
       *length_of_buffer = length;
     }
 
@@ -2344,7 +2345,7 @@ iobuf_read_line (iobuf_t a, byte ** addr_of_buffer,
          length += 3;          /* correct for the reserved byte */
          length += length < 1024 ? 256 : 1024;
          buffer = xrealloc (buffer, length);
-         *addr_of_buffer = buffer;
+         *addr_of_buffer = (unsigned char *)buffer;
          *length_of_buffer = length;
          length -= 3;          /* and reserve again */
          p = buffer + nbytes;
@@ -2363,7 +2364,7 @@ iobuf_read_line (iobuf_t a, byte ** addr_of_buffer,
 int
 iobuf_translate_file_handle (int fd, int for_write)
 {
-#ifdef __MINGW32__
+#ifdef _WIN32
   {
     int x;
 
@@ -2387,7 +2388,7 @@ iobuf_translate_file_handle (int fd, int for_write)
 static int
 translate_file_handle (int fd, int for_write)
 {
-#ifdef __MINGW32__
+#ifdef _WIN32
 #ifdef FILE_FILTER_USES_STDIO
   fd = iobuf_translate_file_handle (fd, for_write);
 #else
@@ -2413,3 +2414,54 @@ translate_file_handle (int fd, int 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;
+           }
+       }
+    }
+}