summaryrefslogtreecommitdiff
path: root/lisp
diff options
context:
space:
mode:
Diffstat (limited to 'lisp')
-rw-r--r--lisp/files.el203
1 files changed, 121 insertions, 82 deletions
diff --git a/lisp/files.el b/lisp/files.el
index d98d09bb1e3..68423f87bbf 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -2309,7 +2309,8 @@ This function ensures that none of these modifications will take place."
;; FIXME: Yuck!! We should turn insert-file-contents-literally
;; into a file operation instead!
(append '(jka-compr-handler image-file-handler epa-file-handler)
- inhibit-file-name-handlers))
+ (and (eq inhibit-file-name-operation 'insert-file-contents)
+ inhibit-file-name-handlers)))
(inhibit-file-name-operation 'insert-file-contents))
(insert-file-contents filename visit beg end replace)))
@@ -6992,99 +6993,100 @@ only these files will be asked to be saved."
;; operations, which return a file name. See Bug#29579.
(defun file-name-non-special (operation &rest arguments)
- (let* ((op-returns-file-name-list
- '(expand-file-name file-name-directory file-name-as-directory
- directory-file-name file-name-sans-versions
- find-backup-file-name file-remote-p))
- (file-name-handler-alist
- (and
- (not (memq operation op-returns-file-name-list))
- file-name-handler-alist))
- (default-directory
- ;; Some operations respect file name handlers in
- ;; `default-directory'. Because core function like
- ;; `call-process' don't care about file name handlers in
- ;; `default-directory', we here have to resolve the
- ;; directory into a local one. For `process-file',
- ;; `start-file-process', and `shell-command', this fixes
- ;; Bug#25949.
- (if (memq operation
- '(insert-directory process-file start-file-process
- shell-command temporary-file-directory))
- (directory-file-name
- (expand-file-name
- (unhandled-file-name-directory default-directory)))
- default-directory))
- ;; Get a list of the indices of the args which are file names.
- (file-arg-indices
- (cdr (or (assq operation
- ;; The first seven are special because they
- ;; return a file name. We want to include the /:
- ;; in the return value.
- ;; So just avoid stripping it in the first place.
- (append
- (mapcar 'list op-returns-file-name-list)
- '(;; `identity' means just return the first arg
- ;; not stripped of its quoting.
- (substitute-in-file-name identity)
- ;; `add' means add "/:" to the result.
- (file-truename add 0)
- (insert-file-contents insert-file-contents 0)
- ;; `unquote-then-quote' means set buffer-file-name
- ;; temporarily to unquoted filename.
- (verify-visited-file-modtime unquote-then-quote)
- ;; List the arguments which are filenames.
- (file-name-completion 0 1)
- (file-name-all-completions 0 1)
- (file-equal-p 0 1)
- (file-newer-than-file-p 0 1)
- (write-region 2 5)
- (rename-file 0 1)
- (copy-file 0 1)
- (copy-directory 0 1)
- (file-in-directory-p 0 1)
- (make-symbolic-link 0 1)
- (add-name-to-file 0 1)
- (make-auto-save-file-name buffer-file-name)
- (set-visited-file-modtime buffer-file-name)
- ;; These file-notify-* operations take a
- ;; descriptor.
- (file-notify-rm-watch . nil)
- (file-notify-valid-p . nil))))
- ;; For all other operations, treat the first argument only
- ;; as the file name.
- '(nil 0))))
- method
- ;; Copy ARGUMENTS so we can replace elements in it.
- (arguments (copy-sequence arguments)))
+ (let (;; In general, we don't want any file name handler. For some
+ ;; few cases, operations with two file name arguments which
+ ;; might be bound to different file name handlers, we still
+ ;; need this.
+ (saved-file-name-handler-alist file-name-handler-alist)
+ file-name-handler-alist
+ ;; Some operations respect file name handlers in
+ ;; `default-directory'. Because core function like
+ ;; `call-process' don't care about file name handlers in
+ ;; `default-directory', we here have to resolve the directory
+ ;; into a local one. For `process-file',
+ ;; `start-file-process', and `shell-command', this fixes
+ ;; Bug#25949.
+ (default-directory
+ (if (memq operation
+ '(insert-directory process-file start-file-process
+ shell-command temporary-file-directory))
+ (directory-file-name
+ (expand-file-name
+ (unhandled-file-name-directory default-directory)))
+ default-directory))
+ ;; Get a list of the indices of the args which are file names.
+ (file-arg-indices
+ (cdr (or (assq operation
+ '(;; The first seven are special because they
+ ;; return a file name. We want to include
+ ;; the /: in the return value. So just
+ ;; avoid stripping it in the first place.
+ (directory-file-name)
+ (expand-file-name)
+ (file-name-as-directory)
+ (file-name-directory)
+ (file-name-sans-versions)
+ (file-remote-p)
+ (find-backup-file-name)
+ ;; `identity' means just return the first
+ ;; arg not stripped of its quoting.
+ (substitute-in-file-name identity)
+ ;; `add' means add "/:" to the result.
+ (file-truename add 0)
+ ;;`insert-file-contents' needs special handling.
+ (insert-file-contents insert-file-contents 0)
+ ;; `unquote-then-quote' means set buffer-file-name
+ ;; temporarily to unquoted filename.
+ (verify-visited-file-modtime unquote-then-quote)
+ ;; Unquote `buffer-file-name' temporarily.
+ (make-auto-save-file-name buffer-file-name)
+ (set-visited-file-modtime buffer-file-name)
+ ;; Use a temporary local copy.
+ (copy-file local-copy)
+ (rename-file local-copy)
+ ;;`copy-directory' needs special handling.
+ (copy-directory copy-directory)
+ ;; List the arguments which are filenames.
+ (file-name-completion 0 1)
+ (file-name-all-completions 0 1)
+ (file-equal-p 0 1)
+ (file-newer-than-file-p 0 1)
+ (write-region 2 5)
+ (file-in-directory-p 0 1)
+ (make-symbolic-link 0 1)
+ (add-name-to-file 0 1)
+ ;; These file-notify-* operations take a
+ ;; descriptor.
+ (file-notify-rm-watch)
+ (file-notify-valid-p)))
+ ;; For all other operations, treat the first
+ ;; argument only as the file name.
+ '(nil 0))))
+ method
+ ;; Copy ARGUMENTS so we can replace elements in it.
+ (arguments (copy-sequence arguments)))
(if (symbolp (car file-arg-indices))
(setq method (pop file-arg-indices)))
;; Strip off the /: from the file names that have it.
(save-match-data
(while (consp file-arg-indices)
(let ((pair (nthcdr (car file-arg-indices) arguments)))
- (and (car pair)
- (string-match "\\`/:" (car pair))
- (setcar pair
- (if (= (length (car pair)) 2)
- "/"
- (substring (car pair) 2)))))
+ (when (car pair)
+ (setcar pair (file-name-unquote-non-special (car pair)))))
(setq file-arg-indices (cdr file-arg-indices))))
(pcase method
(`identity (car arguments))
(`add (file-name-quote (apply operation arguments)))
(`buffer-file-name
(let ((buffer-file-name
- (if (string-match "\\`/:" buffer-file-name)
- (substring buffer-file-name (match-end 0))
- buffer-file-name)))
+ (file-name-unquote-non-special buffer-file-name)))
(apply operation arguments)))
(`insert-file-contents
(let ((visit (nth 1 arguments)))
(unwind-protect
(apply operation arguments)
(when (and visit buffer-file-name)
- (setq buffer-file-name (concat "/:" buffer-file-name))))))
+ (setq buffer-file-name (file-name-quote buffer-file-name))))))
(`unquote-then-quote
;; We can't use `cl-letf' with `(buffer-local-value)' here
;; because it wouldn't work during bootstrapping.
@@ -7093,11 +7095,44 @@ only these files will be asked to be saved."
;; `verify-visited-file-modtime' action, which takes a buffer
;; as only optional argument.
(with-current-buffer (or (car arguments) buffer)
- (let ((buffer-file-name (substring buffer-file-name 2)))
+ (let ((buffer-file-name
+ (file-name-unquote-non-special buffer-file-name)))
;; Make sure to hide the temporary buffer change from the
;; underlying operation.
(with-current-buffer buffer
(apply operation arguments))))))
+ (`local-copy
+ (let* ((file-name-handler-alist saved-file-name-handler-alist)
+ (source (car arguments))
+ (target (car (cdr arguments)))
+ (tmpfile (file-local-copy source)))
+ (let ((handler (find-file-name-handler target 'copy-file)))
+ (unless (and handler (not (eq handler 'file-name-non-special)))
+ (setq target (file-name-unquote-non-special target))))
+ (setcar arguments (or tmpfile (file-name-unquote-non-special source)))
+ (setcar (cdr arguments) target)
+ (apply operation arguments)
+ (when (and tmpfile (file-exists-p tmpfile)) (delete-file tmpfile))))
+ (`copy-directory
+ (let* ((file-name-handler-alist saved-file-name-handler-alist)
+ (source (car arguments))
+ (target (car (cdr arguments)))
+ tmpdir)
+ (let ((handler (find-file-name-handler source 'copy-directory)))
+ (if (and handler (not (eq handler 'file-name-non-special)))
+ (progn
+ (setq tmpdir (make-temp-name temporary-file-directory))
+ (setcar (cdr arguments) tmpdir)
+ (apply operation arguments)
+ (setq source tmpdir))
+ (setq source (file-name-unquote-non-special source))))
+ (let ((handler (find-file-name-handler target 'copy-directory)))
+ (unless (and handler (not (eq handler 'file-name-non-special)))
+ (setq target (file-name-unquote-non-special target))))
+ (setcar arguments source)
+ (setcar (cdr arguments) target)
+ (apply operation arguments)
+ (when tmpdir (delete-directory tmpdir 'recursive))))
(_
(apply operation arguments)))))
@@ -7114,14 +7149,18 @@ If NAME is already a quoted file name, NAME is returned unchanged."
name
(concat (file-remote-p name) "/:" (file-local-name name))))
+(defsubst file-name-unquote-non-special (name)
+ "Remove quotation prefix \"/:\" from file NAME, if any."
+ (let (file-name-handler-alist)
+ (if (file-name-quoted-p name)
+ (if (= (length name) 2) "/" (substring name 2))
+ name)))
+
(defsubst file-name-unquote (name)
"Remove quotation prefix \"/:\" from file NAME, if any.
If NAME is a remote file name, the local part of NAME is unquoted."
- (let ((localname (file-local-name name)))
- (when (file-name-quoted-p localname)
- (setq
- localname (if (= (length localname) 2) "/" (substring localname 2))))
- (concat (file-remote-p name) localname)))
+ (concat
+ (file-remote-p name) (file-name-unquote-non-special (file-local-name name))))
;; Symbolic modes and read-file-modes.