Commit 0fc8e1f6bd9a5148d3a262142e9a70126f5c3a42

Russell Belfer 2014-04-28T14:34:55

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.

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;
 	}