summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2015-06-23 23:30:58 -0400
committerEdward Thomson <ethomson@edwardthomson.com>2015-06-23 23:30:58 -0400
commitbd670abd23944a20c6a84978ea590c8fd4258cb2 (patch)
treedf51120cb908816edcc098da00c433b51f28fbf4 /src
parent8351abc7822c38f597bf0ee07f0f293a4f62b1f3 (diff)
parentbb4896f22c9199e88b25a47ee4389a7e778d9d7f (diff)
downloadlibgit2-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.c7
-rw-r--r--src/index.c43
-rw-r--r--src/iterator.c12
-rw-r--r--src/iterator.h8
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