summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2014-07-25 17:43:59 +0700
committerJunio C Hamano <gitster@pobox.com>2014-07-30 12:54:43 -0700
commit98b23ccb48be9f50146ca9df5aa9b88369a4cad6 (patch)
tree1ecb6fa29bafb43bc7a8715e4547cda947748034
parent6fba9aa4719a8c4568cab321b17f7675e26e6e48 (diff)
downloadgit-nd/unify-ref-parse.tar.gz
refs.c: rewrite resolve_gitlink_ref() to use parse_ref()nd/unify-ref-parse
resolve_gitlink_ref_recursive() is less strict than the old resolve_ref_unsafe() (which is now parse_ref()). It also has another random limit 128 bytes for symrefs. This brings MAXREFLEN check to resolve_ref* family. It looks like an arbitrary limit though (added in 0ebde32 (Add 'resolve_gitlink_ref()' helper function - 2007-04-09) Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--refs.c68
1 files changed, 26 insertions, 42 deletions
diff --git a/refs.c b/refs.c
index 9a49c4033e..704e5b8e0e 100644
--- a/refs.c
+++ b/refs.c
@@ -1237,48 +1237,11 @@ static int resolve_gitlink_packed_ref(struct ref_cache *refs,
return 0;
}
-static int resolve_gitlink_ref_recursive(struct ref_cache *refs,
- const char *refname, unsigned char *sha1,
- int recursion)
-{
- int fd, len;
- char buffer[128], *p;
- char *path;
-
- if (recursion > MAXDEPTH || strlen(refname) > MAXREFLEN)
- return -1;
- path = *refs->name
- ? git_path_submodule(refs->name, "%s", refname)
- : git_path("%s", refname);
- fd = open(path, O_RDONLY);
- if (fd < 0)
- return resolve_gitlink_packed_ref(refs, refname, sha1);
-
- len = read(fd, buffer, sizeof(buffer)-1);
- close(fd);
- if (len < 0)
- return -1;
- while (len && isspace(buffer[len-1]))
- len--;
- buffer[len] = 0;
-
- /* Was it a detached head or an old-fashioned symlink? */
- if (!get_sha1_hex(buffer, sha1))
- return 0;
-
- /* Symref? */
- if (strncmp(buffer, "ref:", 4))
- return -1;
- p = buffer + 4;
- while (isspace(*p))
- p++;
-
- return resolve_gitlink_ref_recursive(refs, p, sha1, recursion+1);
-}
-
int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1)
{
- int len = strlen(path), retval;
+ struct strbuf result = STRBUF_INIT;
+ int len = strlen(path), retval = 0;
+ int depth = MAXDEPTH;
char *submodule;
struct ref_cache *refs;
@@ -1290,8 +1253,24 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh
refs = get_ref_cache(submodule);
free(submodule);
- retval = resolve_gitlink_ref_recursive(refs, refname, sha1, 0);
- return retval;
+ strbuf_addstr(&result, refname);
+ while (!retval) {
+ if (--depth < 0) {
+ errno = ELOOP;
+ retval = -1;
+ break;
+ }
+ path = *refs->name
+ ? git_path_submodule(refs->name, "%s", result.buf)
+ : git_path("%s", result.buf);
+ retval = parse_ref(path, &result, sha1, NULL);
+ if (retval == -2) {
+ retval = resolve_gitlink_packed_ref(refs, result.buf, sha1);
+ retval = retval ? -1 : 1;
+ }
+ }
+ strbuf_release(&result);
+ return retval > 0 ? 0 : -1;
}
/*
@@ -1341,6 +1320,11 @@ int parse_ref(const char *path, struct strbuf *ref,
struct stat st;
const char *buf;
+ if (ref->len > MAXREFLEN) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
/*
* We might have to loop back here to avoid a race condition:
* first we lstat() the file, then we try to read it as a link