From 03feddd6e8e779086ac2d131ded325f8e5601653 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 13 Oct 2005 18:57:39 -0700 Subject: git-check-ref-format: reject funny ref names. Update check_ref_format() function to reject ref names that: * has a path component that begins with a ".", or * has a double dots "..", or * has ASCII control character, "~", "^", ":" or SP, anywhere, or * ends with a "/". Use it in 'git-checkout -b', 'git-branch', and 'git-tag' to make sure that newly created refs are well-formed. Signed-off-by: Junio C Hamano --- refs.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 9 deletions(-) (limited to 'refs.c') diff --git a/refs.c b/refs.c index 42240d2769..97506a4ebd 100644 --- a/refs.c +++ b/refs.c @@ -334,17 +334,54 @@ int write_ref_sha1(const char *ref, int fd, const unsigned char *sha1) return retval; } +/* + * Make sure "ref" is something reasonable to have under ".git/refs/"; + * We do not like it if: + * + * - any path component of it begins with ".", or + * - it has double dots "..", or + * - it has ASCII control character, "~", "^", ":" or SP, anywhere, or + * - it ends with a "/". + */ + +static inline int bad_ref_char(int ch) +{ + return (((unsigned) ch) <= ' ' || + ch == '~' || ch == '^' || ch == ':'); +} + int check_ref_format(const char *ref) { - char *middle; - if (ref[0] == '.' || ref[0] == '/') - return -1; - middle = strchr(ref, '/'); - if (!middle || !middle[1]) - return -1; - if (strchr(middle + 1, '/')) - return -1; - return 0; + int ch, level; + const char *cp = ref; + + level = 0; + while (1) { + while ((ch = *cp++) == '/') + ; /* tolerate duplicated slashes */ + if (!ch) + return -1; /* should not end with slashes */ + + /* we are at the beginning of the path component */ + if (ch == '.' || bad_ref_char(ch)) + return -1; + + /* scan the rest of the path component */ + while ((ch = *cp++) != 0) { + if (bad_ref_char(ch)) + return -1; + if (ch == '/') + break; + if (ch == '.' && *cp == '.') + return -1; + } + level++; + if (!ch) { + if (level < 2) + return -1; /* at least of form "heads/blah" */ + return 0; + } + } } int write_ref_sha1_unlocked(const char *ref, const unsigned char *sha1) -- cgit v1.2.3