]> git.proxmox.com Git - libgit2.git/commitdiff
Use correct case path in icase tree iterator
authorRussell Belfer <rb@github.com>
Mon, 11 Mar 2013 05:38:53 +0000 (22:38 -0700)
committerRussell Belfer <rb@github.com>
Mon, 11 Mar 2013 05:38:53 +0000 (22:38 -0700)
If there are case-ambiguities in the path of a case insensitive
tree iterator, it will now rewrite the entire path when it gives
the path name to an entry, so a tree with "A/b/C/d.txt" and
"a/B/c/E.txt" will give the true full paths (instead of case-
folding them both to "A/B/C/d.txt" or "a/b/c/E.txt" or something
like that.

src/iterator.c
tests-clar/repo/iterator.c

index 84664c0f884e51c6df779003f8001f7cd5c66ef7..53ec6f61bdfdc9527c999a81725a72c1348d071e 100644 (file)
@@ -189,11 +189,30 @@ typedef struct {
        tree_iterator_frame *head, *top;
        git_index_entry entry;
        git_buf path;
+       int path_ambiguities;
        bool path_has_filename;
        int (*strcomp)(const char *a, const char *b);
        int (*strncomp)(const char *a, const char *b, size_t sz);
 } tree_iterator;
 
+static const git_tree_entry *tree_iterator__get_tree_entry(
+       tree_iterator_frame *tf, const tree_iterator_entry *entry, size_t i)
+{
+       git_tree *tree;
+
+       if (!entry) {
+               if (i >= tf->n_entries)
+                       return NULL;
+               entry = &tf->entries[i];
+       }
+
+       tree = tf->parent->entries[entry->parent_entry_index].tree;
+       if (!tree)
+               return NULL;
+
+       return git_tree_entry_byindex(tree, entry->parent_tree_index);
+}
+
 static char *tree_iterator__current_filename(
        tree_iterator *ti, const git_tree_entry *te)
 {
@@ -210,39 +229,27 @@ static char *tree_iterator__current_filename(
        return ti->path.ptr;
 }
 
-static int tree_iterator__create_top_frame(tree_iterator *ti, git_tree *tree)
+static void tree_iterator__rewrite_filename(tree_iterator *ti)
 {
-       size_t sz = sizeof(tree_iterator_frame) + sizeof(tree_iterator_entry);
-       tree_iterator_frame *top = git__calloc(sz, sizeof(char));
-       GITERR_CHECK_ALLOC(top);
+       tree_iterator_frame *scan = ti->head;
+       size_t current = scan->current;
+       ssize_t strpos = ti->path.size;
+       const git_tree_entry *te;
 
-       top->n_entries = 1;
-       top->next = 1;
-       top->start = ti->base.start;
-       top->startlen = top->start ? strlen(top->start) : 0;
-       top->entries[0].tree = tree;
+       while (scan && scan->parent) {
+               tree_iterator_entry *entry = &scan->entries[current];
 
-       ti->head = ti->top = top;
+               te = tree_iterator__get_tree_entry(scan, entry, 0);
+               if (!te)
+                       break;
 
-       return 0;
-}
+               strpos -= te->filename_len;
+               memcpy(&ti->path.ptr[strpos], te->filename, te->filename_len);
+               strpos -= 1; /* separator */
 
-static const git_tree_entry *tree_iterator__get_tree_entry(
-       tree_iterator_frame *tf, const tree_iterator_entry *entry, size_t i)
-{
-       git_tree *tree;
-
-       if (!entry) {
-               if (i >= tf->n_entries)
-                       return NULL;
-               entry = &tf->entries[i];
+               current = entry->parent_entry_index;
+               scan = scan->parent;
        }
-
-       tree = tf->parent->entries[entry->parent_entry_index].tree;
-       if (!tree)
-               return NULL;
-
-       return git_tree_entry_byindex(tree, entry->parent_tree_index);
 }
 
 static int tree_iterator__entry_cmp(const void *a, const void *b, void *p)
@@ -290,6 +297,9 @@ static int tree_iterator__set_next(tree_iterator *ti, tree_iterator_frame *tf)
                last_te = te;
        }
 
+       if (tf->next > tf->current + 1)
+               ti->path_ambiguities++;
+
        if (last_te && !tree_iterator__current_filename(ti, last_te))
                return -1;
 
@@ -376,8 +386,12 @@ static int tree_iterator__push_frame(tree_iterator *ti)
        return 0;
 }
 
-static bool tree_iterator__move_to_next(tree_iterator_frame *tf)
+static bool tree_iterator__move_to_next(
+       tree_iterator *ti, tree_iterator_frame *tf)
 {
+       if (tf->next > tf->current + 1)
+               ti->path_ambiguities--;
+
        while (tf->current < tf->next) {
                if (tf->parent && tf->entries[tf->current].tree) {
                        git_tree_free(tf->entries[tf->current].tree);
@@ -396,7 +410,7 @@ static bool tree_iterator__pop_frame(tree_iterator *ti)
        if (!tf->parent)
                return false;
 
-       tree_iterator__move_to_next(tf);
+       tree_iterator__move_to_next(ti, tf);
 
        ti->head = tf->parent;
        ti->head->child = NULL;
@@ -427,6 +441,9 @@ static int tree_iterator__current(
        if (ti->entry.path == NULL)
                return -1;
 
+       if (ti->path_ambiguities > 0)
+               tree_iterator__rewrite_filename(ti);
+
        if (iterator__past_end(ti, ti->entry.path)) {
                while (tree_iterator__pop_frame(ti)) /* pop to top */;
                ti->head->current = ti->head->n_entries;
@@ -478,7 +495,7 @@ static int tree_iterator__advance(
        }
 
        /* scan forward and up, advancing in frame or popping frame when done */
-       while (!tree_iterator__move_to_next(tf) && tree_iterator__pop_frame(ti))
+       while (!tree_iterator__move_to_next(ti, tf) && tree_iterator__pop_frame(ti))
                tf = ti->head;
 
        /* find next and load trees */
@@ -510,6 +527,7 @@ static int tree_iterator__reset(
        if (iterator__reset_range(self, start, end) < 0)
                return -1;
        git_buf_clear(&ti->path);
+       ti->path_ambiguities = 0;
 
        return tree_iterator__push_frame(ti); /* re-expand top tree */
 }
@@ -537,6 +555,23 @@ static void tree_iterator__free(git_iterator *self)
        git_buf_free(&ti->path);
 }
 
+static int tree_iterator__create_top_frame(tree_iterator *ti, git_tree *tree)
+{
+       size_t sz = sizeof(tree_iterator_frame) + sizeof(tree_iterator_entry);
+       tree_iterator_frame *top = git__calloc(sz, sizeof(char));
+       GITERR_CHECK_ALLOC(top);
+
+       top->n_entries = 1;
+       top->next = 1;
+       top->start = ti->base.start;
+       top->startlen = top->start ? strlen(top->start) : 0;
+       top->entries[0].tree = tree;
+
+       ti->head = ti->top = top;
+
+       return 0;
+}
+
 int git_iterator_for_tree(
        git_iterator **iter,
        git_tree *tree,
index 63613e903a0f81c9efc4c9e85e14a8792da61bbd..804bc832453ae83c004d295bf3bdebdbb245b022 100644 (file)
@@ -456,7 +456,7 @@ void test_repo_iterator__tree_case_conflicts(void)
        const char *expect_cs[] = {
                "A/1.file", "A/3.file", "a/2.file", "a/4.file" };
        const char *expect_ci[] = {
-               "a/1.file", "a/2.file", "a/3.file", "a/4.file" };
+               "A/1.file", "a/2.file", "A/3.file", "a/4.file" };
 
        g_repo = cl_git_sandbox_init("icase");
 
@@ -479,7 +479,7 @@ void test_repo_iterator__tree_case_conflicts(void)
 
        cl_git_pass(git_iterator_for_tree(
                &i, tree, GIT_ITERATOR_IGNORE_CASE, NULL, NULL));
-       expect_iterator_items(i, 4, expect_ci, -4, expect_ci);
+       expect_iterator_items(i, 4, expect_ci, 4, expect_ci);
        git_iterator_free(i);
 
        git_tree_free(tree);