emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 3a8d0cc: Avoid most stat calls when completing file


From: Paul Eggert
Subject: [Emacs-diffs] master 3a8d0cc: Avoid most stat calls when completing file names
Date: Mon, 31 Jul 2017 15:56:57 -0400 (EDT)

branch: master
commit 3a8d0cc825635e07da2a90c4ac987b476fc9b05d
Author: Paul Eggert <address@hidden>
Commit: Paul Eggert <address@hidden>

    Avoid most stat calls when completing file names
    
    * admin/merge-gnulib (GNULIB_MODULES): Add d-type.
    * lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate.
    * m4/d-type.m4: New file, copied from gnulib.
    * src/dired.c (DT_UNKNOWN, DT_DIR, DT_LINK)
    [!HAVE_STRUCT_DIRENT_D_TYPE]: New constants.
    (dirent_type): New function.
    (file_name_completion): Use it, to avoid unnecessary calls to
    stat-like functions on GNU/Linux and other platforms with d_type.
    (file_name_completion_stat): Just follow the link; there is no
    need to try first with AT_SYMLINK_NOFOLLOW since the directory
    entry was already checked to exist.
---
 admin/merge-gnulib |  3 ++-
 lib/gnulib.mk.in   |  2 +-
 m4/d-type.m4       | 32 ++++++++++++++++++++++++
 m4/gnulib-comp.m4  |  3 +++
 src/dired.c        | 71 +++++++++++++++++++++++++++++++-----------------------
 5 files changed, 79 insertions(+), 32 deletions(-)

diff --git a/admin/merge-gnulib b/admin/merge-gnulib
index 18c9ee8..c23e8a4 100755
--- a/admin/merge-gnulib
+++ b/admin/merge-gnulib
@@ -30,7 +30,8 @@ GNULIB_MODULES='
   careadlinkat close-stream
   count-leading-zeros count-one-bits count-trailing-zeros
   crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512
-  diffseq dtoastr dtotimespec dup2 environ execinfo explicit_bzero faccessat
+  d-type diffseq dtoastr dtotimespec dup2
+  environ execinfo explicit_bzero faccessat
   fcntl fcntl-h fdatasync fdopendir
   filemode filevercmp flexmember fstatat fsync
   getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in
index 3e57391..11c1ecf 100644
--- a/lib/gnulib.mk.in
+++ b/lib/gnulib.mk.in
@@ -21,7 +21,7 @@
 # the same distribution terms as the rest of that program.
 #
 # Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --lib=libgnu --source-base=lib 
--m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux 
--avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix 
--avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die 
--avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=setenv 
--avoid=sigprocmask --avoid=stat --avoid=stdarg --avoid=stdbool 
--avoid=threadlib --avoid=tzset --avoid=unsetenv --avoid=utime --avo [...]
+# Reproduce by: gnulib-tool --import --lib=libgnu --source-base=lib 
--m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux 
--avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix 
--avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die 
--avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=setenv 
--avoid=sigprocmask --avoid=stat --avoid=stdarg --avoid=stdbool 
--avoid=threadlib --avoid=tzset --avoid=unsetenv --avoid=utime --avo [...]
 
 
 MOSTLYCLEANFILES += core *.stackdump
diff --git a/m4/d-type.m4 b/m4/d-type.m4
new file mode 100644
index 0000000..c819fc0
--- /dev/null
+++ b/m4/d-type.m4
@@ -0,0 +1,32 @@
+# serial 12
+
+dnl From Jim Meyering.
+dnl
+dnl Check whether struct dirent has a member named d_type.
+dnl
+
+# Copyright (C) 1997, 1999-2004, 2006, 2009-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_CHECK_TYPE_STRUCT_DIRENT_D_TYPE],
+  [AC_CACHE_CHECK([for d_type member in directory struct],
+                  [gl_cv_struct_dirent_d_type],
+     [AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <dirent.h>
+         ]],
+         [[struct dirent dp; dp.d_type = 0;]])],
+       [gl_cv_struct_dirent_d_type=yes],
+       [gl_cv_struct_dirent_d_type=no])
+     ]
+   )
+   if test $gl_cv_struct_dirent_d_type = yes; then
+     AC_DEFINE([HAVE_STRUCT_DIRENT_D_TYPE], [1],
+       [Define if there is a member named d_type in the struct describing
+        directory headers.])
+   fi
+  ]
+)
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
index 2f13577..188c116 100644
--- a/m4/gnulib-comp.m4
+++ b/m4/gnulib-comp.m4
@@ -61,6 +61,7 @@ AC_DEFUN([gl_EARLY],
   # Code from module crypto/sha1:
   # Code from module crypto/sha256:
   # Code from module crypto/sha512:
+  # Code from module d-type:
   # Code from module diffseq:
   # Code from module dirent:
   # Code from module dirfd:
@@ -199,6 +200,7 @@ AC_DEFUN([gl_INIT],
   gl_SHA1
   gl_SHA256
   gl_SHA512
+  gl_CHECK_TYPE_STRUCT_DIRENT_D_TYPE
   gl_DIRENT_H
   AC_REQUIRE([gl_C99_STRTOLD])
   gl_FUNC_DUP2
@@ -968,6 +970,7 @@ AC_DEFUN([gl_FILE_LIST], [
   m4/count-leading-zeros.m4
   m4/count-one-bits.m4
   m4/count-trailing-zeros.m4
+  m4/d-type.m4
   m4/dirent_h.m4
   m4/dirfd.m4
   m4/dup2.m4
diff --git a/src/dired.c b/src/dired.c
index 5ea00fb..288ba6b 100644
--- a/src/dired.c
+++ b/src/dired.c
@@ -64,6 +64,21 @@ dirent_namelen (struct dirent *dp)
 #endif
 }
 
+#ifndef HAVE_STRUCT_DIRENT_D_TYPE
+enum { DT_UNKNOWN, DT_DIR, DT_LNK };
+#endif
+
+/* Return the file type of DP.  */
+static int
+dirent_type (struct dirent *dp)
+{
+#ifdef HAVE_STRUCT_DIRENT_D_TYPE
+  return dp->d_type;
+#else
+  return DT_UNKNOWN;
+#endif
+}
+
 static DIR *
 open_directory (Lisp_Object dirname, int *fdp)
 {
@@ -434,7 +449,7 @@ is matched against file and directory names relative to 
DIRECTORY.  */)
   return file_name_completion (file, directory, 1, Qnil);
 }
 
-static int file_name_completion_stat (int, struct dirent *, struct stat *);
+static bool file_name_completion_dirp (int, struct dirent *, ptrdiff_t);
 
 static Lisp_Object
 file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag,
@@ -448,7 +463,6 @@ file_name_completion (Lisp_Object file, Lisp_Object 
dirname, bool all_flag,
   Lisp_Object bestmatch, tem, elt, name;
   Lisp_Object encoded_file;
   Lisp_Object encoded_dir;
-  struct stat st;
   bool directoryp;
   /* If not INCLUDEALL, exclude files in completion-ignored-extensions as
      well as "." and "..".  Until shown otherwise, assume we can't exclude
@@ -512,10 +526,21 @@ file_name_completion (Lisp_Object file, Lisp_Object 
dirname, bool all_flag,
              >= 0))
        continue;
 
-      if (file_name_completion_stat (fd, dp, &st) < 0)
-       continue;
+      switch (dirent_type (dp))
+       {
+       case DT_DIR:
+         directoryp = true;
+         break;
+
+       case DT_LNK: case DT_UNKNOWN:
+         directoryp = file_name_completion_dirp (fd, dp, len);
+         break;
+
+       default:
+         directoryp = false;
+         break;
+       }
 
-      directoryp = S_ISDIR (st.st_mode) != 0;
       tem = Qnil;
       /* If all_flag is set, always include all.
         It would not actually be helpful to the user to ignore any possible
@@ -781,32 +806,18 @@ scmp (const char *s1, const char *s2, ptrdiff_t len)
     return len - l;
 }
 
-static int
-file_name_completion_stat (int fd, struct dirent *dp, struct stat *st_addr)
+/* Return true if in the directory FD the directory entry DP, whose
+   string length is LEN, is that of a subdirectory that can be searched.  */
+static bool
+file_name_completion_dirp (int fd, struct dirent *dp, ptrdiff_t len)
 {
-  int value;
-
-#ifdef MSDOS
-  /* Some fields of struct stat are *very* expensive to compute on MS-DOS,
-     but aren't required here.  Avoid computing the following fields:
-     st_inode, st_size and st_nlink for directories, and the execute bits
-     in st_mode for non-directory files with non-standard extensions.  */
-
-  unsigned short save_djstat_flags = _djstat_flags;
-
-  _djstat_flags = _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
-#endif /* MSDOS */
-
-  /* We want to return success if a link points to a nonexistent file,
-     but we want to return the status for what the link points to,
-     in case it is a directory.  */
-  value = fstatat (fd, dp->d_name, st_addr, AT_SYMLINK_NOFOLLOW);
-  if (value == 0 && S_ISLNK (st_addr->st_mode))
-    fstatat (fd, dp->d_name, st_addr, 0);
-#ifdef MSDOS
-  _djstat_flags = save_djstat_flags;
-#endif /* MSDOS */
-  return value;
+  USE_SAFE_ALLOCA;
+  char *subdir_name = SAFE_ALLOCA (len + 2);
+  memcpy (subdir_name, dp->d_name, len);
+  strcpy (subdir_name + len, "/");
+  bool dirp = faccessat (fd, subdir_name, F_OK, AT_EACCESS) == 0;
+  SAFE_FREE ();
+  return dirp;
 }
 
 static char *



reply via email to

[Prev in Thread] Current Thread [Next in Thread]