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