summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/index.c9
-rw-r--r--tests/index/racy.c77
2 files changed, 84 insertions, 2 deletions
diff --git a/src/index.c b/src/index.c
index 9eb1289c3..b3fb077cc 100644
--- a/src/index.c
+++ b/src/index.c
@@ -767,7 +767,8 @@ static int truncate_racily_clean(git_index *index)
diff_opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE | GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_DISABLE_PATHSPEC_MATCH;
git_vector_foreach(&index->entries, i, entry) {
- if (!is_racy_timestamp(&index->stamp.mtime, entry))
+ if ((entry->flags_extended & GIT_IDXENTRY_UPTODATE) == 0 &&
+ is_racy_timestamp(&index->stamp.mtime, entry))
git_vector_insert(&paths, (char *)entry->path);
}
@@ -1295,6 +1296,9 @@ static int index_insert(
else
entry->flags |= GIT_IDXENTRY_NAMEMASK;
+ /* this entry is now up-to-date and should not be checked for raciness */
+ entry->flags_extended |= GIT_IDXENTRY_UPTODATE;
+
if (git_mutex_lock(&index->lock) < 0) {
giterr_set(GITERR_OS, "Unable to acquire index lock");
return -1;
@@ -2558,7 +2562,8 @@ static int write_disk_entry(git_filebuf *file, git_index_entry *entry)
if (entry->flags & GIT_IDXENTRY_EXTENDED) {
struct entry_long *ondisk_ext;
ondisk_ext = (struct entry_long *)ondisk;
- ondisk_ext->flags_extended = htons(entry->flags_extended);
+ ondisk_ext->flags_extended = htons(entry->flags_extended &
+ GIT_IDXENTRY_EXTENDED_FLAGS);
path = ondisk_ext->path;
}
else
diff --git a/tests/index/racy.c b/tests/index/racy.c
index df25c851c..6ff12a39a 100644
--- a/tests/index/racy.c
+++ b/tests/index/racy.c
@@ -145,3 +145,80 @@ void test_index_racy__empty_file_after_smudge(void)
git_buf_free(&path);
git_diff_free(diff);
}
+
+static void setup_uptodate_files(void)
+{
+ git_buf path = GIT_BUF_INIT;
+ git_index *index;
+ git_index_entry new_entry = {0};
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+
+ cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "A"));
+ cl_git_mkfile(path.ptr, "A");
+
+ /* Put 'A' into the index */
+ cl_git_pass(git_index_add_bypath(index, "A"));
+
+ /* Put 'B' into the index */
+ new_entry.path = "B";
+ new_entry.mode = GIT_FILEMODE_BLOB;
+ cl_git_pass(git_index_add(index, &new_entry));
+
+ /* Put 'C' into the index */
+ new_entry.path = "C";
+ new_entry.mode = GIT_FILEMODE_BLOB;
+ cl_git_pass(git_index_add_frombuffer(index, &new_entry, "hello!\n", 7));
+
+ git_index_free(index);
+ git_buf_free(&path);
+}
+
+void test_index_racy__adding_to_index_is_uptodate(void)
+{
+ git_index *index;
+ const git_index_entry *entry;
+
+ setup_uptodate_files();
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+
+ /* ensure that they're all uptodate */
+ cl_assert((entry = git_index_get_bypath(index, "A", 0)));
+ cl_assert_equal_i(GIT_IDXENTRY_UPTODATE, (entry->flags_extended & GIT_IDXENTRY_UPTODATE));
+
+ cl_assert((entry = git_index_get_bypath(index, "B", 0)));
+ cl_assert_equal_i(GIT_IDXENTRY_UPTODATE, (entry->flags_extended & GIT_IDXENTRY_UPTODATE));
+
+ cl_assert((entry = git_index_get_bypath(index, "C", 0)));
+ cl_assert_equal_i(GIT_IDXENTRY_UPTODATE, (entry->flags_extended & GIT_IDXENTRY_UPTODATE));
+
+ cl_git_pass(git_index_write(index));
+
+ git_index_free(index);
+}
+
+void test_index_racy__reading_clears_uptodate_bit(void)
+{
+ git_index *index;
+ const git_index_entry *entry;
+
+ setup_uptodate_files();
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+ cl_git_pass(git_index_write(index));
+
+ cl_git_pass(git_index_read(index, true));
+
+ /* ensure that no files are uptodate */
+ cl_assert((entry = git_index_get_bypath(index, "A", 0)));
+ cl_assert_equal_i(0, (entry->flags_extended & GIT_IDXENTRY_UPTODATE));
+
+ cl_assert((entry = git_index_get_bypath(index, "B", 0)));
+ cl_assert_equal_i(0, (entry->flags_extended & GIT_IDXENTRY_UPTODATE));
+
+ cl_assert((entry = git_index_get_bypath(index, "C", 0)));
+ cl_assert_equal_i(0, (entry->flags_extended & GIT_IDXENTRY_UPTODATE));
+
+ git_index_free(index);
+}