diff options
author | Nicolas Pitre <nico@cam.org> | 2005-05-20 16:59:17 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-05-20 15:41:45 -0700 |
commit | d1af002dc608be3213ba18df1a99ced0ab42e6d6 (patch) | |
tree | 191c45603eb3bc4aca09df7721bef8c740786ed5 /delta.c | |
parent | [PATCH] delta read (diff) | |
download | tgif-d1af002dc608be3213ba18df1a99ced0ab42e6d6.tar.xz |
[PATCH] delta check
This adds knowledge of delta objects to fsck-cache and various object
parsing code. A new switch to git-fsck-cache is provided to display the
maximum delta depth found in a repository.
Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'delta.c')
-rw-r--r-- | delta.c | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/delta.c b/delta.c new file mode 100644 index 0000000000..05ef7fd6e4 --- /dev/null +++ b/delta.c @@ -0,0 +1,115 @@ +#include "object.h" +#include "blob.h" +#include "tree.h" +#include "commit.h" +#include "tag.h" +#include "delta.h" +#include "cache.h" +#include <string.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; +} |