Subject: [PATCH] resolve_gitlink_packed_ref(): fix mismerge

From: Junio C Hamano <[email-masked]>
Date: Mon, 17 Oct 2011 11:43:30 -0700

2c5c66b (Merge branch 'jp/get-ref-dir-unsorted', 2011-10-10) merged a
topic that forked from the mainline before a new helper function
get_packed_refs() refactored code to read packed-refs file. The merge made
the call to the helper function with an incorrect argument. The parameter
to the function has to be a path to the submodule.

Fix the mismerge.

Helped-by: Mark Levedahl <[email-masked]>
Helped-by: Michael Haggerty <[email-masked]>
Signed-off-by: Junio C Hamano <[email-masked]>
---

  Junio C Hamano <[email-masked]> writes:

  > Michael Haggerty <[email-masked]> writes:
  > ...
  >> The problem is that the parameter "name" is not NUL-terminated.  The old
  >> code turned it into a (NUL-terminated) filename via
  >>
  >>     strcpy(name + pathlen, "packed-refs");
  >>
  >> but the new code passes it (unterminated) to get_packed_refs()

  Let's do this on the 'master' front while mh/refs-api and mh/refs-api-2
  (the new 14 patch series) are cooking in the 'next' branch. The added
  test does not pass until the second-to-last patch in your new series.

  I made trial merges of this with mh/refs-api and mh/refs-api-2 and both
  were trivial to resolve (merge with mh/refs-api will keep the fix, and
  merge with mh/refs-api-2 can be made by dropping this change), so this is
  purely as interim fix plus---the value of the patch lies primarily in the
  test for regression avoidance.

 refs.c                     |   12 +++++++++++-
 t/t3000-ls-files-others.sh |   19 +++++++++++++++++++
 2 files changed, 30 insertions(+), 1 deletions(-)

diff --git a/refs.c b/refs.c
index 9911c97..cab4394 100644
--- a/refs.c
+++ b/refs.c
@@ -393,12 +393,22 @@ static struct ref_array *get_loose_refs(const char *submodule)
 #define MAXDEPTH 5
 #define MAXREFLEN (1024)
 
+/*
+ * Called by resolve_gitlink_ref_recursive() after it failed to read
+ * from "name", which is "module/.git/<refname>". Find <refname> in
+ * the packed-refs file for the submodule.
+ */
 static int resolve_gitlink_packed_ref(char *name, int pathlen, const char *refname, unsigned char *result)
 {
 	int retval = -1;
 	struct ref_entry *ref;
-	struct ref_array *array = get_packed_refs(name);
+	struct ref_array *array;
 
+	/* being defensive: resolve_gitlink_ref() did this for us */
+	if (pathlen < 6 || memcmp(name + pathlen - 6, "/.git/", 6))
+		die("Oops");
+	name[pathlen - 6] = '\0'; /* make it path to the submodule */
+	array = get_packed_refs(name);
 	ref = search_ref_array(array, refname);
 	if (ref != NULL) {
 		memcpy(result, ref->sha1, 20);
diff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh
index 2eec011..e9160df 100755
--- a/t/t3000-ls-files-others.sh
+++ b/t/t3000-ls-files-others.sh
@@ -65,4 +65,23 @@ test_expect_success '--no-empty-directory hides empty directory' '
 	test_cmp expected3 output
 '
 
+test_expect_success SYMLINKS 'ls-files --others with symlinked submodule' '
+	git init super &&
+	git init sub &&
+	(
+		cd sub &&
+		>a &&
+		git add a &&
+		git commit -m sub &&
+		git pack-refs --all
+	) &&
+	(
+		cd super &&
+		"$TEST_DIRECTORY/../contrib/workdir/git-new-workdir" ../sub sub
+		git ls-files --others --exclude-standard >../actual
+	) &&
+	echo sub/ >expect &&
+	test_cmp expect actual
+'
+
 test_done
-- 
1.7.7.370.gefe43