diff options
author | Carlos Martín Nieto <cmn@dwim.me> | 2015-06-18 14:22:10 +0200 |
---|---|---|
committer | Carlos Martín Nieto <cmn@dwim.me> | 2015-06-22 12:47:30 +0200 |
commit | 74975846510794a874d9c8630f44aa14991901fd (patch) | |
tree | 9e4c722b632ce90ded368891df77c7722b303d1d | |
parent | ff47537557f0ac1919e77c5cb21f36f2e98425de (diff) | |
download | libgit2-74975846510794a874d9c8630f44aa14991901fd.tar.gz |
index: check racily clean entries more thoroughly
When an entry has a racy timestamp, we need to check whether the file
itself has changed since we put its entry in the index. Only then do we
smudge the size field to force a check the next time around.
-rw-r--r-- | src/index.c | 43 |
1 files changed, 41 insertions, 2 deletions
diff --git a/src/index.c b/src/index.c index 1fb3c48f3..5ce5522f8 100644 --- a/src/index.c +++ b/src/index.c @@ -688,20 +688,59 @@ int git_index__changed_relative_to( return !!git_oid_cmp(&index->checksum, checksum); } +static bool is_racy_timestamp(git_time_t stamp, git_index_entry *entry) +{ + /* Git special-cases submodules in the check */ + if (S_ISGITLINK(entry->mode)) + return false; + + /* If we never read the index, we can't have this race either */ + if (stamp == 0) + return false; + + /* If the timestamp is the same or newer than the index, it's racy */ + return ((int32_t) stamp) <= entry->mtime.seconds; +} + /* * Force the next diff to take a look at those entries which have the * same timestamp as the current index. */ -static void truncate_racily_clean(git_index *index) +static int truncate_racily_clean(git_index *index) { size_t i; + int error; git_index_entry *entry; git_time_t ts = index->stamp.mtime; + git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; + git_diff *diff; + /* Nothing to do if there's no repo to talk about */ + if (!INDEX_OWNER(index)) + return 0; + + /* If there's no workdir, we can't know where to even check */ + if (!git_repository_workdir(INDEX_OWNER(index))) + return 0; + + diff_opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE | GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_DISABLE_PATHSPEC_MATCH; git_vector_foreach(&index->entries, i, entry) { - if (entry->mtime.seconds == ts || ts == 0) + if (!is_racy_timestamp(ts, entry)) + continue; + + diff_opts.pathspec.count = 1; + diff_opts.pathspec.strings = (char **) &entry->path; + + if ((error = git_diff_index_to_workdir(&diff, INDEX_OWNER(index), index, &diff_opts)) < 0) + return error; + + if (git_diff_num_deltas(diff) > 0) entry->file_size = 0; + + git_diff_free(diff); } + + return 0; } int git_index_write(git_index *index) |