611
*patternlen = len;
612
}
613
614
+static int pl_hashmap_cmp(const void *unused_cmp_data,
615
+ const struct hashmap_entry *a,
616
+ const struct hashmap_entry *b,
617
+ const void *key)
618
+{
619
+ const struct pattern_entry *ee1 =
620
+ container_of(a, struct pattern_entry, ent);
621
+ const struct pattern_entry *ee2 =
622
+ container_of(b, struct pattern_entry, ent);
623
+
624
+ size_t min_len = ee1->patternlen <= ee2->patternlen
625
+ ? ee1->patternlen
626
+ : ee2->patternlen;
627
+
628
+ return strncmp(ee1->pattern, ee2->pattern, min_len);
629
+}
630
+
631
+static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern *given)
632
+{
633
+ struct pattern_entry *translated;
634
+ char *truncated;
635
+ char *data = NULL;
636
+
637
+ if (!pl->use_cone_patterns)
638
+ return;
639
+
640
+ if (given->flags & PATTERN_FLAG_NEGATIVE &&
641
+ given->flags & PATTERN_FLAG_MUSTBEDIR &&
642
+ !strcmp(given->pattern, "/*")) {
643
+ pl->full_cone = 0;
644
+ return;
645
+ }
646
+
647
+ if (!given->flags && !strcmp(given->pattern, "/*")) {
648
+ pl->full_cone = 1;
649
+ return;
650
+ }
651
+
652
+ if (given->patternlen > 2 &&
653
+ !strcmp(given->pattern + given->patternlen - 2, "/*")) {
654
+ if (!(given->flags & PATTERN_FLAG_NEGATIVE)) {
655
+ /* Not a cone pattern. */
656
+ pl->use_cone_patterns = 0;
657
+ warning(_("unrecognized pattern: '%s'"), given->pattern);
658
+ goto clear_hashmaps;
659
+ }
660
+
661
+ truncated = xstrdup(given->pattern);
662
+ truncated[given->patternlen - 2] = 0;
663
+
664
+ translated = xmalloc(sizeof(struct pattern_entry));
665
+ translated->pattern = truncated;
666
+ translated->patternlen = given->patternlen - 2;
667
+ hashmap_entry_init(&translated->ent,
668
+ memhash(translated->pattern, translated->patternlen));
669
+
670
+ if (!hashmap_get_entry(&pl->recursive_hashmap,
671
+ translated, ent, NULL)) {
672
+ /* We did not see the "parent" included */
673
+ warning(_("unrecognized negative pattern: '%s'"),
674
+ given->pattern);
675
+ free(truncated);
676
+ free(translated);
677
+ goto clear_hashmaps;
678
+ }
679
+
680
+ hashmap_add(&pl->parent_hashmap, &translated->ent);
681
+ hashmap_remove(&pl->recursive_hashmap, &translated->ent, &data);
682
+ free(data);
683
+ return;
684
+ }
685
+
686
+ if (given->flags & PATTERN_FLAG_NEGATIVE) {
687
+ warning(_("unrecognized negative pattern: '%s'"),
688
+ given->pattern);
689
+ goto clear_hashmaps;
690
+ }
691
+
692
+ translated = xmalloc(sizeof(struct pattern_entry));
693
+
694
+ translated->pattern = xstrdup(given->pattern);
695
+ translated->patternlen = given->patternlen;
696
+ hashmap_entry_init(&translated->ent,
697
+ memhash(translated->pattern, translated->patternlen));
698
+
699
+ hashmap_add(&pl->recursive_hashmap, &translated->ent);
700
+
701
+ if (hashmap_get_entry(&pl->parent_hashmap, translated, ent, NULL)) {
702
+ /* we already included this at the parent level */
703
+ warning(_("your sparse-checkout file may have issues: pattern '%s' is repeated"),
704
+ given->pattern);
705
+ hashmap_remove(&pl->parent_hashmap, &translated->ent, &data);
706
+ free(data);
707
+ free(translated);
708
+ }
709
+
710
+ return;
711
+
712
+clear_hashmaps:
713
+ warning(_("disabling cone pattern matching"));
714
+ hashmap_free_entries(&pl->parent_hashmap, struct pattern_entry, ent);
715
+ hashmap_free_entries(&pl->recursive_hashmap, struct pattern_entry, ent);
716
+ pl->use_cone_patterns = 0;
717
+}
718
+
719
+static int hashmap_contains_path(struct hashmap *map,
720
+ struct strbuf *pattern)
721
+{
722
+ struct pattern_entry p;
723
+
724
+ /* Check straight mapping */
725
+ p.pattern = pattern->buf;
726
+ p.patternlen = pattern->len;
727
+ hashmap_entry_init(&p.ent, memhash(p.pattern, p.patternlen));
728
+ return !!hashmap_get_entry(map, &p, ent, NULL);
729
+}
730
+
731
+int hashmap_contains_parent(struct hashmap *map,
732
+ const char *path,
733
+ struct strbuf *buffer)
734
+{
735
+ char *slash_pos;
736
+
737
+ strbuf_setlen(buffer, 0);
738
+
739
+ if (path[0] != '/')
740
+ strbuf_addch(buffer, '/');
741
+
742
+ strbuf_addstr(buffer, path);
743
+
744
+ slash_pos = strrchr(buffer->buf, '/');
745
+
746
+ while (slash_pos > buffer->buf) {
747
+ strbuf_setlen(buffer, slash_pos - buffer->buf);
748
+
749
+ if (hashmap_contains_path(map, buffer))
750
+ return 1;
751
+
752
+ slash_pos = strrchr(buffer->buf, '/');
753
+ }
754
+
755
+ return 0;
756
+}
757
+
758
void add_pattern(const char *string, const char *base,
759
int baselen, struct pattern_list *pl, int srcpos)
760
{
779
ALLOC_GROW(pl->patterns, pl->nr + 1, pl->alloc);
780
pl->patterns[pl->nr++] = pattern;
781
pattern->pl = pl;
782
+
783
+ add_pattern_to_hashsets(pl, pattern);
784
}
785
786
static int read_skip_worktree_file_from_index(const struct index_state *istate,
1006
int i, lineno = 1;
1007
char *entry;
1008
1009
+ hashmap_init(&pl->recursive_hashmap, pl_hashmap_cmp, NULL, 0);
1010
+ hashmap_init(&pl->parent_hashmap, pl_hashmap_cmp, NULL, 0);
1011
+
1012
pl->filebuf = buf;
1013
1014
if (skip_utf8_bom(&buf, size))
1245
struct index_state *istate)
1246
{
1247
struct path_pattern *pattern;
1099
- pattern = last_matching_pattern_from_list(pathname, pathlen, basename,
1100
- dtype, pl, istate);
1101
- if (pattern) {
1102
- if (pattern->flags & PATTERN_FLAG_NEGATIVE)
1103
- return NOT_MATCHED;
1104
- else
1105
- return MATCHED;
1248
+ struct strbuf parent_pathname = STRBUF_INIT;
1249
+ int result = NOT_MATCHED;
1250
+ const char *slash_pos;
1251
+
1252
+ if (!pl->use_cone_patterns) {
1253
+ pattern = last_matching_pattern_from_list(pathname, pathlen, basename,
1254
+ dtype, pl, istate);
1255
+ if (pattern) {
1256
+ if (pattern->flags & PATTERN_FLAG_NEGATIVE)
1257
+ return NOT_MATCHED;
1258
+ else
1259
+ return MATCHED;
1260
+ }
1261
+
1262
+ return UNDECIDED;
1263
+ }
1264
+
1265
+ if (pl->full_cone)
1266
+ return MATCHED;
1267
+
1268
+ strbuf_addch(&parent_pathname, '/');
1269
+ strbuf_add(&parent_pathname, pathname, pathlen);
1270
+
1271
+ if (hashmap_contains_path(&pl->recursive_hashmap,
1272
+ &parent_pathname)) {
1273
+ result = MATCHED;
1274
+ goto done;
1275
+ }
1276
+
1277
+ slash_pos = strrchr(parent_pathname.buf, '/');
1278
+
1279
+ if (slash_pos == parent_pathname.buf) {
1280
+ /* include every file in root */
1281
+ result = MATCHED;
1282
+ goto done;
1283
}
1284
1108
- return UNDECIDED;
1285
+ strbuf_setlen(&parent_pathname, slash_pos - parent_pathname.buf);
1286
+
1287
+ if (hashmap_contains_path(&pl->parent_hashmap, &parent_pathname)) {
1288
+ result = MATCHED;
1289
+ goto done;
1290
+ }
1291
+
1292
+ if (hashmap_contains_parent(&pl->recursive_hashmap,
1293
+ pathname,
1294
+ &parent_pathname))
1295
+ result = MATCHED;
1296
+
1297
+done:
1298
+ strbuf_release(&parent_pathname);
1299
+ return result;
1300
}
1301
1302
static struct path_pattern *last_matching_pattern_from_lists(