@chapter How to Customize Traces
@vindex tramp-verbose
@vindex tramp-debug-to-file
+@vindex tramp-debug-command-messages
@value{tramp} messages are raised with verbosity levels ranging from 0
to 10. @value{tramp} does not display all messages; only those with a
@*@indent @w{11} call traces (maintainer only)
With @code{tramp-verbose} greater than or equal to 4, messages are
-also written to a @value{tramp} debug buffer. Such debug buffers are
-essential to bug and problem analyzes. For @value{tramp} bug reports,
-set the @code{tramp-verbose} level to 6 (@pxref{Bug Reports}).
+also written to the @value{tramp} debug buffer @file{*debug
+tramp/foo*}. Such debug buffers are essential to bug and problem
+analyzes. For @value{tramp} bug reports, set the @code{tramp-verbose}
+level to 6 (@pxref{Bug Reports}).
The debug buffer is in
@ifinfo
performance of @value{tramp} actions.
If @code{tramp-verbose} is greater than or equal to 11, @value{tramp}
-function call traces are written to the buffer @file{*trace-output*}.
+function call traces are written to the buffer @file{*trace tramp/foo*}.
+
+When @code{tramp-debug-command-messages} is non-@code{nil} and
+@code{tramp-verbose} is greater than or equal to 6, the debug buffer
+contains all messages with verbosity level 6 (sent and received
+strings), and the entry and exit messages for the function
+@code{tramp-file-name-handler}. This is intended for @value{tramp}
+maintainers, analyzing the remote commands for performance analysis.
@node GNU Free Documentation License
First arg specifies the OPERATION, second arg is a list of
arguments to pass to the OPERATION."
(if-let ((fn (assoc operation tramp-adb-file-name-handler-alist)))
- (save-match-data (apply (cdr fn) args))
- (tramp-run-real-handler operation args)))
+ (prog1 (save-match-data (apply (cdr fn) args))
+ (setq tramp-debug-message-fnh-function (cdr fn)))
+ (prog1 (tramp-run-real-handler operation args)
+ (setq tramp-debug-message-fnh-function operation))))
;;;###tramp-autoload
(tramp--with-startup
(with-current-buffer (tramp-get-buffer vec)
(goto-char (point-min))
(let (file-properties)
- (while (re-search-forward tramp-adb-ls-toolbox-regexp nil t)
+ (while (search-forward-regexp tramp-adb-ls-toolbox-regexp nil t)
(let* ((mod-string (match-string 1))
(is-dir (eq ?d (aref mod-string 0)))
(is-symlink (eq ?l (aref mod-string 0)))
(tramp-shell-quote-argument localname)))
;; We insert also filename/. and filename/.., because "ls"
;; doesn't on some file systems, like "sdcard".
- (unless (re-search-backward (rx "." eol) nil t)
+ (unless (search-backward-regexp (rx "." eol) nil t)
(narrow-to-region (point-max) (point-max))
(tramp-adb-send-command
v (format "%s -d -a -l %s %s | cat"
;; There must be a better solution by setting the correct coding
;; system, but this requires changes in core Tramp.
(goto-char (point-min))
- (while (re-search-forward (rx (+ "\r") eol) nil t)
+ (while (search-forward-regexp (rx (+ "\r") eol) nil t)
(replace-match "" nil nil)))))))
(defun tramp-adb-send-command-and-check (vec command &optional exit-status)
(let ((inhibit-read-only t))
(goto-char (point-min))
;; ADB terminal sends "^H" sequences.
- (when (re-search-forward (rx "<" (+ "\b")) (line-end-position) t)
+ (when (search-forward-regexp (rx "<" (+ "\b")) (line-end-position) t)
(forward-line 1)
(delete-region (point-min) (point)))
;; Delete the prompt.
(goto-char (point-min))
- (when (re-search-forward prompt (line-end-position) t)
+ (when (search-forward-regexp prompt (line-end-position) t)
(forward-line 1)
(delete-region (point-min) (point)))
(when (tramp-search-regexp prompt)
(unless (tramp-connectable-p vec)
(throw 'non-essential 'non-essential))
- (let* ((buf (tramp-get-connection-buffer vec))
- (p (get-buffer-process buf))
- (host (tramp-file-name-host vec))
- (user (tramp-file-name-user vec))
- (device (tramp-adb-get-device vec)))
-
- ;; Maybe we know already that "su" is not supported. We cannot
- ;; use a connection property, because we have not checked yet
- ;; whether it is still the same device.
- (when (and user (not (tramp-get-file-property vec "/" "su-command-p" t)))
- (tramp-error vec '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))
- (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)
- (args (tramp-expand-args
- vec 'tramp-login-args ?d (or device "")))
- (p (let ((default-directory
- tramp-compat-temporary-file-directory))
- (apply #'start-process (tramp-get-connection-name vec) buf
- tramp-adb-program args)))
- (prompt (md5 (concat (prin1-to-string process-environment)
- (current-time-string)))))
- ;; Wait for initial prompt. On some devices, it needs an
- ;; initial RET, in order to get it.
- (sleep-for 0.1)
- (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!"))
-
- ;; Set sentinel. Initialize variables.
- (set-process-sentinel p #'tramp-process-sentinel)
- (tramp-post-process-creation p vec)
-
- ;; Set connection-local variables.
- (tramp-set-connection-local-variables vec)
-
- ;; Change prompt.
- (tramp-set-connection-property
- p "prompt" (rx "///" (literal prompt) "#$"))
- (tramp-adb-send-command
- vec (format "PS1=\"///\"\"%s\"\"#$\"" prompt))
-
- ;; Disable line editing.
- (tramp-adb-send-command
- vec "set +o vi +o vi-esccomplete +o vi-tabcomplete +o emacs")
-
- ;; Dump option settings in the traces.
- (when (>= tramp-verbose 9)
- (tramp-adb-send-command vec "set -o"))
-
- ;; Check whether the properties have been changed. If
- ;; yes, this is a strong indication that we must expire all
- ;; connection properties. We start again.
- (tramp-message vec 5 "Checking system information")
- (tramp-adb-send-command
- vec
- (concat
- "echo \\\"`getprop ro.product.model` "
- "`getprop ro.product.version` "
- "`getprop ro.build.version.release`\\\""))
- (let ((old-getprop (tramp-get-connection-property vec "getprop"))
- (new-getprop
- (tramp-set-connection-property
- vec "getprop"
- (with-current-buffer (tramp-get-connection-buffer vec)
- ;; Read the expression.
- (goto-char (point-min))
- (read (current-buffer))))))
- (when (and (stringp old-getprop)
- (not (string-equal old-getprop new-getprop)))
- (tramp-message
- vec 3
- "Connection reset, because remote host changed from `%s' to `%s'"
- old-getprop new-getprop)
- (tramp-cleanup-connection vec t)
- (tramp-adb-maybe-open-connection vec)))
-
- ;; Change user if indicated.
- (when user
- (tramp-adb-send-command vec (format "su %s" user))
- (unless (tramp-adb-send-command-and-check vec nil)
- (delete-process p)
- ;; Do not flush, we need the nil value.
- (tramp-set-file-property vec "/" "su-command-p" nil)
- (tramp-error
- vec 'file-error "Cannot switch to user `%s'" user)))
-
- ;; Mark it as connected.
- (tramp-set-connection-property p "connected" t)))))))
+ (with-tramp-debug-message vec "Opening connection"
+ (let* ((buf (tramp-get-connection-buffer vec))
+ (p (get-buffer-process buf))
+ (host (tramp-file-name-host vec))
+ (user (tramp-file-name-user vec))
+ (device (tramp-adb-get-device vec)))
+
+ ;; Maybe we know already that "su" is not supported. We cannot
+ ;; use a connection property, because we have not checked yet
+ ;; whether it is still the same device.
+ (when (and user (not (tramp-get-file-property vec "/" "su-command-p" t)))
+ (tramp-error vec '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))
+ (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)
+ (args (tramp-expand-args
+ vec 'tramp-login-args ?d (or device "")))
+ (p (let ((default-directory
+ tramp-compat-temporary-file-directory))
+ (apply
+ #'start-process (tramp-get-connection-name vec) buf
+ tramp-adb-program args)))
+ (prompt (md5 (concat (prin1-to-string process-environment)
+ (current-time-string)))))
+ ;; Wait for initial prompt. On some devices, it needs
+ ;; an initial RET, in order to get it.
+ (sleep-for 0.1)
+ (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!"))
+
+ ;; Set sentinel. Initialize variables.
+ (set-process-sentinel p #'tramp-process-sentinel)
+ (tramp-post-process-creation p vec)
+
+ ;; Set connection-local variables.
+ (tramp-set-connection-local-variables vec)
+
+ ;; Change prompt.
+ (tramp-set-connection-property
+ p "prompt" (rx "///" (literal prompt) "#$"))
+ (tramp-adb-send-command
+ vec (format "PS1=\"///\"\"%s\"\"#$\"" prompt))
+
+ ;; Disable line editing.
+ (tramp-adb-send-command
+ vec "set +o vi +o vi-esccomplete +o vi-tabcomplete +o emacs")
+
+ ;; Dump option settings in the traces.
+ (when (>= tramp-verbose 9)
+ (tramp-adb-send-command vec "set -o"))
+
+ ;; Check whether the properties have been changed. If
+ ;; yes, this is a strong indication that we must expire
+ ;; all connection properties. We start again.
+ (tramp-message vec 5 "Checking system information")
+ (tramp-adb-send-command
+ vec
+ (concat
+ "echo \\\"`getprop ro.product.model` "
+ "`getprop ro.product.version` "
+ "`getprop ro.build.version.release`\\\""))
+ (let ((old-getprop (tramp-get-connection-property vec "getprop"))
+ (new-getprop
+ (tramp-set-connection-property
+ vec "getprop"
+ (with-current-buffer (tramp-get-connection-buffer vec)
+ ;; Read the expression.
+ (goto-char (point-min))
+ (read (current-buffer))))))
+ (when (and (stringp old-getprop)
+ (not (string-equal old-getprop new-getprop)))
+ (tramp-message
+ vec 3
+ (concat
+ "Connection reset, because remote host changed "
+ "from `%s' to `%s'")
+ old-getprop new-getprop)
+ (tramp-cleanup-connection vec t)
+ (tramp-adb-maybe-open-connection vec)))
+
+ ;; Change user if indicated.
+ (when user
+ (tramp-adb-send-command vec (format "su %s" user))
+ (unless (tramp-adb-send-command-and-check vec nil)
+ (delete-process p)
+ ;; Do not flush, we need the nil value.
+ (tramp-set-file-property vec "/" "su-command-p" nil)
+ (tramp-error
+ vec 'file-error "Cannot switch to user `%s'" user)))
+
+ ;; Mark it as connected.
+ (tramp-set-connection-property p "connected" t))))))))
;;; Default connection-local variables for Tramp.
;; Beautify encoded values.
(goto-char (point-min))
- (while (re-search-forward
+ (while (search-forward-regexp
(rx "'" (group "(decode-coding-string")) nil 'noerror)
(replace-match "\\1"))
(goto-char (point-max))
(setq buffer-read-only nil)
(goto-char (point-min))
(while (not (eobp))
- (if (re-search-forward tramp-buf-regexp (line-end-position) t)
+ (if (search-forward-regexp tramp-buf-regexp (line-end-position) t)
(forward-line 1)
(forward-line 0)
(let ((start (point)))
(let ((matches 0)
(case-fold-search nil))
(goto-char start)
- (while (re-search-forward regexp end t)
+ (while (search-forward-regexp regexp end t)
(replace-match replacement t)
(setq matches (1+ matches)))
(and (not (zerop matches))
(apply #'tramp-crypt-file-name-for-operation operation args))
(fn (and (tramp-crypt-file-name-p filename)
(assoc operation tramp-crypt-file-name-handler-alist))))
- (save-match-data (apply (cdr fn) args))
- (tramp-crypt-run-real-handler operation args)))
+ (prog1 (save-match-data (apply (cdr fn) args))
+ (setq tramp-debug-message-fnh-function (cdr fn)))
+ (prog1 (tramp-run-real-handler operation args)
+ (setq tramp-debug-message-fnh-function operation))))
;;;###tramp-autoload
(progn (defun tramp-register-crypt-file-name-handler ()
;; For password handling, 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)))
-
- ;; The following operations must be performed without
- ;; `tramp-crypt-file-name-handler'.
- (let* (tramp-crypt-enabled
- ;; Don't check for a proper method.
- (non-essential t)
- (remote-config
- (expand-file-name
- tramp-crypt-encfs-config (tramp-crypt-get-remote-dir vec)))
- (local-config (tramp-crypt-config-file-name vec)))
- ;; There is no local encfs6 config file.
- (unless (file-exists-p local-config)
- (if (and tramp-crypt-save-encfs-config-remote
- (file-exists-p remote-config))
- ;; Copy remote encfs6 config file if possible.
- (copy-file remote-config local-config 'ok 'keep)
-
- ;; Create local encfs6 config file otherwise.
- (let* ((default-directory tramp-compat-temporary-file-directory)
- (tmpdir1 (file-name-as-directory
- (tramp-compat-make-temp-file " .crypt" 'dir-flag)))
- (tmpdir2 (file-name-as-directory
- (tramp-compat-make-temp-file " .nocrypt" 'dir-flag))))
- ;; Enable `auth-source', unless "emacs -Q" has been called.
- (tramp-set-connection-property
- vec "first-password-request" tramp-cache-read-persistent-data)
- (with-temp-buffer
- (insert
- (tramp-read-passwd
- (tramp-get-connection-process vec)
- (format
- "New EncFS Password for %s " (tramp-crypt-get-remote-dir vec))))
- (when
- (zerop
- (tramp-call-process-region
- vec (point-min) (point-max)
- tramp-crypt-encfs-program nil (tramp-get-connection-buffer vec)
- nil tramp-crypt-encfs-option "--extpass=cat" tmpdir1 tmpdir2))
- ;; Save the password.
- (ignore-errors
- (and (functionp tramp-password-save-function)
- (funcall tramp-password-save-function)))))
-
- ;; Write local config file. Suppress file name IV chaining mode.
- (with-temp-file local-config
- (insert-file-contents
- (expand-file-name tramp-crypt-encfs-config tmpdir1))
- (when (search-forward
- "<chainedNameIV>1</chainedNameIV>" nil 'noerror)
- (replace-match "<chainedNameIV>0</chainedNameIV>")))
-
- ;; Unmount encfs. Delete temporary directories.
- (tramp-call-process
- vec tramp-crypt-encfs-program nil nil nil
- "--unmount" tmpdir1 tmpdir2)
- (delete-directory tmpdir1 'recursive)
- (delete-directory tmpdir2)
-
- ;; Copy local encfs6 config file to remote.
- (when tramp-crypt-save-encfs-config-remote
- (copy-file local-config remote-config 'ok 'keep)))))))
+ (with-tramp-debug-message vec "Opening connection"
+ (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)))
+
+ ;; The following operations must be performed without
+ ;; `tramp-crypt-file-name-handler'.
+ (let* (tramp-crypt-enabled
+ ;; Don't check for a proper method.
+ (non-essential t)
+ (remote-config
+ (expand-file-name
+ tramp-crypt-encfs-config (tramp-crypt-get-remote-dir vec)))
+ (local-config (tramp-crypt-config-file-name vec)))
+ ;; There is no local encfs6 config file.
+ (unless (file-exists-p local-config)
+ (if (and tramp-crypt-save-encfs-config-remote
+ (file-exists-p remote-config))
+ ;; Copy remote encfs6 config file if possible.
+ (copy-file remote-config local-config 'ok 'keep)
+
+ ;; Create local encfs6 config file otherwise.
+ (let* ((default-directory tramp-compat-temporary-file-directory)
+ (tmpdir1 (file-name-as-directory
+ (tramp-compat-make-temp-file " .crypt" 'dir-flag)))
+ (tmpdir2 (file-name-as-directory
+ (tramp-compat-make-temp-file " .nocrypt" 'dir-flag))))
+ ;; Enable `auth-source', unless "emacs -Q" has been called.
+ (tramp-set-connection-property
+ vec "first-password-request" tramp-cache-read-persistent-data)
+ (with-temp-buffer
+ (insert
+ (tramp-read-passwd
+ (tramp-get-connection-process vec)
+ (format
+ "New EncFS Password for %s " (tramp-crypt-get-remote-dir vec))))
+ (when
+ (zerop
+ (tramp-call-process-region
+ vec (point-min) (point-max)
+ tramp-crypt-encfs-program nil
+ (tramp-get-connection-buffer vec) nil
+ tramp-crypt-encfs-option "--extpass=cat" tmpdir1 tmpdir2))
+ ;; Save the password.
+ (ignore-errors
+ (and (functionp tramp-password-save-function)
+ (funcall tramp-password-save-function)))))
+
+ ;; Write local config file. Suppress file name IV chaining mode.
+ (with-temp-file local-config
+ (insert-file-contents
+ (expand-file-name tramp-crypt-encfs-config tmpdir1))
+ (when (search-forward
+ "<chainedNameIV>1</chainedNameIV>" nil 'noerror)
+ (replace-match "<chainedNameIV>0</chainedNameIV>")))
+
+ ;; Unmount encfs. Delete temporary directories.
+ (tramp-call-process
+ vec tramp-crypt-encfs-program nil nil nil
+ "--unmount" tmpdir1 tmpdir2)
+ (delete-directory tmpdir1 'recursive)
+ (delete-directory tmpdir2)
+
+ ;; Copy local encfs6 config file to remote.
+ (when tramp-crypt-save-encfs-config-remote
+ (copy-file local-config remote-config 'ok 'keep))))))))
(defun tramp-crypt-send-command (vec &rest args)
"Send encfsctl command to connection VEC.
(and (tramp-tramp-file-p filename)
(tramp-dissect-file-name filename)))
(fn (assoc operation tramp-gvfs-file-name-handler-alist)))
- (save-match-data (apply (cdr fn) args))
- (tramp-run-real-handler operation args)))
+ (prog1 (save-match-data (apply (cdr fn) args))
+ (setq tramp-debug-message-fnh-function (cdr fn)))
+ (prog1 (tramp-run-real-handler operation args)
+ (setq tramp-debug-message-fnh-function operation))))
;;;###tramp-autoload
(when (featurep 'dbusbind)
;; Parse output.
(with-current-buffer (tramp-get-connection-buffer v)
(goto-char (point-min))
- (while (re-search-forward
+ (while (search-forward-regexp
(if file-system
tramp-gvfs-file-system-attributes-regexp
tramp-gvfs-file-attributes-with-gvfs-info-regexp)
(unless (tramp-connectable-p vec)
(throw 'non-essential 'non-essential))
- ;; Sanity check.
- (let ((method (tramp-file-name-method vec)))
- (unless (member
- (or (assoc-default
- method '(("smb" . "smb-share")
- ("davs" . "dav")
- ("nextcloud" . "dav")
- ("afp". "afp-volume")
- ("gdrive" . "google-drive")))
- method)
- tramp-gvfs-mounttypes)
- (tramp-error vec '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. 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)
-
- ;; Set connection-local variables.
- (tramp-set-connection-local-variables vec)))
-
- (unless (tramp-gvfs-connection-mounted-p vec)
- (let ((method (tramp-file-name-method vec))
- (user (tramp-file-name-user vec))
- (host (tramp-file-name-host vec))
- (localname (tramp-file-name-unquote-localname vec))
- (object-path
- (tramp-gvfs-object-path (tramp-make-tramp-file-name vec 'noloc))))
-
- (when (and (string-equal method "afp")
- (string-equal localname "/"))
- (tramp-user-error vec "Filename must contain an AFP volume"))
-
- (when (and (string-match-p (rx "dav" (? "s")) method)
- (string-equal localname "/"))
- (tramp-user-error vec "Filename must contain a WebDAV share"))
-
- (when (and (string-equal method "smb")
- (string-equal localname "/"))
- (tramp-user-error vec "Filename must contain a Windows share"))
-
- (when (member method tramp-goa-methods)
- ;; Ensure that GNOME Online Accounts are cached.
- (tramp-get-goa-accounts vec)
- (when (tramp-get-connection-property
- (tramp-get-goa-account vec) "FilesDisabled" t)
- (tramp-user-error
- vec "There is no Online Account `%s'"
- (tramp-make-tramp-file-name vec 'noloc))))
-
- (with-tramp-progress-reporter
- vec 3
- (if (tramp-string-empty-or-nil-p user)
- (format "Opening connection for %s using %s" host method)
- (format "Opening connection for %s@%s using %s" user host method))
-
- ;; Enable `auth-source'.
- (tramp-set-connection-property
- vec "first-password-request" tramp-cache-read-persistent-data)
-
- ;; There will be a callback of "askPassword" when a password is needed.
- (dbus-register-method
- :session dbus-service-emacs object-path
- tramp-gvfs-interface-mountoperation "askPassword"
- #'tramp-gvfs-handler-askpassword)
- (dbus-register-method
- :session dbus-service-emacs object-path
- tramp-gvfs-interface-mountoperation "AskPassword"
- #'tramp-gvfs-handler-askpassword)
-
- ;; There could be a callback of "askQuestion" when adding
- ;; fingerprints or checking certificates.
- (dbus-register-method
- :session dbus-service-emacs object-path
- tramp-gvfs-interface-mountoperation "askQuestion"
- #'tramp-gvfs-handler-askquestion)
- (dbus-register-method
- :session dbus-service-emacs object-path
- tramp-gvfs-interface-mountoperation "AskQuestion"
- #'tramp-gvfs-handler-askquestion)
-
- ;; The call must be asynchronously, because of the "askPassword"
- ;; or "askQuestion" callbacks.
- (if (string-match-p (rx "(so)" eol) tramp-gvfs-mountlocation-signature)
+ (with-tramp-debug-message vec "Opening connection"
+ ;; Sanity check.
+ (let ((method (tramp-file-name-method vec)))
+ (unless (member
+ (or (assoc-default
+ method '(("smb" . "smb-share")
+ ("davs" . "dav")
+ ("nextcloud" . "dav")
+ ("afp". "afp-volume")
+ ("gdrive" . "google-drive")))
+ method)
+ tramp-gvfs-mounttypes)
+ (tramp-error
+ vec '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.
+ ;; 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)
+
+ ;; Set connection-local variables.
+ (tramp-set-connection-local-variables vec)))
+
+ (unless (tramp-gvfs-connection-mounted-p vec)
+ (let ((method (tramp-file-name-method vec))
+ (user (tramp-file-name-user vec))
+ (host (tramp-file-name-host vec))
+ (localname (tramp-file-name-unquote-localname vec))
+ (object-path
+ (tramp-gvfs-object-path (tramp-make-tramp-file-name vec 'noloc))))
+
+ (when (and (string-equal method "afp")
+ (string-equal localname "/"))
+ (tramp-user-error vec "Filename must contain an AFP volume"))
+
+ (when (and (string-match-p (rx "dav" (? "s")) method)
+ (string-equal localname "/"))
+ (tramp-user-error vec "Filename must contain a WebDAV share"))
+
+ (when (and (string-equal method "smb")
+ (string-equal localname "/"))
+ (tramp-user-error vec "Filename must contain a Windows share"))
+
+ (when (member method tramp-goa-methods)
+ ;; Ensure that GNOME Online Accounts are cached.
+ (tramp-get-goa-accounts vec)
+ (when (tramp-get-connection-property
+ (tramp-get-goa-account vec) "FilesDisabled" t)
+ (tramp-user-error
+ vec "There is no Online Account `%s'"
+ (tramp-make-tramp-file-name vec 'noloc))))
+
+ (with-tramp-progress-reporter
+ vec 3
+ (if (tramp-string-empty-or-nil-p user)
+ (format "Opening connection for %s using %s" host method)
+ (format "Opening connection for %s@%s using %s" user host method))
+
+ ;; Enable `auth-source'.
+ (tramp-set-connection-property
+ vec "first-password-request" tramp-cache-read-persistent-data)
+
+ ;; There will be a callback of "askPassword" when a password is needed.
+ (dbus-register-method
+ :session dbus-service-emacs object-path
+ tramp-gvfs-interface-mountoperation "askPassword"
+ #'tramp-gvfs-handler-askpassword)
+ (dbus-register-method
+ :session dbus-service-emacs object-path
+ tramp-gvfs-interface-mountoperation "AskPassword"
+ #'tramp-gvfs-handler-askpassword)
+
+ ;; There could be a callback of "askQuestion" when adding
+ ;; fingerprints or checking certificates.
+ (dbus-register-method
+ :session dbus-service-emacs object-path
+ tramp-gvfs-interface-mountoperation "askQuestion"
+ #'tramp-gvfs-handler-askquestion)
+ (dbus-register-method
+ :session dbus-service-emacs object-path
+ tramp-gvfs-interface-mountoperation "AskQuestion"
+ #'tramp-gvfs-handler-askquestion)
+
+ ;; The call must be asynchronously, because of the
+ ;; "askPassword" or "askQuestion" callbacks.
+ (if (string-match-p (rx "(so)" eol) tramp-gvfs-mountlocation-signature)
+ (with-tramp-dbus-call-method vec nil
+ :session tramp-gvfs-service-daemon tramp-gvfs-path-mounttracker
+ tramp-gvfs-interface-mounttracker tramp-gvfs-mountlocation
+ (tramp-gvfs-mount-spec vec)
+ `(:struct :string ,(dbus-get-unique-name :session)
+ :object-path ,object-path))
(with-tramp-dbus-call-method vec nil
:session tramp-gvfs-service-daemon tramp-gvfs-path-mounttracker
tramp-gvfs-interface-mounttracker tramp-gvfs-mountlocation
(tramp-gvfs-mount-spec vec)
- `(:struct :string ,(dbus-get-unique-name :session)
- :object-path ,object-path))
- (with-tramp-dbus-call-method vec nil
- :session tramp-gvfs-service-daemon tramp-gvfs-path-mounttracker
- tramp-gvfs-interface-mounttracker tramp-gvfs-mountlocation
- (tramp-gvfs-mount-spec vec)
- :string (dbus-get-unique-name :session) :object-path object-path))
-
- ;; We must wait, until the mount is applied. This will be
- ;; indicated by the "mounted" signal, i.e. the "fuse-mountpoint"
- ;; file property.
- (with-timeout
- ((or (tramp-get-method-parameter vec 'tramp-connection-timeout)
- tramp-connection-timeout)
- (if (tramp-string-empty-or-nil-p (tramp-file-name-user vec))
+ :string (dbus-get-unique-name :session) :object-path object-path))
+
+ ;; We must wait, until the mount is applied. This will be
+ ;; indicated by the "mounted" signal, i.e. the
+ ;; "fuse-mountpoint" file property.
+ (with-timeout
+ ((or (tramp-get-method-parameter vec 'tramp-connection-timeout)
+ tramp-connection-timeout)
+ (if (tramp-string-empty-or-nil-p (tramp-file-name-user vec))
+ (tramp-error
+ vec 'file-error
+ "Timeout reached mounting %s using %s" host method)
(tramp-error
vec 'file-error
- "Timeout reached mounting %s using %s" host method)
- (tramp-error
- vec 'file-error
- "Timeout reached mounting %s@%s using %s" user host method)))
- (while (not (tramp-get-file-property vec "/" "fuse-mountpoint"))
- (read-event nil nil 0.1)))
-
- ;; If `tramp-gvfs-handler-askquestion' has returned "No", it
- ;; 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"))
-
- ;; Save the password.
- (ignore-errors
- (and (functionp tramp-password-save-function)
- (funcall tramp-password-save-function)))
-
- ;; Mark it as connected.
- (tramp-set-connection-property
- (tramp-get-connection-process vec) "connected" t)))))
+ "Timeout reached mounting %s@%s using %s" user host method)))
+ (while (not (tramp-get-file-property vec "/" "fuse-mountpoint"))
+ (read-event nil nil 0.1)))
+
+ ;; If `tramp-gvfs-handler-askquestion' has returned "No", it
+ ;; 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"))
+
+ ;; Save the password.
+ (ignore-errors
+ (and (functionp tramp-password-save-function)
+ (funcall tramp-password-save-function)))
+
+ ;; Mark it as connected.
+ (tramp-set-connection-property
+ (tramp-get-connection-process vec) "connected" t))))))
(defun tramp-gvfs-gio-tool-p (vec)
"Check, whether the gio tool is available."
--- /dev/null
+;;; tramp-message.el --- Tramp messages -*- lexical-binding:t -*-
+
+;; Copyright (C) 2023 Free Software Foundation, Inc.
+
+;; Author: Michael Albinus <michael.albinus@gmx.de>
+;; Keywords: comm, processes
+;; Package: tramp
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package collects all Tramp functions to trace. This is driven
+;; by the user option `tramp-verbose'. The following buffers are
+;; created:
+;;
+;; - *debug tramp/method user@host*
+;;
+;; This buffer is created when `tramp-verbose' is greater than or
+;; equal 4. It contains all messages with a level up to `tramp-verbose'.
+;;
+;; When `tramp-debug-command-messages' is non-nil and
+;; `tramp-verbose' is greater than or equal 6, the buffer contains
+;; all messages with level 6 and the entry/exit messages of
+;; `tramp-file-name-handler'. This is intended to analyze which
+;; remote commands are sent for a given file name operation.
+;;
+;; - *trace tramp/method user@host*
+;;
+;; This buffer is created by the trace.el package when
+;; `tramp-verbose' is is greater than or equal 11. It traces all
+;; functions with suffix "tramp-" except those function with the
+;; property `tramp-suppress-trace'.
+
+;;; Code:
+
+(require 'tramp-loaddefs)
+(require 'help-mode)
+
+(declare-function tramp-compat-string-replace "tramp-compat")
+(declare-function tramp-file-name-equal-p "tramp")
+(declare-function tramp-get-default-directory "tramp")
+(defvar tramp-compat-temporary-file-directory)
+
+;;;###tramp-autoload
+(defcustom tramp-verbose 3
+ "Verbosity level for Tramp messages.
+Any level x includes messages for all levels 1 .. x-1. The levels are
+
+ 0 silent (no tramp messages at all)
+ 1 errors
+ 2 warnings
+ 3 connection to remote hosts (default level)
+ 4 activities
+ 5 internal
+ 6 sent and received strings
+ 7 connection properties
+ 8 file caching
+ 9 test commands
+10 traces (huge)
+11 call traces (maintainer only)."
+ :group 'tramp
+ :type 'integer)
+
+(defcustom tramp-debug-to-file nil
+ "Whether Tramp debug messages shall be saved to file.
+The debug file has the same name as the debug buffer, written to
+`tramp-compat-temporary-file-directory'."
+ :group 'tramp
+ :version "28.1"
+ :type 'boolean)
+
+(defcustom tramp-debug-command-messages nil
+ "Whether to write only command messages to the debug buffer.
+This has only effect if `tramp-verbose' is greater than or equal 6."
+ :group 'tramp
+ :version "30.1"
+ :type 'boolean)
+
+(defconst tramp-debug-outline-regexp
+ (rx ;; Timestamp.
+ (+ digit) ":" (+ digit) ":" (+ digit) "." (+ digit) blank
+ ;; Thread.
+ (? (group "#<thread " (+ nonl) ">") blank)
+ ;; Function name, verbosity.
+ (group (+ (any "-" alnum))) " (" (group (+ digit)) ") #")
+ "Used for highlighting Tramp debug buffers in `outline-mode'.
+When it is used for regexp matching, the regexp groups are
+
+ 1 for the thread name (optional)
+ 2 for the function name
+ 3 for the verbosity level.")
+
+(defconst tramp-debug-font-lock-keywords
+ ;; FIXME: Make it a function instead of an ELisp expression, so you
+ ;; can evaluate it with `funcall' rather than `eval'!
+ ;; Also, in `font-lock-defaults' you can specify a function name for
+ ;; the "KEYWORDS" part, so font-lock calls it to get the actual keywords!
+ '(list
+ (rx bol (regexp tramp-debug-outline-regexp) (+ nonl))
+ '(1 font-lock-warning-face t t)
+ '(0 (outline-font-lock-face) keep t))
+ "Used for highlighting Tramp debug buffers in `outline-mode'.")
+
+(defun tramp-debug-outline-level ()
+ "Return the depth to which a statement is nested in the outline.
+Point must be at the beginning of a header line.
+
+The outline level is equal to the verbosity of the Tramp message."
+ (1+ (string-to-number (match-string 3))))
+
+(put #'tramp-debug-outline-level 'tramp-suppress-trace t)
+
+;; This function takes action since Emacs 28.1, when
+;; `read-extended-command-predicate' is set to
+;; `command-completion-default-include-p'.
+(defun tramp-debug-buffer-command-completion-p (_symbol buffer)
+ "A predicate for Tramp interactive commands.
+They are completed by \"M-x TAB\" only in Tramp debug buffers."
+ (with-current-buffer buffer
+ (string-equal
+ (buffer-substring (point-min) (min (+ (point-min) 10) (point-max)))
+ ";; Emacs:")))
+
+(put #'tramp-debug-buffer-command-completion-p 'tramp-suppress-trace t)
+
+(defun tramp-setup-debug-buffer ()
+ "Function to setup debug buffers."
+ ;; (declare (completion tramp-debug-buffer-command-completion-p))
+ (interactive)
+ (set-buffer-file-coding-system 'utf-8)
+ (setq buffer-undo-list t)
+ ;; 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".
+ ;; `(custom-declare-variable outline-minor-mode-prefix ...)' raises
+ ;; on error in `(outline-mode)', we don't want to see it in the
+ ;; traces.
+ (let ((default-directory tramp-compat-temporary-file-directory))
+ (outline-mode))
+ (setq-local outline-level 'tramp-debug-outline-level)
+ (setq-local font-lock-keywords
+ ;; FIXME: This `(t FOO . BAR)' representation in
+ ;; `font-lock-keywords' is supposed to be an internal
+ ;; implementation "detail". Don't abuse it here!
+ `(t (eval ,tramp-debug-font-lock-keywords t)
+ ,(eval tramp-debug-font-lock-keywords t)))
+ ;; Do not edit the debug buffer.
+ (use-local-map special-mode-map)
+ (set-buffer-modified-p nil)
+ ;; For debugging purposes.
+ (local-set-key "\M-n" 'clone-buffer)
+ (add-hook 'clone-buffer-hook #'tramp-setup-debug-buffer nil 'local))
+
+(put #'tramp-setup-debug-buffer 'tramp-suppress-trace t)
+
+(function-put
+ #'tramp-setup-debug-buffer 'completion-predicate
+ #'tramp-debug-buffer-command-completion-p)
+
+(defun tramp-debug-buffer-name (vec)
+ "A name for the debug buffer of VEC."
+ (let ((method (tramp-file-name-method vec))
+ (user-domain (tramp-file-name-user-domain vec))
+ (host-port (tramp-file-name-host-port vec)))
+ (if (or (null user-domain) (string-empty-p user-domain))
+ (format "*debug tramp/%s %s*" method host-port)
+ (format "*debug tramp/%s %s@%s*" method user-domain host-port))))
+
+(put #'tramp-debug-buffer-name 'tramp-suppress-trace t)
+
+(defun tramp-get-debug-buffer (vec)
+ "Get the debug buffer of VEC."
+ (with-current-buffer (get-buffer-create (tramp-debug-buffer-name vec))
+ (when (bobp)
+ (tramp-setup-debug-buffer))
+ (current-buffer)))
+
+(put #'tramp-get-debug-buffer 'tramp-suppress-trace t)
+
+(defun tramp-get-debug-file-name (vec)
+ "Get the debug file name for VEC."
+ (expand-file-name
+ (tramp-compat-string-replace "/" " " (tramp-debug-buffer-name vec))
+ tramp-compat-temporary-file-directory))
+
+(put #'tramp-get-debug-file-name 'tramp-suppress-trace t)
+
+(defun tramp-trace-buffer-name (vec)
+ "A name for the trace buffer for VEC."
+ (tramp-compat-string-replace "*debug" "*trace" (tramp-debug-buffer-name vec)))
+
+(put #'tramp-trace-buffer-name 'tramp-suppress-trace t)
+
+(defvar tramp-trace-functions nil
+ "A list of non-Tramp functions to be traced with `tramp-verbose' > 10.")
+
+(defun tramp-debug-message (vec fmt-string &rest arguments)
+ "Append message to debug buffer of VEC.
+Message is formatted with FMT-STRING as control string and the remaining
+ARGUMENTS to actually emit the message (if applicable)."
+ (let ((inhibit-message t)
+ create-lockfiles file-name-handler-alist message-log-max
+ signal-hook-function)
+ (with-current-buffer (tramp-get-debug-buffer vec)
+ (goto-char (point-max))
+ (let ((point (point)))
+ (when (bobp)
+ ;; Headline.
+ (insert
+ (format
+ ";; Emacs: %s Tramp: %s -*- mode: outline; coding: utf-8; -*-"
+ emacs-version tramp-version))
+ (when (>= tramp-verbose 10)
+ (let ((tramp-verbose 0))
+ (insert
+ (format
+ "\n;; Location: %s Git: %s/%s"
+ (locate-library "tramp")
+ (or tramp-repository-branch "")
+ (or tramp-repository-version "")))))
+ ;; Traces.
+ (when (>= tramp-verbose 11)
+ (dolist
+ (elt
+ (append
+ (mapcar
+ #'intern (all-completions "tramp-" obarray #'functionp))
+ tramp-trace-functions))
+ (unless (get elt 'tramp-suppress-trace)
+ (trace-function-background elt (tramp-trace-buffer-name vec)))))
+ ;; Delete debug file.
+ (when (and tramp-debug-to-file (tramp-get-debug-file-name vec))
+ (ignore-errors (delete-file (tramp-get-debug-file-name vec)))))
+ (unless (bolp)
+ (insert "\n"))
+ ;; Timestamp.
+ (insert (format-time-string "%T.%6N "))
+ ;; Threads. `current-thread' might not exist when Emacs is
+ ;; configured --without-threads.
+ ;; (unless (eq (tramp-compat-funcall 'current-thread) main-thread)
+ ;; (insert (format "%s " (tramp-compat-funcall 'current-thread))))
+ ;; Calling Tramp function. We suppress compat and trace
+ ;; functions from being displayed.
+ (let ((frames (backtrace-frames))
+ btf fn)
+ (while (not fn)
+ (setq btf (cadadr frames))
+ (if (not btf)
+ (setq fn "")
+ (and (symbolp btf) (setq fn (symbol-name btf))
+ (or (not (string-prefix-p "tramp" fn))
+ (get btf 'tramp-suppress-trace))
+ (setq fn nil))
+ (setq frames (cdr frames))))
+ ;; The following code inserts filename and line number.
+ ;; Should be inactive by default, because it is time consuming.
+ ;; (let ((ffn (find-function-noselect (intern fn))))
+ ;; (insert
+ ;; (format
+ ;; "%s:%d: "
+ ;; (file-name-nondirectory (buffer-file-name (car ffn)))
+ ;; (with-current-buffer (car ffn)
+ ;; (1+ (count-lines (point-min) (cdr ffn)))))))
+ (insert (format "%s " fn)))
+ ;; The message.
+ (insert (apply #'format-message fmt-string arguments))
+ (if tramp-debug-command-messages
+ ;; Add help function.
+ (tramp-debug-message-buttonize point)
+ ;; Write message to debug file.
+ (when tramp-debug-to-file
+ (ignore-errors
+ (write-region
+ point (point-max) (tramp-get-debug-file-name vec) 'append))))))))
+
+(put #'tramp-debug-message 'tramp-suppress-trace t)
+
+;;;###tramp-autoload
+(defun tramp-message (vec-or-proc level fmt-string &rest arguments)
+ "Emit a message depending on verbosity level.
+VEC-OR-PROC identifies the Tramp buffer to use. It can be either a
+vector or a process. LEVEL says to be quiet if `tramp-verbose' is
+less than LEVEL. The message is emitted only if `tramp-verbose' is
+greater than or equal to LEVEL.
+
+The message is also logged into the debug buffer when `tramp-verbose'
+is greater than or equal 4.
+
+Calls functions `message' and `tramp-debug-message' with FMT-STRING as
+control string and the remaining ARGUMENTS to actually emit the message (if
+applicable)."
+ (ignore-errors
+ (when (<= level tramp-verbose)
+ ;; Display only when there is a minimum level, and the progress
+ ;; reporter doesn't suppress further messages.
+ (when (and (<= level 3) (null tramp-inhibit-progress-reporter))
+ (apply #'message
+ (concat
+ (cond
+ ((= level 0) "")
+ ((= level 1) "")
+ ((= level 2) "Warning: ")
+ (t "Tramp: "))
+ fmt-string)
+ arguments))
+ ;; Log only when there is a minimum level.
+ (when (>= tramp-verbose 4)
+ (let ((tramp-verbose 0))
+ ;; Append connection buffer for error messages, if exists.
+ (when (= level 1)
+ (ignore-errors
+ (setq fmt-string (concat fmt-string "\n%s")
+ arguments
+ (append
+ arguments
+ `(,(tramp-get-buffer-string
+ (if (processp vec-or-proc)
+ (process-buffer vec-or-proc)
+ (tramp-get-connection-buffer
+ vec-or-proc 'dont-create))))))))
+ ;; Translate proc to vec.
+ (when (processp vec-or-proc)
+ (setq vec-or-proc (process-get vec-or-proc 'tramp-vector))))
+ ;; Do it.
+ (when (and (tramp-file-name-p vec-or-proc)
+ (or (null tramp-debug-command-messages) (= level 6)))
+ (apply #'tramp-debug-message
+ vec-or-proc
+ (concat (format "(%d) # " level) fmt-string)
+ arguments))))))
+
+(defsubst tramp-backtrace (&optional vec-or-proc force)
+ "Dump a backtrace into the debug buffer.
+If VEC-OR-PROC is nil, the buffer *debug tramp* is used. FORCE
+forces the backtrace even if `tramp-verbose' is less than 10.
+This function is meant for debugging purposes."
+ (let ((tramp-verbose (if force 10 tramp-verbose)))
+ (when (>= tramp-verbose 10)
+ (if vec-or-proc
+ (tramp-message
+ vec-or-proc 10 "\n%s" (with-output-to-string (backtrace)))
+ (with-output-to-temp-buffer "*debug tramp*" (backtrace))))))
+
+(defsubst tramp-error (vec-or-proc signal fmt-string &rest arguments)
+ "Emit an error.
+VEC-OR-PROC identifies the connection to use, SIGNAL is the
+signal identifier to be raised, remaining arguments passed to
+`tramp-message'. Finally, signal SIGNAL is raised with
+FMT-STRING and ARGUMENTS."
+ (let (signal-hook-function)
+ (tramp-backtrace vec-or-proc)
+ (unless arguments
+ ;; FMT-STRING could be just a file name, as in
+ ;; `file-already-exists' errors. It could contain the ?\%
+ ;; character, as in smb domain spec.
+ (setq arguments (list fmt-string)
+ fmt-string "%s"))
+ (when vec-or-proc
+ (tramp-message
+ vec-or-proc 1 "%s"
+ (error-message-string
+ (list signal
+ (get signal 'error-message)
+ (apply #'format-message fmt-string arguments)))))
+ (signal signal (list (substring-no-properties
+ (apply #'format-message fmt-string arguments))))))
+
+(defvar tramp-error-show-message-timeout 30
+ "Time to show the Tramp buffer in case of an error.
+If it is bound to nil, the buffer is not shown. This is used in
+tramp-tests.el.")
+
+(defsubst tramp-error-with-buffer
+ (buf vec-or-proc signal fmt-string &rest arguments)
+ "Emit an error, and show BUF.
+If BUF is nil, show the connection buf. Wait for 30\", or until
+an input event arrives. The other arguments are passed to `tramp-error'."
+ (save-window-excursion
+ (let* ((buf (or (and (bufferp buf) buf)
+ (and (processp vec-or-proc) (process-buffer vec-or-proc))
+ (and (tramp-file-name-p vec-or-proc)
+ (tramp-get-connection-buffer vec-or-proc))))
+ (vec (or (and (tramp-file-name-p vec-or-proc) vec-or-proc)
+ (and buf (tramp-dissect-file-name
+ (tramp-get-default-directory buf))))))
+ (unwind-protect
+ (apply #'tramp-error vec-or-proc signal fmt-string arguments)
+ ;; Save exit.
+ (when (and buf
+ (natnump tramp-error-show-message-timeout)
+ (not (zerop tramp-verbose))
+ ;; Do not show when flagged from outside.
+ (not non-essential)
+ ;; Show only when Emacs has started already.
+ (current-message))
+ (let ((enable-recursive-minibuffers t)
+ inhibit-message)
+ ;; `tramp-error' does not show messages. So we must do it
+ ;; ourselves.
+ (apply #'message fmt-string arguments)
+ ;; Show buffer.
+ (pop-to-buffer buf)
+ (discard-input)
+ (sit-for tramp-error-show-message-timeout)))
+ ;; Reset timestamp. It would be wrong after waiting for a while.
+ (when (tramp-file-name-equal-p vec (car tramp-current-connection))
+ (setcdr tramp-current-connection (current-time)))))))
+
+(defsubst tramp-user-error (vec-or-proc fmt-string &rest arguments)
+ "Signal a user error (or \"pilot error\")."
+ (unwind-protect
+ (apply #'tramp-error vec-or-proc 'user-error fmt-string arguments)
+ ;; Save exit.
+ (when (and (natnump tramp-error-show-message-timeout)
+ (not (zerop tramp-verbose))
+ ;; Do not show when flagged from outside.
+ (not non-essential)
+ ;; Show only when Emacs has started already.
+ (current-message))
+ (let ((enable-recursive-minibuffers t)
+ inhibit-message)
+ ;; `tramp-error' does not show messages. So we must do it ourselves.
+ (apply #'message fmt-string arguments)
+ (discard-input)
+ (sit-for tramp-error-show-message-timeout)
+ ;; Reset timestamp. It would be wrong after waiting for a while.
+ (when
+ (tramp-file-name-equal-p vec-or-proc (car tramp-current-connection))
+ (setcdr tramp-current-connection (current-time)))))))
+
+(defmacro tramp-with-demoted-errors (vec-or-proc format &rest body)
+ "Execute BODY while redirecting the error message to `tramp-message'.
+BODY is executed like wrapped by `with-demoted-errors'. FORMAT
+is a format-string containing a %-sequence meaning to substitute
+the resulting error message."
+ (declare (indent 2) (debug (symbolp form body)))
+ (let ((err (make-symbol "err")))
+ `(condition-case-unless-debug ,err
+ (progn ,@body)
+ (error (tramp-message ,vec-or-proc 3 ,format ,err) nil))))
+
+(defun tramp-debug-button-action (button)
+ "Goto the linked message in debug buffer at place."
+ (when (mouse-event-p last-input-event) (mouse-set-point last-input-event))
+ (when-let ((point (button-get button 'position)))
+ (goto-char point)))
+
+(put #'tramp-debug-button-action 'tramp-suppress-trace t)
+
+(define-button-type 'tramp-debug-button-type
+ 'follow-link t
+ 'mouse-face 'highlight
+ 'action #'tramp-debug-button-action)
+
+(defun tramp-debug-link-messages (pos1 pos2)
+ "Set links for two messages in current buffer.
+The link buttons are in the verbositiy level substrings."
+ (save-excursion
+ (let (beg1 end1 beg2 end2)
+ (goto-char pos1)
+ ;; Find positions.
+ (while (not (search-forward-regexp
+ tramp-debug-outline-regexp (line-end-position) t))
+ (forward-line))
+ (setq beg1 (1- (match-beginning 3)) end1 (1+ (match-end 3)))
+ (goto-char pos2)
+ (while (not (search-forward-regexp
+ tramp-debug-outline-regexp (line-end-position) t))
+ (forward-line))
+ (setq beg2 (1- (match-beginning 3)) end2 (1+ (match-end 3)))
+ ;; Create text buttons.
+ (make-text-button
+ beg1 end1 :type 'tramp-debug-button-type
+ 'position (set-marker (make-marker) beg2)
+ 'help-echo "mouse-2, RET: goto exit message")
+ (make-text-button
+ beg2 end2 :type 'tramp-debug-button-type
+ 'position (set-marker (make-marker) beg1)
+ 'help-echo "mouse-2, RET: goto entry message"))))
+
+(put #'tramp-debug-link-messages 'tramp-suppress-trace t)
+
+(defvar tramp-debug-nesting ""
+ "Indicator for debug messages nested level.
+This shouldn't be changed globally, but let-bind where needed.")
+
+(defvar tramp-debug-message-fnh-function nil
+ "The used file name handler operation.
+Bound in `tramp-*-file-name-handler' functions.")
+
+(defun tramp-debug-message-buttonize (position)
+ "Buttonize function in current buffer, at next line starting after POSTION."
+ (save-excursion
+ (goto-char position)
+ (while (not (search-forward-regexp
+ tramp-debug-outline-regexp (line-end-position) t))
+ (forward-line))
+ (let ((fun (intern (match-string 2))))
+ (make-text-button
+ (match-beginning 2) (match-end 2)
+ :type 'help-function-def
+ 'help-args (list fun (symbol-file fun))))))
+
+(put #'tramp-debug-message-buttonize 'tramp-suppress-trace t)
+
+;; This is used in `tramp-file-name-handler' and `tramp-*-maybe-open-connection'.
+(defmacro with-tramp-debug-message (vec message &rest body)
+ "Execute BODY, embedded with MESSAGE in the debug buffer of VEC.
+If BODY does not raise a debug message, MESSAGE is ignored."
+ (declare (indent 2) (debug t))
+ (let ((result (make-symbol "result")))
+ `(if (and tramp-debug-command-messages (>= tramp-verbose 6))
+ (save-match-data
+ (let ((tramp-debug-nesting
+ (concat tramp-debug-nesting "#"))
+ (buf (tramp-get-debug-buffer ,vec))
+ beg end ,result)
+ ;; Insert entry message.
+ (with-current-buffer buf
+ (setq beg (point))
+ (tramp-debug-message
+ ,vec "(4) %s %s ..." tramp-debug-nesting ,message)
+ (setq end (point)))
+ (unwind-protect
+ ;; Run BODY.
+ (setq tramp-debug-message-fnh-function nil
+ ,result (progn ,@body))
+ (with-current-buffer buf
+ (if (= end (point-max))
+ (progn
+ (delete-region beg end)
+ (when (bobp) (kill-buffer)))
+ ;; Insert exit message.
+ (tramp-debug-message
+ ,vec "(5) %s %s ... %s" tramp-debug-nesting ,message ,result)
+ ;; Adapt file name handler function.
+ (dolist (pos (list (point-max) end))
+ (goto-char pos)
+ (when (and tramp-debug-message-fnh-function
+ (search-backward
+ "tramp-file-name-handler"
+ (line-beginning-position) t))
+ (replace-match
+ (symbol-name tramp-debug-message-fnh-function))
+ (tramp-debug-message-buttonize
+ (line-beginning-position))))
+ ;; Link related messages.
+ (goto-char (point-max))
+ (tramp-debug-link-messages beg (line-beginning-position)))))))
+
+ ;; No special messages.
+ ,@body)))
+
+(add-hook 'tramp-unload-hook
+ (lambda ()
+ (unload-feature 'tramp-message 'force)))
+
+(provide 'tramp-message)
First arg specifies the OPERATION, second arg is a list of
arguments to pass to the OPERATION."
(if-let ((fn (assoc operation tramp-rclone-file-name-handler-alist)))
- (save-match-data (apply (cdr fn) args))
- (tramp-run-real-handler operation args)))
+ (prog1 (save-match-data (apply (cdr fn) args))
+ (setq tramp-debug-message-fnh-function (cdr fn)))
+ (prog1 (tramp-run-real-handler operation args)
+ (setq tramp-debug-message-fnh-function operation))))
;;;###tramp-autoload
(tramp--with-startup
(unless (tramp-connectable-p vec)
(throw 'non-essential 'non-essential))
- (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)
-
- ;; Set connection-local variables.
- (tramp-set-connection-local-variables vec)))
-
- ;; Create directory.
- (unless (file-directory-p (tramp-fuse-mount-point vec))
- (make-directory (tramp-fuse-mount-point vec) 'parents))
-
- ;; 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))
-
- ;; Mark it as connected.
- (add-to-list 'tramp-fuse-mount-points (tramp-file-name-unify vec))
- (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)))
+ (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)
+
+ ;; Set connection-local variables.
+ (tramp-set-connection-local-variables vec)))
+
+ ;; Create directory.
+ (unless (file-directory-p (tramp-fuse-mount-point vec))
+ (make-directory (tramp-fuse-mount-point vec) 'parents))
+
+ ;; 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))
+
+ ;; Mark it as connected.
+ (add-to-list 'tramp-fuse-mount-points (tramp-file-name-unify vec))
+ (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.
(tramp-shell-quote-argument localname))))
(with-current-buffer (tramp-get-connection-buffer v)
(goto-char (point-min))
- (when (re-search-forward regexp (line-end-position) t)
+ (when (search-forward-regexp regexp (line-end-position) t)
(setq context (list (match-string 1) (match-string 2)
(match-string 3) (match-string 4))))))
;; Return the context.
(or
(and keep-date
;; Mask cp -f error.
- (re-search-forward
+ (search-forward-regexp
tramp-operation-not-permitted-regexp nil t))
cmd-result)
(tramp-error-with-buffer
(save-restriction
(narrow-to-region beg-marker end-marker)
;; Check for "--dired" output.
- (when (re-search-backward
+ (when (search-backward-regexp
(rx bol "//DIRED//" (+ blank) (group (+ nonl)) eol)
nil 'noerror)
(let ((beg (match-beginning 1))
(put-text-property start end 'dired-filename t))))))
;; Remove trailing lines.
(goto-char (point-max))
- (while (re-search-backward (rx bol "//") nil 'noerror)
+ (while (search-backward-regexp (rx bol "//") nil 'noerror)
(forward-line 1)
(delete-region (match-beginning 0) (point))))
;; Reset multibyte if needed.
(unless (tramp-compat-string-search
"color" (tramp-get-connection-property v "ls" ""))
(goto-char (point-min))
- (while (re-search-forward ansi-color-control-seq-regexp nil t)
+ (while (search-forward-regexp ansi-color-control-seq-regexp nil t)
(replace-match "")))
;; Now decode what read if necessary. Stolen from `insert-directory'.
;; Try to insert the amount of free space.
(goto-char (point-min))
;; First find the line to put it on.
- (when (and (re-search-forward (rx bol (group (* blank) "total")) nil t)
+ (when (and (search-forward-regexp
+ (rx bol (group (* blank) "total")) nil t)
;; Emacs 29.1 or later.
(not (fboundp 'dired--insert-disk-space)))
(when-let ((available (get-free-disk-space ".")))
"Invoke remote-shell Tramp file name handler.
Fall back to normal file name handler if no Tramp handler exists."
(if-let ((fn (assoc operation tramp-sh-file-name-handler-alist)))
- (save-match-data (apply (cdr fn) args))
- (tramp-run-real-handler operation args)))
+ (prog1 (save-match-data (apply (cdr fn) args))
+ (setq tramp-debug-message-fnh-function (cdr fn)))
+ (prog1 (tramp-run-real-handler operation args)
+ (setq tramp-debug-message-fnh-function operation))))
;;;###tramp-autoload
(defun tramp-sh-file-name-handler-p (vec)
(unless (tramp-connectable-p vec)
(throw 'non-essential 'non-essential))
- (let ((p (tramp-get-connection-process vec))
- (process-name (tramp-get-connection-property vec "process-name"))
- (process-environment (copy-sequence process-environment))
- (pos (with-current-buffer (tramp-get-connection-buffer vec) (point))))
-
- ;; If Tramp opens the same connection within a short time frame,
- ;; there is a problem. We shall signal this.
- (unless (or (process-live-p p)
- (and (processp p) (not non-essential))
- (not (tramp-file-name-equal-p
- vec (car tramp-current-connection)))
- (time-less-p
- (time-since (cdr tramp-current-connection))
- (or tramp-connection-min-time-diff 0)))
- (throw 'suppress 'suppress))
-
- ;; If too much time has passed since last command was sent, look
- ;; whether process is still alive. If it isn't, kill it. When
- ;; using ssh, it can sometimes happen that the remote end has hung
- ;; up but the local ssh client doesn't recognize this until it
- ;; tries to send some data to the remote end. So that's why we
- ;; try to send a command from time to time, then look again
- ;; whether the process is really alive.
- (condition-case nil
- (when (and (time-less-p
- 60 (time-since
- (tramp-get-connection-property p "last-cmd-time" 0)))
- (process-live-p p))
- (tramp-send-command vec "echo are you awake" t t)
- (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-cleanup-connection vec t)
- (setq p nil)))
-
- ;; New connection must be opened.
- (condition-case err
- (unless (process-live-p p)
- (with-tramp-progress-reporter
- vec 3
- (if (tramp-string-empty-or-nil-p (tramp-file-name-user vec))
- (format "Opening connection %s for %s using %s"
+ (with-tramp-debug-message vec "Opening connection"
+ (let ((p (tramp-get-connection-process vec))
+ (process-name (tramp-get-connection-property vec "process-name"))
+ (process-environment (copy-sequence process-environment))
+ (pos (with-current-buffer (tramp-get-connection-buffer vec) (point))))
+
+ ;; If Tramp opens the same connection within a short time frame,
+ ;; there is a problem. We shall signal this.
+ (unless (or (process-live-p p)
+ (and (processp p) (not non-essential))
+ (not (tramp-file-name-equal-p
+ vec (car tramp-current-connection)))
+ (time-less-p
+ (time-since (cdr tramp-current-connection))
+ (or tramp-connection-min-time-diff 0)))
+ (throw 'suppress 'suppress))
+
+ ;; If too much time has passed since last command was sent, look
+ ;; whether process is still alive. If it isn't, kill it. When
+ ;; using ssh, it can sometimes happen that the remote end has
+ ;; hung up but the local ssh client doesn't recognize this until
+ ;; it tries to send some data to the remote end. So that's why
+ ;; we try to send a command from time to time, then look again
+ ;; whether the process is really alive.
+ (condition-case nil
+ (when (and (time-less-p
+ 60 (time-since
+ (tramp-get-connection-property p "last-cmd-time" 0)))
+ (process-live-p p))
+ (tramp-send-command vec "echo are you awake" t t)
+ (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-cleanup-connection vec t)
+ (setq p nil)))
+
+ ;; New connection must be opened.
+ (condition-case err
+ (unless (process-live-p p)
+ (with-tramp-progress-reporter
+ vec 3
+ (if (tramp-string-empty-or-nil-p (tramp-file-name-user vec))
+ (format "Opening connection %s for %s using %s"
+ process-name
+ (tramp-file-name-host vec)
+ (tramp-file-name-method vec))
+ (format "Opening connection %s for %s@%s using %s"
process-name
+ (tramp-file-name-user vec)
(tramp-file-name-host vec)
- (tramp-file-name-method vec))
- (format "Opening connection %s for %s@%s using %s"
- process-name
- (tramp-file-name-user vec)
- (tramp-file-name-host vec)
- (tramp-file-name-method vec)))
-
- (catch 'uname-changed
- ;; Start new process.
- (when (and p (processp p))
- (delete-process p))
- (setenv "TERM" tramp-terminal-type)
- (setenv "LC_ALL" (tramp-get-local-locale vec))
- (if (stringp tramp-histfile-override)
- (setenv "HISTFILE" tramp-histfile-override)
- (if tramp-histfile-override
- (progn
- (setenv "HISTFILE")
- (setenv "HISTFILESIZE" "0")
- (setenv "HISTSIZE" "0"))))
- (setenv "PROMPT_COMMAND")
- (setenv "PS1" tramp-initial-end-of-output)
- (unless (stringp tramp-encoding-shell)
- (tramp-error vec '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)
- ;; We will apply `tramp-ssh-controlmaster-options'
- ;; only for the first hop.
- (options (tramp-ssh-controlmaster-options vec))
- (process-connection-type tramp-process-connection-type)
- (process-adaptive-read-buffering nil)
- ;; There are unfortunate settings for "cmdproxy" on
- ;; W32 systems.
- (process-coding-system-alist nil)
- (coding-system-for-read nil)
- (extra-args (tramp-get-sh-extra-args tramp-encoding-shell))
- ;; This must be done in order to avoid our file
- ;; name handler.
- (p (let ((default-directory
- tramp-compat-temporary-file-directory))
- (apply
- #'start-process
- (tramp-get-connection-name vec)
- (tramp-get-connection-buffer vec)
- (append
- (list tramp-encoding-shell)
- (and extra-args (split-string extra-args))
- (and tramp-encoding-command-interactive
- (list tramp-encoding-command-interactive)))))))
-
- ;; This is neded for ssh or PuTTY based processes, and
- ;; only if the respective options are set. Perhaps,
- ;; the setting could be more fine-grained.
- ;; (process-put p 'tramp-shared-socket t)
- ;; Set sentinel. Initialize variables.
- (set-process-sentinel p #'tramp-process-sentinel)
- (tramp-post-process-creation p vec)
- (setq tramp-current-connection (cons vec (current-time)))
-
- ;; Set connection-local variables.
- (tramp-set-connection-local-variables vec)
-
- ;; Check whether process is alive.
- (tramp-barf-if-no-shell-prompt
- p 10
- "Couldn't find local shell prompt for %s" tramp-encoding-shell)
-
- ;; Now do all the connections as specified.
- (while target-alist
- (let* ((hop (car target-alist))
- (l-method (tramp-file-name-method hop))
- (l-user (tramp-file-name-user hop))
- (l-domain (tramp-file-name-domain hop))
- (l-host (tramp-file-name-host hop))
- (l-port (tramp-file-name-port hop))
- (remote-shell
- (tramp-get-method-parameter hop 'tramp-remote-shell))
- (extra-args (tramp-get-sh-extra-args remote-shell))
- (async-args
- (flatten-tree
- (tramp-get-method-parameter hop 'tramp-async-args)))
- (connection-timeout
- (tramp-get-method-parameter
- hop 'tramp-connection-timeout))
- (command
- (tramp-get-method-parameter hop 'tramp-login-program))
- ;; We don't create the temporary file. In
- ;; fact, it is just a prefix for the
- ;; ControlPath option of ssh; the real
- ;; temporary file has another name, and it is
- ;; created and protected by ssh. It is also
- ;; removed by ssh when the connection is
- ;; closed. The temporary file name is cached
- ;; in the main connection process, therefore
- ;; we cannot use `tramp-get-connection-process'.
- (tmpfile
- (with-tramp-connection-property
- (tramp-get-process vec) "temp-file"
- (tramp-compat-make-temp-name)))
- r-shell)
-
- ;; Check, whether there is a restricted shell.
- (dolist (elt tramp-restricted-shell-hosts-alist)
- (when (string-match-p elt current-host)
- (setq r-shell t)))
- (setq current-host l-host)
-
- ;; Set password prompt vector.
- (tramp-set-connection-property
- p "password-vector"
- (if (tramp-get-method-parameter
- hop 'tramp-password-previous-hop)
- (let ((pv (copy-tramp-file-name previous-hop)))
- (setf (tramp-file-name-method pv) l-method)
- pv)
- (make-tramp-file-name
- :method l-method :user l-user :domain l-domain
- :host l-host :port l-port)))
-
- ;; Set session timeout.
- (when (tramp-get-method-parameter
- hop 'tramp-session-timeout)
+ (tramp-file-name-method vec)))
+
+ (catch 'uname-changed
+ ;; Start new process.
+ (when (and p (processp p))
+ (delete-process p))
+ (setenv "TERM" tramp-terminal-type)
+ (setenv "LC_ALL" (tramp-get-local-locale vec))
+ (if (stringp tramp-histfile-override)
+ (setenv "HISTFILE" tramp-histfile-override)
+ (if tramp-histfile-override
+ (progn
+ (setenv "HISTFILE")
+ (setenv "HISTFILESIZE" "0")
+ (setenv "HISTSIZE" "0"))))
+ (setenv "PROMPT_COMMAND")
+ (setenv "PS1" tramp-initial-end-of-output)
+ (unless (stringp tramp-encoding-shell)
+ (tramp-error vec '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)
+ ;; We will apply `tramp-ssh-controlmaster-options'
+ ;; only for the first hop.
+ (options (tramp-ssh-controlmaster-options vec))
+ (process-connection-type tramp-process-connection-type)
+ (process-adaptive-read-buffering nil)
+ ;; There are unfortunate settings for
+ ;; "cmdproxy" on W32 systems.
+ (process-coding-system-alist nil)
+ (coding-system-for-read nil)
+ (extra-args
+ (tramp-get-sh-extra-args tramp-encoding-shell))
+ ;; This must be done in order to avoid our file
+ ;; name handler.
+ (p (let ((default-directory
+ tramp-compat-temporary-file-directory))
+ (apply
+ #'start-process
+ (tramp-get-connection-name vec)
+ (tramp-get-connection-buffer vec)
+ (append
+ `(,tramp-encoding-shell)
+ (and extra-args (split-string extra-args))
+ (and tramp-encoding-command-interactive
+ `(,tramp-encoding-command-interactive)))))))
+
+ ;; This is neded for ssh or PuTTY based processes,
+ ;; and only if the respective options are set.
+ ;; Perhaps, the setting could be more fine-grained.
+ ;; (process-put p 'tramp-shared-socket t)
+ ;; Set sentinel. Initialize variables.
+ (set-process-sentinel p #'tramp-process-sentinel)
+ (tramp-post-process-creation p vec)
+ (setq tramp-current-connection (cons vec (current-time)))
+
+ ;; Set connection-local variables.
+ (tramp-set-connection-local-variables vec)
+
+ ;; Check whether process is alive.
+ (tramp-barf-if-no-shell-prompt
+ p 10
+ "Couldn't find local shell prompt for %s"
+ tramp-encoding-shell)
+
+ ;; Now do all the connections as specified.
+ (while target-alist
+ (let* ((hop (car target-alist))
+ (l-method (tramp-file-name-method hop))
+ (l-user (tramp-file-name-user hop))
+ (l-domain (tramp-file-name-domain hop))
+ (l-host (tramp-file-name-host hop))
+ (l-port (tramp-file-name-port hop))
+ (remote-shell
+ (tramp-get-method-parameter hop 'tramp-remote-shell))
+ (extra-args (tramp-get-sh-extra-args remote-shell))
+ (async-args
+ (flatten-tree
+ (tramp-get-method-parameter hop 'tramp-async-args)))
+ (connection-timeout
+ (tramp-get-method-parameter
+ hop 'tramp-connection-timeout))
+ (command
+ (tramp-get-method-parameter
+ hop 'tramp-login-program))
+ ;; We don't create the temporary file. In
+ ;; fact, it is just a prefix for the
+ ;; ControlPath option of ssh; the real
+ ;; temporary file has another name, and it
+ ;; is created and protected by ssh. It is
+ ;; also removed by ssh when the connection
+ ;; is closed. The temporary file name is
+ ;; cached in the main connection process,
+ ;; therefore we cannot use
+ ;; `tramp-get-connection-process'.
+ (tmpfile
+ (with-tramp-connection-property
+ (tramp-get-process vec) "temp-file"
+ (tramp-compat-make-temp-name)))
+ r-shell)
+
+ ;; Check, whether there is a restricted shell.
+ (dolist (elt tramp-restricted-shell-hosts-alist)
+ (when (string-match-p elt current-host)
+ (setq r-shell t)))
+ (setq current-host l-host)
+
+ ;; Set password prompt vector.
(tramp-set-connection-property
- p "session-timeout"
- (tramp-get-method-parameter
- hop 'tramp-session-timeout)))
-
- ;; Replace `login-args' place holders.
- (setq
- command
- (string-join
- (append
- ;; We do not want to see the trailing local
- ;; prompt in `start-file-process'.
- (unless r-shell '("exec"))
- `(,command)
- ;; Add arguments for asynchronous processes.
- (when process-name async-args)
- (tramp-expand-args
- hop 'tramp-login-args
- ?h (or l-host "") ?u (or l-user "") ?p (or l-port "")
- ?c (format-spec options (format-spec-make ?t tmpfile))
- ?n (concat
- "2>" (tramp-get-remote-null-device previous-hop))
- ?l (concat remote-shell " " extra-args " -i"))
- ;; A restricted shell does not allow "exec".
- (when r-shell '("&&" "exit" "||" "exit")))
- " "))
-
- ;; Send the command.
- (tramp-message vec 3 "Sending command `%s'" command)
- (tramp-send-command vec command t t)
- (tramp-process-actions
- p vec
- (min
- pos (with-current-buffer (process-buffer p) (point-max)))
- tramp-actions-before-shell
- (or connection-timeout tramp-connection-timeout))
- (tramp-message
- vec 3 "Found remote shell prompt on `%s'" l-host)
-
- ;; Next hop.
- (setq options ""
- target-alist (cdr target-alist)
- previous-hop hop)))
-
- ;; Activate session timeout.
- (when (tramp-get-connection-property p "session-timeout")
- (run-at-time
- (tramp-get-connection-property p "session-timeout") nil
- #'tramp-timeout-session vec))
-
- ;; Make initial shell settings.
- (tramp-open-connection-setup-interactive-shell p vec)
-
- ;; Mark it as connected.
- (tramp-set-connection-property p "connected" t)))))
-
- ;; Cleanup, and propagate the signal.
- ((error quit)
- (tramp-cleanup-connection vec t)
- (signal (car err) (cdr err))))))
+ p "password-vector"
+ (if (tramp-get-method-parameter
+ hop 'tramp-password-previous-hop)
+ (let ((pv (copy-tramp-file-name previous-hop)))
+ (setf (tramp-file-name-method pv) l-method)
+ pv)
+ (make-tramp-file-name
+ :method l-method :user l-user :domain l-domain
+ :host l-host :port l-port)))
+
+ ;; Set session timeout.
+ (when (tramp-get-method-parameter
+ hop 'tramp-session-timeout)
+ (tramp-set-connection-property
+ p "session-timeout"
+ (tramp-get-method-parameter
+ hop 'tramp-session-timeout)))
+
+ ;; Replace `login-args' place holders.
+ (setq
+ command
+ (string-join
+ (append
+ ;; We do not want to see the trailing local
+ ;; prompt in `start-file-process'.
+ (unless r-shell '("exec"))
+ `(,command)
+ ;; Add arguments for asynchronous processes.
+ (when process-name async-args)
+ (tramp-expand-args
+ hop 'tramp-login-args
+ ?h (or l-host "") ?u (or l-user "") ?p (or l-port "")
+ ?c (format-spec options (format-spec-make ?t tmpfile))
+ ?n (concat
+ "2>" (tramp-get-remote-null-device previous-hop))
+ ?l (concat remote-shell " " extra-args " -i"))
+ ;; A restricted shell does not allow "exec".
+ (when r-shell '("&&" "exit" "||" "exit")))
+ " "))
+
+ ;; Send the command.
+ (tramp-message vec 3 "Sending command `%s'" command)
+ (tramp-send-command vec command t t)
+ (tramp-process-actions
+ p vec
+ (min
+ pos (with-current-buffer (process-buffer p) (point-max)))
+ tramp-actions-before-shell
+ (or connection-timeout tramp-connection-timeout))
+ (tramp-message
+ vec 3 "Found remote shell prompt on `%s'" l-host)
+
+ ;; Next hop.
+ (setq options ""
+ target-alist (cdr target-alist)
+ previous-hop hop)))
+
+ ;; Activate session timeout.
+ (when (tramp-get-connection-property p "session-timeout")
+ (run-at-time
+ (tramp-get-connection-property p "session-timeout") nil
+ #'tramp-timeout-session vec))
+
+ ;; Make initial shell settings.
+ (tramp-open-connection-setup-interactive-shell p vec)
+
+ ;; Mark it as connected.
+ (tramp-set-connection-property p "connected" t)))))
+
+ ;; Cleanup, and propagate the signal.
+ ((error quit)
+ (tramp-cleanup-connection vec t)
+ (signal (car err) (cdr err)))))))
(defun tramp-send-command (vec command &optional neveropen nooutput)
"Send the COMMAND to connection VEC.
;; A simple-minded busybox has sent " ^H" sequences.
;; Delete them.
(goto-char (point-min))
- (when (re-search-forward
+ (when (search-forward-regexp
(rx bol (+ nonl "\b") eol) (line-end-position) t)
(forward-line 1)
(delete-region (point-min) (point)))
;; Read the marker.
(when (stringp marker)
(condition-case nil
- (re-search-forward marker)
+ (search-forward-regexp marker)
(error (unless noerror
(tramp-error
vec 'file-error
(unless noerror signal-hook-function)))
(read (current-buffer)))
;; Error handling.
- (when (re-search-forward (rx (not blank)) (line-end-position) t)
+ (when (search-forward-regexp (rx (not blank)) (line-end-position) t)
(error nil)))
(error (unless noerror
(tramp-error
(defcustom tramp-smb-acl-program "smbcacls"
"Name of SMB acls to run."
:group 'tramp
- :type 'string
- :version "24.4")
+ :version "24.4"
+ :type 'string)
(defcustom tramp-smb-conf null-device
"Path of the \"smb.conf\" file.
For example, if the deprecated SMB1 protocol shall be used, add to
this variable \"client min protocol=NT1\"."
:group 'tramp
- :type '(repeat string)
- :version "28.1")
+ :version "28.1"
+ :type '(repeat string))
(defvar tramp-smb-version nil
"Version string of the SMB client.")
If it isn't found in the local $PATH, the absolute path of winexe
shall be given. This is needed for remote processes."
:group 'tramp
- :type 'string
- :version "24.3")
+ :version "24.3"
+ :type 'string)
(defcustom tramp-smb-winexe-shell-command "powershell.exe"
"Shell to be used for processes on remote machines.
This must be Powershell V2 compatible."
:group 'tramp
- :type 'string
- :version "24.3")
+ :version "24.3"
+ :type 'string)
(defcustom tramp-smb-winexe-shell-command-switch "-file -"
"Command switch used together with `tramp-smb-winexe-shell-command'.
This can be used to disable echo etc."
:group 'tramp
- :type 'string
- :version "24.3")
+ :version "24.3"
+ :type 'string)
;; It must be a `defsubst' in order to push the whole code into
;; tramp-loaddefs.el. Otherwise, there would be recursive autoloading.
First arg specifies the OPERATION, second arg is a list of
arguments to pass to the OPERATION."
(if-let ((fn (assoc operation tramp-smb-file-name-handler-alist)))
- (save-match-data (apply (cdr fn) args))
- (tramp-run-real-handler operation args)))
+ (prog1 (save-match-data (apply (cdr fn) args))
+ (setq tramp-debug-message-fnh-function (cdr fn)))
+ (prog1 (tramp-run-real-handler operation args)
+ (setq tramp-debug-message-fnh-function operation))))
;;;###tramp-autoload
(unless (memq system-type '(cygwin windows-nt))
;; Loop the listing.
(with-current-buffer (tramp-get-connection-buffer vec)
(goto-char (point-min))
- (unless (re-search-forward tramp-smb-errors nil t)
+ (unless (search-forward-regexp tramp-smb-errors nil t)
(while (not (eobp))
(cond
((looking-at
;; Loop the listing.
(with-current-buffer (tramp-get-connection-buffer v)
(goto-char (point-min))
- (if (re-search-forward tramp-smb-errors nil t)
+ (if (search-forward-regexp tramp-smb-errors nil t)
(tramp-error v 'file-error "%s `%s'" (match-string 0) directory)
(while (not (eobp))
(setq entry (tramp-smb-read-file-entry share))
(when (tramp-smb-send-command vec "posix")
(with-current-buffer (tramp-get-connection-buffer vec)
(goto-char (point-min))
- (when
- (re-search-forward "Server supports CIFS capabilities" nil t)
+ (when (search-forward-regexp
+ "Server supports CIFS capabilities" nil t)
(member
"pathnames"
(split-string
(unless (tramp-connectable-p vec)
(throw 'non-essential 'non-essential))
- (let* ((share (tramp-smb-get-share vec))
- (buf (tramp-get-connection-buffer vec))
- (p (get-buffer-process buf)))
+ (with-tramp-debug-message vec "Opening connection"
+ (let* ((share (tramp-smb-get-share vec))
+ (buf (tramp-get-connection-buffer vec))
+ (p (get-buffer-process buf)))
+
+ ;; Check whether we still have the same smbclient version.
+ ;; Otherwise, we must delete the connection cache, because
+ ;; capabilities might have changed.
+ (unless (or argument (processp p))
+ (let ((default-directory tramp-compat-temporary-file-directory)
+ (command (concat tramp-smb-program " -V")))
+
+ (unless tramp-smb-version
+ (unless (executable-find tramp-smb-program)
+ (tramp-error
+ vec '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)
+ (tramp-message vec 6 "\n%s" tramp-smb-version)
+ (if (string-match (rx (+ (any " \t\r\n")) eos) tramp-smb-version)
+ (setq tramp-smb-version
+ (replace-match "" nil nil tramp-smb-version))))
+
+ (unless (string-equal
+ tramp-smb-version
+ (tramp-get-connection-property
+ vec "smbclient-version" tramp-smb-version))
+ (tramp-flush-directory-properties vec "/")
+ (tramp-flush-connection-properties vec))
+
+ (tramp-set-connection-property
+ vec "smbclient-version" tramp-smb-version)))
+
+ ;; If too much time has passed since last command was sent, look
+ ;; whether there has been an error message; maybe due to
+ ;; connection timeout.
+ (with-current-buffer buf
+ (goto-char (point-min))
+ (when (and (time-less-p
+ 60 (time-since
+ (tramp-get-connection-property p "last-cmd-time" 0)))
+ (process-live-p p)
+ (search-forward-regexp tramp-smb-errors nil t))
+ (delete-process p)
+ (setq p nil)))
+
+ ;; Check whether it is still the same share.
+ (unless (and (process-live-p p)
+ (or argument
+ (string-equal
+ share
+ (tramp-get-connection-property p "smb-share" ""))))
+ (save-match-data
+ ;; There might be unread output from checking for share names.
+ (when buf (with-current-buffer buf (erase-buffer)))
+ (when (and p (processp p)) (delete-process p))
- ;; Check whether we still have the same smbclient version.
- ;; Otherwise, we must delete the connection cache, because
- ;; capabilities might have changed.
- (unless (or argument (processp p))
- (let ((default-directory tramp-compat-temporary-file-directory)
- (command (concat tramp-smb-program " -V")))
+ (let* ((user (tramp-file-name-user vec))
+ (host (tramp-file-name-host vec))
+ (domain (tramp-file-name-domain vec))
+ (port (tramp-file-name-port vec))
+ (options tramp-smb-options)
+ args)
- (unless tramp-smb-version
- (unless (executable-find tramp-smb-program)
- (tramp-error
- vec '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)
- (tramp-message vec 6 "\n%s" tramp-smb-version)
- (if (string-match (rx (+ (any " \t\r\n")) eos) tramp-smb-version)
- (setq tramp-smb-version
- (replace-match "" nil nil tramp-smb-version))))
-
- (unless (string-equal
- tramp-smb-version
- (tramp-get-connection-property
- vec "smbclient-version" tramp-smb-version))
- (tramp-flush-directory-properties vec "/")
- (tramp-flush-connection-properties vec))
-
- (tramp-set-connection-property
- vec "smbclient-version" tramp-smb-version)))
-
- ;; If too much time has passed since last command was sent, look
- ;; whether there has been an error message; maybe due to
- ;; connection timeout.
- (with-current-buffer buf
- (goto-char (point-min))
- (when (and (time-less-p
- 60 (time-since
- (tramp-get-connection-property p "last-cmd-time" 0)))
- (process-live-p p)
- (re-search-forward tramp-smb-errors nil t))
- (delete-process p)
- (setq p nil)))
-
- ;; Check whether it is still the same share.
- (unless (and (process-live-p p)
- (or argument
- (string-equal
- share
- (tramp-get-connection-property p "smb-share" ""))))
- (save-match-data
- ;; There might be unread output from checking for share names.
- (when buf (with-current-buffer buf (erase-buffer)))
- (when (and p (processp p)) (delete-process p))
-
- (let* ((user (tramp-file-name-user vec))
- (host (tramp-file-name-host vec))
- (domain (tramp-file-name-domain vec))
- (port (tramp-file-name-port vec))
- (options tramp-smb-options)
- args)
-
- (cond
- (argument
- (setq args (list (concat "//" host))))
- (share
- (setq args (list (concat "//" host "/" share))))
- (t
- (setq args (list "-g" "-L" host ))))
+ (cond
+ (argument (setq args (list (concat "//" host))))
+ (share (setq args (list (concat "//" host "/" share))))
+ (t (setq args (list "-g" "-L" host ))))
- (if (tramp-string-empty-or-nil-p user)
- (setq args (append args (list "-N")))
- (setq args (append args (list "-U" user))))
+ (if (tramp-string-empty-or-nil-p user)
+ (setq args (append args (list "-N")))
+ (setq args (append args (list "-U" user))))
- (when domain (setq args (append args (list "-W" domain))))
- (when port (setq args (append args (list "-p" port))))
- (when tramp-smb-conf
- (setq args (append args (list "-s" tramp-smb-conf))))
- (dolist (option options)
- (setq args (append args (list "--option" option))))
- (when argument
- (setq args (append args (list argument))))
-
- ;; OK, let's go.
- (with-tramp-progress-reporter
- vec 3
- (format "Opening connection for //%s%s/%s"
- (if (tramp-string-empty-or-nil-p user)
- "" (concat user "@"))
- host (or share ""))
-
- (let* (coding-system-for-read
- (process-connection-type tramp-process-connection-type)
- (p (let ((default-directory
- tramp-compat-temporary-file-directory)
- (process-environment
- (cons (concat "TERM=" tramp-terminal-type)
- process-environment)))
- (apply #'start-process
- (tramp-get-connection-name vec)
- (tramp-get-connection-buffer vec)
- (if argument
- tramp-smb-winexe-program tramp-smb-program)
- args))))
- (tramp-post-process-creation p vec)
-
- ;; Set connection-local variables.
- (tramp-set-connection-local-variables vec)
-
- (condition-case err
- (let ((inhibit-message t))
- ;; Play login scenario.
- (tramp-process-actions
- p vec nil
- (if (or argument share)
- tramp-smb-actions-with-share
- tramp-smb-actions-without-share))
-
- ;; Set chunksize to 1. smbclient reads its input
- ;; character by character; if we send the string
- ;; at once, it is read painfully slow.
- (tramp-set-connection-property p "smb-share" share)
- (tramp-set-connection-property p "chunksize" 1)
-
- ;; Mark it as connected.
- (tramp-set-connection-property p "connected" t))
-
- ;; Check for the error reason. If it was due to wrong
- ;; password, reestablish the connection. We cannot
- ;; handle this in `tramp-process-actions', because
- ;; smbclient does not ask for the password, again.
- (error
- (with-current-buffer (tramp-get-connection-buffer vec)
- (goto-char (point-min))
- (if (and (bound-and-true-p auth-sources)
- (search-forward-regexp
- tramp-smb-wrong-passwd-regexp nil t))
- ;; Disable `auth-source' and `password-cache'.
- (let (auth-sources)
- (tramp-message
- vec 3 "Retry connection with new password")
- (tramp-cleanup-connection vec t)
- (tramp-smb-maybe-open-connection vec argument))
- ;; Propagate the error.
- (signal (car err) (cdr err)))))))))))))
+ (when domain (setq args (append args (list "-W" domain))))
+ (when port (setq args (append args (list "-p" port))))
+ (when tramp-smb-conf
+ (setq args (append args (list "-s" tramp-smb-conf))))
+ (dolist (option options)
+ (setq args (append args (list "--option" option))))
+ (when argument
+ (setq args (append args (list argument))))
+
+ ;; OK, let's go.
+ (with-tramp-progress-reporter
+ vec 3
+ (format "Opening connection for //%s%s/%s"
+ (if (tramp-string-empty-or-nil-p user)
+ "" (concat user "@"))
+ host (or share ""))
+
+ (let* (coding-system-for-read
+ (process-connection-type tramp-process-connection-type)
+ (p (let ((default-directory
+ tramp-compat-temporary-file-directory)
+ (process-environment
+ (cons (concat "TERM=" tramp-terminal-type)
+ process-environment)))
+ (apply #'start-process
+ (tramp-get-connection-name vec)
+ (tramp-get-connection-buffer vec)
+ (if argument
+ tramp-smb-winexe-program tramp-smb-program)
+ args))))
+ (tramp-post-process-creation p vec)
+
+ ;; Set connection-local variables.
+ (tramp-set-connection-local-variables vec)
+
+ (condition-case err
+ (let ((inhibit-message t))
+ ;; Play login scenario.
+ (tramp-process-actions
+ p vec nil
+ (if (or argument share)
+ tramp-smb-actions-with-share
+ tramp-smb-actions-without-share))
+
+ ;; Set chunksize to 1. smbclient reads its
+ ;; input character by character; if we send the
+ ;; string at once, it is read painfully slow.
+ (tramp-set-connection-property p "smb-share" share)
+ (tramp-set-connection-property p "chunksize" 1)
+
+ ;; Mark it as connected.
+ (tramp-set-connection-property p "connected" t))
+
+ ;; Check for the error reason. If it was due to
+ ;; wrong password, reestablish the connection. We
+ ;; cannot handle this in `tramp-process-actions',
+ ;; because smbclient does not ask for the password,
+ ;; again.
+ (error
+ (with-current-buffer (tramp-get-connection-buffer vec)
+ (goto-char (point-min))
+ (if (and (bound-and-true-p auth-sources)
+ (search-forward-regexp
+ tramp-smb-wrong-passwd-regexp nil t))
+ ;; Disable `auth-source' and `password-cache'.
+ (let (auth-sources)
+ (tramp-message
+ vec 3 "Retry connection with new password")
+ (tramp-cleanup-connection vec t)
+ (tramp-smb-maybe-open-connection vec argument))
+ ;; Propagate the error.
+ (signal (car err) (cdr err))))))))))))))
;; We don't use timeouts. If needed, the caller shall wrap around.
(defun tramp-smb-wait-for-output (vec)
(inhibit-read-only t))
;; Read pending output.
- (while (not (re-search-forward tramp-smb-prompt nil t))
+ (while (not (search-forward-regexp tramp-smb-prompt nil t))
(while (tramp-accept-process-output p))
(goto-char (point-min)))
(tramp-message vec 6 "\n%s" (buffer-string))
;; Remove prompt.
(goto-char (point-min))
- (when (re-search-forward tramp-smb-prompt nil t)
+ (when (search-forward-regexp tramp-smb-prompt nil t)
(goto-char (point-max))
- (re-search-backward tramp-smb-prompt nil t)
+ (search-backward-regexp tramp-smb-prompt nil t)
(delete-region (point) (point-max)))
;; Return value is whether no error message has appeared.
(goto-char (point-min))
- (not (re-search-forward tramp-smb-errors nil t)))))
+ (not (search-forward-regexp tramp-smb-errors nil t)))))
(defun tramp-smb-kill-winexe-function ()
"Send SIGKILL to the winexe process."
First arg specifies the OPERATION, second arg is a list of
arguments to pass to the OPERATION."
(if-let ((fn (assoc operation tramp-sshfs-file-name-handler-alist)))
- (save-match-data (apply (cdr fn) args))
- (tramp-run-real-handler operation args)))
+ (prog1 (save-match-data (apply (cdr fn) args))
+ (setq tramp-debug-message-fnh-function (cdr fn)))
+ (prog1 (tramp-run-real-handler operation args)
+ (setq tramp-debug-message-fnh-function operation))))
;;;###tramp-autoload
(tramp--with-startup
(unless (tramp-connectable-p vec)
(throw 'non-essential 'non-essential))
- ;; 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)
-
- ;; Set connection-local variables.
- (tramp-set-connection-local-variables vec)))
-
- ;; Create directory.
- (unless (file-directory-p (tramp-fuse-mount-point vec))
- (make-directory (tramp-fuse-mount-point vec) 'parents))
-
- (unless
- (or (tramp-fuse-mounted-p vec)
- (with-temp-buffer
- (zerop
- (apply
- #'tramp-call-process
- vec tramp-sshfs-program nil t nil
- (tramp-fuse-mount-spec vec)
- (tramp-fuse-mount-point vec)
- (tramp-expand-args
- vec 'tramp-mount-args
- ?p (or (tramp-file-name-port vec) ""))))))
- (tramp-error
- vec '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))
- (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)))
+ (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?
+ (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)
+
+ ;; Set connection-local variables.
+ (tramp-set-connection-local-variables vec)))
+
+ ;; Create directory.
+ (unless (file-directory-p (tramp-fuse-mount-point vec))
+ (make-directory (tramp-fuse-mount-point vec) 'parents))
+
+ (unless
+ (or (tramp-fuse-mounted-p vec)
+ (with-temp-buffer
+ (zerop
+ (apply
+ #'tramp-call-process
+ vec tramp-sshfs-program nil t nil
+ (tramp-fuse-mount-spec vec)
+ (tramp-fuse-mount-point vec)
+ (tramp-expand-args
+ vec 'tramp-mount-args
+ ?p (or (tramp-file-name-port vec) ""))))))
+ (tramp-error
+ vec '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))
+ (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))))
;; `shell-mode' tries to open remote files like "/sshfs:user@host:~/.history".
;; This fails, because the tilde cannot be expanded. Tell
First arg specifies the OPERATION, second arg is a list of
arguments to pass to the OPERATION."
(if-let ((fn (assoc operation tramp-sudoedit-file-name-handler-alist)))
- (save-match-data (apply (cdr fn) args))
- (tramp-run-real-handler operation args)))
+ (prog1 (save-match-data (apply (cdr fn) args))
+ (setq tramp-debug-message-fnh-function (cdr fn)))
+ (prog1 (tramp-run-real-handler operation args)
+ (setq tramp-debug-message-fnh-function operation))))
;;;###tramp-autoload
(tramp--with-startup
v "ls" "-d" "-Z" (file-name-unquote localname)))
(with-current-buffer (tramp-get-connection-buffer v)
(goto-char (point-min))
- (when (re-search-forward regexp (line-end-position) t)
+ (when (search-forward-regexp regexp (line-end-position) t)
(setq context (list (match-string 1) (match-string 2)
(match-string 3) (match-string 4))))))
;; Return the context.
(unless (tramp-connectable-p vec)
(throw 'non-essential 'non-essential))
- ;; We need a process bound to the connection buffer. Therefore, we
- ;; create a dummy process. Maybe there is a better solution?
- (unless (tramp-get-connection-process 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)
+ (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?
+ (unless (tramp-get-connection-process 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)
- ;; Set connection-local variables.
- (tramp-set-connection-local-variables vec)
+ ;; Set connection-local variables.
+ (tramp-set-connection-local-variables vec)
- ;; Mark it as connected.
- (tramp-set-connection-property p "connected" t))))
+ ;; Mark it as connected.
+ (tramp-set-connection-property p "connected" t)))))
(defun tramp-sudoedit-send-command (vec &rest args)
"Send commands ARGS to connection VEC.
(condition-case nil
(prog1 (read (current-buffer))
;; Error handling.
- (when (re-search-forward (rx (not blank)) (line-end-position) t)
+ (when (search-forward-regexp (rx (not blank)) (line-end-position) t)
(error nil)))
(error (tramp-error
vec 'file-error
;;; Code:
(require 'tramp-compat)
+(require 'tramp-message)
(require 'tramp-integration)
(require 'trampver)
"Edit remote files with a combination of ssh, scp, etc."
:group 'files
:group 'comm
- :link '(custom-manual "(tramp)Top")
- :version "22.1")
+ :version "22.1"
+ :link '(custom-manual "(tramp)Top"))
;;;###tramp-autoload
(progn
If it is set to nil, all remote file names are used literally."
:type 'boolean)
-;;;###tramp-autoload
-(defcustom tramp-verbose 3
- "Verbosity level for Tramp messages.
-Any level x includes messages for all levels 1 .. x-1. The levels are
-
- 0 silent (no tramp messages at all)
- 1 errors
- 2 warnings
- 3 connection to remote hosts (default level)
- 4 activities
- 5 internal
- 6 sent and received strings
- 7 connection properties
- 8 file caching
- 9 test commands
-10 traces (huge)
-11 call traces (maintainer only)."
- :type 'integer)
-
-(defcustom tramp-debug-to-file nil
- "Whether Tramp debug messages shall be saved to file.
-The debug file has the same name as the debug buffer, written to
-`tramp-compat-temporary-file-directory'."
- :version "28.1"
- :type 'boolean)
-
(defcustom tramp-backup-directory-alist nil
"Alist of filename patterns and backup directory names.
Each element looks like (REGEXP . DIRECTORY), with the same meaning like
(process-send-eof proc)
(process-send-eof proc))
(while (not (progn (goto-char (point-min))
- (re-search-forward \"\\\\w+\" (point-max) t)))
+ (search-forward-regexp \"\\\\w+\" (point-max) t)))
(accept-process-output proc 1))
(when (process-live-p proc)
(setq received (string-to-number (match-string 0)))
The INSIDE_EMACS environment variable will automatically be set
based on the Tramp and Emacs versions, and should not be set here."
- :group 'tramp
:version "26.1"
:type '(repeat string))
;;; Internal Variables:
+;;;###tramp-autoload
(defvar tramp-current-connection nil
"Last connection timestamp.
It is a cons cell of the actual `tramp-file-name-structure', and
(make-tramp-file-name :user (user-login-name) :host tramp-system-name)
"Connection hop which identifies the virtual hop before the first one.")
+;;;###tramp-autoload
(defun tramp-file-name-user-domain (vec)
"Return user and domain components of VEC."
(when (or (tramp-file-name-user vec) (tramp-file-name-domain vec))
(put #'tramp-file-name-user-domain 'tramp-suppress-trace t)
+;;;###tramp-autoload
(defun tramp-file-name-host-port (vec)
"Return host and port components of VEC."
(when (or (tramp-file-name-host vec) (tramp-file-name-port vec))
buffer (current-buffer))
(substring-no-properties (buffer-string))))
-(defun tramp-debug-buffer-name (vec)
- "A name for the debug buffer for VEC."
- (let ((method (tramp-file-name-method vec))
- (user-domain (tramp-file-name-user-domain vec))
- (host-port (tramp-file-name-host-port vec)))
- (if (tramp-string-empty-or-nil-p user-domain)
- (format "*debug tramp/%s %s*" method host-port)
- (format "*debug tramp/%s %s@%s*" method user-domain host-port))))
-
-(put #'tramp-debug-buffer-name 'tramp-suppress-trace t)
-
-(defconst tramp-debug-outline-regexp
- (rx ;; Timestamp.
- (+ digit) ":" (+ digit) ":" (+ digit) "." (+ digit) blank
- ;; Thread.
- (? (group "#<thread " (+ nonl) ">") blank)
- ;; Function name, verbosity.
- (+ (any "-" alnum)) " (" (group (+ digit)) ") #")
- "Used for highlighting Tramp debug buffers in `outline-mode'.")
-
-(defconst tramp-debug-font-lock-keywords
- ;; FIXME: Make it a function instead of an ELisp expression, so you
- ;; can evaluate it with `funcall' rather than `eval'!
- ;; Also, in `font-lock-defaults' you can specify a function name for
- ;; the "KEYWORDS" part, so font-lock calls it to get the actual keywords!
- '(list
- (rx bol (regexp tramp-debug-outline-regexp) (+ nonl))
- '(1 font-lock-warning-face t t)
- '(0 (outline-font-lock-face) keep t))
- "Used for highlighting Tramp debug buffers in `outline-mode'.")
-
-(defun tramp-debug-outline-level ()
- "Return the depth to which a statement is nested in the outline.
-Point must be at the beginning of a header line.
-
-The outline level is equal to the verbosity of the Tramp message."
- (1+ (string-to-number (match-string 2))))
-
-(put #'tramp-debug-outline-level 'tramp-suppress-trace t)
-
-;; This function takes action since Emacs 28.1, when
-;; `read-extended-command-predicate' is set to
-;; `command-completion-default-include-p'.
-(defun tramp-debug-buffer-command-completion-p (_symbol buffer)
- "A predicate for Tramp interactive commands.
-They are completed by \"M-x TAB\" only in Tramp debug buffers."
- (with-current-buffer buffer
- (string-equal
- (buffer-substring (point-min) (min (+ (point-min) 10) (point-max)))
- ";; Emacs:")))
-
-(put #'tramp-debug-buffer-command-completion-p 'tramp-suppress-trace t)
-
-(defun tramp-setup-debug-buffer ()
- "Function to setup debug buffers."
- ;; (declare (completion tramp-debug-buffer-command-completion-p))
- (interactive)
- (set-buffer-file-coding-system 'utf-8)
- (setq buffer-undo-list t)
- ;; 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".
- ;; `(custom-declare-variable outline-minor-mode-prefix ...)' raises
- ;; on error in `(outline-mode)', we don't want to see it in the
- ;; traces.
- (let ((default-directory tramp-compat-temporary-file-directory))
- (outline-mode))
- (setq-local outline-level 'tramp-debug-outline-level)
- (setq-local font-lock-keywords
- ;; FIXME: This `(t FOO . BAR)' representation in
- ;; `font-lock-keywords' is supposed to be an internal
- ;; implementation "detail". Don't abuse it here!
- `(t (eval ,tramp-debug-font-lock-keywords t)
- ,(eval tramp-debug-font-lock-keywords t)))
- ;; Do not edit the debug buffer.
- (use-local-map special-mode-map)
- (set-buffer-modified-p nil)
- ;; For debugging purposes.
- (local-set-key "\M-n" 'clone-buffer)
- (add-hook 'clone-buffer-hook #'tramp-setup-debug-buffer nil 'local))
-
-(put #'tramp-setup-debug-buffer 'tramp-suppress-trace t)
-
-(function-put
- #'tramp-setup-debug-buffer 'completion-predicate
- #'tramp-debug-buffer-command-completion-p)
-
-(defun tramp-get-debug-buffer (vec)
- "Get the debug buffer for VEC."
- (with-current-buffer (get-buffer-create (tramp-debug-buffer-name vec))
- (when (bobp)
- (tramp-setup-debug-buffer))
- (current-buffer)))
-
-(put #'tramp-get-debug-buffer 'tramp-suppress-trace t)
-
-(defun tramp-get-debug-file-name (vec)
- "Get the debug file name for VEC."
- (expand-file-name
- (tramp-compat-string-replace "/" " " (tramp-debug-buffer-name vec))
- tramp-compat-temporary-file-directory))
-
-(put #'tramp-get-debug-file-name 'tramp-suppress-trace t)
-
-(defun tramp-trace-buffer-name (vec)
- "A name for the trace buffer for VEC."
- (tramp-compat-string-replace "debug" "trace" (tramp-debug-buffer-name vec)))
-
-(put #'tramp-trace-buffer-name 'tramp-suppress-trace t)
-
-(defvar tramp-trace-functions nil
- "A list of non-Tramp functions to be traced with `tramp-verbose' > 10.")
-
-;;;###tramp-autoload
-(defun tramp-debug-message (vec fmt-string &rest arguments)
- "Append message to debug buffer of VEC.
-Message is formatted with FMT-STRING as control string and the remaining
-ARGUMENTS to actually emit the message (if applicable)."
- (let ((inhibit-message t)
- create-lockfiles file-name-handler-alist message-log-max
- signal-hook-function)
- (with-current-buffer (tramp-get-debug-buffer vec)
- (goto-char (point-max))
- (let ((point (point)))
- (when (bobp)
- ;; Headline.
- (insert
- (format
- ";; Emacs: %s Tramp: %s -*- mode: outline; coding: utf-8; -*-"
- emacs-version tramp-version))
- (when (>= tramp-verbose 10)
- (let ((tramp-verbose 0))
- (insert
- (format
- "\n;; Location: %s Git: %s/%s"
- (locate-library "tramp")
- (or tramp-repository-branch "")
- (or tramp-repository-version "")))))
- ;; Traces.
- (when (>= tramp-verbose 11)
- (dolist
- (elt
- (append
- (mapcar
- #'intern (all-completions "tramp-" obarray #'functionp))
- tramp-trace-functions))
- (unless (get elt 'tramp-suppress-trace)
- (trace-function-background elt))))
- ;; Delete debug file.
- (when (and tramp-debug-to-file (tramp-get-debug-file-name vec))
- (ignore-errors (delete-file (tramp-get-debug-file-name vec)))))
- (unless (bolp)
- (insert "\n"))
- ;; Timestamp.
- (insert (format-time-string "%T.%6N "))
- ;; Threads. `current-thread' might not exist when Emacs is
- ;; configured --without-threads.
- ;; (unless (eq (tramp-compat-funcall 'current-thread) main-thread)
- ;; (insert (format "%s " (tramp-compat-funcall 'current-thread))))
- ;; Calling Tramp function. We suppress compat and trace
- ;; functions from being displayed.
- (let ((frames (backtrace-frames))
- btf fn)
- (while (not fn)
- (setq btf (cadadr frames))
- (if (not btf)
- (setq fn "")
- (and (symbolp btf) (setq fn (symbol-name btf))
- (or (not (string-prefix-p "tramp" fn))
- (get btf 'tramp-suppress-trace))
- (setq fn nil))
- (setq frames (cdr frames))))
- ;; The following code inserts filename and line number.
- ;; Should be inactive by default, because it is time consuming.
- ;; (let ((ffn (find-function-noselect (intern fn))))
- ;; (insert
- ;; (format
- ;; "%s:%d: "
- ;; (file-name-nondirectory (buffer-file-name (car ffn)))
- ;; (with-current-buffer (car ffn)
- ;; (1+ (count-lines (point-min) (cdr ffn)))))))
- (insert (format "%s " fn)))
- ;; The message.
- (insert (apply #'format-message fmt-string arguments))
- ;; Write message to debug file.
- (when tramp-debug-to-file
- (ignore-errors
- (write-region
- point (point-max) (tramp-get-debug-file-name vec) 'append)))))))
-
-(put #'tramp-debug-message 'tramp-suppress-trace t)
-
-;;;###tramp-autoload
-(defvar tramp-inhibit-progress-reporter nil
- "Show Tramp progress reporter in the minibuffer.
-This variable is used to disable concurrent progress reporter messages.")
-
-;;;###tramp-autoload
-(defsubst tramp-message (vec-or-proc level fmt-string &rest arguments)
- "Emit a message depending on verbosity level.
-VEC-OR-PROC identifies the Tramp buffer to use. It can be either a
-vector or a process. LEVEL says to be quiet if `tramp-verbose' is
-less than LEVEL. The message is emitted only if `tramp-verbose' is
-greater than or equal to LEVEL.
-
-The message is also logged into the debug buffer when `tramp-verbose'
-is greater than or equal 4.
-
-Calls functions `message' and `tramp-debug-message' with FMT-STRING as
-control string and the remaining ARGUMENTS to actually emit the message (if
-applicable)."
- (ignore-errors
- (when (<= level tramp-verbose)
- ;; Display only when there is a minimum level, and the progress
- ;; reporter doesn't suppress further messages.
- (when (and (<= level 3) (null tramp-inhibit-progress-reporter))
- (apply #'message
- (concat
- (cond
- ((= level 0) "")
- ((= level 1) "")
- ((= level 2) "Warning: ")
- (t "Tramp: "))
- fmt-string)
- arguments))
- ;; Log only when there is a minimum level.
- (when (>= tramp-verbose 4)
- (let ((tramp-verbose 0))
- ;; Append connection buffer for error messages, if exists.
- (when (= level 1)
- (ignore-errors
- (setq fmt-string (concat fmt-string "\n%s")
- arguments
- (append
- arguments
- `(,(tramp-get-buffer-string
- (if (processp vec-or-proc)
- (process-buffer vec-or-proc)
- (tramp-get-connection-buffer
- vec-or-proc 'dont-create))))))))
- ;; Translate proc to vec.
- (when (processp vec-or-proc)
- (setq vec-or-proc (process-get vec-or-proc 'tramp-vector))))
- ;; Do it.
- (when (tramp-file-name-p vec-or-proc)
- (apply #'tramp-debug-message
- vec-or-proc
- (concat (format "(%d) # " level) fmt-string)
- arguments))))))
-
-(defsubst tramp-backtrace (&optional vec-or-proc force)
- "Dump a backtrace into the debug buffer.
-If VEC-OR-PROC is nil, the buffer *debug tramp* is used. FORCE
-forces the backtrace even if `tramp-verbose' is less than 10.
-This function is meant for debugging purposes."
- (let ((tramp-verbose (if force 10 tramp-verbose)))
- (when (>= tramp-verbose 10)
- (if vec-or-proc
- (tramp-message
- vec-or-proc 10 "\n%s" (with-output-to-string (backtrace)))
- (with-output-to-temp-buffer "*debug tramp*" (backtrace))))))
-
-(defun tramp-error (vec-or-proc signal fmt-string &rest arguments)
- "Emit an error.
-VEC-OR-PROC identifies the connection to use, SIGNAL is the
-signal identifier to be raised, remaining arguments passed to
-`tramp-message'. Finally, signal SIGNAL is raised with
-FMT-STRING and ARGUMENTS."
- (let (signal-hook-function)
- (tramp-backtrace vec-or-proc)
- (unless arguments
- ;; FMT-STRING could be just a file name, as in
- ;; `file-already-exists' errors. It could contain the ?\%
- ;; character, as in smb domain spec.
- (setq arguments (list fmt-string)
- fmt-string "%s"))
- (when vec-or-proc
- (tramp-message
- vec-or-proc 1 "%s"
- (error-message-string
- (list signal
- (get signal 'error-message)
- (apply #'format-message fmt-string arguments)))))
- (signal signal (list (substring-no-properties
- (apply #'format-message fmt-string arguments))))))
-
-(put #'tramp-error 'tramp-suppress-trace t)
-
-(defvar tramp-error-show-message-timeout 30
- "Time to show the Tramp buffer in case of an error.
-If it is bound to nil, the buffer is not shown. This is used in
-tramp-tests.el.")
-
-(defsubst tramp-error-with-buffer
- (buf vec-or-proc signal fmt-string &rest arguments)
- "Emit an error, and show BUF.
-If BUF is nil, show the connection buf. Wait for 30\", or until
-an input event arrives. The other arguments are passed to `tramp-error'."
- (save-window-excursion
- (let* ((buf (or (and (bufferp buf) buf)
- (and (processp vec-or-proc) (process-buffer vec-or-proc))
- (and (tramp-file-name-p vec-or-proc)
- (tramp-get-connection-buffer vec-or-proc))))
- (vec (or (and (tramp-file-name-p vec-or-proc) vec-or-proc)
- (and buf (tramp-dissect-file-name
- (tramp-get-default-directory buf))))))
- (unwind-protect
- (apply #'tramp-error vec-or-proc signal fmt-string arguments)
- ;; Save exit.
- (when (and buf
- (natnump tramp-error-show-message-timeout)
- (not (zerop tramp-verbose))
- ;; Do not show when flagged from outside.
- (not non-essential)
- ;; Show only when Emacs has started already.
- (current-message))
- (let ((enable-recursive-minibuffers t)
- inhibit-message)
- ;; `tramp-error' does not show messages. So we must do it
- ;; ourselves.
- (apply #'message fmt-string arguments)
- ;; Show buffer.
- (pop-to-buffer buf)
- (discard-input)
- (sit-for tramp-error-show-message-timeout)))
- ;; Reset timestamp. It would be wrong after waiting for a while.
- (when (tramp-file-name-equal-p vec (car tramp-current-connection))
- (setcdr tramp-current-connection (current-time)))))))
-
-;; We must make it a defun, because it is used earlier already.
-(defun tramp-user-error (vec-or-proc fmt-string &rest arguments)
- "Signal a user error (or \"pilot error\")."
- (unwind-protect
- (apply #'tramp-error vec-or-proc 'user-error fmt-string arguments)
- ;; Save exit.
- (when (and (natnump tramp-error-show-message-timeout)
- (not (zerop tramp-verbose))
- ;; Do not show when flagged from outside.
- (not non-essential)
- ;; Show only when Emacs has started already.
- (current-message))
- (let ((enable-recursive-minibuffers t)
- inhibit-message)
- ;; `tramp-error' does not show messages. So we must do it ourselves.
- (apply #'message fmt-string arguments)
- (discard-input)
- (sit-for tramp-error-show-message-timeout)
- ;; Reset timestamp. It would be wrong after waiting for a while.
- (when
- (tramp-file-name-equal-p vec-or-proc (car tramp-current-connection))
- (setcdr tramp-current-connection (current-time)))))))
-
-(put #'tramp-user-error 'tramp-suppress-trace t)
-
-(defmacro tramp-with-demoted-errors (vec-or-proc format &rest body)
- "Execute BODY while redirecting the error message to `tramp-message'.
-BODY is executed like wrapped by `with-demoted-errors'. FORMAT
-is a format-string containing a %-sequence meaning to substitute
-the resulting error message."
- (declare (indent 2) (debug (symbolp form body)))
- (let ((err (make-symbol "err")))
- `(condition-case-unless-debug ,err
- (progn ,@body)
- (error (tramp-message ,vec-or-proc 3 ,format ,err) nil))))
-
;; This macro shall optimize the cases where a `file-exists-p' call is
;; invoked first. Often, the file exists, so the remote command is
;; superfluous.
(when (tramp-compat-string-search message (or (current-message) ""))
(progress-reporter-update reporter value suffix))))
+;;;###tramp-autoload
+(defvar tramp-inhibit-progress-reporter nil
+ "Show Tramp progress reporter in the minibuffer.
+This variable is used to disable concurrent progress reporter messages.")
+
(defmacro with-tramp-progress-reporter (vec level message &rest body)
"Execute BODY, spinning a progress reporter with MESSAGE in interactive mode.
If LEVEL does not fit for visible messages, there are only traces
tramp-compat-temporary-file-directory)
file-name-handler-alist)
(autoload-do-load sf foreign)))
- ;; (tramp-message
- ;; v 4 "Running `%s'..." (cons operation args))
- ;; 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.
- ;; 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 'non-essential
- (catch 'suppress
- (apply foreign operation args))))
- ;; (tramp-message
- ;; v 4 "Running `%s'...`%s'" (cons operation args) result)
+ (with-tramp-debug-message
+ v (format "Running `%S'" (cons operation args))
+ ;; 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.
+ ;; 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 'non-essential
+ (catch 'suppress
+ (apply foreign operation args)))))
(cond
((eq result 'non-essential)
(tramp-message
"Return a (user host) tuple allowed to access.
User is always nil."
(let (result)
- (when (re-search-forward regexp (line-end-position) t)
+ (when (search-forward-regexp regexp (line-end-position) t)
(setq result (list nil (match-string match-level))))
(or
(> (skip-chars-forward skip-chars) 0)
(rx
bol (group (regexp tramp-host-regexp))
(? (+ blank) (group (regexp tramp-user-regexp))))))
- (when (re-search-forward regexp (line-end-position) t)
+ (when (search-forward-regexp regexp (line-end-position) t)
(setq result (append (list (match-string 2) (match-string 1)))))
(forward-line 1)
result))
Host is always \"localhost\"."
(let (result
(regexp (rx bol (group (regexp tramp-user-regexp)) ":")))
- (when (re-search-forward regexp (line-end-position) t)
+ (when (search-forward-regexp regexp (line-end-position) t)
(setq result (list (match-string 1) "localhost")))
(forward-line 1)
result))
User is always nil."
(let (result
(regexp (rx (literal registry) "\\" (group (+ nonl)))))
- (when (re-search-forward regexp (line-end-position) t)
+ (when (search-forward-regexp regexp (line-end-position) t)
(setq result (list nil (match-string 1))))
(forward-line 1)
result))
(process-put proc 'adjust-window-size-function #'ignore)
(set-process-query-on-exit-flag proc nil)
(tramp-taint-remote-process-buffer (process-buffer proc))
- (tramp-message vec 6 "%s" (string-join (process-command proc) " ")))
+ (when (process-command proc)
+ (tramp-message vec 6 "%s" (string-join (process-command proc) " "))))
(put #'tramp-post-process-creation 'tramp-suppress-trace t)
((zerop (process-file "cat" nil '(t) nil "/proc/meminfo"))
(goto-char (point-min))
(when
- (re-search-forward
+ (search-forward-regexp
(rx bol "MemTotal:" (* space) (group (+ digit)) (* space) "kB" eol)
nil 'noerror)
(setcar (nthcdr 0 result) (string-to-number (match-string 1))))
(goto-char (point-min))
(when
- (re-search-forward
+ (search-forward-regexp
(rx bol "MemFree:" (* space) (group (+ digit)) (* space) "kB" eol)
nil 'noerror)
(setcar (nthcdr 1 result) (string-to-number (match-string 1))))
(goto-char (point-min))
(when
- (re-search-forward
+ (search-forward-regexp
(rx bol "SwapTotal:" (* space) (group (+ digit)) (* space) "kB" eol)
nil 'noerror)
(setcar (nthcdr 2 result) (string-to-number (match-string 1))))
(goto-char (point-min))
(when
- (re-search-forward
+ (search-forward-regexp
(rx bol "SwapFree:" (* space) (group (+ digit)) (* space) "kB" eol)
nil 'noerror)
(setcar (nthcdr 3 result) (string-to-number (match-string 1)))))
((zerop (process-file "sysctl" nil '(t) nil "-a"))
(goto-char (point-min))
(when
- (re-search-forward
+ (search-forward-regexp
(rx bol "hw.pagesize:" (* space) (group (+ digit)) eol)
nil 'noerror)
(let ((pagesize (string-to-number (match-string 1))))
(goto-char (point-min))
(when
- (re-search-forward
+ (search-forward-regexp
(rx bol "vm.stats.vm.v_page_count:" (* space)
(group (+ digit)) eol)
nil 'noerror)
(/ (* (string-to-number (match-string 1)) pagesize) 1024)))
(goto-char (point-min))
(when
- (re-search-forward
+ (search-forward-regexp
(rx bol "vm.stats.vm.v_free_count:" (* space)
(group (+ digit)) eol)
nil 'noerror)
(when (zerop (process-file "swapctl" nil '(t) nil "-sk"))
(goto-char (point-min))
(when
- (re-search-forward
+ (search-forward-regexp
(rx bol "Total:" (* space)
(group (+ digit)) (* space) (group (+ digit)) eol)
nil 'noerror)
;; This can be ignored.
(with-current-buffer (process-buffer proc)
(goto-char (point-min))
- (if (re-search-forward tramp-operation-not-permitted-regexp nil t)
+ (if (search-forward-regexp tramp-operation-not-permitted-regexp nil t)
(progn
(tramp-message vec 5 "'set mode' error ignored.")
(tramp-message vec 3 "Process has finished.")
;; Remove ANSI control escape sequences.
(with-current-buffer (tramp-get-connection-buffer vec)
(goto-char (point-min))
- (while (re-search-forward ansi-color-control-seq-regexp nil t)
+ (while (search-forward-regexp ansi-color-control-seq-regexp nil t)
(replace-match "")))
(setq todo actions)
(while todo
;; We restrict ourselves to the last 256 characters. There were
;; reports of a shell command "git ls-files -zco --exclude-standard"
;; with 85k files involved, which has blocked Tramp forever.
- (re-search-backward regexp (max (point-min) (- (point) 256)) 'noerror))
+ (search-backward-regexp regexp (max (point-min) (- (point) 256)) 'noerror))
(defun tramp-check-for-regexp (proc regexp)
"Check, whether REGEXP is contained in process buffer of PROC.
;; the echo mark regexp is taken for search. We restrict the
;; search for the second echo mark to PIPE_BUF characters.
(when (and (tramp-get-connection-property proc "check-remote-echo")
- (re-search-forward
+ (search-forward-regexp
tramp-echoed-echo-mark-regexp
(+ (point) (* 5 tramp-echo-mark-marker-length)) t))
(let ((begin (match-beginning 0)))
(when
- (re-search-forward
+ (search-forward-regexp
tramp-echoed-echo-mark-regexp
(+ (point) (tramp-get-connection-property proc "pipe-buf" 4096)) t)
;; Discard echo from remote output.
groups-integer groups-string)
(goto-char (point-min))
;; Read uid.
- (when (re-search-forward
+ (when (search-forward-regexp
(rx "uid=" (group (+ digit)) "(" (group (+ (any "_" word))) ")")
nil 'noerror)
(setq uid-integer (string-to-number (match-string 1))
uid-string (match-string 2)))
;; Read gid.
- (when (re-search-forward
+ (when (search-forward-regexp
(rx "gid=" (group (+ digit)) "(" (group (+ (any "_" word))) ")")
nil 'noerror)
(setq gid-integer (string-to-number (match-string 1))
gid-string (match-string 2)))
;; Read groups.
- (when (re-search-forward (rx "groups=") nil 'noerror)
+ (when (search-forward-regexp (rx "groups=") nil 'noerror)
(while (looking-at
(rx (group (+ digit)) "(" (group (+ (any "_" word))) ")"))
(setq groups-integer (cons (string-to-number (match-string 1))
(defconst tramp-bug-report-address "tramp-devel@gnu.org"
"Email address to send bug reports to.")
+;;;###tramp-autoload
(defconst tramp-repository-branch
(ignore-errors
;; Suppress message from `emacs-repository-get-branch'. We must
(emacs-repository-get-branch dir))))
"The repository branch of the Tramp sources.")
+;;;###tramp-autoload
(defconst tramp-repository-version
(ignore-errors
;; Suppress message from `emacs-repository-get-version'. We must
`should-error' is not handled properly. BODY shall not contain a timeout."
(declare (indent 1) (debug (natnump body)))
`(let* ((tramp-verbose (max (or ,verbose 0) (or tramp-verbose 0)))
- (trace-buffer (tramp-trace-buffer-name tramp-test-vec))
(debug-ignored-errors
(append
'("^make-symbolic-link not supported$"
"tramp-test*" ert-remote-temporary-file-directory)))
(goto-char (point-min))
(should
- (re-search-forward
+ (search-forward-regexp
(rx
(literal
(file-relative-name
tmp-name1 ert-remote-temporary-file-directory)))))
(goto-char (point-min))
(should
- (re-search-forward
+ (search-forward-regexp
(rx
(literal
(file-relative-name
"tramp-test*/*" ert-remote-temporary-file-directory)))
(goto-char (point-min))
(should
- (re-search-forward
+ (search-forward-regexp
(rx
(literal
(file-relative-name
tmp-name3 ert-remote-temporary-file-directory)))))
(goto-char (point-min))
(should
- (re-search-forward
+ (search-forward-regexp
(rx
(literal
(file-relative-name
"tramp-test*/*" ert-remote-temporary-file-directory)))
(goto-char (point-min))
(should
- (re-search-forward
+ (search-forward-regexp
(rx
(literal
(file-relative-name
tmp-name3 ert-remote-temporary-file-directory)))))
(goto-char (point-min))
(should
- (re-search-forward
+ (search-forward-regexp
(rx
(literal
(file-relative-name
;; We must remove leading `default-directory'.
(goto-char (point-min))
(let ((inhibit-read-only t))
- (while (re-search-forward "//" nil 'noerror)
+ (while (search-forward-regexp "//" nil 'noerror)
(delete-region (line-beginning-position) (point))))
(goto-char (point-min))
- (re-search-forward
+ (search-forward-regexp
(rx bol (0+ nonl)
(any "Pp") "ossible completions"
(0+ nonl) eol))
(if (bufferp destination) destination (current-buffer))
;; "ls" could produce colorized output.
(goto-char (point-min))
- (while (re-search-forward ansi-color-control-seq-regexp nil t)
+ (while (search-forward-regexp
+ ansi-color-control-seq-regexp nil t)
(replace-match "" nil nil))
(should
(string-equal (if destination (format "%s\n" fnnd) "")
(if (bufferp destination) destination (current-buffer))
;; "ls" could produce colorized output.
(goto-char (point-min))
- (while (re-search-forward ansi-color-control-seq-regexp nil t)
+ (while (search-forward-regexp
+ ansi-color-control-seq-regexp nil t)
(replace-match "" nil nil))
(should
(string-equal
(current-buffer))
;; "ls" could produce colorized output.
(goto-char (point-min))
- (while (re-search-forward ansi-color-control-seq-regexp nil t)
+ (while (search-forward-regexp ansi-color-control-seq-regexp nil t)
(replace-match "" nil nil))
(should
(string-equal
(should (zerop (process-file "printenv" nil t nil)))
(goto-char (point-min))
(should
- (re-search-forward
+ (search-forward-regexp
(rx
bol (literal envvar)
"=" (literal (getenv envvar)) eol))))))))