X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/53b6a8b11383585ae8a175bf53964e35e889d338..d7291032804bbb2f577ef1425dac37e8510181a3:/lisp/net/tramp.el diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index a4be6eab41..a4250f9498 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -1,6 +1,6 @@ ;;; tramp.el --- Transparent Remote Access, Multiple Protocol -;; Copyright (C) 1998-2012 Free Software Foundation, Inc. +;; Copyright (C) 1998-2013 Free Software Foundation, Inc. ;; Author: Kai Großjohann ;; Michael Albinus @@ -280,15 +280,18 @@ started on the local host. You should specify a remote host `localhost' or the name of the local host. Another host name is useful only in combination with `tramp-default-proxies-alist'.") -(defun tramp-detect-ssh-controlmaster () - "Call ssh to detect whether it supports the ControlMaster argument. -This function may return nil when the argument is supported, but -shouldn't return t when it isn't." - (ignore-errors - (with-temp-buffer - (call-process "ssh" nil t nil "-o" "ControlMaster") - (goto-char (point-min)) - (search-forward-regexp "Missing ControlMaster argument" nil t)))) +;;;###tramp-autoload +(defvar tramp-ssh-controlmaster-template + (ignore-errors + (with-temp-buffer + (call-process "ssh" nil t nil "-o" "ControlMaster") + (goto-char (point-min)) + (when (search-forward-regexp "Missing ControlMaster argument" nil t) + '("-o" "ControlPath=%t.%%r@%%h:%%p" + "-o" "ControlMaster=auto" + "-o" "ControlPersist=no")))) + "Call ssh to detect whether it supports the ControlMaster argument. +Return a template to be used in `tramp-methods'.") (defcustom tramp-default-method ;; An external copy method seems to be preferred, because it performs @@ -297,8 +300,9 @@ shouldn't return t when it isn't." ;; permanent password queries. Either a password agent like ;; "ssh-agent" or "Pageant" shall run, or the optional ;; password-cache.el or auth-sources.el packages shall be active for - ;; password caching. "scpc" is chosen if we detect that the user is - ;; running OpenSSH 4.0 or newer. + ;; password caching. If we detect that the user is running OpenSSH + ;; 4.0 or newer, we could reuse the connection, which calls also for + ;; an external method. (cond ;; 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 @@ -314,16 +318,16 @@ shouldn't return t when it isn't." "plink")) ;; There is an ssh installation. ((executable-find "scp") - (cond - ((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")) - "scp") - (t "ssh"))) + (if (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") + ;; We could reuse the connection. + tramp-ssh-controlmaster-template) + "scp" + "ssh")) ;; Fallback. (t "ftp")) "Default method to use for transferring files. @@ -381,6 +385,23 @@ Useful for su and sudo methods mostly." :group 'tramp :type 'string) +;;;###tramp-autoload +(defcustom tramp-default-host-alist nil + "Default host to use for specific method/user pairs. +This is an alist of items (METHOD USER HOST). The first matching item +specifies the host to use for a file name which does not specify a +host. METHOD and HOST are regular expressions or nil, which is +interpreted as a regular expression which always matches. If no entry +matches, the variable `tramp-default-host' takes effect. + +If the file name does not specify the method, lookup is done using the +empty string for the method name." + :group 'tramp + :version "24.4" + :type '(repeat (list (choice :tag "Method regexp" regexp sexp) + (choice :tag " User regexp" regexp sexp) + (choice :tag " Host name" string (const nil))))) + (defcustom tramp-default-proxies-alist nil "Route to be followed for specific host/user pairs. This is an alist of items (HOST USER PROXY). The first matching @@ -918,7 +939,7 @@ See `tramp-file-name-structure' for more explanations.") This regexp should match partial Tramp file names only. Please note that the entry in `file-name-handler-alist' is made when -this file (tramp.el) is loaded. This means that this variable must be set +this file \(tramp.el\) is loaded. This means that this variable must be set before loading tramp.el. Alternatively, `file-name-handler-alist' can be updated after changing this variable. @@ -1001,11 +1022,25 @@ this variable to be set as well." ;; for an override of the system default. (defcustom tramp-process-connection-type t "Overrides `process-connection-type' for connections from Tramp. -Tramp binds process-connection-type to the value given here before +Tramp binds `process-connection-type' to the value given here before opening a connection to a remote host." :group 'tramp :type '(choice (const nil) (const t) (const pty))) +(defcustom tramp-connection-min-time-diff 5 + "Defines seconds between two consecutive connection attempts. +This is necessary as self defense mechanism, in order to avoid +yo-yo connection attempts when the remote host is unavailable. + +A value of 0 or `nil' suppresses this check. This might be +necessary, when several out-of-order copy operations are +performed, or when several asynchronous processes will be started +in a short time frame. In those cases it is recommended to +let-bind this variable." + :group 'tramp + :version "24.4" + :type '(choice (const nil) integer)) + (defcustom tramp-completion-reread-directory-timeout 10 "Defines seconds since last remote command before rereading a directory. A remote directory might have changed its contents. In order to @@ -1016,7 +1051,7 @@ have been gone since last remote command execution. A value of `t' would require an immediate reread during filename completion, `nil' means to use always cached values for the directory contents." :group 'tramp - :type '(choice (const nil) integer)) + :type '(choice (const nil) (const t) integer)) ;;; Internal Variables: @@ -1123,9 +1158,12 @@ If the `tramp-methods' entry does not exist, return nil." ;;;###tramp-autoload (defun tramp-tramp-file-p (name) - "Return t if NAME is a string with Tramp file name syntax." + "Return t if NAME is a string with Tramp file name syntax. +It checks also, whether NAME is unibyte encoded." (save-match-data - (and (stringp name) (string-match tramp-file-name-regexp name)))) + (and (stringp name) +; (string-equal name (string-as-unibyte name)) + (string-match tramp-file-name-regexp name)))) (defun tramp-find-method (method user host) "Return the right method string to use. @@ -1163,6 +1201,15 @@ This is USER, if non-nil. Otherwise, do a lookup in "Return the right host string to use. This is HOST, if non-nil. Otherwise, it is `tramp-default-host'." (or (and (> (length host) 0) host) + (let ((choices tramp-default-host-alist) + lhost item) + (while choices + (setq item (pop choices)) + (when (and (string-match (or (nth 0 item) "") (or method "")) + (string-match (or (nth 1 item) "") (or user ""))) + (setq lhost (nth 2 item)) + (setq choices nil))) + lhost) tramp-default-host)) (defun tramp-dissect-file-name (name &optional nodefault) @@ -1348,7 +1395,9 @@ ARGS to actually emit the message (if applicable)." (concat "^" (regexp-opt - '("tramp-compat-funcall" + '("tramp-backtrace" + "tramp-compat-condition-case-unless-debug" + "tramp-compat-funcall" "tramp-compat-with-temp-message" "tramp-debug-message" "tramp-error" @@ -1455,8 +1504,18 @@ an input event arrives. The other arguments are passed to `tramp-error'." (or (and (bufferp buffer) buffer) (and (processp vec-or-proc) (process-buffer vec-or-proc)) (tramp-get-connection-buffer vec-or-proc))) + (when (string-equal fmt-string "Process died") + (message + "%s\n %s" + "Tramp failed to connect. If this happens repeatedly, try" + "`M-x tramp-cleanup-this-connection'")) (sit-for 30)))))) +(defsubst tramp-backtrace (vec-or-proc) + "Dump a backtrace into the debug buffer. +This function is meant for debugging purposes." + (tramp-message vec-or-proc 10 "\n%s" (with-output-to-string (backtrace)))) + (defmacro with-parsed-tramp-file-name (filename var &rest body) "Parse a Tramp filename and make components available in the body. @@ -1748,28 +1807,23 @@ value of `default-file-modes', without execute permissions." (or (file-modes filename) (logand (default-file-modes) (tramp-compat-octal-to-decimal "0666")))) -(defalias 'tramp-replace-environment-variables - (if (ignore-errors - (equal "${ tramp?}" - (tramp-compat-funcall - 'substitute-env-vars "${ tramp?}" 'only-defined))) - (lambda (filename) - "Like `substitute-env-vars' with `only-defined' non-nil." - (tramp-compat-funcall 'substitute-env-vars filename 'only-defined)) - (lambda (filename) - "Replace environment variables in FILENAME. +(defun tramp-replace-environment-variables (filename) + "Replace environment variables in FILENAME. Return the string with the replaced variables." - (save-match-data - (let ((idx (string-match "$\\(\\w+\\)" filename))) - ;; `$' is coded as `$$'. - (when (and idx - (or (zerop idx) (not (eq ?$ (aref filename (1- idx))))) - (getenv (match-string 1 filename))) - (setq filename - (replace-match - (substitute-in-file-name (match-string 0 filename)) - t nil filename))) - filename))))) + (or (ignore-errors + (tramp-compat-funcall 'substitute-env-vars filename 'only-defined)) + ;; We need an own implementation. + (save-match-data + (let ((idx (string-match "$\\(\\w+\\)" filename))) + ;; `$' is coded as `$$'. + (when (and idx + (or (zerop idx) (not (eq ?$ (aref filename (1- idx))))) + (getenv (match-string 1 filename))) + (setq filename + (replace-match + (substitute-in-file-name (match-string 0 filename)) + t nil filename))) + filename)))) ;; In XEmacs, electricity is implemented via a key map for ?/ and ?~, ;; which calls corresponding functions (see minibuf.el). @@ -2752,6 +2806,11 @@ User is always nil." (if (or dir-p (file-directory-p dir)) dir (file-name-directory dir)) nil (tramp-flush-directory-property v localname))) +(defun tramp-handle-file-accessible-directory-p (filename) + "Like `file-accessible-directory-p' for Tramp files." + (and (file-directory-p filename) + (file-executable-p filename))) + (defun tramp-handle-file-exists-p (filename) "Like `file-exists-p' for Tramp files." (not (null (file-attributes filename)))) @@ -2975,13 +3034,15 @@ User is always nil." (setq tramp-temp-buffer-file-name local-copy)) ;; We must ensure that `file-coding-system-alist' - ;; matches `local-copy'. + ;; matches `local-copy'. We must also use `visit', + ;; otherwise there might be an error in the + ;; `revert-buffer' function under XEmacs. (let ((file-coding-system-alist (tramp-find-file-name-coding-system-alist filename local-copy))) (setq result (insert-file-contents - local-copy nil nil nil replace))))) + local-copy visit nil nil replace))))) ;; Save exit. (progn @@ -3365,7 +3426,9 @@ Erase echoed commands if exists." 0 (min tramp-echo-mark-marker-length (1- (point-max)))) (tramp-compat-funcall 'buffer-substring-no-properties - 1 (min (1+ tramp-echo-mark-marker-length) (point-max)))))) + (point-min) + (min (+ (point-min) tramp-echo-mark-marker-length) + (point-max)))))) ;; No echo to be handled, now we can look for the regexp. ;; Sometimes, lines are much to long, and we run into a "Stack ;; overflow in regexp matcher". For example, //DIRED// lines of @@ -3851,6 +3914,39 @@ Only works for Bourne-like shells." t t result))) result)))) +;;; Integration of eshell.el: + +(eval-when-compile + (defvar eshell-path-env)) + +;; eshell.el keeps the path in `eshell-path-env'. We must change it +;; when `default-directory' points to another host. +(defun tramp-eshell-directory-change () + "Set `eshell-path-env' to $PATH of the host related to `default-directory'." + (setq eshell-path-env + (if (file-remote-p default-directory) + (with-parsed-tramp-file-name default-directory nil + (mapconcat + 'identity + (or + ;; When `tramp-own-remote-path' is in `tramp-remote-path', + ;; the remote path is only set in the session cache. + (tramp-get-connection-property + (tramp-get-connection-process v) "remote-path" nil) + (tramp-get-connection-property v "remote-path" nil)) + ":")) + (getenv "PATH")))) + +(eval-after-load "esh-util" + '(progn + (tramp-eshell-directory-change) + (add-hook 'eshell-directory-change-hook + 'tramp-eshell-directory-change) + (add-hook 'tramp-unload-hook + (lambda () + (remove-hook 'eshell-directory-change-hook + 'tramp-eshell-directory-change))))) + ;; Checklist for `tramp-unload-hook' ;; - Unload all `tramp-*' packages ;; - Reset `file-name-handler-alist'