Lay groundwork for updating stat cache in diff This reorganized the diff OID calculation to make it easier to correctly update the stat cache during a diff once the flags to do so are enabled. This includes marking the path of a git_index_entry as const so we can make a "fake" git_index_entry with a "const char *" path and not get warnings. I was a little surprised at how unobtrusive this change was, but I think it's probably a good thing.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
diff --git a/include/git2/index.h b/include/git2/index.h
index 05e58a6..cdb8728 100644
--- a/include/git2/index.h
+++ b/include/git2/index.h
@@ -61,7 +61,7 @@ typedef struct git_index_entry {
unsigned short flags;
unsigned short flags_extended;
- char *path;
+ const char *path;
} git_index_entry;
/**
diff --git a/src/checkout.c b/src/checkout.c
index 93d6bc9..d94cb0c 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -184,8 +184,7 @@ static bool checkout_is_workdir_modified(
if (baseitem->size && wditem->file_size != baseitem->size)
return true;
- if (git_diff__oid_for_file(
- &oid, data->diff, wditem->path, wditem->mode, wditem->file_size) < 0)
+ if (git_diff__oid_for_entry(&oid, data->diff, wditem) < 0)
return false;
return (git_oid__cmp(&baseitem->id, &oid) != 0);
diff --git a/src/diff.c b/src/diff.c
index 4c028ca..eae4543 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -516,38 +516,52 @@ int git_diff__oid_for_file(
uint16_t mode,
git_off_t size)
{
+ git_index_entry entry;
+
+ memset(&entry, 0, sizeof(entry));
+ entry.mode = mode;
+ entry.file_size = size;
+ entry.path = (char *)path;
+
+ return git_diff__oid_for_entry(out, diff, &entry);
+}
+
+int git_diff__oid_for_entry(
+ git_oid *out, git_diff *diff, const git_index_entry *src)
+{
int error = 0;
git_buf full_path = GIT_BUF_INIT;
+ git_index_entry entry = *src;
git_filter_list *fl = NULL;
memset(out, 0, sizeof(*out));
if (git_buf_joinpath(
- &full_path, git_repository_workdir(diff->repo), path) < 0)
+ &full_path, git_repository_workdir(diff->repo), entry.path) < 0)
return -1;
- if (!mode) {
+ if (!entry.mode) {
struct stat st;
GIT_PERF_INC(diff->stat_calls);
if (p_stat(full_path.ptr, &st) < 0) {
- error = git_path_set_error(errno, path, "stat");
+ error = git_path_set_error(errno, entry.path, "stat");
git_buf_free(&full_path);
return error;
}
- mode = st.st_mode;
- size = st.st_size;
+ git_index_entry__init_from_stat(
+ &entry, &st, (diff->diffcaps & GIT_DIFFCAPS_TRUST_MODE_BITS) != 0);
}
/* calculate OID for file if possible */
- if (S_ISGITLINK(mode)) {
+ if (S_ISGITLINK(entry.mode)) {
git_submodule *sm;
GIT_PERF_INC(diff->submodule_lookups);
- if (!git_submodule_lookup(&sm, diff->repo, path)) {
+ if (!git_submodule_lookup(&sm, diff->repo, entry.path)) {
const git_oid *sm_oid = git_submodule_wd_id(sm);
if (sm_oid)
git_oid_cpy(out, sm_oid);
@@ -558,14 +572,15 @@ int git_diff__oid_for_file(
*/
giterr_clear();
}
- } else if (S_ISLNK(mode)) {
+ } else if (S_ISLNK(entry.mode)) {
GIT_PERF_INC(diff->oid_calculations);
error = git_odb__hashlink(out, full_path.ptr);
- } else if (!git__is_sizet(size)) {
- giterr_set(GITERR_OS, "File size overflow (for 32-bits) on '%s'", path);
+ } else if (!git__is_sizet(entry.file_size)) {
+ giterr_set(GITERR_OS, "File size overflow (for 32-bits) on '%s'",
+ entry.path);
error = -1;
} else if (!(error = git_filter_list_load(
- &fl, diff->repo, NULL, path, GIT_FILTER_TO_ODB)))
+ &fl, diff->repo, NULL, entry.path, GIT_FILTER_TO_ODB)))
{
int fd = git_futils_open_ro(full_path.ptr);
if (fd < 0)
@@ -573,13 +588,15 @@ int git_diff__oid_for_file(
else {
GIT_PERF_INC(diff->oid_calculations);
error = git_odb__hashfd_filtered(
- out, fd, (size_t)size, GIT_OBJ_BLOB, fl);
+ out, fd, (size_t)entry.file_size, GIT_OBJ_BLOB, fl);
p_close(fd);
}
git_filter_list_free(fl);
}
+ /* TODO: update index for entry if requested */
+
git_buf_free(&full_path);
return error;
}
@@ -759,8 +776,7 @@ static int maybe_modified(
*/
if (modified_uncertain && git_oid_iszero(&nitem->id)) {
if (git_oid_iszero(&noid)) {
- if ((error = git_diff__oid_for_file(&noid,
- diff, nitem->path, nitem->mode, nitem->file_size)) < 0)
+ if ((error = git_diff__oid_for_entry(&noid, diff, nitem)) < 0)
return error;
}
diff --git a/src/diff.h b/src/diff.h
index 491fc46..8fa3c9b 100644
--- a/src/diff.h
+++ b/src/diff.h
@@ -95,7 +95,9 @@ extern int git_diff_delta__format_file_header(
int oid_strlen);
extern int git_diff__oid_for_file(
- git_oid *oit, git_diff *, const char *, uint16_t, git_off_t);
+ git_oid *out, git_diff *, const char *, uint16_t, git_off_t);
+extern int git_diff__oid_for_entry(
+ git_oid *out, git_diff *, const git_index_entry *entry);
extern int git_diff__from_iterators(
git_diff **diff_ptr,
diff --git a/src/index.c b/src/index.c
index c044af4..8a7f292 100644
--- a/src/index.c
+++ b/src/index.c
@@ -842,7 +842,7 @@ static int index_entry_reuc_init(git_index_reuc_entry **reuc_out,
static void index_entry_cpy(git_index_entry *tgt, const git_index_entry *src)
{
- char *tgt_path = tgt->path;
+ const char *tgt_path = tgt->path;
memcpy(tgt, src, sizeof(*tgt));
tgt->path = tgt_path; /* reset to existing path data */
}
@@ -2282,9 +2282,7 @@ static int read_tree_cb(
entry->mode == old_entry->mode &&
git_oid_equal(&entry->id, &old_entry->id))
{
- char *oldpath = entry->path;
- memcpy(entry, old_entry, sizeof(*entry));
- entry->path = oldpath;
+ index_entry_cpy(entry, old_entry);
entry->flags_extended = 0;
}