fixing 1584
[oweals/gnunet.git] / src / fs / fs_tree.c
index 3dbf478df00d41bac41001f5d1ee953cf2aaa4b4..760a7e03972dc6b9ca1dc99fc12f908bc2aa32c3 100644 (file)
@@ -4,7 +4,7 @@
 
      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
  * @see http://gnunet.org/encoding.php3
  * @author Krista Bennett
  * @author Christian Grothoff
- *
- * TODO:
- * - decide if this API should be made public (gnunet_fs_service.h)
- *   or remain "internal" (but with exported symbols?)
  */
 #include "platform.h"
 #include "fs_tree.h"
 
+#define DEBUG_TREE GNUNET_NO
 
 /**
  * Context for an ECRS-based file encoder that computes
@@ -172,7 +169,7 @@ GNUNET_FS_tree_encoder_create (struct GNUNET_FS_Handle *h,
   struct GNUNET_FS_TreeEncoder *te;
   
   GNUNET_assert (size > 0);
-  te = GNUNET_malloc (sizeof (struct GNUNET_FS_TreeEncoder));
+  te = GNUNET_malloc (sizeof (struct GNUNET_FS_TreeEncoder));  
   te->h = h;
   te->size = size;
   te->cls = cls;
@@ -197,9 +194,9 @@ GNUNET_FS_tree_encoder_create (struct GNUNET_FS_Handle *h,
  * @param offset current offset in the overall file
  * @return size of the corresponding IBlock
  */
-static uint16_t 
-compute_iblock_size (unsigned int height,
-                    uint64_t offset)
+uint16_t 
+GNUNET_FS_tree_compute_iblock_size (unsigned int height,
+                                   uint64_t offset)
 {
   unsigned int ret;
   unsigned int i;
@@ -229,6 +226,52 @@ compute_iblock_size (unsigned int height,
 }
 
 
+/**
+ * Compute how many bytes of data should be stored in
+ * the specified node.
+ *
+ * @param fsize overall file size
+ * @param totaldepth depth of the entire tree
+ * @param offset offset of the node
+ * @param depth depth of the node
+ * @return number of bytes stored in this node
+ */
+size_t
+GNUNET_FS_tree_calculate_block_size (uint64_t fsize,
+                                    unsigned int totaldepth,
+                                    uint64_t offset,
+                                    unsigned int depth)
+{
+  unsigned int i;
+  size_t ret;
+  uint64_t rsize;
+  uint64_t epos;
+  unsigned int chks;
+
+  GNUNET_assert (offset < fsize);
+  if (depth == totaldepth)
+    {
+      ret = DBLOCK_SIZE;
+      if (offset + ret > fsize)
+        ret = (size_t) (fsize - offset);
+      return ret;
+    }
+  /* FIXME: this code should be *equivalent* to the
+     GNUNET_FS_tree_compute_iblock_size function above! Remove duplication! */
+  rsize = DBLOCK_SIZE;
+  for (i = totaldepth-1; i > depth; i--)
+    rsize *= CHK_PER_INODE;
+  epos = offset + rsize * CHK_PER_INODE;
+  GNUNET_assert (epos > offset);
+  if (epos > fsize)
+    epos = fsize;
+  /* round up when computing #CHKs in our IBlock */
+  chks = (epos - offset + rsize - 1) / rsize;
+  GNUNET_assert (chks <= CHK_PER_INODE);
+  return chks * sizeof (struct ContentHashKey);
+}
+
+
 /**
  * Compute the offset of the CHK for the
  * current block in the IBlock above.
@@ -250,15 +293,16 @@ compute_chk_offset (unsigned int height,
                                  corresponds to */
   for (i=0;i<height;i++)
     bds *= CHK_PER_INODE;
+  if (height > 0)
+    offset--; /* round down since for height > 0 offset is at the END of the block */
   ret = offset / bds;
   return ret % CHK_PER_INODE; 
 }
 
 
 /**
- * Encrypt the next block of the file (and 
- * call proc and progress accordingly; or 
- * of course "cont" if we have already completed
+ * Encrypt the next block of the file (and call proc and progress
+ * accordingly; or of course "cont" if we have already completed
  * encoding of the entire file).
  *
  * @param te tree encoder to use
@@ -286,7 +330,6 @@ void GNUNET_FS_tree_encoder_next (struct GNUNET_FS_TreeEncoder * te)
                      &te->emsg))
        {
          GNUNET_SCHEDULER_add_continuation (te->h->sched,
-                                            GNUNET_NO,
                                             te->cont,
                                             te->cls,
                                             GNUNET_SCHEDULER_REASON_TIMEOUT);
@@ -296,8 +339,8 @@ void GNUNET_FS_tree_encoder_next (struct GNUNET_FS_TreeEncoder * te)
     }
   else
     {
-      pt_size = compute_iblock_size (te->chk_tree_depth - te->current_depth,
-                                    te->publish_offset); 
+      pt_size = GNUNET_FS_tree_compute_iblock_size (te->chk_tree_depth - te->current_depth,
+                                                   te->publish_offset); 
       pt_block = &te->chk_tree[te->current_depth *
                               CHK_PER_INODE];
     }
@@ -308,7 +351,6 @@ void GNUNET_FS_tree_encoder_next (struct GNUNET_FS_TreeEncoder * te)
       te->uri->data.chk.chk = te->chk_tree[0];
       te->uri->data.chk.file_length = GNUNET_htonll (te->size);
       GNUNET_SCHEDULER_add_continuation (te->h->sched,
-                                        GNUNET_NO,
                                         te->cont,
                                         te->cls,
                                         GNUNET_SCHEDULER_REASON_PREREQ_DONE);
@@ -316,6 +358,14 @@ void GNUNET_FS_tree_encoder_next (struct GNUNET_FS_TreeEncoder * te)
     }
   off = compute_chk_offset (te->chk_tree_depth - te->current_depth,
                            te->publish_offset);
+#if DEBUG_TREE
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "TE is at offset %llu and depth %u with block size %u and target-CHK-offset %u\n",
+             (unsigned long long) te->publish_offset,
+             te->current_depth,
+             (unsigned int) pt_size,
+             (unsigned int) off);
+#endif
   mychk = &te->chk_tree[(te->current_depth-1)*CHK_PER_INODE+off];
   GNUNET_CRYPTO_hash (pt_block, pt_size, &mychk->key);
   GNUNET_CRYPTO_hash_to_aes_key (&mychk->key, &sk, &iv);
@@ -324,22 +374,27 @@ void GNUNET_FS_tree_encoder_next (struct GNUNET_FS_TreeEncoder * te)
                             &sk,
                             &iv,
                             enc);
+  GNUNET_CRYPTO_hash (enc, pt_size, &mychk->query);
+#if DEBUG_TREE
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "TE calculates query to be `%s'\n",
+             GNUNET_h2s (&mychk->query));
+#endif
   if (NULL != te->proc)
     te->proc (te->cls,
              &mychk->query,
              te->publish_offset,
-             pt_size,
-             enc,
              (te->current_depth == te->chk_tree_depth) 
-             ? GNUNET_DATASTORE_BLOCKTYPE_DBLOCK 
-             : GNUNET_DATASTORE_BLOCKTYPE_IBLOCK);
+             ? GNUNET_BLOCK_TYPE_DBLOCK 
+             : GNUNET_BLOCK_TYPE_IBLOCK,
+             enc,
+             pt_size);
   if (NULL != te->progress)
     te->progress (te->cls,
                  te->publish_offset,
                  pt_block,
                  pt_size,
                  te->current_depth);
-  GNUNET_CRYPTO_hash (enc, pt_size, &mychk->query);
   if (te->current_depth == te->chk_tree_depth) 
     { 
       te->publish_offset += pt_size;
@@ -373,8 +428,15 @@ void GNUNET_FS_tree_encoder_finish (struct GNUNET_FS_TreeEncoder * te,
                                    struct GNUNET_FS_Uri **uri,
                                    char **emsg)
 {
-  *uri = te->uri;
-  *emsg = te->emsg;
+  if (uri != NULL)
+    *uri = te->uri;
+  else
+    if (NULL != te->uri)
+      GNUNET_FS_uri_destroy (te->uri);
+  if (emsg != NULL)
+    *emsg = te->emsg;
+  else
+    GNUNET_free_non_null (te->emsg);
   GNUNET_free (te->chk_tree);
   GNUNET_free (te);
 }