delta.con commit [PATCH] Finish initial cut of git-pack-object/git-unpack-object pair. (8ee378a)
   1#include "object.h"
   2#include "blob.h"
   3#include "tree.h"
   4#include "commit.h"
   5#include "tag.h"
   6#include "delta.h"
   7#include "cache.h"
   8
   9/* the delta object definition (it can alias any other object) */
  10struct delta {
  11        union {
  12                struct object object;
  13                struct blob blob;
  14                struct tree tree;
  15                struct commit commit;
  16                struct tag tag;
  17        } u;
  18};
  19
  20struct delta *lookup_delta(const unsigned char *sha1)
  21{
  22        struct object *obj = lookup_object(sha1);
  23        if (!obj) {
  24                struct delta *ret = xmalloc(sizeof(struct delta));
  25                memset(ret, 0, sizeof(struct delta));
  26                created_object(sha1, &ret->u.object);
  27                return ret;
  28        }
  29        return (struct delta *) obj;
  30}
  31
  32int parse_delta_buffer(struct delta *item, void *buffer, unsigned long size)
  33{
  34        struct object *reference;
  35        struct object_list *p;
  36
  37        if (item->u.object.delta)
  38                return 0;
  39        item->u.object.delta = 1;
  40        if (size <= 20)
  41                return -1;
  42        reference = lookup_object(buffer);
  43        if (!reference) {
  44                struct delta *ref = xmalloc(sizeof(struct delta));
  45                memset(ref, 0, sizeof(struct delta));
  46                created_object(buffer, &ref->u.object);
  47                reference = &ref->u.object;
  48        }
  49
  50        p = xmalloc(sizeof(*p));
  51        p->item = &item->u.object;
  52        p->next = reference->attached_deltas;
  53        reference->attached_deltas = p;
  54        return 0;
  55}
  56
  57int process_deltas(void *src, unsigned long src_size, const char *src_type,
  58                   struct object_list *delta_list)
  59{
  60        int deepest = 0;
  61        do {
  62                struct object *obj = delta_list->item;
  63                static char type[10];
  64                void *map, *delta, *buf;
  65                unsigned long map_size, delta_size, buf_size;
  66                map = map_sha1_file(obj->sha1, &map_size);
  67                if (!map)
  68                        continue;
  69                delta = unpack_sha1_file(map, map_size, type, &delta_size);
  70                munmap(map, map_size);
  71                if (!delta)
  72                        continue;
  73                if (strcmp(type, "delta") || delta_size <= 20) {
  74                        free(delta);
  75                        continue;
  76                }
  77                buf = patch_delta(src, src_size,
  78                                  delta+20, delta_size-20,
  79                                  &buf_size);
  80                free(delta);
  81                if (!buf)
  82                        continue;
  83                if (check_sha1_signature(obj->sha1, buf, buf_size, src_type) < 0)
  84                        printf("sha1 mismatch for delta %s\n", sha1_to_hex(obj->sha1));
  85                if (obj->type && obj->type != src_type) {
  86                        error("got %s when expecting %s for delta %s",
  87                              src_type, obj->type, sha1_to_hex(obj->sha1));
  88                        free(buf);
  89                        continue;
  90                }
  91                obj->type = src_type;
  92                if (src_type == blob_type) {
  93                        parse_blob_buffer((struct blob *)obj, buf, buf_size);
  94                } else if (src_type == tree_type) {
  95                        parse_tree_buffer((struct tree *)obj, buf, buf_size);
  96                } else if (src_type == commit_type) {
  97                        parse_commit_buffer((struct commit *)obj, buf, buf_size);
  98                } else if (src_type == tag_type) {
  99                        parse_tag_buffer((struct tag *)obj, buf, buf_size);
 100                } else {
 101                        error("unknown object type %s", src_type);
 102                        free(buf);
 103                        continue;
 104                }
 105                if (obj->attached_deltas) {
 106                        int depth = process_deltas(buf, buf_size, src_type,
 107                                                   obj->attached_deltas);
 108                        if (deepest < depth)
 109                                deepest = depth;
 110                }
 111                free(buf);
 112        } while ((delta_list = delta_list->next));
 113        return deepest + 1;
 114}