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; }
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; }
static char * thex_download_handle_xml(struct thex_download *ctx, const char *data, size_t size) { xnode_t *hashtree = NULL, *node; char *hashtree_id = NULL; bool success = FALSE; vxml_parser_t *vp; vxml_error_t e; if (size <= 0) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH XML record has no data"); } goto finish; } /* * Parse the XML record. */ vp = vxml_parser_make("THEX record", VXML_O_STRIP_BLANKS); vxml_parser_add_data(vp, data, size); e = vxml_parse_tree(vp, &hashtree); vxml_parser_free(vp); if (VXML_E_OK != e) { if (GNET_PROPERTY(tigertree_debug)) { g_warning("TTH cannot parse XML record: %s", vxml_strerror(e)); dump_hex(stderr, "XML record", data, size); } goto finish; } if (0 != strcmp("hashtree", xnode_element_name(hashtree))) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH couldn't find root hashtree element"); } goto finish; } node = find_element_by_name(hashtree, "file"); if (node) { if (!verify_element(node, "size", filesize_to_string(ctx->filesize))) goto finish; if (!verify_element(node, "segmentsize", THEX_SEGMENT_SIZE)) goto finish; } else { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH couldn't find hashtree/file element"); } goto finish; } node = find_element_by_name(hashtree, "digest"); if (node) { if (!verify_element(node, "algorithm", THEX_HASH_ALGO)) goto finish; if (!verify_element(node, "outputsize", THEX_HASH_SIZE)) goto finish; } else { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH couldn't find hashtree/digest element"); } goto finish; } node = find_element_by_name(hashtree, "serializedtree"); if (node) { const char *value; int error; if (!verify_element(node, "type", THEX_TREE_TYPE)) goto finish; value = xnode_prop_get(node, "uri"); if (NULL == value) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH couldn't find property \"uri\" of node \"%s\"", xnode_element_name(node)); } goto finish; } hashtree_id = h_strdup(value); value = xnode_prop_get(node, "depth"); if (NULL == value) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH couldn't find property \"depth\" of node \"%s\"", xnode_element_name(node)); } goto finish; } ctx->depth = parse_uint16(value, NULL, 10, &error); error |= ctx->depth > tt_full_depth(ctx->filesize); if (error) { ctx->depth = 0; g_warning("TTH bad value for \"depth\" of node \"%s\": \"%s\"", xnode_element_name(node), value); } if (error) goto finish; } else { if (GNET_PROPERTY(tigertree_debug)) g_debug("TTH couldn't find hashtree/serializedtree element"); goto finish; } success = TRUE; finish: if (!success) HFREE_NULL(hashtree_id); xnode_tree_free_null(&hashtree); return hashtree_id; }
static enum shell_reply shell_exec_download_show(struct gnutella_shell *sh, int argc, const char *argv[]) { fileinfo_t *fi; struct guid guid; const char *id, *property; gnet_fi_status_t status; gnet_fi_info_t *info; int i; shell_check(sh); g_assert(argv); g_assert(argc > 0); if (argc < 3) { shell_set_msg(sh, "parameter missing"); goto error; } id = argv[2]; if (!hex_to_guid(id, &guid)) { shell_set_msg(sh, "Unparsable ID"); goto error; } fi = file_info_by_guid(&guid); if (NULL == fi) { shell_set_msg(sh, "Invalid ID"); goto error; } info = guc_fi_get_info(fi->fi_handle); guc_fi_get_status(fi->fi_handle, &status); for (i = 3; i < argc; i++) { property = argv[i]; if (0 == strcmp(property, "id")) { show_property(sh, property, guid_to_string(info->guid)); } else if (0 == strcmp(property, "filename")) { show_property(sh, property, info->filename); } else if (0 == strcmp(property, "pathname")) { show_property(sh, property, fi->pathname); } else if (0 == strcmp(property, "size")) { show_property(sh, property, filesize_to_string(info->size)); } else if (0 == strcmp(property, "sha1")) { show_property(sh, property, info->sha1 ? sha1_to_urn_string(info->sha1) : ""); } else if (0 == strcmp(property, "tth")) { show_property(sh, property, info->tth ? tth_to_urn_string(info->tth) : ""); } else if (0 == strcmp(property, "bitprint")) { show_property(sh, property, (info->sha1 && info->tth) ? bitprint_to_urn_string(info->sha1, info->tth) : ""); } else if (0 == strcmp(property, "created")) { show_property(sh, property, info->created ? timestamp_to_string(info->created) : ""); } else if (0 == strcmp(property, "modified")) { show_property(sh, property, status.modified ? timestamp_to_string(status.modified) : ""); } else if (0 == strcmp(property, "downloaded")) { show_property(sh, property, filesize_to_string(status.done)); } else if (0 == strcmp(property, "uploaded")) { show_property(sh, property, uint64_to_string(status.uploaded)); } else if (0 == strcmp(property, "paused")) { show_property(sh, property, boolean_to_string(status.paused)); } else if (0 == strcmp(property, "seeding")) { show_property(sh, property, boolean_to_string(status.seeding)); } else if (0 == strcmp(property, "verifying")) { show_property(sh, property, boolean_to_string(status.verifying)); } else if (0 == strcmp(property, "finished")) { show_property(sh, property, boolean_to_string(status.finished)); } else if (0 == strcmp(property, "complete")) { show_property(sh, property, boolean_to_string(status.complete)); } else if (0 == strcmp(property, "magnet")) { char *magnet = file_info_build_magnet(fi->fi_handle); show_property(sh, property, EMPTY_STRING(magnet)); HFREE_NULL(magnet); } } guc_fi_free_info(info); return REPLY_READY; error: return REPLY_ERROR; }