From: Lars Ingebrigtsen Date: Thu, 2 Dec 2021 12:21:20 +0000 (+0100) Subject: Make `C-c C-w' copy the executable bits to the new file X-Git-Tag: emacs-29.0.90~3625^2~12 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=9ea5a915bd1b9458af1587d63170888346e8baec;p=emacs.git Make `C-c C-w' copy the executable bits to the new file * lisp/files.el (write-file): When visiting an executable file, make the new file executable, too (bug#18915). --- diff --git a/etc/NEWS b/etc/NEWS index 55733c6895d..eda12142fed 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -75,6 +75,12 @@ time. * Changes in Emacs 29.1 +--- +** 'write-file' will now copy some file mode bits. +If the current buffer is visiting a file that is executable, the +'C-c C-w' command will now make the new file executable, too. + ++++ ** New user option 'process-error-pause-time'. This determines how long to pause Emacs after a process filter/sentinel error has been handled. diff --git a/lisp/files.el b/lisp/files.el index 07279c4c871..9ed63a60f81 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -4745,7 +4745,6 @@ using \\\\[next-history-element]. If optional second arg CONFIRM is non-nil, this function asks for confirmation before overwriting an existing file. Interactively, confirmation is required unless you supply a prefix argument." -;; (interactive "FWrite file: ") (interactive (list (if buffer-file-name (read-file-name "Write file: " @@ -4756,33 +4755,44 @@ Interactively, confirmation is required unless you supply a prefix argument." default-directory) nil nil)) (not current-prefix-arg))) - (or (null filename) (string-equal filename "") - (progn - ;; If arg is a directory name, - ;; use the default file name, but in that directory. - (if (directory-name-p filename) - (setq filename (concat filename - (file-name-nondirectory - (or buffer-file-name (buffer-name)))))) - (and confirm - (file-exists-p filename) - ;; NS does its own confirm dialog. - (not (and (eq (framep-on-display) 'ns) - (listp last-nonmenu-event) - use-dialog-box)) - (or (y-or-n-p (format-message - "File `%s' exists; overwrite? " filename)) - (user-error "Canceled"))) - (set-visited-file-name filename (not confirm)))) - (set-buffer-modified-p t) - ;; Make buffer writable if file is writable. - (and buffer-file-name - (file-writable-p buffer-file-name) - (setq buffer-read-only nil)) - (save-buffer) - ;; It's likely that the VC status at the new location is different from - ;; the one at the old location. - (vc-refresh-state)) + (let ((old-modes + (and buffer-file-name + ;; File may have gone away; ignore errors in that case. + (ignore-errors (file-modes buffer-file-name))))) + (or (null filename) (string-equal filename "") + (progn + ;; If arg is a directory name, + ;; use the default file name, but in that directory. + (if (directory-name-p filename) + (setq filename (concat filename + (file-name-nondirectory + (or buffer-file-name (buffer-name)))))) + (and confirm + (file-exists-p filename) + ;; NS does its own confirm dialog. + (not (and (eq (framep-on-display) 'ns) + (listp last-nonmenu-event) + use-dialog-box)) + (or (y-or-n-p (format-message + "File `%s' exists; overwrite? " filename)) + (user-error "Canceled"))) + (set-visited-file-name filename (not confirm)))) + (set-buffer-modified-p t) + ;; Make buffer writable if file is writable. + (and buffer-file-name + (file-writable-p buffer-file-name) + (setq buffer-read-only nil)) + (save-buffer) + ;; If the old file was executable, then make the new file + ;; executable, too. + (when (and old-modes + (not (zerop (logand #o111 old-modes)))) + (set-file-modes buffer-file-name + (logior (logand #o111 old-modes) + (file-modes buffer-file-name)))) + ;; It's likely that the VC status at the new location is different from + ;; the one at the old location. + (vc-refresh-state))) (defun file-extended-attributes (filename) "Return an alist of extended attributes of file FILENAME.