diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi index c916588a060..73c3e1ed326 100644 --- a/doc/misc/tramp.texi +++ b/doc/misc/tramp.texi @@ -6658,7 +6658,7 @@ root directory, it is most likely sufficient to make the @code{default-directory} of the process buffer as the root directory. -@subsection Timers, process filters, process sentinels, redisplay +@subsection Timers, process filters, process sentinels, special events, redisplay @vindex remote-file-error Timers run asynchronously at any time when Emacs is waiting for @@ -6678,7 +6678,13 @@ wrapping the timer function body as follows: @end lisp A similar problem could happen with process filters, process -sentinels, and redisplay (updating the mode line). +sentinels, special event handlers, and redisplay (updating the mode +line). + +@strong{Note} that @value{tramp} raises a @code{remote-file-error} +error for any connection-related problem. You can protect against all +such problems with the code snippet above (or with a +@code{condition-case} form with a @code{remote-file-error} handler). @node Extension packages diff --git a/etc/NEWS b/etc/NEWS index 076a4e2c15e..02185050e12 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -62,7 +62,7 @@ You can keep the old behavior by putting '(xterm-mouse-mode -1)' in your init file. +++ -** 'site-start.el' is now loaded before the user's early init file. +** site-start.el is now loaded before the user's early init file. Previously, the order was early-init.el, site-start.el and then the user's regular init file, but now site-start.el comes first. This allows site administrators to customize things that can normally only be @@ -2182,6 +2182,12 @@ To unconditionally enable 'flyspell-mode' from a hook, use this instead: ** Tramp ++++ +*** Tramp signals 'remote-file-error' in case of connection problems. +This is a subcategory of 'file-error'. Therefore, all checks for +'file-error' in 'condition-case', 'ignore-error', 'error-conditions' and +alike still work. + +++ *** New command 'tramp-cleanup-bufferless-connections'. Connection-related objects for which no associated buffers exist, except @@ -3352,7 +3358,7 @@ changing the marking state in the calendar buffer. A new library has been added to the calendar for handling iCalendar (RFC5545) data. The library is designed for reuse in other parts of Emacs and in third-party packages. Package authors can find the new -library in the Emacs distribution under lisp/calendar/icalendar-*.el. +library in the Emacs distribution under "lisp/calendar/icalendar-*.el". Most of the functions and variables in the older icalendar.el have been marked obsolete and now suggest appropriate replacements from the new @@ -3605,7 +3611,7 @@ This package provides platform-neutral interfaces to block your system from entering idle sleep and a hook to process pre-sleep and post-wake events. You can use this to avoid the system entering an idle sleep state and interrupting a long-running process due to lack of user -activity. The sleep event hook lets you, for example close external +activity. The sleep event hook lets you, for example, close external connections or serial ports before sleeping, and reestablish them when the system wakes up. @@ -3615,6 +3621,7 @@ blocking requires org.freedesktop.Screensaver service), macOS (sleep/display blocking requires version 10.9 or later, sleep events are supported on all versions), MS-Windows (sleep blocking is supported on all versions, sleep events require Windows 8 or later). + * Incompatible Lisp Changes in Emacs 31.1 @@ -3788,6 +3795,7 @@ When no tags file is loaded, symbol completion just won't provide any suggestions. So the 'M-?' command now works without a tags table. And the 'M-.' will show a message describing the several built-in options that will provide an Xref backend when used. + * Lisp Changes in Emacs 31.1 diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el index 5bcb92536fd..c20b5df9b59 100644 --- a/lisp/net/tramp-adb.el +++ b/lisp/net/tramp-adb.el @@ -974,7 +974,7 @@ E.g. a host name \"192.168.1.1#5555\" returns \"192.168.1.1:5555\" (sleep-for 0.1) host) (t (tramp-error - vec 'file-error "Could not find device %s" host))))))) + vec 'remote-file-error "Could not find device %s" host))))))) (defun tramp-adb-execute-adb-command (vec &rest args) "Execute an adb command. @@ -1047,7 +1047,7 @@ the exit status." (with-current-buffer (tramp-get-connection-buffer vec) (unless (tramp-search-regexp (rx "tramp_exit_status " (+ digit))) (tramp-error - vec 'file-error "Couldn't find exit status of `%s'" command)) + vec 'remote-file-error "Couldn't find exit status of `%s'" command)) (skip-chars-forward "^ ") (prog1 (if exit-status @@ -1060,13 +1060,14 @@ the exit status." "Run COMMAND, check exit status, throw error if exit status not okay. FMT and ARGS are passed to `error'." (unless (tramp-adb-send-command-and-check vec command) - (apply #'tramp-error vec 'file-error fmt args))) + (apply #'tramp-error vec 'remote-file-error fmt args))) (defun tramp-adb-wait-for-output (proc &optional timeout) "Wait for output from remote command." (unless (buffer-live-p (process-buffer proc)) (delete-process proc) - (tramp-error proc 'file-error "Process `%s' not available, try again" proc)) + (tramp-error + proc 'remote-file-error "Process `%s' not available, try again" proc)) (let ((prompt (tramp-get-connection-property proc "prompt" tramp-adb-prompt))) (with-current-buffer (process-buffer proc) (if (tramp-wait-for-regexp proc timeout prompt) @@ -1085,10 +1086,11 @@ FMT and ARGS are passed to `error'." (delete-region (point) (point-max)))) (if timeout (tramp-error - proc 'file-error + proc 'remote-file-error "[[Remote prompt `%s' not found in %d secs]]" prompt timeout) (tramp-error - proc 'file-error "[[Remote prompt `%s' not found]]" prompt)))))) + proc 'remote-file-error + "[[Remote prompt `%s' not found]]" prompt)))))) (defun tramp-adb-maybe-open-connection (vec) "Maybe open a connection VEC. @@ -1110,13 +1112,14 @@ connection if a previous connection has died for some reason." ;; whether it is still the same device. (when (and user (not (tramp-get-connection-property vec " su-command-p" t))) - (tramp-error vec 'file-error "Cannot switch to user `%s'" user)) + (tramp-error vec 'remote-file-error "Cannot switch to user `%s'" user)) (unless (process-live-p p) (save-match-data (when (and p (processp p)) (delete-process p)) (if (tramp-string-empty-or-nil-p device) - (tramp-error vec 'file-error "Device %s not connected" host)) + (tramp-error + vec 'remote-file-error "Device %s not connected" host)) (with-tramp-progress-reporter vec 3 "Opening adb shell connection" (let* ((coding-system-for-read 'utf-8-dos) ; Is this correct? (process-connection-type tramp-process-connection-type) @@ -1137,7 +1140,7 @@ connection if a previous connection has died for some reason." (tramp-send-string vec tramp-rsh-end-of-line) (tramp-adb-wait-for-output p 30) (unless (process-live-p p) - (tramp-error vec 'file-error "Terminated!")) + (tramp-error vec 'remote-file-error "Terminated!")) ;; Set connection-local variables. (tramp-set-connection-local-variables vec) @@ -1193,7 +1196,7 @@ connection if a previous connection has died for some reason." ;; Do not flush, we need the nil value. (tramp-set-connection-property vec " su-command-p" nil) (tramp-error - vec 'file-error "Cannot switch to user `%s'" user))) + vec 'remote-file-error "Cannot switch to user `%s'" user))) ;; Mark it as connected. (tramp-set-connection-property p "connected" t)))))))) diff --git a/lisp/net/tramp-archive.el b/lisp/net/tramp-archive.el index a4323156c2a..e970fd1cd56 100644 --- a/lisp/net/tramp-archive.el +++ b/lisp/net/tramp-archive.el @@ -737,7 +737,7 @@ offered." (apply #'tramp-archive-file-name-for-operation operation args))))) (tramp-message v 10 "%s" (cons operation args)) (tramp-error - v 'file-error + v 'remote-file-error "Operation `%s' not implemented for file archives" operation))) (add-hook 'tramp-unload-hook diff --git a/lisp/net/tramp-crypt.el b/lisp/net/tramp-crypt.el index 565b9f0a5aa..59e4cea2edb 100644 --- a/lisp/net/tramp-crypt.el +++ b/lisp/net/tramp-crypt.el @@ -446,7 +446,7 @@ Otherwise, return NAME." crypt-vec (if (eq op 'encrypt) "encode" "decode") tramp-compat-temporary-file-directory localname) (tramp-error - crypt-vec 'file-error "%s of file name %s failed" + crypt-vec 'remote-file-error "%s of file name %s failed" (if (eq op 'encrypt) "Encoding" "Decoding") name)) (with-current-buffer (tramp-get-connection-buffer crypt-vec) (goto-char (point-min)) @@ -481,7 +481,7 @@ Raise an error if this fails." (file-name-directory infile) (concat "/" (file-name-nondirectory infile))) (tramp-error - crypt-vec 'file-error "%s of file %s failed" + crypt-vec 'remote-file-error "%s of file %s failed" (if (eq op 'encrypt) "Encrypting" "Decrypting") infile)) (with-current-buffer (tramp-get-connection-buffer crypt-vec) (write-region nil nil outfile))))) diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el index 64efce227d6..0f68e4d768a 100644 --- a/lisp/net/tramp-gvfs.el +++ b/lisp/net/tramp-gvfs.el @@ -1006,7 +1006,7 @@ The global value will always be nil; it is bound where needed.") "Called when a D-Bus error message arrives, see `dbus-event-error-functions'." (when tramp-gvfs-dbus-event-vector (tramp-message tramp-gvfs-dbus-event-vector 6 "%S" event) - (tramp-error tramp-gvfs-dbus-event-vector 'file-error (cadr err)))) + (tramp-error tramp-gvfs-dbus-event-vector 'remote-file-error (cadr err)))) (add-hook 'dbus-event-error-functions #'tramp-gvfs-dbus-event-error) (add-hook 'tramp-gvfs-unload-hook @@ -2234,7 +2234,7 @@ connection if a previous connection has died for some reason." method) tramp-gvfs-mounttypes) (tramp-error - vec 'file-error "Method `%s' not supported by GVFS" method))) + vec 'remote-file-error "Method `%s' not supported by GVFS" method))) ;; For password handling, we need a process bound to the ;; connection buffer. Therefore, we create a dummy process. @@ -2332,10 +2332,10 @@ connection if a previous connection has died for some reason." vec 'tramp-connection-timeout tramp-connection-timeout) (if (tramp-string-empty-or-nil-p user-domain) (tramp-error - vec 'file-error + vec 'remote-file-error "Timeout reached mounting %s using %s" host-port method) (tramp-error - vec 'file-error + vec 'remote-file-error "Timeout reached mounting %s@%s using %s" user-domain host-port method))) (while (not (tramp-get-file-property vec "/" "fuse-mountpoint")) @@ -2345,7 +2345,7 @@ connection if a previous connection has died for some reason." ;; is marked with the fuse-mountpoint "/". We shall react. (when (string-equal (tramp-get-file-property vec "/" "fuse-mountpoint" "") "/") - (tramp-error vec 'file-error "FUSE mount denied")) + (tramp-error vec 'remote-file-error "FUSE mount denied")) ;; Save the password. (ignore-errors diff --git a/lisp/net/tramp-rclone.el b/lisp/net/tramp-rclone.el index 6b0daeba2ac..cd5c3f46f54 100644 --- a/lisp/net/tramp-rclone.el +++ b/lisp/net/tramp-rclone.el @@ -381,53 +381,53 @@ connection if a previous connection has died for some reason." (with-tramp-debug-message vec "Opening connection" (let ((host (tramp-file-name-host vec))) - (when (rassoc `(,host) (tramp-rclone-parse-device-names nil)) - (if (tramp-string-empty-or-nil-p host) - (tramp-error vec 'file-error "Storage %s not connected" host)) - ;; We need a process bound to the connection buffer. - ;; Therefore, we create a dummy process. Maybe there is a - ;; better solution? - (unless (get-buffer-process (tramp-get-connection-buffer vec)) - (let ((p (make-network-process - :name (tramp-get-connection-name vec) - :buffer (tramp-get-connection-buffer vec) - :server t :host 'local :service t :noquery t))) - (tramp-post-process-creation p vec) + (when (or (tramp-string-empty-or-nil-p host) + (not (rassoc `(,host) (tramp-rclone-parse-device-names nil)))) + (tramp-error vec 'remote-file-error "Storage %s not connected" host)) - ;; Set connection-local variables. - (tramp-set-connection-local-variables vec))) + ;; We need a process bound to the connection buffer. Therefore, + ;; we create a dummy process. Maybe there is a better solution? + (unless (get-buffer-process (tramp-get-connection-buffer vec)) + (let ((p (make-network-process + :name (tramp-get-connection-name vec) + :buffer (tramp-get-connection-buffer vec) + :server t :host 'local :service t :noquery t))) + (tramp-post-process-creation p vec) - ;; Create directory. - (unless (file-directory-p (tramp-fuse-mount-point vec)) - (make-directory (tramp-fuse-mount-point vec) 'parents)) + ;; Set connection-local variables. + (tramp-set-connection-local-variables vec))) - ;; Mount. This command does not return, so we use 0 as - ;; DESTINATION of `tramp-call-process'. - (unless (tramp-fuse-mounted-p vec) - (apply - #'tramp-call-process - vec tramp-rclone-program nil 0 nil - "mount" (tramp-fuse-mount-spec vec) - (tramp-fuse-mount-point vec) - (tramp-get-method-parameter vec 'tramp-mount-args)) - (while (not (file-exists-p (tramp-make-tramp-file-name vec 'noloc))) - (tramp-cleanup-connection vec 'keep-debug 'keep-password)) - (add-to-list 'tramp-fuse-mount-points (tramp-file-name-unify vec))) + ;; Create directory. + (unless (file-directory-p (tramp-fuse-mount-point vec)) + (make-directory (tramp-fuse-mount-point vec) 'parents)) - ;; Mark it as connected. - (tramp-set-connection-property - (tramp-get-connection-process vec) "connected" t))) + ;; Mount. This command does not return, so we use 0 as + ;; DESTINATION of `tramp-call-process'. + (unless (tramp-fuse-mounted-p vec) + (apply + #'tramp-call-process + vec tramp-rclone-program nil 0 nil + "mount" (tramp-fuse-mount-spec vec) + (tramp-fuse-mount-point vec) + (tramp-get-method-parameter vec 'tramp-mount-args)) + (while (not (file-exists-p (tramp-make-tramp-file-name vec 'noloc))) + (tramp-cleanup-connection vec 'keep-debug 'keep-password)) + (add-to-list 'tramp-fuse-mount-points (tramp-file-name-unify vec))) - ;; In `tramp-check-cached-permissions', the connection properties - ;; "{uid,gid}-{integer,string}" are used. We set them to proper values. - (with-tramp-connection-property - vec "uid-integer" (tramp-get-local-uid 'integer)) - (with-tramp-connection-property - vec "gid-integer" (tramp-get-local-gid 'integer)) - (with-tramp-connection-property - vec "uid-string" (tramp-get-local-uid 'string)) - (with-tramp-connection-property - vec "gid-string" (tramp-get-local-gid 'string)))) + ;; Mark it as connected. + (tramp-set-connection-property + (tramp-get-connection-process vec) "connected" t))) + + ;; In `tramp-check-cached-permissions', the connection properties + ;; "{uid,gid}-{integer,string}" are used. We set them to proper values. + (with-tramp-connection-property + vec "uid-integer" (tramp-get-local-uid 'integer)) + (with-tramp-connection-property + vec "gid-integer" (tramp-get-local-gid 'integer)) + (with-tramp-connection-property + vec "uid-string" (tramp-get-local-uid 'string)) + (with-tramp-connection-property + vec "gid-string" (tramp-get-local-gid 'string))) (defun tramp-rclone-send-command (vec &rest args) "Send a command to connection VEC. diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index 97b72ba00ad..13e886b2c13 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -1969,7 +1969,7 @@ ID-FORMAT valid values are `string' and `integer'." (tramp-send-command-and-read vec (format "tramp_perl_directory_files_and_attributes %s" (tramp-shell-quote-argument localname))))) - (when (stringp object) (tramp-error vec 'file-error object)) + (when (stringp object) (tramp-error vec 'remote-file-error object)) object)) ;; FIXME: Fix function to work with count parameter. @@ -2378,7 +2378,7 @@ the uid and gid from FILENAME." ((eq op 'copy) "cp -f") ((eq op 'rename) "mv -f") (t (tramp-error - v 'file-error + v 'remote-file-error "Unknown operation `%s', must be `copy' or `rename'" op)))) (localname1 (tramp-file-local-name filename)) @@ -2608,7 +2608,7 @@ The method used must be an out-of-band method." ;; Check for local copy program. (unless (executable-find copy-program) (tramp-error - v 'file-error "Cannot find local copy program: %s" copy-program)) + v 'remote-file-error "Cannot find local copy program: %s" copy-program)) ;; Install listener on the remote side. The prompt must be ;; consumed later on, when the process does not listen anymore. @@ -2618,7 +2618,7 @@ The method used must be an out-of-band method." (tramp-find-executable v remote-copy-program (tramp-get-remote-path v))) (tramp-error - v 'file-error + v 'remote-file-error "Cannot find remote listener: %s" remote-copy-program)) (setq remote-copy-program (string-join @@ -2629,7 +2629,7 @@ The method used must be an out-of-band method." (tramp-send-command v remote-copy-program) (with-timeout (60 (tramp-error - v 'file-error + v 'remote-file-error "Listener process not running on remote host: `%s'" remote-copy-program)) (tramp-send-command v (format "netstat -l | grep -q :%s" listener)) @@ -3468,7 +3468,8 @@ will be used." ;; Oops, I don't know what to do. (t (tramp-error - v 'file-error "Wrong method specification for `%s'" method))) + v 'remote-file-error + "Wrong method specification for `%s'" method))) ;; Error handling. ((error quit) @@ -3663,7 +3664,7 @@ will be used." ;; That's not expected. (t (tramp-error - v 'file-error + v 'remote-file-error (concat "Method `%s' should specify both encoding and " "decoding command or an scp program") method))))))))) @@ -3689,7 +3690,7 @@ are \"file-exists-p\", \"file-readable-p\", \"file-directory-p\" and tramp-end-of-heredoc (mapconcat #'tramp-shell-quote-argument files "\n") tramp-end-of-heredoc)) - (tramp-error vec 'file-error "%s" (tramp-get-buffer-string))) + (tramp-error vec 'remote-file-error "%s" (tramp-get-buffer-string))) ;; Read the expression. (goto-char (point-min)) (read (current-buffer)))) @@ -4165,7 +4166,7 @@ Only send the definition if it has not already been done." ;; Expand format specifiers. (unless (setq script (tramp-expand-script vec script)) (tramp-error - vec 'file-error + vec 'remote-file-error (format "Script %s is not applicable on remote host" name))) ;; Send it. (tramp-barf-unless-okay @@ -4325,13 +4326,15 @@ file exists and nonzero exit status otherwise." ;; We cannot use `tramp-get-ls-command', this results in an infloop. ;; (Bug#65321) (ignore-errors - (and (setq result (format "ls -d >%s" (tramp-get-remote-null-device vec))) + (and (setq + result + (format "ls -d >%s" (tramp-get-remote-null-device vec))) (tramp-send-command-and-check vec (format "%s %s" result existing)) (not (tramp-send-command-and-check vec (format "%s %s" result nonexistent)))))) (tramp-error - vec 'file-error "Couldn't find command to check if file exists")) + vec 'remote-file-error "Couldn't find command to check if file exists")) (tramp-set-file-property vec existing "file-exists-p" t) result)) @@ -4484,7 +4487,8 @@ seconds. If not, it produces an error message with the given ERROR-ARGS." (error (delete-process proc) (apply #'tramp-error-with-buffer - (tramp-get-connection-buffer vec) vec 'file-error error-args))))) + (tramp-get-connection-buffer vec) vec + 'remote-file-error error-args))))) (defvar tramp-config-check nil "A function to be called with one argument, VEC. @@ -5293,8 +5297,8 @@ connection if a previous connection has died for some reason." (unless (and (process-live-p p) (tramp-wait-for-output p 10)) ;; The error will be caught locally. - (tramp-error vec 'file-error "Awake did fail"))) - (file-error + (tramp-error vec 'remote-file-error "Awake did fail"))) + (remote-file-error (tramp-cleanup-connection vec t) (setq p nil))) @@ -5314,7 +5318,8 @@ connection if a previous connection has died for some reason." (setenv "HISTFILESIZE" "0") (setenv "HISTSIZE" "0")))) (unless (stringp tramp-encoding-shell) - (tramp-error vec 'file-error "`tramp-encoding-shell' not set")) + (tramp-error + vec 'remote-file-error "`tramp-encoding-shell' not set")) (let* ((current-host tramp-system-name) (target-alist (tramp-compute-multi-hops vec)) (previous-hop tramp-null-hop) @@ -5520,7 +5525,8 @@ function waits for output unless NOOUTPUT is set." "Wait for output from remote command." (unless (buffer-live-p (process-buffer proc)) (delete-process proc) - (tramp-error proc 'file-error "Process `%s' not available, try again" proc)) + (tramp-error + proc 'remote-file-error "Process `%s' not available, try again" proc)) (with-current-buffer (process-buffer proc) (let* (;; Initially, `tramp-end-of-output' is "#$ ". There might ;; be leading ANSI control escape sequences, which must be @@ -5551,11 +5557,11 @@ function waits for output unless NOOUTPUT is set." (delete-region (point) (point-max)))) (if timeout (tramp-error - proc 'file-error + proc 'remote-file-error "[[Remote prompt `%s' not found in %d secs]]" tramp-end-of-output timeout) (tramp-error - proc 'file-error + proc 'remote-file-error "[[Remote prompt `%s' not found]]" tramp-end-of-output))) ;; Return value is whether end-of-output sentinel was found. found))) @@ -5594,7 +5600,7 @@ the exit status." (with-current-buffer (tramp-get-connection-buffer vec) (unless (tramp-search-regexp (rx "tramp_exit_status " (+ digit))) (tramp-error - vec 'file-error "Couldn't find exit status of `%s'" command)) + vec 'remote-file-error "Couldn't find exit status of `%s'" command)) (skip-chars-forward "^ ") (prog1 (if exit-status @@ -5608,7 +5614,7 @@ the exit status." Similar to `tramp-send-command-and-check' but accepts two more arguments FMT and ARGS which are passed to `error'." (or (tramp-send-command-and-check vec command) - (apply #'tramp-error vec 'file-error fmt args))) + (apply #'tramp-error vec 'remote-file-error fmt args))) (defun tramp-send-command-and-read (vec command &optional noerror marker) "Run COMMAND and return the output, which must be a Lisp expression. @@ -5627,7 +5633,7 @@ raises an error." (search-forward-regexp marker) (error (unless noerror (tramp-error - vec 'file-error + vec 'remote-file-error "`%s' does not return the marker `%s': `%s'" command marker (buffer-string)))))) ;; Read the expression. @@ -5641,7 +5647,7 @@ raises an error." (error nil))) (error (unless noerror (tramp-error - vec 'file-error + vec 'remote-file-error "`%s' does not return a valid Lisp expression: `%s'" command (buffer-string)))))))) @@ -5854,7 +5860,8 @@ Nonexistent directories are removed from spec." (setq result (concat result " --color=never"))) (throw 'ls-found result)) (setq dl (cdr dl)))))) - (tramp-error vec 'file-error "Couldn't find a proper `ls' command")))) + (tramp-error + vec 'remote-file-error "Couldn't find a proper `ls' command")))) (defun tramp-get-ls-command-with (vec option) "Return OPTION, if the remote `ls' command supports the OPTION option." diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el index b87eee0fcce..554aa354c00 100644 --- a/lisp/net/tramp-smb.el +++ b/lisp/net/tramp-smb.el @@ -821,7 +821,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (setq filename (directory-file-name (expand-file-name filename))) (with-parsed-tramp-file-name filename nil (tramp-convert-file-attributes v localname id-format - (ignore-errors + (condition-case err (if (tramp-smb-get-stat-capability v) (tramp-smb-do-file-attributes-with-stat v) ;; Reading just the filename entry via "dir localname" is @@ -851,7 +851,9 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (nth 1 entry) ;8 mode nil ;9 gid weird inode ;10 inode number - device)))))))) ;11 file system number + device)))) ;11 file system number + (remote-file-error (signal (car err) (cdr err))) + (error))))) (defun tramp-smb-do-file-attributes-with-stat (vec) "Implement `file-attributes' for Tramp files using `stat' command." @@ -1382,7 +1384,7 @@ will be used." "Like `make-symbolic-link' for Tramp files." (let ((v (tramp-dissect-file-name (expand-file-name linkname)))) (unless (tramp-smb-get-cifs-capabilities v) - (tramp-error v 'file-error "make-symbolic-link not supported"))) + (tramp-error v 'remote-file-error "make-symbolic-link not supported"))) (tramp-skeleton-make-symbolic-link target linkname ok-if-already-exists (unless (tramp-smb-send-command @@ -1571,8 +1573,7 @@ will be used." (tramp-search-regexp (rx "tramp_exit_status " (+ digit))) (tramp-error v 'file-error - "Couldn't find exit status of `%s'" - tramp-smb-acl-program)) + "Couldn't find exit status of `%s'" tramp-smb-acl-program)) (skip-chars-forward "^ ") (when (zerop (read (current-buffer))) ;; Success. @@ -1705,7 +1706,7 @@ If VEC has no cifs capabilities, exchange \"/\" by \"\\\\\"." (when (string-match-p (rx blank eol) localname) (tramp-error vec 'file-error - "Invalid file name %s" (tramp-make-tramp-file-name vec localname))) + "Invalid file name `%s'" (tramp-make-tramp-file-name vec localname))) localname))) @@ -1988,7 +1989,7 @@ If ARGUMENT is non-nil, use it as argument for (unless tramp-smb-version (unless (executable-find tramp-smb-program) (tramp-error - vec 'file-error + vec 'remote-file-error "Cannot find command %s in %s" tramp-smb-program exec-path)) (setq tramp-smb-version (shell-command-to-string command)) (tramp-message vec 6 command) @@ -2165,11 +2166,12 @@ Removes smb prompt. Returns nil if an error message has appeared." ;; Check for program. (unless (executable-find tramp-smb-winexe-program) (tramp-error - vec 'file-error "Cannot find program: %s" tramp-smb-winexe-program)) + vec 'remote-file-error "Cannot find program: %s" tramp-smb-winexe-program)) ;; winexe does not supports ports. (when (tramp-file-name-port vec) - (tramp-error vec 'file-error "Port not supported for remote processes")) + (tramp-error + vec 'remote-file-error "Port not supported for remote processes")) ;; Check share. (unless (tramp-smb-get-share vec) diff --git a/lisp/net/tramp-sshfs.el b/lisp/net/tramp-sshfs.el index 338d128cc4e..2cb5b5b1ed1 100644 --- a/lisp/net/tramp-sshfs.el +++ b/lisp/net/tramp-sshfs.el @@ -359,7 +359,7 @@ connection if a previous connection has died for some reason." vec 'tramp-mount-args nil ?p (or (tramp-file-name-port vec) "")))))) (tramp-error - vec 'file-error "Error mounting %s" (tramp-fuse-mount-spec vec))) + vec 'remote-file-error "Error mounting %s" (tramp-fuse-mount-spec vec))) ;; Mark it as connected. (add-to-list 'tramp-fuse-mount-points (tramp-file-name-unify vec)) diff --git a/lisp/net/tramp-sudoedit.el b/lisp/net/tramp-sudoedit.el index d3bb8b8478e..9511c899b2b 100644 --- a/lisp/net/tramp-sudoedit.el +++ b/lisp/net/tramp-sudoedit.el @@ -52,6 +52,10 @@ `(,(rx bos (literal tramp-sudoedit-method) eos) nil ,tramp-root-id-string)) + (add-to-list 'tramp-default-host-alist + `(,(rx bos (literal tramp-sudoedit-method) eos) + nil ,(system-name))) + (tramp-set-completion-function tramp-sudoedit-method tramp-completion-function-alist-su)) @@ -742,6 +746,10 @@ connection if a previous connection has died for some reason." (unless (tramp-connectable-p vec) (throw 'non-essential 'non-essential)) + (unless (string-match-p tramp-local-host-regexp (tramp-file-name-host vec)) + (tramp-error + vec 'remote-file-error "%s is not a local host" (tramp-file-name-host vec))) + (with-tramp-debug-message vec "Opening connection" ;; We need a process bound to the connection buffer. Therefore, ;; we create a dummy process. Maybe there is a better solution? @@ -775,7 +783,6 @@ in case of error, t otherwise." (append (tramp-expand-args vec 'tramp-sudo-login nil - ?h (or (tramp-file-name-host vec) "") ?u (or (tramp-file-name-user vec) "")) (flatten-tree args)))) ;; We suppress the messages `Waiting for prompts from remote shell'. @@ -817,7 +824,7 @@ In case there is no valid Lisp expression, it raises an error." (when (search-forward-regexp (rx (not blank)) (line-end-position) t) (error nil))) (error (tramp-error - vec 'file-error + vec 'remote-file-error "`%s' does not return a valid Lisp expression: `%s'" (car args) (buffer-string))))))) diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index f57b572532a..5281d8e4db5 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -3931,7 +3931,7 @@ BODY is the backend specific code." ;; The implementation is not complete yet. (when (and (numberp ,destination) (zerop ,destination)) (tramp-error - v 'file-error "Implementation does not handle immediate return")) + v 'remote-file-error "Implementation does not handle immediate return")) (let (command input tmpinput stderr tmpstderr outbuf ret) ;; Determine input. @@ -5239,6 +5239,9 @@ Do not set it manually, it is used buffer-local in `tramp-get-lock-pid'.") ?u (or (tramp-file-name-user (car target-alist)) "") ?h (or (tramp-file-name-host (car target-alist)) "")))) (with-parsed-tramp-file-name proxy l + (when (member l target-alist) + (tramp-user-error + vec "Cycle proxy definition `%s' in multi-hop" proxy)) ;; Add the hop. (push l target-alist) ;; Start next search. @@ -5505,7 +5508,7 @@ processes." This is the fallback implementation for backends which do not support symbolic links." (tramp-error - (tramp-dissect-file-name (expand-file-name linkname)) 'file-error + (tramp-dissect-file-name (expand-file-name linkname)) 'remote-file-error "make-symbolic-link not supported")) (defun tramp-handle-memory-info () @@ -6255,7 +6258,7 @@ performed successfully. Any other value means an error." (tramp-clear-passwd vec) (delete-process proc) (tramp-error-with-buffer - (tramp-get-connection-buffer vec) vec 'file-error + (tramp-get-connection-buffer vec) vec 'remote-file-error (cond ((eq exit 'permission-denied) "Permission denied") ((eq exit 'out-of-band-failed) @@ -6402,7 +6405,7 @@ nil." (tramp-accept-process-output proc) (unless (process-live-p proc) (tramp-error-with-buffer - nil proc 'file-error "Process has died")) + nil proc 'remote-file-error "Process has died")) (setq found (tramp-check-for-regexp proc regexp)))) ;; The process could have timed out, for example due to session ;; timeout of sudo. The process buffer does not exist any longer then. @@ -6412,9 +6415,10 @@ nil." (unless found (if timeout (tramp-error - proc 'file-error "[[Regexp `%s' not found in %d secs]]" + proc 'remote-file-error "[[Regexp `%s' not found in %d secs]]" regexp timeout) - (tramp-error proc 'file-error "[[Regexp `%s' not found]]" regexp))) + (tramp-error + proc 'remote-file-error "[[Regexp `%s' not found]]" regexp))) found)) ;; It seems that Tru64 Unix does not like it if long strings are sent @@ -6431,7 +6435,8 @@ the remote host use line-endings as defined in the variable (chunksize (tramp-get-connection-property p "chunksize"))) (unless p (tramp-error - vec 'file-error "Can't send string to remote host -- not logged in")) + vec 'remote-file-error + "Can't send string to remote host -- not logged in")) (tramp-set-connection-property p "last-cmd-time" (current-time)) (tramp-message vec 10 "%s" string) (with-current-buffer (tramp-get-connection-buffer vec) diff --git a/test/lisp/net/tramp-archive-tests.el b/test/lisp/net/tramp-archive-tests.el index f3bfaac005c..79fbe38b299 100644 --- a/test/lisp/net/tramp-archive-tests.el +++ b/test/lisp/net/tramp-archive-tests.el @@ -757,7 +757,7 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'." ;; `set-file-modes' is not implemented. (should-error (set-file-modes tmp-name1 #o777) - :type 'file-error) + :type 'remote-file-error) (should (= (file-modes tmp-name1) #o400)) (should-not (file-executable-p tmp-name1)) (should-not (file-writable-p tmp-name1)) @@ -766,7 +766,7 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'." ;; `set-file-modes' is not implemented. (should-error (set-file-modes tmp-name2 #o777) - :type 'file-error) + :type 'remote-file-error) (should (= (file-modes tmp-name2) #o500)) (should (file-executable-p tmp-name2)) (should-not (file-writable-p tmp-name2))) @@ -796,7 +796,7 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'." ;; `make-symbolic-link' is not implemented. (should-error (make-symbolic-link tmp-name1 tmp-name2) - :type 'file-error) + :type 'remote-file-error) (should (file-symlink-p tmp-name2)) (should (file-regular-p tmp-name2)) (should diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el index bbfe15d2f59..28d773ca616 100644 --- a/test/lisp/net/tramp-tests.el +++ b/test/lisp/net/tramp-tests.el @@ -71,6 +71,7 @@ (declare-function edebug-mode "edebug") (declare-function project-mode-line-format "project") (declare-function tramp-check-remote-uname "tramp-sh") +(declare-function tramp-file-name-with-sudo "tramp-cmds") (declare-function tramp-find-executable "tramp-sh") (declare-function tramp-get-remote-chmod-h "tramp-sh") (declare-function tramp-get-remote-path "tramp-sh") @@ -185,7 +186,7 @@ The temporary file is not created." (declare (indent defun) (debug (body))) `(condition-case err (progn ,@body) - (file-error + (remote-file-error (unless (string-match-p (rx bol (| "make-symbolic-link not supported" (: "Making symbolic link" @@ -2203,19 +2204,31 @@ being the result.") m)) :type 'user-error))))) -(ert-deftest tramp-test03-file-name-method-rules () - "Check file name rules for some methods." - (skip-unless (eq tramp-syntax 'default)) - (skip-unless (tramp--test-enabled)) - - ;; Multi hops are allowed for inline methods only. - (let (non-essential) - (should-error - (expand-file-name "/ssh:user1@host1|method:user2@host2:/path/to/file") - :type 'user-error) - (should-error - (expand-file-name "/method:user1@host1|ssh:user2@host2:/path/to/file") - :type 'user-error))) +(ert-deftest tramp-test03-file-error () + "Check that Tramp signals an error in case of connection problems." + ;; Connect to a non-existing host. + (let ((vec (copy-tramp-file-name tramp-test-vec)) + ;; Don't poison it. + (tramp-default-proxies-alist tramp-default-proxies-alist) + (tramp-show-ad-hoc-proxies t)) + (cl-letf* (((symbol-function #'read-string) #'ignore) ; Suppress password. + ((tramp-file-name-host vec) "example.com.invalid")) + (should-error + (file-exists-p (tramp-make-tramp-file-name vec)) + ;; `user-error' is raised if the host shall be local. + ;; `remote-file-error' is raised if the host cannot be connected. + :type (if (tramp--test-ange-ftp-p) + 'ftp-error '(user-error remote-file-error))) + (should-error + (file-exists-p (tramp-make-tramp-file-name vec)) + ;; `ftp-error' and `remote-file-error' are subcategories of + ;; `file-error'. Let's check this as well. + :type '(user-error file-error)) + ;; Check multi-hop. + (should-error + (file-exists-p + (tramp-file-name-with-sudo (tramp-make-tramp-file-name vec))) + :type '(user-error file-error))))) (ert-deftest tramp-test04-substitute-in-file-name () "Check `substitute-in-file-name'." @@ -7637,11 +7650,12 @@ This requires restrictions of file name syntax." (unless (tramp--test-crypt-p) (or (tramp--test-adb-p) (tramp--test-sh-p) (tramp--test-sshfs-p) (and (tramp--test-smb-p) - (file-writable-p - (file-name-concat - (file-remote-p ert-remote-temporary-file-directory) - ;; We check a directory on the "ADMIN$" share. - "ADMIN$" "Boot")))))) + (ignore-errors + (file-writable-p + (file-name-concat + (file-remote-p ert-remote-temporary-file-directory) + ;; We check a directory on the "ADMIN$" share. + "ADMIN$" "Boot"))))))) (defun tramp--test-supports-set-file-modes-p () "Return whether the method under test supports setting file modes."