;;; 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 <kai.grossjohann@gmx.net>
;; Michael Albinus <michael.albinus@gmx.de>
(defcustom tramp-save-ad-hoc-proxies nil
"Whether to save ad-hoc proxies persistently."
:group 'tramp
+ :version "24.3"
:type 'boolean)
+(defcustom tramp-restricted-shell-hosts-alist
+ (when (memq system-type '(windows-nt))
+ (list (concat "\\`" (regexp-quote (system-name)) "\\'")))
+ "List of hosts, which run a restricted shell.
+This is a list of regular expressions, which denote hosts running
+a registered shell like \"rbash\". Those hosts can be used as
+proxies only, see `tramp-default-proxies-alist'. If the local
+host runs a registered shell, it shall be added to this list, too."
+ :version "24.3"
+ :group 'tramp
+ :type '(repeat (regexp :tag "Host regexp")))
+
;;;###tramp-autoload
(defconst tramp-local-host-regexp
(concat
(get-buffer-create (tramp-debug-buffer-name vec))
(when (bobp)
(setq buffer-undo-list t)
+ ;; So it does not get loaded while outline-regexp is let-bound.
+ (require 'outline)
;; Activate `outline-mode'. This runs `text-mode-hook' and
;; `outline-mode-hook'. We must prevent that local processes
;; die. Yes: I've seen `flyspell-mode', which starts "ispell".
"tramp-debug-message"
"tramp-error"
"tramp-error-with-buffer"
- "tramp-message"
- "tramp-with-progress-reporter")
+ "tramp-message")
t)
"$")
fn)))
(defvar tramp-message-show-progress-reporter-message t
"Show Tramp progress reporter message in the minibuffer.
-This variable is used to disable recurive progress reporter messages.")
+This variable is used to disable recursive progress reporter messages.")
(defsubst tramp-message (vec-or-proc level fmt-string &rest args)
"Emit a message depending on verbosity level.
(when (string-match message (or (current-message) ""))
(tramp-compat-funcall 'progress-reporter-update reporter value))))
-(defmacro tramp-with-progress-reporter (vec level message &rest body)
+(defmacro with-tramp-progress-reporter (vec level message &rest body)
"Executes BODY, spinning a progress reporter with MESSAGE.
If LEVEL does not fit for visible messages, or if this is a
nested call of the macro, there are only traces without a visible
(tramp-message ,vec ,level "%s...done" ,message))))
(tramp-compat-font-lock-add-keywords
- 'emacs-lisp-mode '("\\<tramp-with-progress-reporter\\>"))
+ 'emacs-lisp-mode '("\\<with-tramp-progress-reporter\\>"))
+
+(defmacro with-tramp-file-property (vec file property &rest body)
+ "Check in Tramp cache for PROPERTY, otherwise execute BODY and set cache.
+FILE must be a local file name on a connection identified via VEC."
+ `(if (file-name-absolute-p ,file)
+ (let ((value (tramp-get-file-property ,vec ,file ,property 'undef)))
+ (when (eq value 'undef)
+ ;; We cannot pass @body as parameter to
+ ;; `tramp-set-file-property' because it mangles our
+ ;; debug messages.
+ (setq value (progn ,@body))
+ (tramp-set-file-property ,vec ,file ,property value))
+ value)
+ ,@body))
+
+(put 'with-tramp-file-property 'lisp-indent-function 3)
+(put 'with-tramp-file-property 'edebug-form-spec t)
+(tramp-compat-font-lock-add-keywords
+ 'emacs-lisp-mode '("\\<with-tramp-file-property\\>"))
+
+(defmacro with-tramp-connection-property (key property &rest body)
+ "Check in Tramp for property PROPERTY, otherwise executes BODY and set."
+ `(let ((value (tramp-get-connection-property ,key ,property 'undef)))
+ (when (eq value 'undef)
+ ;; We cannot pass ,@body as parameter to
+ ;; `tramp-set-connection-property' because it mangles our debug
+ ;; messages.
+ (setq value (progn ,@body))
+ (tramp-set-connection-property ,key ,property value))
+ value))
+
+(put 'with-tramp-connection-property 'lisp-indent-function 2)
+(put 'with-tramp-connection-property 'edebug-form-spec t)
+(tramp-compat-font-lock-add-keywords
+ 'emacs-lisp-mode '("\\<with-tramp-connection-property\\>"))
(defalias 'tramp-drop-volume-letter
(if (memq system-type '(cygwin windows-nt))
'identity))
+(if (featurep 'xemacs)
+ (defalias 'tramp-drop-volume-letter 'identity))
+
(defun tramp-cleanup (vec)
"Cleanup connection VEC, but keep the debug buffer."
(with-current-buffer (tramp-get-debug-buffer vec)
(let ((default-directory
(tramp-compat-temporary-file-directory)))
(load (cadr sf) 'noerror 'nomessage)))
+ ;; If `non-essential' is non-nil, Tramp shall
+ ;; not open a new connection.
;; If Tramp detects that it shouldn't continue
- ;; to work, it throws the `suppress' event. We
- ;; try the default handler then.
+ ;; to work, it throws the `suppress' event.
;; This could happen for example, when Tramp
;; tries to open the same connection twice in a
;; short time frame.
+ ;; In both cases, we try the default handler then.
(setq result
- (catch 'suppress (apply foreign operation args)))
- (if (eq result 'suppress)
- (let (tramp-message-show-message)
- (tramp-message
- v 1 "Suppress received in operation %s"
- (append (list operation) args))
- (tramp-cleanup v)
- (tramp-run-real-handler operation args))
- result))
+ (catch 'non-essential
+ (catch 'suppress
+ (apply foreign operation args))))
+ (cond
+ ((eq result 'non-essential)
+ (tramp-message
+ v 5 "Non-essential received in operation %s"
+ (append (list operation) args))
+ (tramp-run-real-handler operation args))
+ ((eq result 'suppress)
+ (let (tramp-message-show-message)
+ (tramp-message
+ v 1 "Suppress received in operation %s"
+ (append (list operation) args))
+ (tramp-cleanup v)
+ (tramp-run-real-handler operation args)))
+ (t result)))
;; Trace that somebody has interrupted the operation.
((debug quit)
(setq filename (expand-file-name filename))
(let (result local-copy remote-copy)
(with-parsed-tramp-file-name filename nil
- (tramp-with-progress-reporter
+ (with-tramp-progress-reporter
v 3 (format "Inserting `%s'" filename)
(unwind-protect
(if (not (file-exists-p filename))
(if (not (file-exists-p file))
nil
(let ((tramp-message-show-message (not nomessage)))
- (tramp-with-progress-reporter v 0 (format "Loading %s" file)
+ (with-tramp-progress-reporter v 0 (format "Loading %s" file)
(let ((local-copy (file-local-copy file)))
;; MUST-SUFFIX doesn't exist on XEmacs, so let it default to nil.
(unwind-protect
"Send the login name."
(when (not (stringp tramp-current-user))
(setq tramp-current-user
- (with-connection-property vec "login-as"
+ (with-tramp-connection-property vec "login-as"
(save-window-excursion
(let ((enable-recursive-minibuffers t))
(pop-to-buffer (tramp-get-connection-buffer vec))
;; Under Windows XP, accept-process-output doesn't return
;; sometimes. So we add an additional timeout.
(with-timeout ((or timeout 1))
- (accept-process-output proc timeout timeout-msecs)))
+ (if (featurep 'xemacs)
+ (accept-process-output proc timeout timeout-msecs)
+ (accept-process-output proc timeout timeout-msecs (and proc t)))))
(tramp-message proc 10 "\n%s" (buffer-string))))
(defun tramp-check-for-regexp (proc regexp)
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
(defun tramp-get-inode (vec)
"Returns the virtual inode number.
If it doesn't exist, generate a new one."
- (with-file-property vec (tramp-file-name-localname vec) "inode"
+ (with-tramp-file-property vec (tramp-file-name-localname vec) "inode"
(setq tramp-inodes (1+ tramp-inodes))))
(defun tramp-get-device (vec)
"Returns the virtual device number.
If it doesn't exist, generate a new one."
- (with-connection-property (tramp-get-connection-process vec) "device"
+ (with-tramp-connection-property (tramp-get-connection-process vec) "device"
(cons -1 (setq tramp-devices (1+ tramp-devices)))))
(defun tramp-equal-remote (file1 file2)
(defun tramp-get-remote-tmpdir (vec)
"Return directory for temporary files on the remote host identified by VEC."
- (with-connection-property vec "tmpdir"
+ (with-tramp-connection-property vec "tmpdir"
(let ((dir (tramp-make-tramp-file-name
(tramp-file-name-method vec)
(tramp-file-name-user vec)
("oct" . 10) ("nov" . 11) ("dec" . 12))
"Alist mapping month names to integers.")
+;; FIXME: Shouldn't this also look at any subseconds parts of T1 and T2?
;;;###tramp-autoload
(defun tramp-time-less-p (t1 t2)
"Say whether time value T1 is less than time value T2."
(and (= (car t1) (car t2))
(< (nth 1 t1) (nth 1 t2)))))
+;; FIXME: Shouldn't this also look at any subseconds parts of T1 and T2?
(defun tramp-time-subtract (t1 t2)
"Subtract two time values.
Return the difference in the format of a time value."
;; * In Emacs 21, `insert-directory' shows total number of bytes used
;; by the files in that directory. Add this here.
;; * Avoid screen blanking when hitting `g' in dired. (Eli Tziperman)
-;; * Make ffap.el grok Tramp filenames. (Eli Tziperman)
;; * abbreviate-file-name
;; * Better error checking. At least whenever we see something
;; strange when doing zerop, we should kill the process and start