aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Albinus2019-06-24 17:36:00 +0200
committerMichael Albinus2019-06-24 17:36:00 +0200
commit18a7e5414c534db38eedb06b16ef68f2c17b98fd (patch)
tree355be82e621742ec6768dcf859d6edabc3c643ce
parentb72cd0c74682cf87799f324eb3dace5f1962baf0 (diff)
downloademacs-18a7e5414c534db38eedb06b16ef68f2c17b98fd.tar.gz
emacs-18a7e5414c534db38eedb06b16ef68f2c17b98fd.zip
Improve error handling in Tramp
* lisp/net/tramp-compat.el (ls-lisp): Require. * lisp/net/tramp.el (ls-lisp-use-insert-directory-program): Don't declare. (tramp-current-connection): Adapt docstring. (tramp-debug-message): Adapt function names. (tramp-error, tramp-run-real-handler): Let-bind `signal-hook-function'. (tramp-signal-hook-function): New defun. (tramp-debug-on-error, tramp-condition-case-unless-debug): Remove. (tramp-file-name-handler): Handle `tramp-current-connection'. Let-bind `signal-hook-function'. Use `unwind-protect' instead of `tramp-condition-case-unless-debug'. (tramp-handle-insert-directory): Don't require ls-lisp. (tramp-process-actions): Check, that `tramp-password-save-function' is non-nil. (tramp-equal-remote): Handle the case both files are local. * test/lisp/net/tramp-tests.el (tramp--test-instrument-test-case): Do not bind `tramp-debug-on-error'. (tramp--test-ignore-make-symbolic-link-error): Make error handler more explicit about the error.
-rw-r--r--lisp/net/tramp-compat.el1
-rw-r--r--lisp/net/tramp.el206
-rw-r--r--test/lisp/net/tramp-tests.el15
3 files changed, 103 insertions, 119 deletions
diff --git a/lisp/net/tramp-compat.el b/lisp/net/tramp-compat.el
index d4380f8deb3..15b737d281b 100644
--- a/lisp/net/tramp-compat.el
+++ b/lisp/net/tramp-compat.el
@@ -36,6 +36,7 @@
36 36
37(require 'auth-source) 37(require 'auth-source)
38(require 'format-spec) 38(require 'format-spec)
39(require 'ls-lisp) ;; Due to `tramp-handle-insert-directory'.
39(require 'parse-time) 40(require 'parse-time)
40(require 'shell) 41(require 'shell)
41 42
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index e5b0f149ca6..0a5ccb6f1c6 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -64,7 +64,6 @@
64(require 'cl-lib) 64(require 'cl-lib)
65(declare-function netrc-parse "netrc") 65(declare-function netrc-parse "netrc")
66(defvar auto-save-file-name-transforms) 66(defvar auto-save-file-name-transforms)
67(defvar ls-lisp-use-insert-directory-program)
68(defvar outline-regexp) 67(defvar outline-regexp)
69 68
70;;; User Customizable Internal Variables: 69;;; User Customizable Internal Variables:
@@ -1221,7 +1220,9 @@ means to use always cached values for the directory contents."
1221;;; Internal Variables: 1220;;; Internal Variables:
1222 1221
1223(defvar tramp-current-connection nil 1222(defvar tramp-current-connection nil
1224 "Last connection timestamp.") 1223 "Last connection timestamp.
1224It is a cons cell of the actual `tramp-file-name-structure', and
1225the (optional) timestamp of last activity on this connection.")
1225 1226
1226(defvar tramp-password-save-function nil 1227(defvar tramp-password-save-function nil
1227 "Password save function. 1228 "Password save function.
@@ -1713,11 +1714,11 @@ ARGUMENTS to actually emit the message (if applicable)."
1713 (regexp-opt 1714 (regexp-opt
1714 '("tramp-backtrace" 1715 '("tramp-backtrace"
1715 "tramp-compat-funcall" 1716 "tramp-compat-funcall"
1716 "tramp-condition-case-unless-debug"
1717 "tramp-debug-message" 1717 "tramp-debug-message"
1718 "tramp-error" 1718 "tramp-error"
1719 "tramp-error-with-buffer" 1719 "tramp-error-with-buffer"
1720 "tramp-message" 1720 "tramp-message"
1721 "tramp-signal-hook-function"
1721 "tramp-user-error") 1722 "tramp-user-error")
1722 t) 1723 t)
1723 "$")) 1724 "$"))
@@ -1805,7 +1806,7 @@ function is meant for debugging purposes."
1805VEC-OR-PROC identifies the connection to use, SIGNAL is the 1806VEC-OR-PROC identifies the connection to use, SIGNAL is the
1806signal identifier to be raised, remaining arguments passed to 1807signal identifier to be raised, remaining arguments passed to
1807`tramp-message'. Finally, signal SIGNAL is raised." 1808`tramp-message'. Finally, signal SIGNAL is raised."
1808 (let (tramp-message-show-message) 1809 (let (tramp-message-show-message signal-hook-function)
1809 (tramp-backtrace vec-or-proc) 1810 (tramp-backtrace vec-or-proc)
1810 (unless arguments 1811 (unless arguments
1811 ;; FMT-STRING could be just a file name, as in 1812 ;; FMT-STRING could be just a file name, as in
@@ -1894,6 +1895,12 @@ the resulting error message."
1894 (progn ,@body) 1895 (progn ,@body)
1895 (error (tramp-message ,vec-or-proc 3 ,format ,err) nil)))) 1896 (error (tramp-message ,vec-or-proc 3 ,format ,err) nil))))
1896 1897
1898;; This function provides traces in case of errors not triggered by
1899;; Tramp functions.
1900(defun tramp-signal-hook-function (error-symbol data)
1901 "Funtion to be called via `signal-hook-function'."
1902 (tramp-error (car tramp-current-connection) error-symbol "%s" data))
1903
1897(defmacro with-parsed-tramp-file-name (filename var &rest body) 1904(defmacro with-parsed-tramp-file-name (filename var &rest body)
1898 "Parse a Tramp filename and make components available in the body. 1905 "Parse a Tramp filename and make components available in the body.
1899 1906
@@ -2140,7 +2147,8 @@ pass to the OPERATION."
2140 . 2147 .
2141 ,(and (eq inhibit-file-name-operation operation) 2148 ,(and (eq inhibit-file-name-operation operation)
2142 inhibit-file-name-handlers))) 2149 inhibit-file-name-handlers)))
2143 (inhibit-file-name-operation operation)) 2150 (inhibit-file-name-operation operation)
2151 signal-hook-function)
2144 (apply operation args))) 2152 (apply operation args)))
2145 2153
2146;; We handle here all file primitives. Most of them have the file 2154;; We handle here all file primitives. Most of them have the file
@@ -2250,16 +2258,6 @@ Must be handled by the callers."
2250 res (cdr elt)))) 2258 res (cdr elt))))
2251 res))) 2259 res)))
2252 2260
2253(defvar tramp-debug-on-error nil
2254 "Like `debug-on-error' but used Tramp internal.")
2255
2256(defmacro tramp-condition-case-unless-debug
2257 (var bodyform &rest handlers)
2258 "Like `condition-case-unless-debug' but `tramp-debug-on-error'."
2259 (declare (debug condition-case) (indent 2))
2260 `(let ((debug-on-error tramp-debug-on-error))
2261 (condition-case-unless-debug ,var ,bodyform ,@handlers)))
2262
2263;; In Emacs, there is some concurrency due to timers. If a timer 2261;; In Emacs, there is some concurrency due to timers. If a timer
2264;; interrupts Tramp and wishes to use the same connection buffer as 2262;; interrupts Tramp and wishes to use the same connection buffer as
2265;; the "main" Emacs, then garbage might occur in the connection 2263;; the "main" Emacs, then garbage might occur in the connection
@@ -2299,100 +2297,84 @@ Falls back to normal file name handler if no Tramp file name handler exists."
2299 (save-match-data 2297 (save-match-data
2300 (setq filename (tramp-replace-environment-variables filename)) 2298 (setq filename (tramp-replace-environment-variables filename))
2301 (with-parsed-tramp-file-name filename nil 2299 (with-parsed-tramp-file-name filename nil
2302 (let ((completion (tramp-completion-mode-p)) 2300 (let ((current-connection tramp-current-connection)
2303 (foreign 2301 (foreign
2304 (tramp-find-foreign-file-name-handler filename operation)) 2302 (tramp-find-foreign-file-name-handler filename operation))
2303 (signal-hook-function #'tramp-signal-hook-function)
2305 result) 2304 result)
2305 ;; Set `tramp-current-connection'.
2306 (unless
2307 (tramp-file-name-equal-p v (car tramp-current-connection))
2308 (setq tramp-current-connection (list v)))
2309
2306 ;; Call the backend function. 2310 ;; Call the backend function.
2307 (if foreign 2311 (unwind-protect
2308 (tramp-condition-case-unless-debug err 2312 (if foreign
2309 (let ((sf (symbol-function foreign))) 2313 (let ((sf (symbol-function foreign)))
2310 ;; Some packages set the default directory to a 2314 ;; Some packages set the default directory to
2311 ;; remote path, before respective Tramp packages 2315 ;; a remote path, before respective Tramp
2312 ;; are already loaded. This results in 2316 ;; packages are already loaded. This results
2313 ;; recursive loading. Therefore, we load the 2317 ;; in recursive loading. Therefore, we load
2314 ;; Tramp packages locally. 2318 ;; the Tramp packages locally.
2315 (when (autoloadp sf) 2319 (when (autoloadp sf)
2316 (let ((default-directory 2320 (let ((default-directory
2317 (tramp-compat-temporary-file-directory)) 2321 (tramp-compat-temporary-file-directory))
2318 file-name-handler-alist) 2322 file-name-handler-alist)
2319 (load (cadr sf) 'noerror 'nomessage))) 2323 (load (cadr sf) 'noerror 'nomessage)))
2320;; (tramp-message 2324 ;; (tramp-message
2321;; v 4 "Running `%s'..." (cons operation args)) 2325 ;; v 4 "Running `%s'..." (cons operation args))
2322 ;; If `non-essential' is non-nil, Tramp shall 2326 ;; If `non-essential' is non-nil, Tramp shall
2323 ;; not open a new connection. 2327 ;; not open a new connection.
2324 ;; If Tramp detects that it shouldn't continue 2328 ;; If Tramp detects that it shouldn't continue
2325 ;; to work, it throws the `suppress' event. 2329 ;; to work, it throws the `suppress' event.
2326 ;; This could happen for example, when Tramp 2330 ;; This could happen for example, when Tramp
2327 ;; tries to open the same connection twice in a 2331 ;; tries to open the same connection twice in
2328 ;; short time frame. 2332 ;; a short time frame.
2329 ;; In both cases, we try the default handler then. 2333 ;; In both cases, we try the default handler then.
2330 (setq result 2334 (setq result
2331 (catch 'non-essential 2335 (catch 'non-essential
2332 (catch 'suppress 2336 (catch 'suppress
2333 (when (and tramp-locked (not tramp-locker)) 2337 (when (and tramp-locked (not tramp-locker))
2334 (setq tramp-locked nil) 2338 (setq tramp-locked nil)
2335 (tramp-error 2339 (tramp-error
2336 (car-safe tramp-current-connection) 2340 v 'file-error
2337 'file-error 2341 "Forbidden reentrant call of Tramp"))
2338 "Forbidden reentrant call of Tramp")) 2342 (let ((tl tramp-locked))
2339 (let ((tl tramp-locked)) 2343 (setq tramp-locked t)
2340 (setq tramp-locked t) 2344 (unwind-protect
2341 (unwind-protect 2345 (let ((tramp-locker t))
2342 (let ((tramp-locker t)) 2346 (apply foreign operation args))
2343 (apply foreign operation args)) 2347 (setq tramp-locked tl))))))
2344 (setq tramp-locked tl)))))) 2348 ;; (tramp-message
2345;; (tramp-message 2349 ;; v 4 "Running `%s'...`%s'" (cons operation args) result)
2346;; v 4 "Running `%s'...`%s'" (cons operation args) result) 2350 (cond
2347 (cond 2351 ((eq result 'non-essential)
2348 ((eq result 'non-essential)
2349 (tramp-message
2350 v 5 "Non-essential received in operation %s"
2351 (cons operation args))
2352 (tramp-run-real-handler operation args))
2353 ((eq result 'suppress)
2354 (let (tramp-message-show-message)
2355 (tramp-message 2352 (tramp-message
2356 v 1 "Suppress received in operation %s" 2353 v 5 "Non-essential received in operation %s"
2357 (cons operation args)) 2354 (cons operation args))
2358 (tramp-cleanup-connection v t) 2355 (tramp-run-real-handler operation args))
2359 (tramp-run-real-handler operation args))) 2356 ((eq result 'suppress)
2360 (t result))) 2357 (let (tramp-message-show-message)
2361 2358 (tramp-message
2362 ;; Trace that somebody has interrupted the operation. 2359 v 1 "Suppress received in operation %s"
2363 ((debug quit) 2360 (cons operation args))
2364 (let (tramp-message-show-message) 2361 (tramp-cleanup-connection v t)
2365 (tramp-message 2362 (tramp-run-real-handler operation args)))
2366 v 1 "Interrupt received in operation %s" 2363 (t result)))
2367 (cons operation args))) 2364
2368 ;; Propagate the signal. 2365 ;; Nothing to do for us. However, since we are in
2369 (signal (car err) (cdr err))) 2366 ;; `tramp-mode', we must suppress the volume
2370 2367 ;; letter on MS Windows.
2371 ;; When we are in completion mode, some failed 2368 (setq result (tramp-run-real-handler operation args))
2372 ;; operations shall return at least a default 2369 (if (stringp result)
2373 ;; value in order to give the user a chance to 2370 (tramp-drop-volume-letter result)
2374 ;; correct the file name in the minibuffer. 2371 result))
2375 ;; In order to get a full backtrace, one could apply 2372
2376 ;; (setq tramp-debug-on-error t) 2373 ;; Reset `tramp-current-connection'.
2377 (error 2374 (unless
2378 (cond 2375 (tramp-file-name-equal-p
2379 ((and completion (zerop (length localname)) 2376 (car current-connection) (car tramp-current-connection))
2380 (memq operation '(file-exists-p file-directory-p))) 2377 (setq tramp-current-connection current-connection))))))
2381 t)
2382 ((and completion (zerop (length localname))
2383 (memq operation
2384 '(expand-file-name file-name-as-directory)))
2385 filename)
2386 ;; Propagate the error.
2387 (t (signal (car err) (cdr err))))))
2388
2389 ;; Nothing to do for us. However, since we are in
2390 ;; `tramp-mode', we must suppress the volume letter on
2391 ;; MS Windows.
2392 (setq result (tramp-run-real-handler operation args))
2393 (if (stringp result)
2394 (tramp-drop-volume-letter result)
2395 result)))))
2396 2378
2397 ;; When `tramp-mode' is not enabled, or the file name is quoted, 2379 ;; When `tramp-mode' is not enabled, or the file name is quoted,
2398 ;; we don't do anything. 2380 ;; we don't do anything.
@@ -3403,9 +3385,9 @@ User is always nil."
3403 (access-file filename "Reading directory")) 3385 (access-file filename "Reading directory"))
3404 (with-parsed-tramp-file-name (expand-file-name filename) nil 3386 (with-parsed-tramp-file-name (expand-file-name filename) nil
3405 (with-tramp-progress-reporter v 0 (format "Opening directory %s" filename) 3387 (with-tramp-progress-reporter v 0 (format "Opening directory %s" filename)
3406 ;; We must load it in order to get the advice around `insert-directory'.
3407 (require 'ls-lisp)
3408 (let (ls-lisp-use-insert-directory-program start) 3388 (let (ls-lisp-use-insert-directory-program start)
3389 ;; Silence byte compiler.
3390 ls-lisp-use-insert-directory-program
3409 (tramp-run-real-handler 3391 (tramp-run-real-handler
3410 #'insert-directory 3392 #'insert-directory
3411 (list filename switches wildcard full-directory-p)) 3393 (list filename switches wildcard full-directory-p))
@@ -4074,7 +4056,9 @@ performed successfully. Any other value means an error."
4074 (widen) 4056 (widen)
4075 (tramp-message vec 6 "\n%s" (buffer-string))) 4057 (tramp-message vec 6 "\n%s" (buffer-string)))
4076 (if (eq exit 'ok) 4058 (if (eq exit 'ok)
4077 (ignore-errors (funcall tramp-password-save-function)) 4059 (ignore-errors
4060 (and (functionp tramp-password-save-function)
4061 (funcall tramp-password-save-function)))
4078 ;; Not successful. 4062 ;; Not successful.
4079 (tramp-clear-passwd vec) 4063 (tramp-clear-passwd vec)
4080 (delete-process proc) 4064 (delete-process proc)
@@ -4268,10 +4252,12 @@ Example:
4268 4252
4269would yield t. On the other hand, the following check results in nil: 4253would yield t. On the other hand, the following check results in nil:
4270 4254
4271 (tramp-equal-remote \"/sudo::/etc\" \"/su::/etc\")" 4255 (tramp-equal-remote \"/sudo::/etc\" \"/su::/etc\")
4272 (and (tramp-tramp-file-p file1) 4256
4273 (tramp-tramp-file-p file2) 4257If both files are local, the function returns t."
4274 (string-equal (file-remote-p file1) (file-remote-p file2)))) 4258 (or (and (null (file-remote-p file1)) (null (file-remote-p file2)))
4259 (and (tramp-tramp-file-p file1) (tramp-tramp-file-p file2)
4260 (string-equal (file-remote-p file1) (file-remote-p file2)))))
4275 4261
4276(defun tramp-mode-string-to-int (mode-string) 4262(defun tramp-mode-string-to-int (mode-string)
4277 "Converts a ten-letter `drwxrwxrwx'-style mode string into mode bits." 4263 "Converts a ten-letter `drwxrwxrwx'-style mode string into mode bits."
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el
index c9ae4d8b139..525f62a3c0b 100644
--- a/test/lisp/net/tramp-tests.el
+++ b/test/lisp/net/tramp-tests.el
@@ -169,7 +169,6 @@ properly. BODY shall not contain a timeout."
169 (declare (indent 1) (debug (natnump body))) 169 (declare (indent 1) (debug (natnump body)))
170 `(let ((tramp-verbose (max (or ,verbose 0) (or tramp-verbose 0))) 170 `(let ((tramp-verbose (max (or ,verbose 0) (or tramp-verbose 0)))
171 (tramp-message-show-message t) 171 (tramp-message-show-message t)
172 (tramp-debug-on-error t)
173 (debug-ignored-errors 172 (debug-ignored-errors
174 (cons "^make-symbolic-link not supported$" debug-ignored-errors)) 173 (cons "^make-symbolic-link not supported$" debug-ignored-errors))
175 inhibit-message) 174 inhibit-message)
@@ -178,9 +177,8 @@ properly. BODY shall not contain a timeout."
178 ;; Unwind forms. 177 ;; Unwind forms.
179 (when (and (null tramp--test-instrument-test-case-p) (> tramp-verbose 3)) 178 (when (and (null tramp--test-instrument-test-case-p) (> tramp-verbose 3))
180 (dolist (buf (tramp-list-tramp-buffers)) 179 (dolist (buf (tramp-list-tramp-buffers))
181 (message ";; %s" buf)
182 (with-current-buffer buf 180 (with-current-buffer buf
183 (message "%s" (buffer-string)))))))) 181 (message ";; %s\n%s" buf (buffer-string))))))))
184 182
185(defsubst tramp--test-message (fmt-string &rest arguments) 183(defsubst tramp--test-message (fmt-string &rest arguments)
186 "Emit a message into ERT *Messages*." 184 "Emit a message into ERT *Messages*."
@@ -2960,17 +2958,16 @@ This tests also `file-directory-p' and `file-accessible-directory-p'."
2960 (ignore-errors (delete-directory tmp-name2 'recursive)))))) 2958 (ignore-errors (delete-directory tmp-name2 'recursive))))))
2961 2959
2962;; Method "smb" supports `make-symbolic-link' only if the remote host 2960;; Method "smb" supports `make-symbolic-link' only if the remote host
2963;; has CIFS capabilities. tramp-adb.el and tramp-gvfs.el do not 2961;; has CIFS capabilities. tramp-adb.el, tramp-gvfs.el and
2964;; support symbolic links at all. 2962;; tramp-rclone.el do not support symbolic links at all.
2965(defmacro tramp--test-ignore-make-symbolic-link-error (&rest body) 2963(defmacro tramp--test-ignore-make-symbolic-link-error (&rest body)
2966 "Run BODY, ignoring \"make-symbolic-link not supported\" file error." 2964 "Run BODY, ignoring \"make-symbolic-link not supported\" file error."
2967 (declare (indent defun) (debug (body))) 2965 (declare (indent defun) (debug (body)))
2968 `(condition-case err 2966 `(condition-case err
2969 (progn ,@body) 2967 (progn ,@body)
2970 ((error quit debug) 2968 (file-error
2971 (unless (and (eq (car err) 'file-error) 2969 (unless (string-equal (error-message-string err)
2972 (string-equal (error-message-string err) 2970 "make-symbolic-link not supported")
2973 "make-symbolic-link not supported"))
2974 (signal (car err) (cdr err)))))) 2971 (signal (car err) (cdr err))))))
2975 2972
2976(ert-deftest tramp-test18-file-attributes () 2973(ert-deftest tramp-test18-file-attributes ()