@@ -14,12 +14,11 @@ struct path_simplify {
14
14
const char * path ;
15
15
};
16
16
17
- static int read_directory_recursive (struct dir_struct * dir ,
18
- const char * path , const char * base , int baselen ,
17
+ static int read_directory_recursive (struct dir_struct * dir , const char * path , int len ,
19
18
int check_only , const struct path_simplify * simplify );
20
- static int get_dtype (struct dirent * de , const char * path );
19
+ static int get_dtype (struct dirent * de , const char * path , int len );
21
20
22
- int common_prefix (const char * * pathspec )
21
+ static int common_prefix (const char * * pathspec )
23
22
{
24
23
const char * path , * slash , * next ;
25
24
int prefix ;
@@ -52,6 +51,26 @@ int common_prefix(const char **pathspec)
52
51
return prefix ;
53
52
}
54
53
54
+ int fill_directory (struct dir_struct * dir , const char * * pathspec )
55
+ {
56
+ const char * path ;
57
+ int len ;
58
+
59
+ /*
60
+ * Calculate common prefix for the pathspec, and
61
+ * use that to optimize the directory walk
62
+ */
63
+ len = common_prefix (pathspec );
64
+ path = "" ;
65
+
66
+ if (len )
67
+ path = xmemdupz (* pathspec , len );
68
+
69
+ /* Read the directory and prune it */
70
+ read_directory (dir , path , len , pathspec );
71
+ return len ;
72
+ }
73
+
55
74
/*
56
75
* Does 'match' match the given name?
57
76
* A match is found if
@@ -307,7 +326,7 @@ static int excluded_1(const char *pathname,
307
326
308
327
if (x -> flags & EXC_FLAG_MUSTBEDIR ) {
309
328
if (* dtype == DT_UNKNOWN )
310
- * dtype = get_dtype (NULL , pathname );
329
+ * dtype = get_dtype (NULL , pathname , pathlen );
311
330
if (* dtype != DT_DIR )
312
331
continue ;
313
332
}
@@ -505,7 +524,7 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
505
524
/* This is the "show_other_directories" case */
506
525
if (!(dir -> flags & DIR_HIDE_EMPTY_DIRECTORIES ))
507
526
return show_directory ;
508
- if (!read_directory_recursive (dir , dirname , dirname , len , 1 , simplify ))
527
+ if (!read_directory_recursive (dir , dirname , len , 1 , simplify ))
509
528
return ignore_directory ;
510
529
return show_directory ;
511
530
}
@@ -547,11 +566,52 @@ static int in_pathspec(const char *path, int len, const struct path_simplify *si
547
566
return 0 ;
548
567
}
549
568
550
- static int get_dtype (struct dirent * de , const char * path )
569
+ static int get_index_dtype (const char * path , int len )
570
+ {
571
+ int pos ;
572
+ struct cache_entry * ce ;
573
+
574
+ ce = cache_name_exists (path , len , 0 );
575
+ if (ce ) {
576
+ if (!ce_uptodate (ce ))
577
+ return DT_UNKNOWN ;
578
+ if (S_ISGITLINK (ce -> ce_mode ))
579
+ return DT_DIR ;
580
+ /*
581
+ * Nobody actually cares about the
582
+ * difference between DT_LNK and DT_REG
583
+ */
584
+ return DT_REG ;
585
+ }
586
+
587
+ /* Try to look it up as a directory */
588
+ pos = cache_name_pos (path , len );
589
+ if (pos >= 0 )
590
+ return DT_UNKNOWN ;
591
+ pos = - pos - 1 ;
592
+ while (pos < active_nr ) {
593
+ ce = active_cache [pos ++ ];
594
+ if (strncmp (ce -> name , path , len ))
595
+ break ;
596
+ if (ce -> name [len ] > '/' )
597
+ break ;
598
+ if (ce -> name [len ] < '/' )
599
+ continue ;
600
+ if (!ce_uptodate (ce ))
601
+ break ; /* continue? */
602
+ return DT_DIR ;
603
+ }
604
+ return DT_UNKNOWN ;
605
+ }
606
+
607
+ static int get_dtype (struct dirent * de , const char * path , int len )
551
608
{
552
609
int dtype = de ? DTYPE (de ) : DT_UNKNOWN ;
553
610
struct stat st ;
554
611
612
+ if (dtype != DT_UNKNOWN )
613
+ return dtype ;
614
+ dtype = get_index_dtype (path , len );
555
615
if (dtype != DT_UNKNOWN )
556
616
return dtype ;
557
617
if (lstat (path , & st ))
@@ -574,15 +634,15 @@ static int get_dtype(struct dirent *de, const char *path)
574
634
* Also, we ignore the name ".git" (even if it is not a directory).
575
635
* That likely will not change.
576
636
*/
577
- static int read_directory_recursive (struct dir_struct * dir , const char * path , const char * base , int baselen , int check_only , const struct path_simplify * simplify )
637
+ static int read_directory_recursive (struct dir_struct * dir , const char * base , int baselen , int check_only , const struct path_simplify * simplify )
578
638
{
579
- DIR * fdir = opendir (* path ? path : "." );
639
+ DIR * fdir = opendir (* base ? base : "." );
580
640
int contents = 0 ;
581
641
582
642
if (fdir ) {
583
643
struct dirent * de ;
584
- char fullname [PATH_MAX + 1 ];
585
- memcpy (fullname , base , baselen );
644
+ char path [PATH_MAX + 1 ];
645
+ memcpy (path , base , baselen );
586
646
587
647
while ((de = readdir (fdir )) != NULL ) {
588
648
int len , dtype ;
@@ -593,17 +653,18 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
593
653
continue ;
594
654
len = strlen (de -> d_name );
595
655
/* Ignore overly long pathnames! */
596
- if (len + baselen + 8 > sizeof (fullname ))
656
+ if (len + baselen + 8 > sizeof (path ))
597
657
continue ;
598
- memcpy (fullname + baselen , de -> d_name , len + 1 );
599
- if (simplify_away (fullname , baselen + len , simplify ))
658
+ memcpy (path + baselen , de -> d_name , len + 1 );
659
+ len = baselen + len ;
660
+ if (simplify_away (path , len , simplify ))
600
661
continue ;
601
662
602
663
dtype = DTYPE (de );
603
- exclude = excluded (dir , fullname , & dtype );
664
+ exclude = excluded (dir , path , & dtype );
604
665
if (exclude && (dir -> flags & DIR_COLLECT_IGNORED )
605
- && in_pathspec (fullname , baselen + len , simplify ))
606
- dir_add_ignored (dir , fullname , baselen + len );
666
+ && in_pathspec (path , len , simplify ))
667
+ dir_add_ignored (dir , path , len );
607
668
608
669
/*
609
670
* Excluded? If we don't explicitly want to show
@@ -613,7 +674,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
613
674
continue ;
614
675
615
676
if (dtype == DT_UNKNOWN )
616
- dtype = get_dtype (de , fullname );
677
+ dtype = get_dtype (de , path , len );
617
678
618
679
/*
619
680
* Do we want to see just the ignored files?
@@ -630,17 +691,17 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
630
691
default :
631
692
continue ;
632
693
case DT_DIR :
633
- memcpy (fullname + baselen + len , "/" , 2 );
694
+ memcpy (path + len , "/" , 2 );
634
695
len ++ ;
635
- switch (treat_directory (dir , fullname , baselen + len , simplify )) {
696
+ switch (treat_directory (dir , path , len , simplify )) {
636
697
case show_directory :
637
698
if (exclude != !!(dir -> flags
638
699
& DIR_SHOW_IGNORED ))
639
700
continue ;
640
701
break ;
641
702
case recurse_into_directory :
642
703
contents += read_directory_recursive (dir ,
643
- fullname , fullname , baselen + len , 0 , simplify );
704
+ path , len , 0 , simplify );
644
705
continue ;
645
706
case ignore_directory :
646
707
continue ;
@@ -654,7 +715,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
654
715
if (check_only )
655
716
goto exit_early ;
656
717
else
657
- dir_add_name (dir , fullname , baselen + len );
718
+ dir_add_name (dir , path , len );
658
719
}
659
720
exit_early :
660
721
closedir (fdir );
@@ -717,15 +778,15 @@ static void free_simplify(struct path_simplify *simplify)
717
778
free (simplify );
718
779
}
719
780
720
- int read_directory (struct dir_struct * dir , const char * path , const char * base , int baselen , const char * * pathspec )
781
+ int read_directory (struct dir_struct * dir , const char * path , int len , const char * * pathspec )
721
782
{
722
783
struct path_simplify * simplify ;
723
784
724
- if (has_symlink_leading_path (path , strlen ( path ) ))
785
+ if (has_symlink_leading_path (path , len ))
725
786
return dir -> nr ;
726
787
727
788
simplify = create_simplify (pathspec );
728
- read_directory_recursive (dir , path , base , baselen , 0 , simplify );
789
+ read_directory_recursive (dir , path , len , 0 , simplify );
729
790
free_simplify (simplify );
730
791
qsort (dir -> entries , dir -> nr , sizeof (struct dir_entry * ), cmp_name );
731
792
qsort (dir -> ignored , dir -> ignored_nr , sizeof (struct dir_entry * ), cmp_name );
0 commit comments