Commit 177890838a5d9165d621dfc32674ce5ecc41ee36

Carlos Martín Nieto 2016-04-01T14:33:42

ignore: don't use realpath to canonicalize path If we're looking for a symlink, realpath will give us the resolved path, which is not what we're after, but a canonicalized version of the path the user asked for.

diff --git a/src/ignore.c b/src/ignore.c
index aedc140..ac2af4f 100644
--- a/src/ignore.c
+++ b/src/ignore.c
@@ -263,10 +263,18 @@ int git_ignore__for_path(
 		goto cleanup;
 
 	/* given a unrooted path in a non-bare repo, resolve it */
-	if (workdir && git_path_root(path) < 0)
-		error = git_path_find_dir(&ignores->dir, path, workdir);
-	else
+	if (workdir && git_path_root(path) < 0) {
+		git_buf local = GIT_BUF_INIT;
+
+		if ((error = git_path_dirname_r(&local, path)) < 0 ||
+		    (error = git_path_resolve_relative(&local, 0)) < 0 ||
+		    (error = git_path_to_dir(&local)) < 0 ||
+		    (error = git_buf_joinpath(&ignores->dir, workdir, local.ptr)) < 0)
+		{;} /* Nothing, we just want to stop on the first error */
+		git_buf_free(&local);
+	} else {
 		error = git_buf_joinpath(&ignores->dir, path, "");
+	}
 	if (error < 0)
 		goto cleanup;
 
diff --git a/tests/attr/ignore.c b/tests/attr/ignore.c
index 27fed25..91bf984 100644
--- a/tests/attr/ignore.c
+++ b/tests/attr/ignore.c
@@ -252,3 +252,16 @@ void test_attr_ignore__dont_ignore_files_for_folder(void)
 	if (cl_repo_get_bool(g_repo, "core.ignorecase"))
 		assert_is_ignored(false, "dir/TeSt");
 }
+
+void test_attr_ignore__symlink_to_outside(void)
+{
+#ifdef GIT_WIN32
+	cl_skip();
+#endif
+
+	cl_git_rewritefile("attr/.gitignore", "symlink\n");
+	cl_git_mkfile("target", "target");
+	cl_git_pass(p_symlink("../target", "attr/symlink"));
+	assert_is_ignored(true, "symlink");
+	assert_is_ignored(true, "lala/../symlink");
+}