static void extended_entry_extract(struct tree_desc_x *t, struct name_entry *a, const char *first, int first_len) { const char *path; int len; struct tree_desc probe; struct tree_desc_skip *skip; /* * Extract the first entry from the tree_desc, but skip the * ones that we already returned in earlier rounds. */ while (1) { if (!t->d.size) { entry_clear(a); break; /* not found */ } entry_extract(&t->d, a); for (skip = t->skip; skip; skip = skip->prev) if (a->path == skip->ptr) break; /* found */ if (!skip) break; /* We have processed this entry already. */ update_tree_entry(&t->d); } if (!first || !a->path) return; /* * The caller wants "first" from this tree, or nothing. */ path = a->path; len = tree_entry_len(a->path, a->sha1); switch (check_entry_match(first, first_len, path, len)) { case -1: entry_clear(a); case 0: return; default: break; } /* * We need to look-ahead -- we suspect that a subtree whose * name is "first" may be hiding behind the current entry "path". */ probe = t->d; while (probe.size) { entry_extract(&probe, a); path = a->path; len = tree_entry_len(a->path, a->sha1); switch (check_entry_match(first, first_len, path, len)) { case -1: entry_clear(a); case 0: return; default: update_tree_entry(&probe); break; } /* keep looking */ } entry_clear(a); }
int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info) { int ret = 0; struct name_entry *entry = xmalloc(n*sizeof(*entry)); for (;;) { unsigned long mask = 0; unsigned long dirmask = 0; int i, last; last = -1; for (i = 0; i < n; i++) { if (!t[i].size) continue; entry_extract(t+i, entry+i); if (last >= 0) { int cmp = entry_compare(entry+i, entry+last); /* * Is the new name bigger than the old one? * Ignore it */ if (cmp > 0) continue; /* * Is the new name smaller than the old one? * Ignore all old ones */ if (cmp < 0) mask = 0; } mask |= 1ul << i; if (S_ISDIR(entry[i].mode)) dirmask |= 1ul << i; last = i; } if (!mask) break; dirmask &= mask; /* * Clear all the unused name-entries. */ for (i = 0; i < n; i++) { if (mask & (1ul << i)) continue; entry_clear(entry + i); } ret = info->fn(n, mask, dirmask, entry, info); if (ret < 0) break; if (ret) mask &= ret; ret = 0; for (i = 0; i < n; i++) { if (mask & (1ul << i)) update_tree_entry(t + i); } } free(entry); return ret; }