From 4546738b58a0134eef154231b07d60fc174d56e3 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 13 Oct 2005 11:03:18 -0700 Subject: Unlocalized isspace and friends Do our own ctype.h, just to get the sane semantics: we want locale-independence, _and_ we want the right signed behaviour. Plus we only use a very small subset of ctype.h anyway (isspace, isalpha, isdigit and isalnum). Signed-off-by: Junio C Hamano --- refs.c | 1 - 1 file changed, 1 deletion(-) (limited to 'refs.c') diff --git a/refs.c b/refs.c index 5a8cbd4ef3..42240d2769 100644 --- a/refs.c +++ b/refs.c @@ -2,7 +2,6 @@ #include "cache.h" #include -#include /* We allow "recursive" symbolic refs. Only within reason, though */ #define MAXDEPTH 5 -- cgit v1.3-5-g9baa 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 --- Makefile | 2 +- check-ref-format.c | 17 +++++++++++++++ git-branch.sh | 63 ++++++++++++++++++++++++++++++------------------------ git-checkout.sh | 2 ++ git-tag.sh | 2 ++ refs.c | 55 +++++++++++++++++++++++++++++++++++++++-------- 6 files changed, 103 insertions(+), 38 deletions(-) create mode 100644 check-ref-format.c (limited to 'refs.c') diff --git a/Makefile b/Makefile index 9fe65ba2be..523985566c 100644 --- a/Makefile +++ b/Makefile @@ -121,7 +121,7 @@ PROGRAMS = \ git-ssh-upload$X git-tar-tree$X git-unpack-file$X \ git-unpack-objects$X git-update-index$X git-update-server-info$X \ git-upload-pack$X git-verify-pack$X git-write-tree$X \ - git-update-ref$X git-symbolic-ref$X \ + git-update-ref$X git-symbolic-ref$X git-check-ref-format$X \ $(SIMPLE_PROGRAMS) # Backward compatibility -- to be removed after 1.0 diff --git a/check-ref-format.c b/check-ref-format.c new file mode 100644 index 0000000000..a0adb3dcb3 --- /dev/null +++ b/check-ref-format.c @@ -0,0 +1,17 @@ +/* + * GIT - The information manager from hell + */ + +#include "cache.h" +#include "refs.h" + +#include + +int main(int ac, char **av) +{ + if (ac != 2) + usage("git-check-ref-format refname"); + if (check_ref_format(av[1])) + exit(1); + return 0; +} diff --git a/git-branch.sh b/git-branch.sh index 074229c206..e2db9063d4 100755 --- a/git-branch.sh +++ b/git-branch.sh @@ -13,38 +13,42 @@ If two arguments, create a new branch based off of . } delete_branch () { - option="$1" branch_name="$2" + option="$1" + shift headref=$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD | sed -e 's|^refs/heads/||') - case ",$headref," in - ",$branch_name,") - die "Cannot delete the branch you are on." ;; - ,,) - die "What branch are you on anyway?" ;; - esac - branch=$(cat "$GIT_DIR/refs/heads/$branch_name") && - branch=$(git-rev-parse --verify "$branch^0") || - die "Seriously, what branch are you talking about?" - case "$option" in - -D) - ;; - *) - mbs=$(git-merge-base -a "$branch" HEAD | tr '\012' ' ') - case " $mbs " in - *' '$branch' '*) - # the merge base of branch and HEAD contains branch -- - # which means that the HEAD contains everything in the HEAD. + for branch_name + do + case ",$headref," in + ",$branch_name,") + die "Cannot delete the branch you are on." ;; + ,,) + die "What branch are you on anyway?" ;; + esac + branch=$(cat "$GIT_DIR/refs/heads/$branch_name") && + branch=$(git-rev-parse --verify "$branch^0") || + die "Seriously, what branch are you talking about?" + case "$option" in + -D) ;; *) - echo >&2 "The branch '$branch_name' is not a strict subset of your current HEAD. -If you are sure you want to delete it, run 'git branch -D $branch_name'." - exit 1 + mbs=$(git-merge-base -a "$branch" HEAD | tr '\012' ' ') + case " $mbs " in + *' '$branch' '*) + # the merge base of branch and HEAD contains branch -- + # which means that the HEAD contains everything in the HEAD. + ;; + *) + echo >&2 "The branch '$branch_name' is not a strict subset of your current HEAD. + If you are sure you want to delete it, run 'git branch -D $branch_name'." + exit 1 + ;; + esac ;; esac - ;; - esac - rm -f "$GIT_DIR/refs/heads/$branch_name" - echo "Deleted branch $branch_name." + rm -f "$GIT_DIR/refs/heads/$branch_name" + echo "Deleted branch $branch_name." + done exit 0 } @@ -52,7 +56,7 @@ while case "$#,$1" in 0,*) break ;; *,-*) ;; *) break ;; esac do case "$1" in -d | -D) - delete_branch "$1" "$2" + delete_branch "$@" exit ;; --) @@ -93,6 +97,9 @@ branchname="$1" rev=$(git-rev-parse --verify "$head") || exit -[ -e "$GIT_DIR/refs/heads/$branchname" ] && die "$branchname already exists" +[ -e "$GIT_DIR/refs/heads/$branchname" ] && + die "$branchname already exists." +git-check-ref-format "heads/$branchname" || + die "we do not like '$branchname' as a branch name." echo $rev > "$GIT_DIR/refs/heads/$branchname" diff --git a/git-checkout.sh b/git-checkout.sh index c3825904b6..2c053a33c3 100755 --- a/git-checkout.sh +++ b/git-checkout.sh @@ -17,6 +17,8 @@ while [ "$#" != "0" ]; do die "git checkout: -b needs a branch name" [ -e "$GIT_DIR/refs/heads/$newbranch" ] && die "git checkout: branch $newbranch already exists" + git-check-ref-format "heads/$newbranch" || + die "we do not like '$newbranch' as a branch name." ;; "-f") force=1 diff --git a/git-tag.sh b/git-tag.sh index 25c1a0e88e..faa766799d 100755 --- a/git-tag.sh +++ b/git-tag.sh @@ -53,6 +53,8 @@ if [ -e "$GIT_DIR/refs/tags/$name" -a -z "$force" ]; then die "tag '$name' already exists" fi shift +git-check-ref-format "tags/$name" || + die "we do not like '$name' as a tag name." object=$(git-rev-parse --verify --default HEAD "$@") || exit 1 type=$(git-cat-file -t $object) || exit 1 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.3-5-g9baa From 303958dc42d451aead0e1b9cf7b9836831a05f4b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 Oct 2005 01:40:31 +0200 Subject: create_symref: if symlink fails, fall back to writing a "symbolic ref" There are filesystems out there which do not understand symlinks, even if the OS is perfectly capable of writing them. So, do not fail right away, but try to write a symbolic ref first. If that fails, you can die(). Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- refs.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'refs.c') diff --git a/refs.c b/refs.c index 97506a4ebd..a52b038eef 100644 --- a/refs.c +++ b/refs.c @@ -116,14 +116,17 @@ const char *resolve_ref(const char *path, unsigned char *sha1, int reading) int create_symref(const char *git_HEAD, const char *refs_heads_master) { -#if USE_SYMLINK_HEAD - unlink(git_HEAD); - return symlink(refs_heads_master, git_HEAD); -#else const char *lockpath; char ref[1000]; int fd, len, written; +#if USE_SYMLINK_HEAD + unlink(git_HEAD); + if (!symlink(refs_heads_master, git_HEAD)) + return 0; + fprintf(stderr, "no symlink - falling back to symbolic ref\n"); +#endif + len = snprintf(ref, sizeof(ref), "ref: %s\n", refs_heads_master); if (sizeof(ref) <= len) { error("refname too long: %s", refs_heads_master); @@ -144,7 +147,6 @@ int create_symref(const char *git_HEAD, const char *refs_heads_master) return -3; } return 0; -#endif } int read_ref(const char *filename, unsigned char *sha1) -- cgit v1.3-5-g9baa