LCOV - code coverage report
Current view: top level - lisp/net - tramp-sh.el (source / functions) Hit Total Coverage
Test: tramp-tests-after.info Lines: 1755 2841 61.8 %
Date: 2017-08-30 10:12:24 Functions: 85 122 69.7 %

          Line data    Source code
       1             : ;;; tramp-sh.el --- Tramp access functions for (s)sh-like connections  -*- lexical-binding:t -*-
       2             : 
       3             : ;; Copyright (C) 1998-2017 Free Software Foundation, Inc.
       4             : 
       5             : ;; (copyright statements below in code to be updated with the above notice)
       6             : 
       7             : ;; Author: Kai Großjohann <kai.grossjohann@gmx.net>
       8             : ;;         Michael Albinus <michael.albinus@gmx.de>
       9             : ;; Maintainer: Michael Albinus <michael.albinus@gmx.de>
      10             : ;; Keywords: comm, processes
      11             : ;; Package: tramp
      12             : 
      13             : ;; This file is part of GNU Emacs.
      14             : 
      15             : ;; GNU Emacs is free software: you can redistribute it and/or modify
      16             : ;; it under the terms of the GNU General Public License as published by
      17             : ;; the Free Software Foundation, either version 3 of the License, or
      18             : ;; (at your option) any later version.
      19             : 
      20             : ;; GNU Emacs is distributed in the hope that it will be useful,
      21             : ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
      22             : ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      23             : ;; GNU General Public License for more details.
      24             : 
      25             : ;; You should have received a copy of the GNU General Public License
      26             : ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
      27             : 
      28             : ;;; Code:
      29             : 
      30             : (require 'tramp)
      31             : 
      32             : ;; Pacify byte-compiler.
      33             : (eval-when-compile
      34             :   (require 'dired))
      35             : 
      36             : (declare-function dired-remove-file "dired-aux")
      37             : (defvar dired-compress-file-suffixes)
      38             : (defvar vc-handled-backends)
      39             : (defvar vc-bzr-program)
      40             : (defvar vc-git-program)
      41             : (defvar vc-hg-program)
      42             : 
      43             : ;;;###tramp-autoload
      44             : (defcustom tramp-inline-compress-start-size 4096
      45             :   "The minimum size of compressing where inline transfer.
      46             : When inline transfer, compress transferred data of file
      47             : whose size is this value or above (up to `tramp-copy-size-limit').
      48             : If it is nil, no compression at all will be applied."
      49             :   :group 'tramp
      50             :   :type '(choice (const nil) integer)
      51             :   :require 'tramp)
      52             : 
      53             : ;;;###tramp-autoload
      54             : (defcustom tramp-copy-size-limit 10240
      55             :   "The maximum file size where inline copying is preferred over an \
      56             : out-of-the-band copy.
      57             : If it is nil, out-of-the-band copy will be used without a check."
      58             :   :group 'tramp
      59             :   :type '(choice (const nil) integer)
      60             :   :require 'tramp)
      61             : 
      62             : ;;;###tramp-autoload
      63             : (defcustom tramp-terminal-type "dumb"
      64             :   "Value of TERM environment variable for logging in to remote host.
      65             : Because Tramp wants to parse the output of the remote shell, it is easily
      66             : confused by ANSI color escape sequences and suchlike.  Often, shell init
      67             : files conditionalize this setup based on the TERM environment variable."
      68             :   :group 'tramp
      69             :   :type 'string
      70             :   :require 'tramp)
      71             : 
      72             : ;;;###tramp-autoload
      73             : (defcustom tramp-histfile-override "~/.tramp_history"
      74             :   "When invoking a shell, override the HISTFILE with this value.
      75             : When setting to a string, it redirects the shell history to that
      76             : file.  Be careful when setting to \"/dev/null\"; this might
      77             : result in undesired results when using \"bash\" as shell.
      78             : 
      79             : The value t unsets any setting of HISTFILE, and sets both
      80             : HISTFILESIZE and HISTSIZE to 0.  If you set this variable to nil,
      81             : however, the *override* is disabled, so the history will go to
      82             : the default storage location, e.g. \"$HOME/.sh_history\"."
      83             :   :group 'tramp
      84             :   :version "25.2"
      85             :   :type '(choice (const :tag "Do not override HISTFILE" nil)
      86             :                  (const :tag "Unset HISTFILE" t)
      87             :                  (string :tag "Redirect to a file"))
      88             :   :require 'tramp)
      89             : 
      90             : ;;;###tramp-autoload
      91             : (defconst tramp-display-escape-sequence-regexp "\e[[;0-9]+m"
      92             :   "Terminal control escape sequences for display attributes.")
      93             : 
      94             : ;;;###tramp-autoload
      95             : (defconst tramp-device-escape-sequence-regexp "\e[[0-9]+n"
      96             :   "Terminal control escape sequences for device status.")
      97             : 
      98             : ;; ksh on OpenBSD 4.5 requires that $PS1 contains a `#' character for
      99             : ;; root users.  It uses the `$' character for other users.  In order
     100             : ;; to guarantee a proper prompt, we use "#$ " for the prompt.
     101             : 
     102             : (defvar tramp-end-of-output
     103             :   (format
     104             :    "///%s#$"
     105             :    (md5 (concat (prin1-to-string process-environment) (current-time-string))))
     106             :   "String used to recognize end of output.
     107             : The `$' character at the end is quoted; the string cannot be
     108             : detected as prompt when being sent on echoing hosts, therefore.")
     109             : 
     110             : ;;;###tramp-autoload
     111             : (defconst tramp-initial-end-of-output "#$ "
     112             :   "Prompt when establishing a connection.")
     113             : 
     114             : (defconst tramp-end-of-heredoc (md5 tramp-end-of-output)
     115             :   "String used to recognize end of heredoc strings.")
     116             : 
     117             : ;;;###tramp-autoload
     118             : (defcustom tramp-use-ssh-controlmaster-options t
     119             :   "Whether to use `tramp-ssh-controlmaster-options'."
     120             :   :group 'tramp
     121             :   :version "24.4"
     122             :   :type 'boolean
     123             :   :require 'tramp)
     124             : 
     125             : (defvar tramp-ssh-controlmaster-options nil
     126             :   "Which ssh Control* arguments to use.
     127             : 
     128             : If it is a string, it should have the form
     129             : \"-o ControlMaster=auto -o ControlPath=\\='tramp.%%r@%%h:%%p\\='
     130             : -o ControlPersist=no\".  Percent characters in the ControlPath
     131             : spec must be doubled, because the string is used as format string.
     132             : 
     133             : Otherwise, it will be auto-detected by Tramp, if
     134             : `tramp-use-ssh-controlmaster-options' is non-nil.  The value
     135             : depends on the installed local ssh version.
     136             : 
     137             : The string is used in `tramp-methods'.")
     138             : 
     139             : ;; Initialize `tramp-methods' with the supported methods.
     140             : ;;;###tramp-autoload
     141             : (add-to-list 'tramp-methods
     142             :   '("rcp"
     143             :     (tramp-login-program        "rsh")
     144             :     (tramp-login-args           (("%h") ("-l" "%u")))
     145             :     (tramp-remote-shell         "/bin/sh")
     146             :     (tramp-remote-shell-login   ("-l"))
     147             :     (tramp-remote-shell-args    ("-c"))
     148             :     (tramp-copy-program         "rcp")
     149             :     (tramp-copy-args            (("-p" "%k") ("-r")))
     150             :     (tramp-copy-keep-date       t)
     151             :     (tramp-copy-recursive       t)))
     152             : ;;;###tramp-autoload
     153             : (add-to-list 'tramp-methods
     154             :   '("remcp"
     155             :     (tramp-login-program        "remsh")
     156             :     (tramp-login-args           (("%h") ("-l" "%u")))
     157             :     (tramp-remote-shell         "/bin/sh")
     158             :     (tramp-remote-shell-login   ("-l"))
     159             :     (tramp-remote-shell-args    ("-c"))
     160             :     (tramp-copy-program         "rcp")
     161             :     (tramp-copy-args            (("-p" "%k")))
     162             :     (tramp-copy-keep-date       t)))
     163             : ;;;###tramp-autoload
     164             : (add-to-list 'tramp-methods
     165             :   '("scp"
     166             :     (tramp-login-program        "ssh")
     167             :     (tramp-login-args           (("-l" "%u") ("-p" "%p") ("%c")
     168             :                                  ("-e" "none") ("%h")))
     169             :     (tramp-async-args           (("-q")))
     170             :     (tramp-remote-shell         "/bin/sh")
     171             :     (tramp-remote-shell-login   ("-l"))
     172             :     (tramp-remote-shell-args    ("-c"))
     173             :     (tramp-copy-program         "scp")
     174             :     (tramp-copy-args            (("-P" "%p") ("-p" "%k") ("-q") ("-r") ("%c")))
     175             :     (tramp-copy-keep-date       t)
     176             :     (tramp-copy-recursive       t)))
     177             : ;;;###tramp-autoload
     178             : (add-to-list 'tramp-methods
     179             :   '("scpx"
     180             :     (tramp-login-program        "ssh")
     181             :     (tramp-login-args           (("-l" "%u") ("-p" "%p") ("%c")
     182             :                                  ("-e" "none") ("-t" "-t") ("%h") ("/bin/sh")))
     183             :     (tramp-async-args           (("-q")))
     184             :     (tramp-remote-shell         "/bin/sh")
     185             :     (tramp-remote-shell-login   ("-l"))
     186             :     (tramp-remote-shell-args    ("-c"))
     187             :     (tramp-copy-program         "scp")
     188             :     (tramp-copy-args            (("-P" "%p") ("-p" "%k")
     189             :                                  ("-q") ("-r") ("%c")))
     190             :     (tramp-copy-keep-date       t)
     191             :     (tramp-copy-recursive       t)))
     192             : ;;;###tramp-autoload
     193             : (add-to-list 'tramp-methods
     194             :   '("rsync"
     195             :     (tramp-login-program        "ssh")
     196             :     (tramp-login-args           (("-l" "%u") ("-p" "%p") ("%c")
     197             :                                  ("-e" "none") ("%h")))
     198             :     (tramp-async-args           (("-q")))
     199             :     (tramp-remote-shell         "/bin/sh")
     200             :     (tramp-remote-shell-login   ("-l"))
     201             :     (tramp-remote-shell-args    ("-c"))
     202             :     (tramp-copy-program         "rsync")
     203             :     (tramp-copy-args            (("-t" "%k") ("-p") ("-r") ("-s") ("-c")))
     204             :     (tramp-copy-env             (("RSYNC_RSH") ("ssh" "%c")))
     205             :     (tramp-copy-keep-date       t)
     206             :     (tramp-copy-keep-tmpfile    t)
     207             :     (tramp-copy-recursive       t)))
     208             : ;;;###tramp-autoload
     209             : (add-to-list 'tramp-methods
     210             :   '("rsh"
     211             :     (tramp-login-program        "rsh")
     212             :     (tramp-login-args           (("%h") ("-l" "%u")))
     213             :     (tramp-remote-shell         "/bin/sh")
     214             :     (tramp-remote-shell-login   ("-l"))
     215             :     (tramp-remote-shell-args    ("-c"))))
     216             : ;;;###tramp-autoload
     217             : (add-to-list 'tramp-methods
     218             :   '("remsh"
     219             :     (tramp-login-program        "remsh")
     220             :     (tramp-login-args           (("%h") ("-l" "%u")))
     221             :     (tramp-remote-shell         "/bin/sh")
     222             :     (tramp-remote-shell-login   ("-l"))
     223             :     (tramp-remote-shell-args    ("-c"))))
     224             : ;;;###tramp-autoload
     225             : (add-to-list 'tramp-methods
     226             :   '("ssh"
     227             :     (tramp-login-program        "ssh")
     228             :     (tramp-login-args           (("-l" "%u") ("-p" "%p") ("%c")
     229             :                                  ("-e" "none") ("%h")))
     230             :     (tramp-async-args           (("-q")))
     231             :     (tramp-remote-shell         "/bin/sh")
     232             :     (tramp-remote-shell-login   ("-l"))
     233             :     (tramp-remote-shell-args    ("-c"))))
     234             : ;;;###tramp-autoload
     235             : (add-to-list 'tramp-methods
     236             :   '("sshx"
     237             :     (tramp-login-program        "ssh")
     238             :     (tramp-login-args           (("-l" "%u") ("-p" "%p") ("%c")
     239             :                                  ("-e" "none") ("-t" "-t") ("%h") ("/bin/sh")))
     240             :     (tramp-async-args           (("-q")))
     241             :     (tramp-remote-shell         "/bin/sh")
     242             :     (tramp-remote-shell-login   ("-l"))
     243             :     (tramp-remote-shell-args    ("-c"))))
     244             : ;;;###tramp-autoload
     245             : (add-to-list 'tramp-methods
     246             :   '("telnet"
     247             :     (tramp-login-program        "telnet")
     248             :     (tramp-login-args           (("%h") ("%p") ("2>/dev/null")))
     249             :     (tramp-remote-shell         "/bin/sh")
     250             :     (tramp-remote-shell-login   ("-l"))
     251             :     (tramp-remote-shell-args    ("-c"))))
     252             : ;;;###tramp-autoload
     253             : (add-to-list 'tramp-methods
     254             :   '("nc"
     255             :     (tramp-login-program        "telnet")
     256             :     (tramp-login-args           (("%h") ("%p") ("2>/dev/null")))
     257             :     (tramp-remote-shell         "/bin/sh")
     258             :     (tramp-remote-shell-login   ("-l"))
     259             :     (tramp-remote-shell-args    ("-c"))
     260             :     (tramp-copy-program         "nc")
     261             :     ;; We use "-v" for better error tracking.
     262             :     (tramp-copy-args            (("-w" "1") ("-v") ("%h") ("%r")))
     263             :     (tramp-remote-copy-program  "nc")
     264             :     ;; We use "-p" as required for newer busyboxes.  For older
     265             :     ;; busybox/nc versions, the value must be (("-l") ("%r")).  This
     266             :     ;; can be achieved by tweaking `tramp-connection-properties'.
     267             :     (tramp-remote-copy-args     (("-l") ("-p" "%r") ("2>/dev/null")))))
     268             : ;;;###tramp-autoload
     269             : (add-to-list 'tramp-methods
     270             :   '("su"
     271             :     (tramp-login-program        "su")
     272             :     (tramp-login-args           (("-") ("%u")))
     273             :     (tramp-remote-shell         "/bin/sh")
     274             :     (tramp-remote-shell-login   ("-l"))
     275             :     (tramp-remote-shell-args    ("-c"))
     276             :     (tramp-connection-timeout   10)))
     277             : ;;;###tramp-autoload
     278             : (add-to-list
     279             :  'tramp-methods
     280             :  '("sg"
     281             :    (tramp-login-program        "sg")
     282             :    (tramp-login-args           (("-") ("%u")))
     283             :    (tramp-remote-shell         "/bin/sh")
     284             :    (tramp-remote-shell-args    ("-c"))
     285             :    (tramp-connection-timeout   10)))
     286             : ;;;###tramp-autoload
     287             : (add-to-list 'tramp-methods
     288             :   '("sudo"
     289             :     (tramp-login-program        "sudo")
     290             :     ;; The password template must be masked.  Otherwise, it could be
     291             :     ;; interpreted as password prompt if the remote host echoes the command.
     292             :     (tramp-login-args           (("-u" "%u") ("-s") ("-H")
     293             :                                  ("-p" "P\"\"a\"\"s\"\"s\"\"w\"\"o\"\"r\"\"d\"\":")))
     294             :     ;; Local $SHELL could be a nasty one, like zsh or fish.  Let's override it.
     295             :     (tramp-login-env            (("SHELL") ("/bin/sh")))
     296             :     (tramp-remote-shell         "/bin/sh")
     297             :     (tramp-remote-shell-login   ("-l"))
     298             :     (tramp-remote-shell-args    ("-c"))
     299             :     (tramp-connection-timeout   10)))
     300             : ;;;###tramp-autoload
     301             : (add-to-list 'tramp-methods
     302             :   '("doas"
     303             :     (tramp-login-program        "doas")
     304             :     (tramp-login-args           (("-u" "%u") ("-s")))
     305             :     (tramp-remote-shell         "/bin/sh")
     306             :     (tramp-remote-shell-args    ("-c"))
     307             :     (tramp-connection-timeout   10)))
     308             : ;;;###tramp-autoload
     309             : (add-to-list 'tramp-methods
     310             :   '("ksu"
     311             :     (tramp-login-program        "ksu")
     312             :     (tramp-login-args           (("%u") ("-q")))
     313             :     (tramp-remote-shell         "/bin/sh")
     314             :     (tramp-remote-shell-login   ("-l"))
     315             :     (tramp-remote-shell-args    ("-c"))
     316             :     (tramp-connection-timeout   10)))
     317             : ;;;###tramp-autoload
     318             : (add-to-list 'tramp-methods
     319             :   '("krlogin"
     320             :     (tramp-login-program        "krlogin")
     321             :     (tramp-login-args           (("%h") ("-l" "%u") ("-x")))
     322             :     (tramp-remote-shell         "/bin/sh")
     323             :     (tramp-remote-shell-login   ("-l"))
     324             :     (tramp-remote-shell-args    ("-c"))))
     325             : ;;;###tramp-autoload
     326             : (add-to-list 'tramp-methods
     327             :   `("plink"
     328             :     (tramp-login-program        "plink")
     329             :     ;; ("%h") must be a single element, see `tramp-compute-multi-hops'.
     330             :     (tramp-login-args           (("-l" "%u") ("-P" "%p") ("-ssh") ("-t")
     331             :                                  ("%h") ("\"")
     332             :                                  (,(format
     333             :                                     "env 'TERM=%s' 'PROMPT_COMMAND=' 'PS1=%s'"
     334             :                                     tramp-terminal-type
     335             :                                     tramp-initial-end-of-output))
     336             :                                  ("/bin/sh") ("\"")))
     337             :     (tramp-remote-shell         "/bin/sh")
     338             :     (tramp-remote-shell-login   ("-l"))
     339             :     (tramp-remote-shell-args    ("-c"))))
     340             : ;;;###tramp-autoload
     341             : (add-to-list 'tramp-methods
     342             :   `("plinkx"
     343             :     (tramp-login-program        "plink")
     344             :     (tramp-login-args           (("-load") ("%h") ("-t") ("\"")
     345             :                                  (,(format
     346             :                                     "env 'TERM=%s' 'PROMPT_COMMAND=' 'PS1=%s'"
     347             :                                     tramp-terminal-type
     348             :                                     tramp-initial-end-of-output))
     349             :                                  ("/bin/sh") ("\"")))
     350             :     (tramp-remote-shell         "/bin/sh")
     351             :     (tramp-remote-shell-login   ("-l"))
     352             :     (tramp-remote-shell-args    ("-c"))))
     353             : ;;;###tramp-autoload
     354             : (add-to-list 'tramp-methods
     355             :   `("pscp"
     356             :     (tramp-login-program        "plink")
     357             :     (tramp-login-args           (("-l" "%u") ("-P" "%p") ("-ssh") ("-t")
     358             :                                  ("%h") ("\"")
     359             :                                  (,(format
     360             :                                     "env 'TERM=%s' 'PROMPT_COMMAND=' 'PS1=%s'"
     361             :                                     tramp-terminal-type
     362             :                                     tramp-initial-end-of-output))
     363             :                                  ("/bin/sh") ("\"")))
     364             :     (tramp-remote-shell         "/bin/sh")
     365             :     (tramp-remote-shell-login   ("-l"))
     366             :     (tramp-remote-shell-args    ("-c"))
     367             :     (tramp-copy-program         "pscp")
     368             :     (tramp-copy-args            (("-l" "%u") ("-P" "%p") ("-scp") ("-p" "%k")
     369             :                                  ("-q") ("-r")))
     370             :     (tramp-copy-keep-date       t)
     371             :     (tramp-copy-recursive       t)))
     372             : ;;;###tramp-autoload
     373             : (add-to-list 'tramp-methods
     374             :   `("psftp"
     375             :     (tramp-login-program        "plink")
     376             :     (tramp-login-args           (("-l" "%u") ("-P" "%p") ("-ssh") ("-t")
     377             :                                  ("%h") ("\"")
     378             :                                  (,(format
     379             :                                     "env 'TERM=%s' 'PROMPT_COMMAND=' 'PS1=%s'"
     380             :                                     tramp-terminal-type
     381             :                                     tramp-initial-end-of-output))
     382             :                                  ("/bin/sh") ("\"")))
     383             :     (tramp-remote-shell         "/bin/sh")
     384             :     (tramp-remote-shell-login   ("-l"))
     385             :     (tramp-remote-shell-args    ("-c"))
     386             :     (tramp-copy-program         "pscp")
     387             :     (tramp-copy-args            (("-l" "%u") ("-P" "%p") ("-sftp") ("-p" "%k")
     388             :                                  ("-q")))
     389             :     (tramp-copy-keep-date       t)))
     390             : ;;;###tramp-autoload
     391             : (add-to-list 'tramp-methods
     392             :   '("fcp"
     393             :     (tramp-login-program        "fsh")
     394             :     (tramp-login-args           (("%h") ("-l" "%u") ("sh" "-i")))
     395             :     (tramp-remote-shell         "/bin/sh")
     396             :     (tramp-remote-shell-login   ("-l"))
     397             :     (tramp-remote-shell-args    ("-i") ("-c"))
     398             :     (tramp-copy-program         "fcp")
     399             :     (tramp-copy-args            (("-p" "%k")))
     400             :     (tramp-copy-keep-date       t)))
     401             : 
     402             : ;;;###tramp-autoload
     403             : (add-to-list 'tramp-default-method-alist
     404             :              `(,tramp-local-host-regexp "\\`root\\'" "su"))
     405             : 
     406             : ;;;###tramp-autoload
     407             : (add-to-list 'tramp-default-user-alist
     408             :              `(,(concat "\\`" (regexp-opt '("su" "sudo" "doas" "ksu")) "\\'")
     409             :                nil "root"))
     410             : ;; Do not add "ssh" based methods, otherwise ~/.ssh/config would be ignored.
     411             : ;; Do not add "plink" based methods, they ask interactively for the user.
     412             : ;;;###tramp-autoload
     413             : (add-to-list 'tramp-default-user-alist
     414             :              `(,(concat
     415             :                  "\\`"
     416             :                  (regexp-opt
     417             :                   '("rcp" "remcp" "rsh" "telnet" "nc" "krlogin" "fcp"))
     418             :                  "\\'")
     419             :                nil ,(user-login-name)))
     420             : 
     421             : ;;;###tramp-autoload
     422             : (defconst tramp-completion-function-alist-rsh
     423             :   '((tramp-parse-rhosts "/etc/hosts.equiv")
     424             :     (tramp-parse-rhosts "~/.rhosts"))
     425             :   "Default list of (FUNCTION FILE) pairs to be examined for rsh methods.")
     426             : 
     427             : ;;;###tramp-autoload
     428             : (defconst tramp-completion-function-alist-ssh
     429             :   '((tramp-parse-rhosts      "/etc/hosts.equiv")
     430             :     (tramp-parse-rhosts      "/etc/shosts.equiv")
     431             :     (tramp-parse-shosts      "/etc/ssh_known_hosts")
     432             :     (tramp-parse-sconfig     "/etc/ssh_config")
     433             :     (tramp-parse-shostkeys   "/etc/ssh2/hostkeys")
     434             :     (tramp-parse-sknownhosts "/etc/ssh2/knownhosts")
     435             :     (tramp-parse-rhosts      "~/.rhosts")
     436             :     (tramp-parse-rhosts      "~/.shosts")
     437             :     (tramp-parse-shosts      "~/.ssh/known_hosts")
     438             :     (tramp-parse-sconfig     "~/.ssh/config")
     439             :     (tramp-parse-shostkeys   "~/.ssh2/hostkeys")
     440             :     (tramp-parse-sknownhosts "~/.ssh2/knownhosts"))
     441             :   "Default list of (FUNCTION FILE) pairs to be examined for ssh methods.")
     442             : 
     443             : ;;;###tramp-autoload
     444             : (defconst tramp-completion-function-alist-telnet
     445             :   '((tramp-parse-hosts "/etc/hosts"))
     446             :   "Default list of (FUNCTION FILE) pairs to be examined for telnet methods.")
     447             : 
     448             : ;;;###tramp-autoload
     449             : (defconst tramp-completion-function-alist-su
     450             :   '((tramp-parse-passwd "/etc/passwd"))
     451             :   "Default list of (FUNCTION FILE) pairs to be examined for su methods.")
     452             : 
     453             : ;;;###tramp-autoload
     454             : (defconst tramp-completion-function-alist-sg
     455             :   '((tramp-parse-etc-group "/etc/group"))
     456             :   "Default list of (FUNCTION FILE) pairs to be examined for sg methods.")
     457             : 
     458             : ;;;###tramp-autoload
     459             : (defconst tramp-completion-function-alist-putty
     460             :   `((tramp-parse-putty
     461             :      ,(if (memq system-type '(windows-nt))
     462             :           "HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions"
     463             :         "~/.putty/sessions")))
     464             :  "Default list of (FUNCTION REGISTRY) pairs to be examined for putty sessions.")
     465             : 
     466             : ;;;###tramp-autoload
     467             : (eval-after-load 'tramp
     468             :   '(progn
     469             :      (tramp-set-completion-function "rcp" tramp-completion-function-alist-rsh)
     470             :      (tramp-set-completion-function "remcp" tramp-completion-function-alist-rsh)
     471             :      (tramp-set-completion-function "scp" tramp-completion-function-alist-ssh)
     472             :      (tramp-set-completion-function "scpx" tramp-completion-function-alist-ssh)
     473             :      (tramp-set-completion-function "rsync" tramp-completion-function-alist-ssh)
     474             :      (tramp-set-completion-function "rsh" tramp-completion-function-alist-rsh)
     475             :      (tramp-set-completion-function "remsh" tramp-completion-function-alist-rsh)
     476             :      (tramp-set-completion-function "ssh" tramp-completion-function-alist-ssh)
     477             :      (tramp-set-completion-function "sshx" tramp-completion-function-alist-ssh)
     478             :      (tramp-set-completion-function
     479             :       "telnet" tramp-completion-function-alist-telnet)
     480             :      (tramp-set-completion-function "nc" tramp-completion-function-alist-telnet)
     481             :      (tramp-set-completion-function "su" tramp-completion-function-alist-su)
     482             :      (tramp-set-completion-function "sudo" tramp-completion-function-alist-su)
     483             :      (tramp-set-completion-function "doas" tramp-completion-function-alist-su)
     484             :      (tramp-set-completion-function "ksu" tramp-completion-function-alist-su)
     485             :      (tramp-set-completion-function "sg" tramp-completion-function-alist-sg)
     486             :      (tramp-set-completion-function
     487             :       "krlogin" tramp-completion-function-alist-rsh)
     488             :      (tramp-set-completion-function "plink" tramp-completion-function-alist-ssh)
     489             :      (tramp-set-completion-function
     490             :       "plinkx" tramp-completion-function-alist-putty)
     491             :      (tramp-set-completion-function "pscp" tramp-completion-function-alist-ssh)
     492             :      (tramp-set-completion-function "psftp" tramp-completion-function-alist-ssh)
     493             :      (tramp-set-completion-function "fcp" tramp-completion-function-alist-ssh)))
     494             : 
     495             : ;; "getconf PATH" yields:
     496             : ;; HP-UX: /usr/bin:/usr/ccs/bin:/opt/ansic/bin:/opt/langtools/bin:/opt/fortran/bin
     497             : ;; Solaris: /usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin
     498             : ;; GNU/Linux (Debian, Suse, RHEL): /bin:/usr/bin
     499             : ;; FreeBSD: /usr/bin:/bin:/usr/sbin:/sbin: - beware trailing ":"!
     500             : ;; Darwin: /usr/bin:/bin:/usr/sbin:/sbin
     501             : ;; IRIX64: /usr/bin
     502             : ;; QNAP QTS: ---
     503             : ;;;###tramp-autoload
     504             : (defcustom tramp-remote-path
     505             :   '(tramp-default-remote-path "/bin" "/usr/bin" "/sbin" "/usr/sbin"
     506             :     "/usr/local/bin" "/usr/local/sbin" "/local/bin" "/local/freeware/bin"
     507             :     "/local/gnu/bin" "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin"
     508             :     "/opt/bin" "/opt/sbin" "/opt/local/bin")
     509             :   "List of directories to search for executables on remote host.
     510             : For every remote host, this variable will be set buffer local,
     511             : keeping the list of existing directories on that host.
     512             : 
     513             : You can use `~' in this list, but when searching for a shell which groks
     514             : tilde expansion, all directory names starting with `~' will be ignored.
     515             : 
     516             : `Default Directories' represent the list of directories given by
     517             : the command \"getconf PATH\".  It is recommended to use this
     518             : entry on head of this list, because these are the default
     519             : directories for POSIX compatible commands.  On remote hosts which
     520             : do not offer the getconf command (like cygwin), the value
     521             : \"/bin:/usr/bin\" is used instead.  This entry is represented in
     522             : the list by the special value `tramp-default-remote-path'.
     523             : 
     524             : `Private Directories' are the settings of the $PATH environment,
     525             : as given in your `~/.profile'.  This entry is represented in
     526             : the list by the special value `tramp-own-remote-path'."
     527             :   :group 'tramp
     528             :   :type '(repeat (choice
     529             :                   (const :tag "Default Directories" tramp-default-remote-path)
     530             :                   (const :tag "Private Directories" tramp-own-remote-path)
     531             :                   (string :tag "Directory")))
     532             :   :require 'tramp)
     533             : 
     534             : ;;;###tramp-autoload
     535             : (defcustom tramp-remote-process-environment
     536             :   `("ENV=''" "TMOUT=0" "LC_CTYPE=''"
     537             :     ,(format "TERM=%s" tramp-terminal-type)
     538             :     ,(format "INSIDE_EMACS='%s,tramp:%s'" emacs-version tramp-version)
     539             :     "CDPATH=" "HISTORY=" "MAIL=" "MAILCHECK=" "MAILPATH=" "PAGER=cat"
     540             :     "autocorrect=" "correct=")
     541             :   "List of environment variables to be set on the remote host.
     542             : 
     543             : Each element should be a string of the form ENVVARNAME=VALUE.  An
     544             : entry ENVVARNAME= disables the corresponding environment variable,
     545             : which might have been set in the init files like ~/.profile.
     546             : 
     547             : Special handling is applied to the PATH environment, which should
     548             : not be set here. Instead, it should be set via `tramp-remote-path'."
     549             :   :group 'tramp
     550             :   :version "26.1"
     551             :   :type '(repeat string)
     552             :   :require 'tramp)
     553             : 
     554             : ;;;###tramp-autoload
     555             : (defcustom tramp-sh-extra-args '(("/bash\\'" . "-norc -noprofile"))
     556             :   "Alist specifying extra arguments to pass to the remote shell.
     557             : Entries are (REGEXP . ARGS) where REGEXP is a regular expression
     558             : matching the shell file name and ARGS is a string specifying the
     559             : arguments.
     560             : 
     561             : This variable is only used when Tramp needs to start up another shell
     562             : for tilde expansion.  The extra arguments should typically prevent the
     563             : shell from reading its init file."
     564             :   :group 'tramp
     565             :   ;; This might be the wrong way to test whether the widget type
     566             :   ;; `alist' is available.  Who knows the right way to test it?
     567             :   :type (if (get 'alist 'widget-type)
     568             :             '(alist :key-type string :value-type string)
     569             :           '(repeat (cons string string)))
     570             :   :require 'tramp)
     571             : 
     572             : (defconst tramp-actions-before-shell
     573             :   '((tramp-login-prompt-regexp tramp-action-login)
     574             :     (tramp-password-prompt-regexp tramp-action-password)
     575             :     (tramp-wrong-passwd-regexp tramp-action-permission-denied)
     576             :     (shell-prompt-pattern tramp-action-succeed)
     577             :     (tramp-shell-prompt-pattern tramp-action-succeed)
     578             :     (tramp-yesno-prompt-regexp tramp-action-yesno)
     579             :     (tramp-yn-prompt-regexp tramp-action-yn)
     580             :     (tramp-terminal-prompt-regexp tramp-action-terminal)
     581             :     (tramp-process-alive-regexp tramp-action-process-alive))
     582             :   "List of pattern/action pairs.
     583             : Whenever a pattern matches, the corresponding action is performed.
     584             : Each item looks like (PATTERN ACTION).
     585             : 
     586             : The PATTERN should be a symbol, a variable.  The value of this
     587             : variable gives the regular expression to search for.  Note that the
     588             : regexp must match at the end of the buffer, \"\\'\" is implicitly
     589             : appended to it.
     590             : 
     591             : The ACTION should also be a symbol, but a function.  When the
     592             : corresponding PATTERN matches, the ACTION function is called.")
     593             : 
     594             : (defconst tramp-actions-copy-out-of-band
     595             :   '((tramp-password-prompt-regexp tramp-action-password)
     596             :     (tramp-wrong-passwd-regexp tramp-action-permission-denied)
     597             :     (tramp-copy-failed-regexp tramp-action-permission-denied)
     598             :     (tramp-process-alive-regexp tramp-action-out-of-band))
     599             :   "List of pattern/action pairs.
     600             : This list is used for copying/renaming with out-of-band methods.
     601             : 
     602             : See `tramp-actions-before-shell' for more info.")
     603             : 
     604             : (defconst tramp-uudecode
     605             :   "(echo begin 600 %t; tail -n +2) | uudecode
     606             : cat %t
     607             : rm -f %t"
     608             :   "Shell function to implement `uudecode' to standard output.
     609             : Many systems support `uudecode -o /dev/stdout' or `uudecode -o -'
     610             : for this or `uudecode -p', but some systems don't, and for them
     611             : we have this shell function.")
     612             : 
     613             : (defconst tramp-perl-file-truename
     614             :   "%s -e '
     615             : use File::Spec;
     616             : use Cwd \"realpath\";
     617             : 
     618             : sub myrealpath {
     619             :     my ($file) = @_;
     620             :     return realpath($file) if -e $file;
     621             : }
     622             : 
     623             : sub recursive {
     624             :     my ($volume, @dirs) = @_;
     625             :     my $real = myrealpath(File::Spec->catpath(
     626             :                    $volume, File::Spec->catdir(@dirs), \"\"));
     627             :     if ($real) {
     628             :         my ($vol, $dir) = File::Spec->splitpath($real, 1);
     629             :         return ($vol, File::Spec->splitdir($dir));
     630             :     }
     631             :     else {
     632             :         my $last = pop(@dirs);
     633             :         ($volume, @dirs) = recursive($volume, @dirs);
     634             :         push(@dirs, $last);
     635             :         return ($volume, @dirs);
     636             :     }
     637             : }
     638             : 
     639             : $result = myrealpath($ARGV[0]);
     640             : if (!$result) {
     641             :     my ($vol, $dir) = File::Spec->splitpath($ARGV[0], 1);
     642             :     ($vol, @dirs) = recursive($vol, File::Spec->splitdir($dir));
     643             : 
     644             :     $result = File::Spec->catpath($vol, File::Spec->catdir(@dirs), \"\");
     645             : }
     646             : 
     647             : $result =~ s/\"/\\\\\"/g;
     648             : print \"\\\"$result\\\"\\n\";
     649             : ' \"$1\" 2>/dev/null"
     650             :   "Perl script to produce output suitable for use with `file-truename'
     651             : on the remote file system.
     652             : Escape sequence %s is replaced with name of Perl binary.
     653             : This string is passed to `format', so percent characters need to be doubled.")
     654             : 
     655             : (defconst tramp-perl-file-name-all-completions
     656             :   "%s -e '
     657             : opendir(d, $ARGV[0]) || die(\"$ARGV[0]: $!\\nfail\\n\");
     658             : @files = readdir(d); closedir(d);
     659             : foreach $f (@files) {
     660             :  if (-d \"$ARGV[0]/$f\") {
     661             :   print \"$f/\\n\";
     662             :  }
     663             :  else {
     664             :   print \"$f\\n\";
     665             :  }
     666             : }
     667             : print \"ok\\n\"
     668             : ' \"$1\" 2>/dev/null"
     669             :   "Perl script to produce output suitable for use with
     670             : `file-name-all-completions' on the remote file system.  Escape
     671             : sequence %s is replaced with name of Perl binary.  This string is
     672             : passed to `format', so percent characters need to be doubled.")
     673             : 
     674             : ;; Perl script to implement `file-attributes' in a Lisp `read'able
     675             : ;; output.  If you are hacking on this, note that you get *no* output
     676             : ;; unless this spits out a complete line, including the '\n' at the
     677             : ;; end.
     678             : ;; The device number is returned as "-1", because there will be a virtual
     679             : ;; device number set in `tramp-sh-handle-file-attributes'.
     680             : (defconst tramp-perl-file-attributes
     681             :   "%s -e '
     682             : @stat = lstat($ARGV[0]);
     683             : if (!@stat) {
     684             :     print \"nil\\n\";
     685             :     exit 0;
     686             : }
     687             : if (($stat[2] & 0170000) == 0120000)
     688             : {
     689             :     $type = readlink($ARGV[0]);
     690             :     $type =~ s/\"/\\\\\"/g;
     691             :     $type = \"\\\"$type\\\"\";
     692             : }
     693             : elsif (($stat[2] & 0170000) == 040000)
     694             : {
     695             :     $type = \"t\";
     696             : }
     697             : else
     698             : {
     699             :     $type = \"nil\"
     700             : };
     701             : $uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
     702             : $gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
     703             : printf(
     704             :     \"(%%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) -1)\\n\",
     705             :     $type,
     706             :     $stat[3],
     707             :     $uid,
     708             :     $gid,
     709             :     $stat[8] >> 16 & 0xffff,
     710             :     $stat[8] & 0xffff,
     711             :     $stat[9] >> 16 & 0xffff,
     712             :     $stat[9] & 0xffff,
     713             :     $stat[10] >> 16 & 0xffff,
     714             :     $stat[10] & 0xffff,
     715             :     $stat[7],
     716             :     $stat[2],
     717             :     $stat[1] >> 16 & 0xffff,
     718             :     $stat[1] & 0xffff
     719             : );' \"$1\" \"$2\" 2>/dev/null"
     720             :   "Perl script to produce output suitable for use with `file-attributes'
     721             : on the remote file system.
     722             : Escape sequence %s is replaced with name of Perl binary.
     723             : This string is passed to `format', so percent characters need to be doubled.")
     724             : 
     725             : (defconst tramp-perl-directory-files-and-attributes
     726             :   "%s -e '
     727             : chdir($ARGV[0]) or printf(\"\\\"Cannot change to $ARGV[0]: $''!''\\\"\\n\"), exit();
     728             : opendir(DIR,\".\") or printf(\"\\\"Cannot open directory $ARGV[0]: $''!''\\\"\\n\"), exit();
     729             : @list = readdir(DIR);
     730             : closedir(DIR);
     731             : $n = scalar(@list);
     732             : printf(\"(\\n\");
     733             : for($i = 0; $i < $n; $i++)
     734             : {
     735             :     $filename = $list[$i];
     736             :     @stat = lstat($filename);
     737             :     if (($stat[2] & 0170000) == 0120000)
     738             :     {
     739             :         $type = readlink($filename);
     740             :         $type =~ s/\"/\\\\\"/g;
     741             :         $type = \"\\\"$type\\\"\";
     742             :     }
     743             :     elsif (($stat[2] & 0170000) == 040000)
     744             :     {
     745             :         $type = \"t\";
     746             :     }
     747             :     else
     748             :     {
     749             :         $type = \"nil\"
     750             :     };
     751             :     $uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
     752             :     $gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
     753             :     $filename =~ s/\"/\\\\\"/g;
     754             :     printf(
     755             :         \"(\\\"%%s\\\" %%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) (%%u . %%u))\\n\",
     756             :         $filename,
     757             :         $type,
     758             :         $stat[3],
     759             :         $uid,
     760             :         $gid,
     761             :         $stat[8] >> 16 & 0xffff,
     762             :         $stat[8] & 0xffff,
     763             :         $stat[9] >> 16 & 0xffff,
     764             :         $stat[9] & 0xffff,
     765             :         $stat[10] >> 16 & 0xffff,
     766             :         $stat[10] & 0xffff,
     767             :         $stat[7],
     768             :         $stat[2],
     769             :         $stat[1] >> 16 & 0xffff,
     770             :         $stat[1] & 0xffff,
     771             :         $stat[0] >> 16 & 0xffff,
     772             :         $stat[0] & 0xffff);
     773             : }
     774             : printf(\")\\n\");' \"$1\" \"$2\" 2>/dev/null"
     775             :   "Perl script implementing `directory-files-attributes' as Lisp `read'able
     776             : output.
     777             : Escape sequence %s is replaced with name of Perl binary.
     778             : This string is passed to `format', so percent characters need to be doubled.")
     779             : 
     780             : ;; These two use base64 encoding.
     781             : (defconst tramp-perl-encode-with-module
     782             :   "%s -MMIME::Base64 -0777 -ne 'print encode_base64($_)' 2>/dev/null"
     783             :   "Perl program to use for encoding a file.
     784             : Escape sequence %s is replaced with name of Perl binary.
     785             : This string is passed to `format', so percent characters need to be doubled.
     786             : This implementation requires the MIME::Base64 Perl module to be installed
     787             : on the remote host.")
     788             : 
     789             : (defconst tramp-perl-decode-with-module
     790             :   "%s -MMIME::Base64 -0777 -ne 'print decode_base64($_)' 2>/dev/null"
     791             :   "Perl program to use for decoding a file.
     792             : Escape sequence %s is replaced with name of Perl binary.
     793             : This string is passed to `format', so percent characters need to be doubled.
     794             : This implementation requires the MIME::Base64 Perl module to be installed
     795             : on the remote host.")
     796             : 
     797             : (defconst tramp-perl-encode
     798             :   "%s -e '
     799             : # This script contributed by Juanma Barranquero <lektu@terra.es>.
     800             : # Copyright (C) 2002-2017 Free Software Foundation, Inc.
     801             : use strict;
     802             : 
     803             : my %%trans = do {
     804             :     my $i = 0;
     805             :     map {(substr(unpack(q(B8), chr $i++), 2, 6), $_)}
     806             :       split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/);
     807             : };
     808             : my $data;
     809             : 
     810             : # We read in chunks of 54 bytes, to generate output lines
     811             : # of 72 chars (plus end of line)
     812             : while (read STDIN, $data, 54) {
     813             :     my $pad = q();
     814             : 
     815             :     # Only for the last chunk, and only if did not fill the last three-byte packet
     816             :     if (eof) {
     817             :         my $mod = length($data) %% 3;
     818             :         $pad = q(=) x (3 - $mod) if $mod;
     819             :     }
     820             : 
     821             :     # Not the fastest method, but it is simple: unpack to binary string, split
     822             :     # by groups of 6 bits and convert back from binary to byte; then map into
     823             :     # the translation table
     824             :     print
     825             :       join q(),
     826             :         map($trans{$_},
     827             :             (substr(unpack(q(B*), $data) . q(00000), 0, 432) =~ /....../g)),
     828             :               $pad,
     829             :                 qq(\\n);
     830             : }' 2>/dev/null"
     831             :   "Perl program to use for encoding a file.
     832             : Escape sequence %s is replaced with name of Perl binary.
     833             : This string is passed to `format', so percent characters need to be doubled.")
     834             : 
     835             : (defconst tramp-perl-decode
     836             :   "%s -e '
     837             : # This script contributed by Juanma Barranquero <lektu@terra.es>.
     838             : # Copyright (C) 2002-2017 Free Software Foundation, Inc.
     839             : use strict;
     840             : 
     841             : my %%trans = do {
     842             :     my $i = 0;
     843             :     map {($_, substr(unpack(q(B8), chr $i++), 2, 6))}
     844             :       split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/)
     845             : };
     846             : 
     847             : my %%bytes = map {(unpack(q(B8), chr $_), chr $_)} 0 .. 255;
     848             : 
     849             : binmode(\\*STDOUT);
     850             : 
     851             : # We are going to accumulate into $pending to accept any line length
     852             : # (we do not check they are <= 76 chars as the RFC says)
     853             : my $pending = q();
     854             : 
     855             : while (my $data = <STDIN>) {
     856             :     chomp $data;
     857             : 
     858             :     # If we find one or two =, we have reached the end and
     859             :     # any following data is to be discarded
     860             :     my $finished = $data =~ s/(==?).*/$1/;
     861             :     $pending .= $data;
     862             : 
     863             :     my $len = length($pending);
     864             :     my $chunk = substr($pending, 0, $len & ~3);
     865             :     $pending = substr($pending, $len & ~3 + 1);
     866             : 
     867             :     # Easy method: translate from chars to (pregenerated) six-bit packets, join,
     868             :     # split in 8-bit chunks and convert back to char.
     869             :     print join q(),
     870             :       map $bytes{$_},
     871             :         ((join q(), map {$trans{$_} || q()} split //, $chunk) =~ /......../g);
     872             : 
     873             :     last if $finished;
     874             : }' 2>/dev/null"
     875             :   "Perl program to use for decoding a file.
     876             : Escape sequence %s is replaced with name of Perl binary.
     877             : This string is passed to `format', so percent characters need to be doubled.")
     878             : 
     879             : (defconst tramp-perl-pack
     880             :   "%s -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
     881             :   "Perl program to use for encoding a file.
     882             : Escape sequence %s is replaced with name of Perl binary.")
     883             : 
     884             : (defconst tramp-perl-unpack
     885             :   "%s -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"
     886             :   "Perl program to use for decoding a file.
     887             : Escape sequence %s is replaced with name of Perl binary.")
     888             : 
     889             : (defconst tramp-awk-encode
     890             :   "od -v -t x1 -A n | busybox awk '\\
     891             : BEGIN {
     892             :   b64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"
     893             :   b16 = \"0123456789abcdef\"
     894             : }
     895             : {
     896             :   for (c=1; c<=length($0); c++) {
     897             :     d=index(b16, substr($0,c,1))
     898             :     if (d--) {
     899             :       for (b=1; b<=4; b++) {
     900             :         o=o*2+int(d/8); d=(d*2)%%16
     901             :         if (++obc==6) {
     902             :           printf substr(b64,o+1,1)
     903             :           if (++rc>75) { printf \"\\n\"; rc=0 }
     904             :           obc=0; o=0
     905             :         }
     906             :       }
     907             :     }
     908             :   }
     909             : }
     910             : END {
     911             :   if (obc) {
     912             :     tail=(obc==2) ? \"==\\n\" : \"=\\n\"
     913             :     while (obc++<6) { o=o*2 }
     914             :     printf \"%%c\", substr(b64,o+1,1)
     915             :   } else {
     916             :     tail=\"\\n\"
     917             :   }
     918             :   printf tail
     919             : }'"
     920             :   "Awk program to use for encoding a file.
     921             : This string is passed to `format', so percent characters need to be doubled.")
     922             : 
     923             : (defconst tramp-awk-decode
     924             :   "busybox awk '\\
     925             : BEGIN {
     926             :   b64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"
     927             : }
     928             : {
     929             :   for (i=1; i<=length($0); i++) {
     930             :     c=index(b64, substr($0,i,1))
     931             :     if(c--) {
     932             :       for(b=0; b<6; b++) {
     933             :         o=o*2+int(c/32); c=(c*2)%%64
     934             :         if(++obc==8) {
     935             :           if (o) {
     936             :             printf \"%%c\", o
     937             :           } else {
     938             :             system(\"dd if=/dev/zero bs=1 count=1 2>/dev/null\")
     939             :           }
     940             :           obc=0; o=0
     941             :         }
     942             :       }
     943             :     }
     944             :   }
     945             : }'"
     946             :   "Awk program to use for decoding a file.
     947             : This string is passed to `format', so percent characters need to be doubled.")
     948             : 
     949             : (defconst tramp-awk-coding-test
     950             :   "test -c /dev/zero && \
     951             : od -v -t x1 -A n </dev/null && \
     952             : busybox awk '{}' </dev/null"
     953             :   "Test command for checking `tramp-awk-encode' and `tramp-awk-decode'.")
     954             : 
     955             : (defconst tramp-stat-marker "/////"
     956             :   "Marker in stat commands for file attributes.")
     957             : 
     958             : (defconst tramp-stat-quoted-marker "\\/\\/\\/\\/\\/"
     959             :   "Quoted marker in stat commands for file attributes.")
     960             : 
     961             : (defconst tramp-vc-registered-read-file-names
     962             :   "echo \"(\"
     963             : while read file; do
     964             :     if %s \"$file\"; then
     965             :         echo \"(\\\"$file\\\" \\\"file-exists-p\\\" t)\"
     966             :     else
     967             :         echo \"(\\\"$file\\\" \\\"file-exists-p\\\" nil)\"
     968             :     fi
     969             :     if %s \"$file\"; then
     970             :         echo \"(\\\"$file\\\" \\\"file-readable-p\\\" t)\"
     971             :     else
     972             :         echo \"(\\\"$file\\\" \\\"file-readable-p\\\" nil)\"
     973             :     fi
     974             : done
     975             : echo \")\""
     976             :   "Script to check existence of VC related files.
     977             : It must be send formatted with two strings; the tests for file
     978             : existence, and file readability.  Input shall be read via
     979             : here-document, otherwise the command could exceed maximum length
     980             : of command line.")
     981             : 
     982             : ;; New handlers should be added here.
     983             : ;;;###tramp-autoload
     984             : (defconst tramp-sh-file-name-handler-alist
     985             :   '(;; `access-file' performed by default handler.
     986             :     (add-name-to-file . tramp-sh-handle-add-name-to-file)
     987             :     ;; `byte-compiler-base-file-name' performed by default handler.
     988             :     (copy-directory . tramp-sh-handle-copy-directory)
     989             :     (copy-file . tramp-sh-handle-copy-file)
     990             :     (delete-directory . tramp-sh-handle-delete-directory)
     991             :     (delete-file . tramp-sh-handle-delete-file)
     992             :     ;; `diff-latest-backup-file' performed by default handler.
     993             :     (directory-file-name . tramp-handle-directory-file-name)
     994             :     (directory-files . tramp-handle-directory-files)
     995             :     (directory-files-and-attributes
     996             :      . tramp-sh-handle-directory-files-and-attributes)
     997             :     (dired-compress-file . tramp-sh-handle-dired-compress-file)
     998             :     (dired-uncache . tramp-handle-dired-uncache)
     999             :     (expand-file-name . tramp-sh-handle-expand-file-name)
    1000             :     (file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
    1001             :     (file-acl . tramp-sh-handle-file-acl)
    1002             :     (file-attributes . tramp-sh-handle-file-attributes)
    1003             :     (file-directory-p . tramp-sh-handle-file-directory-p)
    1004             :     (file-equal-p . tramp-handle-file-equal-p)
    1005             :     (file-executable-p . tramp-sh-handle-file-executable-p)
    1006             :     (file-exists-p . tramp-sh-handle-file-exists-p)
    1007             :     (file-in-directory-p . tramp-handle-file-in-directory-p)
    1008             :     (file-local-copy . tramp-sh-handle-file-local-copy)
    1009             :     (file-modes . tramp-handle-file-modes)
    1010             :     (file-name-all-completions . tramp-sh-handle-file-name-all-completions)
    1011             :     (file-name-as-directory . tramp-handle-file-name-as-directory)
    1012             :     (file-name-case-insensitive-p . tramp-handle-file-name-case-insensitive-p)
    1013             :     (file-name-completion . tramp-handle-file-name-completion)
    1014             :     (file-name-directory . tramp-handle-file-name-directory)
    1015             :     (file-name-nondirectory . tramp-handle-file-name-nondirectory)
    1016             :     ;; `file-name-sans-versions' performed by default handler.
    1017             :     (file-newer-than-file-p . tramp-sh-handle-file-newer-than-file-p)
    1018             :     (file-notify-add-watch . tramp-sh-handle-file-notify-add-watch)
    1019             :     (file-notify-rm-watch . tramp-handle-file-notify-rm-watch)
    1020             :     (file-notify-valid-p . tramp-handle-file-notify-valid-p)
    1021             :     (file-ownership-preserved-p . tramp-sh-handle-file-ownership-preserved-p)
    1022             :     (file-readable-p . tramp-sh-handle-file-readable-p)
    1023             :     (file-regular-p . tramp-handle-file-regular-p)
    1024             :     (file-remote-p . tramp-handle-file-remote-p)
    1025             :     (file-selinux-context . tramp-sh-handle-file-selinux-context)
    1026             :     (file-symlink-p . tramp-handle-file-symlink-p)
    1027             :     (file-truename . tramp-sh-handle-file-truename)
    1028             :     (file-writable-p . tramp-sh-handle-file-writable-p)
    1029             :     (find-backup-file-name . tramp-handle-find-backup-file-name)
    1030             :     ;; `find-file-noselect' performed by default handler.
    1031             :     ;; `get-file-buffer' performed by default handler.
    1032             :     (insert-directory . tramp-sh-handle-insert-directory)
    1033             :     (insert-file-contents . tramp-handle-insert-file-contents)
    1034             :     (load . tramp-handle-load)
    1035             :     (make-auto-save-file-name . tramp-handle-make-auto-save-file-name)
    1036             :     (make-directory . tramp-sh-handle-make-directory)
    1037             :     (make-nearby-temp-file . tramp-handle-make-nearby-temp-file)
    1038             :     (make-symbolic-link . tramp-sh-handle-make-symbolic-link)
    1039             :     (process-file . tramp-sh-handle-process-file)
    1040             :     (rename-file . tramp-sh-handle-rename-file)
    1041             :     (set-file-acl . tramp-sh-handle-set-file-acl)
    1042             :     (set-file-modes . tramp-sh-handle-set-file-modes)
    1043             :     (set-file-selinux-context . tramp-sh-handle-set-file-selinux-context)
    1044             :     (set-file-times . tramp-sh-handle-set-file-times)
    1045             :     (set-visited-file-modtime . tramp-sh-handle-set-visited-file-modtime)
    1046             :     (shell-command . tramp-handle-shell-command)
    1047             :     (start-file-process . tramp-sh-handle-start-file-process)
    1048             :     (substitute-in-file-name . tramp-handle-substitute-in-file-name)
    1049             :     (temporary-file-directory . tramp-handle-temporary-file-directory)
    1050             :     (unhandled-file-name-directory . ignore)
    1051             :     (vc-registered . tramp-sh-handle-vc-registered)
    1052             :     (verify-visited-file-modtime . tramp-sh-handle-verify-visited-file-modtime)
    1053             :     (write-region . tramp-sh-handle-write-region))
    1054             :   "Alist of handler functions.
    1055             : Operations not mentioned here will be handled by the normal Emacs functions.")
    1056             : 
    1057             : ;;; File Name Handler Functions:
    1058             : 
    1059             : (defun tramp-sh-handle-make-symbolic-link
    1060             :   (filename linkname &optional ok-if-already-exists)
    1061             :   "Like `make-symbolic-link' for Tramp files.
    1062             : If LINKNAME is a non-Tramp file, it is used verbatim as the target of
    1063             : the symlink.  If LINKNAME is a Tramp file, only the localname component is
    1064             : used as the target of the symlink.
    1065             : 
    1066             : If LINKNAME is a Tramp file and the localname component is relative, then
    1067             : it is expanded first, before the localname component is taken.  Note that
    1068             : this can give surprising results if the user/host for the source and
    1069             : target of the symlink differ."
    1070         164 :   (with-parsed-tramp-file-name linkname l
    1071         162 :     (let ((ln (tramp-get-remote-ln l))
    1072         162 :           (cwd (tramp-run-real-handler
    1073         162 :                 'file-name-directory (list l-localname))))
    1074         162 :       (unless ln
    1075           0 :         (tramp-error
    1076           0 :          l 'file-error
    1077         162 :          "Making a symbolic link.  ln(1) does not exist on the remote host."))
    1078             : 
    1079             :       ;; Do the 'confirm if exists' thing.
    1080         162 :       (when (file-exists-p linkname)
    1081             :         ;; What to do?
    1082           4 :         (if (or (null ok-if-already-exists) ; not allowed to exist
    1083           2 :                 (and (numberp ok-if-already-exists)
    1084           0 :                      (not (yes-or-no-p
    1085           0 :                            (format
    1086             :                             "File %s already exists; make it a link anyway? "
    1087           4 :                             l-localname)))))
    1088           2 :             (tramp-error l 'file-already-exists l-localname)
    1089         160 :           (delete-file linkname)))
    1090             : 
    1091             :       ;; If FILENAME is a Tramp name, use just the localname component.
    1092         160 :       (when (tramp-tramp-file-p filename)
    1093         160 :         (setq filename
    1094         160 :               (tramp-file-name-localname
    1095         160 :                (tramp-dissect-file-name (expand-file-name filename)))))
    1096             : 
    1097         160 :       (tramp-flush-file-property l (file-name-directory l-localname))
    1098         160 :       (tramp-flush-file-property l l-localname)
    1099             : 
    1100             :       ;; Right, they are on the same host, regardless of user, method,
    1101             :       ;; etc.  We now make the link on the remote machine. This will
    1102             :       ;; occur as the user that FILENAME belongs to.
    1103         160 :       (and (tramp-send-command-and-check
    1104         160 :             l (format "cd %s" (tramp-shell-quote-argument cwd)))
    1105         160 :            (tramp-send-command-and-check
    1106         160 :             l (format
    1107             :                "%s -sf %s %s"
    1108         160 :                ln
    1109         160 :                (tramp-shell-quote-argument filename)
    1110             :                ;; The command could exceed PATH_MAX, so we use
    1111             :                ;; relative file names.  However, relative file names
    1112             :                ;; could start with "-".  `tramp-shell-quote-argument'
    1113             :                ;; does not handle this, we must do it ourselves.
    1114         160 :                (tramp-shell-quote-argument
    1115         160 :                 (concat "./" (file-name-nondirectory l-localname)))))))))
    1116             : 
    1117             : (defun tramp-sh-handle-file-truename (filename)
    1118             :   "Like `file-truename' for Tramp files."
    1119        1543 :   (format
    1120             :    "%s%s"
    1121        1543 :    (with-parsed-tramp-file-name (expand-file-name filename) nil
    1122        1543 :      (tramp-make-tramp-file-name
    1123        1543 :       method user domain host port
    1124        3861 :       (with-tramp-file-property v localname "file-truename"
    1125         775 :         (let ((result nil)                      ; result steps in reverse order
    1126         775 :               (quoted (tramp-compat-file-name-quoted-p localname))
    1127         775 :               (localname (tramp-compat-file-name-unquote localname)))
    1128         775 :           (tramp-message v 4 "Finding true name for `%s'" filename)
    1129         775 :           (cond
    1130             :            ;; Use GNU readlink --canonicalize-missing where available.
    1131         775 :            ((tramp-get-remote-readlink v)
    1132         467 :             (tramp-send-command-and-check
    1133         467 :              v
    1134         467 :              (format "%s --canonicalize-missing %s"
    1135         467 :                      (tramp-get-remote-readlink v)
    1136         467 :                      (tramp-shell-quote-argument localname)))
    1137         467 :             (with-current-buffer (tramp-get-connection-buffer v)
    1138         467 :               (goto-char (point-min))
    1139         467 :               (setq result (buffer-substring (point-min) (point-at-eol)))))
    1140             : 
    1141             :            ;; Use Perl implementation.
    1142         308 :            ((and (tramp-get-remote-perl v)
    1143         154 :                  (tramp-get-connection-property v "perl-file-spec" nil)
    1144         308 :                  (tramp-get-connection-property v "perl-cwd-realpath" nil))
    1145         154 :             (tramp-maybe-send-script
    1146         154 :              v tramp-perl-file-truename "tramp_perl_file_truename")
    1147         154 :             (setq result
    1148         154 :                   (tramp-send-command-and-read
    1149         154 :                    v
    1150         154 :                    (format "tramp_perl_file_truename %s"
    1151         154 :                            (tramp-shell-quote-argument localname)))))
    1152             : 
    1153             :            ;; Do it yourself.
    1154         154 :            (t (let ((steps (split-string localname "/" 'omit))
    1155             :                     (thisstep nil)
    1156             :                     (numchase 0)
    1157             :                     ;; Don't make the following value larger than
    1158             :                     ;; necessary.  People expect an error message in a
    1159             :                     ;; timely fashion when something is wrong;
    1160             :                     ;; otherwise they might think that Emacs is hung.
    1161             :                     ;; Of course, correctness has to come first.
    1162             :                     (numchase-limit 20)
    1163             :                     symlink-target)
    1164        1091 :                 (while (and steps (< numchase numchase-limit))
    1165        1874 :                   (setq thisstep (pop steps))
    1166         937 :                   (tramp-message
    1167         937 :                    v 5 "Check %s"
    1168         937 :                    (mapconcat 'identity
    1169         937 :                               (append '("") (reverse result) (list thisstep))
    1170         937 :                               "/"))
    1171         937 :                   (setq symlink-target
    1172         937 :                         (tramp-compat-file-attribute-type
    1173         937 :                          (file-attributes
    1174         937 :                           (tramp-make-tramp-file-name
    1175         937 :                            method user domain host port
    1176         937 :                            (mapconcat 'identity
    1177         937 :                                       (append '("")
    1178         937 :                                               (reverse result)
    1179         937 :                                               (list thisstep))
    1180         937 :                                      "/")))))
    1181         937 :                   (cond ((string= "." thisstep)
    1182           0 :                          (tramp-message v 5 "Ignoring step `.'"))
    1183         937 :                         ((string= ".." thisstep)
    1184           0 :                          (tramp-message v 5 "Processing step `..'")
    1185           0 :                          (pop result))
    1186         937 :                         ((stringp symlink-target)
    1187             :                          ;; It's a symlink, follow it.
    1188          19 :                          (tramp-message
    1189          19 :                           v 5 "Follow symlink to %s" symlink-target)
    1190          19 :                          (setq numchase (1+ numchase))
    1191          19 :                          (when (file-name-absolute-p symlink-target)
    1192          19 :                            (setq result nil))
    1193             :                          ;; If the symlink was absolute, we'll get a
    1194             :                          ;; string like "/user@host:/some/target";
    1195             :                          ;; extract the "/some/target" part from it.
    1196          19 :                          (when (tramp-tramp-file-p symlink-target)
    1197           0 :                            (unless (tramp-equal-remote filename symlink-target)
    1198           0 :                              (tramp-error
    1199           0 :                               v 'file-error
    1200             :                               "Symlink target `%s' on wrong host"
    1201           0 :                               symlink-target))
    1202          19 :                            (setq symlink-target localname))
    1203          19 :                          (setq steps
    1204          19 :                                (append
    1205          19 :                                 (split-string symlink-target "/" 'omit)       steps)))
    1206             :                         (t
    1207             :                          ;; It's a file.
    1208         937 :                          (setq result (cons thisstep result)))))
    1209         154 :                 (when (>= numchase numchase-limit)
    1210           0 :                   (tramp-error
    1211           0 :                    v 'file-error
    1212         154 :                    "Maximum number (%d) of symlinks exceeded" numchase-limit))
    1213         154 :                 (setq result (reverse result))
    1214             :                 ;; Combine list to form string.
    1215         154 :                 (setq result
    1216         154 :                       (if result
    1217         154 :                           (mapconcat 'identity (cons "" result) "/")
    1218         154 :                         "/"))
    1219         154 :                 (when (string= "" result)
    1220         775 :                   (setq result "/")))))
    1221             : 
    1222         775 :           (when quoted (setq result (tramp-compat-file-name-quote result)))
    1223         775 :           (tramp-message v 4 "True name of `%s' is `%s'" localname result)
    1224        1543 :           result))))
    1225             : 
    1226             :    ;; Preserve trailing "/".
    1227        1543 :    (if (string-equal (file-name-nondirectory filename) "") "/" "")))
    1228             : 
    1229             : ;; Basic functions.
    1230             : 
    1231             : (defun tramp-sh-handle-file-exists-p (filename)
    1232             :   "Like `file-exists-p' for Tramp files."
    1233        3085 :   (with-parsed-tramp-file-name filename nil
    1234        8225 :     (with-tramp-file-property v localname "file-exists-p"
    1235        2055 :       (or (not (null (tramp-get-file-property
    1236        2055 :                       v localname "file-attributes-integer" nil)))
    1237        1886 :           (not (null (tramp-get-file-property
    1238        1886 :                       v localname "file-attributes-string" nil)))
    1239        1884 :           (tramp-send-command-and-check
    1240        1884 :            v
    1241        1884 :            (format
    1242             :             "%s %s"
    1243        1884 :             (tramp-get-file-exists-command v)
    1244        3085 :             (tramp-shell-quote-argument localname)))))))
    1245             : 
    1246             : (defun tramp-sh-handle-file-attributes (filename &optional id-format)
    1247             :   "Like `file-attributes' for Tramp files."
    1248        3497 :   (unless id-format (setq id-format 'integer))
    1249        3497 :   (ignore-errors
    1250             :     ;; Don't modify `last-coding-system-used' by accident.
    1251        3497 :     (let ((last-coding-system-used last-coding-system-used))
    1252        3497 :       (with-parsed-tramp-file-name (expand-file-name filename) nil
    1253        3497 :         (with-tramp-file-property
    1254        8380 :             v localname (format "file-attributes-%s" id-format)
    1255        1386 :           (save-excursion
    1256        1386 :             (tramp-convert-file-attributes
    1257        1386 :              v
    1258        1386 :              (or
    1259        1386 :               (cond
    1260        1386 :                ((tramp-get-remote-stat v)
    1261         871 :                 (tramp-do-file-attributes-with-stat v localname id-format))
    1262         515 :                ((tramp-get-remote-perl v)
    1263         162 :                 (tramp-do-file-attributes-with-perl v localname id-format))
    1264        1386 :                (t nil))
    1265             :               ;; The scripts could fail, for example with huge file size.
    1266        3497 :               (tramp-do-file-attributes-with-ls v localname id-format)))))))))
    1267             : 
    1268             : (defun tramp-do-file-attributes-with-ls (vec localname &optional id-format)
    1269             :   "Implement `file-attributes' for Tramp files using the ls(1) command."
    1270         717 :   (let (symlinkp dirp
    1271             :                  res-inode res-filemodes res-numlinks
    1272             :                  res-uid res-gid res-size res-symlink-target)
    1273         717 :     (tramp-message vec 5 "file attributes with ls: %s" localname)
    1274             :     ;; We cannot send all three commands combined, it could exceed
    1275             :     ;; NAME_MAX or PATH_MAX.  Happened on macOS, for example.
    1276         717 :     (when (or (tramp-send-command-and-check
    1277         717 :                vec
    1278         717 :                (format "%s %s"
    1279         717 :                        (tramp-get-file-exists-command vec)
    1280         717 :                        (tramp-shell-quote-argument localname)))
    1281         422 :               (tramp-send-command-and-check
    1282         422 :                vec
    1283         422 :                (format "%s -h %s"
    1284         422 :                        (tramp-get-test-command vec)
    1285         717 :                        (tramp-shell-quote-argument localname))))
    1286         295 :       (tramp-send-command
    1287         295 :        vec
    1288         295 :        (format "%s %s %s %s"
    1289         295 :                (tramp-get-ls-command vec)
    1290         295 :                (if (eq id-format 'integer) "-ildn" "-ild")
    1291             :                ;; On systems which have no quoting style, file names
    1292             :                ;; with special characters could fail.
    1293         295 :                (cond
    1294         295 :                 ((tramp-get-ls-command-with-quoting-style vec)
    1295             :                  "--quoting-style=c")
    1296           0 :                 ((tramp-get-ls-command-with-w-option vec)
    1297             :                  "-w")
    1298         295 :                 (t ""))
    1299         295 :                (tramp-shell-quote-argument localname)))
    1300             :       ;; Parse `ls -l' output ...
    1301         295 :       (with-current-buffer (tramp-get-buffer vec)
    1302         295 :         (when (> (buffer-size) 0)
    1303         295 :           (goto-char (point-min))
    1304             :           ;; ... inode
    1305         295 :           (setq res-inode (read (current-buffer)))
    1306             :           ;; ... file mode flags
    1307         295 :           (setq res-filemodes (symbol-name (read (current-buffer))))
    1308             :           ;; ... number links
    1309         295 :           (setq res-numlinks (read (current-buffer)))
    1310             :           ;; ... uid and gid
    1311         295 :           (setq res-uid (read (current-buffer)))
    1312         295 :           (setq res-gid (read (current-buffer)))
    1313         295 :           (if (eq id-format 'integer)
    1314         289 :               (progn
    1315         289 :                 (unless (numberp res-uid)
    1316         289 :                   (setq res-uid tramp-unknown-id-integer))
    1317         289 :                 (unless (numberp res-gid)
    1318         289 :                   (setq res-gid tramp-unknown-id-integer)))
    1319           6 :             (progn
    1320           6 :               (unless (stringp res-uid) (setq res-uid (symbol-name res-uid)))
    1321         295 :               (unless (stringp res-gid) (setq res-gid (symbol-name res-gid)))))
    1322             :           ;; ... size
    1323         295 :           (setq res-size (read (current-buffer)))
    1324             :           ;; From the file modes, figure out other stuff.
    1325         295 :           (setq symlinkp (eq ?l (aref res-filemodes 0)))
    1326         295 :           (setq dirp (eq ?d (aref res-filemodes 0)))
    1327             :           ;; If symlink, find out file name pointed to.
    1328         295 :           (when symlinkp
    1329          38 :             (search-forward "-> ")
    1330          38 :             (setq res-symlink-target
    1331          38 :                   (if (tramp-get-ls-command-with-quoting-style vec)
    1332          38 :                       (read (current-buffer))
    1333         295 :                     (buffer-substring (point) (point-at-eol)))))
    1334             :           ;; Return data gathered.
    1335         295 :           (list
    1336             :            ;; 0. t for directory, string (name linked to) for symbolic
    1337             :            ;; link, or nil.
    1338         295 :            (or dirp res-symlink-target)
    1339             :            ;; 1. Number of links to file.
    1340         295 :            res-numlinks
    1341             :            ;; 2. File uid.
    1342         295 :            res-uid
    1343             :            ;; 3. File gid.
    1344         295 :            res-gid
    1345             :            ;; 4. Last access time, as a list of integers.  Normally
    1346             :            ;; this would be in the same format as `current-time', but
    1347             :            ;; the subseconds part is not currently implemented, and
    1348             :            ;; (0 0) denotes an unknown time.
    1349             :            ;; 5. Last modification time, likewise.
    1350             :            ;; 6. Last status change time, likewise.
    1351             :            '(0 0) '(0 0) '(0 0)         ;CCC how to find out?
    1352             :            ;; 7. Size in bytes (-1, if number is out of range).
    1353         295 :            res-size
    1354             :            ;; 8. File modes, as a string of ten letters or dashes as in ls -l.
    1355         295 :            res-filemodes
    1356             :            ;; 9. t if file's gid would change if file were deleted and
    1357             :            ;; recreated.  Will be set in `tramp-convert-file-attributes'.
    1358             :            t
    1359             :            ;; 10. Inode number.
    1360         295 :            res-inode
    1361             :            ;; 11. Device number.  Will be replaced by a virtual device number.
    1362         717 :            -1))))))
    1363             : 
    1364             : (defun tramp-do-file-attributes-with-perl
    1365             :   (vec localname &optional id-format)
    1366             :   "Implement `file-attributes' for Tramp files using a Perl script."
    1367         162 :   (tramp-message vec 5 "file attributes with perl: %s" localname)
    1368         162 :   (tramp-maybe-send-script
    1369         162 :    vec tramp-perl-file-attributes "tramp_perl_file_attributes")
    1370         162 :   (tramp-send-command-and-read
    1371         162 :    vec
    1372         162 :    (format "tramp_perl_file_attributes %s %s"
    1373         162 :            (tramp-shell-quote-argument localname) id-format)))
    1374             : 
    1375             : (defun tramp-do-file-attributes-with-stat
    1376             :   (vec localname &optional id-format)
    1377             :   "Implement `file-attributes' for Tramp files using stat(1) command."
    1378         871 :   (tramp-message vec 5 "file attributes with stat: %s" localname)
    1379         871 :   (tramp-send-command-and-read
    1380         871 :    vec
    1381         871 :    (format
    1382         871 :     (concat
    1383             :      ;; On Opsware, pdksh (which is the true name of ksh there)
    1384             :      ;; doesn't parse correctly the sequence "((".  Therefore, we add
    1385             :      ;; a space.  Apostrophes in the stat output are masked as
    1386             :      ;; `tramp-stat-marker', in order to make a proper shell escape of
    1387             :      ;; them in file names.
    1388             :      "( (%s %s || %s -h %s) && (%s -c "
    1389             :      "'((%s%%N%s) %%h %s %s %%Xe0 %%Ye0 %%Ze0 %%se0 %s%%A%s t %%ie0 -1)' "
    1390         871 :      "%s | sed -e 's/\"/\\\\\"/g' -e 's/%s/\"/g') || echo nil)")
    1391         871 :     (tramp-get-file-exists-command vec)
    1392         871 :     (tramp-shell-quote-argument localname)
    1393         871 :     (tramp-get-test-command vec)
    1394         871 :     (tramp-shell-quote-argument localname)
    1395         871 :     (tramp-get-remote-stat vec)
    1396         871 :     tramp-stat-marker tramp-stat-marker
    1397         871 :     (if (eq id-format 'integer)
    1398         871 :         "%ue0" (concat tramp-stat-marker "%U" tramp-stat-marker))
    1399         871 :     (if (eq id-format 'integer)
    1400         871 :         "%ge0" (concat tramp-stat-marker "%G" tramp-stat-marker))
    1401         871 :     tramp-stat-marker tramp-stat-marker
    1402         871 :     (tramp-shell-quote-argument localname)
    1403         871 :     tramp-stat-quoted-marker)))
    1404             : 
    1405             : (defun tramp-sh-handle-set-visited-file-modtime (&optional time-list)
    1406             :   "Like `set-visited-file-modtime' for Tramp files."
    1407           0 :   (unless (buffer-file-name)
    1408           0 :     (error "Can't set-visited-file-modtime: buffer `%s' not visiting a file"
    1409           0 :            (buffer-name)))
    1410           0 :   (if time-list
    1411           0 :       (tramp-run-real-handler 'set-visited-file-modtime (list time-list))
    1412           0 :     (let ((f (buffer-file-name))
    1413             :           coding-system-used)
    1414           0 :       (with-parsed-tramp-file-name f nil
    1415           0 :         (let* ((remote-file-name-inhibit-cache t)
    1416           0 :                (attr (file-attributes f))
    1417             :                ;; '(-1 65535) means file doesn't exists yet.
    1418           0 :                (modtime (or (tramp-compat-file-attribute-modification-time attr)
    1419           0 :                             '(-1 65535))))
    1420           0 :           (setq coding-system-used last-coding-system-used)
    1421             :           ;; We use '(0 0) as a don't-know value.  See also
    1422             :           ;; `tramp-do-file-attributes-with-ls'.
    1423           0 :           (if (not (equal modtime '(0 0)))
    1424           0 :               (tramp-run-real-handler 'set-visited-file-modtime (list modtime))
    1425           0 :             (progn
    1426           0 :               (tramp-send-command
    1427           0 :                v
    1428           0 :                (format "%s -ild %s"
    1429           0 :                        (tramp-get-ls-command v)
    1430           0 :                        (tramp-shell-quote-argument localname)))
    1431           0 :               (setq attr (buffer-substring (point) (point-at-eol))))
    1432           0 :             (tramp-set-file-property
    1433           0 :              v localname "visited-file-modtime-ild" attr))
    1434           0 :           (setq last-coding-system-used coding-system-used)
    1435           0 :           nil)))))
    1436             : 
    1437             : ;; This function makes the same assumption as
    1438             : ;; `tramp-sh-handle-set-visited-file-modtime'.
    1439             : (defun tramp-sh-handle-verify-visited-file-modtime (&optional buf)
    1440             :   "Like `verify-visited-file-modtime' for Tramp files.
    1441             : At the time `verify-visited-file-modtime' calls this function, we
    1442             : already know that the buffer is visiting a file and that
    1443             : `visited-file-modtime' does not return 0.  Do not call this
    1444             : function directly, unless those two cases are already taken care
    1445             : of."
    1446           0 :   (with-current-buffer (or buf (current-buffer))
    1447           0 :     (let ((f (buffer-file-name)))
    1448             :       ;; There is no file visiting the buffer, or the buffer has no
    1449             :       ;; recorded last modification time, or there is no established
    1450             :       ;; connection.
    1451           0 :       (if (or (not f)
    1452           0 :               (eq (visited-file-modtime) 0)
    1453           0 :               (not (file-remote-p f nil 'connected)))
    1454             :           t
    1455           0 :         (with-parsed-tramp-file-name f nil
    1456           0 :           (let* ((remote-file-name-inhibit-cache t)
    1457           0 :                  (attr (file-attributes f))
    1458           0 :                  (modtime (tramp-compat-file-attribute-modification-time attr))
    1459           0 :                  (mt (visited-file-modtime)))
    1460             : 
    1461           0 :             (cond
    1462             :              ;; File exists, and has a known modtime.
    1463           0 :              ((and attr (not (equal modtime '(0 0))))
    1464           0 :               (< (abs (tramp-time-diff
    1465           0 :                        modtime
    1466             :                        ;; For compatibility, deal with both the old
    1467             :                        ;; (HIGH . LOW) and the new (HIGH LOW) return
    1468             :                        ;; values of `visited-file-modtime'.
    1469           0 :                        (if (atom (cdr mt))
    1470           0 :                            (list (car mt) (cdr mt))
    1471           0 :                          mt)))
    1472           0 :                  2))
    1473             :              ;; Modtime has the don't know value.
    1474           0 :              (attr
    1475           0 :               (tramp-send-command
    1476           0 :                v
    1477           0 :                (format "%s -ild %s"
    1478           0 :                        (tramp-get-ls-command v)
    1479           0 :                        (tramp-shell-quote-argument localname)))
    1480           0 :               (with-current-buffer (tramp-get-buffer v)
    1481           0 :                 (setq attr (buffer-substring (point) (point-at-eol))))
    1482           0 :               (equal
    1483           0 :                attr
    1484           0 :                (tramp-get-file-property
    1485           0 :                 v localname "visited-file-modtime-ild" "")))
    1486             :              ;; If file does not exist, say it is not modified if and
    1487             :              ;; only if that agrees with the buffer's record.
    1488           0 :              (t (equal mt '(-1 65535))))))))))
    1489             : 
    1490             : (defun tramp-sh-handle-set-file-modes (filename mode)
    1491             :   "Like `set-file-modes' for Tramp files."
    1492          99 :   (with-parsed-tramp-file-name filename nil
    1493          99 :     (tramp-flush-file-property v (file-name-directory localname))
    1494          99 :     (tramp-flush-file-property v localname)
    1495             :     ;; FIXME: extract the proper text from chmod's stderr.
    1496          99 :     (tramp-barf-unless-okay
    1497          99 :      v
    1498          99 :      (format "chmod %o %s" mode (tramp-shell-quote-argument localname))
    1499          99 :      "Error while changing file's mode %s" filename)))
    1500             : 
    1501             : (defun tramp-sh-handle-set-file-times (filename &optional time)
    1502             :   "Like `set-file-times' for Tramp files."
    1503          10 :   (with-parsed-tramp-file-name filename nil
    1504          10 :     (when (tramp-get-remote-touch v)
    1505          10 :       (tramp-flush-file-property v (file-name-directory localname))
    1506          10 :       (tramp-flush-file-property v localname)
    1507          10 :       (let ((time (if (or (null time) (equal time '(0 0)))
    1508           2 :                       (current-time)
    1509          10 :                     time)))
    1510          10 :         (tramp-send-command-and-check
    1511          10 :          v (format
    1512             :             "env TZ=UTC %s %s %s"
    1513          10 :             (tramp-get-remote-touch v)
    1514          10 :             (if (tramp-get-connection-property v "touch-t" nil)
    1515          10 :                 (format "-t %s" (format-time-string "%Y%m%d%H%M.%S" time t))
    1516          10 :               "")
    1517          10 :             (tramp-shell-quote-argument localname)))))))
    1518             : 
    1519             : (defun tramp-set-file-uid-gid (filename &optional uid gid)
    1520             :   "Set the ownership for FILENAME.
    1521             : If UID and GID are provided, these values are used; otherwise uid
    1522             : and gid of the corresponding user is taken.  Both parameters must
    1523             : be non-negative integers."
    1524             :   ;; Modern Unices allow chown only for root.  So we might need
    1525             :   ;; another implementation, see `dired-do-chown'.  OTOH, it is mostly
    1526             :   ;; working with su(do)? when it is needed, so it shall succeed in
    1527             :   ;; the majority of cases.
    1528             :   ;; Don't modify `last-coding-system-used' by accident.
    1529         675 :   (let ((last-coding-system-used last-coding-system-used))
    1530         675 :     (if (tramp-tramp-file-p filename)
    1531         405 :         (with-parsed-tramp-file-name filename nil
    1532         405 :           (if (and (zerop (user-uid)) (tramp-local-host-p v))
    1533             :               ;; If we are root on the local host, we can do it directly.
    1534           0 :               (tramp-set-file-uid-gid localname uid gid)
    1535         405 :             (let ((uid (or (and (natnump uid) uid)
    1536         405 :                            (tramp-get-remote-uid v 'integer)))
    1537         405 :                   (gid (or (and (natnump gid) gid)
    1538         405 :                            (tramp-get-remote-gid v 'integer))))
    1539         405 :               (tramp-send-command
    1540         405 :                v (format
    1541         405 :                   "chown %d:%d %s" uid gid
    1542         405 :                   (tramp-shell-quote-argument localname))))))
    1543             : 
    1544             :       ;; We handle also the local part, because there doesn't exist
    1545             :       ;; `set-file-uid-gid'.  On W32 "chown" does not work.
    1546         270 :       (unless (memq system-type '(ms-dos windows-nt))
    1547         270 :         (let ((uid (or (and (natnump uid) uid) (tramp-get-local-uid 'integer)))
    1548         270 :               (gid (or (and (natnump gid) gid) (tramp-get-local-gid 'integer))))
    1549         270 :           (tramp-call-process
    1550             :            nil "chown" nil nil nil
    1551         675 :            (format "%d:%d" uid gid) (shell-quote-argument filename)))))))
    1552             : 
    1553             : (defun tramp-remote-selinux-p (vec)
    1554             :   "Check, whether SELINUX is enabled on the remote host."
    1555           0 :   (with-tramp-connection-property (tramp-get-connection-process vec) "selinux-p"
    1556           0 :     (tramp-send-command-and-check vec "selinuxenabled")))
    1557             : 
    1558             : (defun tramp-sh-handle-file-selinux-context (filename)
    1559             :   "Like `file-selinux-context' for Tramp files."
    1560           0 :   (with-parsed-tramp-file-name filename nil
    1561           0 :     (with-tramp-file-property v localname "file-selinux-context"
    1562           0 :       (let ((context '(nil nil nil nil))
    1563           0 :             (regexp (concat "\\([a-z0-9_]+\\):" "\\([a-z0-9_]+\\):"
    1564           0 :                             "\\([a-z0-9_]+\\):" "\\([a-z0-9_]+\\)")))
    1565           0 :         (when (and (tramp-remote-selinux-p v)
    1566           0 :                    (tramp-send-command-and-check
    1567           0 :                     v (format
    1568             :                        "%s -d -Z %s"
    1569           0 :                        (tramp-get-ls-command v)
    1570           0 :                        (tramp-shell-quote-argument localname))))
    1571           0 :           (with-current-buffer (tramp-get-connection-buffer v)
    1572           0 :             (goto-char (point-min))
    1573           0 :             (when (re-search-forward regexp (point-at-eol) t)
    1574           0 :               (setq context (list (match-string 1) (match-string 2)
    1575           0 :                                   (match-string 3) (match-string 4))))))
    1576             :         ;; Return the context.
    1577           0 :         context))))
    1578             : 
    1579             : (defun tramp-sh-handle-set-file-selinux-context (filename context)
    1580             :   "Like `set-file-selinux-context' for Tramp files."
    1581           0 :   (with-parsed-tramp-file-name filename nil
    1582           0 :     (when (and (consp context)
    1583           0 :                (tramp-remote-selinux-p v))
    1584           0 :       (let ((user (and (stringp (nth 0 context)) (nth 0 context)))
    1585           0 :             (role (and (stringp (nth 1 context)) (nth 1 context)))
    1586           0 :             (type (and (stringp (nth 2 context)) (nth 2 context)))
    1587           0 :             (range (and (stringp (nth 3 context)) (nth 3 context))))
    1588           0 :         (when (tramp-send-command-and-check
    1589           0 :                v (format "chcon %s %s %s %s %s"
    1590           0 :                          (if user (format "--user=%s" user) "")
    1591           0 :                          (if role (format "--role=%s" role) "")
    1592           0 :                          (if type (format "--type=%s" type) "")
    1593           0 :                          (if range (format "--range=%s" range) "")
    1594           0 :                        (tramp-shell-quote-argument localname)))
    1595           0 :           (if (and user role type range)
    1596           0 :               (tramp-set-file-property
    1597           0 :                v localname "file-selinux-context" context)
    1598           0 :             (tramp-set-file-property
    1599           0 :              v localname "file-selinux-context" 'undef))
    1600           0 :           t)))))
    1601             : 
    1602             : (defun tramp-remote-acl-p (vec)
    1603             :   "Check, whether ACL is enabled on the remote host."
    1604           0 :   (with-tramp-connection-property (tramp-get-connection-process vec) "acl-p"
    1605           0 :     (tramp-send-command-and-check vec "getfacl /")))
    1606             : 
    1607             : (defun tramp-sh-handle-file-acl (filename)
    1608             :   "Like `file-acl' for Tramp files."
    1609           0 :   (with-parsed-tramp-file-name filename nil
    1610           0 :     (with-tramp-file-property v localname "file-acl"
    1611           0 :       (when (and (tramp-remote-acl-p v)
    1612           0 :                  (tramp-send-command-and-check
    1613           0 :                   v (format
    1614             :                      "getfacl -ac %s"
    1615           0 :                      (tramp-shell-quote-argument localname))))
    1616           0 :         (with-current-buffer (tramp-get-connection-buffer v)
    1617           0 :           (goto-char (point-max))
    1618           0 :           (delete-blank-lines)
    1619           0 :           (when (> (point-max) (point-min))
    1620           0 :             (substring-no-properties (buffer-string))))))))
    1621             : 
    1622             : (defun tramp-sh-handle-set-file-acl (filename acl-string)
    1623             :   "Like `set-file-acl' for Tramp files."
    1624           0 :   (with-parsed-tramp-file-name (expand-file-name filename) nil
    1625           0 :     (if (and (stringp acl-string) (tramp-remote-acl-p v)
    1626           0 :              (progn
    1627           0 :                (tramp-send-command
    1628           0 :                 v (format "setfacl --set-file=- %s <<'%s'\n%s\n%s\n"
    1629           0 :                           (tramp-shell-quote-argument localname)
    1630           0 :                           tramp-end-of-heredoc
    1631           0 :                           acl-string
    1632           0 :                           tramp-end-of-heredoc))
    1633           0 :                (tramp-send-command-and-check v nil)))
    1634             :         ;; Success.
    1635           0 :         (progn
    1636           0 :           (tramp-set-file-property v localname "file-acl" acl-string)
    1637           0 :           t)
    1638             :       ;; In case of errors, we return nil.
    1639           0 :       (tramp-set-file-property v localname "file-acl-string" 'undef)
    1640           0 :       nil)))
    1641             : 
    1642             : ;; Simple functions using the `test' command.
    1643             : 
    1644             : (defun tramp-sh-handle-file-executable-p (filename)
    1645             :   "Like `file-executable-p' for Tramp files."
    1646           4 :   (with-parsed-tramp-file-name filename nil
    1647          12 :     (with-tramp-file-property v localname "file-executable-p"
    1648             :       ;; Examine `file-attributes' cache to see if request can be
    1649             :       ;; satisfied without remote operation.
    1650           4 :       (or (tramp-check-cached-permissions v ?x)
    1651           4 :           (tramp-run-test "-x" filename)))))
    1652             : 
    1653             : (defun tramp-sh-handle-file-readable-p (filename)
    1654             :   "Like `file-readable-p' for Tramp files."
    1655          46 :   (with-parsed-tramp-file-name filename nil
    1656         138 :     (with-tramp-file-property v localname "file-readable-p"
    1657             :       ;; Examine `file-attributes' cache to see if request can be
    1658             :       ;; satisfied without remote operation.
    1659          46 :       (or (tramp-check-cached-permissions v ?r)
    1660          46 :           (tramp-run-test "-r" filename)))))
    1661             : 
    1662             : ;; When the remote shell is started, it looks for a shell which groks
    1663             : ;; tilde expansion.  Here, we assume that all shells which grok tilde
    1664             : ;; expansion will also provide a `test' command which groks `-nt' (for
    1665             : ;; newer than).  If this breaks, tell me about it and I'll try to do
    1666             : ;; something smarter about it.
    1667             : (defun tramp-sh-handle-file-newer-than-file-p (file1 file2)
    1668             :   "Like `file-newer-than-file-p' for Tramp files."
    1669           6 :   (cond ((not (file-exists-p file1))
    1670             :          nil)
    1671           4 :         ((not (file-exists-p file2))
    1672             :          t)
    1673             :         ;; We are sure both files exist at this point.
    1674             :         (t
    1675           2 :          (save-excursion
    1676             :            ;; We try to get the mtime of both files.  If they are not
    1677             :            ;; equal to the "dont-know" value, then we subtract the times
    1678             :            ;; and obtain the result.
    1679           2 :            (let ((fa1 (file-attributes file1))
    1680           2 :                  (fa2 (file-attributes file2)))
    1681           2 :              (if (and
    1682           2 :                   (not
    1683           2 :                    (equal (tramp-compat-file-attribute-modification-time fa1)
    1684           2 :                           '(0 0)))
    1685           2 :                   (not
    1686           2 :                    (equal (tramp-compat-file-attribute-modification-time fa2)
    1687           2 :                           '(0 0))))
    1688           2 :                  (> 0 (tramp-time-diff
    1689           2 :                        (tramp-compat-file-attribute-modification-time fa2)
    1690           2 :                        (tramp-compat-file-attribute-modification-time fa1)))
    1691             :                ;; If one of them is the dont-know value, then we can
    1692             :                ;; still try to run a shell command on the remote host.
    1693             :                ;; However, this only works if both files are Tramp
    1694             :                ;; files and both have the same method, same user, same
    1695             :                ;; host.
    1696           0 :                (unless (tramp-equal-remote file1 file2)
    1697           0 :                  (with-parsed-tramp-file-name
    1698           0 :                      (if (tramp-tramp-file-p file1) file1 file2) nil
    1699           0 :                    (tramp-error
    1700           0 :                     v 'file-error
    1701             :                     "Files %s and %s must have same method, user, host"
    1702           0 :                     file1 file2)))
    1703           0 :                (with-parsed-tramp-file-name file1 nil
    1704           0 :                  (tramp-run-test2
    1705           6 :                   (tramp-get-test-nt-command v) file1 file2))))))))
    1706             : 
    1707             : ;; Functions implemented using the basic functions above.
    1708             : 
    1709             : (defun tramp-sh-handle-file-directory-p (filename)
    1710             :   "Like `file-directory-p' for Tramp files."
    1711        2230 :   (with-parsed-tramp-file-name filename nil
    1712             :     ;; `file-directory-p' is used as predicate for file name completion.
    1713             :     ;; Sometimes, when a connection is not established yet, it is
    1714             :     ;; desirable to return t immediately for "/method:foo:".  It can
    1715             :     ;; be expected that this is always a directory.
    1716        2230 :     (or (zerop (length localname))
    1717        6122 :         (with-tramp-file-property v localname "file-directory-p"
    1718        2230 :           (tramp-run-test "-d" filename)))))
    1719             : 
    1720             : (defun tramp-sh-handle-file-writable-p (filename)
    1721             :   "Like `file-writable-p' for Tramp files."
    1722        1526 :   (with-parsed-tramp-file-name filename nil
    1723        3182 :     (with-tramp-file-property v localname "file-writable-p"
    1724         130 :       (if (file-exists-p filename)
    1725             :           ;; Examine `file-attributes' cache to see if request can be
    1726             :           ;; satisfied without remote operation.
    1727         130 :           (or (tramp-check-cached-permissions v ?w)
    1728         130 :               (tramp-run-test "-w" filename))
    1729             :         ;; If file doesn't exist, check if directory is writable.
    1730           0 :         (and (tramp-run-test "-d" (file-name-directory filename))
    1731        1526 :              (tramp-run-test "-w" (file-name-directory filename)))))))
    1732             : 
    1733             : (defun tramp-sh-handle-file-ownership-preserved-p (filename &optional group)
    1734             :   "Like `file-ownership-preserved-p' for Tramp files."
    1735          12 :   (with-parsed-tramp-file-name filename nil
    1736          34 :     (with-tramp-file-property v localname "file-ownership-preserved-p"
    1737          10 :       (let ((attributes (file-attributes filename)))
    1738             :         ;; Return t if the file doesn't exist, since it's true that no
    1739             :         ;; information would be lost by an (attempted) delete and create.
    1740          10 :         (or (null attributes)
    1741           6 :             (and
    1742           6 :              (= (tramp-compat-file-attribute-user-id attributes)
    1743           6 :                 (tramp-get-remote-uid v 'integer))
    1744           6 :              (or (not group)
    1745           6 :                  (= (tramp-compat-file-attribute-group-id attributes)
    1746          12 :                     (tramp-get-remote-gid v 'integer)))))))))
    1747             : 
    1748             : ;; Directory listings.
    1749             : 
    1750             : (defun tramp-sh-handle-directory-files-and-attributes
    1751             :   (directory &optional full match nosort id-format)
    1752             :   "Like `directory-files-and-attributes' for Tramp files."
    1753         234 :   (unless id-format (setq id-format 'integer))
    1754         234 :   (when (file-directory-p directory)
    1755         234 :     (setq directory (expand-file-name directory))
    1756         234 :     (let* ((temp
    1757         234 :             (copy-tree
    1758         234 :              (with-parsed-tramp-file-name directory nil
    1759         234 :                (with-tramp-file-property
    1760         622 :                    v localname
    1761         388 :                    (format "directory-files-and-attributes-%s" id-format)
    1762         154 :                  (save-excursion
    1763         154 :                    (mapcar
    1764             :                     (lambda (x)
    1765         409 :                       (cons (car x)
    1766         409 :                             (tramp-convert-file-attributes v (cdr x))))
    1767         154 :                     (or
    1768         154 :                      (cond
    1769         154 :                       ((tramp-get-remote-stat v)
    1770          78 :                        (tramp-do-directory-files-and-attributes-with-stat
    1771          78 :                         v localname id-format))
    1772          76 :                       ((tramp-get-remote-perl v)
    1773          38 :                        (tramp-do-directory-files-and-attributes-with-perl
    1774          38 :                         v localname id-format))
    1775         234 :                       (t nil)))))))))
    1776             :            result item)
    1777             : 
    1778         891 :       (while temp
    1779        1314 :         (setq item (pop temp))
    1780         657 :         (when (or (null match) (string-match match (car item)))
    1781         195 :           (when full
    1782         195 :             (setcar item (expand-file-name (car item) directory)))
    1783         657 :           (push item result)))
    1784             : 
    1785         234 :       (or (if nosort
    1786           0 :               result
    1787         264 :             (sort result (lambda (x y) (string< (car x) (car y)))))
    1788             :           ;; The scripts could fail, for example with huge file size.
    1789          57 :           (tramp-handle-directory-files-and-attributes
    1790         234 :            directory full match nosort id-format)))))
    1791             : 
    1792             : (defun tramp-do-directory-files-and-attributes-with-perl
    1793             :   (vec localname &optional id-format)
    1794             :   "Implement `directory-files-and-attributes' for Tramp files using a Perl script."
    1795          38 :   (tramp-message vec 5 "directory-files-and-attributes with perl: %s" localname)
    1796          38 :   (tramp-maybe-send-script
    1797          38 :    vec tramp-perl-directory-files-and-attributes
    1798          38 :    "tramp_perl_directory_files_and_attributes")
    1799          38 :   (let ((object
    1800          38 :          (tramp-send-command-and-read
    1801          38 :           vec
    1802          38 :           (format "tramp_perl_directory_files_and_attributes %s %s"
    1803          38 :                   (tramp-shell-quote-argument localname) id-format))))
    1804          38 :     (when (stringp object) (tramp-error vec 'file-error object))
    1805          38 :     object))
    1806             : 
    1807             : (defun tramp-do-directory-files-and-attributes-with-stat
    1808             :   (vec localname &optional id-format)
    1809             :   "Implement `directory-files-and-attributes' for Tramp files using stat(1) command."
    1810          78 :   (tramp-message vec 5 "directory-files-and-attributes with stat: %s" localname)
    1811          78 :   (tramp-send-command-and-read
    1812          78 :    vec
    1813          78 :    (format
    1814          78 :     (concat
    1815             :      ;; We must care about file names with spaces, or starting with
    1816             :      ;; "-"; this would confuse xargs.  "ls -aQ" might be a solution,
    1817             :      ;; but it does not work on all remote systems.  Apostrophes in
    1818             :      ;; the stat output are masked as `tramp-stat-marker', in order to
    1819             :      ;; make a proper shell escape of them in file names.
    1820             :      "cd %s && echo \"(\"; (%s %s -a | "
    1821             :      "xargs %s -c "
    1822             :      "'(%s%%n%s (%s%%N%s) %%h %s %s %%Xe0 %%Ye0 %%Ze0 %%se0 %s%%A%s t %%ie0 -1)' "
    1823          78 :      "-- 2>/dev/null | sed -e 's/\"/\\\\\"/g' -e 's/%s/\"/g'); echo \")\"")
    1824          78 :     (tramp-shell-quote-argument localname)
    1825          78 :     (tramp-get-ls-command vec)
    1826             :     ;; On systems which have no quoting style, file names with special
    1827             :     ;; characters could fail.
    1828          78 :     (cond
    1829          78 :      ((tramp-get-ls-command-with-quoting-style vec)
    1830             :       "--quoting-style=shell")
    1831           0 :      ((tramp-get-ls-command-with-w-option vec)
    1832             :       "-w")
    1833          78 :      (t ""))
    1834          78 :     (tramp-get-remote-stat vec)
    1835          78 :     tramp-stat-marker tramp-stat-marker
    1836          78 :     tramp-stat-marker tramp-stat-marker
    1837          78 :     (if (eq id-format 'integer)
    1838          78 :         "%ue0" (concat tramp-stat-marker "%U" tramp-stat-marker))
    1839          78 :     (if (eq id-format 'integer)
    1840          78 :         "%ge0" (concat tramp-stat-marker "%G" tramp-stat-marker))
    1841          78 :     tramp-stat-marker tramp-stat-marker
    1842          78 :     tramp-stat-quoted-marker)))
    1843             : 
    1844             : ;; This function should return "foo/" for directories and "bar" for
    1845             : ;; files.
    1846             : (defun tramp-sh-handle-file-name-all-completions (filename directory)
    1847             :   "Like `file-name-all-completions' for Tramp files."
    1848         226 :   (unless (save-match-data (string-match "/" filename))
    1849         226 :     (all-completions
    1850         226 :      filename
    1851         226 :      (with-parsed-tramp-file-name (expand-file-name directory) nil
    1852         578 :        (with-tramp-file-property v localname "file-name-all-completions"
    1853         126 :          (let (result)
    1854             :            ;; Get a list of directories and files, including reliably
    1855             :            ;; tagging the directories with a trailing "/".  Because I
    1856             :            ;; rock.  --daniel@danann.net
    1857         126 :            (tramp-send-command
    1858         126 :             v
    1859         126 :             (if (tramp-get-remote-perl v)
    1860          61 :                 (progn
    1861          61 :                   (tramp-maybe-send-script
    1862          61 :                    v tramp-perl-file-name-all-completions
    1863          61 :                    "tramp_perl_file_name_all_completions")
    1864          61 :                   (format "tramp_perl_file_name_all_completions %s"
    1865          61 :                           (tramp-shell-quote-argument localname)))
    1866             : 
    1867          65 :               (format (concat
    1868             :                        "(cd %s 2>&1 && %s -a 2>/dev/null"
    1869             :                        " | while IFS= read f; do"
    1870             :                        " if %s -d \"$f\" 2>/dev/null;"
    1871             :                        " then \\echo \"$f/\"; else \\echo \"$f\"; fi; done"
    1872          65 :                        " && \\echo ok) || \\echo fail")
    1873          65 :                       (tramp-shell-quote-argument localname)
    1874          65 :                       (tramp-get-ls-command v)
    1875         126 :                       (tramp-get-test-command v))))
    1876             : 
    1877             :            ;; Now grab the output.
    1878         126 :            (with-current-buffer (tramp-get-buffer v)
    1879         126 :              (goto-char (point-max))
    1880             : 
    1881             :              ;; Check result code, found in last line of output.
    1882         126 :              (forward-line -1)
    1883         126 :              (if (looking-at "^fail$")
    1884           0 :                  (progn
    1885             :                    ;; Grab error message from line before last line
    1886             :                    ;; (it was put there by `cd 2>&1').
    1887           0 :                    (forward-line -1)
    1888           0 :                    (tramp-error
    1889           0 :                     v 'file-error
    1890             :                     "tramp-sh-handle-file-name-all-completions: %s"
    1891           0 :                     (buffer-substring (point) (point-at-eol))))
    1892             :                ;; For peace of mind, if buffer doesn't end in `fail'
    1893             :                ;; then it should end in `ok'.  If neither are in the
    1894             :                ;; buffer something went seriously wrong on the remote
    1895             :                ;; side.
    1896         126 :                (unless (looking-at "^ok$")
    1897           0 :                  (tramp-error
    1898           0 :                   v 'file-error "\
    1899             : tramp-sh-handle-file-name-all-completions: internal error accessing `%s': `%s'"
    1900         126 :                   (tramp-shell-quote-argument localname) (buffer-string))))
    1901             : 
    1902         684 :              (while (zerop (forward-line -1))
    1903        1116 :                (push (buffer-substring (point) (point-at-eol)) result)))
    1904         226 :            result))))))
    1905             : 
    1906             : ;; cp, mv and ln
    1907             : 
    1908             : (defun tramp-sh-handle-add-name-to-file
    1909             :   (filename newname &optional ok-if-already-exists)
    1910             :   "Like `add-name-to-file' for Tramp files."
    1911           8 :   (unless (tramp-equal-remote filename newname)
    1912           2 :     (with-parsed-tramp-file-name
    1913           2 :         (if (tramp-tramp-file-p filename) filename newname) nil
    1914           2 :       (tramp-error
    1915           2 :        v 'file-error
    1916             :        "add-name-to-file: %s"
    1917           6 :        "only implemented for same method, same user, same host")))
    1918           6 :   (with-parsed-tramp-file-name filename v1
    1919           6 :     (with-parsed-tramp-file-name newname v2
    1920           6 :       (let ((ln (when v1 (tramp-get-remote-ln v1))))
    1921           6 :         (when (and (numberp ok-if-already-exists)
    1922           0 :                    (file-exists-p newname)
    1923           0 :                    (yes-or-no-p
    1924           0 :                     (format
    1925             :                      "File %s already exists; make it a new name anyway? "
    1926           6 :                      newname)))
    1927           6 :           (tramp-error v2 'file-already-exists newname))
    1928           6 :         (when ok-if-already-exists (setq ln (concat ln " -f")))
    1929           6 :         (tramp-flush-file-property v2 (file-name-directory v2-localname))
    1930           6 :         (tramp-flush-file-property v2 v2-localname)
    1931           6 :         (tramp-barf-unless-okay
    1932           6 :          v1
    1933           6 :          (format "%s %s %s" ln
    1934           6 :                  (tramp-shell-quote-argument v1-localname)
    1935           6 :                  (tramp-shell-quote-argument v2-localname))
    1936             :          "error with add-name-to-file, see buffer `%s' for details"
    1937           6 :          (buffer-name))))))
    1938             : 
    1939             : (defun tramp-sh-handle-copy-file
    1940             :   (filename newname &optional ok-if-already-exists keep-date
    1941             :    preserve-uid-gid preserve-extended-attributes)
    1942             :   "Like `copy-file' for Tramp files."
    1943         176 :   (setq filename (expand-file-name filename)
    1944         176 :         newname (expand-file-name newname))
    1945         176 :   (if (or (tramp-tramp-file-p filename)
    1946         176 :           (tramp-tramp-file-p newname))
    1947         176 :       (tramp-do-copy-or-rename-file
    1948         176 :        'copy filename newname ok-if-already-exists keep-date
    1949         176 :        preserve-uid-gid preserve-extended-attributes)
    1950           0 :     (tramp-run-real-handler
    1951             :      'copy-file
    1952           0 :      (list filename newname ok-if-already-exists keep-date
    1953         173 :            preserve-uid-gid preserve-extended-attributes))))
    1954             : 
    1955             : (defun tramp-sh-handle-copy-directory
    1956             :   (dirname newname &optional keep-date parents copy-contents)
    1957             :   "Like `copy-directory' for Tramp files."
    1958           8 :   (let ((t1 (tramp-tramp-file-p dirname))
    1959           8 :         (t2 (tramp-tramp-file-p newname)))
    1960           8 :     (with-parsed-tramp-file-name (if t1 dirname newname) nil
    1961           8 :       (if (and (not copy-contents)
    1962           4 :                (tramp-get-method-parameter v 'tramp-copy-recursive)
    1963             :                ;; When DIRNAME and NEWNAME are remote, they must have
    1964             :                ;; the same method.
    1965           0 :                (or (null t1) (null t2)
    1966           0 :                    (string-equal
    1967           0 :                     (tramp-file-name-method (tramp-dissect-file-name dirname))
    1968           0 :                     (tramp-file-name-method
    1969           8 :                      (tramp-dissect-file-name newname)))))
    1970             :           ;; scp or rsync DTRT.
    1971           0 :           (progn
    1972           0 :             (setq dirname (directory-file-name (expand-file-name dirname))
    1973           0 :                   newname (directory-file-name (expand-file-name newname)))
    1974           0 :             (if (and (file-directory-p newname)
    1975           0 :                      (not (string-equal (file-name-nondirectory dirname)
    1976           0 :                                         (file-name-nondirectory newname))))
    1977           0 :                 (setq newname
    1978           0 :                       (expand-file-name
    1979           0 :                        (file-name-nondirectory dirname) newname)))
    1980           0 :             (if (not (file-directory-p (file-name-directory newname)))
    1981           0 :                 (make-directory (file-name-directory newname) parents))
    1982           0 :             (tramp-do-copy-or-rename-file-out-of-band
    1983           0 :              'copy dirname newname keep-date))
    1984             :         ;; We must do it file-wise.
    1985           8 :         (tramp-run-real-handler
    1986             :          'copy-directory
    1987           8 :          (if copy-contents
    1988           4 :              (list dirname newname keep-date parents copy-contents)
    1989           8 :            (list dirname newname keep-date parents))))
    1990             : 
    1991             :       ;; When newname did exist, we have wrong cached values.
    1992           8 :       (when t2
    1993           8 :         (with-parsed-tramp-file-name newname nil
    1994           8 :           (tramp-flush-file-property v (file-name-directory localname))
    1995           8 :           (tramp-flush-file-property v localname))))))
    1996             : 
    1997             : (defun tramp-sh-handle-rename-file
    1998             :   (filename newname &optional ok-if-already-exists)
    1999             :   "Like `rename-file' for Tramp files."
    2000             :   ;; Check if both files are local -- invoke normal rename-file.
    2001             :   ;; Otherwise, use Tramp from local system.
    2002          12 :   (setq filename (expand-file-name filename))
    2003          12 :   (setq newname (expand-file-name newname))
    2004             :   ;; At least one file a Tramp file?
    2005          12 :   (if (or (tramp-tramp-file-p filename)
    2006          12 :           (tramp-tramp-file-p newname))
    2007          12 :       (tramp-do-copy-or-rename-file
    2008          12 :        'rename filename newname ok-if-already-exists
    2009           9 :        'keep-time 'preserve-uid-gid)
    2010           0 :     (tramp-run-real-handler
    2011           9 :      'rename-file (list filename newname ok-if-already-exists))))
    2012             : 
    2013             : (defun tramp-do-copy-or-rename-file
    2014             :   (op filename newname &optional ok-if-already-exists keep-date
    2015             :    preserve-uid-gid preserve-extended-attributes)
    2016             :   "Copy or rename a remote file.
    2017             : OP must be `copy' or `rename' and indicates the operation to perform.
    2018             : FILENAME specifies the file to copy or rename, NEWNAME is the name of
    2019             : the new file (for copy) or the new name of the file (for rename).
    2020             : OK-IF-ALREADY-EXISTS means don't barf if NEWNAME exists already.
    2021             : KEEP-DATE means to make sure that NEWNAME has the same timestamp
    2022             : as FILENAME.  PRESERVE-UID-GID, when non-nil, instructs to keep
    2023             : the uid and gid if both files are on the same host.
    2024             : PRESERVE-EXTENDED-ATTRIBUTES activates selinux and acl commands.
    2025             : 
    2026             : This function is invoked by `tramp-sh-handle-copy-file' and
    2027             : `tramp-sh-handle-rename-file'.  It is an error if OP is neither
    2028             : of `copy' and `rename'.  FILENAME and NEWNAME must be absolute
    2029             : file names."
    2030         188 :   (unless (memq op '(copy rename))
    2031         188 :     (error "Unknown operation `%s', must be `copy' or `rename'" op))
    2032         188 :   (let ((t1 (tramp-tramp-file-p filename))
    2033         188 :         (t2 (tramp-tramp-file-p newname))
    2034         188 :         (length (tramp-compat-file-attribute-size
    2035         188 :                  (file-attributes (file-truename filename))))
    2036         188 :         (attributes (and preserve-extended-attributes
    2037         188 :                          (apply 'file-extended-attributes (list filename)))))
    2038             : 
    2039         188 :     (with-parsed-tramp-file-name (if t1 filename newname) nil
    2040         188 :       (when (and (not ok-if-already-exists) (file-exists-p newname))
    2041         182 :         (tramp-error v 'file-already-exists newname))
    2042             : 
    2043         182 :       (with-tramp-progress-reporter
    2044         364 :           v 0 (format "%s %s to %s"
    2045         364 :                       (if (eq op 'copy) "Copying" "Renaming")
    2046         364 :                       filename newname)
    2047             : 
    2048         182 :         (cond
    2049             :          ;; Both are Tramp files.
    2050         182 :          ((and t1 t2)
    2051          14 :           (with-parsed-tramp-file-name filename v1
    2052          14 :             (with-parsed-tramp-file-name newname v2
    2053          14 :               (cond
    2054             :                ;; Shortcut: if method, host, user are the same for
    2055             :                ;; both files, we invoke `cp' or `mv' on the remote
    2056             :                ;; host directly.
    2057          14 :                ((tramp-equal-remote filename newname)
    2058          14 :                 (tramp-do-copy-or-rename-file-directly
    2059          14 :                  op filename newname
    2060          14 :                  ok-if-already-exists keep-date preserve-uid-gid))
    2061             : 
    2062             :                ;; Try out-of-band operation.
    2063           0 :                ((and
    2064           0 :                  (tramp-method-out-of-band-p v1 length)
    2065           0 :                  (tramp-method-out-of-band-p v2 length))
    2066           0 :                 (tramp-do-copy-or-rename-file-out-of-band
    2067           0 :                  op filename newname keep-date))
    2068             : 
    2069             :                ;; No shortcut was possible.  So we copy the file
    2070             :                ;; first.  If the operation was `rename', we go back
    2071             :                ;; and delete the original file (if the copy was
    2072             :                ;; successful).  The approach is simple-minded: we
    2073             :                ;; create a new buffer, insert the contents of the
    2074             :                ;; source file into it, then write out the buffer to
    2075             :                ;; the target file.  The advantage is that it doesn't
    2076             :                ;; matter which file name handlers are used for the
    2077             :                ;; source and target file.
    2078             :                (t
    2079           0 :                 (tramp-do-copy-or-rename-file-via-buffer
    2080          14 :                  op filename newname keep-date))))))
    2081             : 
    2082             :          ;; One file is a Tramp file, the other one is local.
    2083         168 :          ((or t1 t2)
    2084         168 :           (cond
    2085             :            ;; Fast track on local machine.
    2086         168 :            ((tramp-local-host-p v)
    2087           0 :             (tramp-do-copy-or-rename-file-directly
    2088           0 :              op filename newname
    2089           0 :              ok-if-already-exists keep-date preserve-uid-gid))
    2090             : 
    2091             :            ;; If the Tramp file has an out-of-band method, the
    2092             :            ;; corresponding copy-program can be invoked.
    2093         168 :            ((tramp-method-out-of-band-p v length)
    2094           0 :             (tramp-do-copy-or-rename-file-out-of-band
    2095           0 :              op filename newname keep-date))
    2096             : 
    2097             :            ;; Use the inline method via a Tramp buffer.
    2098         168 :            (t (tramp-do-copy-or-rename-file-via-buffer
    2099         168 :                op filename newname keep-date))))
    2100             : 
    2101             :          (t
    2102             :           ;; One of them must be a Tramp file.
    2103         182 :           (error "Tramp implementation says this cannot happen")))
    2104             : 
    2105             :         ;; Handle `preserve-extended-attributes'.  We ignore possible
    2106             :         ;; errors, because ACL strings could be incompatible.
    2107         182 :         (when attributes
    2108           0 :           (ignore-errors
    2109         182 :             (apply 'set-file-extended-attributes (list newname attributes))))
    2110             : 
    2111             :         ;; In case of `rename', we must flush the cache of the source file.
    2112         182 :         (when (and t1 (eq op 'rename))
    2113           6 :           (with-parsed-tramp-file-name filename v1
    2114           6 :             (tramp-flush-file-property v1 (file-name-directory v1-localname))
    2115         182 :             (tramp-flush-file-property v1 v1-localname)))
    2116             : 
    2117             :         ;; When newname did exist, we have wrong cached values.
    2118         182 :         (when t2
    2119          96 :           (with-parsed-tramp-file-name newname v2
    2120          96 :             (tramp-flush-file-property v2 (file-name-directory v2-localname))
    2121         182 :             (tramp-flush-file-property v2 v2-localname)))))))
    2122             : 
    2123             : (defun tramp-do-copy-or-rename-file-via-buffer (op filename newname keep-date)
    2124             :   "Use an Emacs buffer to copy or rename a file.
    2125             : First arg OP is either `copy' or `rename' and indicates the operation.
    2126             : FILENAME is the source file, NEWNAME the target file.
    2127             : KEEP-DATE is non-nil if NEWNAME should have the same timestamp as FILENAME."
    2128             :   ;; Check, whether file is too large.  Emacs checks in `insert-file-1'
    2129             :   ;; and `find-file-noselect', but that's not called here.
    2130         168 :   (abort-if-file-too-large
    2131         168 :    (tramp-compat-file-attribute-size (file-attributes (file-truename filename)))
    2132         168 :    (symbol-name op) filename)
    2133             :   ;; We must disable multibyte, because binary data shall not be
    2134             :   ;; converted.  We don't want the target file to be compressed, so we
    2135             :   ;; let-bind `jka-compr-inhibit' to t.  `epa-file-handler' shall not
    2136             :   ;; be called either.  We remove `tramp-file-name-handler' from
    2137             :   ;; `inhibit-file-name-handlers'; otherwise the file name handler for
    2138             :   ;; `insert-file-contents' might be deactivated in some corner cases.
    2139         168 :   (let ((coding-system-for-read 'binary)
    2140             :         (coding-system-for-write 'binary)
    2141             :         (jka-compr-inhibit t)
    2142             :         (inhibit-file-name-operation 'write-region)
    2143             :         (inhibit-file-name-handlers
    2144         168 :          (cons 'epa-file-handler
    2145         168 :                (remq 'tramp-file-name-handler inhibit-file-name-handlers))))
    2146         168 :     (with-temp-file newname
    2147         168 :       (set-buffer-multibyte nil)
    2148         168 :       (insert-file-contents-literally filename)))
    2149             :   ;; KEEP-DATE handling.
    2150         168 :   (when keep-date
    2151           6 :     (set-file-times
    2152           6 :      newname
    2153           6 :      (tramp-compat-file-attribute-modification-time
    2154         168 :       (file-attributes filename))))
    2155             :   ;; Set the mode.
    2156         168 :   (set-file-modes newname (tramp-default-file-modes filename))
    2157             :   ;; If the operation was `rename', delete the original file.
    2158         168 :   (unless (eq op 'copy) (delete-file filename)))
    2159             : 
    2160             : (defun tramp-do-copy-or-rename-file-directly
    2161             :  (op filename newname ok-if-already-exists keep-date preserve-uid-gid)
    2162             :   "Invokes `cp' or `mv' on the remote system.
    2163             : OP must be one of `copy' or `rename', indicating `cp' or `mv',
    2164             : respectively.  FILENAME specifies the file to copy or rename,
    2165             : NEWNAME is the name of the new file (for copy) or the new name of
    2166             : the file (for rename).  Both files must reside on the same host.
    2167             : KEEP-DATE means to make sure that NEWNAME has the same timestamp
    2168             : as FILENAME.  PRESERVE-UID-GID, when non-nil, instructs to keep
    2169             : the uid and gid from FILENAME."
    2170          14 :   (let ((t1 (tramp-tramp-file-p filename))
    2171          14 :         (t2 (tramp-tramp-file-p newname))
    2172          14 :         (file-times (tramp-compat-file-attribute-modification-time
    2173          14 :                      (file-attributes filename)))
    2174          14 :         (file-modes (tramp-default-file-modes filename)))
    2175          14 :     (with-parsed-tramp-file-name (if t1 filename newname) nil
    2176          14 :       (let* ((cmd (cond ((and (eq op 'copy) preserve-uid-gid) "cp -f -p")
    2177          14 :                         ((eq op 'copy) "cp -f")
    2178           3 :                         ((eq op 'rename) "mv -f")
    2179           0 :                         (t (tramp-error
    2180           0 :                             v 'file-error
    2181             :                             "Unknown operation `%s', must be `copy' or `rename'"
    2182          14 :                             op))))
    2183          14 :              (localname1 (if t1 (file-remote-p filename 'localname) filename))
    2184          14 :              (localname2 (if t2 (file-remote-p newname 'localname) newname))
    2185          14 :              (prefix (file-remote-p (if t1 filename newname)))
    2186             :              cmd-result)
    2187             : 
    2188          14 :         (cond
    2189             :          ;; Both files are on a remote host, with same user.
    2190          14 :          ((and t1 t2)
    2191          14 :           (setq cmd-result
    2192          14 :                 (tramp-send-command-and-check
    2193          14 :                  v (format "%s %s %s" cmd
    2194          14 :                            (tramp-shell-quote-argument localname1)
    2195          14 :                            (tramp-shell-quote-argument localname2))))
    2196          14 :           (with-current-buffer (tramp-get-buffer v)
    2197          14 :             (goto-char (point-min))
    2198          14 :             (unless
    2199          14 :                 (or
    2200          14 :                  (and keep-date
    2201             :                       ;; Mask cp -f error.
    2202           3 :                       (re-search-forward
    2203          14 :                        tramp-operation-not-permitted-regexp nil t))
    2204          14 :                  cmd-result)
    2205           0 :               (tramp-error-with-buffer
    2206           0 :                nil v 'file-error
    2207             :                "Copying directly failed, see buffer `%s' for details."
    2208          14 :                (buffer-name)))))
    2209             : 
    2210             :          ;; We are on the local host.
    2211           0 :          ((or t1 t2)
    2212           0 :           (cond
    2213             :            ;; We can do it directly.
    2214           0 :            ((let (file-name-handler-alist)
    2215           0 :               (and (file-readable-p localname1)
    2216             :                    ;; No sticky bit when renaming.
    2217           0 :                    (or (eq op 'copy)
    2218           0 :                        (zerop
    2219           0 :                         (logand
    2220           0 :                          (file-modes (file-name-directory localname1))
    2221           0 :                          (string-to-number "1000" 8))))
    2222           0 :                    (file-writable-p (file-name-directory localname2))
    2223           0 :                    (or (file-directory-p localname2)
    2224           0 :                        (file-writable-p localname2))))
    2225           0 :             (if (eq op 'copy)
    2226           0 :                 (copy-file
    2227           0 :                  localname1 localname2 ok-if-already-exists
    2228           0 :                  keep-date preserve-uid-gid)
    2229           0 :               (tramp-run-real-handler
    2230           0 :                'rename-file (list localname1 localname2 ok-if-already-exists))))
    2231             : 
    2232             :            ;; We can do it directly with `tramp-send-command'
    2233           0 :            ((and (file-readable-p (concat prefix localname1))
    2234           0 :                  (file-writable-p
    2235           0 :                   (file-name-directory (concat prefix localname2)))
    2236           0 :                  (or (file-directory-p (concat prefix localname2))
    2237           0 :                      (file-writable-p (concat prefix localname2))))
    2238           0 :             (tramp-do-copy-or-rename-file-directly
    2239           0 :              op (concat prefix localname1) (concat prefix localname2)
    2240           0 :              ok-if-already-exists keep-date t)
    2241             :             ;; We must change the ownership to the local user.
    2242           0 :             (tramp-set-file-uid-gid
    2243           0 :              (concat prefix localname2)
    2244           0 :              (tramp-get-local-uid 'integer)
    2245           0 :              (tramp-get-local-gid 'integer)))
    2246             : 
    2247             :            ;; We need a temporary file in between.
    2248             :            (t
    2249             :             ;; Create the temporary file.
    2250           0 :             (let ((tmpfile (tramp-compat-make-temp-file localname1)))
    2251           0 :               (unwind-protect
    2252           0 :                   (progn
    2253           0 :                     (cond
    2254           0 :                      (t1
    2255           0 :                       (tramp-barf-unless-okay
    2256           0 :                        v (format
    2257           0 :                           "%s %s %s" cmd
    2258           0 :                           (tramp-shell-quote-argument localname1)
    2259           0 :                           (tramp-shell-quote-argument tmpfile))
    2260             :                        "Copying directly failed, see buffer `%s' for details."
    2261           0 :                        (tramp-get-buffer v))
    2262             :                       ;; We must change the ownership as remote user.
    2263             :                       ;; Since this does not work reliable, we also
    2264             :                       ;; give read permissions.
    2265           0 :                       (set-file-modes
    2266           0 :                        (concat prefix tmpfile) (string-to-number "0777" 8))
    2267           0 :                       (tramp-set-file-uid-gid
    2268           0 :                        (concat prefix tmpfile)
    2269           0 :                        (tramp-get-local-uid 'integer)
    2270           0 :                        (tramp-get-local-gid 'integer)))
    2271           0 :                      (t2
    2272           0 :                       (if (eq op 'copy)
    2273           0 :                           (copy-file
    2274           0 :                            localname1 tmpfile t keep-date preserve-uid-gid)
    2275           0 :                         (tramp-run-real-handler
    2276           0 :                          'rename-file (list localname1 tmpfile t)))
    2277             :                       ;; We must change the ownership as local user.
    2278             :                       ;; Since this does not work reliable, we also
    2279             :                       ;; give read permissions.
    2280           0 :                       (set-file-modes tmpfile (string-to-number "0777" 8))
    2281           0 :                       (tramp-set-file-uid-gid
    2282           0 :                        tmpfile
    2283           0 :                        (tramp-get-remote-uid v 'integer)
    2284           0 :                        (tramp-get-remote-gid v 'integer))))
    2285             : 
    2286             :                     ;; Move the temporary file to its destination.
    2287           0 :                     (cond
    2288           0 :                      (t2
    2289           0 :                       (tramp-barf-unless-okay
    2290           0 :                        v (format
    2291             :                           "cp -f -p %s %s"
    2292           0 :                           (tramp-shell-quote-argument tmpfile)
    2293           0 :                           (tramp-shell-quote-argument localname2))
    2294             :                        "Copying directly failed, see buffer `%s' for details."
    2295           0 :                        (tramp-get-buffer v)))
    2296           0 :                      (t1
    2297           0 :                       (tramp-run-real-handler
    2298             :                        'rename-file
    2299           0 :                        (list tmpfile localname2 ok-if-already-exists)))))
    2300             : 
    2301             :                 ;; Save exit.
    2302          14 :                 (ignore-errors (delete-file tmpfile)))))))))
    2303             : 
    2304             :       ;; Set the time and mode. Mask possible errors.
    2305          14 :       (ignore-errors
    2306          14 :           (when keep-date
    2307           3 :             (set-file-times newname file-times)
    2308          14 :             (set-file-modes newname file-modes))))))
    2309             : 
    2310             : (defun tramp-do-copy-or-rename-file-out-of-band (op filename newname keep-date)
    2311             :   "Invoke `scp' program to copy.
    2312             : The method used must be an out-of-band method."
    2313           0 :   (let* ((t1 (tramp-tramp-file-p filename))
    2314           0 :          (t2 (tramp-tramp-file-p newname))
    2315           0 :          (orig-vec (tramp-dissect-file-name (if t1 filename newname)))
    2316             :          copy-program copy-args copy-env copy-keep-date listener spec
    2317             :          options source target remote-copy-program remote-copy-args)
    2318             : 
    2319           0 :     (with-parsed-tramp-file-name (if t1 filename newname) nil
    2320           0 :       (if (and t1 t2)
    2321             : 
    2322             :           ;; Both are Tramp files.  We shall optimize it when the
    2323             :           ;; methods for FILENAME and NEWNAME are the same.
    2324           0 :           (let* ((dir-flag (file-directory-p filename))
    2325           0 :                  (tmpfile (tramp-compat-make-temp-file localname dir-flag)))
    2326           0 :             (if dir-flag
    2327           0 :                 (setq tmpfile
    2328           0 :                       (expand-file-name
    2329           0 :                        (file-name-nondirectory newname) tmpfile)))
    2330           0 :             (unwind-protect
    2331           0 :                 (progn
    2332           0 :                   (tramp-do-copy-or-rename-file-out-of-band
    2333           0 :                    op filename tmpfile keep-date)
    2334           0 :                   (tramp-do-copy-or-rename-file-out-of-band
    2335           0 :                    'rename tmpfile newname keep-date))
    2336             :               ;; Save exit.
    2337           0 :               (ignore-errors
    2338           0 :                 (if dir-flag
    2339           0 :                     (delete-directory
    2340           0 :                      (expand-file-name ".." tmpfile) 'recursive)
    2341           0 :                   (delete-file tmpfile)))))
    2342             : 
    2343             :         ;; Set variables for computing the prompt for reading password.
    2344           0 :         (setq tramp-current-method (tramp-file-name-method v)
    2345           0 :               tramp-current-user (or (tramp-file-name-user v)
    2346           0 :                                      (tramp-get-connection-property
    2347           0 :                                       v "login-as" nil))
    2348           0 :               tramp-current-domain (tramp-file-name-domain v)
    2349           0 :               tramp-current-host (tramp-file-name-host v)
    2350           0 :               tramp-current-port (tramp-file-name-port v))
    2351             : 
    2352             :         ;; Check which ones of source and target are Tramp files.
    2353           0 :         (setq source (funcall
    2354           0 :                       (if (and (file-directory-p filename)
    2355           0 :                                (not (file-exists-p newname)))
    2356             :                           'file-name-as-directory
    2357           0 :                         'identity)
    2358           0 :                       (if t1
    2359           0 :                           (tramp-make-copy-program-file-name v)
    2360           0 :                         (tramp-unquote-shell-quote-argument filename)))
    2361           0 :               target (if t2
    2362           0 :                          (tramp-make-copy-program-file-name v)
    2363           0 :                        (tramp-unquote-shell-quote-argument newname)))
    2364             : 
    2365             :         ;; Check for user.  There might be an interactive setting.
    2366           0 :         (setq user (or (tramp-file-name-user v)
    2367           0 :                        (tramp-get-connection-property v "login-as" nil)))
    2368             : 
    2369             :         ;; Check for listener port.
    2370           0 :         (when (tramp-get-method-parameter v 'tramp-remote-copy-args)
    2371           0 :           (setq listener (number-to-string (+ 50000 (random 10000))))
    2372           0 :           (while
    2373           0 :               (zerop (tramp-call-process v "nc" nil nil nil "-z" host listener))
    2374           0 :             (setq listener (number-to-string (+ 50000 (random 10000))))))
    2375             : 
    2376             :         ;; Compose copy command.
    2377           0 :         (setq host (or host "")
    2378           0 :               user (or user "")
    2379           0 :               port (or port "")
    2380           0 :               spec (format-spec-make
    2381           0 :                     ?t (tramp-get-connection-property
    2382           0 :                         (tramp-get-connection-process v) "temp-file" ""))
    2383           0 :               options (format-spec (tramp-ssh-controlmaster-options v) spec)
    2384           0 :               spec (format-spec-make
    2385           0 :                     ?h host ?u user ?p port ?r listener ?c options
    2386           0 :                     ?k (if keep-date " " ""))
    2387           0 :               copy-program (tramp-get-method-parameter v 'tramp-copy-program)
    2388           0 :               copy-keep-date (tramp-get-method-parameter
    2389           0 :                               v 'tramp-copy-keep-date)
    2390             : 
    2391             :               copy-args
    2392           0 :               (delete
    2393             :                ;; " " has either been a replacement of "%k" (when
    2394             :                ;; keep-date argument is non-nil), or a replacement
    2395             :                ;; for the whole keep-date sublist.
    2396             :                " "
    2397           0 :                (dolist
    2398           0 :                    (x (tramp-get-method-parameter v 'tramp-copy-args) copy-args)
    2399           0 :                  (setq copy-args
    2400           0 :                        (append
    2401           0 :                         copy-args
    2402           0 :                         (let ((y (mapcar (lambda (z) (format-spec z spec)) x)))
    2403           0 :                           (if (member "" y) '(" ") y))))))
    2404             : 
    2405             :               copy-env
    2406           0 :               (delq
    2407             :                nil
    2408           0 :                (mapcar
    2409             :                 (lambda (x)
    2410           0 :                   (setq x (mapcar (lambda (y) (format-spec y spec)) x))
    2411           0 :                   (unless (member "" x) (mapconcat 'identity x " ")))
    2412           0 :                 (tramp-get-method-parameter v 'tramp-copy-env)))
    2413             : 
    2414             :               remote-copy-program
    2415           0 :               (tramp-get-method-parameter v 'tramp-remote-copy-program))
    2416             : 
    2417           0 :         (dolist (x (tramp-get-method-parameter v 'tramp-remote-copy-args))
    2418           0 :           (setq remote-copy-args
    2419           0 :                 (append
    2420           0 :                  remote-copy-args
    2421           0 :                  (let ((y (mapcar (lambda (z) (format-spec z spec)) x)))
    2422           0 :                    (if (member "" y) '(" ") y)))))
    2423             : 
    2424             :         ;; Check for local copy program.
    2425           0 :         (unless (executable-find copy-program)
    2426           0 :           (tramp-error
    2427           0 :            v 'file-error "Cannot find local copy program: %s" copy-program))
    2428             : 
    2429             :         ;; Install listener on the remote side.  The prompt must be
    2430             :         ;; consumed later on, when the process does not listen anymore.
    2431           0 :         (when remote-copy-program
    2432           0 :           (unless (with-tramp-connection-property
    2433           0 :                       v (concat "remote-copy-program-" remote-copy-program)
    2434           0 :                     (tramp-find-executable
    2435           0 :                      v remote-copy-program (tramp-get-remote-path v)))
    2436           0 :             (tramp-error
    2437           0 :              v 'file-error
    2438           0 :              "Cannot find remote listener: %s" remote-copy-program))
    2439           0 :           (setq remote-copy-program
    2440           0 :                 (mapconcat
    2441             :                  'identity
    2442           0 :                  (append
    2443           0 :                   (list remote-copy-program) remote-copy-args
    2444           0 :                   (list (if t1 (concat "<" source) (concat ">" target)) "&"))
    2445           0 :                  " "))
    2446           0 :           (tramp-send-command v remote-copy-program)
    2447           0 :           (with-timeout
    2448           0 :               (60 (tramp-error
    2449           0 :                    v 'file-error
    2450             :                    "Listener process not running on remote host: `%s'"
    2451           0 :                    remote-copy-program))
    2452           0 :             (tramp-send-command v (format "netstat -l | grep -q :%s" listener))
    2453           0 :             (while (not (tramp-send-command-and-check v nil))
    2454           0 :               (tramp-send-command
    2455           0 :                v (format "netstat -l | grep -q :%s" listener)))))
    2456             : 
    2457           0 :         (with-temp-buffer
    2458           0 :           (unwind-protect
    2459             :               ;; The default directory must be remote.
    2460           0 :               (let ((default-directory
    2461           0 :                       (file-name-directory (if t1 filename newname)))
    2462           0 :                     (process-environment (copy-sequence process-environment)))
    2463             :                 ;; Set the transfer process properties.
    2464           0 :                 (tramp-set-connection-property
    2465           0 :                  v "process-name" (buffer-name (current-buffer)))
    2466           0 :                 (tramp-set-connection-property
    2467           0 :                  v "process-buffer" (current-buffer))
    2468           0 :                 (while copy-env
    2469           0 :                   (tramp-message
    2470           0 :                    orig-vec 6 "%s=\"%s\"" (car copy-env) (cadr copy-env))
    2471           0 :                   (setenv (pop copy-env) (pop copy-env)))
    2472           0 :                 (setq
    2473             :                  copy-args
    2474           0 :                  (append
    2475           0 :                   copy-args
    2476           0 :                   (if remote-copy-program
    2477           0 :                       (list (if t1 (concat ">" target) (concat "<" source)))
    2478           0 :                     (list source target))))
    2479             : 
    2480             :                 ;; Use an asynchronous process.  By this, password can
    2481             :                 ;; be handled.  We don't set a timeout, because the
    2482             :                 ;; copying of large files can last longer than 60 secs.
    2483           0 :                 (let* ((command
    2484           0 :                         (mapconcat
    2485           0 :                          'identity (append (list copy-program) copy-args)
    2486           0 :                          " "))
    2487           0 :                        (p (let ((default-directory
    2488           0 :                                   (tramp-compat-temporary-file-directory)))
    2489           0 :                             (start-process-shell-command
    2490           0 :                              (tramp-get-connection-name v)
    2491           0 :                              (tramp-get-connection-buffer v)
    2492           0 :                              command))))
    2493           0 :                   (tramp-message orig-vec 6 "%s" command)
    2494           0 :                   (tramp-set-connection-property p "vector" orig-vec)
    2495           0 :                   (process-put p 'adjust-window-size-function 'ignore)
    2496           0 :                   (set-process-query-on-exit-flag p nil)
    2497             : 
    2498             :                   ;; We must adapt `tramp-local-end-of-line' for
    2499             :                   ;; sending the password.
    2500           0 :                   (let ((tramp-local-end-of-line tramp-rsh-end-of-line))
    2501           0 :                     (tramp-process-actions
    2502           0 :                      p v nil tramp-actions-copy-out-of-band))))
    2503             : 
    2504             :             ;; Reset the transfer process properties.
    2505           0 :             (tramp-set-connection-property v "process-name" nil)
    2506           0 :             (tramp-set-connection-property v "process-buffer" nil)
    2507             :             ;; Clear the remote prompt.
    2508           0 :             (when (and remote-copy-program
    2509           0 :                        (not (tramp-send-command-and-check v nil)))
    2510             :               ;; Houston, we have a problem!  Likely, the listener is
    2511             :               ;; still running, so let's clear everything (but the
    2512             :               ;; cached password).
    2513           0 :               (tramp-cleanup-connection v 'keep-debug 'keep-password))))
    2514             : 
    2515             :         ;; Handle KEEP-DATE argument.
    2516           0 :         (when (and keep-date (not copy-keep-date))
    2517           0 :           (set-file-times
    2518           0 :            newname
    2519           0 :            (tramp-compat-file-attribute-modification-time
    2520           0 :             (file-attributes filename))))
    2521             : 
    2522             :         ;; Set the mode.
    2523           0 :         (unless (and keep-date copy-keep-date)
    2524           0 :           (ignore-errors
    2525           0 :             (set-file-modes newname (tramp-default-file-modes filename)))))
    2526             : 
    2527             :       ;; If the operation was `rename', delete the original file.
    2528           0 :       (unless (eq op 'copy)
    2529           0 :         (if (file-regular-p filename)
    2530           0 :             (delete-file filename)
    2531           0 :           (delete-directory filename 'recursive))))))
    2532             : 
    2533             : (defun tramp-sh-handle-make-directory (dir &optional parents)
    2534             :   "Like `make-directory' for Tramp files."
    2535         132 :   (setq dir (expand-file-name dir))
    2536         132 :   (with-parsed-tramp-file-name dir nil
    2537         132 :     (tramp-flush-directory-property v (file-name-directory localname))
    2538         132 :     (save-excursion
    2539         132 :       (tramp-barf-unless-okay
    2540         132 :        v (format "%s %s"
    2541         132 :                  (if parents "mkdir -p" "mkdir")
    2542         132 :                  (tramp-shell-quote-argument localname))
    2543         132 :        "Couldn't make directory %s" dir))))
    2544             : 
    2545             : (defun tramp-sh-handle-delete-directory (directory &optional recursive trash)
    2546             :   "Like `delete-directory' for Tramp files."
    2547         124 :   (setq directory (expand-file-name directory))
    2548         124 :   (with-parsed-tramp-file-name directory nil
    2549         124 :     (tramp-flush-file-property v (file-name-directory localname))
    2550         124 :     (tramp-flush-directory-property v localname)
    2551         124 :     (tramp-barf-unless-okay
    2552         124 :      v (format "cd / && %s %s"
    2553         124 :                (or (and trash (tramp-get-remote-trash v))
    2554         124 :                    (if recursive "rm -rf" "rmdir"))
    2555         124 :                (tramp-shell-quote-argument localname))
    2556         124 :      "Couldn't delete %s" directory)))
    2557             : 
    2558             : (defun tramp-sh-handle-delete-file (filename &optional trash)
    2559             :   "Like `delete-file' for Tramp files."
    2560         378 :   (setq filename (expand-file-name filename))
    2561         378 :   (with-parsed-tramp-file-name filename nil
    2562         378 :     (tramp-flush-file-property v (file-name-directory localname))
    2563         378 :     (tramp-flush-file-property v localname)
    2564         378 :     (tramp-barf-unless-okay
    2565         378 :      v (format "%s %s"
    2566         378 :                (or (and trash (tramp-get-remote-trash v)) "rm -f")
    2567         378 :                (tramp-shell-quote-argument localname))
    2568         378 :      "Couldn't delete %s" filename)))
    2569             : 
    2570             : ;; Dired.
    2571             : 
    2572             : (defun tramp-sh-handle-dired-compress-file (file)
    2573             :   "Like `dired-compress-file' for Tramp files."
    2574             :   ;; Code stolen mainly from dired-aux.el.
    2575           0 :   (with-parsed-tramp-file-name file nil
    2576           0 :     (tramp-flush-file-property v localname)
    2577           0 :     (save-excursion
    2578           0 :       (let ((suffixes dired-compress-file-suffixes)
    2579             :             suffix)
    2580             :         ;; See if any suffix rule matches this file name.
    2581           0 :         (while suffixes
    2582           0 :           (let (case-fold-search)
    2583           0 :             (if (string-match (car (car suffixes)) localname)
    2584           0 :                 (setq suffix (car suffixes) suffixes nil))
    2585           0 :             (setq suffixes (cdr suffixes))))
    2586             : 
    2587           0 :         (cond ((file-symlink-p file)
    2588             :                nil)
    2589           0 :               ((and suffix (nth 2 suffix))
    2590             :                ;; We found an uncompression rule.
    2591           0 :                (with-tramp-progress-reporter
    2592           0 :                    v 0 (format "Uncompressing %s" file)
    2593           0 :                  (when (tramp-send-command-and-check
    2594           0 :                         v (concat (nth 2 suffix) " "
    2595           0 :                                   (tramp-shell-quote-argument localname)))
    2596           0 :                    (dired-remove-file file)
    2597           0 :                    (string-match (car suffix) file)
    2598           0 :                    (concat (substring file 0 (match-beginning 0))))))
    2599             :               (t
    2600             :                ;; We don't recognize the file as compressed, so compress it.
    2601             :                ;; Try gzip.
    2602           0 :                (with-tramp-progress-reporter v 0 (format "Compressing %s" file)
    2603           0 :                  (when (tramp-send-command-and-check
    2604           0 :                         v (concat "gzip -f "
    2605           0 :                                   (tramp-shell-quote-argument localname)))
    2606           0 :                    (dired-remove-file file)
    2607           0 :                    (cond ((file-exists-p (concat file ".gz"))
    2608           0 :                           (concat file ".gz"))
    2609           0 :                          ((file-exists-p (concat file ".z"))
    2610           0 :                           (concat file ".z"))
    2611           0 :                          (t nil))))))))))
    2612             : 
    2613             : (defun tramp-sh-handle-insert-directory
    2614             :   (filename switches &optional wildcard full-directory-p)
    2615             :   "Like `insert-directory' for Tramp files."
    2616          10 :   (setq filename (expand-file-name filename))
    2617          10 :   (unless switches (setq switches ""))
    2618          10 :   (with-parsed-tramp-file-name filename nil
    2619          10 :     (if (and (featurep 'ls-lisp)
    2620          10 :              (not (symbol-value 'ls-lisp-use-insert-directory-program)))
    2621           0 :         (tramp-handle-insert-directory
    2622           0 :          filename switches wildcard full-directory-p)
    2623          10 :       (when (stringp switches)
    2624          10 :         (setq switches (split-string switches)))
    2625          10 :       (when (tramp-get-ls-command-with-quoting-style v)
    2626          10 :         (setq switches (append switches '("--quoting-style=literal"))))
    2627          10 :       (when (and (member "--dired" switches)
    2628          10 :                  (not (tramp-get-ls-command-with-dired v)))
    2629          10 :         (setq switches (delete "--dired" switches)))
    2630          10 :       (when wildcard
    2631           2 :         (setq wildcard (tramp-run-real-handler
    2632           2 :                         'file-name-nondirectory (list localname)))
    2633           2 :         (setq localname (tramp-run-real-handler
    2634          10 :                          'file-name-directory (list localname))))
    2635          10 :       (unless (or full-directory-p (member "-d" switches))
    2636          10 :         (setq switches (append switches '("-d"))))
    2637          10 :       (setq switches (mapconcat 'tramp-shell-quote-argument switches " "))
    2638          10 :       (when wildcard
    2639          10 :         (setq switches (concat switches " " wildcard)))
    2640          10 :       (tramp-message
    2641          10 :        v 4 "Inserting directory `ls %s %s', wildcard %s, fulldir %s"
    2642          10 :        switches filename (if wildcard "yes" "no")
    2643          10 :        (if full-directory-p "yes" "no"))
    2644             :       ;; If `full-directory-p', we just say `ls -l FILENAME'.
    2645             :       ;; Else we chdir to the parent directory, then say `ls -ld BASENAME'.
    2646          10 :       (if full-directory-p
    2647           2 :           (tramp-send-command
    2648           2 :            v
    2649           2 :            (format "%s %s %s 2>/dev/null"
    2650           2 :                    (tramp-get-ls-command v)
    2651           2 :                    switches
    2652           2 :                    (if wildcard
    2653           0 :                        localname
    2654           2 :                      (tramp-shell-quote-argument (concat localname ".")))))
    2655           8 :         (tramp-barf-unless-okay
    2656           8 :          v
    2657           8 :          (format "cd %s" (tramp-shell-quote-argument
    2658           8 :                           (tramp-run-real-handler
    2659           8 :                            'file-name-directory (list localname))))
    2660             :          "Couldn't `cd %s'"
    2661           8 :          (tramp-shell-quote-argument
    2662           8 :           (tramp-run-real-handler 'file-name-directory (list localname))))
    2663           8 :         (tramp-send-command
    2664           8 :          v
    2665           8 :          (format "%s %s %s 2>/dev/null"
    2666           8 :                  (tramp-get-ls-command v)
    2667           8 :                  switches
    2668           8 :                  (if (or wildcard
    2669           6 :                          (zerop (length
    2670           6 :                                  (tramp-run-real-handler
    2671           8 :                                   'file-name-nondirectory (list localname)))))
    2672             :                      ""
    2673           4 :                    (tramp-shell-quote-argument
    2674           4 :                     (tramp-run-real-handler
    2675          10 :                      'file-name-nondirectory (list localname)))))))
    2676             : 
    2677          10 :       (save-restriction
    2678          10 :         (let ((beg (point)))
    2679          10 :           (narrow-to-region (point) (point))
    2680             :           ;; We cannot use `insert-buffer-substring' because the Tramp
    2681             :           ;; buffer changes its contents before insertion due to calling
    2682             :           ;; `expand-file-name' and alike.
    2683          10 :           (insert
    2684          10 :            (with-current-buffer (tramp-get-buffer v)
    2685          10 :              (buffer-string)))
    2686             : 
    2687             :           ;; Check for "--dired" output.
    2688          10 :           (forward-line -2)
    2689          10 :           (when (looking-at "//SUBDIRED//")
    2690          10 :             (forward-line -1))
    2691          10 :           (when (looking-at "//DIRED//\\s-+")
    2692           2 :             (let ((databeg (match-end 0))
    2693           2 :                   (end (point-at-eol)))
    2694             :               ;; Now read the numeric positions of file names.
    2695           2 :               (goto-char databeg)
    2696          16 :               (while (< (point) end)
    2697          14 :                 (let ((start (+ beg (read (current-buffer))))
    2698          14 :                       (end (+ beg (read (current-buffer)))))
    2699          14 :                   (if (memq (char-after end) '(?\n ?\ ))
    2700             :                       ;; End is followed by \n or by " -> ".
    2701          14 :                       (put-text-property start end 'dired-filename t))))))
    2702             :           ;; Remove trailing lines.
    2703          10 :           (goto-char (point-at-bol))
    2704          14 :           (while (looking-at "//")
    2705           4 :             (forward-line 1)
    2706          10 :             (delete-region (match-beginning 0) (point)))
    2707             : 
    2708             :           ;; Some busyboxes are reluctant to discard colors.
    2709          10 :           (unless
    2710          10 :               (string-match "color" (tramp-get-connection-property v "ls" ""))
    2711           0 :             (goto-char beg)
    2712           0 :             (while
    2713           0 :                 (re-search-forward tramp-display-escape-sequence-regexp nil t)
    2714          10 :               (replace-match "")))
    2715             : 
    2716             :           ;; Decode the output, it could be multibyte.
    2717          10 :           (decode-coding-region
    2718          10 :            beg (point-max)
    2719          10 :            (or file-name-coding-system default-file-name-coding-system))
    2720             : 
    2721             :           ;; The inserted file could be from somewhere else.
    2722          10 :           (when (and (not wildcard) (not full-directory-p))
    2723           6 :             (goto-char (point-max))
    2724           6 :             (when (file-symlink-p filename)
    2725           6 :               (goto-char (search-backward "->" beg 'noerror)))
    2726           6 :             (search-backward
    2727           6 :              (if (zerop (length (file-name-nondirectory filename)))
    2728             :                  "."
    2729           6 :                (file-name-nondirectory filename))
    2730           6 :              beg 'noerror)
    2731          10 :             (replace-match (file-relative-name filename) t))
    2732             : 
    2733          10 :           (goto-char (point-max)))))))
    2734             : 
    2735             : ;; Canonicalization of file names.
    2736             : 
    2737             : (defun tramp-sh-handle-expand-file-name (name &optional dir)
    2738             :   "Like `expand-file-name' for Tramp files.
    2739             : If the localname part of the given file name starts with \"/../\" then
    2740             : the result will be a local, non-Tramp, file name."
    2741             :   ;; If DIR is not given, use `default-directory' or "/".
    2742       24378 :   (setq dir (or dir default-directory "/"))
    2743             :   ;; Unless NAME is absolute, concat DIR and NAME.
    2744       24378 :   (unless (file-name-absolute-p name)
    2745       24378 :     (setq name (concat (file-name-as-directory dir) name)))
    2746             :   ;; If connection is not established yet, run the real handler.
    2747       24378 :   (if (not (tramp-connectable-p name))
    2748         240 :       (tramp-run-real-handler 'expand-file-name (list name nil))
    2749             :     ;; Dissect NAME.
    2750       24138 :     (with-parsed-tramp-file-name name nil
    2751       24138 :       (unless (tramp-run-real-handler 'file-name-absolute-p (list localname))
    2752       24138 :         (setq localname (concat "~/" localname)))
    2753             :       ;; Tilde expansion if necessary.  This needs a shell which
    2754             :       ;; groks tilde expansion!  The function `tramp-find-shell' is
    2755             :       ;; supposed to find such a shell on the remote host.  Please
    2756             :       ;; tell me about it when this doesn't work on your system.
    2757       24138 :       (when (string-match "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname)
    2758           1 :         (let ((uname (match-string 1 localname))
    2759           1 :               (fname (match-string 2 localname)))
    2760             :           ;; We cannot simply apply "~/", because under sudo "~/" is
    2761             :           ;; expanded to the local user home directory but to the
    2762             :           ;; root home directory.  On the other hand, using always
    2763             :           ;; the default user name for tilde expansion is not
    2764             :           ;; appropriate either, because ssh and companions might
    2765             :           ;; use a user name from the config file.
    2766           1 :           (when (and (string-equal uname "~")
    2767           1 :                      (string-match "\\`su\\(do\\)?\\'" method))
    2768           1 :             (setq uname (concat uname user)))
    2769           1 :           (setq uname
    2770           2 :                 (with-tramp-connection-property v uname
    2771           1 :                   (tramp-send-command
    2772           1 :                    v (format "cd %s && pwd" (tramp-shell-quote-argument uname)))
    2773           1 :                   (with-current-buffer (tramp-get-buffer v)
    2774           1 :                     (goto-char (point-min))
    2775           1 :                     (buffer-substring (point) (point-at-eol)))))
    2776       24138 :           (setq localname (concat uname fname))))
    2777             :       ;; There might be a double slash, for example when "~/"
    2778             :       ;; expands to "/".  Remove this.
    2779       24138 :       (while (string-match "//" localname)
    2780       24138 :         (setq localname (replace-match "/" t t localname)))
    2781             :       ;; No tilde characters in file name, do normal
    2782             :       ;; `expand-file-name' (this does "/./" and "/../").
    2783             :       ;; `default-directory' is bound, because on Windows there would
    2784             :       ;; be problems with UNC shares or Cygwin mounts.
    2785       24138 :       (let ((default-directory (tramp-compat-temporary-file-directory)))
    2786       24138 :         (tramp-make-tramp-file-name
    2787       24138 :          method user domain host port
    2788       24138 :          (tramp-drop-volume-letter
    2789       24138 :           (tramp-run-real-handler
    2790       24138 :            'expand-file-name (list localname)))
    2791       24378 :          hop)))))
    2792             : 
    2793             : ;;; Remote commands:
    2794             : 
    2795             : (defun tramp-process-sentinel (proc event)
    2796             :   "Flush file caches."
    2797          51 :   (unless (process-live-p proc)
    2798          51 :     (let ((vec (tramp-get-connection-property proc "vector" nil)))
    2799          51 :       (when vec
    2800           0 :         (tramp-message vec 5 "Sentinel called: `%S' `%s'" proc event)
    2801           0 :         (tramp-flush-connection-property proc)
    2802          51 :         (tramp-flush-directory-property vec "")))))
    2803             : 
    2804             : ;; We use BUFFER also as connection buffer during setup. Because of
    2805             : ;; this, its original contents must be saved, and restored once
    2806             : ;; connection has been setup.
    2807             : (defun tramp-sh-handle-start-file-process (name buffer program &rest args)
    2808             :   "Like `start-file-process' for Tramp files."
    2809          27 :   (with-parsed-tramp-file-name (expand-file-name default-directory) nil
    2810          27 :     (let* ((buffer
    2811          27 :             (if buffer
    2812          27 :                 (get-buffer-create buffer)
    2813             :               ;; BUFFER can be nil.  We use a temporary buffer.
    2814          27 :               (generate-new-buffer tramp-temp-buffer-name)))
    2815             :            ;; When PROGRAM matches "*sh", and the first arg is "-c",
    2816             :            ;; it might be that the arguments exceed the command line
    2817             :            ;; length.  Therefore, we modify the command.
    2818          27 :            (heredoc (and (stringp program)
    2819          27 :                          (string-match "sh$" program)
    2820          21 :                          (string-equal "-c" (car args))
    2821          27 :                          (= (length args) 2)))
    2822             :            ;; When PROGRAM is nil, we just provide a tty.
    2823          27 :            (args (if (not heredoc) args
    2824          20 :                    (let ((i 250))
    2825          20 :                      (while (and (< i (length (cadr args)))
    2826          20 :                                  (string-match " " (cadr args) i))
    2827           0 :                        (setcdr
    2828           0 :                         args
    2829           0 :                         (list (replace-match " \\\\\n" nil nil (cadr args))))
    2830          20 :                        (setq i (+ i 250))))
    2831          27 :                    (cdr args)))
    2832             :            ;; Use a human-friendly prompt, for example for `shell'.
    2833             :            ;; We discard hops, if existing, that's why we cannot use
    2834             :            ;; `file-remote-p'.
    2835          27 :            (prompt (format "PS1=%s %s"
    2836          27 :                            (tramp-make-tramp-file-name
    2837          27 :                             (tramp-file-name-method v)
    2838          27 :                             (tramp-file-name-user v)
    2839          27 :                             (tramp-file-name-domain v)
    2840          27 :                             (tramp-file-name-host v)
    2841          27 :                             (tramp-file-name-port v)
    2842          27 :                             (tramp-file-name-localname v))
    2843          27 :                            tramp-initial-end-of-output))
    2844             :            ;; We use as environment the difference to toplevel
    2845             :            ;; `process-environment'.
    2846             :            env uenv
    2847          27 :            (env (dolist (elt (cons prompt process-environment) env)
    2848        2871 :                   (or (member elt (default-toplevel-value 'process-environment))
    2849          36 :                       (if (string-match "=" elt)
    2850          34 :                           (setq env (append env `(,elt)))
    2851           2 :                         (if (tramp-get-env-with-u-option v)
    2852           2 :                             (setq env (append `("-u" ,elt) env))
    2853        2871 :                           (setq uenv (cons elt uenv)))))))
    2854             :            (command
    2855          27 :             (when (stringp program)
    2856          27 :               (format "cd %s && %s exec %s env %s %s"
    2857          27 :                       (tramp-shell-quote-argument localname)
    2858          27 :                       (if uenv
    2859           0 :                           (format
    2860             :                            "unset %s &&"
    2861           0 :                            (mapconcat 'tramp-shell-quote-argument uenv " "))
    2862          27 :                         "")
    2863          27 :                       (if heredoc (format "<<'%s'" tramp-end-of-heredoc) "")
    2864          27 :                       (mapconcat 'tramp-shell-quote-argument env " ")
    2865          27 :                       (if heredoc
    2866          20 :                           (format "%s\n(\n%s\n) </dev/tty\n%s"
    2867          20 :                                   program (car args) tramp-end-of-heredoc)
    2868           7 :                         (mapconcat 'tramp-shell-quote-argument
    2869          27 :                                    (cons program args) " ")))))
    2870             :            (tramp-process-connection-type
    2871          27 :             (or (null program) tramp-process-connection-type))
    2872          27 :            (bmp (and (buffer-live-p buffer) (buffer-modified-p buffer)))
    2873          27 :            (name1 name)
    2874             :            (i 0)
    2875             :            ;; We do not want to raise an error when
    2876             :            ;; `start-file-process' has been started several times in
    2877             :            ;; `eshell' and friends.
    2878             :            (tramp-current-connection nil))
    2879             : 
    2880          27 :       (while (get-process name1)
    2881             :         ;; NAME must be unique as process name.
    2882           0 :         (setq i (1+ i)
    2883          27 :               name1 (format "%s<%d>" name i)))
    2884          27 :       (setq name name1)
    2885             :       ;; Set the new process properties.
    2886          27 :       (tramp-set-connection-property v "process-name" name)
    2887          27 :       (tramp-set-connection-property v "process-buffer" buffer)
    2888             : 
    2889          27 :       (with-current-buffer (tramp-get-connection-buffer v)
    2890          27 :         (unwind-protect
    2891             :             ;; We catch this event.  Otherwise, `start-process' could
    2892             :             ;; be called on the local host.
    2893          27 :             (save-excursion
    2894          27 :               (save-restriction
    2895             :                 ;; Activate narrowing in order to save BUFFER
    2896             :                 ;; contents.  Clear also the modification time;
    2897             :                 ;; otherwise we might be interrupted by
    2898             :                 ;; `verify-visited-file-modtime'.
    2899          27 :                 (let ((buffer-undo-list t)
    2900             :                       (buffer-read-only nil)
    2901          27 :                       (mark (point-max)))
    2902          27 :                   (clear-visited-file-modtime)
    2903          27 :                   (narrow-to-region (point-max) (point-max))
    2904             :                   ;; We call `tramp-maybe-open-connection', in order
    2905             :                   ;; to cleanup the prompt afterwards.
    2906          27 :                   (catch 'suppress
    2907          27 :                     (tramp-maybe-open-connection v)
    2908          27 :                     (widen)
    2909          27 :                     (delete-region mark (point))
    2910          27 :                     (narrow-to-region (point-max) (point-max))
    2911             :                     ;; Now do it.
    2912          27 :                     (if command
    2913             :                         ;; Send the command.
    2914          27 :                         (tramp-send-command v command nil t) ; nooutput
    2915             :                       ;; Check, whether a pty is associated.
    2916           0 :                       (unless (process-get
    2917           0 :                                (tramp-get-connection-process v) 'remote-tty)
    2918           0 :                         (tramp-error
    2919           0 :                          v 'file-error
    2920          27 :                          "pty association is not supported for `%s'" name))))
    2921          27 :                   (let ((p (tramp-get-connection-process v)))
    2922             :                     ;; Set query flag and process marker for this
    2923             :                     ;; process.  We ignore errors, because the process
    2924             :                     ;; could have finished already.
    2925          27 :                     (ignore-errors
    2926          27 :                       (set-process-query-on-exit-flag p t)
    2927          27 :                       (set-marker (process-mark p) (point)))
    2928             :                     ;; Return process.
    2929          27 :                     p))))
    2930             : 
    2931             :           ;; Save exit.
    2932          27 :           (if (string-match tramp-temp-buffer-name (buffer-name))
    2933           0 :               (ignore-errors
    2934           0 :                 (set-process-buffer (tramp-get-connection-process v) nil)
    2935           0 :                 (kill-buffer (current-buffer)))
    2936          27 :             (set-buffer-modified-p bmp))
    2937          27 :           (tramp-set-connection-property v "process-name" nil)
    2938          27 :           (tramp-set-connection-property v "process-buffer" nil))))))
    2939             : 
    2940             : (defun tramp-sh-handle-process-file
    2941             :   (program &optional infile destination display &rest args)
    2942             :   "Like `process-file' for Tramp files."
    2943             :   ;; The implementation is not complete yet.
    2944         102 :   (when (and (numberp destination) (zerop destination))
    2945         102 :     (error "Implementation does not handle immediate return"))
    2946             : 
    2947         102 :   (with-parsed-tramp-file-name default-directory nil
    2948         102 :     (let (command env uenv input tmpinput stderr tmpstderr outbuf ret)
    2949             :       ;; Compute command.
    2950         102 :       (setq command (mapconcat 'tramp-shell-quote-argument
    2951         102 :                                (cons program args) " "))
    2952             :       ;; We use as environment the difference to toplevel `process-environment'.
    2953         102 :       (dolist (elt process-environment)
    2954       10867 :         (or (member elt (default-toplevel-value 'process-environment))
    2955         157 :             (if (string-match "=" elt)
    2956          79 :                 (setq env (append env `(,elt)))
    2957          78 :               (if (tramp-get-env-with-u-option v)
    2958          78 :                   (setq env (append `("-u" ,elt) env))
    2959       10867 :                 (setq uenv (cons elt uenv))))))
    2960         102 :       (when env
    2961          81 :         (setq command
    2962          81 :               (format
    2963             :                "env %s %s"
    2964         102 :                (mapconcat 'tramp-shell-quote-argument env " ") command)))
    2965         102 :       (when uenv
    2966           0 :         (setq command
    2967           0 :               (format
    2968             :                "unset %s && %s"
    2969         102 :                (mapconcat 'tramp-shell-quote-argument uenv " ") command)))
    2970             :       ;; Determine input.
    2971         102 :       (if (null infile)
    2972         102 :           (setq input "/dev/null")
    2973           0 :         (setq infile (expand-file-name infile))
    2974           0 :         (if (tramp-equal-remote default-directory infile)
    2975             :             ;; INFILE is on the same remote host.
    2976           0 :             (setq input (with-parsed-tramp-file-name infile nil localname))
    2977             :           ;; INFILE must be copied to remote host.
    2978           0 :           (setq input (tramp-make-tramp-temp-file v)
    2979             :                 tmpinput
    2980           0 :                 (tramp-make-tramp-file-name method user domain host port input))
    2981         102 :           (copy-file infile tmpinput t)))
    2982         102 :       (when input (setq command (format "%s <%s" command input)))
    2983             : 
    2984             :       ;; Determine output.
    2985         102 :       (cond
    2986             :        ;; Just a buffer.
    2987         102 :        ((bufferp destination)
    2988           8 :         (setq outbuf destination))
    2989             :        ;; A buffer name.
    2990          94 :        ((stringp destination)
    2991           0 :         (setq outbuf (get-buffer-create destination)))
    2992             :        ;; (REAL-DESTINATION ERROR-DESTINATION)
    2993          94 :        ((consp destination)
    2994             :         ;; output.
    2995           0 :         (cond
    2996           0 :          ((bufferp (car destination))
    2997           0 :           (setq outbuf (car destination)))
    2998           0 :          ((stringp (car destination))
    2999           0 :           (setq outbuf (get-buffer-create (car destination))))
    3000           0 :          ((car destination)
    3001           0 :           (setq outbuf (current-buffer))))
    3002             :         ;; stderr.
    3003           0 :         (cond
    3004           0 :          ((stringp (cadr destination))
    3005           0 :           (setcar (cdr destination) (expand-file-name (cadr destination)))
    3006           0 :           (if (tramp-equal-remote default-directory (cadr destination))
    3007             :               ;; stderr is on the same remote host.
    3008           0 :               (setq stderr (with-parsed-tramp-file-name
    3009           0 :                                (cadr destination) nil localname))
    3010             :             ;; stderr must be copied to remote host.  The temporary
    3011             :             ;; file must be deleted after execution.
    3012           0 :             (setq stderr (tramp-make-tramp-temp-file v)
    3013           0 :                   tmpstderr (tramp-make-tramp-file-name
    3014           0 :                              method user domain host port stderr))))
    3015             :          ;; stderr to be discarded.
    3016           0 :          ((null (cadr destination))
    3017           0 :           (setq stderr "/dev/null"))))
    3018             :        ;; 't
    3019          94 :        (destination
    3020         102 :         (setq outbuf (current-buffer))))
    3021         102 :       (when stderr (setq command (format "%s 2>%s" command stderr)))
    3022             : 
    3023             :       ;; Send the command.  It might not return in time, so we protect
    3024             :       ;; it.  Call it in a subshell, in order to preserve working
    3025             :       ;; directory.
    3026         102 :       (condition-case nil
    3027         102 :           (unwind-protect
    3028         102 :               (setq ret
    3029         102 :                     (if (tramp-send-command-and-check
    3030         102 :                          v (format "cd %s && %s"
    3031         102 :                                    (tramp-shell-quote-argument localname)
    3032         102 :                                    command)
    3033         102 :                          t t)
    3034         102 :                         0 1))
    3035             :             ;; We should add the output anyway.
    3036         102 :             (when outbuf
    3037          96 :               (with-current-buffer outbuf
    3038          96 :                 (insert
    3039          96 :                  (with-current-buffer (tramp-get-connection-buffer v)
    3040          96 :                    (buffer-string))))
    3041         102 :               (when (and display (get-buffer-window outbuf t)) (redisplay))))
    3042             :         ;; When the user did interrupt, we should do it also.  We use
    3043             :         ;; return code -1 as marker.
    3044             :         (quit
    3045           0 :          (kill-buffer (tramp-get-connection-buffer v))
    3046           0 :          (setq ret -1))
    3047             :         ;; Handle errors.
    3048             :         (error
    3049           0 :          (kill-buffer (tramp-get-connection-buffer v))
    3050         102 :          (setq ret 1)))
    3051             : 
    3052             :       ;; Provide error file.
    3053         102 :       (when tmpstderr (rename-file tmpstderr (cadr destination) t))
    3054             : 
    3055             :       ;; Cleanup.  We remove all file cache values for the connection,
    3056             :       ;; because the remote process could have changed them.
    3057         102 :       (when tmpinput (delete-file tmpinput))
    3058             : 
    3059         102 :       (unless process-file-side-effects
    3060         102 :         (tramp-flush-directory-property v ""))
    3061             : 
    3062             :       ;; Return exit status.
    3063         102 :       (if (equal ret -1)
    3064           0 :           (keyboard-quit)
    3065         102 :         ret))))
    3066             : 
    3067             : (defun tramp-sh-handle-file-local-copy (filename)
    3068             :   "Like `file-local-copy' for Tramp files."
    3069         270 :   (with-parsed-tramp-file-name filename nil
    3070         270 :     (unless (file-exists-p filename)
    3071           0 :       (tramp-error
    3072           0 :        v tramp-file-missing
    3073         270 :        "Cannot make local copy of non-existing file `%s'" filename))
    3074             : 
    3075         270 :     (let* ((size (tramp-compat-file-attribute-size
    3076         270 :                   (file-attributes (file-truename filename))))
    3077         270 :            (rem-enc (tramp-get-inline-coding v "remote-encoding" size))
    3078         270 :            (loc-dec (tramp-get-inline-coding v "local-decoding" size))
    3079         270 :            (tmpfile (tramp-compat-make-temp-file filename)))
    3080             : 
    3081         270 :       (condition-case err
    3082         270 :           (cond
    3083             :            ;; `copy-file' handles direct copy and out-of-band methods.
    3084         270 :            ((or (tramp-local-host-p v)
    3085         270 :                 (tramp-method-out-of-band-p v size))
    3086           0 :             (copy-file filename tmpfile 'ok-if-already-exists 'keep-time))
    3087             : 
    3088             :            ;; Use inline encoding for file transfer.
    3089         270 :            (rem-enc
    3090         270 :             (save-excursion
    3091         270 :               (with-tramp-progress-reporter
    3092         540 :                v 3
    3093         540 :                (format-message "Encoding remote file `%s' with `%s'"
    3094         540 :                                filename rem-enc)
    3095         270 :                (tramp-barf-unless-okay
    3096         270 :                 v (format rem-enc (tramp-shell-quote-argument localname))
    3097         270 :                 "Encoding remote file failed"))
    3098             : 
    3099         270 :               (with-tramp-progress-reporter
    3100         540 :                   v 3 (format-message "Decoding local file `%s' with `%s'"
    3101         540 :                                       tmpfile loc-dec)
    3102         270 :                 (if (functionp loc-dec)
    3103             :                     ;; If local decoding is a function, we call it.
    3104             :                     ;; We must disable multibyte, because
    3105             :                     ;; `uudecode-decode-region' doesn't handle it
    3106             :                     ;; correctly.  Unset `file-name-handler-alist'.
    3107             :                     ;; Otherwise, epa-file gets confused.
    3108         270 :                     (let (file-name-handler-alist
    3109             :                           (coding-system-for-write 'binary))
    3110         270 :                       (with-temp-file tmpfile
    3111         270 :                         (set-buffer-multibyte nil)
    3112         270 :                         (insert-buffer-substring (tramp-get-buffer v))
    3113         270 :                         (funcall loc-dec (point-min) (point-max))))
    3114             : 
    3115             :                   ;; If tramp-decoding-function is not defined for this
    3116             :                   ;; method, we invoke tramp-decoding-command instead.
    3117           0 :                   (let ((tmpfile2 (tramp-compat-make-temp-file filename)))
    3118             :                     ;; Unset `file-name-handler-alist'.  Otherwise,
    3119             :                     ;; epa-file gets confused.
    3120           0 :                     (let (file-name-handler-alist
    3121             :                           (coding-system-for-write 'binary))
    3122           0 :                       (with-current-buffer (tramp-get-buffer v)
    3123           0 :                         (write-region
    3124           0 :                          (point-min) (point-max) tmpfile2 nil 'no-message)))
    3125           0 :                     (unwind-protect
    3126           0 :                         (tramp-call-local-coding-command
    3127           0 :                          loc-dec tmpfile2 tmpfile)
    3128         270 :                       (delete-file tmpfile2)))))
    3129             : 
    3130             :               ;; Set proper permissions.
    3131         270 :               (set-file-modes tmpfile (tramp-default-file-modes filename))
    3132             :               ;; Set local user ownership.
    3133         270 :               (tramp-set-file-uid-gid tmpfile)))
    3134             : 
    3135             :            ;; Oops, I don't know what to do.
    3136           0 :            (t (tramp-error
    3137         270 :                v 'file-error "Wrong method specification for `%s'" method)))
    3138             : 
    3139             :         ;; Error handling.
    3140             :         ((error quit)
    3141           0 :          (delete-file tmpfile)
    3142         270 :          (signal (car err) (cdr err))))
    3143             : 
    3144         270 :       (run-hooks 'tramp-handle-file-local-copy-hook)
    3145         270 :       tmpfile)))
    3146             : 
    3147             : ;; CCC grok LOCKNAME
    3148             : (defun tramp-sh-handle-write-region
    3149             :   (start end filename &optional append visit lockname mustbenew)
    3150             :   "Like `write-region' for Tramp files."
    3151         409 :   (setq filename (expand-file-name filename))
    3152         409 :   (with-parsed-tramp-file-name filename nil
    3153         409 :     (when (and mustbenew (file-exists-p filename)
    3154           6 :                (or (eq mustbenew 'excl)
    3155           4 :                    (not
    3156           4 :                     (y-or-n-p
    3157         409 :                      (format "File %s exists; overwrite anyway? " filename)))))
    3158         405 :       (tramp-error v 'file-already-exists filename))
    3159             : 
    3160         405 :     (let ((uid (or (tramp-compat-file-attribute-user-id
    3161         405 :                     (file-attributes filename 'integer))
    3162         405 :                    (tramp-get-remote-uid v 'integer)))
    3163         405 :           (gid (or (tramp-compat-file-attribute-group-id
    3164         405 :                     (file-attributes filename 'integer))
    3165         405 :                    (tramp-get-remote-gid v 'integer))))
    3166             : 
    3167         405 :       (if (and (tramp-local-host-p v)
    3168             :                ;; `file-writable-p' calls `file-expand-file-name'.  We
    3169             :                ;; cannot use `tramp-run-real-handler' therefore.
    3170           0 :                (let (file-name-handler-alist)
    3171           0 :                  (and
    3172           0 :                   (file-writable-p (file-name-directory localname))
    3173           0 :                   (or (file-directory-p localname)
    3174         405 :                       (file-writable-p localname)))))
    3175             :           ;; Short track: if we are on the local host, we can run directly.
    3176           0 :           (tramp-run-real-handler
    3177           0 :            'write-region (list start end localname append 'no-message lockname))
    3178             : 
    3179         405 :         (let* ((modes (save-excursion (tramp-default-file-modes filename)))
    3180             :                ;; We use this to save the value of
    3181             :                ;; `last-coding-system-used' after writing the tmp
    3182             :                ;; file.  At the end of the function, we set
    3183             :                ;; `last-coding-system-used' to this saved value.  This
    3184             :                ;; way, any intermediary coding systems used while
    3185             :                ;; talking to the remote shell or suchlike won't hose
    3186             :                ;; this variable.  This approach was snarfed from
    3187             :                ;; ange-ftp.el.
    3188             :                coding-system-used
    3189             :                ;; Write region into a tmp file.  This isn't really
    3190             :                ;; needed if we use an encoding function, but currently
    3191             :                ;; we use it always because this makes the logic
    3192             :                ;; simpler.  We must also set `temporary-file-directory',
    3193             :                ;; because it could point to a remote directory.
    3194             :                (temporary-file-directory
    3195         405 :                 (tramp-compat-temporary-file-directory))
    3196         405 :                (tmpfile (or tramp-temp-buffer-file-name
    3197         405 :                             (tramp-compat-make-temp-file filename))))
    3198             : 
    3199             :           ;; If `append' is non-nil, we copy the file locally, and let
    3200             :           ;; the native `write-region' implementation do the job.
    3201         405 :           (when append (copy-file filename tmpfile 'ok))
    3202             : 
    3203             :           ;; We say `no-message' here because we don't want the
    3204             :           ;; visited file modtime data to be clobbered from the temp
    3205             :           ;; file.  We call `set-visited-file-modtime' ourselves later
    3206             :           ;; on.  We must ensure that `file-coding-system-alist'
    3207             :           ;; matches `tmpfile'.
    3208         405 :           (let (file-name-handler-alist
    3209             :                 (file-coding-system-alist
    3210         405 :                  (tramp-find-file-name-coding-system-alist filename tmpfile)))
    3211         405 :             (condition-case err
    3212         405 :                 (tramp-run-real-handler
    3213             :                  'write-region
    3214         405 :                  (list start end tmpfile append 'no-message lockname))
    3215             :               ((error quit)
    3216           0 :                (setq tramp-temp-buffer-file-name nil)
    3217           0 :                (delete-file tmpfile)
    3218         405 :                (signal (car err) (cdr err))))
    3219             : 
    3220             :             ;; Now, `last-coding-system-used' has the right value.  Remember it.
    3221         405 :             (setq coding-system-used last-coding-system-used))
    3222             : 
    3223             :           ;; The permissions of the temporary file should be set.  If
    3224             :           ;; FILENAME does not exist (eq modes nil) it has been
    3225             :           ;; renamed to the backup file.  This case `save-buffer'
    3226             :           ;; handles permissions.
    3227             :           ;; Ensure that it is still readable.
    3228         405 :           (when modes
    3229         405 :             (set-file-modes
    3230         405 :              tmpfile
    3231         405 :              (logior (or modes 0) (string-to-number "0400" 8))))
    3232             : 
    3233             :           ;; This is a bit lengthy due to the different methods
    3234             :           ;; possible for file transfer.  First, we check whether the
    3235             :           ;; method uses an scp program.  If so, we call it.
    3236             :           ;; Otherwise, both encoding and decoding command must be
    3237             :           ;; specified.  However, if the method _also_ specifies an
    3238             :           ;; encoding function, then that is used for encoding the
    3239             :           ;; contents of the tmp file.
    3240         405 :           (let* ((size (tramp-compat-file-attribute-size
    3241         405 :                         (file-attributes tmpfile)))
    3242         405 :                  (rem-dec (tramp-get-inline-coding v "remote-decoding" size))
    3243         405 :                  (loc-enc (tramp-get-inline-coding v "local-encoding" size)))
    3244         405 :             (cond
    3245             :              ;; `copy-file' handles direct copy and out-of-band methods.
    3246         405 :              ((or (tramp-local-host-p v)
    3247         405 :                   (tramp-method-out-of-band-p v size))
    3248           0 :               (if (and (not (stringp start))
    3249           0 :                        (= (or end (point-max)) (point-max))
    3250           0 :                        (= (or start (point-min)) (point-min))
    3251           0 :                        (tramp-get-method-parameter v 'tramp-copy-keep-tmpfile))
    3252           0 :                   (progn
    3253           0 :                     (setq tramp-temp-buffer-file-name tmpfile)
    3254           0 :                     (condition-case err
    3255             :                         ;; We keep the local file for performance
    3256             :                         ;; reasons, useful for "rsync".
    3257           0 :                         (copy-file tmpfile filename t)
    3258             :                       ((error quit)
    3259           0 :                        (setq tramp-temp-buffer-file-name nil)
    3260           0 :                        (delete-file tmpfile)
    3261           0 :                        (signal (car err) (cdr err)))))
    3262           0 :                 (setq tramp-temp-buffer-file-name nil)
    3263             :                 ;; Don't rename, in order to keep context in SELinux.
    3264           0 :                 (unwind-protect
    3265           0 :                     (copy-file tmpfile filename t)
    3266           0 :                   (delete-file tmpfile))))
    3267             : 
    3268             :              ;; Use inline file transfer.
    3269         405 :              (rem-dec
    3270             :               ;; Encode tmpfile.
    3271         405 :               (unwind-protect
    3272         405 :                   (with-temp-buffer
    3273         405 :                     (set-buffer-multibyte nil)
    3274             :                     ;; Use encoding function or command.
    3275         405 :                     (with-tramp-progress-reporter
    3276         810 :                         v 3 (format-message
    3277             :                              "Encoding local file `%s' using `%s'"
    3278         810 :                              tmpfile loc-enc)
    3279         405 :                       (if (functionp loc-enc)
    3280             :                           ;; The following `let' is a workaround for
    3281             :                           ;; the base64.el that comes with pgnus-0.84.
    3282             :                           ;; If both of the following conditions are
    3283             :                           ;; satisfied, it tries to write to a local
    3284             :                           ;; file in default-directory, but at this
    3285             :                           ;; point, default-directory is remote.
    3286             :                           ;; (`call-process-region' can't write to
    3287             :                           ;; remote files, it seems.)  The file in
    3288             :                           ;; question is a tmp file anyway.
    3289         405 :                           (let ((coding-system-for-read 'binary)
    3290             :                                 (default-directory
    3291         405 :                                   (tramp-compat-temporary-file-directory)))
    3292         405 :                             (insert-file-contents-literally tmpfile)
    3293         405 :                             (funcall loc-enc (point-min) (point-max)))
    3294             : 
    3295           0 :                         (unless (zerop (tramp-call-local-coding-command
    3296           0 :                                         loc-enc tmpfile t))
    3297           0 :                           (tramp-error
    3298           0 :                            v 'file-error
    3299           0 :                            (concat "Cannot write to `%s', "
    3300           0 :                                    "local encoding command `%s' failed")
    3301         405 :                            filename loc-enc))))
    3302             : 
    3303             :                     ;; Send buffer into remote decoding command which
    3304             :                     ;; writes to remote file.  Because this happens on
    3305             :                     ;; the remote host, we cannot use the function.
    3306         405 :                     (with-tramp-progress-reporter
    3307         810 :                         v 3 (format-message
    3308             :                              "Decoding remote file `%s' using `%s'"
    3309         810 :                              filename rem-dec)
    3310         405 :                       (goto-char (point-max))
    3311         405 :                       (unless (bolp) (newline))
    3312         405 :                       (tramp-send-command
    3313         405 :                        v
    3314         405 :                        (format
    3315         405 :                         (concat rem-dec " <<'%s'\n%s%s")
    3316         405 :                         (tramp-shell-quote-argument localname)
    3317         405 :                         tramp-end-of-heredoc
    3318         405 :                         (buffer-string)
    3319         405 :                         tramp-end-of-heredoc))
    3320         405 :                       (tramp-barf-unless-okay
    3321         405 :                        v nil
    3322             :                        "Couldn't write region to `%s', decode using `%s' failed"
    3323         405 :                        filename rem-dec)
    3324             :                       ;; When `file-precious-flag' is set, the region is
    3325             :                       ;; written to a temporary file.  Check that the
    3326             :                       ;; checksum is equal to that from the local tmpfile.
    3327         405 :                       (when file-precious-flag
    3328           0 :                         (erase-buffer)
    3329           0 :                         (and
    3330             :                          ;; cksum runs locally, if possible.
    3331           0 :                          (zerop (tramp-call-process v "cksum" tmpfile t))
    3332             :                          ;; cksum runs remotely.
    3333           0 :                          (tramp-send-command-and-check
    3334           0 :                           v
    3335           0 :                           (format
    3336           0 :                            "cksum <%s" (tramp-shell-quote-argument localname)))
    3337             :                          ;; ... they are different.
    3338           0 :                          (not
    3339           0 :                           (string-equal
    3340           0 :                            (buffer-string)
    3341           0 :                            (with-current-buffer (tramp-get-buffer v)
    3342           0 :                              (buffer-string))))
    3343           0 :                          (tramp-error
    3344           0 :                           v 'file-error
    3345           0 :                           (concat "Couldn't write region to `%s',"
    3346           0 :                                   " decode using `%s' failed")
    3347         405 :                           filename rem-dec)))))
    3348             : 
    3349             :                 ;; Save exit.
    3350         405 :                 (delete-file tmpfile)))
    3351             : 
    3352             :              ;; That's not expected.
    3353             :              (t
    3354           0 :               (tramp-error
    3355           0 :                v 'file-error
    3356           0 :                (concat "Method `%s' should specify both encoding and "
    3357           0 :                        "decoding command or an scp program")
    3358         405 :                method))))
    3359             : 
    3360             :           ;; Make `last-coding-system-used' have the right value.
    3361         405 :           (when coding-system-used
    3362         405 :             (set 'last-coding-system-used coding-system-used))))
    3363             : 
    3364         405 :       (tramp-flush-file-property v (file-name-directory localname))
    3365         405 :       (tramp-flush-file-property v localname)
    3366             : 
    3367             :       ;; We must protect `last-coding-system-used', now we have set it
    3368             :       ;; to its correct value.
    3369         405 :       (let (last-coding-system-used (need-chown t))
    3370             :         ;; Set file modification time.
    3371         405 :         (when (or (eq visit t) (stringp visit))
    3372           0 :           (let ((file-attr (file-attributes filename 'integer)))
    3373           0 :             (set-visited-file-modtime
    3374             :              ;; We must pass modtime explicitly, because FILENAME can
    3375             :              ;; be different from (buffer-file-name), f.e. if
    3376             :              ;; `file-precious-flag' is set.
    3377           0 :              (tramp-compat-file-attribute-modification-time file-attr))
    3378           0 :             (when (and (= (tramp-compat-file-attribute-user-id file-attr) uid)
    3379           0 :                        (= (tramp-compat-file-attribute-group-id file-attr) gid))
    3380         405 :               (setq need-chown nil))))
    3381             : 
    3382             :         ;; Set the ownership.
    3383         405 :         (when need-chown
    3384         405 :           (tramp-set-file-uid-gid filename uid gid))
    3385         405 :         (when (or (eq visit t) (null visit) (stringp visit))
    3386         405 :           (tramp-message v 0 "Wrote %s" filename))
    3387         405 :         (run-hooks 'tramp-handle-write-region-hook)))))
    3388             : 
    3389             : (defvar tramp-vc-registered-file-names nil
    3390             :   "List used to collect file names, which are checked during `vc-registered'.")
    3391             : 
    3392             : ;; VC backends check for the existence of various different special
    3393             : ;; files.  This is very time consuming, because every single check
    3394             : ;; requires a remote command (the file cache must be invalidated).
    3395             : ;; Therefore, we apply a kind of optimization.  We install the file
    3396             : ;; name handler `tramp-vc-file-name-handler', which does nothing but
    3397             : ;; remembers all file names for which `file-exists-p' or
    3398             : ;; `file-readable-p' has been applied.  A first run of `vc-registered'
    3399             : ;; is performed.  Afterwards, a script is applied for all collected
    3400             : ;; file names, using just one remote command.  The result of this
    3401             : ;; script is used to fill the file cache with actual values.  Now we
    3402             : ;; can reset the file name handlers, and we make a second run of
    3403             : ;; `vc-registered', which returns the expected result without sending
    3404             : ;; any other remote command.
    3405             : (defun tramp-sh-handle-vc-registered (file)
    3406             :   "Like `vc-registered' for Tramp files."
    3407           0 :   (with-temp-message ""
    3408           0 :     (with-parsed-tramp-file-name file nil
    3409           0 :       (with-tramp-progress-reporter
    3410           0 :           v 3 (format-message "Checking `vc-registered' for %s" file)
    3411             : 
    3412             :         ;; There could be new files, created by the vc backend.  We
    3413             :         ;; cannot reuse the old cache entries, therefore.  In
    3414             :         ;; `tramp-get-file-property', `remote-file-name-inhibit-cache'
    3415             :         ;; could also be a timestamp as `current-time' returns.  This
    3416             :         ;; means invalidate all cache entries with an older timestamp.
    3417           0 :         (let (tramp-vc-registered-file-names
    3418           0 :               (remote-file-name-inhibit-cache (current-time))
    3419             :               (file-name-handler-alist
    3420           0 :                `((,(tramp-file-name-regexp) . tramp-vc-file-name-handler))))
    3421             : 
    3422             :           ;; Here we collect only file names, which need an operation.
    3423           0 :           (tramp-with-demoted-errors
    3424             :               v "Error in 1st pass of `vc-registered': %s"
    3425           0 :             (tramp-run-real-handler 'vc-registered (list file)))
    3426           0 :           (tramp-message v 10 "\n%s" tramp-vc-registered-file-names)
    3427             : 
    3428             :           ;; Send just one command, in order to fill the cache.
    3429           0 :           (when tramp-vc-registered-file-names
    3430           0 :             (tramp-maybe-send-script
    3431           0 :              v
    3432           0 :              (format tramp-vc-registered-read-file-names
    3433           0 :                      (tramp-get-file-exists-command v)
    3434           0 :                      (format "%s -r" (tramp-get-test-command v)))
    3435           0 :              "tramp_vc_registered_read_file_names")
    3436             : 
    3437           0 :             (dolist
    3438             :                 (elt
    3439           0 :                  (ignore-errors
    3440             :                    ;; We cannot use `tramp-send-command-and-read',
    3441             :                    ;; because this does not cooperate well with
    3442             :                    ;; heredoc documents.
    3443           0 :                    (tramp-send-command
    3444           0 :                     v
    3445           0 :                     (format
    3446             :                      "tramp_vc_registered_read_file_names <<'%s'\n%s\n%s\n"
    3447           0 :                      tramp-end-of-heredoc
    3448           0 :                      (mapconcat 'tramp-shell-quote-argument
    3449           0 :                                 tramp-vc-registered-file-names
    3450           0 :                                 "\n")
    3451           0 :                      tramp-end-of-heredoc))
    3452           0 :                    (with-current-buffer (tramp-get-connection-buffer v)
    3453             :                      ;; Read the expression.
    3454           0 :                      (goto-char (point-min))
    3455           0 :                      (read (current-buffer)))))
    3456             : 
    3457           0 :               (tramp-set-file-property
    3458           0 :                v (car elt) (cadr elt) (cadr (cdr elt))))))
    3459             : 
    3460             :         ;; Second run.  Now all `file-exists-p' or `file-readable-p'
    3461             :         ;; calls shall be answered from the file cache.  We unset
    3462             :         ;; `process-file-side-effects' and `remote-file-name-inhibit-cache'
    3463             :         ;; in order to keep the cache.
    3464           0 :         (let ((vc-handled-backends vc-handled-backends)
    3465             :               remote-file-name-inhibit-cache process-file-side-effects)
    3466             :           ;; Reduce `vc-handled-backends' in order to minimize process calls.
    3467           0 :           (when (and (memq 'Bzr vc-handled-backends)
    3468           0 :                      (boundp 'vc-bzr-program)
    3469           0 :                      (not (with-tramp-connection-property v vc-bzr-program
    3470           0 :                             (tramp-find-executable
    3471           0 :                              v vc-bzr-program (tramp-get-remote-path v)))))
    3472           0 :             (setq vc-handled-backends (remq 'Bzr vc-handled-backends)))
    3473           0 :           (when (and (memq 'Git vc-handled-backends)
    3474           0 :                      (boundp 'vc-git-program)
    3475           0 :                      (not (with-tramp-connection-property v vc-git-program
    3476           0 :                             (tramp-find-executable
    3477           0 :                              v vc-git-program (tramp-get-remote-path v)))))
    3478           0 :             (setq vc-handled-backends (remq 'Git vc-handled-backends)))
    3479           0 :           (when (and (memq 'Hg vc-handled-backends)
    3480           0 :                      (boundp 'vc-hg-program)
    3481           0 :                      (not (with-tramp-connection-property v vc-hg-program
    3482           0 :                             (tramp-find-executable
    3483           0 :                              v vc-hg-program (tramp-get-remote-path v)))))
    3484           0 :             (setq vc-handled-backends (remq 'Hg vc-handled-backends)))
    3485             :           ;; Run.
    3486           0 :           (tramp-with-demoted-errors
    3487             :               v "Error in 2nd pass of `vc-registered': %s"
    3488           0 :             (tramp-run-real-handler 'vc-registered (list file))))))))
    3489             : 
    3490             : ;;;###tramp-autoload
    3491             : (defun tramp-sh-file-name-handler (operation &rest args)
    3492             :   "Invoke remote-shell Tramp file name handler.
    3493             : Fall back to normal file name handler if no Tramp handler exists."
    3494       46539 :   (let ((fn (assoc operation tramp-sh-file-name-handler-alist)))
    3495       46539 :     (if fn
    3496       46539 :         (save-match-data (apply (cdr fn) args))
    3497       46517 :       (tramp-run-real-handler operation args))))
    3498             : 
    3499             : ;; This must be the last entry, because `identity' always matches.
    3500             : ;;;###tramp-autoload
    3501             : (tramp-register-foreign-file-name-handler
    3502             :  'identity 'tramp-sh-file-name-handler 'append)
    3503             : 
    3504             : (defun tramp-vc-file-name-handler (operation &rest args)
    3505             :   "Invoke special file name handler, which collects files to be handled."
    3506           0 :   (save-match-data
    3507           0 :     (let ((filename
    3508           0 :            (tramp-replace-environment-variables
    3509           0 :             (apply 'tramp-file-name-for-operation operation args)))
    3510           0 :           (fn (assoc operation tramp-sh-file-name-handler-alist)))
    3511           0 :       (with-parsed-tramp-file-name filename nil
    3512           0 :         (cond
    3513             :          ;; That's what we want: file names, for which checks are
    3514             :          ;; applied.  We assume that VC uses only `file-exists-p' and
    3515             :          ;; `file-readable-p' checks; otherwise we must extend the
    3516             :          ;; list.  We do not perform any action, but return nil, in
    3517             :          ;; order to keep `vc-registered' running.
    3518           0 :          ((and fn (memq operation '(file-exists-p file-readable-p)))
    3519           0 :           (add-to-list 'tramp-vc-registered-file-names localname 'append)
    3520             :           nil)
    3521             :          ;; `process-file' and `start-file-process' shall be ignored.
    3522           0 :          ((and fn (eq operation 'process-file) 0))
    3523           0 :          ((and fn (eq operation 'start-file-process) nil))
    3524             :          ;; Tramp file name handlers like `expand-file-name'.  They
    3525             :          ;; must still work.
    3526           0 :          (fn (save-match-data (apply (cdr fn) args)))
    3527             :          ;; Default file name handlers, we don't care.
    3528           0 :          (t (tramp-run-real-handler operation args)))))))
    3529             : 
    3530             : (defun tramp-sh-handle-file-notify-add-watch (file-name flags _callback)
    3531             :   "Like `file-notify-add-watch' for Tramp files."
    3532           0 :   (setq file-name (expand-file-name file-name))
    3533           0 :   (with-parsed-tramp-file-name file-name nil
    3534           0 :     (let ((default-directory (file-name-directory file-name))
    3535             :           command events filter p sequence)
    3536           0 :       (cond
    3537             :        ;; gvfs-monitor-dir.
    3538           0 :        ((setq command (tramp-get-remote-gvfs-monitor-dir v))
    3539           0 :         (setq filter 'tramp-sh-gvfs-monitor-dir-process-filter
    3540             :               events
    3541           0 :               (cond
    3542           0 :                ((and (memq 'change flags) (memq 'attribute-change flags))
    3543             :                 '(created changed changes-done-hint moved deleted
    3544             :                           attribute-changed))
    3545           0 :                ((memq 'change flags)
    3546             :                 '(created changed changes-done-hint moved deleted))
    3547           0 :                ((memq 'attribute-change flags) '(attribute-changed)))
    3548           0 :               sequence `(,command ,localname)))
    3549             :        ;; inotifywait.
    3550           0 :        ((setq command (tramp-get-remote-inotifywait v))
    3551           0 :         (setq filter 'tramp-sh-inotifywait-process-filter
    3552             :               events
    3553           0 :               (cond
    3554           0 :                ((and (memq 'change flags) (memq 'attribute-change flags))
    3555           0 :                 (concat "create,modify,move,moved_from,moved_to,move_self,"
    3556           0 :                         "delete,delete_self,attrib,ignored"))
    3557           0 :                ((memq 'change flags)
    3558           0 :                 (concat "create,modify,move,moved_from,moved_to,move_self,"
    3559           0 :                         "delete,delete_self,ignored"))
    3560           0 :                ((memq 'attribute-change flags) "attrib,ignored"))
    3561           0 :               sequence `(,command "-mq" "-e" ,events ,localname)
    3562             :               ;; Make events a list of symbols.
    3563             :               events
    3564           0 :               (mapcar
    3565           0 :                (lambda (x) (intern-soft (replace-regexp-in-string "_" "-" x)))
    3566           0 :                (split-string events "," 'omit))))
    3567             :        ;; None.
    3568           0 :        (t (tramp-error
    3569           0 :            v 'file-notify-error
    3570             :            "No file notification program found on %s"
    3571           0 :            (file-remote-p file-name))))
    3572             :       ;; Start process.
    3573           0 :       (setq p (apply
    3574             :                'start-file-process
    3575           0 :                (file-name-nondirectory command)
    3576           0 :                (generate-new-buffer
    3577           0 :                 (format " *%s*" (file-name-nondirectory command)))
    3578           0 :                sequence))
    3579             :       ;; Return the process object as watch-descriptor.
    3580           0 :       (if (not (processp p))
    3581           0 :           (tramp-error
    3582           0 :            v 'file-notify-error
    3583             :            "`%s' failed to start on remote host"
    3584           0 :            (mapconcat 'identity sequence " "))
    3585           0 :         (tramp-message v 6 "Run `%s', %S" (mapconcat 'identity sequence " ") p)
    3586           0 :         (tramp-set-connection-property p "vector" v)
    3587             :         ;; Needed for process filter.
    3588           0 :         (process-put p 'events events)
    3589           0 :         (process-put p 'watch-name localname)
    3590           0 :         (set-process-query-on-exit-flag p nil)
    3591           0 :         (set-process-filter p filter)
    3592             :         ;; There might be an error if the monitor is not supported.
    3593             :         ;; Give the filter a chance to read the output.
    3594           0 :         (tramp-accept-process-output p 1)
    3595           0 :         (unless (process-live-p p)
    3596           0 :           (tramp-error
    3597           0 :            v 'file-notify-error "Monitoring not supported for `%s'" file-name))
    3598           0 :         p))))
    3599             : 
    3600             : (defun tramp-sh-gvfs-monitor-dir-process-filter (proc string)
    3601             :   "Read output from \"gvfs-monitor-dir\" and add corresponding \
    3602             : file-notify events."
    3603           0 :   (let ((events (process-get proc 'events))
    3604             :         (remote-prefix
    3605           0 :          (with-current-buffer (process-buffer proc)
    3606           0 :            (file-remote-p default-directory)))
    3607           0 :         (rest-string (process-get proc 'rest-string)))
    3608           0 :     (when rest-string
    3609           0 :       (tramp-message proc 10 "Previous string:\n%s" rest-string))
    3610           0 :     (tramp-message proc 6 "%S\n%s" proc string)
    3611           0 :     (setq string (concat rest-string string)
    3612             :           ;; Attribute change is returned in unused wording.
    3613           0 :           string (replace-regexp-in-string
    3614           0 :                   "ATTRIB CHANGED" "ATTRIBUTE_CHANGED" string))
    3615           0 :     (when (string-match "Monitoring not supported" string)
    3616           0 :       (delete-process proc))
    3617             : 
    3618           0 :     (while (string-match
    3619           0 :             (concat "^[\n\r]*"
    3620             :                     "Directory Monitor Event:[\n\r]+"
    3621             :                     "Child = \\([^\n\r]+\\)[\n\r]+"
    3622             :                     "\\(Other = \\([^\n\r]+\\)[\n\r]+\\)?"
    3623           0 :                     "Event = \\([^[:blank:]]+\\)[\n\r]+")
    3624           0 :             string)
    3625           0 :       (let* ((file (match-string 1 string))
    3626           0 :              (file1 (match-string 3 string))
    3627             :              (object
    3628           0 :               (list
    3629           0 :                proc
    3630           0 :                (list
    3631           0 :                 (intern-soft
    3632           0 :                  (replace-regexp-in-string
    3633           0 :                   "_" "-" (downcase (match-string 4 string)))))
    3634             :                ;; File names are returned as absolute paths.  We must
    3635             :                ;; add the remote prefix.
    3636           0 :                (concat remote-prefix file)
    3637           0 :                (when file1 (concat remote-prefix file1)))))
    3638           0 :         (setq string (replace-match "" nil nil string))
    3639             :         ;; Remove watch when file or directory to be watched is deleted.
    3640           0 :         (when (and (member (cl-caadr object) '(moved deleted))
    3641           0 :                    (string-equal file (process-get proc 'watch-name)))
    3642           0 :           (delete-process proc))
    3643             :         ;; Usually, we would add an Emacs event now.  Unfortunately,
    3644             :         ;; `unread-command-events' does not accept several events at
    3645             :         ;; once.  Therefore, we apply the handler directly.
    3646           0 :         (when (member (cl-caadr object) events)
    3647           0 :           (tramp-compat-funcall
    3648             :            'file-notify-handle-event
    3649           0 :            `(file-notify ,object file-notify-callback)))))
    3650             : 
    3651             :     ;; Save rest of the string.
    3652           0 :     (when (zerop (length string)) (setq string nil))
    3653           0 :     (when string (tramp-message proc 10 "Rest string:\n%s" string))
    3654           0 :     (process-put proc 'rest-string string)))
    3655             : 
    3656             : (defun tramp-sh-inotifywait-process-filter (proc string)
    3657             :   "Read output from \"inotifywait\" and add corresponding file-notify events."
    3658           0 :   (let ((events (process-get proc 'events)))
    3659           0 :     (tramp-message proc 6 "%S\n%s" proc string)
    3660           0 :     (dolist (line (split-string string "[\n\r]+" 'omit))
    3661             :       ;; Check, whether there is a problem.
    3662           0 :       (unless
    3663           0 :           (string-match
    3664           0 :            (concat "^[^[:blank:]]+"
    3665             :                    "[[:blank:]]+\\([^[:blank:]]+\\)+"
    3666           0 :                    "\\([[:blank:]]+\\([^\n\r]+\\)\\)?")
    3667           0 :            line)
    3668           0 :         (tramp-error proc 'file-notify-error "%s" line))
    3669             : 
    3670           0 :       (let ((object
    3671           0 :              (list
    3672           0 :               proc
    3673           0 :               (mapcar
    3674             :                (lambda (x)
    3675           0 :                  (intern-soft
    3676           0 :                   (replace-regexp-in-string "_" "-" (downcase x))))
    3677           0 :                (split-string (match-string 1 line) "," 'omit))
    3678           0 :               (match-string 3 line))))
    3679             :         ;; Remove watch when file or directory to be watched is deleted.
    3680           0 :         (when (member (cl-caadr object) '(move-self delete-self ignored))
    3681           0 :           (delete-process proc))
    3682             :         ;; Usually, we would add an Emacs event now.  Unfortunately,
    3683             :         ;; `unread-command-events' does not accept several events at
    3684             :         ;; once.  Therefore, we apply the handler directly.
    3685           0 :         (when (member (cl-caadr object) events)
    3686           0 :           (tramp-compat-funcall
    3687             :            'file-notify-handle-event
    3688           0 :            `(file-notify ,object file-notify-callback)))))))
    3689             : 
    3690             : ;;; Internal Functions:
    3691             : 
    3692             : (defun tramp-maybe-send-script (vec script name)
    3693             :   "Define in remote shell function NAME implemented as SCRIPT.
    3694             : Only send the definition if it has not already been done."
    3695             :   ;; We cannot let-bind (tramp-get-connection-process vec) because it
    3696             :   ;; might be nil.
    3697         415 :   (let ((scripts (tramp-get-connection-property
    3698         415 :                   (tramp-get-connection-process vec) "scripts" nil)))
    3699         415 :     (unless (member name scripts)
    3700          14 :       (with-tramp-progress-reporter
    3701          28 :           vec 5 (format-message "Sending script `%s'" name)
    3702             :         ;; In bash, leading TABs like in `tramp-vc-registered-read-file-names'
    3703             :         ;; could result in unwanted command expansion.  Avoid this.
    3704          14 :         (setq script (replace-regexp-in-string
    3705          14 :                       (make-string 1 ?\t) (make-string 8 ? ) script))
    3706             :         ;; The script could contain a call of Perl.  This is masked with `%s'.
    3707          14 :         (when (and (string-match "%s" script)
    3708          14 :                    (not (tramp-get-remote-perl vec)))
    3709          14 :           (tramp-error vec 'file-error "No Perl available on remote host"))
    3710          14 :         (tramp-barf-unless-okay
    3711          14 :          vec
    3712          14 :          (format "%s () {\n%s\n}"
    3713          14 :                  name (format script (tramp-get-remote-perl vec)))
    3714          14 :          "Script %s sending failed" name)
    3715          14 :         (tramp-set-connection-property
    3716         415 :          (tramp-get-connection-process vec) "scripts" (cons name scripts))))))
    3717             : 
    3718             : (defun tramp-run-test (switch filename)
    3719             :   "Run `test' on the remote system, given a SWITCH and a FILENAME.
    3720             : Returns the exit code of the `test' program."
    3721        1702 :   (with-parsed-tramp-file-name filename nil
    3722        1702 :     (tramp-send-command-and-check
    3723        1702 :      v
    3724        1702 :      (format
    3725             :       "%s %s %s"
    3726        1702 :       (tramp-get-test-command v)
    3727        1702 :       switch
    3728        1702 :       (tramp-shell-quote-argument localname)))))
    3729             : 
    3730             : (defun tramp-run-test2 (format-string file1 file2)
    3731             :   "Run `test'-like program on the remote system, given FILE1, FILE2.
    3732             : FORMAT-STRING contains the program name, switches, and place holders.
    3733             : Returns the exit code of the `test' program.  Barfs if the methods,
    3734             : hosts, or files, disagree."
    3735           0 :   (unless (tramp-equal-remote file1 file2)
    3736           0 :     (with-parsed-tramp-file-name (if (tramp-tramp-file-p file1) file1 file2) nil
    3737           0 :       (tramp-error
    3738           0 :        v 'file-error
    3739           0 :        "tramp-run-test2 only implemented for same method, user, host")))
    3740           0 :   (with-parsed-tramp-file-name file1 v1
    3741           0 :     (with-parsed-tramp-file-name file1 v2
    3742           0 :       (tramp-send-command-and-check
    3743           0 :        v1
    3744           0 :        (format format-string
    3745           0 :                (tramp-shell-quote-argument v1-localname)
    3746           0 :                (tramp-shell-quote-argument v2-localname))))))
    3747             : 
    3748             : (defun tramp-find-executable
    3749             :   (vec progname dirlist &optional ignore-tilde ignore-path)
    3750             :   "Searches for PROGNAME in $PATH and all directories mentioned in DIRLIST.
    3751             : First arg VEC specifies the connection, PROGNAME is the program
    3752             : to search for, and DIRLIST gives the list of directories to
    3753             : search.  If IGNORE-TILDE is non-nil, directory names starting
    3754             : with `~' will be ignored. If IGNORE-PATH is non-nil, searches
    3755             : only in DIRLIST.
    3756             : 
    3757             : Returns the absolute file name of PROGNAME, if found, and nil otherwise.
    3758             : 
    3759             : This function expects to be in the right *tramp* buffer."
    3760         136 :   (with-current-buffer (tramp-get-connection-buffer vec)
    3761         136 :     (let (result)
    3762             :       ;; Check whether the executable is in $PATH. "which(1)" does not
    3763             :       ;; report always a correct error code; therefore we check the
    3764             :       ;; number of words it returns.  "SunOS 5.10" (and maybe "SunOS
    3765             :       ;; 5.11") have problems with this command, we disable the call
    3766             :       ;; therefore.
    3767         136 :       (unless (or ignore-path
    3768          91 :                   (string-match
    3769          91 :                    (regexp-opt '("SunOS 5.10" "SunOS 5.11"))
    3770         136 :                    (tramp-get-connection-property vec "uname" "")))
    3771          91 :         (tramp-send-command vec (format "which \\%s | wc -w" progname))
    3772          91 :         (goto-char (point-min))
    3773          91 :         (if (looking-at "^\\s-*1$")
    3774         136 :             (setq result (concat "\\" progname))))
    3775         136 :       (unless result
    3776          56 :         (when ignore-tilde
    3777             :           ;; Remove all ~/foo directories from dirlist.
    3778          45 :           (let (newdl d)
    3779         180 :             (while dirlist
    3780         135 :               (setq d (car dirlist))
    3781         135 :               (setq dirlist (cdr dirlist))
    3782         135 :               (unless (char-equal ?~ (aref d 0))
    3783         135 :                 (setq newdl (cons d newdl))))
    3784          56 :             (setq dirlist (nreverse newdl))))
    3785          56 :         (tramp-send-command
    3786          56 :          vec
    3787          56 :          (format (concat "while read d; "
    3788             :                          "do if test -x $d/%s && test -f $d/%s; "
    3789             :                          "then echo tramp_executable $d/%s; "
    3790             :                          "break; fi; done <<'%s'\n"
    3791          56 :                          "%s\n%s")
    3792          56 :                  progname progname progname
    3793          56 :                  tramp-end-of-heredoc
    3794          56 :                  (mapconcat 'identity dirlist "\n")
    3795          56 :                  tramp-end-of-heredoc))
    3796          56 :         (goto-char (point-max))
    3797          56 :         (when (search-backward "tramp_executable " nil t)
    3798          45 :           (skip-chars-forward "^ ")
    3799          45 :           (skip-chars-forward " ")
    3800         136 :           (setq result (buffer-substring (point) (point-at-eol)))))
    3801         136 :     result)))
    3802             : 
    3803             : (defun tramp-set-remote-path (vec)
    3804             :   "Sets the remote environment PATH to existing directories.
    3805             : I.e., for each directory in `tramp-remote-path', it is tested
    3806             : whether it exists and if so, it is added to the environment
    3807             : variable PATH."
    3808          71 :   (tramp-message vec 5 "Setting $PATH environment variable")
    3809          71 :   (tramp-send-command
    3810          71 :    vec (format "PATH=%s; export PATH"
    3811          71 :                (mapconcat 'identity (tramp-get-remote-path vec) ":"))))
    3812             : 
    3813             : ;; ------------------------------------------------------------
    3814             : ;; -- Communication with external shell --
    3815             : ;; ------------------------------------------------------------
    3816             : 
    3817             : (defun tramp-find-file-exists-command (vec)
    3818             :   "Find a command on the remote host for checking if a file exists.
    3819             : Here, we are looking for a command which has zero exit status if the
    3820             : file exists and nonzero exit status otherwise."
    3821          36 :   (let ((existing "/")
    3822             :         (nonexistent
    3823          36 :          (tramp-shell-quote-argument "/ this file does not exist "))
    3824             :         result)
    3825             :     ;; The algorithm is as follows: we try a list of several commands.
    3826             :     ;; For each command, we first run `$cmd /' -- this should return
    3827             :     ;; true, as the root directory always exists.  And then we run
    3828             :     ;; `$cmd /this\ file\ does\ not\ exist ', hoping that the file indeed
    3829             :     ;; does not exist.  This should return false.  We use the first
    3830             :     ;; command we find that seems to work.
    3831             :     ;; The list of commands to try is as follows:
    3832             :     ;; `ls -d'            This works on most systems, but NetBSD 1.4
    3833             :     ;;                    has a bug: `ls' always returns zero exit
    3834             :     ;;                    status, even for files which don't exist.
    3835             :     ;; `test -e'          Some Bourne shells have a `test' builtin
    3836             :     ;;                    which does not know the `-e' option.
    3837             :     ;; `/bin/test -e'     For those, the `test' binary on disk normally
    3838             :     ;;                    provides the option.  Alas, the binary
    3839             :     ;;                    is sometimes `/bin/test' and sometimes it's
    3840             :     ;;                    `/usr/bin/test'.
    3841             :     ;; `/usr/bin/test -e' In case `/bin/test' does not exist.
    3842          36 :     (unless (or
    3843          36 :              (ignore-errors
    3844          36 :                (and (setq result (format "%s -e" (tramp-get-test-command vec)))
    3845          36 :                     (tramp-send-command-and-check
    3846          36 :                      vec (format "%s %s" result existing))
    3847          36 :                     (not (tramp-send-command-and-check
    3848          36 :                           vec (format "%s %s" result nonexistent)))))
    3849           0 :              (ignore-errors
    3850           0 :                (and (setq result "/bin/test -e")
    3851           0 :                     (tramp-send-command-and-check
    3852           0 :                      vec (format "%s %s" result existing))
    3853           0 :                     (not (tramp-send-command-and-check
    3854           0 :                           vec (format "%s %s" result nonexistent)))))
    3855           0 :              (ignore-errors
    3856           0 :                (and (setq result "/usr/bin/test -e")
    3857           0 :                     (tramp-send-command-and-check
    3858           0 :                      vec (format "%s %s" result existing))
    3859           0 :                     (not (tramp-send-command-and-check
    3860           0 :                           vec (format "%s %s" result nonexistent)))))
    3861           0 :              (ignore-errors
    3862           0 :                (and (setq result (format "%s -d" (tramp-get-ls-command vec)))
    3863           0 :                     (tramp-send-command-and-check
    3864           0 :                      vec (format "%s %s" result existing))
    3865           0 :                     (not (tramp-send-command-and-check
    3866          36 :                           vec (format "%s %s" result nonexistent))))))
    3867           0 :       (tramp-error
    3868          36 :        vec 'file-error "Couldn't find command to check if file exists"))
    3869          36 :     result))
    3870             : 
    3871             : (defun tramp-open-shell (vec shell)
    3872             :   "Opens shell SHELL."
    3873          71 :   (with-tramp-progress-reporter
    3874         142 :       vec 5 (format-message "Opening remote shell `%s'" shell)
    3875             :     ;; Find arguments for this shell.
    3876          71 :     (let ((alist tramp-sh-extra-args)
    3877             :           item extra-args)
    3878         142 :       (while (and alist (null extra-args))
    3879         142 :         (setq item (pop alist))
    3880          71 :         (when (string-match (car item) shell)
    3881          71 :           (setq extra-args (cdr item))))
    3882             :       ;; It is useful to set the prompt in the following command
    3883             :       ;; because some people have a setting for $PS1 which /bin/sh
    3884             :       ;; doesn't know about and thus /bin/sh will display a strange
    3885             :       ;; prompt.  For example, if $PS1 has "${CWD}" in the value, then
    3886             :       ;; ksh will display the current working directory but /bin/sh
    3887             :       ;; will display a dollar sign.  The following command line sets
    3888             :       ;; $PS1 to a sane value, and works under Bourne-ish shells as
    3889             :       ;; well as csh-like shells.  We also unset the variable $ENV
    3890             :       ;; because that is read by some sh implementations (eg, bash
    3891             :       ;; when called as sh) on startup; this way, we avoid the startup
    3892             :       ;; file clobbering $PS1.  $PROMPT_COMMAND is another way to set
    3893             :       ;; the prompt in /bin/bash, it must be discarded as well.
    3894             :       ;; $HISTFILE is set according to `tramp-histfile-override'.
    3895          71 :       (tramp-send-command
    3896          71 :        vec (format
    3897             :             "exec env ENV=%s %s PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s %s"
    3898          71 :             (or (getenv-internal "ENV" tramp-remote-process-environment) "")
    3899          71 :             (if (stringp tramp-histfile-override)
    3900          71 :                 (format "HISTFILE=%s"
    3901          71 :                         (tramp-shell-quote-argument tramp-histfile-override))
    3902           0 :               (if tramp-histfile-override
    3903             :                   "HISTFILE='' HISTFILESIZE=0 HISTSIZE=0"
    3904          71 :                 ""))
    3905          71 :             (tramp-shell-quote-argument tramp-end-of-output)
    3906          71 :             shell (or extra-args ""))
    3907          71 :        t)
    3908             :       ;; Check proper HISTFILE setting.  We give up when not working.
    3909          71 :       (when (and (stringp tramp-histfile-override)
    3910          71 :                  (file-name-directory tramp-histfile-override))
    3911          71 :         (tramp-barf-unless-okay
    3912          71 :          vec
    3913          71 :          (format
    3914             :           "(cd %s)"
    3915          71 :           (tramp-shell-quote-argument
    3916          71 :            (file-name-directory tramp-histfile-override)))
    3917             :          "`tramp-histfile-override' uses invalid file `%s'"
    3918          71 :          tramp-histfile-override)))
    3919             : 
    3920          71 :     (tramp-set-connection-property
    3921          71 :      (tramp-get-connection-process vec) "remote-shell" shell)))
    3922             : 
    3923             : (defun tramp-find-shell (vec)
    3924             :   "Opens a shell on the remote host which groks tilde expansion."
    3925          71 :   (with-current-buffer (tramp-get-buffer vec)
    3926          71 :     (let ((default-shell (tramp-get-method-parameter vec 'tramp-remote-shell))
    3927             :           shell)
    3928          71 :       (setq shell
    3929         115 :             (with-tramp-connection-property vec "remote-shell"
    3930             :               ;; CCC: "root" does not exist always, see my QNAP TS-459.
    3931             :               ;; Which check could we apply instead?
    3932          44 :               (tramp-send-command vec "echo ~root" t)
    3933          44 :               (if (or (string-match "^~root$" (buffer-string))
    3934             :                       ;; The default shell (ksh93) of OpenSolaris and
    3935             :                       ;; Solaris is buggy.  We've got reports for
    3936             :                       ;; "SunOS 5.10" and "SunOS 5.11" so far.
    3937          44 :                       (string-match (regexp-opt '("SunOS 5.10" "SunOS 5.11"))
    3938          44 :                                     (tramp-get-connection-property
    3939          44 :                                      vec "uname" "")))
    3940             : 
    3941           0 :                   (or (tramp-find-executable
    3942           0 :                        vec "bash" (tramp-get-remote-path vec) t t)
    3943           0 :                       (tramp-find-executable
    3944           0 :                        vec "ksh" (tramp-get-remote-path vec) t t)
    3945             :                       ;; Maybe it works at least for some other commands.
    3946           0 :                       (prog1
    3947           0 :                           default-shell
    3948           0 :                         (tramp-message
    3949           0 :                          vec 2
    3950           0 :                          (concat
    3951             :                           "Couldn't find a remote shell which groks tilde "
    3952           0 :                           "expansion, using `%s'")
    3953           0 :                          default-shell)))
    3954             : 
    3955          71 :                 default-shell)))
    3956             : 
    3957             :       ;; Open a new shell if needed.
    3958          71 :       (unless (string-equal shell default-shell)
    3959           0 :         (tramp-message
    3960           0 :          vec 5 "Starting remote shell `%s' for tilde expansion" shell)
    3961          71 :         (tramp-open-shell vec shell)))))
    3962             : 
    3963             : ;; Utility functions.
    3964             : 
    3965             : (defun tramp-barf-if-no-shell-prompt (proc timeout &rest error-args)
    3966             :   "Wait for shell prompt and barf if none appears.
    3967             : Looks at process PROC to see if a shell prompt appears in TIMEOUT
    3968             : seconds.  If not, it produces an error message with the given ERROR-ARGS."
    3969          71 :   (let ((vec (tramp-get-connection-property proc "vector" nil)))
    3970          71 :     (condition-case nil
    3971          71 :         (tramp-wait-for-regexp
    3972          71 :          proc timeout
    3973          71 :          (format
    3974          71 :           "\\(%s\\|%s\\)\\'" shell-prompt-pattern tramp-shell-prompt-pattern))
    3975             :       (error
    3976           0 :        (delete-process proc)
    3977           0 :        (apply 'tramp-error-with-buffer
    3978          71 :               (tramp-get-connection-buffer vec) vec 'file-error error-args)))))
    3979             : 
    3980             : (defun tramp-open-connection-setup-interactive-shell (proc vec)
    3981             :   "Set up an interactive shell.
    3982             : Mainly sets the prompt and the echo correctly.  PROC is the shell
    3983             : process to set up.  VEC specifies the connection."
    3984          71 :   (let ((tramp-end-of-output tramp-initial-end-of-output)
    3985             :         (case-fold-search t))
    3986          71 :     (tramp-open-shell vec (tramp-get-method-parameter vec 'tramp-remote-shell))
    3987             : 
    3988             :     ;; Disable echo expansion.
    3989          71 :     (tramp-message vec 5 "Setting up remote shell environment")
    3990          71 :     (tramp-send-command
    3991          71 :      vec "stty -inlcr -onlcr -echo kill '^U' erase '^H'" t)
    3992             :     ;; Check whether the echo has really been disabled.  Some
    3993             :     ;; implementations, like busybox of embedded GNU/Linux, don't
    3994             :     ;; support disabling.
    3995          71 :     (tramp-send-command vec "echo foo" t)
    3996          71 :     (with-current-buffer (process-buffer proc)
    3997          71 :       (goto-char (point-min))
    3998          71 :       (when (looking-at "echo foo")
    3999           0 :         (tramp-set-connection-property proc "remote-echo" t)
    4000           0 :         (tramp-message vec 5 "Remote echo still on. Ok.")
    4001             :         ;; Make sure backspaces and their echo are enabled and no line
    4002             :         ;; width magic interferes with them.
    4003          71 :         (tramp-send-command vec "stty icanon erase ^H cols 32767" t))))
    4004             : 
    4005          71 :   (tramp-message vec 5 "Setting shell prompt")
    4006          71 :   (tramp-send-command
    4007          71 :    vec (format "PS1=%s PS2='' PS3='' PROMPT_COMMAND=''"
    4008          71 :                (tramp-shell-quote-argument tramp-end-of-output))
    4009          71 :    t)
    4010             : 
    4011             :   ;; Check whether the output of "uname -sr" has been changed.  If
    4012             :   ;; yes, this is a strong indication that we must expire all
    4013             :   ;; connection properties.  We start again with
    4014             :   ;; `tramp-maybe-open-connection', it will be caught there.
    4015          71 :   (tramp-message vec 5 "Checking system information")
    4016          71 :   (let ((old-uname (tramp-get-connection-property vec "uname" nil))
    4017             :         (uname
    4018          71 :          (tramp-set-connection-property
    4019          71 :           vec "uname"
    4020          71 :           (tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\""))))
    4021          71 :     (when (and (stringp old-uname) (not (string-equal old-uname uname)))
    4022           0 :       (tramp-message
    4023           0 :        vec 3
    4024             :        "Connection reset, because remote host changed from `%s' to `%s'"
    4025           0 :        old-uname uname)
    4026             :       ;; We want to keep the password.
    4027           0 :       (tramp-cleanup-connection vec t t)
    4028          71 :       (throw 'uname-changed (tramp-maybe-open-connection vec)))
    4029             : 
    4030             :     ;; Try to set up the coding system correctly.
    4031             :     ;; CCC this can't be the right way to do it.  Hm.
    4032          71 :     (tramp-message vec 5 "Determining coding system")
    4033          71 :     (with-current-buffer (process-buffer proc)
    4034             :       ;; Use MULE to select the right EOL convention for communicating
    4035             :       ;; with the process.
    4036          71 :       (let ((cs (or (and (memq 'utf-8 (coding-system-list))
    4037          71 :                          (string-match "utf-?8" (tramp-get-remote-locale vec))
    4038          71 :                          (cons 'utf-8 'utf-8))
    4039           0 :                     (process-coding-system proc)
    4040          71 :                     (cons 'undecided 'undecided)))
    4041             :             cs-decode cs-encode)
    4042          71 :         (when (symbolp cs) (setq cs (cons cs cs)))
    4043          71 :         (setq cs-decode (or (car cs) 'undecided)
    4044          71 :               cs-encode (or (cdr cs) 'undecided)
    4045             :               cs-encode
    4046          71 :               (coding-system-change-eol-conversion
    4047          71 :                cs-encode (if (string-match "^Darwin" uname) 'mac 'unix)))
    4048          71 :         (tramp-send-command vec "echo foo ; echo bar" t)
    4049          71 :         (goto-char (point-min))
    4050          71 :         (when (search-forward "\r" nil t)
    4051          71 :           (setq cs-decode (coding-system-change-eol-conversion cs-decode 'dos)))
    4052             :         ;; Special setting for macOS.
    4053          71 :         (when (and (string-match "^Darwin" uname)
    4054          71 :                    (memq 'utf-8-hfs (coding-system-list)))
    4055           0 :           (setq cs-decode 'utf-8-hfs
    4056          71 :                 cs-encode 'utf-8-hfs))
    4057          71 :         (set-buffer-process-coding-system cs-decode cs-encode)
    4058          71 :         (tramp-message
    4059          71 :          vec 5 "Setting coding system to `%s' and `%s'" cs-decode cs-encode)))
    4060             : 
    4061          71 :     (tramp-send-command vec "set +o vi +o emacs" t)
    4062             : 
    4063             :     ;; Check whether the remote host suffers from buggy
    4064             :     ;; `send-process-string'.  This is known for FreeBSD (see comment
    4065             :     ;; in `send_process', file process.c).  I've tested sending 624
    4066             :     ;; bytes successfully, sending 625 bytes failed.  Emacs makes a
    4067             :     ;; hack when this host type is detected locally.  It cannot handle
    4068             :     ;; remote hosts, though.
    4069         142 :     (with-tramp-connection-property proc "chunksize"
    4070          71 :       (cond
    4071          71 :        ((and (integerp tramp-chunksize) (> tramp-chunksize 0))
    4072           0 :         tramp-chunksize)
    4073             :        (t
    4074          71 :         (tramp-message
    4075          71 :          vec 5 "Checking remote host type for `send-process-string' bug")
    4076          71 :         (if (string-match "^FreeBSD" uname) 500 0))))
    4077             : 
    4078             :     ;; Set remote PATH variable.
    4079          71 :     (tramp-set-remote-path vec)
    4080             : 
    4081             :     ;; Search for a good shell before searching for a command which
    4082             :     ;; checks if a file exists.  This is done because Tramp wants to
    4083             :     ;; use "test foo; echo $?" to check if various conditions hold,
    4084             :     ;; and there are buggy /bin/sh implementations which don't execute
    4085             :     ;; the "echo $?"  part if the "test" part has an error.  In
    4086             :     ;; particular, the OpenSolaris /bin/sh is a problem.  There are
    4087             :     ;; also other problems with /bin/sh of OpenSolaris, like
    4088             :     ;; redirection of stderr in function declarations, or changing
    4089             :     ;; HISTFILE in place.  Therefore, OpenSolaris' /bin/sh is replaced
    4090             :     ;; by bash, when detected.
    4091          71 :     (tramp-find-shell vec)
    4092             : 
    4093             :     ;; Disable unexpected output.
    4094          71 :     (tramp-send-command vec "mesg n 2>/dev/null; biff n 2>/dev/null" t)
    4095             : 
    4096             :     ;; IRIX64 bash expands "!" even when in single quotes.  This
    4097             :     ;; destroys our shell functions, we must disable it.  See
    4098             :     ;; <http://stackoverflow.com/questions/3291692/irix-bash-shell-expands-expression-in-single-quotes-yet-shouldnt>.
    4099          71 :     (when (string-match "^IRIX64" uname)
    4100          71 :       (tramp-send-command vec "set +H" t))
    4101             : 
    4102             :     ;; Disable tab expansion.
    4103          71 :     (if (string-match "BSD\\|Darwin" uname)
    4104           0 :         (tramp-send-command vec "stty tabs" t)
    4105          71 :       (tramp-send-command vec "stty tab0" t))
    4106             : 
    4107             :     ;; Set utf8 encoding.  Needed for macOS, for example.  This is
    4108             :     ;; non-POSIX, so we must expect errors on some systems.
    4109          71 :     (tramp-send-command vec "stty iutf8 2>/dev/null" t)
    4110             : 
    4111             :     ;; Set `remote-tty' process property.
    4112          71 :     (let ((tty (tramp-send-command-and-read vec "echo \\\"`tty`\\\"" 'noerror)))
    4113          71 :       (unless (zerop (length tty))
    4114          71 :         (process-put proc 'remote-tty tty)))
    4115             : 
    4116             :     ;; Dump stty settings in the traces.
    4117          71 :     (when (>= tramp-verbose 9)
    4118          71 :       (tramp-send-command vec "stty -a" t))
    4119             : 
    4120             :     ;; Set the environment.
    4121          71 :     (tramp-message vec 5 "Setting default environment")
    4122             : 
    4123          71 :     (let (unset vars)
    4124          71 :       (dolist (item (reverse
    4125          71 :                      (append `(,(tramp-get-remote-locale vec))
    4126          71 :                              (copy-sequence tramp-remote-process-environment))))
    4127        1001 :         (setq item (split-string item "=" 'omit))
    4128        1001 :         (setcdr item (mapconcat 'identity (cdr item) "="))
    4129        1001 :         (if (and (stringp (cdr item)) (not (string-equal (cdr item) "")))
    4130        1008 :             (push (format "%s %s" (car item) (cdr item)) vars)
    4131        1001 :           (push (car item) unset)))
    4132          71 :       (when vars
    4133          71 :         (tramp-send-command
    4134          71 :          vec
    4135          71 :          (format
    4136             :           "while read var val; do export $var=\"$val\"; done <<'%s'\n%s\n%s"
    4137          71 :           tramp-end-of-heredoc
    4138          71 :           (mapconcat 'identity vars "\n")
    4139          71 :           tramp-end-of-heredoc)
    4140          71 :          t))
    4141          71 :       (when unset
    4142          71 :         (tramp-send-command
    4143          71 :          vec (format "unset %s" (mapconcat 'identity unset " ")) t)))))
    4144             : 
    4145             : ;; Old text from documentation of tramp-methods:
    4146             : ;; Using a uuencode/uudecode inline method is discouraged, please use one
    4147             : ;; of the base64 methods instead since base64 encoding is much more
    4148             : ;; reliable and the commands are more standardized between the different
    4149             : ;; Unix versions.  But if you can't use base64 for some reason, please
    4150             : ;; note that the default uudecode command does not work well for some
    4151             : ;; Unices, in particular AIX and Irix.  For AIX, you might want to use
    4152             : ;; the following command for uudecode:
    4153             : ;;
    4154             : ;;     sed '/^begin/d;/^[` ]$/d;/^end/d' | iconv -f uucode -t ISO8859-1
    4155             : ;;
    4156             : ;; For Irix, no solution is known yet.
    4157             : 
    4158             : (autoload 'uudecode-decode-region "uudecode")
    4159             : 
    4160             : (defconst tramp-local-coding-commands
    4161             :   `((b64 base64-encode-region base64-decode-region)
    4162             :     (uu  tramp-uuencode-region uudecode-decode-region)
    4163             :     (pack ,(format tramp-perl-pack "perl") ,(format tramp-perl-unpack "perl")))
    4164             :   "List of local coding commands for inline transfer.
    4165             : Each item is a list that looks like this:
    4166             : 
    4167             : \(FORMAT ENCODING DECODING)
    4168             : 
    4169             : FORMAT is  symbol describing the encoding/decoding format.  It can be
    4170             : `b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
    4171             : 
    4172             : ENCODING and DECODING can be strings, giving commands, or symbols,
    4173             : giving functions.  If they are strings, then they can contain
    4174             : the \"%s\" format specifier.  If that specifier is present, the input
    4175             : file name will be put into the command line at that spot.  If the
    4176             : specifier is not present, the input should be read from standard
    4177             : input.
    4178             : 
    4179             : If they are functions, they will be called with two arguments, start
    4180             : and end of region, and are expected to replace the region contents
    4181             : with the encoded or decoded results, respectively.")
    4182             : 
    4183             : (defconst tramp-remote-coding-commands
    4184             :   `((b64 "base64" "base64 -d -i")
    4185             :     ;; "-i" is more robust with older base64 from GNU coreutils.
    4186             :     ;; However, I don't know whether all base64 versions do supports
    4187             :     ;; this option.
    4188             :     (b64 "base64" "base64 -d")
    4189             :     (b64 "openssl enc -base64" "openssl enc -d -base64")
    4190             :     (b64 "mimencode -b" "mimencode -u -b")
    4191             :     (b64 "mmencode -b" "mmencode -u -b")
    4192             :     (b64 "recode data..base64" "recode base64..data")
    4193             :     (b64 tramp-perl-encode-with-module tramp-perl-decode-with-module)
    4194             :     (b64 tramp-perl-encode tramp-perl-decode)
    4195             :     ;; This is painful slow, so we put it on the end.
    4196             :     (b64 tramp-awk-encode tramp-awk-decode ,tramp-awk-coding-test)
    4197             :     (uu  "uuencode xxx" "uudecode -o /dev/stdout" "test -c /dev/stdout")
    4198             :     (uu  "uuencode xxx" "uudecode -o -")
    4199             :     (uu  "uuencode xxx" "uudecode -p")
    4200             :     (uu  "uuencode xxx" tramp-uudecode)
    4201             :     (pack tramp-perl-pack tramp-perl-unpack))
    4202             :   "List of remote coding commands for inline transfer.
    4203             : Each item is a list that looks like this:
    4204             : 
    4205             : \(FORMAT ENCODING DECODING [TEST])
    4206             : 
    4207             : FORMAT is a symbol describing the encoding/decoding format.  It can be
    4208             : `b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
    4209             : 
    4210             : ENCODING and DECODING can be strings, giving commands, or symbols,
    4211             : giving variables.  If they are strings, then they can contain
    4212             : the \"%s\" format specifier.  If that specifier is present, the input
    4213             : file name will be put into the command line at that spot.  If the
    4214             : specifier is not present, the input should be read from standard
    4215             : input.
    4216             : 
    4217             : If they are variables, this variable is a string containing a
    4218             : Perl or Shell implementation for this functionality.  This
    4219             : program will be transferred to the remote host, and it is
    4220             : available as shell function with the same name.  A \"%t\" format
    4221             : specifier in the variable value denotes a temporary file.
    4222             : 
    4223             : The optional TEST command can be used for further tests, whether
    4224             : ENCODING and DECODING are applicable.")
    4225             : 
    4226             : (defun tramp-find-inline-encoding (vec)
    4227             :   "Find an inline transfer encoding that works.
    4228             : Goes through the list `tramp-local-coding-commands' and
    4229             : `tramp-remote-coding-commands'."
    4230          31 :   (save-excursion
    4231          31 :     (let ((local-commands tramp-local-coding-commands)
    4232             :           (magic "xyzzy")
    4233          31 :           (p (tramp-get-connection-process vec))
    4234             :           loc-enc loc-dec rem-enc rem-dec rem-test litem ritem found)
    4235          62 :       (while (and local-commands (not found))
    4236          62 :         (setq litem (pop local-commands))
    4237          31 :         (catch 'wont-work-local
    4238          31 :           (let ((format (nth 0 litem))
    4239          31 :                 (remote-commands tramp-remote-coding-commands))
    4240          31 :             (setq loc-enc (nth 1 litem))
    4241          31 :             (setq loc-dec (nth 2 litem))
    4242             :             ;; If the local encoder or decoder is a string, the
    4243             :             ;; corresponding command has to work locally.
    4244          31 :             (if (not (stringp loc-enc))
    4245          31 :                 (tramp-message
    4246          31 :                  vec 5 "Checking local encoding function `%s'" loc-enc)
    4247           0 :               (tramp-message
    4248           0 :                vec 5 "Checking local encoding command `%s' for sanity" loc-enc)
    4249           0 :               (unless (zerop (tramp-call-local-coding-command
    4250           0 :                               loc-enc nil nil))
    4251          31 :                 (throw 'wont-work-local nil)))
    4252          31 :             (if (not (stringp loc-dec))
    4253          31 :                 (tramp-message
    4254          31 :                  vec 5 "Checking local decoding function `%s'" loc-dec)
    4255           0 :               (tramp-message
    4256           0 :                vec 5 "Checking local decoding command `%s' for sanity" loc-dec)
    4257           0 :               (unless (zerop (tramp-call-local-coding-command
    4258           0 :                               loc-dec nil nil))
    4259          31 :                 (throw 'wont-work-local nil)))
    4260             :             ;; Search for remote coding commands with the same format
    4261          62 :             (while (and remote-commands (not found))
    4262          62 :               (setq ritem (pop remote-commands))
    4263          31 :               (catch 'wont-work-remote
    4264          31 :                 (when (equal format (nth 0 ritem))
    4265          31 :                   (setq rem-enc (nth 1 ritem))
    4266          31 :                   (setq rem-dec (nth 2 ritem))
    4267          31 :                   (setq rem-test (nth 3 ritem))
    4268             :                   ;; Check the remote test command if exists.
    4269          31 :                   (when (stringp rem-test)
    4270           0 :                     (tramp-message
    4271           0 :                      vec 5 "Checking remote test command `%s'" rem-test)
    4272           0 :                     (unless (tramp-send-command-and-check vec rem-test t)
    4273          31 :                       (throw 'wont-work-remote nil)))
    4274             :                   ;; Check if remote perl exists when necessary.
    4275          31 :                   (when (and (symbolp rem-enc)
    4276           0 :                              (string-match "perl" (symbol-name rem-enc))
    4277          31 :                              (not (tramp-get-remote-perl vec)))
    4278          31 :                     (throw 'wont-work-remote nil))
    4279             :                   ;; Check if remote encoding and decoding commands can be
    4280             :                   ;; called remotely with null input and output.  This makes
    4281             :                   ;; sure there are no syntax errors and the command is really
    4282             :                   ;; found.  Note that we do not redirect stdout to /dev/null,
    4283             :                   ;; for two reasons: when checking the decoding command, we
    4284             :                   ;; actually check the output it gives.  And also, when
    4285             :                   ;; redirecting "mimencode" output to /dev/null, then as root
    4286             :                   ;; it might change the permissions of /dev/null!
    4287          31 :                   (when (not (stringp rem-enc))
    4288           0 :                     (let ((name (symbol-name rem-enc)))
    4289           0 :                       (while (string-match (regexp-quote "-") name)
    4290           0 :                         (setq name (replace-match "_" nil t name)))
    4291           0 :                       (tramp-maybe-send-script vec (symbol-value rem-enc) name)
    4292          31 :                       (setq rem-enc name)))
    4293          31 :                   (tramp-message
    4294          31 :                    vec 5
    4295          31 :                    "Checking remote encoding command `%s' for sanity" rem-enc)
    4296          31 :                   (unless (tramp-send-command-and-check
    4297          31 :                            vec (format "%s </dev/null" rem-enc) t)
    4298          31 :                     (throw 'wont-work-remote nil))
    4299             : 
    4300          31 :                   (when (not (stringp rem-dec))
    4301           0 :                     (let ((name (symbol-name rem-dec))
    4302           0 :                           (value (symbol-value rem-dec))
    4303             :                           tmpfile)
    4304           0 :                       (while (string-match (regexp-quote "-") name)
    4305           0 :                         (setq name (replace-match "_" nil t name)))
    4306           0 :                       (when (string-match "\\(^\\|[^%]\\)%t" value)
    4307           0 :                         (setq tmpfile
    4308           0 :                               (make-temp-name
    4309           0 :                                (expand-file-name
    4310           0 :                                 tramp-temp-name-prefix
    4311           0 :                                 (tramp-get-remote-tmpdir vec)))
    4312             :                               value
    4313           0 :                               (format-spec
    4314           0 :                                value
    4315           0 :                                (format-spec-make
    4316             :                                 ?t
    4317           0 :                                 (file-remote-p tmpfile 'localname)))))
    4318           0 :                       (tramp-maybe-send-script vec value name)
    4319          31 :                       (setq rem-dec name)))
    4320          31 :                   (tramp-message
    4321          31 :                    vec 5
    4322          31 :                    "Checking remote decoding command `%s' for sanity" rem-dec)
    4323          31 :                   (unless (tramp-send-command-and-check
    4324          31 :                            vec
    4325          31 :                            (format "echo %s | %s | %s" magic rem-enc rem-dec)
    4326          31 :                            t)
    4327          31 :                     (throw 'wont-work-remote nil))
    4328             : 
    4329          31 :                   (with-current-buffer (tramp-get-buffer vec)
    4330          31 :                     (goto-char (point-min))
    4331          31 :                     (unless (looking-at (regexp-quote magic))
    4332          31 :                       (throw 'wont-work-remote nil)))
    4333             : 
    4334             :                   ;; `rem-enc' and `rem-dec' could be a string meanwhile.
    4335          31 :                   (setq rem-enc (nth 1 ritem))
    4336          31 :                   (setq rem-dec (nth 2 ritem))
    4337          31 :                   (setq found t)))))))
    4338             : 
    4339          31 :       (when found
    4340             :         ;; Set connection properties.  Since the commands are risky
    4341             :         ;; (due to output direction), we cache them in the process cache.
    4342          31 :         (tramp-message vec 5 "Using local encoding `%s'" loc-enc)
    4343          31 :         (tramp-set-connection-property p "local-encoding" loc-enc)
    4344          31 :         (tramp-message vec 5 "Using local decoding `%s'" loc-dec)
    4345          31 :         (tramp-set-connection-property p "local-decoding" loc-dec)
    4346          31 :         (tramp-message vec 5 "Using remote encoding `%s'" rem-enc)
    4347          31 :         (tramp-set-connection-property p "remote-encoding" rem-enc)
    4348          31 :         (tramp-message vec 5 "Using remote decoding `%s'" rem-dec)
    4349          31 :         (tramp-set-connection-property p "remote-decoding" rem-dec)))))
    4350             : 
    4351             : (defun tramp-call-local-coding-command (cmd input output)
    4352             :   "Call the local encoding or decoding command.
    4353             : If CMD contains \"%s\", provide input file INPUT there in command.
    4354             : Otherwise, INPUT is passed via standard input.
    4355             : INPUT can also be nil which means `/dev/null'.
    4356             : OUTPUT can be a string (which specifies a file name), or t (which
    4357             : means standard output and thus the current buffer), or nil (which
    4358             : means discard it)."
    4359           1 :   (tramp-call-process
    4360           1 :    nil tramp-encoding-shell
    4361           1 :    (when (and input (not (string-match "%s" cmd))) input)
    4362           1 :    (if (eq output t) t nil)
    4363             :    nil
    4364           1 :    tramp-encoding-command-switch
    4365           1 :    (concat
    4366           1 :     (if (string-match "%s" cmd) (format cmd input) cmd)
    4367           1 :     (if (stringp output) (concat " >" output) ""))))
    4368             : 
    4369             : (defconst tramp-inline-compress-commands
    4370             :   '(("gzip" "gzip -d")
    4371             :     ("bzip2" "bzip2 -d")
    4372             :     ("xz" "xz -d")
    4373             :     ("compress" "compress -d"))
    4374             :   "List of compress and decompress commands for inline transfer.
    4375             : Each item is a list that looks like this:
    4376             : 
    4377             : \(COMPRESS DECOMPRESS)
    4378             : 
    4379             : COMPRESS or DECOMPRESS are strings with the respective commands.")
    4380             : 
    4381             : (defun tramp-find-inline-compress (vec)
    4382             :   "Find an inline transfer compress command that works.
    4383             : Goes through the list `tramp-inline-compress-commands'."
    4384           1 :   (save-excursion
    4385           1 :     (let ((commands tramp-inline-compress-commands)
    4386             :           (magic "xyzzy")
    4387           1 :           (p (tramp-get-connection-process vec))
    4388             :           item compress decompress found)
    4389           2 :       (while (and commands (not found))
    4390           1 :         (catch 'next
    4391           2 :           (setq item (pop commands)
    4392           1 :                 compress (nth 0 item)
    4393           1 :                 decompress (nth 1 item))
    4394           1 :           (tramp-message
    4395           1 :            vec 5
    4396             :            "Checking local compress commands `%s', `%s' for sanity"
    4397           1 :            compress decompress)
    4398           1 :           (unless
    4399           1 :               (zerop
    4400           1 :                (tramp-call-local-coding-command
    4401           1 :                 (format
    4402             :                  ;; Windows shells need the program file name after
    4403             :                  ;; the pipe symbol be quoted if they use forward
    4404             :                  ;; slashes as directory separators.
    4405           1 :                  (if (memq system-type '(windows-nt))
    4406             :                      "echo %s | \"%s\" | \"%s\""
    4407           1 :                    "echo %s | %s | %s")
    4408           1 :                  magic compress decompress)
    4409           1 :                 nil nil))
    4410           1 :             (throw 'next nil))
    4411           1 :           (tramp-message
    4412           1 :            vec 5
    4413             :            "Checking remote compress commands `%s', `%s' for sanity"
    4414           1 :            compress decompress)
    4415           1 :           (unless (tramp-send-command-and-check
    4416           1 :                    vec (format "echo %s | %s | %s" magic compress decompress) t)
    4417           1 :             (throw 'next nil))
    4418           1 :           (setq found t)))
    4419             : 
    4420             :       ;; Did we find something?
    4421           1 :       (if found
    4422           1 :           (progn
    4423             :             ;; Set connection properties.  Since the commands are
    4424             :             ;; risky (due to output direction), we cache them in the
    4425             :             ;; process cache.
    4426           1 :             (tramp-message
    4427           1 :              vec 5 "Using inline transfer compress command `%s'" compress)
    4428           1 :             (tramp-set-connection-property p "inline-compress" compress)
    4429           1 :             (tramp-message
    4430           1 :              vec 5 "Using inline transfer decompress command `%s'" decompress)
    4431           1 :             (tramp-set-connection-property p "inline-decompress" decompress))
    4432             : 
    4433           0 :         (tramp-set-connection-property p "inline-compress" nil)
    4434           0 :         (tramp-set-connection-property p "inline-decompress" nil)
    4435           0 :         (tramp-message
    4436           1 :          vec 2 "Couldn't find an inline transfer compress command")))))
    4437             : 
    4438             : (defun tramp-compute-multi-hops (vec)
    4439             :   "Expands VEC according to `tramp-default-proxies-alist'."
    4440          71 :   (let ((target-alist `(,vec))
    4441          71 :         (hops (or (tramp-file-name-hop vec) ""))
    4442          71 :         (item vec)
    4443             :         choices proxy)
    4444             : 
    4445             :     ;; Ad-hoc proxy definitions.
    4446          71 :     (dolist (proxy (reverse (split-string hops tramp-postfix-hop-regexp 'omit)))
    4447           0 :       (let ((user (tramp-file-name-user item))
    4448           0 :             (host (tramp-file-name-host item))
    4449           0 :             (proxy (concat
    4450           0 :                     (tramp-prefix-format) proxy (tramp-postfix-host-format))))
    4451           0 :         (tramp-message
    4452           0 :          vec 5 "Add proxy (\"%s\" \"%s\" \"%s\")"
    4453           0 :          (and (stringp host) (regexp-quote host))
    4454           0 :          (and (stringp user) (regexp-quote user))
    4455           0 :          proxy)
    4456             :         ;; Add the hop.
    4457           0 :         (add-to-list
    4458             :          'tramp-default-proxies-alist
    4459           0 :          (list (and (stringp host) (regexp-quote host))
    4460           0 :                (and (stringp user) (regexp-quote user))
    4461           0 :                proxy))
    4462          71 :         (setq item (tramp-dissect-file-name proxy))))
    4463             :     ;; Save the new value.
    4464          71 :     (when (and hops tramp-save-ad-hoc-proxies)
    4465           0 :       (customize-save-variable
    4466          71 :        'tramp-default-proxies-alist tramp-default-proxies-alist))
    4467             : 
    4468             :     ;; Look for proxy hosts to be passed.
    4469          71 :     (setq choices tramp-default-proxies-alist)
    4470          71 :     (while choices
    4471           0 :       (setq item (pop choices)
    4472           0 :             proxy (eval (nth 2 item)))
    4473           0 :       (when (and
    4474             :              ;; Host.
    4475           0 :              (string-match (or (eval (nth 0 item)) "")
    4476           0 :                            (or (tramp-file-name-host (car target-alist)) ""))
    4477             :              ;; User.
    4478           0 :              (string-match (or (eval (nth 1 item)) "")
    4479           0 :                            (or (tramp-file-name-user (car target-alist)) "")))
    4480           0 :         (if (null proxy)
    4481             :             ;; No more hops needed.
    4482           0 :             (setq choices nil)
    4483             :           ;; Replace placeholders.
    4484           0 :           (setq proxy
    4485           0 :                 (format-spec
    4486           0 :                  proxy
    4487           0 :                  (format-spec-make
    4488           0 :                   ?u (or (tramp-file-name-user (car target-alist)) "")
    4489           0 :                   ?h (or (tramp-file-name-host (car target-alist)) ""))))
    4490           0 :           (with-parsed-tramp-file-name proxy l
    4491             :             ;; Add the hop.
    4492           0 :             (push l target-alist)
    4493             :             ;; Start next search.
    4494          71 :             (setq choices tramp-default-proxies-alist)))))
    4495             : 
    4496             :     ;; Foreign and out-of-band methods are not supported for multi-hops.
    4497          71 :     (when (cdr target-alist)
    4498           0 :       (setq choices target-alist)
    4499           0 :       (while (setq item (pop choices))
    4500           0 :         (when (or (not (tramp-get-method-parameter item 'tramp-login-program))
    4501           0 :                   (tramp-get-method-parameter item 'tramp-copy-program))
    4502           0 :           (tramp-error
    4503           0 :            vec 'file-error
    4504             :            "Method `%s' is not supported for multi-hops."
    4505          71 :            (tramp-file-name-method item)))))
    4506             : 
    4507             :     ;; In case the host name is not used for the remote shell
    4508             :     ;; command, the user could be misguided by applying a random
    4509             :     ;; host name.
    4510          71 :     (let* ((v (car target-alist))
    4511          71 :            (method (tramp-file-name-method v))
    4512          71 :            (host (tramp-file-name-host v)))
    4513          71 :       (unless
    4514          71 :           (or
    4515             :            ;; There are multi-hops.
    4516          71 :            (cdr target-alist)
    4517             :            ;; The host name is used for the remote shell command.
    4518          71 :            (member '("%h") (tramp-get-method-parameter v 'tramp-login-args))
    4519             :            ;; The host is local.  We cannot use `tramp-local-host-p'
    4520             :            ;; here, because it opens a connection as well.
    4521          71 :            (string-match tramp-local-host-regexp host))
    4522           0 :         (tramp-error
    4523           0 :          v 'file-error
    4524             :          "Host `%s' looks like a remote host, `%s' can only use the local host"
    4525          71 :          host method)))
    4526             : 
    4527             :     ;; Result.
    4528          71 :     target-alist))
    4529             : 
    4530             : (defun tramp-ssh-controlmaster-options (vec)
    4531             :   "Return the Control* arguments of the local ssh."
    4532          71 :   (cond
    4533             :    ;; No options to be computed.
    4534          71 :    ((or (null tramp-use-ssh-controlmaster-options)
    4535          71 :         (null (assoc "%c" (tramp-get-method-parameter vec 'tramp-login-args))))
    4536             :     "")
    4537             : 
    4538             :    ;; There is already a value to be used.
    4539           0 :    ((stringp tramp-ssh-controlmaster-options) tramp-ssh-controlmaster-options)
    4540             : 
    4541             :    ;; Determine the options.
    4542           0 :    (t (setq tramp-ssh-controlmaster-options "")
    4543           0 :       (let ((case-fold-search t))
    4544           0 :         (ignore-errors
    4545           0 :           (when (executable-find "ssh")
    4546           0 :             (with-tramp-progress-reporter
    4547           0 :                 vec 4  "Computing ControlMaster options"
    4548           0 :               (with-temp-buffer
    4549           0 :                 (tramp-call-process vec "ssh" nil t nil "-o" "ControlMaster")
    4550           0 :                 (goto-char (point-min))
    4551           0 :                 (when (search-forward-regexp "missing.+argument" nil t)
    4552           0 :                   (setq tramp-ssh-controlmaster-options
    4553           0 :                         "-o ControlMaster=auto")))
    4554           0 :               (unless (zerop (length tramp-ssh-controlmaster-options))
    4555           0 :                 (with-temp-buffer
    4556             :                   ;; We use a non-existing IP address, in order to
    4557             :                   ;; avoid useless connections, and DNS timeouts.
    4558             :                   ;; Setting ConnectTimeout is needed since OpenSSH 7.
    4559           0 :                   (tramp-call-process
    4560           0 :                    vec "ssh" nil t nil
    4561           0 :                    "-o" "ConnectTimeout=1" "-o" "ControlPath=%C" "0.0.0.1")
    4562           0 :                   (goto-char (point-min))
    4563           0 :                   (setq tramp-ssh-controlmaster-options
    4564           0 :                         (concat tramp-ssh-controlmaster-options
    4565           0 :                                 (if (search-forward-regexp "unknown.+key" nil t)
    4566             :                                     " -o ControlPath='tramp.%%r@%%h:%%p'"
    4567           0 :                                   " -o ControlPath='tramp.%%C'"))))
    4568           0 :                 (with-temp-buffer
    4569           0 :                   (tramp-call-process vec "ssh" nil t nil "-o" "ControlPersist")
    4570           0 :                   (goto-char (point-min))
    4571           0 :                   (when (search-forward-regexp "missing.+argument" nil t)
    4572           0 :                     (setq tramp-ssh-controlmaster-options
    4573           0 :                           (concat tramp-ssh-controlmaster-options
    4574           0 :                                   " -o ControlPersist=no")))))))))
    4575          71 :       tramp-ssh-controlmaster-options)))
    4576             : 
    4577             : (defun tramp-maybe-open-connection (vec)
    4578             :   "Maybe open a connection VEC.
    4579             : Does not do anything if a connection is already open, but re-opens the
    4580             : connection if a previous connection has died for some reason."
    4581       10661 :   (let ((p (tramp-get-connection-process vec))
    4582       10661 :         (process-name (tramp-get-connection-property vec "process-name" nil))
    4583       10661 :         (process-environment (copy-sequence process-environment))
    4584       10661 :         (pos (with-current-buffer (tramp-get-connection-buffer vec) (point))))
    4585             : 
    4586             :     ;; If Tramp opens the same connection within a short time frame,
    4587             :     ;; there is a problem.  We shall signal this.
    4588       10661 :     (unless (or (process-live-p p)
    4589          71 :                 (not (tramp-file-name-equal-p
    4590          71 :                       vec (car tramp-current-connection)))
    4591           0 :                 (> (tramp-time-diff
    4592           0 :                     (current-time) (cdr tramp-current-connection))
    4593       10661 :                    (or tramp-connection-min-time-diff 0)))
    4594       10661 :       (throw 'suppress 'suppress))
    4595             : 
    4596             :     ;; If too much time has passed since last command was sent, look
    4597             :     ;; whether process is still alive.  If it isn't, kill it.  When
    4598             :     ;; using ssh, it can sometimes happen that the remote end has hung
    4599             :     ;; up but the local ssh client doesn't recognize this until it
    4600             :     ;; tries to send some data to the remote end.  So that's why we
    4601             :     ;; try to send a command from time to time, then look again
    4602             :     ;; whether the process is really alive.
    4603       10661 :     (condition-case nil
    4604       10661 :         (when (and (> (tramp-time-diff
    4605       10661 :                        (current-time)
    4606       10661 :                        (tramp-get-connection-property
    4607       10661 :                         p "last-cmd-time" '(0 0 0)))
    4608       10661 :                       60)
    4609       10661 :                    (process-live-p p))
    4610           0 :           (tramp-send-command vec "echo are you awake" t t)
    4611           0 :           (unless (and (process-live-p p)
    4612           0 :                        (tramp-wait-for-output p 10))
    4613             :             ;; The error will be caught locally.
    4614       10661 :             (tramp-error vec 'file-error "Awake did fail")))
    4615             :       (file-error
    4616           0 :        (tramp-cleanup-connection vec t)
    4617       10661 :        (setq p nil)))
    4618             : 
    4619             :     ;; New connection must be opened.
    4620       10661 :     (condition-case err
    4621       10661 :         (unless (process-live-p p)
    4622             : 
    4623             :           ;; During completion, don't reopen a new connection.  We
    4624             :           ;; check this for the process related to
    4625             :           ;; `tramp-buffer-name'; otherwise `start-file-process'
    4626             :           ;; wouldn't run ever when `non-essential' is non-nil.
    4627          71 :           (when (and (tramp-completion-mode-p)
    4628          71 :                      (null (get-process (tramp-buffer-name vec))))
    4629          71 :             (throw 'non-essential 'non-essential))
    4630             : 
    4631          71 :           (with-tramp-progress-reporter
    4632         142 :               vec 3
    4633         142 :               (if (zerop (length (tramp-file-name-user vec)))
    4634         142 :                   (format "Opening connection for %s using %s"
    4635         142 :                           (tramp-file-name-host vec)
    4636         142 :                           (tramp-file-name-method vec))
    4637           0 :                 (format "Opening connection for %s@%s using %s"
    4638           0 :                         (tramp-file-name-user vec)
    4639           0 :                         (tramp-file-name-host vec)
    4640         142 :                         (tramp-file-name-method vec)))
    4641             : 
    4642          71 :             (catch 'uname-changed
    4643             :               ;; Start new process.
    4644          71 :               (when (and p (processp p))
    4645          71 :                 (delete-process p))
    4646          71 :               (setenv "TERM" tramp-terminal-type)
    4647          71 :               (setenv "LC_ALL" (tramp-get-local-locale vec))
    4648          71 :               (if (stringp tramp-histfile-override)
    4649          71 :                   (setenv "HISTFILE" tramp-histfile-override)
    4650           0 :                 (if tramp-histfile-override
    4651           0 :                     (progn
    4652           0 :                       (setenv "HISTFILE")
    4653           0 :                       (setenv "HISTFILESIZE" "0")
    4654          71 :                       (setenv "HISTSIZE" "0"))))
    4655          71 :               (setenv "PROMPT_COMMAND")
    4656          71 :               (setenv "PS1" tramp-initial-end-of-output)
    4657          71 :               (unless (stringp tramp-encoding-shell)
    4658          71 :                 (tramp-error vec 'file-error "`tramp-encoding-shell' not set"))
    4659          71 :               (let* ((target-alist (tramp-compute-multi-hops vec))
    4660             :                      ;; We will apply `tramp-ssh-controlmaster-options'
    4661             :                      ;; only for the first hop.
    4662          71 :                      (options (tramp-ssh-controlmaster-options vec))
    4663          71 :                      (process-connection-type tramp-process-connection-type)
    4664             :                      (process-adaptive-read-buffering nil)
    4665             :                      ;; There are unfortunate settings for "cmdproxy" on
    4666             :                      ;; W32 systems.
    4667             :                      (process-coding-system-alist nil)
    4668             :                      (coding-system-for-read nil)
    4669             :                      ;; This must be done in order to avoid our file
    4670             :                      ;; name handler.
    4671          71 :                      (p (let ((default-directory
    4672          71 :                                 (tramp-compat-temporary-file-directory)))
    4673          71 :                           (apply
    4674             :                            'start-process
    4675          71 :                            (tramp-get-connection-name vec)
    4676          71 :                            (tramp-get-connection-buffer vec)
    4677          71 :                            (if tramp-encoding-command-interactive
    4678          71 :                                (list tramp-encoding-shell
    4679          71 :                                      tramp-encoding-command-interactive)
    4680          71 :                              (list tramp-encoding-shell))))))
    4681             : 
    4682             :                 ;; Set sentinel and query flag.
    4683          71 :                 (tramp-set-connection-property p "vector" vec)
    4684          71 :                 (set-process-sentinel p 'tramp-process-sentinel)
    4685          71 :                 (process-put p 'adjust-window-size-function 'ignore)
    4686          71 :                 (set-process-query-on-exit-flag p nil)
    4687          71 :                 (setq tramp-current-connection (cons vec (current-time))
    4688          71 :                       tramp-current-host (system-name))
    4689             : 
    4690          71 :                 (tramp-message
    4691          71 :                  vec 6 "%s" (mapconcat 'identity (process-command p) " "))
    4692             : 
    4693             :                 ;; Check whether process is alive.
    4694          71 :                 (tramp-barf-if-no-shell-prompt
    4695          71 :                  p 10
    4696          71 :                  "Couldn't find local shell prompt for %s" tramp-encoding-shell)
    4697             : 
    4698             :                 ;; Now do all the connections as specified.
    4699         142 :                 (while target-alist
    4700          71 :                   (let* ((hop (car target-alist))
    4701          71 :                          (l-method (tramp-file-name-method hop))
    4702          71 :                          (l-user (tramp-file-name-user hop))
    4703          71 :                          (l-domain (tramp-file-name-domain hop))
    4704          71 :                          (l-host (tramp-file-name-host hop))
    4705          71 :                          (l-port (tramp-file-name-port hop))
    4706             :                          (login-program
    4707          71 :                           (tramp-get-method-parameter hop 'tramp-login-program))
    4708             :                          (login-args
    4709          71 :                           (tramp-get-method-parameter hop 'tramp-login-args))
    4710             :                          (login-env
    4711          71 :                           (tramp-get-method-parameter hop 'tramp-login-env))
    4712             :                          (async-args
    4713          71 :                           (tramp-get-method-parameter hop 'tramp-async-args))
    4714             :                          (connection-timeout
    4715          71 :                           (tramp-get-method-parameter
    4716          71 :                            hop 'tramp-connection-timeout))
    4717          71 :                          (command login-program)
    4718             :                          ;; We don't create the temporary file.  In
    4719             :                          ;; fact, it is just a prefix for the
    4720             :                          ;; ControlPath option of ssh; the real
    4721             :                          ;; temporary file has another name, and it is
    4722             :                          ;; created and protected by ssh.  It is also
    4723             :                          ;; removed by ssh when the connection is
    4724             :                          ;; closed.  The temporary file name is cached
    4725             :                          ;; in the main connection process, therefore
    4726             :                          ;; we cannot use `tramp-get-connection-process'.
    4727             :                          (tmpfile
    4728          71 :                           (with-tramp-connection-property
    4729         116 :                               (get-process (tramp-buffer-name vec)) "temp-file"
    4730          45 :                             (make-temp-name
    4731          45 :                              (expand-file-name
    4732          45 :                               tramp-temp-name-prefix
    4733          71 :                               (tramp-compat-temporary-file-directory)))))
    4734             :                          spec r-shell)
    4735             : 
    4736             :                     ;; Add arguments for asynchronous processes.
    4737          71 :                     (when (and process-name async-args)
    4738          71 :                       (setq login-args (append async-args login-args)))
    4739             : 
    4740             :                     ;; Check, whether there is a restricted shell.
    4741          71 :                     (dolist (elt tramp-restricted-shell-hosts-alist)
    4742           0 :                       (when (string-match elt tramp-current-host)
    4743          71 :                         (setq r-shell t)))
    4744             : 
    4745             :                     ;; Set variables for computing the prompt for
    4746             :                     ;; reading password.
    4747          71 :                     (setq tramp-current-method l-method
    4748          71 :                           tramp-current-user   l-user
    4749          71 :                           tramp-current-domain l-domain
    4750          71 :                           tramp-current-host   l-host
    4751          71 :                           tramp-current-port   l-port)
    4752             : 
    4753             :                     ;; Add login environment.
    4754          71 :                     (when login-env
    4755           0 :                       (setq
    4756             :                        login-env
    4757           0 :                        (mapcar
    4758             :                         (lambda (x)
    4759           0 :                           (setq x (mapcar (lambda (y) (format-spec y spec)) x))
    4760           0 :                           (unless (member "" x) (mapconcat 'identity x " ")))
    4761           0 :                         login-env))
    4762           0 :                       (while login-env
    4763           0 :                         (setq command
    4764           0 :                               (format
    4765             :                                "%s=%s %s"
    4766           0 :                                (pop login-env)
    4767           0 :                                (tramp-shell-quote-argument (pop login-env))
    4768           0 :                                command)))
    4769          71 :                       (setq command (concat "env " command)))
    4770             : 
    4771             :                     ;; Replace `login-args' place holders.
    4772          71 :                     (setq
    4773          71 :                      l-host (or l-host "")
    4774          71 :                      l-user (or l-user "")
    4775          71 :                      l-port (or l-port "")
    4776          71 :                      spec (format-spec-make ?t tmpfile)
    4777          71 :                      options (format-spec options spec)
    4778          71 :                      spec (format-spec-make
    4779          71 :                            ?h l-host ?u l-user ?p l-port ?c options)
    4780             :                      command
    4781          71 :                      (concat
    4782             :                       ;; We do not want to see the trailing local
    4783             :                       ;; prompt in `start-file-process'.
    4784          71 :                       (unless r-shell "exec ")
    4785          71 :                       command " "
    4786          71 :                       (mapconcat
    4787             :                        (lambda (x)
    4788         142 :                          (setq x (mapcar (lambda (y) (format-spec y spec)) x))
    4789          71 :                          (unless (member "" x) (mapconcat 'identity x " ")))
    4790          71 :                        login-args " ")
    4791             :                       ;; Local shell could be a Windows COMSPEC.  It
    4792             :                       ;; doesn't know the ";" syntax, but we must exit
    4793             :                       ;; always for `start-file-process'.  It could
    4794             :                       ;; also be a restricted shell, which does not
    4795             :                       ;; allow "exec".
    4796          71 :                       (when r-shell " && exit || exit")))
    4797             : 
    4798             :                     ;; Send the command.
    4799          71 :                     (tramp-message vec 3 "Sending command `%s'" command)
    4800          71 :                     (tramp-send-command vec command t t)
    4801          71 :                     (tramp-process-actions
    4802          71 :                      p vec
    4803          71 :                      (min
    4804          71 :                       pos (with-current-buffer (process-buffer p) (point-max)))
    4805          71 :                      tramp-actions-before-shell
    4806          71 :                      (or connection-timeout tramp-connection-timeout))
    4807          71 :                     (tramp-message
    4808          71 :                      vec 3 "Found remote shell prompt on `%s'" l-host))
    4809             :                   ;; Next hop.
    4810          71 :                   (setq options ""
    4811          71 :                         target-alist (cdr target-alist)))
    4812             : 
    4813             :                 ;; Set connection-local variables.
    4814          71 :                 (tramp-set-connection-local-variables vec)
    4815             : 
    4816             :                 ;; Make initial shell settings.
    4817          71 :                 (tramp-open-connection-setup-interactive-shell p vec)
    4818             : 
    4819             :                 ;; Mark it as connected.
    4820       10661 :                 (tramp-set-connection-property p "connected" t)))))
    4821             : 
    4822             :       ;; Cleanup, and propagate the signal.
    4823             :       ((error quit)
    4824           0 :        (tramp-cleanup-connection vec t)
    4825       10661 :        (signal (car err) (cdr err))))))
    4826             : 
    4827             : (defun tramp-send-command (vec command &optional neveropen nooutput)
    4828             :   "Send the COMMAND to connection VEC.
    4829             : Erases temporary buffer before sending the command.  If optional
    4830             : arg NEVEROPEN is non-nil, never try to open the connection.  This
    4831             : is meant to be used from `tramp-maybe-open-connection' only.  The
    4832             : function waits for output unless NOOUTPUT is set."
    4833       11530 :   (unless neveropen (tramp-maybe-open-connection vec))
    4834       11530 :   (let ((p (tramp-get-connection-process vec)))
    4835       11530 :     (when (tramp-get-connection-property p "remote-echo" nil)
    4836             :       ;; We mark the command string that it can be erased in the output buffer.
    4837           0 :       (tramp-set-connection-property p "check-remote-echo" t)
    4838             :       ;; If we put `tramp-echo-mark' after a trailing newline (which
    4839             :       ;; is assumed to be unquoted) `tramp-send-string' doesn't see
    4840             :       ;; that newline and adds `tramp-rsh-end-of-line' right after
    4841             :       ;; `tramp-echo-mark', so the remote shell sees two consecutive
    4842             :       ;; trailing line endings and sends two prompts after executing
    4843             :       ;; the command, which confuses `tramp-wait-for-output'.
    4844           0 :       (when (and (not (string= command ""))
    4845           0 :                  (string-equal (substring command -1) "\n"))
    4846           0 :         (setq command (substring command 0 -1)))
    4847             :       ;; No need to restore a trailing newline here since `tramp-send-string'
    4848             :       ;; makes sure that the string ends in `tramp-rsh-end-of-line', anyway.
    4849       11530 :       (setq command (format "%s%s%s" tramp-echo-mark command tramp-echo-mark)))
    4850             :     ;; Send the command.
    4851       11530 :     (tramp-message vec 6 "%s" command)
    4852       11530 :     (tramp-send-string vec command)
    4853       11530 :     (unless nooutput (tramp-wait-for-output p))))
    4854             : 
    4855             : (defun tramp-wait-for-output (proc &optional timeout)
    4856             :   "Wait for output from remote command."
    4857       11432 :   (unless (buffer-live-p (process-buffer proc))
    4858           0 :     (delete-process proc)
    4859       11432 :     (tramp-error proc 'file-error "Process `%s' not available, try again" proc))
    4860       11432 :   (with-current-buffer (process-buffer proc)
    4861       11432 :     (let* (;; Initially, `tramp-end-of-output' is "#$ ".  There might
    4862             :            ;; be leading escape sequences, which must be ignored.
    4863             :            ;; Busyboxes built with the EDITING_ASK_TERMINAL config
    4864             :            ;; option send also escape sequences, which must be
    4865             :            ;; ignored.
    4866       11432 :            (regexp (format "[^#$\n]*%s\\(%s\\)?\r?$"
    4867       11432 :                            (regexp-quote tramp-end-of-output)
    4868       11432 :                            tramp-device-escape-sequence-regexp))
    4869             :            ;; Sometimes, the commands do not return a newline but a
    4870             :            ;; null byte before the shell prompt, for example "git
    4871             :            ;; ls-files -c -z ...".
    4872       11432 :            (regexp1 (format "\\(^\\|\000\\)%s" regexp))
    4873       11432 :            (found (tramp-wait-for-regexp proc timeout regexp1)))
    4874       11432 :       (if found
    4875       11432 :           (let (buffer-read-only)
    4876             :             ;; A simple-minded busybox has sent " ^H" sequences.
    4877             :             ;; Delete them.
    4878       11432 :             (goto-char (point-min))
    4879       11432 :             (when (re-search-forward "^\\(.\b\\)+$" (point-at-eol) t)
    4880           0 :               (forward-line 1)
    4881       11432 :               (delete-region (point-min) (point)))
    4882             :             ;; Delete the prompt.
    4883       11432 :             (goto-char (point-max))
    4884       11432 :             (re-search-backward regexp nil t)
    4885       11432 :             (delete-region (point) (point-max)))
    4886           0 :         (if timeout
    4887           0 :             (tramp-error
    4888           0 :              proc 'file-error
    4889             :              "[[Remote prompt `%s' not found in %d secs]]"
    4890           0 :              tramp-end-of-output timeout)
    4891           0 :           (tramp-error
    4892           0 :            proc 'file-error
    4893       11432 :            "[[Remote prompt `%s' not found]]" tramp-end-of-output)))
    4894             :       ;; Return value is whether end-of-output sentinel was found.
    4895       11432 :       found)))
    4896             : 
    4897             : (defun tramp-send-command-and-check
    4898             :   (vec command &optional subshell dont-suppress-err)
    4899             :   "Run COMMAND and check its exit status.
    4900             : Sends `echo $?' along with the COMMAND for checking the exit status.
    4901             : If COMMAND is nil, just sends `echo $?'.  Returns t if the exit
    4902             : status is 0, and nil otherwise.
    4903             : 
    4904             : If the optional argument SUBSHELL is non-nil, the command is
    4905             : executed in a subshell, ie surrounded by parentheses.  If
    4906             : DONT-SUPPRESS-ERR is non-nil, stderr won't be sent to /dev/null."
    4907        9101 :   (tramp-send-command
    4908        9101 :    vec
    4909        9101 :    (concat (if subshell "( " "")
    4910        9101 :            command
    4911        9101 :            (if command (if dont-suppress-err "; " " 2>/dev/null; ") "")
    4912             :            "echo tramp_exit_status $?"
    4913        9101 :            (if subshell " )" "")))
    4914        9101 :   (with-current-buffer (tramp-get-connection-buffer vec)
    4915        9101 :     (goto-char (point-max))
    4916        9101 :     (unless (re-search-backward "tramp_exit_status [0-9]+" nil t)
    4917           0 :       (tramp-error
    4918        9101 :        vec 'file-error "Couldn't find exit status of `%s'" command))
    4919        9101 :     (skip-chars-forward "^ ")
    4920        9101 :     (prog1
    4921        9101 :         (zerop (read (current-buffer)))
    4922        9101 :       (let (buffer-read-only)
    4923        9101 :         (delete-region (match-beginning 0) (point-max))))))
    4924             : 
    4925             : (defun tramp-barf-unless-okay (vec command fmt &rest args)
    4926             :   "Run COMMAND, check exit status, throw error if exit status not okay.
    4927             : Similar to `tramp-send-command-and-check' but accepts two more arguments
    4928             : FMT and ARGS which are passed to `error'."
    4929        2982 :   (or (tramp-send-command-and-check vec command)
    4930        2976 :       (apply 'tramp-error vec 'file-error fmt args)))
    4931             : 
    4932             : (defun tramp-send-command-and-read (vec command &optional noerror marker)
    4933             :   "Run COMMAND and return the output, which must be a Lisp expression.
    4934             : If MARKER is a regexp, read the output after that string.
    4935             : In case there is no valid Lisp expression and NOERROR is nil, it
    4936             : raises an error."
    4937        1641 :   (when (if noerror
    4938         166 :             (tramp-send-command-and-check vec command)
    4939        1475 :           (tramp-barf-unless-okay
    4940        1641 :            vec command "`%s' returns with error" command))
    4941        1641 :     (with-current-buffer (tramp-get-connection-buffer vec)
    4942        1641 :       (goto-char (point-min))
    4943             :       ;; Read the marker.
    4944        1641 :       (when (stringp marker)
    4945           0 :         (condition-case nil
    4946           0 :             (re-search-forward marker)
    4947           0 :           (error (unless noerror
    4948           0 :                    (tramp-error
    4949           0 :                     vec 'file-error
    4950             :                     "`%s' does not return the marker `%s': `%s'"
    4951        1641 :                     command marker (buffer-string))))))
    4952             :       ;; Read the expression.
    4953        1641 :       (condition-case nil
    4954        1641 :           (prog1 (read (current-buffer))
    4955             :             ;; Error handling.
    4956        1641 :             (when (re-search-forward "\\S-" (point-at-eol) t)
    4957        1641 :               (error nil)))
    4958           0 :         (error (unless noerror
    4959           0 :                  (tramp-error
    4960           0 :                   vec 'file-error
    4961             :                   "`%s' does not return a valid Lisp expression: `%s'"
    4962        1641 :                   command (buffer-string))))))))
    4963             : 
    4964             : (defun tramp-convert-file-attributes (vec attr)
    4965             :   "Convert `file-attributes' ATTR generated by perl script, stat or ls.
    4966             : Convert file mode bits to string and set virtual device number.
    4967             : Return ATTR."
    4968        1795 :   (when attr
    4969             :     ;; Remove color escape sequences from symlink.
    4970        1373 :     (when (stringp (car attr))
    4971          95 :       (while (string-match tramp-display-escape-sequence-regexp (car attr))
    4972        1373 :         (setcar attr (replace-match "" nil nil (car attr)))))
    4973             :     ;; Convert uid and gid.  Use `tramp-unknown-id-integer' as
    4974             :     ;; indication of unusable value.
    4975        1373 :     (when (and (numberp (nth 2 attr)) (< (nth 2 attr) 0))
    4976        1373 :       (setcar (nthcdr 2 attr) tramp-unknown-id-integer))
    4977        1373 :     (when (and (floatp (nth 2 attr))
    4978        1373 :                (<= (nth 2 attr) most-positive-fixnum))
    4979        1373 :       (setcar (nthcdr 2 attr) (round (nth 2 attr))))
    4980        1373 :     (when (and (numberp (nth 3 attr)) (< (nth 3 attr) 0))
    4981        1373 :       (setcar (nthcdr 3 attr) tramp-unknown-id-integer))
    4982        1373 :     (when (and (floatp (nth 3 attr))
    4983        1373 :                (<= (nth 3 attr) most-positive-fixnum))
    4984        1373 :       (setcar (nthcdr 3 attr) (round (nth 3 attr))))
    4985             :     ;; Convert last access time.
    4986        1373 :     (unless (listp (nth 4 attr))
    4987         841 :       (setcar (nthcdr 4 attr)
    4988         841 :               (list (floor (nth 4 attr) 65536)
    4989        1373 :                     (floor (mod (nth 4 attr) 65536)))))
    4990             :     ;; Convert last modification time.
    4991        1373 :     (unless (listp (nth 5 attr))
    4992         841 :       (setcar (nthcdr 5 attr)
    4993         841 :               (list (floor (nth 5 attr) 65536)
    4994        1373 :                     (floor (mod (nth 5 attr) 65536)))))
    4995             :     ;; Convert last status change time.
    4996        1373 :     (unless (listp (nth 6 attr))
    4997         841 :       (setcar (nthcdr 6 attr)
    4998         841 :               (list (floor (nth 6 attr) 65536)
    4999        1373 :                     (floor (mod (nth 6 attr) 65536)))))
    5000             :     ;; Convert file size.
    5001        1373 :     (when (< (nth 7 attr) 0)
    5002        1373 :       (setcar (nthcdr 7 attr) -1))
    5003        1373 :     (when (and (floatp (nth 7 attr))
    5004        1373 :                (<= (nth 7 attr) most-positive-fixnum))
    5005        1373 :       (setcar (nthcdr 7 attr) (round (nth 7 attr))))
    5006             :     ;; Convert file mode bits to string.
    5007        1373 :     (unless (stringp (nth 8 attr))
    5008         237 :       (setcar (nthcdr 8 attr) (tramp-file-mode-from-int (nth 8 attr)))
    5009         237 :       (when (stringp (car attr))
    5010        1373 :         (aset (nth 8 attr) 0 ?l)))
    5011             :     ;; Convert directory indication bit.
    5012        1373 :     (when (string-match "^d" (nth 8 attr))
    5013        1373 :       (setcar attr t))
    5014             :     ;; Convert symlink from `tramp-do-file-attributes-with-stat'.
    5015        1373 :     (when (consp (car attr))
    5016         439 :       (if (and (stringp (caar attr))
    5017         439 :                (string-match ".+ -> .\\(.+\\)." (caar attr)))
    5018         123 :           (setcar attr (match-string 1 (caar attr)))
    5019        1373 :         (setcar attr nil)))
    5020             :     ;; Set file's gid change bit.
    5021        1373 :     (setcar (nthcdr 9 attr)
    5022        1373 :             (if (numberp (nth 3 attr))
    5023        1232 :                 (not (= (nth 3 attr)
    5024        1232 :                         (tramp-get-remote-gid vec 'integer)))
    5025         141 :               (not (string-equal
    5026         141 :                     (nth 3 attr)
    5027        1373 :                     (tramp-get-remote-gid vec 'string)))))
    5028             :     ;; Convert inode.
    5029        1373 :     (unless (listp (nth 10 attr))
    5030        1136 :       (setcar (nthcdr 10 attr)
    5031        1136 :               (condition-case nil
    5032        1136 :                   (let ((high (nth 10 attr))
    5033             :                         middle low)
    5034        1136 :                     (if (<= high most-positive-fixnum)
    5035        1136 :                         (floor high)
    5036             :                       ;; The low 16 bits.
    5037           0 :                       (setq low (mod high #x10000)
    5038           0 :                             high (/ high #x10000))
    5039           0 :                       (if (<= high most-positive-fixnum)
    5040           0 :                           (cons (floor high) (floor low))
    5041             :                         ;; The middle 24 bits.
    5042           0 :                         (setq middle (mod high #x1000000)
    5043           0 :                               high (/ high #x1000000))
    5044        1136 :                         (cons (floor high) (cons (floor middle) (floor low))))))
    5045             :                 ;; Inodes can be incredible huge.  We must hide this.
    5046        1373 :                 (error (tramp-get-inode vec)))))
    5047             :     ;; Set virtual device number.
    5048        1373 :     (setcar (nthcdr 11 attr)
    5049        1373 :             (tramp-get-device vec))
    5050        1795 :     attr))
    5051             : 
    5052             : (defun tramp-shell-case-fold (string)
    5053             :   "Converts STRING to shell glob pattern which ignores case."
    5054           0 :   (mapconcat
    5055             :    (lambda (c)
    5056           0 :      (if (equal (downcase c) (upcase c))
    5057           0 :          (vector c)
    5058           0 :        (format "[%c%c]" (downcase c) (upcase c))))
    5059           0 :    string
    5060           0 :    ""))
    5061             : 
    5062             : (defun tramp-make-copy-program-file-name (vec)
    5063             :   "Create a file name suitable for `scp', `pscp', or `nc' and workalikes."
    5064           0 :   (let ((method (tramp-file-name-method vec))
    5065           0 :         (user (tramp-file-name-user vec))
    5066           0 :         (host (tramp-file-name-host vec))
    5067             :         (localname
    5068           0 :          (directory-file-name (tramp-file-name-unquote-localname vec))))
    5069           0 :     (when (string-match tramp-ipv6-regexp host)
    5070           0 :       (setq host (format "[%s]" host)))
    5071           0 :     (unless (string-match "ftp$" method)
    5072           0 :       (setq localname (tramp-shell-quote-argument localname)))
    5073           0 :     (cond
    5074           0 :      ((tramp-get-method-parameter vec 'tramp-remote-copy-program)
    5075           0 :       localname)
    5076           0 :      ((not (zerop (length user)))
    5077           0 :       (format "%s@%s:%s" user host (shell-quote-argument localname)))
    5078           0 :      (t (format "%s:%s" host (shell-quote-argument localname))))))
    5079             : 
    5080             : (defun tramp-method-out-of-band-p (vec size)
    5081             :   "Return t if this is an out-of-band method, nil otherwise."
    5082         843 :   (and
    5083             :    ;; It shall be an out-of-band method.
    5084         843 :    (tramp-get-method-parameter vec 'tramp-copy-program)
    5085             :    ;; There must be a size, otherwise the file doesn't exist.
    5086           0 :    (numberp size)
    5087             :    ;; Either the file size is large enough, or (in rare cases) there
    5088             :    ;; does not exist a remote encoding.
    5089           0 :    (or (null tramp-copy-size-limit)
    5090           0 :        (> size tramp-copy-size-limit)
    5091         843 :        (null (tramp-get-inline-coding vec "remote-encoding" size)))))
    5092             : 
    5093             : ;; Variables local to connection.
    5094             : 
    5095             : (defun tramp-get-remote-path (vec)
    5096             :   "Compile list of remote directories for $PATH.
    5097             : Nonexistent directories are removed from spec."
    5098         207 :   (with-tramp-connection-property
    5099             :       ;; When `tramp-own-remote-path' is in `tramp-remote-path', we
    5100             :       ;; cache the result for the session only.  Otherwise, the result
    5101             :       ;; is cached persistently.
    5102         270 :       (if (memq 'tramp-own-remote-path tramp-remote-path)
    5103           0 :           (tramp-get-connection-process vec)
    5104         270 :         vec)
    5105             :       "remote-path"
    5106          63 :     (let* ((remote-path (copy-tree tramp-remote-path))
    5107          63 :            (elt1 (memq 'tramp-default-remote-path remote-path))
    5108          63 :            (elt2 (memq 'tramp-own-remote-path remote-path))
    5109             :            (default-remote-path
    5110          63 :              (when elt1
    5111          63 :                (or
    5112          63 :                 (tramp-send-command-and-read
    5113          63 :                  vec "echo \\\"`getconf PATH 2>/dev/null`\\\"" 'noerror)
    5114             :                 ;; Default if "getconf" is not available.
    5115           0 :                 (progn
    5116           0 :                   (tramp-message
    5117           0 :                    vec 3
    5118             :                    "`getconf PATH' not successful, using default value \"%s\"."
    5119           0 :                    "/bin:/usr/bin")
    5120          63 :                   "/bin:/usr/bin"))))
    5121             :            (own-remote-path
    5122             :             ;; The login shell could return more than just the $PATH
    5123             :             ;; string.  So we use `tramp-end-of-heredoc' as marker.
    5124          63 :             (when elt2
    5125           0 :               (or
    5126           0 :                (tramp-send-command-and-read
    5127           0 :                 vec
    5128           0 :                 (format
    5129             :                  "%s %s %s 'echo %s \\\"$PATH\\\"'"
    5130           0 :                  (tramp-get-method-parameter vec 'tramp-remote-shell)
    5131           0 :                  (mapconcat
    5132             :                   'identity
    5133           0 :                   (tramp-get-method-parameter vec 'tramp-remote-shell-login)
    5134           0 :                   " ")
    5135           0 :                  (mapconcat
    5136             :                   'identity
    5137           0 :                   (tramp-get-method-parameter vec 'tramp-remote-shell-args)
    5138           0 :                   " ")
    5139           0 :                  (tramp-shell-quote-argument tramp-end-of-heredoc))
    5140           0 :                 'noerror (regexp-quote tramp-end-of-heredoc))
    5141           0 :                (progn
    5142           0 :                  (tramp-message
    5143           0 :                   vec 2 "Could not retrieve `tramp-own-remote-path'")
    5144          63 :                  nil)))))
    5145             : 
    5146             :       ;; Replace place holder `tramp-default-remote-path'.
    5147          63 :       (when elt1
    5148          63 :         (setcdr elt1
    5149          63 :                 (append
    5150          63 :                  (split-string (or default-remote-path "") ":" 'omit)
    5151          63 :                  (cdr elt1)))
    5152          63 :         (setq remote-path (delq 'tramp-default-remote-path remote-path)))
    5153             : 
    5154             :       ;; Replace place holder `tramp-own-remote-path'.
    5155          63 :       (when elt2
    5156           0 :         (setcdr elt2
    5157           0 :                 (append
    5158           0 :                  (split-string (or own-remote-path "") ":" 'omit)
    5159           0 :                  (cdr elt2)))
    5160          63 :         (setq remote-path (delq 'tramp-own-remote-path remote-path)))
    5161             : 
    5162             :       ;; Remove double entries.
    5163          63 :       (setq elt1 remote-path)
    5164        1197 :       (while (consp elt1)
    5165        1260 :         (while (and (car elt1) (setq elt2 (member (car elt1) (cdr elt1))))
    5166        1134 :           (setcar elt2 nil))
    5167        1134 :         (setq elt1 (cdr elt1)))
    5168             : 
    5169             :       ;; Remove non-existing directories.
    5170          63 :       (delq
    5171             :        nil
    5172          63 :        (mapcar
    5173             :         (lambda (x)
    5174        1134 :           (and
    5175        1134 :            (stringp x)
    5176        1008 :            (file-directory-p
    5177        1008 :             (tramp-make-tramp-file-name
    5178        1008 :              (tramp-file-name-method vec)
    5179        1008 :              (tramp-file-name-user vec)
    5180        1008 :              (tramp-file-name-domain vec)
    5181        1008 :              (tramp-file-name-host vec)
    5182        1008 :              (tramp-file-name-port vec)
    5183        1008 :              x))
    5184        1134 :            x))
    5185         207 :         remote-path)))))
    5186             : 
    5187             : (defun tramp-get-remote-locale (vec)
    5188             :   "Determine remote locale, supporting UTF8 if possible."
    5189         186 :   (with-tramp-connection-property vec "locale"
    5190          44 :     (tramp-send-command vec "locale -a")
    5191          44 :     (let ((candidates '("en_US.utf8" "C.utf8" "en_US.UTF-8" "C.UTF-8"))
    5192             :           locale)
    5193          44 :       (with-current-buffer (tramp-get-connection-buffer vec)
    5194          88 :         (while candidates
    5195          44 :           (goto-char (point-min))
    5196          44 :           (if (string-match (format "^%s\r?$" (regexp-quote (car candidates)))
    5197          44 :                             (buffer-string))
    5198          44 :               (setq locale (car candidates)
    5199          44 :                     candidates nil)
    5200          44 :             (setq candidates (cdr candidates)))))
    5201             :       ;; Return value.
    5202         142 :       (format "LC_ALL=%s" (or locale "C")))))
    5203             : 
    5204             : (defun tramp-get-ls-command (vec)
    5205             :   "Determine remote `ls' command."
    5206         467 :   (with-tramp-connection-property vec "ls"
    5207           9 :     (tramp-message vec 5 "Finding a suitable `ls' command")
    5208           9 :     (or
    5209           9 :      (catch 'ls-found
    5210           9 :        (dolist (cmd '("ls" "gnuls" "gls"))
    5211           9 :          (let ((dl (tramp-get-remote-path vec))
    5212             :                result)
    5213           9 :            (while (and dl (setq result (tramp-find-executable vec cmd dl t t)))
    5214             :              ;; Check parameters.  On busybox, "ls" output coloring is
    5215             :              ;; enabled by default sometimes.  So we try to disable it
    5216             :              ;; when possible.  $LS_COLORING is not supported there.
    5217             :              ;; Some "ls" versions are sensible wrt the order of
    5218             :              ;; arguments, they fail when "-al" is after the
    5219             :              ;; "--color=never" argument (for example on FreeBSD).
    5220           9 :              (when (tramp-send-command-and-check
    5221           9 :                     vec (format "%s -lnd /" result))
    5222           9 :                (when (tramp-send-command-and-check
    5223           9 :                       vec (format
    5224           9 :                            "%s --color=never -al /dev/null" result))
    5225           9 :                  (setq result (concat result " --color=never")))
    5226           9 :                (throw 'ls-found result))
    5227           9 :              (setq dl (cdr dl))))))
    5228         458 :      (tramp-error vec 'file-error "Couldn't find a proper `ls' command"))))
    5229             : 
    5230             : (defun tramp-get-ls-command-with-dired (vec)
    5231             :   "Check, whether the remote `ls' command supports the --dired option."
    5232           2 :   (save-match-data
    5233           3 :     (with-tramp-connection-property vec "ls-dired"
    5234           1 :       (tramp-message vec 5 "Checking, whether `ls --dired' works")
    5235             :       ;; Some "ls" versions are sensible wrt the order of arguments,
    5236             :       ;; they fail when "-al" is after the "--dired" argument (for
    5237             :       ;; example on FreeBSD).
    5238           1 :       (tramp-send-command-and-check
    5239           2 :        vec (format "%s --dired -al /dev/null" (tramp-get-ls-command vec))))))
    5240             : 
    5241             : (defun tramp-get-ls-command-with-quoting-style (vec)
    5242             :   "Check, whether the remote `ls' command supports the --quoting-style option."
    5243         421 :   (save-match-data
    5244         430 :     (with-tramp-connection-property vec "ls-quoting-style"
    5245           9 :       (tramp-message vec 5 "Checking, whether `ls --quoting-style=shell' works")
    5246           9 :       (tramp-send-command-and-check
    5247           9 :        vec (format "%s --quoting-style=shell -al /dev/null"
    5248         421 :                    (tramp-get-ls-command vec))))))
    5249             : 
    5250             : (defun tramp-get-ls-command-with-w-option (vec)
    5251             :   "Check, whether the remote `ls' command supports the -w option."
    5252           0 :   (save-match-data
    5253           0 :     (with-tramp-connection-property vec "ls-w-option"
    5254           0 :       (tramp-message vec 5 "Checking, whether `ls -w' works")
    5255             :       ;; Option "-w" is available on BSD systems.  No argument is
    5256             :       ;; given, because this could return wrong results in case "ls"
    5257             :       ;; supports the "-w NUM" argument, as for busyboxes.
    5258           0 :       (tramp-send-command-and-check
    5259           0 :        vec (format "%s -alw" (tramp-get-ls-command vec))))))
    5260             : 
    5261             : (defun tramp-get-test-command (vec)
    5262             :   "Determine remote `test' command."
    5263        3148 :   (with-tramp-connection-property vec "test"
    5264          52 :     (tramp-message vec 5 "Finding a suitable `test' command")
    5265          52 :     (if (tramp-send-command-and-check vec "test 0")
    5266             :         "test"
    5267        3096 :       (tramp-find-executable vec "test" (tramp-get-remote-path vec)))))
    5268             : 
    5269             : (defun tramp-get-test-nt-command (vec)
    5270             :   "Check, whether the remote `test' command supports the -nt option."
    5271             :   ;; Does `test A -nt B' work?  Use abominable `find' construct if it
    5272             :   ;; doesn't.  BSD/OS 4.0 wants the parentheses around the command,
    5273             :   ;; for otherwise the shell crashes.
    5274           0 :   (with-tramp-connection-property vec "test-nt"
    5275           0 :     (or
    5276           0 :      (progn
    5277           0 :        (tramp-send-command
    5278           0 :         vec (format "( %s / -nt / )" (tramp-get-test-command vec)))
    5279           0 :        (with-current-buffer (tramp-get-buffer vec)
    5280           0 :          (goto-char (point-min))
    5281           0 :          (when (looking-at (regexp-quote tramp-end-of-output))
    5282           0 :            (format "%s %%s -nt %%s" (tramp-get-test-command vec)))))
    5283           0 :      (progn
    5284           0 :        (tramp-send-command
    5285           0 :         vec
    5286           0 :         (format
    5287             :          "tramp_test_nt () {\n%s -n \"`find $1 -prune -newer $2 -print`\"\n}"
    5288           0 :          (tramp-get-test-command vec)))
    5289           0 :        "tramp_test_nt %s %s"))))
    5290             : 
    5291             : (defun tramp-get-file-exists-command (vec)
    5292             :   "Determine remote command for file existing check."
    5293        3508 :   (with-tramp-connection-property vec "file-exists"
    5294          36 :     (tramp-message vec 5 "Finding command to check if file exists")
    5295        3472 :     (tramp-find-file-exists-command vec)))
    5296             : 
    5297             : (defun tramp-get-remote-ln (vec)
    5298             :   "Determine remote `ln' command."
    5299         178 :   (with-tramp-connection-property vec "ln"
    5300          10 :     (tramp-message vec 5 "Finding a suitable `ln' command")
    5301         168 :     (tramp-find-executable vec "ln" (tramp-get-remote-path vec))))
    5302             : 
    5303             : (defun tramp-get-remote-perl (vec)
    5304             :   "Determine remote `perl' command."
    5305        1063 :   (with-tramp-connection-property vec "perl"
    5306           8 :     (tramp-message vec 5 "Finding a suitable `perl' command")
    5307           8 :     (let ((result
    5308           8 :            (or (tramp-find-executable vec "perl5" (tramp-get-remote-path vec))
    5309           8 :                (tramp-find-executable vec "perl" (tramp-get-remote-path vec)))))
    5310             :       ;; Perform a basic check.
    5311           8 :       (and result
    5312           8 :            (null (tramp-send-command-and-check
    5313           8 :                   vec (format "%s -e 'print \"Hello\n\";'" result)))
    5314           8 :            (setq result nil))
    5315             :       ;; We must check also for some Perl modules.
    5316           8 :       (when result
    5317          16 :         (with-tramp-connection-property vec "perl-file-spec"
    5318           8 :           (tramp-send-command-and-check
    5319           8 :            vec (format "%s -e 'use File::Spec;'" result)))
    5320          16 :         (with-tramp-connection-property vec "perl-cwd-realpath"
    5321           8 :           (tramp-send-command-and-check
    5322           8 :            vec (format "%s -e 'use Cwd \"realpath\";'" result))))
    5323        1055 :       result)))
    5324             : 
    5325             : (defun tramp-get-remote-stat (vec)
    5326             :   "Determine remote `stat' command."
    5327        2523 :   (with-tramp-connection-property vec "stat"
    5328          32 :     (tramp-message vec 5 "Finding a suitable `stat' command")
    5329          32 :     (let ((result (tramp-find-executable
    5330          32 :                    vec "stat" (tramp-get-remote-path vec)))
    5331             :           tmp)
    5332             :       ;; Check whether stat(1) returns usable syntax.  "%s" does not
    5333             :       ;; work on older AIX systems.  Recent GNU stat versions (8.24?)
    5334             :       ;; use shell quoted format for "%N", we check the boundaries "`"
    5335             :       ;; and "'", therefore.  See Bug#23422 in coreutils.
    5336             :       ;; Since GNU stat 8.26, environment variable QUOTING_STYLE is
    5337             :       ;; supported.
    5338          32 :       (when result
    5339          32 :         (setq result (concat "env QUOTING_STYLE=locale " result)
    5340          32 :               tmp (tramp-send-command-and-read
    5341          32 :                    vec (format "%s -c '(\"%%N\" %%s)' /" result) 'noerror))
    5342          32 :         (unless (and (listp tmp) (stringp (car tmp))
    5343          32 :                      (string-match "^\\(`/'\\|‘/’\\)$" (car tmp))
    5344          32 :                      (integerp (cadr tmp)))
    5345          32 :           (setq result nil)))
    5346        2491 :       result)))
    5347             : 
    5348             : (defun tramp-get-remote-readlink (vec)
    5349             :   "Determine remote `readlink' command."
    5350        1269 :   (with-tramp-connection-property vec "readlink"
    5351          27 :     (tramp-message vec 5 "Finding a suitable `readlink' command")
    5352          27 :     (let ((result (tramp-find-executable
    5353          27 :                    vec "readlink" (tramp-get-remote-path vec))))
    5354          27 :       (when (and result
    5355          27 :                  (tramp-send-command-and-check
    5356          27 :                   vec (format "%s --canonicalize-missing /" result)))
    5357        1242 :         result))))
    5358             : 
    5359             : (defun tramp-get-remote-trash (vec)
    5360             :   "Determine remote `trash' command.
    5361             : This command is returned only if `delete-by-moving-to-trash' is non-nil."
    5362           0 :   (and delete-by-moving-to-trash
    5363           0 :        (with-tramp-connection-property vec "trash"
    5364           0 :          (tramp-message vec 5 "Finding a suitable `trash' command")
    5365           0 :          (tramp-find-executable vec "trash" (tramp-get-remote-path vec)))))
    5366             : 
    5367             : (defun tramp-get-remote-touch (vec)
    5368             :   "Determine remote `touch' command."
    5369          23 :   (with-tramp-connection-property vec "touch"
    5370           3 :     (tramp-message vec 5 "Finding a suitable `touch' command")
    5371           3 :     (let ((result (tramp-find-executable
    5372           3 :                    vec "touch" (tramp-get-remote-path vec)))
    5373             :           (tmpfile
    5374           3 :            (make-temp-name
    5375           3 :             (expand-file-name
    5376           3 :              tramp-temp-name-prefix (tramp-get-remote-tmpdir vec)))))
    5377             :       ;; Busyboxes do support the "-t" option only when they have been
    5378             :       ;; built with the DESKTOP config option.  Let's check it.
    5379           3 :       (when result
    5380           3 :         (tramp-set-connection-property
    5381           3 :          vec "touch-t"
    5382           3 :          (tramp-send-command-and-check
    5383           3 :           vec
    5384           3 :           (format
    5385             :            "%s -t %s %s"
    5386           3 :            result
    5387           3 :            (format-time-string "%Y%m%d%H%M.%S")
    5388           3 :            (file-remote-p tmpfile 'localname))))
    5389           3 :         (delete-file tmpfile))
    5390          20 :       result)))
    5391             : 
    5392             : (defun tramp-get-remote-gvfs-monitor-dir (vec)
    5393             :   "Determine remote `gvfs-monitor-dir' command."
    5394           0 :   (with-tramp-connection-property vec "gvfs-monitor-dir"
    5395           0 :     (tramp-message vec 5 "Finding a suitable `gvfs-monitor-dir' command")
    5396             :     ;; We distinguish "gvfs-monitor-dir.exe" from cygwin in order to
    5397             :     ;; establish better timeouts in filenotify-tests.el.  Any better
    5398             :     ;; distinction approach would be welcome!
    5399           0 :     (or (tramp-find-executable
    5400           0 :          vec "gvfs-monitor-dir.exe" (tramp-get-remote-path vec) t t)
    5401           0 :         (tramp-find-executable
    5402           0 :          vec "gvfs-monitor-dir" (tramp-get-remote-path vec) t t))))
    5403             : 
    5404             : (defun tramp-get-remote-inotifywait (vec)
    5405             :   "Determine remote `inotifywait' command."
    5406           0 :   (with-tramp-connection-property vec "inotifywait"
    5407           0 :     (tramp-message vec 5 "Finding a suitable `inotifywait' command")
    5408           0 :     (tramp-find-executable vec "inotifywait" (tramp-get-remote-path vec) t t)))
    5409             : 
    5410             : (defun tramp-get-remote-id (vec)
    5411             :   "Determine remote `id' command."
    5412         238 :   (with-tramp-connection-property vec "id"
    5413          36 :     (tramp-message vec 5 "Finding POSIX `id' command")
    5414          36 :     (catch 'id-found
    5415          36 :       (dolist (cmd '("id" "gid"))
    5416          36 :         (let ((dl (tramp-get-remote-path vec))
    5417             :               result)
    5418          36 :           (while (and dl (setq result (tramp-find-executable vec cmd dl t t)))
    5419             :             ;; Check POSIX parameter.
    5420          36 :             (when (tramp-send-command-and-check vec (format "%s -u" result))
    5421          36 :               (throw 'id-found result))
    5422         202 :             (setq dl (cdr dl))))))))
    5423             : 
    5424             : (defun tramp-get-remote-uid-with-id (vec id-format)
    5425             :   "Implement `tramp-get-remote-uid' for Tramp files using `id'."
    5426          31 :   (tramp-send-command-and-read
    5427          31 :    vec
    5428          31 :    (format "%s -u%s %s"
    5429          31 :            (tramp-get-remote-id vec)
    5430          31 :            (if (equal id-format 'integer) "" "n")
    5431          31 :            (if (equal id-format 'integer)
    5432          31 :                "" "| sed -e s/^/\\\"/ -e s/\\$/\\\"/"))))
    5433             : 
    5434             : (defun tramp-get-remote-uid-with-perl (vec id-format)
    5435             :   "Implement `tramp-get-remote-uid' for Tramp files using a Perl script."
    5436           0 :   (tramp-send-command-and-read
    5437           0 :    vec
    5438           0 :    (format "%s -le '%s'"
    5439           0 :            (tramp-get-remote-perl vec)
    5440           0 :            (if (equal id-format 'integer)
    5441             :                "print $>"
    5442           0 :              "print \"\\\"\", scalar getpwuid($>), \"\\\"\""))))
    5443             : 
    5444             : (defun tramp-get-remote-python (vec)
    5445             :   "Determine remote `python' command."
    5446           0 :   (with-tramp-connection-property vec "python"
    5447           0 :     (tramp-message vec 5 "Finding a suitable `python' command")
    5448           0 :     (or (tramp-find-executable vec "python" (tramp-get-remote-path vec))
    5449           0 :         (tramp-find-executable vec "python2" (tramp-get-remote-path vec))
    5450           0 :         (tramp-find-executable vec "python3" (tramp-get-remote-path vec)))))
    5451             : 
    5452             : (defun tramp-get-remote-uid-with-python (vec id-format)
    5453             :   "Implement `tramp-get-remote-uid' for Tramp files using `python'."
    5454           0 :   (tramp-send-command-and-read
    5455           0 :    vec
    5456           0 :    (format "%s -c \"%s\""
    5457           0 :            (tramp-get-remote-python vec)
    5458           0 :            (if (equal id-format 'integer)
    5459             :                "import os; print (os.getuid())"
    5460           0 :              "import os, pwd; print ('\\\"' + pwd.getpwuid(os.getuid())[0] + '\\\"')"))))
    5461             : 
    5462             : (defun tramp-get-remote-uid (vec id-format)
    5463             :   "The uid of the remote connection VEC, in ID-FORMAT.
    5464             : ID-FORMAT valid values are `string' and `integer'."
    5465        1870 :   (with-tramp-connection-property vec (format "uid-%s" id-format)
    5466          31 :     (let ((res
    5467          31 :            (ignore-errors
    5468          31 :              (cond
    5469          31 :               ((tramp-get-remote-id vec)
    5470          31 :                (tramp-get-remote-uid-with-id vec id-format))
    5471           0 :               ((tramp-get-remote-perl vec)
    5472           0 :                (tramp-get-remote-uid-with-perl vec id-format))
    5473           0 :               ((tramp-get-remote-python vec)
    5474          31 :                (tramp-get-remote-uid-with-python vec id-format))))))
    5475             :       ;; Ensure there is a valid result.
    5476          31 :       (cond
    5477          31 :        ((and (equal id-format 'integer) (not (integerp res)))
    5478           0 :         tramp-unknown-id-integer)
    5479          31 :        ((and (equal id-format 'string) (not (stringp res)))
    5480           0 :         tramp-unknown-id-string)
    5481        1839 :        (t res)))))
    5482             : 
    5483             : (defun tramp-get-remote-gid-with-id (vec id-format)
    5484             :   "Implement `tramp-get-remote-gid' for Tramp files using `id'."
    5485          70 :   (tramp-send-command-and-read
    5486          70 :    vec
    5487          70 :    (format "%s -g%s %s"
    5488          70 :            (tramp-get-remote-id vec)
    5489          70 :            (if (equal id-format 'integer) "" "n")
    5490          70 :            (if (equal id-format 'integer)
    5491          70 :                "" "| sed -e s/^/\\\"/ -e s/\\$/\\\"/"))))
    5492             : 
    5493             : (defun tramp-get-remote-gid-with-perl (vec id-format)
    5494             :   "Implement `tramp-get-remote-gid' for Tramp files using a Perl script."
    5495           0 :   (tramp-send-command-and-read
    5496           0 :    vec
    5497           0 :    (format "%s -le '%s'"
    5498           0 :            (tramp-get-remote-perl vec)
    5499           0 :            (if (equal id-format 'integer)
    5500             :                "print ($)=~/(\\d+)/)"
    5501           0 :              "print \"\\\"\", scalar getgrgid($)), \"\\\"\""))))
    5502             : 
    5503             : (defun tramp-get-remote-gid-with-python (vec id-format)
    5504             :   "Implement `tramp-get-remote-gid' for Tramp files using `python'."
    5505           0 :   (tramp-send-command-and-read
    5506           0 :    vec
    5507           0 :    (format "%s -c \"%s\""
    5508           0 :            (tramp-get-remote-python vec)
    5509           0 :            (if (equal id-format 'integer)
    5510             :                "import os; print (os.getgid())"
    5511           0 :              "import os, grp; print ('\\\"' + grp.getgrgid(os.getgid())[0] + '\\\"')"))))
    5512             : 
    5513             : (defun tramp-get-remote-gid (vec id-format)
    5514             :   "The gid of the remote connection VEC, in ID-FORMAT.
    5515             : ID-FORMAT valid values are `string' and `integer'."
    5516        1770 :   (with-tramp-connection-property vec (format "gid-%s" id-format)
    5517          70 :     (let ((res
    5518          70 :            (ignore-errors
    5519          70 :              (cond
    5520          70 :               ((tramp-get-remote-id vec)
    5521          70 :                (tramp-get-remote-gid-with-id vec id-format))
    5522           0 :               ((tramp-get-remote-perl vec)
    5523           0 :                (tramp-get-remote-gid-with-perl vec id-format))
    5524           0 :               ((tramp-get-remote-python vec)
    5525          70 :                (tramp-get-remote-gid-with-python vec id-format))))))
    5526             :       ;; Ensure there is a valid result.
    5527          70 :       (cond
    5528          70 :        ((and (equal id-format 'integer) (not (integerp res)))
    5529           0 :         tramp-unknown-id-integer)
    5530          70 :        ((and (equal id-format 'string) (not (stringp res)))
    5531           0 :         tramp-unknown-id-string)
    5532        1700 :        (t res)))))
    5533             : 
    5534             : (defun tramp-get-env-with-u-option (vec)
    5535             :   "Check, whether the remote `env' command supports the -u option."
    5536          90 :   (with-tramp-connection-property vec "env-u-option"
    5537          10 :     (tramp-message vec 5 "Checking, whether `env -u' works")
    5538             :     ;; Option "-u" is a GNU extension.
    5539          10 :     (tramp-send-command-and-check
    5540          80 :      vec "env FOO=foo env -u FOO 2>/dev/null | grep -qv FOO" t)))
    5541             : 
    5542             : ;; Some predefined connection properties.
    5543             : (defun tramp-get-inline-compress (vec prop size)
    5544             :   "Return the compress command related to PROP.
    5545             : PROP is either `inline-compress' or `inline-decompress'. SIZE is
    5546             : the length of the file to be compressed.
    5547             : 
    5548             : If no corresponding command is found, nil is returned."
    5549        1350 :   (when (and (integerp tramp-inline-compress-start-size)
    5550        1350 :              (> size tramp-inline-compress-start-size))
    5551           5 :     (with-tramp-connection-property (tramp-get-connection-process vec) prop
    5552           1 :       (tramp-find-inline-compress vec)
    5553           1 :       (tramp-get-connection-property
    5554        1350 :        (tramp-get-connection-process vec) prop nil))))
    5555             : 
    5556             : (defun tramp-get-inline-coding (vec prop size)
    5557             :   "Return the coding command related to PROP.
    5558             : PROP is either `remote-encoding', `remote-decoding',
    5559             : `local-encoding' or `local-decoding'.
    5560             : 
    5561             : SIZE is the length of the file to be coded.  Depending on SIZE,
    5562             : compression might be applied.
    5563             : 
    5564             : If no corresponding command is found, nil is returned.
    5565             : Otherwise, either a string is returned which contains a `%s' mark
    5566             : to be used for the respective input or output file; or a Lisp
    5567             : function cell is returned to be applied on a buffer."
    5568             :   ;; We must catch the errors, because we want to return nil, when
    5569             :   ;; no inline coding is found.
    5570        1350 :   (ignore-errors
    5571        1350 :     (let ((coding
    5572        1350 :            (with-tramp-connection-property
    5573        1381 :                (tramp-get-connection-process vec) prop
    5574          31 :              (tramp-find-inline-encoding vec)
    5575          31 :              (tramp-get-connection-property
    5576        1350 :               (tramp-get-connection-process vec) prop nil)))
    5577        1350 :           (prop1 (if (string-match "encoding" prop)
    5578        1350 :                      "inline-compress" "inline-decompress"))
    5579             :           compress)
    5580             :       ;; The connection property might have been cached.  So we must
    5581             :       ;; send the script to the remote side - maybe.
    5582        1350 :       (when (and coding (symbolp coding) (string-match "remote" prop))
    5583           0 :         (let ((name (symbol-name coding)))
    5584           0 :           (while (string-match (regexp-quote "-") name)
    5585           0 :             (setq name (replace-match "_" nil t name)))
    5586           0 :           (tramp-maybe-send-script vec (symbol-value coding) name)
    5587        1350 :           (setq coding name)))
    5588        1350 :       (when coding
    5589             :         ;; Check for the `compress' command.
    5590        1350 :         (setq compress (tramp-get-inline-compress vec prop1 size))
    5591             :         ;; Return the value.
    5592        1350 :         (cond
    5593        1350 :          ((and compress (symbolp coding))
    5594           2 :           (if (string-match "decompress" prop1)
    5595           2 :               `(lambda (beg end)
    5596           2 :                  (,coding beg end)
    5597             :                  (let ((coding-system-for-write 'binary)
    5598             :                        (coding-system-for-read 'binary))
    5599             :                    (apply
    5600           2 :                     'tramp-call-process-region ',vec (point-min) (point-max)
    5601           2 :                     (car (split-string ,compress)) t t nil
    5602           2 :                     (cdr (split-string ,compress)))))
    5603           0 :             `(lambda (beg end)
    5604             :                (let ((coding-system-for-write 'binary)
    5605             :                      (coding-system-for-read 'binary))
    5606             :                  (apply
    5607           0 :                   'tramp-call-process-region ',vec beg end
    5608           0 :                   (car (split-string ,compress)) t t nil
    5609           0 :                   (cdr (split-string ,compress))))
    5610           2 :                (,coding (point-min) (point-max)))))
    5611        1348 :          ((symbolp coding)
    5612         673 :           coding)
    5613         675 :          ((and compress (string-match "decoding" prop))
    5614           0 :           (format
    5615             :            ;; Windows shells need the program file name after
    5616             :            ;; the pipe symbol be quoted if they use forward
    5617             :            ;; slashes as directory separators.
    5618           0 :            (cond
    5619           0 :             ((and (string-match "local" prop)
    5620           0 :                   (memq system-type '(windows-nt)))
    5621             :                "(%s | \"%s\")")
    5622           0 :             ((string-match "local" prop) "(%s | %s)")
    5623           0 :             (t "(%s | %s >%%s)"))
    5624           0 :            coding compress))
    5625         675 :          (compress
    5626           2 :           (format
    5627             :            ;; Windows shells need the program file name after
    5628             :            ;; the pipe symbol be quoted if they use forward
    5629             :            ;; slashes as directory separators.
    5630           2 :            (if (and (string-match "local" prop)
    5631           2 :                     (memq system-type '(windows-nt)))
    5632             :                "(%s <%%s | \"%s\")"
    5633           2 :              "(%s <%%s | %s)")
    5634           2 :            compress coding))
    5635         673 :          ((string-match "decoding" prop)
    5636         405 :           (cond
    5637         405 :            ((string-match "local" prop) (format "%s" coding))
    5638         405 :            (t (format "%s >%%s" coding))))
    5639             :          (t
    5640        1350 :           (format "%s <%%s" coding)))))))
    5641             : 
    5642             : (add-hook 'tramp-unload-hook
    5643             :           (lambda ()
    5644             :             (unload-feature 'tramp-sh 'force)))
    5645             : 
    5646             : (provide 'tramp-sh)
    5647             : 
    5648             : ;;; TODO:
    5649             : 
    5650             : ;; * Don't use globbing for directories with many files, as this is
    5651             : ;;   likely to produce long command lines, and some shells choke on
    5652             : ;;   long command lines.
    5653             : ;;
    5654             : ;; * Don't search for perl5 and perl.  Instead, only search for perl and
    5655             : ;;   then look if it's the right version (with `perl -v').
    5656             : ;;
    5657             : ;; * When editing a remote CVS controlled file as a different user, VC
    5658             : ;;   gets confused about the file locking status.  Try to find out why
    5659             : ;;   the workaround doesn't work.
    5660             : ;;
    5661             : ;; * Allow out-of-band methods as _last_ multi-hop.  Open a connection
    5662             : ;;   until the last but one hop via `start-file-process'.  Apply it
    5663             : ;;   also for ftp and smb.
    5664             : ;;
    5665             : ;; * WIBNI if we had a command "trampclient"?  If I was editing in
    5666             : ;;   some shell with root privileges, it would be nice if I could
    5667             : ;;   just call
    5668             : ;;     trampclient filename.c
    5669             : ;;   as an editor, and the _current_ shell would connect to an Emacs
    5670             : ;;   server and would be used in an existing non-privileged Emacs
    5671             : ;;   session for doing the editing in question.
    5672             : ;;   That way, I need not tell Emacs my password again and be afraid
    5673             : ;;   that it makes it into core dumps or other ugly stuff (I had Emacs
    5674             : ;;   once display a just typed password in the context of a keyboard
    5675             : ;;   sequence prompt for a question immediately following in a shell
    5676             : ;;   script run within Emacs -- nasty).
    5677             : ;;   And if I have some ssh session running to a different computer,
    5678             : ;;   having the possibility of passing a local file there to a local
    5679             : ;;   Emacs session (in case I can arrange for a connection back) would
    5680             : ;;   be nice.
    5681             : ;;   Likely the corresponding Tramp server should not allow the
    5682             : ;;   equivalent of the emacsclient -eval option in order to make this
    5683             : ;;   reasonably unproblematic.  And maybe trampclient should have some
    5684             : ;;   way of passing credentials, like by using an SSL socket or
    5685             : ;;   something.  (David Kastrup)
    5686             : ;;
    5687             : ;; * Reconnect directly to a compliant shell without first going
    5688             : ;;   through the user's default shell.  (Pete Forman)
    5689             : ;;
    5690             : ;; * How can I interrupt the remote process with a signal
    5691             : ;;   (interrupt-process seems not to work)?  (Markus Triska)
    5692             : ;;
    5693             : ;; * Avoid the local shell entirely for starting remote processes.  If
    5694             : ;;   so, I think even a signal, when delivered directly to the local
    5695             : ;;   SSH instance, would correctly be propagated to the remote process
    5696             : ;;   automatically; possibly SSH would have to be started with
    5697             : ;;   "-t".  (Markus Triska)
    5698             : ;;
    5699             : ;; * It makes me wonder if tramp couldn't fall back to ssh when scp
    5700             : ;;   isn't on the remote host.  (Mark A. Hershberger)
    5701             : ;;
    5702             : ;; * Use lsh instead of ssh.  (Alfred M. Szmidt)
    5703             : ;;
    5704             : ;; * Optimize out-of-band copying when both methods are scp-like (not
    5705             : ;;   rsync).
    5706             : ;;
    5707             : ;; * Keep a second connection open for out-of-band methods like scp or
    5708             : ;;   rsync.
    5709             : ;;
    5710             : ;; * Implement completion for "/method:user@host:~<abc> TAB".
    5711             : ;;
    5712             : ;; * I think you could get the best of both worlds by using an
    5713             : ;;   approach similar to Tramp but running a little tramp-daemon on
    5714             : ;;   the other end, such that we can use a more efficient
    5715             : ;;   communication protocol (e.g. when saving a file we could locally
    5716             : ;;   diff it against the last version (of which the remote daemon
    5717             : ;;   would also keep a copy), and then only send the diff).
    5718             : ;;
    5719             : ;;   This said, even using such a daemon it might be difficult to get
    5720             : ;;   good performance: part of the problem is the number of
    5721             : ;;   round-trips.  E.g. when saving a file we have to check if the
    5722             : ;;   file was modified in the mean time and whether saving into a new
    5723             : ;;   inode would change the owner (etc...), which each require a
    5724             : ;;   round-trip.  To get rid of these round-trips, we'd have to
    5725             : ;;   shortcut this code and delegate the higher-level "save file"
    5726             : ;;   operation to the remote server, which then has to perform those
    5727             : ;;   tasks but still obeying the locally set customizations about how
    5728             : ;;   to do each one of those tasks.
    5729             : ;;
    5730             : ;;   We could either put higher-level ops in there (like
    5731             : ;;   `save-buffer'), which implies replicating the whole `save-buffer'
    5732             : ;;   behavior, which is a lot of work and likely to be not 100%
    5733             : ;;   faithful.
    5734             : ;;
    5735             : ;;   Or we could introduce new low-level ops that are asynchronous,
    5736             : ;;   and then rewrite save-buffer to use them.  IOW save-buffer would
    5737             : ;;   start with a bunch of calls like `start-getting-file-attributes'
    5738             : ;;   which could immediately be passed on to the remote side, and
    5739             : ;;   later on checks the return value of those calls as and when
    5740             : ;;   needed.  (Stefan Monnier)
    5741             : 
    5742             : ;;; tramp-sh.el ends here

Generated by: LCOV version 1.12