service_new: ready_confirm_fd
[oweals/gnunet.git] / src / util / bio.c
index e1085faa6c69755c7f9c029579cba98084efda1c..62f4904f7d19367ab973161cbbaaf6e56551f045 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
 /*
      This file is part of GNUnet.
-     (C) 2006, 2009 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2006, 2009, 2013 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      GNUnet 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, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
@@ -14,8 +14,8 @@
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 /**
  * @file util/bio.c
 */
 /**
  * @file util/bio.c
  * @author Christian Grothoff
  */
 #include "platform.h"
  * @author Christian Grothoff
  */
 #include "platform.h"
-#include "gnunet_bio_lib.h"
-#include "gnunet_disk_lib.h"
+#include "gnunet_util_lib.h"
 
 
+#define LOG(kind,...) GNUNET_log_from (kind, "util",__VA_ARGS__)
+
+#ifndef PATH_MAX
+/**
+ * Assumed maximum path length (for source file names).
+ */
+#define PATH_MAX 4096
+#endif
+
+
+/**
+ * Size for I/O buffers.
+ */
 #define BIO_BUFFER_SIZE 65536
 
 #define BIO_BUFFER_SIZE 65536
 
+/**
+ * Maximum size allowed for meta data written/read from disk.
+ * File-sharing limits to 64k, so this should be rather generous.
+ */
 #define MAX_META_DATA (1024 * 1024)
 
 #define MAX_META_DATA (1024 * 1024)
 
+
 /**
  * Handle for buffered reading.
  */
 struct GNUNET_BIO_ReadHandle
 {
 /**
  * Handle for buffered reading.
  */
 struct GNUNET_BIO_ReadHandle
 {
+  /**
+   * Underlying file abstraction.
+   */
   struct GNUNET_DISK_FileHandle *fd;
   struct GNUNET_DISK_FileHandle *fd;
+
+  /**
+   * Error message, NULL if there were no errors.
+   */
   char *emsg;
   char *emsg;
+
+  /**
+   * I/O buffer.  Allocated at the end of the struct, do not free!
+   */
   char *buffer;
   char *buffer;
+
+  /**
+   * Number of bytes available in read @e buffer.
+   */
   size_t have;
   size_t have;
+
+  /**
+   * Total size of @e buffer.
+   */
   size_t size;
   size_t size;
+
+  /**
+   * Current read offset in @e buffer.
+   */
   off_t pos;
 };
 
   off_t pos;
 };
 
@@ -56,8 +96,7 @@ GNUNET_BIO_read_open (const char *fn)
   struct GNUNET_DISK_FileHandle *fd;
   struct GNUNET_BIO_ReadHandle *h;
 
   struct GNUNET_DISK_FileHandle *fd;
   struct GNUNET_BIO_ReadHandle *h;
 
-  fd = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ,
-                              GNUNET_DISK_PERM_NONE);
+  fd = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE);
   if (NULL == fd)
     return NULL;
   h = GNUNET_malloc (sizeof (struct GNUNET_BIO_ReadHandle) + BIO_BUFFER_SIZE);
   if (NULL == fd)
     return NULL;
   h = GNUNET_malloc (sizeof (struct GNUNET_BIO_ReadHandle) + BIO_BUFFER_SIZE);
@@ -74,15 +113,22 @@ GNUNET_BIO_read_open (const char *fn)
  *
  * @param h file handle
  * @param emsg set to the error message
  *
  * @param h file handle
  * @param emsg set to the error message
- * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
  */
 int
  */
 int
-GNUNET_BIO_read_close (struct GNUNET_BIO_ReadHandle *h, char **emsg)
+GNUNET_BIO_read_close (struct GNUNET_BIO_ReadHandle *h,
+                       char **emsg)
 {
 {
-  *emsg = h->emsg;
+  int err;
+
+  err = (NULL == h->emsg) ? GNUNET_OK : GNUNET_SYSERR;
+  if (emsg != NULL)
+    *emsg = h->emsg;
+  else
+    GNUNET_free_non_null (h->emsg);
   GNUNET_DISK_file_close (h->fd);
   GNUNET_free (h);
   GNUNET_DISK_file_close (h->fd);
   GNUNET_free (h);
-  return (NULL == *emsg) ? GNUNET_OK : GNUNET_SYSERR;
+  return err;
 }
 
 
 }
 
 
@@ -93,59 +139,86 @@ GNUNET_BIO_read_close (struct GNUNET_BIO_ReadHandle *h, char **emsg)
  * @param what describes what is being read (for error message creation)
  * @param result the buffer to write the result to
  * @param len the number of bytes to read
  * @param what describes what is being read (for error message creation)
  * @param result the buffer to write the result to
  * @param len the number of bytes to read
- * @return GNUNET_OK on success, GNUNET_SYSERR on failure
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
  */
 int
 GNUNET_BIO_read (struct GNUNET_BIO_ReadHandle *h,
  */
 int
 GNUNET_BIO_read (struct GNUNET_BIO_ReadHandle *h,
-                 const char *what, void *result, size_t len)
+                 const char *what,
+                 void *result, size_t len)
 {
   char *dst = result;
   size_t min;
   size_t pos;
   ssize_t ret;
 
 {
   char *dst = result;
   size_t min;
   size_t pos;
   ssize_t ret;
 
-  if (h->emsg != NULL)
+  if (NULL != h->emsg)
     return GNUNET_SYSERR;
   pos = 0;
   do
     return GNUNET_SYSERR;
   pos = 0;
   do
+  {
+    /* first, use buffer */
+    min = h->have - h->pos;
+    if (min > 0)
     {
     {
-      /* first, use buffer */
-      min = h->have - h->pos;
-      if (min > 0)
-        {
-          if (min > len - pos)
-            min = len - pos;
-          memcpy (&dst[pos], &h->buffer[h->pos], min);
-          h->pos += min;
-          pos += min;
-        }
-      if (pos == len)
-        return GNUNET_OK;       /* done! */
-      GNUNET_assert (h->have == h->pos);
-      /* fill buffer */
-      ret = GNUNET_DISK_file_read (h->fd, h->buffer, h->size);
-      if (ret == -1)
-        {
-          GNUNET_asprintf (&h->emsg,
-                           _("Error reading `%s': %s"),
-                           what, STRERROR (errno));
-          return GNUNET_SYSERR;
-        }
-      if (ret == 0)
-        {
-          GNUNET_asprintf (&h->emsg,
-                           _("Error reading `%s': %s"),
-                           what, _("End of file"));
-          return GNUNET_SYSERR;
-        }
-      h->pos = 0;
-      h->have = ret;
+      if (min > len - pos)
+        min = len - pos;
+      GNUNET_memcpy (&dst[pos], &h->buffer[h->pos], min);
+      h->pos += min;
+      pos += min;
     }
     }
+    if (pos == len)
+      return GNUNET_OK;         /* done! */
+    GNUNET_assert (h->have == h->pos);
+    /* fill buffer */
+    ret = GNUNET_DISK_file_read (h->fd, h->buffer, h->size);
+    if (-1 == ret)
+    {
+      GNUNET_asprintf (&h->emsg,
+                      _("Error reading `%s': %s"),
+                      what,
+                       STRERROR (errno));
+      return GNUNET_SYSERR;
+    }
+    if (0 == ret)
+    {
+      GNUNET_asprintf (&h->emsg,
+                      _("Error reading `%s': %s"),
+                      what,
+                       _("End of file"));
+      return GNUNET_SYSERR;
+    }
+    h->pos = 0;
+    h->have = ret;
+  }
   while (pos < len);            /* should always be true */
   return GNUNET_OK;
 }
 
 
   while (pos < len);            /* should always be true */
   return GNUNET_OK;
 }
 
 
+/**
+ * Read the contents of a binary file into a buffer.
+ *
+ * @param h handle to an open file
+ * @param file name of the source file
+ * @param line line number in the source file
+ * @param result the buffer to write the result to
+ * @param len the number of bytes to read
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
+ */
+int
+GNUNET_BIO_read_fn (struct GNUNET_BIO_ReadHandle *h,
+                    const char *file,
+                    int line,
+                    void *result,
+                    size_t len)
+{
+  char what[PATH_MAX + 1024];
+
+  GNUNET_snprintf (what, sizeof (what), "%s:%d", file, line);
+  return GNUNET_BIO_read (h, what, result, len);
+}
+
+
 /**
  * Read 0-terminated string from a file.
  *
 /**
  * Read 0-terminated string from a file.
  *
@@ -153,41 +226,46 @@ GNUNET_BIO_read (struct GNUNET_BIO_ReadHandle *h,
  * @param what describes what is being read (for error message creation)
  * @param result the buffer to store a pointer to the (allocated) string to
  *        (note that *result could be set to NULL as well)
  * @param what describes what is being read (for error message creation)
  * @param result the buffer to store a pointer to the (allocated) string to
  *        (note that *result could be set to NULL as well)
- * @param maxLen maximum allowed length for the string
- * @return GNUNET_OK on success, GNUNET_SYSERR on failure
+ * @param max_length maximum allowed length for the string
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
  */
 int
 GNUNET_BIO_read_string (struct GNUNET_BIO_ReadHandle *h,
  */
 int
 GNUNET_BIO_read_string (struct GNUNET_BIO_ReadHandle *h,
-                        const char *what, char **result, size_t maxLen)
+                        const char *what,
+                        char **result,
+                        size_t max_length)
 {
   char *buf;
   uint32_t big;
 
   if (GNUNET_OK != GNUNET_BIO_read_int32 (h, &big))
 {
   char *buf;
   uint32_t big;
 
   if (GNUNET_OK != GNUNET_BIO_read_int32 (h, &big))
+  {
+    GNUNET_free_non_null (h->emsg);
+    GNUNET_asprintf (&h->emsg, _("Error reading length of string `%s'"), what);
     return GNUNET_SYSERR;
     return GNUNET_SYSERR;
-  if (big == 0)
-    {
-      *result = NULL;
-      return GNUNET_OK;
-    }
-  if (big > maxLen)
-    {
-      GNUNET_asprintf (&h->emsg,
-                       _("String `%s' longer than allowed (%u > %u)"),
-                       what, big, maxLen);
-      return GNUNET_SYSERR;
-    }
+  }
+  if (0 == big)
+  {
+    *result = NULL;
+    return GNUNET_OK;
+  }
+  if (big > max_length)
+  {
+    GNUNET_asprintf (&h->emsg, _("String `%s' longer than allowed (%u > %u)"),
+                     what, big, max_length);
+    return GNUNET_SYSERR;
+  }
   buf = GNUNET_malloc (big);
   *result = buf;
   buf[--big] = '\0';
   buf = GNUNET_malloc (big);
   *result = buf;
   buf[--big] = '\0';
-  if (big == 0)
+  if (0 == big)
     return GNUNET_OK;
   if (GNUNET_OK != GNUNET_BIO_read (h, what, buf, big))
     return GNUNET_OK;
   if (GNUNET_OK != GNUNET_BIO_read (h, what, buf, big))
-    {
-      GNUNET_free (buf);
-      *result = NULL;
-      return GNUNET_SYSERR;
-    }
+  {
+    GNUNET_free (buf);
+    *result = NULL;
+    return GNUNET_SYSERR;
+  }
   return GNUNET_OK;
 }
 
   return GNUNET_OK;
 }
 
@@ -198,7 +276,7 @@ GNUNET_BIO_read_string (struct GNUNET_BIO_ReadHandle *h,
  * @param h handle to an open file
  * @param what describes what is being read (for error message creation)
  * @param result the buffer to store a pointer to the (allocated) metadata
  * @param h handle to an open file
  * @param what describes what is being read (for error message creation)
  * @param result the buffer to store a pointer to the (allocated) metadata
- * @return GNUNET_OK on success, GNUNET_SYSERR on failure
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
  */
 int
 GNUNET_BIO_read_meta_data (struct GNUNET_BIO_ReadHandle *h,
  */
 int
 GNUNET_BIO_read_meta_data (struct GNUNET_BIO_ReadHandle *h,
@@ -209,29 +287,33 @@ GNUNET_BIO_read_meta_data (struct GNUNET_BIO_ReadHandle *h,
   char *buf;
   struct GNUNET_CONTAINER_MetaData *meta;
 
   char *buf;
   struct GNUNET_CONTAINER_MetaData *meta;
 
-  if (GNUNET_BIO_read_int32__ (h, what, (int32_t *) &size) != GNUNET_OK)
+  if (GNUNET_BIO_read_int32 (h, (int32_t *) & size) != GNUNET_OK)
     return GNUNET_SYSERR;
     return GNUNET_SYSERR;
+  if (size == 0)
+  {
+    *result = NULL;
+    return GNUNET_OK;
+  }
   if (size > MAX_META_DATA)
   if (size > MAX_META_DATA)
-    {
-      GNUNET_asprintf (&h->emsg,
-                       _("Serialized metadata `%s' larger than allowed (%u>%u)"),
-                       what, size, MAX_META_DATA);
-      return GNUNET_SYSERR;
-    }
+  {
+    GNUNET_asprintf (&h->emsg,
+                     _("Serialized metadata `%s' larger than allowed (%u>%u)"),
+                     what, size, MAX_META_DATA);
+    return GNUNET_SYSERR;
+  }
   buf = GNUNET_malloc (size);
   if (GNUNET_OK != GNUNET_BIO_read (h, what, buf, size))
   buf = GNUNET_malloc (size);
   if (GNUNET_OK != GNUNET_BIO_read (h, what, buf, size))
-    {
-      GNUNET_free (buf);
-      return GNUNET_SYSERR;
-    }
+  {
+    GNUNET_free (buf);
+    return GNUNET_SYSERR;
+  }
   meta = GNUNET_CONTAINER_meta_data_deserialize (buf, size);
   if (meta == NULL)
   meta = GNUNET_CONTAINER_meta_data_deserialize (buf, size);
   if (meta == NULL)
-    {
-      GNUNET_free (buf);
-      GNUNET_asprintf (&h->emsg,
-                       _("Metadata `%s' failed to deserialize"), what);
-      return GNUNET_SYSERR;
-    }
+  {
+    GNUNET_free (buf);
+    GNUNET_asprintf (&h->emsg, _("Metadata `%s' failed to deserialize"), what);
+    return GNUNET_SYSERR;
+  }
   GNUNET_free (buf);
   *result = meta;
   return GNUNET_OK;
   GNUNET_free (buf);
   *result = meta;
   return GNUNET_OK;
@@ -242,17 +324,18 @@ GNUNET_BIO_read_meta_data (struct GNUNET_BIO_ReadHandle *h,
  * Read an (u)int32_t.
  *
  * @param h hande to open file
  * Read an (u)int32_t.
  *
  * @param h hande to open file
- * @param what describes what is being read (for error message creation)
+ * @param file name of the source file
+ * @param line line number in the source file
  * @param i address of 32-bit integer to read
  * @param i address of 32-bit integer to read
- * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
 int
  */
 int
-GNUNET_BIO_read_int32__ (struct GNUNET_BIO_ReadHandle *h,
-                         const char *what, int32_t * i)
+GNUNET_BIO_read_int32__ (struct GNUNET_BIO_ReadHandle *h, const char *file,
+                         int line, int32_t * i)
 {
   int32_t big;
 
 {
   int32_t big;
 
-  if (GNUNET_OK != GNUNET_BIO_read (h, what, &big, sizeof (int32_t)))
+  if (GNUNET_OK != GNUNET_BIO_read_fn (h, file, line, &big, sizeof (int32_t)))
     return GNUNET_SYSERR;
   *i = ntohl (big);
   return GNUNET_OK;
     return GNUNET_SYSERR;
   *i = ntohl (big);
   return GNUNET_OK;
@@ -263,17 +346,20 @@ GNUNET_BIO_read_int32__ (struct GNUNET_BIO_ReadHandle *h,
  * Read an (u)int64_t.
  *
  * @param h hande to open file
  * Read an (u)int64_t.
  *
  * @param h hande to open file
- * @param what describes what is being read (for error message creation)
+ * @param file name of the source file
+ * @param line line number in the source file
  * @param i address of 64-bit integer to read
  * @param i address of 64-bit integer to read
- * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
 int
 GNUNET_BIO_read_int64__ (struct GNUNET_BIO_ReadHandle *h,
  */
 int
 GNUNET_BIO_read_int64__ (struct GNUNET_BIO_ReadHandle *h,
-                         const char *what, int64_t * i)
+                         const char *file,
+                         int line,
+                         int64_t *i)
 {
   int64_t big;
 
 {
   int64_t big;
 
-  if (GNUNET_OK != GNUNET_BIO_read (h, what, &big, sizeof (int64_t)))
+  if (GNUNET_OK != GNUNET_BIO_read_fn (h, file, line, &big, sizeof (int64_t)))
     return GNUNET_SYSERR;
   *i = GNUNET_ntohll (big);
   return GNUNET_OK;
     return GNUNET_SYSERR;
   *i = GNUNET_ntohll (big);
   return GNUNET_OK;
@@ -285,9 +371,24 @@ GNUNET_BIO_read_int64__ (struct GNUNET_BIO_ReadHandle *h,
  */
 struct GNUNET_BIO_WriteHandle
 {
  */
 struct GNUNET_BIO_WriteHandle
 {
+  /**
+   * Underlying file handle.
+   */
   struct GNUNET_DISK_FileHandle *fd;
   struct GNUNET_DISK_FileHandle *fd;
+
+  /**
+   * I/O buffer.  Do not free, allocated at the end of the struct.
+   */
   char *buffer;
   char *buffer;
+
+  /**
+   * Number of bytes already in @e buffer.
+   */
   size_t have;
   size_t have;
+
+  /**
+   * Total size of @e buffer.
+   */
   size_t size;
 };
 
   size_t size;
 };
 
@@ -305,19 +406,16 @@ GNUNET_BIO_write_open (const char *fn)
   struct GNUNET_BIO_WriteHandle *h;
 
   fd = GNUNET_DISK_file_open (fn,
   struct GNUNET_BIO_WriteHandle *h;
 
   fd = GNUNET_DISK_file_open (fn,
-                              GNUNET_DISK_OPEN_WRITE |
-                              GNUNET_DISK_OPEN_TRUNCATE |
-                              GNUNET_DISK_OPEN_CREATE,
+                              GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE
+                              | GNUNET_DISK_OPEN_CREATE,
                               GNUNET_DISK_PERM_USER_READ |
                               GNUNET_DISK_PERM_USER_WRITE);
   if (NULL == fd)
     return NULL;
                               GNUNET_DISK_PERM_USER_READ |
                               GNUNET_DISK_PERM_USER_WRITE);
   if (NULL == fd)
     return NULL;
-  h =
-    GNUNET_malloc (sizeof (struct GNUNET_BIO_WriteHandle) + BIO_BUFFER_SIZE);
+  h = GNUNET_malloc (sizeof (struct GNUNET_BIO_WriteHandle) + BIO_BUFFER_SIZE);
   h->buffer = (char *) &h[1];
   h->size = BIO_BUFFER_SIZE;
   h->fd = fd;
   h->buffer = (char *) &h[1];
   h->size = BIO_BUFFER_SIZE;
   h->fd = fd;
-
   return h;
 }
 
   return h;
 }
 
@@ -326,73 +424,79 @@ GNUNET_BIO_write_open (const char *fn)
  * Close an open file for writing.
  *
  * @param h file handle
  * Close an open file for writing.
  *
  * @param h file handle
- * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
  */
 int
 GNUNET_BIO_write_close (struct GNUNET_BIO_WriteHandle *h)
 {
  */
 int
 GNUNET_BIO_write_close (struct GNUNET_BIO_WriteHandle *h)
 {
-  ssize_t wrt;
   int ret;
 
   int ret;
 
-  if (NULL == h->fd)
-    {
-      ret = GNUNET_SYSERR;
-    }
-  else
-    {
-      wrt = GNUNET_DISK_file_write (h->fd, h->buffer, h->have);
-      if (wrt == h->have)
-        ret = GNUNET_OK;
-      else
-        ret = GNUNET_SYSERR;
-      GNUNET_DISK_file_close (h->fd);
-    }
+  ret = GNUNET_SYSERR;
+  if ( (NULL != h->fd) && (GNUNET_OK == (ret = GNUNET_BIO_flush (h))) )
+    GNUNET_DISK_file_close (h->fd);
   GNUNET_free (h);
   return ret;
 }
 
 
   GNUNET_free (h);
   return ret;
 }
 
 
+/**
+ * Force a buffered writer to flush its buffer
+ *
+ * @param h the writer handle
+ * @return #GNUNET_OK upon success.  Upon failure #GNUNET_SYSERR is returned and
+ *           the file is closed
+ */
+int
+GNUNET_BIO_flush (struct GNUNET_BIO_WriteHandle *h)
+{
+  ssize_t ret;
+
+  ret = GNUNET_DISK_file_write (h->fd, h->buffer, h->have);
+  if (ret != h->have)
+  {
+    GNUNET_DISK_file_close (h->fd);
+    h->fd = NULL;
+    return GNUNET_SYSERR;     /* error */
+  }
+  h->have = 0;
+  return GNUNET_OK;
+}
+
+
 /**
  * Write a buffer to a file.
  *
  * @param h handle to open file
  * @param buffer the data to write
  * @param n number of bytes to write
 /**
  * Write a buffer to a file.
  *
  * @param h handle to open file
  * @param buffer the data to write
  * @param n number of bytes to write
- * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
 int
  */
 int
-GNUNET_BIO_write (struct GNUNET_BIO_WriteHandle *h,
-                  const void *buffer, size_t n)
+GNUNET_BIO_write (struct GNUNET_BIO_WriteHandle *h, const void *buffer,
+                  size_t n)
 {
   const char *src = buffer;
   size_t min;
   size_t pos;
 {
   const char *src = buffer;
   size_t min;
   size_t pos;
-  ssize_t ret;
 
   if (NULL == h->fd)
     return GNUNET_SYSERR;
   pos = 0;
   do
 
   if (NULL == h->fd)
     return GNUNET_SYSERR;
   pos = 0;
   do
-    {
-      /* first, just use buffer */
-      min = h->size - h->have;
-      if (min > n - pos)
-        min = n - pos;
-      memcpy (&h->buffer[h->have], &src[pos], min);
-      pos += min;
-      h->have += min;
-      if (pos == n)
-        return GNUNET_OK;       /* done */
-      GNUNET_assert (h->have == h->size);
-      ret = GNUNET_DISK_file_write (h->fd, h->buffer, h->size);
-      if (ret != h->size)
-        {
-          GNUNET_DISK_file_close (h->fd);
-          h->fd = NULL;
-          return GNUNET_SYSERR; /* error */
-        }
-      h->have = 0;
-    }
+  {
+    /* first, just use buffer */
+    min = h->size - h->have;
+    if (min > n - pos)
+      min = n - pos;
+    GNUNET_memcpy (&h->buffer[h->have], &src[pos], min);
+    pos += min;
+    h->have += min;
+    if (pos == n)
+      return GNUNET_OK;         /* done */
+    GNUNET_assert (h->have == h->size);
+    if (GNUNET_OK != GNUNET_BIO_flush (h))
+      return GNUNET_SYSERR;     /* error */
+  }
   while (pos < n);              /* should always be true */
   GNUNET_break (0);
   return GNUNET_OK;
   while (pos < n);              /* should always be true */
   GNUNET_break (0);
   return GNUNET_OK;
@@ -404,10 +508,11 @@ GNUNET_BIO_write (struct GNUNET_BIO_WriteHandle *h,
  *
  * @param h handle to open file
  * @param s string to write (can be NULL)
  *
  * @param h handle to open file
  * @param s string to write (can be NULL)
- * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
 int
  */
 int
-GNUNET_BIO_write_string (struct GNUNET_BIO_WriteHandle *h, const char *s)
+GNUNET_BIO_write_string (struct GNUNET_BIO_WriteHandle *h,
+                        const char *s)
 {
   uint32_t slen;
 
 {
   uint32_t slen;
 
@@ -425,7 +530,7 @@ GNUNET_BIO_write_string (struct GNUNET_BIO_WriteHandle *h, const char *s)
  *
  * @param h handle to open file
  * @param m metadata to write
  *
  * @param h handle to open file
  * @param m metadata to write
- * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
 int
 GNUNET_BIO_write_meta_data (struct GNUNET_BIO_WriteHandle *h,
  */
 int
 GNUNET_BIO_write_meta_data (struct GNUNET_BIO_WriteHandle *h,
@@ -434,32 +539,23 @@ GNUNET_BIO_write_meta_data (struct GNUNET_BIO_WriteHandle *h,
   ssize_t size;
   char *buf;
 
   ssize_t size;
   char *buf;
 
-  size = GNUNET_CONTAINER_meta_data_get_serialized_size (m,
-                                                         GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL
-                                                         |
-                                                         GNUNET_CONTAINER_META_DATA_SERIALIZE_NO_COMPRESS);
+  if (m == NULL)
+    return GNUNET_BIO_write_int32 (h, 0);
+  buf = NULL;
+  size =
+      GNUNET_CONTAINER_meta_data_serialize (m, &buf, MAX_META_DATA,
+                                            GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
   if (size == -1)
   if (size == -1)
+  {
+    GNUNET_free (buf);
     return GNUNET_SYSERR;
     return GNUNET_SYSERR;
-  if (size > MAX_META_DATA)
-    size = MAX_META_DATA;  
-  buf = GNUNET_malloc (size);
-  size = GNUNET_CONTAINER_meta_data_serialize (m,
-                                              buf,
-                                              size,
-                                              GNUNET_CONTAINER_META_DATA_SERIALIZE_PART
-                                              |
-                                              GNUNET_CONTAINER_META_DATA_SERIALIZE_NO_COMPRESS);
-  if (size == -1)
-    {
-      GNUNET_free (buf);
-      return GNUNET_SYSERR;
-    }
-  if ( (GNUNET_OK != GNUNET_BIO_write_int32 (h, (uint32_t) size)) ||
-       (GNUNET_OK != GNUNET_BIO_write (h, buf, size)) )
-    {
-      GNUNET_free (buf);
-      return GNUNET_SYSERR;
-    }
+  }
+  if ((GNUNET_OK != GNUNET_BIO_write_int32 (h, (uint32_t) size)) ||
+      (GNUNET_OK != GNUNET_BIO_write (h, buf, size)))
+  {
+    GNUNET_free (buf);
+    return GNUNET_SYSERR;
+  }
   GNUNET_free (buf);
   return GNUNET_OK;
 }
   GNUNET_free (buf);
   return GNUNET_OK;
 }
@@ -469,13 +565,15 @@ GNUNET_BIO_write_meta_data (struct GNUNET_BIO_WriteHandle *h,
  * Write an (u)int32_t.
  *
  * @param h hande to open file
  * Write an (u)int32_t.
  *
  * @param h hande to open file
- * @param i address of 32-bit integer to write
- * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ * @param i 32-bit integer to write
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
 int
  */
 int
-GNUNET_BIO_write_int32 (struct GNUNET_BIO_WriteHandle *h, int32_t i)
+GNUNET_BIO_write_int32 (struct GNUNET_BIO_WriteHandle *h,
+                        int32_t i)
 {
   int32_t big;
 {
   int32_t big;
+
   big = htonl (i);
   return GNUNET_BIO_write (h, &big, sizeof (int32_t));
 }
   big = htonl (i);
   return GNUNET_BIO_write (h, &big, sizeof (int32_t));
 }
@@ -485,13 +583,15 @@ GNUNET_BIO_write_int32 (struct GNUNET_BIO_WriteHandle *h, int32_t i)
  * Write an (u)int64_t.
  *
  * @param h hande to open file
  * Write an (u)int64_t.
  *
  * @param h hande to open file
- * @param i address of 64-bit integer to write
- * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ * @param i 64-bit integer to write
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
 int
  */
 int
-GNUNET_BIO_write_int64 (struct GNUNET_BIO_WriteHandle *h, int64_t i)
+GNUNET_BIO_write_int64 (struct GNUNET_BIO_WriteHandle *h,
+                        int64_t i)
 {
   int64_t big;
 {
   int64_t big;
+
   big = GNUNET_htonll (i);
   return GNUNET_BIO_write (h, &big, sizeof (int64_t));
 }
   big = GNUNET_htonll (i);
   return GNUNET_BIO_write (h, &big, sizeof (int64_t));
 }