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
* @param flen file length for which to compute the depth
* @return depth of the tree
*/
-static unsigned int
-compute_depth (uint64_t flen)
+unsigned int
+GNUNET_FS_compute_depth (uint64_t flen)
{
unsigned int treeDepth;
uint64_t fl;
{
struct GNUNET_FS_TreeEncoder *te;
- te = GNUNET_malloc (sizeof (struct GNUNET_FS_TreeEncoder));
+ GNUNET_assert (size > 0);
+ te = GNUNET_malloc (sizeof (struct GNUNET_FS_TreeEncoder));
te->h = h;
te->size = size;
te->cls = cls;
te->proc = proc;
te->progress = progress;
te->cont = cont;
- te->chk_tree_depth = compute_depth (size);
+ te->chk_tree_depth = GNUNET_FS_compute_depth (size);
te->current_depth = te->chk_tree_depth;
te->chk_tree = GNUNET_malloc (te->chk_tree_depth *
CHK_PER_INODE *
* @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;
}
+/**
+ * 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.
corresponds to */
for (i=0;i<height;i++)
bds *= CHK_PER_INODE;
- GNUNET_assert (0 == (offset % bds));
+ 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
&te->emsg))
{
GNUNET_SCHEDULER_add_continuation (te->h->sched,
- GNUNET_NO,
te->cont,
te->cls,
GNUNET_SCHEDULER_REASON_TIMEOUT);
}
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];
}
+ if (0 == te->current_depth)
+ {
+ te->uri = GNUNET_malloc (sizeof(struct GNUNET_FS_Uri));
+ te->uri->type = chk;
+ 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,
+ te->cont,
+ te->cls,
+ GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+ return;
+ }
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);
&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_FS_DBLOCK
+ : GNUNET_BLOCK_TYPE_FS_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;
else
te->current_depth = te->chk_tree_depth;
}
- if (0 == te->current_depth)
- {
- te->uri = GNUNET_malloc (sizeof(struct GNUNET_FS_Uri));
- te->uri->type = chk;
- te->uri->data.chk.chk = te->chk_tree[0];
- te->uri->data.chk.file_length = te->size;
- GNUNET_SCHEDULER_add_continuation (te->h->sched,
- GNUNET_NO,
- te->cont,
- te->cls,
- GNUNET_SCHEDULER_REASON_PREREQ_DONE);
- }
}
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);
}