diff options
| author | Michael Albinus | 2019-06-24 17:36:00 +0200 |
|---|---|---|
| committer | Michael Albinus | 2019-06-24 17:36:00 +0200 |
| commit | 18a7e5414c534db38eedb06b16ef68f2c17b98fd (patch) | |
| tree | 355be82e621742ec6768dcf859d6edabc3c643ce | |
| parent | b72cd0c74682cf87799f324eb3dace5f1962baf0 (diff) | |
| download | emacs-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.el | 1 | ||||
| -rw-r--r-- | lisp/net/tramp.el | 206 | ||||
| -rw-r--r-- | test/lisp/net/tramp-tests.el | 15 |
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. |
| 1224 | It is a cons cell of the actual `tramp-file-name-structure', and | ||
| 1225 | the (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." | |||
| 1805 | VEC-OR-PROC identifies the connection to use, SIGNAL is the | 1806 | VEC-OR-PROC identifies the connection to use, SIGNAL is the |
| 1806 | signal identifier to be raised, remaining arguments passed to | 1807 | signal 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 | ||
| 4269 | would yield t. On the other hand, the following check results in nil: | 4253 | would 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) | 4257 | If 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 () |