;;; tramp.el --- Transparent Remote Access, Multiple Protocol
-;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+;; Copyright (C) 1998-2011 Free Software Foundation, Inc.
;; Author: Kai Großjohann <kai.grossjohann@gmx.net>
;; Michael Albinus <michael.albinus@gmx.de>
;; password caching. "scpc" is chosen if we detect that the user is
;; running OpenSSH 4.0 or newer.
(cond
- ;; PuTTY is installed.
- ((executable-find "pscp")
+ ;; PuTTY is installed. We don't take it, if it is installed on a
+ ;; non-windows system, or pscp from the pssh (parallel ssh) package
+ ;; is found.
+ ((and (eq system-type 'windows-nt)
+ (executable-find "pscp"))
(if (or (fboundp 'password-read)
(fboundp 'auth-source-user-or-password)
+ (fboundp 'auth-source-search)
;; Pageant is running.
(tramp-compat-process-running-p "Pageant"))
"pscp"
((tramp-detect-ssh-controlmaster) "scpc")
((or (fboundp 'password-read)
(fboundp 'auth-source-user-or-password)
+ (fboundp 'auth-source-search)
;; ssh-agent is running.
(getenv "SSH_AUTH_SOCK")
(getenv "SSH_AGENT_PID"))
:group 'tramp
:type 'string)
+;;;###tramp-autoload
(defcustom tramp-default-method-alist nil
"*Default method to use for specific host/user pairs.
This is an alist of items (HOST USER METHOD). The first matching item
See `tramp-methods' for a list of possibilities for METHOD."
:group 'tramp
- :type '(repeat (list (regexp :tag "Host regexp")
- (regexp :tag "User regexp")
- (string :tag "Method"))))
+ :type '(repeat (list (choice :tag "Host regexp" regexp sexp)
+ (choice :tag "User regexp" regexp sexp)
+ (choice :tag "Method name" string (const nil)))))
(defcustom tramp-default-user nil
"*Default user to use for transferring files.
:group 'tramp
:type '(choice (const nil) string))
+;;;###tramp-autoload
(defcustom tramp-default-user-alist nil
"*Default user to use for specific method/host pairs.
This is an alist of items (METHOD HOST USER). The first matching item
If the file name does not specify the method, lookup is done using the
empty string for the method name."
:group 'tramp
- :type '(repeat (list (regexp :tag "Method regexp")
- (regexp :tag "Host regexp")
- (string :tag "User"))))
+ :type '(repeat (list (choice :tag "Method regexp" regexp sexp)
+ (choice :tag " Host regexp" regexp sexp)
+ (choice :tag " User name" string (const nil)))))
(defcustom tramp-default-host (system-name)
"*Default host to use for transferring files.
:group 'tramp
:type '(repeat (list (choice :tag "Host regexp" regexp sexp)
(choice :tag "User regexp" regexp sexp)
- (choice :tag "Proxy remote name" string (const nil)))))
+ (choice :tag " Proxy name" string (const nil)))))
+;;;###tramp-autoload
(defconst tramp-local-host-regexp
(concat
- "^" (regexp-opt (list "localhost" (system-name) "127\.0\.0\.1" "::1") t) "$")
+ "\\`"
+ (regexp-opt
+ (list "localhost" "localhost6" (system-name) "127\.0\.0\.1" "::1") t)
+ "\\'")
"*Host names which are regarded as local host.")
(defvar tramp-completion-function-alist nil
"File name of a persistent local temporary file.
Useful for \"rsync\" like methods.")
(make-variable-buffer-local 'tramp-temp-buffer-file-name)
+(put 'tramp-temp-buffer-file-name 'permanent-local t)
;; XEmacs is distributed with few Lisp packages. Further packages are
;; installed using EFS. If we use a unified filename format, then
((equal tramp-syntax 'sep) "/")
((equal tramp-syntax 'url) "://")
(t (error "Wrong `tramp-syntax' defined")))
- "*String matching delimeter between method and user or host names.
+ "*String matching delimiter between method and user or host names.
Used in `tramp-make-tramp-file-name'.")
(defconst tramp-postfix-method-regexp
(regexp-quote tramp-postfix-method-format)
- "*Regexp matching delimeter between method and user or host names.
+ "*Regexp matching delimiter between method and user or host names.
Derived from `tramp-postfix-method-format'.")
(defconst tramp-user-regexp "[^:/ \t]+"
"*Regexp matching user names.")
+;;;###tramp-autoload
(defconst tramp-prefix-domain-format "%"
- "*String matching delimeter between user and domain names.")
+ "*String matching delimiter between user and domain names.")
+;;;###tramp-autoload
(defconst tramp-prefix-domain-regexp
(regexp-quote tramp-prefix-domain-format)
- "*Regexp matching delimeter between user and domain names.
+ "*Regexp matching delimiter between user and domain names.
Derived from `tramp-prefix-domain-format'.")
(defconst tramp-domain-regexp "[-a-zA-Z0-9_.]+"
"*Regexp matching user names with domain names.")
(defconst tramp-postfix-user-format "@"
- "*String matching delimeter between user and host names.
+ "*String matching delimiter between user and host names.
Used in `tramp-make-tramp-file-name'.")
(defconst tramp-postfix-user-regexp
(regexp-quote tramp-postfix-user-format)
- "*Regexp matching delimeter between user and host names.
+ "*Regexp matching delimiter between user and host names.
Derived from `tramp-postfix-user-format'.")
(defconst tramp-host-regexp "[a-zA-Z0-9_.-]+"
((equal tramp-syntax 'sep) "#")
((equal tramp-syntax 'url) ":")
(t (error "Wrong `tramp-syntax' defined")))
- "*String matching delimeter between host names and port numbers.")
+ "*String matching delimiter between host names and port numbers.")
(defconst tramp-prefix-port-regexp
(regexp-quote tramp-prefix-port-format)
- "*Regexp matching delimeter between host names and port numbers.
+ "*Regexp matching delimiter between host names and port numbers.
Derived from `tramp-prefix-port-format'.")
(defconst tramp-port-regexp "[0-9]+"
((equal tramp-syntax 'sep) "]")
((equal tramp-syntax 'url) "")
(t (error "Wrong `tramp-syntax' defined")))
- "*String matching delimeter between host names and localnames.
+ "*String matching delimiter between host names and localnames.
Used in `tramp-make-tramp-file-name'.")
(defconst tramp-postfix-host-regexp
(regexp-quote tramp-postfix-host-format)
- "*Regexp matching delimeter between host names and localnames.
+ "*Regexp matching delimiter between host names and localnames.
Derived from `tramp-postfix-host-format'.")
(defconst tramp-localname-regexp ".*$"
(defun tramp-file-name-port (vec)
"Return the port number of VEC."
(save-match-data
- (let ((host (tramp-file-name-host vec)))
- (and (stringp host)
- (string-match tramp-host-with-port-regexp host)
- (string-to-number (match-string 2 host))))))
+ (let ((method (tramp-file-name-method vec))
+ (host (tramp-file-name-host vec)))
+ (or (and (stringp host)
+ (string-match tramp-host-with-port-regexp host)
+ (string-to-number (match-string 2 host)))
+ (tramp-get-method-parameter method 'tramp-default-port)))))
;;;###tramp-autoload
(defun tramp-tramp-file-p (name)
(or (tramp-get-connection-property vec "process-buffer" nil)
(tramp-get-buffer vec)))
+(defun tramp-get-connection-name (vec)
+ "Get the connection name to be used for VEC.
+In case a second asynchronous communication has been started, it is different
+from the default one."
+ (or (tramp-get-connection-property vec "process-name" nil)
+ (tramp-buffer-name vec)))
+
(defun tramp-get-connection-process (vec)
"Get the connection process to be used for VEC.
In case a second asynchronous communication has been started, it is different
from the default one."
- (get-process
- (or (tramp-get-connection-property vec "process-name" nil)
- (tramp-buffer-name vec))))
+ (get-process (tramp-get-connection-name vec)))
(defun tramp-debug-buffer-name (vec)
"A name for the debug buffer for VEC."
(let ((now (current-time)))
(insert (format-time-string "%T." now))
(insert (format "%06d " (nth 2 now))))
- ;; Calling function.
+ ;; Calling Tramp function. We suppress compat and trace
+ ;; functions from being displayed.
(let ((btn 1) btf fn)
(while (not fn)
(setq btf (nth 1 (backtrace-frame btn)))
(setq fn "")
(when (symbolp btf)
(setq fn (symbol-name btf))
- (unless (and (string-match "^tramp" fn)
- (not (string-match
- "^tramp\\(-debug\\)?\\(-message\\|-error\\|-compat-funcall\\)$"
- fn)))
+ (unless
+ (and
+ (string-match "^tramp" fn)
+ (not
+ (string-match
+ (concat
+ "^"
+ (regexp-opt
+ '("tramp-compat-funcall"
+ "tramp-compat-with-temp-message"
+ "tramp-debug-message"
+ "tramp-error"
+ "tramp-error-with-buffer"
+ "tramp-message")
+ t)
+ "$")
+ fn)))
(setq fn nil)))
(setq btn (1+ btn))))
;; The following code inserts filename and line number.
(if (memq system-type '(cygwin windows-nt))
(defun tramp-drop-volume-letter (name)
"Cut off unnecessary drive letter from file NAME.
-The function `tramp-handle-expand-file-name' calls `expand-file-name'
+The functions `tramp-*-handle-expand-file-name' call `expand-file-name'
locally on a remote file name. When the local system is a W32 system
but the remote system is Unix, this introduces a superfluous drive
letter into the file name. This function removes it."
(let ((props (tramp-compat-funcall
'overlay-properties (symbol-value 'rfn-eshadow-overlay))))
(while props
- (tramp-compat-funcall
- 'overlay-put tramp-rfn-eshadow-overlay (pop props) (pop props))))))
+ ;; The `field' property prevents correct minibuffer
+ ;; completion; we exclude it.
+ (if (not (eq (car props) 'field))
+ (tramp-compat-funcall
+ 'overlay-put tramp-rfn-eshadow-overlay (pop props) (pop props))
+ (pop props) (pop props))))))
(when (boundp 'rfn-eshadow-setup-minibuffer-hook)
(add-hook 'rfn-eshadow-setup-minibuffer-hook
(condition-case err
(apply foreign operation args)
- ;; Trace, that somebody has interrupted the operation.
+ ;; Trace that somebody has interrupted the operation.
(quit
(let (tramp-message-show-message)
(tramp-message
(vector method user host localname)))))
;; This function returns all possible method completions, adding the
-;; trailing method delimeter.
+;; trailing method delimiter.
(defun tramp-get-completion-methods (partial-method)
"Returns all method completions for PARTIAL-METHOD."
(mapcar
(t (file-local-copy filename)))))
;; When the file is not readable for the owner, it
- ;; cannot be inserted, even it is redable for the group
- ;; or for everybody.
+ ;; cannot be inserted, even if it is readable for the
+ ;; group or for everybody.
(set-file-modes local-copy (tramp-compat-octal-to-decimal "0600"))
(when (and (null remote-copy)
method 'tramp-copy-keep-tmpfile))
;; We keep the local file for performance reasons,
;; useful for "rsync".
- (setq tramp-temp-buffer-file-name local-copy)
- (put 'tramp-temp-buffer-file-name 'permanent-local t))
+ (setq tramp-temp-buffer-file-name local-copy))
(with-progress-reporter
v 3 (format "Inserting local temp file `%s'" local-copy)
(setq buffer-file-name filename)
(setq buffer-read-only (not (file-writable-p filename)))
(set-visited-file-modtime)
- (set-buffer-modified-p nil)
- ;; For root, preserve owner and group when editing files.
- (when (string-equal (file-remote-p filename 'user) "root")
- (set (make-local-variable 'backup-by-copying-when-mismatch) t)))
+ (set-buffer-modified-p nil))
(when (and (stringp local-copy)
(or remote-copy (null tramp-temp-buffer-file-name)))
(delete-file local-copy))
(defun tramp-handle-substitute-in-file-name (filename)
"Like `substitute-in-file-name' for Tramp files.
\"//\" and \"/~\" substitute only in the local filename part.
-If the URL Tramp syntax is chosen, \"//\" as method delimeter and \"/~\" at
+If the URL Tramp syntax is chosen, \"//\" as method delimiter and \"/~\" at
beginning of local filename are not substituted."
;; First, we must replace environment variables.
(setq filename (tramp-replace-environment-variables filename))
(tramp-compat-with-temp-message ""
;; Enable auth-source and password-cache.
(tramp-set-connection-property vec "first-password-request" t)
- (let (exit)
- (while (not exit)
- (tramp-message proc 3 "Waiting for prompts from remote shell")
- (setq exit
- (catch 'tramp-action
- (if timeout
- (with-timeout (timeout)
- (tramp-process-one-action proc vec actions))
- (tramp-process-one-action proc vec actions)))))
- (with-current-buffer (tramp-get-connection-buffer vec)
- (widen)
- (tramp-message vec 6 "\n%s" (buffer-string)))
- (unless (eq exit 'ok)
- (tramp-clear-passwd vec)
- (tramp-error-with-buffer
- nil vec 'file-error
- (cond
- ((eq exit 'permission-denied) "Permission denied")
- ((eq exit 'process-died) "Process died")
- (t "Login failed")))))))
+ (save-restriction
+ (let (exit)
+ (while (not exit)
+ (tramp-message proc 3 "Waiting for prompts from remote shell")
+ (setq exit
+ (catch 'tramp-action
+ (if timeout
+ (with-timeout (timeout)
+ (tramp-process-one-action proc vec actions))
+ (tramp-process-one-action proc vec actions)))))
+ (with-current-buffer (tramp-get-connection-buffer vec)
+ (widen)
+ (tramp-message vec 6 "\n%s" (buffer-string)))
+ (unless (eq exit 'ok)
+ (tramp-clear-passwd vec)
+ (tramp-error-with-buffer
+ nil vec 'file-error
+ (cond
+ ((eq exit 'permission-denied) "Permission denied")
+ ((eq exit 'process-died) "Process died")
+ (t "Login failed"))))))))
:;; Utility functions:
(or prompt
(with-current-buffer (process-buffer proc)
(tramp-check-for-regexp proc tramp-password-prompt-regexp)
- (format "%s for %s " (capitalize (match-string 1)) key)))))
+ (format "%s for %s " (capitalize (match-string 1)) key))))
+ auth-info auth-passwd)
(with-parsed-tramp-file-name key nil
(prog1
(or
- ;; See if auth-sources contains something useful, if it's bound.
+ ;; See if auth-sources contains something useful, if it's
+ ;; bound. `auth-source-user-or-password' is an obsoleted
+ ;; function, it has been replaced by `auth-source-search'.
(and (boundp 'auth-sources)
(tramp-get-connection-property v "first-password-request" nil)
;; Try with Tramp's current method.
- (tramp-compat-funcall
- 'auth-source-user-or-password
- "password" tramp-current-host tramp-current-method))
+ (if (fboundp 'auth-source-search)
+ (setq auth-info
+ (tramp-compat-funcall
+ 'auth-source-search
+ :max 1
+ :user (or tramp-current-user t)
+ :host tramp-current-host
+ :port tramp-current-method)
+ auth-passwd (plist-get (nth 0 auth-info) :secret)
+ auth-passwd (if (functionp auth-passwd)
+ (funcall auth-passwd)
+ auth-passwd))
+ (tramp-compat-funcall
+ 'auth-source-user-or-password
+ "password" tramp-current-host tramp-current-method)))
;; Try the password cache.
(when (functionp 'password-read)
(unless (tramp-get-connection-property