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