From e6629d8313bcc4e1ca1213ef6d78db09b3a8f8ac Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 13 Jul 2011 03:36:03 +0200 Subject: [PATCH] tree: More accurate matching on entries The old matcher was returning fake matches when given stupid entry names. E.g. `git2` could be matched by `git2 /`, `git2/foobar`, git2/////` and other stupid stuff --- src/tree.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/tree.c b/src/tree.c index de557d2ae..114181f1b 100644 --- a/src/tree.c +++ b/src/tree.c @@ -47,9 +47,12 @@ int entry_search_cmp(const void *key, const void *array_member) struct tree_key_search *ksearch = (struct tree_key_search *)key; const git_tree_entry *entry = (const git_tree_entry *)(array_member); - return git_futils_cmp_path( - ksearch->filename, ksearch->filename_len, entry->attr & 040000, - entry->filename, entry->filename_len, entry->attr & 040000); + int result = + git_futils_cmp_path( + ksearch->filename, ksearch->filename_len, entry->attr & 040000, + entry->filename, entry->filename_len, entry->attr & 040000); + + return result ? result : ((int)ksearch->filename_len - (int)entry->filename_len); } int entry_sort_cmp(const void *a, const void *b) @@ -62,6 +65,22 @@ int entry_sort_cmp(const void *a, const void *b) entry_b->filename, entry_b->filename_len, entry_b->attr & 040000); } +static int build_ksearch(struct tree_key_search *ksearch, const char *path) +{ + size_t len = strlen(path); + + if (len && path[len - 1] == '/') + len--; + + if (len == 0 || memchr(path, '/', len) != NULL) + return GIT_ERROR; + + ksearch->filename = path; + ksearch->filename_len = len; + + return GIT_SUCCESS; +} + void git_tree__free(git_tree *tree) { unsigned int i; @@ -125,8 +144,8 @@ const git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename assert(tree && filename); - ksearch.filename = filename; - ksearch.filename_len = strlen(filename); + if (build_ksearch(&ksearch, filename) < GIT_SUCCESS) + return NULL; idx = git_vector_bsearch2(&tree->entries, entry_search_cmp, &ksearch); if (idx == GIT_ENOTFOUND) @@ -362,10 +381,8 @@ int git_treebuilder_insert(git_tree_entry **entry_out, git_treebuilder *bld, con if (!valid_attributes(attributes)) return git__throw(GIT_ERROR, "Failed to insert entry. Invalid atrributes"); - ksearch.filename = filename; - ksearch.filename_len = strlen(filename); - - if ((pos = git_vector_bsearch2(&bld->entries, entry_search_cmp, &ksearch)) != GIT_ENOTFOUND) { + if (build_ksearch(&ksearch, filename) == GIT_SUCCESS && + (pos = git_vector_bsearch2(&bld->entries, entry_search_cmp, &ksearch)) != GIT_ENOTFOUND) { entry = git_vector_get(&bld->entries, pos); if (entry->removed) { entry->removed = 0; @@ -404,8 +421,8 @@ const git_tree_entry *git_treebuilder_get(git_treebuilder *bld, const char *file assert(bld && filename); - ksearch.filename = filename; - ksearch.filename_len = strlen(filename); + if (build_ksearch(&ksearch, filename) < GIT_SUCCESS) + return NULL; sort_entries(bld); idx = git_vector_bsearch2(&bld->entries, entry_search_cmp, &ksearch);