@@ -817,12 +817,55 @@ static int add_excludes(const char *fname, const char *base, int baselen,
817817 size_t size = 0 ;
818818 char * buf ;
819819
820- fd = open (fname , O_RDONLY );
821- if (fd < 0 || fstat (fd , & st ) < 0 ) {
822- if (fd < 0 )
823- warn_on_fopen_errors (fname );
824- else
825- close (fd );
820+ /*
821+ * A performance optimization for status.
822+ *
823+ * During a status scan, git looks in each directory for a .gitignore
824+ * file before scanning the directory. Since .gitignore files are not
825+ * that common, we can waste a lot of time looking for files that are
826+ * not there. Fortunately, the fscache already knows if the directory
827+ * contains a .gitignore file, since it has already read the directory
828+ * and it already has the stat-data.
829+ *
830+ * If the fscache is enabled, use the fscache-lstat() interlude to see
831+ * if the file exists (in the fscache hash maps) before trying to open()
832+ * it.
833+ *
834+ * This causes problem when the .gitignore file is a symlink, because
835+ * we call lstat() rather than stat() on the symlnk and the resulting
836+ * stat-data is for the symlink itself rather than the target file.
837+ * We CANNOT use stat() here because the fscache DOES NOT install an
838+ * interlude for stat() and mingw_stat() always calls "open-fstat-close"
839+ * on the file and defeats the purpose of the optimization here. Since
840+ * symlinks are even more rare than .gitignore files, we force a fstat()
841+ * after our open() to get stat-data for the target file.
842+ */
843+ if (is_fscache_enabled (fname )) {
844+ if (lstat (fname , & st ) < 0 ) {
845+ fd = -1 ;
846+ } else {
847+ fd = open (fname , O_RDONLY );
848+ if (fd < 0 )
849+ warn_on_fopen_errors (fname );
850+ else if (S_ISLNK (st .st_mode ) && fstat (fd , & st ) < 0 ) {
851+ warn_on_fopen_errors (fname );
852+ close (fd );
853+ fd = -1 ;
854+ }
855+ }
856+ } else {
857+ fd = open (fname , O_RDONLY );
858+ if (fd < 0 || fstat (fd , & st ) < 0 ) {
859+ if (fd < 0 )
860+ warn_on_fopen_errors (fname );
861+ else {
862+ close (fd );
863+ fd = -1 ;
864+ }
865+ }
866+ }
867+
868+ if (fd < 0 ) {
826869 if (!istate )
827870 return -1 ;
828871 r = read_skip_worktree_file_from_index (istate , fname ,
0 commit comments