fix
[oweals/gnunet.git] / src / namestore / plugin_namestore_flat.c
index fb6ece5ecbc25bcc544d05e910e13f5beba9f5d9..e16fe91b7b88b30f74ae5361436f54632b1add4d 100644 (file)
@@ -1,27 +1,26 @@
  /*
   * This file is part of GNUnet
-  * Copyright (C) 2009-2015 Christian Grothoff (and other contributing authors)
+  * Copyright (C) 2009-2015, 2018 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
-  * by the Free Software Foundation; either version 3, or (at your
-  * option) any later version.
+  * GNUnet is free software: you can redistribute it and/or modify it
+  * under the terms of the GNU Affero General Public License as published
+  * by the Free Software Foundation, either version 3 of the License,
+  * or (at your option) any later version.
   *
   * GNUnet is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-  * General Public License for more details.
+  * Affero General Public License for more details.
   *
-  * 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., 51 Franklin Street, Fifth Floor,
-  * Boston, MA 02110-1301, USA.
+  * You should have received a copy of the GNU Affero General Public License
+  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
 
 /**
  * @file namestore/plugin_namestore_flat.c
  * @brief file-based namestore backend
  * @author Martin Schanzenbach
+ * @author Christian Grothoff
  */
 
 #include "platform.h"
@@ -48,54 +47,15 @@ struct Plugin
    */
   struct GNUNET_CONTAINER_MultiHashMap *hm;
 
-  /**
-   * Offset
-   */
-  uint32_t offset;
-
-  /**
-   * Target Offset
-   */
-  uint32_t target_offset;
-
-  /**
-   * Iterator closure
-   */
-  void *iter_cls;
-
-  /**
-   * Iterator
-   */
-  GNUNET_NAMESTORE_RecordIterator iter;
-
-  /**
-   * Zone to iterate
-   */
-  const struct GNUNET_CRYPTO_EcdsaPrivateKey *iter_zone;
-
-  /**
-   * PKEY to look for in zone to name
-   */
-  struct GNUNET_CRYPTO_EcdsaPublicKey *iter_pkey;
-
-  /**
-   * Iteration result found
-   */
-  int iter_result_found;
-
 };
 
+
 struct FlatFileEntry
 {
   /**
    * Entry zone
    */
-  struct GNUNET_CRYPTO_EcdsaPrivateKey *private_key;
-
-  /**
-   * Entry zone pkey
-   */
-  struct GNUNET_CRYPTO_EcdsaPublicKey *pkey;
+  struct GNUNET_CRYPTO_EcdsaPrivateKey private_key;
 
   /**
    * Record cound
@@ -133,10 +93,8 @@ static int
 database_setup (struct Plugin *plugin)
 {
   char *afsdir;
-  char *key_str;
   char *record_data;
   char *zone_private_key;
-  char *pkey;
   char *record_data_b64;
   char *buffer;
   char *line;
@@ -144,23 +102,27 @@ database_setup (struct Plugin *plugin)
   char *rvalue;
   char *record_count;
   size_t record_data_size;
-  size_t size;
+  uint64_t size;
   struct GNUNET_HashCode hkey;
   struct GNUNET_DISK_FileHandle *fh;
-  struct FlatFileEntry *entry; 
+  struct FlatFileEntry *entry;
 
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, 
+      GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
                                                "namestore-flat",
-                                               "FILENAME", &afsdir))
+                                               "FILENAME",
+                                              &afsdir))
   {
     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
-                               "namestore-flat", "FILENAME");
+                               "namestore-flat",
+                              "FILENAME");
     return GNUNET_SYSERR;
   }
-  if (GNUNET_OK != GNUNET_DISK_file_test (afsdir))
+  if (GNUNET_OK !=
+      GNUNET_DISK_file_test (afsdir))
   {
-    if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (afsdir))
+    if (GNUNET_OK !=
+       GNUNET_DISK_directory_create_for_file (afsdir))
     {
       GNUNET_break (0);
       GNUNET_free (afsdir);
@@ -185,78 +147,145 @@ database_setup (struct Plugin *plugin)
          afsdir);
     return GNUNET_SYSERR;
   }
-
-  if (GNUNET_SYSERR == GNUNET_DISK_file_size (afsdir,
-                                              &size,
-                                              GNUNET_YES,
-                                              GNUNET_YES))
+  if (GNUNET_SYSERR ==
+      GNUNET_DISK_file_size (afsdir,
+                             &size,
+                             GNUNET_YES,
+                             GNUNET_YES))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
          _("Unable to get filesize: %s.\n"),
          afsdir);
+    GNUNET_DISK_file_close (fh);
     return GNUNET_SYSERR;
   }
 
-  buffer = GNUNET_malloc (size);
-
-  if (GNUNET_SYSERR == GNUNET_DISK_file_read (fh,
-                                              buffer,
-                                              size))
+  buffer = GNUNET_malloc (size + 1);
+  if (GNUNET_SYSERR ==
+      GNUNET_DISK_file_read (fh,
+                             buffer,
+                             size))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
          _("Unable to read file: %s.\n"),
          afsdir);
+    GNUNET_free (buffer);
+    GNUNET_DISK_file_close (fh);
     return GNUNET_SYSERR;
   }
-
+  buffer[size] = '\0';
   GNUNET_DISK_file_close (fh);
 
-  line = strtok ("\n", buffer);
-  while (line != NULL) {
-    zone_private_key = strtok (",", line);
-    pkey = strtok (NULL, line);
-    rvalue = strtok (NULL, line);
-    record_count = strtok (NULL, line);
-    record_data_b64 = strtok (NULL, line);
-    label = strtok (NULL, line);
-    line = strtok ("\n", buffer);
-    entry = GNUNET_malloc (sizeof (struct FlatFileEntry));
-    GNUNET_CRYPTO_ecdsa_public_key_from_string (pkey,
-                                                strlen (pkey),
-                                                entry->pkey);
-    sscanf (rvalue, "%lu", &entry->rvalue);
-    sscanf (record_count, "%u", &entry->record_count);
-    entry->label = GNUNET_strdup (label);
-    record_data_size = GNUNET_STRINGS_base64_decode (record_data_b64,
-                                                     strlen (record_data_b64),
-                                                     &record_data);
-    entry->record_data = 
-      GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Data) * entry->record_count);
-    GNUNET_GNSRECORD_records_deserialize (record_data_size,
-                                          record_data,
-                                          entry->record_count,
-                                          entry->record_data);
-    GNUNET_free (record_data);
-    GNUNET_STRINGS_base64_decode (zone_private_key,
-                                  strlen (zone_private_key),
-                                  (char**)&entry->private_key);
-    key_str = GNUNET_malloc (strlen (label) + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
-    memcpy (key_str, label, strlen (label));
-    memcpy (key_str+strlen(label),
-            entry->private_key,
-            sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
-    GNUNET_CRYPTO_hash (key_str,
-                        strlen (key_str),
-                        &hkey);
-    GNUNET_free (key_str);
-    if (GNUNET_OK != 
-        GNUNET_CONTAINER_multihashmap_put (plugin->hm,
-                                           &hkey,
-                                           entry,
-                                           GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+  if (0 < size)
+  {
+    line = strtok (buffer, "\n");
+    while (line != NULL)
     {
-      GNUNET_free (entry);
-      GNUNET_break (0);
+      zone_private_key = strtok (line, ",");
+      if (NULL == zone_private_key)
+        break;
+      rvalue = strtok (NULL, ",");
+      if (NULL == rvalue)
+        break;
+      record_count = strtok (NULL, ",");
+      if (NULL == record_count)
+        break;
+      record_data_b64 = strtok (NULL, ",");
+      if (NULL == record_data_b64)
+        break;
+      label = strtok (NULL, ",");
+      if (NULL == label)
+        break;
+      line = strtok (NULL, "\n");
+      entry = GNUNET_new (struct FlatFileEntry);
+      {
+        unsigned long long ll;
+
+        if (1 != sscanf (rvalue,
+                         "%llu",
+                         &ll))
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                      "Error parsing entry\n");
+          GNUNET_free (entry);
+          break;
+        }
+        entry->rvalue = (uint64_t) ll;
+      }
+      {
+        unsigned int ui;
+
+        if (1 != sscanf (record_count,
+                         "%u",
+                         &ui))
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                      "Error parsing entry\n");
+          GNUNET_free (entry);
+          break;
+        }
+        entry->record_count = (uint32_t) ui;
+      }
+      entry->label = GNUNET_strdup (label);
+      record_data_size
+       = GNUNET_STRINGS_base64_decode (record_data_b64,
+                                       strlen (record_data_b64),
+                                       (void **) &record_data);
+      entry->record_data =
+        GNUNET_new_array (entry->record_count,
+                         struct GNUNET_GNSRECORD_Data);
+      if (GNUNET_OK !=
+         GNUNET_GNSRECORD_records_deserialize (record_data_size,
+                                               record_data,
+                                               entry->record_count,
+                                               entry->record_data))
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                    "Unable to deserialize record %s\n",
+                   label);
+        GNUNET_free (entry->label);
+        GNUNET_free (entry);
+        GNUNET_free (record_data);
+        break;
+      }
+      GNUNET_free (record_data);
+
+      {
+        struct GNUNET_CRYPTO_EcdsaPrivateKey *private_key;
+
+        GNUNET_STRINGS_base64_decode (zone_private_key,
+                                      strlen (zone_private_key),
+                                      (void**)&private_key);
+        entry->private_key = *private_key;
+        GNUNET_free (private_key);
+      }
+
+      {
+        char *key;
+        size_t key_len;
+
+        key_len = strlen (label) + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey);
+        key = GNUNET_malloc (strlen (label) + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
+        GNUNET_memcpy (key,
+                       label,
+                       strlen (label));
+        GNUNET_memcpy (key+strlen(label),
+                       &entry->private_key,
+                       sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
+        GNUNET_CRYPTO_hash (key,
+                            key_len,
+                            &hkey);
+        GNUNET_free (key);
+      }
+      if (GNUNET_OK !=
+          GNUNET_CONTAINER_multihashmap_put (plugin->hm,
+                                             &hkey,
+                                             entry,
+                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+      {
+        GNUNET_free (entry);
+        GNUNET_break (0);
+      }
     }
   }
   GNUNET_free (buffer);
@@ -268,6 +297,8 @@ database_setup (struct Plugin *plugin)
  * Store values in hashmap in file and free data
  *
  * @param plugin the plugin context
+ * @param key key in the map
+ * @param value a `struct FlatFileEntry`
  */
 static int
 store_and_free_entries (void *cls,
@@ -278,59 +309,68 @@ store_and_free_entries (void *cls,
   struct FlatFileEntry *entry = value;
   char *line;
   char *zone_private_key;
-  char *pkey;
-  char *rvalue;
-  char *record_count;
-  char *record_data_buf;
   char *record_data_b64;
-  size_t record_data_len;
+  ssize_t data_size;
 
-  GNUNET_STRINGS_base64_encode ((char*)entry->private_key,
+  (void) key;
+  GNUNET_STRINGS_base64_encode (&entry->private_key,
                                 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
                                 &zone_private_key);
-  pkey = GNUNET_CRYPTO_ecdsa_public_key_to_string (entry->pkey);
-  GNUNET_asprintf (&rvalue, "%hhu", entry->rvalue);
-  GNUNET_asprintf (&record_count, "%u", entry->record_count);
-
-  record_data_len = GNUNET_GNSRECORD_records_get_size (entry->record_count,
-                                                       entry->record_data);
-
-  record_data_buf = GNUNET_malloc (record_data_len);
-  GNUNET_GNSRECORD_records_serialize (entry->record_count,
-                                      entry->record_data,
-                                      record_data_len,
-                                      record_data_buf);
-
-  GNUNET_STRINGS_base64_encode (record_data_buf,
-                                strlen (record_data_buf),
-                                &record_data_b64);
-
+  data_size = GNUNET_GNSRECORD_records_get_size (entry->record_count,
+                                                 entry->record_data);
+  if (data_size < 0)
+  {
+    GNUNET_break (0);
+    GNUNET_free (zone_private_key);
+    return GNUNET_SYSERR;
+  }
+  if (data_size >= UINT16_MAX)
+  {
+    GNUNET_break (0);
+    GNUNET_free (zone_private_key);
+    return GNUNET_SYSERR;
+  }
+  {
+    char data[data_size];
+    ssize_t ret;
+
+    ret = GNUNET_GNSRECORD_records_serialize (entry->record_count,
+                                             entry->record_data,
+                                             data_size,
+                                             data);
+    if ( (ret < 0) ||
+        (data_size != ret) )
+    {
+      GNUNET_break (0);
+      GNUNET_free (zone_private_key);
+      return GNUNET_SYSERR;
+    }
+    GNUNET_STRINGS_base64_encode (data,
+                                  data_size,
+                                  &record_data_b64);
+  }
   GNUNET_asprintf (&line,
-                   "%s,%s,%s,%s,%s,%s\n",
+                   "%s,%llu,%u,%s,%s\n",
                    zone_private_key,
-                   pkey,
-                   rvalue,
-                   record_count,
+                   (unsigned long long) entry->rvalue,
+                   (unsigned int) entry->record_count,
                    record_data_b64,
                    entry->label);
-
-  GNUNET_free (rvalue);
-  GNUNET_free (record_count);
-  GNUNET_free (record_data_buf);
   GNUNET_free (record_data_b64);
+  GNUNET_free (zone_private_key);
 
   GNUNET_DISK_file_write (fh,
                           line,
                           strlen (line));
 
-  GNUNET_free (entry->private_key);
-  GNUNET_free (entry->pkey);
+  GNUNET_free (line);
   GNUNET_free (entry->label);
   GNUNET_free (entry->record_data);
   GNUNET_free (entry);
   return GNUNET_YES;
 }
 
+
 /**
  * Shutdown database connection and associate data
  * structures.
@@ -340,16 +380,18 @@ static void
 database_shutdown (struct Plugin *plugin)
 {
   struct GNUNET_DISK_FileHandle *fh;
+
   fh = GNUNET_DISK_file_open (plugin->fn,
                               GNUNET_DISK_OPEN_CREATE |
-                              GNUNET_DISK_OPEN_TRUNCATE,
+                              GNUNET_DISK_OPEN_TRUNCATE |
+                              GNUNET_DISK_OPEN_READWRITE,
                               GNUNET_DISK_PERM_USER_WRITE |
                               GNUNET_DISK_PERM_USER_READ);
   if (NULL == fh)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-         _("Unable to initialize file: %s.\n"),
-         plugin->fn);
+                _("Unable to initialize file: %s.\n"),
+                plugin->fn);
     return;
   }
 
@@ -373,79 +415,67 @@ database_shutdown (struct Plugin *plugin)
  * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  */
 static int
-namestore_store_records (void *cls,
-                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
-                         const char *label,
-                         unsigned int rd_count,
-                         const struct GNUNET_GNSRECORD_Data *rd)
+namestore_flat_store_records (void *cls,
+                              const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
+                              const char *label,
+                              unsigned int rd_count,
+                              const struct GNUNET_GNSRECORD_Data *rd)
 {
   struct Plugin *plugin = cls;
-  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
   uint64_t rvalue;
-  size_t data_size;
-  unsigned int i;
-  char *key_str;
+  size_t key_len;
+  char *key;
   struct GNUNET_HashCode hkey;
   struct FlatFileEntry *entry;
 
-  memset (&pkey, 0, sizeof (pkey));
-  for (i=0;i<rd_count;i++)
-    if (GNUNET_GNSRECORD_TYPE_PKEY == rd[i].record_type)
-    {
-      GNUNET_break (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) == rd[i].data_size);
-      memcpy (&pkey,
-              rd[i].data,
-              rd[i].data_size);
-      break;
-    }
-  rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
-  data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
-  if (data_size > 64 * 65536)
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  char data[data_size];
-
-  if (data_size != GNUNET_GNSRECORD_records_serialize (rd_count, rd,
-                                                       data_size, data))
+  rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
+                                    UINT64_MAX);
+  key_len = strlen (label) + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey);
+  key = GNUNET_malloc (key_len);
+  GNUNET_memcpy (key,
+                 label,
+                 strlen (label));
+  GNUNET_memcpy (key + strlen(label),
+                 zone_key,
+                 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
+  GNUNET_CRYPTO_hash (key,
+                      key_len,
+                      &hkey);
+  GNUNET_CONTAINER_multihashmap_remove_all (plugin->hm,
+                                            &hkey);
+  if (0 == rd_count)
   {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                     "sqlite",
+                     "Record deleted\n");
+    return GNUNET_OK;
   }
-
-  key_str = GNUNET_malloc (strlen (label) + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
-  memcpy (key_str, label, strlen (label));
-  memcpy (key_str+strlen(label),
-          zone_key,
-          sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
-  GNUNET_CRYPTO_hash (key_str,
-                      strlen (key_str),
-                      &hkey);
-
-  GNUNET_CONTAINER_multihashmap_remove_all (plugin->hm, &hkey);
-
-  if (0 != rd_count)
+  entry = GNUNET_new (struct FlatFileEntry);
+  GNUNET_asprintf (&entry->label,
+                   label,
+                   strlen (label));
+  GNUNET_memcpy (&entry->private_key,
+                 zone_key,
+                 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
+  entry->rvalue = rvalue;
+  entry->record_count = rd_count;
+  entry->record_data = GNUNET_new_array (rd_count,
+                                         struct GNUNET_GNSRECORD_Data);
+  for (unsigned int i = 0; i < rd_count; i++)
   {
-    entry = GNUNET_malloc (sizeof (struct FlatFileEntry));
-    entry->private_key = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
-    memcpy (&entry->private_key,
-            zone_key,
-            sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
-    entry->pkey = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
-    memcpy (entry->pkey,
-            &pkey,
-            sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
-    entry->rvalue = rvalue;
-    entry->record_count = rd_count;
-    entry->record_data = GNUNET_malloc (data_size);
-    memcpy (&entry->record_data, data, data_size);
-    return GNUNET_CONTAINER_multihashmap_put (plugin->hm,
-                                              &hkey,
-                                              entry,
-                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+    entry->record_data[i].expiration_time = rd[i].expiration_time;
+    entry->record_data[i].record_type = rd[i].record_type;
+    entry->record_data[i].flags = rd[i].flags;
+    entry->record_data[i].data_size = rd[i].data_size;
+    entry->record_data[i].data = GNUNET_malloc (rd[i].data_size);
+    GNUNET_memcpy ((char*)entry->record_data[i].data,
+                   rd[i].data,
+                   rd[i].data_size);
   }
-  return GNUNET_NO;
+  return GNUNET_CONTAINER_multihashmap_put (plugin->hm,
+                                            &hkey,
+                                            entry,
+                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
 }
 
 
@@ -457,134 +487,222 @@ namestore_store_records (void *cls,
  * @param label name of the record in the zone
  * @param iter function to call with the result
  * @param iter_cls closure for @a iter
- * @return #GNUNET_OK on success, else #GNUNET_SYSERR
+ * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
  */
 static int
-namestore_lookup_records (void *cls,
-                          const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
-                          const char *label,
-                          GNUNET_NAMESTORE_RecordIterator iter,
-                          void *iter_cls)
+namestore_flat_lookup_records (void *cls,
+                               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+                               const char *label,
+                               GNUNET_NAMESTORE_RecordIterator iter,
+                               void *iter_cls)
 {
   struct Plugin *plugin = cls;
   struct FlatFileEntry *entry;
   struct GNUNET_HashCode hkey;
-  char *key_str;
+  char *key;
+  size_t key_len;
 
   if (NULL == zone)
   {
+    GNUNET_break (0);
     return GNUNET_SYSERR;
   }
-  key_str = GNUNET_malloc (strlen (label) + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
-  memcpy (key_str, label, strlen (label));
-  memcpy (key_str+strlen(label),
-          zone,
-          sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
-  GNUNET_CRYPTO_hash (key_str,
-                      strlen (key_str),
+  key_len = strlen (label) + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey);
+  key = GNUNET_malloc (key_len);
+  GNUNET_memcpy (key,
+                label,
+                strlen (label));
+  GNUNET_memcpy (key+strlen(label),
+                zone,
+                sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
+  GNUNET_CRYPTO_hash (key,
+                      key_len,
                       &hkey);
-  GNUNET_free (key_str);
+  GNUNET_free (key);
 
-  entry = GNUNET_CONTAINER_multihashmap_get (plugin->hm, &hkey);
+  entry = GNUNET_CONTAINER_multihashmap_get (plugin->hm,
+                                            &hkey);
 
   if (NULL == entry)
     return GNUNET_NO;
   if (NULL != iter)
-    iter (iter_cls, entry->private_key, entry->label, entry->record_count, entry->record_data);
+    iter (iter_cls,
+         0,
+         &entry->private_key,
+         entry->label,
+         entry->record_count,
+         entry->record_data);
   return GNUNET_YES;
 }
 
 
+/**
+ * Closure for #iterate_zones.
+ */
+struct IterateContext
+{
+  /**
+   * How many more records should we skip before returning results?
+   */
+  uint64_t offset;
+
+  /**
+   * How many more records should we return?
+   */
+  uint64_t limit;
+
+  /**
+   * What is the position of the current entry, counting
+   * starts from 1.
+   */
+  uint64_t pos;
+
+  /**
+   * Target zone.
+   */
+  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone;
+
+  /**
+   * Function to call on each record.
+   */
+  GNUNET_NAMESTORE_RecordIterator iter;
+
+  /**
+   * Closure for @e iter.
+   */
+  void *iter_cls;
+
+};
+
+
+/**
+ * Helper function for #namestore_flat_iterate_records().
+ *
+ * @param cls a `struct IterateContext`
+ * @param key unused
+ * @param value a `struct FlatFileEntry`
+ * @return #GNUNET_YES to continue the iteration
+ */
 static int
 iterate_zones (void *cls,
                const struct GNUNET_HashCode *key,
                void *value)
 {
-  struct Plugin *plugin = cls;
+  struct IterateContext *ic = cls;
   struct FlatFileEntry *entry = value;
 
-
-  if ((plugin->target_offset > plugin->offset) ||
-      (0 != memcmp (entry->private_key,
-                    plugin->iter_zone,
-                    sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))) {
-    plugin->offset++;
+  (void) key;
+  if (0 == ic->limit)
+    return GNUNET_NO;
+  if ( (NULL != ic->zone) &&
+       (0 != memcmp (&entry->private_key,
+                     ic->zone,
+                     sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))) )
+    return GNUNET_YES;
+  ic->pos++;
+  if (ic->offset > 0)
+  {
+    ic->offset--;
     return GNUNET_YES;
   }
-
-  plugin->iter (plugin->iter_cls,
-                entry->private_key,
-                entry->label,
-                entry->record_count,
-                entry->record_data);
-  plugin->iter_result_found = GNUNET_YES;
-  return GNUNET_NO;
+  ic->iter (ic->iter_cls,
+           ic->pos,
+            &entry->private_key,
+            entry->label,
+            entry->record_count,
+            entry->record_data);
+  ic->limit--;
+  if (0 == ic->limit)
+    return GNUNET_NO;
+  return GNUNET_YES;
 }
 
+
 /**
  * Iterate over the results for a particular key and zone in the
  * datastore.  Will return at most one result to the iterator.
  *
  * @param cls closure (internal context for the plugin)
  * @param zone hash of public key of the zone, NULL to iterate over all zones
- * @param offset offset in the list of all matching records
+ * @param serial serial number to exclude in the list of all matching records
+ * @param limit maximum number of results to return to @a iter
  * @param iter function to call with the result
  * @param iter_cls closure for @a iter
- * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
+ * @return #GNUNET_OK on success, #GNUNET_NO if there were no more results, #GNUNET_SYSERR on error
  */
 static int
-namestore_iterate_records (void *cls,
-                           const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
-                           uint64_t offset,
-                           GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
+namestore_flat_iterate_records (void *cls,
+                                const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+                                uint64_t serial,
+                                uint64_t limit,
+                                GNUNET_NAMESTORE_RecordIterator iter,
+                                void *iter_cls)
 {
   struct Plugin *plugin = cls;
-  plugin->target_offset = offset;
-  plugin->offset = 0;
-  plugin->iter = iter;
-  plugin->iter_cls = cls;
-  plugin->iter_zone = zone;
-  plugin->iter_result_found = GNUNET_NO;
+  struct IterateContext ic;
+
+  ic.offset = serial;
+  ic.pos = 0;
+  ic.limit = limit;
+  ic.iter = iter;
+  ic.iter_cls = iter_cls;
+  ic.zone = zone;
   GNUNET_CONTAINER_multihashmap_iterate (plugin->hm,
                                          &iterate_zones,
-                                         plugin);
-  return plugin->iter_result_found;
+                                         &ic);
+  return (0 == ic.limit) ? GNUNET_OK : GNUNET_NO;
 }
 
+
+/**
+ * Closure for #zone_to_name.
+ */
+struct ZoneToNameContext
+{
+  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone;
+  const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone;
+  GNUNET_NAMESTORE_RecordIterator iter;
+  void *iter_cls;
+
+  int result_found;
+};
+
+
 static int
 zone_to_name (void *cls,
               const struct GNUNET_HashCode *key,
               void *value)
 {
-  struct Plugin *plugin = cls;
+  struct ZoneToNameContext *ztn = cls;
   struct FlatFileEntry *entry = value;
-  int i;
 
-  if (0 != memcmp (entry->private_key,
-                   plugin->iter_zone,
+  (void) key;
+  if (0 != memcmp (&entry->private_key,
+                   ztn->zone,
                    sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
     return GNUNET_YES;
 
-  for (i = 0; i < entry->record_count; i++) {
+  for (unsigned int i = 0; i < entry->record_count; i++)
+  {
     if (GNUNET_GNSRECORD_TYPE_PKEY != entry->record_data[i].record_type)
       continue;
-    if (0 == memcmp (plugin->iter_pkey,
+    if (0 == memcmp (ztn->value_zone,
                      entry->record_data[i].data,
                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
     {
-      plugin->iter (plugin->iter_cls,
-                    entry->private_key,
-                    entry->label,
-                    entry->record_count,
-                    entry->record_data);
-      plugin->iter_result_found = GNUNET_YES;
-
+      ztn->iter (ztn->iter_cls,
+                 0,
+                 &entry->private_key,
+                 entry->label,
+                 entry->record_count,
+                 entry->record_data);
+      ztn->result_found = GNUNET_YES;
     }
   }
-
   return GNUNET_YES;
 }
 
+
 /**
  * Look for an existing PKEY delegation record for a given public key.
  * Returns at most one result to the iterator.
@@ -597,23 +715,28 @@ zone_to_name (void *cls,
  * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
  */
 static int
-namestore_zone_to_name (void *cls,
-                        const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
-                        const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone,
-                        GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
+namestore_flat_zone_to_name (void *cls,
+                             const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+                             const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone,
+                             GNUNET_NAMESTORE_RecordIterator iter,
+                             void *iter_cls)
 {
   struct Plugin *plugin = cls;
+  struct ZoneToNameContext ztn = {
+    .iter = iter,
+    .iter_cls = iter_cls,
+    .zone = zone,
+    .value_zone = value_zone,
+    .result_found = GNUNET_NO
+  };
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-       "Performing reverse lookup for `%s'\n",
-       GNUNET_GNSRECORD_z2s (value_zone));
-
+              "Performing reverse lookup for `%s'\n",
+              GNUNET_GNSRECORD_z2s (value_zone));
   GNUNET_CONTAINER_multihashmap_iterate (plugin->hm,
                                          &zone_to_name,
-                                         plugin);
-
-
-  return plugin->iter_result_found;
+                                         &ztn);
+  return ztn.result_found;
 }
 
 
@@ -632,7 +755,9 @@ libgnunet_plugin_namestore_flat_init (void *cls)
 
   if (NULL != plugin.cfg)
     return NULL;                /* can only initialize once! */
-  memset (&plugin, 0, sizeof (struct Plugin));
+  memset (&plugin,
+         0,
+         sizeof (struct Plugin));
   plugin.cfg = cfg;
   if (GNUNET_OK != database_setup (&plugin))
   {
@@ -641,12 +766,12 @@ libgnunet_plugin_namestore_flat_init (void *cls)
   }
   api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions);
   api->cls = &plugin;
-  api->store_records = &namestore_store_records;
-  api->iterate_records = &namestore_iterate_records;
-  api->zone_to_name = &namestore_zone_to_name;
-  api->lookup_records = &namestore_lookup_records;
+  api->store_records = &namestore_flat_store_records;
+  api->iterate_records = &namestore_flat_iterate_records;
+  api->zone_to_name = &namestore_flat_zone_to_name;
+  api->lookup_records = &namestore_flat_lookup_records;
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-       _("flat file database running\n"));
+              _("flat file database running\n"));
   return api;
 }
 
@@ -667,7 +792,7 @@ libgnunet_plugin_namestore_flat_done (void *cls)
   plugin->cfg = NULL;
   GNUNET_free (api);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-       "flat file plugin is finished\n");
+              "flat file plugin is finished\n");
   return NULL;
 }