]> git.proxmox.com Git - libgit2.git/blob - src/index.c
Include stacktrace summary in memory leak output.
[libgit2.git] / src / index.c
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 <stddef.h>
9
10 #include "common.h"
11 #include "repository.h"
12 #include "index.h"
13 #include "tree.h"
14 #include "tree-cache.h"
15 #include "hash.h"
16 #include "iterator.h"
17 #include "pathspec.h"
18 #include "ignore.h"
19 #include "blob.h"
20
21 #include "git2/odb.h"
22 #include "git2/oid.h"
23 #include "git2/blob.h"
24 #include "git2/config.h"
25 #include "git2/sys/index.h"
26
27 static int index_apply_to_wd_diff(git_index *index, int action, const git_strarray *paths,
28 unsigned int flags,
29 git_index_matched_path_cb cb, void *payload);
30
31 #define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7)
32 #define short_entry_size(len) entry_size(struct entry_short, len)
33 #define long_entry_size(len) entry_size(struct entry_long, len)
34
35 #define minimal_entry_size (offsetof(struct entry_short, path))
36
37 static const size_t INDEX_FOOTER_SIZE = GIT_OID_RAWSZ;
38 static const size_t INDEX_HEADER_SIZE = 12;
39
40 static const unsigned int INDEX_VERSION_NUMBER = 2;
41 static const unsigned int INDEX_VERSION_NUMBER_EXT = 3;
42
43 static const unsigned int INDEX_HEADER_SIG = 0x44495243;
44 static const char INDEX_EXT_TREECACHE_SIG[] = {'T', 'R', 'E', 'E'};
45 static const char INDEX_EXT_UNMERGED_SIG[] = {'R', 'E', 'U', 'C'};
46 static const char INDEX_EXT_CONFLICT_NAME_SIG[] = {'N', 'A', 'M', 'E'};
47
48 #define INDEX_OWNER(idx) ((git_repository *)(GIT_REFCOUNT_OWNER(idx)))
49
50 struct index_header {
51 uint32_t signature;
52 uint32_t version;
53 uint32_t entry_count;
54 };
55
56 struct index_extension {
57 char signature[4];
58 uint32_t extension_size;
59 };
60
61 struct entry_time {
62 uint32_t seconds;
63 uint32_t nanoseconds;
64 };
65
66 struct entry_short {
67 struct entry_time ctime;
68 struct entry_time mtime;
69 uint32_t dev;
70 uint32_t ino;
71 uint32_t mode;
72 uint32_t uid;
73 uint32_t gid;
74 uint32_t file_size;
75 git_oid oid;
76 uint16_t flags;
77 char path[1]; /* arbitrary length */
78 };
79
80 struct entry_long {
81 struct entry_time ctime;
82 struct entry_time mtime;
83 uint32_t dev;
84 uint32_t ino;
85 uint32_t mode;
86 uint32_t uid;
87 uint32_t gid;
88 uint32_t file_size;
89 git_oid oid;
90 uint16_t flags;
91 uint16_t flags_extended;
92 char path[1]; /* arbitrary length */
93 };
94
95 struct entry_srch_key {
96 const char *path;
97 size_t pathlen;
98 int stage;
99 };
100
101 struct entry_internal {
102 git_index_entry entry;
103 size_t pathlen;
104 char path[GIT_FLEX_ARRAY];
105 };
106
107 struct reuc_entry_internal {
108 git_index_reuc_entry entry;
109 size_t pathlen;
110 char path[GIT_FLEX_ARRAY];
111 };
112
113 /* local declarations */
114 static size_t read_extension(git_index *index, const char *buffer, size_t buffer_size);
115 static int read_header(struct index_header *dest, const void *buffer);
116
117 static int parse_index(git_index *index, const char *buffer, size_t buffer_size);
118 static bool is_index_extended(git_index *index);
119 static int write_index(git_oid *checksum, git_index *index, git_filebuf *file);
120
121 static void index_entry_free(git_index_entry *entry);
122 static void index_entry_reuc_free(git_index_reuc_entry *reuc);
123
124 int git_index_entry_srch(const void *key, const void *array_member)
125 {
126 const struct entry_srch_key *srch_key = key;
127 const struct entry_internal *entry = array_member;
128 int cmp;
129 size_t len1, len2, len;
130
131 len1 = srch_key->pathlen;
132 len2 = entry->pathlen;
133 len = len1 < len2 ? len1 : len2;
134
135 cmp = memcmp(srch_key->path, entry->path, len);
136 if (cmp)
137 return cmp;
138 if (len1 < len2)
139 return -1;
140 if (len1 > len2)
141 return 1;
142
143 if (srch_key->stage != GIT_INDEX_STAGE_ANY)
144 return srch_key->stage - GIT_IDXENTRY_STAGE(&entry->entry);
145
146 return 0;
147 }
148
149 int git_index_entry_isrch(const void *key, const void *array_member)
150 {
151 const struct entry_srch_key *srch_key = key;
152 const struct entry_internal *entry = array_member;
153 int cmp;
154 size_t len1, len2, len;
155
156 len1 = srch_key->pathlen;
157 len2 = entry->pathlen;
158 len = len1 < len2 ? len1 : len2;
159
160 cmp = strncasecmp(srch_key->path, entry->path, len);
161
162 if (cmp)
163 return cmp;
164 if (len1 < len2)
165 return -1;
166 if (len1 > len2)
167 return 1;
168
169 if (srch_key->stage != GIT_INDEX_STAGE_ANY)
170 return srch_key->stage - GIT_IDXENTRY_STAGE(&entry->entry);
171
172 return 0;
173 }
174
175 static int index_entry_srch_path(const void *path, const void *array_member)
176 {
177 const git_index_entry *entry = array_member;
178
179 return strcmp((const char *)path, entry->path);
180 }
181
182 static int index_entry_isrch_path(const void *path, const void *array_member)
183 {
184 const git_index_entry *entry = array_member;
185
186 return strcasecmp((const char *)path, entry->path);
187 }
188
189 int git_index_entry_cmp(const void *a, const void *b)
190 {
191 int diff;
192 const git_index_entry *entry_a = a;
193 const git_index_entry *entry_b = b;
194
195 diff = strcmp(entry_a->path, entry_b->path);
196
197 if (diff == 0)
198 diff = (GIT_IDXENTRY_STAGE(entry_a) - GIT_IDXENTRY_STAGE(entry_b));
199
200 return diff;
201 }
202
203 int git_index_entry_icmp(const void *a, const void *b)
204 {
205 int diff;
206 const git_index_entry *entry_a = a;
207 const git_index_entry *entry_b = b;
208
209 diff = strcasecmp(entry_a->path, entry_b->path);
210
211 if (diff == 0)
212 diff = (GIT_IDXENTRY_STAGE(entry_a) - GIT_IDXENTRY_STAGE(entry_b));
213
214 return diff;
215 }
216
217 static int conflict_name_cmp(const void *a, const void *b)
218 {
219 const git_index_name_entry *name_a = a;
220 const git_index_name_entry *name_b = b;
221
222 if (name_a->ancestor && !name_b->ancestor)
223 return 1;
224
225 if (!name_a->ancestor && name_b->ancestor)
226 return -1;
227
228 if (name_a->ancestor)
229 return strcmp(name_a->ancestor, name_b->ancestor);
230
231 if (!name_a->ours || !name_b->ours)
232 return 0;
233
234 return strcmp(name_a->ours, name_b->ours);
235 }
236
237 /**
238 * TODO: enable this when resolving case insensitive conflicts
239 */
240 #if 0
241 static int conflict_name_icmp(const void *a, const void *b)
242 {
243 const git_index_name_entry *name_a = a;
244 const git_index_name_entry *name_b = b;
245
246 if (name_a->ancestor && !name_b->ancestor)
247 return 1;
248
249 if (!name_a->ancestor && name_b->ancestor)
250 return -1;
251
252 if (name_a->ancestor)
253 return strcasecmp(name_a->ancestor, name_b->ancestor);
254
255 if (!name_a->ours || !name_b->ours)
256 return 0;
257
258 return strcasecmp(name_a->ours, name_b->ours);
259 }
260 #endif
261
262 static int reuc_srch(const void *key, const void *array_member)
263 {
264 const git_index_reuc_entry *reuc = array_member;
265
266 return strcmp(key, reuc->path);
267 }
268
269 static int reuc_isrch(const void *key, const void *array_member)
270 {
271 const git_index_reuc_entry *reuc = array_member;
272
273 return strcasecmp(key, reuc->path);
274 }
275
276 static int reuc_cmp(const void *a, const void *b)
277 {
278 const git_index_reuc_entry *info_a = a;
279 const git_index_reuc_entry *info_b = b;
280
281 return strcmp(info_a->path, info_b->path);
282 }
283
284 static int reuc_icmp(const void *a, const void *b)
285 {
286 const git_index_reuc_entry *info_a = a;
287 const git_index_reuc_entry *info_b = b;
288
289 return strcasecmp(info_a->path, info_b->path);
290 }
291
292 static void index_entry_reuc_free(git_index_reuc_entry *reuc)
293 {
294 git__free(reuc);
295 }
296
297 static void index_entry_free(git_index_entry *entry)
298 {
299 if (!entry)
300 return;
301
302 memset(&entry->id, 0, sizeof(entry->id));
303 git__free(entry);
304 }
305
306 unsigned int git_index__create_mode(unsigned int mode)
307 {
308 if (S_ISLNK(mode))
309 return S_IFLNK;
310
311 if (S_ISDIR(mode) || (mode & S_IFMT) == (S_IFLNK | S_IFDIR))
312 return (S_IFLNK | S_IFDIR);
313
314 return S_IFREG | GIT_PERMS_CANONICAL(mode);
315 }
316
317 static unsigned int index_merge_mode(
318 git_index *index, git_index_entry *existing, unsigned int mode)
319 {
320 if (index->no_symlinks && S_ISREG(mode) &&
321 existing && S_ISLNK(existing->mode))
322 return existing->mode;
323
324 if (index->distrust_filemode && S_ISREG(mode))
325 return (existing && S_ISREG(existing->mode)) ?
326 existing->mode : git_index__create_mode(0666);
327
328 return git_index__create_mode(mode);
329 }
330
331 static int index_sort_if_needed(git_index *index, bool need_lock)
332 {
333 /* not truly threadsafe because between when this checks and/or
334 * sorts the array another thread could come in and unsort it
335 */
336
337 if (git_vector_is_sorted(&index->entries))
338 return 0;
339
340 if (need_lock && git_mutex_lock(&index->lock) < 0) {
341 giterr_set(GITERR_OS, "Unable to lock index");
342 return -1;
343 }
344
345 git_vector_sort(&index->entries);
346
347 if (need_lock)
348 git_mutex_unlock(&index->lock);
349
350 return 0;
351 }
352
353 GIT_INLINE(int) index_find_in_entries(
354 size_t *out, git_vector *entries, git_vector_cmp entry_srch,
355 const char *path, size_t path_len, int stage)
356 {
357 struct entry_srch_key srch_key;
358 srch_key.path = path;
359 srch_key.pathlen = !path_len ? strlen(path) : path_len;
360 srch_key.stage = stage;
361 return git_vector_bsearch2(out, entries, entry_srch, &srch_key);
362 }
363
364 GIT_INLINE(int) index_find(
365 size_t *out, git_index *index,
366 const char *path, size_t path_len, int stage, bool need_lock)
367 {
368 if (index_sort_if_needed(index, need_lock) < 0)
369 return -1;
370
371 return index_find_in_entries(
372 out, &index->entries, index->entries_search, path, path_len, stage);
373 }
374
375 void git_index__set_ignore_case(git_index *index, bool ignore_case)
376 {
377 index->ignore_case = ignore_case;
378
379 if (ignore_case) {
380 index->entries_cmp_path = git__strcasecmp_cb;
381 index->entries_search = git_index_entry_isrch;
382 index->entries_search_path = index_entry_isrch_path;
383 index->reuc_search = reuc_isrch;
384 } else {
385 index->entries_cmp_path = git__strcmp_cb;
386 index->entries_search = git_index_entry_srch;
387 index->entries_search_path = index_entry_srch_path;
388 index->reuc_search = reuc_srch;
389 }
390
391 git_vector_set_cmp(&index->entries,
392 ignore_case ? git_index_entry_icmp : git_index_entry_cmp);
393 index_sort_if_needed(index, true);
394
395 git_vector_set_cmp(&index->reuc, ignore_case ? reuc_icmp : reuc_cmp);
396 git_vector_sort(&index->reuc);
397 }
398
399 int git_index_open(git_index **index_out, const char *index_path)
400 {
401 git_index *index;
402 int error = -1;
403
404 assert(index_out);
405
406 index = git__calloc(1, sizeof(git_index));
407 GITERR_CHECK_ALLOC(index);
408
409 if (git_mutex_init(&index->lock)) {
410 giterr_set(GITERR_OS, "Failed to initialize lock");
411 git__free(index);
412 return -1;
413 }
414
415 git_pool_init(&index->tree_pool, 1, 0);
416
417 if (index_path != NULL) {
418 index->index_file_path = git__strdup(index_path);
419 if (!index->index_file_path)
420 goto fail;
421
422 /* Check if index file is stored on disk already */
423 if (git_path_exists(index->index_file_path) == true)
424 index->on_disk = 1;
425 }
426
427 if (git_vector_init(&index->entries, 32, git_index_entry_cmp) < 0 ||
428 git_vector_init(&index->names, 8, conflict_name_cmp) < 0 ||
429 git_vector_init(&index->reuc, 8, reuc_cmp) < 0 ||
430 git_vector_init(&index->deleted, 8, git_index_entry_cmp) < 0)
431 goto fail;
432
433 index->entries_cmp_path = git__strcmp_cb;
434 index->entries_search = git_index_entry_srch;
435 index->entries_search_path = index_entry_srch_path;
436 index->reuc_search = reuc_srch;
437
438 if (index_path != NULL && (error = git_index_read(index, true)) < 0)
439 goto fail;
440
441 *index_out = index;
442 GIT_REFCOUNT_INC(index);
443
444 return 0;
445
446 fail:
447 git_pool_clear(&index->tree_pool);
448 git_index_free(index);
449 return error;
450 }
451
452 int git_index_new(git_index **out)
453 {
454 return git_index_open(out, NULL);
455 }
456
457 static void index_free(git_index *index)
458 {
459 /* index iterators increment the refcount of the index, so if we
460 * get here then there should be no outstanding iterators.
461 */
462 assert(!git_atomic_get(&index->readers));
463
464 git_index_clear(index);
465 git_vector_free(&index->entries);
466 git_vector_free(&index->names);
467 git_vector_free(&index->reuc);
468 git_vector_free(&index->deleted);
469
470 git__free(index->index_file_path);
471 git_mutex_free(&index->lock);
472
473 git__memzero(index, sizeof(*index));
474 git__free(index);
475 }
476
477 void git_index_free(git_index *index)
478 {
479 if (index == NULL)
480 return;
481
482 GIT_REFCOUNT_DEC(index, index_free);
483 }
484
485 /* call with locked index */
486 static void index_free_deleted(git_index *index)
487 {
488 int readers = (int)git_atomic_get(&index->readers);
489 size_t i;
490
491 if (readers > 0 || !index->deleted.length)
492 return;
493
494 for (i = 0; i < index->deleted.length; ++i) {
495 git_index_entry *ie = git__swap(index->deleted.contents[i], NULL);
496 index_entry_free(ie);
497 }
498
499 git_vector_clear(&index->deleted);
500 }
501
502 /* call with locked index */
503 static int index_remove_entry(git_index *index, size_t pos)
504 {
505 int error = 0;
506 git_index_entry *entry = git_vector_get(&index->entries, pos);
507
508 if (entry != NULL)
509 git_tree_cache_invalidate_path(index->tree, entry->path);
510
511 error = git_vector_remove(&index->entries, pos);
512
513 if (!error) {
514 if (git_atomic_get(&index->readers) > 0) {
515 error = git_vector_insert(&index->deleted, entry);
516 } else {
517 index_entry_free(entry);
518 }
519 }
520
521 return error;
522 }
523
524 int git_index_clear(git_index *index)
525 {
526 int error = 0;
527
528 assert(index);
529
530 index->tree = NULL;
531 git_pool_clear(&index->tree_pool);
532
533 if (git_mutex_lock(&index->lock) < 0) {
534 giterr_set(GITERR_OS, "Failed to lock index");
535 return -1;
536 }
537
538 while (!error && index->entries.length > 0)
539 error = index_remove_entry(index, index->entries.length - 1);
540 index_free_deleted(index);
541
542 git_index_reuc_clear(index);
543 git_index_name_clear(index);
544
545 git_futils_filestamp_set(&index->stamp, NULL);
546
547 git_mutex_unlock(&index->lock);
548
549 return error;
550 }
551
552 static int create_index_error(int error, const char *msg)
553 {
554 giterr_set(GITERR_INDEX, msg);
555 return error;
556 }
557
558 int git_index_set_caps(git_index *index, int caps)
559 {
560 unsigned int old_ignore_case;
561
562 assert(index);
563
564 old_ignore_case = index->ignore_case;
565
566 if (caps == GIT_INDEXCAP_FROM_OWNER) {
567 git_repository *repo = INDEX_OWNER(index);
568 int val;
569
570 if (!repo)
571 return create_index_error(
572 -1, "Cannot access repository to set index caps");
573
574 if (!git_repository__cvar(&val, repo, GIT_CVAR_IGNORECASE))
575 index->ignore_case = (val != 0);
576 if (!git_repository__cvar(&val, repo, GIT_CVAR_FILEMODE))
577 index->distrust_filemode = (val == 0);
578 if (!git_repository__cvar(&val, repo, GIT_CVAR_SYMLINKS))
579 index->no_symlinks = (val == 0);
580 }
581 else {
582 index->ignore_case = ((caps & GIT_INDEXCAP_IGNORE_CASE) != 0);
583 index->distrust_filemode = ((caps & GIT_INDEXCAP_NO_FILEMODE) != 0);
584 index->no_symlinks = ((caps & GIT_INDEXCAP_NO_SYMLINKS) != 0);
585 }
586
587 if (old_ignore_case != index->ignore_case) {
588 git_index__set_ignore_case(index, (bool)index->ignore_case);
589 }
590
591 return 0;
592 }
593
594 int git_index_caps(const git_index *index)
595 {
596 return ((index->ignore_case ? GIT_INDEXCAP_IGNORE_CASE : 0) |
597 (index->distrust_filemode ? GIT_INDEXCAP_NO_FILEMODE : 0) |
598 (index->no_symlinks ? GIT_INDEXCAP_NO_SYMLINKS : 0));
599 }
600
601 const git_oid *git_index_checksum(git_index *index)
602 {
603 return &index->checksum;
604 }
605
606 /**
607 * Returns 1 for changed, 0 for not changed and <0 for errors
608 */
609 static int compare_checksum(git_index *index)
610 {
611 int fd, error;
612 ssize_t bytes_read;
613 git_oid checksum = {{ 0 }};
614
615 if ((fd = p_open(index->index_file_path, O_RDONLY)) < 0)
616 return fd;
617
618 if ((error = p_lseek(fd, -20, SEEK_END)) < 0) {
619 p_close(fd);
620 giterr_set(GITERR_OS, "failed to seek to end of file");
621 return -1;
622 }
623
624 bytes_read = p_read(fd, &checksum, GIT_OID_RAWSZ);
625 p_close(fd);
626
627 if (bytes_read < 0)
628 return -1;
629
630 return !!git_oid_cmp(&checksum, &index->checksum);
631 }
632
633 int git_index_read(git_index *index, int force)
634 {
635 int error = 0, updated;
636 git_buf buffer = GIT_BUF_INIT;
637 git_futils_filestamp stamp = index->stamp;
638
639 if (!index->index_file_path)
640 return create_index_error(-1,
641 "Failed to read index: The index is in-memory only");
642
643 index->on_disk = git_path_exists(index->index_file_path);
644
645 if (!index->on_disk) {
646 if (force)
647 return git_index_clear(index);
648 return 0;
649 }
650
651 if ((updated = git_futils_filestamp_check(&stamp, index->index_file_path) < 0) ||
652 ((updated = compare_checksum(index)) < 0)) {
653 giterr_set(
654 GITERR_INDEX,
655 "Failed to read index: '%s' no longer exists",
656 index->index_file_path);
657 return updated;
658 }
659 if (!updated && !force)
660 return 0;
661
662 error = git_futils_readbuffer(&buffer, index->index_file_path);
663 if (error < 0)
664 return error;
665
666 index->tree = NULL;
667 git_pool_clear(&index->tree_pool);
668
669 error = git_index_clear(index);
670
671 if (!error)
672 error = parse_index(index, buffer.ptr, buffer.size);
673
674 if (!error)
675 git_futils_filestamp_set(&index->stamp, &stamp);
676
677 git_buf_free(&buffer);
678 return error;
679 }
680
681 int git_index__changed_relative_to(
682 git_index *index, const git_oid *checksum)
683 {
684 /* attempt to update index (ignoring errors) */
685 if (git_index_read(index, false) < 0)
686 giterr_clear();
687
688 return !!git_oid_cmp(&index->checksum, checksum);
689 }
690
691 static bool is_racy_timestamp(git_time_t stamp, git_index_entry *entry)
692 {
693 /* Git special-cases submodules in the check */
694 if (S_ISGITLINK(entry->mode))
695 return false;
696
697 /* If we never read the index, we can't have this race either */
698 if (stamp == 0)
699 return false;
700
701 /* If the timestamp is the same or newer than the index, it's racy */
702 return ((int32_t) stamp) <= entry->mtime.seconds;
703 }
704
705 /*
706 * Force the next diff to take a look at those entries which have the
707 * same timestamp as the current index.
708 */
709 static int truncate_racily_clean(git_index *index)
710 {
711 size_t i;
712 int error;
713 git_index_entry *entry;
714 git_time_t ts = index->stamp.mtime;
715 git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
716 git_diff *diff;
717
718 /* Nothing to do if there's no repo to talk about */
719 if (!INDEX_OWNER(index))
720 return 0;
721
722 /* If there's no workdir, we can't know where to even check */
723 if (!git_repository_workdir(INDEX_OWNER(index)))
724 return 0;
725
726 diff_opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE | GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_DISABLE_PATHSPEC_MATCH;
727 git_vector_foreach(&index->entries, i, entry) {
728 if (!is_racy_timestamp(ts, entry))
729 continue;
730
731 diff_opts.pathspec.count = 1;
732 diff_opts.pathspec.strings = (char **) &entry->path;
733
734 if ((error = git_diff_index_to_workdir(&diff, INDEX_OWNER(index), index, &diff_opts)) < 0)
735 return error;
736
737 if (git_diff_num_deltas(diff) > 0)
738 entry->file_size = 0;
739
740 git_diff_free(diff);
741 }
742
743 return 0;
744 }
745
746 int git_index_write(git_index *index)
747 {
748 git_indexwriter writer = GIT_INDEXWRITER_INIT;
749 int error;
750
751 truncate_racily_clean(index);
752
753 if ((error = git_indexwriter_init(&writer, index)) == 0)
754 error = git_indexwriter_commit(&writer);
755
756 git_indexwriter_cleanup(&writer);
757
758 return error;
759 }
760
761 const char * git_index_path(const git_index *index)
762 {
763 assert(index);
764 return index->index_file_path;
765 }
766
767 int git_index_write_tree(git_oid *oid, git_index *index)
768 {
769 git_repository *repo;
770
771 assert(oid && index);
772
773 repo = INDEX_OWNER(index);
774
775 if (repo == NULL)
776 return create_index_error(-1, "Failed to write tree. "
777 "The index file is not backed up by an existing repository");
778
779 return git_tree__write_index(oid, index, repo);
780 }
781
782 int git_index_write_tree_to(
783 git_oid *oid, git_index *index, git_repository *repo)
784 {
785 assert(oid && index && repo);
786 return git_tree__write_index(oid, index, repo);
787 }
788
789 size_t git_index_entrycount(const git_index *index)
790 {
791 assert(index);
792 return index->entries.length;
793 }
794
795 const git_index_entry *git_index_get_byindex(
796 git_index *index, size_t n)
797 {
798 assert(index);
799 if (index_sort_if_needed(index, true) < 0)
800 return NULL;
801 return git_vector_get(&index->entries, n);
802 }
803
804 const git_index_entry *git_index_get_bypath(
805 git_index *index, const char *path, int stage)
806 {
807 size_t pos;
808
809 assert(index);
810
811 if (index_find(&pos, index, path, 0, stage, true) < 0) {
812 giterr_set(GITERR_INDEX, "Index does not contain %s", path);
813 return NULL;
814 }
815
816 return git_index_get_byindex(index, pos);
817 }
818
819 void git_index_entry__init_from_stat(
820 git_index_entry *entry, struct stat *st, bool trust_mode)
821 {
822 entry->ctime.seconds = (git_time_t)st->st_ctime;
823 entry->mtime.seconds = (git_time_t)st->st_mtime;
824 /* entry->mtime.nanoseconds = st->st_mtimensec; */
825 /* entry->ctime.nanoseconds = st->st_ctimensec; */
826 entry->dev = st->st_rdev;
827 entry->ino = st->st_ino;
828 entry->mode = (!trust_mode && S_ISREG(st->st_mode)) ?
829 git_index__create_mode(0666) : git_index__create_mode(st->st_mode);
830 entry->uid = st->st_uid;
831 entry->gid = st->st_gid;
832 entry->file_size = st->st_size;
833 }
834
835 static int index_entry_create(
836 git_index_entry **out,
837 git_repository *repo,
838 const char *path)
839 {
840 size_t pathlen = strlen(path), alloclen;
841 struct entry_internal *entry;
842
843 if (!git_path_isvalid(repo, path,
844 GIT_PATH_REJECT_DEFAULTS | GIT_PATH_REJECT_DOT_GIT)) {
845 giterr_set(GITERR_INDEX, "Invalid path: '%s'", path);
846 return -1;
847 }
848
849 GITERR_CHECK_ALLOC_ADD(&alloclen, sizeof(struct entry_internal), pathlen);
850 GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
851 entry = git__calloc(1, alloclen);
852 GITERR_CHECK_ALLOC(entry);
853
854 entry->pathlen = pathlen;
855 memcpy(entry->path, path, pathlen);
856 entry->entry.path = entry->path;
857
858 *out = (git_index_entry *)entry;
859 return 0;
860 }
861
862 static int index_entry_init(
863 git_index_entry **entry_out,
864 git_index *index,
865 const char *rel_path)
866 {
867 int error = 0;
868 git_index_entry *entry = NULL;
869 struct stat st;
870 git_oid oid;
871
872 if (INDEX_OWNER(index) == NULL)
873 return create_index_error(-1,
874 "Could not initialize index entry. "
875 "Index is not backed up by an existing repository.");
876
877 if (index_entry_create(&entry, INDEX_OWNER(index), rel_path) < 0)
878 return -1;
879
880 /* write the blob to disk and get the oid and stat info */
881 error = git_blob__create_from_paths(
882 &oid, &st, INDEX_OWNER(index), NULL, rel_path, 0, true);
883
884 if (error < 0) {
885 index_entry_free(entry);
886 return error;
887 }
888
889 entry->id = oid;
890 git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode);
891
892 *entry_out = (git_index_entry *)entry;
893 return 0;
894 }
895
896 static git_index_reuc_entry *reuc_entry_alloc(const char *path)
897 {
898 size_t pathlen = strlen(path),
899 structlen = sizeof(struct reuc_entry_internal),
900 alloclen;
901 struct reuc_entry_internal *entry;
902
903 if (GIT_ADD_SIZET_OVERFLOW(&alloclen, structlen, pathlen) ||
904 GIT_ADD_SIZET_OVERFLOW(&alloclen, alloclen, 1))
905 return NULL;
906
907 entry = git__calloc(1, alloclen);
908 if (!entry)
909 return NULL;
910
911 entry->pathlen = pathlen;
912 memcpy(entry->path, path, pathlen);
913 entry->entry.path = entry->path;
914
915 return (git_index_reuc_entry *)entry;
916 }
917
918 static int index_entry_reuc_init(git_index_reuc_entry **reuc_out,
919 const char *path,
920 int ancestor_mode, const git_oid *ancestor_oid,
921 int our_mode, const git_oid *our_oid,
922 int their_mode, const git_oid *their_oid)
923 {
924 git_index_reuc_entry *reuc = NULL;
925
926 assert(reuc_out && path);
927
928 *reuc_out = reuc = reuc_entry_alloc(path);
929 GITERR_CHECK_ALLOC(reuc);
930
931 if ((reuc->mode[0] = ancestor_mode) > 0)
932 git_oid_cpy(&reuc->oid[0], ancestor_oid);
933
934 if ((reuc->mode[1] = our_mode) > 0)
935 git_oid_cpy(&reuc->oid[1], our_oid);
936
937 if ((reuc->mode[2] = their_mode) > 0)
938 git_oid_cpy(&reuc->oid[2], their_oid);
939
940 return 0;
941 }
942
943 static void index_entry_cpy(git_index_entry *tgt, const git_index_entry *src)
944 {
945 const char *tgt_path = tgt->path;
946 memcpy(tgt, src, sizeof(*tgt));
947 tgt->path = tgt_path; /* reset to existing path data */
948 }
949
950 static int index_entry_dup(
951 git_index_entry **out,
952 git_repository *repo,
953 const git_index_entry *src)
954 {
955 git_index_entry *entry;
956
957 if (!src) {
958 *out = NULL;
959 return 0;
960 }
961
962 if (index_entry_create(&entry, repo, src->path) < 0)
963 return -1;
964
965 index_entry_cpy(entry, src);
966 *out = entry;
967 return 0;
968 }
969
970 static int has_file_name(git_index *index,
971 const git_index_entry *entry, size_t pos, int ok_to_replace)
972 {
973 int retval = 0;
974 size_t len = strlen(entry->path);
975 int stage = GIT_IDXENTRY_STAGE(entry);
976 const char *name = entry->path;
977
978 while (pos < index->entries.length) {
979 struct entry_internal *p = index->entries.contents[pos++];
980
981 if (len >= p->pathlen)
982 break;
983 if (memcmp(name, p->path, len))
984 break;
985 if (GIT_IDXENTRY_STAGE(&p->entry) != stage)
986 continue;
987 if (p->path[len] != '/')
988 continue;
989 retval = -1;
990 if (!ok_to_replace)
991 break;
992
993 if (index_remove_entry(index, --pos) < 0)
994 break;
995 }
996 return retval;
997 }
998
999 /*
1000 * Do we have another file with a pathname that is a proper
1001 * subset of the name we're trying to add?
1002 */
1003 static int has_dir_name(git_index *index,
1004 const git_index_entry *entry, int ok_to_replace)
1005 {
1006 int retval = 0;
1007 int stage = GIT_IDXENTRY_STAGE(entry);
1008 const char *name = entry->path;
1009 const char *slash = name + strlen(name);
1010
1011 for (;;) {
1012 size_t len, pos;
1013
1014 for (;;) {
1015 if (*--slash == '/')
1016 break;
1017 if (slash <= entry->path)
1018 return retval;
1019 }
1020 len = slash - name;
1021
1022 if (!index_find(&pos, index, name, len, stage, false)) {
1023 retval = -1;
1024 if (!ok_to_replace)
1025 break;
1026
1027 if (index_remove_entry(index, pos) < 0)
1028 break;
1029 continue;
1030 }
1031
1032 /*
1033 * Trivial optimization: if we find an entry that
1034 * already matches the sub-directory, then we know
1035 * we're ok, and we can exit.
1036 */
1037 for (; pos < index->entries.length; ++pos) {
1038 struct entry_internal *p = index->entries.contents[pos];
1039
1040 if (p->pathlen <= len ||
1041 p->path[len] != '/' ||
1042 memcmp(p->path, name, len))
1043 break; /* not our subdirectory */
1044
1045 if (GIT_IDXENTRY_STAGE(&p->entry) == stage)
1046 return retval;
1047 }
1048 }
1049
1050 return retval;
1051 }
1052
1053 static int check_file_directory_collision(git_index *index,
1054 git_index_entry *entry, size_t pos, int ok_to_replace)
1055 {
1056 int retval = has_file_name(index, entry, pos, ok_to_replace);
1057 retval = retval + has_dir_name(index, entry, ok_to_replace);
1058
1059 if (retval) {
1060 giterr_set(GITERR_INDEX,
1061 "'%s' appears as both a file and a directory", entry->path);
1062 return -1;
1063 }
1064
1065 return 0;
1066 }
1067
1068 static int index_no_dups(void **old, void *new)
1069 {
1070 const git_index_entry *entry = new;
1071 GIT_UNUSED(old);
1072 giterr_set(GITERR_INDEX, "'%s' appears multiple times at stage %d",
1073 entry->path, GIT_IDXENTRY_STAGE(entry));
1074 return GIT_EEXISTS;
1075 }
1076
1077 /* index_insert takes ownership of the new entry - if it can't insert
1078 * it, then it will return an error **and also free the entry**. When
1079 * it replaces an existing entry, it will update the entry_ptr with the
1080 * actual entry in the index (and free the passed in one).
1081 * trust_mode is whether we trust the mode in entry_ptr.
1082 */
1083 static int index_insert(
1084 git_index *index, git_index_entry **entry_ptr, int replace, bool trust_mode)
1085 {
1086 int error = 0;
1087 size_t path_length, position;
1088 git_index_entry *existing = NULL, *entry;
1089
1090 assert(index && entry_ptr);
1091
1092 entry = *entry_ptr;
1093
1094 /* make sure that the path length flag is correct */
1095 path_length = ((struct entry_internal *)entry)->pathlen;
1096
1097 entry->flags &= ~GIT_IDXENTRY_NAMEMASK;
1098
1099 if (path_length < GIT_IDXENTRY_NAMEMASK)
1100 entry->flags |= path_length & GIT_IDXENTRY_NAMEMASK;
1101 else
1102 entry->flags |= GIT_IDXENTRY_NAMEMASK;
1103
1104 if (git_mutex_lock(&index->lock) < 0) {
1105 giterr_set(GITERR_OS, "Unable to acquire index lock");
1106 return -1;
1107 }
1108
1109 git_vector_sort(&index->entries);
1110
1111 /* look if an entry with this path already exists */
1112 if (!index_find(
1113 &position, index, entry->path, 0, GIT_IDXENTRY_STAGE(entry), false)) {
1114 existing = index->entries.contents[position];
1115 /* update filemode to existing values if stat is not trusted */
1116 if (trust_mode)
1117 entry->mode = git_index__create_mode(entry->mode);
1118 else
1119 entry->mode = index_merge_mode(index, existing, entry->mode);
1120 }
1121
1122 /* look for tree / blob name collisions, removing conflicts if requested */
1123 error = check_file_directory_collision(index, entry, position, replace);
1124 if (error < 0)
1125 /* skip changes */;
1126
1127 /* if we are replacing an existing item, overwrite the existing entry
1128 * and return it in place of the passed in one.
1129 */
1130 else if (existing) {
1131 if (replace)
1132 index_entry_cpy(existing, entry);
1133 index_entry_free(entry);
1134 *entry_ptr = entry = existing;
1135 }
1136 else {
1137 /* if replace is not requested or no existing entry exists, insert
1138 * at the sorted position. (Since we re-sort after each insert to
1139 * check for dups, this is actually cheaper in the long run.)
1140 */
1141 error = git_vector_insert_sorted(&index->entries, entry, index_no_dups);
1142 }
1143
1144 if (error < 0) {
1145 index_entry_free(*entry_ptr);
1146 *entry_ptr = NULL;
1147 }
1148
1149 git_mutex_unlock(&index->lock);
1150
1151 return error;
1152 }
1153
1154 static int index_conflict_to_reuc(git_index *index, const char *path)
1155 {
1156 const git_index_entry *conflict_entries[3];
1157 int ancestor_mode, our_mode, their_mode;
1158 git_oid const *ancestor_oid, *our_oid, *their_oid;
1159 int ret;
1160
1161 if ((ret = git_index_conflict_get(&conflict_entries[0],
1162 &conflict_entries[1], &conflict_entries[2], index, path)) < 0)
1163 return ret;
1164
1165 ancestor_mode = conflict_entries[0] == NULL ? 0 : conflict_entries[0]->mode;
1166 our_mode = conflict_entries[1] == NULL ? 0 : conflict_entries[1]->mode;
1167 their_mode = conflict_entries[2] == NULL ? 0 : conflict_entries[2]->mode;
1168
1169 ancestor_oid = conflict_entries[0] == NULL ? NULL : &conflict_entries[0]->id;
1170 our_oid = conflict_entries[1] == NULL ? NULL : &conflict_entries[1]->id;
1171 their_oid = conflict_entries[2] == NULL ? NULL : &conflict_entries[2]->id;
1172
1173 if ((ret = git_index_reuc_add(index, path, ancestor_mode, ancestor_oid,
1174 our_mode, our_oid, their_mode, their_oid)) >= 0)
1175 ret = git_index_conflict_remove(index, path);
1176
1177 return ret;
1178 }
1179
1180 static bool valid_filemode(const int filemode)
1181 {
1182 return (filemode == GIT_FILEMODE_BLOB ||
1183 filemode == GIT_FILEMODE_BLOB_EXECUTABLE ||
1184 filemode == GIT_FILEMODE_LINK ||
1185 filemode == GIT_FILEMODE_COMMIT);
1186 }
1187
1188 int git_index_add_frombuffer(
1189 git_index *index, const git_index_entry *source_entry,
1190 const void *buffer, size_t len)
1191 {
1192 git_index_entry *entry = NULL;
1193 int error = 0;
1194 git_oid id;
1195
1196 assert(index && source_entry->path);
1197
1198 if (INDEX_OWNER(index) == NULL)
1199 return create_index_error(-1,
1200 "Could not initialize index entry. "
1201 "Index is not backed up by an existing repository.");
1202
1203 if (!valid_filemode(source_entry->mode)) {
1204 giterr_set(GITERR_INDEX, "invalid filemode");
1205 return -1;
1206 }
1207
1208 if (index_entry_dup(&entry, INDEX_OWNER(index), source_entry) < 0)
1209 return -1;
1210
1211 error = git_blob_create_frombuffer(&id, INDEX_OWNER(index), buffer, len);
1212 if (error < 0) {
1213 index_entry_free(entry);
1214 return error;
1215 }
1216
1217 git_oid_cpy(&entry->id, &id);
1218 entry->file_size = len;
1219
1220 if ((error = index_insert(index, &entry, 1, true)) < 0)
1221 return error;
1222
1223 /* Adding implies conflict was resolved, move conflict entries to REUC */
1224 if ((error = index_conflict_to_reuc(index, entry->path)) < 0 && error != GIT_ENOTFOUND)
1225 return error;
1226
1227 git_tree_cache_invalidate_path(index->tree, entry->path);
1228 return 0;
1229 }
1230
1231
1232 int git_index_add_bypath(git_index *index, const char *path)
1233 {
1234 git_index_entry *entry = NULL;
1235 int ret;
1236
1237 assert(index && path);
1238
1239 if ((ret = index_entry_init(&entry, index, path)) < 0 ||
1240 (ret = index_insert(index, &entry, 1, false)) < 0)
1241 return ret;
1242
1243 /* Adding implies conflict was resolved, move conflict entries to REUC */
1244 if ((ret = index_conflict_to_reuc(index, path)) < 0 && ret != GIT_ENOTFOUND)
1245 return ret;
1246
1247 git_tree_cache_invalidate_path(index->tree, entry->path);
1248 return 0;
1249 }
1250
1251 int git_index_remove_bypath(git_index *index, const char *path)
1252 {
1253 int ret;
1254
1255 assert(index && path);
1256
1257 if (((ret = git_index_remove(index, path, 0)) < 0 &&
1258 ret != GIT_ENOTFOUND) ||
1259 ((ret = index_conflict_to_reuc(index, path)) < 0 &&
1260 ret != GIT_ENOTFOUND))
1261 return ret;
1262
1263 if (ret == GIT_ENOTFOUND)
1264 giterr_clear();
1265
1266 return 0;
1267 }
1268
1269
1270 int git_index_add(git_index *index, const git_index_entry *source_entry)
1271 {
1272 git_index_entry *entry = NULL;
1273 int ret;
1274
1275 assert(index && source_entry && source_entry->path);
1276
1277 if (!valid_filemode(source_entry->mode)) {
1278 giterr_set(GITERR_INDEX, "invalid filemode");
1279 return -1;
1280 }
1281
1282 if ((ret = index_entry_dup(&entry, INDEX_OWNER(index), source_entry)) < 0 ||
1283 (ret = index_insert(index, &entry, 1, true)) < 0)
1284 return ret;
1285
1286 git_tree_cache_invalidate_path(index->tree, entry->path);
1287 return 0;
1288 }
1289
1290 int git_index_remove(git_index *index, const char *path, int stage)
1291 {
1292 int error;
1293 size_t position;
1294
1295 if (git_mutex_lock(&index->lock) < 0) {
1296 giterr_set(GITERR_OS, "Failed to lock index");
1297 return -1;
1298 }
1299
1300 if (index_find(&position, index, path, 0, stage, false) < 0) {
1301 giterr_set(
1302 GITERR_INDEX, "Index does not contain %s at stage %d", path, stage);
1303 error = GIT_ENOTFOUND;
1304 } else {
1305 error = index_remove_entry(index, position);
1306 }
1307
1308 git_mutex_unlock(&index->lock);
1309 return error;
1310 }
1311
1312 int git_index_remove_directory(git_index *index, const char *dir, int stage)
1313 {
1314 git_buf pfx = GIT_BUF_INIT;
1315 int error = 0;
1316 size_t pos;
1317 git_index_entry *entry;
1318
1319 if (git_mutex_lock(&index->lock) < 0) {
1320 giterr_set(GITERR_OS, "Failed to lock index");
1321 return -1;
1322 }
1323
1324 if (!(error = git_buf_sets(&pfx, dir)) &&
1325 !(error = git_path_to_dir(&pfx)))
1326 index_find(&pos, index, pfx.ptr, pfx.size, GIT_INDEX_STAGE_ANY, false);
1327
1328 while (!error) {
1329 entry = git_vector_get(&index->entries, pos);
1330 if (!entry || git__prefixcmp(entry->path, pfx.ptr) != 0)
1331 break;
1332
1333 if (GIT_IDXENTRY_STAGE(entry) != stage) {
1334 ++pos;
1335 continue;
1336 }
1337
1338 error = index_remove_entry(index, pos);
1339
1340 /* removed entry at 'pos' so we don't need to increment */
1341 }
1342
1343 git_mutex_unlock(&index->lock);
1344 git_buf_free(&pfx);
1345
1346 return error;
1347 }
1348
1349 int git_index__find_pos(
1350 size_t *out, git_index *index, const char *path, size_t path_len, int stage)
1351 {
1352 assert(index && path);
1353 return index_find(out, index, path, path_len, stage, true);
1354 }
1355
1356 int git_index_find(size_t *at_pos, git_index *index, const char *path)
1357 {
1358 size_t pos;
1359
1360 assert(index && path);
1361
1362 if (git_mutex_lock(&index->lock) < 0) {
1363 giterr_set(GITERR_OS, "Failed to lock index");
1364 return -1;
1365 }
1366
1367 if (git_vector_bsearch2(
1368 &pos, &index->entries, index->entries_search_path, path) < 0) {
1369 git_mutex_unlock(&index->lock);
1370 giterr_set(GITERR_INDEX, "Index does not contain %s", path);
1371 return GIT_ENOTFOUND;
1372 }
1373
1374 /* Since our binary search only looked at path, we may be in the
1375 * middle of a list of stages.
1376 */
1377 for (; pos > 0; --pos) {
1378 const git_index_entry *prev = git_vector_get(&index->entries, pos - 1);
1379
1380 if (index->entries_cmp_path(prev->path, path) != 0)
1381 break;
1382 }
1383
1384 if (at_pos)
1385 *at_pos = pos;
1386
1387 git_mutex_unlock(&index->lock);
1388 return 0;
1389 }
1390
1391 int git_index_conflict_add(git_index *index,
1392 const git_index_entry *ancestor_entry,
1393 const git_index_entry *our_entry,
1394 const git_index_entry *their_entry)
1395 {
1396 git_index_entry *entries[3] = { 0 };
1397 unsigned short i;
1398 int ret = 0;
1399
1400 assert (index);
1401
1402 if ((ret = index_entry_dup(&entries[0], INDEX_OWNER(index), ancestor_entry)) < 0 ||
1403 (ret = index_entry_dup(&entries[1], INDEX_OWNER(index), our_entry)) < 0 ||
1404 (ret = index_entry_dup(&entries[2], INDEX_OWNER(index), their_entry)) < 0)
1405 goto on_error;
1406
1407 /* Validate entries */
1408 for (i = 0; i < 3; i++) {
1409 if (entries[i] && !valid_filemode(entries[i]->mode)) {
1410 giterr_set(GITERR_INDEX, "invalid filemode for stage %d entry",
1411 i);
1412 return -1;
1413 }
1414 }
1415
1416 /* Remove existing index entries for each path */
1417 for (i = 0; i < 3; i++) {
1418 if (entries[i] == NULL)
1419 continue;
1420
1421 if ((ret = git_index_remove(index, entries[i]->path, 0)) != 0) {
1422 if (ret != GIT_ENOTFOUND)
1423 goto on_error;
1424
1425 giterr_clear();
1426 ret = 0;
1427 }
1428 }
1429
1430 /* Add the conflict entries */
1431 for (i = 0; i < 3; i++) {
1432 if (entries[i] == NULL)
1433 continue;
1434
1435 /* Make sure stage is correct */
1436 GIT_IDXENTRY_STAGE_SET(entries[i], i + 1);
1437
1438 if ((ret = index_insert(index, &entries[i], 0, true)) < 0)
1439 goto on_error;
1440
1441 entries[i] = NULL; /* don't free if later entry fails */
1442 }
1443
1444 return 0;
1445
1446 on_error:
1447 for (i = 0; i < 3; i++) {
1448 if (entries[i] != NULL)
1449 index_entry_free(entries[i]);
1450 }
1451
1452 return ret;
1453 }
1454
1455 static int index_conflict__get_byindex(
1456 const git_index_entry **ancestor_out,
1457 const git_index_entry **our_out,
1458 const git_index_entry **their_out,
1459 git_index *index,
1460 size_t n)
1461 {
1462 const git_index_entry *conflict_entry;
1463 const char *path = NULL;
1464 size_t count;
1465 int stage, len = 0;
1466
1467 assert(ancestor_out && our_out && their_out && index);
1468
1469 *ancestor_out = NULL;
1470 *our_out = NULL;
1471 *their_out = NULL;
1472
1473 for (count = git_index_entrycount(index); n < count; ++n) {
1474 conflict_entry = git_vector_get(&index->entries, n);
1475
1476 if (path && index->entries_cmp_path(conflict_entry->path, path) != 0)
1477 break;
1478
1479 stage = GIT_IDXENTRY_STAGE(conflict_entry);
1480 path = conflict_entry->path;
1481
1482 switch (stage) {
1483 case 3:
1484 *their_out = conflict_entry;
1485 len++;
1486 break;
1487 case 2:
1488 *our_out = conflict_entry;
1489 len++;
1490 break;
1491 case 1:
1492 *ancestor_out = conflict_entry;
1493 len++;
1494 break;
1495 default:
1496 break;
1497 };
1498 }
1499
1500 return len;
1501 }
1502
1503 int git_index_conflict_get(
1504 const git_index_entry **ancestor_out,
1505 const git_index_entry **our_out,
1506 const git_index_entry **their_out,
1507 git_index *index,
1508 const char *path)
1509 {
1510 size_t pos;
1511 int len = 0;
1512
1513 assert(ancestor_out && our_out && their_out && index && path);
1514
1515 *ancestor_out = NULL;
1516 *our_out = NULL;
1517 *their_out = NULL;
1518
1519 if (git_index_find(&pos, index, path) < 0)
1520 return GIT_ENOTFOUND;
1521
1522 if ((len = index_conflict__get_byindex(
1523 ancestor_out, our_out, their_out, index, pos)) < 0)
1524 return len;
1525 else if (len == 0)
1526 return GIT_ENOTFOUND;
1527
1528 return 0;
1529 }
1530
1531 static int index_conflict_remove(git_index *index, const char *path)
1532 {
1533 size_t pos = 0;
1534 git_index_entry *conflict_entry;
1535 int error = 0;
1536
1537 if (path != NULL && git_index_find(&pos, index, path) < 0)
1538 return GIT_ENOTFOUND;
1539
1540 if (git_mutex_lock(&index->lock) < 0) {
1541 giterr_set(GITERR_OS, "Unable to lock index");
1542 return -1;
1543 }
1544
1545 while ((conflict_entry = git_vector_get(&index->entries, pos)) != NULL) {
1546
1547 if (path != NULL &&
1548 index->entries_cmp_path(conflict_entry->path, path) != 0)
1549 break;
1550
1551 if (GIT_IDXENTRY_STAGE(conflict_entry) == 0) {
1552 pos++;
1553 continue;
1554 }
1555
1556 if ((error = index_remove_entry(index, pos)) < 0)
1557 break;
1558 }
1559
1560 git_mutex_unlock(&index->lock);
1561
1562 return error;
1563 }
1564
1565 int git_index_conflict_remove(git_index *index, const char *path)
1566 {
1567 assert(index && path);
1568 return index_conflict_remove(index, path);
1569 }
1570
1571 int git_index_conflict_cleanup(git_index *index)
1572 {
1573 assert(index);
1574 return index_conflict_remove(index, NULL);
1575 }
1576
1577 int git_index_has_conflicts(const git_index *index)
1578 {
1579 size_t i;
1580 git_index_entry *entry;
1581
1582 assert(index);
1583
1584 git_vector_foreach(&index->entries, i, entry) {
1585 if (GIT_IDXENTRY_STAGE(entry) > 0)
1586 return 1;
1587 }
1588
1589 return 0;
1590 }
1591
1592 int git_index_conflict_iterator_new(
1593 git_index_conflict_iterator **iterator_out,
1594 git_index *index)
1595 {
1596 git_index_conflict_iterator *it = NULL;
1597
1598 assert(iterator_out && index);
1599
1600 it = git__calloc(1, sizeof(git_index_conflict_iterator));
1601 GITERR_CHECK_ALLOC(it);
1602
1603 it->index = index;
1604
1605 *iterator_out = it;
1606 return 0;
1607 }
1608
1609 int git_index_conflict_next(
1610 const git_index_entry **ancestor_out,
1611 const git_index_entry **our_out,
1612 const git_index_entry **their_out,
1613 git_index_conflict_iterator *iterator)
1614 {
1615 const git_index_entry *entry;
1616 int len;
1617
1618 assert(ancestor_out && our_out && their_out && iterator);
1619
1620 *ancestor_out = NULL;
1621 *our_out = NULL;
1622 *their_out = NULL;
1623
1624 while (iterator->cur < iterator->index->entries.length) {
1625 entry = git_index_get_byindex(iterator->index, iterator->cur);
1626
1627 if (git_index_entry_is_conflict(entry)) {
1628 if ((len = index_conflict__get_byindex(
1629 ancestor_out,
1630 our_out,
1631 their_out,
1632 iterator->index,
1633 iterator->cur)) < 0)
1634 return len;
1635
1636 iterator->cur += len;
1637 return 0;
1638 }
1639
1640 iterator->cur++;
1641 }
1642
1643 return GIT_ITEROVER;
1644 }
1645
1646 void git_index_conflict_iterator_free(git_index_conflict_iterator *iterator)
1647 {
1648 if (iterator == NULL)
1649 return;
1650
1651 git__free(iterator);
1652 }
1653
1654 size_t git_index_name_entrycount(git_index *index)
1655 {
1656 assert(index);
1657 return index->names.length;
1658 }
1659
1660 const git_index_name_entry *git_index_name_get_byindex(
1661 git_index *index, size_t n)
1662 {
1663 assert(index);
1664
1665 git_vector_sort(&index->names);
1666 return git_vector_get(&index->names, n);
1667 }
1668
1669 static void index_name_entry_free(git_index_name_entry *ne)
1670 {
1671 if (!ne)
1672 return;
1673 git__free(ne->ancestor);
1674 git__free(ne->ours);
1675 git__free(ne->theirs);
1676 git__free(ne);
1677 }
1678
1679 int git_index_name_add(git_index *index,
1680 const char *ancestor, const char *ours, const char *theirs)
1681 {
1682 git_index_name_entry *conflict_name;
1683
1684 assert((ancestor && ours) || (ancestor && theirs) || (ours && theirs));
1685
1686 conflict_name = git__calloc(1, sizeof(git_index_name_entry));
1687 GITERR_CHECK_ALLOC(conflict_name);
1688
1689 if ((ancestor && !(conflict_name->ancestor = git__strdup(ancestor))) ||
1690 (ours && !(conflict_name->ours = git__strdup(ours))) ||
1691 (theirs && !(conflict_name->theirs = git__strdup(theirs))) ||
1692 git_vector_insert(&index->names, conflict_name) < 0)
1693 {
1694 index_name_entry_free(conflict_name);
1695 return -1;
1696 }
1697
1698 return 0;
1699 }
1700
1701 void git_index_name_clear(git_index *index)
1702 {
1703 size_t i;
1704 git_index_name_entry *conflict_name;
1705
1706 assert(index);
1707
1708 git_vector_foreach(&index->names, i, conflict_name)
1709 index_name_entry_free(conflict_name);
1710
1711 git_vector_clear(&index->names);
1712 }
1713
1714 size_t git_index_reuc_entrycount(git_index *index)
1715 {
1716 assert(index);
1717 return index->reuc.length;
1718 }
1719
1720 static int index_reuc_insert(
1721 git_index *index,
1722 git_index_reuc_entry *reuc,
1723 int replace)
1724 {
1725 git_index_reuc_entry **existing = NULL;
1726 size_t position;
1727
1728 assert(index && reuc && reuc->path != NULL);
1729
1730 if (!git_index_reuc_find(&position, index, reuc->path))
1731 existing = (git_index_reuc_entry **)&index->reuc.contents[position];
1732
1733 if (!replace || !existing)
1734 return git_vector_insert(&index->reuc, reuc);
1735
1736 /* exists, replace it */
1737 git__free(*existing);
1738 *existing = reuc;
1739
1740 return 0;
1741 }
1742
1743 int git_index_reuc_add(git_index *index, const char *path,
1744 int ancestor_mode, const git_oid *ancestor_oid,
1745 int our_mode, const git_oid *our_oid,
1746 int their_mode, const git_oid *their_oid)
1747 {
1748 git_index_reuc_entry *reuc = NULL;
1749 int error = 0;
1750
1751 assert(index && path);
1752
1753 if ((error = index_entry_reuc_init(&reuc, path, ancestor_mode,
1754 ancestor_oid, our_mode, our_oid, their_mode, their_oid)) < 0 ||
1755 (error = index_reuc_insert(index, reuc, 1)) < 0)
1756 index_entry_reuc_free(reuc);
1757
1758 return error;
1759 }
1760
1761 int git_index_reuc_find(size_t *at_pos, git_index *index, const char *path)
1762 {
1763 return git_vector_bsearch2(at_pos, &index->reuc, index->reuc_search, path);
1764 }
1765
1766 const git_index_reuc_entry *git_index_reuc_get_bypath(
1767 git_index *index, const char *path)
1768 {
1769 size_t pos;
1770 assert(index && path);
1771
1772 if (!index->reuc.length)
1773 return NULL;
1774
1775 git_vector_sort(&index->reuc);
1776
1777 if (git_index_reuc_find(&pos, index, path) < 0)
1778 return NULL;
1779
1780 return git_vector_get(&index->reuc, pos);
1781 }
1782
1783 const git_index_reuc_entry *git_index_reuc_get_byindex(
1784 git_index *index, size_t n)
1785 {
1786 assert(index);
1787
1788 git_vector_sort(&index->reuc);
1789 return git_vector_get(&index->reuc, n);
1790 }
1791
1792 int git_index_reuc_remove(git_index *index, size_t position)
1793 {
1794 int error;
1795 git_index_reuc_entry *reuc;
1796
1797 git_vector_sort(&index->reuc);
1798
1799 reuc = git_vector_get(&index->reuc, position);
1800 error = git_vector_remove(&index->reuc, position);
1801
1802 if (!error)
1803 index_entry_reuc_free(reuc);
1804
1805 return error;
1806 }
1807
1808 void git_index_reuc_clear(git_index *index)
1809 {
1810 size_t i;
1811
1812 assert(index);
1813
1814 for (i = 0; i < index->reuc.length; ++i)
1815 index_entry_reuc_free(git__swap(index->reuc.contents[i], NULL));
1816
1817 git_vector_clear(&index->reuc);
1818 }
1819
1820 static int index_error_invalid(const char *message)
1821 {
1822 giterr_set(GITERR_INDEX, "Invalid data in index - %s", message);
1823 return -1;
1824 }
1825
1826 static int read_reuc(git_index *index, const char *buffer, size_t size)
1827 {
1828 const char *endptr;
1829 size_t len;
1830 int i;
1831
1832 /* If called multiple times, the vector might already be initialized */
1833 if (index->reuc._alloc_size == 0 &&
1834 git_vector_init(&index->reuc, 16, reuc_cmp) < 0)
1835 return -1;
1836
1837 while (size) {
1838 git_index_reuc_entry *lost;
1839
1840 len = p_strnlen(buffer, size) + 1;
1841 if (size <= len)
1842 return index_error_invalid("reading reuc entries");
1843
1844 lost = reuc_entry_alloc(buffer);
1845 GITERR_CHECK_ALLOC(lost);
1846
1847 size -= len;
1848 buffer += len;
1849
1850 /* read 3 ASCII octal numbers for stage entries */
1851 for (i = 0; i < 3; i++) {
1852 int tmp;
1853
1854 if (git__strtol32(&tmp, buffer, &endptr, 8) < 0 ||
1855 !endptr || endptr == buffer || *endptr ||
1856 (unsigned)tmp > UINT_MAX) {
1857 index_entry_reuc_free(lost);
1858 return index_error_invalid("reading reuc entry stage");
1859 }
1860
1861 lost->mode[i] = tmp;
1862
1863 len = (endptr + 1) - buffer;
1864 if (size <= len) {
1865 index_entry_reuc_free(lost);
1866 return index_error_invalid("reading reuc entry stage");
1867 }
1868
1869 size -= len;
1870 buffer += len;
1871 }
1872
1873 /* read up to 3 OIDs for stage entries */
1874 for (i = 0; i < 3; i++) {
1875 if (!lost->mode[i])
1876 continue;
1877 if (size < 20) {
1878 index_entry_reuc_free(lost);
1879 return index_error_invalid("reading reuc entry oid");
1880 }
1881
1882 git_oid_fromraw(&lost->oid[i], (const unsigned char *) buffer);
1883 size -= 20;
1884 buffer += 20;
1885 }
1886
1887 /* entry was read successfully - insert into reuc vector */
1888 if (git_vector_insert(&index->reuc, lost) < 0)
1889 return -1;
1890 }
1891
1892 /* entries are guaranteed to be sorted on-disk */
1893 git_vector_set_sorted(&index->reuc, true);
1894
1895 return 0;
1896 }
1897
1898
1899 static int read_conflict_names(git_index *index, const char *buffer, size_t size)
1900 {
1901 size_t len;
1902
1903 /* This gets called multiple times, the vector might already be initialized */
1904 if (index->names._alloc_size == 0 &&
1905 git_vector_init(&index->names, 16, conflict_name_cmp) < 0)
1906 return -1;
1907
1908 #define read_conflict_name(ptr) \
1909 len = p_strnlen(buffer, size) + 1; \
1910 if (size < len) \
1911 return index_error_invalid("reading conflict name entries"); \
1912 \
1913 if (len == 1) \
1914 ptr = NULL; \
1915 else { \
1916 ptr = git__malloc(len); \
1917 GITERR_CHECK_ALLOC(ptr); \
1918 memcpy(ptr, buffer, len); \
1919 } \
1920 \
1921 buffer += len; \
1922 size -= len;
1923
1924 while (size) {
1925 git_index_name_entry *conflict_name = git__calloc(1, sizeof(git_index_name_entry));
1926 GITERR_CHECK_ALLOC(conflict_name);
1927
1928 read_conflict_name(conflict_name->ancestor);
1929 read_conflict_name(conflict_name->ours);
1930 read_conflict_name(conflict_name->theirs);
1931
1932 if (git_vector_insert(&index->names, conflict_name) < 0)
1933 return -1;
1934 }
1935
1936 #undef read_conflict_name
1937
1938 /* entries are guaranteed to be sorted on-disk */
1939 git_vector_set_sorted(&index->names, true);
1940
1941 return 0;
1942 }
1943
1944 static size_t read_entry(
1945 git_index_entry **out,
1946 git_index *index,
1947 const void *buffer,
1948 size_t buffer_size)
1949 {
1950 size_t path_length, entry_size;
1951 const char *path_ptr;
1952 struct entry_short source;
1953 git_index_entry entry = {{0}};
1954
1955 if (INDEX_FOOTER_SIZE + minimal_entry_size > buffer_size)
1956 return 0;
1957
1958 /* buffer is not guaranteed to be aligned */
1959 memcpy(&source, buffer, sizeof(struct entry_short));
1960
1961 entry.ctime.seconds = (git_time_t)ntohl(source.ctime.seconds);
1962 entry.ctime.nanoseconds = ntohl(source.ctime.nanoseconds);
1963 entry.mtime.seconds = (git_time_t)ntohl(source.mtime.seconds);
1964 entry.mtime.nanoseconds = ntohl(source.mtime.nanoseconds);
1965 entry.dev = ntohl(source.dev);
1966 entry.ino = ntohl(source.ino);
1967 entry.mode = ntohl(source.mode);
1968 entry.uid = ntohl(source.uid);
1969 entry.gid = ntohl(source.gid);
1970 entry.file_size = ntohl(source.file_size);
1971 git_oid_cpy(&entry.id, &source.oid);
1972 entry.flags = ntohs(source.flags);
1973
1974 if (entry.flags & GIT_IDXENTRY_EXTENDED) {
1975 uint16_t flags_raw;
1976 size_t flags_offset;
1977
1978 flags_offset = offsetof(struct entry_long, flags_extended);
1979 memcpy(&flags_raw, (const char *) buffer + flags_offset,
1980 sizeof(flags_raw));
1981 flags_raw = ntohs(flags_raw);
1982
1983 memcpy(&entry.flags_extended, &flags_raw, sizeof(flags_raw));
1984 path_ptr = (const char *) buffer + offsetof(struct entry_long, path);
1985 } else
1986 path_ptr = (const char *) buffer + offsetof(struct entry_short, path);
1987
1988 path_length = entry.flags & GIT_IDXENTRY_NAMEMASK;
1989
1990 /* if this is a very long string, we must find its
1991 * real length without overflowing */
1992 if (path_length == 0xFFF) {
1993 const char *path_end;
1994
1995 path_end = memchr(path_ptr, '\0', buffer_size);
1996 if (path_end == NULL)
1997 return 0;
1998
1999 path_length = path_end - path_ptr;
2000 }
2001
2002 if (entry.flags & GIT_IDXENTRY_EXTENDED)
2003 entry_size = long_entry_size(path_length);
2004 else
2005 entry_size = short_entry_size(path_length);
2006
2007 if (INDEX_FOOTER_SIZE + entry_size > buffer_size)
2008 return 0;
2009
2010 entry.path = (char *)path_ptr;
2011
2012 if (index_entry_dup(out, INDEX_OWNER(index), &entry) < 0)
2013 return 0;
2014
2015 return entry_size;
2016 }
2017
2018 static int read_header(struct index_header *dest, const void *buffer)
2019 {
2020 const struct index_header *source = buffer;
2021
2022 dest->signature = ntohl(source->signature);
2023 if (dest->signature != INDEX_HEADER_SIG)
2024 return index_error_invalid("incorrect header signature");
2025
2026 dest->version = ntohl(source->version);
2027 if (dest->version != INDEX_VERSION_NUMBER_EXT &&
2028 dest->version != INDEX_VERSION_NUMBER)
2029 return index_error_invalid("incorrect header version");
2030
2031 dest->entry_count = ntohl(source->entry_count);
2032 return 0;
2033 }
2034
2035 static size_t read_extension(git_index *index, const char *buffer, size_t buffer_size)
2036 {
2037 struct index_extension dest;
2038 size_t total_size;
2039
2040 /* buffer is not guaranteed to be aligned */
2041 memcpy(&dest, buffer, sizeof(struct index_extension));
2042 dest.extension_size = ntohl(dest.extension_size);
2043
2044 total_size = dest.extension_size + sizeof(struct index_extension);
2045
2046 if (dest.extension_size > total_size ||
2047 buffer_size < total_size ||
2048 buffer_size - total_size < INDEX_FOOTER_SIZE)
2049 return 0;
2050
2051 /* optional extension */
2052 if (dest.signature[0] >= 'A' && dest.signature[0] <= 'Z') {
2053 /* tree cache */
2054 if (memcmp(dest.signature, INDEX_EXT_TREECACHE_SIG, 4) == 0) {
2055 if (git_tree_cache_read(&index->tree, buffer + 8, dest.extension_size, &index->tree_pool) < 0)
2056 return 0;
2057 } else if (memcmp(dest.signature, INDEX_EXT_UNMERGED_SIG, 4) == 0) {
2058 if (read_reuc(index, buffer + 8, dest.extension_size) < 0)
2059 return 0;
2060 } else if (memcmp(dest.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4) == 0) {
2061 if (read_conflict_names(index, buffer + 8, dest.extension_size) < 0)
2062 return 0;
2063 }
2064 /* else, unsupported extension. We cannot parse this, but we can skip
2065 * it by returning `total_size */
2066 } else {
2067 /* we cannot handle non-ignorable extensions;
2068 * in fact they aren't even defined in the standard */
2069 return 0;
2070 }
2071
2072 return total_size;
2073 }
2074
2075 static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
2076 {
2077 int error = 0;
2078 unsigned int i;
2079 struct index_header header = { 0 };
2080 git_oid checksum_calculated, checksum_expected;
2081
2082 #define seek_forward(_increase) { \
2083 if (_increase >= buffer_size) { \
2084 error = index_error_invalid("ran out of data while parsing"); \
2085 goto done; } \
2086 buffer += _increase; \
2087 buffer_size -= _increase;\
2088 }
2089
2090 if (buffer_size < INDEX_HEADER_SIZE + INDEX_FOOTER_SIZE)
2091 return index_error_invalid("insufficient buffer space");
2092
2093 /* Precalculate the SHA1 of the files's contents -- we'll match it to
2094 * the provided SHA1 in the footer */
2095 git_hash_buf(&checksum_calculated, buffer, buffer_size - INDEX_FOOTER_SIZE);
2096
2097 /* Parse header */
2098 if ((error = read_header(&header, buffer)) < 0)
2099 return error;
2100
2101 seek_forward(INDEX_HEADER_SIZE);
2102
2103 if (git_mutex_lock(&index->lock) < 0) {
2104 giterr_set(GITERR_OS, "Unable to acquire index lock");
2105 return -1;
2106 }
2107
2108 assert(!index->entries.length);
2109
2110 /* Parse all the entries */
2111 for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) {
2112 git_index_entry *entry;
2113 size_t entry_size = read_entry(&entry, index, buffer, buffer_size);
2114
2115 /* 0 bytes read means an object corruption */
2116 if (entry_size == 0) {
2117 error = index_error_invalid("invalid entry");
2118 goto done;
2119 }
2120
2121 if ((error = git_vector_insert(&index->entries, entry)) < 0) {
2122 index_entry_free(entry);
2123 goto done;
2124 }
2125
2126 seek_forward(entry_size);
2127 }
2128
2129 if (i != header.entry_count) {
2130 error = index_error_invalid("header entries changed while parsing");
2131 goto done;
2132 }
2133
2134 /* There's still space for some extensions! */
2135 while (buffer_size > INDEX_FOOTER_SIZE) {
2136 size_t extension_size;
2137
2138 extension_size = read_extension(index, buffer, buffer_size);
2139
2140 /* see if we have read any bytes from the extension */
2141 if (extension_size == 0) {
2142 error = index_error_invalid("extension is truncated");
2143 goto done;
2144 }
2145
2146 seek_forward(extension_size);
2147 }
2148
2149 if (buffer_size != INDEX_FOOTER_SIZE) {
2150 error = index_error_invalid(
2151 "buffer size does not match index footer size");
2152 goto done;
2153 }
2154
2155 /* 160-bit SHA-1 over the content of the index file before this checksum. */
2156 git_oid_fromraw(&checksum_expected, (const unsigned char *)buffer);
2157
2158 if (git_oid__cmp(&checksum_calculated, &checksum_expected) != 0) {
2159 error = index_error_invalid(
2160 "calculated checksum does not match expected");
2161 goto done;
2162 }
2163
2164 git_oid_cpy(&index->checksum, &checksum_calculated);
2165
2166 #undef seek_forward
2167
2168 /* Entries are stored case-sensitively on disk, so re-sort now if
2169 * in-memory index is supposed to be case-insensitive
2170 */
2171 git_vector_set_sorted(&index->entries, !index->ignore_case);
2172 error = index_sort_if_needed(index, false);
2173
2174 done:
2175 git_mutex_unlock(&index->lock);
2176 return error;
2177 }
2178
2179 static bool is_index_extended(git_index *index)
2180 {
2181 size_t i, extended;
2182 git_index_entry *entry;
2183
2184 extended = 0;
2185
2186 git_vector_foreach(&index->entries, i, entry) {
2187 entry->flags &= ~GIT_IDXENTRY_EXTENDED;
2188 if (entry->flags_extended & GIT_IDXENTRY_EXTENDED_FLAGS) {
2189 extended++;
2190 entry->flags |= GIT_IDXENTRY_EXTENDED;
2191 }
2192 }
2193
2194 return (extended > 0);
2195 }
2196
2197 static int write_disk_entry(git_filebuf *file, git_index_entry *entry)
2198 {
2199 void *mem = NULL;
2200 struct entry_short *ondisk;
2201 size_t path_len, disk_size;
2202 char *path;
2203
2204 path_len = ((struct entry_internal *)entry)->pathlen;
2205
2206 if (entry->flags & GIT_IDXENTRY_EXTENDED)
2207 disk_size = long_entry_size(path_len);
2208 else
2209 disk_size = short_entry_size(path_len);
2210
2211 if (git_filebuf_reserve(file, &mem, disk_size) < 0)
2212 return -1;
2213
2214 ondisk = (struct entry_short *)mem;
2215
2216 memset(ondisk, 0x0, disk_size);
2217
2218 /**
2219 * Yes, we have to truncate.
2220 *
2221 * The on-disk format for Index entries clearly defines
2222 * the time and size fields to be 4 bytes each -- so even if
2223 * we store these values with 8 bytes on-memory, they must
2224 * be truncated to 4 bytes before writing to disk.
2225 *
2226 * In 2038 I will be either too dead or too rich to care about this
2227 */
2228 ondisk->ctime.seconds = htonl((uint32_t)entry->ctime.seconds);
2229 ondisk->mtime.seconds = htonl((uint32_t)entry->mtime.seconds);
2230 ondisk->ctime.nanoseconds = htonl(entry->ctime.nanoseconds);
2231 ondisk->mtime.nanoseconds = htonl(entry->mtime.nanoseconds);
2232 ondisk->dev = htonl(entry->dev);
2233 ondisk->ino = htonl(entry->ino);
2234 ondisk->mode = htonl(entry->mode);
2235 ondisk->uid = htonl(entry->uid);
2236 ondisk->gid = htonl(entry->gid);
2237 ondisk->file_size = htonl((uint32_t)entry->file_size);
2238
2239 git_oid_cpy(&ondisk->oid, &entry->id);
2240
2241 ondisk->flags = htons(entry->flags);
2242
2243 if (entry->flags & GIT_IDXENTRY_EXTENDED) {
2244 struct entry_long *ondisk_ext;
2245 ondisk_ext = (struct entry_long *)ondisk;
2246 ondisk_ext->flags_extended = htons(entry->flags_extended);
2247 path = ondisk_ext->path;
2248 }
2249 else
2250 path = ondisk->path;
2251
2252 memcpy(path, entry->path, path_len);
2253
2254 return 0;
2255 }
2256
2257 static int write_entries(git_index *index, git_filebuf *file)
2258 {
2259 int error = 0;
2260 size_t i;
2261 git_vector case_sorted, *entries;
2262 git_index_entry *entry;
2263
2264 if (git_mutex_lock(&index->lock) < 0) {
2265 giterr_set(GITERR_OS, "Failed to lock index");
2266 return -1;
2267 }
2268
2269 /* If index->entries is sorted case-insensitively, then we need
2270 * to re-sort it case-sensitively before writing */
2271 if (index->ignore_case) {
2272 git_vector_dup(&case_sorted, &index->entries, git_index_entry_cmp);
2273 git_vector_sort(&case_sorted);
2274 entries = &case_sorted;
2275 } else {
2276 entries = &index->entries;
2277 }
2278
2279 git_vector_foreach(entries, i, entry)
2280 if ((error = write_disk_entry(file, entry)) < 0)
2281 break;
2282
2283 git_mutex_unlock(&index->lock);
2284
2285 if (index->ignore_case)
2286 git_vector_free(&case_sorted);
2287
2288 return error;
2289 }
2290
2291 static int write_extension(git_filebuf *file, struct index_extension *header, git_buf *data)
2292 {
2293 struct index_extension ondisk;
2294
2295 memset(&ondisk, 0x0, sizeof(struct index_extension));
2296 memcpy(&ondisk, header, 4);
2297 ondisk.extension_size = htonl(header->extension_size);
2298
2299 git_filebuf_write(file, &ondisk, sizeof(struct index_extension));
2300 return git_filebuf_write(file, data->ptr, data->size);
2301 }
2302
2303 static int create_name_extension_data(git_buf *name_buf, git_index_name_entry *conflict_name)
2304 {
2305 int error = 0;
2306
2307 if (conflict_name->ancestor == NULL)
2308 error = git_buf_put(name_buf, "\0", 1);
2309 else
2310 error = git_buf_put(name_buf, conflict_name->ancestor, strlen(conflict_name->ancestor) + 1);
2311
2312 if (error != 0)
2313 goto on_error;
2314
2315 if (conflict_name->ours == NULL)
2316 error = git_buf_put(name_buf, "\0", 1);
2317 else
2318 error = git_buf_put(name_buf, conflict_name->ours, strlen(conflict_name->ours) + 1);
2319
2320 if (error != 0)
2321 goto on_error;
2322
2323 if (conflict_name->theirs == NULL)
2324 error = git_buf_put(name_buf, "\0", 1);
2325 else
2326 error = git_buf_put(name_buf, conflict_name->theirs, strlen(conflict_name->theirs) + 1);
2327
2328 on_error:
2329 return error;
2330 }
2331
2332 static int write_name_extension(git_index *index, git_filebuf *file)
2333 {
2334 git_buf name_buf = GIT_BUF_INIT;
2335 git_vector *out = &index->names;
2336 git_index_name_entry *conflict_name;
2337 struct index_extension extension;
2338 size_t i;
2339 int error = 0;
2340
2341 git_vector_foreach(out, i, conflict_name) {
2342 if ((error = create_name_extension_data(&name_buf, conflict_name)) < 0)
2343 goto done;
2344 }
2345
2346 memset(&extension, 0x0, sizeof(struct index_extension));
2347 memcpy(&extension.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4);
2348 extension.extension_size = (uint32_t)name_buf.size;
2349
2350 error = write_extension(file, &extension, &name_buf);
2351
2352 git_buf_free(&name_buf);
2353
2354 done:
2355 return error;
2356 }
2357
2358 static int create_reuc_extension_data(git_buf *reuc_buf, git_index_reuc_entry *reuc)
2359 {
2360 int i;
2361 int error = 0;
2362
2363 if ((error = git_buf_put(reuc_buf, reuc->path, strlen(reuc->path) + 1)) < 0)
2364 return error;
2365
2366 for (i = 0; i < 3; i++) {
2367 if ((error = git_buf_printf(reuc_buf, "%o", reuc->mode[i])) < 0 ||
2368 (error = git_buf_put(reuc_buf, "\0", 1)) < 0)
2369 return error;
2370 }
2371
2372 for (i = 0; i < 3; i++) {
2373 if (reuc->mode[i] && (error = git_buf_put(reuc_buf, (char *)&reuc->oid[i].id, GIT_OID_RAWSZ)) < 0)
2374 return error;
2375 }
2376
2377 return 0;
2378 }
2379
2380 static int write_reuc_extension(git_index *index, git_filebuf *file)
2381 {
2382 git_buf reuc_buf = GIT_BUF_INIT;
2383 git_vector *out = &index->reuc;
2384 git_index_reuc_entry *reuc;
2385 struct index_extension extension;
2386 size_t i;
2387 int error = 0;
2388
2389 git_vector_foreach(out, i, reuc) {
2390 if ((error = create_reuc_extension_data(&reuc_buf, reuc)) < 0)
2391 goto done;
2392 }
2393
2394 memset(&extension, 0x0, sizeof(struct index_extension));
2395 memcpy(&extension.signature, INDEX_EXT_UNMERGED_SIG, 4);
2396 extension.extension_size = (uint32_t)reuc_buf.size;
2397
2398 error = write_extension(file, &extension, &reuc_buf);
2399
2400 git_buf_free(&reuc_buf);
2401
2402 done:
2403 return error;
2404 }
2405
2406 static int write_tree_extension(git_index *index, git_filebuf *file)
2407 {
2408 struct index_extension extension;
2409 git_buf buf = GIT_BUF_INIT;
2410 int error;
2411
2412 if (index->tree == NULL)
2413 return 0;
2414
2415 if ((error = git_tree_cache_write(&buf, index->tree)) < 0)
2416 return error;
2417
2418 memset(&extension, 0x0, sizeof(struct index_extension));
2419 memcpy(&extension.signature, INDEX_EXT_TREECACHE_SIG, 4);
2420 extension.extension_size = (uint32_t)buf.size;
2421
2422 error = write_extension(file, &extension, &buf);
2423
2424 git_buf_free(&buf);
2425
2426 return error;
2427 }
2428
2429 static int write_index(git_oid *checksum, git_index *index, git_filebuf *file)
2430 {
2431 git_oid hash_final;
2432 struct index_header header;
2433 bool is_extended;
2434 uint32_t index_version_number;
2435
2436 assert(index && file);
2437
2438 is_extended = is_index_extended(index);
2439 index_version_number = is_extended ? INDEX_VERSION_NUMBER_EXT : INDEX_VERSION_NUMBER;
2440
2441 header.signature = htonl(INDEX_HEADER_SIG);
2442 header.version = htonl(index_version_number);
2443 header.entry_count = htonl((uint32_t)index->entries.length);
2444
2445 if (git_filebuf_write(file, &header, sizeof(struct index_header)) < 0)
2446 return -1;
2447
2448 if (write_entries(index, file) < 0)
2449 return -1;
2450
2451 /* write the tree cache extension */
2452 if (index->tree != NULL && write_tree_extension(index, file) < 0)
2453 return -1;
2454
2455 /* write the rename conflict extension */
2456 if (index->names.length > 0 && write_name_extension(index, file) < 0)
2457 return -1;
2458
2459 /* write the reuc extension */
2460 if (index->reuc.length > 0 && write_reuc_extension(index, file) < 0)
2461 return -1;
2462
2463 /* get out the hash for all the contents we've appended to the file */
2464 git_filebuf_hash(&hash_final, file);
2465 git_oid_cpy(checksum, &hash_final);
2466
2467 /* write it at the end of the file */
2468 return git_filebuf_write(file, hash_final.id, GIT_OID_RAWSZ);
2469 }
2470
2471 int git_index_entry_stage(const git_index_entry *entry)
2472 {
2473 return GIT_IDXENTRY_STAGE(entry);
2474 }
2475
2476 int git_index_entry_is_conflict(const git_index_entry *entry)
2477 {
2478 return (GIT_IDXENTRY_STAGE(entry) > 0);
2479 }
2480
2481 typedef struct read_tree_data {
2482 git_index *index;
2483 git_vector *old_entries;
2484 git_vector *new_entries;
2485 git_vector_cmp entry_cmp;
2486 git_tree_cache *tree;
2487 } read_tree_data;
2488
2489 static int read_tree_cb(
2490 const char *root, const git_tree_entry *tentry, void *payload)
2491 {
2492 read_tree_data *data = payload;
2493 git_index_entry *entry = NULL, *old_entry;
2494 git_buf path = GIT_BUF_INIT;
2495 size_t pos;
2496
2497 if (git_tree_entry__is_tree(tentry))
2498 return 0;
2499
2500 if (git_buf_joinpath(&path, root, tentry->filename) < 0)
2501 return -1;
2502
2503 if (index_entry_create(&entry, INDEX_OWNER(data->index), path.ptr) < 0)
2504 return -1;
2505
2506 entry->mode = tentry->attr;
2507 entry->id = tentry->oid;
2508
2509 /* look for corresponding old entry and copy data to new entry */
2510 if (data->old_entries != NULL &&
2511 !index_find_in_entries(
2512 &pos, data->old_entries, data->entry_cmp, path.ptr, 0, 0) &&
2513 (old_entry = git_vector_get(data->old_entries, pos)) != NULL &&
2514 entry->mode == old_entry->mode &&
2515 git_oid_equal(&entry->id, &old_entry->id))
2516 {
2517 index_entry_cpy(entry, old_entry);
2518 entry->flags_extended = 0;
2519 }
2520
2521 if (path.size < GIT_IDXENTRY_NAMEMASK)
2522 entry->flags = path.size & GIT_IDXENTRY_NAMEMASK;
2523 else
2524 entry->flags = GIT_IDXENTRY_NAMEMASK;
2525
2526 git_buf_free(&path);
2527
2528 if (git_vector_insert(data->new_entries, entry) < 0) {
2529 index_entry_free(entry);
2530 return -1;
2531 }
2532
2533 return 0;
2534 }
2535
2536 int git_index_read_tree(git_index *index, const git_tree *tree)
2537 {
2538 int error = 0;
2539 git_vector entries = GIT_VECTOR_INIT;
2540 read_tree_data data;
2541
2542 git_vector_set_cmp(&entries, index->entries._cmp); /* match sort */
2543
2544 data.index = index;
2545 data.old_entries = &index->entries;
2546 data.new_entries = &entries;
2547 data.entry_cmp = index->entries_search;
2548
2549 index->tree = NULL;
2550 git_pool_clear(&index->tree_pool);
2551
2552 if (index_sort_if_needed(index, true) < 0)
2553 return -1;
2554
2555 error = git_tree_walk(tree, GIT_TREEWALK_POST, read_tree_cb, &data);
2556
2557 if (!error) {
2558 git_vector_sort(&entries);
2559
2560 if ((error = git_index_clear(index)) < 0)
2561 /* well, this isn't good */;
2562 else if (git_mutex_lock(&index->lock) < 0) {
2563 giterr_set(GITERR_OS, "Unable to acquire index lock");
2564 error = -1;
2565 } else {
2566 git_vector_swap(&entries, &index->entries);
2567 git_mutex_unlock(&index->lock);
2568 }
2569 }
2570
2571 git_vector_free(&entries);
2572 if (error < 0)
2573 return error;
2574
2575 error = git_tree_cache_read_tree(&index->tree, tree, &index->tree_pool);
2576
2577 return error;
2578 }
2579
2580 int git_index_read_index(
2581 git_index *index,
2582 const git_index *new_index)
2583 {
2584 git_vector new_entries = GIT_VECTOR_INIT,
2585 remove_entries = GIT_VECTOR_INIT;
2586 git_iterator *index_iterator = NULL;
2587 git_iterator *new_iterator = NULL;
2588 const git_index_entry *old_entry, *new_entry;
2589 git_index_entry *entry;
2590 size_t i;
2591 int error;
2592
2593 if ((error = git_vector_init(&new_entries, new_index->entries.length, index->entries._cmp)) < 0 ||
2594 (error = git_vector_init(&remove_entries, index->entries.length, NULL)) < 0)
2595 goto done;
2596
2597 if ((error = git_iterator_for_index(&index_iterator,
2598 index, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
2599 (error = git_iterator_for_index(&new_iterator,
2600 (git_index *)new_index, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0)
2601 goto done;
2602
2603 if (((error = git_iterator_current(&old_entry, index_iterator)) < 0 &&
2604 error != GIT_ITEROVER) ||
2605 ((error = git_iterator_current(&new_entry, new_iterator)) < 0 &&
2606 error != GIT_ITEROVER))
2607 goto done;
2608
2609 while (true) {
2610 int diff;
2611
2612 if (old_entry && new_entry)
2613 diff = git_index_entry_cmp(old_entry, new_entry);
2614 else if (!old_entry && new_entry)
2615 diff = 1;
2616 else if (old_entry && !new_entry)
2617 diff = -1;
2618 else
2619 break;
2620
2621 if (diff < 0) {
2622 git_vector_insert(&remove_entries, (git_index_entry *)old_entry);
2623 } else if (diff > 0) {
2624 if ((error = index_entry_dup(&entry, git_index_owner(index), new_entry)) < 0)
2625 goto done;
2626
2627 git_vector_insert(&new_entries, entry);
2628 } else {
2629 /* Path and stage are equal, if the OID is equal, keep it to
2630 * keep the stat cache data.
2631 */
2632 if (git_oid_equal(&old_entry->id, &new_entry->id)) {
2633 git_vector_insert(&new_entries, (git_index_entry *)old_entry);
2634 } else {
2635 if ((error = index_entry_dup(&entry, git_index_owner(index), new_entry)) < 0)
2636 goto done;
2637
2638 git_vector_insert(&new_entries, entry);
2639 git_vector_insert(&remove_entries, (git_index_entry *)old_entry);
2640 }
2641 }
2642
2643 if (diff <= 0) {
2644 if ((error = git_iterator_advance(&old_entry, index_iterator)) < 0 &&
2645 error != GIT_ITEROVER)
2646 goto done;
2647 }
2648
2649 if (diff >= 0) {
2650 if ((error = git_iterator_advance(&new_entry, new_iterator)) < 0 &&
2651 error != GIT_ITEROVER)
2652 goto done;
2653 }
2654 }
2655
2656 git_index_name_clear(index);
2657 git_index_reuc_clear(index);
2658
2659 git_vector_swap(&new_entries, &index->entries);
2660
2661 git_vector_foreach(&remove_entries, i, entry) {
2662 if (index->tree)
2663 git_tree_cache_invalidate_path(index->tree, entry->path);
2664
2665 index_entry_free(entry);
2666 }
2667
2668 error = 0;
2669
2670 done:
2671 git_vector_free(&new_entries);
2672 git_vector_free(&remove_entries);
2673 git_iterator_free(index_iterator);
2674 git_iterator_free(new_iterator);
2675 return error;
2676 }
2677
2678 git_repository *git_index_owner(const git_index *index)
2679 {
2680 return INDEX_OWNER(index);
2681 }
2682
2683 enum {
2684 INDEX_ACTION_NONE = 0,
2685 INDEX_ACTION_UPDATE = 1,
2686 INDEX_ACTION_REMOVE = 2,
2687 INDEX_ACTION_ADDALL = 3,
2688 };
2689
2690 int git_index_add_all(
2691 git_index *index,
2692 const git_strarray *paths,
2693 unsigned int flags,
2694 git_index_matched_path_cb cb,
2695 void *payload)
2696 {
2697 int error;
2698 git_repository *repo;
2699 git_iterator *wditer = NULL;
2700 git_pathspec ps;
2701 bool no_fnmatch = (flags & GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH) != 0;
2702
2703 assert(index);
2704
2705 repo = INDEX_OWNER(index);
2706 if ((error = git_repository__ensure_not_bare(repo, "index add all")) < 0)
2707 return error;
2708
2709 if ((error = git_pathspec__init(&ps, paths)) < 0)
2710 return error;
2711
2712 /* optionally check that pathspec doesn't mention any ignored files */
2713 if ((flags & GIT_INDEX_ADD_CHECK_PATHSPEC) != 0 &&
2714 (flags & GIT_INDEX_ADD_FORCE) == 0 &&
2715 (error = git_ignore__check_pathspec_for_exact_ignores(
2716 repo, &ps.pathspec, no_fnmatch)) < 0)
2717 goto cleanup;
2718
2719 error = index_apply_to_wd_diff(index, INDEX_ACTION_ADDALL, paths, flags, cb, payload);
2720
2721 if (error)
2722 giterr_set_after_callback(error);
2723
2724 cleanup:
2725 git_iterator_free(wditer);
2726 git_pathspec__clear(&ps);
2727
2728 return error;
2729 }
2730
2731 struct foreach_diff_data {
2732 git_index *index;
2733 const git_pathspec *pathspec;
2734 unsigned int flags;
2735 git_index_matched_path_cb cb;
2736 void *payload;
2737 };
2738
2739 static int apply_each_file(const git_diff_delta *delta, float progress, void *payload)
2740 {
2741 struct foreach_diff_data *data = payload;
2742 const char *match, *path;
2743 int error = 0;
2744
2745 GIT_UNUSED(progress);
2746
2747 path = delta->old_file.path;
2748
2749 /* We only want those which match the pathspecs */
2750 if (!git_pathspec__match(
2751 &data->pathspec->pathspec, path, false, (bool)data->index->ignore_case,
2752 &match, NULL))
2753 return 0;
2754
2755 if (data->cb)
2756 error = data->cb(path, match, data->payload);
2757
2758 if (error > 0) /* skip this entry */
2759 return 0;
2760 if (error < 0) /* actual error */
2761 return error;
2762
2763 /* If the workdir item does not exist, remove it from the index. */
2764 if ((delta->new_file.flags & GIT_DIFF_FLAG_EXISTS) == 0)
2765 error = git_index_remove_bypath(data->index, path);
2766 else
2767 error = git_index_add_bypath(data->index, delta->new_file.path);
2768
2769 return error;
2770 }
2771
2772 static int index_apply_to_wd_diff(git_index *index, int action, const git_strarray *paths,
2773 unsigned int flags,
2774 git_index_matched_path_cb cb, void *payload)
2775 {
2776 int error;
2777 git_diff *diff;
2778 git_pathspec ps;
2779 git_repository *repo;
2780 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
2781 struct foreach_diff_data data = {
2782 index,
2783 NULL,
2784 flags,
2785 cb,
2786 payload,
2787 };
2788
2789 assert(index);
2790 assert(action == INDEX_ACTION_UPDATE || action == INDEX_ACTION_ADDALL);
2791
2792 repo = INDEX_OWNER(index);
2793
2794 if (!repo) {
2795 return create_index_error(-1,
2796 "cannot run update; the index is not backed up by a repository.");
2797 }
2798
2799 /*
2800 * We do the matching ourselves intead of passing the list to
2801 * diff because we want to tell the callback which one
2802 * matched, which we do not know if we ask diff to filter for us.
2803 */
2804 if ((error = git_pathspec__init(&ps, paths)) < 0)
2805 return error;
2806
2807 opts.flags = GIT_DIFF_INCLUDE_TYPECHANGE;
2808 if (action == INDEX_ACTION_ADDALL) {
2809 opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED |
2810 GIT_DIFF_RECURSE_UNTRACKED_DIRS;
2811
2812 if (flags == GIT_INDEX_ADD_FORCE)
2813 opts.flags |= GIT_DIFF_INCLUDE_IGNORED;
2814 }
2815
2816 if ((error = git_diff_index_to_workdir(&diff, repo, index, &opts)) < 0)
2817 goto cleanup;
2818
2819 data.pathspec = &ps;
2820 error = git_diff_foreach(diff, apply_each_file, NULL, NULL, NULL, &data);
2821 git_diff_free(diff);
2822
2823 if (error) /* make sure error is set if callback stopped iteration */
2824 giterr_set_after_callback(error);
2825
2826 cleanup:
2827 git_pathspec__clear(&ps);
2828 return error;
2829 }
2830
2831 static int index_apply_to_all(
2832 git_index *index,
2833 int action,
2834 const git_strarray *paths,
2835 git_index_matched_path_cb cb,
2836 void *payload)
2837 {
2838 int error = 0;
2839 size_t i;
2840 git_pathspec ps;
2841 const char *match;
2842 git_buf path = GIT_BUF_INIT;
2843
2844 assert(index);
2845
2846 if ((error = git_pathspec__init(&ps, paths)) < 0)
2847 return error;
2848
2849 git_vector_sort(&index->entries);
2850
2851 for (i = 0; !error && i < index->entries.length; ++i) {
2852 git_index_entry *entry = git_vector_get(&index->entries, i);
2853
2854 /* check if path actually matches */
2855 if (!git_pathspec__match(
2856 &ps.pathspec, entry->path, false, (bool)index->ignore_case,
2857 &match, NULL))
2858 continue;
2859
2860 /* issue notification callback if requested */
2861 if (cb && (error = cb(entry->path, match, payload)) != 0) {
2862 if (error > 0) { /* return > 0 means skip this one */
2863 error = 0;
2864 continue;
2865 }
2866 if (error < 0) /* return < 0 means abort */
2867 break;
2868 }
2869
2870 /* index manipulation may alter entry, so don't depend on it */
2871 if ((error = git_buf_sets(&path, entry->path)) < 0)
2872 break;
2873
2874 switch (action) {
2875 case INDEX_ACTION_NONE:
2876 break;
2877 case INDEX_ACTION_UPDATE:
2878 error = git_index_add_bypath(index, path.ptr);
2879
2880 if (error == GIT_ENOTFOUND) {
2881 giterr_clear();
2882
2883 error = git_index_remove_bypath(index, path.ptr);
2884
2885 if (!error) /* back up foreach if we removed this */
2886 i--;
2887 }
2888 break;
2889 case INDEX_ACTION_REMOVE:
2890 if (!(error = git_index_remove_bypath(index, path.ptr)))
2891 i--; /* back up foreach if we removed this */
2892 break;
2893 default:
2894 giterr_set(GITERR_INVALID, "Unknown index action %d", action);
2895 error = -1;
2896 break;
2897 }
2898 }
2899
2900 git_buf_free(&path);
2901 git_pathspec__clear(&ps);
2902
2903 return error;
2904 }
2905
2906 int git_index_remove_all(
2907 git_index *index,
2908 const git_strarray *pathspec,
2909 git_index_matched_path_cb cb,
2910 void *payload)
2911 {
2912 int error = index_apply_to_all(
2913 index, INDEX_ACTION_REMOVE, pathspec, cb, payload);
2914
2915 if (error) /* make sure error is set if callback stopped iteration */
2916 giterr_set_after_callback(error);
2917
2918 return error;
2919 }
2920
2921 int git_index_update_all(
2922 git_index *index,
2923 const git_strarray *pathspec,
2924 git_index_matched_path_cb cb,
2925 void *payload)
2926 {
2927 int error = index_apply_to_wd_diff(index, INDEX_ACTION_UPDATE, pathspec, 0, cb, payload);
2928 if (error) /* make sure error is set if callback stopped iteration */
2929 giterr_set_after_callback(error);
2930
2931 return error;
2932 }
2933
2934 int git_index_snapshot_new(git_vector *snap, git_index *index)
2935 {
2936 int error;
2937
2938 GIT_REFCOUNT_INC(index);
2939
2940 if (git_mutex_lock(&index->lock) < 0) {
2941 giterr_set(GITERR_OS, "Failed to lock index");
2942 return -1;
2943 }
2944
2945 git_atomic_inc(&index->readers);
2946 git_vector_sort(&index->entries);
2947
2948 error = git_vector_dup(snap, &index->entries, index->entries._cmp);
2949
2950 git_mutex_unlock(&index->lock);
2951
2952 if (error < 0)
2953 git_index_free(index);
2954
2955 return error;
2956 }
2957
2958 void git_index_snapshot_release(git_vector *snap, git_index *index)
2959 {
2960 git_vector_free(snap);
2961
2962 git_atomic_dec(&index->readers);
2963
2964 if (!git_mutex_lock(&index->lock)) {
2965 index_free_deleted(index); /* try to free pending deleted items */
2966 git_mutex_unlock(&index->lock);
2967 }
2968
2969 git_index_free(index);
2970 }
2971
2972 int git_index_snapshot_find(
2973 size_t *out, git_vector *entries, git_vector_cmp entry_srch,
2974 const char *path, size_t path_len, int stage)
2975 {
2976 return index_find_in_entries(out, entries, entry_srch, path, path_len, stage);
2977 }
2978
2979 int git_indexwriter_init(
2980 git_indexwriter *writer,
2981 git_index *index)
2982 {
2983 int error;
2984
2985 GIT_REFCOUNT_INC(index);
2986
2987 writer->index = index;
2988
2989 if (!index->index_file_path)
2990 return create_index_error(-1,
2991 "Failed to write index: The index is in-memory only");
2992
2993 if ((error = git_filebuf_open(
2994 &writer->file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS, GIT_INDEX_FILE_MODE)) < 0) {
2995
2996 if (error == GIT_ELOCKED)
2997 giterr_set(GITERR_INDEX, "The index is locked. This might be due to a concurrent or crashed process");
2998
2999 return error;
3000 }
3001
3002 writer->should_write = 1;
3003
3004 return 0;
3005 }
3006
3007 int git_indexwriter_init_for_operation(
3008 git_indexwriter *writer,
3009 git_repository *repo,
3010 unsigned int *checkout_strategy)
3011 {
3012 git_index *index;
3013 int error;
3014
3015 if ((error = git_repository_index__weakptr(&index, repo)) < 0 ||
3016 (error = git_indexwriter_init(writer, index)) < 0)
3017 return error;
3018
3019 writer->should_write = (*checkout_strategy & GIT_CHECKOUT_DONT_WRITE_INDEX) == 0;
3020 *checkout_strategy |= GIT_CHECKOUT_DONT_WRITE_INDEX;
3021
3022 return 0;
3023 }
3024
3025 int git_indexwriter_commit(git_indexwriter *writer)
3026 {
3027 int error;
3028 git_oid checksum = {{ 0 }};
3029
3030 if (!writer->should_write)
3031 return 0;
3032
3033 if (index_sort_if_needed(writer->index, true) < 0)
3034 return -1;
3035
3036 git_vector_sort(&writer->index->reuc);
3037
3038 if ((error = write_index(&checksum, writer->index, &writer->file)) < 0) {
3039 git_indexwriter_cleanup(writer);
3040 return error;
3041 }
3042
3043 if ((error = git_filebuf_commit(&writer->file)) < 0)
3044 return error;
3045
3046 if ((error = git_futils_filestamp_check(
3047 &writer->index->stamp, writer->index->index_file_path)) < 0) {
3048 giterr_set(GITERR_OS, "Could not read index timestamp");
3049 return -1;
3050 }
3051
3052 writer->index->on_disk = 1;
3053 git_oid_cpy(&writer->index->checksum, &checksum);
3054
3055 git_index_free(writer->index);
3056 writer->index = NULL;
3057
3058 return 0;
3059 }
3060
3061 void git_indexwriter_cleanup(git_indexwriter *writer)
3062 {
3063 git_filebuf_cleanup(&writer->file);
3064
3065 git_index_free(writer->index);
3066 writer->index = NULL;
3067 }