static size_t thex_upload_prepare_xml(char **data_ptr, const struct tth *tth, filesize_t filesize) { struct dime_record *dime; char buf[512]; size_t len, size; unsigned depth; depth = tt_good_depth(filesize); len = concat_strings(buf, sizeof buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" "<!DOCTYPE hashtree S" /* NOTE: HIDE FROM METACONFIG */ "YSTEM \"" THEX_DOCTYPE "\">\r\n" "<hashtree>\r\n" "<file" " size=\"", filesize_to_string(filesize), "\"" " segmentsize=\"" THEX_SEGMENT_SIZE "\"/>\r\n" "<digest" " algorithm=\"" THEX_HASH_ALGO "\"" " outputsize=\"" THEX_HASH_SIZE "\"/>\r\n" "<serializedtree" " depth=\"", uint32_to_string(depth), "\"" " type=\"" THEX_TREE_TYPE "\"" " uri=\"", thex_upload_uuid(tth), "\"/>\r\n" "</hashtree>\r\n", (void *) 0); dime = dime_record_alloc(); dime_record_set_data(dime, buf, len); dime_record_set_type_mime(dime, "text/xml"); size = dime_create_record(dime, data_ptr, TRUE, FALSE); dime_record_free(&dime); return size; }
filesize_t tt_good_slice_size(filesize_t filesize) { filesize_t n_blocks; size_t n_nodes; n_blocks = tt_block_count(filesize); n_nodes = (1 << tt_good_depth(filesize)); return (n_blocks / n_nodes) * TTH_BLOCKSIZE; }
void tt_init(TTH_CONTEXT *ctx, filesize_t filesize) { g_assert(ctx); ctx->block_fill = 1; ctx->block.bytes[0] = 0x00; ctx->si = 0; ctx->li = 0; ctx->n = 0; ctx->bpl = tt_blocks_per_leaf(filesize); ctx->depth = 0; ctx->good_depth = tt_good_depth(filesize); ctx->flags = TTH_F_INITIALIZED; }
static filesize_t tt_blocks_per_leaf(filesize_t filesize) { unsigned full_depth, good_depth; filesize_t n_bpl; good_depth = tt_good_depth(filesize); full_depth = tt_full_depth(filesize); if (full_depth > good_depth) { n_bpl = (filesize_t) 1 << (full_depth - good_depth); } else { n_bpl = 1; } return n_bpl; }
static bool thex_download_handle_hashtree(struct thex_download *ctx, const char *data, size_t size) { bool success = FALSE; size_t n_nodes, n_leaves, n, start; unsigned good_depth; const struct tth *leaves; struct tth tth; if (size <= 0) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH hashtree record has no data"); } goto finish; } if (size < TTH_RAW_SIZE) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH hashtree record is too small"); } goto finish; } if (size % TTH_RAW_SIZE) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH hashtree has bad size"); } goto finish; } memcpy(tth.data, data, TTH_RAW_SIZE); if (!tth_eq(&tth, ctx->tth)) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH hashtree has different root hash %s", tth_base32(&tth)); } goto finish; } n_nodes = size / TTH_RAW_SIZE; n_leaves = tt_node_count_at_depth(ctx->filesize, ctx->depth); /* Shareaza uses a fixed depth of 9, allow one level less like others */ good_depth = tt_good_depth(ctx->filesize); ctx->depth = MIN(ctx->depth, good_depth); if (n_nodes < n_leaves * 2 - 1) { ctx->depth = good_depth; n = tt_node_count_at_depth(ctx->filesize, ctx->depth); n = n * 2 - 1; /* All nodes, not just leaves */ while (n > n_nodes) { n = (n + 1) / 2; ctx->depth--; } if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH calculated depth of hashtree: %u", ctx->depth); } n_leaves = tt_node_count_at_depth(ctx->filesize, ctx->depth); } if (ctx->depth < good_depth) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH tree depth (%u) is below the good depth (%u)", ctx->depth, good_depth); } } start = 0; n = n_leaves; while (n > 1) { n = (n + 1) / 2; start += n; } if (n_nodes < start + n_leaves) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH hashtree has too few nodes " "(filesize=%s depth=%u nodes=%zu expected=%zu)", filesize_to_string(ctx->filesize), ctx->depth, n_nodes, n_leaves * 2 - 1); } goto finish; } STATIC_ASSERT(TTH_RAW_SIZE == sizeof(struct tth)); leaves = (const struct tth *) &data[start * TTH_RAW_SIZE]; tth = tt_root_hash(leaves, n_leaves); if (!tth_eq(&tth, ctx->tth)) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH hashtree does not match root hash %s", tth_base32(&tth)); } goto finish; } ctx->leaves = g_memdup(leaves, TTH_RAW_SIZE * n_leaves); ctx->num_leaves = n_leaves; success = TRUE; finish: return success; }
size_t tt_good_node_count(filesize_t filesize) { return tt_node_count_at_depth(filesize, tt_good_depth(filesize)); }