2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
11 #include "repository.h"
14 #include "tree-cache.h"
23 #include "git2/blob.h"
24 #include "git2/config.h"
25 #include "git2/sys/index.h"
27 static int index_apply_to_wd_diff(git_index
*index
, int action
, const git_strarray
*paths
,
29 git_index_matched_path_cb cb
, void *payload
);
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)
35 #define minimal_entry_size (offsetof(struct entry_short, path))
37 static const size_t INDEX_FOOTER_SIZE
= GIT_OID_RAWSZ
;
38 static const size_t INDEX_HEADER_SIZE
= 12;
40 static const unsigned int INDEX_VERSION_NUMBER
= 2;
41 static const unsigned int INDEX_VERSION_NUMBER_EXT
= 3;
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'};
48 #define INDEX_OWNER(idx) ((git_repository *)(GIT_REFCOUNT_OWNER(idx)))
56 struct index_extension
{
58 uint32_t extension_size
;
67 struct entry_time ctime
;
68 struct entry_time mtime
;
77 char path
[1]; /* arbitrary length */
81 struct entry_time ctime
;
82 struct entry_time mtime
;
91 uint16_t flags_extended
;
92 char path
[1]; /* arbitrary length */
95 struct entry_srch_key
{
101 struct entry_internal
{
102 git_index_entry entry
;
104 char path
[GIT_FLEX_ARRAY
];
107 struct reuc_entry_internal
{
108 git_index_reuc_entry entry
;
110 char path
[GIT_FLEX_ARRAY
];
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
);
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
);
121 static void index_entry_free(git_index_entry
*entry
);
122 static void index_entry_reuc_free(git_index_reuc_entry
*reuc
);
124 int git_index_entry_srch(const void *key
, const void *array_member
)
126 const struct entry_srch_key
*srch_key
= key
;
127 const struct entry_internal
*entry
= array_member
;
129 size_t len1
, len2
, len
;
131 len1
= srch_key
->pathlen
;
132 len2
= entry
->pathlen
;
133 len
= len1
< len2
? len1
: len2
;
135 cmp
= memcmp(srch_key
->path
, entry
->path
, len
);
143 if (srch_key
->stage
!= GIT_INDEX_STAGE_ANY
)
144 return srch_key
->stage
- GIT_IDXENTRY_STAGE(&entry
->entry
);
149 int git_index_entry_isrch(const void *key
, const void *array_member
)
151 const struct entry_srch_key
*srch_key
= key
;
152 const struct entry_internal
*entry
= array_member
;
154 size_t len1
, len2
, len
;
156 len1
= srch_key
->pathlen
;
157 len2
= entry
->pathlen
;
158 len
= len1
< len2
? len1
: len2
;
160 cmp
= strncasecmp(srch_key
->path
, entry
->path
, len
);
169 if (srch_key
->stage
!= GIT_INDEX_STAGE_ANY
)
170 return srch_key
->stage
- GIT_IDXENTRY_STAGE(&entry
->entry
);
175 static int index_entry_srch_path(const void *path
, const void *array_member
)
177 const git_index_entry
*entry
= array_member
;
179 return strcmp((const char *)path
, entry
->path
);
182 static int index_entry_isrch_path(const void *path
, const void *array_member
)
184 const git_index_entry
*entry
= array_member
;
186 return strcasecmp((const char *)path
, entry
->path
);
189 int git_index_entry_cmp(const void *a
, const void *b
)
192 const git_index_entry
*entry_a
= a
;
193 const git_index_entry
*entry_b
= b
;
195 diff
= strcmp(entry_a
->path
, entry_b
->path
);
198 diff
= (GIT_IDXENTRY_STAGE(entry_a
) - GIT_IDXENTRY_STAGE(entry_b
));
203 int git_index_entry_icmp(const void *a
, const void *b
)
206 const git_index_entry
*entry_a
= a
;
207 const git_index_entry
*entry_b
= b
;
209 diff
= strcasecmp(entry_a
->path
, entry_b
->path
);
212 diff
= (GIT_IDXENTRY_STAGE(entry_a
) - GIT_IDXENTRY_STAGE(entry_b
));
217 static int conflict_name_cmp(const void *a
, const void *b
)
219 const git_index_name_entry
*name_a
= a
;
220 const git_index_name_entry
*name_b
= b
;
222 if (name_a
->ancestor
&& !name_b
->ancestor
)
225 if (!name_a
->ancestor
&& name_b
->ancestor
)
228 if (name_a
->ancestor
)
229 return strcmp(name_a
->ancestor
, name_b
->ancestor
);
231 if (!name_a
->ours
|| !name_b
->ours
)
234 return strcmp(name_a
->ours
, name_b
->ours
);
238 * TODO: enable this when resolving case insensitive conflicts
241 static int conflict_name_icmp(const void *a
, const void *b
)
243 const git_index_name_entry
*name_a
= a
;
244 const git_index_name_entry
*name_b
= b
;
246 if (name_a
->ancestor
&& !name_b
->ancestor
)
249 if (!name_a
->ancestor
&& name_b
->ancestor
)
252 if (name_a
->ancestor
)
253 return strcasecmp(name_a
->ancestor
, name_b
->ancestor
);
255 if (!name_a
->ours
|| !name_b
->ours
)
258 return strcasecmp(name_a
->ours
, name_b
->ours
);
262 static int reuc_srch(const void *key
, const void *array_member
)
264 const git_index_reuc_entry
*reuc
= array_member
;
266 return strcmp(key
, reuc
->path
);
269 static int reuc_isrch(const void *key
, const void *array_member
)
271 const git_index_reuc_entry
*reuc
= array_member
;
273 return strcasecmp(key
, reuc
->path
);
276 static int reuc_cmp(const void *a
, const void *b
)
278 const git_index_reuc_entry
*info_a
= a
;
279 const git_index_reuc_entry
*info_b
= b
;
281 return strcmp(info_a
->path
, info_b
->path
);
284 static int reuc_icmp(const void *a
, const void *b
)
286 const git_index_reuc_entry
*info_a
= a
;
287 const git_index_reuc_entry
*info_b
= b
;
289 return strcasecmp(info_a
->path
, info_b
->path
);
292 static void index_entry_reuc_free(git_index_reuc_entry
*reuc
)
297 static void index_entry_free(git_index_entry
*entry
)
302 memset(&entry
->id
, 0, sizeof(entry
->id
));
306 unsigned int git_index__create_mode(unsigned int mode
)
311 if (S_ISDIR(mode
) || (mode
& S_IFMT
) == (S_IFLNK
| S_IFDIR
))
312 return (S_IFLNK
| S_IFDIR
);
314 return S_IFREG
| GIT_PERMS_CANONICAL(mode
);
317 static unsigned int index_merge_mode(
318 git_index
*index
, git_index_entry
*existing
, unsigned int mode
)
320 if (index
->no_symlinks
&& S_ISREG(mode
) &&
321 existing
&& S_ISLNK(existing
->mode
))
322 return existing
->mode
;
324 if (index
->distrust_filemode
&& S_ISREG(mode
))
325 return (existing
&& S_ISREG(existing
->mode
)) ?
326 existing
->mode
: git_index__create_mode(0666);
328 return git_index__create_mode(mode
);
331 static int index_sort_if_needed(git_index
*index
, bool need_lock
)
333 /* not truly threadsafe because between when this checks and/or
334 * sorts the array another thread could come in and unsort it
337 if (git_vector_is_sorted(&index
->entries
))
340 if (need_lock
&& git_mutex_lock(&index
->lock
) < 0) {
341 giterr_set(GITERR_OS
, "Unable to lock index");
345 git_vector_sort(&index
->entries
);
348 git_mutex_unlock(&index
->lock
);
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
)
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
);
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
)
368 if (index_sort_if_needed(index
, need_lock
) < 0)
371 return index_find_in_entries(
372 out
, &index
->entries
, index
->entries_search
, path
, path_len
, stage
);
375 void git_index__set_ignore_case(git_index
*index
, bool ignore_case
)
377 index
->ignore_case
= 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
;
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
;
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);
395 git_vector_set_cmp(&index
->reuc
, ignore_case
? reuc_icmp
: reuc_cmp
);
396 git_vector_sort(&index
->reuc
);
399 int git_index_open(git_index
**index_out
, const char *index_path
)
406 index
= git__calloc(1, sizeof(git_index
));
407 GITERR_CHECK_ALLOC(index
);
409 if (git_mutex_init(&index
->lock
)) {
410 giterr_set(GITERR_OS
, "Failed to initialize lock");
415 git_pool_init(&index
->tree_pool
, 1, 0);
417 if (index_path
!= NULL
) {
418 index
->index_file_path
= git__strdup(index_path
);
419 if (!index
->index_file_path
)
422 /* Check if index file is stored on disk already */
423 if (git_path_exists(index
->index_file_path
) == true)
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)
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
;
438 if (index_path
!= NULL
&& (error
= git_index_read(index
, true)) < 0)
442 GIT_REFCOUNT_INC(index
);
447 git_pool_clear(&index
->tree_pool
);
448 git_index_free(index
);
452 int git_index_new(git_index
**out
)
454 return git_index_open(out
, NULL
);
457 static void index_free(git_index
*index
)
459 /* index iterators increment the refcount of the index, so if we
460 * get here then there should be no outstanding iterators.
462 assert(!git_atomic_get(&index
->readers
));
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
);
470 git__free(index
->index_file_path
);
471 git_mutex_free(&index
->lock
);
473 git__memzero(index
, sizeof(*index
));
477 void git_index_free(git_index
*index
)
482 GIT_REFCOUNT_DEC(index
, index_free
);
485 /* call with locked index */
486 static void index_free_deleted(git_index
*index
)
488 int readers
= (int)git_atomic_get(&index
->readers
);
491 if (readers
> 0 || !index
->deleted
.length
)
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
);
499 git_vector_clear(&index
->deleted
);
502 /* call with locked index */
503 static int index_remove_entry(git_index
*index
, size_t pos
)
506 git_index_entry
*entry
= git_vector_get(&index
->entries
, pos
);
509 git_tree_cache_invalidate_path(index
->tree
, entry
->path
);
511 error
= git_vector_remove(&index
->entries
, pos
);
514 if (git_atomic_get(&index
->readers
) > 0) {
515 error
= git_vector_insert(&index
->deleted
, entry
);
517 index_entry_free(entry
);
524 int git_index_clear(git_index
*index
)
531 git_pool_clear(&index
->tree_pool
);
533 if (git_mutex_lock(&index
->lock
) < 0) {
534 giterr_set(GITERR_OS
, "Failed to lock index");
538 while (!error
&& index
->entries
.length
> 0)
539 error
= index_remove_entry(index
, index
->entries
.length
- 1);
540 index_free_deleted(index
);
542 git_index_reuc_clear(index
);
543 git_index_name_clear(index
);
545 git_futils_filestamp_set(&index
->stamp
, NULL
);
547 git_mutex_unlock(&index
->lock
);
552 static int create_index_error(int error
, const char *msg
)
554 giterr_set(GITERR_INDEX
, msg
);
558 int git_index_set_caps(git_index
*index
, int caps
)
560 unsigned int old_ignore_case
;
564 old_ignore_case
= index
->ignore_case
;
566 if (caps
== GIT_INDEXCAP_FROM_OWNER
) {
567 git_repository
*repo
= INDEX_OWNER(index
);
571 return create_index_error(
572 -1, "Cannot access repository to set index caps");
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);
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);
587 if (old_ignore_case
!= index
->ignore_case
) {
588 git_index__set_ignore_case(index
, (bool)index
->ignore_case
);
594 int git_index_caps(const git_index
*index
)
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));
601 const git_oid
*git_index_checksum(git_index
*index
)
603 return &index
->checksum
;
607 * Returns 1 for changed, 0 for not changed and <0 for errors
609 static int compare_checksum(git_index
*index
)
613 git_oid checksum
= {{ 0 }};
615 if ((fd
= p_open(index
->index_file_path
, O_RDONLY
)) < 0)
618 if ((error
= p_lseek(fd
, -20, SEEK_END
)) < 0) {
620 giterr_set(GITERR_OS
, "failed to seek to end of file");
624 bytes_read
= p_read(fd
, &checksum
, GIT_OID_RAWSZ
);
630 return !!git_oid_cmp(&checksum
, &index
->checksum
);
633 int git_index_read(git_index
*index
, int force
)
635 int error
= 0, updated
;
636 git_buf buffer
= GIT_BUF_INIT
;
637 git_futils_filestamp stamp
= index
->stamp
;
639 if (!index
->index_file_path
)
640 return create_index_error(-1,
641 "Failed to read index: The index is in-memory only");
643 index
->on_disk
= git_path_exists(index
->index_file_path
);
645 if (!index
->on_disk
) {
647 return git_index_clear(index
);
651 if ((updated
= git_futils_filestamp_check(&stamp
, index
->index_file_path
) < 0) ||
652 ((updated
= compare_checksum(index
)) < 0)) {
655 "Failed to read index: '%s' no longer exists",
656 index
->index_file_path
);
659 if (!updated
&& !force
)
662 error
= git_futils_readbuffer(&buffer
, index
->index_file_path
);
667 git_pool_clear(&index
->tree_pool
);
669 error
= git_index_clear(index
);
672 error
= parse_index(index
, buffer
.ptr
, buffer
.size
);
675 git_futils_filestamp_set(&index
->stamp
, &stamp
);
677 git_buf_free(&buffer
);
681 int git_index__changed_relative_to(
682 git_index
*index
, const git_oid
*checksum
)
684 /* attempt to update index (ignoring errors) */
685 if (git_index_read(index
, false) < 0)
688 return !!git_oid_cmp(&index
->checksum
, checksum
);
691 static bool is_racy_timestamp(git_time_t stamp
, git_index_entry
*entry
)
693 /* Git special-cases submodules in the check */
694 if (S_ISGITLINK(entry
->mode
))
697 /* If we never read the index, we can't have this race either */
701 /* If the timestamp is the same or newer than the index, it's racy */
702 return ((int32_t) stamp
) <= entry
->mtime
.seconds
;
706 * Force the next diff to take a look at those entries which have the
707 * same timestamp as the current index.
709 static int truncate_racily_clean(git_index
*index
)
713 git_index_entry
*entry
;
714 git_time_t ts
= index
->stamp
.mtime
;
715 git_diff_options diff_opts
= GIT_DIFF_OPTIONS_INIT
;
718 /* Nothing to do if there's no repo to talk about */
719 if (!INDEX_OWNER(index
))
722 /* If there's no workdir, we can't know where to even check */
723 if (!git_repository_workdir(INDEX_OWNER(index
)))
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
))
731 diff_opts
.pathspec
.count
= 1;
732 diff_opts
.pathspec
.strings
= (char **) &entry
->path
;
734 if ((error
= git_diff_index_to_workdir(&diff
, INDEX_OWNER(index
), index
, &diff_opts
)) < 0)
737 if (git_diff_num_deltas(diff
) > 0)
738 entry
->file_size
= 0;
746 int git_index_write(git_index
*index
)
748 git_indexwriter writer
= GIT_INDEXWRITER_INIT
;
751 truncate_racily_clean(index
);
753 if ((error
= git_indexwriter_init(&writer
, index
)) == 0)
754 error
= git_indexwriter_commit(&writer
);
756 git_indexwriter_cleanup(&writer
);
761 const char * git_index_path(const git_index
*index
)
764 return index
->index_file_path
;
767 int git_index_write_tree(git_oid
*oid
, git_index
*index
)
769 git_repository
*repo
;
771 assert(oid
&& index
);
773 repo
= INDEX_OWNER(index
);
776 return create_index_error(-1, "Failed to write tree. "
777 "The index file is not backed up by an existing repository");
779 return git_tree__write_index(oid
, index
, repo
);
782 int git_index_write_tree_to(
783 git_oid
*oid
, git_index
*index
, git_repository
*repo
)
785 assert(oid
&& index
&& repo
);
786 return git_tree__write_index(oid
, index
, repo
);
789 size_t git_index_entrycount(const git_index
*index
)
792 return index
->entries
.length
;
795 const git_index_entry
*git_index_get_byindex(
796 git_index
*index
, size_t n
)
799 if (index_sort_if_needed(index
, true) < 0)
801 return git_vector_get(&index
->entries
, n
);
804 const git_index_entry
*git_index_get_bypath(
805 git_index
*index
, const char *path
, int stage
)
811 if (index_find(&pos
, index
, path
, 0, stage
, true) < 0) {
812 giterr_set(GITERR_INDEX
, "Index does not contain %s", path
);
816 return git_index_get_byindex(index
, pos
);
819 void git_index_entry__init_from_stat(
820 git_index_entry
*entry
, struct stat
*st
, bool trust_mode
)
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
;
835 static int index_entry_create(
836 git_index_entry
**out
,
837 git_repository
*repo
,
840 size_t pathlen
= strlen(path
), alloclen
;
841 struct entry_internal
*entry
;
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
);
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
);
854 entry
->pathlen
= pathlen
;
855 memcpy(entry
->path
, path
, pathlen
);
856 entry
->entry
.path
= entry
->path
;
858 *out
= (git_index_entry
*)entry
;
862 static int index_entry_init(
863 git_index_entry
**entry_out
,
865 const char *rel_path
)
868 git_index_entry
*entry
= NULL
;
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.");
877 if (index_entry_create(&entry
, INDEX_OWNER(index
), rel_path
) < 0)
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);
885 index_entry_free(entry
);
890 git_index_entry__init_from_stat(entry
, &st
, !index
->distrust_filemode
);
892 *entry_out
= (git_index_entry
*)entry
;
896 static git_index_reuc_entry
*reuc_entry_alloc(const char *path
)
898 size_t pathlen
= strlen(path
),
899 structlen
= sizeof(struct reuc_entry_internal
),
901 struct reuc_entry_internal
*entry
;
903 if (GIT_ADD_SIZET_OVERFLOW(&alloclen
, structlen
, pathlen
) ||
904 GIT_ADD_SIZET_OVERFLOW(&alloclen
, alloclen
, 1))
907 entry
= git__calloc(1, alloclen
);
911 entry
->pathlen
= pathlen
;
912 memcpy(entry
->path
, path
, pathlen
);
913 entry
->entry
.path
= entry
->path
;
915 return (git_index_reuc_entry
*)entry
;
918 static int index_entry_reuc_init(git_index_reuc_entry
**reuc_out
,
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
)
924 git_index_reuc_entry
*reuc
= NULL
;
926 assert(reuc_out
&& path
);
928 *reuc_out
= reuc
= reuc_entry_alloc(path
);
929 GITERR_CHECK_ALLOC(reuc
);
931 if ((reuc
->mode
[0] = ancestor_mode
) > 0)
932 git_oid_cpy(&reuc
->oid
[0], ancestor_oid
);
934 if ((reuc
->mode
[1] = our_mode
) > 0)
935 git_oid_cpy(&reuc
->oid
[1], our_oid
);
937 if ((reuc
->mode
[2] = their_mode
) > 0)
938 git_oid_cpy(&reuc
->oid
[2], their_oid
);
943 static void index_entry_cpy(git_index_entry
*tgt
, const git_index_entry
*src
)
945 const char *tgt_path
= tgt
->path
;
946 memcpy(tgt
, src
, sizeof(*tgt
));
947 tgt
->path
= tgt_path
; /* reset to existing path data */
950 static int index_entry_dup(
951 git_index_entry
**out
,
952 git_repository
*repo
,
953 const git_index_entry
*src
)
955 git_index_entry
*entry
;
962 if (index_entry_create(&entry
, repo
, src
->path
) < 0)
965 index_entry_cpy(entry
, src
);
970 static int has_file_name(git_index
*index
,
971 const git_index_entry
*entry
, size_t pos
, int ok_to_replace
)
974 size_t len
= strlen(entry
->path
);
975 int stage
= GIT_IDXENTRY_STAGE(entry
);
976 const char *name
= entry
->path
;
978 while (pos
< index
->entries
.length
) {
979 struct entry_internal
*p
= index
->entries
.contents
[pos
++];
981 if (len
>= p
->pathlen
)
983 if (memcmp(name
, p
->path
, len
))
985 if (GIT_IDXENTRY_STAGE(&p
->entry
) != stage
)
987 if (p
->path
[len
] != '/')
993 if (index_remove_entry(index
, --pos
) < 0)
1000 * Do we have another file with a pathname that is a proper
1001 * subset of the name we're trying to add?
1003 static int has_dir_name(git_index
*index
,
1004 const git_index_entry
*entry
, int ok_to_replace
)
1007 int stage
= GIT_IDXENTRY_STAGE(entry
);
1008 const char *name
= entry
->path
;
1009 const char *slash
= name
+ strlen(name
);
1015 if (*--slash
== '/')
1017 if (slash
<= entry
->path
)
1022 if (!index_find(&pos
, index
, name
, len
, stage
, false)) {
1027 if (index_remove_entry(index
, pos
) < 0)
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.
1037 for (; pos
< index
->entries
.length
; ++pos
) {
1038 struct entry_internal
*p
= index
->entries
.contents
[pos
];
1040 if (p
->pathlen
<= len
||
1041 p
->path
[len
] != '/' ||
1042 memcmp(p
->path
, name
, len
))
1043 break; /* not our subdirectory */
1045 if (GIT_IDXENTRY_STAGE(&p
->entry
) == stage
)
1053 static int check_file_directory_collision(git_index
*index
,
1054 git_index_entry
*entry
, size_t pos
, int ok_to_replace
)
1056 int retval
= has_file_name(index
, entry
, pos
, ok_to_replace
);
1057 retval
= retval
+ has_dir_name(index
, entry
, ok_to_replace
);
1060 giterr_set(GITERR_INDEX
,
1061 "'%s' appears as both a file and a directory", entry
->path
);
1068 static int index_no_dups(void **old
, void *new)
1070 const git_index_entry
*entry
= new;
1072 giterr_set(GITERR_INDEX
, "'%s' appears multiple times at stage %d",
1073 entry
->path
, GIT_IDXENTRY_STAGE(entry
));
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.
1083 static int index_insert(
1084 git_index
*index
, git_index_entry
**entry_ptr
, int replace
, bool trust_mode
)
1087 size_t path_length
, position
;
1088 git_index_entry
*existing
= NULL
, *entry
;
1090 assert(index
&& entry_ptr
);
1094 /* make sure that the path length flag is correct */
1095 path_length
= ((struct entry_internal
*)entry
)->pathlen
;
1097 entry
->flags
&= ~GIT_IDXENTRY_NAMEMASK
;
1099 if (path_length
< GIT_IDXENTRY_NAMEMASK
)
1100 entry
->flags
|= path_length
& GIT_IDXENTRY_NAMEMASK
;
1102 entry
->flags
|= GIT_IDXENTRY_NAMEMASK
;
1104 if (git_mutex_lock(&index
->lock
) < 0) {
1105 giterr_set(GITERR_OS
, "Unable to acquire index lock");
1109 git_vector_sort(&index
->entries
);
1111 /* look if an entry with this path already exists */
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 */
1117 entry
->mode
= git_index__create_mode(entry
->mode
);
1119 entry
->mode
= index_merge_mode(index
, existing
, entry
->mode
);
1122 /* look for tree / blob name collisions, removing conflicts if requested */
1123 error
= check_file_directory_collision(index
, entry
, position
, replace
);
1127 /* if we are replacing an existing item, overwrite the existing entry
1128 * and return it in place of the passed in one.
1130 else if (existing
) {
1132 index_entry_cpy(existing
, entry
);
1133 index_entry_free(entry
);
1134 *entry_ptr
= entry
= existing
;
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.)
1141 error
= git_vector_insert_sorted(&index
->entries
, entry
, index_no_dups
);
1145 index_entry_free(*entry_ptr
);
1149 git_mutex_unlock(&index
->lock
);
1154 static int index_conflict_to_reuc(git_index
*index
, const char *path
)
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
;
1161 if ((ret
= git_index_conflict_get(&conflict_entries
[0],
1162 &conflict_entries
[1], &conflict_entries
[2], index
, path
)) < 0)
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
;
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
;
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
);
1180 static bool valid_filemode(const int filemode
)
1182 return (filemode
== GIT_FILEMODE_BLOB
||
1183 filemode
== GIT_FILEMODE_BLOB_EXECUTABLE
||
1184 filemode
== GIT_FILEMODE_LINK
||
1185 filemode
== GIT_FILEMODE_COMMIT
);
1188 int git_index_add_frombuffer(
1189 git_index
*index
, const git_index_entry
*source_entry
,
1190 const void *buffer
, size_t len
)
1192 git_index_entry
*entry
= NULL
;
1196 assert(index
&& source_entry
->path
);
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.");
1203 if (!valid_filemode(source_entry
->mode
)) {
1204 giterr_set(GITERR_INDEX
, "invalid filemode");
1208 if (index_entry_dup(&entry
, INDEX_OWNER(index
), source_entry
) < 0)
1211 error
= git_blob_create_frombuffer(&id
, INDEX_OWNER(index
), buffer
, len
);
1213 index_entry_free(entry
);
1217 git_oid_cpy(&entry
->id
, &id
);
1218 entry
->file_size
= len
;
1220 if ((error
= index_insert(index
, &entry
, 1, true)) < 0)
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
)
1227 git_tree_cache_invalidate_path(index
->tree
, entry
->path
);
1232 int git_index_add_bypath(git_index
*index
, const char *path
)
1234 git_index_entry
*entry
= NULL
;
1237 assert(index
&& path
);
1239 if ((ret
= index_entry_init(&entry
, index
, path
)) < 0 ||
1240 (ret
= index_insert(index
, &entry
, 1, false)) < 0)
1243 /* Adding implies conflict was resolved, move conflict entries to REUC */
1244 if ((ret
= index_conflict_to_reuc(index
, path
)) < 0 && ret
!= GIT_ENOTFOUND
)
1247 git_tree_cache_invalidate_path(index
->tree
, entry
->path
);
1251 int git_index_remove_bypath(git_index
*index
, const char *path
)
1255 assert(index
&& path
);
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
))
1263 if (ret
== GIT_ENOTFOUND
)
1270 int git_index_add(git_index
*index
, const git_index_entry
*source_entry
)
1272 git_index_entry
*entry
= NULL
;
1275 assert(index
&& source_entry
&& source_entry
->path
);
1277 if (!valid_filemode(source_entry
->mode
)) {
1278 giterr_set(GITERR_INDEX
, "invalid filemode");
1282 if ((ret
= index_entry_dup(&entry
, INDEX_OWNER(index
), source_entry
)) < 0 ||
1283 (ret
= index_insert(index
, &entry
, 1, true)) < 0)
1286 git_tree_cache_invalidate_path(index
->tree
, entry
->path
);
1290 int git_index_remove(git_index
*index
, const char *path
, int stage
)
1295 if (git_mutex_lock(&index
->lock
) < 0) {
1296 giterr_set(GITERR_OS
, "Failed to lock index");
1300 if (index_find(&position
, index
, path
, 0, stage
, false) < 0) {
1302 GITERR_INDEX
, "Index does not contain %s at stage %d", path
, stage
);
1303 error
= GIT_ENOTFOUND
;
1305 error
= index_remove_entry(index
, position
);
1308 git_mutex_unlock(&index
->lock
);
1312 int git_index_remove_directory(git_index
*index
, const char *dir
, int stage
)
1314 git_buf pfx
= GIT_BUF_INIT
;
1317 git_index_entry
*entry
;
1319 if (git_mutex_lock(&index
->lock
) < 0) {
1320 giterr_set(GITERR_OS
, "Failed to lock index");
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);
1329 entry
= git_vector_get(&index
->entries
, pos
);
1330 if (!entry
|| git__prefixcmp(entry
->path
, pfx
.ptr
) != 0)
1333 if (GIT_IDXENTRY_STAGE(entry
) != stage
) {
1338 error
= index_remove_entry(index
, pos
);
1340 /* removed entry at 'pos' so we don't need to increment */
1343 git_mutex_unlock(&index
->lock
);
1349 int git_index__find_pos(
1350 size_t *out
, git_index
*index
, const char *path
, size_t path_len
, int stage
)
1352 assert(index
&& path
);
1353 return index_find(out
, index
, path
, path_len
, stage
, true);
1356 int git_index_find(size_t *at_pos
, git_index
*index
, const char *path
)
1360 assert(index
&& path
);
1362 if (git_mutex_lock(&index
->lock
) < 0) {
1363 giterr_set(GITERR_OS
, "Failed to lock index");
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
;
1374 /* Since our binary search only looked at path, we may be in the
1375 * middle of a list of stages.
1377 for (; pos
> 0; --pos
) {
1378 const git_index_entry
*prev
= git_vector_get(&index
->entries
, pos
- 1);
1380 if (index
->entries_cmp_path(prev
->path
, path
) != 0)
1387 git_mutex_unlock(&index
->lock
);
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
)
1396 git_index_entry
*entries
[3] = { 0 };
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)
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",
1416 /* Remove existing index entries for each path */
1417 for (i
= 0; i
< 3; i
++) {
1418 if (entries
[i
] == NULL
)
1421 if ((ret
= git_index_remove(index
, entries
[i
]->path
, 0)) != 0) {
1422 if (ret
!= GIT_ENOTFOUND
)
1430 /* Add the conflict entries */
1431 for (i
= 0; i
< 3; i
++) {
1432 if (entries
[i
] == NULL
)
1435 /* Make sure stage is correct */
1436 GIT_IDXENTRY_STAGE_SET(entries
[i
], i
+ 1);
1438 if ((ret
= index_insert(index
, &entries
[i
], 0, true)) < 0)
1441 entries
[i
] = NULL
; /* don't free if later entry fails */
1447 for (i
= 0; i
< 3; i
++) {
1448 if (entries
[i
] != NULL
)
1449 index_entry_free(entries
[i
]);
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
,
1462 const git_index_entry
*conflict_entry
;
1463 const char *path
= NULL
;
1467 assert(ancestor_out
&& our_out
&& their_out
&& index
);
1469 *ancestor_out
= NULL
;
1473 for (count
= git_index_entrycount(index
); n
< count
; ++n
) {
1474 conflict_entry
= git_vector_get(&index
->entries
, n
);
1476 if (path
&& index
->entries_cmp_path(conflict_entry
->path
, path
) != 0)
1479 stage
= GIT_IDXENTRY_STAGE(conflict_entry
);
1480 path
= conflict_entry
->path
;
1484 *their_out
= conflict_entry
;
1488 *our_out
= conflict_entry
;
1492 *ancestor_out
= conflict_entry
;
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
,
1513 assert(ancestor_out
&& our_out
&& their_out
&& index
&& path
);
1515 *ancestor_out
= NULL
;
1519 if (git_index_find(&pos
, index
, path
) < 0)
1520 return GIT_ENOTFOUND
;
1522 if ((len
= index_conflict__get_byindex(
1523 ancestor_out
, our_out
, their_out
, index
, pos
)) < 0)
1526 return GIT_ENOTFOUND
;
1531 static int index_conflict_remove(git_index
*index
, const char *path
)
1534 git_index_entry
*conflict_entry
;
1537 if (path
!= NULL
&& git_index_find(&pos
, index
, path
) < 0)
1538 return GIT_ENOTFOUND
;
1540 if (git_mutex_lock(&index
->lock
) < 0) {
1541 giterr_set(GITERR_OS
, "Unable to lock index");
1545 while ((conflict_entry
= git_vector_get(&index
->entries
, pos
)) != NULL
) {
1548 index
->entries_cmp_path(conflict_entry
->path
, path
) != 0)
1551 if (GIT_IDXENTRY_STAGE(conflict_entry
) == 0) {
1556 if ((error
= index_remove_entry(index
, pos
)) < 0)
1560 git_mutex_unlock(&index
->lock
);
1565 int git_index_conflict_remove(git_index
*index
, const char *path
)
1567 assert(index
&& path
);
1568 return index_conflict_remove(index
, path
);
1571 int git_index_conflict_cleanup(git_index
*index
)
1574 return index_conflict_remove(index
, NULL
);
1577 int git_index_has_conflicts(const git_index
*index
)
1580 git_index_entry
*entry
;
1584 git_vector_foreach(&index
->entries
, i
, entry
) {
1585 if (GIT_IDXENTRY_STAGE(entry
) > 0)
1592 int git_index_conflict_iterator_new(
1593 git_index_conflict_iterator
**iterator_out
,
1596 git_index_conflict_iterator
*it
= NULL
;
1598 assert(iterator_out
&& index
);
1600 it
= git__calloc(1, sizeof(git_index_conflict_iterator
));
1601 GITERR_CHECK_ALLOC(it
);
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
)
1615 const git_index_entry
*entry
;
1618 assert(ancestor_out
&& our_out
&& their_out
&& iterator
);
1620 *ancestor_out
= NULL
;
1624 while (iterator
->cur
< iterator
->index
->entries
.length
) {
1625 entry
= git_index_get_byindex(iterator
->index
, iterator
->cur
);
1627 if (git_index_entry_is_conflict(entry
)) {
1628 if ((len
= index_conflict__get_byindex(
1633 iterator
->cur
)) < 0)
1636 iterator
->cur
+= len
;
1643 return GIT_ITEROVER
;
1646 void git_index_conflict_iterator_free(git_index_conflict_iterator
*iterator
)
1648 if (iterator
== NULL
)
1651 git__free(iterator
);
1654 size_t git_index_name_entrycount(git_index
*index
)
1657 return index
->names
.length
;
1660 const git_index_name_entry
*git_index_name_get_byindex(
1661 git_index
*index
, size_t n
)
1665 git_vector_sort(&index
->names
);
1666 return git_vector_get(&index
->names
, n
);
1669 static void index_name_entry_free(git_index_name_entry
*ne
)
1673 git__free(ne
->ancestor
);
1674 git__free(ne
->ours
);
1675 git__free(ne
->theirs
);
1679 int git_index_name_add(git_index
*index
,
1680 const char *ancestor
, const char *ours
, const char *theirs
)
1682 git_index_name_entry
*conflict_name
;
1684 assert((ancestor
&& ours
) || (ancestor
&& theirs
) || (ours
&& theirs
));
1686 conflict_name
= git__calloc(1, sizeof(git_index_name_entry
));
1687 GITERR_CHECK_ALLOC(conflict_name
);
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)
1694 index_name_entry_free(conflict_name
);
1701 void git_index_name_clear(git_index
*index
)
1704 git_index_name_entry
*conflict_name
;
1708 git_vector_foreach(&index
->names
, i
, conflict_name
)
1709 index_name_entry_free(conflict_name
);
1711 git_vector_clear(&index
->names
);
1714 size_t git_index_reuc_entrycount(git_index
*index
)
1717 return index
->reuc
.length
;
1720 static int index_reuc_insert(
1722 git_index_reuc_entry
*reuc
,
1725 git_index_reuc_entry
**existing
= NULL
;
1728 assert(index
&& reuc
&& reuc
->path
!= NULL
);
1730 if (!git_index_reuc_find(&position
, index
, reuc
->path
))
1731 existing
= (git_index_reuc_entry
**)&index
->reuc
.contents
[position
];
1733 if (!replace
|| !existing
)
1734 return git_vector_insert(&index
->reuc
, reuc
);
1736 /* exists, replace it */
1737 git__free(*existing
);
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
)
1748 git_index_reuc_entry
*reuc
= NULL
;
1751 assert(index
&& path
);
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
);
1761 int git_index_reuc_find(size_t *at_pos
, git_index
*index
, const char *path
)
1763 return git_vector_bsearch2(at_pos
, &index
->reuc
, index
->reuc_search
, path
);
1766 const git_index_reuc_entry
*git_index_reuc_get_bypath(
1767 git_index
*index
, const char *path
)
1770 assert(index
&& path
);
1772 if (!index
->reuc
.length
)
1775 git_vector_sort(&index
->reuc
);
1777 if (git_index_reuc_find(&pos
, index
, path
) < 0)
1780 return git_vector_get(&index
->reuc
, pos
);
1783 const git_index_reuc_entry
*git_index_reuc_get_byindex(
1784 git_index
*index
, size_t n
)
1788 git_vector_sort(&index
->reuc
);
1789 return git_vector_get(&index
->reuc
, n
);
1792 int git_index_reuc_remove(git_index
*index
, size_t position
)
1795 git_index_reuc_entry
*reuc
;
1797 git_vector_sort(&index
->reuc
);
1799 reuc
= git_vector_get(&index
->reuc
, position
);
1800 error
= git_vector_remove(&index
->reuc
, position
);
1803 index_entry_reuc_free(reuc
);
1808 void git_index_reuc_clear(git_index
*index
)
1814 for (i
= 0; i
< index
->reuc
.length
; ++i
)
1815 index_entry_reuc_free(git__swap(index
->reuc
.contents
[i
], NULL
));
1817 git_vector_clear(&index
->reuc
);
1820 static int index_error_invalid(const char *message
)
1822 giterr_set(GITERR_INDEX
, "Invalid data in index - %s", message
);
1826 static int read_reuc(git_index
*index
, const char *buffer
, size_t size
)
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)
1838 git_index_reuc_entry
*lost
;
1840 len
= p_strnlen(buffer
, size
) + 1;
1842 return index_error_invalid("reading reuc entries");
1844 lost
= reuc_entry_alloc(buffer
);
1845 GITERR_CHECK_ALLOC(lost
);
1850 /* read 3 ASCII octal numbers for stage entries */
1851 for (i
= 0; i
< 3; i
++) {
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");
1861 lost
->mode
[i
] = tmp
;
1863 len
= (endptr
+ 1) - buffer
;
1865 index_entry_reuc_free(lost
);
1866 return index_error_invalid("reading reuc entry stage");
1873 /* read up to 3 OIDs for stage entries */
1874 for (i
= 0; i
< 3; i
++) {
1878 index_entry_reuc_free(lost
);
1879 return index_error_invalid("reading reuc entry oid");
1882 git_oid_fromraw(&lost
->oid
[i
], (const unsigned char *) buffer
);
1887 /* entry was read successfully - insert into reuc vector */
1888 if (git_vector_insert(&index
->reuc
, lost
) < 0)
1892 /* entries are guaranteed to be sorted on-disk */
1893 git_vector_set_sorted(&index
->reuc
, true);
1899 static int read_conflict_names(git_index
*index
, const char *buffer
, size_t size
)
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)
1908 #define read_conflict_name(ptr) \
1909 len = p_strnlen(buffer, size) + 1; \
1911 return index_error_invalid("reading conflict name entries"); \
1916 ptr = git__malloc(len); \
1917 GITERR_CHECK_ALLOC(ptr); \
1918 memcpy(ptr, buffer, len); \
1925 git_index_name_entry
*conflict_name
= git__calloc(1, sizeof(git_index_name_entry
));
1926 GITERR_CHECK_ALLOC(conflict_name
);
1928 read_conflict_name(conflict_name
->ancestor
);
1929 read_conflict_name(conflict_name
->ours
);
1930 read_conflict_name(conflict_name
->theirs
);
1932 if (git_vector_insert(&index
->names
, conflict_name
) < 0)
1936 #undef read_conflict_name
1938 /* entries are guaranteed to be sorted on-disk */
1939 git_vector_set_sorted(&index
->names
, true);
1944 static size_t read_entry(
1945 git_index_entry
**out
,
1950 size_t path_length
, entry_size
;
1951 const char *path_ptr
;
1952 struct entry_short source
;
1953 git_index_entry entry
= {{0}};
1955 if (INDEX_FOOTER_SIZE
+ minimal_entry_size
> buffer_size
)
1958 /* buffer is not guaranteed to be aligned */
1959 memcpy(&source
, buffer
, sizeof(struct entry_short
));
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
);
1974 if (entry
.flags
& GIT_IDXENTRY_EXTENDED
) {
1976 size_t flags_offset
;
1978 flags_offset
= offsetof(struct entry_long
, flags_extended
);
1979 memcpy(&flags_raw
, (const char *) buffer
+ flags_offset
,
1981 flags_raw
= ntohs(flags_raw
);
1983 memcpy(&entry
.flags_extended
, &flags_raw
, sizeof(flags_raw
));
1984 path_ptr
= (const char *) buffer
+ offsetof(struct entry_long
, path
);
1986 path_ptr
= (const char *) buffer
+ offsetof(struct entry_short
, path
);
1988 path_length
= entry
.flags
& GIT_IDXENTRY_NAMEMASK
;
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
;
1995 path_end
= memchr(path_ptr
, '\0', buffer_size
);
1996 if (path_end
== NULL
)
1999 path_length
= path_end
- path_ptr
;
2002 if (entry
.flags
& GIT_IDXENTRY_EXTENDED
)
2003 entry_size
= long_entry_size(path_length
);
2005 entry_size
= short_entry_size(path_length
);
2007 if (INDEX_FOOTER_SIZE
+ entry_size
> buffer_size
)
2010 entry
.path
= (char *)path_ptr
;
2012 if (index_entry_dup(out
, INDEX_OWNER(index
), &entry
) < 0)
2018 static int read_header(struct index_header
*dest
, const void *buffer
)
2020 const struct index_header
*source
= buffer
;
2022 dest
->signature
= ntohl(source
->signature
);
2023 if (dest
->signature
!= INDEX_HEADER_SIG
)
2024 return index_error_invalid("incorrect header signature");
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");
2031 dest
->entry_count
= ntohl(source
->entry_count
);
2035 static size_t read_extension(git_index
*index
, const char *buffer
, size_t buffer_size
)
2037 struct index_extension dest
;
2040 /* buffer is not guaranteed to be aligned */
2041 memcpy(&dest
, buffer
, sizeof(struct index_extension
));
2042 dest
.extension_size
= ntohl(dest
.extension_size
);
2044 total_size
= dest
.extension_size
+ sizeof(struct index_extension
);
2046 if (dest
.extension_size
> total_size
||
2047 buffer_size
< total_size
||
2048 buffer_size
- total_size
< INDEX_FOOTER_SIZE
)
2051 /* optional extension */
2052 if (dest
.signature
[0] >= 'A' && dest
.signature
[0] <= 'Z') {
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)
2057 } else if (memcmp(dest
.signature
, INDEX_EXT_UNMERGED_SIG
, 4) == 0) {
2058 if (read_reuc(index
, buffer
+ 8, dest
.extension_size
) < 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)
2064 /* else, unsupported extension. We cannot parse this, but we can skip
2065 * it by returning `total_size */
2067 /* we cannot handle non-ignorable extensions;
2068 * in fact they aren't even defined in the standard */
2075 static int parse_index(git_index
*index
, const char *buffer
, size_t buffer_size
)
2079 struct index_header header
= { 0 };
2080 git_oid checksum_calculated
, checksum_expected
;
2082 #define seek_forward(_increase) { \
2083 if (_increase >= buffer_size) { \
2084 error = index_error_invalid("ran out of data while parsing"); \
2086 buffer += _increase; \
2087 buffer_size -= _increase;\
2090 if (buffer_size
< INDEX_HEADER_SIZE
+ INDEX_FOOTER_SIZE
)
2091 return index_error_invalid("insufficient buffer space");
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
);
2098 if ((error
= read_header(&header
, buffer
)) < 0)
2101 seek_forward(INDEX_HEADER_SIZE
);
2103 if (git_mutex_lock(&index
->lock
) < 0) {
2104 giterr_set(GITERR_OS
, "Unable to acquire index lock");
2108 assert(!index
->entries
.length
);
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
);
2115 /* 0 bytes read means an object corruption */
2116 if (entry_size
== 0) {
2117 error
= index_error_invalid("invalid entry");
2121 if ((error
= git_vector_insert(&index
->entries
, entry
)) < 0) {
2122 index_entry_free(entry
);
2126 seek_forward(entry_size
);
2129 if (i
!= header
.entry_count
) {
2130 error
= index_error_invalid("header entries changed while parsing");
2134 /* There's still space for some extensions! */
2135 while (buffer_size
> INDEX_FOOTER_SIZE
) {
2136 size_t extension_size
;
2138 extension_size
= read_extension(index
, buffer
, buffer_size
);
2140 /* see if we have read any bytes from the extension */
2141 if (extension_size
== 0) {
2142 error
= index_error_invalid("extension is truncated");
2146 seek_forward(extension_size
);
2149 if (buffer_size
!= INDEX_FOOTER_SIZE
) {
2150 error
= index_error_invalid(
2151 "buffer size does not match index footer size");
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
);
2158 if (git_oid__cmp(&checksum_calculated
, &checksum_expected
) != 0) {
2159 error
= index_error_invalid(
2160 "calculated checksum does not match expected");
2164 git_oid_cpy(&index
->checksum
, &checksum_calculated
);
2168 /* Entries are stored case-sensitively on disk, so re-sort now if
2169 * in-memory index is supposed to be case-insensitive
2171 git_vector_set_sorted(&index
->entries
, !index
->ignore_case
);
2172 error
= index_sort_if_needed(index
, false);
2175 git_mutex_unlock(&index
->lock
);
2179 static bool is_index_extended(git_index
*index
)
2182 git_index_entry
*entry
;
2186 git_vector_foreach(&index
->entries
, i
, entry
) {
2187 entry
->flags
&= ~GIT_IDXENTRY_EXTENDED
;
2188 if (entry
->flags_extended
& GIT_IDXENTRY_EXTENDED_FLAGS
) {
2190 entry
->flags
|= GIT_IDXENTRY_EXTENDED
;
2194 return (extended
> 0);
2197 static int write_disk_entry(git_filebuf
*file
, git_index_entry
*entry
)
2200 struct entry_short
*ondisk
;
2201 size_t path_len
, disk_size
;
2204 path_len
= ((struct entry_internal
*)entry
)->pathlen
;
2206 if (entry
->flags
& GIT_IDXENTRY_EXTENDED
)
2207 disk_size
= long_entry_size(path_len
);
2209 disk_size
= short_entry_size(path_len
);
2211 if (git_filebuf_reserve(file
, &mem
, disk_size
) < 0)
2214 ondisk
= (struct entry_short
*)mem
;
2216 memset(ondisk
, 0x0, disk_size
);
2219 * Yes, we have to truncate.
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.
2226 * In 2038 I will be either too dead or too rich to care about this
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
);
2239 git_oid_cpy(&ondisk
->oid
, &entry
->id
);
2241 ondisk
->flags
= htons(entry
->flags
);
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
;
2250 path
= ondisk
->path
;
2252 memcpy(path
, entry
->path
, path_len
);
2257 static int write_entries(git_index
*index
, git_filebuf
*file
)
2261 git_vector case_sorted
, *entries
;
2262 git_index_entry
*entry
;
2264 if (git_mutex_lock(&index
->lock
) < 0) {
2265 giterr_set(GITERR_OS
, "Failed to lock index");
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
;
2276 entries
= &index
->entries
;
2279 git_vector_foreach(entries
, i
, entry
)
2280 if ((error
= write_disk_entry(file
, entry
)) < 0)
2283 git_mutex_unlock(&index
->lock
);
2285 if (index
->ignore_case
)
2286 git_vector_free(&case_sorted
);
2291 static int write_extension(git_filebuf
*file
, struct index_extension
*header
, git_buf
*data
)
2293 struct index_extension ondisk
;
2295 memset(&ondisk
, 0x0, sizeof(struct index_extension
));
2296 memcpy(&ondisk
, header
, 4);
2297 ondisk
.extension_size
= htonl(header
->extension_size
);
2299 git_filebuf_write(file
, &ondisk
, sizeof(struct index_extension
));
2300 return git_filebuf_write(file
, data
->ptr
, data
->size
);
2303 static int create_name_extension_data(git_buf
*name_buf
, git_index_name_entry
*conflict_name
)
2307 if (conflict_name
->ancestor
== NULL
)
2308 error
= git_buf_put(name_buf
, "\0", 1);
2310 error
= git_buf_put(name_buf
, conflict_name
->ancestor
, strlen(conflict_name
->ancestor
) + 1);
2315 if (conflict_name
->ours
== NULL
)
2316 error
= git_buf_put(name_buf
, "\0", 1);
2318 error
= git_buf_put(name_buf
, conflict_name
->ours
, strlen(conflict_name
->ours
) + 1);
2323 if (conflict_name
->theirs
== NULL
)
2324 error
= git_buf_put(name_buf
, "\0", 1);
2326 error
= git_buf_put(name_buf
, conflict_name
->theirs
, strlen(conflict_name
->theirs
) + 1);
2332 static int write_name_extension(git_index
*index
, git_filebuf
*file
)
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
;
2341 git_vector_foreach(out
, i
, conflict_name
) {
2342 if ((error
= create_name_extension_data(&name_buf
, conflict_name
)) < 0)
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
;
2350 error
= write_extension(file
, &extension
, &name_buf
);
2352 git_buf_free(&name_buf
);
2358 static int create_reuc_extension_data(git_buf
*reuc_buf
, git_index_reuc_entry
*reuc
)
2363 if ((error
= git_buf_put(reuc_buf
, reuc
->path
, strlen(reuc
->path
) + 1)) < 0)
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)
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)
2380 static int write_reuc_extension(git_index
*index
, git_filebuf
*file
)
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
;
2389 git_vector_foreach(out
, i
, reuc
) {
2390 if ((error
= create_reuc_extension_data(&reuc_buf
, reuc
)) < 0)
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
;
2398 error
= write_extension(file
, &extension
, &reuc_buf
);
2400 git_buf_free(&reuc_buf
);
2406 static int write_tree_extension(git_index
*index
, git_filebuf
*file
)
2408 struct index_extension extension
;
2409 git_buf buf
= GIT_BUF_INIT
;
2412 if (index
->tree
== NULL
)
2415 if ((error
= git_tree_cache_write(&buf
, index
->tree
)) < 0)
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
;
2422 error
= write_extension(file
, &extension
, &buf
);
2429 static int write_index(git_oid
*checksum
, git_index
*index
, git_filebuf
*file
)
2432 struct index_header header
;
2434 uint32_t index_version_number
;
2436 assert(index
&& file
);
2438 is_extended
= is_index_extended(index
);
2439 index_version_number
= is_extended
? INDEX_VERSION_NUMBER_EXT
: INDEX_VERSION_NUMBER
;
2441 header
.signature
= htonl(INDEX_HEADER_SIG
);
2442 header
.version
= htonl(index_version_number
);
2443 header
.entry_count
= htonl((uint32_t)index
->entries
.length
);
2445 if (git_filebuf_write(file
, &header
, sizeof(struct index_header
)) < 0)
2448 if (write_entries(index
, file
) < 0)
2451 /* write the tree cache extension */
2452 if (index
->tree
!= NULL
&& write_tree_extension(index
, file
) < 0)
2455 /* write the rename conflict extension */
2456 if (index
->names
.length
> 0 && write_name_extension(index
, file
) < 0)
2459 /* write the reuc extension */
2460 if (index
->reuc
.length
> 0 && write_reuc_extension(index
, file
) < 0)
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
);
2467 /* write it at the end of the file */
2468 return git_filebuf_write(file
, hash_final
.id
, GIT_OID_RAWSZ
);
2471 int git_index_entry_stage(const git_index_entry
*entry
)
2473 return GIT_IDXENTRY_STAGE(entry
);
2476 int git_index_entry_is_conflict(const git_index_entry
*entry
)
2478 return (GIT_IDXENTRY_STAGE(entry
) > 0);
2481 typedef struct read_tree_data
{
2483 git_vector
*old_entries
;
2484 git_vector
*new_entries
;
2485 git_vector_cmp entry_cmp
;
2486 git_tree_cache
*tree
;
2489 static int read_tree_cb(
2490 const char *root
, const git_tree_entry
*tentry
, void *payload
)
2492 read_tree_data
*data
= payload
;
2493 git_index_entry
*entry
= NULL
, *old_entry
;
2494 git_buf path
= GIT_BUF_INIT
;
2497 if (git_tree_entry__is_tree(tentry
))
2500 if (git_buf_joinpath(&path
, root
, tentry
->filename
) < 0)
2503 if (index_entry_create(&entry
, INDEX_OWNER(data
->index
), path
.ptr
) < 0)
2506 entry
->mode
= tentry
->attr
;
2507 entry
->id
= tentry
->oid
;
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
))
2517 index_entry_cpy(entry
, old_entry
);
2518 entry
->flags_extended
= 0;
2521 if (path
.size
< GIT_IDXENTRY_NAMEMASK
)
2522 entry
->flags
= path
.size
& GIT_IDXENTRY_NAMEMASK
;
2524 entry
->flags
= GIT_IDXENTRY_NAMEMASK
;
2526 git_buf_free(&path
);
2528 if (git_vector_insert(data
->new_entries
, entry
) < 0) {
2529 index_entry_free(entry
);
2536 int git_index_read_tree(git_index
*index
, const git_tree
*tree
)
2539 git_vector entries
= GIT_VECTOR_INIT
;
2540 read_tree_data data
;
2542 git_vector_set_cmp(&entries
, index
->entries
._cmp
); /* match sort */
2545 data
.old_entries
= &index
->entries
;
2546 data
.new_entries
= &entries
;
2547 data
.entry_cmp
= index
->entries_search
;
2550 git_pool_clear(&index
->tree_pool
);
2552 if (index_sort_if_needed(index
, true) < 0)
2555 error
= git_tree_walk(tree
, GIT_TREEWALK_POST
, read_tree_cb
, &data
);
2558 git_vector_sort(&entries
);
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");
2566 git_vector_swap(&entries
, &index
->entries
);
2567 git_mutex_unlock(&index
->lock
);
2571 git_vector_free(&entries
);
2575 error
= git_tree_cache_read_tree(&index
->tree
, tree
, &index
->tree_pool
);
2580 int git_index_read_index(
2582 const git_index
*new_index
)
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
;
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)
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)
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
))
2612 if (old_entry
&& new_entry
)
2613 diff
= git_index_entry_cmp(old_entry
, new_entry
);
2614 else if (!old_entry
&& new_entry
)
2616 else if (old_entry
&& !new_entry
)
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)
2627 git_vector_insert(&new_entries
, entry
);
2629 /* Path and stage are equal, if the OID is equal, keep it to
2630 * keep the stat cache data.
2632 if (git_oid_equal(&old_entry
->id
, &new_entry
->id
)) {
2633 git_vector_insert(&new_entries
, (git_index_entry
*)old_entry
);
2635 if ((error
= index_entry_dup(&entry
, git_index_owner(index
), new_entry
)) < 0)
2638 git_vector_insert(&new_entries
, entry
);
2639 git_vector_insert(&remove_entries
, (git_index_entry
*)old_entry
);
2644 if ((error
= git_iterator_advance(&old_entry
, index_iterator
)) < 0 &&
2645 error
!= GIT_ITEROVER
)
2650 if ((error
= git_iterator_advance(&new_entry
, new_iterator
)) < 0 &&
2651 error
!= GIT_ITEROVER
)
2656 git_index_name_clear(index
);
2657 git_index_reuc_clear(index
);
2659 git_vector_swap(&new_entries
, &index
->entries
);
2661 git_vector_foreach(&remove_entries
, i
, entry
) {
2663 git_tree_cache_invalidate_path(index
->tree
, entry
->path
);
2665 index_entry_free(entry
);
2671 git_vector_free(&new_entries
);
2672 git_vector_free(&remove_entries
);
2673 git_iterator_free(index_iterator
);
2674 git_iterator_free(new_iterator
);
2678 git_repository
*git_index_owner(const git_index
*index
)
2680 return INDEX_OWNER(index
);
2684 INDEX_ACTION_NONE
= 0,
2685 INDEX_ACTION_UPDATE
= 1,
2686 INDEX_ACTION_REMOVE
= 2,
2687 INDEX_ACTION_ADDALL
= 3,
2690 int git_index_add_all(
2692 const git_strarray
*paths
,
2694 git_index_matched_path_cb cb
,
2698 git_repository
*repo
;
2699 git_iterator
*wditer
= NULL
;
2701 bool no_fnmatch
= (flags
& GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH
) != 0;
2705 repo
= INDEX_OWNER(index
);
2706 if ((error
= git_repository__ensure_not_bare(repo
, "index add all")) < 0)
2709 if ((error
= git_pathspec__init(&ps
, paths
)) < 0)
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)
2719 error
= index_apply_to_wd_diff(index
, INDEX_ACTION_ADDALL
, paths
, flags
, cb
, payload
);
2722 giterr_set_after_callback(error
);
2725 git_iterator_free(wditer
);
2726 git_pathspec__clear(&ps
);
2731 struct foreach_diff_data
{
2733 const git_pathspec
*pathspec
;
2735 git_index_matched_path_cb cb
;
2739 static int apply_each_file(const git_diff_delta
*delta
, float progress
, void *payload
)
2741 struct foreach_diff_data
*data
= payload
;
2742 const char *match
, *path
;
2745 GIT_UNUSED(progress
);
2747 path
= delta
->old_file
.path
;
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
,
2756 error
= data
->cb(path
, match
, data
->payload
);
2758 if (error
> 0) /* skip this entry */
2760 if (error
< 0) /* actual error */
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
);
2767 error
= git_index_add_bypath(data
->index
, delta
->new_file
.path
);
2772 static int index_apply_to_wd_diff(git_index
*index
, int action
, const git_strarray
*paths
,
2774 git_index_matched_path_cb cb
, void *payload
)
2779 git_repository
*repo
;
2780 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
2781 struct foreach_diff_data data
= {
2790 assert(action
== INDEX_ACTION_UPDATE
|| action
== INDEX_ACTION_ADDALL
);
2792 repo
= INDEX_OWNER(index
);
2795 return create_index_error(-1,
2796 "cannot run update; the index is not backed up by a repository.");
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.
2804 if ((error
= git_pathspec__init(&ps
, paths
)) < 0)
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
;
2812 if (flags
== GIT_INDEX_ADD_FORCE
)
2813 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
;
2816 if ((error
= git_diff_index_to_workdir(&diff
, repo
, index
, &opts
)) < 0)
2819 data
.pathspec
= &ps
;
2820 error
= git_diff_foreach(diff
, apply_each_file
, NULL
, NULL
, NULL
, &data
);
2821 git_diff_free(diff
);
2823 if (error
) /* make sure error is set if callback stopped iteration */
2824 giterr_set_after_callback(error
);
2827 git_pathspec__clear(&ps
);
2831 static int index_apply_to_all(
2834 const git_strarray
*paths
,
2835 git_index_matched_path_cb cb
,
2842 git_buf path
= GIT_BUF_INIT
;
2846 if ((error
= git_pathspec__init(&ps
, paths
)) < 0)
2849 git_vector_sort(&index
->entries
);
2851 for (i
= 0; !error
&& i
< index
->entries
.length
; ++i
) {
2852 git_index_entry
*entry
= git_vector_get(&index
->entries
, i
);
2854 /* check if path actually matches */
2855 if (!git_pathspec__match(
2856 &ps
.pathspec
, entry
->path
, false, (bool)index
->ignore_case
,
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 */
2866 if (error
< 0) /* return < 0 means abort */
2870 /* index manipulation may alter entry, so don't depend on it */
2871 if ((error
= git_buf_sets(&path
, entry
->path
)) < 0)
2875 case INDEX_ACTION_NONE
:
2877 case INDEX_ACTION_UPDATE
:
2878 error
= git_index_add_bypath(index
, path
.ptr
);
2880 if (error
== GIT_ENOTFOUND
) {
2883 error
= git_index_remove_bypath(index
, path
.ptr
);
2885 if (!error
) /* back up foreach if we removed this */
2889 case INDEX_ACTION_REMOVE
:
2890 if (!(error
= git_index_remove_bypath(index
, path
.ptr
)))
2891 i
--; /* back up foreach if we removed this */
2894 giterr_set(GITERR_INVALID
, "Unknown index action %d", action
);
2900 git_buf_free(&path
);
2901 git_pathspec__clear(&ps
);
2906 int git_index_remove_all(
2908 const git_strarray
*pathspec
,
2909 git_index_matched_path_cb cb
,
2912 int error
= index_apply_to_all(
2913 index
, INDEX_ACTION_REMOVE
, pathspec
, cb
, payload
);
2915 if (error
) /* make sure error is set if callback stopped iteration */
2916 giterr_set_after_callback(error
);
2921 int git_index_update_all(
2923 const git_strarray
*pathspec
,
2924 git_index_matched_path_cb cb
,
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
);
2934 int git_index_snapshot_new(git_vector
*snap
, git_index
*index
)
2938 GIT_REFCOUNT_INC(index
);
2940 if (git_mutex_lock(&index
->lock
) < 0) {
2941 giterr_set(GITERR_OS
, "Failed to lock index");
2945 git_atomic_inc(&index
->readers
);
2946 git_vector_sort(&index
->entries
);
2948 error
= git_vector_dup(snap
, &index
->entries
, index
->entries
._cmp
);
2950 git_mutex_unlock(&index
->lock
);
2953 git_index_free(index
);
2958 void git_index_snapshot_release(git_vector
*snap
, git_index
*index
)
2960 git_vector_free(snap
);
2962 git_atomic_dec(&index
->readers
);
2964 if (!git_mutex_lock(&index
->lock
)) {
2965 index_free_deleted(index
); /* try to free pending deleted items */
2966 git_mutex_unlock(&index
->lock
);
2969 git_index_free(index
);
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
)
2976 return index_find_in_entries(out
, entries
, entry_srch
, path
, path_len
, stage
);
2979 int git_indexwriter_init(
2980 git_indexwriter
*writer
,
2985 GIT_REFCOUNT_INC(index
);
2987 writer
->index
= index
;
2989 if (!index
->index_file_path
)
2990 return create_index_error(-1,
2991 "Failed to write index: The index is in-memory only");
2993 if ((error
= git_filebuf_open(
2994 &writer
->file
, index
->index_file_path
, GIT_FILEBUF_HASH_CONTENTS
, GIT_INDEX_FILE_MODE
)) < 0) {
2996 if (error
== GIT_ELOCKED
)
2997 giterr_set(GITERR_INDEX
, "The index is locked. This might be due to a concurrent or crashed process");
3002 writer
->should_write
= 1;
3007 int git_indexwriter_init_for_operation(
3008 git_indexwriter
*writer
,
3009 git_repository
*repo
,
3010 unsigned int *checkout_strategy
)
3015 if ((error
= git_repository_index__weakptr(&index
, repo
)) < 0 ||
3016 (error
= git_indexwriter_init(writer
, index
)) < 0)
3019 writer
->should_write
= (*checkout_strategy
& GIT_CHECKOUT_DONT_WRITE_INDEX
) == 0;
3020 *checkout_strategy
|= GIT_CHECKOUT_DONT_WRITE_INDEX
;
3025 int git_indexwriter_commit(git_indexwriter
*writer
)
3028 git_oid checksum
= {{ 0 }};
3030 if (!writer
->should_write
)
3033 if (index_sort_if_needed(writer
->index
, true) < 0)
3036 git_vector_sort(&writer
->index
->reuc
);
3038 if ((error
= write_index(&checksum
, writer
->index
, &writer
->file
)) < 0) {
3039 git_indexwriter_cleanup(writer
);
3043 if ((error
= git_filebuf_commit(&writer
->file
)) < 0)
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");
3052 writer
->index
->on_disk
= 1;
3053 git_oid_cpy(&writer
->index
->checksum
, &checksum
);
3055 git_index_free(writer
->index
);
3056 writer
->index
= NULL
;
3061 void git_indexwriter_cleanup(git_indexwriter
*writer
)
3063 git_filebuf_cleanup(&writer
->file
);
3065 git_index_free(writer
->index
);
3066 writer
->index
= NULL
;