@@ -308,42 +308,69 @@ static int no_wildcard(const char *string)
308
308
return string [simple_length (string )] == '\0' ;
309
309
}
310
310
311
+ void parse_exclude_pattern (const char * * pattern ,
312
+ int * patternlen ,
313
+ int * flags ,
314
+ int * nowildcardlen )
315
+ {
316
+ const char * p = * pattern ;
317
+ size_t i , len ;
318
+
319
+ * flags = 0 ;
320
+ if (* p == '!' ) {
321
+ * flags |= EXC_FLAG_NEGATIVE ;
322
+ p ++ ;
323
+ }
324
+ len = strlen (p );
325
+ if (len && p [len - 1 ] == '/' ) {
326
+ len -- ;
327
+ * flags |= EXC_FLAG_MUSTBEDIR ;
328
+ }
329
+ for (i = 0 ; i < len ; i ++ ) {
330
+ if (p [i ] == '/' )
331
+ break ;
332
+ }
333
+ if (i == len )
334
+ * flags |= EXC_FLAG_NODIR ;
335
+ * nowildcardlen = simple_length (p );
336
+ /*
337
+ * we should have excluded the trailing slash from 'p' too,
338
+ * but that's one more allocation. Instead just make sure
339
+ * nowildcardlen does not exceed real patternlen
340
+ */
341
+ if (* nowildcardlen > len )
342
+ * nowildcardlen = len ;
343
+ if (* p == '*' && no_wildcard (p + 1 ))
344
+ * flags |= EXC_FLAG_ENDSWITH ;
345
+ * pattern = p ;
346
+ * patternlen = len ;
347
+ }
348
+
311
349
void add_exclude (const char * string , const char * base ,
312
350
int baselen , struct exclude_list * which )
313
351
{
314
352
struct exclude * x ;
315
- size_t len ;
316
- int to_exclude = 1 ;
317
- int flags = 0 ;
353
+ int patternlen ;
354
+ int flags ;
355
+ int nowildcardlen ;
318
356
319
- if (* string == '!' ) {
320
- to_exclude = 0 ;
321
- string ++ ;
322
- }
323
- len = strlen (string );
324
- if (len && string [len - 1 ] == '/' ) {
357
+ parse_exclude_pattern (& string , & patternlen , & flags , & nowildcardlen );
358
+ if (flags & EXC_FLAG_MUSTBEDIR ) {
325
359
char * s ;
326
- x = xmalloc (sizeof (* x ) + len );
360
+ x = xmalloc (sizeof (* x ) + patternlen + 1 );
327
361
s = (char * )(x + 1 );
328
- memcpy (s , string , len - 1 );
329
- s [len - 1 ] = '\0' ;
330
- string = s ;
362
+ memcpy (s , string , patternlen );
363
+ s [patternlen ] = '\0' ;
331
364
x -> pattern = s ;
332
- flags = EXC_FLAG_MUSTBEDIR ;
333
365
} else {
334
366
x = xmalloc (sizeof (* x ));
335
367
x -> pattern = string ;
336
368
}
337
- x -> to_exclude = to_exclude ;
338
- x -> patternlen = strlen ( string ) ;
369
+ x -> patternlen = patternlen ;
370
+ x -> nowildcardlen = nowildcardlen ;
339
371
x -> base = base ;
340
372
x -> baselen = baselen ;
341
373
x -> flags = flags ;
342
- if (!strchr (string , '/' ))
343
- x -> flags |= EXC_FLAG_NODIR ;
344
- x -> nowildcardlen = simple_length (string );
345
- if (* string == '*' && no_wildcard (string + 1 ))
346
- x -> flags |= EXC_FLAG_ENDSWITH ;
347
374
ALLOC_GROW (which -> excludes , which -> nr + 1 , which -> alloc );
348
375
which -> excludes [which -> nr ++ ] = x ;
349
376
}
@@ -505,6 +532,72 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
505
532
dir -> basebuf [baselen ] = '\0' ;
506
533
}
507
534
535
+ int match_basename (const char * basename , int basenamelen ,
536
+ const char * pattern , int prefix , int patternlen ,
537
+ int flags )
538
+ {
539
+ if (prefix == patternlen ) {
540
+ if (!strcmp_icase (pattern , basename ))
541
+ return 1 ;
542
+ } else if (flags & EXC_FLAG_ENDSWITH ) {
543
+ if (patternlen - 1 <= basenamelen &&
544
+ !strcmp_icase (pattern + 1 ,
545
+ basename + basenamelen - patternlen + 1 ))
546
+ return 1 ;
547
+ } else {
548
+ if (fnmatch_icase (pattern , basename , 0 ) == 0 )
549
+ return 1 ;
550
+ }
551
+ return 0 ;
552
+ }
553
+
554
+ int match_pathname (const char * pathname , int pathlen ,
555
+ const char * base , int baselen ,
556
+ const char * pattern , int prefix , int patternlen ,
557
+ int flags )
558
+ {
559
+ const char * name ;
560
+ int namelen ;
561
+
562
+ /*
563
+ * match with FNM_PATHNAME; the pattern has base implicitly
564
+ * in front of it.
565
+ */
566
+ if (* pattern == '/' ) {
567
+ pattern ++ ;
568
+ prefix -- ;
569
+ }
570
+
571
+ /*
572
+ * baselen does not count the trailing slash. base[] may or
573
+ * may not end with a trailing slash though.
574
+ */
575
+ if (pathlen < baselen + 1 ||
576
+ (baselen && pathname [baselen ] != '/' ) ||
577
+ strncmp_icase (pathname , base , baselen ))
578
+ return 0 ;
579
+
580
+ namelen = baselen ? pathlen - baselen - 1 : pathlen ;
581
+ name = pathname + pathlen - namelen ;
582
+
583
+ if (prefix ) {
584
+ /*
585
+ * if the non-wildcard part is longer than the
586
+ * remaining pathname, surely it cannot match.
587
+ */
588
+ if (prefix > namelen )
589
+ return 0 ;
590
+
591
+ if (strncmp_icase (pattern , name , prefix ))
592
+ return 0 ;
593
+ pattern += prefix ;
594
+ name += prefix ;
595
+ namelen -= prefix ;
596
+ }
597
+
598
+ return fnmatch_icase (pattern , name , FNM_PATHNAME ) == 0 ;
599
+ }
600
+
508
601
/* Scan the list and let the last match determine the fate.
509
602
* Return 1 for exclude, 0 for include and -1 for undecided.
510
603
*/
@@ -519,9 +612,9 @@ int excluded_from_list(const char *pathname,
519
612
520
613
for (i = el -> nr - 1 ; 0 <= i ; i -- ) {
521
614
struct exclude * x = el -> excludes [i ];
522
- const char * name , * exclude = x -> pattern ;
523
- int to_exclude = x -> to_exclude ;
524
- int namelen , prefix = x -> nowildcardlen ;
615
+ const char * exclude = x -> pattern ;
616
+ int to_exclude = x -> flags & EXC_FLAG_NEGATIVE ? 0 : 1 ;
617
+ int prefix = x -> nowildcardlen ;
525
618
526
619
if (x -> flags & EXC_FLAG_MUSTBEDIR ) {
527
620
if (* dtype == DT_UNKNOWN )
@@ -531,51 +624,18 @@ int excluded_from_list(const char *pathname,
531
624
}
532
625
533
626
if (x -> flags & EXC_FLAG_NODIR ) {
534
- /* match basename */
535
- if (prefix == x -> patternlen ) {
536
- if (!strcmp_icase (exclude , basename ))
537
- return to_exclude ;
538
- } else if (x -> flags & EXC_FLAG_ENDSWITH ) {
539
- if (x -> patternlen - 1 <= pathlen &&
540
- !strcmp_icase (exclude + 1 , pathname + pathlen - x -> patternlen + 1 ))
541
- return to_exclude ;
542
- } else {
543
- if (fnmatch_icase (exclude , basename , 0 ) == 0 )
544
- return to_exclude ;
545
- }
546
- continue ;
547
- }
548
-
549
- /* match with FNM_PATHNAME:
550
- * exclude has base (baselen long) implicitly in front of it.
551
- */
552
- if (* exclude == '/' ) {
553
- exclude ++ ;
554
- prefix -- ;
555
- }
556
-
557
- if (pathlen < x -> baselen ||
558
- (x -> baselen && pathname [x -> baselen - 1 ] != '/' ) ||
559
- strncmp_icase (pathname , x -> base , x -> baselen ))
627
+ if (match_basename (basename ,
628
+ pathlen - (basename - pathname ),
629
+ exclude , prefix , x -> patternlen ,
630
+ x -> flags ))
631
+ return to_exclude ;
560
632
continue ;
561
-
562
- namelen = x -> baselen ? pathlen - x -> baselen : pathlen ;
563
- name = pathname + pathlen - namelen ;
564
-
565
- /* if the non-wildcard part is longer than the
566
- remaining pathname, surely it cannot match */
567
- if (prefix > namelen )
568
- continue ;
569
-
570
- if (prefix ) {
571
- if (strncmp_icase (exclude , name , prefix ))
572
- continue ;
573
- exclude += prefix ;
574
- name += prefix ;
575
- namelen -= prefix ;
576
633
}
577
634
578
- if (!namelen || !fnmatch_icase (exclude , name , FNM_PATHNAME ))
635
+ assert (x -> baselen == 0 || x -> base [x -> baselen - 1 ] == '/' );
636
+ if (match_pathname (pathname , pathlen ,
637
+ x -> base , x -> baselen ? x -> baselen - 1 : 0 ,
638
+ exclude , prefix , x -> patternlen , x -> flags ))
579
639
return to_exclude ;
580
640
}
581
641
return -1 ; /* undecided */
0 commit comments