1#include"cache.h" 2#include"dir.h" 3#include"tag.h" 4#include"commit.h" 5#include"tree.h" 6#include"blob.h" 7#include"diff.h" 8#include"tree-walk.h" 9#include"revision.h" 10#include"list-objects.h" 11#include"list-objects-filter.h" 12#include"list-objects-filter-options.h" 13#include"oidset.h" 14 15/* Remember to update object flag allocation in object.h */ 16/* 17 * FILTER_SHOWN_BUT_REVISIT -- we set this bit on tree objects 18 * that have been shown, but should be revisited if they appear 19 * in the traversal (until we mark it SEEN). This is a way to 20 * let us silently de-dup calls to show() in the caller. This 21 * is subtly different from the "revision.h:SHOWN" and the 22 * "sha1-name.c:ONELINE_SEEN" bits. And also different from 23 * the non-de-dup usage in pack-bitmap.c 24 */ 25#define FILTER_SHOWN_BUT_REVISIT (1<<21) 26 27/* 28 * A filter for list-objects to omit ALL blobs from the traversal. 29 * And to OPTIONALLY collect a list of the omitted OIDs. 30 */ 31struct filter_blobs_none_data { 32struct oidset *omits; 33}; 34 35static enum list_objects_filter_result filter_blobs_none( 36enum list_objects_filter_situation filter_situation, 37struct object *obj, 38const char*pathname, 39const char*filename, 40void*filter_data_) 41{ 42struct filter_blobs_none_data *filter_data = filter_data_; 43 44switch(filter_situation) { 45default: 46die("unknown filter_situation"); 47return LOFR_ZERO; 48 49case LOFS_BEGIN_TREE: 50assert(obj->type == OBJ_TREE); 51/* always include all tree objects */ 52return LOFR_MARK_SEEN | LOFR_DO_SHOW; 53 54case LOFS_END_TREE: 55assert(obj->type == OBJ_TREE); 56return LOFR_ZERO; 57 58case LOFS_BLOB: 59assert(obj->type == OBJ_BLOB); 60assert((obj->flags & SEEN) ==0); 61 62if(filter_data->omits) 63oidset_insert(filter_data->omits, &obj->oid); 64return LOFR_MARK_SEEN;/* but not LOFR_DO_SHOW (hard omit) */ 65} 66} 67 68static void*filter_blobs_none__init( 69struct oidset *omitted, 70struct list_objects_filter_options *filter_options, 71 filter_object_fn *filter_fn, 72 filter_free_fn *filter_free_fn) 73{ 74struct filter_blobs_none_data *d =xcalloc(1,sizeof(*d)); 75 d->omits = omitted; 76 77*filter_fn = filter_blobs_none; 78*filter_free_fn = free; 79return d; 80} 81 82/* 83 * A filter for list-objects to omit large blobs. 84 * And to OPTIONALLY collect a list of the omitted OIDs. 85 */ 86struct filter_blobs_limit_data { 87struct oidset *omits; 88unsigned long max_bytes; 89}; 90 91static enum list_objects_filter_result filter_blobs_limit( 92enum list_objects_filter_situation filter_situation, 93struct object *obj, 94const char*pathname, 95const char*filename, 96void*filter_data_) 97{ 98struct filter_blobs_limit_data *filter_data = filter_data_; 99unsigned long object_length; 100enum object_type t; 101 102switch(filter_situation) { 103default: 104die("unknown filter_situation"); 105return LOFR_ZERO; 106 107case LOFS_BEGIN_TREE: 108assert(obj->type == OBJ_TREE); 109/* always include all tree objects */ 110return LOFR_MARK_SEEN | LOFR_DO_SHOW; 111 112case LOFS_END_TREE: 113assert(obj->type == OBJ_TREE); 114return LOFR_ZERO; 115 116case LOFS_BLOB: 117assert(obj->type == OBJ_BLOB); 118assert((obj->flags & SEEN) ==0); 119 120 t =oid_object_info(the_repository, &obj->oid, &object_length); 121if(t != OBJ_BLOB) {/* probably OBJ_NONE */ 122/* 123 * We DO NOT have the blob locally, so we cannot 124 * apply the size filter criteria. Be conservative 125 * and force show it (and let the caller deal with 126 * the ambiguity). 127 */ 128goto include_it; 129} 130 131if(object_length < filter_data->max_bytes) 132goto include_it; 133 134if(filter_data->omits) 135oidset_insert(filter_data->omits, &obj->oid); 136return LOFR_MARK_SEEN;/* but not LOFR_DO_SHOW (hard omit) */ 137} 138 139include_it: 140if(filter_data->omits) 141oidset_remove(filter_data->omits, &obj->oid); 142return LOFR_MARK_SEEN | LOFR_DO_SHOW; 143} 144 145static void*filter_blobs_limit__init( 146struct oidset *omitted, 147struct list_objects_filter_options *filter_options, 148 filter_object_fn *filter_fn, 149 filter_free_fn *filter_free_fn) 150{ 151struct filter_blobs_limit_data *d =xcalloc(1,sizeof(*d)); 152 d->omits = omitted; 153 d->max_bytes = filter_options->blob_limit_value; 154 155*filter_fn = filter_blobs_limit; 156*filter_free_fn = free; 157return d; 158} 159 160/* 161 * A filter driven by a sparse-checkout specification to only 162 * include blobs that a sparse checkout would populate. 163 * 164 * The sparse-checkout spec can be loaded from a blob with the 165 * given OID or from a local pathname. We allow an OID because 166 * the repo may be bare or we may be doing the filtering on the 167 * server. 168 */ 169struct frame { 170/* 171 * defval is the usual default include/exclude value that 172 * should be inherited as we recurse into directories based 173 * upon pattern matching of the directory itself or of a 174 * containing directory. 175 */ 176int defval; 177 178/* 179 * 1 if the directory (recursively) contains any provisionally 180 * omitted objects. 181 * 182 * 0 if everything (recursively) contained in this directory 183 * has been explicitly included (SHOWN) in the result and 184 * the directory may be short-cut later in the traversal. 185 */ 186unsigned child_prov_omit :1; 187}; 188 189struct filter_sparse_data { 190struct oidset *omits; 191struct exclude_list el; 192 193size_t nr, alloc; 194struct frame *array_frame; 195}; 196 197static enum list_objects_filter_result filter_sparse( 198enum list_objects_filter_situation filter_situation, 199struct object *obj, 200const char*pathname, 201const char*filename, 202void*filter_data_) 203{ 204struct filter_sparse_data *filter_data = filter_data_; 205int val, dtype; 206struct frame *frame; 207 208switch(filter_situation) { 209default: 210die("unknown filter_situation"); 211return LOFR_ZERO; 212 213case LOFS_BEGIN_TREE: 214assert(obj->type == OBJ_TREE); 215 dtype = DT_DIR; 216 val =is_excluded_from_list(pathname,strlen(pathname), 217 filename, &dtype, &filter_data->el, 218&the_index); 219if(val <0) 220 val = filter_data->array_frame[filter_data->nr].defval; 221 222ALLOC_GROW(filter_data->array_frame, filter_data->nr +1, 223 filter_data->alloc); 224 filter_data->nr++; 225 filter_data->array_frame[filter_data->nr].defval = val; 226 filter_data->array_frame[filter_data->nr].child_prov_omit =0; 227 228/* 229 * A directory with this tree OID may appear in multiple 230 * places in the tree. (Think of a directory move or copy, 231 * with no other changes, so the OID is the same, but the 232 * full pathnames of objects within this directory are new 233 * and may match is_excluded() patterns differently.) 234 * So we cannot mark this directory as SEEN (yet), since 235 * that will prevent process_tree() from revisiting this 236 * tree object with other pathname prefixes. 237 * 238 * Only _DO_SHOW the tree object the first time we visit 239 * this tree object. 240 * 241 * We always show all tree objects. A future optimization 242 * may want to attempt to narrow this. 243 */ 244if(obj->flags & FILTER_SHOWN_BUT_REVISIT) 245return LOFR_ZERO; 246 obj->flags |= FILTER_SHOWN_BUT_REVISIT; 247return LOFR_DO_SHOW; 248 249case LOFS_END_TREE: 250assert(obj->type == OBJ_TREE); 251assert(filter_data->nr >0); 252 253 frame = &filter_data->array_frame[filter_data->nr]; 254 filter_data->nr--; 255 256/* 257 * Tell our parent directory if any of our children were 258 * provisionally omitted. 259 */ 260 filter_data->array_frame[filter_data->nr].child_prov_omit |= 261 frame->child_prov_omit; 262 263/* 264 * If there are NO provisionally omitted child objects (ALL child 265 * objects in this folder were INCLUDED), then we can mark the 266 * folder as SEEN (so we will not have to revisit it again). 267 */ 268if(!frame->child_prov_omit) 269return LOFR_MARK_SEEN; 270return LOFR_ZERO; 271 272case LOFS_BLOB: 273assert(obj->type == OBJ_BLOB); 274assert((obj->flags & SEEN) ==0); 275 276 frame = &filter_data->array_frame[filter_data->nr]; 277 278 dtype = DT_REG; 279 val =is_excluded_from_list(pathname,strlen(pathname), 280 filename, &dtype, &filter_data->el, 281&the_index); 282if(val <0) 283 val = frame->defval; 284if(val >0) { 285if(filter_data->omits) 286oidset_remove(filter_data->omits, &obj->oid); 287return LOFR_MARK_SEEN | LOFR_DO_SHOW; 288} 289 290/* 291 * Provisionally omit it. We've already established that 292 * this pathname is not in the sparse-checkout specification 293 * with the CURRENT pathname, so we *WANT* to omit this blob. 294 * 295 * However, a pathname elsewhere in the tree may also 296 * reference this same blob, so we cannot reject it yet. 297 * Leave the LOFR_ bits unset so that if the blob appears 298 * again in the traversal, we will be asked again. 299 */ 300if(filter_data->omits) 301oidset_insert(filter_data->omits, &obj->oid); 302 303/* 304 * Remember that at least 1 blob in this tree was 305 * provisionally omitted. This prevents us from short 306 * cutting the tree in future iterations. 307 */ 308 frame->child_prov_omit =1; 309return LOFR_ZERO; 310} 311} 312 313 314static voidfilter_sparse_free(void*filter_data) 315{ 316struct filter_sparse_data *d = filter_data; 317/* TODO free contents of 'd' */ 318free(d); 319} 320 321static void*filter_sparse_oid__init( 322struct oidset *omitted, 323struct list_objects_filter_options *filter_options, 324 filter_object_fn *filter_fn, 325 filter_free_fn *filter_free_fn) 326{ 327struct filter_sparse_data *d =xcalloc(1,sizeof(*d)); 328 d->omits = omitted; 329if(add_excludes_from_blob_to_list(filter_options->sparse_oid_value, 330 NULL,0, &d->el) <0) 331die("could not load filter specification"); 332 333ALLOC_GROW(d->array_frame, d->nr +1, d->alloc); 334 d->array_frame[d->nr].defval =0;/* default to include */ 335 d->array_frame[d->nr].child_prov_omit =0; 336 337*filter_fn = filter_sparse; 338*filter_free_fn = filter_sparse_free; 339return d; 340} 341 342static void*filter_sparse_path__init( 343struct oidset *omitted, 344struct list_objects_filter_options *filter_options, 345 filter_object_fn *filter_fn, 346 filter_free_fn *filter_free_fn) 347{ 348struct filter_sparse_data *d =xcalloc(1,sizeof(*d)); 349 d->omits = omitted; 350if(add_excludes_from_file_to_list(filter_options->sparse_path_value, 351 NULL,0, &d->el, NULL) <0) 352die("could not load filter specification"); 353 354ALLOC_GROW(d->array_frame, d->nr +1, d->alloc); 355 d->array_frame[d->nr].defval =0;/* default to include */ 356 d->array_frame[d->nr].child_prov_omit =0; 357 358*filter_fn = filter_sparse; 359*filter_free_fn = filter_sparse_free; 360return d; 361} 362 363typedefvoid*(*filter_init_fn)( 364struct oidset *omitted, 365struct list_objects_filter_options *filter_options, 366 filter_object_fn *filter_fn, 367 filter_free_fn *filter_free_fn); 368 369/* 370 * Must match "enum list_objects_filter_choice". 371 */ 372static filter_init_fn s_filters[] = { 373 NULL, 374 filter_blobs_none__init, 375 filter_blobs_limit__init, 376 filter_sparse_oid__init, 377 filter_sparse_path__init, 378}; 379 380void*list_objects_filter__init( 381struct oidset *omitted, 382struct list_objects_filter_options *filter_options, 383 filter_object_fn *filter_fn, 384 filter_free_fn *filter_free_fn) 385{ 386 filter_init_fn init_fn; 387 388assert((sizeof(s_filters) /sizeof(s_filters[0])) == LOFC__COUNT); 389 390if(filter_options->choice >= LOFC__COUNT) 391die("invalid list-objects filter choice:%d", 392 filter_options->choice); 393 394 init_fn = s_filters[filter_options->choice]; 395if(init_fn) 396returninit_fn(omitted, filter_options, 397 filter_fn, filter_free_fn); 398*filter_fn = NULL; 399*filter_free_fn = NULL; 400return NULL; 401}