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
This commit is contained in:
Junio C Hamano 2016-10-28 09:01:15 -07:00
commit 42a9c6c0e2
2 changed files with 18 additions and 1 deletions

View File

@ -1451,6 +1451,7 @@ int read_raw_ref(const char *refname, unsigned char *sha1,
int fd; int fd;
int ret = -1; int ret = -1;
int save_errno; int save_errno;
int remaining_retries = 3;
*type = 0; *type = 0;
strbuf_reset(&sb_path); strbuf_reset(&sb_path);
@ -1466,8 +1467,14 @@ stat_ref:
* <-> symlink) between the lstat() and reading, then * <-> symlink) between the lstat() and reading, then
* we don't want to report that as an error but rather * we don't want to report that as an error but rather
* try again starting with the lstat(). * 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 (lstat(path, &st) < 0) {
if (errno != ENOENT) if (errno != ENOENT)
goto out; goto out;
@ -1496,6 +1503,11 @@ stat_ref:
ret = 0; ret = 0;
goto out; 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? */ /* Is it a directory? */
@ -1519,7 +1531,7 @@ stat_ref:
*/ */
fd = open(path, O_RDONLY); fd = open(path, O_RDONLY);
if (fd < 0) { if (fd < 0) {
if (errno == ENOENT) if (errno == ENOENT && !S_ISLNK(st.st_mode))
/* inconsistent with lstat; retry */ /* inconsistent with lstat; retry */
goto stat_ref; goto stat_ref;
else else

View File

@ -139,4 +139,9 @@ test_expect_success 'master@{n} for various n' '
test_must_fail git rev-parse --verify master@{$Np1} 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 test_done