Commit 65c86048cb63813453af184118e86947b5a9b161

Carlos Martín Nieto 2011-10-05T01:28:16

Introduce the git_pkt_buffer_ family of functions Signed-off-by: Carlos Martín Nieto <carlos@cmartin.tk>

diff --git a/src/pkt.c b/src/pkt.c
index a9ac4ad..801dd9b 100644
--- a/src/pkt.c
+++ b/src/pkt.c
@@ -262,6 +262,12 @@ void git_pkt_free(git_pkt *pkt)
 	free(pkt);
 }
 
+int git_pkt_buffer_flush(git_buf *buf)
+{
+	git_buf_puts(buf, "0000");
+	return git_buf_oom(buf) ? GIT_ENOMEM : GIT_SUCCESS;
+}
+
 int git_pkt_send_flush(int s, int chunked)
 {
 	char flush[] = "0000";
@@ -275,30 +281,36 @@ int git_pkt_send_flush(int s, int chunked)
 	return gitno_send(s, flush, strlen(flush), 0);
 }
 
-static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps, int fd, int chunked)
+static int buffer_want_with_caps(git_remote_head *head, git_transport_caps *caps, git_buf *buf)
 {
-	char capstr[20]; /* Longer than we need */
-	char oid[GIT_OID_HEXSZ +1] = {0}, *cmd;
-	int error, len;
-	git_buf buf = GIT_BUF_INIT;
+	char capstr[20];
+	char oid[GIT_OID_HEXSZ +1] = {0};
+	int len;
 
 	if (caps->ofs_delta)
 		strcpy(capstr, GIT_CAP_OFS_DELTA);
 
 	len = strlen("XXXXwant ") + GIT_OID_HEXSZ + 1 /* NUL */ + strlen(capstr) + 1 /* LF */;
-	cmd = git__malloc(len + 1);
-	if (cmd == NULL)
-		return GIT_ENOMEM;
+	git_buf_grow(buf, buf->size + len);
 
 	git_oid_fmt(oid, &head->oid);
-	git_buf_printf(&buf, "%04xwant %s%c%s\n", len, oid, 0, capstr);
-	if (chunked) {
-		error = gitno_send_chunk_size(fd, len);
-		if (error < GIT_SUCCESS)
-			return git__rethrow(error, "Failed to send first want chunk size");
-	}
-	error = gitno_send(fd, git_buf_cstr(&buf), len, 0);
-	free(cmd);
+	git_buf_printf(buf, "%04xwant %s%c%s\n", len, oid, 0, capstr);
+
+	return git_buf_oom(buf) ? GIT_ENOMEM : GIT_SUCCESS;
+}
+
+static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps, GIT_SOCKET fd)
+{
+	git_buf buf = GIT_BUF_INIT;
+	int error;
+
+	error = buffer_want_with_caps(head, caps, &buf);
+	if (error < GIT_SUCCESS)
+		return git__rethrow(error, "Failed to buffer want with caps");
+
+	error = gitno_send(fd, buf.ptr, buf.size, 0);
+	git_buf_free(&buf);
+
 	return error;
 }
 
@@ -308,6 +320,41 @@ static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps, 
  */
 #define WANT_PREFIX "0032want "
 
+int git_pkt_buffer_wants(git_headarray *refs, git_transport_caps *caps, git_buf *buf)
+{
+	unsigned int i = 0;
+	int error;
+	git_remote_head *head;
+
+	if (caps->common) {
+		for (; i < refs->len; ++i) {
+			head = refs->heads[i];
+			if (!head->local)
+				break;
+		}
+
+		error = buffer_want_with_caps(refs->heads[i], caps, buf);
+		if (error < GIT_SUCCESS)
+			return git__rethrow(error, "Failed to buffer want with caps");
+
+		i++;
+	}
+
+	for (; i < refs->len; ++i) {
+		char oid[GIT_OID_HEXSZ];
+
+		head = refs->heads[i];
+		if (head->local)
+			continue;
+
+		git_oid_fmt(oid, &head->oid);
+		git_buf_puts(buf, WANT_PREFIX);
+		git_buf_put(buf, oid, GIT_OID_HEXSZ);
+	}
+
+	return git_pkt_buffer_flush(buf);
+}
+
 int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd, int chunked)
 {
 	unsigned int i = 0;
@@ -329,7 +376,7 @@ int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd, in
 				break;
 		}
 
-		error = send_want_with_caps(refs->heads[i], caps, fd, chunked);
+		error = send_want_with_caps(refs->heads[i], caps, fd);
 		if (error < GIT_SUCCESS)
 			return git__rethrow(error, "Failed to send want pkt with caps");
 		/* Increase it here so it's correct whether we run this or not */
@@ -356,12 +403,18 @@ int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd, in
 	return git_pkt_send_flush(fd, chunked);
 }
 
-/*
- * TODO: this should be a more generic function, maybe to be used by
- * git_pkt_send_wants, as it's not performance-critical
- */
 #define HAVE_PREFIX "0032have "
 
+int git_pkt_buffer_have(git_oid *oid, git_buf *buf)
+{
+	char oidhex[GIT_OID_HEXSZ + 1];
+
+	memset(oidhex, 0x0, sizeof(oidhex));
+	git_oid_fmt(oidhex, oid);
+	git_buf_printf(buf, "%s%s\n", HAVE_PREFIX, oidhex);
+	return git_buf_oom(buf) ? GIT_ENOMEM : GIT_SUCCESS;
+}
+
 int git_pkt_send_have(git_oid *oid, int fd, int chunked)
 {
 	char buf[] = "0032have 0000000000000000000000000000000000000000\n";
@@ -376,6 +429,14 @@ int git_pkt_send_have(git_oid *oid, int fd, int chunked)
 	return gitno_send(fd, buf, strlen(buf), 0);
 }
 
+static char *donestr = "0009done\n";
+
+int git_pkt_buffer_done(git_buf *buf)
+{
+	git_buf_puts(buf, donestr);
+	return git_buf_oom(buf) ? GIT_ENOMEM : GIT_SUCCESS;
+}
+
 int git_pkt_send_done(int fd, int chunked)
 {
 	char buf[] = "0009done\n";
diff --git a/src/pkt.h b/src/pkt.h
index 0689e29..44c36b4 100644
--- a/src/pkt.h
+++ b/src/pkt.h
@@ -10,6 +10,7 @@
 
 #include "common.h"
 #include "transport.h"
+#include "buffer.h"
 #include "git2/net.h"
 
 enum git_pkt_type {
@@ -63,9 +64,13 @@ typedef struct {
 } git_pkt_comment;
 
 int git_pkt_parse_line(git_pkt **head, const char *line, const char **out, size_t len);
+int git_pkt_buffer_flush(git_buf *buf);
 int git_pkt_send_flush(int s, int chunked);
+int git_pkt_buffer_done(git_buf *buf);
 int git_pkt_send_done(int s, int chunked);
+int git_pkt_buffer_wants(git_headarray *refs, git_transport_caps *caps, git_buf *buf);
 int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd, int chunked);
+int git_pkt_buffer_have(git_oid *oid, git_buf *buf);
 int git_pkt_send_have(git_oid *oid, int fd, int chunked);
 void git_pkt_free(git_pkt *pkt);