Fix Bug#17295.
[bpt/emacs.git] / lisp / net / tramp-sh.el
index e45c2cf..431d618 100644 (file)
@@ -1,6 +1,6 @@
 ;;; tramp-sh.el --- Tramp access functions for (s)sh-like connections
 
-;; Copyright (C) 1998-2013 Free Software Foundation, Inc.
+;; Copyright (C) 1998-2014 Free Software Foundation, Inc.
 
 ;; (copyright statements below in code to be updated with the above notice)
 
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))      ; ignore-errors
 (require 'tramp)
 
-;; Pacify byte-compiler.  The function is needed on XEmacs only.  I'm
-;; not sure at all that this is the right way to do it, but let's hope
-;; it works for now, and wait for a guru to point out the Right Way to
-;; achieve this.
-;;(eval-when-compile
-;;  (unless (fboundp 'dired-insert-set-properties)
-;;    (fset 'dired-insert-set-properties 'ignore)))
-;; Gerd suggests this:
-(eval-when-compile (require 'dired))
-;; Note that dired is required at run-time, too, when it is needed.
-;; It is only needed on XEmacs for the function
-;; `dired-insert-set-properties'.
+;; Pacify byte-compiler.
+(eval-when-compile
+  (require 'cl)
+  (require 'dired))
+(defvar directory-sep-char)
+(defvar tramp-gw-tunnel-method)
+(defvar tramp-gw-socks-method)
 
 (defcustom tramp-inline-compress-start-size 4096
   "The minimum size of compressing where inline transfer.
@@ -66,6 +60,7 @@ files conditionalize this setup based on the TERM environment variable."
   :group 'tramp
   :type 'string)
 
+;;;###tramp-autoload
 (defconst tramp-color-escape-sequence-regexp "\e[[;0-9]+m"
   "Escape sequences produced by the \"ls\" command.")
 
@@ -85,6 +80,9 @@ detected as prompt when being sent on echoing hosts, therefore.")
 (defconst tramp-initial-end-of-output "#$ "
   "Prompt when establishing a connection.")
 
+(defconst tramp-end-of-heredoc (md5 tramp-end-of-output)
+  "String used to recognize end of heredoc strings.")
+
 ;; Initialize `tramp-methods' with the supported methods.
 ;;;###tramp-autoload
 (add-to-list 'tramp-methods
@@ -222,21 +220,26 @@ detected as prompt when being sent on echoing hosts, therefore.")
     (tramp-login-program        "su")
     (tramp-login-args           (("-") ("%u")))
     (tramp-remote-shell         "/bin/sh")
-    (tramp-remote-shell-args    ("-c"))))
+    (tramp-remote-shell-args    ("-c"))
+    (tramp-connection-timeout   10)))
 ;;;###tramp-autoload
 (add-to-list 'tramp-methods
   '("sudo"
     (tramp-login-program        "sudo")
     (tramp-login-args           (("-u" "%u") ("-s") ("-H") ("-p" "Password:")))
+    ;; Local $SHELL could be a nasty one, like zsh or fish.  Let's override it.
+    (tramp-login-env            (("SHELL") ("/bin/sh")))
     (tramp-remote-shell         "/bin/sh")
-    (tramp-remote-shell-args    ("-c"))))
+    (tramp-remote-shell-args    ("-c"))
+    (tramp-connection-timeout   10)))
 ;;;###tramp-autoload
 (add-to-list 'tramp-methods
   '("ksu"
     (tramp-login-program        "ksu")
     (tramp-login-args           (("%u") ("-q")))
     (tramp-remote-shell         "/bin/sh")
-    (tramp-remote-shell-args    ("-c"))))
+    (tramp-remote-shell-args    ("-c"))
+    (tramp-connection-timeout   10)))
 ;;;###tramp-autoload
 (add-to-list 'tramp-methods
   '("krlogin"
@@ -422,7 +425,7 @@ as given in your `~/.profile'."
 
 ;;;###tramp-autoload
 (defcustom tramp-remote-process-environment
-  `("HISTFILE=$HOME/.tramp_history" "HISTSIZE=1" "TMOUT=0" "LC_ALL=C"
+  `("TMOUT=0" "LC_CTYPE=''"
     ,(format "TERM=%s" tramp-terminal-type)
     "EMACS=t" ;; Deprecated.
     ,(format "INSIDE_EMACS='%s,tramp:%s'" emacs-version tramp-version)
@@ -437,6 +440,7 @@ which might have been set in the init files like ~/.profile.
 Special handling is applied to the PATH environment, which should
 not be set here. Instead, it should be set via `tramp-remote-path'."
   :group 'tramp
+  :version "24.4"
   :type '(repeat string))
 
 (defcustom tramp-sh-extra-args '(("/bash\\'" . "-norc -noprofile"))
@@ -688,7 +692,7 @@ on the remote host.")
 (defconst tramp-perl-encode
   "%s -e '
 # This script contributed by Juanma Barranquero <lektu@terra.es>.
-# Copyright (C) 2002-2013 Free Software Foundation, Inc.
+# Copyright (C) 2002-2014 Free Software Foundation, Inc.
 use strict;
 
 my %%trans = do {
@@ -726,7 +730,7 @@ This string is passed to `format', so percent characters need to be doubled.")
 (defconst tramp-perl-decode
   "%s -e '
 # This script contributed by Juanma Barranquero <lektu@terra.es>.
-# Copyright (C) 2002-2013 Free Software Foundation, Inc.
+# Copyright (C) 2002-2014 Free Software Foundation, Inc.
 use strict;
 
 my %%trans = do {
@@ -798,71 +802,78 @@ existence, and file readability.  Input shall be read via
 here-document, otherwise the command could exceed maximum length
 of command line.")
 
-;; New handlers should be added here.  The following operations can be
-;; handled using the normal primitives: file-name-sans-versions,
-;; get-file-buffer.
+;; New handlers should be added here.
 (defconst tramp-sh-file-name-handler-alist
-  '((load . tramp-handle-load)
-    (make-symbolic-link . tramp-sh-handle-make-symbolic-link)
-    (file-name-as-directory . tramp-handle-file-name-as-directory)
-    (file-name-directory . tramp-handle-file-name-directory)
-    (file-name-nondirectory . tramp-handle-file-name-nondirectory)
-    (file-truename . tramp-sh-handle-file-truename)
-    (file-exists-p . tramp-sh-handle-file-exists-p)
+  '(;; `access-file' performed by default handler.
+    (add-name-to-file . tramp-sh-handle-add-name-to-file)
+    ;; `byte-compiler-base-file-name' performed by default handler.
+    (copy-directory . tramp-sh-handle-copy-directory)
+    (copy-file . tramp-sh-handle-copy-file)
+    (delete-directory . tramp-sh-handle-delete-directory)
+    (delete-file . tramp-sh-handle-delete-file)
+    ;; `diff-latest-backup-file' performed by default handler.
+    (directory-file-name . tramp-handle-directory-file-name)
+    (directory-files . tramp-handle-directory-files)
+    (directory-files-and-attributes
+     . tramp-sh-handle-directory-files-and-attributes)
+    ;; `dired-call-process' performed by default handler.
+    (dired-compress-file . tramp-sh-handle-dired-compress-file)
+    (dired-recursive-delete-directory
+     . tramp-sh-handle-dired-recursive-delete-directory)
+    (dired-uncache . tramp-handle-dired-uncache)
+    (expand-file-name . tramp-sh-handle-expand-file-name)
     (file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
+    (file-acl . tramp-sh-handle-file-acl)
+    (file-attributes . tramp-sh-handle-file-attributes)
     (file-directory-p . tramp-sh-handle-file-directory-p)
+    ;; `file-equal-p' performed by default handler.
     (file-executable-p . tramp-sh-handle-file-executable-p)
+    (file-exists-p . tramp-sh-handle-file-exists-p)
+    ;; `file-in-directory-p' performed by default handler.
+    (file-local-copy . tramp-sh-handle-file-local-copy)
+    (file-modes . tramp-handle-file-modes)
+    (file-name-all-completions . tramp-sh-handle-file-name-all-completions)
+    (file-name-as-directory . tramp-handle-file-name-as-directory)
+    (file-name-completion . tramp-handle-file-name-completion)
+    (file-name-directory . tramp-handle-file-name-directory)
+    (file-name-nondirectory . tramp-handle-file-name-nondirectory)
+    ;; `file-name-sans-versions' performed by default handler.
+    (file-newer-than-file-p . tramp-sh-handle-file-newer-than-file-p)
+    (file-notify-add-watch . tramp-sh-handle-file-notify-add-watch)
+    (file-notify-rm-watch . tramp-handle-file-notify-rm-watch)
+    (file-ownership-preserved-p . tramp-sh-handle-file-ownership-preserved-p)
     (file-readable-p . tramp-sh-handle-file-readable-p)
     (file-regular-p . tramp-handle-file-regular-p)
+    (file-remote-p . tramp-handle-file-remote-p)
+    (file-selinux-context . tramp-sh-handle-file-selinux-context)
     (file-symlink-p . tramp-handle-file-symlink-p)
+    (file-truename . tramp-sh-handle-file-truename)
     (file-writable-p . tramp-sh-handle-file-writable-p)
-    (file-ownership-preserved-p . tramp-sh-handle-file-ownership-preserved-p)
-    (file-newer-than-file-p . tramp-sh-handle-file-newer-than-file-p)
-    (file-attributes . tramp-sh-handle-file-attributes)
-    (file-modes . tramp-handle-file-modes)
-    (directory-files . tramp-handle-directory-files)
-    (directory-files-and-attributes
-     . tramp-sh-handle-directory-files-and-attributes)
-    (file-name-all-completions . tramp-sh-handle-file-name-all-completions)
-    (file-name-completion . tramp-handle-file-name-completion)
-    (add-name-to-file . tramp-sh-handle-add-name-to-file)
-    (copy-file . tramp-sh-handle-copy-file)
-    (copy-directory . tramp-sh-handle-copy-directory)
+    (find-backup-file-name . tramp-handle-find-backup-file-name)
+    ;; `find-file-noselect' performed by default handler.
+    ;; `get-file-buffer' performed by default handler.
+    (insert-directory . tramp-sh-handle-insert-directory)
+    (insert-file-contents . tramp-handle-insert-file-contents)
+    (insert-file-contents-literally
+     . tramp-sh-handle-insert-file-contents-literally)
+    (load . tramp-handle-load)
+    (make-auto-save-file-name . tramp-handle-make-auto-save-file-name)
+    (make-directory . tramp-sh-handle-make-directory)
+    (make-symbolic-link . tramp-sh-handle-make-symbolic-link)
+    (process-file . tramp-sh-handle-process-file)
     (rename-file . tramp-sh-handle-rename-file)
+    (set-file-acl . tramp-sh-handle-set-file-acl)
     (set-file-modes . tramp-sh-handle-set-file-modes)
+    (set-file-selinux-context . tramp-sh-handle-set-file-selinux-context)
     (set-file-times . tramp-sh-handle-set-file-times)
-    (make-directory . tramp-sh-handle-make-directory)
-    (delete-directory . tramp-sh-handle-delete-directory)
-    (delete-file . tramp-sh-handle-delete-file)
-    (directory-file-name . tramp-handle-directory-file-name)
-    ;; `executable-find' is not official yet.
-    (executable-find . tramp-sh-handle-executable-find)
-    (start-file-process . tramp-sh-handle-start-file-process)
-    (process-file . tramp-sh-handle-process-file)
+    (set-visited-file-modtime . tramp-sh-handle-set-visited-file-modtime)
     (shell-command . tramp-handle-shell-command)
-    (insert-directory . tramp-sh-handle-insert-directory)
-    (expand-file-name . tramp-sh-handle-expand-file-name)
+    (start-file-process . tramp-sh-handle-start-file-process)
     (substitute-in-file-name . tramp-handle-substitute-in-file-name)
-    (file-local-copy . tramp-sh-handle-file-local-copy)
-    (file-remote-p . tramp-handle-file-remote-p)
-    (insert-file-contents . tramp-handle-insert-file-contents)
-    (insert-file-contents-literally
-     . tramp-sh-handle-insert-file-contents-literally)
-    (write-region . tramp-sh-handle-write-region)
-    (find-backup-file-name . tramp-handle-find-backup-file-name)
-    (make-auto-save-file-name . tramp-sh-handle-make-auto-save-file-name)
     (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
-    (dired-compress-file . tramp-sh-handle-dired-compress-file)
-    (dired-recursive-delete-directory
-     . tramp-sh-handle-dired-recursive-delete-directory)
-    (dired-uncache . tramp-handle-dired-uncache)
-    (set-visited-file-modtime . tramp-sh-handle-set-visited-file-modtime)
+    (vc-registered . tramp-sh-handle-vc-registered)
     (verify-visited-file-modtime . tramp-sh-handle-verify-visited-file-modtime)
-    (file-selinux-context . tramp-sh-handle-file-selinux-context)
-    (set-file-selinux-context . tramp-sh-handle-set-file-selinux-context)
-    (file-acl . tramp-sh-handle-file-acl)
-    (set-file-acl . tramp-sh-handle-set-file-acl)
-    (vc-registered . tramp-sh-handle-vc-registered))
+    (write-region . tramp-sh-handle-write-region))
   "Alist of handler functions.
 Operations not mentioned here will be handled by the normal Emacs functions.")
 
@@ -928,22 +939,27 @@ target of the symlink differ."
        (tramp-shell-quote-argument l-localname))
        t))))
 
-(defun tramp-sh-handle-file-truename (filename &optional counter prev-dirs)
+(defun tramp-sh-handle-file-truename (filename)
   "Like `file-truename' for Tramp files."
-  (with-parsed-tramp-file-name (expand-file-name filename) nil
-    (tramp-make-tramp-file-name method user host
+  (format
+   "%s%s"
+   (with-parsed-tramp-file-name (expand-file-name filename) nil
+     (tramp-make-tramp-file-name
+      method user host
       (with-tramp-file-property v localname "file-truename"
        (let ((result nil))                     ; result steps in reverse order
          (tramp-message v 4 "Finding true name for `%s'" filename)
          (cond
           ;; Use GNU readlink --canonicalize-missing where available.
           ((tramp-get-remote-readlink v)
-           (setq result
-                 (tramp-send-command-and-read
-                  v
-                  (format "echo \"\\\"`%s --canonicalize-missing %s`\\\"\""
-                          (tramp-get-remote-readlink v)
-                          (tramp-shell-quote-argument localname)))))
+           (tramp-send-command-and-check
+            v
+            (format "%s --canonicalize-missing %s"
+                    (tramp-get-remote-readlink v)
+                    (tramp-shell-quote-argument localname)))
+           (with-current-buffer (tramp-get-connection-buffer v)
+             (goto-char (point-min))
+             (setq result (buffer-substring (point-min) (point-at-eol)))))
 
           ;; Use Perl implementation.
           ((and (tramp-get-remote-perl v)
@@ -1034,7 +1050,10 @@ target of the symlink differ."
                  (setq result (concat result "/"))))))
 
          (tramp-message v 4 "True name of `%s' is `%s'" localname result)
-         result)))))
+         result))))
+
+   ;; Preserve trailing "/".
+   (if (string-equal (file-name-nondirectory filename) "") "/" "")))
 
 ;; Basic functions.
 
@@ -1230,14 +1249,14 @@ target of the symlink differ."
 
 ;; This function makes the same assumption as
 ;; `tramp-sh-handle-set-visited-file-modtime'.
-(defun tramp-sh-handle-verify-visited-file-modtime (buf)
+(defun tramp-sh-handle-verify-visited-file-modtime (&optional buf)
   "Like `verify-visited-file-modtime' for Tramp files.
 At the time `verify-visited-file-modtime' calls this function, we
 already know that the buffer is visiting a file and that
 `visited-file-modtime' does not return 0.  Do not call this
 function directly, unless those two cases are already taken care
 of."
-  (with-current-buffer buf
+  (with-current-buffer (or buf (current-buffer))
     (let ((f (buffer-file-name)))
       ;; There is no file visiting the buffer, or the buffer has no
       ;; recorded last modification time, or there is no established
@@ -1296,24 +1315,31 @@ of."
 
 (defun tramp-sh-handle-set-file-times (filename &optional time)
   "Like `set-file-times' for Tramp files."
-  (if (file-remote-p filename)
+  (if (tramp-tramp-file-p filename)
       (with-parsed-tramp-file-name filename nil
-       (tramp-flush-file-property v localname)
-       (let ((time (if (or (null time) (equal time '(0 0)))
-                       (current-time)
-                     time))
-             ;; With GNU Emacs, `format-time-string' has an optional
-             ;; parameter UNIVERSAL.  This is preferred, because we
-             ;; could handle the case when the remote host is located
-             ;; in a different time zone as the local host.
-             (utc (not (featurep 'xemacs))))
-         (tramp-send-command-and-check
-          v (format "%s touch -t %s %s"
-                    (if utc "env TZ=UTC" "")
-                    (if utc
-                        (format-time-string "%Y%m%d%H%M.%S" time t)
-                      (format-time-string "%Y%m%d%H%M.%S" time))
-                    (tramp-shell-quote-argument localname)))))
+       (when (tramp-get-remote-touch v)
+         (tramp-flush-file-property v localname)
+         (let ((time (if (or (null time) (equal time '(0 0)))
+                         (current-time)
+                       time))
+               ;; With GNU Emacs, `format-time-string' has an
+               ;; optional parameter UNIVERSAL.  This is preferred,
+               ;; because we could handle the case when the remote
+               ;; host is located in a different time zone as the
+               ;; local host.
+               (utc (not (featurep 'xemacs))))
+           (tramp-send-command-and-check
+            v (format
+               "%s %s %s %s"
+               (if utc "env TZ=UTC" "")
+               (tramp-get-remote-touch v)
+               (if (tramp-get-connection-property v "touch-t" nil)
+                   (format "-t %s"
+                           (if utc
+                               (format-time-string "%Y%m%d%H%M.%S" time t)
+                             (format-time-string "%Y%m%d%H%M.%S" time)))
+                 "")
+               (tramp-shell-quote-argument localname))))))
 
     ;; We handle also the local part, because in older Emacsen,
     ;; without `set-file-times', this function is an alias for this.
@@ -1335,7 +1361,7 @@ be non-negative integers."
   ;; the majority of cases.
   ;; Don't modify `last-coding-system-used' by accident.
   (let ((last-coding-system-used last-coding-system-used))
-    (if (file-remote-p filename)
+    (if (tramp-tramp-file-p filename)
        (with-parsed-tramp-file-name filename nil
          (if (and (zerop (user-uid)) (tramp-local-host-p v))
              ;; If we are root on the local host, we can do it directly.
@@ -1439,8 +1465,11 @@ be non-negative integers."
     (if (and (stringp acl-string) (tramp-remote-acl-p v)
             (progn
               (tramp-send-command
-               v (format "setfacl --set-file=- %s <<'EOF'\n%s\nEOF\n"
-                         (tramp-shell-quote-argument localname) acl-string))
+               v (format "setfacl --set-file=- %s <<'%s'\n%s\n%s\n"
+                         (tramp-shell-quote-argument localname)
+                         tramp-end-of-heredoc
+                         acl-string
+                         tramp-end-of-heredoc))
               (tramp-send-command-and-check v nil)))
        ;; Success.
        (progn
@@ -1552,39 +1581,45 @@ be non-negative integers."
 (defun tramp-sh-handle-directory-files-and-attributes
   (directory &optional full match nosort id-format)
   "Like `directory-files-and-attributes' for Tramp files."
-  (unless id-format (setq id-format 'integer))
-  (when (file-directory-p directory)
-    (setq directory (expand-file-name directory))
-    (let* ((temp
-           (copy-tree
-            (with-parsed-tramp-file-name directory nil
-              (with-tramp-file-property
-                  v localname
-                  (format "directory-files-and-attributes-%s" id-format)
-                (save-excursion
-                  (mapcar
-                   (lambda (x)
-                     (cons (car x)
-                           (tramp-convert-file-attributes v (cdr x))))
-                   (cond
-                    ((tramp-get-remote-stat v)
-                     (tramp-do-directory-files-and-attributes-with-stat
-                      v localname id-format))
-                    ((tramp-get-remote-perl v)
-                     (tramp-do-directory-files-and-attributes-with-perl
-                      v localname id-format)))))))))
-          result item)
-
-      (while temp
-       (setq item (pop temp))
-       (when (or (null match) (string-match match (car item)))
-         (when full
-           (setcar item (expand-file-name (car item) directory)))
-         (push item result)))
-
-      (if nosort
-         result
-       (sort result (lambda (x y) (string< (car x) (car y))))))))
+  (if (with-parsed-tramp-file-name directory nil
+       (not (or (tramp-get-remote-stat v) (tramp-get-remote-perl v))))
+      (tramp-handle-directory-files-and-attributes
+       directory full match nosort id-format)
+
+    ;; Do it directly.
+    (unless id-format (setq id-format 'integer))
+    (when (file-directory-p directory)
+      (setq directory (expand-file-name directory))
+      (let* ((temp
+             (copy-tree
+              (with-parsed-tramp-file-name directory nil
+                (with-tramp-file-property
+                    v localname
+                    (format "directory-files-and-attributes-%s" id-format)
+                  (save-excursion
+                    (mapcar
+                     (lambda (x)
+                       (cons (car x)
+                             (tramp-convert-file-attributes v (cdr x))))
+                     (cond
+                      ((tramp-get-remote-stat v)
+                       (tramp-do-directory-files-and-attributes-with-stat
+                        v localname id-format))
+                      ((tramp-get-remote-perl v)
+                       (tramp-do-directory-files-and-attributes-with-perl
+                        v localname id-format)))))))))
+            result item)
+
+       (while temp
+         (setq item (pop temp))
+         (when (or (null match) (string-match match (car item)))
+           (when full
+             (setcar item (expand-file-name (car item) directory)))
+           (push item result)))
+
+       (if nosort
+           result
+         (sort result (lambda (x y) (string< (car x) (car y)))))))))
 
 (defun tramp-do-directory-files-and-attributes-with-perl
   (vec localname &optional id-format)
@@ -1700,7 +1735,7 @@ be non-negative integers."
                        ;; wildcard.  This will return "too many" entries
                        ;; but that isn't harmful.
                        " || %s -a 2>/dev/null)"
-                       " | while read f; do"
+                       " | while IFS= read f; do"
                        " if %s -d \"$f\" 2>/dev/null;"
                        " then \\echo \"$f/\"; else \\echo \"$f\"; fi; done"
                        " && \\echo ok) || \\echo fail")
@@ -1780,21 +1815,21 @@ tramp-sh-handle-file-name-all-completions: internal error accessing `%s': `%s'"
   (with-parsed-tramp-file-name filename v1
     (with-parsed-tramp-file-name newname v2
       (let ((ln (when v1 (tramp-get-remote-ln v1))))
-       (when (and (not ok-if-already-exists)
+       (when (and (numberp ok-if-already-exists)
                   (file-exists-p newname)
-                  (not (numberp ok-if-already-exists))
-                  (y-or-n-p
+                  (yes-or-no-p
                    (format
                     "File %s already exists; make it a new name anyway? "
                     newname)))
          (tramp-error
-          v2 'file-error
-          "add-name-to-file: file %s already exists" newname))
+          v2 'file-error "add-name-to-file: file %s already exists" newname))
+       (when ok-if-already-exists (setq ln (concat ln " -f")))
        (tramp-flush-file-property v2 (file-name-directory v2-localname))
        (tramp-flush-file-property v2 v2-localname)
        (tramp-barf-unless-okay
         v1
-        (format "%s %s %s" ln (tramp-shell-quote-argument v1-localname)
+        (format "%s %s %s" ln
+                (tramp-shell-quote-argument v1-localname)
                 (tramp-shell-quote-argument v2-localname))
         "error with add-name-to-file, see buffer `%s' for details"
         (buffer-name))))))
@@ -1832,13 +1867,15 @@ tramp-sh-handle-file-name-all-completions: internal error accessing `%s': `%s'"
   (let ((t1 (tramp-tramp-file-p dirname))
        (t2 (tramp-tramp-file-p newname)))
     (with-parsed-tramp-file-name (if t1 dirname newname) nil
-      (if (and (tramp-get-method-parameter method 'tramp-copy-recursive)
+      (if (and (not copy-contents)
+              (tramp-get-method-parameter method 'tramp-copy-recursive)
               ;; When DIRNAME and NEWNAME are remote, they must have
               ;; the same method.
               (or (null t1) (null t2)
                   (string-equal
                    (tramp-file-name-method (tramp-dissect-file-name dirname))
-                   (tramp-file-name-method (tramp-dissect-file-name newname)))))
+                   (tramp-file-name-method
+                    (tramp-dissect-file-name newname)))))
          ;; scp or rsync DTRT.
          (progn
            (setq dirname (directory-file-name (expand-file-name dirname))
@@ -1855,7 +1892,10 @@ tramp-sh-handle-file-name-all-completions: internal error accessing `%s': `%s'"
             'copy dirname newname keep-date))
        ;; We must do it file-wise.
        (tramp-run-real-handler
-        'copy-directory (list dirname newname keep-date parents)))
+        'copy-directory
+        (if copy-contents
+            (list dirname newname keep-date parents copy-contents)
+          (list dirname newname keep-date parents))))
 
       ;; When newname did exist, we have wrong cached values.
       (when t2
@@ -1901,8 +1941,7 @@ file names."
        (t2 (tramp-tramp-file-p newname))
        (length (nth 7 (file-attributes (file-truename filename))))
        (attributes (and preserve-extended-attributes
-                        (apply 'file-extended-attributes (list filename))))
-       pr tm)
+                        (apply 'file-extended-attributes (list filename)))))
 
     (with-parsed-tramp-file-name (if t1 filename newname) nil
       (when (and (not ok-if-already-exists) (file-exists-p newname))
@@ -1980,14 +2019,14 @@ file names."
        ;; In case of `rename', we must flush the cache of the source file.
        (when (and t1 (eq op 'rename))
          (with-parsed-tramp-file-name filename v1
-           (tramp-flush-file-property v1 (file-name-directory localname))
-           (tramp-flush-file-property v1 localname)))
+           (tramp-flush-file-property v1 (file-name-directory v1-localname))
+           (tramp-flush-file-property v1 v1-localname)))
 
        ;; When newname did exist, we have wrong cached values.
        (when t2
          (with-parsed-tramp-file-name newname v2
-           (tramp-flush-file-property v2 (file-name-directory localname))
-           (tramp-flush-file-property v2 localname)))))))
+           (tramp-flush-file-property v2 (file-name-directory v2-localname))
+           (tramp-flush-file-property v2 v2-localname)))))))
 
 (defun tramp-do-copy-or-rename-file-via-buffer (op filename newname keep-date)
   "Use an Emacs buffer to copy or rename a file.
@@ -2005,7 +2044,7 @@ KEEP-DATE is non-nil if NEWNAME should have the same timestamp as FILENAME."
     ;; `jka-compr-inhibit' to t.
     (let ((coding-system-for-write 'binary)
          (jka-compr-inhibit t))
-      (write-region (point-min) (point-max) newname)))
+      (write-region (point-min) (point-max) newname nil 'no-message)))
   ;; KEEP-DATE handling.
   (when keep-date (set-file-times newname (nth 5 (file-attributes filename))))
   ;; Set the mode.
@@ -2074,6 +2113,12 @@ the uid and gid from FILENAME."
           ;; We can do it directly.
           ((let (file-name-handler-alist)
              (and (file-readable-p localname1)
+                  ;; No sticky bit when renaming.
+                  (or (eq op 'copy)
+                      (zerop
+                       (logand
+                        (file-modes (file-name-directory localname1))
+                        (tramp-compat-octal-to-decimal "1000"))))
                   (file-writable-p (file-name-directory localname2))
                   (or (file-directory-p localname2)
                       (file-writable-p localname2))))
@@ -2212,7 +2257,9 @@ The method used must be an out-of-band method."
        (aset v 3 localname)
 
        ;; Check which ones of source and target are Tramp files.
-       (setq source (if t1 (tramp-make-copy-program-file-name v) filename)
+       (setq source (if t1
+                        (tramp-make-copy-program-file-name v)
+                      (shell-quote-argument filename))
              target (funcall
                      (if (and (file-directory-p filename)
                               (string-equal
@@ -2220,7 +2267,9 @@ The method used must be an out-of-band method."
                                (file-name-nondirectory newname)))
                          'file-name-directory
                        'identity)
-                     (if t2 (tramp-make-copy-program-file-name v) newname)))
+                     (if t2
+                         (tramp-make-copy-program-file-name v)
+                       (shell-quote-argument newname))))
 
        ;; Check for host and port number.  We cannot use
        ;; `tramp-file-name-port', because this returns also
@@ -2243,7 +2292,10 @@ The method used must be an out-of-band method."
              spec (format-spec-make
                    ?t (tramp-get-connection-property
                        (tramp-get-connection-process v) "temp-file" ""))
-             options (format-spec tramp-ssh-controlmaster-options spec)
+             options (format-spec
+                      (if tramp-use-ssh-controlmaster-options
+                          tramp-ssh-controlmaster-options "")
+                      spec)
              spec (format-spec-make
                    ?h host ?u user ?p port ?c options
                    ?k (if keep-date " " ""))
@@ -2276,9 +2328,7 @@ The method used must be an out-of-band method."
                (tramp-get-method-parameter method 'tramp-copy-env))))
 
        ;; Check for program.
-       (unless (let ((default-directory
-                       (tramp-compat-temporary-file-directory)))
-                 (executable-find copy-program))
+       (unless (executable-find copy-program)
          (tramp-error
           v 'file-error "Cannot find copy program: %s" copy-program))
 
@@ -2312,13 +2362,13 @@ The method used must be an out-of-band method."
                                  (append
                                   copy-args
                                   (list
-                                   (shell-quote-argument source)
-                                   (shell-quote-argument target)
+                                   source target
                                    "&&" "echo" "tramp_exit_status" "0"
                                    "||" "echo" "tramp_exit_status" "1"))))))
                  (tramp-message
                   orig-vec 6 "%s"
                   (mapconcat 'identity (process-command p) " "))
+                 (tramp-set-connection-property p "vector" orig-vec)
                  (tramp-compat-set-process-query-on-exit-flag p nil)
                  (tramp-process-actions
                   p v nil tramp-actions-copy-out-of-band)
@@ -2329,7 +2379,8 @@ The method used must be an out-of-band method."
                      (re-search-backward "tramp_exit_status [0-9]+" nil t)
                    (tramp-error
                     orig-vec 'file-error
-                    "Couldn't find exit status of `%s'" (process-command p)))
+                    "Couldn't find exit status of `%s'"
+                    (mapconcat 'identity (process-command p) " ")))
                  (skip-chars-forward "^ ")
                  (unless (zerop (read (current-buffer)))
                    (forward-line -1)
@@ -2339,7 +2390,6 @@ The method used must be an out-of-band method."
                     (buffer-substring (point-min) (point-at-eol))))))
 
            ;; Reset the transfer process properties.
-           (tramp-message orig-vec 6 "\n%s" (buffer-string))
            (tramp-set-connection-property v "process-name" nil)
            (tramp-set-connection-property v "process-buffer" nil)))
 
@@ -2422,7 +2472,7 @@ This is like `dired-recursive-delete-directory' for Tramp files."
         (tramp-error
          v 'file-error "Failed to recursively delete %s" filename))))
 
-(defun tramp-sh-handle-dired-compress-file (file &rest ok-flag)
+(defun tramp-sh-handle-dired-compress-file (file &rest _ok-flag)
   "Like `dired-compress-file' for Tramp files."
   ;; OK-FLAG is valid for XEmacs only, but not implemented.
   ;; Code stolen mainly from dired-aux.el.
@@ -2481,11 +2531,12 @@ This is like `dired-recursive-delete-directory' for Tramp files."
   (filename switches &optional wildcard full-directory-p)
   "Like `insert-directory' for Tramp files."
   (setq filename (expand-file-name filename))
+  (unless switches (setq switches ""))
   (with-parsed-tramp-file-name filename nil
     (if (and (featurep 'ls-lisp)
             (not (symbol-value 'ls-lisp-use-insert-directory-program)))
-       (tramp-run-real-handler
-        'insert-directory (list filename switches wildcard full-directory-p))
+       (tramp-handle-insert-directory
+        filename switches wildcard full-directory-p)
       (when (stringp switches)
         (setq switches (split-string switches)))
       (when (and (member "--dired" switches)
@@ -2496,8 +2547,8 @@ This is like `dired-recursive-delete-directory' for Tramp files."
                        'file-name-nondirectory (list localname)))
         (setq localname (tramp-run-real-handler
                         'file-name-directory (list localname))))
-      (unless full-directory-p
-        (setq switches (add-to-list 'switches "-d" 'append)))
+      (unless (or full-directory-p (member "-d" switches))
+        (setq switches (append switches '("-d"))))
       (setq switches (mapconcat 'tramp-shell-quote-argument switches " "))
       (when wildcard
        (setq switches (concat switches " " wildcard)))
@@ -2507,13 +2558,10 @@ This is like `dired-recursive-delete-directory' for Tramp files."
        (if full-directory-p "yes" "no"))
       ;; If `full-directory-p', we just say `ls -l FILENAME'.
       ;; Else we chdir to the parent directory, then say `ls -ld BASENAME'.
-      ;; "--dired" returns byte positions.  Therefore, the file names
-      ;; must be encoded, which is guaranteed by "LC_ALL=en_US.utf8
-      ;; LC_CTYPE=''".
       (if full-directory-p
          (tramp-send-command
           v
-          (format "env LC_ALL=en_US.utf8 LC_CTYPE='' %s %s %s 2>/dev/null"
+          (format "%s %s %s 2>/dev/null"
                   (tramp-get-ls-command v)
                   switches
                   (if wildcard
@@ -2529,7 +2577,7 @@ This is like `dired-recursive-delete-directory' for Tramp files."
          (tramp-run-real-handler 'file-name-directory (list localname))))
        (tramp-send-command
         v
-        (format "env LC_ALL=en_US.utf8 LC_CTYPE='' %s %s %s 2>/dev/null"
+        (format "%s %s %s 2>/dev/null"
                 (tramp-get-ls-command v)
                 switches
                 (if (or wildcard
@@ -2540,61 +2588,64 @@ This is like `dired-recursive-delete-directory' for Tramp files."
                   (tramp-shell-quote-argument
                    (tramp-run-real-handler
                     'file-name-nondirectory (list localname)))))))
-      (let ((beg (point)))
-       ;; We cannot use `insert-buffer-substring' because the Tramp
-       ;; buffer changes its contents before insertion due to calling
-       ;; `expand-file' and alike.
-       (insert
-        (with-current-buffer (tramp-get-buffer v)
-          (buffer-string)))
-
-       ;; Check for "--dired" output.
-       (forward-line -2)
-       (when (looking-at "//SUBDIRED//")
-         (forward-line -1))
-       (when (looking-at "//DIRED//\\s-+")
-         (let ((databeg (match-end 0))
-               (end (point-at-eol)))
-           ;; Now read the numeric positions of file names.
-           (goto-char databeg)
-           (while (< (point) end)
-             (let ((start (+ beg (read (current-buffer))))
-                   (end (+ beg (read (current-buffer)))))
-               (if (memq (char-after end) '(?\n ?\ ))
-                   ;; End is followed by \n or by " -> ".
-                   (put-text-property start end 'dired-filename t))))))
-       ;; Remove trailing lines.
-       (goto-char (point-at-bol))
-       (while (looking-at "//")
-         (forward-line 1)
-         (delete-region (match-beginning 0) (point)))
-
-       ;; Some busyboxes are reluctant to discard colors.
-       (unless (string-match "color" (tramp-get-connection-property v "ls" ""))
-         (goto-char beg)
-         (while (re-search-forward tramp-color-escape-sequence-regexp nil t)
-           (replace-match "")))
-
-       ;; Decode the output, it could be multibyte.
-       (decode-coding-region
-        beg (point-max)
-        (or file-name-coding-system
-            (and (boundp 'default-file-name-coding-system)
-                 (symbol-value 'default-file-name-coding-system))))
-
-       ;; The inserted file could be from somewhere else.
-       (when (and (not wildcard) (not full-directory-p))
-         (goto-char (point-max))
-         (when (file-symlink-p filename)
-           (goto-char (search-backward "->" beg 'noerror)))
-         (search-backward
-          (if (zerop (length (file-name-nondirectory filename)))
-              "."
-            (file-name-nondirectory filename))
-          beg 'noerror)
-         (replace-match (file-relative-name filename) t))
 
-       (goto-char (point-max))))))
+      (save-restriction
+       (let ((beg (point)))
+         (narrow-to-region (point) (point))
+         ;; We cannot use `insert-buffer-substring' because the Tramp
+         ;; buffer changes its contents before insertion due to calling
+         ;; `expand-file' and alike.
+         (insert
+          (with-current-buffer (tramp-get-buffer v)
+            (buffer-string)))
+
+         ;; Check for "--dired" output.
+         (forward-line -2)
+         (when (looking-at "//SUBDIRED//")
+           (forward-line -1))
+         (when (looking-at "//DIRED//\\s-+")
+           (let ((databeg (match-end 0))
+                 (end (point-at-eol)))
+             ;; Now read the numeric positions of file names.
+             (goto-char databeg)
+             (while (< (point) end)
+               (let ((start (+ beg (read (current-buffer))))
+                     (end (+ beg (read (current-buffer)))))
+                 (if (memq (char-after end) '(?\n ?\ ))
+                     ;; End is followed by \n or by " -> ".
+                     (put-text-property start end 'dired-filename t))))))
+         ;; Remove trailing lines.
+         (goto-char (point-at-bol))
+         (while (looking-at "//")
+           (forward-line 1)
+           (delete-region (match-beginning 0) (point)))
+
+         ;; Some busyboxes are reluctant to discard colors.
+         (unless (string-match "color" (tramp-get-connection-property v "ls" ""))
+           (goto-char beg)
+           (while (re-search-forward tramp-color-escape-sequence-regexp nil t)
+             (replace-match "")))
+
+         ;; Decode the output, it could be multibyte.
+         (decode-coding-region
+          beg (point-max)
+          (or file-name-coding-system
+              (and (boundp 'default-file-name-coding-system)
+                   (symbol-value 'default-file-name-coding-system))))
+
+         ;; The inserted file could be from somewhere else.
+         (when (and (not wildcard) (not full-directory-p))
+           (goto-char (point-max))
+           (when (file-symlink-p filename)
+             (goto-char (search-backward "->" beg 'noerror)))
+           (search-backward
+            (if (zerop (length (file-name-nondirectory filename)))
+                "."
+              (file-name-nondirectory filename))
+            beg 'noerror)
+           (replace-match (file-relative-name filename) t))
+
+         (goto-char (point-max)))))))
 
 ;; Canonicalization of file names.
 
@@ -2659,17 +2710,12 @@ the result will be a local, non-Tramp, filename."
 
 ;;; Remote commands:
 
-(defun tramp-sh-handle-executable-find (command)
-  "Like `executable-find' for Tramp files."
-  (with-parsed-tramp-file-name default-directory nil
-    (tramp-find-executable v command (tramp-get-remote-path v) t)))
-
 (defun tramp-process-sentinel (proc event)
   "Flush file caches."
   (unless (memq (process-status proc) '(run open))
     (let ((vec (tramp-get-connection-property proc "vector" nil)))
       (when vec
-       (tramp-message vec 5 "Sentinel called: `%s' `%s'" proc event)
+       (tramp-message vec 5 "Sentinel called: `%S' `%s'" proc event)
         (tramp-flush-connection-property proc)
         (tramp-flush-directory-property vec "")))))
 
@@ -2679,27 +2725,47 @@ the result will be a local, non-Tramp, filename."
 (defun tramp-sh-handle-start-file-process (name buffer program &rest args)
   "Like `start-file-process' for Tramp files."
   (with-parsed-tramp-file-name default-directory nil
-    ;; When PROGRAM is nil, we just provide a tty.
-    (let ((command
-          (when (stringp program)
-            (format "cd %s; exec env PS1=%s %s"
-                    (tramp-shell-quote-argument localname)
-                    ;; Use a human-friendly prompt, for example for `shell'.
-                    (tramp-shell-quote-argument
-                     (format "%s %s"
-                             (file-remote-p default-directory)
-                             tramp-initial-end-of-output))
-                    (mapconcat 'tramp-shell-quote-argument
-                               (cons program args) " "))))
-         (tramp-process-connection-type
-          (or (null program) tramp-process-connection-type))
-         (bmp (and (buffer-live-p buffer) (buffer-modified-p buffer)))
-         (name1 name)
-         (i 0)
-         ;; We do not want to raise an error when
-         ;; `start-file-process' has been started several time in
-         ;; `eshell' and friends.
-         (tramp-current-connection nil))
+    (let* (;; When PROGRAM matches "*sh", and the first arg is "-c",
+          ;; it might be that the arguments exceed the command line
+          ;; length.  Therefore, we modify the command.
+          (heredoc (and (stringp program)
+                        (string-match "sh$" program)
+                        (string-equal "-c" (car args))
+                        (= (length args) 2)))
+          ;; When PROGRAM is nil, we just provide a tty.
+          (args (if (not heredoc) args
+                  (let ((i 250))
+                    (while (and (< i (length (cadr args)))
+                                (string-match " " (cadr args) i))
+                      (setcdr
+                       args
+                       (list (replace-match " \\\\\n" nil nil (cadr args))))
+                      (setq i (+ i 250))))
+                  (cdr args)))
+          (command
+           (when (stringp program)
+             (format "cd %s && exec %s env PS1=%s %s"
+                     (tramp-shell-quote-argument localname)
+                     (if heredoc (format "<<'%s'" tramp-end-of-heredoc) "")
+                     ;; Use a human-friendly prompt, for example for `shell'.
+                     (tramp-shell-quote-argument
+                      (format "%s %s"
+                              (file-remote-p default-directory)
+                              tramp-initial-end-of-output))
+                     (if heredoc
+                         (format "%s\n(\n%s\n) </dev/tty\n%s"
+                                 program (car args) tramp-end-of-heredoc)
+                       (mapconcat 'tramp-shell-quote-argument
+                                  (cons program args) " ")))))
+          (tramp-process-connection-type
+           (or (null program) tramp-process-connection-type))
+          (bmp (and (buffer-live-p buffer) (buffer-modified-p buffer)))
+          (name1 name)
+          (i 0)
+          ;; We do not want to raise an error when
+          ;; `start-file-process' has been started several time in
+          ;; `eshell' and friends.
+          (tramp-current-connection nil))
 
       (unless buffer
        ;; BUFFER can be nil.  We use a temporary buffer.
@@ -2725,7 +2791,7 @@ the result will be a local, non-Tramp, filename."
                ;; `verify-visited-file-modtime'.
                (let ((buffer-undo-list t)
                      (buffer-read-only nil)
-                     (mark (point)))
+                     (mark (point-max)))
                  (clear-visited-file-modtime)
                  (narrow-to-region (point-max) (point-max))
                  ;; We call `tramp-maybe-open-connection', in order
@@ -2923,7 +2989,8 @@ the result will be a local, non-Tramp, filename."
                      ;; epa-file gets confused.
                      (let (file-name-handler-alist
                            (coding-system-for-write 'binary))
-                       (write-region (point-min) (point-max) tmpfile)))
+                       (write-region
+                        (point-min) (point-max) tmpfile nil 'no-message)))
 
                  ;; If tramp-decoding-function is not defined for this
                  ;; method, we invoke tramp-decoding-command instead.
@@ -2933,7 +3000,8 @@ the result will be a local, non-Tramp, filename."
                    (let (file-name-handler-alist
                          (coding-system-for-write 'binary))
                      (with-current-buffer (tramp-get-buffer v)
-                       (write-region (point-min) (point-max) tmpfile2)))
+                       (write-region
+                        (point-min) (point-max) tmpfile2 nil 'no-message)))
                    (unwind-protect
                        (tramp-call-local-coding-command
                         loc-dec tmpfile2 tmpfile)
@@ -2972,55 +3040,13 @@ the result will be a local, non-Tramp, filename."
        (inhibit-file-name-operation 'insert-file-contents))
     (unwind-protect
        (progn
-         (fset 'find-buffer-file-type (lambda (filename) t))
+         (fset 'find-buffer-file-type (lambda (_filename) t))
          (insert-file-contents filename visit beg end replace))
       ;; Save exit.
       (if find-buffer-file-type-function
          (fset 'find-buffer-file-type find-buffer-file-type-function)
        (fmakunbound 'find-buffer-file-type)))))
 
-(defun tramp-sh-handle-make-auto-save-file-name ()
-  "Like `make-auto-save-file-name' for Tramp files.
-Returns a file name in `tramp-auto-save-directory' for autosaving this file."
-  (let ((tramp-auto-save-directory tramp-auto-save-directory)
-       (buffer-file-name
-        (tramp-subst-strs-in-string
-         '(("_" . "|")
-           ("/" . "_a")
-           (":" . "_b")
-           ("|" . "__")
-           ("[" . "_l")
-           ("]" . "_r"))
-         (buffer-file-name))))
-    ;; File name must be unique.  This is ensured with Emacs 22 (see
-    ;; UNIQUIFY element of `auto-save-file-name-transforms'); but for
-    ;; all other cases we must do it ourselves.
-    (when (boundp 'auto-save-file-name-transforms)
-      (mapc
-       (lambda (x)
-        (when (and (string-match (car x) buffer-file-name)
-                   (not (car (cddr x))))
-          (setq tramp-auto-save-directory
-                (or tramp-auto-save-directory
-                    (tramp-compat-temporary-file-directory)))))
-       (symbol-value 'auto-save-file-name-transforms)))
-    ;; Create directory.
-    (when tramp-auto-save-directory
-      (setq buffer-file-name
-           (expand-file-name buffer-file-name tramp-auto-save-directory))
-      (unless (file-exists-p tramp-auto-save-directory)
-       (make-directory tramp-auto-save-directory t)))
-    ;; Run plain `make-auto-save-file-name'.  There might be an advice when
-    ;; it is not a magic file name operation (since Emacs 22).
-    ;; We must deactivate it temporarily.
-    (if (not (ad-is-active 'make-auto-save-file-name))
-       (tramp-run-real-handler 'make-auto-save-file-name nil)
-      ;; else
-      (ad-deactivate 'make-auto-save-file-name)
-      (prog1
-       (tramp-run-real-handler 'make-auto-save-file-name nil)
-       (ad-activate 'make-auto-save-file-name)))))
-
 ;; CCC grok LOCKNAME
 (defun tramp-sh-handle-write-region
   (start end filename &optional append visit lockname confirm)
@@ -3196,9 +3222,11 @@ Returns a file name in `tramp-auto-save-directory' for autosaving this file."
                      (tramp-send-command
                       v
                       (format
-                       (concat rem-dec " <<'EOF'\n%sEOF")
+                       (concat rem-dec " <<'%s'\n%s%s")
                        (tramp-shell-quote-argument localname)
-                       (buffer-string)))
+                       tramp-end-of-heredoc
+                       (buffer-string)
+                       tramp-end-of-heredoc))
                      (tramp-barf-unless-okay
                       v nil
                       "Couldn't write region to `%s', decode using `%s' failed"
@@ -3292,7 +3320,10 @@ Returns a file name in `tramp-auto-save-directory' for autosaving this file."
          v 3 (format "Checking `vc-registered' for %s" file)
 
        ;; There could be new files, created by the vc backend.  We
-       ;; cannot reuse the old cache entries, therefore.
+       ;; cannot reuse the old cache entries, therefore.  In
+       ;; `tramp-get-file-property', `remote-file-name-inhibit-cache'
+       ;; could also be a timestamp as `current-time' returns.  This
+       ;; means invalidate all cache entries with an older timestamp.
        (let (tramp-vc-registered-file-names
              (remote-file-name-inhibit-cache (current-time))
              (file-name-handler-alist
@@ -3313,23 +3344,34 @@ Returns a file name in `tramp-auto-save-directory' for autosaving this file."
 
            (dolist
                (elt
-                (tramp-send-command-and-read
-                 v
-                 (format
-                  "tramp_vc_registered_read_file_names <<'EOF'\n%s\nEOF\n"
-                  (mapconcat 'tramp-shell-quote-argument
-                             tramp-vc-registered-file-names
-                             "\n"))))
+                (ignore-errors
+                  ;; We cannot use `tramp-send-command-and-read',
+                  ;; because this does not cooperate well with
+                  ;; heredoc documents.
+                  (tramp-send-command
+                   v
+                   (format
+                    "tramp_vc_registered_read_file_names <<'%s'\n%s\n%s\n"
+                    tramp-end-of-heredoc
+                    (mapconcat 'tramp-shell-quote-argument
+                               tramp-vc-registered-file-names
+                               "\n")
+                    tramp-end-of-heredoc))
+                  (with-current-buffer (tramp-get-connection-buffer v)
+                    ;; Read the expression.
+                    (goto-char (point-min))
+                    (read (current-buffer)))))
 
              (tramp-set-file-property
               v (car elt) (cadr elt) (cadr (cdr elt))))))
 
        ;; Second run.  Now all `file-exists-p' or `file-readable-p'
        ;; calls shall be answered from the file cache.  We unset
-       ;; `process-file-side-effects' in order to keep the cache when
-       ;; `process-file' calls appear.
-       (let (process-file-side-effects)
-         (tramp-run-real-handler 'vc-registered (list file)))))))
+       ;; `process-file-side-effects' and `remote-file-name-inhibit-cache'
+       ;; in order to keep the cache.
+       (let (remote-file-name-inhibit-cache process-file-side-effects)
+         (ignore-errors
+           (tramp-run-real-handler 'vc-registered (list file))))))))
 
 ;;;###tramp-autoload
 (defun tramp-sh-file-name-handler (operation &rest args)
@@ -3337,17 +3379,18 @@ Returns a file name in `tramp-auto-save-directory' for autosaving this file."
 Fall back to normal file name handler if no Tramp handler exists."
   (when (and tramp-locked (not tramp-locker))
     (setq tramp-locked nil)
-    (signal 'file-error (list "Forbidden reentrant call of Tramp")))
+    (tramp-error
+     (car-safe tramp-current-connection) 'file-error
+     "Forbidden reentrant call of Tramp"))
   (let ((tl tramp-locked))
+    (setq tramp-locked t)
     (unwind-protect
-       (progn
-         (setq tramp-locked t)
-         (let ((tramp-locker t))
-           (save-match-data
-             (let ((fn (assoc operation tramp-sh-file-name-handler-alist)))
-               (if fn
-                   (apply (cdr fn) args)
-                 (tramp-run-real-handler operation args))))))
+       (let ((tramp-locker t))
+         (save-match-data
+           (let ((fn (assoc operation tramp-sh-file-name-handler-alist)))
+             (if fn
+                 (apply (cdr fn) args)
+               (tramp-run-real-handler operation args)))))
       (setq tramp-locked tl))))
 
 (defun tramp-vc-file-name-handler (operation &rest args)
@@ -3376,6 +3419,121 @@ Fall back to normal file name handler if no Tramp handler exists."
         ;; Default file name handlers, we don't care.
         (t (tramp-run-real-handler operation args)))))))
 
+(defun tramp-sh-handle-file-notify-add-watch (file-name flags _callback)
+  "Like `file-notify-add-watch' for Tramp files."
+  (setq file-name (expand-file-name file-name))
+  (with-parsed-tramp-file-name file-name nil
+    (let* ((default-directory (file-name-directory file-name))
+          command events filter p sequence)
+      (cond
+       ;; gvfs-monitor-dir.
+       ((setq command (tramp-get-remote-gvfs-monitor-dir v))
+       (setq filter 'tramp-sh-file-gvfs-monitor-dir-process-filter
+             sequence `(,command ,localname)))
+       ;; inotifywait.
+       ((setq command (tramp-get-remote-inotifywait v))
+       (setq filter 'tramp-sh-file-inotifywait-process-filter
+             events
+             (cond
+              ((and (memq 'change flags) (memq 'attribute-change flags))
+               "create,modify,move,delete,attrib")
+              ((memq 'change flags) "create,modify,move,delete")
+              ((memq 'attribute-change flags) "attrib"))
+             sequence `(,command "-mq" "-e" ,events ,localname)))
+       ;; None.
+       (t (tramp-error
+          v 'file-notify-error
+          "No file notification program found on %s"
+          (file-remote-p file-name))))
+      ;; Start process.
+      (setq p (apply
+              'start-file-process
+              (file-name-nondirectory command)
+              (generate-new-buffer
+               (format " *%s*" (file-name-nondirectory command)))
+              sequence))
+      ;; Return the process object as watch-descriptor.
+      (if (not (processp p))
+         (tramp-error
+          v 'file-notify-error
+          "`%s' failed to start on remote host"
+          (mapconcat 'identity sequence " "))
+       (tramp-message v 6 "Run `%s', %S" (mapconcat 'identity sequence " ") p)
+       (tramp-set-connection-property p "vector" v)
+       (tramp-compat-set-process-query-on-exit-flag p nil)
+       (set-process-filter p filter)
+       p))))
+
+(defun tramp-sh-file-gvfs-monitor-dir-process-filter (proc string)
+  "Read output from \"gvfs-monitor-dir\" and add corresponding file-notify events."
+  (let ((remote-prefix
+        (with-current-buffer (process-buffer proc)
+          (file-remote-p default-directory)))
+       (rest-string (tramp-compat-process-get proc 'rest-string)))
+    (when rest-string
+      (tramp-message proc 10 "Previous string:\n%s" rest-string))
+    (tramp-message proc 6 "%S\n%s" proc string)
+    (setq string (concat rest-string string)
+         ;; Attribute change is returned in unused wording.
+         string (tramp-compat-replace-regexp-in-string
+                 "ATTRIB CHANGED" "ATTRIBUTE_CHANGED" string))
+
+    (while (string-match
+           (concat "^[\n\r]*"
+                   "Directory Monitor Event:[\n\r]+"
+                   "Child = \\([^\n\r]+\\)[\n\r]+"
+                   "\\(Other = \\([^\n\r]+\\)[\n\r]+\\)?"
+                   "Event = \\([^[:blank:]]+\\)[\n\r]+")
+           string)
+      (let ((object
+            (list
+             proc
+             (intern-soft
+              (tramp-compat-replace-regexp-in-string
+               "_" "-" (downcase (match-string 4 string))))
+             ;; File names are returned as absolute paths.  We must
+             ;; add the remote prefix.
+             (concat remote-prefix (match-string 1 string))
+             (when (match-string 3 string)
+               (concat remote-prefix (match-string 3 string))))))
+       (setq string (replace-match "" nil nil string))
+       ;; Usually, we would add an Emacs event now.  Unfortunately,
+       ;; `unread-command-events' does not accept several events at
+       ;; once.  Therefore, we apply the callback directly.
+       (tramp-compat-funcall 'file-notify-callback object)))
+
+    ;; Save rest of the string.
+    (when (zerop (length string)) (setq string nil))
+    (when string (tramp-message proc 10 "Rest string:\n%s" string))
+    (tramp-compat-process-put proc 'rest-string string)))
+
+(defun tramp-sh-file-inotifywait-process-filter (proc string)
+  "Read output from \"inotifywait\" and add corresponding file-notify events."
+  (tramp-message proc 6 "%S\n%s" proc string)
+  (dolist (line (split-string string "[\n\r]+" 'omit-nulls))
+    ;; Check, whether there is a problem.
+    (unless
+       (string-match
+        (concat "^[^[:blank:]]+"
+                "[[:blank:]]+\\([^[:blank:]]+\\)+"
+                "\\([[:blank:]]+\\([^\n\r]+\\)\\)?")
+        line)
+      (tramp-error proc 'file-notify-error "%s" line))
+
+    (let ((object
+          (list
+           proc
+           (mapcar
+            (lambda (x)
+              (intern-soft
+               (tramp-compat-replace-regexp-in-string "_" "-" (downcase x))))
+            (split-string (match-string 1 line) "," 'omit-nulls))
+           (match-string 3 line))))
+      ;; Usually, we would add an Emacs event now.  Unfortunately,
+      ;; `unread-command-events' does not accept several events at
+      ;; once.  Therefore, we apply the callback directly.
+      (tramp-compat-funcall 'file-notify-callback object))))
+
 ;;; Internal Functions:
 
 (defun tramp-maybe-send-script (vec script name)
@@ -3456,8 +3614,13 @@ This function expects to be in the right *tramp* buffer."
     (let (result)
       ;; Check whether the executable is in $PATH. "which(1)" does not
       ;; report always a correct error code; therefore we check the
-      ;; number of words it returns.
-      (unless ignore-path
+      ;; number of words it returns.  "SunOS 5.10" (and maybe "SunOS
+      ;; 5.11") have problems with this command, we disable the call
+      ;; therefore.
+      (unless (or ignore-path
+                 (string-match
+                  (regexp-opt '("SunOS 5.10" "SunOS 5.11"))
+                  (tramp-get-connection-property vec "uname" "")))
        (tramp-send-command vec (format "which \\%s | wc -w" progname))
        (goto-char (point-min))
        (if (looking-at "^\\s-*1$")
@@ -3478,9 +3641,12 @@ This function expects to be in the right *tramp* buffer."
         (format (concat "while read d; "
                         "do if test -x $d/%s -a -f $d/%s; "
                         "then echo tramp_executable $d/%s; "
-                        "break; fi; done <<'EOF'\n"
-                        "%s\nEOF")
-                progname progname progname (mapconcat 'identity dirlist "\n")))
+                        "break; fi; done <<'%s'\n"
+                        "%s\n%s")
+                progname progname progname
+                tramp-end-of-heredoc
+                (mapconcat 'identity dirlist "\n")
+                tramp-end-of-heredoc))
        (goto-char (point-max))
        (when (search-backward "tramp_executable " nil t)
          (skip-chars-forward "^ ")
@@ -3493,7 +3659,7 @@ This function expects to be in the right *tramp* buffer."
 I.e., for each directory in `tramp-remote-path', it is tested
 whether it exists and if so, it is added to the environment
 variable PATH."
-  (tramp-message vec 5 (format "Setting $PATH environment variable"))
+  (tramp-message vec 5 "Setting $PATH environment variable")
   (tramp-send-command
    vec (format "PATH=%s; export PATH"
               (mapconcat 'identity (tramp-get-remote-path vec) ":"))))
@@ -3561,8 +3727,7 @@ file exists and nonzero exit status otherwise."
   (with-tramp-progress-reporter
       vec 5 (format "Opening remote shell `%s'" shell)
     ;; Find arguments for this shell.
-    (let ((tramp-end-of-output tramp-initial-end-of-output)
-         (alist tramp-sh-extra-args)
+    (let ((alist tramp-sh-extra-args)
          item extra-args)
       (while (and alist (null extra-args))
        (setq item (pop alist))
@@ -3570,18 +3735,12 @@ file exists and nonzero exit status otherwise."
          (setq extra-args (cdr item))))
       (tramp-send-command
        vec (format
-           "exec env ENV='' PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s %s"
+           "exec env ENV='' HISTFILE=/dev/null PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s %s"
            (tramp-shell-quote-argument tramp-end-of-output)
            shell (or extra-args ""))
        t))
     (tramp-set-connection-property
-     (tramp-get-connection-process vec) "remote-shell" shell)
-    ;; Setting prompts.
-    (tramp-send-command
-     vec (format "PS1=%s" (tramp-shell-quote-argument tramp-end-of-output)) t)
-    (tramp-send-command vec "PS2=''" t)
-    (tramp-send-command vec "PS3=''" t)
-    (tramp-send-command vec "PROMPT_COMMAND=''" t)))
+     (tramp-get-connection-process vec) "remote-shell" shell)))
 
 (defun tramp-find-shell (vec)
   "Opens a shell on the remote host which groks tilde expansion."
@@ -3626,13 +3785,7 @@ file exists and nonzero exit status otherwise."
       (unless (string-equal shell default-shell)
        (tramp-message
         vec 5 "Starting remote shell `%s' for tilde expansion" shell)
-       (tramp-open-shell vec shell))
-
-      ;; Busyboxes tend to behave strange.  We check for the existence.
-      (with-tramp-connection-property vec "busybox"
-       (tramp-send-command vec (format "%s --version" shell) t)
-       (let ((case-fold-search t))
-         (and (string-match "busybox" (buffer-string)) t))))))
+       (tramp-open-shell vec shell)))))
 
 ;; Utility functions.
 
@@ -3640,12 +3793,16 @@ file exists and nonzero exit status otherwise."
   "Wait for shell prompt and barf if none appears.
 Looks at process PROC to see if a shell prompt appears in TIMEOUT
 seconds.  If not, it produces an error message with the given ERROR-ARGS."
-  (unless
-      (tramp-wait-for-regexp
-       proc timeout
-       (format
-       "\\(%s\\|%s\\)\\'" shell-prompt-pattern tramp-shell-prompt-pattern))
-    (apply 'tramp-error-with-buffer nil proc 'file-error error-args)))
+  (let ((vec (tramp-get-connection-property proc "vector" nil)))
+    (condition-case nil
+       (tramp-wait-for-regexp
+        proc timeout
+        (format
+         "\\(%s\\|%s\\)\\'" shell-prompt-pattern tramp-shell-prompt-pattern))
+      (error
+       (delete-process proc)
+       (apply 'tramp-error-with-buffer
+             (tramp-get-connection-buffer vec) vec 'file-error error-args)))))
 
 (defun tramp-open-connection-setup-interactive-shell (proc vec)
   "Set up an interactive shell.
@@ -3741,11 +3898,12 @@ process to set up.  VEC specifies the connection."
          vec "uname"
          (tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\""))))
     (when (and (stringp old-uname) (not (string-equal old-uname new-uname)))
-      (tramp-cleanup vec)
       (tramp-message
        vec 3
        "Connection reset, because remote host changed from `%s' to `%s'"
        old-uname new-uname)
+      ;; We want to keep the password.
+      (tramp-cleanup-connection vec t t)
       (throw 'uname-changed (tramp-maybe-open-connection vec))))
 
   ;; Check whether the remote host suffers from buggy
@@ -3806,7 +3964,9 @@ process to set up.  VEC specifies the connection."
   ;; Set the environment.
   (tramp-message vec 5 "Setting default environment")
 
-  (let ((env (copy-sequence tramp-remote-process-environment))
+  (let ((env (append (when (tramp-get-remote-locale vec) ; Discard `(nil)'.
+                      `(,(tramp-get-remote-locale vec)))
+                    (copy-sequence tramp-remote-process-environment)))
        unset item)
     (while env
       (setq item (tramp-compat-split-string (car env) "="))
@@ -3944,6 +4104,10 @@ Goes through the list `tramp-local-coding-commands' and
                     vec 5 "Checking remote test command `%s'" rem-test)
                    (unless (tramp-send-command-and-check vec rem-test t)
                      (throw 'wont-work-remote nil)))
+                 ;; Check if remote perl exists when necessary.
+                 (when (and (not (stringp rem-enc))
+                            (not (tramp-get-remote-perl vec)))
+                   (throw 'wont-work-remote nil))
                  ;; Check if remote encoding and decoding commands can be
                  ;; called remotely with null input and output.  This makes
                  ;; sure there are no syntax errors and the command is really
@@ -4092,9 +4256,6 @@ Goes through the list `tramp-inline-compress-commands'."
        (tramp-message
         vec 2 "Couldn't find an inline transfer compress command")))))
 
-(defvar tramp-gw-tunnel-method)
-(defvar tramp-gw-socks-method)
-
 (defun tramp-compute-multi-hops (vec)
   "Expands VEC according to `tramp-default-proxies-alist'.
 Gateway hops are already opened."
@@ -4150,7 +4311,7 @@ Gateway hops are already opened."
                  ?h (or (tramp-file-name-host (car target-alist)) ""))))
          (with-parsed-tramp-file-name proxy l
            ;; Add the hop.
-           (add-to-list 'target-alist l)
+           (push l target-alist)
            ;; Start next search.
            (setq choices tramp-default-proxies-alist)))))
 
@@ -4168,11 +4329,11 @@ Gateway hops are already opened."
           vec 'file-error
           "Connection `%s' is not supported for gateway access." hop))
        ;; Open the gateway connection.
-       (add-to-list
-        'target-alist
+       (push
         (vector
          (tramp-file-name-method hop) (tramp-file-name-user hop)
-         (tramp-compat-funcall 'tramp-gw-open-connection vec gw hop) nil nil))
+         (tramp-compat-funcall 'tramp-gw-open-connection vec gw hop) nil nil)
+        target-alist)
        ;; For the password prompt, we need the correct values.
        ;; Therefore, we must remember the gateway vector.  But we
        ;; cannot do it as connection property, because it shouldn't
@@ -4220,86 +4381,83 @@ Gateway hops are already opened."
     ;; Result.
     target-alist))
 
-(defvar tramp-current-connection nil
-  "Last connection timestamp.")
-
 (defun tramp-maybe-open-connection (vec)
   "Maybe open a connection VEC.
 Does not do anything if a connection is already open, but re-opens the
 connection if a previous connection has died for some reason."
-  (catch 'uname-changed
-    (let ((p (tramp-get-connection-process vec))
-         (process-name (tramp-get-connection-property vec "process-name" nil))
-         (process-environment (copy-sequence process-environment))
-         (pos (with-current-buffer (tramp-get-connection-buffer vec) (point))))
-
-      ;; If Tramp opens the same connection within a short time frame,
-      ;; there is a problem.  We shall signal this.
-      (unless (or (and p (processp p) (memq (process-status p) '(run open)))
-                 (not (equal (butlast (append vec nil))
-                             (car tramp-current-connection)))
-                 (> (tramp-time-diff
-                     (current-time) (cdr tramp-current-connection))
-                    (or tramp-connection-min-time-diff 0)))
-       (throw 'suppress 'suppress))
-
-      ;; If too much time has passed since last command was sent, look
-      ;; whether process is still alive.  If it isn't, kill it.  When
-      ;; using ssh, it can sometimes happen that the remote end has
-      ;; hung up but the local ssh client doesn't recognize this until
-      ;; it tries to send some data to the remote end.  So that's why
-      ;; we try to send a command from time to time, then look again
-      ;; whether the process is really alive.
-      (condition-case nil
-         (when (and (> (tramp-time-diff
-                        (current-time)
-                        (tramp-get-connection-property
-                         p "last-cmd-time" '(0 0 0)))
-                       60)
-                    p (processp p) (memq (process-status p) '(run open)))
-           (tramp-send-command vec "echo are you awake" t t)
-           (unless (and (memq (process-status p) '(run open))
-                        (tramp-wait-for-output p 10))
-             ;; The error will be caught locally.
-             (tramp-error vec 'file-error "Awake did fail")))
-       (file-error
-        (tramp-cleanup vec)
-        (setq p nil)))
-
-      ;; New connection must be opened.
-      (condition-case err
-         (unless (and p (processp p) (memq (process-status p) '(run open)))
-
-           ;; We call `tramp-get-buffer' in order to get a debug
-           ;; buffer for messages from the beginning.
-           (tramp-get-buffer vec)
-
-           ;; If `non-essential' is non-nil, don't reopen a new connection.
-           (when (and (boundp 'non-essential) (symbol-value 'non-essential))
-             (throw 'non-essential 'non-essential))
-
-           (with-tramp-progress-reporter
-               vec 3
-               (if (zerop (length (tramp-file-name-user vec)))
-                   (format "Opening connection for %s using %s"
-                           (tramp-file-name-host vec)
-                           (tramp-file-name-method vec))
-                 (format "Opening connection for %s@%s using %s"
-                         (tramp-file-name-user vec)
+  (tramp-check-proper-method-and-host vec)
+
+  (let ((p (tramp-get-connection-process vec))
+       (process-name (tramp-get-connection-property vec "process-name" nil))
+       (process-environment (copy-sequence process-environment))
+       (pos (with-current-buffer (tramp-get-connection-buffer vec) (point))))
+
+    ;; If Tramp opens the same connection within a short time frame,
+    ;; there is a problem.  We shall signal this.
+    (unless (or (and p (processp p) (memq (process-status p) '(run open)))
+               (not (equal (butlast (append vec nil) 2)
+                           (car tramp-current-connection)))
+               (> (tramp-time-diff
+                   (current-time) (cdr tramp-current-connection))
+                  (or tramp-connection-min-time-diff 0)))
+      (throw 'suppress 'suppress))
+
+    ;; If too much time has passed since last command was sent, look
+    ;; whether process is still alive.  If it isn't, kill it.  When
+    ;; using ssh, it can sometimes happen that the remote end has hung
+    ;; up but the local ssh client doesn't recognize this until it
+    ;; tries to send some data to the remote end.  So that's why we
+    ;; try to send a command from time to time, then look again
+    ;; whether the process is really alive.
+    (condition-case nil
+       (when (and (> (tramp-time-diff
+                      (current-time)
+                      (tramp-get-connection-property
+                       p "last-cmd-time" '(0 0 0)))
+                     60)
+                  p (processp p) (memq (process-status p) '(run open)))
+         (tramp-send-command vec "echo are you awake" t t)
+         (unless (and (memq (process-status p) '(run open))
+                      (tramp-wait-for-output p 10))
+           ;; The error will be caught locally.
+           (tramp-error vec 'file-error "Awake did fail")))
+      (file-error
+       (tramp-cleanup-connection vec t)
+       (setq p nil)))
+
+    ;; New connection must be opened.
+    (condition-case err
+       (unless (and p (processp p) (memq (process-status p) '(run open)))
+
+         ;; If `non-essential' is non-nil, don't reopen a new connection.
+         (when (and (boundp 'non-essential) (symbol-value 'non-essential))
+           (throw 'non-essential 'non-essential))
+
+         (with-tramp-progress-reporter
+             vec 3
+             (if (zerop (length (tramp-file-name-user vec)))
+                 (format "Opening connection for %s using %s"
                          (tramp-file-name-host vec)
-                         (tramp-file-name-method vec)))
+                         (tramp-file-name-method vec))
+               (format "Opening connection for %s@%s using %s"
+                       (tramp-file-name-user vec)
+                       (tramp-file-name-host vec)
+                       (tramp-file-name-method vec)))
 
+           (catch 'uname-changed
              ;; Start new process.
              (when (and p (processp p))
                (delete-process p))
              (setenv "TERM" tramp-terminal-type)
-             (setenv "LC_ALL" "C")
+             (setenv "LC_ALL" "en_US.utf8")
+             (setenv "HISTFILE" "/dev/null")
              (setenv "PROMPT_COMMAND")
              (setenv "PS1" tramp-initial-end-of-output)
              (let* ((target-alist (tramp-compute-multi-hops vec))
                     ;; We will apply `tramp-ssh-controlmaster-options'
                     ;; only for the first hop.
-                    (options tramp-ssh-controlmaster-options)
+                    (options (if tramp-use-ssh-controlmaster-options
+                                 tramp-ssh-controlmaster-options ""))
                     (process-connection-type tramp-process-connection-type)
                     (process-adaptive-read-buffering nil)
                     (coding-system-for-read nil)
@@ -4321,7 +4479,7 @@ connection if a previous connection has died for some reason."
                (set-process-sentinel p 'tramp-process-sentinel)
                (tramp-compat-set-process-query-on-exit-flag p nil)
                (setq tramp-current-connection
-                     (cons (butlast (append vec nil)) (current-time))
+                     (cons (butlast (append vec nil) 2) (current-time))
                      tramp-current-host (system-name))
 
                (tramp-message
@@ -4329,8 +4487,8 @@ connection if a previous connection has died for some reason."
 
                ;; Check whether process is alive.
                (tramp-barf-if-no-shell-prompt
-                p 60
-                "Couldn't find local shell prompt %s" tramp-encoding-shell)
+                p 10
+                "Couldn't find local shell prompt for %s" tramp-encoding-shell)
 
                ;; Now do all the connections as specified.
                (while target-alist
@@ -4345,9 +4503,15 @@ connection if a previous connection has died for some reason."
                         (login-args
                          (tramp-get-method-parameter
                           l-method 'tramp-login-args))
+                        (login-env
+                         (tramp-get-method-parameter
+                          l-method 'tramp-login-env))
                         (async-args
                          (tramp-get-method-parameter
                           l-method 'tramp-async-args))
+                        (connection-timeout
+                         (tramp-get-method-parameter
+                          l-method 'tramp-connection-timeout))
                         (gw-args
                          (tramp-get-method-parameter l-method 'tramp-gw-args))
                         (gw (tramp-get-file-property hop "" "gateway" nil))
@@ -4399,7 +4563,25 @@ connection if a previous connection has died for some reason."
                          tramp-current-user   (or g-user   l-user)
                          tramp-current-host   (or g-host   l-host))
 
-                   ;; Replace login-args place holders.
+                   ;; Add login environment.
+                   (when login-env
+                     (setq
+                      login-env
+                      (mapcar
+                       (lambda (x)
+                         (setq x (mapcar (lambda (y) (format-spec y spec)) x))
+                         (unless (member "" x) (mapconcat 'identity x " ")))
+                       login-env))
+                     (while login-env
+                       (setq command
+                             (format
+                              "%s=%s %s"
+                              (pop login-env)
+                              (tramp-shell-quote-argument (pop login-env))
+                              command)))
+                     (setq command (concat "env " command)))
+
+                   ;; Replace `login-args' place holders.
                    (setq
                     l-host (or l-host "")
                     l-user (or l-user "")
@@ -4430,7 +4612,8 @@ connection if a previous connection has died for some reason."
                    (tramp-message vec 3 "Sending command `%s'" command)
                    (tramp-send-command vec command t t)
                    (tramp-process-actions
-                    p vec pos tramp-actions-before-shell 60)
+                    p vec pos tramp-actions-before-shell
+                    (or connection-timeout tramp-connection-timeout))
                    (tramp-message
                     vec 3 "Found remote shell prompt on `%s'" l-host))
                  ;; Next hop.
@@ -4438,13 +4621,13 @@ connection if a previous connection has died for some reason."
                        target-alist (cdr target-alist)))
 
                ;; Make initial shell settings.
-               (tramp-open-connection-setup-interactive-shell p vec))))
+               (tramp-open-connection-setup-interactive-shell p vec)))))
 
-       ;; When the user did interrupt, we must cleanup.
-       (quit
-        (tramp-cleanup vec)
-        ;; Propagate the quit signal.
-        (signal (car err) (cdr err)))))))
+      ;; When the user did interrupt, we must cleanup.
+      (quit
+       (tramp-cleanup-connection vec t)
+       ;; Propagate the quit signal.
+       (signal (car err) (cdr err))))))
 
 (defun tramp-send-command (vec command &optional neveropen nooutput)
   "Send the COMMAND to connection VEC.
@@ -4458,11 +4641,6 @@ function waits for output unless NOOUTPUT is set."
       ;; We mark the command string that it can be erased in the output buffer.
       (tramp-set-connection-property p "check-remote-echo" t)
       (setq command (format "%s%s%s" tramp-echo-mark command tramp-echo-mark)))
-    (when (and (string-match "<<'EOF'" command)
-              (not (tramp-get-connection-property vec "busybox" nil)))
-      ;; Unset $PS1 when using here documents, in order to avoid
-      ;; multiple prompts.
-      (setq command (concat "(PS1= ; " command "\n)")))
     ;; Send the command.
     (tramp-message vec 6 "%s" command)
     (tramp-send-string vec command)
@@ -4508,8 +4686,9 @@ function waits for output unless NOOUTPUT is set."
 (defun tramp-send-command-and-check
   (vec command &optional subshell dont-suppress-err)
   "Run COMMAND and check its exit status.
-Sends `echo $?' along with the COMMAND for checking the exit status.  If
-COMMAND is nil, just sends `echo $?'.  Returns the exit status found.
+Sends `echo $?' along with the COMMAND for checking the exit status.
+If COMMAND is nil, just sends `echo $?'.  Returns `t' if the exit
+status is 0, and `nil' otherwise.
 
 If the optional argument SUBSHELL is non-nil, the command is
 executed in a subshell, ie surrounded by parentheses.  If
@@ -4653,9 +4832,10 @@ Return ATTR."
        (host (tramp-file-name-real-host vec))
        (localname (tramp-shell-quote-argument
                    (tramp-file-name-localname vec))))
-    (if (not (zerop (length user)))
-        (format "%s@%s:%s" user host localname)
-      (format "%s:%s" host localname))))
+    (shell-quote-argument
+     (if (not (zerop (length user)))
+        (format "%s@%s:%s" user host localname)
+       (format "%s:%s" host localname)))))
 
 (defun tramp-method-out-of-band-p (vec size)
   "Return t if this is an out-of-band method, nil otherwise."
@@ -4709,7 +4889,7 @@ Return ATTR."
       (when elt1
        (setcdr elt1
                (append
-                (tramp-compat-split-string default-remote-path ":")
+                (tramp-compat-split-string (or default-remote-path "") ":")
                 (cdr elt1)))
        (setq remote-path (delq 'tramp-default-remote-path remote-path)))
 
@@ -4717,7 +4897,7 @@ Return ATTR."
       (when elt2
        (setcdr elt2
                (append
-                (tramp-compat-split-string own-remote-path ":")
+                (tramp-compat-split-string (or own-remote-path "") ":")
                 (cdr elt2)))
        (setq remote-path (delq 'tramp-own-remote-path remote-path)))
 
@@ -4744,6 +4924,21 @@ Return ATTR."
           x))
        remote-path)))))
 
+(defun tramp-get-remote-locale (vec)
+  (with-tramp-connection-property vec "locale"
+    (tramp-send-command vec "locale -a")
+    (let ((candidates '("en_US.utf8" "C.utf8" "C"))
+         locale)
+      (with-current-buffer (tramp-get-connection-buffer vec)
+       (while candidates
+         (goto-char (point-min))
+         (if (string-match (concat "^" (car candidates) "$") (buffer-string))
+             (setq locale (car candidates)
+                   candidates nil)
+           (setq candidates (cdr candidates)))))
+      ;; Return value.
+      (when locale (format "LC_ALL=%s" locale)))))
+
 (defun tramp-get-ls-command (vec)
   (with-tramp-connection-property vec "ls"
     (tramp-message vec 5 "Finding a suitable `ls' command")
@@ -4867,41 +5062,137 @@ Return ATTR."
     (tramp-message vec 5 "Finding a suitable `trash' command")
     (tramp-find-executable vec "trash" (tramp-get-remote-path vec))))
 
+(defun tramp-get-remote-touch (vec)
+  (with-tramp-connection-property vec "touch"
+    (tramp-message vec 5 "Finding a suitable `touch' command")
+    (let ((result (tramp-find-executable
+                  vec "touch" (tramp-get-remote-path vec)))
+         (tmpfile
+          (make-temp-name
+           (expand-file-name
+            tramp-temp-name-prefix (tramp-get-remote-tmpdir vec)))))
+      ;; Busyboxes do support the "-t" option only when they have been
+      ;; built with the DESKTOP config option.  Let's check it.
+      (when result
+       (tramp-set-connection-property
+        vec "touch-t"
+        (tramp-send-command-and-check
+         vec
+         (format
+          "%s -t %s %s"
+          result
+          (format-time-string "%Y%m%d%H%M.%S" (current-time))
+          (tramp-file-name-handler 'file-remote-p tmpfile 'localname))))
+       (delete-file tmpfile))
+      result)))
+
+(defun tramp-get-remote-gvfs-monitor-dir (vec)
+  (with-tramp-connection-property vec "gvfs-monitor-dir"
+    (tramp-message vec 5 "Finding a suitable `gvfs-monitor-dir' command")
+    (tramp-find-executable
+     vec "gvfs-monitor-dir" (tramp-get-remote-path vec) t t)))
+
+(defun tramp-get-remote-inotifywait (vec)
+  (with-tramp-connection-property vec "inotifywait"
+    (tramp-message vec 5 "Finding a suitable `inotifywait' command")
+    (tramp-find-executable vec "inotifywait" (tramp-get-remote-path vec) t t)))
+
 (defun tramp-get-remote-id (vec)
   (with-tramp-connection-property vec "id"
     (tramp-message vec 5 "Finding POSIX `id' command")
-    (or
-     (catch 'id-found
-       (let ((dl (tramp-get-remote-path vec))
-            result)
-        (while (and dl (setq result (tramp-find-executable vec "id" dl t t)))
-          ;; Check POSIX parameter.
-          (when (tramp-send-command-and-check vec (format "%s -u" result))
-            (throw 'id-found result))
-          (setq dl (cdr dl)))))
-     (tramp-error vec 'file-error "Couldn't find a POSIX `id' command"))))
+    (catch 'id-found
+      (let ((dl (tramp-get-remote-path vec))
+           result)
+       (while (and dl (setq result (tramp-find-executable vec "id" dl t t)))
+         ;; Check POSIX parameter.
+         (when (tramp-send-command-and-check vec (format "%s -u" result))
+           (throw 'id-found result))
+         (setq dl (cdr dl)))))))
+
+(defun tramp-get-remote-uid-with-id (vec id-format)
+  (tramp-send-command-and-read
+   vec
+   (format "%s -u%s %s"
+          (tramp-get-remote-id vec)
+          (if (equal id-format 'integer) "" "n")
+          (if (equal id-format 'integer)
+              "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/"))))
+
+(defun tramp-get-remote-uid-with-perl (vec id-format)
+  (tramp-send-command-and-read
+   vec
+   (format "%s -le '%s'"
+          (tramp-get-remote-perl vec)
+          (if (equal id-format 'integer)
+              "print $>"
+            "print \"\\\"\", scalar getpwuid($>), \"\\\"\""))))
+
+(defun tramp-get-remote-python (vec)
+  (with-tramp-connection-property vec "python"
+    (tramp-message vec 5 "Finding a suitable `python' command")
+    (tramp-find-executable vec "python" (tramp-get-remote-path vec))))
+
+(defun tramp-get-remote-uid-with-python (vec id-format)
+  (tramp-send-command-and-read
+   vec
+   (format "%s -c \"%s\""
+          (tramp-get-remote-python vec)
+          (if (equal id-format 'integer)
+              "import os; print os.getuid()"
+            "import os, pwd; print '\\\"' + pwd.getpwuid(os.getuid())[0] + '\\\"'"))))
 
 (defun tramp-get-remote-uid (vec id-format)
   (with-tramp-connection-property vec (format "uid-%s" id-format)
-    (let ((res (tramp-send-command-and-read
-               vec
-               (format "%s -u%s %s"
-                       (tramp-get-remote-id vec)
-                       (if (equal id-format 'integer) "" "n")
-                       (if (equal id-format 'integer)
-                           "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
+    (let ((res (cond
+               ((tramp-get-remote-id vec)
+                (tramp-get-remote-uid-with-id vec id-format))
+               ((tramp-get-remote-perl vec)
+                (tramp-get-remote-uid-with-perl vec id-format))
+               ((tramp-get-remote-python vec)
+                (tramp-get-remote-uid-with-python vec id-format))
+               (t (tramp-error
+                   vec 'file-error "Cannot determine remote uid")))))
       ;; The command might not always return a number.
       (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
 
+(defun tramp-get-remote-gid-with-id (vec id-format)
+  (tramp-send-command-and-read
+   vec
+   (format "%s -g%s %s"
+          (tramp-get-remote-id vec)
+          (if (equal id-format 'integer) "" "n")
+          (if (equal id-format 'integer)
+              "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/"))))
+
+(defun tramp-get-remote-gid-with-perl (vec id-format)
+  (tramp-send-command-and-read
+   vec
+   (format "%s -le '%s'"
+          (tramp-get-remote-perl vec)
+          (if (equal id-format 'integer)
+              "print ($)=~/(\\d+)/)"
+            "print \"\\\"\", scalar getgrgid($)), \"\\\"\""))))
+
+(defun tramp-get-remote-gid-with-python (vec id-format)
+  (tramp-send-command-and-read
+   vec
+   (format "%s -c \"%s\""
+          (tramp-get-remote-python vec)
+          (if (equal id-format 'integer)
+              "import os; print os.getgid()"
+            "import os, grp; print '\\\"' + grp.getgrgid(os.getgid())[0] + '\\\"'"))))
+
 (defun tramp-get-remote-gid (vec id-format)
   (with-tramp-connection-property vec (format "gid-%s" id-format)
-    (let ((res (tramp-send-command-and-read
-               vec
-               (format "%s -g%s %s"
-                       (tramp-get-remote-id vec)
-                       (if (equal id-format 'integer) "" "n")
-                       (if (equal id-format 'integer)
-                           "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
+    (let ((res (cond
+               ((tramp-get-remote-id vec)
+                (tramp-get-remote-gid-with-id vec id-format))
+               ((tramp-get-remote-perl vec)
+                (tramp-get-remote-gid-with-perl vec id-format))
+               ((tramp-get-remote-python vec)
+                (tramp-get-remote-gid-with-python vec id-format))
+               (t (tramp-error
+                   vec 'file-error "Cannot determine remote gid")))))
       ;; The command might not always return a number.
       (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
 
@@ -5065,5 +5356,7 @@ function cell is returned to be applied on a buffer."
 ;;   rsync.
 ;; * Try telnet+curl as new method.  It might be useful for busybox,
 ;;   without built-in uuencode/uudecode.
+;; * Try telnet+nc as new method.  It might be useful for busybox,
+;;   without built-in uuencode/uudecode.
 
 ;;; tramp-sh.el ends here