"Get the PROPERTY of FILE from the cache context of KEY.
Returns DEFAULT if not set."
;; Unify localname. Remove hop from vector.
+ (setq file (tramp-compat-file-name-unquote file))
(setq key (copy-sequence key))
(aset key 3 (tramp-run-real-handler 'directory-file-name (list file)))
(aset key 4 nil)
"Set the PROPERTY of FILE to VALUE, in the cache context of KEY.
Returns VALUE."
;; Unify localname. Remove hop from vector.
+ (setq file (tramp-compat-file-name-unquote file))
(setq key (copy-sequence key))
(aset key 3 (tramp-run-real-handler 'directory-file-name (list file)))
(aset key 4 nil)
(let* ((file (tramp-run-real-handler
'directory-file-name (list file)))
(truename (tramp-get-file-property key file "file-truename" nil)))
- ;; Remove file properties of symlinks.
- (when (and (stringp truename)
- (not (string-equal file (directory-file-name truename))))
- (tramp-flush-file-property key truename))
;; Unify localname. Remove hop from vector.
+ (setq file (tramp-compat-file-name-unquote file))
(setq key (copy-sequence key))
(aset key 3 file)
(aset key 4 nil)
(tramp-message key 8 "%s" file)
- (remhash key tramp-cache-data)))
+ (remhash key tramp-cache-data)
+ ;; Remove file properties of symlinks.
+ (when (and (stringp truename)
+ (not (string-equal file (directory-file-name truename))))
+ (tramp-flush-file-property key truename))))
;;;###tramp-autoload
(defun tramp-flush-directory-property (key directory)
"Remove all properties of DIRECTORY in the cache context of KEY.
Remove also properties of all files in subdirectories."
+ (setq directory (tramp-compat-file-name-unquote directory))
(let* ((directory (tramp-run-real-handler
'directory-file-name (list directory)))
(truename (tramp-get-file-property key directory "file-truename" nil)))
- ;; Remove file properties of symlinks.
- (when (and (stringp truename)
- (not (string-equal directory (directory-file-name truename))))
- (tramp-flush-directory-property key truename))
(tramp-message key 8 "%s" directory)
(maphash
(lambda (key _value)
(string-match (regexp-quote directory)
(tramp-file-name-localname key)))
(remhash key tramp-cache-data)))
- tramp-cache-data)))
+ tramp-cache-data)
+ ;; Remove file properties of symlinks.
+ (when (and (stringp truename)
+ (not (string-equal directory (directory-file-name truename))))
+ (tramp-flush-directory-property key truename))))
;; Reverting or killing a buffer should also flush file properties.
;; They could have been changed outside Tramp. In eshell, "ls" would
(unload-feature 'tramp-loaddefs 'force)
(unload-feature 'tramp-compat 'force)))
+;; `file-name-quoted-p', `file-name-quote' and `file-name-unquote' are
+;; introduced in Emacs 26.
+(if (fboundp 'file-name-quoted-p)
+ (defalias 'tramp-compat-file-name-quoted-p 'file-name-quoted-p)
+ (defsubst tramp-compat-file-name-quoted-p (name)
+ "Whether NAME is quoted with prefix \"/:\".
+If NAME is a remote file name, check the local part of NAME."
+ (string-match "^/:" (or (file-remote-p name 'localname) name))))
+
+(if (fboundp 'file-name-quote)
+ (defalias 'tramp-compat-file-name-quote 'file-name-quote)
+ (defsubst tramp-compat-file-name-quote (name)
+ "Add the quotation prefix \"/:\" to file NAME.
+If NAME is a remote file name, the local part of NAME is quoted."
+ (concat
+ (file-remote-p name) "/:" (or (file-remote-p name 'localname) name))))
+
+(if (fboundp 'file-name-unquote)
+ (defalias 'tramp-compat-file-name-unquote 'file-name-unquote)
+ (defsubst tramp-compat-file-name-unquote (name)
+ "Remove quotation prefix \"/:\" from file NAME.
+If NAME is a remote file name, the local part of NAME is unquoted."
+ (save-match-data
+ (let ((localname (or (file-remote-p name 'localname) name)))
+ (when (tramp-compat-file-name-quoted-p localname)
+ (setq
+ localname
+ (replace-match
+ (if (= (length localname) 2) "/" "") nil t localname)))
+ (concat (file-remote-p name) localname)))))
+
(provide 'tramp-compat)
;;; TODO:
(defun tramp-gvfs-url-file-name (filename)
"Return FILENAME in URL syntax."
;; "/" must NOT be hexlified.
+ (setq filename (tramp-compat-file-name-unquote filename))
(let ((url-unreserved-chars (cons ?/ url-unreserved-chars))
result)
(setq
method user host
(with-tramp-file-property v localname "file-truename"
(let ((result nil) ; result steps in reverse order
- (quoted (tramp-quoted-name-p localname))
- (localname (tramp-unquote-name localname)))
+ (quoted (tramp-compat-file-name-quoted-p localname))
+ (localname (tramp-compat-file-name-unquote localname)))
(tramp-message v 4 "Finding true name for `%s'" filename)
(cond
;; Use GNU readlink --canonicalize-missing where available.
(when (string= "" result)
(setq result "/")))))
- (when quoted (setq result (tramp-quote-name result)))
+ (when quoted (setq result (tramp-compat-file-name-quote result)))
(tramp-message v 4 "True name of `%s' is `%s'" localname result)
result))))
(let ((method (tramp-file-name-method vec))
(user (tramp-file-name-user vec))
(host (tramp-file-name-real-host vec))
- (localname (directory-file-name (tramp-file-name-localname vec))))
+ (localname (tramp-compat-file-name-unquote
+ (directory-file-name (tramp-file-name-localname vec)))))
(when (string-match tramp-ipv6-regexp host)
(setq host (format "[%s]" host)))
(unless (string-match "ftp$" method)
((tramp-get-method-parameter vec 'tramp-remote-copy-program)
localname)
((not (zerop (length user)))
- (tramp-unquote-shell-quote-argument
- (format "%s@%s:%s" user host localname)))
- (t (tramp-unquote-shell-quote-argument (format "%s:%s" host localname))))))
+ (tramp-shell-quote-argument (format "%s@%s:%s" user host localname)))
+ (t (tramp-shell-quote-argument (format "%s:%s" host localname))))))
(defun tramp-method-out-of-band-p (vec size)
"Return t if this is an out-of-band method, nil otherwise."
v 'file-error "Target `%s' must contain a share name" newname))
(unless (tramp-smb-send-command
v (format "put \"%s\" \"%s\""
- filename (tramp-smb-get-localname v)))
+ (tramp-compat-file-name-unquote filename)
+ (tramp-smb-get-localname v)))
(tramp-error
v 'file-error "Cannot copy `%s' to `%s'" filename newname))))))
"Like `handle-substitute-in-file-name' for Tramp files.
\"//\" substitutes only in the local filename part. Catches
errors for shares like \"C$/\", which are common in Microsoft Windows."
- (with-parsed-tramp-file-name filename nil
- ;; Ignore in LOCALNAME everything before "//".
- (when (and (stringp localname) (string-match ".+?/\\(/\\|~\\)" localname))
- (setq filename
- (concat (file-remote-p filename)
- (replace-match "\\1" nil nil localname)))))
- (condition-case nil
- (tramp-run-real-handler 'substitute-in-file-name (list filename))
- (error filename)))
+ ;; Check, whether the local part is a quoted file name.
+ (if (tramp-compat-file-name-quoted-p filename)
+ filename
+ (with-parsed-tramp-file-name filename nil
+ ;; Ignore in LOCALNAME everything before "//".
+ (when (and (stringp localname) (string-match ".+?/\\(/\\|~\\)" localname))
+ (setq filename
+ (concat (file-remote-p filename)
+ (replace-match "\\1" nil nil localname)))))
+ (condition-case nil
+ (tramp-run-real-handler 'substitute-in-file-name (list filename))
+ (error filename))))
(defun tramp-smb-handle-write-region
(start end filename &optional append visit lockname confirm)
(defun tramp-smb-get-share (vec)
"Returns the share name of LOCALNAME."
(save-match-data
- (let ((localname (tramp-file-name-localname vec)))
+ (let ((localname
+ (tramp-compat-file-name-unquote (tramp-file-name-localname vec))))
(when (string-match "^/?\\([^/]+\\)/" localname)
(match-string 1 localname)))))
"Returns the file name of LOCALNAME.
If VEC has no cifs capabilities, exchange \"/\" by \"\\\\\"."
(save-match-data
- (let ((localname (tramp-file-name-localname vec)))
+ (let ((localname
+ (tramp-compat-file-name-unquote (tramp-file-name-localname vec))))
(setq
localname
(if (string-match "^/?[^/]+\\(/.*\\)" localname)
(font-lock-add-keywords
'emacs-lisp-mode '("\\<with-tramp-connection-property\\>"))
-(defsubst tramp-quoted-name-p (name)
- "Whether NAME is quoted with prefix \"/:\".
-If NAME is a remote file name, check the local part of NAME."
- (string-match "^/:" (or (file-remote-p name 'localname) name)))
-
-(defsubst tramp-quote-name (name)
- "Add the quotation prefix \"/:\" to file NAME.
-If NAME is a remote file name, the local part of NAME is quoted."
- (concat (file-remote-p name) "/:" (or (file-remote-p name 'localname) name)))
-
-(defsubst tramp-unquote-name (name)
- "Remove quotation prefix \"/:\" from file NAME.
-If NAME is a remote file name, the local part of NAME is unquoted."
- (save-match-data
- (let ((localname (or (file-remote-p name 'localname) name)))
- (when (tramp-quoted-name-p localname)
- (setq
- localname
- (replace-match (if (= (length localname) 2) "/" "") nil t localname)))
- (concat (file-remote-p name) localname))))
-
(defun tramp-drop-volume-letter (name)
"Cut off unnecessary drive letter from file NAME.
The functions `tramp-*-handle-expand-file-name' call `expand-file-name'
"Like `substitute-in-file-name' for Tramp files.
\"//\" and \"/~\" substitute only in the local filename part."
;; Check, whether the local part is a quoted file name.
- (if (tramp-quoted-name-p filename)
+ (if (tramp-compat-file-name-quoted-p filename)
filename
;; First, we must replace environment variables.
(setq filename (tramp-replace-environment-variables filename))
("|" . "__")
("[" . "_l")
("]" . "_r"))
- (tramp-unquote-name (buffer-file-name)))
+ (tramp-compat-file-name-unquote (buffer-file-name)))
tramp-auto-save-directory))))
;; Run plain `make-auto-save-file-name'.
(tramp-run-real-handler 'make-auto-save-file-name nil)))
(defun tramp-unquote-shell-quote-argument (s)
"Remove quotation prefix \"/:\" from string S, and quote it then for shell."
- (shell-quote-argument (tramp-unquote-name s)))
+ (shell-quote-argument (tramp-compat-file-name-unquote s)))
;; Currently (as of Emacs 20.5), the function `shell-quote-argument'
;; does not deal well with newline characters. Newline is replaced by
If LOCAL is non-nil, a local file is created.
If QUOTED is non-nil, the local part of the file is quoted."
(funcall
- (if quoted 'tramp-quote-name 'identity)
+ (if quoted 'tramp-compat-file-name-quote 'identity)
(expand-file-name
(make-temp-name "tramp-test")
(if local temporary-file-directory tramp-test-temporary-file-directory))))
(should
(string-equal
(funcall
- (if quoted 'tramp-quote-name 'identity)
+ (if quoted 'tramp-compat-file-name-quote 'identity)
(car attr))
(file-remote-p (file-truename tmp-name1) 'localname)))
(delete-file tmp-name2))
(string-equal
(make-auto-save-file-name)
(funcall
- (if quoted 'tramp-quote-name 'identity)
+ (if quoted 'tramp-compat-file-name-quote 'identity)
(expand-file-name
(format "#%s#" (file-name-nondirectory tmp-name1))
tramp-test-temporary-file-directory))))))
("|" . "__")
("[" . "_l")
("]" . "_r"))
- (tramp-unquote-name tmp-name1)))
+ (tramp-compat-file-name-unquote tmp-name1)))
tmp-name2)))
(should (file-directory-p tmp-name2))))
("|" . "__")
("[" . "_l")
("]" . "_r"))
- (tramp-unquote-name tmp-name1)))
+ (tramp-compat-file-name-unquote tmp-name1)))
tmp-name2)))
(should (file-directory-p tmp-name2)))))
(should
(string-equal
(funcall
- (if quoted 'tramp-quote-name 'identity)
+ (if quoted 'tramp-compat-file-name-quote 'identity)
(car (file-attributes file3)))
(file-remote-p (file-truename file1) 'localname)))
;; Check file contents.
(should
(string-equal
(funcall
- (if quoted 'tramp-quote-name 'identity)
+ (if quoted 'tramp-compat-file-name-quote 'identity)
(cadr (car (directory-files-and-attributes
file1 nil (regexp-quote elt1)))))
(file-remote-p (file-truename file2) 'localname)))