@@ -14,12 +14,11 @@ struct path_simplify {
1414 const char * path ;
1515};
1616
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 ,
1918 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 );
2120
22- int common_prefix (const char * * pathspec )
21+ static int common_prefix (const char * * pathspec )
2322{
2423 const char * path , * slash , * next ;
2524 int prefix ;
@@ -52,6 +51,26 @@ int common_prefix(const char **pathspec)
5251 return prefix ;
5352}
5453
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+
5574/*
5675 * Does 'match' match the given name?
5776 * A match is found if
@@ -307,7 +326,7 @@ static int excluded_1(const char *pathname,
307326
308327 if (x -> flags & EXC_FLAG_MUSTBEDIR ) {
309328 if (* dtype == DT_UNKNOWN )
310- * dtype = get_dtype (NULL , pathname );
329+ * dtype = get_dtype (NULL , pathname , pathlen );
311330 if (* dtype != DT_DIR )
312331 continue ;
313332 }
@@ -505,7 +524,7 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
505524 /* This is the "show_other_directories" case */
506525 if (!(dir -> flags & DIR_HIDE_EMPTY_DIRECTORIES ))
507526 return show_directory ;
508- if (!read_directory_recursive (dir , dirname , dirname , len , 1 , simplify ))
527+ if (!read_directory_recursive (dir , dirname , len , 1 , simplify ))
509528 return ignore_directory ;
510529 return show_directory ;
511530}
@@ -547,11 +566,52 @@ static int in_pathspec(const char *path, int len, const struct path_simplify *si
547566 return 0 ;
548567}
549568
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 )
551608{
552609 int dtype = de ? DTYPE (de ) : DT_UNKNOWN ;
553610 struct stat st ;
554611
612+ if (dtype != DT_UNKNOWN )
613+ return dtype ;
614+ dtype = get_index_dtype (path , len );
555615 if (dtype != DT_UNKNOWN )
556616 return dtype ;
557617 if (lstat (path , & st ))
@@ -574,15 +634,15 @@ static int get_dtype(struct dirent *de, const char *path)
574634 * Also, we ignore the name ".git" (even if it is not a directory).
575635 * That likely will not change.
576636 */
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 )
578638{
579- DIR * fdir = opendir (* path ? path : "." );
639+ DIR * fdir = opendir (* base ? base : "." );
580640 int contents = 0 ;
581641
582642 if (fdir ) {
583643 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 );
586646
587647 while ((de = readdir (fdir )) != NULL ) {
588648 int len , dtype ;
@@ -593,17 +653,18 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
593653 continue ;
594654 len = strlen (de -> d_name );
595655 /* Ignore overly long pathnames! */
596- if (len + baselen + 8 > sizeof (fullname ))
656+ if (len + baselen + 8 > sizeof (path ))
597657 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 ))
600661 continue ;
601662
602663 dtype = DTYPE (de );
603- exclude = excluded (dir , fullname , & dtype );
664+ exclude = excluded (dir , path , & dtype );
604665 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 );
607668
608669 /*
609670 * 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
613674 continue ;
614675
615676 if (dtype == DT_UNKNOWN )
616- dtype = get_dtype (de , fullname );
677+ dtype = get_dtype (de , path , len );
617678
618679 /*
619680 * 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
630691 default :
631692 continue ;
632693 case DT_DIR :
633- memcpy (fullname + baselen + len , "/" , 2 );
694+ memcpy (path + len , "/" , 2 );
634695 len ++ ;
635- switch (treat_directory (dir , fullname , baselen + len , simplify )) {
696+ switch (treat_directory (dir , path , len , simplify )) {
636697 case show_directory :
637698 if (exclude != !!(dir -> flags
638699 & DIR_SHOW_IGNORED ))
639700 continue ;
640701 break ;
641702 case recurse_into_directory :
642703 contents += read_directory_recursive (dir ,
643- fullname , fullname , baselen + len , 0 , simplify );
704+ path , len , 0 , simplify );
644705 continue ;
645706 case ignore_directory :
646707 continue ;
@@ -654,7 +715,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
654715 if (check_only )
655716 goto exit_early ;
656717 else
657- dir_add_name (dir , fullname , baselen + len );
718+ dir_add_name (dir , path , len );
658719 }
659720exit_early :
660721 closedir (fdir );
@@ -717,15 +778,15 @@ static void free_simplify(struct path_simplify *simplify)
717778 free (simplify );
718779}
719780
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 )
721782{
722783 struct path_simplify * simplify ;
723784
724- if (has_symlink_leading_path (path , strlen ( path ) ))
785+ if (has_symlink_leading_path (path , len ))
725786 return dir -> nr ;
726787
727788 simplify = create_simplify (pathspec );
728- read_directory_recursive (dir , path , base , baselen , 0 , simplify );
789+ read_directory_recursive (dir , path , len , 0 , simplify );
729790 free_simplify (simplify );
730791 qsort (dir -> entries , dir -> nr , sizeof (struct dir_entry * ), cmp_name );
731792 qsort (dir -> ignored , dir -> ignored_nr , sizeof (struct dir_entry * ), cmp_name );
0 commit comments