diff options
| author | Carlos Martín Nieto <carlos@cmartin.tk> | 2012-03-06 10:47:18 +0100 | 
|---|---|---|
| committer | Vicent Martí <tanoku@gmail.com> | 2012-04-11 19:16:10 +0200 | 
| commit | 2b386acdb310394b7a227b27d6eff330e1f935ec (patch) | |
| tree | e4310eab361dd713ec66168a0766ea095fde5108 /src | |
| parent | 84d250bfeb244d1fe82efafa296141c807135fb0 (diff) | |
| download | libgit2-2b386acdb310394b7a227b27d6eff330e1f935ec.tar.gz | |
error-handling: git transport
Diffstat (limited to 'src')
| -rw-r--r-- | src/transports/git.c | 261 | 
1 files changed, 127 insertions, 134 deletions
diff --git a/src/transports/git.c b/src/transports/git.c index befdec5ee..fd3ff5b32 100644 --- a/src/transports/git.c +++ b/src/transports/git.c @@ -49,8 +49,10 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url)  	int len;  	delim = strchr(url, '/'); -	if (delim == NULL) -		return git__throw(GIT_EOBJCORRUPTED, "Failed to create proto-request: malformed URL"); +	if (delim == NULL) { +		giterr_set(GITERR_NET, "Malformed URL"); +		return -1; +	}  	repo = delim; @@ -80,7 +82,7 @@ static int send_request(GIT_SOCKET s, const char *cmd, const char *url)  	git_buf request = GIT_BUF_INIT;  	error = gen_proto(&request, cmd, url); -	if (error < GIT_SUCCESS) +	if (error < 0)  		goto cleanup;  	error = gitno_send(s, request.ptr, request.size, 0); @@ -105,9 +107,8 @@ static int do_connect(transport_git *t, const char *url)  	if (!git__prefixcmp(url, prefix))  		url += strlen(prefix); -	error = gitno_extract_host_and_port(&host, &port, url, GIT_DEFAULT_PORT); -	if (error < GIT_SUCCESS) -		return error; +	if (gitno_extract_host_and_port(&host, &port, url, GIT_DEFAULT_PORT) < 0) +		return -1;  	s = gitno_connect(host, port);  	connected = 1; @@ -119,8 +120,10 @@ static int do_connect(transport_git *t, const char *url)  	if (error < GIT_SUCCESS && s > 0)  		close(s); -	if (!connected) -		error = git__throw(GIT_EOSERR, "Failed to connect to any of the addresses"); +	if (!connected) { +		giterr_set(GITERR_NET, "Failed to connect to the host"); +		return -1; +	}  	return error;  } @@ -131,33 +134,30 @@ static int do_connect(transport_git *t, const char *url)  static int store_refs(transport_git *t)  {  	gitno_buffer *buf = &t->buf; -	int error = GIT_SUCCESS; +	int ret = 0;  	while (1) { -		error = gitno_recv(buf); -		if (error < GIT_SUCCESS) -			return git__rethrow(GIT_EOSERR, "Failed to receive data"); -		if (error == GIT_SUCCESS) /* Orderly shutdown, so exit */ -			return GIT_SUCCESS; - -		error = git_protocol_store_refs(&t->proto, buf->data, buf->offset); -		if (error == GIT_ESHORTBUFFER) { +		if ((ret = gitno_recv(buf)) < 0) +			return -1; +		if (ret == 0) /* Orderly shutdown, so exit */ +			return 0; + +		ret = git_protocol_store_refs(&t->proto, buf->data, buf->offset); +		if (ret == GIT_ESHORTBUFFER) {  			gitno_consume_n(buf, buf->len);  			continue;  		} -		if (error < GIT_SUCCESS) -			return git__rethrow(error, "Failed to store refs"); +		if (ret < 0) +			return ret;  		gitno_consume_n(buf, buf->offset);  		if (t->proto.flush) { /* No more refs */  			t->proto.flush = 0; -			return GIT_SUCCESS; +			return 0;  		}  	} - -	return error;  }  static int detect_caps(transport_git *t) @@ -170,7 +170,7 @@ static int detect_caps(transport_git *t)  	pkt = git_vector_get(refs, 0);  	/* No refs or capabilites, odd but not a problem */  	if (pkt == NULL || pkt->capabilities == NULL) -		return GIT_SUCCESS; +		return 0;  	ptr = pkt->capabilities;  	while (ptr != NULL && *ptr != '\0') { @@ -187,7 +187,7 @@ static int detect_caps(transport_git *t)  		ptr = strchr(ptr, ' ');  	} -	return GIT_SUCCESS; +	return 0;  }  /* @@ -197,36 +197,33 @@ static int detect_caps(transport_git *t)  static int git_connect(git_transport *transport, int direction)  {  	transport_git *t = (transport_git *) transport; -	int error = GIT_SUCCESS; -	if (direction == GIT_DIR_PUSH) -		return git__throw(GIT_EINVALIDARGS, "Pushing is not supported with the git protocol"); +	if (direction == GIT_DIR_PUSH) { +		giterr_set(GITERR_NET, "Pushing over git:// is not supported"); +		return -1; +	}  	t->parent.direction = direction; -	error = git_vector_init(&t->refs, 16, NULL); -	if (error < GIT_SUCCESS) -		goto cleanup; +	if (git_vector_init(&t->refs, 16, NULL) < 0) +		return -1;  	/* Connect and ask for the refs */ -	error = do_connect(t, transport->url); -	if (error < GIT_SUCCESS) -		return error; +	if (do_connect(t, transport->url) < 0) +		goto cleanup;  	gitno_buffer_setup(&t->buf, t->buff, sizeof(t->buff), t->socket);  	t->parent.connected = 1; -	error = store_refs(t); -	if (error < GIT_SUCCESS) -		return error; +	if (store_refs(t) < 0) +		goto cleanup; -	error = detect_caps(t); +	if (detect_caps(t) < 0) +		goto cleanup; +	return 0;  cleanup: -	if (error < GIT_SUCCESS) { -		git_vector_free(&t->refs); -	} - -	return error; +	git_vector_free(&t->refs); +	return -1;  }  static int git_ls(git_transport *transport, git_headlist_cb list_cb, void *opaque) @@ -244,12 +241,51 @@ static int git_ls(git_transport *transport, git_headlist_cb list_cb, void *opaqu  		pkt = (git_pkt_ref *)p; -		if (list_cb(&pkt->head, opaque) < 0) -			return git__throw(GIT_ERROR, -				"The user callback returned an error code"); +		if (list_cb(&pkt->head, opaque) < 0) { +			giterr_set(GITERR_NET, "User callback returned error"); +			return -1; +		}  	} -	return GIT_SUCCESS; +	return 0; +} + +/* Wait until we get an ack from the */ +static int recv_pkt(gitno_buffer *buf) +{ +	const char *ptr = buf->data, *line_end; +	git_pkt *pkt; +	int pkt_type, error; + +	do { +		/* Wait for max. 1 second */ +		if ((error = gitno_select_in(buf, 1, 0)) < 0) { +			return -1; +		} else if (error == 0) { +			/* +			 * Some servers don't respond immediately, so if this +			 * happens, we keep sending information until it +			 * answers. Pretend we received a NAK to convince higher +			 * layers to do so. +			 */ +			return GIT_PKT_NAK; +		} + +		if ((error = gitno_recv(buf)) < 0) +			return -1; + +		error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset); +		if (error == GIT_ESHORTBUFFER) +			continue; +		if (error < 0) +			return -1; +	} while (error); + +	gitno_consume(buf, line_end); +	pkt_type = pkt->type; +	git__free(pkt); + +	return pkt_type;  }  static int git_negotiate_fetch(git_transport *transport, git_repository *repo, const git_vector *wants) @@ -263,19 +299,15 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, c  	unsigned int i;  	gitno_buffer *buf = &t->buf; -	error = git_pkt_send_wants(wants, &t->caps, t->socket); -	if (error < GIT_SUCCESS) -		return git__rethrow(error, "Failed to send wants list"); +	if (git_pkt_send_wants(wants, &t->caps, t->socket) < 0) +		return -1; -	error = git_reference_listall(&refs, repo, GIT_REF_LISTALL); -	if (error < GIT_ERROR) -		return git__rethrow(error, "Failed to list all references"); +	if (git_reference_listall(&refs, repo, GIT_REF_LISTALL) < 0) +		return -1; + +	if (git_revwalk_new(&walk, repo) < 0) +		return -1; -	error = git_revwalk_new(&walk, repo); -	if (error < GIT_ERROR) { -		error = git__rethrow(error, "Failed to list all references"); -		goto cleanup; -	}  	git_revwalk_sorting(walk, GIT_SORT_TIME);  	for (i = 0; i < refs.count; ++i) { @@ -283,20 +315,15 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, c  		if (!git__prefixcmp(refs.strings[i], GIT_REFS_TAGS_DIR))  			continue; -		error = git_reference_lookup(&ref, repo, refs.strings[i]); -		if (error < GIT_ERROR) { -			error = git__rethrow(error, "Failed to lookup %s", refs.strings[i]); -			goto cleanup; -		} +		if (git_reference_lookup(&ref, repo, refs.strings[i]) < 0) +			goto on_error;  		if (git_reference_type(ref) == GIT_REF_SYMBOLIC)  			continue; -		error = git_revwalk_push(walk, git_reference_oid(ref)); -		if (error < GIT_ERROR) { -			error = git__rethrow(error, "Failed to push %s", refs.strings[i]); -			goto cleanup; -		} +		if ((error = git_revwalk_push(walk, git_reference_oid(ref))) < 0) +			goto on_error; +  	}  	git_strarray_free(&refs); @@ -306,67 +333,38 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, c  	 * every once in a while.  	 */  	i = 0; -	while ((error = git_revwalk_next(&oid, walk)) == GIT_SUCCESS) { +	while ((error = git_revwalk_next(&oid, walk)) == 0) {  		error = git_pkt_send_have(&oid, t->socket);  		i++;  		if (i % 20 == 0) { -			const char *ptr = buf->data, *line_end; -			git_pkt *pkt; +			int pkt_type; +  			git_pkt_send_flush(t->socket); -			while (1) { -				/* Wait for max. 1 second */ -				error = gitno_select_in(buf, 1, 0); -				if (error < GIT_SUCCESS) { -					error = git__throw(GIT_EOSERR, "Error in select"); -				} else if (error == 0) { -				/* -				 * Some servers don't respond immediately, so if this -				 * happens, we keep sending information until it -				 * answers. -				 */ -					break; -				} - -				error = gitno_recv(buf); -				if (error < GIT_SUCCESS) { -				 error = git__rethrow(error, "Error receiving data"); -				 goto cleanup; -				} -				error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset); -				if (error == GIT_ESHORTBUFFER) -					continue; -				if (error < GIT_SUCCESS) { -					error = git__rethrow(error, "Failed to get answer"); -					goto cleanup; -				} - -				gitno_consume(buf, line_end); - -				if (pkt->type == GIT_PKT_ACK) { -					git__free(pkt); -					error = GIT_SUCCESS; -					goto done; -				} else if (pkt->type == GIT_PKT_NAK) { -					git__free(pkt); -					break; -				} else { -					error = git__throw(GIT_ERROR, "Got unexpected pkt type"); -					goto cleanup; -				} +			pkt_type = recv_pkt(buf); + +			if (pkt_type == GIT_PKT_ACK) { +				break; +			} else if (pkt_type == GIT_PKT_NAK) { +				continue; +			} else { +				giterr_set(GITERR_NET, "Unexpected pkt type"); +				goto on_error;  			} +  		}  	} -	if (error == GIT_EREVWALKOVER) -		error = GIT_SUCCESS; +	if (error != GIT_EREVWALKOVER) +		goto on_error; -done:  	git_pkt_send_flush(t->socket);  	git_pkt_send_done(t->socket); -cleanup:  	git_revwalk_free(walk); +	return 0; -	return error; +on_error: +	git_revwalk_free(walk); +	return -1;  }  static int git_send_flush(git_transport *transport) @@ -386,7 +384,7 @@ static int git_send_done(git_transport *transport)  static int git_download_pack(char **out, git_transport *transport, git_repository *repo)  {  	transport_git *t = (transport_git *) transport; -	int error = GIT_SUCCESS; +	int error = 0, read_bytes;  	gitno_buffer *buf = &t->buf;  	git_pkt *pkt;  	const char *line_end, *ptr; @@ -394,7 +392,7 @@ static int git_download_pack(char **out, git_transport *transport, git_repositor  	/*  	 * For now, we ignore everything and wait for the pack  	 */ -	while (1) { +	do {  		ptr = buf->data;  		/* Whilst we're searching for the pack */  		while (1) { @@ -419,34 +417,29 @@ static int git_download_pack(char **out, git_transport *transport, git_repositor  			gitno_consume(buf, line_end);  		} -		error = gitno_recv(buf); -		if (error < GIT_SUCCESS) -			return git__rethrow(GIT_EOSERR, "Failed to receive data"); -		if (error == 0) { /* Orderly shutdown */ -			return GIT_SUCCESS; -		} +		read_bytes = gitno_recv(buf); +	} while (read_bytes); -	} +	return read_bytes;  }  static int git_close(git_transport *transport)  {  	transport_git *t = (transport_git*) transport; -	int error;  	/* Can't do anything if there's an error, so don't bother checking  */  	git_pkt_send_flush(t->socket); -	error = gitno_close(t->socket); - -	if (error < 0) -		error = git__throw(GIT_EOSERR, "Failed to close socket"); +	if (gitno_close(t->socket) < 0) { +		giterr_set(GITERR_NET, "Failed to close socket"); +		return -1; +	}  #ifdef GIT_WIN32  	WSACleanup();  #endif -	return error; +	return 0;  }  static void git_free(git_transport *transport) @@ -475,8 +468,7 @@ int git_transport_git(git_transport **out)  #endif  	t = git__malloc(sizeof(transport_git)); -	if (t == NULL) -		return GIT_ENOMEM; +	GITERR_CHECK_ALLOC(t);  	memset(t, 0x0, sizeof(transport_git)); @@ -497,9 +489,10 @@ int git_transport_git(git_transport **out)  	ret = WSAStartup(MAKEWORD(2,2), &t->wsd);  	if (ret != 0) {  		git_free(*out); -		return git__throw(GIT_EOSERR, "Winsock init failed"); +		giterr_set(GITERR_NET, "Winsock init failed"); +		return -1;  	}  #endif -	return GIT_SUCCESS; +	return 0;  }  | 
