Subject: [PATCH 3/9] pv4_tree_desc: introduce new struct for pack v4 tree walker

From: Nguyễn Thái Ngọc Duy <[email-masked]>
Date: Wed, 9 Oct 2013 21:46:10 +0700

This struct is intended to be the successor of struct tree_desc. For
now it only holds a buffer for converting pv4 tree to canonical format.

Signed-off-by: Nguyễn Thái Ngọc Duy <[email-masked]>
---
 packv4-parse.c | 73 ++++++++++++++++++++++++++++------------------------------
 packv4-parse.h |  9 ++++++++
 2 files changed, 44 insertions(+), 38 deletions(-)

diff --git a/packv4-parse.c b/packv4-parse.c
index 7b096cb..f9db364 100644
--- a/packv4-parse.c
+++ b/packv4-parse.c
@@ -344,9 +344,8 @@ void *pv4_get_commit(struct packed_git *p, struct pack_window **w_curs,
 	return dst;
 }
 
-static int copy_canonical_tree_entries(struct packed_git *p, off_t offset,
-				       unsigned int start, unsigned int count,
-				       unsigned char **dstp, unsigned long *sizep)
+static int copy_canonical_tree_entries(struct pv4_tree_desc *v4, off_t offset,
+				       unsigned int start, unsigned int count)
 {
 	void *data;
 	const unsigned char *from, *end;
@@ -354,7 +353,7 @@ static int copy_canonical_tree_entries(struct packed_git *p, off_t offset,
 	unsigned long size;
 	struct tree_desc desc;
 
-	data = unpack_entry(p, offset, &type, &size);
+	data = unpack_entry(v4->p, offset, &type, &size);
 	if (!data)
 		return -1;
 	if (type != OBJ_TREE) {
@@ -372,13 +371,11 @@ static int copy_canonical_tree_entries(struct packed_git *p, off_t offset,
 		update_tree_entry(&desc);
 	end = desc.buffer;
 
-	if (end - from > *sizep) {
+	if (end - from > strbuf_avail(&v4->buf)) {
 		free(data);
 		return -1;
 	}
-	memcpy(*dstp, from, end - from);
-	*dstp += end - from;
-	*sizep -= end - from;
+	strbuf_add(&v4->buf, from, end - from);
 	free(data);
 	return 0;
 }
@@ -417,7 +414,7 @@ static struct pv4_tree_cache *get_tree_offset_cache(struct packed_git *p, off_t
 	return c;
 }
 
-static int tree_entry_prefix(unsigned char *buf, unsigned long size,
+static int tree_entry_prefix(char *buf, unsigned long size,
 			     const unsigned char *path, int path_len,
 			     unsigned mode)
 {
@@ -443,35 +440,33 @@ static int tree_entry_prefix(unsigned char *buf, unsigned long size,
 	return len;
 }
 
-static int generate_tree_entry(struct packed_git *p,
+static int generate_tree_entry(struct pv4_tree_desc *desc,
 			       const unsigned char **bufp,
-			       unsigned char **dstp, unsigned long *sizep,
 			       int what)
 {
 	const unsigned char *path, *sha1;
+	char *buf = desc->buf.buf + desc->buf.len;
 	unsigned mode;
 	int len, pathlen;
 
-	path = get_pathref(p, what >> 1, &pathlen);
-	sha1 = get_sha1ref(p, bufp);
+	path = get_pathref(desc->p, what >> 1, &pathlen);
+	sha1 = get_sha1ref(desc->p, bufp);
 	if (!path || !sha1)
 		return -1;
 	mode = (path[0] << 8) | path[1];
-	len = tree_entry_prefix(*dstp, *sizep,
+	len = tree_entry_prefix(buf, strbuf_avail(&desc->buf),
 				path + 2, pathlen - 2, mode);
-	if (!len || len + 20 > *sizep)
+	if (!len || len + 20 > strbuf_avail(&desc->buf))
 		return -1;
-	hashcpy(*dstp + len, sha1);
-	len += 20;
-	*dstp += len;
-	*sizep -= len;
+	memcpy(buf + len, sha1, 20);
+	desc->buf.len += len + 20;
 	return 0;
 }
 
-static int decode_entries(struct packed_git *p, struct pack_window **w_curs,
-			  off_t obj_offset, unsigned int start, unsigned int count,
-			  unsigned char **dstp, unsigned long *sizep)
+static int decode_entries(struct pv4_tree_desc *desc, off_t obj_offset,
+			  unsigned int start, unsigned int count)
 {
+	struct packed_git *p = desc->p;
 	unsigned long avail;
 	const unsigned char *src, *scp;
 	unsigned int curpos;
@@ -490,7 +485,7 @@ static int decode_entries(struct packed_git *p, struct pack_window **w_curs,
 	} else {
 		unsigned int nb_entries;
 
-		src = use_pack(p, w_curs, obj_offset, &avail);
+		src = use_pack(p, &desc->w_curs, obj_offset, &avail);
 		scp = src;
 
 		/* we need to skip over the object header */
@@ -502,9 +497,8 @@ static int decode_entries(struct packed_git *p, struct pack_window **w_curs,
 		/* is this a canonical tree object? */
 		case OBJ_TREE:
 		case OBJ_REF_DELTA:
-			return copy_canonical_tree_entries(p, obj_offset,
-							   start, count,
-							   dstp, sizep);
+			return copy_canonical_tree_entries(desc, obj_offset,
+							   start, count);
 		/* let's still make sure this is actually a pv4 tree */
 		case OBJ_PV4_TREE:
 			break;
@@ -542,7 +536,7 @@ static int decode_entries(struct packed_git *p, struct pack_window **w_curs,
 		unsigned int what;
 
 		if (avail < 20) {
-			src = use_pack(p, w_curs, offset, &avail);
+			src = use_pack(p, &desc->w_curs, offset, &avail);
 			if (avail < 20)
 				return -1;
 		}
@@ -568,7 +562,7 @@ static int decode_entries(struct packed_git *p, struct pack_window **w_curs,
 			/*
 			 * This is an actual tree entry to recreate.
 			 */
-			if (generate_tree_entry(p, &scp, dstp, sizep, what))
+			if (generate_tree_entry(desc, &scp, what))
 				return -1;
 			count--;
 			curpos++;
@@ -638,9 +632,8 @@ static int decode_entries(struct packed_git *p, struct pack_window **w_curs,
 					start = 0;
 				}
 
-				ret = decode_entries(p, w_curs, copy_objoffset,
-						     copy_start, copy_count,
-						     dstp, sizep);
+				ret = decode_entries(desc, copy_objoffset,
+						     copy_start, copy_count);
 				if (ret)
 					return ret;
 
@@ -672,17 +665,21 @@ static int decode_entries(struct packed_git *p, struct pack_window **w_curs,
 void *pv4_get_tree(struct packed_git *p, struct pack_window **w_curs,
 		   off_t obj_offset, unsigned long size)
 {
-	unsigned char *dst, *dcp;
+	struct pv4_tree_desc desc;
 	int ret;
 
-	dst = xmallocz(size);
-	dcp = dst;
-	ret = decode_entries(p, w_curs, obj_offset, 0, 0, &dcp, &size);
-	if (ret < 0 || size != 0) {
-		free(dst);
+	memset(&desc, 0, sizeof(desc));
+	desc.p = p;
+	desc.w_curs = *w_curs;
+	strbuf_init(&desc.buf, size);
+
+	ret = decode_entries(&desc, obj_offset, 0, 0);
+	*w_curs = desc.w_curs;
+	if (ret < 0 || desc.buf.len != size) {
+		strbuf_release(&desc.buf);
 		return NULL;
 	}
-	return dst;
+	return strbuf_detach(&desc.buf, NULL);
 }
 
 unsigned long pv4_unpack_object_header_buffer(const unsigned char *base,
diff --git a/packv4-parse.h b/packv4-parse.h
index b437159..cad7a82 100644
--- a/packv4-parse.h
+++ b/packv4-parse.h
@@ -22,4 +22,13 @@ void *pv4_get_commit(struct packed_git *p, struct pack_window **w_curs,
 void *pv4_get_tree(struct packed_git *p, struct pack_window **w_curs,
 		   off_t obj_offset, unsigned long size);
 
+struct pv4_tree_desc {
+	/* v4 entry */
+	struct packed_git *p;
+	struct pack_window *w_curs;
+
+	/* full canonical tree */
+	struct strbuf buf;
+};
+
 #endif
-- 
1.8.2.83.gc99314b