@@ -930,6 +930,75 @@ static int match_sticky(struct exclude *exc, const char *pathname, int pathlen,
930930 return 0 ;
931931}
932932
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+
9331002/*
9341003 * Scan the given exclude list in reverse to see whether pathname
9351004 * should be ignored. The first match (i.e. the last on the list), if
@@ -943,7 +1012,7 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
9431012 struct exclude_list * el )
9441013{
9451014 struct exclude * exc = NULL ; /* undecided */
946- int i ;
1015+ int i , maybe_descend = 0 ;
9471016
9481017 if (!el -> nr )
9491018 return NULL ; /* undefined */
@@ -955,6 +1024,10 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
9551024 const char * exclude = x -> pattern ;
9561025 int prefix = x -> nowildcardlen ;
9571026
1027+ if (!maybe_descend && i < el -> nr - 1 &&
1028+ different_decisions (x , el -> excludes [i + 1 ]))
1029+ maybe_descend = 1 ;
1030+
9581031 if (x -> sticky_paths .nr ) {
9591032 if (* dtype == DT_UNKNOWN )
9601033 * dtype = get_dtype (NULL , pathname , pathlen );
@@ -998,6 +1071,34 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
9981071 return NULL ;
9991072 }
10001073
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+
10011102 trace_printf_key (& trace_exclude , "exclude: %.*s vs %s at line %d => %s%s\n" ,
10021103 pathlen , pathname , exc -> pattern , exc -> srcpos ,
10031104 exc -> flags & EXC_FLAG_NEGATIVE ? "no" : "yes" ,
@@ -2096,6 +2197,12 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru
20962197 if (has_symlink_leading_path (path , len ))
20972198 return dir -> nr ;
20982199
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+
20992206 /*
21002207 * exclude patterns are treated like positive ones in
21012208 * create_simplify. Usually exclude patterns should be a
0 commit comments