diff options
Diffstat (limited to 'lisp/files.el')
-rw-r--r-- | lisp/files.el | 95 |
1 files changed, 59 insertions, 36 deletions
diff --git a/lisp/files.el b/lisp/files.el index 77977f14116..90de1499340 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -5437,6 +5437,15 @@ Used only by `save-buffer'." :type 'hook :group 'files) +(defcustom copy-directory-create-symlink nil + "This option influences the handling of symbolic links in `copy-directory'. +If non-nil, `copy-directory' will create a symbolic link if the +source directory is a symbolic link. If nil, it'll follow the +symbolic link and copy the contents instead." + :type 'boolean + :version "28.1" + :group 'files) + (defvar-local save-buffer-coding-system nil "If non-nil, use this coding system for saving the buffer. More precisely, use this coding system in place of the @@ -6165,6 +6174,9 @@ Noninteractively, the PARENTS argument says whether to create parent directories if they don't exist. Interactively, this happens by default. +If DIRECTORY is a symlink and `copy-directory-create-symlink' is +non-nil, create a symlink with the same target as DIRECTORY. + If NEWNAME is a directory name, copy DIRECTORY as a subdirectory there. However, if called from Lisp with a non-nil optional argument COPY-CONTENTS, copy the contents of DIRECTORY directly @@ -6193,42 +6205,53 @@ into NEWNAME instead." (setq directory (directory-file-name (expand-file-name directory)) newname (expand-file-name newname)) - (cond ((not (directory-name-p newname)) - ;; If NEWNAME is not a directory name, create it; - ;; that is where we will copy the files of DIRECTORY. - (make-directory newname parents)) - ;; NEWNAME is a directory name. If COPY-CONTENTS is non-nil, - ;; create NEWNAME if it is not already a directory; - ;; otherwise, create NEWNAME/[DIRECTORY-BASENAME]. - ((if copy-contents - (or parents (not (file-directory-p newname))) - (setq newname (concat newname - (file-name-nondirectory directory)))) - (make-directory (directory-file-name newname) parents)) - (t (setq follow t))) - - ;; Copy recursively. - (dolist (file - ;; We do not want to copy "." and "..". - (directory-files directory 'full - directory-files-no-dot-files-regexp)) - (let ((target (concat (file-name-as-directory newname) - (file-name-nondirectory file))) - (filetype (car (file-attributes file)))) - (cond - ((eq filetype t) ; Directory but not a symlink. - (copy-directory file target keep-time parents t)) - ((stringp filetype) ; Symbolic link - (make-symbolic-link filetype target t)) - ((copy-file file target t keep-time))))) - - ;; Set directory attributes. - (let ((modes (file-modes directory)) - (times (and keep-time (file-attribute-modification-time - (file-attributes directory)))) - (follow-flag (unless follow 'nofollow))) - (if modes (set-file-modes newname modes follow-flag)) - (if times (set-file-times newname times follow-flag)))))) + ;; If DIRECTORY is a symlink, create a symlink with the same target. + (if (and (file-symlink-p directory) + copy-directory-create-symlink) + (let ((target (car (file-attributes directory)))) + (if (directory-name-p newname) + (make-symbolic-link target + (concat newname + (file-name-nondirectory directory)) + t) + (make-symbolic-link target newname t))) + ;; Else proceed to copy as a regular directory + (cond ((not (directory-name-p newname)) + ;; If NEWNAME is not a directory name, create it; + ;; that is where we will copy the files of DIRECTORY. + (make-directory newname parents)) + ;; NEWNAME is a directory name. If COPY-CONTENTS is non-nil, + ;; create NEWNAME if it is not already a directory; + ;; otherwise, create NEWNAME/[DIRECTORY-BASENAME]. + ((if copy-contents + (or parents (not (file-directory-p newname))) + (setq newname (concat newname + (file-name-nondirectory directory)))) + (make-directory (directory-file-name newname) parents)) + (t (setq follow t))) + + ;; Copy recursively. + (dolist (file + ;; We do not want to copy "." and "..". + (directory-files directory 'full + directory-files-no-dot-files-regexp)) + (let ((target (concat (file-name-as-directory newname) + (file-name-nondirectory file))) + (filetype (car (file-attributes file)))) + (cond + ((eq filetype t) ; Directory but not a symlink. + (copy-directory file target keep-time parents t)) + ((stringp filetype) ; Symbolic link + (make-symbolic-link filetype target t)) + ((copy-file file target t keep-time))))) + + ;; Set directory attributes. + (let ((modes (file-modes directory)) + (times (and keep-time (file-attribute-modification-time + (file-attributes directory)))) + (follow-flag (unless follow 'nofollow))) + (if modes (set-file-modes newname modes follow-flag)) + (if times (set-file-times newname times follow-flag))))))) ;; At time of writing, only info uses this. |