diff options
author | Junio C Hamano <gitster@pobox.com> | 2016-10-28 09:01:15 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2016-10-28 09:01:15 -0700 |
commit | 42a9c6c0e2060327def808d9c4c2aa167d6d8934 (patch) | |
tree | aeaf7616738519ed6e8e930b0e57060713156836 | |
parent | e2f1d2c3179cae92c9502d10c13e25624726caa2 (diff) | |
parent | e8c42cb9ce6a566aad797cc6c5bc1279d608d819 (diff) | |
download | git-42a9c6c0e2060327def808d9c4c2aa167d6d8934.tar.gz |
Merge branch 'jk/ref-symlink-loop' into maint
A stray symbolic link in $GIT_DIR/refs/ directory could make name
resolution loop forever, which has been corrected.
* jk/ref-symlink-loop:
files_read_raw_ref: prevent infinite retry loops in general
files_read_raw_ref: avoid infinite loop on broken symlinks
-rw-r--r-- | refs/files-backend.c | 14 | ||||
-rwxr-xr-x | t/t1503-rev-parse-verify.sh | 5 |
2 files changed, 18 insertions, 1 deletions
diff --git a/refs/files-backend.c b/refs/files-backend.c index 12290d2496..2455564352 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -1451,6 +1451,7 @@ int read_raw_ref(const char *refname, unsigned char *sha1, int fd; int ret = -1; int save_errno; + int remaining_retries = 3; *type = 0; strbuf_reset(&sb_path); @@ -1466,8 +1467,14 @@ stat_ref: * <-> symlink) between the lstat() and reading, then * we don't want to report that as an error but rather * try again starting with the lstat(). + * + * We'll keep a count of the retries, though, just to avoid + * any confusing situation sending us into an infinite loop. */ + if (remaining_retries-- <= 0) + goto out; + if (lstat(path, &st) < 0) { if (errno != ENOENT) goto out; @@ -1496,6 +1503,11 @@ stat_ref: ret = 0; goto out; } + /* + * It doesn't look like a refname; fall through to just + * treating it like a non-symlink, and reading whatever it + * points to. + */ } /* Is it a directory? */ @@ -1519,7 +1531,7 @@ stat_ref: */ fd = open(path, O_RDONLY); if (fd < 0) { - if (errno == ENOENT) + if (errno == ENOENT && !S_ISLNK(st.st_mode)) /* inconsistent with lstat; retry */ goto stat_ref; else diff --git a/t/t1503-rev-parse-verify.sh b/t/t1503-rev-parse-verify.sh index ab27d0db5c..492edffa9c 100755 --- a/t/t1503-rev-parse-verify.sh +++ b/t/t1503-rev-parse-verify.sh @@ -139,4 +139,9 @@ test_expect_success 'master@{n} for various n' ' test_must_fail git rev-parse --verify master@{$Np1} ' +test_expect_success SYMLINKS 'ref resolution not confused by broken symlinks' ' + ln -s does-not-exist .git/refs/heads/broken && + test_must_fail git rev-parse --verify broken +' + test_done |