THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

Git Source Code Mirror - This is a publish-only repository and all pull requests are ignored. Please follow Documentation/SubmittingPatches procedure for any of your improvements.
git
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

520 lines
14 KiB

  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 "oidmap.h"
  14. #include "oidset.h"
  15. #include "object-store.h"
  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. * A filter for list-objects to omit ALL blobs from the traversal.
  29. * And to OPTIONALLY collect a list of the omitted OIDs.
  30. */
  31. struct filter_blobs_none_data {
  32. struct oidset *omits;
  33. };
  34. static enum list_objects_filter_result filter_blobs_none(
  35. struct repository *r,
  36. enum list_objects_filter_situation filter_situation,
  37. struct object *obj,
  38. const char *pathname,
  39. const char *filename,
  40. void *filter_data_)
  41. {
  42. struct filter_blobs_none_data *filter_data = filter_data_;
  43. switch (filter_situation) {
  44. default:
  45. BUG("unknown filter_situation: %d", filter_situation);
  46. case LOFS_BEGIN_TREE:
  47. assert(obj->type == OBJ_TREE);
  48. /* always include all tree objects */
  49. return LOFR_MARK_SEEN | LOFR_DO_SHOW;
  50. case LOFS_END_TREE:
  51. assert(obj->type == OBJ_TREE);
  52. return LOFR_ZERO;
  53. case LOFS_BLOB:
  54. assert(obj->type == OBJ_BLOB);
  55. assert((obj->flags & SEEN) == 0);
  56. if (filter_data->omits)
  57. oidset_insert(filter_data->omits, &obj->oid);
  58. return LOFR_MARK_SEEN; /* but not LOFR_DO_SHOW (hard omit) */
  59. }
  60. }
  61. static void *filter_blobs_none__init(
  62. struct oidset *omitted,
  63. struct list_objects_filter_options *filter_options,
  64. filter_object_fn *filter_fn,
  65. filter_free_fn *filter_free_fn)
  66. {
  67. struct filter_blobs_none_data *d = xcalloc(1, sizeof(*d));
  68. d->omits = omitted;
  69. *filter_fn = filter_blobs_none;
  70. *filter_free_fn = free;
  71. return d;
  72. }
  73. /*
  74. * A filter for list-objects to omit ALL trees and blobs from the traversal.
  75. * Can OPTIONALLY collect a list of the omitted OIDs.
  76. */
  77. struct filter_trees_depth_data {
  78. struct oidset *omits;
  79. /*
  80. * Maps trees to the minimum depth at which they were seen. It is not
  81. * necessary to re-traverse a tree at deeper or equal depths than it has
  82. * already been traversed.
  83. *
  84. * We can't use LOFR_MARK_SEEN for tree objects since this will prevent
  85. * it from being traversed at shallower depths.
  86. */
  87. struct oidmap seen_at_depth;
  88. unsigned long exclude_depth;
  89. unsigned long current_depth;
  90. };
  91. struct seen_map_entry {
  92. struct oidmap_entry base;
  93. size_t depth;
  94. };
  95. /* Returns 1 if the oid was in the omits set before it was invoked. */
  96. static int filter_trees_update_omits(
  97. struct object *obj,
  98. struct filter_trees_depth_data *filter_data,
  99. int include_it)
  100. {
  101. if (!filter_data->omits)
  102. return 0;
  103. if (include_it)
  104. return oidset_remove(filter_data->omits, &obj->oid);
  105. else
  106. return oidset_insert(filter_data->omits, &obj->oid);
  107. }
  108. static enum list_objects_filter_result filter_trees_depth(
  109. struct repository *r,
  110. enum list_objects_filter_situation filter_situation,
  111. struct object *obj,
  112. const char *pathname,
  113. const char *filename,
  114. void *filter_data_)
  115. {
  116. struct filter_trees_depth_data *filter_data = filter_data_;
  117. struct seen_map_entry *seen_info;
  118. int include_it = filter_data->current_depth <
  119. filter_data->exclude_depth;
  120. int filter_res;
  121. int already_seen;
  122. /*
  123. * Note that we do not use _MARK_SEEN in order to allow re-traversal in
  124. * case we encounter a tree or blob again at a shallower depth.
  125. */
  126. switch (filter_situation) {
  127. default:
  128. BUG("unknown filter_situation: %d", filter_situation);
  129. case LOFS_END_TREE:
  130. assert(obj->type == OBJ_TREE);
  131. filter_data->current_depth--;
  132. return LOFR_ZERO;
  133. case LOFS_BLOB:
  134. filter_trees_update_omits(obj, filter_data, include_it);
  135. return include_it ? LOFR_MARK_SEEN | LOFR_DO_SHOW : LOFR_ZERO;
  136. case LOFS_BEGIN_TREE:
  137. seen_info = oidmap_get(
  138. &filter_data->seen_at_depth, &obj->oid);
  139. if (!seen_info) {
  140. seen_info = xcalloc(1, sizeof(*seen_info));
  141. oidcpy(&seen_info->base.oid, &obj->oid);
  142. seen_info->depth = filter_data->current_depth;
  143. oidmap_put(&filter_data->seen_at_depth, seen_info);
  144. already_seen = 0;
  145. } else {
  146. already_seen =
  147. filter_data->current_depth >= seen_info->depth;
  148. }
  149. if (already_seen) {
  150. filter_res = LOFR_SKIP_TREE;
  151. } else {
  152. int been_omitted = filter_trees_update_omits(
  153. obj, filter_data, include_it);
  154. seen_info->depth = filter_data->current_depth;
  155. if (include_it)
  156. filter_res = LOFR_DO_SHOW;
  157. else if (filter_data->omits && !been_omitted)
  158. /*
  159. * Must update omit information of children
  160. * recursively; they have not been omitted yet.
  161. */
  162. filter_res = LOFR_ZERO;
  163. else
  164. filter_res = LOFR_SKIP_TREE;
  165. }
  166. filter_data->current_depth++;
  167. return filter_res;
  168. }
  169. }
  170. static void filter_trees_free(void *filter_data) {
  171. struct filter_trees_depth_data *d = filter_data;
  172. if (!d)
  173. return;
  174. oidmap_free(&d->seen_at_depth, 1);
  175. free(d);
  176. }
  177. static void *filter_trees_depth__init(
  178. struct oidset *omitted,
  179. struct list_objects_filter_options *filter_options,
  180. filter_object_fn *filter_fn,
  181. filter_free_fn *filter_free_fn)
  182. {
  183. struct filter_trees_depth_data *d = xcalloc(1, sizeof(*d));
  184. d->omits = omitted;
  185. oidmap_init(&d->seen_at_depth, 0);
  186. d->exclude_depth = filter_options->tree_exclude_depth;
  187. d->current_depth = 0;
  188. *filter_fn = filter_trees_depth;
  189. *filter_free_fn = filter_trees_free;
  190. return d;
  191. }
  192. /*
  193. * A filter for list-objects to omit large blobs.
  194. * And to OPTIONALLY collect a list of the omitted OIDs.
  195. */
  196. struct filter_blobs_limit_data {
  197. struct oidset *omits;
  198. unsigned long max_bytes;
  199. };
  200. static enum list_objects_filter_result filter_blobs_limit(
  201. struct repository *r,
  202. enum list_objects_filter_situation filter_situation,
  203. struct object *obj,
  204. const char *pathname,
  205. const char *filename,
  206. void *filter_data_)
  207. {
  208. struct filter_blobs_limit_data *filter_data = filter_data_;
  209. unsigned long object_length;
  210. enum object_type t;
  211. switch (filter_situation) {
  212. default:
  213. BUG("unknown filter_situation: %d", filter_situation);
  214. case LOFS_BEGIN_TREE:
  215. assert(obj->type == OBJ_TREE);
  216. /* always include all tree objects */
  217. return LOFR_MARK_SEEN | LOFR_DO_SHOW;
  218. case LOFS_END_TREE:
  219. assert(obj->type == OBJ_TREE);
  220. return LOFR_ZERO;
  221. case LOFS_BLOB:
  222. assert(obj->type == OBJ_BLOB);
  223. assert((obj->flags & SEEN) == 0);
  224. t = oid_object_info(r, &obj->oid, &object_length);
  225. if (t != OBJ_BLOB) { /* probably OBJ_NONE */
  226. /*
  227. * We DO NOT have the blob locally, so we cannot
  228. * apply the size filter criteria. Be conservative
  229. * and force show it (and let the caller deal with
  230. * the ambiguity).
  231. */
  232. goto include_it;
  233. }
  234. if (object_length < filter_data->max_bytes)
  235. goto include_it;
  236. if (filter_data->omits)
  237. oidset_insert(filter_data->omits, &obj->oid);
  238. return LOFR_MARK_SEEN; /* but not LOFR_DO_SHOW (hard omit) */
  239. }
  240. include_it:
  241. if (filter_data->omits)
  242. oidset_remove(filter_data->omits, &obj->oid);
  243. return LOFR_MARK_SEEN | LOFR_DO_SHOW;
  244. }
  245. static void *filter_blobs_limit__init(
  246. struct oidset *omitted,
  247. struct list_objects_filter_options *filter_options,
  248. filter_object_fn *filter_fn,
  249. filter_free_fn *filter_free_fn)
  250. {
  251. struct filter_blobs_limit_data *d = xcalloc(1, sizeof(*d));
  252. d->omits = omitted;
  253. d->max_bytes = filter_options->blob_limit_value;
  254. *filter_fn = filter_blobs_limit;
  255. *filter_free_fn = free;
  256. return d;
  257. }
  258. /*
  259. * A filter driven by a sparse-checkout specification to only
  260. * include blobs that a sparse checkout would populate.
  261. *
  262. * The sparse-checkout spec can be loaded from a blob with the
  263. * given OID or from a local pathname. We allow an OID because
  264. * the repo may be bare or we may be doing the filtering on the
  265. * server.
  266. */
  267. struct frame {
  268. /*
  269. * defval is the usual default include/exclude value that
  270. * should be inherited as we recurse into directories based
  271. * upon pattern matching of the directory itself or of a
  272. * containing directory.
  273. */
  274. int defval;
  275. /*
  276. * 1 if the directory (recursively) contains any provisionally
  277. * omitted objects.
  278. *
  279. * 0 if everything (recursively) contained in this directory
  280. * has been explicitly included (SHOWN) in the result and
  281. * the directory may be short-cut later in the traversal.
  282. */
  283. unsigned child_prov_omit : 1;
  284. };
  285. struct filter_sparse_data {
  286. struct oidset *omits;
  287. struct exclude_list el;
  288. size_t nr, alloc;
  289. struct frame *array_frame;
  290. };
  291. static enum list_objects_filter_result filter_sparse(
  292. struct repository *r,
  293. enum list_objects_filter_situation filter_situation,
  294. struct object *obj,
  295. const char *pathname,
  296. const char *filename,
  297. void *filter_data_)
  298. {
  299. struct filter_sparse_data *filter_data = filter_data_;
  300. int val, dtype;
  301. struct frame *frame;
  302. switch (filter_situation) {
  303. default:
  304. BUG("unknown filter_situation: %d", filter_situation);
  305. case LOFS_BEGIN_TREE:
  306. assert(obj->type == OBJ_TREE);
  307. dtype = DT_DIR;
  308. val = is_excluded_from_list(pathname, strlen(pathname),
  309. filename, &dtype, &filter_data->el,
  310. r->index);
  311. if (val < 0)
  312. val = filter_data->array_frame[filter_data->nr - 1].defval;
  313. ALLOC_GROW(filter_data->array_frame, filter_data->nr + 1,
  314. filter_data->alloc);
  315. filter_data->array_frame[filter_data->nr].defval = val;
  316. filter_data->array_frame[filter_data->nr].child_prov_omit = 0;
  317. filter_data->nr++;
  318. /*
  319. * A directory with this tree OID may appear in multiple
  320. * places in the tree. (Think of a directory move or copy,
  321. * with no other changes, so the OID is the same, but the
  322. * full pathnames of objects within this directory are new
  323. * and may match is_excluded() patterns differently.)
  324. * So we cannot mark this directory as SEEN (yet), since
  325. * that will prevent process_tree() from revisiting this
  326. * tree object with other pathname prefixes.
  327. *
  328. * Only _DO_SHOW the tree object the first time we visit
  329. * this tree object.
  330. *
  331. * We always show all tree objects. A future optimization
  332. * may want to attempt to narrow this.
  333. */
  334. if (obj->flags & FILTER_SHOWN_BUT_REVISIT)
  335. return LOFR_ZERO;
  336. obj->flags |= FILTER_SHOWN_BUT_REVISIT;
  337. return LOFR_DO_SHOW;
  338. case LOFS_END_TREE:
  339. assert(obj->type == OBJ_TREE);
  340. assert(filter_data->nr > 1);
  341. frame = &filter_data->array_frame[--filter_data->nr];
  342. /*
  343. * Tell our parent directory if any of our children were
  344. * provisionally omitted.
  345. */
  346. filter_data->array_frame[filter_data->nr - 1].child_prov_omit |=
  347. frame->child_prov_omit;
  348. /*
  349. * If there are NO provisionally omitted child objects (ALL child
  350. * objects in this folder were INCLUDED), then we can mark the
  351. * folder as SEEN (so we will not have to revisit it again).
  352. */
  353. if (!frame->child_prov_omit)
  354. return LOFR_MARK_SEEN;
  355. return LOFR_ZERO;
  356. case LOFS_BLOB:
  357. assert(obj->type == OBJ_BLOB);
  358. assert((obj->flags & SEEN) == 0);
  359. frame = &filter_data->array_frame[filter_data->nr - 1];
  360. dtype = DT_REG;
  361. val = is_excluded_from_list(pathname, strlen(pathname),
  362. filename, &dtype, &filter_data->el,
  363. r->index);
  364. if (val < 0)
  365. val = frame->defval;
  366. if (val > 0) {
  367. if (filter_data->omits)
  368. oidset_remove(filter_data->omits, &obj->oid);
  369. return LOFR_MARK_SEEN | LOFR_DO_SHOW;
  370. }
  371. /*
  372. * Provisionally omit it. We've already established that
  373. * this pathname is not in the sparse-checkout specification
  374. * with the CURRENT pathname, so we *WANT* to omit this blob.
  375. *
  376. * However, a pathname elsewhere in the tree may also
  377. * reference this same blob, so we cannot reject it yet.
  378. * Leave the LOFR_ bits unset so that if the blob appears
  379. * again in the traversal, we will be asked again.
  380. */
  381. if (filter_data->omits)
  382. oidset_insert(filter_data->omits, &obj->oid);
  383. /*
  384. * Remember that at least 1 blob in this tree was
  385. * provisionally omitted. This prevents us from short
  386. * cutting the tree in future iterations.
  387. */
  388. frame->child_prov_omit = 1;
  389. return LOFR_ZERO;
  390. }
  391. }
  392. static void filter_sparse_free(void *filter_data)
  393. {
  394. struct filter_sparse_data *d = filter_data;
  395. free(d->array_frame);
  396. free(d);
  397. }
  398. static void *filter_sparse_oid__init(
  399. struct oidset *omitted,
  400. struct list_objects_filter_options *filter_options,
  401. filter_object_fn *filter_fn,
  402. filter_free_fn *filter_free_fn)
  403. {
  404. struct filter_sparse_data *d = xcalloc(1, sizeof(*d));
  405. d->omits = omitted;
  406. if (add_excludes_from_blob_to_list(filter_options->sparse_oid_value,
  407. NULL, 0, &d->el) < 0)
  408. die("could not load filter specification");
  409. ALLOC_GROW(d->array_frame, d->nr + 1, d->alloc);
  410. d->array_frame[d->nr].defval = 0; /* default to include */
  411. d->array_frame[d->nr].child_prov_omit = 0;
  412. d->nr++;
  413. *filter_fn = filter_sparse;
  414. *filter_free_fn = filter_sparse_free;
  415. return d;
  416. }
  417. typedef void *(*filter_init_fn)(
  418. struct oidset *omitted,
  419. struct list_objects_filter_options *filter_options,
  420. filter_object_fn *filter_fn,
  421. filter_free_fn *filter_free_fn);
  422. /*
  423. * Must match "enum list_objects_filter_choice".
  424. */
  425. static filter_init_fn s_filters[] = {
  426. NULL,
  427. filter_blobs_none__init,
  428. filter_blobs_limit__init,
  429. filter_trees_depth__init,
  430. filter_sparse_oid__init,
  431. };
  432. void *list_objects_filter__init(
  433. struct oidset *omitted,
  434. struct list_objects_filter_options *filter_options,
  435. filter_object_fn *filter_fn,
  436. filter_free_fn *filter_free_fn)
  437. {
  438. filter_init_fn init_fn;
  439. assert((sizeof(s_filters) / sizeof(s_filters[0])) == LOFC__COUNT);
  440. if (filter_options->choice >= LOFC__COUNT)
  441. BUG("invalid list-objects filter choice: %d",
  442. filter_options->choice);
  443. init_fn = s_filters[filter_options->choice];
  444. if (init_fn)
  445. return init_fn(omitted, filter_options,
  446. filter_fn, filter_free_fn);
  447. *filter_fn = NULL;
  448. *filter_free_fn = NULL;
  449. return NULL;
  450. }