X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ffs%2Ffs_tree.c;h=e57e4e4943e806adcc2e8ba4367203f23076bd5c;hb=0e592870059883b779d02a14fa5ea13be5f50595;hp=e22ce82213d61e613f97ccba037d6c46facb63d4;hpb=c9432075d84d3c50171367e7d648a3a09f431994;p=oweals%2Fgnunet.git diff --git a/src/fs/fs_tree.c b/src/fs/fs_tree.c index e22ce8221..e57e4e494 100644 --- a/src/fs/fs_tree.c +++ b/src/fs/fs_tree.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2009-2011 Christian Grothoff (and other contributing authors) + Copyright (C) 2009-2011 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 @@ -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 - 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 fs/fs_tree.c @@ -27,7 +27,6 @@ #include "platform.h" #include "fs_tree.h" -#define DEBUG_TREE GNUNET_NO /** * Context for an ECRS-based file encoder that computes @@ -40,7 +39,7 @@ struct GNUNET_FS_TreeEncoder * Global FS context. */ struct GNUNET_FS_Handle *h; - + /** * Closure for all callbacks. */ @@ -64,8 +63,8 @@ struct GNUNET_FS_TreeEncoder /** * Function to call once we're done with processing. */ - GNUNET_SCHEDULER_Task cont; - + GNUNET_SCHEDULER_TaskCallback cont; + /** * Set to an error message (if we had an error). */ @@ -100,7 +99,7 @@ struct GNUNET_FS_TreeEncoder * In-memory cache of the current CHK tree. * This struct will contain the CHK values * from the root to the currently processed - * node in the tree as identified by + * node in the tree as identified by * "current_depth" and "publish_offset". * The "chktree" will be initially NULL, * then allocated to a sufficient number of @@ -132,15 +131,15 @@ GNUNET_FS_compute_depth (uint64_t flen) treeDepth = 1; fl = DBLOCK_SIZE; while (fl < flen) + { + treeDepth++; + if (fl * CHK_PER_INODE < fl) { - treeDepth++; - if (fl * CHK_PER_INODE < fl) - { - /* integer overflow, this is a HUGE file... */ - return treeDepth; - } - fl = fl * CHK_PER_INODE; + /* integer overflow, this is a HUGE file... */ + return treeDepth; } + fl = fl * CHK_PER_INODE; + } return treeDepth; } @@ -161,7 +160,7 @@ GNUNET_FS_tree_compute_tree_size (unsigned int depth) unsigned int i; rsize = DBLOCK_SIZE; - for (i = 0; i 0 (this function is for IBLOCKs only!) - * @param end_offset current offset in the payload (!) of the overall file, - * must be > 0 (since this function is called at the + * @param end_offset current offset in the payload (!) of the overall file, + * must be > 0 (since this function is called at the * end of a block). * @return size of the corresponding IBlock */ -static uint16_t -GNUNET_FS_tree_compute_iblock_size (unsigned int depth, - uint64_t end_offset) +static uint16_t +GNUNET_FS_tree_compute_iblock_size (unsigned int depth, uint64_t end_offset) { unsigned int ret; uint64_t mod; @@ -194,19 +192,19 @@ GNUNET_FS_tree_compute_iblock_size (unsigned int depth, bds = GNUNET_FS_tree_compute_tree_size (depth); mod = end_offset % bds; if (0 == mod) - { - /* we were triggered at the end of a full block */ - ret = CHK_PER_INODE; - } + { + /* we were triggered at the end of a full block */ + ret = CHK_PER_INODE; + } else - { - /* we were triggered at the end of the file */ - bds /= CHK_PER_INODE; - ret = mod / bds; - if (0 != mod % bds) - ret++; - } - return (uint16_t) (ret * sizeof(struct ContentHashKey)); + { + /* we were triggered at the end of the file */ + bds /= CHK_PER_INODE; + ret = mod / bds; + if (0 != mod % bds) + ret++; + } + return (uint16_t) (ret * sizeof (struct ContentHashKey)); } @@ -222,9 +220,8 @@ GNUNET_FS_tree_compute_iblock_size (unsigned int depth, * @return number of bytes stored in this node */ size_t -GNUNET_FS_tree_calculate_block_size (uint64_t fsize, - uint64_t offset, - unsigned int depth) +GNUNET_FS_tree_calculate_block_size (uint64_t fsize, uint64_t offset, + unsigned int depth) { size_t ret; uint64_t rsize; @@ -234,18 +231,16 @@ GNUNET_FS_tree_calculate_block_size (uint64_t fsize, GNUNET_assert (fsize > 0); GNUNET_assert (offset <= fsize); if (depth == 0) - { - ret = DBLOCK_SIZE; - if ( (offset + ret > fsize) || - (offset + ret < offset) ) - ret = (size_t) (fsize - offset); - return ret; - } + { + ret = DBLOCK_SIZE; + if ((offset + ret > fsize) || (offset + ret < offset)) + ret = (size_t) (fsize - offset); + return ret; + } rsize = GNUNET_FS_tree_compute_tree_size (depth - 1); epos = offset + rsize * CHK_PER_INODE; - if ( (epos < offset) || - (epos > fsize) ) + if ((epos < offset) || (epos > fsize)) epos = fsize; /* round up when computing #CHKs in our IBlock */ chks = (epos - offset + rsize - 1) / rsize; @@ -255,34 +250,33 @@ GNUNET_FS_tree_calculate_block_size (uint64_t fsize, /** - * Initialize a tree encoder. This function will call "proc" and + * Initialize a tree encoder. This function will call @a proc and * "progress" on each block in the tree. Once all blocks have been - * processed, "cont" will be scheduled. The "reader" will be called + * processed, "cont" will be scheduled. The @a reader will be called * to obtain the (plaintext) blocks for the file. Note that this - * function will not actually call "proc". The client must - * call "GNUNET_FS_tree_encoder_next" to trigger encryption (and - * calling of "proc") for the each block. + * function will not actually call @a proc. The client must + * call #GNUNET_FS_tree_encoder_next to trigger encryption (and + * calling of @a proc) for the each block. * * @param h the global FS context * @param size overall size of the file to encode * @param cls closure for reader, proc, progress and cont * @param reader function to call to read plaintext data * @param proc function to call on each encrypted block - * @param progress function to call with progress information + * @param progress function to call with progress information * @param cont function to call when done */ struct GNUNET_FS_TreeEncoder * -GNUNET_FS_tree_encoder_create (struct GNUNET_FS_Handle *h, - uint64_t size, - void *cls, +GNUNET_FS_tree_encoder_create (struct GNUNET_FS_Handle *h, uint64_t size, + void *cls, GNUNET_FS_DataReader reader, - GNUNET_FS_TreeBlockProcessor proc, - GNUNET_FS_TreeProgressCallback progress, - GNUNET_SCHEDULER_Task cont) + GNUNET_FS_TreeBlockProcessor proc, + GNUNET_FS_TreeProgressCallback progress, + GNUNET_SCHEDULER_TaskCallback cont) { struct GNUNET_FS_TreeEncoder *te; - - te = GNUNET_malloc (sizeof (struct GNUNET_FS_TreeEncoder)); + + te = GNUNET_new (struct GNUNET_FS_TreeEncoder); te->h = h; te->size = size; te->cls = cls; @@ -291,9 +285,13 @@ GNUNET_FS_tree_encoder_create (struct GNUNET_FS_Handle *h, te->progress = progress; te->cont = cont; te->chk_tree_depth = GNUNET_FS_compute_depth (size); - te->chk_tree = GNUNET_malloc (te->chk_tree_depth * - CHK_PER_INODE * - sizeof (struct ContentHashKey)); + te->chk_tree + = GNUNET_new_array (te->chk_tree_depth * CHK_PER_INODE, + struct ContentHashKey); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Created tree encoder for file with %llu bytes and depth %u\n", + (unsigned long long) size, + te->chk_tree_depth); return te; } @@ -304,23 +302,22 @@ GNUNET_FS_tree_encoder_create (struct GNUNET_FS_Handle *h, * * @param depth depth of the IBlock in the tree (aka overall * number of tree levels minus depth); 0 == DBlock - * @param end_offset current offset in the overall file, + * @param end_offset current offset in the overall file, * at the *beginning* of the block for DBLOCKs (depth==0), * otherwise at the *end* of the block (exclusive) * @return (array of CHKs') offset in the above IBlock */ static unsigned int -compute_chk_offset (unsigned int depth, - uint64_t end_offset) +compute_chk_offset (unsigned int depth, uint64_t end_offset) { uint64_t bds; unsigned int ret; bds = GNUNET_FS_tree_compute_tree_size (depth); if (depth > 0) - end_offset--; /* round down since for depth > 0 offset is at the END of the block */ + end_offset--; /* round down since for depth > 0 offset is at the END of the block */ ret = end_offset / bds; - return ret % CHK_PER_INODE; + return ret % CHK_PER_INODE; } @@ -331,145 +328,130 @@ compute_chk_offset (unsigned int depth, * * @param te tree encoder to use */ -void -GNUNET_FS_tree_encoder_next (struct GNUNET_FS_TreeEncoder * te) +void +GNUNET_FS_tree_encoder_next (struct GNUNET_FS_TreeEncoder *te) { struct ContentHashKey *mychk; const void *pt_block; uint16_t pt_size; char iob[DBLOCK_SIZE]; char enc[DBLOCK_SIZE]; - struct GNUNET_CRYPTO_AesSessionKey sk; - struct GNUNET_CRYPTO_AesInitializationVector iv; + struct GNUNET_CRYPTO_SymmetricSessionKey sk; + struct GNUNET_CRYPTO_SymmetricInitializationVector iv; unsigned int off; GNUNET_assert (GNUNET_NO == te->in_next); te->in_next = GNUNET_YES; if (te->chk_tree_depth == te->current_depth) + { + off = CHK_PER_INODE * (te->chk_tree_depth - 1); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TE done, reading CHK `%s' from %u\n", + GNUNET_h2s (&te->chk_tree[off].query), off); + te->uri = GNUNET_new (struct GNUNET_FS_Uri); + te->uri->type = GNUNET_FS_URI_CHK; + te->uri->data.chk.chk = te->chk_tree[off]; + te->uri->data.chk.file_length = GNUNET_htonll (te->size); + te->in_next = GNUNET_NO; + te->cont (te->cls); + return; + } + if (0 == te->current_depth) + { + /* read DBLOCK */ + pt_size = GNUNET_MIN (DBLOCK_SIZE, te->size - te->publish_offset); + if (pt_size != + te->reader (te->cls, te->publish_offset, pt_size, iob, &te->emsg)) { - off = CHK_PER_INODE * (te->chk_tree_depth - 1); -#if DEBUG_TREE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "TE done, reading CHK `%s' from %u\n", - GNUNET_h2s (&te->chk_tree[off].query), - off); -#endif - te->uri = GNUNET_malloc (sizeof(struct GNUNET_FS_Uri)); - te->uri->type = chk; - te->uri->data.chk.chk = te->chk_tree[off]; - te->uri->data.chk.file_length = GNUNET_htonll (te->size); te->in_next = GNUNET_NO; - te->cont (te->cls, NULL); + te->cont (te->cls); return; } - if (0 == te->current_depth) - { - /* read DBLOCK */ - pt_size = GNUNET_MIN(DBLOCK_SIZE, - te->size - te->publish_offset); - if (pt_size != - te->reader (te->cls, - te->publish_offset, - pt_size, - iob, - &te->emsg)) - { - GNUNET_SCHEDULER_add_continuation (te->cont, - te->cls, - GNUNET_SCHEDULER_REASON_TIMEOUT); - te->in_next = GNUNET_NO; - return; - } - pt_block = iob; - } + pt_block = iob; + } else - { - pt_size = GNUNET_FS_tree_compute_iblock_size (te->current_depth, - te->publish_offset); - pt_block = &te->chk_tree[(te->current_depth - 1) * - CHK_PER_INODE]; - } - off = compute_chk_offset (te->current_depth, - te->publish_offset); -#if DEBUG_TREE + { + pt_size = + GNUNET_FS_tree_compute_iblock_size (te->current_depth, + te->publish_offset); + pt_block = &te->chk_tree[(te->current_depth - 1) * CHK_PER_INODE]; + } + off = compute_chk_offset (te->current_depth, te->publish_offset); 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*CHK_PER_INODE+off]; + "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); + mychk = &te->chk_tree[te->current_depth * CHK_PER_INODE + off]; GNUNET_CRYPTO_hash (pt_block, pt_size, &mychk->key); GNUNET_CRYPTO_hash_to_aes_key (&mychk->key, &sk, &iv); - GNUNET_CRYPTO_aes_encrypt (pt_block, - pt_size, - &sk, - &iv, - enc); + GNUNET_CRYPTO_symmetric_encrypt (pt_block, pt_size, &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', stored at %u\n", - GNUNET_h2s (&mychk->query), - te->current_depth * CHK_PER_INODE + off); -#endif + "TE calculates query to be `%s', stored at %u\n", + GNUNET_h2s (&mychk->query), + te->current_depth * CHK_PER_INODE + off); if (NULL != te->proc) - te->proc (te->cls, - mychk, - te->publish_offset, - te->current_depth, - (0 == te->current_depth) - ? GNUNET_BLOCK_TYPE_FS_DBLOCK - : GNUNET_BLOCK_TYPE_FS_IBLOCK, - enc, - pt_size); + te->proc (te->cls, mychk, te->publish_offset, te->current_depth, + (0 == + te->current_depth) ? 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); - if (0 == te->current_depth) - { - te->publish_offset += pt_size; - if ( (te->publish_offset == te->size) || - (0 == te->publish_offset % (CHK_PER_INODE * DBLOCK_SIZE) ) ) - te->current_depth++; - } + te->progress (te->cls, te->publish_offset, pt_block, pt_size, + te->current_depth); + if (0 == te->current_depth) + { + te->publish_offset += pt_size; + if ((te->publish_offset == te->size) || + (0 == te->publish_offset % (CHK_PER_INODE * DBLOCK_SIZE))) + te->current_depth++; + } else - { - if ( (off == CHK_PER_INODE) || - (te->publish_offset == te->size) ) - te->current_depth++; - else - te->current_depth = 0; - } + { + if ((off == CHK_PER_INODE) || (te->publish_offset == te->size)) + te->current_depth++; + else + te->current_depth = 0; + } te->in_next = GNUNET_NO; } +/** + * Get the resulting URI from the encoding. + * + * @param te the tree encoder to clean up + * @return uri set to the resulting URI (if encoding finished), NULL otherwise + */ +struct GNUNET_FS_Uri * +GNUNET_FS_tree_encoder_get_uri (struct GNUNET_FS_TreeEncoder *te) +{ + if (NULL != te->uri) + return GNUNET_FS_uri_dup (te->uri); + return NULL; +} + + /** * Clean up a tree encoder and return information - * about the resulting URI or an error message. - * + * about possible errors. + * * @param te the tree encoder to clean up - * @param uri set to the resulting URI (if encoding finished) * @param emsg set to an error message (if an error occured * within the tree encoder; if this function is called * prior to completion and prior to an internal error, - * both "*uri" and "*emsg" will be set to NULL). + * both "*emsg" will be set to NULL). */ -void GNUNET_FS_tree_encoder_finish (struct GNUNET_FS_TreeEncoder *te, - struct GNUNET_FS_Uri **uri, - char **emsg) +void +GNUNET_FS_tree_encoder_finish (struct GNUNET_FS_TreeEncoder *te, + char **emsg) { + if (NULL != te->reader) + { + (void) te->reader (te->cls, UINT64_MAX, 0, 0, NULL); + te->reader = NULL; + } GNUNET_assert (GNUNET_NO == te->in_next); - if (uri != NULL) - *uri = te->uri; - else - if (NULL != te->uri) - GNUNET_FS_uri_destroy (te->uri); + if (NULL != te->uri) + GNUNET_FS_uri_destroy (te->uri); if (emsg != NULL) *emsg = te->emsg; else