aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dired.c71
1 files changed, 41 insertions, 30 deletions
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 *