that can be read.
@end defun
-@defun directory-files-recursively directory regexp &optional include-directories predicate
+@defun directory-files-recursively directory regexp &optional include-directories predicate follow-symlinks
Return all files under @var{directory} whose names match @var{regexp}.
This function searches the specified @var{directory} and its
sub-directories, recursively, for files whose basenames (i.e., without
neither @code{nil} nor @code{t}, it should be a function that takes
one parameter (the subdirectory name) and should return non-@code{nil}
if the directory is to be descended into.
+
+Symbolic links to subdirectories are not followed by default, but if
+@var{follow-symlinks} is non-@code{nil}, they are followed.
@end defun
@defun directory-files-and-attributes directory &optional full-name match-regexp nosort id-format
+++
** `directory-files-recursively' can now take an optional PREDICATE
-parameter to control descending into subdirectories.
+parameter to control descending into subdirectories, and a
+FOLLOW-SYMLINK parameter to say that symbolic links that point to
+other directories should be followed.
\f
* Changes in Emacs 27.1 on Non-Free Operating Systems
(error "No such directory found via CDPATH environment variable"))))
(defun directory-files-recursively (dir regexp
- &optional include-directories predicate)
+ &optional include-directories predicate
+ follow-symlinks)
"Return list of all files under DIR that have file names matching REGEXP.
This function works recursively. Files are returned in \"depth
first\" order, and files from each directory are sorted in
are descended into), t (which means that subdirectories that
can't be read are ignored), or a function (which is called with
name name of the subdirectory and should return non-nil if the
-subdirectory is to be descended into)."
+subdirectory is to be descended into).
+
+If FOLLOW-SYMLINKS, symbolic links that point to directories are
+followed. Note that this can lead to infinite recursion."
(let* ((result nil)
(files nil)
(dir (directory-file-name dir))
(let* ((leaf (substring file 0 (1- (length file))))
(full-file (concat dir "/" leaf)))
;; Don't follow symlinks to other directories.
- (when (and (not (file-symlink-p full-file))
+ (when (and (or (not (file-symlink-p full-file))
+ (and (file-symlink-p full-file)
+ follow-symlinks))
;; Allow filtering subdirectories.
(or (eq predicate nil)
(eq predicate t)
(funcall predicate full-file)))
(let ((sub-files
(if (eq predicate t)
- (condition-case _
- (directory-files-recursively
- full-file regexp include-directories)
- (file-error nil))
+ (ignore-error file-error
+ (directory-files-recursively
+ full-file regexp include-directories
+ predicate follow-symlinks))
(directory-files-recursively
- full-file regexp include-directories))))
+ full-file regexp include-directories
+ predicate follow-symlinks))))
(setq result (nconc result sub-files))))
(when (and include-directories
(string-match regexp leaf))