Beispiel #1
0
static void
tt_finish(TTH_CONTEXT *ctx)
{
	if (0 == ctx->n || ctx->block_fill > 1) {
		tt_block(ctx);
	}

	if (ctx->bpl > 1) {
		fileoffset_t n_blocks;
		unsigned depth;

		n_blocks = ctx->n;
		depth = ctx->depth;
		while (0 == (n_blocks & 1)) {
			n_blocks /= 2;
			depth--;
		}
		while (n_blocks > 1) {
			if (0 == (n_blocks & 1)) {
				tt_compose(ctx);
			}
			depth--;
			n_blocks = (n_blocks + 1) / 2;
			if (depth == ctx->good_depth) {
				g_assert(ctx->li < G_N_ELEMENTS(ctx->leaves));
				ctx->leaves[ctx->li] = ctx->stack[ctx->si - 1];
				ctx->li++;
			}
		}
	}
	ctx->stack[0] = tt_root_hash(ctx->leaves, ctx->li);
	ctx->flags |= TTH_F_FINISHED;
}
Beispiel #2
0
void
tth_cache_insert(const struct tth *tth, const struct tth *leaves, int n_leaves)
{
	int fd;
	
	g_return_if_fail(tth);
	g_return_if_fail(leaves);
	g_return_if_fail(n_leaves >= 1);

	{
		struct tth root;

		root = tt_root_hash(leaves, n_leaves);
		g_return_if_fail(tth_eq(tth, &root));
	}

	if (1 == n_leaves)
		return;

	fd = tth_cache_file_create(tth);
	if (fd >= 0) {
		size_t size;
		ssize_t ret;

		STATIC_ASSERT(TTH_RAW_SIZE == sizeof(leaves[0]));
			
		size = TTH_RAW_SIZE * n_leaves;
		ret = write(fd, leaves, size);
		if ((ssize_t) -1 == ret) {
			g_warning("%s(%s): write() failed: %m", G_STRFUNC, tth_base32(tth));
		} else if ((size_t) ret != size) {
			g_warning("%s(%s): incomplete write()", G_STRFUNC, tth_base32(tth));
		}
		fd_forget_and_close(&fd);
	}
}
Beispiel #3
0
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;
}