git-tar-tree: no more void pointer arithmetic
[git.git] / object.c
1 #include "cache.h"
2 #include "object.h"
3 #include "blob.h"
4 #include "tree.h"
5 #include "commit.h"
6 #include "tag.h"
7
8 struct object **objs;
9 static int nr_objs;
10 int obj_allocs;
11
12 const char *type_names[] = {
13         "none", "blob", "tree", "commit", "bad"
14 };
15
16 int track_object_refs = 0;
17
18 static int hashtable_index(const unsigned char *sha1)
19 {
20         unsigned int i;
21         memcpy(&i, sha1, sizeof(unsigned int));
22         return (int)(i % obj_allocs);
23 }
24
25 static int find_object(const unsigned char *sha1)
26 {
27         int i;
28
29         if (!objs)
30                 return -1;
31
32         i = hashtable_index(sha1);
33         while (objs[i]) {
34                 if (memcmp(sha1, objs[i]->sha1, 20) == 0)
35                         return i;
36                 i++;
37                 if (i == obj_allocs)
38                         i = 0;
39         }
40         return -1 - i;
41 }
42
43 struct object *lookup_object(const unsigned char *sha1)
44 {
45         int pos = find_object(sha1);
46         if (pos >= 0)
47                 return objs[pos];
48         return NULL;
49 }
50
51 void created_object(const unsigned char *sha1, struct object *obj)
52 {
53         int pos;
54
55         obj->parsed = 0;
56         memcpy(obj->sha1, sha1, 20);
57         obj->type = TYPE_NONE;
58         obj->refs = NULL;
59         obj->used = 0;
60
61         if (obj_allocs - 1 <= nr_objs * 2) {
62                 int i, count = obj_allocs;
63                 obj_allocs = (obj_allocs < 32 ? 32 : 2 * obj_allocs);
64                 objs = xrealloc(objs, obj_allocs * sizeof(struct object *));
65                 memset(objs + count, 0, (obj_allocs - count)
66                                 * sizeof(struct object *));
67                 for (i = 0; i < obj_allocs; i++)
68                         if (objs[i]) {
69                                 int j = find_object(objs[i]->sha1);
70                                 if (j != i) {
71                                         j = -1 - j;
72                                         objs[j] = objs[i];
73                                         objs[i] = NULL;
74                                 }
75                         }
76         }
77
78         pos = find_object(sha1);
79         if (pos >= 0)
80                 die("Inserting %s twice\n", sha1_to_hex(sha1));
81         pos = -pos-1;
82
83         objs[pos] = obj;
84         nr_objs++;
85 }
86
87 struct object_refs *alloc_object_refs(unsigned count)
88 {
89         struct object_refs *refs;
90         size_t size = sizeof(*refs) + count*sizeof(struct object *);
91
92         refs = xcalloc(1, size);
93         refs->count = count;
94         return refs;
95 }
96
97 static int compare_object_pointers(const void *a, const void *b)
98 {
99         const struct object * const *pa = a;
100         const struct object * const *pb = b;
101         if (*pa == *pb)
102                 return 0;
103         else if (*pa < *pb)
104                 return -1;
105         else
106                 return 1;
107 }
108
109 void set_object_refs(struct object *obj, struct object_refs *refs)
110 {
111         unsigned int i, j;
112
113         /* Do not install empty list of references */
114         if (refs->count < 1) {
115                 free(refs);
116                 return;
117         }
118
119         /* Sort the list and filter out duplicates */
120         qsort(refs->ref, refs->count, sizeof(refs->ref[0]),
121               compare_object_pointers);
122         for (i = j = 1; i < refs->count; i++) {
123                 if (refs->ref[i] != refs->ref[i - 1])
124                         refs->ref[j++] = refs->ref[i];
125         }
126         if (j < refs->count) {
127                 /* Duplicates were found - reallocate list */
128                 size_t size = sizeof(*refs) + j*sizeof(struct object *);
129                 refs->count = j;
130                 refs = xrealloc(refs, size);
131         }
132
133         for (i = 0; i < refs->count; i++)
134                 refs->ref[i]->used = 1;
135         obj->refs = refs;
136 }
137
138 void mark_reachable(struct object *obj, unsigned int mask)
139 {
140         if (!track_object_refs)
141                 die("cannot do reachability with object refs turned off");
142         /* If we've been here already, don't bother */
143         if (obj->flags & mask)
144                 return;
145         obj->flags |= mask;
146         if (obj->refs) {
147                 const struct object_refs *refs = obj->refs;
148                 unsigned i;
149                 for (i = 0; i < refs->count; i++)
150                         mark_reachable(refs->ref[i], mask);
151         }
152 }
153
154 struct object *lookup_object_type(const unsigned char *sha1, const char *type)
155 {
156         if (!type) {
157                 return lookup_unknown_object(sha1);
158         } else if (!strcmp(type, blob_type)) {
159                 return &lookup_blob(sha1)->object;
160         } else if (!strcmp(type, tree_type)) {
161                 return &lookup_tree(sha1)->object;
162         } else if (!strcmp(type, commit_type)) {
163                 return &lookup_commit(sha1)->object;
164         } else if (!strcmp(type, tag_type)) {
165                 return &lookup_tag(sha1)->object;
166         } else {
167                 error("Unknown type %s", type);
168                 return NULL;
169         }
170 }
171
172 union any_object {
173         struct object object;
174         struct commit commit;
175         struct tree tree;
176         struct blob blob;
177         struct tag tag;
178 };
179
180 struct object *lookup_unknown_object(const unsigned char *sha1)
181 {
182         struct object *obj = lookup_object(sha1);
183         if (!obj) {
184                 union any_object *ret = xcalloc(1, sizeof(*ret));
185                 created_object(sha1, &ret->object);
186                 ret->object.type = TYPE_NONE;
187                 return &ret->object;
188         }
189         return obj;
190 }
191
192 struct object *parse_object(const unsigned char *sha1)
193 {
194         unsigned long size;
195         char type[20];
196         void *buffer = read_sha1_file(sha1, type, &size);
197         if (buffer) {
198                 struct object *obj;
199                 if (check_sha1_signature(sha1, buffer, size, type) < 0)
200                         printf("sha1 mismatch %s\n", sha1_to_hex(sha1));
201                 if (!strcmp(type, blob_type)) {
202                         struct blob *blob = lookup_blob(sha1);
203                         parse_blob_buffer(blob, buffer, size);
204                         obj = &blob->object;
205                 } else if (!strcmp(type, tree_type)) {
206                         struct tree *tree = lookup_tree(sha1);
207                         obj = &tree->object;
208                         if (!tree->object.parsed) {
209                                 parse_tree_buffer(tree, buffer, size);
210                                 buffer = NULL;
211                         }
212                 } else if (!strcmp(type, commit_type)) {
213                         struct commit *commit = lookup_commit(sha1);
214                         parse_commit_buffer(commit, buffer, size);
215                         if (!commit->buffer) {
216                                 commit->buffer = buffer;
217                                 buffer = NULL;
218                         }
219                         obj = &commit->object;
220                 } else if (!strcmp(type, tag_type)) {
221                         struct tag *tag = lookup_tag(sha1);
222                         parse_tag_buffer(tag, buffer, size);
223                         obj = &tag->object;
224                 } else {
225                         obj = NULL;
226                 }
227                 free(buffer);
228                 return obj;
229         }
230         return NULL;
231 }
232
233 struct object_list *object_list_insert(struct object *item,
234                                        struct object_list **list_p)
235 {
236         struct object_list *new_list = xmalloc(sizeof(struct object_list));
237         new_list->item = item;
238         new_list->next = *list_p;
239         *list_p = new_list;
240         return new_list;
241 }
242
243 void object_list_append(struct object *item,
244                         struct object_list **list_p)
245 {
246         while (*list_p) {
247                 list_p = &((*list_p)->next);
248         }
249         *list_p = xmalloc(sizeof(struct object_list));
250         (*list_p)->next = NULL;
251         (*list_p)->item = item;
252 }
253
254 unsigned object_list_length(struct object_list *list)
255 {
256         unsigned ret = 0;
257         while (list) {
258                 list = list->next;
259                 ret++;
260         }
261         return ret;
262 }
263
264 int object_list_contains(struct object_list *list, struct object *obj)
265 {
266         while (list) {
267                 if (list->item == obj)
268                         return 1;
269                 list = list->next;
270         }
271         return 0;
272 }