--- /dev/null
+# 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
+ ]
+)
#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)
{
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,
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
>= 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
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;
}
\f
static char *