diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/protocol.c | 50 | ||||
| -rw-r--r-- | src/protocol.h | 23 | ||||
| -rw-r--r-- | src/refspec.c | 9 | ||||
| -rw-r--r-- | src/refspec.h | 5 | ||||
| -rw-r--r-- | src/remote.c | 46 | ||||
| -rw-r--r-- | src/transports/git.c | 45 | ||||
| -rw-r--r-- | src/transports/http.c | 53 | 
7 files changed, 147 insertions, 84 deletions
diff --git a/src/protocol.c b/src/protocol.c new file mode 100644 index 000000000..1f39f105b --- /dev/null +++ b/src/protocol.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2009-2011 the libgit2 contributors + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#include "common.h" +#include "protocol.h" +#include "pkt.h" +#include "buffer.h" + +int git_protocol_store_refs(git_protocol *p, const char *data, size_t len) +{ +	git_buf *buf = &p->buf; +	git_vector *refs = p->refs; +	int error; +	const char *line_end, *ptr; + +	if (len == 0) { /* EOF */ +		if (buf->size != 0) +			return p->error = git__throw(GIT_ERROR, "EOF and unprocessed data"); +		else +			return 0; +	} + +	git_buf_put(buf, data, len); +	ptr = buf->ptr; +	while (1) { +		git_pkt *pkt; + +		if (buf->size == 0) +			return 0; + +		error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->size); +		if (error == GIT_ESHORTBUFFER) +			return 0; /* Ask for more */ +		if (error < GIT_SUCCESS) +			return p->error = git__rethrow(error, "Failed to parse pkt-line"); + +		git_buf_consume(buf, line_end); +		error = git_vector_insert(refs, pkt); +		if (error < GIT_SUCCESS) +			return p->error = git__rethrow(error, "Failed to add pkt to list"); + +		if (pkt->type == GIT_PKT_FLUSH) +			p->flush = 1; +	} + +	return error; +} diff --git a/src/protocol.h b/src/protocol.h new file mode 100644 index 000000000..e3315738a --- /dev/null +++ b/src/protocol.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2009-2011 the libgit2 contributors + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_protocol_h__ +#define INCLUDE_protocol_h__ + +#include "transport.h" +#include "buffer.h" + +typedef struct { +	git_transport *transport; +	git_vector *refs; +	git_buf buf; +	int error; +	unsigned int flush :1; +} git_protocol; + +int git_protocol_store_refs(git_protocol *p, const char *data, size_t len); + +#endif diff --git a/src/refspec.c b/src/refspec.c index e60e8f5b5..62683e7b7 100644 --- a/src/refspec.c +++ b/src/refspec.c @@ -23,8 +23,13 @@ int git_refspec_parse(git_refspec *refspec, const char *str)  	}  	delim = strchr(str, ':'); -	if (delim == NULL) -		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse refspec. No ':'"); +	if (delim == NULL) { +		refspec->src = git__strdup(str); +		if (refspec->src == NULL) +			return GIT_ENOMEM; + +		return GIT_SUCCESS; +	}  	refspec->src = git__strndup(str, delim - str);  	if (refspec->src == NULL) diff --git a/src/refspec.h b/src/refspec.h index 58f3fe472..7c389719b 100644 --- a/src/refspec.h +++ b/src/refspec.h @@ -10,9 +10,12 @@  #include "git2/refspec.h"  struct git_refspec { -	int force; +	struct git_refspec *next;  	char *src;  	char *dst; +	unsigned int force :1, +		pattern :1, +		matching :1;  };  int git_refspec_parse(struct git_refspec *refspec, const char *str); diff --git a/src/remote.c b/src/remote.c index 3ff08a21e..e0c127bd3 100644 --- a/src/remote.c +++ b/src/remote.c @@ -56,22 +56,34 @@ static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const cha  	return refspec_parse(refspec, val);  } -int git_remote_new(git_remote **out, git_repository *repo, const char *url) +int git_remote_new(git_remote **out, git_repository *repo, const char *url, const char *name)  {  	git_remote *remote; +	if (url == NULL) +		return git__throw(GIT_EINVALIDARGS, "No URL was given"); +  	remote = git__malloc(sizeof(git_remote));  	if (remote == NULL)  		return GIT_ENOMEM;  	memset(remote, 0x0, sizeof(git_remote));  	remote->repo = repo; +  	remote->url = git__strdup(url);  	if (remote->url == NULL) {  		git__free(remote);  		return GIT_ENOMEM;  	} +	if (name != NULL) { +		remote->name = git__strdup(name); +		if (remote->name == NULL) { +			git__free(remote); +			return GIT_ENOMEM; +		} +	} +  	*out = remote;  	return GIT_SUCCESS;  } @@ -206,13 +218,13 @@ int git_remote_ls(git_remote *remote, git_headarray *refs)  	return remote->transport->ls(remote->transport, refs);  } -int git_remote_negotiate(git_remote *remote) -{ -	return git_fetch_negotiate(remote); -} -  int git_remote_download(char **filename, git_remote *remote)  { +	int error; + +	if ((error = git_fetch_negotiate(remote)) < 0) +		return git__rethrow(error, "Error negotiating"); +  	return git_fetch_download_pack(filename, remote);  } @@ -255,6 +267,21 @@ int git_remote_update_tips(struct git_remote *remote)  	return GIT_SUCCESS;  } +int git_remote_connected(git_remote *remote) +{ +	return remote->transport == NULL ? 0 : remote->transport->connected; +} + +void git_remote_disconnect(git_remote *remote) +{ +	if (remote->transport != NULL) { +		if (remote->transport->connected) +			remote->transport->close(remote->transport); + +		remote->transport->free(remote->transport); +	} +} +  void git_remote_free(git_remote *remote)  {  	if (remote == NULL) @@ -266,11 +293,6 @@ void git_remote_free(git_remote *remote)  	git__free(remote->push.dst);  	git__free(remote->url);  	git__free(remote->name); -	if (remote->transport != NULL) { -		if (remote->transport->connected) -			remote->transport->close(remote->transport); - -		remote->transport->free(remote->transport); -	} +	git_remote_disconnect(remote);  	git__free(remote);  } diff --git a/src/transports/git.c b/src/transports/git.c index c2014529b..2ee2e4831 100644 --- a/src/transports/git.c +++ b/src/transports/git.c @@ -20,9 +20,11 @@  #include "filebuf.h"  #include "repository.h"  #include "fetch.h" +#include "protocol.h"  typedef struct {  	git_transport parent; +	git_protocol proto;  	GIT_SOCKET socket;  	git_vector refs;  	git_remote_head **heads; @@ -126,11 +128,7 @@ static int do_connect(transport_git *t, const char *url)  static int store_refs(transport_git *t)  {  	gitno_buffer *buf = &t->buf; -	git_vector *refs = &t->refs;  	int error = GIT_SUCCESS; -	const char *line_end, *ptr; -	git_pkt *pkt; -  	while (1) {  		error = gitno_recv(buf); @@ -139,34 +137,20 @@ static int store_refs(transport_git *t)  		if (error == GIT_SUCCESS) /* Orderly shutdown, so exit */  			return GIT_SUCCESS; -		ptr = buf->data; -		while (1) { -			if (buf->offset == 0) -				break; -			error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset); -			/* -			 * If the error is GIT_ESHORTBUFFER, it means the buffer -			 * isn't long enough to satisfy the request. Break out and -			 * wait for more input. -			 * On any other error, fail. -			 */ -			if (error == GIT_ESHORTBUFFER) { -				break; -			} -			if (error < GIT_SUCCESS) { -				return error; -			} - -			/* Get rid of the part we've used already */ -			gitno_consume(buf, line_end); +		error = git_protocol_store_refs(&t->proto, buf->data, buf->offset); +		if (error == GIT_ESHORTBUFFER) { +			gitno_consume_n(buf, buf->len); +			continue; +		} -			error = git_vector_insert(refs, pkt); -			if (error < GIT_SUCCESS) -				return error; +		if (error < GIT_SUCCESS) +			return git__rethrow(error, "Failed to store refs"); -			if (pkt->type == GIT_PKT_FLUSH) -				return GIT_SUCCESS; +		gitno_consume_n(buf, buf->offset); +		if (t->proto.flush) { /* No more refs */ +			t->proto.flush = 0; +			return GIT_SUCCESS;  		}  	} @@ -476,6 +460,7 @@ static void git_free(git_transport *transport)  	git_vector_free(refs);  	git__free(t->heads); +	git_buf_free(&t->proto.buf);  	git__free(t->parent.url);  	git__free(t);  } @@ -501,6 +486,8 @@ int git_transport_git(git_transport **out)  	t->parent.download_pack = git_download_pack;  	t->parent.close = git_close;  	t->parent.free = git_free; +	t->proto.refs = &t->refs; +	t->proto.transport = (git_transport *) t;  	*out = (git_transport *) t; diff --git a/src/transports/http.c b/src/transports/http.c index 66b6f252c..ae0c56a73 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -19,6 +19,7 @@  #include "fetch.h"  #include "filebuf.h"  #include "repository.h" +#include "protocol.h"  enum last_cb {  	NONE, @@ -28,6 +29,7 @@ enum last_cb {  typedef struct {  	git_transport parent; +	git_protocol proto;  	git_vector refs;  	git_vector common;  	int socket; @@ -186,47 +188,8 @@ static int on_headers_complete(http_parser *parser)  static int on_body_store_refs(http_parser *parser, const char *str, size_t len)  {  	transport_http *t = (transport_http *) parser->data; -	git_buf *buf = &t->buf; -	git_vector *refs = &t->refs; -	int error; -	const char *line_end, *ptr; -	static int first_pkt = 1; - -	if (len == 0) { /* EOF */ -		if (buf->size != 0) -			return t->error = git__throw(GIT_ERROR, "EOF and unprocessed data"); -		else -			return 0; -	} - -	git_buf_put(buf, str, len); -	ptr = buf->ptr; -	while (1) { -		git_pkt *pkt; - -		if (buf->size == 0) -			return 0; - -		error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->size); -		if (error == GIT_ESHORTBUFFER) -			return 0; /* Ask for more */ -		if (error < GIT_SUCCESS) -			return t->error = git__rethrow(error, "Failed to parse pkt-line"); - -		git_buf_consume(buf, line_end); -		if (first_pkt) { -			first_pkt = 0; -			if (pkt->type != GIT_PKT_COMMENT) -				return t->error = git__throw(GIT_EOBJCORRUPTED, "Not a valid smart HTTP response"); -		} - -		error = git_vector_insert(refs, pkt); -		if (error < GIT_SUCCESS) -			return t->error = git__rethrow(error, "Failed to add pkt to list"); -	} - -	return error; +	return git_protocol_store_refs(&t->proto, str, len);  }  static int on_message_complete(http_parser *parser) @@ -243,6 +206,7 @@ static int store_refs(transport_http *t)  	http_parser_settings settings;  	char buffer[1024];  	gitno_buffer buf; +	git_pkt *pkt;  	http_parser_init(&t->parser, HTTP_RESPONSE);  	t->parser.data = t; @@ -273,6 +237,12 @@ static int store_refs(transport_http *t)  			return GIT_SUCCESS;  	} +	pkt = git_vector_get(&t->refs, 0); +	if (pkt == NULL || pkt->type != GIT_PKT_COMMENT) +		return t->error = git__throw(GIT_EOBJCORRUPTED, "Not a valid smart HTTP response"); +	else +		git_vector_remove(&t->refs, 0); +  	return error;  } @@ -750,6 +720,7 @@ static void http_free(git_transport *transport)  	}  	git_vector_free(common);  	git_buf_free(&t->buf); +	git_buf_free(&t->proto.buf);  	git__free(t->heads);  	git__free(t->content_type);  	git__free(t->host); @@ -775,6 +746,8 @@ int git_transport_http(git_transport **out)  	t->parent.download_pack = http_download_pack;  	t->parent.close = http_close;  	t->parent.free = http_free; +	t->proto.refs = &t->refs; +	t->proto.transport = (git_transport *) t;  #ifdef GIT_WIN32  	/* on win32, the WSA context needs to be initialized  | 
