config: resolve symlinks in conditional include's patterns

$GIT_DIR returned by get_git_dir() is normalized, with all symlinks resolved (see setup_work_tree function). In order to match paths (or patterns) against $GIT_DIR char-by-char, they have to be normalized too. There is a note in config.txt about this, that the user need to resolve symlinks by themselves if needed. The problem is, we allow certain path expansion, '~/' and './', for convenience and can't ask the user to resolve symlinks in these expansions. Make sure the expanded paths have all symlinks resolved. PS. The strbuf_realpath(&text, get_git_dir(), 1) is still needed because get_git_dir() may return relative path. Noticed-by: Torsten Bögershausen <tboegi@web.de> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Apr 5, 2017 at 17:24 UTC 86f951570839e241cfa8effbe195674193693a7f
2 files changed +57 -3
config.c
+3 -3
@@ -177,7 +177,7 @@ static int prepare_include_condition_pattern(struct strbuf *pat)
177 char *expanded;
178 int prefix = 0;
179
180 - expanded = expand_user_path(pat->buf, 0);
180 + expanded = expand_user_path(pat->buf, 1);
181 if (expanded) {
182 strbuf_reset(pat);
183 strbuf_addstr(pat, expanded);
@@ -191,7 +191,7 @@ static int prepare_include_condition_pattern(struct strbuf *pat)
191 return error(_("relative config include "
192 "conditionals must come from files"));
193
194 - strbuf_add_absolute_path(&path, cf->path);
194 + strbuf_realpath(&path, cf->path, 1);
195 slash = find_last_dir_sep(path.buf);
196 if (!slash)
197 die("BUG: how is this possible?");
@@ -213,7 +213,7 @@ static int include_by_gitdir(const char *cond, size_t cond_len, int icase)
213 struct strbuf pattern = STRBUF_INIT;
214 int ret = 0, prefix;
215
216 - strbuf_add_absolute_path(&text, get_git_dir());
216 + strbuf_realpath(&text, get_git_dir(), 1);
217 strbuf_add(&pattern, cond, cond_len);
218 prefix = prepare_include_condition_pattern(&pattern);
219
t/t1305-config-include.sh
+54
@@ -3,6 +3,16 @@
3 test_description='test config file include directives'
4 . ./test-lib.sh
5
6 +# Force setup_explicit_git_dir() to run until the end. This is needed
7 +# by some tests to make sure real_path() is called on $GIT_DIR. The
8 +# caller needs to make sure git commands are run from a subdirectory
9 +# though or real_path() will not be called.
10 +force_setup_explicit_git_dir() {
11 + GIT_DIR="$(pwd)/.git"
12 + GIT_WORK_TREE="$(pwd)"
13 + export GIT_DIR GIT_WORK_TREE
14 +}
15 +
16 test_expect_success 'include file by absolute path' '
17 echo "[test]one = 1" >one &&
18 echo "[include]path = \"$(pwd)/one\"" >.gitconfig &&
@@ -208,6 +218,50 @@ test_expect_success 'conditional include, both unanchored, icase' '
218 )
219 '
220
221 +test_expect_success SYMLINKS 'conditional include, set up symlinked $HOME' '
222 + mkdir real-home &&
223 + ln -s real-home home &&
224 + (
225 + HOME="$TRASH_DIRECTORY/home" &&
226 + export HOME &&
227 + cd "$HOME" &&
228 +
229 + git init foo &&
230 + cd foo &&
231 + mkdir sub
232 + )
233 +'
234 +
235 +test_expect_success SYMLINKS 'conditional include, $HOME expansion with symlinks' '
236 + (
237 + HOME="$TRASH_DIRECTORY/home" &&
238 + export HOME &&
239 + cd "$HOME"/foo &&
240 +
241 + echo "[includeIf \"gitdir:~/foo/\"]path=bar2" >>.git/config &&
242 + echo "[test]two=2" >.git/bar2 &&
243 + echo 2 >expect &&
244 + force_setup_explicit_git_dir &&
245 + git -C sub config test.two >actual &&
246 + test_cmp expect actual
247 + )
248 +'
249 +
250 +test_expect_success SYMLINKS 'conditional include, relative path with symlinks' '
251 + echo "[includeIf \"gitdir:./foo/.git\"]path=bar4" >home/.gitconfig &&
252 + echo "[test]four=4" >home/bar4 &&
253 + (
254 + HOME="$TRASH_DIRECTORY/home" &&
255 + export HOME &&
256 + cd "$HOME"/foo &&
257 +
258 + echo 4 >expect &&
259 + force_setup_explicit_git_dir &&
260 + git -C sub config test.four >actual &&
261 + test_cmp expect actual
262 + )
263 +'
264 +
265 test_expect_success 'include cycles are detected' '
266 cat >.gitconfig <<-\EOF &&
267 [test]value = gitconfig