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