aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Albinus2020-08-25 15:18:57 +0200
committerMichael Albinus2020-08-25 15:18:57 +0200
commit4657f08b7eebf01159f7d7dba8bcb0d44d68ac48 (patch)
tree6cebb54d4c3f86285a94f127b8251eaec3a55871
parent44104a607aeb7fd73bf7edcbbe6a508eee36dd0f (diff)
downloademacs-4657f08b7eebf01159f7d7dba8bcb0d44d68ac48.tar.gz
emacs-4657f08b7eebf01159f7d7dba8bcb0d44d68ac48.zip
Sync with Tramp 2.4.5-pre
* doc/misc/tramp.texi: Adapt Tramp and Emacs version numbers. (Remote processes): Describe `process-file-return-signal-string' and $INSIDE_EMACS. (Frequently Asked Questions): Mention Emacs 28. Describe `tramp-smb-options'. * doc/misc/trampver.texi: Change version to "2.4.5-pre". * lisp/net/tramp-adb.el (process-file-return-signal-string): Declare. (tramp-adb-handle-write-region): Flush the cache after the file has been written. (tramp-adb-handle-set-file-modes, tramp-adb-handle-set-file-times): Add optional _FLAG. (tramp-adb-handle-copy-file, tramp-adb-handle-rename-file) (tramp-adb-handle-process-file): Use `tramp-file-local-name'. (tramp-adb-get-signal-strings): New defun. (tramp-adb-handle-process-file): Use it. (tramp-adb-handle-make-process): Implement `stderr'. Use `insert-file-contents-literally'. (tramp-adb-send-command-and-check): Add optional argument EXIT-STATUS. (tramp-adb-handle-process-file): Use it. * lisp/net/tramp-archive.el (tramp-archive-file-name-handler): Increase `max-specpdl-size' temporarily. * lisp/net/tramp-cache.el (top): Use `insert-file-contents-literally'. * lisp/net/tramp-cmds.el (tramp-rename-files): Use `tramp-file-local-name'. * lisp/net/tramp-gvfs.el (tramp-gvfs-enabled): Prevent crash for older Emacsen. (top): Adapt `tramp-gvfs-unload-hook'. (tramp-gvfs-handle-file-system-info): Fix error. (tramp-gvfs-handle-set-file-modes, tramp-gvfs-handle-set-file-times): Add optional _FLAG. * lisp/net/tramp-rclone.el (tramp-rclone-flush-directory-cache): Fix a problem with older Emacsen. * lisp/net/tramp-sh.el (process-file-return-signal-string): Declare. (tramp-sh-extra-args): Add "-noediting" as bash arg. (tramp-hexdump-encode, tramp-hexdump-awk-encode) (tramp-od-encode, tramp-od-awk-encode): New defconst. (tramp-awk-encode, tramp-awk-decode): Adapt. (tramp-awk-coding-test): Remove. (tramp-remote-coding-commands): Add hexdump/awk encoding. (Bug#35639) (tramp-find-inline-encoding): Adapt handling of awk, hexdump and od. (tramp-get-remote-busybox, tramp-get-remote-awk) (tramp-get-remote-hexdump, tramp-get-remote-od): New defuns. (tramp-sh-handle-make-symbolic-link): (tramp-do-copy-or-rename-file-directly) (tramp-sh-handle-process-file, tramp-set-remote-path) (tramp-find-inline-encoding, tramp-get-remote-touch): Use `tramp-file-local-name'. (tramp-do-file-attributes-with-stat): Simplify shell command. Suppress errors (interpret as nil). (tramp-sh-handle-set-file-modes, tramp-sh-handle-set-file-times): Add optional _FLAG. (tramp-sh-handle-make-process): Do not visit with `insert-file-contents'. Delete tmp file only if exists. Support `stderr' as file name. Delete temporary stderr file. Flush connection properties in time. (tramp-sh-get-signal-strings): New defun. (tramp-sh-handle-process-file): Use it. (tramp-sh-handle-write-region): Copy to temp file only if FILENAME exists. (Bug#40156) (tramp-set-remote-path): Send the command in several chunks if it is too large. (Bug#42538) (tramp-open-connection-setup-interactive-shell): Move up "set +o vi +o emacs" command. (Bug#39399) (tramp-send-command-and-read): Suppress `signal-hook-function' when reading expression. (tramp-send-command-and-check): Add optional argument EXIT-STATUS. (tramp-sh-handle-process-file): Use it. (Bug#41099) * lisp/net/tramp-smb.el (tramp-smb-conf): Fix docstring. (tramp-smb-options): New defcustom. (tramp-smb-handle-copy-directory, tramp-smb-handle-file-acl) (tramp-smb-handle-set-file-acl, tramp-smb-maybe-open-connection): Use it. (tramp-smb-errors): Add "NT_STATUS_INVALID_PARAMETER". (tramp-smb-handle-make-symbolic-link) (tramp-smb-handle-process-file): Use `tramp-file-local-name'. * lisp/net/tramp-sudoedit.el (tramp-sudoedit-do-copy-or-rename-file): (tramp-sudoedit-handle-set-file-uid-gid): Use `tramp-unquote-file-local-name'. (tramp-sudoedit-handle-make-symbolic-link): Use `tramp-file-local-name'. (tramp-sudoedit-handle-file-system-info): Fix a scoping error. (tramp-sudoedit-handle-set-file-modes): (tramp-sudoedit-handle-set-file-times): Add optional _FLAG. * lisp/net/tramp.el: Bump version to 2.4.5-pre. (tramp-file-local-name, tramp-unquote-file-local-name): New defuns. (tramp-set-connection-local-variables-for-buffer) (tramp-equal-remote, tramp-handle-make-auto-save-file-name): Use `tramp-tramp-file-p'. (tramp-parse-file): Use `insert-file-contents-literally'. (tramp-handle-file-modes, tramp-handle-file-times): Add optional _FLAG. (tramp-handle-shell-command): Fix `window-start' in output buffer. (Bug#39171) Handle `shell-command-dont-erase-buffer'. (Bug#39067) Reorganize error-buffer handling. Set `default-directory'. (Bug#39253) (tramp-handle-shell-command, tramp-handle-start-file-process): Implement asynchronous `error-buffer'. (tramp-action-process-alive): Read pending output. (tramp-read-passwd): Use `tramp-compat-temporary-file-directory'. (Bug#39389, Bug#39489) (tramp-interrupt-process): Improve command. * lisp/net/trampver.el: Change version to "2.4.5-pre". (tramp-repository-branch, tramp-repository-version): Bind `debug-on-error' to nil. * test/lisp/net/tramp-tests.el (tramp-get-remote-gid) (process-file-return-signal-string) (shell-command-dont-erase-buffer): Declare. (tramp-test10-write-region, tramp-test28-process-file) (tramp-test29-start-file-process, tramp-test30-make-process) (tramp-test31-interrupt-process, tramp-test32-shell-command): Extend test. (tramp-test10-write-region, tramp-test21-file-links): Use function symbols. (tramp-test18-file-attributes): Check `file-ownership-preserved-p' only if possible. (tramp--test-async-shell-command): New defun. (tramp--test-shell-command-to-string-asynchronously): Use it. (tramp-test32-shell-command-dont-erase-buffer): New test.
-rw-r--r--doc/misc/tramp.texi74
-rw-r--r--doc/misc/trampver.texi2
-rw-r--r--lisp/net/tramp-adb.el132
-rw-r--r--lisp/net/tramp-archive.el7
-rw-r--r--lisp/net/tramp-cache.el2
-rw-r--r--lisp/net/tramp-cmds.el2
-rw-r--r--lisp/net/tramp-compat.el1
-rw-r--r--lisp/net/tramp-gvfs.el22
-rw-r--r--lisp/net/tramp-rclone.el15
-rw-r--r--lisp/net/tramp-sh.el463
-rw-r--r--lisp/net/tramp-smb.el59
-rw-r--r--lisp/net/tramp-sudoedit.el17
-rw-r--r--lisp/net/tramp.el149
-rw-r--r--lisp/net/trampver.el6
-rw-r--r--test/lisp/net/tramp-tests.el568
15 files changed, 1103 insertions, 416 deletions
diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi
index c68b9aad528..97a26421f2f 100644
--- a/doc/misc/tramp.texi
+++ b/doc/misc/tramp.texi
@@ -318,14 +318,14 @@ behind the scenes when you open a file with @value{tramp}.
318@uref{https://ftp.gnu.org/gnu/tramp/}. The version number of 318@uref{https://ftp.gnu.org/gnu/tramp/}. The version number of
319@value{tramp} can be obtained by the variable @code{tramp-version}. 319@value{tramp} can be obtained by the variable @code{tramp-version}.
320For released @value{tramp} versions, this is a three-number string 320For released @value{tramp} versions, this is a three-number string
321like ``2.4.2''. 321like ``2.4.3''.
322 322
323A @value{tramp} release, which is packaged with Emacs, could differ 323A @value{tramp} release, which is packaged with Emacs, could differ
324slightly from the corresponding standalone release. This is because 324slightly from the corresponding standalone release. This is because
325it isn't always possible to synchronize release dates between Emacs 325it isn't always possible to synchronize release dates between Emacs
326and @value{tramp}. Such version numbers have the Emacs version number 326and @value{tramp}. Such version numbers have the Emacs version number
327as suffix, like ``2.3.5.26.3''. This means @value{tramp} 2.3.5 as 327as suffix, like ``2.4.3.27.1''. This means @value{tramp} 2.4.3 as
328integrated in Emacs 26.3. A complete list of @value{tramp} versions 328integrated in Emacs 27.1. A complete list of @value{tramp} versions
329packaged with Emacs can be retrieved by 329packaged with Emacs can be retrieved by
330 330
331@vindex customize-package-emacs-version-alist 331@vindex customize-package-emacs-version-alist
@@ -337,12 +337,12 @@ packaged with Emacs can be retrieved by
337ELPA} package. Besides the standalone releases, further minor version 337ELPA} package. Besides the standalone releases, further minor version
338of @value{tramp} will appear on GNU ELPA, until the next @value{tramp} 338of @value{tramp} will appear on GNU ELPA, until the next @value{tramp}
339release appears. These minor versions have a four-number string, like 339release appears. These minor versions have a four-number string, like
340``2.4.2.1''. 340``2.4.3.1''.
341 341
342@value{tramp} development versions are available on Git servers. 342@value{tramp} development versions are available on Git servers.
343Development versions contain new and incomplete features. The 343Development versions contain new and incomplete features. The
344development version of @value{tramp} is always the version number of 344development version of @value{tramp} is always the version number of
345the next release, plus the suffix ``-pre'', like ``2.4.3-pre''. 345the next release, plus the suffix ``-pre'', like ``2.4.4-pre''.
346 346
347One way to obtain @value{tramp} from Git server is to visit the 347One way to obtain @value{tramp} from Git server is to visit the
348Savannah project page at the following URL and then clicking on the 348Savannah project page at the following URL and then clicking on the
@@ -2299,7 +2299,7 @@ string of that environment variable looks always like
2299@example 2299@example
2300@group 2300@group
2301echo $INSIDE_EMACS 2301echo $INSIDE_EMACS
2302@result{} 26.2,tramp:2.3.4 2302@result{} 27.1,tramp:2.4.3
2303@end group 2303@end group
2304@end example 2304@end example
2305 2305
@@ -3034,6 +3034,17 @@ host when the variable @code{default-directory} is remote:
3034@end group 3034@end group
3035@end lisp 3035@end lisp
3036 3036
3037@vindex process-file-return-signal-string
3038@code{process-file} shall return either the exit code of the process,
3039or a string describing the signal, when the process has been
3040interrupted. Since it cannot be determined reliably whether a remote
3041process has been interrupted, @code{process-file} returns always the
3042exit code. When the user option
3043@code{process-file-return-signal-string} is non-nil,
3044@code{process-file} regards all exit codes greater than 128 as an
3045indication that the process has been interrupted, and returns a
3046respective string.
3047
3037Remote processes do not apply to @acronym{GVFS} (see @ref{GVFS-based 3048Remote processes do not apply to @acronym{GVFS} (see @ref{GVFS-based
3038methods}) because the remote file system is mounted on the local host 3049methods}) because the remote file system is mounted on the local host
3039and @value{tramp} just accesses by changing the 3050and @value{tramp} just accesses by changing the
@@ -3041,9 +3052,17 @@ and @value{tramp} just accesses by changing the
3041 3052
3042@value{tramp} starts a remote process when a command is executed in a 3053@value{tramp} starts a remote process when a command is executed in a
3043remote file or directory buffer. As of now, these packages have been 3054remote file or directory buffer. As of now, these packages have been
3044integrated to work with @value{tramp}: @file{compile.el} (commands 3055integrated to work with @value{tramp}: @file{shell.el},
3045like @code{compile} and @code{grep}) and @file{gud.el} (@code{gdb} or 3056@file{eshell.el}, @file{compile.el} (commands like @code{compile} and
3046@code{perldb}). 3057@code{grep}) and @file{gud.el} (@code{gdb} or @code{perldb}).
3058
3059@vindex INSIDE_EMACS@r{, environment variable}
3060@value{tramp} always modifies the @env{INSIDE_EMACS} environment
3061variable for remote processes. Per default, this environment variable
3062shows the Emacs version. @value{tramp} adds its own version string,
3063so it looks like @samp{27.1,tramp:2.4.3.1}. However, other packages
3064might also add their name to this environment variable, like
3065@samp{27.1,comint,tramp:2.4.3.1}.
3047 3066
3048For @value{tramp} to find the command on the remote, it must be 3067For @value{tramp} to find the command on the remote, it must be
3049accessible through the default search path as setup by @value{tramp} 3068accessible through the default search path as setup by @value{tramp}
@@ -3238,10 +3257,10 @@ variables.
3238@vindex async-shell-command-width 3257@vindex async-shell-command-width
3239@vindex COLUMNS@r{, environment variable} 3258@vindex COLUMNS@r{, environment variable}
3240If Emacs supports the variable @code{async-shell-command-width} (since 3259If Emacs supports the variable @code{async-shell-command-width} (since
3241Emacs 27.1), @value{tramp} cares about its value for asynchronous 3260Emacs 27), @value{tramp} cares about its value for asynchronous shell
3242shell commands. It specifies the number of display columns for 3261commands. It specifies the number of display columns for command
3243command output. For synchronous shell commands, a similar effect can 3262output. For synchronous shell commands, a similar effect can be
3244be achieved by adding the environment variable @env{COLUMNS} to 3263achieved by adding the environment variable @env{COLUMNS} to
3245@code{tramp-remote-process-environment}. 3264@code{tramp-remote-process-environment}.
3246 3265
3247 3266
@@ -3725,7 +3744,7 @@ row are possible, like @file{/path/to/dir/file.tar.gz.uu/dir/file}.
3725 3744
3726@vindex tramp-archive-all-gvfs-methods 3745@vindex tramp-archive-all-gvfs-methods
3727An archive file name could be a remote file name, as in 3746An archive file name could be a remote file name, as in
3728@file{/ftp:anonymous@@ftp.gnu.org:/gnu/tramp/tramp-2.3.2.tar.gz/INSTALL}. 3747@file{/ftp:anonymous@@ftp.gnu.org:/gnu/tramp/tramp-2.4.3.tar.gz/INSTALL}.
3729Since all file operations are mapped internally to @acronym{GVFS} 3748Since all file operations are mapped internally to @acronym{GVFS}
3730operations, remote file names supported by @code{tramp-gvfs} perform 3749operations, remote file names supported by @code{tramp-gvfs} perform
3731better, because no local copy of the file archive must be downloaded 3750better, because no local copy of the file archive must be downloaded
@@ -3736,7 +3755,7 @@ the similar @samp{/scp:user@@host:...}. See the constant
3736 3755
3737If @code{url-handler-mode} is enabled, archives could be visited via 3756If @code{url-handler-mode} is enabled, archives could be visited via
3738URLs, like 3757URLs, like
3739@file{https://ftp.gnu.org/gnu/tramp/tramp-2.3.2.tar.gz/INSTALL}. This 3758@file{https://ftp.gnu.org/gnu/tramp/tramp-2.4.3.tar.gz/INSTALL}. This
3740allows complex file operations like 3759allows complex file operations like
3741 3760
3742@lisp 3761@lisp
@@ -3744,8 +3763,8 @@ allows complex file operations like
3744(progn 3763(progn
3745 (url-handler-mode 1) 3764 (url-handler-mode 1)
3746 (ediff-directories 3765 (ediff-directories
3747 "https://ftp.gnu.org/gnu/tramp/tramp-2.3.1.tar.gz/tramp-2.3.1" 3766 "https://ftp.gnu.org/gnu/tramp/tramp-2.4.2.tar.gz/tramp-2.4.2"
3748 "https://ftp.gnu.org/gnu/tramp/tramp-2.3.2.tar.gz/tramp-2.3.2" "")) 3767 "https://ftp.gnu.org/gnu/tramp/tramp-2.4.3.tar.gz/tramp-2.4.3" ""))
3749@end group 3768@end group
3750@end lisp 3769@end lisp
3751 3770
@@ -3860,8 +3879,8 @@ Where is the latest @value{tramp}?
3860@item 3879@item
3861Which systems does it work on? 3880Which systems does it work on?
3862 3881
3863The package works successfully on Emacs 24, Emacs 25, Emacs 26, and 3882The package works successfully on Emacs 24, Emacs 25, Emacs 26, Emacs
3864Emacs 27. 388327, and Emacs 28.
3865 3884
3866While Unix and Unix-like systems are the primary remote targets, 3885While Unix and Unix-like systems are the primary remote targets,
3867@value{tramp} has equal success connecting to other platforms, such as 3886@value{tramp} has equal success connecting to other platforms, such as
@@ -4128,6 +4147,23 @@ your proxy host.
4128 4147
4129 4148
4130@item 4149@item
4150@value{tramp} does not connect to Samba or MS Windows hosts running
4151SMB1 connection protocol.
4152
4153@vindex tramp-smb-options
4154Recent versions of @command{smbclient} do not support old connection
4155protocols by default. In order to connect to such a host, add a
4156respective option:
4157
4158@lisp
4159(add-to-list 'tramp-smb-options "client min protocol=NT1")
4160@end lisp
4161
4162@strong{Note} that using a deprecated connection protocol raises
4163security problems, you should do it only if absolutely necessary.
4164
4165
4166@item
4131File name completion does not work with @value{tramp} 4167File name completion does not work with @value{tramp}
4132 4168
4133@acronym{ANSI} escape sequences from the remote shell may cause errors 4169@acronym{ANSI} escape sequences from the remote shell may cause errors
diff --git a/doc/misc/trampver.texi b/doc/misc/trampver.texi
index 478ec7037a8..cc3c768fe6e 100644
--- a/doc/misc/trampver.texi
+++ b/doc/misc/trampver.texi
@@ -8,7 +8,7 @@
8@c In the Tramp GIT, the version numbers are auto-frobbed from 8@c In the Tramp GIT, the version numbers are auto-frobbed from
9@c tramp.el, and the bug report address is auto-frobbed from 9@c tramp.el, and the bug report address is auto-frobbed from
10@c configure.ac. 10@c configure.ac.
11@set trampver 2.4.3.27.1 11@set trampver 2.4.5-pre
12@set tramp-bug-report-address tramp-devel@@gnu.org 12@set tramp-bug-report-address tramp-devel@@gnu.org
13@set emacsver 24.4 13@set emacsver 24.4
14 14
diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el
index 5cfcb81708f..0efe055b084 100644
--- a/lisp/net/tramp-adb.el
+++ b/lisp/net/tramp-adb.el
@@ -35,6 +35,8 @@
35 35
36(require 'tramp) 36(require 'tramp)
37 37
38(defvar process-file-return-signal-string)
39
38;;;###tramp-autoload 40;;;###tramp-autoload
39(defcustom tramp-adb-program "adb" 41(defcustom tramp-adb-program "adb"
40 "Name of the Android Debug Bridge program." 42 "Name of the Android Debug Bridge program."
@@ -631,9 +633,6 @@ But handle the case, if the \"test\" command is not available."
631 (format "File %s exists; overwrite anyway? " filename))))) 633 (format "File %s exists; overwrite anyway? " filename)))))
632 (tramp-error v 'file-already-exists filename)) 634 (tramp-error v 'file-already-exists filename))
633 635
634 ;; We must also flush the cache of the directory, because
635 ;; `file-attributes' reads the values from there.
636 (tramp-flush-file-properties v localname)
637 (let* ((curbuf (current-buffer)) 636 (let* ((curbuf (current-buffer))
638 (tmpfile (tramp-compat-make-temp-file filename))) 637 (tmpfile (tramp-compat-make-temp-file filename)))
639 (when (and append (file-exists-p filename)) 638 (when (and append (file-exists-p filename))
@@ -650,6 +649,10 @@ But handle the case, if the \"test\" command is not available."
650 (tramp-error v 'file-error "Cannot write: `%s'" filename)) 649 (tramp-error v 'file-error "Cannot write: `%s'" filename))
651 (delete-file tmpfile))) 650 (delete-file tmpfile)))
652 651
652 ;; We must also flush the cache of the directory, because
653 ;; `file-attributes' reads the values from there.
654 (tramp-flush-file-properties v localname)
655
653 (unless (equal curbuf (current-buffer)) 656 (unless (equal curbuf (current-buffer))
654 (tramp-error 657 (tramp-error
655 v 'file-error 658 v 'file-error
@@ -667,13 +670,13 @@ But handle the case, if the \"test\" command is not available."
667 (tramp-message v 0 "Wrote %s" filename)) 670 (tramp-message v 0 "Wrote %s" filename))
668 (run-hooks 'tramp-handle-write-region-hook)))) 671 (run-hooks 'tramp-handle-write-region-hook))))
669 672
670(defun tramp-adb-handle-set-file-modes (filename mode) 673(defun tramp-adb-handle-set-file-modes (filename mode &optional _flag)
671 "Like `set-file-modes' for Tramp files." 674 "Like `set-file-modes' for Tramp files."
672 (with-parsed-tramp-file-name filename nil 675 (with-parsed-tramp-file-name filename nil
673 (tramp-flush-file-properties v localname) 676 (tramp-flush-file-properties v localname)
674 (tramp-adb-send-command-and-check v (format "chmod %o %s" mode localname)))) 677 (tramp-adb-send-command-and-check v (format "chmod %o %s" mode localname))))
675 678
676(defun tramp-adb-handle-set-file-times (filename &optional time) 679(defun tramp-adb-handle-set-file-times (filename &optional time _flag)
677 "Like `set-file-times' for Tramp files." 680 "Like `set-file-times' for Tramp files."
678 (with-parsed-tramp-file-name filename nil 681 (with-parsed-tramp-file-name filename nil
679 (tramp-flush-file-properties v localname) 682 (tramp-flush-file-properties v localname)
@@ -725,8 +728,8 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
725 (with-tramp-progress-reporter 728 (with-tramp-progress-reporter
726 v 0 (format "Copying %s to %s" filename newname) 729 v 0 (format "Copying %s to %s" filename newname)
727 (if (and t1 t2 (tramp-equal-remote filename newname)) 730 (if (and t1 t2 (tramp-equal-remote filename newname))
728 (let ((l1 (tramp-compat-file-local-name filename)) 731 (let ((l1 (tramp-file-local-name filename))
729 (l2 (tramp-compat-file-local-name newname))) 732 (l2 (tramp-file-local-name newname)))
730 ;; We must also flush the cache of the directory, 733 ;; We must also flush the cache of the directory,
731 ;; because `file-attributes' reads the values from 734 ;; because `file-attributes' reads the values from
732 ;; there. 735 ;; there.
@@ -809,8 +812,8 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
809 (if (and t1 t2 812 (if (and t1 t2
810 (tramp-equal-remote filename newname) 813 (tramp-equal-remote filename newname)
811 (not (file-directory-p filename))) 814 (not (file-directory-p filename)))
812 (let ((l1 (tramp-compat-file-local-name filename)) 815 (let ((l1 (tramp-file-local-name filename))
813 (l2 (tramp-compat-file-local-name newname))) 816 (l2 (tramp-file-local-name newname)))
814 ;; We must also flush the cache of the directory, because 817 ;; We must also flush the cache of the directory, because
815 ;; `file-attributes' reads the values from there. 818 ;; `file-attributes' reads the values from there.
816 (tramp-flush-file-properties v l1) 819 (tramp-flush-file-properties v l1)
@@ -828,6 +831,33 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
828 filename newname ok-if-already-exists 'keep-time 'preserve-uid-gid) 831 filename newname ok-if-already-exists 'keep-time 'preserve-uid-gid)
829 (delete-file filename))))))) 832 (delete-file filename)))))))
830 833
834(defun tramp-adb-get-signal-strings (vec)
835 "Strings to return by `process-file' in case of signals."
836 (with-tramp-connection-property vec "signal-strings"
837 (let ((default-directory (tramp-make-tramp-file-name vec 'localname))
838 ;; `shell-file-name' and `shell-command-switch' are needed
839 ;; for Emacs < 27.1, which doesn't support connection-local
840 ;; variables in `shell-command'.
841 (shell-file-name "/system/bin/sh")
842 (shell-command-switch "-c")
843 process-file-return-signal-string signals result)
844 (dotimes (i 128) (push (format "Signal %d" i) result))
845 (setq result (reverse result)
846 signals (split-string
847 (shell-command-to-string "COLUMNS=40 kill -l") "\n" 'omit))
848 (setcar result 0)
849 (dolist (line signals)
850 (when (string-match
851 (concat
852 "^[[:space:]]*\\([[:digit:]]+\\)"
853 "[[:space:]]+\\S-+[[:space:]]+"
854 "\\([[:alpha:]].*\\)$")
855 line)
856 (setcar
857 (nthcdr (string-to-number (match-string 1 line)) result)
858 (match-string 2 line))))
859 result)))
860
831(defun tramp-adb-handle-process-file 861(defun tramp-adb-handle-process-file
832 (program &optional infile destination display &rest args) 862 (program &optional infile destination display &rest args)
833 "Like `process-file' for Tramp files." 863 "Like `process-file' for Tramp files."
@@ -846,7 +876,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
846 (setq infile (expand-file-name infile)) 876 (setq infile (expand-file-name infile))
847 (if (tramp-equal-remote default-directory infile) 877 (if (tramp-equal-remote default-directory infile)
848 ;; INFILE is on the same remote host. 878 ;; INFILE is on the same remote host.
849 (setq input (with-parsed-tramp-file-name infile nil localname)) 879 (setq input (tramp-file-local-name infile))
850 ;; INFILE must be copied to remote host. 880 ;; INFILE must be copied to remote host.
851 (setq input (tramp-make-tramp-temp-file v) 881 (setq input (tramp-make-tramp-temp-file v)
852 tmpinput (tramp-make-tramp-file-name v input)) 882 tmpinput (tramp-make-tramp-file-name v input))
@@ -877,8 +907,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
877 (setcar (cdr destination) (expand-file-name (cadr destination))) 907 (setcar (cdr destination) (expand-file-name (cadr destination)))
878 (if (tramp-equal-remote default-directory (cadr destination)) 908 (if (tramp-equal-remote default-directory (cadr destination))
879 ;; stderr is on the same remote host. 909 ;; stderr is on the same remote host.
880 (setq stderr (with-parsed-tramp-file-name 910 (setq stderr (tramp-file-local-name (cadr destination)))
881 (cadr destination) nil localname))
882 ;; stderr must be copied to remote host. The temporary 911 ;; stderr must be copied to remote host. The temporary
883 ;; file must be deleted after execution. 912 ;; file must be deleted after execution.
884 (setq stderr (tramp-make-tramp-temp-file v) 913 (setq stderr (tramp-make-tramp-temp-file v)
@@ -895,14 +924,13 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
895 ;; it. Call it in a subshell, in order to preserve working 924 ;; it. Call it in a subshell, in order to preserve working
896 ;; directory. 925 ;; directory.
897 (condition-case nil 926 (condition-case nil
898 (progn 927 (unwind-protect
899 (setq ret 928 (setq ret (tramp-adb-send-command-and-check
900 (if (tramp-adb-send-command-and-check 929 v (format
901 v 930 "(cd %s; %s)"
902 (format "(cd %s; %s)" 931 (tramp-shell-quote-argument localname) command)
903 (tramp-shell-quote-argument localname) command)) 932 t))
904 ;; Set return status accordingly. 933 (unless (natnump ret) (setq ret 1))
905 0 1))
906 ;; We should add the output anyway. 934 ;; We should add the output anyway.
907 (when outbuf 935 (when outbuf
908 (with-current-buffer outbuf 936 (with-current-buffer outbuf
@@ -918,6 +946,12 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
918 (kill-buffer (tramp-get-connection-buffer v)) 946 (kill-buffer (tramp-get-connection-buffer v))
919 (setq ret 1))) 947 (setq ret 1)))
920 948
949 ;; Handle signals. `process-file-return-signal-string' exists
950 ;; since Emacs 28.1.
951 (when (and (bound-and-true-p process-file-return-signal-string)
952 (natnump ret) (> ret 128))
953 (setq ret (nth (- ret 128) (tramp-adb-get-signal-strings v))))
954
921 ;; Provide error file. 955 ;; Provide error file.
922 (when tmpstderr (rename-file tmpstderr (cadr destination) t)) 956 (when tmpstderr (rename-file tmpstderr (cadr destination) t))
923 957
@@ -936,6 +970,8 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
936;; We use BUFFER also as connection buffer during setup. Because of 970;; We use BUFFER also as connection buffer during setup. Because of
937;; this, its original contents must be saved, and restored once 971;; this, its original contents must be saved, and restored once
938;; connection has been setup. 972;; connection has been setup.
973;; The complete STDERR buffer is available only when the process has
974;; terminated.
939(defun tramp-adb-handle-make-process (&rest args) 975(defun tramp-adb-handle-make-process (&rest args)
940 "Like `make-process' for Tramp files." 976 "Like `make-process' for Tramp files."
941 (when args 977 (when args
@@ -969,17 +1005,29 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
969 (signal 'wrong-type-argument (list #'functionp sentinel))) 1005 (signal 'wrong-type-argument (list #'functionp sentinel)))
970 (unless (or (null stderr) (bufferp stderr) (stringp stderr)) 1006 (unless (or (null stderr) (bufferp stderr) (stringp stderr))
971 (signal 'wrong-type-argument (list #'stringp stderr))) 1007 (signal 'wrong-type-argument (list #'stringp stderr)))
1008 (when (and (stringp stderr) (tramp-tramp-file-p stderr)
1009 (not (tramp-equal-remote default-directory stderr)))
1010 (signal 'file-error (list "Wrong stderr" stderr)))
972 1011
973 (let* ((buffer 1012 (let* ((buffer
974 (if buffer 1013 (if buffer
975 (get-buffer-create buffer) 1014 (get-buffer-create buffer)
976 ;; BUFFER can be nil. We use a temporary buffer. 1015 ;; BUFFER can be nil. We use a temporary buffer.
977 (generate-new-buffer tramp-temp-buffer-name))) 1016 (generate-new-buffer tramp-temp-buffer-name)))
1017 ;; STDERR can also be a file name.
1018 (tmpstderr
1019 (and stderr
1020 (if (and (stringp stderr) (tramp-tramp-file-p stderr))
1021 (tramp-unquote-file-local-name stderr)
1022 (tramp-make-tramp-temp-file v))))
1023 (remote-tmpstderr
1024 (and tmpstderr (tramp-make-tramp-file-name v tmpstderr)))
978 (program (car command)) 1025 (program (car command))
979 (args (cdr command)) 1026 (args (cdr command))
980 (command 1027 (command
981 (format "cd %s && exec %s" 1028 (format "cd %s && exec %s %s"
982 (tramp-shell-quote-argument localname) 1029 (tramp-shell-quote-argument localname)
1030 (if tmpstderr (format "2>'%s'" tmpstderr) "")
983 (mapconcat #'tramp-shell-quote-argument 1031 (mapconcat #'tramp-shell-quote-argument
984 (cons program args) " "))) 1032 (cons program args) " ")))
985 (tramp-process-connection-type 1033 (tramp-process-connection-type
@@ -1029,6 +1077,18 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
1029 (ignore-errors 1077 (ignore-errors
1030 (set-process-query-on-exit-flag p (null noquery)) 1078 (set-process-query-on-exit-flag p (null noquery))
1031 (set-marker (process-mark p) (point))) 1079 (set-marker (process-mark p) (point)))
1080 ;; We must flush them here already; otherwise
1081 ;; `rename-file', `delete-file' or
1082 ;; `insert-file-contents' will fail.
1083 (tramp-flush-connection-property v "process-name")
1084 (tramp-flush-connection-property v "process-buffer")
1085 ;; Copy tmpstderr file.
1086 (when (and (stringp stderr)
1087 (not (tramp-tramp-file-p stderr)))
1088 (add-function
1089 :after (process-sentinel p)
1090 (lambda (_proc _msg)
1091 (rename-file remote-tmpstderr stderr))))
1032 ;; Read initial output. Remove the first line, 1092 ;; Read initial output. Remove the first line,
1033 ;; which is the command echo. 1093 ;; which is the command echo.
1034 (while 1094 (while
@@ -1037,6 +1097,23 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
1037 (not (re-search-forward "[\n]" nil t))) 1097 (not (re-search-forward "[\n]" nil t)))
1038 (tramp-accept-process-output p 0)) 1098 (tramp-accept-process-output p 0))
1039 (delete-region (point-min) (point)) 1099 (delete-region (point-min) (point))
1100 ;; Provide error buffer. This shows only
1101 ;; initial error messages; messages arriving
1102 ;; later on will be inserted when the process
1103 ;; is deleted. The temporary file will exist
1104 ;; until the process is deleted.
1105 (when (bufferp stderr)
1106 (with-current-buffer stderr
1107 (insert-file-contents-literally
1108 remote-tmpstderr 'visit))
1109 ;; Delete tmpstderr file.
1110 (add-function
1111 :after (process-sentinel p)
1112 (lambda (_proc _msg)
1113 (with-current-buffer stderr
1114 (insert-file-contents-literally
1115 remote-tmpstderr 'visit nil nil 'replace))
1116 (delete-file remote-tmpstderr))))
1040 ;; Return process. 1117 ;; Return process.
1041 p)))) 1118 p))))
1042 1119
@@ -1062,7 +1139,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
1062 (read (current-buffer))) 1139 (read (current-buffer)))
1063 ":" 'omit))) 1140 ":" 'omit)))
1064 ;; The equivalent to `exec-directory'. 1141 ;; The equivalent to `exec-directory'.
1065 `(,(tramp-compat-file-local-name default-directory)))) 1142 `(,(tramp-file-local-name (expand-file-name default-directory)))))
1066 1143
1067(defun tramp-adb-get-device (vec) 1144(defun tramp-adb-get-device (vec)
1068 "Return full host name from VEC to be used in shell execution. 1145 "Return full host name from VEC to be used in shell execution.
@@ -1146,11 +1223,14 @@ This happens for Android >= 4.0."
1146 (while (re-search-forward "\r+$" nil t) 1223 (while (re-search-forward "\r+$" nil t)
1147 (replace-match "" nil nil)))))) 1224 (replace-match "" nil nil))))))
1148 1225
1149(defun tramp-adb-send-command-and-check (vec command) 1226(defun tramp-adb-send-command-and-check (vec command &optional exit-status)
1150 "Run COMMAND and check its exit status. 1227 "Run COMMAND and check its exit status.
1151Sends `echo $?' along with the COMMAND for checking the exit 1228Sends `echo $?' along with the COMMAND for checking the exit
1152status. If COMMAND is nil, just sends `echo $?'. Returns nil if 1229status. If COMMAND is nil, just sends `echo $?'. Returns nil if
1153the exit status is not equal 0, and t otherwise." 1230the exit status is not equal 0, and t otherwise.
1231
1232Optional argument EXIT-STATUS, if non-nil, triggers the return of
1233the exit status."
1154 (tramp-adb-send-command 1234 (tramp-adb-send-command
1155 vec (if command 1235 vec (if command
1156 (format "%s; echo tramp_exit_status $?" command) 1236 (format "%s; echo tramp_exit_status $?" command)
@@ -1161,7 +1241,9 @@ the exit status is not equal 0, and t otherwise."
1161 vec 'file-error "Couldn't find exit status of `%s'" command)) 1241 vec 'file-error "Couldn't find exit status of `%s'" command))
1162 (skip-chars-forward "^ ") 1242 (skip-chars-forward "^ ")
1163 (prog1 1243 (prog1
1164 (zerop (read (current-buffer))) 1244 (if exit-status
1245 (read (current-buffer))
1246 (zerop (read (current-buffer))))
1165 (let ((inhibit-read-only t)) 1247 (let ((inhibit-read-only t))
1166 (delete-region (match-beginning 0) (point-max)))))) 1248 (delete-region (match-beginning 0) (point-max))))))
1167 1249
diff --git a/lisp/net/tramp-archive.el b/lisp/net/tramp-archive.el
index b9bf6180a5d..611247ef2cb 100644
--- a/lisp/net/tramp-archive.el
+++ b/lisp/net/tramp-archive.el
@@ -109,7 +109,7 @@
109 109
110(eval-when-compile (require 'cl-lib)) 110(eval-when-compile (require 'cl-lib))
111;; Sometimes, compilation fails with "Variable binding depth exceeds 111;; Sometimes, compilation fails with "Variable binding depth exceeds
112;; max-specpdl-size". 112;; max-specpdl-size". Shall be fixed in Emacs 27.
113(eval-and-compile 113(eval-and-compile
114 (let ((max-specpdl-size (* 2 max-specpdl-size))) (require 'tramp-gvfs))) 114 (let ((max-specpdl-size (* 2 max-specpdl-size))) (require 'tramp-gvfs)))
115 115
@@ -318,7 +318,10 @@ arguments to pass to the OPERATION."
318 318
319 (let* ((filename (apply #'tramp-archive-file-name-for-operation 319 (let* ((filename (apply #'tramp-archive-file-name-for-operation
320 operation args)) 320 operation args))
321 (archive (tramp-archive-file-name-archive filename))) 321 (archive (tramp-archive-file-name-archive filename))
322 ;; Sometimes, it fails with "Variable binding depth exceeds
323 ;; max-specpdl-size". Shall be fixed in Emacs 27.
324 (max-specpdl-size (* 2 max-specpdl-size)))
322 325
323 ;; `filename' could be a quoted file name. Or the file 326 ;; `filename' could be a quoted file name. Or the file
324 ;; archive could be a directory, see Bug#30293. 327 ;; archive could be a directory, see Bug#30293.
diff --git a/lisp/net/tramp-cache.el b/lisp/net/tramp-cache.el
index 62e25fa1f08..0f2d7a1800f 100644
--- a/lisp/net/tramp-cache.el
+++ b/lisp/net/tramp-cache.el
@@ -514,7 +514,7 @@ for all methods. Resulting data are derived from connection history."
514 tramp-cache-read-persistent-data) 514 tramp-cache-read-persistent-data)
515 (condition-case err 515 (condition-case err
516 (with-temp-buffer 516 (with-temp-buffer
517 (insert-file-contents tramp-persistency-file-name) 517 (insert-file-contents-literally tramp-persistency-file-name)
518 (let ((list (read (current-buffer))) 518 (let ((list (read (current-buffer)))
519 (tramp-verbose 0) 519 (tramp-verbose 0)
520 element key item) 520 element key item)
diff --git a/lisp/net/tramp-cmds.el b/lisp/net/tramp-cmds.el
index 9d1025b9072..b4dca2321c1 100644
--- a/lisp/net/tramp-cmds.el
+++ b/lisp/net/tramp-cmds.el
@@ -358,7 +358,7 @@ The remote connection identified by SOURCE is flushed by
358 358
359 ;; Append local file name if none is specified. 359 ;; Append local file name if none is specified.
360 (when (string-equal (file-remote-p target) target) 360 (when (string-equal (file-remote-p target) target)
361 (setq target (concat target (file-remote-p source 'localname)))) 361 (setq target (concat target (tramp-file-local-name source))))
362 ;; Make them directory names. 362 ;; Make them directory names.
363 (setq source (directory-file-name source) 363 (setq source (directory-file-name source)
364 target (directory-file-name target)) 364 target (directory-file-name target))
diff --git a/lisp/net/tramp-compat.el b/lisp/net/tramp-compat.el
index 723b8cfa1e3..3f25afedb99 100644
--- a/lisp/net/tramp-compat.el
+++ b/lisp/net/tramp-compat.el
@@ -41,6 +41,7 @@
41(require 'shell) 41(require 'shell)
42(require 'subr-x) 42(require 'subr-x)
43 43
44;; `temporary-file-directory' as function is introduced with Emacs 26.1.
44(declare-function tramp-handle-temporary-file-directory "tramp") 45(declare-function tramp-handle-temporary-file-directory "tramp")
45 46
46;; For not existing functions, obsolete functions, or functions with a 47;; For not existing functions, obsolete functions, or functions with a
diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el
index 34a234c47f0..ddb535fea6e 100644
--- a/lisp/net/tramp-gvfs.el
+++ b/lisp/net/tramp-gvfs.el
@@ -121,7 +121,10 @@
121 (autoload 'zeroconf-init "zeroconf") 121 (autoload 'zeroconf-init "zeroconf")
122 (tramp-compat-funcall 'dbus-get-unique-name :system) 122 (tramp-compat-funcall 'dbus-get-unique-name :system)
123 (tramp-compat-funcall 'dbus-get-unique-name :session) 123 (tramp-compat-funcall 'dbus-get-unique-name :session)
124 (or (tramp-compat-process-running-p "gvfs-fuse-daemon") 124 (or ;; Until Emacs 25, `process-attributes' could crash Emacs
125 ;; for some processes. Better we don't check.
126 (<= emacs-major-version 25)
127 (tramp-compat-process-running-p "gvfs-fuse-daemon")
125 (tramp-compat-process-running-p "gvfsd-fuse")))) 128 (tramp-compat-process-running-p "gvfsd-fuse"))))
126 "Non-nil when GVFS is available.") 129 "Non-nil when GVFS is available.")
127 130
@@ -728,6 +731,10 @@ is no information where to trace the message.")
728 (tramp-error tramp-gvfs-dbus-event-vector 'file-error "%s" (cadr err)))) 731 (tramp-error tramp-gvfs-dbus-event-vector 'file-error "%s" (cadr err))))
729 732
730(add-hook 'dbus-event-error-functions #'tramp-gvfs-dbus-event-error) 733(add-hook 'dbus-event-error-functions #'tramp-gvfs-dbus-event-error)
734(add-hook
735 'tramp-gvfs-unload-hook
736 (lambda ()
737 (remove-hook 'dbus-event-error-functions #'tramp-gvfs-dbus-event-error)))
731 738
732 739
733;; File name primitives. 740;; File name primitives.
@@ -1301,10 +1308,11 @@ If FILE-SYSTEM is non-nil, return file system attributes."
1301 (size (cdr (assoc "filesystem::size" attr))) 1308 (size (cdr (assoc "filesystem::size" attr)))
1302 (used (cdr (assoc "filesystem::used" attr))) 1309 (used (cdr (assoc "filesystem::used" attr)))
1303 (free (cdr (assoc "filesystem::free" attr)))) 1310 (free (cdr (assoc "filesystem::free" attr))))
1304 (when (and (stringp size) (stringp used) (stringp free)) 1311 (when (or size used free)
1305 (list (string-to-number size) 1312 (list (string-to-number (or size "0"))
1306 (- (string-to-number size) (string-to-number used)) 1313 (string-to-number (or free "0"))
1307 (string-to-number free)))))) 1314 (- (string-to-number (or size "0"))
1315 (string-to-number (or used "0"))))))))
1308 1316
1309(defun tramp-gvfs-handle-make-directory (dir &optional parents) 1317(defun tramp-gvfs-handle-make-directory (dir &optional parents)
1310 "Like `make-directory' for Tramp files." 1318 "Like `make-directory' for Tramp files."
@@ -1341,7 +1349,7 @@ If FILE-SYSTEM is non-nil, return file system attributes."
1341 (tramp-run-real-handler 1349 (tramp-run-real-handler
1342 #'rename-file (list filename newname ok-if-already-exists)))) 1350 #'rename-file (list filename newname ok-if-already-exists))))
1343 1351
1344(defun tramp-gvfs-handle-set-file-modes (filename mode) 1352(defun tramp-gvfs-handle-set-file-modes (filename mode &optional _flag)
1345 "Like `set-file-modes' for Tramp files." 1353 "Like `set-file-modes' for Tramp files."
1346 (with-parsed-tramp-file-name filename nil 1354 (with-parsed-tramp-file-name filename nil
1347 (tramp-flush-file-properties v localname) 1355 (tramp-flush-file-properties v localname)
@@ -1350,7 +1358,7 @@ If FILE-SYSTEM is non-nil, return file system attributes."
1350 (tramp-gvfs-url-file-name (tramp-make-tramp-file-name v)) 1358 (tramp-gvfs-url-file-name (tramp-make-tramp-file-name v))
1351 "unix::mode" (number-to-string mode)))) 1359 "unix::mode" (number-to-string mode))))
1352 1360
1353(defun tramp-gvfs-handle-set-file-times (filename &optional time) 1361(defun tramp-gvfs-handle-set-file-times (filename &optional time _flag)
1354 "Like `set-file-times' for Tramp files." 1362 "Like `set-file-times' for Tramp files."
1355 (with-parsed-tramp-file-name filename nil 1363 (with-parsed-tramp-file-name filename nil
1356 (tramp-flush-file-properties v localname) 1364 (tramp-flush-file-properties v localname)
diff --git a/lisp/net/tramp-rclone.el b/lisp/net/tramp-rclone.el
index 9f539850139..fcbd2010a26 100644
--- a/lisp/net/tramp-rclone.el
+++ b/lisp/net/tramp-rclone.el
@@ -478,7 +478,18 @@ file names."
478 (with-tramp-connection-property 478 (with-tramp-connection-property
479 (tramp-get-connection-process vec) "rclone-pid" 479 (tramp-get-connection-process vec) "rclone-pid"
480 (catch 'pid 480 (catch 'pid
481 (dolist (pid (list-system-processes)) ;; "pidof rclone" ? 481 (dolist
482 (pid
483 ;; Until Emacs 25, `process-attributes' could
484 ;; crash Emacs for some processes. So we use
485 ;; "pidof", which might not work everywhere.
486 (if (<= emacs-major-version 25)
487 (let ((default-directory temporary-file-directory))
488 (mapcar
489 #'string-to-number
490 (split-string
491 (shell-command-to-string "pidof rclone"))))
492 (list-system-processes)))
482 (and (string-match-p 493 (and (string-match-p
483 (regexp-quote 494 (regexp-quote
484 (format "rclone mount %s:" (tramp-file-name-host vec))) 495 (format "rclone mount %s:" (tramp-file-name-host vec)))
@@ -564,7 +575,7 @@ connection if a previous connection has died for some reason."
564 ,(tramp-rclone-mount-point vec) 575 ,(tramp-rclone-mount-point vec)
565 ;; This could be nil. 576 ;; This could be nil.
566 ,(tramp-get-method-parameter vec 'tramp-mount-args)))) 577 ,(tramp-get-method-parameter vec 'tramp-mount-args))))
567 (while (not (file-exists-p (tramp-make-tramp-file-name vec 'localname))) 578 (while (not (file-exists-p (tramp-make-tramp-file-name vec 'noloc)))
568 (tramp-cleanup-connection vec 'keep-debug 'keep-password)) 579 (tramp-cleanup-connection vec 'keep-debug 'keep-password))
569 580
570 ;; Mark it as connected. 581 ;; Mark it as connected.
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
index af97328b3d3..9e8a3168fd7 100644
--- a/lisp/net/tramp-sh.el
+++ b/lisp/net/tramp-sh.el
@@ -36,6 +36,7 @@
36 36
37(declare-function dired-remove-file "dired-aux") 37(declare-function dired-remove-file "dired-aux")
38(defvar dired-compress-file-suffixes) 38(defvar dired-compress-file-suffixes)
39(defvar process-file-return-signal-string)
39(defvar vc-handled-backends) 40(defvar vc-handled-backends)
40(defvar vc-bzr-program) 41(defvar vc-bzr-program)
41(defvar vc-git-program) 42(defvar vc-git-program)
@@ -537,12 +538,13 @@ based on the Tramp and Emacs versions, and should not be set here."
537 538
538;;;###tramp-autoload 539;;;###tramp-autoload
539(defcustom tramp-sh-extra-args 540(defcustom tramp-sh-extra-args
540 '(("/bash\\'" . "-norc -noprofile") 541 '(("/bash\\'" . "-noediting -norc -noprofile")
541 ("/zsh\\'" . "-f +Z -V")) 542 ("/zsh\\'" . "-f +Z -V"))
542 "Alist specifying extra arguments to pass to the remote shell. 543 "Alist specifying extra arguments to pass to the remote shell.
543Entries are (REGEXP . ARGS) where REGEXP is a regular expression 544Entries are (REGEXP . ARGS) where REGEXP is a regular expression
544matching the shell file name and ARGS is a string specifying the 545matching the shell file name and ARGS is a string specifying the
545arguments. 546arguments. These arguments shall disable line editing, see
547`tramp-open-shell'.
546 548
547This variable is only used when Tramp needs to start up another shell 549This variable is only used when Tramp needs to start up another shell
548for tilde expansion. The extra arguments should typically prevent the 550for tilde expansion. The extra arguments should typically prevent the
@@ -866,8 +868,12 @@ Escape sequence %s is replaced with name of Perl binary.")
866 "Perl program to use for decoding a file. 868 "Perl program to use for decoding a file.
867Escape sequence %s is replaced with name of Perl binary.") 869Escape sequence %s is replaced with name of Perl binary.")
868 870
871(defconst tramp-hexdump-encode "%h -v -e '16/1 \" %%02x\" \"\\n\"'"
872 "`hexdump' program to use for encoding a file.
873This string is passed to `format', so percent characters need to be doubled.")
874
869(defconst tramp-awk-encode 875(defconst tramp-awk-encode
870 "od -v -t x1 -A n | busybox awk '\\ 876 "%a '\\
871BEGIN { 877BEGIN {
872 b64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\" 878 b64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"
873 b16 = \"0123456789abcdef\" 879 b16 = \"0123456789abcdef\"
@@ -897,11 +903,25 @@ END {
897 } 903 }
898 printf tail 904 printf tail
899}'" 905}'"
900 "Awk program to use for encoding a file. 906 "`awk' program to use for encoding a file.
907This string is passed to `format', so percent characters need to be doubled.")
908
909(defconst tramp-hexdump-awk-encode
910 (format "%s | %s" tramp-hexdump-encode tramp-awk-encode)
911 "`hexdump' / `awk' pipe to use for encoding a file.
912This string is passed to `format', so percent characters need to be doubled.")
913
914(defconst tramp-od-encode "%o -v -t x1 -A n"
915 "`od' program to use for encoding a file.
916This string is passed to `format', so percent characters need to be doubled.")
917
918(defconst tramp-od-awk-encode
919 (format "%s | %s" tramp-od-encode tramp-awk-encode)
920 "`od' / `awk' pipe to use for encoding a file.
901This string is passed to `format', so percent characters need to be doubled.") 921This string is passed to `format', so percent characters need to be doubled.")
902 922
903(defconst tramp-awk-decode 923(defconst tramp-awk-decode
904 "busybox awk '\\ 924 "%a '\\
905BEGIN { 925BEGIN {
906 b64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\" 926 b64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"
907} 927}
@@ -926,12 +946,6 @@ BEGIN {
926 "Awk program to use for decoding a file. 946 "Awk program to use for decoding a file.
927This string is passed to `format', so percent characters need to be doubled.") 947This string is passed to `format', so percent characters need to be doubled.")
928 948
929(defconst tramp-awk-coding-test
930 "test -c /dev/zero && \
931od -v -t x1 -A n </dev/null && \
932busybox awk '{}' </dev/null"
933 "Test command for checking `tramp-awk-encode' and `tramp-awk-decode'.")
934
935(defconst tramp-vc-registered-read-file-names 949(defconst tramp-vc-registered-read-file-names
936 "echo \"(\" 950 "echo \"(\"
937while read file; do 951while read file; do
@@ -1051,9 +1065,7 @@ component is used as the target of the symlink."
1051 (let ((non-essential t)) 1065 (let ((non-essential t))
1052 (when (and (tramp-tramp-file-p target) 1066 (when (and (tramp-tramp-file-p target)
1053 (tramp-file-name-equal-p v (tramp-dissect-file-name target))) 1067 (tramp-file-name-equal-p v (tramp-dissect-file-name target)))
1054 (setq target 1068 (setq target (tramp-file-local-name (expand-file-name target)))))
1055 (tramp-file-name-localname
1056 (tramp-dissect-file-name (expand-file-name target))))))
1057 1069
1058 ;; If TARGET is still remote, quote it. 1070 ;; If TARGET is still remote, quote it.
1059 (if (tramp-tramp-file-p target) 1071 (if (tramp-tramp-file-p target)
@@ -1263,8 +1275,8 @@ component is used as the target of the symlink."
1263(defun tramp-do-file-attributes-with-ls (vec localname &optional id-format) 1275(defun tramp-do-file-attributes-with-ls (vec localname &optional id-format)
1264 "Implement `file-attributes' for Tramp files using the ls(1) command." 1276 "Implement `file-attributes' for Tramp files using the ls(1) command."
1265 (let (symlinkp dirp 1277 (let (symlinkp dirp
1266 res-inode res-filemodes res-numlinks 1278 res-inode res-filemodes res-numlinks
1267 res-uid res-gid res-size res-symlink-target) 1279 res-uid res-gid res-size res-symlink-target)
1268 (tramp-message vec 5 "file attributes with ls: %s" localname) 1280 (tramp-message vec 5 "file attributes with ls: %s" localname)
1269 ;; We cannot send all three commands combined, it could exceed 1281 ;; We cannot send all three commands combined, it could exceed
1270 ;; NAME_MAX or PATH_MAX. Happened on macOS, for example. 1282 ;; NAME_MAX or PATH_MAX. Happened on macOS, for example.
@@ -1368,18 +1380,11 @@ component is used as the target of the symlink."
1368 (format 1380 (format
1369 (eval-when-compile 1381 (eval-when-compile
1370 (concat 1382 (concat
1371 ;; On Opsware, pdksh (which is the true name of ksh there) 1383 ;; Apostrophes in the stat output are masked as
1372 ;; doesn't parse correctly the sequence "((". Therefore, we
1373 ;; add a space. Apostrophes in the stat output are masked as
1374 ;; `tramp-stat-marker', in order to make a proper shell escape 1384 ;; `tramp-stat-marker', in order to make a proper shell escape
1375 ;; of them in file names. 1385 ;; of them in file names.
1376 "( (%s %s || %s -h %s) && (%s -c " 1386 "(%s -c '((%s%%N%s) %%h %s %s %%X %%Y %%Z %%s %s%%A%s t %%i -1)' %s |"
1377 "'((%s%%N%s) %%h %s %s %%X %%Y %%Z %%s %s%%A%s t %%i -1)' " 1387 " sed -e 's/\"/\\\\\"/g' -e 's/%s/\"/g')"))
1378 "%s | sed -e 's/\"/\\\\\"/g' -e 's/%s/\"/g') || echo nil)"))
1379 (tramp-get-file-exists-command vec)
1380 (tramp-shell-quote-argument localname)
1381 (tramp-get-test-command vec)
1382 (tramp-shell-quote-argument localname)
1383 (tramp-get-remote-stat vec) 1388 (tramp-get-remote-stat vec)
1384 tramp-stat-marker tramp-stat-marker 1389 tramp-stat-marker tramp-stat-marker
1385 (if (eq id-format 'integer) 1390 (if (eq id-format 'integer)
@@ -1390,7 +1395,8 @@ component is used as the target of the symlink."
1390 (eval-when-compile (concat tramp-stat-marker "%G" tramp-stat-marker))) 1395 (eval-when-compile (concat tramp-stat-marker "%G" tramp-stat-marker)))
1391 tramp-stat-marker tramp-stat-marker 1396 tramp-stat-marker tramp-stat-marker
1392 (tramp-shell-quote-argument localname) 1397 (tramp-shell-quote-argument localname)
1393 tramp-stat-quoted-marker))) 1398 tramp-stat-quoted-marker)
1399 'noerror))
1394 1400
1395(defun tramp-sh-handle-set-visited-file-modtime (&optional time-list) 1401(defun tramp-sh-handle-set-visited-file-modtime (&optional time-list)
1396 "Like `set-visited-file-modtime' for Tramp files." 1402 "Like `set-visited-file-modtime' for Tramp files."
@@ -1468,7 +1474,7 @@ of."
1468 ;; only if that agrees with the buffer's record. 1474 ;; only if that agrees with the buffer's record.
1469 (t (tramp-compat-time-equal-p mt tramp-time-doesnt-exist))))))))) 1475 (t (tramp-compat-time-equal-p mt tramp-time-doesnt-exist)))))))))
1470 1476
1471(defun tramp-sh-handle-set-file-modes (filename mode) 1477(defun tramp-sh-handle-set-file-modes (filename mode &optional _flag)
1472 "Like `set-file-modes' for Tramp files." 1478 "Like `set-file-modes' for Tramp files."
1473 (with-parsed-tramp-file-name filename nil 1479 (with-parsed-tramp-file-name filename nil
1474 (tramp-flush-file-properties v localname) 1480 (tramp-flush-file-properties v localname)
@@ -1478,7 +1484,7 @@ of."
1478 (format "chmod %o %s" mode (tramp-shell-quote-argument localname)) 1484 (format "chmod %o %s" mode (tramp-shell-quote-argument localname))
1479 "Error while changing file's mode %s" filename))) 1485 "Error while changing file's mode %s" filename)))
1480 1486
1481(defun tramp-sh-handle-set-file-times (filename &optional time) 1487(defun tramp-sh-handle-set-file-times (filename &optional time _flag)
1482 "Like `set-file-times' for Tramp files." 1488 "Like `set-file-times' for Tramp files."
1483 (with-parsed-tramp-file-name filename nil 1489 (with-parsed-tramp-file-name filename nil
1484 (when (tramp-get-remote-touch v) 1490 (when (tramp-get-remote-touch v)
@@ -2171,8 +2177,8 @@ the uid and gid from FILENAME."
2171 v 'file-error 2177 v 'file-error
2172 "Unknown operation `%s', must be `copy' or `rename'" 2178 "Unknown operation `%s', must be `copy' or `rename'"
2173 op)))) 2179 op))))
2174 (localname1 (tramp-compat-file-local-name filename)) 2180 (localname1 (tramp-file-local-name filename))
2175 (localname2 (tramp-compat-file-local-name newname)) 2181 (localname2 (tramp-file-local-name newname))
2176 (prefix (file-remote-p (if t1 filename newname))) 2182 (prefix (file-remote-p (if t1 filename newname)))
2177 cmd-result) 2183 cmd-result)
2178 (when (and (eq op 'copy) (file-directory-p filename)) 2184 (when (and (eq op 'copy) (file-directory-p filename))
@@ -2796,8 +2802,11 @@ the result will be a local, non-Tramp, file name."
2796;; We use BUFFER also as connection buffer during setup. Because of 2802;; We use BUFFER also as connection buffer during setup. Because of
2797;; this, its original contents must be saved, and restored once 2803;; this, its original contents must be saved, and restored once
2798;; connection has been setup. 2804;; connection has been setup.
2805;; The complete STDERR buffer is available only when the process has
2806;; terminated.
2799(defun tramp-sh-handle-make-process (&rest args) 2807(defun tramp-sh-handle-make-process (&rest args)
2800 "Like `make-process' for Tramp files." 2808 "Like `make-process' for Tramp files.
2809STDERR can also be a file name."
2801 (when args 2810 (when args
2802 (with-parsed-tramp-file-name (expand-file-name default-directory) nil 2811 (with-parsed-tramp-file-name (expand-file-name default-directory) nil
2803 (let ((name (plist-get args :name)) 2812 (let ((name (plist-get args :name))
@@ -2829,14 +2838,23 @@ the result will be a local, non-Tramp, file name."
2829 (signal 'wrong-type-argument (list #'functionp sentinel))) 2838 (signal 'wrong-type-argument (list #'functionp sentinel)))
2830 (unless (or (null stderr) (bufferp stderr) (stringp stderr)) 2839 (unless (or (null stderr) (bufferp stderr) (stringp stderr))
2831 (signal 'wrong-type-argument (list #'stringp stderr))) 2840 (signal 'wrong-type-argument (list #'stringp stderr)))
2841 (when (and (stringp stderr) (tramp-tramp-file-p stderr)
2842 (not (tramp-equal-remote default-directory stderr)))
2843 (signal 'file-error (list "Wrong stderr" stderr)))
2832 2844
2833 (let* ((buffer 2845 (let* ((buffer
2834 (if buffer 2846 (if buffer
2835 (get-buffer-create buffer) 2847 (get-buffer-create buffer)
2836 ;; BUFFER can be nil. We use a temporary buffer. 2848 ;; BUFFER can be nil. We use a temporary buffer.
2837 (generate-new-buffer tramp-temp-buffer-name))) 2849 (generate-new-buffer tramp-temp-buffer-name)))
2838 (stderr (and stderr (get-buffer-create stderr))) 2850 ;; STDERR can also be a file name.
2839 (tmpstderr (and stderr (tramp-make-tramp-temp-file v))) 2851 (tmpstderr
2852 (and stderr
2853 (if (and (stringp stderr) (tramp-tramp-file-p stderr))
2854 (tramp-unquote-file-local-name stderr)
2855 (tramp-make-tramp-temp-file v))))
2856 (remote-tmpstderr
2857 (and tmpstderr (tramp-make-tramp-file-name v tmpstderr)))
2840 (program (car command)) 2858 (program (car command))
2841 (args (cdr command)) 2859 (args (cdr command))
2842 ;; When PROGRAM matches "*sh", and the first arg is 2860 ;; When PROGRAM matches "*sh", and the first arg is
@@ -2965,21 +2983,35 @@ the result will be a local, non-Tramp, file name."
2965 (ignore-errors 2983 (ignore-errors
2966 (set-process-query-on-exit-flag p (null noquery)) 2984 (set-process-query-on-exit-flag p (null noquery))
2967 (set-marker (process-mark p) (point))) 2985 (set-marker (process-mark p) (point)))
2986 ;; We must flush them here already; otherwise
2987 ;; `rename-file', `delete-file' or
2988 ;; `insert-file-contents' will fail.
2989 (tramp-flush-connection-property v "process-name")
2990 (tramp-flush-connection-property v "process-buffer")
2991 ;; Copy tmpstderr file.
2992 (when (and (stringp stderr)
2993 (not (tramp-tramp-file-p stderr)))
2994 (add-function
2995 :after (process-sentinel p)
2996 (lambda (_proc _msg)
2997 (rename-file remote-tmpstderr stderr))))
2968 ;; Provide error buffer. This shows only 2998 ;; Provide error buffer. This shows only
2969 ;; initial error messages; messages arriving 2999 ;; initial error messages; messages arriving
2970 ;; later on shall be inserted by `auto-revert'. 3000 ;; later on will be inserted when the process is
2971 ;; The temporary file will still be existing. 3001 ;; deleted. The temporary file will exist until
2972 ;; TODO: Write a sentinel, which deletes the 3002 ;; the process is deleted.
2973 ;; temporary file. 3003 (when (bufferp stderr)
2974 (when tmpstderr
2975 ;; We must flush them here already; otherwise
2976 ;; `insert-file-contents' will fail.
2977 (tramp-flush-connection-property v "process-name")
2978 (tramp-flush-connection-property v "process-buffer")
2979 (with-current-buffer stderr 3004 (with-current-buffer stderr
2980 (insert-file-contents 3005 (insert-file-contents-literally remote-tmpstderr))
2981 (tramp-make-tramp-file-name v tmpstderr) 'visit) 3006 ;; Delete tmpstderr file.
2982 (auto-revert-mode))) 3007 (add-function
3008 :after (process-sentinel p)
3009 (lambda (_proc _msg)
3010 (when (file-exists-p remote-tmpstderr)
3011 (with-current-buffer stderr
3012 (insert-file-contents-literally
3013 remote-tmpstderr nil nil nil 'replace))
3014 (delete-file remote-tmpstderr)))))
2983 ;; Return process. 3015 ;; Return process.
2984 p))) 3016 p)))
2985 3017
@@ -2992,6 +3024,65 @@ the result will be a local, non-Tramp, file name."
2992 (tramp-flush-connection-property v "process-name") 3024 (tramp-flush-connection-property v "process-name")
2993 (tramp-flush-connection-property v "process-buffer")))))))) 3025 (tramp-flush-connection-property v "process-buffer"))))))))
2994 3026
3027(defun tramp-sh-get-signal-strings (vec)
3028 "Strings to return by `process-file' in case of signals."
3029 (with-tramp-connection-property
3030 vec
3031 (concat
3032 "signal-strings-" (tramp-get-method-parameter vec 'tramp-remote-shell))
3033 (let ((default-directory (tramp-make-tramp-file-name vec 'localname))
3034 process-file-return-signal-string signals res result)
3035 (setq signals
3036 (append
3037 '(0) (split-string (shell-command-to-string "kill -l") nil 'omit)))
3038 ;; Sanity check. Sometimes, the first entry is "0", although we
3039 ;; don't expect it. Remove it.
3040 (when (and (stringp (cadr signals)) (string-equal "0" (cadr signals)))
3041 (setcdr signals (cddr signals)))
3042 ;; Sanity check. "kill -l" shall have returned just the signal
3043 ;; names. Some shells don't, like the one in "docker alpine".
3044 (let (signal-hook-function)
3045 (condition-case nil
3046 (dolist (sig (cdr signals))
3047 (unless (string-match-p "^[[:alnum:]+-]+$" sig)
3048 (error nil)))
3049 (error (setq signals '(0)))))
3050 (dotimes (i 128)
3051 (push
3052 (cond
3053 ;; Some predefined values, which aren't reported sometimes,
3054 ;; or would raise problems (all Stopped signals).
3055 ((= i 0) 0)
3056 ((string-equal (nth i signals) "HUP") "Hangup")
3057 ((string-equal (nth i signals) "INT") "Interrupt")
3058 ((string-equal (nth i signals) "QUIT") "Quit")
3059 ((string-equal (nth i signals) "STOP") "Stopped (signal)")
3060 ((string-equal (nth i signals) "TSTP") "Stopped")
3061 ((string-equal (nth i signals) "TTIN") "Stopped (tty input)")
3062 ((string-equal (nth i signals) "TTOU") "Stopped (tty output)")
3063 (t (setq res
3064 (if (null (nth i signals))
3065 ""
3066 (tramp-send-command
3067 vec
3068 (format
3069 "%s %s %s"
3070 (tramp-get-method-parameter vec 'tramp-remote-shell)
3071 (mapconcat
3072 #'identity
3073 (tramp-get-method-parameter vec 'tramp-remote-shell-args)
3074 " ")
3075 (tramp-shell-quote-argument (format "kill -%d $$" i))))
3076 (with-current-buffer (tramp-get-connection-buffer vec)
3077 (goto-char (point-min))
3078 (buffer-substring (point-at-bol) (point-at-eol)))))
3079 (if (string-equal res "")
3080 (format "Signal %d" i)
3081 res)))
3082 result))
3083 ;; Due to Bug#41287, we cannot add this to the `dotimes' clause.
3084 (reverse result))))
3085
2995(defun tramp-sh-handle-process-file 3086(defun tramp-sh-handle-process-file
2996 (program &optional infile destination display &rest args) 3087 (program &optional infile destination display &rest args)
2997 "Like `process-file' for Tramp files." 3088 "Like `process-file' for Tramp files."
@@ -3028,7 +3119,7 @@ the result will be a local, non-Tramp, file name."
3028 (setq infile (expand-file-name infile)) 3119 (setq infile (expand-file-name infile))
3029 (if (tramp-equal-remote default-directory infile) 3120 (if (tramp-equal-remote default-directory infile)
3030 ;; INFILE is on the same remote host. 3121 ;; INFILE is on the same remote host.
3031 (setq input (with-parsed-tramp-file-name infile nil localname)) 3122 (setq input (tramp-file-local-name infile))
3032 ;; INFILE must be copied to remote host. 3123 ;; INFILE must be copied to remote host.
3033 (setq input (tramp-make-tramp-temp-file v) 3124 (setq input (tramp-make-tramp-temp-file v)
3034 tmpinput (tramp-make-tramp-file-name v input 'nohop)) 3125 tmpinput (tramp-make-tramp-file-name v input 'nohop))
@@ -3059,8 +3150,7 @@ the result will be a local, non-Tramp, file name."
3059 (setcar (cdr destination) (expand-file-name (cadr destination))) 3150 (setcar (cdr destination) (expand-file-name (cadr destination)))
3060 (if (tramp-equal-remote default-directory (cadr destination)) 3151 (if (tramp-equal-remote default-directory (cadr destination))
3061 ;; stderr is on the same remote host. 3152 ;; stderr is on the same remote host.
3062 (setq stderr (with-parsed-tramp-file-name 3153 (setq stderr (tramp-file-local-name (cadr destination)))
3063 (cadr destination) nil localname))
3064 ;; stderr must be copied to remote host. The temporary 3154 ;; stderr must be copied to remote host. The temporary
3065 ;; file must be deleted after execution. 3155 ;; file must be deleted after execution.
3066 (setq stderr (tramp-make-tramp-temp-file v) 3156 (setq stderr (tramp-make-tramp-temp-file v)
@@ -3078,13 +3168,12 @@ the result will be a local, non-Tramp, file name."
3078 ;; directory. 3168 ;; directory.
3079 (condition-case nil 3169 (condition-case nil
3080 (unwind-protect 3170 (unwind-protect
3081 (setq ret 3171 (setq ret (tramp-send-command-and-check
3082 (if (tramp-send-command-and-check 3172 v (format
3083 v (format "cd %s && %s" 3173 "cd %s && %s"
3084 (tramp-shell-quote-argument localname) 3174 (tramp-shell-quote-argument localname) command)
3085 command) 3175 t t t))
3086 t t) 3176 (unless (natnump ret) (setq ret 1))
3087 0 1))
3088 ;; We should add the output anyway. 3177 ;; We should add the output anyway.
3089 (when outbuf 3178 (when outbuf
3090 (with-current-buffer outbuf 3179 (with-current-buffer outbuf
@@ -3102,6 +3191,12 @@ the result will be a local, non-Tramp, file name."
3102 (kill-buffer (tramp-get-connection-buffer v)) 3191 (kill-buffer (tramp-get-connection-buffer v))
3103 (setq ret 1))) 3192 (setq ret 1)))
3104 3193
3194 ;; Handle signals. `process-file-return-signal-string' exists
3195 ;; since Emacs 28.1.
3196 (when (and (bound-and-true-p process-file-return-signal-string)
3197 (natnump ret) (>= ret 128))
3198 (setq ret (nth (- ret 128) (tramp-sh-get-signal-strings v))))
3199
3105 ;; Provide error file. 3200 ;; Provide error file.
3106 (when tmpstderr (rename-file tmpstderr (cadr destination) t)) 3201 (when tmpstderr (rename-file tmpstderr (cadr destination) t))
3107 3202
@@ -3122,7 +3217,7 @@ the result will be a local, non-Tramp, file name."
3122 (append 3217 (append
3123 (tramp-get-remote-path (tramp-dissect-file-name default-directory)) 3218 (tramp-get-remote-path (tramp-dissect-file-name default-directory))
3124 ;; The equivalent to `exec-directory'. 3219 ;; The equivalent to `exec-directory'.
3125 `(,(tramp-compat-file-local-name default-directory)))) 3220 `(,(tramp-file-local-name (expand-file-name default-directory)))))
3126 3221
3127(defun tramp-sh-handle-file-local-copy (filename) 3222(defun tramp-sh-handle-file-local-copy (filename)
3128 "Like `file-local-copy' for Tramp files." 3223 "Like `file-local-copy' for Tramp files."
@@ -3258,7 +3353,8 @@ the result will be a local, non-Tramp, file name."
3258 3353
3259 ;; If `append' is non-nil, we copy the file locally, and let 3354 ;; If `append' is non-nil, we copy the file locally, and let
3260 ;; the native `write-region' implementation do the job. 3355 ;; the native `write-region' implementation do the job.
3261 (when append (copy-file filename tmpfile 'ok)) 3356 (when (and append (file-exists-p filename))
3357 (copy-file filename tmpfile 'ok))
3262 3358
3263 ;; We say `no-message' here because we don't want the 3359 ;; We say `no-message' here because we don't want the
3264 ;; visited file modtime data to be clobbered from the temp 3360 ;; visited file modtime data to be clobbered from the temp
@@ -3981,23 +4077,30 @@ whether it exists and if so, it is added to the environment
3981variable PATH." 4077variable PATH."
3982 (let ((command 4078 (let ((command
3983 (format 4079 (format
3984 "PATH=%s; export PATH" (string-join (tramp-get-remote-path vec) ":"))) 4080 "PATH=%s && export PATH" (string-join (tramp-get-remote-path vec) ":")))
3985 (pipe-buf 4081 (pipe-buf
3986 (or (with-tramp-connection-property vec "pipe-buf" 4082 (with-tramp-connection-property vec "pipe-buf"
3987 (tramp-send-command-and-read 4083 (tramp-send-command-and-read
3988 vec "getconf PIPE_BUF / 2>/dev/null || echo nil" 'noerror)) 4084 vec "getconf PIPE_BUF / 2>/dev/null || echo 4096" 'noerror)))
3989 4096)) 4085 tmpfile chunk chunksize)
3990 tmpfile)
3991 (tramp-message vec 5 "Setting $PATH environment variable") 4086 (tramp-message vec 5 "Setting $PATH environment variable")
3992 (if (< (length command) pipe-buf) 4087 (if (< (length command) pipe-buf)
3993 (tramp-send-command vec command) 4088 (tramp-send-command vec command)
3994 ;; Use a temporary file. 4089 ;; Use a temporary file. We cannot use `write-region' because
3995 (setq tmpfile 4090 ;; setting the remote path happens in the early connection
3996 (tramp-make-tramp-file-name vec (tramp-make-tramp-temp-file vec))) 4091 ;; handshake, and not all external tools are determined yet.
3997 (write-region command nil tmpfile) 4092 (setq command (concat command "\n")
3998 (tramp-send-command 4093 tmpfile (tramp-make-tramp-temp-file vec))
3999 vec (format ". %s" (tramp-compat-file-local-name tmpfile))) 4094 (while (not (string-empty-p command))
4000 (delete-file tmpfile)))) 4095 (setq chunksize (min (length command) (/ pipe-buf 2))
4096 chunk (substring command 0 chunksize)
4097 command (substring command chunksize))
4098 (tramp-send-command vec (format
4099 "echo -n %s >>%s"
4100 (tramp-shell-quote-argument chunk)
4101 (tramp-shell-quote-argument tmpfile))))
4102 (tramp-send-command vec (format ". %s" tmpfile))
4103 (tramp-send-command vec (format "rm -f %s" tmpfile)))))
4001 4104
4002;; ------------------------------------------------------------ 4105;; ------------------------------------------------------------
4003;; -- Communication with external shell -- 4106;; -- Communication with external shell --
@@ -4069,54 +4172,54 @@ file exists and nonzero exit status otherwise."
4069 4172
4070(defun tramp-open-shell (vec shell) 4173(defun tramp-open-shell (vec shell)
4071 "Open shell SHELL." 4174 "Open shell SHELL."
4175 ;; Find arguments for this shell.
4072 (with-tramp-progress-reporter 4176 (with-tramp-progress-reporter
4073 vec 5 (format-message "Opening remote shell `%s'" shell) 4177 vec 5 (format-message "Opening remote shell `%s'" shell)
4074 ;; Find arguments for this shell. 4178 ;; It is useful to set the prompt in the following command because
4075 (let ((extra-args (tramp-get-sh-extra-args shell))) 4179 ;; some people have a setting for $PS1 which /bin/sh doesn't know
4076 ;; doesn't know about and thus /bin/sh will display a strange 4180 ;; about and thus /bin/sh will display a strange prompt. For
4077 ;; prompt. For example, if $PS1 has "${CWD}" in the value, then 4181 ;; example, if $PS1 has "${CWD}" in the value, then ksh will
4078 ;; ksh will display the current working directory but /bin/sh 4182 ;; display the current working directory but /bin/sh will display
4079 ;; will display a dollar sign. The following command line sets 4183 ;; a dollar sign. The following command line sets $PS1 to a sane
4080 ;; $PS1 to a sane value, and works under Bourne-ish shells as 4184 ;; value, and works under Bourne-ish shells as well as csh-like
4081 ;; well as csh-like shells. We also unset the variable $ENV 4185 ;; shells. We also unset the variable $ENV because that is read
4082 ;; because that is read by some sh implementations (eg, bash 4186 ;; by some sh implementations (eg, bash when called as sh) on
4083 ;; when called as sh) on startup; this way, we avoid the startup 4187 ;; startup; this way, we avoid the startup file clobbering $PS1.
4084 ;; file clobbering $PS1. $PROMPT_COMMAND is another way to set 4188 ;; $PROMPT_COMMAND is another way to set the prompt in /bin/bash,
4085 ;; the prompt in /bin/bash, it must be discarded as well. 4189 ;; it must be discarded as well. $HISTFILE is set according to
4086 ;; $HISTFILE is set according to `tramp-histfile-override'. 4190 ;; `tramp-histfile-override'. $TERM and $INSIDE_EMACS set here to
4087 ;; $TERM and $INSIDE_EMACS set here to ensure they have the 4191 ;; ensure they have the correct values when the shell starts, not
4088 ;; correct values when the shell starts, not just processes 4192 ;; just processes run within the shell. (Which processes include
4089 ;; run within the shell. (Which processes include our 4193 ;; our initial probes to ensure the remote shell is usable.)
4090 ;; initial probes to ensure the remote shell is usable.) 4194 (tramp-send-command
4091 (tramp-send-command 4195 vec (format
4092 vec (format 4196 (eval-when-compile
4093 (eval-when-compile 4197 (concat
4094 (concat 4198 "exec env TERM='%s' INSIDE_EMACS='%s,tramp:%s' "
4095 "exec env TERM='%s' INSIDE_EMACS='%s,tramp:%s' " 4199 "ENV=%s %s PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s %s"))
4096 "ENV=%s %s PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s %s")) 4200 tramp-terminal-type
4097 tramp-terminal-type 4201 emacs-version tramp-version ; INSIDE_EMACS
4098 emacs-version tramp-version ; INSIDE_EMACS 4202 (or (getenv-internal "ENV" tramp-remote-process-environment) "")
4099 (or (getenv-internal "ENV" tramp-remote-process-environment) "") 4203 (if (stringp tramp-histfile-override)
4100 (if (stringp tramp-histfile-override) 4204 (format "HISTFILE=%s"
4101 (format "HISTFILE=%s" 4205 (tramp-shell-quote-argument tramp-histfile-override))
4102 (tramp-shell-quote-argument tramp-histfile-override)) 4206 (if tramp-histfile-override
4103 (if tramp-histfile-override 4207 "HISTFILE='' HISTFILESIZE=0 HISTSIZE=0"
4104 "HISTFILE='' HISTFILESIZE=0 HISTSIZE=0" 4208 ""))
4105 "")) 4209 (tramp-shell-quote-argument tramp-end-of-output)
4106 (tramp-shell-quote-argument tramp-end-of-output) 4210 shell (or (tramp-get-sh-extra-args shell) ""))
4107 shell (or extra-args "")) 4211 t)
4108 t) 4212 ;; Check proper HISTFILE setting. We give up when not working.
4109 ;; Check proper HISTFILE setting. We give up when not working. 4213 (when (and (stringp tramp-histfile-override)
4110 (when (and (stringp tramp-histfile-override) 4214 (file-name-directory tramp-histfile-override))
4111 (file-name-directory tramp-histfile-override)) 4215 (tramp-barf-unless-okay
4112 (tramp-barf-unless-okay 4216 vec
4113 vec 4217 (format
4114 (format 4218 "(cd %s)"
4115 "(cd %s)" 4219 (tramp-shell-quote-argument
4116 (tramp-shell-quote-argument 4220 (file-name-directory tramp-histfile-override)))
4117 (file-name-directory tramp-histfile-override))) 4221 "`tramp-histfile-override' uses invalid file `%s'"
4118 "`tramp-histfile-override' uses invalid file `%s'" 4222 tramp-histfile-override))
4119 tramp-histfile-override)))
4120 4223
4121 (tramp-set-connection-property 4224 (tramp-set-connection-property
4122 (tramp-get-connection-process vec) "remote-shell" shell))) 4225 (tramp-get-connection-process vec) "remote-shell" shell)))
@@ -4187,9 +4290,16 @@ process to set up. VEC specifies the connection."
4187 (let ((tramp-end-of-output tramp-initial-end-of-output) 4290 (let ((tramp-end-of-output tramp-initial-end-of-output)
4188 (case-fold-search t)) 4291 (case-fold-search t))
4189 (tramp-open-shell vec (tramp-get-method-parameter vec 'tramp-remote-shell)) 4292 (tramp-open-shell vec (tramp-get-method-parameter vec 'tramp-remote-shell))
4293 (tramp-message vec 5 "Setting up remote shell environment")
4294
4295 ;; Disable line editing.
4296 (tramp-send-command vec "set +o vi +o emacs" t)
4297
4298 ;; Dump option settings in the traces.
4299 (when (>= tramp-verbose 9)
4300 (tramp-send-command vec "set -o" t))
4190 4301
4191 ;; Disable echo expansion. 4302 ;; Disable echo expansion.
4192 (tramp-message vec 5 "Setting up remote shell environment")
4193 (tramp-send-command 4303 (tramp-send-command
4194 vec "stty -inlcr -onlcr -echo kill '^U' erase '^H'" t) 4304 vec "stty -inlcr -onlcr -echo kill '^U' erase '^H'" t)
4195 ;; Check whether the echo has really been disabled. Some 4305 ;; Check whether the echo has really been disabled. Some
@@ -4259,8 +4369,6 @@ process to set up. VEC specifies the connection."
4259 (tramp-message 4369 (tramp-message
4260 vec 5 "Setting coding system to `%s' and `%s'" cs-decode cs-encode))) 4370 vec 5 "Setting coding system to `%s' and `%s'" cs-decode cs-encode)))
4261 4371
4262 (tramp-send-command vec "set +o vi +o emacs" t)
4263
4264 ;; Check whether the remote host suffers from buggy 4372 ;; Check whether the remote host suffers from buggy
4265 ;; `send-process-string'. This is known for FreeBSD (see comment 4373 ;; `send-process-string'. This is known for FreeBSD (see comment
4266 ;; in `send_process', file process.c). I've tested sending 624 4374 ;; in `send_process', file process.c). I've tested sending 624
@@ -4383,7 +4491,7 @@ and end of region, and are expected to replace the region contents
4383with the encoded or decoded results, respectively.") 4491with the encoded or decoded results, respectively.")
4384 4492
4385(defconst tramp-remote-coding-commands 4493(defconst tramp-remote-coding-commands
4386 `((b64 "base64" "base64 -d -i") 4494 '((b64 "base64" "base64 -d -i")
4387 ;; "-i" is more robust with older base64 from GNU coreutils. 4495 ;; "-i" is more robust with older base64 from GNU coreutils.
4388 ;; However, I don't know whether all base64 versions do supports 4496 ;; However, I don't know whether all base64 versions do supports
4389 ;; this option. 4497 ;; this option.
@@ -4394,8 +4502,9 @@ with the encoded or decoded results, respectively.")
4394 (b64 "recode data..base64" "recode base64..data") 4502 (b64 "recode data..base64" "recode base64..data")
4395 (b64 tramp-perl-encode-with-module tramp-perl-decode-with-module) 4503 (b64 tramp-perl-encode-with-module tramp-perl-decode-with-module)
4396 (b64 tramp-perl-encode tramp-perl-decode) 4504 (b64 tramp-perl-encode tramp-perl-decode)
4397 ;; This is painful slow, so we put it on the end. 4505 ;; These are painfully slow, so we put them on the end.
4398 (b64 tramp-awk-encode tramp-awk-decode ,tramp-awk-coding-test) 4506 (b64 tramp-hexdump-awk-encode tramp-awk-decode)
4507 (b64 tramp-od-awk-encode tramp-awk-decode)
4399 (uu "uuencode xxx" "uudecode -o /dev/stdout" "test -c /dev/stdout") 4508 (uu "uuencode xxx" "uudecode -o /dev/stdout" "test -c /dev/stdout")
4400 (uu "uuencode xxx" "uudecode -o -") 4509 (uu "uuencode xxx" "uudecode -o -")
4401 (uu "uuencode xxx" "uudecode -p") 4510 (uu "uuencode xxx" "uudecode -p")
@@ -4421,6 +4530,8 @@ Perl or Shell implementation for this functionality. This
4421program will be transferred to the remote host, and it is 4530program will be transferred to the remote host, and it is
4422available as shell function with the same name. A \"%t\" format 4531available as shell function with the same name. A \"%t\" format
4423specifier in the variable value denotes a temporary file. 4532specifier in the variable value denotes a temporary file.
4533\"%a\", \"%h\" and \"%o\" format specifiers are replaced by the
4534respective `awk', `hexdump' and `od' commands.
4424 4535
4425The optional TEST command can be used for further tests, whether 4536The optional TEST command can be used for further tests, whether
4426ENCODING and DECODING are applicable.") 4537ENCODING and DECODING are applicable.")
@@ -4471,11 +4582,6 @@ Goes through the list `tramp-local-coding-commands' and
4471 vec 5 "Checking remote test command `%s'" rem-test) 4582 vec 5 "Checking remote test command `%s'" rem-test)
4472 (unless (tramp-send-command-and-check vec rem-test t) 4583 (unless (tramp-send-command-and-check vec rem-test t)
4473 (throw 'wont-work-remote nil))) 4584 (throw 'wont-work-remote nil)))
4474 ;; Check if remote perl exists when necessary.
4475 (when (and (symbolp rem-enc)
4476 (string-match-p "perl" (symbol-name rem-enc))
4477 (not (tramp-get-remote-perl vec)))
4478 (throw 'wont-work-remote nil))
4479 ;; Check if remote encoding and decoding commands can be 4585 ;; Check if remote encoding and decoding commands can be
4480 ;; called remotely with null input and output. This makes 4586 ;; called remotely with null input and output. This makes
4481 ;; sure there are no syntax errors and the command is really 4587 ;; sure there are no syntax errors and the command is really
@@ -4485,10 +4591,36 @@ Goes through the list `tramp-local-coding-commands' and
4485 ;; redirecting "mimencode" output to /dev/null, then as root 4591 ;; redirecting "mimencode" output to /dev/null, then as root
4486 ;; it might change the permissions of /dev/null! 4592 ;; it might change the permissions of /dev/null!
4487 (unless (stringp rem-enc) 4593 (unless (stringp rem-enc)
4488 (let ((name (symbol-name rem-enc))) 4594 (let ((name (symbol-name rem-enc))
4595 (value (symbol-value rem-enc)))
4596 ;; Check if remote perl exists when necessary.
4597 (and (string-match-p "perl" name)
4598 (not (tramp-get-remote-perl vec))
4599 (throw 'wont-work-remote nil))
4600 ;; Check if remote awk exists when necessary.
4601 (and (string-match-p "\\(^\\|[^%]\\)%a" value)
4602 (not (tramp-get-remote-awk vec))
4603 (throw 'wont-work-remote nil))
4604 ;; Check if remote hexdump exists when necessary.
4605 (and (string-match-p "\\(^\\|[^%]\\)%h" value)
4606 (not (tramp-get-remote-hexdump vec))
4607 (throw 'wont-work-remote nil))
4608 ;; Check if remote od exists when necessary.
4609 (and (string-match-p "\\(^\\|[^%]\\)%o" value)
4610 (not (tramp-get-remote-od vec))
4611 (throw 'wont-work-remote nil))
4489 (while (string-match "-" name) 4612 (while (string-match "-" name)
4490 (setq name (replace-match "_" nil t name))) 4613 (setq name (replace-match "_" nil t name)))
4491 (tramp-maybe-send-script vec (symbol-value rem-enc) name) 4614 (when (string-match-p "\\(^\\|[^%]\\)%[aho]" value)
4615 (setq value
4616 (format-spec
4617 value
4618 (format-spec-make
4619 ?a (tramp-get-remote-awk vec)
4620 ?h (tramp-get-remote-hexdump vec)
4621 ?o (tramp-get-remote-od vec)))
4622 value (replace-regexp-in-string "%" "%%" value)))
4623 (tramp-maybe-send-script vec value name)
4492 (setq rem-enc name))) 4624 (setq rem-enc name)))
4493 (tramp-message 4625 (tramp-message
4494 vec 5 4626 vec 5
@@ -4503,6 +4635,15 @@ Goes through the list `tramp-local-coding-commands' and
4503 tmpfile) 4635 tmpfile)
4504 (while (string-match "-" name) 4636 (while (string-match "-" name)
4505 (setq name (replace-match "_" nil t name))) 4637 (setq name (replace-match "_" nil t name)))
4638 (when (string-match-p "\\(^\\|[^%]\\)%[aho]" value)
4639 (setq value
4640 (format-spec
4641 value
4642 (format-spec-make
4643 ?a (tramp-get-remote-awk vec)
4644 ?h (tramp-get-remote-hexdump vec)
4645 ?o (tramp-get-remote-od vec)))
4646 value (replace-regexp-in-string "%" "%%" value)))
4506 (when (string-match-p "\\(^\\|[^%]\\)%t" value) 4647 (when (string-match-p "\\(^\\|[^%]\\)%t" value)
4507 (setq tmpfile 4648 (setq tmpfile
4508 (make-temp-name 4649 (make-temp-name
@@ -4513,7 +4654,7 @@ Goes through the list `tramp-local-coding-commands' and
4513 (format-spec 4654 (format-spec
4514 value 4655 value
4515 (format-spec-make 4656 (format-spec-make
4516 ?t (tramp-compat-file-local-name tmpfile))))) 4657 ?t (tramp-file-local-name tmpfile)))))
4517 (tramp-maybe-send-script vec value name) 4658 (tramp-maybe-send-script vec value name)
4518 (setq rem-dec name))) 4659 (setq rem-dec name)))
4519 (tramp-message 4660 (tramp-message
@@ -4796,7 +4937,7 @@ If there is just some editing, retry it after 5 seconds."
4796 vec 5 "Cannot timeout session, trying it again in %s seconds." 5) 4937 vec 5 "Cannot timeout session, trying it again in %s seconds." 5)
4797 (run-at-time 5 nil 'tramp-timeout-session vec)) 4938 (run-at-time 5 nil 'tramp-timeout-session vec))
4798 (tramp-message 4939 (tramp-message
4799 vec 3 "Timeout session %s" (tramp-make-tramp-file-name vec 'localname)) 4940 vec 3 "Timeout session %s" (tramp-make-tramp-file-name vec 'noloc))
4800 (tramp-cleanup-connection vec 'keep-debug))) 4941 (tramp-cleanup-connection vec 'keep-debug)))
4801 4942
4802(defun tramp-maybe-open-connection (vec) 4943(defun tramp-maybe-open-connection (vec)
@@ -5116,7 +5257,7 @@ function waits for output unless NOOUTPUT is set."
5116 found))) 5257 found)))
5117 5258
5118(defun tramp-send-command-and-check 5259(defun tramp-send-command-and-check
5119 (vec command &optional subshell dont-suppress-err) 5260 (vec command &optional subshell dont-suppress-err exit-status)
5120 "Run COMMAND and check its exit status. 5261 "Run COMMAND and check its exit status.
5121Send `echo $?' along with the COMMAND for checking the exit status. 5262Send `echo $?' along with the COMMAND for checking the exit status.
5122If COMMAND is nil, just send `echo $?'. Return t if the exit 5263If COMMAND is nil, just send `echo $?'. Return t if the exit
@@ -5124,7 +5265,9 @@ status is 0, and nil otherwise.
5124 5265
5125If the optional argument SUBSHELL is non-nil, the command is 5266If the optional argument SUBSHELL is non-nil, the command is
5126executed in a subshell, ie surrounded by parentheses. If 5267executed in a subshell, ie surrounded by parentheses. If
5127DONT-SUPPRESS-ERR is non-nil, stderr won't be sent to /dev/null." 5268DONT-SUPPRESS-ERR is non-nil, stderr won't be sent to /dev/null.
5269Optional argument EXIT-STATUS, if non-nil, triggers the return of
5270the exit status."
5128 (tramp-send-command 5271 (tramp-send-command
5129 vec 5272 vec
5130 (concat (if subshell "( " "") 5273 (concat (if subshell "( " "")
@@ -5138,7 +5281,9 @@ DONT-SUPPRESS-ERR is non-nil, stderr won't be sent to /dev/null."
5138 vec 'file-error "Couldn't find exit status of `%s'" command)) 5281 vec 'file-error "Couldn't find exit status of `%s'" command))
5139 (skip-chars-forward "^ ") 5282 (skip-chars-forward "^ ")
5140 (prog1 5283 (prog1
5141 (zerop (read (current-buffer))) 5284 (if exit-status
5285 (read (current-buffer))
5286 (zerop (read (current-buffer))))
5142 (let ((inhibit-read-only t)) 5287 (let ((inhibit-read-only t))
5143 (delete-region (match-beginning 0) (point-max)))))) 5288 (delete-region (match-beginning 0) (point-max))))))
5144 5289
@@ -5171,7 +5316,10 @@ raises an error."
5171 command marker (buffer-string)))))) 5316 command marker (buffer-string))))))
5172 ;; Read the expression. 5317 ;; Read the expression.
5173 (condition-case nil 5318 (condition-case nil
5174 (prog1 (read (current-buffer)) 5319 (prog1
5320 (let ((signal-hook-function
5321 (unless noerror signal-hook-function)))
5322 (read (current-buffer)))
5175 ;; Error handling. 5323 ;; Error handling.
5176 (when (re-search-forward "\\S-" (point-at-eol) t) 5324 (when (re-search-forward "\\S-" (point-at-eol) t)
5177 (error nil))) 5325 (error nil)))
@@ -5594,7 +5742,7 @@ This command is returned only if `delete-by-moving-to-trash' is non-nil."
5594 "%s -t %s %s" 5742 "%s -t %s %s"
5595 result 5743 result
5596 (format-time-string "%Y%m%d%H%M.%S") 5744 (format-time-string "%Y%m%d%H%M.%S")
5597 (tramp-compat-file-local-name tmpfile)))) 5745 (tramp-file-local-name tmpfile))))
5598 (delete-file tmpfile)) 5746 (delete-file tmpfile))
5599 result))) 5747 result)))
5600 5748
@@ -5769,6 +5917,47 @@ ID-FORMAT valid values are `string' and `integer'."
5769 tramp-unknown-id-string) 5917 tramp-unknown-id-string)
5770 (t res))))) 5918 (t res)))))
5771 5919
5920(defun tramp-get-remote-busybox (vec)
5921 "Determine remote `busybox' command."
5922 (with-tramp-connection-property vec "busybox"
5923 (tramp-message vec 5 "Finding a suitable `busybox' command")
5924 (tramp-find-executable vec "busybox" (tramp-get-remote-path vec))))
5925
5926(defun tramp-get-remote-awk (vec)
5927 "Determine remote `awk' command."
5928 (with-tramp-connection-property vec "awk"
5929 (tramp-message vec 5 "Finding a suitable `awk' command")
5930 (or (tramp-find-executable vec "awk" (tramp-get-remote-path vec))
5931 (let* ((busybox (tramp-get-remote-busybox vec))
5932 (command (format "%s %s" busybox "awk")))
5933 (and busybox
5934 (tramp-send-command-and-check
5935 vec (concat command " {} </dev/null"))
5936 command)))))
5937
5938(defun tramp-get-remote-hexdump (vec)
5939 "Determine remote `hexdump' command."
5940 (with-tramp-connection-property vec "hexdump"
5941 (tramp-message vec 5 "Finding a suitable `hexdump' command")
5942 (or (tramp-find-executable vec "hexdump" (tramp-get-remote-path vec))
5943 (let* ((busybox (tramp-get-remote-busybox vec))
5944 (command (format "%s %s" busybox "hexdump")))
5945 (and busybox
5946 (tramp-send-command-and-check vec (concat command " </dev/null"))
5947 command)))))
5948
5949(defun tramp-get-remote-od (vec)
5950 "Determine remote `od' command."
5951 (with-tramp-connection-property vec "od"
5952 (tramp-message vec 5 "Finding a suitable `od' command")
5953 (or (tramp-find-executable vec "od" (tramp-get-remote-path vec))
5954 (let* ((busybox (tramp-get-remote-busybox vec))
5955 (command (format "%s %s" busybox "od")))
5956 (and busybox
5957 (tramp-send-command-and-check
5958 vec (concat command " -A n </dev/null"))
5959 command)))))
5960
5772(defun tramp-get-env-with-u-option (vec) 5961(defun tramp-get-env-with-u-option (vec)
5773 "Check, whether the remote `env' command supports the -u option." 5962 "Check, whether the remote `env' command supports the -u option."
5774 (with-tramp-connection-property vec "env-u-option" 5963 (with-tramp-connection-property vec "env-u-option"
diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el
index bf77ab9dee8..902fcf4b6e3 100644
--- a/lisp/net/tramp-smb.el
+++ b/lisp/net/tramp-smb.el
@@ -75,12 +75,23 @@
75 75
76;;;###tramp-autoload 76;;;###tramp-autoload
77(defcustom tramp-smb-conf "/dev/null" 77(defcustom tramp-smb-conf "/dev/null"
78 "Path of the smb.conf file. 78 "Path of the \"smb.conf\" file.
79If it is nil, no smb.conf will be added to the `tramp-smb-program' 79If it is nil, no \"smb.conf\" will be added to the `tramp-smb-program'
80call, letting the SMB client use the default one." 80call, letting the SMB client use the default one."
81 :group 'tramp 81 :group 'tramp
82 :type '(choice (const nil) (file :must-match t))) 82 :type '(choice (const nil) (file :must-match t)))
83 83
84;;;###tramp-autoload
85(defcustom tramp-smb-options nil
86 "List of additional options.
87They are added to the `tramp-smb-program' call via \"--option '...'\".
88
89For example, if the deprecated SMB1 protocol shall be used, add to
90this variable (\"client min protocol=NT1\") ."
91 :group 'tramp
92 :type '(repeat string)
93 :version "27.2")
94
84(defvar tramp-smb-version nil 95(defvar tramp-smb-version nil
85 "Version string of the SMB client.") 96 "Version string of the SMB client.")
86 97
@@ -135,6 +146,7 @@ call, letting the SMB client use the default one."
135 "NT_STATUS_HOST_UNREACHABLE" 146 "NT_STATUS_HOST_UNREACHABLE"
136 "NT_STATUS_IMAGE_ALREADY_LOADED" 147 "NT_STATUS_IMAGE_ALREADY_LOADED"
137 "NT_STATUS_INVALID_LEVEL" 148 "NT_STATUS_INVALID_LEVEL"
149 "NT_STATUS_INVALID_PARAMETER"
138 "NT_STATUS_INVALID_PARAMETER_MIX" 150 "NT_STATUS_INVALID_PARAMETER_MIX"
139 "NT_STATUS_IO_TIMEOUT" 151 "NT_STATUS_IO_TIMEOUT"
140 "NT_STATUS_LOGON_FAILURE" 152 "NT_STATUS_LOGON_FAILURE"
@@ -461,7 +473,8 @@ pass to the OPERATION."
461 (expand-file-name 473 (expand-file-name
462 tramp-temp-name-prefix 474 tramp-temp-name-prefix
463 (tramp-compat-temporary-file-directory)))) 475 (tramp-compat-temporary-file-directory))))
464 (args (list (concat "//" host "/" share) "-E"))) 476 (args (list (concat "//" host "/" share) "-E"))
477 (options tramp-smb-options))
465 478
466 (if (not (zerop (length user))) 479 (if (not (zerop (length user)))
467 (setq args (append args (list "-U" user))) 480 (setq args (append args (list "-U" user)))
@@ -471,6 +484,10 @@ pass to the OPERATION."
471 (when port (setq args (append args (list "-p" port)))) 484 (when port (setq args (append args (list "-p" port))))
472 (when tramp-smb-conf 485 (when tramp-smb-conf
473 (setq args (append args (list "-s" tramp-smb-conf)))) 486 (setq args (append args (list "-s" tramp-smb-conf))))
487 (while options
488 (setq args
489 (append args `("--option" ,(format "%s" (car options))))
490 options (cdr options)))
474 (setq args 491 (setq args
475 (if t1 492 (if t1
476 ;; Source is remote. 493 ;; Source is remote.
@@ -760,7 +777,8 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
760 (let* ((share (tramp-smb-get-share v)) 777 (let* ((share (tramp-smb-get-share v))
761 (localname (replace-regexp-in-string 778 (localname (replace-regexp-in-string
762 "\\\\" "/" (tramp-smb-get-localname v))) 779 "\\\\" "/" (tramp-smb-get-localname v)))
763 (args (list (concat "//" host "/" share) "-E"))) 780 (args (list (concat "//" host "/" share) "-E"))
781 (options tramp-smb-options))
764 782
765 (if (not (zerop (length user))) 783 (if (not (zerop (length user)))
766 (setq args (append args (list "-U" user))) 784 (setq args (append args (list "-U" user)))
@@ -770,6 +788,10 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
770 (when port (setq args (append args (list "-p" port)))) 788 (when port (setq args (append args (list "-p" port))))
771 (when tramp-smb-conf 789 (when tramp-smb-conf
772 (setq args (append args (list "-s" tramp-smb-conf)))) 790 (setq args (append args (list "-s" tramp-smb-conf))))
791 (while options
792 (setq args
793 (append args `("--option" ,(format "%s" (car options))))
794 options (cdr options)))
773 (setq 795 (setq
774 args 796 args
775 (append args (list (tramp-unquote-shell-quote-argument localname) 797 (append args (list (tramp-unquote-shell-quote-argument localname)
@@ -1188,9 +1210,7 @@ component is used as the target of the symlink."
1188 (let ((non-essential t)) 1210 (let ((non-essential t))
1189 (when (and (tramp-tramp-file-p target) 1211 (when (and (tramp-tramp-file-p target)
1190 (tramp-file-name-equal-p v (tramp-dissect-file-name target))) 1212 (tramp-file-name-equal-p v (tramp-dissect-file-name target)))
1191 (setq target 1213 (setq target (tramp-file-local-name (expand-file-name target)))))
1192 (tramp-file-name-localname
1193 (tramp-dissect-file-name (expand-file-name target))))))
1194 1214
1195 ;; If TARGET is still remote, quote it. 1215 ;; If TARGET is still remote, quote it.
1196 (if (tramp-tramp-file-p target) 1216 (if (tramp-tramp-file-p target)
@@ -1244,7 +1264,7 @@ component is used as the target of the symlink."
1244 (setq infile (expand-file-name infile)) 1264 (setq infile (expand-file-name infile))
1245 (if (tramp-equal-remote default-directory infile) 1265 (if (tramp-equal-remote default-directory infile)
1246 ;; INFILE is on the same remote host. 1266 ;; INFILE is on the same remote host.
1247 (setq input (with-parsed-tramp-file-name infile nil localname)) 1267 (setq input (tramp-file-local-name infile))
1248 ;; INFILE must be copied to remote host. 1268 ;; INFILE must be copied to remote host.
1249 (setq input (tramp-make-tramp-temp-file v) 1269 (setq input (tramp-make-tramp-temp-file v)
1250 tmpinput (tramp-make-tramp-file-name v input)) 1270 tmpinput (tramp-make-tramp-file-name v input))
@@ -1414,7 +1434,8 @@ component is used as the target of the symlink."
1414 "\\\\" "/" (tramp-smb-get-localname v))) 1434 "\\\\" "/" (tramp-smb-get-localname v)))
1415 (args (list (concat "//" host "/" share) "-E" "-S" 1435 (args (list (concat "//" host "/" share) "-E" "-S"
1416 (replace-regexp-in-string 1436 (replace-regexp-in-string
1417 "\n" "," acl-string)))) 1437 "\n" "," acl-string)))
1438 (options tramp-smb-options))
1418 1439
1419 (if (not (zerop (length user))) 1440 (if (not (zerop (length user)))
1420 (setq args (append args (list "-U" user))) 1441 (setq args (append args (list "-U" user)))
@@ -1424,6 +1445,10 @@ component is used as the target of the symlink."
1424 (when port (setq args (append args (list "-p" port)))) 1445 (when port (setq args (append args (list "-p" port))))
1425 (when tramp-smb-conf 1446 (when tramp-smb-conf
1426 (setq args (append args (list "-s" tramp-smb-conf)))) 1447 (setq args (append args (list "-s" tramp-smb-conf))))
1448 (while options
1449 (setq args
1450 (append args `("--option" ,(format "%s" (car options))))
1451 options (cdr options)))
1427 (setq 1452 (setq
1428 args 1453 args
1429 (append args (list (tramp-unquote-shell-quote-argument localname) 1454 (append args (list (tramp-unquote-shell-quote-argument localname)
@@ -1468,7 +1493,7 @@ component is used as the target of the symlink."
1468 (tramp-flush-connection-property v "process-name") 1493 (tramp-flush-connection-property v "process-name")
1469 (tramp-flush-connection-property v "process-buffer"))))))) 1494 (tramp-flush-connection-property v "process-buffer")))))))
1470 1495
1471(defun tramp-smb-handle-set-file-modes (filename mode) 1496(defun tramp-smb-handle-set-file-modes (filename mode &optional _flag)
1472 "Like `set-file-modes' for Tramp files." 1497 "Like `set-file-modes' for Tramp files."
1473 (with-parsed-tramp-file-name filename nil 1498 (with-parsed-tramp-file-name filename nil
1474 (when (tramp-smb-get-cifs-capabilities v) 1499 (when (tramp-smb-get-cifs-capabilities v)
@@ -1557,9 +1582,6 @@ errors for shares like \"C$/\", which are common in Microsoft Windows."
1557 (format "File %s exists; overwrite anyway? " filename))))) 1582 (format "File %s exists; overwrite anyway? " filename)))))
1558 (tramp-error v 'file-already-exists filename)) 1583 (tramp-error v 'file-already-exists filename))
1559 1584
1560 ;; We must also flush the cache of the directory, because
1561 ;; `file-attributes' reads the values from there.
1562 (tramp-flush-file-properties v localname)
1563 (let ((curbuf (current-buffer)) 1585 (let ((curbuf (current-buffer))
1564 (tmpfile (tramp-compat-make-temp-file filename))) 1586 (tmpfile (tramp-compat-make-temp-file filename)))
1565 (when (and append (file-exists-p filename)) 1587 (when (and append (file-exists-p filename))
@@ -1579,6 +1601,10 @@ errors for shares like \"C$/\", which are common in Microsoft Windows."
1579 (tramp-error v 'file-error "Cannot write `%s'" filename)) 1601 (tramp-error v 'file-error "Cannot write `%s'" filename))
1580 (delete-file tmpfile))) 1602 (delete-file tmpfile)))
1581 1603
1604 ;; We must also flush the cache of the directory, because
1605 ;; `file-attributes' reads the values from there.
1606 (tramp-flush-file-properties v localname)
1607
1582 (unless (equal curbuf (current-buffer)) 1608 (unless (equal curbuf (current-buffer))
1583 (tramp-error 1609 (tramp-error
1584 v 'file-error 1610 v 'file-error
@@ -1949,6 +1975,7 @@ If ARGUMENT is non-nil, use it as argument for
1949 (host (tramp-file-name-host vec)) 1975 (host (tramp-file-name-host vec))
1950 (domain (tramp-file-name-domain vec)) 1976 (domain (tramp-file-name-domain vec))
1951 (port (tramp-file-name-port vec)) 1977 (port (tramp-file-name-port vec))
1978 (options tramp-smb-options)
1952 args) 1979 args)
1953 1980
1954 (cond 1981 (cond
@@ -1967,6 +1994,10 @@ If ARGUMENT is non-nil, use it as argument for
1967 (when port (setq args (append args (list "-p" port)))) 1994 (when port (setq args (append args (list "-p" port))))
1968 (when tramp-smb-conf 1995 (when tramp-smb-conf
1969 (setq args (append args (list "-s" tramp-smb-conf)))) 1996 (setq args (append args (list "-s" tramp-smb-conf))))
1997 (while options
1998 (setq args
1999 (append args `("--option" ,(format "%s" (car options))))
2000 options (cdr options)))
1970 (when argument 2001 (when argument
1971 (setq args (append args (list argument)))) 2002 (setq args (append args (list argument))))
1972 2003
@@ -2132,7 +2163,5 @@ Removes smb prompt. Returns nil if an error message has appeared."
2132;; 2163;;
2133;; * Try to remove the inclusion of dummy "" directory. Seems to be at 2164;; * Try to remove the inclusion of dummy "" directory. Seems to be at
2134;; several places, especially in `tramp-smb-handle-insert-directory'. 2165;; several places, especially in `tramp-smb-handle-insert-directory'.
2135;;
2136;; * Ignore case in file names.
2137 2166
2138;;; tramp-smb.el ends here 2167;;; tramp-smb.el ends here
diff --git a/lisp/net/tramp-sudoedit.el b/lisp/net/tramp-sudoedit.el
index 08188cefde3..4af58618a6a 100644
--- a/lisp/net/tramp-sudoedit.el
+++ b/lisp/net/tramp-sudoedit.el
@@ -265,10 +265,8 @@ absolute file names."
265 v 0 (format "%s %s to %s" msg-operation filename newname) 265 v 0 (format "%s %s to %s" msg-operation filename newname)
266 (unless (tramp-sudoedit-send-command 266 (unless (tramp-sudoedit-send-command
267 v sudoedit-operation 267 v sudoedit-operation
268 (tramp-compat-file-name-unquote 268 (tramp-unquote-file-local-name filename)
269 (tramp-compat-file-local-name filename)) 269 (tramp-unquote-file-local-name newname))
270 (tramp-compat-file-name-unquote
271 (tramp-compat-file-local-name newname)))
272 (tramp-error 270 (tramp-error
273 v 'file-error 271 v 'file-error
274 "Error %s `%s' `%s'" msg-operation filename newname)))) 272 "Error %s `%s' `%s'" msg-operation filename newname))))
@@ -466,7 +464,7 @@ the result will be a local, non-Tramp, file name."
466 (tramp-sudoedit-send-command 464 (tramp-sudoedit-send-command
467 v "test" "-r" (tramp-compat-file-name-unquote localname))))) 465 v "test" "-r" (tramp-compat-file-name-unquote localname)))))
468 466
469(defun tramp-sudoedit-handle-set-file-modes (filename mode) 467(defun tramp-sudoedit-handle-set-file-modes (filename mode &optional _flag)
470 "Like `set-file-modes' for Tramp files." 468 "Like `set-file-modes' for Tramp files."
471 (with-parsed-tramp-file-name filename nil 469 (with-parsed-tramp-file-name filename nil
472 (tramp-flush-file-properties v localname) 470 (tramp-flush-file-properties v localname)
@@ -524,7 +522,7 @@ the result will be a local, non-Tramp, file name."
524 (string-to-number (match-string 2))) 522 (string-to-number (match-string 2)))
525 (string-to-number (match-string 3))))))))) 523 (string-to-number (match-string 3)))))))))
526 524
527(defun tramp-sudoedit-handle-set-file-times (filename &optional time) 525(defun tramp-sudoedit-handle-set-file-times (filename &optional time _flag)
528 "Like `set-file-times' for Tramp files." 526 "Like `set-file-times' for Tramp files."
529 (with-parsed-tramp-file-name filename nil 527 (with-parsed-tramp-file-name filename nil
530 (tramp-flush-file-properties v localname) 528 (tramp-flush-file-properties v localname)
@@ -615,9 +613,7 @@ component is used as the target of the symlink."
615 (let ((non-essential t)) 613 (let ((non-essential t))
616 (when (and (tramp-tramp-file-p target) 614 (when (and (tramp-tramp-file-p target)
617 (tramp-file-name-equal-p v (tramp-dissect-file-name target))) 615 (tramp-file-name-equal-p v (tramp-dissect-file-name target)))
618 (setq target 616 (setq target (tramp-file-local-name (expand-file-name target)))))
619 (tramp-file-name-localname
620 (tramp-dissect-file-name (expand-file-name target))))))
621 617
622 ;; If TARGET is still remote, quote it. 618 ;; If TARGET is still remote, quote it.
623 (if (tramp-tramp-file-p target) 619 (if (tramp-tramp-file-p target)
@@ -715,8 +711,7 @@ ID-FORMAT valid values are `string' and `integer'."
715 (format "%d:%d" 711 (format "%d:%d"
716 (or uid (tramp-sudoedit-get-remote-uid v 'integer)) 712 (or uid (tramp-sudoedit-get-remote-uid v 'integer))
717 (or gid (tramp-sudoedit-get-remote-gid v 'integer))) 713 (or gid (tramp-sudoedit-get-remote-gid v 'integer)))
718 (tramp-compat-file-name-unquote 714 (tramp-unquote-file-local-name filename))))
719 (tramp-compat-file-local-name filename)))))
720 715
721(defun tramp-sudoedit-handle-write-region 716(defun tramp-sudoedit-handle-write-region
722 (start end filename &optional append visit lockname mustbenew) 717 (start end filename &optional append visit lockname mustbenew)
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 4f3249d966a..2e6fbe1c767 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -7,7 +7,7 @@
7;; Maintainer: Michael Albinus <michael.albinus@gmx.de> 7;; Maintainer: Michael Albinus <michael.albinus@gmx.de>
8;; Keywords: comm, processes 8;; Keywords: comm, processes
9;; Package: tramp 9;; Package: tramp
10;; Version: 2.4.3 10;; Version: 2.4.5-pre
11;; Package-Requires: ((emacs "24.4")) 11;; Package-Requires: ((emacs "24.4"))
12;; Package-Type: multi 12;; Package-Type: multi
13;; URL: https://savannah.gnu.org/projects/tramp 13;; URL: https://savannah.gnu.org/projects/tramp
@@ -37,7 +37,7 @@
37;; For more detailed instructions, please see the info file. 37;; For more detailed instructions, please see the info file.
38;; 38;;
39;; Notes: 39;; Notes:
40;; ----- 40;; ------
41;; 41;;
42;; Also see the todo list at the bottom of this file. 42;; Also see the todo list at the bottom of this file.
43;; 43;;
@@ -46,6 +46,7 @@
46;; 46;;
47;; There's a mailing list for this, as well. Its name is: 47;; There's a mailing list for this, as well. Its name is:
48;; tramp-devel@gnu.org 48;; tramp-devel@gnu.org
49
49;; You can use the Web to subscribe, under the following URL: 50;; You can use the Web to subscribe, under the following URL:
50;; https://lists.gnu.org/mailman/listinfo/tramp-devel 51;; https://lists.gnu.org/mailman/listinfo/tramp-devel
51;; 52;;
@@ -1347,6 +1348,11 @@ of `process-file', `start-file-process', or `shell-command'."
1347 (match-string (nth 4 tramp-file-name-structure) name)) 1348 (match-string (nth 4 tramp-file-name-structure) name))
1348 (tramp-compat-file-local-name name))) 1349 (tramp-compat-file-local-name name)))
1349 1350
1351;; The localname can be quoted with "/:". Extract this.
1352(defun tramp-unquote-file-local-name (name)
1353 "Return unquoted localname of NAME."
1354 (tramp-compat-file-name-unquote (tramp-file-local-name name)))
1355
1350(defun tramp-find-method (method user host) 1356(defun tramp-find-method (method user host)
1351 "Return the right method string to use depending on USER and HOST. 1357 "Return the right method string to use depending on USER and HOST.
1352This is METHOD, if non-nil. Otherwise, do a lookup in 1358This is METHOD, if non-nil. Otherwise, do a lookup in
@@ -1592,7 +1598,7 @@ necessary only. This function will be used in file name completion."
1592 tramp-prefix-ipv6-format host tramp-postfix-ipv6-format) 1598 tramp-prefix-ipv6-format host tramp-postfix-ipv6-format)
1593 host) 1599 host)
1594 tramp-postfix-host-format)) 1600 tramp-postfix-host-format))
1595 (when localname localname))) 1601 localname))
1596 1602
1597(defun tramp-get-buffer (vec &optional dont-create) 1603(defun tramp-get-buffer (vec &optional dont-create)
1598 "Get the connection buffer to be used for VEC. 1604 "Get the connection buffer to be used for VEC.
@@ -1648,7 +1654,7 @@ version, the function does nothing."
1648 "Set connection-local variables in the current buffer. 1654 "Set connection-local variables in the current buffer.
1649If connection-local variables are not supported by this Emacs 1655If connection-local variables are not supported by this Emacs
1650version, the function does nothing." 1656version, the function does nothing."
1651 (when (file-remote-p default-directory) 1657 (when (tramp-tramp-file-p default-directory)
1652 ;; `hack-connection-local-variables-apply' exists since Emacs 26.1. 1658 ;; `hack-connection-local-variables-apply' exists since Emacs 26.1.
1653 (tramp-compat-funcall 1659 (tramp-compat-funcall
1654 'hack-connection-local-variables-apply 1660 'hack-connection-local-variables-apply
@@ -2864,7 +2870,7 @@ User is always nil."
2864 (let ((default-directory (tramp-compat-temporary-file-directory))) 2870 (let ((default-directory (tramp-compat-temporary-file-directory)))
2865 (when (file-readable-p filename) 2871 (when (file-readable-p filename)
2866 (with-temp-buffer 2872 (with-temp-buffer
2867 (insert-file-contents filename) 2873 (insert-file-contents-literally filename)
2868 (goto-char (point-min)) 2874 (goto-char (point-min))
2869 (cl-loop while (not (eobp)) collect (funcall function)))))) 2875 (cl-loop while (not (eobp)) collect (funcall function))))))
2870 2876
@@ -3199,7 +3205,7 @@ User is always nil."
3199 (copy-file filename tmpfile 'ok-if-already-exists 'keep-time) 3205 (copy-file filename tmpfile 'ok-if-already-exists 'keep-time)
3200 tmpfile))) 3206 tmpfile)))
3201 3207
3202(defun tramp-handle-file-modes (filename) 3208(defun tramp-handle-file-modes (filename &optional _flag)
3203 "Like `file-modes' for Tramp files." 3209 "Like `file-modes' for Tramp files."
3204 ;; Starting with Emacs 25.1, `when-let' can be used. 3210 ;; Starting with Emacs 25.1, `when-let' can be used.
3205 (let ((attrs (file-attributes (or (file-truename filename) filename)))) 3211 (let ((attrs (file-attributes (or (file-truename filename) filename))))
@@ -3247,7 +3253,7 @@ User is always nil."
3247 ;; lower case letters. This avoids us to create a 3253 ;; lower case letters. This avoids us to create a
3248 ;; temporary file. 3254 ;; temporary file.
3249 (while (and (string-match-p 3255 (while (and (string-match-p
3250 "[a-z]" (tramp-compat-file-local-name candidate)) 3256 "[a-z]" (tramp-file-local-name candidate))
3251 (not (file-exists-p candidate))) 3257 (not (file-exists-p candidate)))
3252 (setq candidate 3258 (setq candidate
3253 (directory-file-name 3259 (directory-file-name
@@ -3257,8 +3263,7 @@ User is always nil."
3257 ;; to Emacs 26+ like `file-name-case-insensitive-p', 3263 ;; to Emacs 26+ like `file-name-case-insensitive-p',
3258 ;; so there is no compatibility problem calling it. 3264 ;; so there is no compatibility problem calling it.
3259 (unless 3265 (unless
3260 (string-match-p 3266 (string-match-p "[a-z]" (tramp-file-local-name candidate))
3261 "[a-z]" (tramp-compat-file-local-name candidate))
3262 (setq tmpfile 3267 (setq tmpfile
3263 (let ((default-directory 3268 (let ((default-directory
3264 (file-name-directory filename))) 3269 (file-name-directory filename)))
@@ -3271,7 +3276,7 @@ User is always nil."
3271 (file-exists-p 3276 (file-exists-p
3272 (concat 3277 (concat
3273 (file-remote-p candidate) 3278 (file-remote-p candidate)
3274 (upcase (tramp-compat-file-local-name candidate)))) 3279 (upcase (tramp-file-local-name candidate))))
3275 ;; Cleanup. 3280 ;; Cleanup.
3276 (when tmpfile (delete-file tmpfile))))))))))) 3281 (when tmpfile (delete-file tmpfile)))))))))))
3277 3282
@@ -3413,7 +3418,7 @@ User is always nil."
3413 (tramp-error 3418 (tramp-error
3414 v1 'file-error 3419 v1 'file-error
3415 "Maximum number (%d) of symlinks exceeded" numchase-limit))) 3420 "Maximum number (%d) of symlinks exceeded" numchase-limit)))
3416 (tramp-compat-file-local-name (directory-file-name result))))))))) 3421 (tramp-file-local-name (directory-file-name result)))))))))
3417 3422
3418(defun tramp-handle-file-writable-p (filename) 3423(defun tramp-handle-file-writable-p (filename)
3419 "Like `file-writable-p' for Tramp files." 3424 "Like `file-writable-p' for Tramp files."
@@ -3645,10 +3650,16 @@ support symbolic links."
3645 (let* ((asynchronous (string-match-p "[ \t]*&[ \t]*\\'" command)) 3650 (let* ((asynchronous (string-match-p "[ \t]*&[ \t]*\\'" command))
3646 (command (substring command 0 asynchronous)) 3651 (command (substring command 0 asynchronous))
3647 current-buffer-p 3652 current-buffer-p
3653 (output-buffer-p output-buffer)
3648 (output-buffer 3654 (output-buffer
3649 (cond 3655 (cond
3650 ((bufferp output-buffer) output-buffer) 3656 ((bufferp output-buffer)
3651 ((stringp output-buffer) (get-buffer-create output-buffer)) 3657 (setq current-buffer-p (eq (current-buffer) output-buffer))
3658 output-buffer)
3659 ((stringp output-buffer)
3660 (setq current-buffer-p
3661 (eq (buffer-name (current-buffer)) output-buffer))
3662 (get-buffer-create output-buffer))
3652 (output-buffer 3663 (output-buffer
3653 (setq current-buffer-p t) 3664 (setq current-buffer-p t)
3654 (current-buffer)) 3665 (current-buffer))
@@ -3660,13 +3671,19 @@ support symbolic links."
3660 (cond 3671 (cond
3661 ((bufferp error-buffer) error-buffer) 3672 ((bufferp error-buffer) error-buffer)
3662 ((stringp error-buffer) (get-buffer-create error-buffer)))) 3673 ((stringp error-buffer) (get-buffer-create error-buffer))))
3674 (error-file
3675 (and error-buffer
3676 (with-parsed-tramp-file-name default-directory nil
3677 (tramp-make-tramp-file-name
3678 v (tramp-make-tramp-temp-file v)))))
3663 (bname (buffer-name output-buffer)) 3679 (bname (buffer-name output-buffer))
3664 (p (get-buffer-process output-buffer)) 3680 (p (get-buffer-process output-buffer))
3681 (dir default-directory)
3665 buffer) 3682 buffer)
3666 3683
3667 ;; The following code is taken from `shell-command', slightly 3684 ;; The following code is taken from `shell-command', slightly
3668 ;; adapted. Shouldn't it be factored out? 3685 ;; adapted. Shouldn't it be factored out?
3669 (when p 3686 (when (and (integerp asynchronous) p)
3670 (cond 3687 (cond
3671 ((eq async-shell-command-buffer 'confirm-kill-process) 3688 ((eq async-shell-command-buffer 'confirm-kill-process)
3672 ;; If will kill a process, query first. 3689 ;; If will kill a process, query first.
@@ -3698,22 +3715,25 @@ support symbolic links."
3698 (rename-uniquely)) 3715 (rename-uniquely))
3699 (setq output-buffer (get-buffer-create bname))))) 3716 (setq output-buffer (get-buffer-create bname)))))
3700 3717
3701 (setq buffer (if (and (not asynchronous) error-buffer) 3718 (unless output-buffer-p
3702 (with-parsed-tramp-file-name default-directory nil
3703 (list output-buffer
3704 (tramp-make-tramp-file-name
3705 v (tramp-make-tramp-temp-file v))))
3706 output-buffer))
3707
3708 (if current-buffer-p
3709 (progn
3710 (barf-if-buffer-read-only)
3711 (push-mark nil t))
3712 (with-current-buffer output-buffer 3719 (with-current-buffer output-buffer
3720 (setq default-directory dir)))
3721
3722 (setq buffer (if error-file (list output-buffer error-file) output-buffer))
3723
3724 (with-current-buffer output-buffer
3725 (when current-buffer-p
3726 (barf-if-buffer-read-only)
3727 (push-mark nil t))
3728 ;; `shell-command-save-pos-or-erase' has been introduced with
3729 ;; Emacs 27.1.
3730 (if (fboundp 'shell-command-save-pos-or-erase)
3731 (tramp-compat-funcall
3732 'shell-command-save-pos-or-erase current-buffer-p)
3713 (setq buffer-read-only nil) 3733 (setq buffer-read-only nil)
3714 (erase-buffer))) 3734 (erase-buffer)))
3715 3735
3716 (if (and (not current-buffer-p) (integerp asynchronous)) 3736 (if (integerp asynchronous)
3717 (let ((tramp-remote-process-environment 3737 (let ((tramp-remote-process-environment
3718 ;; `async-shell-command-width' has been introduced with 3738 ;; `async-shell-command-width' has been introduced with
3719 ;; Emacs 27.1. 3739 ;; Emacs 27.1.
@@ -3726,42 +3746,68 @@ support symbolic links."
3726 ;; Run the process. 3746 ;; Run the process.
3727 (setq p (start-file-process-shell-command 3747 (setq p (start-file-process-shell-command
3728 (buffer-name output-buffer) buffer command)) 3748 (buffer-name output-buffer) buffer command))
3729 ;; Display output. 3749 ;; Insert error messages if they were separated.
3730 (with-current-buffer output-buffer 3750 (when error-file
3731 (display-buffer output-buffer '(nil (allow-no-window . t))) 3751 (with-current-buffer error-buffer
3732 (setq mode-line-process '(":%s")) 3752 (insert-file-contents-literally error-file)))
3733 (shell-mode) 3753 (if (process-live-p p)
3734 (set-process-sentinel p #'shell-command-sentinel) 3754 ;; Display output.
3735 (set-process-filter p #'comint-output-filter)))) 3755 (with-current-buffer output-buffer
3756 (setq mode-line-process '(":%s"))
3757 (unless (eq major-mode 'shell-mode)
3758 (shell-mode))
3759 (set-process-filter p #'comint-output-filter)
3760 (set-process-sentinel p #'shell-command-sentinel)
3761 (when error-file
3762 (add-function
3763 :after (process-sentinel p)
3764 (lambda (_proc _string)
3765 (with-current-buffer error-buffer
3766 (insert-file-contents-literally
3767 error-file nil nil nil 'replace))
3768 (delete-file error-file))))
3769 (display-buffer output-buffer '(nil (allow-no-window . t))))
3770
3771 (when error-file
3772 (delete-file error-file)))))
3736 3773
3737 (prog1 3774 (prog1
3738 ;; Run the process. 3775 ;; Run the process.
3739 (process-file-shell-command command nil buffer nil) 3776 (process-file-shell-command command nil buffer nil)
3740 ;; Insert error messages if they were separated. 3777 ;; Insert error messages if they were separated.
3741 (when (listp buffer) 3778 (when error-file
3742 (with-current-buffer error-buffer 3779 (with-current-buffer error-buffer
3743 (insert-file-contents (cadr buffer))) 3780 (insert-file-contents-literally error-file))
3744 (delete-file (cadr buffer))) 3781 (delete-file error-file))
3745 (if current-buffer-p 3782 (if current-buffer-p
3746 ;; This is like exchange-point-and-mark, but doesn't 3783 ;; This is like exchange-point-and-mark, but doesn't
3747 ;; activate the mark. It is cleaner to avoid activation, 3784 ;; activate the mark. It is cleaner to avoid activation,
3748 ;; even though the command loop would deactivate the mark 3785 ;; even though the command loop would deactivate the mark
3749 ;; because we inserted text. 3786 ;; because we inserted text.
3750 (goto-char (prog1 (mark t) 3787 (progn
3751 (set-marker (mark-marker) (point) 3788 (goto-char (prog1 (mark t)
3752 (current-buffer)))) 3789 (set-marker (mark-marker) (point)
3790 (current-buffer))))
3791 ;; `shell-command-set-point-after-cmd' has been
3792 ;; introduced with Emacs 27.1.
3793 (if (fboundp 'shell-command-set-point-after-cmd)
3794 (tramp-compat-funcall
3795 'shell-command-set-point-after-cmd)))
3753 ;; There's some output, display it. 3796 ;; There's some output, display it.
3754 (when (with-current-buffer output-buffer (> (point-max) (point-min))) 3797 (when (with-current-buffer output-buffer (> (point-max) (point-min)))
3755 (display-message-or-buffer output-buffer))))))) 3798 (display-message-or-buffer output-buffer)))))))
3756 3799
3757(defun tramp-handle-start-file-process (name buffer program &rest args) 3800(defun tramp-handle-start-file-process (name buffer program &rest args)
3758 "Like `start-file-process' for Tramp files." 3801 "Like `start-file-process' for Tramp files.
3802BUFFER might be a list, in this case STDERR is separated."
3759 ;; `make-process' knows the `:file-handler' argument since Emacs 27.1 only. 3803 ;; `make-process' knows the `:file-handler' argument since Emacs 27.1 only.
3760 (tramp-file-name-handler 3804 (tramp-file-name-handler
3761 'make-process 3805 'make-process
3762 :name name 3806 :name name
3763 :buffer buffer 3807 :buffer (if (consp buffer) (car buffer) buffer)
3764 :command (and program (cons program args)) 3808 :command (and program (cons program args))
3809 ;; `shell-command' adds an errfile to `buffer'.
3810 :stderr (when (consp buffer) (cadr buffer))
3765 :noquery nil 3811 :noquery nil
3766 :file-handler t)) 3812 :file-handler t))
3767 3813
@@ -4044,6 +4090,8 @@ The terminal type can be configured with `tramp-terminal-type'."
4044(defun tramp-action-process-alive (proc _vec) 4090(defun tramp-action-process-alive (proc _vec)
4045 "Check, whether a process has finished." 4091 "Check, whether a process has finished."
4046 (unless (process-live-p proc) 4092 (unless (process-live-p proc)
4093 ;; There might be pending output.
4094 (while (tramp-accept-process-output proc 0))
4047 (throw 'tramp-action 'process-died))) 4095 (throw 'tramp-action 'process-died)))
4048 4096
4049(defun tramp-action-out-of-band (proc vec) 4097(defun tramp-action-out-of-band (proc vec)
@@ -4362,7 +4410,7 @@ would yield t. On the other hand, the following check results in nil:
4362 (tramp-equal-remote \"/sudo::/etc\" \"/su::/etc\") 4410 (tramp-equal-remote \"/sudo::/etc\" \"/su::/etc\")
4363 4411
4364If both files are local, the function returns t." 4412If both files are local, the function returns t."
4365 (or (and (null (file-remote-p file1)) (null (file-remote-p file2))) 4413 (or (and (null (tramp-tramp-file-p file1)) (null (tramp-tramp-file-p file2)))
4366 (and (tramp-tramp-file-p file1) (tramp-tramp-file-p file2) 4414 (and (tramp-tramp-file-p file1) (tramp-tramp-file-p file2)
4367 (string-equal (file-remote-p file1) (file-remote-p file2))))) 4415 (string-equal (file-remote-p file1) (file-remote-p file2)))))
4368 4416
@@ -4632,7 +4680,7 @@ This handles also chrooted environments, which are not regarded as local."
4632 (tramp-make-tramp-file-name 4680 (tramp-make-tramp-file-name
4633 vec (or (tramp-get-method-parameter vec 'tramp-tmpdir) "/tmp")))) 4681 vec (or (tramp-get-method-parameter vec 'tramp-tmpdir) "/tmp"))))
4634 (or (and (file-directory-p dir) (file-writable-p dir) 4682 (or (and (file-directory-p dir) (file-writable-p dir)
4635 (tramp-compat-file-local-name dir)) 4683 (tramp-file-local-name dir))
4636 (tramp-error vec 'file-error "Directory %s not accessible" dir)) 4684 (tramp-error vec 'file-error "Directory %s not accessible" dir))
4637 dir))) 4685 dir)))
4638 4686
@@ -4655,7 +4703,7 @@ Return the local name of the temporary file."
4655 (set-file-modes result #o0700))) 4703 (set-file-modes result #o0700)))
4656 4704
4657 ;; Return the local part. 4705 ;; Return the local part.
4658 (with-parsed-tramp-file-name result nil localname))) 4706 (tramp-file-local-name result)))
4659 4707
4660(defun tramp-delete-temp-file-function () 4708(defun tramp-delete-temp-file-function ()
4661 "Remove temporary files related to current buffer." 4709 "Remove temporary files related to current buffer."
@@ -4682,7 +4730,7 @@ this file, if that variable is non-nil."
4682 4730
4683 (let ((system-type 4731 (let ((system-type
4684 (if (and (stringp tramp-auto-save-directory) 4732 (if (and (stringp tramp-auto-save-directory)
4685 (file-remote-p tramp-auto-save-directory)) 4733 (tramp-tramp-file-p tramp-auto-save-directory))
4686 'not-windows 4734 'not-windows
4687 system-type)) 4735 system-type))
4688 (auto-save-file-name-transforms 4736 (auto-save-file-name-transforms
@@ -4824,7 +4872,12 @@ verbosity of 6."
4824 "Read a password from user (compat function). 4872 "Read a password from user (compat function).
4825Consults the auth-source package. 4873Consults the auth-source package.
4826Invokes `password-read' if available, `read-passwd' else." 4874Invokes `password-read' if available, `read-passwd' else."
4827 (let* ((case-fold-search t) 4875 (let* (;; If `auth-sources' contains "~/.authinfo.gpg", and
4876 ;; `exec-path' contains a relative file name like ".", it
4877 ;; could happen that the "gpg" command is not found. So we
4878 ;; adapt `default-directory'. (Bug#39389, Bug#39489)
4879 (default-directory (tramp-compat-temporary-file-directory))
4880 (case-fold-search t)
4828 (key (tramp-make-tramp-file-name 4881 (key (tramp-make-tramp-file-name
4829 ;; In tramp-sh.el, we must use "password-vector" due to 4882 ;; In tramp-sh.el, we must use "password-vector" due to
4830 ;; multi-hop. 4883 ;; multi-hop.
@@ -4976,10 +5029,12 @@ name of a process or buffer, or nil to default to the current buffer."
4976 (tramp-error proc 'error "Process %s is not active" proc) 5029 (tramp-error proc 'error "Process %s is not active" proc)
4977 (tramp-message proc 5 "Interrupt process %s with pid %s" proc pid) 5030 (tramp-message proc 5 "Interrupt process %s with pid %s" proc pid)
4978 ;; This is for tramp-sh.el. Other backends do not support this (yet). 5031 ;; This is for tramp-sh.el. Other backends do not support this (yet).
5032 ;; Not all "kill" implementations support process groups by
5033 ;; negative pid, so we try both variants.
4979 (tramp-compat-funcall 5034 (tramp-compat-funcall
4980 'tramp-send-command 5035 'tramp-send-command
4981 (process-get proc 'vector) 5036 (process-get proc 'vector)
4982 (format "kill -2 -%d" pid)) 5037 (format "(\\kill -2 -%d || \\kill -2 %d) 2>/dev/null" pid pid))
4983 ;; Wait, until the process has disappeared. If it doesn't, 5038 ;; Wait, until the process has disappeared. If it doesn't,
4984 ;; fall back to the default implementation. 5039 ;; fall back to the default implementation.
4985 (while (tramp-accept-process-output proc 0)) 5040 (while (tramp-accept-process-output proc 0))
diff --git a/lisp/net/trampver.el b/lisp/net/trampver.el
index dacdd44102f..4aed8abd9b3 100644
--- a/lisp/net/trampver.el
+++ b/lisp/net/trampver.el
@@ -39,7 +39,7 @@
39(defvar inhibit-message) 39(defvar inhibit-message)
40 40
41;;;###tramp-autoload 41;;;###tramp-autoload
42(defconst tramp-version "2.4.3.27.1" 42(defconst tramp-version "2.4.5-pre"
43 "This version of Tramp.") 43 "This version of Tramp.")
44 44
45;;;###tramp-autoload 45;;;###tramp-autoload
@@ -51,6 +51,7 @@
51 ;; Suppress message from `emacs-repository-get-branch'. We must 51 ;; Suppress message from `emacs-repository-get-branch'. We must
52 ;; also handle out-of-tree builds. 52 ;; also handle out-of-tree builds.
53 (let ((inhibit-message t) 53 (let ((inhibit-message t)
54 (debug-on-error nil)
54 (dir (or (locate-dominating-file (locate-library "tramp") ".git") 55 (dir (or (locate-dominating-file (locate-library "tramp") ".git")
55 source-directory))) 56 source-directory)))
56 ;; `emacs-repository-get-branch' has been introduced with Emacs 27.1. 57 ;; `emacs-repository-get-branch' has been introduced with Emacs 27.1.
@@ -64,6 +65,7 @@
64 ;; Suppress message from `emacs-repository-get-version'. We must 65 ;; Suppress message from `emacs-repository-get-version'. We must
65 ;; also handle out-of-tree builds. 66 ;; also handle out-of-tree builds.
66 (let ((inhibit-message t) 67 (let ((inhibit-message t)
68 (debug-on-error nil)
67 (dir (or (locate-dominating-file (locate-library "tramp") ".git") 69 (dir (or (locate-dominating-file (locate-library "tramp") ".git")
68 source-directory))) 70 source-directory)))
69 (and (stringp dir) (file-directory-p dir) 71 (and (stringp dir) (file-directory-p dir)
@@ -73,7 +75,7 @@
73;; Check for Emacs version. 75;; Check for Emacs version.
74(let ((x (if (not (string-lessp emacs-version "24.4")) 76(let ((x (if (not (string-lessp emacs-version "24.4"))
75 "ok" 77 "ok"
76 (format "Tramp 2.4.3.27.1 is not fit for %s" 78 (format "Tramp 2.4.5-pre is not fit for %s"
77 (replace-regexp-in-string "\n" "" (emacs-version)))))) 79 (replace-regexp-in-string "\n" "" (emacs-version))))))
78 (unless (string-equal "ok" x) (error "%s" x))) 80 (unless (string-equal "ok" x) (error "%s" x)))
79 81
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el
index 544bdb5c058..9e46d7f538b 100644
--- a/test/lisp/net/tramp-tests.el
+++ b/test/lisp/net/tramp-tests.el
@@ -50,6 +50,7 @@
50(require 'vc-hg) 50(require 'vc-hg)
51 51
52(declare-function tramp-find-executable "tramp-sh") 52(declare-function tramp-find-executable "tramp-sh")
53(declare-function tramp-get-remote-gid "tramp-sh")
53(declare-function tramp-get-remote-path "tramp-sh") 54(declare-function tramp-get-remote-path "tramp-sh")
54(declare-function tramp-get-remote-perl "tramp-sh") 55(declare-function tramp-get-remote-perl "tramp-sh")
55(declare-function tramp-get-remote-stat "tramp-sh") 56(declare-function tramp-get-remote-stat "tramp-sh")
@@ -74,6 +75,9 @@
74(defvar connection-local-profile-alist) 75(defvar connection-local-profile-alist)
75;; Needed for Emacs 26. 76;; Needed for Emacs 26.
76(defvar async-shell-command-width) 77(defvar async-shell-command-width)
78;; Needed for Emacs 27.
79(defvar process-file-return-signal-string)
80(defvar shell-command-dont-erase-buffer)
77 81
78;; Beautify batch mode. 82;; Beautify batch mode.
79(when noninteractive 83(when noninteractive
@@ -2357,7 +2361,14 @@ This checks also `file-name-as-directory', `file-name-directory',
2357 (write-region nil nil tmp-name 3)) 2361 (write-region nil nil tmp-name 3))
2358 (with-temp-buffer 2362 (with-temp-buffer
2359 (insert-file-contents tmp-name) 2363 (insert-file-contents tmp-name)
2360 (should (string-equal (buffer-string) "foobaz")))) 2364 (should (string-equal (buffer-string) "foobaz")))
2365 (delete-file tmp-name)
2366 (with-temp-buffer
2367 (insert "foo")
2368 (write-region nil nil tmp-name 'append))
2369 (with-temp-buffer
2370 (insert-file-contents tmp-name)
2371 (should (string-equal (buffer-string) "foo"))))
2361 2372
2362 ;; Write string. 2373 ;; Write string.
2363 (write-region "foo" nil tmp-name) 2374 (write-region "foo" nil tmp-name)
@@ -2393,14 +2404,14 @@ This checks also `file-name-as-directory', `file-name-directory',
2393 tramp--test-messages)))))))) 2404 tramp--test-messages))))))))
2394 2405
2395 ;; Do not overwrite if excluded. 2406 ;; Do not overwrite if excluded.
2396 (cl-letf (((symbol-function 'y-or-n-p) (lambda (_prompt) t)) 2407 (cl-letf (((symbol-function #'y-or-n-p) (lambda (_prompt) t))
2397 ;; Ange-FTP. 2408 ;; Ange-FTP.
2398 ((symbol-function 'yes-or-no-p) (lambda (_prompt) t))) 2409 ((symbol-function 'yes-or-no-p) (lambda (_prompt) t)))
2399 (write-region "foo" nil tmp-name nil nil nil 'mustbenew)) 2410 (write-region "foo" nil tmp-name nil nil nil 'mustbenew))
2400 ;; `mustbenew' is passed to Tramp since Emacs 26.1. 2411 ;; `mustbenew' is passed to Tramp since Emacs 26.1.
2401 (when (tramp--test-emacs26-p) 2412 (when (tramp--test-emacs26-p)
2402 (should-error 2413 (should-error
2403 (cl-letf (((symbol-function 'y-or-n-p) 'ignore) 2414 (cl-letf (((symbol-function #'y-or-n-p) #'ignore)
2404 ;; Ange-FTP. 2415 ;; Ange-FTP.
2405 ((symbol-function 'yes-or-no-p) 'ignore)) 2416 ((symbol-function 'yes-or-no-p) 'ignore))
2406 (write-region "foo" nil tmp-name nil nil nil 'mustbenew)) 2417 (write-region "foo" nil tmp-name nil nil nil 'mustbenew))
@@ -3115,22 +3126,38 @@ This tests also `access-file', `file-readable-p',
3115 (file-remote-p tmp-name1) 3126 (file-remote-p tmp-name1)
3116 (replace-regexp-in-string 3127 (replace-regexp-in-string
3117 "/" "//" (file-remote-p tmp-name1 'localname)))) 3128 "/" "//" (file-remote-p tmp-name1 'localname))))
3129 ;; `file-ownership-preserved-p' is implemented only in tramp-sh.el.
3130 (test-file-ownership-preserved-p (tramp--test-sh-p))
3118 attr) 3131 attr)
3119 (unwind-protect 3132 (unwind-protect
3120 (progn 3133 (progn
3134 ;; A sticky bit could damage the `file-ownership-preserved-p' test.
3135 (when
3136 (and test-file-ownership-preserved-p
3137 (zerop (logand
3138 #o1000
3139 (file-modes tramp-test-temporary-file-directory))))
3140 (write-region "foo" nil tmp-name1)
3141 (setq test-file-ownership-preserved-p
3142 (= (tramp-compat-file-attribute-group-id
3143 (file-attributes tmp-name1))
3144 (tramp-get-remote-gid
3145 (tramp-dissect-file-name tmp-name1) 'integer)))
3146 (delete-file tmp-name1))
3147
3121 (should-error 3148 (should-error
3122 (access-file tmp-name1 "error") 3149 (access-file tmp-name1 "error")
3123 :type tramp-file-missing) 3150 :type tramp-file-missing)
3124 ;; `file-ownership-preserved-p' should return t for 3151 ;; `file-ownership-preserved-p' should return t for
3125 ;; non-existing files. It is implemented only in tramp-sh.el. 3152 ;; non-existing files.
3126 (when (tramp--test-sh-p) 3153 (when test-file-ownership-preserved-p
3127 (should (file-ownership-preserved-p tmp-name1 'group))) 3154 (should (file-ownership-preserved-p tmp-name1 'group)))
3128 (write-region "foo" nil tmp-name1) 3155 (write-region "foo" nil tmp-name1)
3129 (should (file-exists-p tmp-name1)) 3156 (should (file-exists-p tmp-name1))
3130 (should (file-readable-p tmp-name1)) 3157 (should (file-readable-p tmp-name1))
3131 (should (file-regular-p tmp-name1)) 3158 (should (file-regular-p tmp-name1))
3132 (should-not (access-file tmp-name1 "error")) 3159 (should-not (access-file tmp-name1 "error"))
3133 (when (tramp--test-sh-p) 3160 (when test-file-ownership-preserved-p
3134 (should (file-ownership-preserved-p tmp-name1 'group))) 3161 (should (file-ownership-preserved-p tmp-name1 'group)))
3135 3162
3136 ;; We do not test inodes and device numbers. 3163 ;; We do not test inodes and device numbers.
@@ -3160,16 +3187,16 @@ This tests also `access-file', `file-readable-p',
3160 (should (stringp (tramp-compat-file-attribute-group-id attr))) 3187 (should (stringp (tramp-compat-file-attribute-group-id attr)))
3161 3188
3162 (tramp--test-ignore-make-symbolic-link-error 3189 (tramp--test-ignore-make-symbolic-link-error
3163 (should-error 3190 (should-error
3164 (access-file tmp-name2 "error") 3191 (access-file tmp-name2 "error")
3165 :type tramp-file-missing) 3192 :type tramp-file-missing)
3166 (when (tramp--test-sh-p) 3193 (when test-file-ownership-preserved-p
3167 (should (file-ownership-preserved-p tmp-name2 'group))) 3194 (should (file-ownership-preserved-p tmp-name2 'group)))
3168 (make-symbolic-link tmp-name1 tmp-name2) 3195 (make-symbolic-link tmp-name1 tmp-name2)
3169 (should (file-exists-p tmp-name2)) 3196 (should (file-exists-p tmp-name2))
3170 (should (file-symlink-p tmp-name2)) 3197 (should (file-symlink-p tmp-name2))
3171 (should-not (access-file tmp-name2 "error")) 3198 (should-not (access-file tmp-name2 "error"))
3172 (when (tramp--test-sh-p) 3199 (when test-file-ownership-preserved-p
3173 (should (file-ownership-preserved-p tmp-name2 'group))) 3200 (should (file-ownership-preserved-p tmp-name2 'group)))
3174 (setq attr (file-attributes tmp-name2)) 3201 (setq attr (file-attributes tmp-name2))
3175 (should 3202 (should
@@ -3200,7 +3227,7 @@ This tests also `access-file', `file-readable-p',
3200 (tramp-dissect-file-name tmp-name3)))) 3227 (tramp-dissect-file-name tmp-name3))))
3201 (delete-file tmp-name2)) 3228 (delete-file tmp-name2))
3202 3229
3203 (when (tramp--test-sh-p) 3230 (when test-file-ownership-preserved-p
3204 (should (file-ownership-preserved-p tmp-name1 'group))) 3231 (should (file-ownership-preserved-p tmp-name1 'group)))
3205 (delete-file tmp-name1) 3232 (delete-file tmp-name1)
3206 (make-directory tmp-name1) 3233 (make-directory tmp-name1)
@@ -3208,7 +3235,7 @@ This tests also `access-file', `file-readable-p',
3208 (should (file-readable-p tmp-name1)) 3235 (should (file-readable-p tmp-name1))
3209 (should-not (file-regular-p tmp-name1)) 3236 (should-not (file-regular-p tmp-name1))
3210 (should-not (access-file tmp-name1 "")) 3237 (should-not (access-file tmp-name1 ""))
3211 (when (tramp--test-sh-p) 3238 (when test-file-ownership-preserved-p
3212 (should (file-ownership-preserved-p tmp-name1 'group))) 3239 (should (file-ownership-preserved-p tmp-name1 'group)))
3213 (setq attr (file-attributes tmp-name1)) 3240 (setq attr (file-attributes tmp-name1))
3214 (should (eq (tramp-compat-file-attribute-type attr) t))) 3241 (should (eq (tramp-compat-file-attribute-type attr) t)))
@@ -3420,11 +3447,11 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
3420 :type 'file-already-exists)) 3447 :type 'file-already-exists))
3421 (when (tramp--test-expensive-test) 3448 (when (tramp--test-expensive-test)
3422 ;; A number means interactive case. 3449 ;; A number means interactive case.
3423 (cl-letf (((symbol-function 'yes-or-no-p) #'ignore)) 3450 (cl-letf (((symbol-function #'yes-or-no-p) #'ignore))
3424 (should-error 3451 (should-error
3425 (make-symbolic-link tmp-name1 tmp-name2 0) 3452 (make-symbolic-link tmp-name1 tmp-name2 0)
3426 :type 'file-already-exists))) 3453 :type 'file-already-exists)))
3427 (cl-letf (((symbol-function 'yes-or-no-p) (lambda (_prompt) t))) 3454 (cl-letf (((symbol-function #'yes-or-no-p) (lambda (_prompt) t)))
3428 (make-symbolic-link tmp-name1 tmp-name2 0) 3455 (make-symbolic-link tmp-name1 tmp-name2 0)
3429 (should 3456 (should
3430 (string-equal 3457 (string-equal
@@ -3496,11 +3523,11 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
3496 (add-name-to-file tmp-name1 tmp-name2) 3523 (add-name-to-file tmp-name1 tmp-name2)
3497 :type 'file-already-exists) 3524 :type 'file-already-exists)
3498 ;; A number means interactive case. 3525 ;; A number means interactive case.
3499 (cl-letf (((symbol-function 'yes-or-no-p) #'ignore)) 3526 (cl-letf (((symbol-function #'yes-or-no-p) #'ignore))
3500 (should-error 3527 (should-error
3501 (add-name-to-file tmp-name1 tmp-name2 0) 3528 (add-name-to-file tmp-name1 tmp-name2 0)
3502 :type 'file-already-exists)) 3529 :type 'file-already-exists))
3503 (cl-letf (((symbol-function 'yes-or-no-p) (lambda (_prompt) t))) 3530 (cl-letf (((symbol-function #'yes-or-no-p) (lambda (_prompt) t)))
3504 (add-name-to-file tmp-name1 tmp-name2 0) 3531 (add-name-to-file tmp-name1 tmp-name2 0)
3505 (should (file-regular-p tmp-name2))) 3532 (should (file-regular-p tmp-name2)))
3506 (add-name-to-file tmp-name1 tmp-name2 'ok-if-already-exists) 3533 (add-name-to-file tmp-name1 tmp-name2 'ok-if-already-exists)
@@ -4126,6 +4153,28 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
4126 (should (zerop (process-file "true"))) 4153 (should (zerop (process-file "true")))
4127 (should-not (zerop (process-file "false"))) 4154 (should-not (zerop (process-file "false")))
4128 (should-not (zerop (process-file "binary-does-not-exist"))) 4155 (should-not (zerop (process-file "binary-does-not-exist")))
4156 ;; Return exit code.
4157 (should (= 42 (process-file
4158 (if (tramp--test-adb-p) "/system/bin/sh" "/bin/sh")
4159 nil nil nil "-c" "exit 42")))
4160 ;; Return exit code in case the process is interrupted,
4161 ;; and there's no indication for a signal describing string.
4162 (let (process-file-return-signal-string)
4163 (should
4164 (= (+ 128 2)
4165 (process-file
4166 (if (tramp--test-adb-p) "/system/bin/sh" "/bin/sh")
4167 nil nil nil "-c" "kill -2 $$"))))
4168 ;; Return string in case the process is interrupted and
4169 ;; there's an indication for a signal describing string.
4170 (let ((process-file-return-signal-string t))
4171 (should
4172 (string-match
4173 "Interrupt\\|Signal 2"
4174 (process-file
4175 (if (tramp--test-adb-p) "/system/bin/sh" "/bin/sh")
4176 nil nil nil "-c" "kill -2 $$"))))
4177
4129 (with-temp-buffer 4178 (with-temp-buffer
4130 (write-region "foo" nil tmp-name) 4179 (write-region "foo" nil tmp-name)
4131 (should (file-exists-p tmp-name)) 4180 (should (file-exists-p tmp-name))
@@ -4181,7 +4230,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
4181 (setq proc (start-file-process "test1" (current-buffer) "cat")) 4230 (setq proc (start-file-process "test1" (current-buffer) "cat"))
4182 (should (processp proc)) 4231 (should (processp proc))
4183 (should (equal (process-status proc) 'run)) 4232 (should (equal (process-status proc) 'run))
4184 (process-send-string proc "foo") 4233 (process-send-string proc "foo\n")
4185 (process-send-eof proc) 4234 (process-send-eof proc)
4186 ;; Read output. 4235 ;; Read output.
4187 (with-timeout (10 (tramp--test-timeout-handler)) 4236 (with-timeout (10 (tramp--test-timeout-handler))
@@ -4224,7 +4273,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
4224 (set-process-filter 4273 (set-process-filter
4225 proc 4274 proc
4226 (lambda (p s) (with-current-buffer (process-buffer p) (insert s)))) 4275 (lambda (p s) (with-current-buffer (process-buffer p) (insert s))))
4227 (process-send-string proc "foo") 4276 (process-send-string proc "foo\n")
4228 (process-send-eof proc) 4277 (process-send-eof proc)
4229 ;; Read output. 4278 ;; Read output.
4230 (with-timeout (10 (tramp--test-timeout-handler)) 4279 (with-timeout (10 (tramp--test-timeout-handler))
@@ -4248,7 +4297,8 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
4248 4297
4249 (dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil))) 4298 (dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
4250 (let ((default-directory tramp-test-temporary-file-directory) 4299 (let ((default-directory tramp-test-temporary-file-directory)
4251 (tmp-name (tramp--test-make-temp-name nil quoted)) 4300 (tmp-name1 (tramp--test-make-temp-name nil quoted))
4301 (tmp-name2 (tramp--test-make-temp-name 'local quoted))
4252 kill-buffer-query-functions proc) 4302 kill-buffer-query-functions proc)
4253 (with-no-warnings (should-not (make-process))) 4303 (with-no-warnings (should-not (make-process)))
4254 4304
@@ -4262,7 +4312,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
4262 :file-handler t))) 4312 :file-handler t)))
4263 (should (processp proc)) 4313 (should (processp proc))
4264 (should (equal (process-status proc) 'run)) 4314 (should (equal (process-status proc) 'run))
4265 (process-send-string proc "foo") 4315 (process-send-string proc "foo\n")
4266 (process-send-eof proc) 4316 (process-send-eof proc)
4267 ;; Read output. 4317 ;; Read output.
4268 (with-timeout (10 (tramp--test-timeout-handler)) 4318 (with-timeout (10 (tramp--test-timeout-handler))
@@ -4278,13 +4328,13 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
4278 ;; Simple process using a file. 4328 ;; Simple process using a file.
4279 (unwind-protect 4329 (unwind-protect
4280 (with-temp-buffer 4330 (with-temp-buffer
4281 (write-region "foo" nil tmp-name) 4331 (write-region "foo" nil tmp-name1)
4282 (should (file-exists-p tmp-name)) 4332 (should (file-exists-p tmp-name1))
4283 (setq proc 4333 (setq proc
4284 (with-no-warnings 4334 (with-no-warnings
4285 (make-process 4335 (make-process
4286 :name "test2" :buffer (current-buffer) 4336 :name "test2" :buffer (current-buffer)
4287 :command `("cat" ,(file-name-nondirectory tmp-name)) 4337 :command `("cat" ,(file-name-nondirectory tmp-name1))
4288 :file-handler t))) 4338 :file-handler t)))
4289 (should (processp proc)) 4339 (should (processp proc))
4290 ;; Read output. 4340 ;; Read output.
@@ -4296,7 +4346,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
4296 ;; Cleanup. 4346 ;; Cleanup.
4297 (ignore-errors 4347 (ignore-errors
4298 (delete-process proc) 4348 (delete-process proc)
4299 (delete-file tmp-name))) 4349 (delete-file tmp-name1)))
4300 4350
4301 ;; Process filter. 4351 ;; Process filter.
4302 (unwind-protect 4352 (unwind-protect
@@ -4311,7 +4361,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
4311 :file-handler t))) 4361 :file-handler t)))
4312 (should (processp proc)) 4362 (should (processp proc))
4313 (should (equal (process-status proc) 'run)) 4363 (should (equal (process-status proc) 'run))
4314 (process-send-string proc "foo") 4364 (process-send-string proc "foo\n")
4315 (process-send-eof proc) 4365 (process-send-eof proc)
4316 ;; Read output. 4366 ;; Read output.
4317 (with-timeout (10 (tramp--test-timeout-handler)) 4367 (with-timeout (10 (tramp--test-timeout-handler))
@@ -4337,7 +4387,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
4337 :file-handler t))) 4387 :file-handler t)))
4338 (should (processp proc)) 4388 (should (processp proc))
4339 (should (equal (process-status proc) 'run)) 4389 (should (equal (process-status proc) 'run))
4340 (process-send-string proc "foo") 4390 (process-send-string proc "foo\n")
4341 (process-send-eof proc) 4391 (process-send-eof proc)
4342 (delete-process proc) 4392 (delete-process proc)
4343 ;; Read output. 4393 ;; Read output.
@@ -4345,36 +4395,67 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
4345 (while (accept-process-output proc 0 nil t))) 4395 (while (accept-process-output proc 0 nil t)))
4346 ;; We cannot use `string-equal', because tramp-adb.el 4396 ;; We cannot use `string-equal', because tramp-adb.el
4347 ;; echoes also the sent string. And a remote macOS sends 4397 ;; echoes also the sent string. And a remote macOS sends
4348 ;; a slightly modified string. 4398 ;; a slightly modified string. On MS Windows,
4349 (should (string-match "killed.*\n\\'" (buffer-string)))) 4399 ;; `delete-process' sends an unknown signal.
4400 (should
4401 (string-match
4402 (if (eq system-type 'windows-nt)
4403 "unknown signal\n\\'" "killed.*\n\\'")
4404 (buffer-string))))
4350 4405
4351 ;; Cleanup. 4406 ;; Cleanup.
4352 (ignore-errors (delete-process proc))) 4407 (ignore-errors (delete-process proc)))
4353 4408
4354 ;; Process with stderr. tramp-adb.el doesn't support it (yet). 4409 ;; Process with stderr buffer.
4355 (unless (tramp--test-adb-p) 4410 (let ((stderr (generate-new-buffer "*stderr*")))
4356 (let ((stderr (generate-new-buffer "*stderr*"))) 4411 (unwind-protect
4357 (unwind-protect 4412 (with-temp-buffer
4413 (setq proc
4414 (with-no-warnings
4415 (make-process
4416 :name "test5" :buffer (current-buffer)
4417 :command '("cat" "/does-not-exist")
4418 :stderr stderr
4419 :file-handler t)))
4420 (should (processp proc))
4421 ;; Read stderr.
4422 (with-timeout (10 (tramp--test-timeout-handler))
4423 (while (accept-process-output proc 0 nil t)))
4424 (delete-process proc)
4425 (with-current-buffer stderr
4426 (should
4427 (string-match
4428 "cat:.* No such file or directory" (buffer-string)))))
4429
4430 ;; Cleanup.
4431 (ignore-errors (delete-process proc))
4432 (ignore-errors (kill-buffer stderr))))
4433
4434 ;; Process with stderr file.
4435 (dolist (tmpfile `(,tmp-name1 ,tmp-name2))
4436 (unwind-protect
4437 (with-temp-buffer
4438 (setq proc
4439 (with-no-warnings
4440 (make-process
4441 :name "test6" :buffer (current-buffer)
4442 :command '("cat" "/does-not-exist")
4443 :stderr tmpfile
4444 :file-handler t)))
4445 (should (processp proc))
4446 ;; Read stderr.
4447 (with-timeout (10 (tramp--test-timeout-handler))
4448 (while (accept-process-output proc nil nil t)))
4449 (delete-process proc)
4358 (with-temp-buffer 4450 (with-temp-buffer
4359 (setq proc 4451 (insert-file-contents tmpfile)
4360 (with-no-warnings 4452 (should
4361 (make-process 4453 (string-match
4362 :name "test5" :buffer (current-buffer) 4454 "cat:.* No such file or directory" (buffer-string)))))
4363 :command '("cat" "/")
4364 :stderr stderr
4365 :file-handler t)))
4366 (should (processp proc))
4367 ;; Read stderr.
4368 (with-current-buffer stderr
4369 (with-timeout (10 (tramp--test-timeout-handler))
4370 (while (= (point-min) (point-max))
4371 (while (accept-process-output proc 0 nil t))))
4372 (should
4373 (string-match "^cat:.* Is a directory" (buffer-string)))))
4374 4455
4375 ;; Cleanup. 4456 ;; Cleanup.
4376 (ignore-errors (delete-process proc)) 4457 (ignore-errors (delete-process proc))
4377 (ignore-errors (kill-buffer stderr)))))))) 4458 (ignore-errors (delete-file tmpfile)))))))
4378 4459
4379(ert-deftest tramp-test31-interrupt-process () 4460(ert-deftest tramp-test31-interrupt-process ()
4380 "Check `interrupt-process'." 4461 "Check `interrupt-process'."
@@ -4388,10 +4469,13 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
4388 ;; order to establish the connection prior running an asynchronous 4469 ;; order to establish the connection prior running an asynchronous
4389 ;; process. 4470 ;; process.
4390 (let ((default-directory (file-truename tramp-test-temporary-file-directory)) 4471 (let ((default-directory (file-truename tramp-test-temporary-file-directory))
4472 (delete-exited-processes t)
4391 kill-buffer-query-functions proc) 4473 kill-buffer-query-functions proc)
4392 (unwind-protect 4474 (unwind-protect
4393 (with-temp-buffer 4475 (with-temp-buffer
4394 (setq proc (start-file-process "test" (current-buffer) "sleep" "10")) 4476 (setq proc (start-file-process-shell-command
4477 "test" (current-buffer)
4478 "trap 'echo boom; exit 1' 2; sleep 100"))
4395 (should (processp proc)) 4479 (should (processp proc))
4396 (should (process-live-p proc)) 4480 (should (process-live-p proc))
4397 (should (equal (process-status proc) 'run)) 4481 (should (equal (process-status proc) 'run))
@@ -4399,7 +4483,8 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
4399 (should (interrupt-process proc)) 4483 (should (interrupt-process proc))
4400 ;; Let the process accept the interrupt. 4484 ;; Let the process accept the interrupt.
4401 (with-timeout (10 (tramp--test-timeout-handler)) 4485 (with-timeout (10 (tramp--test-timeout-handler))
4402 (while (accept-process-output proc nil nil 0))) 4486 (while (process-live-p proc)
4487 (while (accept-process-output proc 0 nil t))))
4403 (should-not (process-live-p proc)) 4488 (should-not (process-live-p proc))
4404 ;; An interrupted process cannot be interrupted, again. 4489 ;; An interrupted process cannot be interrupted, again.
4405 (should-error 4490 (should-error
@@ -4409,14 +4494,24 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
4409 ;; Cleanup. 4494 ;; Cleanup.
4410 (ignore-errors (delete-process proc))))) 4495 (ignore-errors (delete-process proc)))))
4411 4496
4497(defun tramp--test-async-shell-command
4498 (command output-buffer &optional error-buffer input)
4499 "Like `async-shell-command', reading the output.
4500INPUT, if non-nil, is a string sent to the process."
4501 (async-shell-command command output-buffer error-buffer)
4502 (let ((proc (get-buffer-process output-buffer))
4503 (delete-exited-processes t))
4504 (when (stringp input)
4505 (process-send-string proc input))
4506 (with-timeout
4507 ((if (getenv "EMACS_EMBA_CI") 30 10) (tramp--test-timeout-handler))
4508 (while (or (accept-process-output proc nil nil t) (process-live-p proc))))
4509 (accept-process-output proc nil nil t)))
4510
4412(defun tramp--test-shell-command-to-string-asynchronously (command) 4511(defun tramp--test-shell-command-to-string-asynchronously (command)
4413 "Like `shell-command-to-string', but for asynchronous processes." 4512 "Like `shell-command-to-string', but for asynchronous processes."
4414 (with-temp-buffer 4513 (with-temp-buffer
4415 (async-shell-command command (current-buffer)) 4514 (tramp--test-async-shell-command command (current-buffer))
4416 (with-timeout
4417 ((if (getenv "EMACS_EMBA_CI") 30 10) (tramp--test-timeout-handler))
4418 (while (accept-process-output
4419 (get-buffer-process (current-buffer)) nil nil t)))
4420 (buffer-substring-no-properties (point-min) (point-max)))) 4515 (buffer-substring-no-properties (point-min) (point-max))))
4421 4516
4422(ert-deftest tramp-test32-shell-command () 4517(ert-deftest tramp-test32-shell-command ()
@@ -4435,111 +4530,294 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
4435 (inhibit-message t) 4530 (inhibit-message t)
4436 kill-buffer-query-functions) 4531 kill-buffer-query-functions)
4437 4532
4438 ;; Test ordinary `shell-command'. 4533 (dolist (this-shell-command
4439 (unwind-protect 4534 '(;; Synchronously.
4440 (with-temp-buffer 4535 shell-command
4441 (write-region "foo" nil tmp-name) 4536 ;; Asynchronously.
4442 (should (file-exists-p tmp-name)) 4537 tramp--test-async-shell-command))
4443 (shell-command
4444 (format "ls %s" (file-name-nondirectory tmp-name))
4445 (current-buffer))
4446 ;; `ls' could produce colorized output.
4447 (goto-char (point-min))
4448 (while
4449 (re-search-forward tramp-display-escape-sequence-regexp nil t)
4450 (replace-match "" nil nil))
4451 (should
4452 (string-equal
4453 (format "%s\n" (file-name-nondirectory tmp-name))
4454 (buffer-string))))
4455 4538
4456 ;; Cleanup. 4539 ;; Test ordinary `{async-}shell-command'.
4457 (ignore-errors (delete-file tmp-name)))
4458
4459 ;; Test `shell-command' with error buffer.
4460 (let ((stderr (generate-new-buffer "*stderr*")))
4461 (unwind-protect 4540 (unwind-protect
4462 (with-temp-buffer 4541 (with-temp-buffer
4463 (shell-command "error" (current-buffer) stderr) 4542 (write-region "foo" nil tmp-name)
4464 (should (= (point-min) (point-max))) 4543 (should (file-exists-p tmp-name))
4544 (funcall
4545 this-shell-command
4546 (format "ls %s" (file-name-nondirectory tmp-name))
4547 (current-buffer))
4548 ;; `ls' could produce colorized output.
4549 (goto-char (point-min))
4550 (while
4551 (re-search-forward tramp-display-escape-sequence-regexp nil t)
4552 (replace-match "" nil nil))
4465 (should 4553 (should
4466 (string-match 4554 (string-equal
4467 "error:.+not found" 4555 (format "%s\n" (file-name-nondirectory tmp-name))
4468 (with-current-buffer stderr (buffer-string))))) 4556 (buffer-string))))
4469 4557
4470 ;; Cleanup. 4558 ;; Cleanup.
4471 (ignore-errors (kill-buffer stderr)))) 4559 (ignore-errors (delete-file tmp-name)))
4472 4560
4473 ;; Test ordinary `async-shell-command'. 4561 ;; Test `{async-}shell-command' with error buffer.
4562 (let ((stderr (generate-new-buffer "*stderr*")))
4563 (unwind-protect
4564 (with-temp-buffer
4565 (funcall
4566 this-shell-command
4567 "echo foo >&2; echo bar" (current-buffer) stderr)
4568 (should (string-equal "bar\n" (buffer-string)))
4569 ;; Check stderr.
4570 (with-current-buffer stderr
4571 (should (string-equal "foo\n" (buffer-string)))))
4572
4573 ;; Cleanup.
4574 (ignore-errors (kill-buffer stderr)))))
4575
4576 ;; Test sending string to `async-shell-command'.
4474 (unwind-protect 4577 (unwind-protect
4475 (with-temp-buffer 4578 (with-temp-buffer
4476 (write-region "foo" nil tmp-name) 4579 (write-region "foo" nil tmp-name)
4477 (should (file-exists-p tmp-name)) 4580 (should (file-exists-p tmp-name))
4478 (async-shell-command 4581 (tramp--test-async-shell-command
4479 (format "ls %s" (file-name-nondirectory tmp-name)) 4582 "read line; ls $line" (current-buffer) nil
4480 (current-buffer)) 4583 ;; String to be sent.
4481 ;; Read output. 4584 (format "%s\n" (file-name-nondirectory tmp-name)))
4482 (with-timeout (10 (tramp--test-timeout-handler))
4483 (while (accept-process-output
4484 (get-buffer-process (current-buffer)) nil nil t)))
4485 ;; `ls' could produce colorized output.
4486 (goto-char (point-min))
4487 (while
4488 (re-search-forward tramp-display-escape-sequence-regexp nil t)
4489 (replace-match "" nil nil))
4490 (should 4585 (should
4491 (string-equal 4586 (string-equal
4492 (format "%s\n" (file-name-nondirectory tmp-name)) 4587 ;; tramp-adb.el echoes, so we must add the string.
4588 (if (tramp--test-adb-p)
4589 (format
4590 "%s\n%s\n"
4591 (file-name-nondirectory tmp-name)
4592 (file-name-nondirectory tmp-name))
4593 (format "%s\n" (file-name-nondirectory tmp-name)))
4493 (buffer-string)))) 4594 (buffer-string))))
4494 4595
4495 ;; Cleanup. 4596 ;; Cleanup.
4496 (ignore-errors (delete-file tmp-name))) 4597 (ignore-errors (delete-file tmp-name)))))
4497 4598
4498 ;; Test sending string to `async-shell-command'. 4599 ;; Test `async-shell-command-width'. It exists since Emacs 26.1,
4600 ;; but seems to work since Emacs 27.1 only.
4601 (when (and (tramp--test-sh-p) (tramp--test-emacs27-p))
4602 (let* ((async-shell-command-width 1024)
4603 (default-directory tramp-test-temporary-file-directory)
4604 (cols (ignore-errors
4605 (read (tramp--test-shell-command-to-string-asynchronously
4606 "tput cols")))))
4607 (when (natnump cols)
4608 (should (= cols async-shell-command-width))))))
4609
4610;; This test is inspired by Bug#39067.
4611(ert-deftest tramp-test32-shell-command-dont-erase-buffer ()
4612 "Check `shell-command-dont-erase-buffer'."
4613 :tags '(:expensive-test)
4614 (skip-unless (tramp--test-enabled))
4615 (skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p)))
4616 ;; Prior Emacs 27, `shell-command-dont-erase-buffer' wasn't working properly.
4617 (skip-unless (tramp--test-emacs27-p))
4618
4619 ;; We check both the local and remote case, in order to guarantee
4620 ;; that they behave similar.
4621 (dolist (default-directory
4622 `(,temporary-file-directory ,tramp-test-temporary-file-directory))
4623 (let ((buffer (generate-new-buffer "foo"))
4624 ;; Suppress nasty messages.
4625 (inhibit-message t)
4626 point kill-buffer-query-functions)
4499 (unwind-protect 4627 (unwind-protect
4500 (with-temp-buffer 4628 (progn
4501 (write-region "foo" nil tmp-name) 4629 ;; Don't erase if buffer is the current one. Point is not moved.
4502 (should (file-exists-p tmp-name)) 4630 (let (shell-command-dont-erase-buffer)
4503 (async-shell-command "read line; ls $line" (current-buffer)) 4631 (with-temp-buffer
4504 (process-send-string 4632 (insert "bar")
4505 (get-buffer-process (current-buffer)) 4633 (setq point (point))
4506 (format "%s\n" (file-name-nondirectory tmp-name))) 4634 (should (string-equal "bar" (buffer-string)))
4507 ;; Read output. 4635 (should (= (point) (point-max)))
4508 (with-timeout (10 (tramp--test-timeout-handler)) 4636 (shell-command "echo baz" (current-buffer))
4509 (while (accept-process-output 4637 (should (string-equal "barbaz\n" (buffer-string)))
4510 (get-buffer-process (current-buffer)) nil nil t))) 4638 (should (= point (point)))
4511 ;; `ls' could produce colorized output. 4639 (should-not (= (point) (point-max)))))
4512 (goto-char (point-min)) 4640
4513 (while 4641 ;; Erase if the buffer is not current one. Point is not moved.
4514 (re-search-forward tramp-display-escape-sequence-regexp nil t) 4642 (let (shell-command-dont-erase-buffer)
4515 (replace-match "" nil nil)) 4643 (with-current-buffer buffer
4516 ;; We cannot use `string-equal', because tramp-adb.el 4644 (erase-buffer)
4517 ;; echoes also the sent string. 4645 (insert "bar")
4518 (should 4646 (setq point (point))
4519 (string-match 4647 (should (string-equal "bar" (buffer-string)))
4520 (format "\\`%s" (regexp-quote (file-name-nondirectory tmp-name))) 4648 (should (= (point) (point-max)))
4521 (buffer-string)))) 4649 (with-temp-buffer
4650 (shell-command "echo baz" buffer))
4651 (should (string-equal "baz\n" (buffer-string)))
4652 (should (= point (point)))
4653 (should-not (= (point) (point-max)))))
4654
4655 ;; Erase if buffer is the current one, but
4656 ;; `shell-command-dont-erase-buffer' is set to `erase'.
4657 ;; There is no point to check point.
4658 (let ((shell-command-dont-erase-buffer 'erase))
4659 (with-temp-buffer
4660 (insert "bar")
4661 (should (string-equal "bar" (buffer-string)))
4662 (should (= (point) (point-max)))
4663 (shell-command "echo baz" (current-buffer))
4664 (should (string-equal "baz\n" (buffer-string)))
4665 ;; In the local case, point is not moved after the
4666 ;; inserted text.
4667 (should (= (point)
4668 (if (file-remote-p default-directory)
4669 (point-max) (point-min))))))
4670
4671 ;; Don't erase if the buffer is the current one and
4672 ;; `shell-command-dont-erase-buffer' is set to
4673 ;; `beg-last-out'. Check point.
4674 (let ((shell-command-dont-erase-buffer 'beg-last-out))
4675 (with-temp-buffer
4676 (insert "bar")
4677 (setq point (point))
4678 (should (string-equal "bar" (buffer-string)))
4679 (should (= (point) (point-max)))
4680 (shell-command "echo baz" (current-buffer))
4681 (should (string-equal "barbaz\n" (buffer-string)))
4682 ;; There is still an error in Tramp.
4683 (unless (file-remote-p default-directory)
4684 (should (= point (point)))
4685 (should-not (= (point) (point-max))))))
4686
4687 ;; Don't erase if the buffer is not the current one and
4688 ;; `shell-command-dont-erase-buffer' is set to
4689 ;; `beg-last-out'. Check point.
4690 (let ((shell-command-dont-erase-buffer 'beg-last-out))
4691 (with-current-buffer buffer
4692 (erase-buffer)
4693 (insert "bar")
4694 (setq point (point))
4695 (should (string-equal "bar" (buffer-string)))
4696 (should (= (point) (point-max)))
4697 (with-temp-buffer
4698 (shell-command "echo baz" buffer))
4699 (should (string-equal "barbaz\n" (buffer-string)))
4700 ;; There is still an error in Tramp.
4701 (unless (file-remote-p default-directory)
4702 (should (= point (point)))
4703 (should-not (= (point) (point-max))))))
4704
4705 ;; Don't erase if the buffer is the current one and
4706 ;; `shell-command-dont-erase-buffer' is set to
4707 ;; `end-last-out'. Check point.
4708 (let ((shell-command-dont-erase-buffer 'end-last-out))
4709 (with-temp-buffer
4710 (insert "bar")
4711 (setq point (point))
4712 (should (string-equal "bar" (buffer-string)))
4713 (should (= (point) (point-max)))
4714 (shell-command "echo baz" (current-buffer))
4715 (should (string-equal "barbaz\n" (buffer-string)))
4716 ;; This does not work as expected in the local case.
4717 ;; Therefore, we negate the test for the time being.
4718 (should-not
4719 (funcall (if (file-remote-p default-directory) #'identity #'not)
4720 (= point (point))))
4721 (should
4722 (funcall (if (file-remote-p default-directory) #'identity #'not)
4723 (= (point) (point-max))))))
4724
4725 ;; Don't erase if the buffer is not the current one and
4726 ;; `shell-command-dont-erase-buffer' is set to
4727 ;; `end-last-out'. Check point.
4728 (let ((shell-command-dont-erase-buffer 'end-last-out))
4729 (with-current-buffer buffer
4730 (erase-buffer)
4731 (insert "bar")
4732 (setq point (point))
4733 (should (string-equal "bar" (buffer-string)))
4734 (should (= (point) (point-max)))
4735 (with-temp-buffer
4736 (shell-command "echo baz" buffer))
4737 (should (string-equal "barbaz\n" (buffer-string)))
4738 ;; There is still an error in Tramp.
4739 (unless (file-remote-p default-directory)
4740 (should-not (= point (point)))
4741 (should (= (point) (point-max))))))
4742
4743 ;; Don't erase if the buffer is the current one and
4744 ;; `shell-command-dont-erase-buffer' is set to
4745 ;; `save-point'. Check point.
4746 (let ((shell-command-dont-erase-buffer 'save-point))
4747 (with-temp-buffer
4748 (insert "bar")
4749 (goto-char (1- (point-max)))
4750 (setq point (point))
4751 (should (string-equal "bar" (buffer-string)))
4752 (should (= (point) (1- (point-max))))
4753 (shell-command "echo baz" (current-buffer))
4754 (should (string-equal "babaz\nr" (buffer-string)))
4755 ;; There is still an error in Tramp.
4756 (unless (file-remote-p default-directory)
4757 (should (= point (point)))
4758 (should-not (= (point) (point-max))))))
4759
4760 ;; Don't erase if the buffer is not the current one and
4761 ;; `shell-command-dont-erase-buffer' is set to
4762 ;; `save-point'. Check point.
4763 (let ((shell-command-dont-erase-buffer 'save-point))
4764 (with-current-buffer buffer
4765 (erase-buffer)
4766 (insert "bar")
4767 (goto-char (1- (point-max)))
4768 (setq point (point))
4769 (should (string-equal "bar" (buffer-string)))
4770 (should (= (point) (1- (point-max))))
4771 (with-temp-buffer
4772 (shell-command "echo baz" buffer))
4773 ;; This does not work as expected. Therefore, we
4774 ;; use the "wrong" string.
4775 (should (string-equal "barbaz\n" (buffer-string)))
4776 ;; There is still an error in Tramp.
4777 (unless (file-remote-p default-directory)
4778 (should (= point (point)))
4779 (should-not (= (point) (point-max))))))
4780
4781 ;; Don't erase if the buffer is the current one and
4782 ;; `shell-command-dont-erase-buffer' is set to a random
4783 ;; value. Check point.
4784 (let ((shell-command-dont-erase-buffer 'random))
4785 (with-temp-buffer
4786 (insert "bar")
4787 (setq point (point))
4788 (should (string-equal "bar" (buffer-string)))
4789 (should (= (point) (point-max)))
4790 (shell-command "echo baz" (current-buffer))
4791 (should (string-equal "barbaz\n" (buffer-string)))
4792 ;; This does not work as expected in the local case.
4793 ;; Therefore, we negate the test for the time being.
4794 (should-not
4795 (funcall (if (file-remote-p default-directory) #'identity #'not)
4796 (= point (point))))
4797 (should
4798 (funcall (if (file-remote-p default-directory) #'identity #'not)
4799 (= (point) (point-max))))))
4800
4801 ;; Don't erase if the buffer is not the current one and
4802 ;; `shell-command-dont-erase-buffer' is set to a random
4803 ;; value. Check point.
4804 (let ((shell-command-dont-erase-buffer 'random))
4805 (with-current-buffer buffer
4806 (erase-buffer)
4807 (insert "bar")
4808 (setq point (point))
4809 (should (string-equal "bar" (buffer-string)))
4810 (should (= (point) (point-max)))
4811 (with-temp-buffer
4812 (shell-command "echo baz" buffer))
4813 (should (string-equal "barbaz\n" (buffer-string)))
4814 ;; There is still an error in Tramp.
4815 (unless (file-remote-p default-directory)
4816 (should-not (= point (point)))
4817 (should (= (point) (point-max)))))))
4522 4818
4523 ;; Cleanup. 4819 ;; Cleanup.
4524 (ignore-errors (delete-file tmp-name))) 4820 (ignore-errors (kill-buffer buffer))))))
4525
4526 ;; Test `async-shell-command-width'. Since Emacs 27.1.
4527 (when (ignore-errors
4528 (and (boundp 'async-shell-command-width)
4529 (zerop (call-process "tput" nil nil nil "cols"))
4530 (zerop (process-file "tput" nil nil nil "cols"))))
4531 (let (async-shell-command-width)
4532 (should
4533 (string-equal
4534 (format "%s\n" (car (process-lines "tput" "cols")))
4535 (tramp--test-shell-command-to-string-asynchronously
4536 "tput cols")))
4537 (setq async-shell-command-width 1024)
4538 (should
4539 (string-equal
4540 "1024\n"
4541 (tramp--test-shell-command-to-string-asynchronously
4542 "tput cols"))))))))
4543 4821
4544;; This test is inspired by Bug#23952. 4822;; This test is inspired by Bug#23952.
4545(ert-deftest tramp-test33-environment-variables () 4823(ert-deftest tramp-test33-environment-variables ()
@@ -5753,7 +6031,7 @@ Use the `ls' command."
5753 ;; Since Emacs 27.1. 6031 ;; Since Emacs 27.1.
5754 (skip-unless (fboundp 'file-system-info)) 6032 (skip-unless (fboundp 'file-system-info))
5755 6033
5756 ;; `file-system-info' exists since Emacs 27. We don't want to see 6034 ;; `file-system-info' exists since Emacs 27.1. We don't want to see
5757 ;; compiler warnings for older Emacsen. 6035 ;; compiler warnings for older Emacsen.
5758 (let ((fsi (with-no-warnings 6036 (let ((fsi (with-no-warnings
5759 (file-system-info tramp-test-temporary-file-directory)))) 6037 (file-system-info tramp-test-temporary-file-directory))))
@@ -6191,8 +6469,6 @@ If INTERACTIVE is non-nil, the tests are run interactively."
6191;; * Fix `tramp-test06-directory-file-name' for `ftp'. 6469;; * Fix `tramp-test06-directory-file-name' for `ftp'.
6192;; * Investigate, why `tramp-test11-copy-file' and `tramp-test12-rename-file' 6470;; * Investigate, why `tramp-test11-copy-file' and `tramp-test12-rename-file'
6193;; do not work properly for `nextcloud'. 6471;; do not work properly for `nextcloud'.
6194;; * Fix `tramp-test29-start-file-process' and
6195;; `tramp-test30-make-process' on MS Windows (`process-send-eof'?).
6196;; * Implement `tramp-test31-interrupt-process' for `adb'. 6472;; * Implement `tramp-test31-interrupt-process' for `adb'.
6197;; * Fix Bug#16928 in `tramp-test43-asynchronous-requests'. A remote 6473;; * Fix Bug#16928 in `tramp-test43-asynchronous-requests'. A remote
6198;; file name operation cannot run in the timer. Remove `:unstable' tag? 6474;; file name operation cannot run in the timer. Remove `:unstable' tag?