@@ -53,6 +53,8 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
53
53
int check_only , const struct path_simplify * simplify );
54
54
static int get_dtype (struct dirent * de , const char * path , int len );
55
55
56
+ static struct trace_key trace_exclude = TRACE_KEY_INIT (EXCLUDE );
57
+
56
58
/* helper string functions with support for the ignore_case flag */
57
59
int strcmp_icase (const char * a , const char * b )
58
60
{
@@ -519,6 +521,7 @@ void add_exclude(const char *string, const char *base,
519
521
x -> baselen = baselen ;
520
522
x -> flags = flags ;
521
523
x -> srcpos = srcpos ;
524
+ string_list_init (& x -> sticky_paths , 1 );
522
525
ALLOC_GROW (el -> excludes , el -> nr + 1 , el -> alloc );
523
526
el -> excludes [el -> nr ++ ] = x ;
524
527
x -> el = el ;
@@ -559,8 +562,10 @@ void clear_exclude_list(struct exclude_list *el)
559
562
{
560
563
int i ;
561
564
562
- for (i = 0 ; i < el -> nr ; i ++ )
565
+ for (i = 0 ; i < el -> nr ; i ++ ) {
566
+ string_list_clear (& el -> excludes [i ]-> sticky_paths , 0 );
563
567
free (el -> excludes [i ]);
568
+ }
564
569
free (el -> excludes );
565
570
free (el -> filebuf );
566
571
@@ -878,7 +883,7 @@ int match_pathname(const char *pathname, int pathlen,
878
883
* then our prefix match is all we need; we
879
884
* do not need to call fnmatch at all.
880
885
*/
881
- if (!patternlen && !namelen )
886
+ if (!patternlen && ( !namelen || * name == '/' ) )
882
887
return 1 ;
883
888
}
884
889
@@ -887,6 +892,113 @@ int match_pathname(const char *pathname, int pathlen,
887
892
WM_PATHNAME ) == 0 ;
888
893
}
889
894
895
+ static void add_sticky (struct exclude * exc , const char * pathname , int pathlen )
896
+ {
897
+ struct strbuf sb = STRBUF_INIT ;
898
+ int i ;
899
+
900
+ for (i = exc -> sticky_paths .nr - 1 ; i >= 0 ; i -- ) {
901
+ const char * sticky = exc -> sticky_paths .items [i ].string ;
902
+ int len = strlen (sticky );
903
+
904
+ if (pathlen < len && sticky [pathlen ] == '/' &&
905
+ !strncmp (pathname , sticky , pathlen ))
906
+ return ;
907
+ }
908
+
909
+ strbuf_add (& sb , pathname , pathlen );
910
+ string_list_append_nodup (& exc -> sticky_paths , strbuf_detach (& sb , NULL ));
911
+ }
912
+
913
+ static int match_sticky (struct exclude * exc , const char * pathname , int pathlen , int dtype )
914
+ {
915
+ int i ;
916
+
917
+ for (i = exc -> sticky_paths .nr - 1 ; i >= 0 ; i -- ) {
918
+ const char * sticky = exc -> sticky_paths .items [i ].string ;
919
+ int len = strlen (sticky );
920
+
921
+ if (pathlen == len && dtype == DT_DIR &&
922
+ !strncmp (pathname , sticky , len ))
923
+ return 1 ;
924
+
925
+ if (pathlen > len && pathname [len ] == '/' &&
926
+ !strncmp (pathname , sticky , len ))
927
+ return 1 ;
928
+ }
929
+
930
+ return 0 ;
931
+ }
932
+
933
+ static inline int different_decisions (const struct exclude * a ,
934
+ const struct exclude * b )
935
+ {
936
+ return (a -> flags & EXC_FLAG_NEGATIVE ) != (b -> flags & EXC_FLAG_NEGATIVE );
937
+ }
938
+
939
+ /*
940
+ * Return non-zero if pathname is a directory and an ancestor of the
941
+ * literal path in a pattern.
942
+ */
943
+ static int match_directory_part (const char * pathname , int pathlen ,
944
+ int * dtype , struct exclude * x )
945
+ {
946
+ const char * base = x -> base ;
947
+ int baselen = x -> baselen ? x -> baselen - 1 : 0 ;
948
+ const char * pattern = x -> pattern ;
949
+ int prefix = x -> nowildcardlen ;
950
+ int patternlen = x -> patternlen ;
951
+
952
+ if (* dtype == DT_UNKNOWN )
953
+ * dtype = get_dtype (NULL , pathname , pathlen );
954
+ if (* dtype != DT_DIR )
955
+ return 0 ;
956
+
957
+ if (* pattern == '/' ) {
958
+ pattern ++ ;
959
+ patternlen -- ;
960
+ prefix -- ;
961
+ }
962
+
963
+ if (baselen ) {
964
+ if (((pathlen < baselen && base [pathlen ] == '/' ) ||
965
+ pathlen == baselen ) &&
966
+ !strncmp_icase (pathname , base , pathlen ))
967
+ return 1 ;
968
+ pathname += baselen + 1 ;
969
+ pathlen -= baselen + 1 ;
970
+ }
971
+
972
+
973
+ if (prefix &&
974
+ (((pathlen < prefix && pattern [pathlen ] == '/' ) ||
975
+ pathlen == prefix ) &&
976
+ !strncmp_icase (pathname , pattern , pathlen )))
977
+ return 1 ;
978
+
979
+ return 0 ;
980
+ }
981
+
982
+ static struct exclude * should_descend (const char * pathname , int pathlen ,
983
+ int * dtype , struct exclude_list * el ,
984
+ struct exclude * exc )
985
+ {
986
+ int i ;
987
+
988
+ for (i = el -> nr - 1 ; 0 <= i ; i -- ) {
989
+ struct exclude * x = el -> excludes [i ];
990
+
991
+ if (x == exc )
992
+ break ;
993
+
994
+ if (!(x -> flags & EXC_FLAG_NODIR ) &&
995
+ different_decisions (x , exc ) &&
996
+ match_directory_part (pathname , pathlen , dtype , x ))
997
+ return x ;
998
+ }
999
+ return NULL ;
1000
+ }
1001
+
890
1002
/*
891
1003
* Scan the given exclude list in reverse to see whether pathname
892
1004
* should be ignored. The first match (i.e. the last on the list), if
@@ -900,16 +1012,32 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
900
1012
struct exclude_list * el )
901
1013
{
902
1014
struct exclude * exc = NULL ; /* undecided */
903
- int i ;
1015
+ int i , maybe_descend = 0 ;
904
1016
905
1017
if (!el -> nr )
906
1018
return NULL ; /* undefined */
907
1019
1020
+ trace_printf_key (& trace_exclude , "exclude: from %s\n" , el -> src );
1021
+
908
1022
for (i = el -> nr - 1 ; 0 <= i ; i -- ) {
909
1023
struct exclude * x = el -> excludes [i ];
910
1024
const char * exclude = x -> pattern ;
911
1025
int prefix = x -> nowildcardlen ;
912
1026
1027
+ if (!maybe_descend && i < el -> nr - 1 &&
1028
+ different_decisions (x , el -> excludes [i + 1 ]))
1029
+ maybe_descend = 1 ;
1030
+
1031
+ if (x -> sticky_paths .nr ) {
1032
+ if (* dtype == DT_UNKNOWN )
1033
+ * dtype = get_dtype (NULL , pathname , pathlen );
1034
+ if (match_sticky (x , pathname , pathlen , * dtype )) {
1035
+ exc = x ;
1036
+ break ;
1037
+ }
1038
+ continue ;
1039
+ }
1040
+
913
1041
if (x -> flags & EXC_FLAG_MUSTBEDIR ) {
914
1042
if (* dtype == DT_UNKNOWN )
915
1043
* dtype = get_dtype (NULL , pathname , pathlen );
@@ -936,6 +1064,45 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
936
1064
break ;
937
1065
}
938
1066
}
1067
+
1068
+ if (!exc ) {
1069
+ trace_printf_key (& trace_exclude , "exclude: %.*s => n/a\n" ,
1070
+ pathlen , pathname );
1071
+ return NULL ;
1072
+ }
1073
+
1074
+ /*
1075
+ * We have found a matching pattern "exc" that may exclude whole
1076
+ * directory. We also found that there may be a pattern that matches
1077
+ * something inside the directory and reincludes stuff.
1078
+ *
1079
+ * Go through the patterns again, find that pattern and double check.
1080
+ * If it's true, return "undecided" and keep descending in. "exc" is
1081
+ * marked sticky so that it continues to match inside the directory.
1082
+ */
1083
+ if (!(exc -> flags & EXC_FLAG_NEGATIVE ) && maybe_descend ) {
1084
+ struct exclude * x ;
1085
+
1086
+ if (* dtype == DT_UNKNOWN )
1087
+ * dtype = get_dtype (NULL , pathname , pathlen );
1088
+
1089
+ if (* dtype == DT_DIR &&
1090
+ (x = should_descend (pathname , pathlen , dtype , el , exc ))) {
1091
+ add_sticky (exc , pathname , pathlen );
1092
+ trace_printf_key (& trace_exclude ,
1093
+ "exclude: %.*s vs %s at line %d => %s,"
1094
+ " forced open by %s at line %d => n/a\n" ,
1095
+ pathlen , pathname , exc -> pattern , exc -> srcpos ,
1096
+ exc -> flags & EXC_FLAG_NEGATIVE ? "no" : "yes" ,
1097
+ x -> pattern , x -> srcpos );
1098
+ return NULL ;
1099
+ }
1100
+ }
1101
+
1102
+ trace_printf_key (& trace_exclude , "exclude: %.*s vs %s at line %d => %s%s\n" ,
1103
+ pathlen , pathname , exc -> pattern , exc -> srcpos ,
1104
+ exc -> flags & EXC_FLAG_NEGATIVE ? "no" : "yes" ,
1105
+ exc -> sticky_paths .nr ? " (stuck)" : "" );
939
1106
return exc ;
940
1107
}
941
1108
@@ -1683,9 +1850,13 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
1683
1850
struct cached_dir cdir ;
1684
1851
enum path_treatment state , subdir_state , dir_state = path_none ;
1685
1852
struct strbuf path = STRBUF_INIT ;
1853
+ static int level = 0 ;
1686
1854
1687
1855
strbuf_add (& path , base , baselen );
1688
1856
1857
+ trace_printf_key (& trace_exclude , "exclude: [%d] enter '%.*s'\n" ,
1858
+ level ++ , baselen , base );
1859
+
1689
1860
if (open_cached_dir (& cdir , dir , untracked , & path , check_only ))
1690
1861
goto out ;
1691
1862
@@ -1749,6 +1920,8 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
1749
1920
}
1750
1921
close_cached_dir (& cdir );
1751
1922
out :
1923
+ trace_printf_key (& trace_exclude , "exclude: [%d] leave '%.*s'\n" ,
1924
+ -- level , baselen , base );
1752
1925
strbuf_release (& path );
1753
1926
1754
1927
return dir_state ;
@@ -1985,6 +2158,25 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
1985
2158
return root ;
1986
2159
}
1987
2160
2161
+ static void clear_sticky (struct dir_struct * dir )
2162
+ {
2163
+ struct exclude_list_group * g ;
2164
+ struct exclude_list * el ;
2165
+ struct exclude * x ;
2166
+ int i , j , k ;
2167
+
2168
+ for (i = EXC_CMDL ; i <= EXC_FILE ; i ++ ) {
2169
+ g = & dir -> exclude_list_group [i ];
2170
+ for (j = g -> nr - 1 ; j >= 0 ; j -- ) {
2171
+ el = & g -> el [j ];
2172
+ for (k = el -> nr - 1 ; 0 <= k ; k -- ) {
2173
+ x = el -> excludes [k ];
2174
+ string_list_clear (& x -> sticky_paths , 0 );
2175
+ }
2176
+ }
2177
+ }
2178
+ }
2179
+
1988
2180
int read_directory (struct dir_struct * dir , const char * path , int len , const struct pathspec * pathspec )
1989
2181
{
1990
2182
struct path_simplify * simplify ;
@@ -2005,6 +2197,12 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru
2005
2197
if (has_symlink_leading_path (path , len ))
2006
2198
return dir -> nr ;
2007
2199
2200
+ /*
2201
+ * Stay on the safe side. if read_directory() has run once on
2202
+ * "dir", some sticky flag may have been left. Clear them all.
2203
+ */
2204
+ clear_sticky (dir );
2205
+
2008
2206
/*
2009
2207
* exclude patterns are treated like positive ones in
2010
2208
* create_simplify. Usually exclude patterns should be a
0 commit comments