Example #1
0
/**
 * This is the same as urn_get_sha1(), only the leading "urn:" part
 * is missing (typically a URN embedded in a GGEP "u").
 *
 * `buf' MUST start with "sha1:" or "bitprint:" indications.  Since the
 * leading "urn:" part is missing, we cannot be lenient.
 *
 * Extract the SHA1 out of it, placing it in the supplied `digest' buffer.
 *
 * @return whether we successfully extracted the SHA1.
 */
bool
urn_get_sha1_no_prefix(const char *buf, struct sha1 *sha1)
{
	const char *p;
	size_t len;

	/*
	 * We handle both "sha1:" and "bitprint:".  In the latter case,
	 * the first 32 bytes of the bitprint is the SHA1.
	 */

	if (
		NULL == (p = is_strcaseprefix(buf, "sha1:")) &&
		NULL == (p = is_strcaseprefix(buf, "bitprint:"))
	)
		return FALSE;

	len = clamp_strlen(p, SHA1_BASE32_SIZE);
	if (parse_base32_sha1(p, len, sha1))
		return TRUE;

	/*
	 * Maybe it was generated by clueless people who use an hexadecimal
	 * representation?
	 */

	len = clamp_strlen(p, SHA1_BASE16_SIZE);
	return parse_base16_sha1(p, len, sha1);
}
Example #2
0
/**
 * Locate the start of "urn:bitprint:" indications and extract
 * the SHA1 and TTH out of it, placing them in the supplied buffers.
 *
 * @return whether we successfully extracted the bitprint, i.e. the two
 * hashes.
 */
bool
urn_get_bitprint(const char *buf, size_t size,
	struct sha1 *sha1, struct tth *tth)
{
	static const char prefix[] = "urn:bitprint:";
	size_t len;
	const char *p;
	bool base16_tth = FALSE;

	g_assert(0 == size || NULL != buf);
	g_assert(sha1);
	g_assert(tth);

	/*
	 * Because some clueless sites list magnets with hexadecimal-encoded
	 * values, we attempt to parse both base32 and base16 encoded hashes.
	 *
	 * Note that we expect both hashes to be similarily encoded.
	 */

	if (size < CONST_STRLEN(prefix) + BITPRINT_BASE32_SIZE)
		return FALSE;
	p = is_strcaseprefix(buf, prefix);
	if (NULL == p)
		return FALSE;
	if (!parse_base32_sha1(p, SHA1_BASE32_SIZE, sha1)) {
		if (
			size >= CONST_STRLEN(prefix) + BITPRINT_BASE16_SIZE &&
			parse_base16_sha1(p, SHA1_BASE16_SIZE, sha1)
		) {
			p += SHA1_BASE16_SIZE;
			base16_tth = TRUE;		/* SHA1 was hexa, expects TTH as hexa */
		} else {
			return FALSE;
		}
	} else {
		p += SHA1_BASE32_SIZE;
	}
	if ('.' != *p++) {
		return FALSE;
	}
	if (base16_tth) {
		len = base16_decode(tth, sizeof *tth, p, TTH_BASE16_SIZE);
	} else {
		len = base32_decode(tth, sizeof *tth, p, TTH_BASE32_SIZE);
	}
	if (len != TTH_RAW_SIZE) {
		return FALSE;
	}
	return TRUE;
}
Example #3
0
G_GNUC_COLD void
upload_stats_load_history(void)
{
	FILE *upload_stats_file;
	file_path_t fp;
	char line[FILENAME_MAX + 64];
	guint lineno = 0;

	gcu_upload_stats_gui_freeze();
	
	file_path_set(&fp, settings_config_dir(), ul_stats_file);

	/* open file for reading */
	upload_stats_file = file_config_open_read(ul_stats_what, &fp, 1);
	if (upload_stats_file == NULL)
		goto done;

	/* parse, insert names into ul_stats_clist */
	while (fgets(line, sizeof(line), upload_stats_file)) {
		static const struct ul_stats zero_item;
		struct ul_stats item;
		struct sha1 sha1_buf;
		const char *p;
		size_t i;

		lineno++;
		if (line[0] == '#' || line[0] == '\n')
			continue;

		p = strchr(line, '\t');
		if (NULL == p)
			goto corrupted;

		line[p - line] = '\0';		/* line is now the URL-escaped file name */
		p++;

		/* URL-unescape in-place */
		if (!url_unescape(line, TRUE))
			goto corrupted;

		item = zero_item;
		item.pathname = line;

		for (i = 0; i < 8; i++) {
			guint64 v;
			int error;
			const char *endptr;

			p = skip_ascii_spaces(p);

			/* SVN versions up to 15322 had only 6 fields in the history */
			if (5 == i && '\0' == *p)
				break;

			switch (i) {
			case 7:
				/* We have a SHA1 or '*' if none known */
				if ('*' != *p) {
					size_t len = clamp_strlen(p, SHA1_BASE32_SIZE);
					
					error = !parse_base32_sha1(p, len, &sha1_buf);
					item.sha1 = error ? NULL : &sha1_buf;
				} else {
					error = FALSE;
				}
				p = skip_ascii_non_spaces(p);
				v = 0;
				break;
			default:
				v = parse_uint64(p, &endptr, 10, &error);
				p = deconstify_gchar(endptr);
			}

			if (error || !is_ascii_space(*endptr))
				goto corrupted;

			switch (i) {
			case 0: item.size = v; break;
			case 1: item.attempts = v; break;
			case 2: item.complete = v; break;
			case 3: item.bytes_sent |= ((guint64) (guint32) v) << 32; break;
			case 4: item.bytes_sent |= (guint32) v; break;
			case 5: item.rtime = MIN(v + (time_t) 0, TIME_T_MAX + (guint64) 0);
			case 6: item.dtime = MIN(v + (time_t) 0, TIME_T_MAX + (guint64) 0); 
			case 7: break;	/* Already stored above */
			default:
				g_assert_not_reached();
				goto corrupted;
			}
		}

		/* 
		 * We store the filenames UTF-8 encoded but the file might have been
		 * edited or corrupted.
		 */
		if (is_absolute_path(item.pathname)) {
			item.filename = lazy_filename_to_utf8_normalized(
						filepath_basename(item.pathname), UNI_NORM_NFC);
		} else {
			item.filename = lazy_unknown_to_utf8_normalized(
						filepath_basename(item.pathname), UNI_NORM_NFC, NULL);
		}

		if (upload_stats_find(NULL, item.pathname, item.size)) {
			g_warning("upload_stats_load_history():"
				" Ignoring line %u due to duplicate file.", lineno);
		} else if (upload_stats_find(item.sha1, item.pathname, item.size)) {
			g_warning("upload_stats_load_history():"
				" Ignoring line %u due to duplicate file.", lineno);
		} else {
			upload_stats_add(item.pathname, item.size, item.filename,
				item.attempts, item.complete, item.bytes_sent,
				item.rtime, item.dtime, item.sha1);
		}
		continue;

	corrupted:
		g_warning("upload statistics file corrupted at line %u.", lineno);
	}

	/* close file */
	fclose(upload_stats_file);

done:
	gcu_upload_stats_gui_thaw();
	return;
}