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