File Coverage

deps/libgit2/src/libgit2/indexer.c
Criterion Covered Total %
statement 367 661 55.5
branch 167 382 43.7
condition n/a
subroutine n/a
pod n/a
total 534 1043 51.2


line stmt bran cond sub pod time code
1             /*
2             * Copyright (C) the libgit2 contributors. All rights reserved.
3             *
4             * This file is part of libgit2, distributed under the GNU GPL v2 with
5             * a Linking Exception. For full terms see the included COPYING file.
6             */
7              
8             #include "indexer.h"
9              
10             #include "git2/indexer.h"
11             #include "git2/object.h"
12              
13             #include "commit.h"
14             #include "tree.h"
15             #include "tag.h"
16             #include "pack.h"
17             #include "mwindow.h"
18             #include "posix.h"
19             #include "pack.h"
20             #include "filebuf.h"
21             #include "oid.h"
22             #include "oidarray.h"
23             #include "oidmap.h"
24             #include "zstream.h"
25             #include "object.h"
26              
27             size_t git_indexer__max_objects = UINT32_MAX;
28              
29             #define UINT31_MAX (0x7FFFFFFF)
30              
31             struct entry {
32             git_oid oid;
33             uint32_t crc;
34             uint32_t offset;
35             uint64_t offset_long;
36             };
37              
38             struct git_indexer {
39             unsigned int parsed_header :1,
40             pack_committed :1,
41             have_stream :1,
42             have_delta :1,
43             do_fsync :1,
44             do_verify :1;
45             struct git_pack_header hdr;
46             struct git_pack_file *pack;
47             unsigned int mode;
48             off64_t off;
49             off64_t entry_start;
50             git_object_t entry_type;
51             git_str entry_data;
52             git_packfile_stream stream;
53             size_t nr_objects;
54             git_vector objects;
55             git_vector deltas;
56             unsigned int fanout[256];
57             git_hash_ctx hash_ctx;
58             unsigned char checksum[GIT_HASH_SHA1_SIZE];
59             char name[(GIT_HASH_SHA1_SIZE * 2) + 1];
60             git_indexer_progress_cb progress_cb;
61             void *progress_payload;
62             char objbuf[8*1024];
63              
64             /* OIDs referenced from pack objects. Used for verification. */
65             git_oidmap *expected_oids;
66              
67             /* Needed to look up objects which we want to inject to fix a thin pack */
68             git_odb *odb;
69              
70             /* Fields for calculating the packfile trailer (hash of everything before it) */
71             char inbuf[GIT_OID_RAWSZ];
72             size_t inbuf_len;
73             git_hash_ctx trailer;
74             };
75              
76             struct delta_info {
77             off64_t delta_off;
78             };
79              
80             #ifndef GIT_DEPRECATE_HARD
81 5           const git_oid *git_indexer_hash(const git_indexer *idx)
82             {
83 5           return (git_oid *)idx->checksum;
84             }
85             #endif
86              
87 4           const char *git_indexer_name(const git_indexer *idx)
88             {
89 4           return idx->name;
90             }
91              
92 5           static int parse_header(struct git_pack_header *hdr, struct git_pack_file *pack)
93             {
94             int error;
95             git_map map;
96              
97 5 50         if ((error = p_mmap(&map, sizeof(*hdr), GIT_PROT_READ, GIT_MAP_SHARED, pack->mwf.fd, 0)) < 0)
98 0           return error;
99              
100 5           memcpy(hdr, map.data, sizeof(*hdr));
101 5           p_munmap(&map);
102              
103             /* Verify we recognize this pack file format. */
104 5 50         if (hdr->hdr_signature != ntohl(PACK_SIGNATURE)) {
105 0           git_error_set(GIT_ERROR_INDEXER, "wrong pack signature");
106 0           return -1;
107             }
108              
109 5 50         if (!pack_version_ok(hdr->hdr_version)) {
110 0           git_error_set(GIT_ERROR_INDEXER, "wrong pack version");
111 0           return -1;
112             }
113              
114 5           return 0;
115             }
116              
117 142           static int objects_cmp(const void *a, const void *b)
118             {
119 142           const struct entry *entrya = a;
120 142           const struct entry *entryb = b;
121              
122 142           return git_oid__cmp(&entrya->oid, &entryb->oid);
123             }
124              
125 0           int git_indexer_options_init(git_indexer_options *opts, unsigned int version)
126             {
127 0 0         GIT_INIT_STRUCTURE_FROM_TEMPLATE(
128             opts, version, git_indexer_options, GIT_INDEXER_OPTIONS_INIT);
129 0           return 0;
130             }
131              
132             #ifndef GIT_DEPRECATE_HARD
133 0           int git_indexer_init_options(git_indexer_options *opts, unsigned int version)
134             {
135 0           return git_indexer_options_init(opts, version);
136             }
137             #endif
138              
139 5           int git_indexer_new(
140             git_indexer **out,
141             const char *prefix,
142             unsigned int mode,
143             git_odb *odb,
144             git_indexer_options *in_opts)
145             {
146 5           git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT;
147             git_indexer *idx;
148 5           git_str path = GIT_STR_INIT, tmp_path = GIT_STR_INIT;
149             static const char suff[] = "/pack";
150 5           int error, fd = -1;
151              
152 5 100         if (in_opts)
153 4           memcpy(&opts, in_opts, sizeof(opts));
154              
155 5           idx = git__calloc(1, sizeof(git_indexer));
156 5 50         GIT_ERROR_CHECK_ALLOC(idx);
157 5           idx->odb = odb;
158 5           idx->progress_cb = opts.progress_cb;
159 5           idx->progress_payload = opts.progress_cb_payload;
160 5 50         idx->mode = mode ? mode : GIT_PACK_FILE_MODE;
161 5           git_str_init(&idx->entry_data, 0);
162              
163 5 50         if ((error = git_hash_ctx_init(&idx->hash_ctx, GIT_HASH_ALGORITHM_SHA1)) < 0 ||
    50          
164 5 50         (error = git_hash_ctx_init(&idx->trailer, GIT_HASH_ALGORITHM_SHA1)) < 0 ||
165 5           (error = git_oidmap_new(&idx->expected_oids)) < 0)
166             goto cleanup;
167              
168 5           idx->do_verify = opts.verify;
169              
170 5 50         if (git_repository__fsync_gitdir)
171 0           idx->do_fsync = 1;
172              
173 5           error = git_str_joinpath(&path, prefix, suff);
174 5 50         if (error < 0)
175 0           goto cleanup;
176              
177 5           fd = git_futils_mktmp(&tmp_path, git_str_cstr(&path), idx->mode);
178 5           git_str_dispose(&path);
179 5 50         if (fd < 0)
180 0           goto cleanup;
181              
182 5           error = git_packfile_alloc(&idx->pack, git_str_cstr(&tmp_path));
183 5           git_str_dispose(&tmp_path);
184              
185 5 50         if (error < 0)
186 0           goto cleanup;
187              
188 5           idx->pack->mwf.fd = fd;
189 5 50         if ((error = git_mwindow_file_register(&idx->pack->mwf)) < 0)
190 0           goto cleanup;
191              
192 5           *out = idx;
193 5           return 0;
194              
195             cleanup:
196 0 0         if (fd != -1)
197 0           p_close(fd);
198              
199 0 0         if (git_str_len(&tmp_path) > 0)
200 0           p_unlink(git_str_cstr(&tmp_path));
201              
202 0 0         if (idx->pack != NULL)
203 0           p_unlink(idx->pack->pack_name);
204              
205 0           git_str_dispose(&path);
206 0           git_str_dispose(&tmp_path);
207 0           git__free(idx);
208 5           return -1;
209             }
210              
211 0           void git_indexer__set_fsync(git_indexer *idx, int do_fsync)
212             {
213 0           idx->do_fsync = !!do_fsync;
214 0           }
215              
216             /* Try to store the delta so we can try to resolve it later */
217 2           static int store_delta(git_indexer *idx)
218             {
219             struct delta_info *delta;
220              
221 2           delta = git__calloc(1, sizeof(struct delta_info));
222 2 50         GIT_ERROR_CHECK_ALLOC(delta);
223 2           delta->delta_off = idx->entry_start;
224              
225 2 50         if (git_vector_insert(&idx->deltas, delta) < 0)
226 0           return -1;
227              
228 2           return 0;
229             }
230              
231 43           static int hash_header(git_hash_ctx *ctx, off64_t len, git_object_t type)
232             {
233             char buffer[64];
234             size_t hdrlen;
235             int error;
236              
237 43 50         if ((error = git_odb__format_object_header(&hdrlen,
238             buffer, sizeof(buffer), (size_t)len, type)) < 0)
239 0           return error;
240              
241 43           return git_hash_update(ctx, buffer, hdrlen);
242             }
243              
244 43           static int hash_object_stream(git_indexer*idx, git_packfile_stream *stream)
245             {
246             ssize_t read;
247              
248 43 50         GIT_ASSERT_ARG(idx);
249 43 50         GIT_ASSERT_ARG(stream);
250              
251             do {
252 86 50         if ((read = git_packfile_stream_read(stream, idx->objbuf, sizeof(idx->objbuf))) < 0)
253 0           break;
254              
255 86 50         if (idx->do_verify)
256 0           git_str_put(&idx->entry_data, idx->objbuf, read);
257              
258 86           git_hash_update(&idx->hash_ctx, idx->objbuf, read);
259 86 100         } while (read > 0);
260              
261 43 50         if (read < 0)
262 0           return (int)read;
263              
264 43           return 0;
265             }
266              
267             /* In order to create the packfile stream, we need to skip over the delta base description */
268 2           static int advance_delta_offset(git_indexer *idx, git_object_t type)
269             {
270 2           git_mwindow *w = NULL;
271              
272 2 50         GIT_ASSERT_ARG(type == GIT_OBJECT_REF_DELTA || type == GIT_OBJECT_OFS_DELTA);
    0          
273              
274 2 50         if (type == GIT_OBJECT_REF_DELTA) {
275 2           idx->off += GIT_OID_RAWSZ;
276             } else {
277             off64_t base_off;
278 0           int error = get_delta_base(&base_off, idx->pack, &w, &idx->off, type, idx->entry_start);
279 0           git_mwindow_close(&w);
280 0 0         if (error < 0)
281 0           return error;
282             }
283              
284 2           return 0;
285             }
286              
287             /* Read from the stream and discard any output */
288 4           static int read_object_stream(git_indexer *idx, git_packfile_stream *stream)
289             {
290             ssize_t read;
291              
292 4 50         GIT_ASSERT_ARG(stream);
293              
294             do {
295 6           read = git_packfile_stream_read(stream, idx->objbuf, sizeof(idx->objbuf));
296 6 100         } while (read > 0);
297              
298 4 100         if (read < 0)
299 2           return (int)read;
300              
301 2           return 0;
302             }
303              
304 45           static int crc_object(uint32_t *crc_out, git_mwindow_file *mwf, off64_t start, off64_t size)
305             {
306             void *ptr;
307             uint32_t crc;
308             unsigned int left, len;
309 45           git_mwindow *w = NULL;
310              
311 45           crc = crc32(0L, Z_NULL, 0);
312 90 100         while (size) {
313 45           ptr = git_mwindow_open(mwf, &w, start, (size_t)size, &left);
314 45 50         if (ptr == NULL)
315 0           return -1;
316              
317 45           len = min(left, (unsigned int)size);
318 45           crc = crc32(crc, ptr, len);
319 45           size -= len;
320 45           start += len;
321 45           git_mwindow_close(&w);
322             }
323              
324 45           *crc_out = htonl(crc);
325 45           return 0;
326             }
327              
328 0           static int add_expected_oid(git_indexer *idx, const git_oid *oid)
329             {
330             /*
331             * If we know about that object because it is stored in our ODB or
332             * because we have already processed it as part of our pack file, we do
333             * not have to expect it.
334             */
335 0 0         if ((!idx->odb || !git_odb_exists(idx->odb, oid)) &&
336 0 0         !git_oidmap_exists(idx->pack->idx_cache, oid) &&
337 0           !git_oidmap_exists(idx->expected_oids, oid)) {
338 0           git_oid *dup = git__malloc(sizeof(*oid));
339 0 0         GIT_ERROR_CHECK_ALLOC(dup);
340 0           git_oid_cpy(dup, oid);
341 0           return git_oidmap_set(idx->expected_oids, dup, dup);
342             }
343              
344 0           return 0;
345             }
346              
347 0           static int check_object_connectivity(git_indexer *idx, const git_rawobj *obj)
348             {
349             git_object *object;
350             git_oid *expected;
351 0           int error = 0;
352              
353 0 0         if (obj->type != GIT_OBJECT_BLOB &&
    0          
354 0 0         obj->type != GIT_OBJECT_TREE &&
355 0 0         obj->type != GIT_OBJECT_COMMIT &&
356 0           obj->type != GIT_OBJECT_TAG)
357 0           return 0;
358              
359 0 0         if (git_object__from_raw(&object, obj->data, obj->len, obj->type) < 0) {
360             /*
361             * parse_raw returns EINVALID on invalid data; downgrade
362             * that to a normal -1 error code.
363             */
364 0           error = -1;
365 0           goto out;
366             }
367              
368 0 0         if ((expected = git_oidmap_get(idx->expected_oids, &object->cached.oid)) != NULL) {
369 0           git_oidmap_delete(idx->expected_oids, &object->cached.oid);
370 0           git__free(expected);
371             }
372              
373             /*
374             * Check whether this is a known object. If so, we can just continue as
375             * we assume that the ODB has a complete graph.
376             */
377 0 0         if (idx->odb && git_odb_exists(idx->odb, &object->cached.oid))
    0          
378 0           return 0;
379              
380 0           switch (obj->type) {
381             case GIT_OBJECT_TREE:
382             {
383 0           git_tree *tree = (git_tree *) object;
384             git_tree_entry *entry;
385             size_t i;
386              
387 0 0         git_array_foreach(tree->entries, i, entry)
    0          
388 0 0         if (add_expected_oid(idx, &entry->oid) < 0)
389 0           goto out;
390              
391 0           break;
392             }
393             case GIT_OBJECT_COMMIT:
394             {
395 0           git_commit *commit = (git_commit *) object;
396             git_oid *parent_oid;
397             size_t i;
398              
399 0 0         git_array_foreach(commit->parent_ids, i, parent_oid)
    0          
400 0 0         if (add_expected_oid(idx, parent_oid) < 0)
401 0           goto out;
402              
403 0 0         if (add_expected_oid(idx, &commit->tree_id) < 0)
404 0           goto out;
405              
406 0           break;
407             }
408             case GIT_OBJECT_TAG:
409             {
410 0           git_tag *tag = (git_tag *) object;
411              
412 0 0         if (add_expected_oid(idx, &tag->target) < 0)
413 0           goto out;
414              
415 0           break;
416             }
417             case GIT_OBJECT_BLOB:
418             default:
419 0           break;
420             }
421              
422             out:
423 0           git_object_free(object);
424              
425 0           return error;
426             }
427              
428 43           static int store_object(git_indexer *idx)
429             {
430             int i, error;
431             git_oid oid;
432             struct entry *entry;
433             off64_t entry_size;
434             struct git_pack_entry *pentry;
435 43           off64_t entry_start = idx->entry_start;
436              
437 43           entry = git__calloc(1, sizeof(*entry));
438 43 50         GIT_ERROR_CHECK_ALLOC(entry);
439              
440 43           pentry = git__calloc(1, sizeof(struct git_pack_entry));
441 43 50         GIT_ERROR_CHECK_ALLOC(pentry);
442              
443 43 50         if (git_hash_final(oid.id, &idx->hash_ctx)) {
444 0           git__free(pentry);
445 0           goto on_error;
446             }
447 43           entry_size = idx->off - entry_start;
448 43 50         if (entry_start > UINT31_MAX) {
449 0           entry->offset = UINT32_MAX;
450 0           entry->offset_long = entry_start;
451             } else {
452 43           entry->offset = (uint32_t)entry_start;
453             }
454              
455 43 50         if (idx->do_verify) {
456 0           git_rawobj rawobj = {
457 0           idx->entry_data.ptr,
458 0           idx->entry_data.size,
459 0           idx->entry_type
460             };
461              
462 0 0         if ((error = check_object_connectivity(idx, &rawobj)) < 0)
463 0           goto on_error;
464             }
465              
466 43           git_oid_cpy(&pentry->sha1, &oid);
467 43           pentry->offset = entry_start;
468              
469 43 50         if (git_oidmap_exists(idx->pack->idx_cache, &pentry->sha1)) {
470 0           git_error_set(GIT_ERROR_INDEXER, "duplicate object %s found in pack", git_oid_tostr_s(&pentry->sha1));
471 0           git__free(pentry);
472 0           goto on_error;
473             }
474              
475 43 50         if ((error = git_oidmap_set(idx->pack->idx_cache, &pentry->sha1, pentry)) < 0) {
476 0           git__free(pentry);
477 0           git_error_set_oom();
478 0           goto on_error;
479             }
480              
481 43           git_oid_cpy(&entry->oid, &oid);
482              
483 43 50         if (crc_object(&entry->crc, &idx->pack->mwf, entry_start, entry_size) < 0)
484 0           goto on_error;
485              
486             /* Add the object to the list */
487 43 50         if (git_vector_insert(&idx->objects, entry) < 0)
488 0           goto on_error;
489              
490 5191 100         for (i = oid.id[0]; i < 256; ++i) {
491 5148           idx->fanout[i]++;
492             }
493              
494 43           return 0;
495              
496             on_error:
497 0           git__free(entry);
498              
499 43           return -1;
500             }
501              
502 0           GIT_INLINE(bool) has_entry(git_indexer *idx, git_oid *id)
503             {
504 0           return git_oidmap_exists(idx->pack->idx_cache, id);
505             }
506              
507 2           static int save_entry(git_indexer *idx, struct entry *entry, struct git_pack_entry *pentry, off64_t entry_start)
508             {
509             int i;
510              
511 2 50         if (entry_start > UINT31_MAX) {
512 0           entry->offset = UINT32_MAX;
513 0           entry->offset_long = entry_start;
514             } else {
515 2           entry->offset = (uint32_t)entry_start;
516             }
517              
518 2           pentry->offset = entry_start;
519              
520 4           if (git_oidmap_exists(idx->pack->idx_cache, &pentry->sha1) ||
521 2           git_oidmap_set(idx->pack->idx_cache, &pentry->sha1, pentry) < 0) {
522 0           git_error_set(GIT_ERROR_INDEXER, "cannot insert object into pack");
523 0           return -1;
524             }
525              
526             /* Add the object to the list */
527 2 50         if (git_vector_insert(&idx->objects, entry) < 0)
528 0           return -1;
529              
530 136 100         for (i = entry->oid.id[0]; i < 256; ++i) {
531 134           idx->fanout[i]++;
532             }
533              
534 2           return 0;
535             }
536              
537 2           static int hash_and_save(git_indexer *idx, git_rawobj *obj, off64_t entry_start)
538             {
539             git_oid oid;
540             size_t entry_size;
541             struct entry *entry;
542 2           struct git_pack_entry *pentry = NULL;
543              
544 2           entry = git__calloc(1, sizeof(*entry));
545 2 50         GIT_ERROR_CHECK_ALLOC(entry);
546              
547 2 50         if (git_odb__hashobj(&oid, obj) < 0) {
548 0           git_error_set(GIT_ERROR_INDEXER, "failed to hash object");
549 0           goto on_error;
550             }
551              
552 2           pentry = git__calloc(1, sizeof(struct git_pack_entry));
553 2 50         GIT_ERROR_CHECK_ALLOC(pentry);
554              
555 2           git_oid_cpy(&pentry->sha1, &oid);
556 2           git_oid_cpy(&entry->oid, &oid);
557 2           entry->crc = crc32(0L, Z_NULL, 0);
558              
559 2           entry_size = (size_t)(idx->off - entry_start);
560 2 50         if (crc_object(&entry->crc, &idx->pack->mwf, entry_start, entry_size) < 0)
561 0           goto on_error;
562              
563 2           return save_entry(idx, entry, pentry, entry_start);
564              
565             on_error:
566 0           git__free(pentry);
567 0           git__free(entry);
568 0           git__free(obj->data);
569 2           return -1;
570             }
571              
572 52           static int do_progress_callback(git_indexer *idx, git_indexer_progress *stats)
573             {
574 52 100         if (idx->progress_cb)
575 41           return git_error_set_after_callback_function(
576 41           idx->progress_cb(stats, idx->progress_payload),
577             "indexer progress");
578 11           return 0;
579             }
580              
581             /* Hash everything but the last 20B of input */
582 91           static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size)
583             {
584             size_t to_expell, to_keep;
585              
586 91 50         if (size == 0)
587 0           return;
588              
589             /* Easy case, dump the buffer and the data minus the last 20 bytes */
590 91 100         if (size >= GIT_OID_RAWSZ) {
591 45           git_hash_update(&idx->trailer, idx->inbuf, idx->inbuf_len);
592 45           git_hash_update(&idx->trailer, data, size - GIT_OID_RAWSZ);
593              
594 45           data += size - GIT_OID_RAWSZ;
595 45           memcpy(idx->inbuf, data, GIT_OID_RAWSZ);
596 45           idx->inbuf_len = GIT_OID_RAWSZ;
597 45           return;
598             }
599              
600             /* We can just append */
601 46 100         if (idx->inbuf_len + size <= GIT_OID_RAWSZ) {
602 8           memcpy(idx->inbuf + idx->inbuf_len, data, size);
603 8           idx->inbuf_len += size;
604 8           return;
605             }
606              
607             /* We need to partially drain the buffer and then append */
608 38           to_keep = GIT_OID_RAWSZ - size;
609 38           to_expell = idx->inbuf_len - to_keep;
610              
611 38           git_hash_update(&idx->trailer, idx->inbuf, to_expell);
612              
613 38           memmove(idx->inbuf, idx->inbuf + to_expell, to_keep);
614 38           memcpy(idx->inbuf + to_keep, data, size);
615 38           idx->inbuf_len += size - to_expell;
616             }
617              
618             #if defined(NO_MMAP) || !defined(GIT_WIN32)
619              
620 91           static int write_at(git_indexer *idx, const void *data, off64_t offset, size_t size)
621             {
622 91           size_t remaining_size = size;
623 91           const char *ptr = (const char *)data;
624              
625             /* Handle data size larger that ssize_t */
626 182 100         while (remaining_size > 0) {
627             ssize_t nb;
628 91 50         HANDLE_EINTR(nb, p_pwrite(idx->pack->mwf.fd, (void *)ptr,
    0          
629             remaining_size, offset));
630 91 50         if (nb <= 0)
631 0           return -1;
632              
633 91           ptr += nb;
634 91           offset += nb;
635 91           remaining_size -= nb;
636             }
637              
638 91           return 0;
639             }
640              
641 91           static int append_to_pack(git_indexer *idx, const void *data, size_t size)
642             {
643 91 50         if (write_at(idx, data, idx->pack->mwf.size, size) < 0) {
644 0           git_error_set(GIT_ERROR_OS, "cannot extend packfile '%s'", idx->pack->pack_name);
645 0           return -1;
646             }
647              
648 91           return 0;
649             }
650              
651             #else
652              
653             /*
654             * Windows may keep different views to a networked file for the mmap- and
655             * open-accessed versions of a file, so any writes done through
656             * `write(2)`/`pwrite(2)` may not be reflected on the data that `mmap(2)` is
657             * able to read.
658             */
659              
660             static int write_at(git_indexer *idx, const void *data, off64_t offset, size_t size)
661             {
662             git_file fd = idx->pack->mwf.fd;
663             size_t mmap_alignment;
664             size_t page_offset;
665             off64_t page_start;
666             unsigned char *map_data;
667             git_map map;
668             int error;
669              
670             GIT_ASSERT_ARG(data);
671             GIT_ASSERT_ARG(size);
672              
673             if ((error = git__mmap_alignment(&mmap_alignment)) < 0)
674             return error;
675              
676             /* the offset needs to be at the mmap boundary for the platform */
677             page_offset = offset % mmap_alignment;
678             page_start = offset - page_offset;
679              
680             if ((error = p_mmap(&map, page_offset + size, GIT_PROT_WRITE, GIT_MAP_SHARED, fd, page_start)) < 0)
681             return error;
682              
683             map_data = (unsigned char *)map.data;
684             memcpy(map_data + page_offset, data, size);
685             p_munmap(&map);
686              
687             return 0;
688             }
689              
690             static int append_to_pack(git_indexer *idx, const void *data, size_t size)
691             {
692             off64_t new_size;
693             size_t mmap_alignment;
694             size_t page_offset;
695             off64_t page_start;
696             off64_t current_size = idx->pack->mwf.size;
697             int error;
698              
699             if (!size)
700             return 0;
701              
702             if ((error = git__mmap_alignment(&mmap_alignment)) < 0)
703             return error;
704              
705             /* Write a single byte to force the file system to allocate space now or
706             * report an error, since we can't report errors when writing using mmap.
707             * Round the size up to the nearest page so that we only need to perform file
708             * I/O when we add a page, instead of whenever we write even a single byte. */
709             new_size = current_size + size;
710             page_offset = new_size % mmap_alignment;
711             page_start = new_size - page_offset;
712              
713             if (p_pwrite(idx->pack->mwf.fd, data, 1, page_start + mmap_alignment - 1) < 0) {
714             git_error_set(GIT_ERROR_OS, "cannot extend packfile '%s'", idx->pack->pack_name);
715             return -1;
716             }
717              
718             return write_at(idx, data, idx->pack->mwf.size, size);
719             }
720              
721             #endif
722              
723 131           static int read_stream_object(git_indexer *idx, git_indexer_progress *stats)
724             {
725 131           git_packfile_stream *stream = &idx->stream;
726 131           off64_t entry_start = idx->off;
727             size_t entry_size;
728             git_object_t type;
729 131           git_mwindow *w = NULL;
730             int error;
731              
732 131 100         if (idx->pack->mwf.size <= idx->off + 20)
733 84           return GIT_EBUFS;
734              
735 47 100         if (!idx->have_stream) {
736 45           error = git_packfile_unpack_header(&entry_size, &type, idx->pack, &w, &idx->off);
737 45 50         if (error == GIT_EBUFS) {
738 0           idx->off = entry_start;
739 0           return error;
740             }
741 45 50         if (error < 0)
742 0           return error;
743              
744 45           git_mwindow_close(&w);
745 45           idx->entry_start = entry_start;
746 45           git_hash_init(&idx->hash_ctx);
747 45           git_str_clear(&idx->entry_data);
748              
749 45 100         if (type == GIT_OBJECT_REF_DELTA || type == GIT_OBJECT_OFS_DELTA) {
    50          
750 2           error = advance_delta_offset(idx, type);
751 2 50         if (error == GIT_EBUFS) {
752 0           idx->off = entry_start;
753 0           return error;
754             }
755 2 50         if (error < 0)
756 0           return error;
757              
758 2           idx->have_delta = 1;
759             } else {
760 43           idx->have_delta = 0;
761              
762 43           error = hash_header(&idx->hash_ctx, entry_size, type);
763 43 50         if (error < 0)
764 0           return error;
765             }
766              
767 45           idx->have_stream = 1;
768 45           idx->entry_type = type;
769              
770 45           error = git_packfile_stream_open(stream, idx->pack, idx->off);
771 45 50         if (error < 0)
772 0           return error;
773             }
774              
775 47 100         if (idx->have_delta) {
776 4           error = read_object_stream(idx, stream);
777             } else {
778 43           error = hash_object_stream(idx, stream);
779             }
780              
781 47           idx->off = stream->curpos;
782 47 100         if (error == GIT_EBUFS)
783 2           return error;
784              
785             /* We want to free the stream reasorces no matter what here */
786 45           idx->have_stream = 0;
787 45           git_packfile_stream_dispose(stream);
788              
789 45 50         if (error < 0)
790 0           return error;
791              
792 45 100         if (idx->have_delta) {
793 2           error = store_delta(idx);
794             } else {
795 43           error = store_object(idx);
796             }
797              
798 45 50         if (error < 0)
799 0           return error;
800              
801 45 100         if (!idx->have_delta) {
802 43           stats->indexed_objects++;
803             }
804 45           stats->received_objects++;
805              
806 45 50         if ((error = do_progress_callback(idx, stats)) != 0)
807 0           return error;
808              
809 131           return 0;
810             }
811              
812 91           int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_indexer_progress *stats)
813             {
814 91           int error = -1;
815 91           struct git_pack_header *hdr = &idx->hdr;
816 91           git_mwindow_file *mwf = &idx->pack->mwf;
817              
818 91 50         GIT_ASSERT_ARG(idx);
819 91 50         GIT_ASSERT_ARG(data);
820 91 50         GIT_ASSERT_ARG(stats);
821              
822 91 50         if ((error = append_to_pack(idx, data, size)) < 0)
823 0           return error;
824              
825 91           hash_partially(idx, data, (int)size);
826              
827             /* Make sure we set the new size of the pack */
828 91           idx->pack->mwf.size += size;
829              
830 91 100         if (!idx->parsed_header) {
831             unsigned int total_objects;
832              
833 5 50         if ((unsigned)idx->pack->mwf.size < sizeof(struct git_pack_header))
834 0           return 0;
835              
836 5 50         if ((error = parse_header(&idx->hdr, idx->pack)) < 0)
837 0           return error;
838              
839 5           idx->parsed_header = 1;
840 5           idx->nr_objects = ntohl(hdr->hdr_entries);
841 5           idx->off = sizeof(struct git_pack_header);
842              
843 5 50         if (idx->nr_objects <= git_indexer__max_objects) {
844 5           total_objects = (unsigned int)idx->nr_objects;
845             } else {
846 0           git_error_set(GIT_ERROR_INDEXER, "too many objects");
847 0           return -1;
848             }
849              
850 5 50         if (git_oidmap_new(&idx->pack->idx_cache) < 0)
851 0           return -1;
852              
853 5           idx->pack->has_cache = 1;
854 5 50         if (git_vector_init(&idx->objects, total_objects, objects_cmp) < 0)
855 0           return -1;
856              
857 5 50         if (git_vector_init(&idx->deltas, total_objects / 2, NULL) < 0)
858 0           return -1;
859              
860 5           stats->received_objects = 0;
861 5           stats->local_objects = 0;
862 5           stats->total_deltas = 0;
863 5           stats->indexed_deltas = 0;
864 5           stats->indexed_objects = 0;
865 5           stats->total_objects = total_objects;
866              
867 5 50         if ((error = do_progress_callback(idx, stats)) != 0)
868 0           return error;
869             }
870              
871             /* Now that we have data in the pack, let's try to parse it */
872              
873             /* As the file grows any windows we try to use will be out of date */
874 91 50         if ((error = git_mwindow_free_all(mwf)) < 0)
875 0           goto on_error;
876              
877 136 100         while (stats->indexed_objects < idx->nr_objects) {
878 131 100         if ((error = read_stream_object(idx, stats)) != 0) {
879 86 50         if (error == GIT_EBUFS)
880 86           break;
881             else
882 0           goto on_error;
883             }
884             }
885              
886 91           return 0;
887              
888             on_error:
889 0           git_mwindow_free_all(mwf);
890 0           return error;
891             }
892              
893 10           static int index_path(git_str *path, git_indexer *idx, const char *suffix)
894             {
895 10           const char prefix[] = "pack-";
896 10           size_t slash = (size_t)path->size;
897              
898             /* search backwards for '/' */
899 380 50         while (slash > 0 && path->ptr[slash - 1] != '/')
    100          
900 370           slash--;
901              
902 10 50         if (git_str_grow(path, slash + 1 + strlen(prefix) +
903 10           GIT_OID_HEXSZ + strlen(suffix) + 1) < 0)
904 0           return -1;
905              
906 10           git_str_truncate(path, slash);
907 10           git_str_puts(path, prefix);
908 10           git_str_puts(path, idx->name);
909 10           git_str_puts(path, suffix);
910              
911 10 50         return git_str_oom(path) ? -1 : 0;
912             }
913              
914             /**
915             * Rewind the packfile by the trailer, as we might need to fix the
916             * packfile by injecting objects at the tail and must overwrite it.
917             */
918 0           static int seek_back_trailer(git_indexer *idx)
919             {
920 0           idx->pack->mwf.size -= GIT_OID_RAWSZ;
921 0           return git_mwindow_free_all(&idx->pack->mwf);
922             }
923              
924 0           static int inject_object(git_indexer *idx, git_oid *id)
925             {
926 0           git_odb_object *obj = NULL;
927 0           struct entry *entry = NULL;
928 0           struct git_pack_entry *pentry = NULL;
929 0           unsigned char empty_checksum[GIT_HASH_SHA1_SIZE] = {0};
930             unsigned char hdr[64];
931 0           git_str buf = GIT_STR_INIT;
932             off64_t entry_start;
933             const void *data;
934             size_t len, hdr_len;
935 0           size_t checksum_size = GIT_HASH_SHA1_SIZE;
936             int error;
937              
938 0 0         if ((error = seek_back_trailer(idx)) < 0)
939 0           goto cleanup;
940              
941 0           entry_start = idx->pack->mwf.size;
942              
943 0 0         if ((error = git_odb_read(&obj, idx->odb, id)) < 0) {
944 0           git_error_set(GIT_ERROR_INDEXER, "missing delta bases");
945 0           goto cleanup;
946             }
947              
948 0           data = git_odb_object_data(obj);
949 0           len = git_odb_object_size(obj);
950              
951 0           entry = git__calloc(1, sizeof(*entry));
952 0 0         GIT_ERROR_CHECK_ALLOC(entry);
953              
954 0           entry->crc = crc32(0L, Z_NULL, 0);
955              
956             /* Write out the object header */
957 0 0         if ((error = git_packfile__object_header(&hdr_len, hdr, len, git_odb_object_type(obj))) < 0 ||
    0          
958 0           (error = append_to_pack(idx, hdr, hdr_len)) < 0)
959             goto cleanup;
960              
961 0           idx->pack->mwf.size += hdr_len;
962 0           entry->crc = crc32(entry->crc, hdr, (uInt)hdr_len);
963              
964 0 0         if ((error = git_zstream_deflatebuf(&buf, data, len)) < 0)
965 0           goto cleanup;
966              
967             /* And then the compressed object */
968 0 0         if ((error = append_to_pack(idx, buf.ptr, buf.size)) < 0)
969 0           goto cleanup;
970              
971 0           idx->pack->mwf.size += buf.size;
972 0           entry->crc = htonl(crc32(entry->crc, (unsigned char *)buf.ptr, (uInt)buf.size));
973 0           git_str_dispose(&buf);
974              
975             /* Write a fake trailer so the pack functions play ball */
976              
977 0 0         if ((error = append_to_pack(idx, empty_checksum, checksum_size)) < 0)
978 0           goto cleanup;
979              
980 0           idx->pack->mwf.size += GIT_OID_RAWSZ;
981              
982 0           pentry = git__calloc(1, sizeof(struct git_pack_entry));
983 0 0         GIT_ERROR_CHECK_ALLOC(pentry);
984              
985 0           git_oid_cpy(&pentry->sha1, id);
986 0           git_oid_cpy(&entry->oid, id);
987 0           idx->off = entry_start + hdr_len + len;
988              
989 0           error = save_entry(idx, entry, pentry, entry_start);
990              
991             cleanup:
992 0 0         if (error) {
993 0           git__free(entry);
994 0           git__free(pentry);
995             }
996              
997 0           git_odb_object_free(obj);
998 0           return error;
999             }
1000              
1001 0           static int fix_thin_pack(git_indexer *idx, git_indexer_progress *stats)
1002             {
1003 0           int error, found_ref_delta = 0;
1004             unsigned int i;
1005             struct delta_info *delta;
1006             size_t size;
1007             git_object_t type;
1008 0           git_mwindow *w = NULL;
1009 0           off64_t curpos = 0;
1010             unsigned char *base_info;
1011 0           unsigned int left = 0;
1012             git_oid base;
1013              
1014 0 0         GIT_ASSERT(git_vector_length(&idx->deltas) > 0);
1015              
1016 0 0         if (idx->odb == NULL) {
1017 0           git_error_set(GIT_ERROR_INDEXER, "cannot fix a thin pack without an ODB");
1018 0           return -1;
1019             }
1020              
1021             /* Loop until we find the first REF delta */
1022 0 0         git_vector_foreach(&idx->deltas, i, delta) {
1023 0 0         if (!delta)
1024 0           continue;
1025              
1026 0           curpos = delta->delta_off;
1027 0           error = git_packfile_unpack_header(&size, &type, idx->pack, &w, &curpos);
1028 0 0         if (error < 0)
1029 0           return error;
1030              
1031 0 0         if (type == GIT_OBJECT_REF_DELTA) {
1032 0           found_ref_delta = 1;
1033 0           break;
1034             }
1035             }
1036              
1037 0 0         if (!found_ref_delta) {
1038 0           git_error_set(GIT_ERROR_INDEXER, "no REF_DELTA found, cannot inject object");
1039 0           return -1;
1040             }
1041              
1042             /* curpos now points to the base information, which is an OID */
1043 0           base_info = git_mwindow_open(&idx->pack->mwf, &w, curpos, GIT_OID_RAWSZ, &left);
1044 0 0         if (base_info == NULL) {
1045 0           git_error_set(GIT_ERROR_INDEXER, "failed to map delta information");
1046 0           return -1;
1047             }
1048              
1049 0           git_oid_fromraw(&base, base_info);
1050 0           git_mwindow_close(&w);
1051              
1052 0 0         if (has_entry(idx, &base))
1053 0           return 0;
1054              
1055 0 0         if (inject_object(idx, &base) < 0)
1056 0           return -1;
1057              
1058 0           stats->local_objects++;
1059              
1060 0           return 0;
1061             }
1062              
1063 5           static int resolve_deltas(git_indexer *idx, git_indexer_progress *stats)
1064             {
1065             unsigned int i;
1066             int error;
1067             struct delta_info *delta;
1068 5           int progressed = 0, non_null = 0, progress_cb_result;
1069              
1070 7 100         while (idx->deltas.length > 0) {
1071 4           progressed = 0;
1072 4           non_null = 0;
1073 8 100         git_vector_foreach(&idx->deltas, i, delta) {
1074 4           git_rawobj obj = {0};
1075              
1076 4 100         if (!delta)
1077 2           continue;
1078              
1079 2           non_null = 1;
1080 2           idx->off = delta->delta_off;
1081 2 50         if ((error = git_packfile_unpack(&obj, idx->pack, &idx->off)) < 0) {
1082 0 0         if (error == GIT_PASSTHROUGH) {
1083             /* We have not seen the base object, we'll try again later. */
1084 0           continue;
1085             }
1086 0           return -1;
1087             }
1088              
1089 2 50         if (idx->do_verify && check_object_connectivity(idx, &obj) < 0)
    0          
1090             /* TODO: error? continue? */
1091 0           continue;
1092              
1093 2 50         if (hash_and_save(idx, &obj, delta->delta_off) < 0)
1094 0           continue;
1095              
1096 2           git__free(obj.data);
1097 2           stats->indexed_objects++;
1098 2           stats->indexed_deltas++;
1099 2           progressed = 1;
1100 2 50         if ((progress_cb_result = do_progress_callback(idx, stats)) < 0)
1101 0           return progress_cb_result;
1102              
1103             /* remove from the list */
1104 2           git_vector_set(NULL, &idx->deltas, i, NULL);
1105 2           git__free(delta);
1106             }
1107              
1108             /* if none were actually set, we're done */
1109 4 100         if (!non_null)
1110 2           break;
1111              
1112 2 50         if (!progressed && (fix_thin_pack(idx, stats) < 0)) {
    0          
1113 0           return -1;
1114             }
1115             }
1116              
1117 5           return 0;
1118             }
1119              
1120 0           static int update_header_and_rehash(git_indexer *idx, git_indexer_progress *stats)
1121             {
1122             void *ptr;
1123 0           size_t chunk = 1024*1024;
1124 0           off64_t hashed = 0;
1125 0           git_mwindow *w = NULL;
1126             git_mwindow_file *mwf;
1127             unsigned int left;
1128              
1129 0           mwf = &idx->pack->mwf;
1130              
1131 0           git_hash_init(&idx->trailer);
1132              
1133              
1134             /* Update the header to include the number of local objects we injected */
1135 0           idx->hdr.hdr_entries = htonl(stats->total_objects + stats->local_objects);
1136 0 0         if (write_at(idx, &idx->hdr, 0, sizeof(struct git_pack_header)) < 0)
1137 0           return -1;
1138              
1139             /*
1140             * We now use the same technique as before to determine the
1141             * hash. We keep reading up to the end and let
1142             * hash_partially() keep the existing trailer out of the
1143             * calculation.
1144             */
1145 0 0         if (git_mwindow_free_all(mwf) < 0)
1146 0           return -1;
1147              
1148 0           idx->inbuf_len = 0;
1149 0 0         while (hashed < mwf->size) {
1150 0           ptr = git_mwindow_open(mwf, &w, hashed, chunk, &left);
1151 0 0         if (ptr == NULL)
1152 0           return -1;
1153              
1154 0           hash_partially(idx, ptr, left);
1155 0           hashed += left;
1156              
1157 0           git_mwindow_close(&w);
1158             }
1159              
1160 0           return 0;
1161             }
1162              
1163 5           int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats)
1164             {
1165 5           git_mwindow *w = NULL;
1166 5           unsigned int i, long_offsets = 0, left;
1167             int error;
1168             struct git_pack_idx_header hdr;
1169 5           git_str filename = GIT_STR_INIT;
1170             struct entry *entry;
1171             unsigned char checksum[GIT_HASH_SHA1_SIZE];
1172 5           git_filebuf index_file = {0};
1173             void *packfile_trailer;
1174 5           size_t checksum_size = GIT_HASH_SHA1_SIZE;
1175             bool mismatch;
1176              
1177 5 50         if (!idx->parsed_header) {
1178 0           git_error_set(GIT_ERROR_INDEXER, "incomplete pack header");
1179 0           return -1;
1180             }
1181              
1182             /* Test for this before resolve_deltas(), as it plays with idx->off */
1183 5 50         if (idx->off + (ssize_t)checksum_size < idx->pack->mwf.size) {
1184 0           git_error_set(GIT_ERROR_INDEXER, "unexpected data at the end of the pack");
1185 0           return -1;
1186             }
1187 5 50         if (idx->off + (ssize_t)checksum_size > idx->pack->mwf.size) {
1188 0           git_error_set(GIT_ERROR_INDEXER, "missing trailer at the end of the pack");
1189 0           return -1;
1190             }
1191              
1192 5           packfile_trailer = git_mwindow_open(&idx->pack->mwf, &w, idx->pack->mwf.size - checksum_size, checksum_size, &left);
1193 5 50         if (packfile_trailer == NULL) {
1194 0           git_mwindow_close(&w);
1195 0           goto on_error;
1196             }
1197              
1198             /* Compare the packfile trailer as it was sent to us and what we calculated */
1199 5           git_hash_final(checksum, &idx->trailer);
1200 5           mismatch = !!memcmp(checksum, packfile_trailer, checksum_size);
1201 5           git_mwindow_close(&w);
1202              
1203 5 50         if (mismatch) {
1204 0           git_error_set(GIT_ERROR_INDEXER, "packfile trailer mismatch");
1205 0           return -1;
1206             }
1207              
1208             /* Freeze the number of deltas */
1209 5           stats->total_deltas = stats->total_objects - stats->indexed_objects;
1210              
1211 5 50         if ((error = resolve_deltas(idx, stats)) < 0)
1212 0           return error;
1213              
1214 5 50         if (stats->indexed_objects != stats->total_objects) {
1215 0           git_error_set(GIT_ERROR_INDEXER, "early EOF");
1216 0           return -1;
1217             }
1218              
1219 5 50         if (stats->local_objects > 0) {
1220 0 0         if (update_header_and_rehash(idx, stats) < 0)
1221 0           return -1;
1222              
1223 0           git_hash_final(checksum, &idx->trailer);
1224 0           write_at(idx, checksum, idx->pack->mwf.size - checksum_size, checksum_size);
1225             }
1226              
1227             /*
1228             * Is the resulting graph fully connected or are we still
1229             * missing some objects? In the second case, we can
1230             * bail out due to an incomplete and thus corrupt
1231             * packfile.
1232             */
1233 5 50         if (git_oidmap_size(idx->expected_oids) > 0) {
1234 0           git_error_set(GIT_ERROR_INDEXER, "packfile is missing %"PRIuZ" objects",
1235             git_oidmap_size(idx->expected_oids));
1236 0           return -1;
1237             }
1238              
1239 5           git_vector_sort(&idx->objects);
1240              
1241             /* Use the trailer hash as the pack file name to ensure
1242             * files with different contents have different names */
1243 5           memcpy(idx->checksum, checksum, checksum_size);
1244 5 50         if (git_hash_fmt(idx->name, checksum, checksum_size) < 0)
1245 0           return -1;
1246              
1247 5           git_str_sets(&filename, idx->pack->pack_name);
1248 5           git_str_shorten(&filename, strlen("pack"));
1249 5           git_str_puts(&filename, "idx");
1250 5 50         if (git_str_oom(&filename))
1251 0           return -1;
1252              
1253 5 50         if (git_filebuf_open(&index_file, filename.ptr,
    50          
1254             GIT_FILEBUF_HASH_CONTENTS |
1255 5           (idx->do_fsync ? GIT_FILEBUF_FSYNC : 0),
1256             idx->mode) < 0)
1257 0           goto on_error;
1258              
1259             /* Write out the header */
1260 5           hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
1261 5           hdr.idx_version = htonl(2);
1262 5           git_filebuf_write(&index_file, &hdr, sizeof(hdr));
1263              
1264             /* Write out the fanout table */
1265 1285 100         for (i = 0; i < 256; ++i) {
1266 1280           uint32_t n = htonl(idx->fanout[i]);
1267 1280           git_filebuf_write(&index_file, &n, sizeof(n));
1268             }
1269              
1270             /* Write out the object names (SHA-1 hashes) */
1271 50 100         git_vector_foreach(&idx->objects, i, entry) {
1272 45           git_filebuf_write(&index_file, &entry->oid.id, GIT_OID_RAWSZ);
1273             }
1274              
1275             /* Write out the CRC32 values */
1276 50 100         git_vector_foreach(&idx->objects, i, entry) {
1277 45           git_filebuf_write(&index_file, &entry->crc, sizeof(uint32_t));
1278             }
1279              
1280             /* Write out the offsets */
1281 50 100         git_vector_foreach(&idx->objects, i, entry) {
1282             uint32_t n;
1283              
1284 45 50         if (entry->offset == UINT32_MAX)
1285 0           n = htonl(0x80000000 | long_offsets++);
1286             else
1287 45           n = htonl(entry->offset);
1288              
1289 45           git_filebuf_write(&index_file, &n, sizeof(uint32_t));
1290             }
1291              
1292             /* Write out the long offsets */
1293 50 100         git_vector_foreach(&idx->objects, i, entry) {
1294             uint32_t split[2];
1295              
1296 45 50         if (entry->offset != UINT32_MAX)
1297 45           continue;
1298              
1299 0           split[0] = htonl(entry->offset_long >> 32);
1300 0           split[1] = htonl(entry->offset_long & 0xffffffff);
1301              
1302 0           git_filebuf_write(&index_file, &split, sizeof(uint32_t) * 2);
1303             }
1304              
1305             /* Write out the packfile trailer to the index */
1306 5 50         if (git_filebuf_write(&index_file, checksum, checksum_size) < 0)
1307 0           goto on_error;
1308              
1309             /* Write out the hash of the idx */
1310 5 50         if (git_filebuf_hash(checksum, &index_file) < 0)
1311 0           goto on_error;
1312              
1313 5           git_filebuf_write(&index_file, checksum, checksum_size);
1314              
1315             /* Figure out what the final name should be */
1316 5 50         if (index_path(&filename, idx, ".idx") < 0)
1317 0           goto on_error;
1318              
1319             /* Commit file */
1320 5 50         if (git_filebuf_commit_at(&index_file, filename.ptr) < 0)
1321 0           goto on_error;
1322              
1323 5 50         if (git_mwindow_free_all(&idx->pack->mwf) < 0)
1324 0           goto on_error;
1325              
1326             #if !defined(NO_MMAP) && defined(GIT_WIN32)
1327             /*
1328             * Some non-Windows remote filesystems fail when truncating files if the
1329             * file permissions change after opening the file (done by p_mkstemp).
1330             *
1331             * Truncation is only needed when mmap is used to undo rounding up to next
1332             * page_size in append_to_pack.
1333             */
1334             if (p_ftruncate(idx->pack->mwf.fd, idx->pack->mwf.size) < 0) {
1335             git_error_set(GIT_ERROR_OS, "failed to truncate pack file '%s'", idx->pack->pack_name);
1336             return -1;
1337             }
1338             #endif
1339              
1340 5 50         if (idx->do_fsync && p_fsync(idx->pack->mwf.fd) < 0) {
    0          
1341 0           git_error_set(GIT_ERROR_OS, "failed to fsync packfile");
1342 0           goto on_error;
1343             }
1344              
1345             /* We need to close the descriptor here so Windows doesn't choke on commit_at */
1346 5 50         if (p_close(idx->pack->mwf.fd) < 0) {
1347 0           git_error_set(GIT_ERROR_OS, "failed to close packfile");
1348 0           goto on_error;
1349             }
1350              
1351 5           idx->pack->mwf.fd = -1;
1352              
1353 5 50         if (index_path(&filename, idx, ".pack") < 0)
1354 0           goto on_error;
1355              
1356             /* And don't forget to rename the packfile to its new place. */
1357 5 50         if (p_rename(idx->pack->pack_name, git_str_cstr(&filename)) < 0)
1358 0           goto on_error;
1359              
1360             /* And fsync the parent directory if we're asked to. */
1361 5           if (idx->do_fsync &&
1362 0           git_futils_fsync_parent(git_str_cstr(&filename)) < 0)
1363 0           goto on_error;
1364              
1365 5           idx->pack_committed = 1;
1366              
1367 5           git_str_dispose(&filename);
1368 5           return 0;
1369              
1370             on_error:
1371 0           git_mwindow_free_all(&idx->pack->mwf);
1372 0           git_filebuf_cleanup(&index_file);
1373 0           git_str_dispose(&filename);
1374 5           return -1;
1375             }
1376              
1377 5           void git_indexer_free(git_indexer *idx)
1378             {
1379             const git_oid *key;
1380             git_oid *value;
1381             size_t iter;
1382              
1383 5 50         if (idx == NULL)
1384 0           return;
1385              
1386 5 50         if (idx->have_stream)
1387 0           git_packfile_stream_dispose(&idx->stream);
1388              
1389 5           git_vector_free_deep(&idx->objects);
1390              
1391 5 50         if (idx->pack->idx_cache) {
1392             struct git_pack_entry *pentry;
1393 50 100         git_oidmap_foreach_value(idx->pack->idx_cache, pentry, {
1394             git__free(pentry);
1395             });
1396              
1397 5           git_oidmap_free(idx->pack->idx_cache);
1398             }
1399              
1400 5           git_vector_free_deep(&idx->deltas);
1401              
1402 5           git_packfile_free(idx->pack, !idx->pack_committed);
1403              
1404 5           iter = 0;
1405 5 50         while (git_oidmap_iterate((void **) &value, idx->expected_oids, &iter, &key) == 0)
1406 0           git__free(value);
1407              
1408 5           git_hash_ctx_cleanup(&idx->trailer);
1409 5           git_hash_ctx_cleanup(&idx->hash_ctx);
1410 5           git_str_dispose(&idx->entry_data);
1411 5           git_oidmap_free(idx->expected_oids);
1412 5           git__free(idx);
1413             }