Line | Count | Source (jump to first uncovered line) |
1 | | #define USE_THE_REPOSITORY_VARIABLE |
2 | | |
3 | | #include "git-compat-util.h" |
4 | | #include "gettext.h" |
5 | | #include "hex.h" |
6 | | #include "object.h" |
7 | | #include "replace-object.h" |
8 | | #include "object-file.h" |
9 | | #include "object-store.h" |
10 | | #include "blob.h" |
11 | | #include "statinfo.h" |
12 | | #include "tree.h" |
13 | | #include "commit.h" |
14 | | #include "tag.h" |
15 | | #include "alloc.h" |
16 | | #include "packfile.h" |
17 | | #include "commit-graph.h" |
18 | | #include "loose.h" |
19 | | |
20 | | unsigned int get_max_object_index(void) |
21 | 0 | { |
22 | 0 | return the_repository->parsed_objects->obj_hash_size; |
23 | 0 | } |
24 | | |
25 | | struct object *get_indexed_object(unsigned int idx) |
26 | 0 | { |
27 | 0 | return the_repository->parsed_objects->obj_hash[idx]; |
28 | 0 | } |
29 | | |
30 | | static const char *object_type_strings[] = { |
31 | | NULL, /* OBJ_NONE = 0 */ |
32 | | "commit", /* OBJ_COMMIT = 1 */ |
33 | | "tree", /* OBJ_TREE = 2 */ |
34 | | "blob", /* OBJ_BLOB = 3 */ |
35 | | "tag", /* OBJ_TAG = 4 */ |
36 | | }; |
37 | | |
38 | | const char *type_name(unsigned int type) |
39 | 46.8k | { |
40 | 46.8k | if (type >= ARRAY_SIZE(object_type_strings)) |
41 | 0 | return NULL; |
42 | 46.8k | return object_type_strings[type]; |
43 | 46.8k | } |
44 | | |
45 | | int type_from_string_gently(const char *str, ssize_t len, int gentle) |
46 | 64.0k | { |
47 | 64.0k | int i; |
48 | | |
49 | 64.0k | if (len < 0) |
50 | 0 | len = strlen(str); |
51 | | |
52 | 107k | for (i = 1; i < ARRAY_SIZE(object_type_strings); i++) |
53 | 107k | if (!xstrncmpz(object_type_strings[i], str, len)) |
54 | 64.0k | return i; |
55 | | |
56 | 0 | if (gentle) |
57 | 0 | return -1; |
58 | | |
59 | 0 | die(_("invalid object type \"%s\""), str); |
60 | 0 | } |
61 | | |
62 | | /* |
63 | | * Return a numerical hash value between 0 and n-1 for the object with |
64 | | * the specified sha1. n must be a power of 2. Please note that the |
65 | | * return value is *not* consistent across computer architectures. |
66 | | */ |
67 | | static unsigned int hash_obj(const struct object_id *oid, unsigned int n) |
68 | 143k | { |
69 | 143k | return oidhash(oid) & (n - 1); |
70 | 143k | } |
71 | | |
72 | | /* |
73 | | * Insert obj into the hash table hash, which has length size (which |
74 | | * must be a power of 2). On collisions, simply overflow to the next |
75 | | * empty bucket. |
76 | | */ |
77 | | static void insert_obj_hash(struct object *obj, struct object **hash, unsigned int size) |
78 | 27.8k | { |
79 | 27.8k | unsigned int j = hash_obj(&obj->oid, size); |
80 | | |
81 | 36.2k | while (hash[j]) { |
82 | 8.42k | j++; |
83 | 8.42k | if (j >= size) |
84 | 230 | j = 0; |
85 | 8.42k | } |
86 | 27.8k | hash[j] = obj; |
87 | 27.8k | } |
88 | | |
89 | | /* |
90 | | * Look up the record for the given sha1 in the hash map stored in |
91 | | * obj_hash. Return NULL if it was not found. |
92 | | */ |
93 | | struct object *lookup_object(struct repository *r, const struct object_id *oid) |
94 | 118k | { |
95 | 118k | unsigned int i, first; |
96 | 118k | struct object *obj; |
97 | | |
98 | 118k | if (!r->parsed_objects->obj_hash) |
99 | 2.92k | return NULL; |
100 | | |
101 | 115k | first = i = hash_obj(oid, r->parsed_objects->obj_hash_size); |
102 | 133k | while ((obj = r->parsed_objects->obj_hash[i]) != NULL) { |
103 | 109k | if (oideq(oid, &obj->oid)) |
104 | 91.2k | break; |
105 | 17.9k | i++; |
106 | 17.9k | if (i == r->parsed_objects->obj_hash_size) |
107 | 477 | i = 0; |
108 | 17.9k | } |
109 | 115k | if (obj && i != first) { |
110 | | /* |
111 | | * Move object to where we started to look for it so |
112 | | * that we do not need to walk the hash table the next |
113 | | * time we look for it. |
114 | | */ |
115 | 4.15k | SWAP(r->parsed_objects->obj_hash[i], |
116 | 4.15k | r->parsed_objects->obj_hash[first]); |
117 | 4.15k | } |
118 | 115k | return obj; |
119 | 118k | } |
120 | | |
121 | | /* |
122 | | * Increase the size of the hash map stored in obj_hash to the next |
123 | | * power of 2 (but at least 32). Copy the existing values to the new |
124 | | * hash map. |
125 | | */ |
126 | | static void grow_object_hash(struct repository *r) |
127 | 1.95k | { |
128 | 1.95k | int i; |
129 | | /* |
130 | | * Note that this size must always be power-of-2 to match hash_obj |
131 | | * above. |
132 | | */ |
133 | 1.95k | int new_hash_size = r->parsed_objects->obj_hash_size < 32 ? 32 : 2 * r->parsed_objects->obj_hash_size; |
134 | 1.95k | struct object **new_hash; |
135 | | |
136 | 1.95k | CALLOC_ARRAY(new_hash, new_hash_size); |
137 | 21.3k | for (i = 0; i < r->parsed_objects->obj_hash_size; i++) { |
138 | 19.3k | struct object *obj = r->parsed_objects->obj_hash[i]; |
139 | | |
140 | 19.3k | if (!obj) |
141 | 9.69k | continue; |
142 | 9.69k | insert_obj_hash(obj, new_hash, new_hash_size); |
143 | 9.69k | } |
144 | 1.95k | free(r->parsed_objects->obj_hash); |
145 | 1.95k | r->parsed_objects->obj_hash = new_hash; |
146 | 1.95k | r->parsed_objects->obj_hash_size = new_hash_size; |
147 | 1.95k | } |
148 | | |
149 | | void *create_object(struct repository *r, const struct object_id *oid, void *o) |
150 | 18.1k | { |
151 | 18.1k | struct object *obj = o; |
152 | | |
153 | 18.1k | obj->parsed = 0; |
154 | 18.1k | obj->flags = 0; |
155 | 18.1k | oidcpy(&obj->oid, oid); |
156 | | |
157 | 18.1k | if (r->parsed_objects->obj_hash_size - 1 <= r->parsed_objects->nr_objs * 2) |
158 | 1.95k | grow_object_hash(r); |
159 | | |
160 | 18.1k | insert_obj_hash(obj, r->parsed_objects->obj_hash, |
161 | 18.1k | r->parsed_objects->obj_hash_size); |
162 | 18.1k | r->parsed_objects->nr_objs++; |
163 | 18.1k | return obj; |
164 | 18.1k | } |
165 | | |
166 | | void *object_as_type(struct object *obj, enum object_type type, int quiet) |
167 | 36.2k | { |
168 | 36.2k | if (obj->type == type) |
169 | 36.2k | return obj; |
170 | 0 | else if (obj->type == OBJ_NONE) { |
171 | 0 | if (type == OBJ_COMMIT) |
172 | 0 | init_commit_node((struct commit *) obj); |
173 | 0 | else |
174 | 0 | obj->type = type; |
175 | 0 | return obj; |
176 | 0 | } |
177 | 0 | else { |
178 | 0 | if (!quiet) |
179 | 0 | error(_("object %s is a %s, not a %s"), |
180 | 0 | oid_to_hex(&obj->oid), |
181 | 0 | type_name(obj->type), type_name(type)); |
182 | 0 | return NULL; |
183 | 0 | } |
184 | 36.2k | } |
185 | | |
186 | | struct object *lookup_unknown_object(struct repository *r, const struct object_id *oid) |
187 | 0 | { |
188 | 0 | struct object *obj = lookup_object(r, oid); |
189 | 0 | if (!obj) |
190 | 0 | obj = create_object(r, oid, alloc_object_node(r)); |
191 | 0 | return obj; |
192 | 0 | } |
193 | | |
194 | | struct object *lookup_object_by_type(struct repository *r, |
195 | | const struct object_id *oid, |
196 | | enum object_type type) |
197 | 0 | { |
198 | 0 | switch (type) { |
199 | 0 | case OBJ_COMMIT: |
200 | 0 | return (struct object *)lookup_commit(r, oid); |
201 | 0 | case OBJ_TREE: |
202 | 0 | return (struct object *)lookup_tree(r, oid); |
203 | 0 | case OBJ_TAG: |
204 | 0 | return (struct object *)lookup_tag(r, oid); |
205 | 0 | case OBJ_BLOB: |
206 | 0 | return (struct object *)lookup_blob(r, oid); |
207 | 0 | default: |
208 | 0 | BUG("unknown object type %d", type); |
209 | 0 | } |
210 | 0 | } |
211 | | |
212 | | enum peel_status peel_object(struct repository *r, |
213 | | const struct object_id *name, |
214 | | struct object_id *oid) |
215 | 0 | { |
216 | 0 | struct object *o = lookup_unknown_object(r, name); |
217 | |
|
218 | 0 | if (o->type == OBJ_NONE) { |
219 | 0 | int type = oid_object_info(r, name, NULL); |
220 | 0 | if (type < 0 || !object_as_type(o, type, 0)) |
221 | 0 | return PEEL_INVALID; |
222 | 0 | } |
223 | | |
224 | 0 | if (o->type != OBJ_TAG) |
225 | 0 | return PEEL_NON_TAG; |
226 | | |
227 | 0 | o = deref_tag_noverify(r, o); |
228 | 0 | if (!o) |
229 | 0 | return PEEL_INVALID; |
230 | | |
231 | 0 | oidcpy(oid, &o->oid); |
232 | 0 | return PEEL_PEELED; |
233 | 0 | } |
234 | | |
235 | | struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten_p) |
236 | 18.1k | { |
237 | 18.1k | struct object *obj; |
238 | 18.1k | *eaten_p = 0; |
239 | | |
240 | 18.1k | obj = NULL; |
241 | 18.1k | if (type == OBJ_BLOB) { |
242 | 0 | struct blob *blob = lookup_blob(r, oid); |
243 | 0 | if (blob) { |
244 | 0 | parse_blob_buffer(blob); |
245 | 0 | obj = &blob->object; |
246 | 0 | } |
247 | 18.1k | } else if (type == OBJ_TREE) { |
248 | 9.08k | struct tree *tree = lookup_tree(r, oid); |
249 | 9.08k | if (tree) { |
250 | 9.08k | obj = &tree->object; |
251 | 9.08k | if (!tree->buffer) |
252 | 9.08k | tree->object.parsed = 0; |
253 | 9.08k | if (!tree->object.parsed) { |
254 | 9.08k | if (parse_tree_buffer(tree, buffer, size)) |
255 | 0 | return NULL; |
256 | 9.08k | *eaten_p = 1; |
257 | 9.08k | } |
258 | 9.08k | } |
259 | 9.08k | } else if (type == OBJ_COMMIT) { |
260 | 9.08k | struct commit *commit = lookup_commit(r, oid); |
261 | 9.08k | if (commit) { |
262 | 9.08k | if (parse_commit_buffer(r, commit, buffer, size, 1)) |
263 | 0 | return NULL; |
264 | 9.08k | if (save_commit_buffer && |
265 | 9.08k | !get_cached_commit_buffer(r, commit, NULL)) { |
266 | 9.08k | set_commit_buffer(r, commit, buffer, size); |
267 | 9.08k | *eaten_p = 1; |
268 | 9.08k | } |
269 | 9.08k | obj = &commit->object; |
270 | 9.08k | } |
271 | 9.08k | } else if (type == OBJ_TAG) { |
272 | 0 | struct tag *tag = lookup_tag(r, oid); |
273 | 0 | if (tag) { |
274 | 0 | if (parse_tag_buffer(r, tag, buffer, size)) |
275 | 0 | return NULL; |
276 | 0 | obj = &tag->object; |
277 | 0 | } |
278 | 0 | } else { |
279 | 0 | warning(_("object %s has unknown type id %d"), oid_to_hex(oid), type); |
280 | 0 | obj = NULL; |
281 | 0 | } |
282 | 18.1k | return obj; |
283 | 18.1k | } |
284 | | |
285 | | struct object *parse_object_or_die(const struct object_id *oid, |
286 | | const char *name) |
287 | 0 | { |
288 | 0 | struct object *o = parse_object(the_repository, oid); |
289 | 0 | if (o) |
290 | 0 | return o; |
291 | | |
292 | 0 | die(_("unable to parse object: %s"), name ? name : oid_to_hex(oid)); |
293 | 0 | } |
294 | | |
295 | | struct object *parse_object_with_flags(struct repository *r, |
296 | | const struct object_id *oid, |
297 | | enum parse_object_flags flags) |
298 | 74.5k | { |
299 | 74.5k | int skip_hash = !!(flags & PARSE_OBJECT_SKIP_HASH_CHECK); |
300 | 74.5k | int discard_tree = !!(flags & PARSE_OBJECT_DISCARD_TREE); |
301 | 74.5k | unsigned long size; |
302 | 74.5k | enum object_type type; |
303 | 74.5k | int eaten; |
304 | 74.5k | const struct object_id *repl = lookup_replace_object(r, oid); |
305 | 74.5k | void *buffer; |
306 | 74.5k | struct object *obj; |
307 | | |
308 | 74.5k | obj = lookup_object(r, oid); |
309 | 74.5k | if (obj && obj->parsed) |
310 | 56.4k | return obj; |
311 | | |
312 | 18.1k | if (skip_hash) { |
313 | 0 | struct commit *commit = lookup_commit_in_graph(r, repl); |
314 | 0 | if (commit) |
315 | 0 | return &commit->object; |
316 | 0 | } |
317 | | |
318 | 18.1k | if ((!obj || obj->type == OBJ_BLOB) && |
319 | 18.1k | oid_object_info(r, oid, NULL) == OBJ_BLOB) { |
320 | 0 | if (!skip_hash && stream_object_signature(r, repl) < 0) { |
321 | 0 | error(_("hash mismatch %s"), oid_to_hex(oid)); |
322 | 0 | return NULL; |
323 | 0 | } |
324 | 0 | parse_blob_buffer(lookup_blob(r, oid)); |
325 | 0 | return lookup_object(r, oid); |
326 | 0 | } |
327 | | |
328 | | /* |
329 | | * If the caller does not care about the tree buffer and does not |
330 | | * care about checking the hash, we can simply verify that we |
331 | | * have the on-disk object with the correct type. |
332 | | */ |
333 | 18.1k | if (skip_hash && discard_tree && |
334 | 18.1k | (!obj || obj->type == OBJ_TREE) && |
335 | 18.1k | oid_object_info(r, oid, NULL) == OBJ_TREE) { |
336 | 0 | return &lookup_tree(r, oid)->object; |
337 | 0 | } |
338 | | |
339 | 18.1k | buffer = repo_read_object_file(r, oid, &type, &size); |
340 | 18.1k | if (buffer) { |
341 | 18.1k | if (!skip_hash && |
342 | 18.1k | check_object_signature(r, repl, buffer, size, type) < 0) { |
343 | 0 | free(buffer); |
344 | 0 | error(_("hash mismatch %s"), oid_to_hex(repl)); |
345 | 0 | return NULL; |
346 | 0 | } |
347 | | |
348 | 18.1k | obj = parse_object_buffer(r, oid, type, size, |
349 | 18.1k | buffer, &eaten); |
350 | 18.1k | if (!eaten) |
351 | 0 | free(buffer); |
352 | 18.1k | if (discard_tree && type == OBJ_TREE) |
353 | 0 | free_tree_buffer((struct tree *)obj); |
354 | 18.1k | return obj; |
355 | 18.1k | } |
356 | 0 | return NULL; |
357 | 18.1k | } |
358 | | |
359 | | struct object *parse_object(struct repository *r, const struct object_id *oid) |
360 | 50.2k | { |
361 | 50.2k | return parse_object_with_flags(r, oid, 0); |
362 | 50.2k | } |
363 | | |
364 | | struct object_list *object_list_insert(struct object *item, |
365 | | struct object_list **list_p) |
366 | 0 | { |
367 | 0 | struct object_list *new_list = xmalloc(sizeof(struct object_list)); |
368 | 0 | new_list->item = item; |
369 | 0 | new_list->next = *list_p; |
370 | 0 | *list_p = new_list; |
371 | 0 | return new_list; |
372 | 0 | } |
373 | | |
374 | | int object_list_contains(struct object_list *list, struct object *obj) |
375 | 0 | { |
376 | 0 | while (list) { |
377 | 0 | if (list->item == obj) |
378 | 0 | return 1; |
379 | 0 | list = list->next; |
380 | 0 | } |
381 | 0 | return 0; |
382 | 0 | } |
383 | | |
384 | | void object_list_free(struct object_list **list) |
385 | 0 | { |
386 | 0 | while (*list) { |
387 | 0 | struct object_list *p = *list; |
388 | 0 | *list = p->next; |
389 | 0 | free(p); |
390 | 0 | } |
391 | 0 | } |
392 | | |
393 | | /* |
394 | | * A zero-length string to which object_array_entry::name can be |
395 | | * initialized without requiring a malloc/free. |
396 | | */ |
397 | | static char object_array_slopbuf[1]; |
398 | | |
399 | | void object_array_init(struct object_array *array) |
400 | 0 | { |
401 | 0 | struct object_array blank = OBJECT_ARRAY_INIT; |
402 | 0 | memcpy(array, &blank, sizeof(*array)); |
403 | 0 | } |
404 | | |
405 | | void add_object_array_with_path(struct object *obj, const char *name, |
406 | | struct object_array *array, |
407 | | unsigned mode, const char *path) |
408 | 35.4k | { |
409 | 35.4k | unsigned nr = array->nr; |
410 | 35.4k | unsigned alloc = array->alloc; |
411 | 35.4k | struct object_array_entry *objects = array->objects; |
412 | 35.4k | struct object_array_entry *entry; |
413 | | |
414 | 35.4k | if (nr >= alloc) { |
415 | 31.2k | alloc = (alloc + 32) * 2; |
416 | 31.2k | REALLOC_ARRAY(objects, alloc); |
417 | 31.2k | array->alloc = alloc; |
418 | 31.2k | array->objects = objects; |
419 | 31.2k | } |
420 | 35.4k | entry = &objects[nr]; |
421 | 35.4k | entry->item = obj; |
422 | 35.4k | if (!name) |
423 | 0 | entry->name = NULL; |
424 | 35.4k | else if (!*name) |
425 | | /* Use our own empty string instead of allocating one: */ |
426 | 0 | entry->name = object_array_slopbuf; |
427 | 35.4k | else |
428 | 35.4k | entry->name = xstrdup(name); |
429 | 35.4k | entry->mode = mode; |
430 | 35.4k | if (path) |
431 | 0 | entry->path = xstrdup(path); |
432 | 35.4k | else |
433 | 35.4k | entry->path = NULL; |
434 | 35.4k | array->nr = ++nr; |
435 | 35.4k | } |
436 | | |
437 | | void add_object_array(struct object *obj, const char *name, struct object_array *array) |
438 | 9.67k | { |
439 | 9.67k | add_object_array_with_path(obj, name, array, S_IFINVALID, NULL); |
440 | 9.67k | } |
441 | | |
442 | | /* |
443 | | * Free all memory associated with an entry; the result is |
444 | | * in an unspecified state and should not be examined. |
445 | | */ |
446 | | static void object_array_release_entry(struct object_array_entry *ent) |
447 | 31.2k | { |
448 | 31.2k | if (ent->name != object_array_slopbuf) |
449 | 31.2k | free(ent->name); |
450 | 31.2k | free(ent->path); |
451 | 31.2k | } |
452 | | |
453 | | struct object *object_array_pop(struct object_array *array) |
454 | 0 | { |
455 | 0 | struct object *ret; |
456 | |
|
457 | 0 | if (!array->nr) |
458 | 0 | return NULL; |
459 | | |
460 | 0 | ret = array->objects[array->nr - 1].item; |
461 | 0 | object_array_release_entry(&array->objects[array->nr - 1]); |
462 | 0 | array->nr--; |
463 | 0 | return ret; |
464 | 0 | } |
465 | | |
466 | | void object_array_filter(struct object_array *array, |
467 | | object_array_each_func_t want, void *cb_data) |
468 | 0 | { |
469 | 0 | unsigned nr = array->nr, src, dst; |
470 | 0 | struct object_array_entry *objects = array->objects; |
471 | |
|
472 | 0 | for (src = dst = 0; src < nr; src++) { |
473 | 0 | if (want(&objects[src], cb_data)) { |
474 | 0 | if (src != dst) |
475 | 0 | objects[dst] = objects[src]; |
476 | 0 | dst++; |
477 | 0 | } else { |
478 | 0 | object_array_release_entry(&objects[src]); |
479 | 0 | } |
480 | 0 | } |
481 | 0 | array->nr = dst; |
482 | 0 | } |
483 | | |
484 | | void object_array_clear(struct object_array *array) |
485 | 106k | { |
486 | 106k | int i; |
487 | 137k | for (i = 0; i < array->nr; i++) |
488 | 31.2k | object_array_release_entry(&array->objects[i]); |
489 | 106k | FREE_AND_NULL(array->objects); |
490 | 106k | array->nr = array->alloc = 0; |
491 | 106k | } |
492 | | |
493 | | /* |
494 | | * Return true if array already contains an entry. |
495 | | */ |
496 | | static int contains_object(struct object_array *array, |
497 | | const struct object *item, const char *name) |
498 | 0 | { |
499 | 0 | unsigned nr = array->nr, i; |
500 | 0 | struct object_array_entry *object = array->objects; |
501 | |
|
502 | 0 | for (i = 0; i < nr; i++, object++) |
503 | 0 | if (item == object->item && !strcmp(object->name, name)) |
504 | 0 | return 1; |
505 | 0 | return 0; |
506 | 0 | } |
507 | | |
508 | | void object_array_remove_duplicates(struct object_array *array) |
509 | 0 | { |
510 | 0 | unsigned nr = array->nr, src; |
511 | 0 | struct object_array_entry *objects = array->objects; |
512 | |
|
513 | 0 | array->nr = 0; |
514 | 0 | for (src = 0; src < nr; src++) { |
515 | 0 | if (!contains_object(array, objects[src].item, |
516 | 0 | objects[src].name)) { |
517 | 0 | if (src != array->nr) |
518 | 0 | objects[array->nr] = objects[src]; |
519 | 0 | array->nr++; |
520 | 0 | } else { |
521 | 0 | object_array_release_entry(&objects[src]); |
522 | 0 | } |
523 | 0 | } |
524 | 0 | } |
525 | | |
526 | | void clear_object_flags(unsigned flags) |
527 | 0 | { |
528 | 0 | int i; |
529 | |
|
530 | 0 | for (i=0; i < the_repository->parsed_objects->obj_hash_size; i++) { |
531 | 0 | struct object *obj = the_repository->parsed_objects->obj_hash[i]; |
532 | 0 | if (obj) |
533 | 0 | obj->flags &= ~flags; |
534 | 0 | } |
535 | 0 | } |
536 | | |
537 | | void repo_clear_commit_marks(struct repository *r, unsigned int flags) |
538 | 0 | { |
539 | 0 | int i; |
540 | |
|
541 | 0 | for (i = 0; i < r->parsed_objects->obj_hash_size; i++) { |
542 | 0 | struct object *obj = r->parsed_objects->obj_hash[i]; |
543 | 0 | if (obj && obj->type == OBJ_COMMIT) |
544 | 0 | obj->flags &= ~flags; |
545 | 0 | } |
546 | 0 | } |
547 | | |
548 | | struct parsed_object_pool *parsed_object_pool_new(void) |
549 | 1.46k | { |
550 | 1.46k | struct parsed_object_pool *o = xmalloc(sizeof(*o)); |
551 | 1.46k | memset(o, 0, sizeof(*o)); |
552 | | |
553 | 1.46k | o->blob_state = allocate_alloc_state(); |
554 | 1.46k | o->tree_state = allocate_alloc_state(); |
555 | 1.46k | o->commit_state = allocate_alloc_state(); |
556 | 1.46k | o->tag_state = allocate_alloc_state(); |
557 | 1.46k | o->object_state = allocate_alloc_state(); |
558 | | |
559 | 1.46k | o->is_shallow = -1; |
560 | 1.46k | CALLOC_ARRAY(o->shallow_stat, 1); |
561 | | |
562 | 1.46k | o->buffer_slab = allocate_commit_buffer_slab(); |
563 | | |
564 | 1.46k | return o; |
565 | 1.46k | } |
566 | | |
567 | | struct raw_object_store *raw_object_store_new(void) |
568 | 1.46k | { |
569 | 1.46k | struct raw_object_store *o = xmalloc(sizeof(*o)); |
570 | | |
571 | 1.46k | memset(o, 0, sizeof(*o)); |
572 | 1.46k | INIT_LIST_HEAD(&o->packed_git_mru); |
573 | 1.46k | hashmap_init(&o->pack_map, pack_map_entry_cmp, NULL, 0); |
574 | 1.46k | pthread_mutex_init(&o->replace_mutex, NULL); |
575 | 1.46k | return o; |
576 | 1.46k | } |
577 | | |
578 | | void free_object_directory(struct object_directory *odb) |
579 | 1.46k | { |
580 | 1.46k | free(odb->path); |
581 | 1.46k | odb_clear_loose_cache(odb); |
582 | 1.46k | loose_object_map_clear(&odb->loose_map); |
583 | 1.46k | free(odb); |
584 | 1.46k | } |
585 | | |
586 | | static void free_object_directories(struct raw_object_store *o) |
587 | 1.46k | { |
588 | 2.92k | while (o->odb) { |
589 | 1.46k | struct object_directory *next; |
590 | | |
591 | 1.46k | next = o->odb->next; |
592 | 1.46k | free_object_directory(o->odb); |
593 | 1.46k | o->odb = next; |
594 | 1.46k | } |
595 | 1.46k | kh_destroy_odb_path_map(o->odb_by_path); |
596 | 1.46k | o->odb_by_path = NULL; |
597 | 1.46k | } |
598 | | |
599 | | void raw_object_store_clear(struct raw_object_store *o) |
600 | 1.46k | { |
601 | 1.46k | FREE_AND_NULL(o->alternate_db); |
602 | | |
603 | 1.46k | oidmap_free(o->replace_map, 1); |
604 | 1.46k | FREE_AND_NULL(o->replace_map); |
605 | 1.46k | pthread_mutex_destroy(&o->replace_mutex); |
606 | | |
607 | 1.46k | free_commit_graph(o->commit_graph); |
608 | 1.46k | o->commit_graph = NULL; |
609 | 1.46k | o->commit_graph_attempted = 0; |
610 | | |
611 | 1.46k | free_object_directories(o); |
612 | 1.46k | o->odb_tail = NULL; |
613 | 1.46k | o->loaded_alternates = 0; |
614 | | |
615 | 1.46k | INIT_LIST_HEAD(&o->packed_git_mru); |
616 | 1.46k | close_object_store(o); |
617 | | |
618 | | /* |
619 | | * `close_object_store()` only closes the packfiles, but doesn't free |
620 | | * them. We thus have to do this manually. |
621 | | */ |
622 | 1.46k | for (struct packed_git *p = o->packed_git, *next; p; p = next) { |
623 | 0 | next = p->next; |
624 | 0 | free(p); |
625 | 0 | } |
626 | 1.46k | o->packed_git = NULL; |
627 | | |
628 | 1.46k | hashmap_clear(&o->pack_map); |
629 | 1.46k | } |
630 | | |
631 | | void parsed_object_pool_clear(struct parsed_object_pool *o) |
632 | 1.46k | { |
633 | | /* |
634 | | * As objects are allocated in slabs (see alloc.c), we do |
635 | | * not need to free each object, but each slab instead. |
636 | | * |
637 | | * Before doing so, we need to free any additional memory |
638 | | * the objects may hold. |
639 | | */ |
640 | 1.46k | unsigned i; |
641 | | |
642 | 67.7k | for (i = 0; i < o->obj_hash_size; i++) { |
643 | 66.2k | struct object *obj = o->obj_hash[i]; |
644 | | |
645 | 66.2k | if (!obj) |
646 | 48.0k | continue; |
647 | | |
648 | 18.1k | if (obj->type == OBJ_TREE) |
649 | 9.08k | free_tree_buffer((struct tree*)obj); |
650 | 9.08k | else if (obj->type == OBJ_COMMIT) |
651 | 9.08k | release_commit_memory(o, (struct commit*)obj); |
652 | 0 | else if (obj->type == OBJ_TAG) |
653 | 0 | release_tag_memory((struct tag*)obj); |
654 | 18.1k | } |
655 | | |
656 | 1.46k | FREE_AND_NULL(o->obj_hash); |
657 | 1.46k | o->obj_hash_size = 0; |
658 | | |
659 | 1.46k | free_commit_buffer_slab(o->buffer_slab); |
660 | 1.46k | o->buffer_slab = NULL; |
661 | | |
662 | 1.46k | clear_alloc_state(o->blob_state); |
663 | 1.46k | clear_alloc_state(o->tree_state); |
664 | 1.46k | clear_alloc_state(o->commit_state); |
665 | 1.46k | clear_alloc_state(o->tag_state); |
666 | 1.46k | clear_alloc_state(o->object_state); |
667 | 1.46k | stat_validity_clear(o->shallow_stat); |
668 | 1.46k | FREE_AND_NULL(o->blob_state); |
669 | 1.46k | FREE_AND_NULL(o->tree_state); |
670 | 1.46k | FREE_AND_NULL(o->commit_state); |
671 | 1.46k | FREE_AND_NULL(o->tag_state); |
672 | 1.46k | FREE_AND_NULL(o->object_state); |
673 | 1.46k | FREE_AND_NULL(o->shallow_stat); |
674 | 1.46k | } |