Re: [PATCH 12/12] index-pack: resolve v4 one-base trees

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, 7 Sep 2013, Nguyễn Thái Ngọc Duy wrote:

> 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 <pclouds@xxxxxxxxx>
> ---
>  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

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]