[PATCH v6 2/2] setup: allow cwd/.git to be a symlink to a directory
- From
Tian Yuchen <a3205153416@gmail.com>
- Date
- Feb 18, 2026, 12:46 UTC
- Message-ID
- <20260218124638.176936-3-a3205153416@gmail.com>
- In-Reply-To
- <20260218124638.176936-1-a3205153416@gmail.com>
Strictly enforcing 'lstat()' prevents valid '.git' symlinks.
Rely on 'stat()' (via 'read_gitfile_gently()') to handle filesystem resolution, instead of blocking it with strict logic checks in 'setup_git_directory_gently_1()'.
To ensure safety and correctness, we unconditionally delegate benign cases ('ENOENT', 'IS_A_DIR') and security risks ('NOT_A_FILE') to 'read_gitfile_error_die()'.
For other errors (like invalid format), we only invoke the handler if 'die_on_error' is true; otherwise, we return the error code to respect the gentle fallback behavior.
Add 't/t0009-git-dir-validation.sh' to verify symlink support and FIFO rejection, and register it in 't/meson.build'.
Signed-off-by: Tian Yuchen <a3205153416@gmail.com> --- setup.c | 21 ++++++---- t/meson.build | 1 + t/t0009-git-dir-validation.sh | 72 +++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 8 deletions(-) create mode 100755 t/t0009-git-dir-validation.sh
diff --git a/setup.c b/setup.c index d48b6a3a3d..f4b9d41f78 100644 --- a/setup.c +++ b/setup.c @@ -1590,15 +1590,20 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir, gitdirenv = read_gitfile_gently(dir->buf, die_on_error ? NULL : &error_code); if (!gitdirenv) { - if (die_on_error || - error_code == READ_GITFILE_ERR_NOT_A_FILE) { - /* NEEDSWORK: fail if .git is not file nor dir */ - if (is_git_directory(dir->buf)) { - gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT; - gitdir_path = xstrdup(dir->buf); + if (error_code){ + if (error_code == READ_GITFILE_ERR_STAT_ENOENT || + error_code == READ_GITFILE_ERR_IS_A_DIR || + error_code == READ_GITFILE_ERR_NOT_A_FILE || + die_on_error) { + read_gitfile_error_die(error_code, dir->buf, NULL); + } else { + return GIT_DIR_INVALID_GITFILE; } - } else if (error_code != READ_GITFILE_ERR_STAT_FAILED) - return GIT_DIR_INVALID_GITFILE; + } + if (is_git_directory(dir->buf)) { + gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT; + gitdir_path = xstrdup(dir->buf); + } } else gitfile = xstrdup(dir->buf); /* diff --git a/t/meson.build b/t/meson.build index f80e366cff..c4afaacee5 100644 --- a/t/meson.build +++ b/t/meson.build @@ -80,6 +80,7 @@ integration_tests = [ 't0006-date.sh', 't0007-git-var.sh', 't0008-ignores.sh', + 't0009-git-dir-validation.sh', 't0010-racy-git.sh', 't0012-help.sh', 't0013-sha1dc.sh', diff --git a/t/t0009-git-dir-validation.sh b/t/t0009-git-dir-validation.sh new file mode 100755 index 0000000000..9b3925c85f --- /dev/null +++ b/t/t0009-git-dir-validation.sh @@ -0,0 +1,72 @@ +#!/bin/sh + +test_description='setup: validation of .git file/directory types + +Verify that setup_git_directory() correctly handles: +1. Valid .git directories (including symlinks to them). +2. Invalid .git files (FIFOs, sockets) by erroring out. +3. Invalid .git files (garbage) by erroring out. +' + +. ./test-lib.sh + +test_expect_success 'setup: create parent git repository' ' + git init parent && + test_commit -C parent "root-commit" +' + +test_expect_success SYMLINKS 'setup: .git as a symlink to a directory is valid' ' + mkdir -p parent/link-to-dir && + ( + cd parent/link-to-dir && + git init real-repo && + ln -s real-repo/.git .git && + git rev-parse --git-dir >actual && + echo .git >expect && + test_cmp expect actual + ) +' + +test_expect_success PIPE 'setup: .git as a FIFO (named pipe) is rejected' ' + mkdir -p parent/fifo-trap && + ( + cd parent/fifo-trap && + mkfifo .git && + test_must_fail git rev-parse --git-dir 2>stderr && + grep "not a regular file" stderr + ) +' + +test_expect_success SYMLINKS,PIPE 'setup: .git as a symlink to a FIFO is rejected' ' + mkdir -p parent/symlink-fifo-trap && + ( + cd parent/symlink-fifo-trap && + mkfifo target-fifo && + ln -s target-fifo .git && + test_must_fail git rev-parse --git-dir 2>stderr && + grep "not a regular file" stderr + ) +' + +test_expect_success 'setup: .git with garbage content is rejected' ' + mkdir -p parent/garbage-trap && + ( + cd parent/garbage-trap && + echo "garbage" >.git && + test_must_fail git rev-parse --git-dir 2>stderr && + grep "invalid gitfile format" stderr + ) +' + +test_expect_success 'setup: .git as an empty directory is ignored' ' + mkdir -p parent/empty-dir && + ( + cd parent/empty-dir && + mkdir .git && + git rev-parse --git-dir >actual && + echo "$TRASH_DIRECTORY/parent/.git" >expect && + test_cmp expect actual + ) +' + +test_done
-- 2.43.0