fix
[oweals/gnunet.git] / src / fs / fs_tree.c
index 83da423f3c16aa6d433fbbfa52e5d4960e905e20..713594c457e42d4ee286b644ad426dd6e0e88139 100644 (file)
  * @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"
@@ -173,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;
@@ -198,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;
@@ -230,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.
@@ -251,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
@@ -287,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);
@@ -297,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];
     }
@@ -309,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);
@@ -344,8 +385,8 @@ void GNUNET_FS_tree_encoder_next (struct GNUNET_FS_TreeEncoder * te)
              &mychk->query,
              te->publish_offset,
              (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)
@@ -387,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);
 }