X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;ds=inline;f=refs.c;h=b0555018995e5f029f3dd1d014e1ac9ef74c3672;hb=313fb010da4343eca22ee48a2cc18048d999de53;hp=6f313a9e0cdec2400a993cf7c3dfa87529a493ae;hpb=cfd2f0f5580a5524707693d4d055b18b519a325c;p=git.git diff --git a/refs.c b/refs.c index 6f313a9e0..b05550189 100644 --- a/refs.c +++ b/refs.c @@ -451,7 +451,7 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *re memcpy(gitdir + len, "/.git", 6); len += 5; - tmp = read_gitfile_gently(gitdir); + tmp = read_gitfile(gitdir); if (tmp) { free(gitdir); len = strlen(tmp); @@ -465,6 +465,23 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *re return retval; } +/* + * Try to read ref from the packed references. On success, set sha1 + * and return 0; otherwise, return -1. + */ +static int get_packed_ref(const char *ref, unsigned char *sha1) +{ + struct ref_list *list = get_packed_refs(NULL); + while (list) { + if (!strcmp(ref, list->name)) { + hashcpy(sha1, list->sha1); + return 0; + } + list = list->next; + } + return -1; +} + /* * If the "reading" argument is set, this function finds out what _object_ * the ref points at by "reading" the ref. The ref, if it is not symbolic, @@ -497,29 +514,36 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int * return NULL; git_snpath(path, sizeof(path), "%s", ref); - /* Special case: non-existing file. */ + if (lstat(path, &st) < 0) { - struct ref_list *list = get_packed_refs(NULL); - while (list) { - if (!strcmp(ref, list->name)) { - hashcpy(sha1, list->sha1); - if (flag) - *flag |= REF_ISPACKED; - return ref; - } - list = list->next; + if (errno != ENOENT) + return NULL; + /* + * The loose reference file does not exist; + * check for a packed reference. + */ + if (!get_packed_ref(ref, sha1)) { + if (flag) + *flag |= REF_ISPACKED; + return ref; } - if (reading || errno != ENOENT) + /* The reference is not a packed reference, either. */ + if (reading) { return NULL; - hashclr(sha1); - return ref; + } else { + hashclr(sha1); + return ref; + } } /* Follow "normalized" - ie "refs/.." symlinks by hand */ if (S_ISLNK(st.st_mode)) { len = readlink(path, buffer, sizeof(buffer)-1); - if (len >= 5 && !memcmp("refs/", buffer, 5)) { - buffer[len] = 0; + if (len < 0) + return NULL; + buffer[len] = 0; + if (!prefixcmp(buffer, "refs/") && + !check_refname_format(buffer, 0)) { strcpy(ref_buffer, buffer); ref = ref_buffer; if (flag) @@ -543,25 +567,30 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int * return NULL; len = read_in_full(fd, buffer, sizeof(buffer)-1); close(fd); + if (len < 0) + return NULL; + while (len && isspace(buffer[len-1])) + len--; + buffer[len] = '\0'; /* * Is it a symbolic ref? */ - if (len < 4 || memcmp("ref:", buffer, 4)) + if (prefixcmp(buffer, "ref:")) break; buf = buffer + 4; - len -= 4; - while (len && isspace(*buf)) - buf++, len--; - while (len && isspace(buf[len-1])) - len--; - buf[len] = 0; - memcpy(ref_buffer, buf, len + 1); - ref = ref_buffer; + while (isspace(*buf)) + buf++; + if (check_refname_format(buf, REFNAME_ALLOW_ONELEVEL)) { + warning("symbolic reference in %s is formatted incorrectly", + path); + return NULL; + } + ref = strcpy(ref_buffer, buf); if (flag) *flag |= REF_ISSYMREF; } - if (len < 40 || get_sha1_hex(buffer, sha1)) + if (get_sha1_hex(buffer, sha1)) return NULL; return ref; } @@ -860,70 +889,79 @@ int for_each_rawref(each_ref_fn fn, void *cb_data) * - it contains a "\" (backslash) */ +/* Return true iff ch is not allowed in reference names. */ static inline int bad_ref_char(int ch) { - if (((unsigned) ch) <= ' ' || + if (((unsigned) ch) <= ' ' || ch == 0x7f || ch == '~' || ch == '^' || ch == ':' || ch == '\\') return 1; /* 2.13 Pattern Matching Notation */ - if (ch == '?' || ch == '[') /* Unsupported */ + if (ch == '*' || ch == '?' || ch == '[') /* Unsupported */ return 1; - if (ch == '*') /* Supported at the end */ - return 2; return 0; } -int check_ref_format(const char *ref) +/* + * Try to read one refname component from the front of ref. Return + * the length of the component found, or -1 if the component is not + * legal. + */ +static int check_refname_component(const char *ref) { - int ch, level, bad_type, last; - int ret = CHECK_REF_FORMAT_OK; - const char *cp = ref; - - level = 0; - while (1) { - while ((ch = *cp++) == '/') - ; /* tolerate duplicated slashes */ - if (!ch) - /* should not end with slashes */ - return CHECK_REF_FORMAT_ERROR; - - /* we are at the beginning of the path component */ - if (ch == '.') - return CHECK_REF_FORMAT_ERROR; - bad_type = bad_ref_char(ch); - if (bad_type) { - if (bad_type == 2 && (!*cp || *cp == '/') && - ret == CHECK_REF_FORMAT_OK) - ret = CHECK_REF_FORMAT_WILDCARD; - else - return CHECK_REF_FORMAT_ERROR; - } + const char *cp; + char last = '\0'; + for (cp = ref; ; cp++) { + char ch = *cp; + if (ch == '\0' || ch == '/') + break; + if (bad_ref_char(ch)) + return -1; /* Illegal character in refname. */ + if (last == '.' && ch == '.') + return -1; /* Refname contains "..". */ + if (last == '@' && ch == '{') + return -1; /* Refname contains "@{". */ last = ch; - /* scan the rest of the path component */ - while ((ch = *cp++) != 0) { - bad_type = bad_ref_char(ch); - if (bad_type) - return CHECK_REF_FORMAT_ERROR; - if (ch == '/') - break; - if (last == '.' && ch == '.') - return CHECK_REF_FORMAT_ERROR; - if (last == '@' && ch == '{') - return CHECK_REF_FORMAT_ERROR; - last = ch; - } - level++; - if (!ch) { - if (ref <= cp - 2 && cp[-2] == '.') - return CHECK_REF_FORMAT_ERROR; - if (level < 2) - return CHECK_REF_FORMAT_ONELEVEL; - if (has_extension(ref, ".lock")) - return CHECK_REF_FORMAT_ERROR; - return ret; + } + if (cp == ref) + return -1; /* Component has zero length. */ + if (ref[0] == '.') + return -1; /* Component starts with '.'. */ + if (cp - ref >= 5 && !memcmp(cp - 5, ".lock", 5)) + return -1; /* Refname ends with ".lock". */ + return cp - ref; +} + +int check_refname_format(const char *ref, int flags) +{ + int component_len, component_count = 0; + + while (1) { + /* We are at the start of a path component. */ + component_len = check_refname_component(ref); + if (component_len < 0) { + if ((flags & REFNAME_REFSPEC_PATTERN) && + ref[0] == '*' && + (ref[1] == '\0' || ref[1] == '/')) { + /* Accept one wildcard as a full refname component. */ + flags &= ~REFNAME_REFSPEC_PATTERN; + component_len = 1; + } else { + return -1; + } } + component_count++; + if (ref[component_len] == '\0') + break; + /* Skip to next component. */ + ref += component_len + 1; } + + if (ref[component_len - 1] == '.') + return -1; /* Refname ends with '.'. */ + if (!(flags & REFNAME_ALLOW_ONELEVEL) && component_count < 2) + return -1; /* Refname has only one component. */ + return 0; } const char *prettify_refname(const char *name) @@ -1106,7 +1144,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char struct ref_lock *lock_ref_sha1(const char *ref, const unsigned char *old_sha1) { char refpath[PATH_MAX]; - if (check_ref_format(ref)) + if (check_refname_format(ref, 0)) return NULL; strcpy(refpath, mkpath("refs/%s", ref)); return lock_ref_sha1_basic(refpath, old_sha1, 0, NULL); @@ -1114,13 +1152,9 @@ struct ref_lock *lock_ref_sha1(const char *ref, const unsigned char *old_sha1) struct ref_lock *lock_any_ref_for_update(const char *ref, const unsigned char *old_sha1, int flags) { - switch (check_ref_format(ref)) { - default: + if (check_refname_format(ref, REFNAME_ALLOW_ONELEVEL)) return NULL; - case 0: - case CHECK_REF_FORMAT_ONELEVEL: - return lock_ref_sha1_basic(ref, old_sha1, flags, NULL); - } + return lock_ref_sha1_basic(ref, old_sha1, flags, NULL); } static struct lock_file packlock;