Commit 3368c520dcd345cbc404afe9da68f4c8c3035981

Vicent Martí 2012-12-03T07:38:58

Merge pull request #1112 from barrbrain/odb-pack-read-header odb-pack: resurrect pack_backend__read_header

diff --git a/src/delta-apply.c b/src/delta-apply.c
index 815ca8f..85e2ef8 100644
--- a/src/delta-apply.c
+++ b/src/delta-apply.c
@@ -36,6 +36,19 @@ static int hdr_sz(
 	return 0;
 }
 
+int git__delta_read_header(
+	const unsigned char *delta,
+	size_t delta_len,
+	size_t *base_sz,
+	size_t *res_sz)
+{
+	const unsigned char *delta_end = delta + delta_len;
+	if ((hdr_sz(base_sz, &delta, delta_end) < 0) ||
+	    (hdr_sz(res_sz, &delta, delta_end) < 0))
+		return -1;
+	return 0;
+}
+
 int git__delta_apply(
 	git_rawobj *out,
 	const unsigned char *base,
diff --git a/src/delta-apply.h b/src/delta-apply.h
index 66fa76d..9aea4ac 100644
--- a/src/delta-apply.h
+++ b/src/delta-apply.h
@@ -30,4 +30,21 @@ extern int git__delta_apply(
 	const unsigned char *delta,
 	size_t delta_len);
 
+/**
+ * Read the header of a git binary delta.
+ *
+ * @param delta the delta to execute copy/insert instructions from.
+ * @param delta_len total number of bytes in the delta.
+ * @param base_sz pointer to store the base size field.
+ * @param res_sz pointer to store the result size field.
+ * @return
+ * - 0 on a successful decoding the header.
+ * - GIT_ERROR if the delta is corrupt.
+ */
+extern int git__delta_read_header(
+	const unsigned char *delta,
+	size_t delta_len,
+	size_t *base_sz,
+	size_t *res_sz);
+
 #endif
diff --git a/src/odb_pack.c b/src/odb_pack.c
index 35bf158..fc282dd 100644
--- a/src/odb_pack.c
+++ b/src/odb_pack.c
@@ -384,19 +384,18 @@ cleanup:
  *
  ***********************************************************/
 
-/*
-int pack_backend__read_header(git_rawobj *obj, git_odb_backend *backend, const git_oid *oid)
+static int pack_backend__read_header(size_t *len_p, git_otype *type_p, struct git_odb_backend *backend, const git_oid *oid)
 {
-	pack_location location;
+	struct git_pack_entry e;
+	int error;
 
-	assert(obj && backend && oid);
+	assert(len_p && type_p && backend && oid);
 
-	if (locate_packfile(&location, (struct pack_backend *)backend, oid) < 0)
-		return GIT_ENOTFOUND;
+	if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < 0)
+		return error;
 
-	return read_header_packed(obj, &location);
+	return git_packfile_resolve_header(len_p, type_p, e.p, e.offset);
 }
-*/
 
 static int pack_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
 {
@@ -579,7 +578,7 @@ int git_odb_backend_one_pack(git_odb_backend **backend_out, const char *idx)
 
 	backend->parent.read = &pack_backend__read;
 	backend->parent.read_prefix = &pack_backend__read_prefix;
-	backend->parent.read_header = NULL;
+	backend->parent.read_header = &pack_backend__read_header;
 	backend->parent.exists = &pack_backend__exists;
 	backend->parent.foreach = &pack_backend__foreach;
 	backend->parent.free = &pack_backend__free;
@@ -616,7 +615,7 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
 
 	backend->parent.read = &pack_backend__read;
 	backend->parent.read_prefix = &pack_backend__read_prefix;
-	backend->parent.read_header = NULL;
+	backend->parent.read_header = &pack_backend__read_header;
 	backend->parent.exists = &pack_backend__exists;
 	backend->parent.foreach = &pack_backend__foreach;
 	backend->parent.writepack = &pack_backend__writepack;
diff --git a/src/pack.c b/src/pack.c
index 6cb46d3..d7d3939 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -277,6 +277,56 @@ int git_packfile_unpack_header(
 	return 0;
 }
 
+int git_packfile_resolve_header(
+		size_t *size_p,
+		git_otype *type_p,
+		struct git_pack_file *p,
+		git_off_t offset)
+{
+	git_mwindow *w_curs = NULL;
+	git_off_t curpos = offset;
+	size_t size;
+	git_otype type;
+	git_off_t base_offset;
+	int error;
+
+	error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos);
+	git_mwindow_close(&w_curs);
+	if (error < 0)
+		return error;
+
+	if (type == GIT_OBJ_OFS_DELTA || type == GIT_OBJ_REF_DELTA) {
+		size_t base_size;
+		git_rawobj delta;
+		base_offset = get_delta_base(p, &w_curs, &curpos, type, offset);
+		git_mwindow_close(&w_curs);
+		error = packfile_unpack_compressed(&delta, p, &w_curs, &curpos, size, type);
+		git_mwindow_close(&w_curs);
+		if (error < 0)
+			return error;
+		error = git__delta_read_header(delta.data, delta.len, &base_size, size_p);
+		git__free(delta.data);
+		if (error < 0)
+			return error;
+	} else
+		*size_p = size;
+
+	while (type == GIT_OBJ_OFS_DELTA || type == GIT_OBJ_REF_DELTA) {
+		curpos = base_offset;
+		error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos);
+		git_mwindow_close(&w_curs);
+		if (error < 0)
+			return error;
+		if (type != GIT_OBJ_OFS_DELTA && type != GIT_OBJ_REF_DELTA)
+			break;
+		base_offset = get_delta_base(p, &w_curs, &curpos, type, base_offset);
+		git_mwindow_close(&w_curs);
+	}
+	*type_p = type;
+
+	return error;
+}
+
 static int packfile_unpack_delta(
 		git_rawobj *obj,
 		struct git_pack_file *p,
diff --git a/src/pack.h b/src/pack.h
index 9fb26b6..c1277fd 100644
--- a/src/pack.h
+++ b/src/pack.h
@@ -83,6 +83,12 @@ int git_packfile_unpack_header(
 		git_mwindow **w_curs,
 		git_off_t *curpos);
 
+int git_packfile_resolve_header(
+		size_t *size_p,
+		git_otype *type_p,
+		struct git_pack_file *p,
+		git_off_t offset);
+
 int git_packfile_unpack(git_rawobj *obj, struct git_pack_file *p, git_off_t *obj_offset);
 int packfile_unpack_compressed(
 	git_rawobj *obj,