Re: [PATCH 12/12] index-pack: resolve v4 one-base trees
From: Nicolas Pitre <nico@fluxnic.net>
Date: 2016-06-15 22:58:40
On Sat, 7 Sep 2013, Nguyễn Thái Ngọc Duy wrote:
quoted hunk ↗ jump to hunk
This is the most common case for delta trees. In fact it's the only kind that's produced by packv4-create. It fits well in the way index-pack resolves deltas and benefits from threading (the set of objects depending on this base does not overlap with the set of objects depending on another base) Multi-base trees will be probably processed differently. Signed-off-by: Nguyễn Thái Ngọc Duy <redacted> --- builtin/index-pack.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 178 insertions(+), 16 deletions(-)diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 1fa74f4..4a24bc3 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c@@ -12,6 +12,8 @@ #include "streaming.h" #include "thread-utils.h" #include "packv4-parse.h" +#include "varint.h" +#include "tree-walk.h" static const char index_pack_usage[] = "git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";@@ -38,8 +40,8 @@ struct base_data { struct object_entry *obj; void *data; unsigned long size; - int ref_first, ref_last; - int ofs_first, ofs_last; + int ref_first, ref_last, tree_first; + int ofs_first, ofs_last, tree_last; }; #if !defined(NO_PTHREADS) && defined(NO_THREAD_SAFE_PREAD)@@ -437,6 +439,7 @@ static struct base_data *alloc_base_data(void) memset(base, 0, sizeof(*base)); base->ref_last = -1; base->ofs_last = -1; + base->tree_last = -1; return base; }@@ -670,6 +673,8 @@ static void *unpack_tree_v4(struct object_entry *obj, } if (last_base) { + if (nr_deltas - delta_start > 1) + die("sorry guys, multi-base trees are not supported yet"); strbuf_release(&sb); return NULL; } else {@@ -794,6 +799,83 @@ static void *unpack_raw_entry(struct object_entry *obj, return data; } +static void *patch_one_base_tree(const struct object_entry *src, + const unsigned char *src_buf, + const unsigned char *delta_buf, + unsigned long delta_size, + unsigned long *dst_size) +{ + unsigned int nr; + const unsigned char *last_base = NULL; + struct strbuf sb = STRBUF_INIT; + const unsigned char *p = delta_buf; + + nr = decode_varint(&p); + while (nr && p < delta_buf + delta_size) { + unsigned int copy_start_or_path = decode_varint(&p); + if (copy_start_or_path & 1) { /* copy_start */ + struct tree_desc desc; + struct name_entry entry; + unsigned int copy_count = decode_varint(&p); + unsigned int copy_start = copy_start_or_path >> 1; + if (!src) + die("we are not supposed to copy from another tree!"); + if (copy_count & 1) { /* first delta */ + unsigned int id = decode_varint(&p); + if (!id) { + last_base = p; + p += 20; + } else + last_base = sha1_table + (id - 1) * 20; + if (hashcmp(last_base, src->idx.sha1)) + die(_("bad tree base in patch_one_base_tree")); + } else if (!last_base) + die(_("bad copy count index in patch_one_base_tree")); + copy_count >>= 1; + if (!copy_count) + die(_("bad copy count index in patch_one_base_tree")); + nr -= copy_count; + + init_tree_desc(&desc, src_buf, src->size); + while (tree_entry(&desc, &entry)) { + if (copy_start) + copy_start--; + else if (copy_count) { + strbuf_addf(&sb, "%o %s%c", entry.mode, entry.path, '\0'); + strbuf_add(&sb, entry.sha1, 20); + copy_count--; + } else + break; + } + } else { /* path */ + unsigned int path_idx = copy_start_or_path >> 1; + const unsigned char *path; + unsigned mode; + unsigned int id; + const unsigned char *entry_sha1; + + if (path_idx >= path_dict->nb_entries) + die(_("bad path index in unpack_tree_v4")); + id = decode_varint(&p); + if (!id) { + entry_sha1 = p; + p += 20; + } else + entry_sha1 = sha1_table + (id - 1) * 20;
You should verify that id doesn't overflow the sha1 table here. Similarly in other places. Nicolas