int git_check_excluded_1(const char *pathname, int pathlen, const char *basename, int *dtype, EXCLUDE_LIST el, int ignorecase) { ignore_case = ignorecase; return is_excluded_from_list(pathname, pathlen, basename, dtype, el, &the_index); }
/* Whole directory matching */ static int clear_ce_flags_dir(struct cache_entry **cache, int nr, struct strbuf *prefix, char *basename, int select_mask, int clear_mask, struct exclude_list *el, int defval) { struct cache_entry **cache_end; int dtype = DT_DIR; int ret = is_excluded_from_list(prefix->buf, prefix->len, basename, &dtype, el); int rc; strbuf_addch(prefix, '/'); /* If undecided, use matching result of parent dir in defval */ if (ret < 0) ret = defval; for (cache_end = cache; cache_end != cache + nr; cache_end++) { struct cache_entry *ce = *cache_end; if (strncmp(ce->name, prefix->buf, prefix->len)) break; } /* * TODO: check el, if there are no patterns that may conflict * with ret (iow, we know in advance the incl/excl * decision for the entire directory), clear flag here without * calling clear_ce_flags_1(). That function will call * the expensive is_excluded_from_list() on every entry. */ rc = clear_ce_flags_1(cache, cache_end - cache, prefix, select_mask, clear_mask, el, ret); strbuf_setlen(prefix, prefix->len - 1); return rc; }
/* * Traverse the index, find every entry that matches according to * o->el. Do "ce_flags &= ~clear_mask" on those entries. Return the * number of traversed entries. * * If select_mask is non-zero, only entries whose ce_flags has on of * those bits enabled are traversed. * * cache : pointer to an index entry * prefix_len : an offset to its path * * The current path ("prefix") including the trailing '/' is * cache[0]->name[0..(prefix_len-1)] * Top level path has prefix_len zero. */ static int clear_ce_flags_1(struct cache_entry **cache, int nr, struct strbuf *prefix, int select_mask, int clear_mask, struct exclude_list *el, int defval) { struct cache_entry **cache_end = cache + nr; /* * Process all entries that have the given prefix and meet * select_mask condition */ while(cache != cache_end) { struct cache_entry *ce = *cache; const char *name, *slash; int len, dtype, ret; if (select_mask && !(ce->ce_flags & select_mask)) { cache++; continue; } if (prefix->len && strncmp(ce->name, prefix->buf, prefix->len)) break; name = ce->name + prefix->len; slash = strchr(name, '/'); /* If it's a directory, try whole directory match first */ if (slash) { int processed; len = slash - name; strbuf_add(prefix, name, len); processed = clear_ce_flags_dir(cache, cache_end - cache, prefix, prefix->buf + prefix->len - len, select_mask, clear_mask, el, defval); /* clear_c_f_dir eats a whole dir already? */ if (processed) { cache += processed; strbuf_setlen(prefix, prefix->len - len); continue; } strbuf_addch(prefix, '/'); cache += clear_ce_flags_1(cache, cache_end - cache, prefix, select_mask, clear_mask, el, defval); strbuf_setlen(prefix, prefix->len - len - 1); continue; } /* Non-directory */ dtype = ce_to_dtype(ce); ret = is_excluded_from_list(ce->name, ce_namelen(ce), name, &dtype, el); if (ret < 0) ret = defval; if (ret > 0) ce->ce_flags &= ~clear_mask; cache++; } return nr - (cache_end - cache); }
static enum list_objects_filter_result filter_sparse( struct repository *r, enum list_objects_filter_situation filter_situation, struct object *obj, const char *pathname, const char *filename, void *filter_data_) { struct filter_sparse_data *filter_data = filter_data_; int val, dtype; struct frame *frame; switch (filter_situation) { default: BUG("unknown filter_situation: %d", filter_situation); case LOFS_BEGIN_TREE: assert(obj->type == OBJ_TREE); dtype = DT_DIR; val = is_excluded_from_list(pathname, strlen(pathname), filename, &dtype, &filter_data->el, r->index); if (val < 0) val = filter_data->array_frame[filter_data->nr].defval; ALLOC_GROW(filter_data->array_frame, filter_data->nr + 1, filter_data->alloc); filter_data->nr++; filter_data->array_frame[filter_data->nr].defval = val; filter_data->array_frame[filter_data->nr].child_prov_omit = 0; /* * A directory with this tree OID may appear in multiple * places in the tree. (Think of a directory move or copy, * with no other changes, so the OID is the same, but the * full pathnames of objects within this directory are new * and may match is_excluded() patterns differently.) * So we cannot mark this directory as SEEN (yet), since * that will prevent process_tree() from revisiting this * tree object with other pathname prefixes. * * Only _DO_SHOW the tree object the first time we visit * this tree object. * * We always show all tree objects. A future optimization * may want to attempt to narrow this. */ if (obj->flags & FILTER_SHOWN_BUT_REVISIT) return LOFR_ZERO; obj->flags |= FILTER_SHOWN_BUT_REVISIT; return LOFR_DO_SHOW; case LOFS_END_TREE: assert(obj->type == OBJ_TREE); assert(filter_data->nr > 0); frame = &filter_data->array_frame[filter_data->nr]; filter_data->nr--; /* * Tell our parent directory if any of our children were * provisionally omitted. */ filter_data->array_frame[filter_data->nr].child_prov_omit |= frame->child_prov_omit; /* * If there are NO provisionally omitted child objects (ALL child * objects in this folder were INCLUDED), then we can mark the * folder as SEEN (so we will not have to revisit it again). */ if (!frame->child_prov_omit) return LOFR_MARK_SEEN; return LOFR_ZERO; case LOFS_BLOB: assert(obj->type == OBJ_BLOB); assert((obj->flags & SEEN) == 0); frame = &filter_data->array_frame[filter_data->nr]; dtype = DT_REG; val = is_excluded_from_list(pathname, strlen(pathname), filename, &dtype, &filter_data->el, r->index); if (val < 0) val = frame->defval; if (val > 0) { if (filter_data->omits) oidset_remove(filter_data->omits, &obj->oid); return LOFR_MARK_SEEN | LOFR_DO_SHOW; } /* * Provisionally omit it. We've already established that * this pathname is not in the sparse-checkout specification * with the CURRENT pathname, so we *WANT* to omit this blob. * * However, a pathname elsewhere in the tree may also * reference this same blob, so we cannot reject it yet. * Leave the LOFR_ bits unset so that if the blob appears * again in the traversal, we will be asked again. */ if (filter_data->omits) oidset_insert(filter_data->omits, &obj->oid); /* * Remember that at least 1 blob in this tree was * provisionally omitted. This prevents us from short * cutting the tree in future iterations. */ frame->child_prov_omit = 1; return LOFR_ZERO; } }
int git_check_excluded_1(const char *pathname, int pathlen, const char *basename, int *dtype, EXCLUDE_LIST el) { return is_excluded_from_list(pathname, pathlen, basename, dtype, el); }