aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2017-07-31 12:31:02 -0700
committerPaul Eggert2017-07-31 12:56:51 -0700
commit3a8d0cc825635e07da2a90c4ac987b476fc9b05d (patch)
tree7a18ef1a777007f05feff6a35ebadc4338330906
parent192342a3a93a2e467ab589ae2d1ffd5e7acf1398 (diff)
downloademacs-3a8d0cc825635e07da2a90c4ac987b476fc9b05d.tar.gz
emacs-3a8d0cc825635e07da2a90c4ac987b476fc9b05d.zip
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.
-rwxr-xr-xadmin/merge-gnulib3
-rw-r--r--lib/gnulib.mk.in2
-rw-r--r--m4/d-type.m432
-rw-r--r--m4/gnulib-comp.m43
-rw-r--r--src/dired.c71
5 files changed, 79 insertions, 32 deletions
diff --git a/admin/merge-gnulib b/admin/merge-gnulib
index 18c9ee8def7..c23e8a40ea7 100755
--- a/admin/merge-gnulib
+++ b/admin/merge-gnulib
@@ -30,7 +30,8 @@ GNULIB_MODULES='
30 careadlinkat close-stream 30 careadlinkat close-stream
31 count-leading-zeros count-one-bits count-trailing-zeros 31 count-leading-zeros count-one-bits count-trailing-zeros
32 crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 32 crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512
33 diffseq dtoastr dtotimespec dup2 environ execinfo explicit_bzero faccessat 33 d-type diffseq dtoastr dtotimespec dup2
34 environ execinfo explicit_bzero faccessat
34 fcntl fcntl-h fdatasync fdopendir 35 fcntl fcntl-h fdatasync fdopendir
35 filemode filevercmp flexmember fstatat fsync 36 filemode filevercmp flexmember fstatat fsync
36 getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog 37 getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in
index 3e57391372a..11c1ecf05ad 100644
--- a/lib/gnulib.mk.in
+++ b/lib/gnulib.mk.in
@@ -21,7 +21,7 @@
21# the same distribution terms as the rest of that program. 21# the same distribution terms as the rest of that program.
22# 22#
23# Generated by gnulib-tool. 23# Generated by gnulib-tool.
24# 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 --avoid=utime-h --gnu-make --makefile-name=gnulib.mk.in --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase 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 fcntl fcntl-h fdatasync fdopendir filemode filevercmp flexmember fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog ignore-value intprops largefile lstat manywarnings memrchr minmax mkostemp mktime nstrftime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time std-gnu11 stdalign stddef stdio stpcpy strtoimax symlink sys_stat sys_time time time_r time_rz timegm timer-time timespec-add timespec-sub unlocked-io update-copyright utimens vla warnings 24# 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 --avoid=utime-h --gnu-make --makefile-name=gnulib.mk.in --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-leading-zeros count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 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 ignore-value intprops largefile lstat manywarnings memrchr minmax mkostemp mktime nstrftime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time std-gnu11 stdalign stddef stdio stpcpy strtoimax symlink sys_stat sys_time time time_r time_rz timegm timer-time timespec-add timespec-sub unlocked-io update-copyright utimens vla warnings
25 25
26 26
27MOSTLYCLEANFILES += core *.stackdump 27MOSTLYCLEANFILES += core *.stackdump
diff --git a/m4/d-type.m4 b/m4/d-type.m4
new file mode 100644
index 00000000000..c819fc02f84
--- /dev/null
+++ b/m4/d-type.m4
@@ -0,0 +1,32 @@
1# serial 12
2
3dnl From Jim Meyering.
4dnl
5dnl Check whether struct dirent has a member named d_type.
6dnl
7
8# Copyright (C) 1997, 1999-2004, 2006, 2009-2017 Free Software Foundation, Inc.
9#
10# This file is free software; the Free Software Foundation
11# gives unlimited permission to copy and/or distribute it,
12# with or without modifications, as long as this notice is preserved.
13
14AC_DEFUN([gl_CHECK_TYPE_STRUCT_DIRENT_D_TYPE],
15 [AC_CACHE_CHECK([for d_type member in directory struct],
16 [gl_cv_struct_dirent_d_type],
17 [AC_LINK_IFELSE([AC_LANG_PROGRAM([[
18#include <sys/types.h>
19#include <dirent.h>
20 ]],
21 [[struct dirent dp; dp.d_type = 0;]])],
22 [gl_cv_struct_dirent_d_type=yes],
23 [gl_cv_struct_dirent_d_type=no])
24 ]
25 )
26 if test $gl_cv_struct_dirent_d_type = yes; then
27 AC_DEFINE([HAVE_STRUCT_DIRENT_D_TYPE], [1],
28 [Define if there is a member named d_type in the struct describing
29 directory headers.])
30 fi
31 ]
32)
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
index 2f135773930..188c116c851 100644
--- a/m4/gnulib-comp.m4
+++ b/m4/gnulib-comp.m4
@@ -61,6 +61,7 @@ AC_DEFUN([gl_EARLY],
61 # Code from module crypto/sha1: 61 # Code from module crypto/sha1:
62 # Code from module crypto/sha256: 62 # Code from module crypto/sha256:
63 # Code from module crypto/sha512: 63 # Code from module crypto/sha512:
64 # Code from module d-type:
64 # Code from module diffseq: 65 # Code from module diffseq:
65 # Code from module dirent: 66 # Code from module dirent:
66 # Code from module dirfd: 67 # Code from module dirfd:
@@ -199,6 +200,7 @@ AC_DEFUN([gl_INIT],
199 gl_SHA1 200 gl_SHA1
200 gl_SHA256 201 gl_SHA256
201 gl_SHA512 202 gl_SHA512
203 gl_CHECK_TYPE_STRUCT_DIRENT_D_TYPE
202 gl_DIRENT_H 204 gl_DIRENT_H
203 AC_REQUIRE([gl_C99_STRTOLD]) 205 AC_REQUIRE([gl_C99_STRTOLD])
204 gl_FUNC_DUP2 206 gl_FUNC_DUP2
@@ -968,6 +970,7 @@ AC_DEFUN([gl_FILE_LIST], [
968 m4/count-leading-zeros.m4 970 m4/count-leading-zeros.m4
969 m4/count-one-bits.m4 971 m4/count-one-bits.m4
970 m4/count-trailing-zeros.m4 972 m4/count-trailing-zeros.m4
973 m4/d-type.m4
971 m4/dirent_h.m4 974 m4/dirent_h.m4
972 m4/dirfd.m4 975 m4/dirfd.m4
973 m4/dup2.m4 976 m4/dup2.m4
diff --git a/src/dired.c b/src/dired.c
index 5ea00fb8db4..288ba6b1038 100644
--- a/src/dired.c
+++ b/src/dired.c
@@ -64,6 +64,21 @@ dirent_namelen (struct dirent *dp)
64#endif 64#endif
65} 65}
66 66
67#ifndef HAVE_STRUCT_DIRENT_D_TYPE
68enum { DT_UNKNOWN, DT_DIR, DT_LNK };
69#endif
70
71/* Return the file type of DP. */
72static int
73dirent_type (struct dirent *dp)
74{
75#ifdef HAVE_STRUCT_DIRENT_D_TYPE
76 return dp->d_type;
77#else
78 return DT_UNKNOWN;
79#endif
80}
81
67static DIR * 82static DIR *
68open_directory (Lisp_Object dirname, int *fdp) 83open_directory (Lisp_Object dirname, int *fdp)
69{ 84{
@@ -434,7 +449,7 @@ is matched against file and directory names relative to DIRECTORY. */)
434 return file_name_completion (file, directory, 1, Qnil); 449 return file_name_completion (file, directory, 1, Qnil);
435} 450}
436 451
437static int file_name_completion_stat (int, struct dirent *, struct stat *); 452static bool file_name_completion_dirp (int, struct dirent *, ptrdiff_t);
438 453
439static Lisp_Object 454static Lisp_Object
440file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag, 455file_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,
448 Lisp_Object bestmatch, tem, elt, name; 463 Lisp_Object bestmatch, tem, elt, name;
449 Lisp_Object encoded_file; 464 Lisp_Object encoded_file;
450 Lisp_Object encoded_dir; 465 Lisp_Object encoded_dir;
451 struct stat st;
452 bool directoryp; 466 bool directoryp;
453 /* If not INCLUDEALL, exclude files in completion-ignored-extensions as 467 /* If not INCLUDEALL, exclude files in completion-ignored-extensions as
454 well as "." and "..". Until shown otherwise, assume we can't exclude 468 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,
512 >= 0)) 526 >= 0))
513 continue; 527 continue;
514 528
515 if (file_name_completion_stat (fd, dp, &st) < 0) 529 switch (dirent_type (dp))
516 continue; 530 {
531 case DT_DIR:
532 directoryp = true;
533 break;
534
535 case DT_LNK: case DT_UNKNOWN:
536 directoryp = file_name_completion_dirp (fd, dp, len);
537 break;
538
539 default:
540 directoryp = false;
541 break;
542 }
517 543
518 directoryp = S_ISDIR (st.st_mode) != 0;
519 tem = Qnil; 544 tem = Qnil;
520 /* If all_flag is set, always include all. 545 /* If all_flag is set, always include all.
521 It would not actually be helpful to the user to ignore any possible 546 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)
781 return len - l; 806 return len - l;
782} 807}
783 808
784static int 809/* Return true if in the directory FD the directory entry DP, whose
785file_name_completion_stat (int fd, struct dirent *dp, struct stat *st_addr) 810 string length is LEN, is that of a subdirectory that can be searched. */
811static bool
812file_name_completion_dirp (int fd, struct dirent *dp, ptrdiff_t len)
786{ 813{
787 int value; 814 USE_SAFE_ALLOCA;
788 815 char *subdir_name = SAFE_ALLOCA (len + 2);
789#ifdef MSDOS 816 memcpy (subdir_name, dp->d_name, len);
790 /* Some fields of struct stat are *very* expensive to compute on MS-DOS, 817 strcpy (subdir_name + len, "/");
791 but aren't required here. Avoid computing the following fields: 818 bool dirp = faccessat (fd, subdir_name, F_OK, AT_EACCESS) == 0;
792 st_inode, st_size and st_nlink for directories, and the execute bits 819 SAFE_FREE ();
793 in st_mode for non-directory files with non-standard extensions. */ 820 return dirp;
794
795 unsigned short save_djstat_flags = _djstat_flags;
796
797 _djstat_flags = _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
798#endif /* MSDOS */
799
800 /* We want to return success if a link points to a nonexistent file,
801 but we want to return the status for what the link points to,
802 in case it is a directory. */
803 value = fstatat (fd, dp->d_name, st_addr, AT_SYMLINK_NOFOLLOW);
804 if (value == 0 && S_ISLNK (st_addr->st_mode))
805 fstatat (fd, dp->d_name, st_addr, 0);
806#ifdef MSDOS
807 _djstat_flags = save_djstat_flags;
808#endif /* MSDOS */
809 return value;
810} 821}
811 822
812static char * 823static char *