diff options
| author | Edward Thomson <ethomson@edwardthomson.com> | 2015-06-23 23:30:58 -0400 |
|---|---|---|
| committer | Edward Thomson <ethomson@edwardthomson.com> | 2015-06-23 23:30:58 -0400 |
| commit | bd670abd23944a20c6a84978ea590c8fd4258cb2 (patch) | |
| tree | df51120cb908816edcc098da00c433b51f28fbf4 /src | |
| parent | 8351abc7822c38f597bf0ee07f0f293a4f62b1f3 (diff) | |
| parent | bb4896f22c9199e88b25a47ee4389a7e778d9d7f (diff) | |
| download | libgit2-bd670abd23944a20c6a84978ea590c8fd4258cb2.tar.gz | |
Merge pull request #3226 from libgit2/cmn/racy-diff-again
racy-git, the missing link
Diffstat (limited to 'src')
| -rw-r--r-- | src/diff.c | 7 | ||||
| -rw-r--r-- | src/index.c | 43 | ||||
| -rw-r--r-- | src/iterator.c | 12 | ||||
| -rw-r--r-- | src/iterator.h | 8 |
4 files changed, 65 insertions, 5 deletions
diff --git a/src/diff.c b/src/diff.c index d7365ef77..cc93f57cd 100644 --- a/src/diff.c +++ b/src/diff.c @@ -816,11 +816,11 @@ static int maybe_modified( } else if (git_oid_iszero(&nitem->id) && new_is_workdir) { bool use_ctime = ((diff->diffcaps & GIT_DIFFCAPS_TRUST_CTIME) != 0); bool use_nanos = ((diff->diffcaps & GIT_DIFFCAPS_TRUST_NANOSECS) != 0); + git_index *index; + git_iterator_index(&index, info->new_iter); status = GIT_DELTA_UNMODIFIED; - /* TODO: add check against index file st_mtime to avoid racy-git */ - if (S_ISGITLINK(nmode)) { if ((error = maybe_modified_submodule(&status, &noid, diff, info)) < 0) return error; @@ -839,7 +839,8 @@ static int maybe_modified( !diff_time_eq(&oitem->ctime, &nitem->ctime, use_nanos)) || oitem->ino != nitem->ino || oitem->uid != nitem->uid || - oitem->gid != nitem->gid) + oitem->gid != nitem->gid || + (index && nitem->mtime.seconds >= index->stamp.mtime)) { status = GIT_DELTA_MODIFIED; modified_uncertain = true; 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) diff --git a/src/iterator.c b/src/iterator.c index 7807a1636..d5f7eec34 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -1762,6 +1762,18 @@ int git_iterator_current_workdir_path(git_buf **path, git_iterator *iter) return 0; } +int git_iterator_index(git_index **out, git_iterator *iter) +{ + workdir_iterator *wi = (workdir_iterator *)iter; + + if (iter->type != GIT_ITERATOR_TYPE_WORKDIR) + *out = NULL; + + *out = wi->index; + + return 0; +} + int git_iterator_advance_over_with_status( const git_index_entry **entryptr, git_iterator_status_t *status, diff --git a/src/iterator.h b/src/iterator.h index db1f325a7..57f82416a 100644 --- a/src/iterator.h +++ b/src/iterator.h @@ -11,6 +11,7 @@ #include "git2/index.h" #include "vector.h" #include "buffer.h" +#include "ignore.h" typedef struct git_iterator git_iterator; @@ -286,4 +287,11 @@ typedef enum { extern int git_iterator_advance_over_with_status( const git_index_entry **entry, git_iterator_status_t *status, git_iterator *iter); +/** + * Retrieve the index stored in the iterator. + * + * Only implemented for the workdir iterator + */ +extern int git_iterator_index(git_index **out, git_iterator *iter); + #endif |
