@@ -655,6 +655,92 @@ static int get_dtype(struct dirent *de, const char *path, int len)
655655 return dtype ;
656656}
657657
658+ enum path_treatment {
659+ path_ignored ,
660+ path_handled ,
661+ path_recurse ,
662+ };
663+
664+ static enum path_treatment treat_one_path (struct dir_struct * dir ,
665+ char * path , int * len ,
666+ const struct path_simplify * simplify ,
667+ int dtype , struct dirent * de )
668+ {
669+ int exclude = excluded (dir , path , & dtype );
670+ if (exclude && (dir -> flags & DIR_COLLECT_IGNORED )
671+ && in_pathspec (path , * len , simplify ))
672+ dir_add_ignored (dir , path , * len );
673+
674+ /*
675+ * Excluded? If we don't explicitly want to show
676+ * ignored files, ignore it
677+ */
678+ if (exclude && !(dir -> flags & DIR_SHOW_IGNORED ))
679+ return path_ignored ;
680+
681+ if (dtype == DT_UNKNOWN )
682+ dtype = get_dtype (de , path , * len );
683+
684+ /*
685+ * Do we want to see just the ignored files?
686+ * We still need to recurse into directories,
687+ * even if we don't ignore them, since the
688+ * directory may contain files that we do..
689+ */
690+ if (!exclude && (dir -> flags & DIR_SHOW_IGNORED )) {
691+ if (dtype != DT_DIR )
692+ return path_ignored ;
693+ }
694+
695+ switch (dtype ) {
696+ default :
697+ return path_ignored ;
698+ case DT_DIR :
699+ memcpy (path + * len , "/" , 2 );
700+ (* len )++ ;
701+ switch (treat_directory (dir , path , * len , simplify )) {
702+ case show_directory :
703+ if (exclude != !!(dir -> flags
704+ & DIR_SHOW_IGNORED ))
705+ return path_ignored ;
706+ break ;
707+ case recurse_into_directory :
708+ return path_recurse ;
709+ case ignore_directory :
710+ return path_ignored ;
711+ }
712+ break ;
713+ case DT_REG :
714+ case DT_LNK :
715+ break ;
716+ }
717+ return path_handled ;
718+ }
719+
720+ static enum path_treatment treat_path (struct dir_struct * dir ,
721+ struct dirent * de ,
722+ char * path , int path_max ,
723+ int baselen ,
724+ const struct path_simplify * simplify ,
725+ int * len )
726+ {
727+ int dtype ;
728+
729+ if (is_dot_or_dotdot (de -> d_name ) || !strcmp (de -> d_name , ".git" ))
730+ return path_ignored ;
731+ * len = strlen (de -> d_name );
732+ /* Ignore overly long pathnames! */
733+ if (* len + baselen + 8 > path_max )
734+ return path_ignored ;
735+ memcpy (path + baselen , de -> d_name , * len + 1 );
736+ * len += baselen ;
737+ if (simplify_away (path , * len , simplify ))
738+ return path_ignored ;
739+
740+ dtype = DTYPE (de );
741+ return treat_one_path (dir , path , len , simplify , dtype , de );
742+ }
743+
658744/*
659745 * Read a directory tree. We currently ignore anything but
660746 * directories, regular files and symlinks. That's because git
@@ -664,7 +750,10 @@ static int get_dtype(struct dirent *de, const char *path, int len)
664750 * Also, we ignore the name ".git" (even if it is not a directory).
665751 * That likely will not change.
666752 */
667- static int read_directory_recursive (struct dir_struct * dir , const char * base , int baselen , int check_only , const struct path_simplify * simplify )
753+ static int read_directory_recursive (struct dir_struct * dir ,
754+ const char * base , int baselen ,
755+ int check_only ,
756+ const struct path_simplify * simplify )
668757{
669758 DIR * fdir = opendir (* base ? base : "." );
670759 int contents = 0 ;
@@ -675,70 +764,16 @@ static int read_directory_recursive(struct dir_struct *dir, const char *base, in
675764 memcpy (path , base , baselen );
676765
677766 while ((de = readdir (fdir )) != NULL ) {
678- int len , dtype ;
679- int exclude ;
680-
681- if (is_dot_or_dotdot (de -> d_name ) ||
682- !strcmp (de -> d_name , ".git" ))
683- continue ;
684- len = strlen (de -> d_name );
685- /* Ignore overly long pathnames! */
686- if (len + baselen + 8 > sizeof (path ))
687- continue ;
688- memcpy (path + baselen , de -> d_name , len + 1 );
689- len = baselen + len ;
690- if (simplify_away (path , len , simplify ))
767+ int len ;
768+ switch (treat_path (dir , de , path , sizeof (path ),
769+ baselen , simplify , & len )) {
770+ case path_recurse :
771+ contents += read_directory_recursive
772+ (dir , path , len , 0 , simplify );
691773 continue ;
692-
693- dtype = DTYPE (de );
694- exclude = excluded (dir , path , & dtype );
695- if (exclude && (dir -> flags & DIR_COLLECT_IGNORED )
696- && in_pathspec (path , len , simplify ))
697- dir_add_ignored (dir , path ,len );
698-
699- /*
700- * Excluded? If we don't explicitly want to show
701- * ignored files, ignore it
702- */
703- if (exclude && !(dir -> flags & DIR_SHOW_IGNORED ))
774+ case path_ignored :
704775 continue ;
705-
706- if (dtype == DT_UNKNOWN )
707- dtype = get_dtype (de , path , len );
708-
709- /*
710- * Do we want to see just the ignored files?
711- * We still need to recurse into directories,
712- * even if we don't ignore them, since the
713- * directory may contain files that we do..
714- */
715- if (!exclude && (dir -> flags & DIR_SHOW_IGNORED )) {
716- if (dtype != DT_DIR )
717- continue ;
718- }
719-
720- switch (dtype ) {
721- default :
722- continue ;
723- case DT_DIR :
724- memcpy (path + len , "/" , 2 );
725- len ++ ;
726- switch (treat_directory (dir , path , len , simplify )) {
727- case show_directory :
728- if (exclude != !!(dir -> flags
729- & DIR_SHOW_IGNORED ))
730- continue ;
731- break ;
732- case recurse_into_directory :
733- contents += read_directory_recursive (dir ,
734- path , len , 0 , simplify );
735- continue ;
736- case ignore_directory :
737- continue ;
738- }
739- break ;
740- case DT_REG :
741- case DT_LNK :
776+ case path_handled :
742777 break ;
743778 }
744779 contents ++ ;
@@ -808,6 +843,41 @@ static void free_simplify(struct path_simplify *simplify)
808843 free (simplify );
809844}
810845
846+ static int treat_leading_path (struct dir_struct * dir ,
847+ const char * path , int len ,
848+ const struct path_simplify * simplify )
849+ {
850+ char pathbuf [PATH_MAX ];
851+ int baselen , blen ;
852+ const char * cp ;
853+
854+ while (len && path [len - 1 ] == '/' )
855+ len -- ;
856+ if (!len )
857+ return 1 ;
858+ baselen = 0 ;
859+ while (1 ) {
860+ cp = path + baselen + !!baselen ;
861+ cp = memchr (cp , '/' , path + len - cp );
862+ if (!cp )
863+ baselen = len ;
864+ else
865+ baselen = cp - path ;
866+ memcpy (pathbuf , path , baselen );
867+ pathbuf [baselen ] = '\0' ;
868+ if (!is_directory (pathbuf ))
869+ return 0 ;
870+ if (simplify_away (pathbuf , baselen , simplify ))
871+ return 0 ;
872+ blen = baselen ;
873+ if (treat_one_path (dir , pathbuf , & blen , simplify ,
874+ DT_DIR , NULL ) == path_ignored )
875+ return 0 ; /* do not recurse into it */
876+ if (len <= baselen )
877+ return 1 ; /* finished checking */
878+ }
879+ }
880+
811881int read_directory (struct dir_struct * dir , const char * path , int len , const char * * pathspec )
812882{
813883 struct path_simplify * simplify ;
@@ -816,7 +886,8 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const char
816886 return dir -> nr ;
817887
818888 simplify = create_simplify (pathspec );
819- read_directory_recursive (dir , path , len , 0 , simplify );
889+ if (!len || treat_leading_path (dir , path , len , simplify ))
890+ read_directory_recursive (dir , path , len , 0 , simplify );
820891 free_simplify (simplify );
821892 qsort (dir -> entries , dir -> nr , sizeof (struct dir_entry * ), cmp_name );
822893 qsort (dir -> ignored , dir -> ignored_nr , sizeof (struct dir_entry * ), cmp_name );
0 commit comments