@@ -786,12 +786,55 @@ static int add_excludes(const char *fname, const char *base, int baselen,
786786 size_t size = 0 ;
787787 char * buf ;
788788
789- fd = open (fname , O_RDONLY );
790- if (fd < 0 || fstat (fd , & st ) < 0 ) {
791- if (fd < 0 )
792- warn_on_fopen_errors (fname );
793- else
794- close (fd );
789+ /*
790+ * A performance optimization for status.
791+ *
792+ * During a status scan, git looks in each directory for a .gitignore
793+ * file before scanning the directory. Since .gitignore files are not
794+ * that common, we can waste a lot of time looking for files that are
795+ * not there. Fortunately, the fscache already knows if the directory
796+ * contains a .gitignore file, since it has already read the directory
797+ * and it already has the stat-data.
798+ *
799+ * If the fscache is enabled, use the fscache-lstat() interlude to see
800+ * if the file exists (in the fscache hash maps) before trying to open()
801+ * it.
802+ *
803+ * This causes problem when the .gitignore file is a symlink, because
804+ * we call lstat() rather than stat() on the symlnk and the resulting
805+ * stat-data is for the symlink itself rather than the target file.
806+ * We CANNOT use stat() here because the fscache DOES NOT install an
807+ * interlude for stat() and mingw_stat() always calls "open-fstat-close"
808+ * on the file and defeats the purpose of the optimization here. Since
809+ * symlinks are even more rare than .gitignore files, we force a fstat()
810+ * after our open() to get stat-data for the target file.
811+ */
812+ if (is_fscache_enabled (fname )) {
813+ if (lstat (fname , & st ) < 0 ) {
814+ fd = -1 ;
815+ } else {
816+ fd = open (fname , O_RDONLY );
817+ if (fd < 0 )
818+ warn_on_fopen_errors (fname );
819+ else if (S_ISLNK (st .st_mode ) && fstat (fd , & st ) < 0 ) {
820+ warn_on_fopen_errors (fname );
821+ close (fd );
822+ fd = -1 ;
823+ }
824+ }
825+ } else {
826+ fd = open (fname , O_RDONLY );
827+ if (fd < 0 || fstat (fd , & st ) < 0 ) {
828+ if (fd < 0 )
829+ warn_on_fopen_errors (fname );
830+ else {
831+ close (fd );
832+ fd = -1 ;
833+ }
834+ }
835+ }
836+
837+ if (fd < 0 ) {
795838 if (!istate )
796839 return -1 ;
797840 r = read_skip_worktree_file_from_index (istate , fname ,
0 commit comments