You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
2.9 KiB
114 lines
2.9 KiB
#include "object.h" |
|
#include "blob.h" |
|
#include "tree.h" |
|
#include "commit.h" |
|
#include "tag.h" |
|
#include "delta.h" |
|
#include "cache.h" |
|
|
|
/* the delta object definition (it can alias any other object) */ |
|
struct delta { |
|
union { |
|
struct object object; |
|
struct blob blob; |
|
struct tree tree; |
|
struct commit commit; |
|
struct tag tag; |
|
} u; |
|
}; |
|
|
|
struct delta *lookup_delta(unsigned char *sha1) |
|
{ |
|
struct object *obj = lookup_object(sha1); |
|
if (!obj) { |
|
struct delta *ret = xmalloc(sizeof(struct delta)); |
|
memset(ret, 0, sizeof(struct delta)); |
|
created_object(sha1, &ret->u.object); |
|
return ret; |
|
} |
|
return (struct delta *) obj; |
|
} |
|
|
|
int parse_delta_buffer(struct delta *item, void *buffer, unsigned long size) |
|
{ |
|
struct object *reference; |
|
struct object_list *p; |
|
|
|
if (item->u.object.delta) |
|
return 0; |
|
item->u.object.delta = 1; |
|
if (size <= 20) |
|
return -1; |
|
reference = lookup_object(buffer); |
|
if (!reference) { |
|
struct delta *ref = xmalloc(sizeof(struct delta)); |
|
memset(ref, 0, sizeof(struct delta)); |
|
created_object(buffer, &ref->u.object); |
|
reference = &ref->u.object; |
|
} |
|
|
|
p = xmalloc(sizeof(*p)); |
|
p->item = &item->u.object; |
|
p->next = reference->attached_deltas; |
|
reference->attached_deltas = p; |
|
return 0; |
|
} |
|
|
|
int process_deltas(void *src, unsigned long src_size, const char *src_type, |
|
struct object_list *delta_list) |
|
{ |
|
int deepest = 0; |
|
do { |
|
struct object *obj = delta_list->item; |
|
static char type[10]; |
|
void *map, *delta, *buf; |
|
unsigned long map_size, delta_size, buf_size; |
|
map = map_sha1_file(obj->sha1, &map_size); |
|
if (!map) |
|
continue; |
|
delta = unpack_sha1_file(map, map_size, type, &delta_size); |
|
munmap(map, map_size); |
|
if (!delta) |
|
continue; |
|
if (strcmp(type, "delta") || delta_size <= 20) { |
|
free(delta); |
|
continue; |
|
} |
|
buf = patch_delta(src, src_size, |
|
delta+20, delta_size-20, |
|
&buf_size); |
|
free(delta); |
|
if (!buf) |
|
continue; |
|
if (check_sha1_signature(obj->sha1, buf, buf_size, src_type) < 0) |
|
printf("sha1 mismatch for delta %s\n", sha1_to_hex(obj->sha1)); |
|
if (obj->type && obj->type != src_type) { |
|
error("got %s when expecting %s for delta %s", |
|
src_type, obj->type, sha1_to_hex(obj->sha1)); |
|
free(buf); |
|
continue; |
|
} |
|
obj->type = src_type; |
|
if (src_type == blob_type) { |
|
parse_blob_buffer((struct blob *)obj, buf, buf_size); |
|
} else if (src_type == tree_type) { |
|
parse_tree_buffer((struct tree *)obj, buf, buf_size); |
|
} else if (src_type == commit_type) { |
|
parse_commit_buffer((struct commit *)obj, buf, buf_size); |
|
} else if (src_type == tag_type) { |
|
parse_tag_buffer((struct tag *)obj, buf, buf_size); |
|
} else { |
|
error("unknown object type %s", src_type); |
|
free(buf); |
|
continue; |
|
} |
|
if (obj->attached_deltas) { |
|
int depth = process_deltas(buf, buf_size, src_type, |
|
obj->attached_deltas); |
|
if (deepest < depth) |
|
deepest = depth; |
|
} |
|
free(buf); |
|
} while ((delta_list = delta_list->next)); |
|
return deepest + 1; |
|
}
|
|
|