Пример #1
0
static int extract_how_many(int *n, const char *spec, size_t *pos)
{
	const char *end_ptr;
	int parsed, accumulated;
	char kind = spec[*pos];

	assert(spec[*pos] == '^' || spec[*pos] == '~');

	accumulated = 0;

	do {
		do {
			(*pos)++;
			accumulated++;
		} while (spec[(*pos)] == kind && kind == '~');

		if (git__isdigit(spec[*pos])) {
			if (git__strtol32(&parsed, spec + *pos, &end_ptr, 10) < 0)
				return GIT_EINVALIDSPEC;

			accumulated += (parsed - 1);
			*pos = end_ptr - spec;
		}

	} 	while (spec[(*pos)] == kind && kind == '~');

	*n = accumulated;

	return 0;
}
Пример #2
0
static int winhttp_connect(
    winhttp_subtransport *t,
    const char *url)
{
    wchar_t *ua = L"git/1.0 (libgit2 " WIDEN(LIBGIT2_VERSION) L")";
    wchar_t *wide_host;
    int32_t port;
    const char *default_port = "80";
    int error = -1;
    int default_timeout = TIMEOUT_INFINITE;
    int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT;

    /* Prepare port */
    if (git__strtol32(&port, t->connection_data.port, NULL, 10) < 0)
        return -1;

    /* Prepare host */
    if (git__utf8_to_16_alloc(&wide_host, t->connection_data.host) < 0) {
        giterr_set(GITERR_OS, "Unable to convert host to wide characters");
        return -1;
    }

    /* Establish session */
    t->session = WinHttpOpen(
                     ua,
                     WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
                     WINHTTP_NO_PROXY_NAME,
                     WINHTTP_NO_PROXY_BYPASS,
                     0);

    if (!t->session) {
        giterr_set(GITERR_OS, "Failed to init WinHTTP");
        goto on_error;
    }

    if (!WinHttpSetTimeouts(t->session, default_timeout, default_connect_timeout, default_timeout, default_timeout)) {
        giterr_set(GITERR_OS, "Failed to set timeouts for WinHTTP");
        goto on_error;
    }


    /* Establish connection */
    t->connection = WinHttpConnect(
                        t->session,
                        wide_host,
                        (INTERNET_PORT) port,
                        0);

    if (!t->connection) {
        giterr_set(GITERR_OS, "Failed to connect to host");
        goto on_error;
    }

    error = 0;

on_error:
    git__free(wide_host);

    return error;
}
Пример #3
0
static int32_t parse_len(const char *line)
{
	char num[PKT_LEN_SIZE + 1];
	int i, k, error;
	int32_t len;
	const char *num_end;

	memcpy(num, line, PKT_LEN_SIZE);
	num[PKT_LEN_SIZE] = '\0';

	for (i = 0; i < PKT_LEN_SIZE; ++i) {
		if (!isxdigit(num[i])) {
			/* Make sure there are no special characters before passing to error message */
			for (k = 0; k < PKT_LEN_SIZE; ++k) {
				if(!isprint(num[k])) {
					num[k] = '.';
				}
			}
			
			giterr_set(GITERR_NET, "invalid hex digit in length: '%s'", num);
			return -1;
		}
	}

	if ((error = git__strtol32(&len, num, &num_end, 16)) < 0)
		return error;

	return len;
}
Пример #4
0
static int read_unmerged(git_index *index, const char *buffer, size_t size)
{
	const char *endptr;
	size_t len;
	int i;

	git_vector_init(&index->unmerged, 16, unmerged_cmp);

	while (size) {
		git_index_entry_unmerged *lost;

		len = strlen(buffer) + 1;
		if (size <= len)
			return git__throw(GIT_ERROR, "Failed to read unmerged entries");

		if ((lost = git__malloc(sizeof(git_index_entry_unmerged))) == NULL)
			return GIT_ENOMEM;

		if (git_vector_insert(&index->unmerged, lost) < GIT_SUCCESS)
			return git__throw(GIT_ERROR, "Failed to read unmerged entries");

		lost->path = git__strdup(buffer);
		if (!lost->path)
			return GIT_ENOMEM;

		size -= len;
		buffer += len;

		for (i = 0; i < 3; i++) {
			long tmp;

			if (git__strtol32(&tmp, buffer, &endptr, 8) < GIT_SUCCESS ||
				!endptr || endptr == buffer || *endptr || tmp > UINT_MAX)
				return GIT_ERROR;

			lost->mode[i] = tmp;

			len = (endptr + 1) - buffer;
			if (size <= len)
				return git__throw(GIT_ERROR, "Failed to read unmerged entries");

			size -= len;
			buffer += len;
		}

		for (i = 0; i < 3; i++) {
			if (!lost->mode[i])
				continue;
			if (size < 20)
				return git__throw(GIT_ERROR, "Failed to read unmerged entries");
			git_oid_fromraw(&lost->oid[i], (unsigned char *) buffer);
			size -= 20;
			buffer += 20;
		}
	}

	return GIT_SUCCESS;
}
Пример #5
0
static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buffer_end)
{
	int error = GIT_SUCCESS;

	if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < GIT_SUCCESS)
		return GIT_ENOMEM;

	while (buffer < buffer_end) {
		git_tree_entry *entry;
		int tmp;

		entry = git__calloc(1, sizeof(git_tree_entry));
		if (entry == NULL) {
			error = GIT_ENOMEM;
			break;
		}

		if (git_vector_insert(&tree->entries, entry) < GIT_SUCCESS)
			return GIT_ENOMEM;

		if (git__strtol32(&tmp, buffer, &buffer, 8) < GIT_SUCCESS ||
			!buffer || !valid_attributes(tmp))
			return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tree. Can't parse attributes");

		entry->attr = tmp;

		if (*buffer++ != ' ') {
			error = git__throw(GIT_EOBJCORRUPTED, "Failed to parse tree. Object it corrupted");
			break;
		}

		if (memchr(buffer, 0, buffer_end - buffer) == NULL) {
			error = git__throw(GIT_EOBJCORRUPTED, "Failed to parse tree. Object it corrupted");
			break;
		}

		entry->filename = git__strdup(buffer);
		entry->filename_len = strlen(buffer);

		while (buffer < buffer_end && *buffer != 0)
			buffer++;

		buffer++;

		git_oid_fromraw(&entry->oid, (const unsigned char *)buffer);
		buffer += GIT_OID_RAWSZ;
	}

	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to parse buffer");
}
Пример #6
0
static int try_parse_numeric(int *n, const char *curly_braces_content)
{
	int32_t content;
	const char *end_ptr;

	if (git__strtol32(&content, curly_braces_content, &end_ptr, 10) < 0)
		return -1;

	if (*end_ptr != '\0')
		return -1;

	*n = (int)content;
	return 0;
}
Пример #7
0
static int parse_timezone_offset(const char *buffer, long *offset_out)
{
	long offset, dec_offset;
	int mins, hours;

	const char *offset_start;
	const char *offset_end;

	//we are sure that *buffer == ' ' 
	offset_start = buffer + 1;

	if (*offset_start == '\n') {
		*offset_out = 0;
		return GIT_SUCCESS;
	}

	if (offset_start[0] != '-' && offset_start[0] != '+')
		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. It doesn't start with '+' or '-'");

	if (offset_start[1] < '0' || offset_start[1] > '9')
		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset.");

	if (git__strtol32(&dec_offset, offset_start + 1, &offset_end, 10) < GIT_SUCCESS)
		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. It isn't a number");

	if (offset_end - offset_start != 5)
		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. Invalid length");

	if (dec_offset > 1400)
		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. Value too large");

	hours = dec_offset / 100;
	mins = dec_offset % 100;

	if (hours > 14)	// see http://www.worldtimezone.com/faq.html 
		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. Hour value too large");

	if (mins > 59)
		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. Minute value too large");

	offset = (hours * 60) + mins;

	if (offset_start[0] == '-')
		offset *= -1;
	
	*offset_out = offset;

	return GIT_SUCCESS;
}
Пример #8
0
int git_curl_stream_new(git_stream **out, const char *host, const char *port)
{
	curl_stream *st;
	CURL *handle;
	int iport = 0, error;

	st = git__calloc(1, sizeof(curl_stream));
	GITERR_CHECK_ALLOC(st);

	handle = curl_easy_init();
	if (handle == NULL) {
		giterr_set(GITERR_NET, "failed to create curl handle");
		git__free(st);
		return -1;
	}

	if ((error = git__strtol32(&iport, port, NULL, 10)) < 0) {
		git__free(st);
		return error;
	}

	curl_easy_setopt(handle, CURLOPT_URL, host);
	curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, st->curl_error);
	curl_easy_setopt(handle, CURLOPT_PORT, iport);
	curl_easy_setopt(handle, CURLOPT_CONNECT_ONLY, 1);
	curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 1);
	curl_easy_setopt(handle, CURLOPT_CERTINFO, 1);
	curl_easy_setopt(handle, CURLOPT_HTTPPROXYTUNNEL, 1);
	curl_easy_setopt(handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);

	/* curl_easy_setopt(handle, CURLOPT_VERBOSE, 1); */

	st->parent.version = GIT_STREAM_VERSION;
	st->parent.encrypted = 0; /* we don't encrypt ourselves */
	st->parent.proxy_support = 1;
	st->parent.connect = curls_connect;
	st->parent.certificate = curls_certificate;
	st->parent.set_proxy = curls_set_proxy;
	st->parent.read = curls_read;
	st->parent.write = curls_write;
	st->parent.close = curls_close;
	st->parent.free = curls_free;
	st->handle = handle;

	*out = (git_stream *) st;
	return 0;
}
Пример #9
0
static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buffer_end)
{
	int error = GIT_SUCCESS;

	if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < GIT_SUCCESS)
		return GIT_ENOMEM;

	while (buffer < buffer_end) {
		git_tree_entry *entry;

		entry = git__calloc(1, sizeof(git_tree_entry));
		if (entry == NULL) {
			error = GIT_ENOMEM;
			break;
		}

		if (git_vector_insert(&tree->entries, entry) < GIT_SUCCESS)
			return GIT_ENOMEM;

		if (git__strtol32((long *)&entry->attr, buffer, &buffer, 8) < GIT_SUCCESS)
			return GIT_EOBJCORRUPTED;

		if (*buffer++ != ' ') {
			error = GIT_EOBJCORRUPTED;
			break;
		}

		if (memchr(buffer, 0, buffer_end - buffer) == NULL) {
			error = GIT_EOBJCORRUPTED;
			break;
		}

		entry->filename = git__strdup(buffer);
		entry->filename_len = strlen(buffer);

		while (buffer < buffer_end && *buffer != 0)
			buffer++;

		buffer++;

		git_oid_mkraw(&entry->oid, (const unsigned char *)buffer);
		buffer += GIT_OID_RAWSZ;
	}

	return error;
}
Пример #10
0
GIT_INLINE(int) rebase_readint(
	size_t *out, git_buf *asc_out, git_buf *state_path, const char *filename)
{
	int32_t num;
	const char *eol;
	int error = 0;

	if ((error = rebase_readfile(asc_out, state_path, filename)) < 0)
		return error;

	if (git__strtol32(&num, asc_out->ptr, &eol, 10) < 0 || num < 0 || *eol) {
		giterr_set(GITERR_REBASE, "The file '%s' contains an invalid numeric value", filename);
		return -1;
	}

	*out = (size_t) num;

	return 0;
}
Пример #11
0
static int winhttp_connect(
	winhttp_subtransport *t,
	const char *url)
{
	wchar_t *ua = L"git/1.0 (libgit2 " WIDEN(LIBGIT2_VERSION) L")";
	git_win32_path host;
	int32_t port;
	const char *default_port = "80";

	/* Prepare port */
	if (git__strtol32(&port, t->connection_data.port, NULL, 10) < 0)
		return -1;

	/* Prepare host */
	git_win32_path_from_c(host, t->connection_data.host);

	/* Establish session */
	t->session = WinHttpOpen(
		ua,
		WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
		WINHTTP_NO_PROXY_NAME,
		WINHTTP_NO_PROXY_BYPASS,
		0);

	if (!t->session) {
		giterr_set(GITERR_OS, QT_TRANSLATE_NOOP("libgit2", "Failed to init WinHTTP"));
		return -1;
	}

	/* Establish connection */
	t->connection = WinHttpConnect(
		t->session,
		host,
		(INTERNET_PORT) port,
		0);

	if (!t->connection) {
		giterr_set(GITERR_OS, QT_TRANSLATE_NOOP("libgit2", "Failed to connect to host"));
		return -1;
	}

	return 0;
}
Пример #12
0
void test_core_strtol__int32(void)
{
	int32_t i;

	cl_git_pass(git__strtol32(&i, "123", NULL, 10));
	cl_assert(i == 123);
	cl_git_pass(git__strtol32(&i, "  +123 ", NULL, 10));
	cl_assert(i == 123);
	cl_git_pass(git__strtol32(&i, "  +2147483647 ", NULL, 10));
	cl_assert(i == 2147483647);
	cl_git_pass(git__strtol32(&i, "  -2147483648 ", NULL, 10));
	cl_assert(i == -2147483648LL);
	
	cl_git_fail(git__strtol32(&i, "  2147483657 ", NULL, 10));
	cl_git_fail(git__strtol32(&i, "  -2147483657 ", NULL, 10));
}
Пример #13
0
static int32_t parse_len(const char *line)
{
	char num[PKT_LEN_SIZE + 1];
	int i, error;
	int32_t len;
	const char *num_end;

	memcpy(num, line, PKT_LEN_SIZE);
	num[PKT_LEN_SIZE] = '\0';

	for (i = 0; i < PKT_LEN_SIZE; ++i) {
		if (!isxdigit(num[i])) {
			giterr_set(GITERR_NET, "Found invalid hex digit in length");
			return -1;
		}
	}

	if ((error = git__strtol32(&len, num, &num_end, 16)) < 0)
		return error;

	return len;
}
Пример #14
0
static ssize_t parse_len(const char *line)
{
	char num[PKT_LEN_SIZE + 1];
	int i, error;
	long len;
	const char *num_end;

	memcpy(num, line, PKT_LEN_SIZE);
	num[PKT_LEN_SIZE] = '\0';

	for (i = 0; i < PKT_LEN_SIZE; ++i) {
		if (!isxdigit(num[i]))
			return GIT_ENOTNUM;
	}

	error = git__strtol32(&len, num, &num_end, 16);
	if (error < GIT_SUCCESS) {
		return error;
	}

	return (unsigned int) len;
}
Пример #15
0
static int read_tree_internal(git_index_tree **out,
		const char **buffer_in, const char *buffer_end, git_index_tree *parent)
{
	git_index_tree *tree;
	const char *name_start, *buffer;
	long count;
	int error = GIT_SUCCESS;

	if ((tree = git__malloc(sizeof(git_index_tree))) == NULL)
		return GIT_ENOMEM;

	memset(tree, 0x0, sizeof(git_index_tree));
	tree->parent = parent;

	buffer = name_start = *buffer_in;

	if ((buffer = memchr(buffer, '\0', buffer_end - buffer)) == NULL) {
		error = GIT_EOBJCORRUPTED;
		goto cleanup;
	}

	/* NUL-terminated tree name */
	tree->name = git__strdup(name_start);
	if (tree->name == NULL) {
		error = GIT_ENOMEM;
		goto cleanup;
	}

	if (++buffer >= buffer_end) {
		error = GIT_EOBJCORRUPTED;
		goto cleanup;
	}

	/* Blank-terminated ASCII decimal number of entries in this tree */
	if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS || count < -1) {
		error = GIT_EOBJCORRUPTED;
		goto cleanup;
	}

	/* Invalidated TREE. Free the tree but report success */
	if (count == -1) {
		/* FIXME: return buffer_end or the end position for
		 * this single tree entry */
		*buffer_in = buffer_end;
		*out = NULL;
		free_tree(tree); /* Needs to be done manually */
		return GIT_SUCCESS;
	}

	tree->entries = count;

	if (*buffer != ' ' || ++buffer >= buffer_end) {
		error = GIT_EOBJCORRUPTED;
		goto cleanup;
	}

	 /* Number of children of the tree, newline-terminated */
	if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS ||
		count < 0) {
		error = GIT_EOBJCORRUPTED;
		goto cleanup;
	}

	tree->children_count = count;

	if (*buffer != '\n' || ++buffer >= buffer_end) {
		error = GIT_EOBJCORRUPTED;
		goto cleanup;
	}

	/* 160-bit SHA-1 for this tree and it's children */
	if (buffer + GIT_OID_RAWSZ > buffer_end) {
		error = GIT_EOBJCORRUPTED;
		goto cleanup;
	}

	git_oid_fromraw(&tree->oid, (const unsigned char *)buffer);
	buffer += GIT_OID_RAWSZ;

	/* Parse children: */
	if (tree->children_count > 0) {
		unsigned int i;
		int err;

		tree->children = git__malloc(tree->children_count * sizeof(git_index_tree *));
		if (tree->children == NULL)
			goto cleanup;

		for (i = 0; i < tree->children_count; ++i) {
			err = read_tree_internal(&tree->children[i], &buffer, buffer_end, tree);

			if (err < GIT_SUCCESS)
				goto cleanup;
		}
	}

	*buffer_in = buffer;
	*out = tree;
	return GIT_SUCCESS;

 cleanup:
	free_tree(tree);
	return error;
}
Пример #16
0
int git_signature__parse(git_signature *sig, const char **buffer_out,
		const char *buffer_end, const char *header, char ender)
{
	const char *buffer = *buffer_out;
	const char *email_start, *email_end;

	memset(sig, 0, sizeof(git_signature));

	if ((buffer_end = memchr(buffer, ender, buffer_end - buffer)) == NULL)
		return signature_error("no newline given");

	if (header) {
		const size_t header_len = strlen(header);

		if (buffer + header_len >= buffer_end || memcmp(buffer, header, header_len) != 0)
			return signature_error("expected prefix doesn't match actual");

		buffer += header_len;
	}

	email_start = git__memrchr(buffer, '<', buffer_end - buffer);
	email_end = git__memrchr(buffer, '>', buffer_end - buffer);

	if (!email_start || !email_end || email_end <= email_start)
		return signature_error("malformed e-mail");

	email_start += 1;
	sig->name = extract_trimmed(buffer, email_start - buffer - 1);
	sig->email = extract_trimmed(email_start, email_end - email_start);

	/* Do we even have a time at the end of the signature? */
	if (email_end + 2 < buffer_end) {
		const char *time_start = email_end + 2;
		const char *time_end;

		if (git__strtol64(&sig->when.time, time_start, &time_end, 10) < 0)
			return signature_error("invalid Unix timestamp");

		/* do we have a timezone? */
		if (time_end + 1 < buffer_end) {
			int offset, hours, mins;
			const char *tz_start, *tz_end;

			tz_start = time_end + 1;

			if ((tz_start[0] != '-' && tz_start[0] != '+') ||
				git__strtol32(&offset, tz_start + 1, &tz_end, 10) < 0) {
				//malformed timezone, just assume it's zero
				offset = 0;
			}

			hours = offset / 100;
			mins = offset % 100;

			/*
			 * only store timezone if it's not overflowing;
			 * see http://www.worldtimezone.com/faq.html
			 */
			if (hours < 14 && mins < 59) {
				sig->when.offset = (hours * 60) + mins;
				if (tz_start[0] == '-')
					sig->when.offset = -sig->when.offset;
			}
		}
	}

	*buffer_out = buffer_end + 1;
	return 0;
}
Пример #17
0
static int winhttp_connect(
	winhttp_subtransport *t)
{
	wchar_t *wide_host;
	int32_t port;
	wchar_t *wide_ua;
	git_buf ua = GIT_BUF_INIT;
	int error = -1;
	int default_timeout = TIMEOUT_INFINITE;
	int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT;

	t->session = NULL;
	t->connection = NULL;

	/* Prepare port */
	if (git__strtol32(&port, t->connection_data.port, NULL, 10) < 0)
		return -1;

	/* Prepare host */
	if (git__utf8_to_16_alloc(&wide_host, t->connection_data.host) < 0) {
		giterr_set(GITERR_OS, "unable to convert host to wide characters");
		return -1;
	}

	if ((error = user_agent(&ua)) < 0) {
		git__free(wide_host);
		return error;
	}

	if (git__utf8_to_16_alloc(&wide_ua, git_buf_cstr(&ua)) < 0) {
		giterr_set(GITERR_OS, "unable to convert host to wide characters");
		git__free(wide_host);
		git_buf_free(&ua);
		return -1;
	}

	git_buf_free(&ua);

	/* Establish session */
	t->session = WinHttpOpen(
		wide_ua,
		WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
		WINHTTP_NO_PROXY_NAME,
		WINHTTP_NO_PROXY_BYPASS,
		0);

	if (!t->session) {
		giterr_set(GITERR_OS, "failed to init WinHTTP");
		goto on_error;
	}

	if (!WinHttpSetTimeouts(t->session, default_timeout, default_connect_timeout, default_timeout, default_timeout)) {
		giterr_set(GITERR_OS, "failed to set timeouts for WinHTTP");
		goto on_error;
	}

	
	/* Establish connection */
	t->connection = WinHttpConnect(
		t->session,
		wide_host,
		(INTERNET_PORT) port,
		0);

	if (!t->connection) {
		giterr_set(GITERR_OS, "failed to connect to host");
		goto on_error;
	}

	if (WinHttpSetStatusCallback(t->connection, winhttp_status, WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, 0) == WINHTTP_INVALID_STATUS_CALLBACK) {
		giterr_set(GITERR_OS, "failed to set status callback");
		goto on_error;
	}

	error = 0;

on_error:
	if (error < 0)
		winhttp_close_connection(t);

	git__free(wide_host);
	git__free(wide_ua);

	return error;
}
Пример #18
0
static int commit_quick_parse(git_revwalk *walk, git_commit_list_node *commit, git_rawobj *raw)
{
	const size_t parent_len = strlen("parent ") + GIT_OID_HEXSZ + 1;
	unsigned char *buffer = raw->data;
	unsigned char *buffer_end = buffer + raw->len;
	unsigned char *parents_start, *committer_start;
	int i, parents = 0;
	int commit_time;

	buffer += strlen("tree ") + GIT_OID_HEXSZ + 1;

	parents_start = buffer;
	while (buffer + parent_len < buffer_end && memcmp(buffer, "parent ", strlen("parent ")) == 0) {
		parents++;
		buffer += parent_len;
	}

	commit->parents = alloc_parents(walk, commit, parents);
	GITERR_CHECK_ALLOC(commit->parents);

	buffer = parents_start;
	for (i = 0; i < parents; ++i) {
		git_oid oid;

		if (git_oid_fromstr(&oid, (char *)buffer + strlen("parent ")) < 0)
			return -1;

		commit->parents[i] = git_revwalk__commit_lookup(walk, &oid);
		if (commit->parents[i] == NULL)
			return -1;

		buffer += parent_len;
	}

	commit->out_degree = (unsigned short)parents;

	if ((committer_start = buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL)
		return commit_error(commit, "object is corrupted");

	buffer++;

	if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL)
		return commit_error(commit, "object is corrupted");

	/* Skip trailing spaces */
	while (buffer > committer_start && git__isspace(*buffer))
		buffer--;

	/* Seek for the begining of the pack of digits */
	while (buffer > committer_start && git__isdigit(*buffer))
		buffer--;

	/* Skip potential timezone offset */
	if ((buffer > committer_start) && (*buffer == '+' || *buffer == '-')) {
		buffer--;

		while (buffer > committer_start && git__isspace(*buffer))
			buffer--;

		while (buffer > committer_start && git__isdigit(*buffer))
			buffer--;
	}

	if ((buffer == committer_start) || (git__strtol32(&commit_time, (char *)(buffer + 1), NULL, 10) < 0))
		return commit_error(commit, "cannot parse commit time");

	commit->time = (time_t)commit_time;
	commit->parsed = 1;
	return 0;
}
Пример #19
0
int git_signature__parse(git_signature *sig, const char **buffer_out,
		const char *buffer_end, const char *header)
{
	const size_t header_len = strlen(header);

	int name_length, email_length;
	const char *buffer = *buffer_out;
	const char *line_end, *name_end, *email_end;
	long offset = 0, time;

	memset(sig, 0x0, sizeof(git_signature));

	line_end = memchr(buffer, '\n', buffer_end - buffer);
	if (!line_end)
		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. No newline found");;

	if (buffer + (header_len + 1) > line_end)
		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Signature too short");

	if (memcmp(buffer, header, header_len) != 0)
		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Expected prefix '%s' doesn't match actual", header);

	buffer += header_len;

	/* Parse name */
	if ((name_end = strstr(buffer, " <")) == NULL)
		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Can't find e-mail start");

	name_length = name_end - buffer;
	if (name_length <= 0)
		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Missing tagger name");

	sig->name = git__malloc(name_length + 1);
	if (sig->name == NULL)
		return GIT_ENOMEM;

	memcpy(sig->name, buffer, name_length);
	sig->name[name_length] = 0;
	buffer = name_end + 2;

	if (buffer >= line_end)
		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Ended unexpectedly");

	/* Parse email */
	if ((email_end = strstr(buffer, "> ")) == NULL)
		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Can't find e-mail end");

	email_length = email_end - buffer;
	sig->email = git__malloc(email_length + 1);
	if (sig->name == NULL)
		return GIT_ENOMEM;

	memcpy(sig->email, buffer, email_length);
	sig->email[email_length] = 0;
	buffer = email_end + 2;

	if (buffer >= line_end)
		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Ended unexpectedly");

	/* verify email */
	if (strpbrk(sig->email, "><\n ") != NULL)
		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Malformed e-mail");

	if (git__strtol32(&time, buffer, &buffer, 10) < GIT_SUCCESS)
		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Timestamp isn't a number");

	sig->when.time = (time_t)time;

	if (parse_timezone_offset(buffer, &offset) < GIT_SUCCESS)
		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Could not parse timezone offset");
	
	sig->when.offset = offset;

	*buffer_out = (line_end + 1);
	return GIT_SUCCESS;
}
Пример #20
0
static int winhttp_connect(
	winhttp_subtransport *t)
{
	wchar_t *wide_host;
	int32_t port;
	wchar_t *wide_ua;
	git_buf ua = GIT_BUF_INIT;
	int error = -1;
	int default_timeout = TIMEOUT_INFINITE;
	int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
	DWORD protocols =
		WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 |
		WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 |
		WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2;

	t->session = NULL;
	t->connection = NULL;

	/* Prepare port */
	if (git__strtol32(&port, t->connection_data.port, NULL, 10) < 0)
		return -1;

	/* Prepare host */
	if (git__utf8_to_16_alloc(&wide_host, t->connection_data.host) < 0) {
		giterr_set(GITERR_OS, "unable to convert host to wide characters");
		return -1;
	}


	if ((error = git_http__user_agent(&ua)) < 0) {
		git__free(wide_host);
		return error;
	}

	if (git__utf8_to_16_alloc(&wide_ua, git_buf_cstr(&ua)) < 0) {
		giterr_set(GITERR_OS, "unable to convert host to wide characters");
		git__free(wide_host);
		git_buf_free(&ua);
		return -1;
	}

	git_buf_free(&ua);

	/* Establish session */
	t->session = WinHttpOpen(
		wide_ua,
		WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
		WINHTTP_NO_PROXY_NAME,
		WINHTTP_NO_PROXY_BYPASS,
		0);

	if (!t->session) {
		giterr_set(GITERR_OS, "failed to init WinHTTP");
		goto on_error;
	}

	/*
	 * Do a best-effort attempt to enable TLS 1.2 but allow this to
	 * fail; if TLS 1.2 support is not available for some reason,
	 * ignore the failure (it will keep the default protocols).
	 */
	WinHttpSetOption(t->session,
		WINHTTP_OPTION_SECURE_PROTOCOLS,
		&protocols,
		sizeof(protocols));

	if (!WinHttpSetTimeouts(t->session, default_timeout, default_connect_timeout, default_timeout, default_timeout)) {
		giterr_set(GITERR_OS, "failed to set timeouts for WinHTTP");
		goto on_error;
	}


	/* Establish connection */
	t->connection = WinHttpConnect(
		t->session,
		wide_host,
		(INTERNET_PORT) port,
		0);

	if (!t->connection) {
		giterr_set(GITERR_OS, "failed to connect to host");
		goto on_error;
	}

	if (WinHttpSetStatusCallback(t->connection, winhttp_status, WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, 0) == WINHTTP_INVALID_STATUS_CALLBACK) {
		giterr_set(GITERR_OS, "failed to set status callback");
		goto on_error;
	}

	error = 0;

on_error:
	if (error < 0)
		winhttp_close_connection(t);

	git__free(wide_host);
	git__free(wide_ua);

	return error;
}
Пример #21
0
static int read_tree_internal(git_tree_cache **out,
		const char **buffer_in, const char *buffer_end, git_tree_cache *parent)
{
	git_tree_cache *tree = NULL;
	const char *name_start, *buffer;
	int count;
	size_t name_len;

	buffer = name_start = *buffer_in;

	if ((buffer = memchr(buffer, '\0', buffer_end - buffer)) == NULL)
		goto corrupted;

	if (++buffer >= buffer_end)
		goto corrupted;

	name_len = strlen(name_start);
	tree = git__malloc(sizeof(git_tree_cache) + name_len + 1);
	GITERR_CHECK_ALLOC(tree);

	memset(tree, 0x0, sizeof(git_tree_cache));
	tree->parent = parent;

	/* NUL-terminated tree name */
	memcpy(tree->name, name_start, name_len);
	tree->name[name_len] = '\0';

	/* Blank-terminated ASCII decimal number of entries in this tree */
	if (git__strtol32(&count, buffer, &buffer, 10) < 0)
		goto corrupted;

	tree->entries = count;

	if (*buffer != ' ' || ++buffer >= buffer_end)
		goto corrupted;

	 /* Number of children of the tree, newline-terminated */
	if (git__strtol32(&count, buffer, &buffer, 10) < 0 || count < 0)
		goto corrupted;

	tree->children_count = count;

	if (*buffer != '\n' || ++buffer > buffer_end)
		goto corrupted;

	/* The SHA1 is only there if it's not invalidated */
	if (tree->entries >= 0) {
		/* 160-bit SHA-1 for this tree and it's children */
		if (buffer + GIT_OID_RAWSZ > buffer_end)
			goto corrupted;

		git_oid_fromraw(&tree->oid, (const unsigned char *)buffer);
		buffer += GIT_OID_RAWSZ;
	}

	/* Parse children: */
	if (tree->children_count > 0) {
		unsigned int i;

		tree->children = git__malloc(tree->children_count * sizeof(git_tree_cache *));
		GITERR_CHECK_ALLOC(tree->children);

		memset(tree->children, 0x0, tree->children_count * sizeof(git_tree_cache *));

		for (i = 0; i < tree->children_count; ++i) {
			if (read_tree_internal(&tree->children[i], &buffer, buffer_end, tree) < 0)
				goto corrupted;
		}
	}

	*buffer_in = buffer;
	*out = tree;
	return 0;

 corrupted:
	git_tree_cache_free(tree);
	giterr_set(GITERR_INDEX, "Corrupted TREE extension in index");
	return -1;
}