Function: file-name-non-special
file-name-non-special is a byte-compiled function defined in
files.el.gz.
Signature
(file-name-non-special OPERATION &rest ARGUMENTS)
Source Code
;; Defined in /usr/src/emacs/lisp/files.el.gz
;; We depend on being the last handler on the list,
;; so that anything else that does need handling
;; has been handled already.
;; So it is safe for us to inhibit *all* magic file name handlers for
;; operations, which return a file name. See Bug#29579.
(defun file-name-non-special (operation &rest arguments)
(let ((inhibit-file-name-handlers
(cons 'file-name-non-special
(and (eq inhibit-file-name-operation operation)
inhibit-file-name-handlers)))
(inhibit-file-name-operation operation)
;; 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
make-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 that 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 local-copy)
;; List the arguments that 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)
;; `make-process' uses keyword arguments and
;; doesn't mangle its filenames in any way.
;; It already strips /: from the binary
;; filename, so we don't have to do this
;; here.
(make-process)))
;; 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 ;FIXME: Why?
(while (consp file-arg-indices)
(let ((pair (nthcdr (car file-arg-indices) arguments)))
(when (car pair)
(setcar pair (file-name-unquote (car pair) t))))
(setq file-arg-indices (cdr file-arg-indices))))
;; In general, we don't want any file name handler, see Bug#47625,
;; Bug#48349. For some few cases, operations with two file name
;; arguments which might be bound to different file name handlers,
;; we still need this.
(let ((tramp-mode (and tramp-mode (eq method 'local-copy))))
(pcase method
('identity (car arguments))
('add (file-name-quote (apply operation arguments) t))
('buffer-file-name
(let ((buffer-file-name (file-name-unquote buffer-file-name t)))
(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 (file-name-quote buffer-file-name t))))))
('unquote-then-quote
;; We can't use `cl-letf' with `(buffer-local-value)' here
;; because it wouldn't work during bootstrapping.
(let ((buffer (current-buffer)))
;; `unquote-then-quote' is used only for the
;; `verify-visited-file-modtime' action, which takes a
;; buffer as only optional argument.
(with-current-buffer (or (car arguments) buffer)
(let ((buffer-file-name (file-name-unquote buffer-file-name t)))
;; Make sure to hide the temporary buffer change from
;; the underlying operation.
(with-current-buffer buffer
(apply operation arguments))))))
('local-copy
(let ((source (car arguments))
(target (car (cdr arguments)))
(prefix (expand-file-name
"file-name-non-special" temporary-file-directory))
tmpfile)
(cond
;; If source is remote, we must create a local copy.
((file-remote-p source)
(setq tmpfile (make-temp-name prefix))
(apply operation source tmpfile (cddr arguments))
(setq source tmpfile))
;; If source is quoted, and the unquoted source looks
;; remote, we must create a local copy.
((file-name-quoted-p source t)
(setq source (file-name-unquote source t))
(when (file-remote-p source)
(setq tmpfile (make-temp-name prefix))
(let (file-name-handler-alist)
(apply operation source tmpfile (cddr arguments)))
(setq source tmpfile))))
;; If target is quoted, and the unquoted target looks
;; remote, we must disable the file name handler.
(when (file-name-quoted-p target t)
(setq target (file-name-unquote target t))
(when (file-remote-p target)
(setq file-name-handler-alist nil)))
;; Do it.
(setcar arguments source)
(setcar (cdr arguments) target)
(apply operation arguments)
;; Cleanup.
(when (and tmpfile (file-exists-p tmpfile))
(if (file-directory-p tmpfile)
(delete-directory tmpfile 'recursive) (delete-file tmpfile)))))
(_
(apply operation arguments))))))