static int cmp_name(const void *p1, const void *p2) { const struct dir_entry *e1 = *(const struct dir_entry **)p1; const struct dir_entry *e2 = *(const struct dir_entry **)p2; return name_compare(e1->name, e1->len, e2->name, e2->len); }
/* * The tree traversal is looking at name p. If we have a matching entry, * return it. If name p is a directory in the index, do not return * anything, as we will want to match it when the traversal descends into * the directory. */ static int find_cache_pos(struct traverse_info *info, const struct name_entry *p) { int pos; struct unpack_trees_options *o = info->data; struct index_state *index = o->src_index; int pfxlen = info->pathlen; int p_len = tree_entry_len(p); for (pos = o->cache_bottom; pos < index->cache_nr; pos++) { const struct cache_entry *ce = index->cache[pos]; const char *ce_name, *ce_slash; int cmp, ce_len; if (ce->ce_flags & CE_UNPACKED) { /* * cache_bottom entry is already unpacked, so * we can never match it; don't check it * again. */ if (pos == o->cache_bottom) ++o->cache_bottom; continue; } if (!ce_in_traverse_path(ce, info)) continue; ce_name = ce->name + pfxlen; ce_slash = strchr(ce_name, '/'); if (ce_slash) ce_len = ce_slash - ce_name; else ce_len = ce_namelen(ce) - pfxlen; cmp = name_compare(p->path, p_len, ce_name, ce_len); /* * Exact match; if we have a directory we need to * delay returning it. */ if (!cmp) return ce_slash ? -2 - pos : pos; if (0 < cmp) continue; /* keep looking */ /* * ce_name sorts after p->path; could it be that we * have files under p->path directory in the index? * E.g. ce_name == "t-i", and p->path == "t"; we may * have "t/a" in the index. */ if (p_len < ce_len && !memcmp(ce_name, p->path, p_len) && ce_name[p_len] < '/') continue; /* keep looking */ break; } return -1; }
static int check_entry_match(const char *a, int a_len, const char *b, int b_len) { /* * The caller wants to pick *a* from a tree or nothing. * We are looking at *b* in a tree. * * (0) If a and b are the same name, we are trivially happy. * * There are three possibilities where *a* could be hiding * behind *b*. * * (1) *a* == "t", *b* == "ab" i.e. *b* sorts earlier than *a* no * matter what. * (2) *a* == "t", *b* == "t-2" and "t" is a subtree in the tree; * (3) *a* == "t-2", *b* == "t" and "t-2" is a blob in the tree. * * Otherwise we know *a* won't appear in the tree without * scanning further. */ int cmp = name_compare(a, a_len, b, b_len); /* Most common case first -- reading sync'd trees */ if (!cmp) return cmp; if (0 < cmp) { /* a comes after b; it does not matter if it is case (3) if (b_len < a_len && !memcmp(a, b, b_len) && a[b_len] < '/') return 1; */ return 1; /* keep looking */ } /* b comes after a; are we looking at case (2)? */ if (a_len < b_len && !memcmp(a, b, a_len) && b[a_len] < '/') return 1; /* keep looking */ return -1; /* a cannot appear in the tree */ }
int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info) { int ret = 0; struct name_entry *entry = xmalloc(n*sizeof(*entry)); int i; struct tree_desc_x *tx = xcalloc(n, sizeof(*tx)); for (i = 0; i < n; i++) tx[i].d = t[i]; for (;;) { unsigned long mask, dirmask; const char *first = NULL; int first_len = 0; struct name_entry *e; int len; for (i = 0; i < n; i++) { e = entry + i; extended_entry_extract(tx + i, e, NULL, 0); } /* * A tree may have "t-2" at the current location even * though it may have "t" that is a subtree behind it, * and another tree may return "t". We want to grab * all "t" from all trees to match in such a case. */ for (i = 0; i < n; i++) { e = entry + i; if (!e->path) continue; len = tree_entry_len(e->path, e->sha1); if (!first) { first = e->path; first_len = len; continue; } if (name_compare(e->path, len, first, first_len) < 0) { first = e->path; first_len = len; } } if (first) { for (i = 0; i < n; i++) { e = entry + i; extended_entry_extract(tx + i, e, first, first_len); /* Cull the ones that are not the earliest */ if (!e->path) continue; len = tree_entry_len(e->path, e->sha1); if (name_compare(e->path, len, first, first_len)) entry_clear(e); } } /* Now we have in entry[i] the earliest name from the trees */ mask = 0; dirmask = 0; for (i = 0; i < n; i++) { if (!entry[i].path) continue; mask |= 1ul << i; if (S_ISDIR(entry[i].mode)) dirmask |= 1ul << i; } if (!mask) break; ret = info->fn(n, mask, dirmask, entry, info); if (ret < 0) break; mask &= ret; ret = 0; for (i = 0; i < n; i++) if (mask & (1ul << i)) update_extended_entry(tx + i, entry + i); } free(entry); for (i = 0; i < n; i++) free_extended_entry(tx + i); free(tx); return ret; }
int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info) { int error = 0; struct name_entry *entry = xmalloc(n*sizeof(*entry)); int i; struct tree_desc_x *tx = xcalloc(n, sizeof(*tx)); struct strbuf base = STRBUF_INIT; int interesting = 1; for (i = 0; i < n; i++) tx[i].d = t[i]; if (info->prev) { strbuf_grow(&base, info->pathlen); make_traverse_path(base.buf, info->prev, &info->name); base.buf[info->pathlen-1] = '/'; strbuf_setlen(&base, info->pathlen); } for (;;) { int trees_used; unsigned long mask, dirmask; const char *first = NULL; int first_len = 0; struct name_entry *e = NULL; int len; for (i = 0; i < n; i++) { e = entry + i; extended_entry_extract(tx + i, e, NULL, 0); } /* * A tree may have "t-2" at the current location even * though it may have "t" that is a subtree behind it, * and another tree may return "t". We want to grab * all "t" from all trees to match in such a case. */ for (i = 0; i < n; i++) { e = entry + i; if (!e->path) continue; len = tree_entry_len(e); if (!first) { first = e->path; first_len = len; continue; } if (name_compare(e->path, len, first, first_len) < 0) { first = e->path; first_len = len; } } if (first) { for (i = 0; i < n; i++) { e = entry + i; extended_entry_extract(tx + i, e, first, first_len); /* Cull the ones that are not the earliest */ if (!e->path) continue; len = tree_entry_len(e); if (name_compare(e->path, len, first, first_len)) entry_clear(e); } } /* Now we have in entry[i] the earliest name from the trees */ mask = 0; dirmask = 0; for (i = 0; i < n; i++) { if (!entry[i].path) continue; mask |= 1ul << i; if (S_ISDIR(entry[i].mode)) dirmask |= 1ul << i; e = &entry[i]; } if (!mask) break; interesting = prune_traversal(e, info, &base, interesting); if (interesting < 0) break; if (interesting) { trees_used = info->fn(n, mask, dirmask, entry, info); if (trees_used < 0) { error = trees_used; if (!info->show_all_errors) break; } mask &= trees_used; } for (i = 0; i < n; i++) if (mask & (1ul << i)) update_extended_entry(tx + i, entry + i); } free(entry); for (i = 0; i < n; i++) free_extended_entry(tx + i); free(tx); strbuf_release(&base); return error; }