Detect ssh 'ControlMaster' argument automatically in some cases.
[bpt/emacs.git] / lisp / net / tramp.el
CommitLineData
b1a2b924 1;;; tramp.el --- Transparent Remote Access, Multiple Protocol
fb7933a3 2
5fd6d89f 3;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
114f9c96 4;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
fb7933a3 5
cbd12ed7
GM
6;; (copyright statements below in code to be updated with the above notice)
7
cdd44874 8;; Author: Kai Großjohann <kai.grossjohann@gmx.net>
d2a2c17f 9;; Michael Albinus <michael.albinus@gmx.de>
fb7933a3
KG
10;; Keywords: comm, processes
11
12;; This file is part of GNU Emacs.
13
874a927a 14;; GNU Emacs is free software: you can redistribute it and/or modify
fb7933a3 15;; it under the terms of the GNU General Public License as published by
874a927a
GM
16;; the Free Software Foundation, either version 3 of the License, or
17;; (at your option) any later version.
fb7933a3
KG
18
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.
23
24;; You should have received a copy of the GNU General Public License
874a927a 25;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
fb7933a3
KG
26
27;;; Commentary:
28
29;; This package provides remote file editing, similar to ange-ftp.
30;; The difference is that ange-ftp uses FTP to transfer files between
31;; the local and the remote host, whereas tramp.el uses a combination
32;; of rsh and rcp or other work-alike programs, such as ssh/scp.
33;;
b1a2b924 34;; For more detailed instructions, please see the info file.
fb7933a3
KG
35;;
36;; Notes:
37;; -----
bf247b6e 38;;
b533bc97 39;; This package only works for Emacs 22.1 and higher, and for XEmacs 21.4
00d6fd04 40;; and higher. For XEmacs 21, you need the package `fsf-compat' for
7f4d4a97 41;; the `with-timeout' macro.
fb7933a3 42;;
fb7933a3
KG
43;; Also see the todo list at the bottom of this file.
44;;
b1a2b924 45;; The current version of Tramp can be retrieved from the following URL:
340b8d4f 46;; http://ftp.gnu.org/gnu/tramp/
fb7933a3
KG
47;;
48;; There's a mailing list for this, as well. Its name is:
340b8d4f
MA
49;; tramp-devel@gnu.org
50;; You can use the Web to subscribe, under the following URL:
51;; http://lists.gnu.org/mailman/listinfo/tramp-devel
fb7933a3
KG
52;;
53;; For the adventurous, the current development sources are available
54;; via CVS. You can find instructions about this at the following URL:
c62c9d08 55;; http://savannah.gnu.org/projects/tramp/
fb7933a3
KG
56;; Click on "CVS" in the navigation bar near the top.
57;;
58;; Don't forget to put on your asbestos longjohns, first!
59
60;;; Code:
61
ccb4a481
MA
62;; Since Emacs 23.1, loading messages have been disabled during
63;; autoload. However, loading Tramp takes a while, and it could
64;; happen while typing a filename in the minibuffer. Therefore, Tramp
65;; shall inform about.
66(when (and load-in-progress (null (current-message)))
67 (message "Loading tramp..."))
68
b1a2b924
KG
69;; The Tramp version number and bug report address, as prepared by configure.
70(require 'trampver)
a69c01a0 71(add-hook 'tramp-unload-hook
aa485f7c
MA
72 (lambda ()
73 (when (featurep 'trampver)
74 (unload-feature 'trampver 'force))))
a69c01a0 75
9e6ab520 76(require 'tramp-compat)
94be87e8 77(add-hook 'tramp-unload-hook
aa485f7c
MA
78 (lambda ()
79 (when (featurep 'tramp-compat)
80 (unload-feature 'tramp-compat 'force))))
fb7933a3 81
b533bc97 82(require 'format-spec)
5ec2cc41
KG
83;; As long as password.el is not part of (X)Emacs, it shouldn't
84;; be mandatory
85(if (featurep 'xemacs)
86 (load "password" 'noerror)
fd48cd18
GM
87 (or (require 'password-cache nil 'noerror)
88 (require 'password nil 'noerror))) ; from No Gnus, also in tar ball
5ec2cc41 89
fb7933a3
KG
90(require 'shell)
91(require 'advice)
92
bcb04d98
GM
93(eval-and-compile
94 (if (featurep 'xemacs)
95 (load "auth-source" 'noerror)
96 (require 'auth-source nil 'noerror)))
5615d63f 97
00d6fd04
MA
98;; Requiring 'tramp-cache results in an endless loop.
99(autoload 'tramp-get-file-property "tramp-cache")
100(autoload 'tramp-set-file-property "tramp-cache")
101(autoload 'tramp-flush-file-property "tramp-cache")
102(autoload 'tramp-flush-directory-property "tramp-cache")
00d6fd04
MA
103(autoload 'tramp-get-connection-property "tramp-cache")
104(autoload 'tramp-set-connection-property "tramp-cache")
105(autoload 'tramp-flush-connection-property "tramp-cache")
106(autoload 'tramp-parse-connection-properties "tramp-cache")
107(add-hook 'tramp-unload-hook
aa485f7c
MA
108 (lambda ()
109 (when (featurep 'tramp-cache)
110 (unload-feature 'tramp-cache 'force))))
00d6fd04 111
16674e4f
KG
112(autoload 'tramp-uuencode-region "tramp-uu"
113 "Implementation of `uuencode' in Lisp.")
a69c01a0 114(add-hook 'tramp-unload-hook
aa485f7c
MA
115 (lambda ()
116 (when (featurep 'tramp-uu)
117 (unload-feature 'tramp-uu 'force))))
16674e4f 118
00d6fd04 119(autoload 'uudecode-decode-region "uudecode")
16674e4f 120
0664ff72
MA
121;; The following Tramp packages must be loaded after tramp.el, because
122;; they require it as well.
00d6fd04 123(eval-after-load "tramp"
9c13938d
MA
124 '(dolist
125 (feature
126 (list
127
0664ff72 128 ;; Tramp interactive commands.
9c13938d
MA
129 'tramp-cmds
130
131 ;; Load foreign FTP method.
132 (if (featurep 'xemacs) 'tramp-efs 'tramp-ftp)
133
134 ;; tramp-smb uses "smbclient" from Samba. Not available
135 ;; under Cygwin and Windows, because they don't offer
136 ;; "smbclient". And even not necessary there, because Emacs
137 ;; supports UNC file names like "//host/share/localname".
138 (unless (memq system-type '(cygwin windows-nt)) 'tramp-smb)
139
140 ;; Load foreign FISH method.
141 'tramp-fish
00d6fd04 142
70c11b0b 143 ;; tramp-gvfs needs D-Bus messages. Available since Emacs 23
8e754ea2
MA
144 ;; on some system types. We don't call `dbus-ping', because
145 ;; this would load dbus.el.
70c11b0b 146 (when (and (featurep 'dbusbind)
2ac33804
MA
147 (condition-case nil
148 (funcall 'dbus-get-unique-name :session)
149 (error nil))
70c11b0b
MA
150 (tramp-compat-process-running-p "gvfs-fuse-daemon"))
151 'tramp-gvfs)
152
9c13938d 153 ;; Load gateways. It needs `make-network-process' from Emacs 22.
03db0efc
MA
154 (when (functionp 'make-network-process) 'tramp-gw)
155
156 ;; tramp-imap needs both epa (from Emacs 23.1) and imap-hash
157 ;; (from Emacs 23.2).
158 (when (and (locate-library "epa") (locate-library "imap-hash"))
159 'tramp-imap)))
9c13938d
MA
160
161 (when feature
70c11b0b
MA
162 ;; We have used just some basic tests, whether a package shall
163 ;; be added. There might still be other errors during loading,
164 ;; which we will catch here.
165 (catch 'tramp-loading
166 (require feature)
167 (add-hook 'tramp-unload-hook
168 `(lambda ()
169 (when (featurep (quote ,feature))
170 (unload-feature (quote ,feature) 'force)))))
171 (unless (featurep feature)
172 (message "Loading %s failed, ignoring this package" feature)))))
fb7933a3
KG
173
174;;; User Customizable Internal Variables:
175
176(defgroup tramp nil
177 "Edit remote files with a combination of rsh and rcp or similar programs."
589d30dd 178 :group 'files
26f4b8ab 179 :group 'comm
bf247b6e 180 :version "22.1")
fb7933a3 181
2e271195
MA
182;; Maybe we need once a real Tramp mode, with key bindings etc.
183;;;###autoload
184(defcustom tramp-mode t
185 "*Whether Tramp is enabled.
186If it is set to nil, all remote file names are used literally."
187 :group 'tramp
188 :type 'boolean)
189
00d6fd04 190(defcustom tramp-verbose 3
263c02ef 191 "*Verbosity level for Tramp messages.
00d6fd04
MA
192Any level x includes messages for all levels 1 .. x-1. The levels are
193
194 0 silent (no tramp messages at all)
195 1 errors
196 2 warnings
197 3 connection to remote hosts (default level)
198 4 activities
199 5 internal
200 6 sent and received strings
201 7 file caching
202 8 connection properties
20310 traces (huge)."
fb7933a3
KG
204 :group 'tramp
205 :type 'integer)
206
263c02ef 207;; Emacs case.
38c65fca
KG
208(eval-and-compile
209 (when (boundp 'backup-directory-alist)
210 (defcustom tramp-backup-directory-alist nil
211 "Alist of filename patterns and backup directory names.
212Each element looks like (REGEXP . DIRECTORY), with the same meaning like
213in `backup-directory-alist'. If a Tramp file is backed up, and DIRECTORY
214is a local file name, the backup directory is prepended with Tramp file
00d6fd04 215name prefix \(method, user, host\) of file.
38c65fca
KG
216
217\(setq tramp-backup-directory-alist backup-directory-alist\)
218
219gives the same backup policy for Tramp files on their hosts like the
220policy for local files."
221 :group 'tramp
222 :type '(repeat (cons (regexp :tag "Regexp matching filename")
223 (directory :tag "Backup directory name"))))))
224
225;; XEmacs case. We cannot check for `bkup-backup-directory-info', because
226;; the package "backup-dir" might not be loaded yet.
227(eval-and-compile
228 (when (featurep 'xemacs)
229 (defcustom tramp-bkup-backup-directory-info nil
230 "*Alist of (FILE-REGEXP BACKUP-DIR OPTIONS ...))
231It has the same meaning like `bkup-backup-directory-info' from package
232`backup-dir'. If a Tramp file is backed up, and BACKUP-DIR is a local
233file name, the backup directory is prepended with Tramp file name prefix
00d6fd04 234\(method, user, host\) of file.
38c65fca
KG
235
236\(setq tramp-bkup-backup-directory-info bkup-backup-directory-info\)
237
238gives the same backup policy for Tramp files on their hosts like the
239policy for local files."
bf247b6e 240 :type '(repeat
38c65fca
KG
241 (list (regexp :tag "File regexp")
242 (string :tag "Backup Dir")
243 (set :inline t
244 (const ok-create)
245 (const full-path)
246 (const prepend-name)
247 (const search-upward))))
248 :group 'tramp)))
249
fb7933a3
KG
250(defcustom tramp-auto-save-directory nil
251 "*Put auto-save files in this directory, if set.
252The idea is to use a local directory so that auto-saving is faster."
253 :group 'tramp
00d6fd04 254 :type '(choice (const nil) string))
fb7933a3 255
16674e4f
KG
256(defcustom tramp-encoding-shell
257 (if (memq system-type '(windows-nt))
258 (getenv "COMSPEC")
259 "/bin/sh")
260 "*Use this program for encoding and decoding commands on the local host.
261This shell is used to execute the encoding and decoding command on the
262local host, so if you want to use `~' in those commands, you should
263choose a shell here which groks tilde expansion. `/bin/sh' normally
264does not understand tilde expansion.
265
266For encoding and deocding, commands like the following are executed:
267
268 /bin/sh -c COMMAND < INPUT > OUTPUT
269
270This variable can be used to change the \"/bin/sh\" part. See the
00d6fd04 271variable `tramp-encoding-command-switch' for the \"-c\" part.
fb7933a3
KG
272
273Note that this variable is not used for remote commands. There are
274mechanisms in tramp.el which automatically determine the right shell to
275use for the remote host."
276 :group 'tramp
277 :type '(file :must-match t))
278
16674e4f
KG
279(defcustom tramp-encoding-command-switch
280 (if (string-match "cmd\\.exe" tramp-encoding-shell)
281 "/c"
282 "-c")
283 "*Use this switch together with `tramp-encoding-shell' for local commands.
284See the variable `tramp-encoding-shell' for more information."
285 :group 'tramp
286 :type 'string)
287
00d6fd04
MA
288(defcustom tramp-copy-size-limit 10240
289 "*The maximum file size where inline copying is preferred over an out-of-the-band copy."
16674e4f 290 :group 'tramp
00d6fd04 291 :type 'integer)
90dc758d 292
00d6fd04
MA
293(defcustom tramp-terminal-type "dumb"
294 "*Value of TERM environment variable for logging in to remote host.
295Because Tramp wants to parse the output of the remote shell, it is easily
296confused by ANSI color escape sequences and suchlike. Often, shell init
297files conditionalize this setup based on the TERM environment variable."
90dc758d 298 :group 'tramp
00d6fd04 299 :type 'string)
90dc758d 300
dab816a9
MA
301;; ksh on OpenBSD 4.5 requires, that PS1 contains a `#' character for
302;; root users. It uses the `$' character for other users. In order
303;; to guarantee a proper prompt, we use "#$" for the prompt.
304
305(defvar tramp-end-of-output
306 (format
307 "///%s#$"
308 (md5 (concat (prin1-to-string process-environment) (current-time-string))))
309 "String used to recognize end of output.
310The '$' character at the end is quoted; the string cannot be
311detected as prompt when being sent on echoing hosts, therefore.")
312
313(defconst tramp-initial-end-of-output "#$ "
314 "Prompt when establishing a connection.")
315
00d6fd04
MA
316(defvar tramp-methods
317 `(("rcp" (tramp-login-program "rsh")
318 (tramp-login-args (("%h") ("-l" "%u")))
319 (tramp-remote-sh "/bin/sh")
320 (tramp-copy-program "rcp")
263c02ef 321 (tramp-copy-args (("-p" "%k") ("-r")))
00d6fd04 322 (tramp-copy-keep-date t)
263c02ef 323 (tramp-copy-recursive t)
00d6fd04
MA
324 (tramp-password-end-of-line nil))
325 ("scp" (tramp-login-program "ssh")
2296b54d 326 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
327 ("-e" "none")))
328 (tramp-remote-sh "/bin/sh")
329 (tramp-copy-program "scp")
263c02ef
MA
330 (tramp-copy-args (("-P" "%p") ("-p" "%k")
331 ("-q") ("-r")))
00d6fd04 332 (tramp-copy-keep-date t)
263c02ef 333 (tramp-copy-recursive t)
00d6fd04
MA
334 (tramp-password-end-of-line nil)
335 (tramp-gw-args (("-o"
336 "GlobalKnownHostsFile=/dev/null")
337 ("-o" "UserKnownHostsFile=/dev/null")
338 ("-o" "StrictHostKeyChecking=no")))
339 (tramp-default-port 22))
340 ("scp1" (tramp-login-program "ssh")
2296b54d 341 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
342 ("-1" "-e" "none")))
343 (tramp-remote-sh "/bin/sh")
344 (tramp-copy-program "scp")
345 (tramp-copy-args (("-1") ("-P" "%p") ("-p" "%k")
263c02ef 346 ("-q") ("-r")))
00d6fd04 347 (tramp-copy-keep-date t)
263c02ef 348 (tramp-copy-recursive t)
00d6fd04
MA
349 (tramp-password-end-of-line nil)
350 (tramp-gw-args (("-o"
351 "GlobalKnownHostsFile=/dev/null")
352 ("-o" "UserKnownHostsFile=/dev/null")
353 ("-o" "StrictHostKeyChecking=no")))
354 (tramp-default-port 22))
355 ("scp2" (tramp-login-program "ssh")
2296b54d 356 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
357 ("-2" "-e" "none")))
358 (tramp-remote-sh "/bin/sh")
359 (tramp-copy-program "scp")
360 (tramp-copy-args (("-2") ("-P" "%p") ("-p" "%k")
263c02ef 361 ("-q") ("-r")))
00d6fd04 362 (tramp-copy-keep-date t)
263c02ef 363 (tramp-copy-recursive t)
00d6fd04
MA
364 (tramp-password-end-of-line nil)
365 (tramp-gw-args (("-o"
366 "GlobalKnownHostsFile=/dev/null")
367 ("-o" "UserKnownHostsFile=/dev/null")
368 ("-o" "StrictHostKeyChecking=no")))
369 (tramp-default-port 22))
370 ("scp1_old"
371 (tramp-login-program "ssh1")
372 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
373 ("-e" "none")))
374 (tramp-remote-sh "/bin/sh")
375 (tramp-copy-program "scp1")
263c02ef 376 (tramp-copy-args (("-p" "%k") ("-r")))
00d6fd04 377 (tramp-copy-keep-date t)
263c02ef 378 (tramp-copy-recursive t)
00d6fd04
MA
379 (tramp-password-end-of-line nil))
380 ("scp2_old"
381 (tramp-login-program "ssh2")
382 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
383 ("-e" "none")))
384 (tramp-remote-sh "/bin/sh")
385 (tramp-copy-program "scp2")
263c02ef 386 (tramp-copy-args (("-p" "%k") ("-r")))
00d6fd04 387 (tramp-copy-keep-date t)
263c02ef 388 (tramp-copy-recursive t)
00d6fd04
MA
389 (tramp-password-end-of-line nil))
390 ("sftp" (tramp-login-program "ssh")
391 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
392 ("-e" "none")))
393 (tramp-remote-sh "/bin/sh")
394 (tramp-copy-program "sftp")
395 (tramp-copy-args nil)
396 (tramp-copy-keep-date nil)
397 (tramp-password-end-of-line nil))
398 ("rsync" (tramp-login-program "ssh")
399 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
400 ("-e" "none")))
401 (tramp-remote-sh "/bin/sh")
402 (tramp-copy-program "rsync")
263c02ef 403 (tramp-copy-args (("-e" "ssh") ("-t" "%k") ("-r")))
00d6fd04 404 (tramp-copy-keep-date t)
b88f2d0a 405 (tramp-copy-keep-tmpfile t)
263c02ef 406 (tramp-copy-recursive t)
00d6fd04 407 (tramp-password-end-of-line nil))
263c02ef
MA
408 ("rsyncc"
409 (tramp-login-program "ssh")
946a5aeb
MA
410 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
411 ("-o" "ControlPath=%t.%%r@%%h:%%p")
412 ("-o" "ControlMaster=yes")
413 ("-e" "none")))
414 (tramp-remote-sh "/bin/sh")
415 (tramp-copy-program "rsync")
263c02ef 416 (tramp-copy-args (("-t" "%k") ("-r")))
946a5aeb
MA
417 (tramp-copy-env (("RSYNC_RSH")
418 (,(concat
419 "ssh"
420 " -o ControlPath=%t.%%r@%%h:%%p"
421 " -o ControlMaster=auto"))))
422 (tramp-copy-keep-date t)
b88f2d0a 423 (tramp-copy-keep-tmpfile t)
263c02ef 424 (tramp-copy-recursive t)
946a5aeb 425 (tramp-password-end-of-line nil))
00d6fd04
MA
426 ("remcp" (tramp-login-program "remsh")
427 (tramp-login-args (("%h") ("-l" "%u")))
428 (tramp-remote-sh "/bin/sh")
429 (tramp-copy-program "rcp")
430 (tramp-copy-args (("-p" "%k")))
431 (tramp-copy-keep-date t)
432 (tramp-password-end-of-line nil))
433 ("rsh" (tramp-login-program "rsh")
434 (tramp-login-args (("%h") ("-l" "%u")))
435 (tramp-remote-sh "/bin/sh")
436 (tramp-copy-program nil)
437 (tramp-copy-args nil)
438 (tramp-copy-keep-date nil)
439 (tramp-password-end-of-line nil))
440 ("ssh" (tramp-login-program "ssh")
2296b54d 441 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
442 ("-e" "none")))
443 (tramp-remote-sh "/bin/sh")
444 (tramp-copy-program nil)
445 (tramp-copy-args nil)
446 (tramp-copy-keep-date nil)
447 (tramp-password-end-of-line nil)
448 (tramp-gw-args (("-o"
449 "GlobalKnownHostsFile=/dev/null")
450 ("-o" "UserKnownHostsFile=/dev/null")
451 ("-o" "StrictHostKeyChecking=no")))
452 (tramp-default-port 22))
453 ("ssh1" (tramp-login-program "ssh")
2296b54d 454 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
455 ("-1" "-e" "none")))
456 (tramp-remote-sh "/bin/sh")
457 (tramp-copy-program nil)
458 (tramp-copy-args nil)
459 (tramp-copy-keep-date nil)
460 (tramp-password-end-of-line nil)
461 (tramp-gw-args (("-o"
462 "GlobalKnownHostsFile=/dev/null")
463 ("-o" "UserKnownHostsFile=/dev/null")
464 ("-o" "StrictHostKeyChecking=no")))
465 (tramp-default-port 22))
466 ("ssh2" (tramp-login-program "ssh")
2296b54d 467 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
468 ("-2" "-e" "none")))
469 (tramp-remote-sh "/bin/sh")
470 (tramp-copy-program nil)
471 (tramp-copy-args nil)
472 (tramp-copy-keep-date nil)
473 (tramp-password-end-of-line nil)
474 (tramp-gw-args (("-o"
475 "GlobalKnownHostsFile=/dev/null")
476 ("-o" "UserKnownHostsFile=/dev/null")
477 ("-o" "StrictHostKeyChecking=no")))
478 (tramp-default-port 22))
479 ("ssh1_old"
480 (tramp-login-program "ssh1")
481 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
482 ("-e" "none")))
483 (tramp-remote-sh "/bin/sh")
484 (tramp-copy-program nil)
485 (tramp-copy-args nil)
486 (tramp-copy-keep-date nil)
487 (tramp-password-end-of-line nil))
488 ("ssh2_old"
489 (tramp-login-program "ssh2")
490 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
491 ("-e" "none")))
492 (tramp-remote-sh "/bin/sh")
493 (tramp-copy-program nil)
494 (tramp-copy-args nil)
495 (tramp-copy-keep-date nil)
496 (tramp-password-end-of-line nil))
497 ("remsh" (tramp-login-program "remsh")
498 (tramp-login-args (("%h") ("-l" "%u")))
499 (tramp-remote-sh "/bin/sh")
500 (tramp-copy-program nil)
501 (tramp-copy-args nil)
502 (tramp-copy-keep-date nil)
503 (tramp-password-end-of-line nil))
504 ("telnet"
505 (tramp-login-program "telnet")
506 (tramp-login-args (("%h") ("%p")))
507 (tramp-remote-sh "/bin/sh")
508 (tramp-copy-program nil)
509 (tramp-copy-args nil)
510 (tramp-copy-keep-date nil)
511 (tramp-password-end-of-line nil)
512 (tramp-default-port 23))
513 ("su" (tramp-login-program "su")
514 (tramp-login-args (("-") ("%u")))
515 (tramp-remote-sh "/bin/sh")
516 (tramp-copy-program nil)
517 (tramp-copy-args nil)
518 (tramp-copy-keep-date nil)
519 (tramp-password-end-of-line nil))
520 ("sudo" (tramp-login-program "sudo")
521 (tramp-login-args (("-u" "%u")
42bc9b6d 522 ("-s") ("-H") ("-p" "Password:")))
00d6fd04
MA
523 (tramp-remote-sh "/bin/sh")
524 (tramp-copy-program nil)
525 (tramp-copy-args nil)
526 (tramp-copy-keep-date nil)
527 (tramp-password-end-of-line nil))
528 ("scpc" (tramp-login-program "ssh")
2296b54d 529 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
530 ("-o" "ControlPath=%t.%%r@%%h:%%p")
531 ("-o" "ControlMaster=yes")
532 ("-e" "none")))
533 (tramp-remote-sh "/bin/sh")
534 (tramp-copy-program "scp")
535 (tramp-copy-args (("-P" "%p") ("-p" "%k") ("-q")
536 ("-o" "ControlPath=%t.%%r@%%h:%%p")
537 ("-o" "ControlMaster=auto")))
538 (tramp-copy-keep-date t)
539 (tramp-password-end-of-line nil)
540 (tramp-gw-args (("-o"
541 "GlobalKnownHostsFile=/dev/null")
542 ("-o" "UserKnownHostsFile=/dev/null")
543 ("-o" "StrictHostKeyChecking=no")))
544 (tramp-default-port 22))
545 ("scpx" (tramp-login-program "ssh")
2296b54d 546 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
547 ("-e" "none" "-t" "-t" "/bin/sh")))
548 (tramp-remote-sh "/bin/sh")
549 (tramp-copy-program "scp")
550 (tramp-copy-args (("-p" "%k")))
551 (tramp-copy-keep-date t)
552 (tramp-password-end-of-line nil)
553 (tramp-gw-args (("-o"
554 "GlobalKnownHostsFile=/dev/null")
555 ("-o" "UserKnownHostsFile=/dev/null")
556 ("-o" "StrictHostKeyChecking=no")))
557 (tramp-default-port 22))
558 ("sshx" (tramp-login-program "ssh")
2296b54d 559 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
560 ("-e" "none" "-t" "-t" "/bin/sh")))
561 (tramp-remote-sh "/bin/sh")
562 (tramp-copy-program nil)
563 (tramp-copy-args nil)
564 (tramp-copy-keep-date nil)
565 (tramp-password-end-of-line nil)
566 (tramp-gw-args (("-o"
567 "GlobalKnownHostsFile=/dev/null")
568 ("-o" "UserKnownHostsFile=/dev/null")
569 ("-o" "StrictHostKeyChecking=no")))
570 (tramp-default-port 22))
571 ("krlogin"
572 (tramp-login-program "krlogin")
573 (tramp-login-args (("%h") ("-l" "%u") ("-x")))
574 (tramp-remote-sh "/bin/sh")
575 (tramp-copy-program nil)
576 (tramp-copy-args nil)
577 (tramp-copy-keep-date nil)
578 (tramp-password-end-of-line nil))
579 ("plink" (tramp-login-program "plink")
580 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
581 ("-ssh")))
582 (tramp-remote-sh "/bin/sh")
583 (tramp-copy-program nil)
584 (tramp-copy-args nil)
585 (tramp-copy-keep-date nil)
586 (tramp-password-end-of-line "xy") ;see docstring for "xy"
587 (tramp-default-port 22))
588 ("plink1"
589 (tramp-login-program "plink")
590 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
591 ("-1" "-ssh")))
592 (tramp-remote-sh "/bin/sh")
593 (tramp-copy-program nil)
594 (tramp-copy-args nil)
595 (tramp-copy-keep-date nil)
596 (tramp-password-end-of-line "xy") ;see docstring for "xy"
597 (tramp-default-port 22))
598 ("plinkx"
599 (tramp-login-program "plink")
42bc9b6d
MA
600 ;; ("%h") must be a single element, see
601 ;; `tramp-compute-multi-hops'.
602 (tramp-login-args (("-load") ("%h") ("-t")
ce3f516f 603 (,(format
dab816a9
MA
604 "env 'TERM=%s' 'PROMPT_COMMAND=' 'PS1=%s'"
605 tramp-terminal-type
606 tramp-initial-end-of-output))
00d6fd04
MA
607 ("/bin/sh")))
608 (tramp-remote-sh "/bin/sh")
609 (tramp-copy-program nil)
610 (tramp-copy-args nil)
611 (tramp-copy-keep-date nil)
612 (tramp-password-end-of-line nil))
613 ("pscp" (tramp-login-program "plink")
614 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
615 ("-ssh")))
616 (tramp-remote-sh "/bin/sh")
617 (tramp-copy-program "pscp")
60f2c210 618 (tramp-copy-args (("-P" "%p") ("-scp") ("-p" "%k")))
00d6fd04
MA
619 (tramp-copy-keep-date t)
620 (tramp-password-end-of-line "xy") ;see docstring for "xy"
621 (tramp-default-port 22))
622 ("psftp" (tramp-login-program "plink")
623 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
624 ("-ssh")))
625 (tramp-remote-sh "/bin/sh")
626 (tramp-copy-program "pscp")
60f2c210 627 (tramp-copy-args (("-P" "%p") ("-sftp") ("-p" "%k")))
00d6fd04
MA
628 (tramp-copy-keep-date t)
629 (tramp-password-end-of-line "xy")) ;see docstring for "xy"
630 ("fcp" (tramp-login-program "fsh")
631 (tramp-login-args (("%h") ("-l" "%u") ("sh" "-i")))
632 (tramp-remote-sh "/bin/sh -i")
633 (tramp-copy-program "fcp")
634 (tramp-copy-args (("-p" "%k")))
635 (tramp-copy-keep-date t)
636 (tramp-password-end-of-line nil)))
fb7933a3
KG
637 "*Alist of methods for remote files.
638This is a list of entries of the form (NAME PARAM1 PARAM2 ...).
639Each NAME stands for a remote access method. Each PARAM is a
640pair of the form (KEY VALUE). The following KEYs are defined:
fb7933a3
KG
641 * `tramp-remote-sh'
642 This specifies the Bourne shell to use on the remote host. This
643 MUST be a Bourne-like shell. It is normally not necessary to set
a4aeb9a4 644 this to any value other than \"/bin/sh\": Tramp wants to use a shell
fb7933a3
KG
645 which groks tilde expansion, but it can search for it. Also note
646 that \"/bin/sh\" exists on all Unixen, this might not be true for
647 the value that you decide to use. You Have Been Warned.
b25a52cc
KG
648 * `tramp-login-program'
649 This specifies the name of the program to use for logging in to the
00d6fd04
MA
650 remote host. This may be the name of rsh or a workalike program,
651 or the name of telnet or a workalike, or the name of su or a workalike.
b25a52cc 652 * `tramp-login-args'
fb7933a3 653 This specifies the list of arguments to pass to the above
00d6fd04 654 mentioned program. Please note that this is a list of list of arguments,
fb7933a3 655 that is, normally you don't want to put \"-a -b\" or \"-f foo\"
00d6fd04
MA
656 here. Instead, you want a list (\"-a\" \"-b\"), or (\"-f\" \"foo\").
657 There are some patterns: \"%h\" in this list is replaced by the host
658 name, \"%u\" is replaced by the user name, \"%p\" is replaced by the
659 port number, and \"%%\" can be used to obtain a literal percent character.
660 If a list containing \"%h\", \"%u\" or \"%p\" is unchanged during
661 expansion (i.e. no host or no user specified), this list is not used as
662 argument. By this, arguments like (\"-l\" \"%u\") are optional.
663 \"%t\" is replaced by the temporary file name produced with
664 `tramp-make-tramp-temp-file'. \"%k\" indicates the keep-date
665 parameter of a program, if exists.
b25a52cc
KG
666 * `tramp-copy-program'
667 This specifies the name of the program to use for remotely copying
668 the file; this might be the absolute filename of rcp or the name of
669 a workalike program.
670 * `tramp-copy-args'
fb7933a3 671 This specifies the list of parameters to pass to the above mentioned
b25a52cc 672 program, the hints for `tramp-login-args' also apply here.
00d6fd04
MA
673 * `tramp-copy-keep-date'
674 This specifies whether the copying program when the preserves the
675 timestamp of the original file.
b88f2d0a
MA
676 * `tramp-copy-keep-tmpfile'
677 This specifies whether a temporary local file shall be kept
678 for optimization reasons (useful for \"rsync\" methods).
679 * `tramp-copy-recursive'
680 Whether the operation copies directories recursively.
00d6fd04
MA
681 * `tramp-default-port'
682 The default port of a method is needed in case of gateway connections.
683 Additionally, it is used as indication which method is prepared for
684 passing gateways.
685 * `tramp-gw-args'
686 As the attribute name says, additional arguments are specified here
687 when a method is applied via a gateway.
90f8dc03
KG
688 * `tramp-password-end-of-line'
689 This specifies the string to use for terminating the line after
690 submitting the password. If this method parameter is nil, then the
691 value of the normal variable `tramp-default-password-end-of-line'
692 is used. This parameter is necessary because the \"plink\" program
693 requires any two characters after sending the password. These do
694 not have to be newline or carriage return characters. Other login
695 programs are happy with just one character, the newline character.
696 We use \"xy\" as the value for methods using \"plink\".
b25a52cc
KG
697
698What does all this mean? Well, you should specify `tramp-login-program'
699for all methods; this program is used to log in to the remote site. Then,
700there are two ways to actually transfer the files between the local and the
701remote side. One way is using an additional rcp-like program. If you want
702to do this, set `tramp-copy-program' in the method.
fb7933a3
KG
703
704Another possibility for file transfer is inline transfer, i.e. the
b25a52cc 705file is passed through the same buffer used by `tramp-login-program'. In
fb7933a3 706this case, the file contents need to be protected since the
b25a52cc 707`tramp-login-program' might use escape codes or the connection might not
fb7933a3 708be eight-bit clean. Therefore, file contents are encoded for transit.
00d6fd04
MA
709See the variables `tramp-local-coding-commands' and
710`tramp-remote-coding-commands' for details.
fb7933a3 711
16674e4f 712So, to summarize: if the method is an out-of-band method, then you
b25a52cc 713must specify `tramp-copy-program' and `tramp-copy-args'. If it is an
00d6fd04
MA
714inline method, then these two parameters should be nil. Methods which
715are fit for gateways must have `tramp-default-port' at least.
fb7933a3
KG
716
717Notes:
718
00d6fd04
MA
719When using `su' or `sudo' the phrase `open connection to a remote
720host' sounds strange, but it is used nevertheless, for consistency.
721No connection is opened to a remote host, but `su' or `sudo' is
722started on the local host. You should specify a remote host
723`localhost' or the name of the local host. Another host name is
724useful only in combination with `tramp-default-proxies-alist'.")
fb7933a3 725
a92375d9
MA
726(defun tramp-detect-ssh-controlmaster ()
727 "Call ssh to detect whether it supports the ControlMaster argument.
728This function may return nil when the argument is supported, but
729shouldn't return t when it isn't."
730 (ignore-errors
731 (with-temp-buffer
732 (call-process "ssh" nil t nil "-o" "ControlMaster")
733 (goto-char (point-min))
734 (search-forward-regexp "Missing ControlMaster argument" nil t))))
735
b25a52cc 736(defcustom tramp-default-method
83e20b5c
MA
737 ;; An external copy method seems to be preferred, because it is much
738 ;; more performant for large files, and it hasn't too serious delays
739 ;; for small files. But it must be ensured that there aren't
740 ;; permanent password queries. Either a password agent like
263c02ef
MA
741 ;; "ssh-agent" or "Pageant" shall run, or the optional
742 ;; password-cache.el or auth-sources.el packages shall be active for
a92375d9
MA
743 ;; password caching. "scpc" is chosen if we detect that the user is
744 ;; running OpenSSH 4.0 or newer.
00d6fd04
MA
745 (cond
746 ;; PuTTY is installed.
747 ((executable-find "pscp")
748 (if (or (fboundp 'password-read)
263c02ef 749 (fboundp 'auth-source-user-or-password)
00d6fd04 750 ;; Pageant is running.
70c11b0b 751 (tramp-compat-process-running-p "Pageant"))
00d6fd04
MA
752 "pscp"
753 "plink"))
754 ;; There is an ssh installation.
755 ((executable-find "scp")
a92375d9
MA
756 (cond
757 ((tramp-detect-ssh-controlmaster) "scpc")
758 ((or (fboundp 'password-read)
759 (fboundp 'auth-source-user-or-password)
760 ;; ssh-agent is running.
761 (getenv "SSH_AUTH_SOCK")
762 (getenv "SSH_AGENT_PID"))
763 "scp")
764 (t "ssh")))
00d6fd04
MA
765 ;; Fallback.
766 (t "ftp"))
fb7933a3 767 "*Default method to use for transferring files.
c62c9d08 768See `tramp-methods' for possibilities.
4007ba5b 769Also see `tramp-default-method-alist'."
c62c9d08
KG
770 :group 'tramp
771 :type 'string)
772
505edaeb 773(defcustom tramp-default-method-alist
4007ba5b 774 '(("\\`localhost\\'" "\\`root\\'" "su"))
00d6fd04 775 "*Default method to use for specific host/user pairs.
c62c9d08
KG
776This is an alist of items (HOST USER METHOD). The first matching item
777specifies the method to use for a file name which does not specify a
778method. HOST and USER are regular expressions or nil, which is
779interpreted as a regular expression which always matches. If no entry
780matches, the variable `tramp-default-method' takes effect.
781
782If the file name does not specify the user, lookup is done using the
783empty string for the user name.
784
785See `tramp-methods' for a list of possibilities for METHOD."
786 :group 'tramp
787 :type '(repeat (list (regexp :tag "Host regexp")
788 (regexp :tag "User regexp")
789 (string :tag "Method"))))
790
00d6fd04
MA
791(defcustom tramp-default-user
792 nil
793 "*Default user to use for transferring files.
794It is nil by default; otherwise settings in configuration files like
795\"~/.ssh/config\" would be overwritten. Also see `tramp-default-user-alist'.
796
797This variable is regarded as obsolete, and will be removed soon."
798 :group 'tramp
799 :type '(choice (const nil) string))
800
801(defcustom tramp-default-user-alist
802 `(("\\`su\\(do\\)?\\'" nil "root")
803 ("\\`r\\(em\\)?\\(cp\\|sh\\)\\|telnet\\|plink1?\\'"
804 nil ,(user-login-name)))
805 "*Default user to use for specific method/host pairs.
806This is an alist of items (METHOD HOST USER). The first matching item
807specifies the user to use for a file name which does not specify a
808user. METHOD and USER are regular expressions or nil, which is
809interpreted as a regular expression which always matches. If no entry
810matches, the variable `tramp-default-user' takes effect.
811
812If the file name does not specify the method, lookup is done using the
813empty string for the method name."
814 :group 'tramp
815 :type '(repeat (list (regexp :tag "Method regexp")
816 (regexp :tag "Host regexp")
817 (string :tag "User"))))
818
819(defcustom tramp-default-host
820 (system-name)
821 "*Default host to use for transferring files.
822Useful for su and sudo methods mostly."
823 :group 'tramp
824 :type 'string)
825
826(defcustom tramp-default-proxies-alist nil
827 "*Route to be followed for specific host/user pairs.
828This is an alist of items (HOST USER PROXY). The first matching
829item specifies the proxy to be passed for a file name located on
830a remote target matching USER@HOST. HOST and USER are regular
70c11b0b
MA
831expressions. PROXY must be a Tramp filename without a localname
832part. Method and user name on PROXY are optional, which is
833interpreted with the default values. PROXY can contain the
834patterns %h and %u, which are replaced by the strings matching
835HOST or USER, respectively.
836
837HOST, USER or PROXY could also be Lisp forms, which will be
838evaluated. The result must be a string or nil, which is
839interpreted as a regular expression which always matches."
00d6fd04 840 :group 'tramp
70c11b0b
MA
841 :type '(repeat (list (choice :tag "Host regexp" regexp sexp)
842 (choice :tag "User regexp" regexp sexp)
843 (choice :tag "Proxy remote name" string (const nil)))))
00d6fd04 844
b96e6899
MA
845(defconst tramp-local-host-regexp
846 (concat
847 "^" (regexp-opt (list "localhost" (system-name) "127\.0\.0\.1" "::1") t) "$")
848 "*Host names which are regarded as local host.")
849
16674e4f 850(defconst tramp-completion-function-alist-rsh
00d6fd04
MA
851 '((tramp-parse-rhosts "/etc/hosts.equiv")
852 (tramp-parse-rhosts "~/.rhosts"))
b25a52cc 853 "Default list of (FUNCTION FILE) pairs to be examined for rsh methods.")
16674e4f 854
16674e4f 855(defconst tramp-completion-function-alist-ssh
00d6fd04
MA
856 '((tramp-parse-rhosts "/etc/hosts.equiv")
857 (tramp-parse-rhosts "/etc/shosts.equiv")
858 (tramp-parse-shosts "/etc/ssh_known_hosts")
859 (tramp-parse-sconfig "/etc/ssh_config")
860 (tramp-parse-shostkeys "/etc/ssh2/hostkeys")
861 (tramp-parse-sknownhosts "/etc/ssh2/knownhosts")
862 (tramp-parse-rhosts "~/.rhosts")
863 (tramp-parse-rhosts "~/.shosts")
864 (tramp-parse-shosts "~/.ssh/known_hosts")
865 (tramp-parse-sconfig "~/.ssh/config")
866 (tramp-parse-shostkeys "~/.ssh2/hostkeys")
867 (tramp-parse-sknownhosts "~/.ssh2/knownhosts"))
b25a52cc 868 "Default list of (FUNCTION FILE) pairs to be examined for ssh methods.")
16674e4f 869
16674e4f 870(defconst tramp-completion-function-alist-telnet
00d6fd04 871 '((tramp-parse-hosts "/etc/hosts"))
b25a52cc 872 "Default list of (FUNCTION FILE) pairs to be examined for telnet methods.")
16674e4f 873
16674e4f 874(defconst tramp-completion-function-alist-su
00d6fd04 875 '((tramp-parse-passwd "/etc/passwd"))
b25a52cc 876 "Default list of (FUNCTION FILE) pairs to be examined for su methods.")
292ffc15 877
00d6fd04
MA
878(defconst tramp-completion-function-alist-putty
879 '((tramp-parse-putty
880 "HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions"))
881 "Default list of (FUNCTION REGISTRY) pairs to be examined for putty methods.")
882
5ec2cc41 883(defvar tramp-completion-function-alist nil
16674e4f 884 "*Alist of methods for remote files.
b533bc97 885This is a list of entries of the form \(NAME PAIR1 PAIR2 ...\).
16674e4f 886Each NAME stands for a remote access method. Each PAIR is of the form
b533bc97 887\(FUNCTION FILE\). FUNCTION is responsible to extract user names and host
16674e4f
KG
888names from FILE for completion. The following predefined FUNCTIONs exists:
889
5ec2cc41
KG
890 * `tramp-parse-rhosts' for \"~/.rhosts\" like files,
891 * `tramp-parse-shosts' for \"~/.ssh/known_hosts\" like files,
892 * `tramp-parse-sconfig' for \"~/.ssh/config\" like files,
893 * `tramp-parse-shostkeys' for \"~/.ssh2/hostkeys/*\" like files,
894 * `tramp-parse-sknownhosts' for \"~/.ssh2/knownhosts/*\" like files,
895 * `tramp-parse-hosts' for \"/etc/hosts\" like files,
896 * `tramp-parse-passwd' for \"/etc/passwd\" like files.
897 * `tramp-parse-netrc' for \"~/.netrc\" like files.
00d6fd04 898 * `tramp-parse-putty' for PuTTY registry keys.
5ec2cc41
KG
899
900FUNCTION can also be a customer defined function. For more details see
901the info pages.")
902
903(eval-after-load "tramp"
904 '(progn
905 (tramp-set-completion-function
906 "rcp" tramp-completion-function-alist-rsh)
907 (tramp-set-completion-function
908 "scp" tramp-completion-function-alist-ssh)
909 (tramp-set-completion-function
910 "scp1" tramp-completion-function-alist-ssh)
911 (tramp-set-completion-function
912 "scp2" tramp-completion-function-alist-ssh)
913 (tramp-set-completion-function
914 "scp1_old" tramp-completion-function-alist-ssh)
915 (tramp-set-completion-function
916 "scp2_old" tramp-completion-function-alist-ssh)
917 (tramp-set-completion-function
70c11b0b 918 "rsync" tramp-completion-function-alist-ssh)
946a5aeb
MA
919 (tramp-set-completion-function
920 "rsyncc" tramp-completion-function-alist-ssh)
5ec2cc41
KG
921 (tramp-set-completion-function
922 "remcp" tramp-completion-function-alist-rsh)
923 (tramp-set-completion-function
924 "rsh" tramp-completion-function-alist-rsh)
925 (tramp-set-completion-function
926 "ssh" tramp-completion-function-alist-ssh)
927 (tramp-set-completion-function
928 "ssh1" tramp-completion-function-alist-ssh)
929 (tramp-set-completion-function
930 "ssh2" tramp-completion-function-alist-ssh)
931 (tramp-set-completion-function
932 "ssh1_old" tramp-completion-function-alist-ssh)
933 (tramp-set-completion-function
934 "ssh2_old" tramp-completion-function-alist-ssh)
935 (tramp-set-completion-function
936 "remsh" tramp-completion-function-alist-rsh)
937 (tramp-set-completion-function
938 "telnet" tramp-completion-function-alist-telnet)
939 (tramp-set-completion-function
940 "su" tramp-completion-function-alist-su)
941 (tramp-set-completion-function
942 "sudo" tramp-completion-function-alist-su)
bf247b6e 943 (tramp-set-completion-function
5ec2cc41
KG
944 "scpx" tramp-completion-function-alist-ssh)
945 (tramp-set-completion-function
946 "sshx" tramp-completion-function-alist-ssh)
947 (tramp-set-completion-function
948 "krlogin" tramp-completion-function-alist-rsh)
949 (tramp-set-completion-function
950 "plink" tramp-completion-function-alist-ssh)
951 (tramp-set-completion-function
952 "plink1" tramp-completion-function-alist-ssh)
00d6fd04
MA
953 (tramp-set-completion-function
954 "plinkx" tramp-completion-function-alist-putty)
5ec2cc41
KG
955 (tramp-set-completion-function
956 "pscp" tramp-completion-function-alist-ssh)
957 (tramp-set-completion-function
958 "fcp" tramp-completion-function-alist-ssh)))
16674e4f 959
674da028
MA
960(defconst tramp-echo-mark-marker "_echo"
961 "String marker to surround echoed commands.")
962
68712eb6
MA
963(defconst tramp-echo-mark-marker-length (length tramp-echo-mark-marker)
964 "String length of `tramp-echo-mark-marker'.")
965
966(defconst tramp-echo-mark
967 (concat tramp-echo-mark-marker
968 (make-string tramp-echo-mark-marker-length ?\b))
00d6fd04
MA
969 "String mark to be transmitted around shell commands.
970Used to separate their echo from the output they produce. This
971will only be used if we cannot disable remote echo via stty.
972This string must have no effect on the remote shell except for
973producing some echo which can later be detected by
674da028
MA
974`tramp-echoed-echo-mark-regexp'. Using `tramp-echo-mark-marker',
975followed by an equal number of backspaces to erase them will
976usually suffice.")
00d6fd04 977
68712eb6
MA
978(defconst tramp-echoed-echo-mark-regexp
979 (format "%s\\(\b\\( \b\\)?\\)\\{%d\\}"
980 tramp-echo-mark-marker tramp-echo-mark-marker-length)
00d6fd04
MA
981 "Regexp which matches `tramp-echo-mark' as it gets echoed by
982the remote shell.")
983
fb7933a3
KG
984(defcustom tramp-rsh-end-of-line "\n"
985 "*String used for end of line in rsh connections.
986I don't think this ever needs to be changed, so please tell me about it
16674e4f 987if you need to change this.
90f8dc03
KG
988Also see the method parameter `tramp-password-end-of-line' and the normal
989variable `tramp-default-password-end-of-line'."
16674e4f
KG
990 :group 'tramp
991 :type 'string)
992
90f8dc03
KG
993(defcustom tramp-default-password-end-of-line
994 tramp-rsh-end-of-line
16674e4f 995 "*String used for end of line after sending a password.
90f8dc03
KG
996This variable provides the default value for the method parameter
997`tramp-password-end-of-line', see `tramp-methods' for more details.
998
16674e4f
KG
999It seems that people using plink under Windows need to send
1000\"\\r\\n\" (carriage-return, then newline) after a password, but just
1001\"\\n\" after all other lines. This variable can be used for the
1002password, see `tramp-rsh-end-of-line' for the other cases.
1003
1004The default value is to use the same value as `tramp-rsh-end-of-line'."
fb7933a3
KG
1005 :group 'tramp
1006 :type 'string)
1007
00d6fd04
MA
1008;; "getconf PATH" yields:
1009;; HP-UX: /usr/bin:/usr/ccs/bin:/opt/ansic/bin:/opt/langtools/bin:/opt/fortran/bin
1010;; Solaris: /usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin
0664ff72 1011;; GNU/Linux (Debian, Suse): /bin:/usr/bin
00d6fd04 1012;; FreeBSD: /usr/bin:/bin:/usr/sbin:/sbin: - beware trailing ":"!
fb7933a3 1013(defcustom tramp-remote-path
00d6fd04
MA
1014 '(tramp-default-remote-path "/usr/sbin" "/usr/local/bin"
1015 "/local/bin" "/local/freeware/bin" "/local/gnu/bin"
fb7933a3
KG
1016 "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin")
1017 "*List of directories to search for executables on remote host.
00d6fd04
MA
1018For every remote host, this variable will be set buffer local,
1019keeping the list of existing directories on that host.
fb7933a3
KG
1020
1021You can use `~' in this list, but when searching for a shell which groks
00d6fd04
MA
1022tilde expansion, all directory names starting with `~' will be ignored.
1023
1024`Default Directories' represent the list of directories given by
1025the command \"getconf PATH\". It is recommended to use this
1026entry on top of this list, because these are the default
70c11b0b
MA
1027directories for POSIX compatible commands.
1028
1029`Private Directories' are the settings of the $PATH environment,
1030as given in your `~/.profile'."
00d6fd04
MA
1031 :group 'tramp
1032 :type '(repeat (choice
1033 (const :tag "Default Directories" tramp-default-remote-path)
70c11b0b 1034 (const :tag "Private Directories" tramp-own-remote-path)
00d6fd04
MA
1035 (string :tag "Directory"))))
1036
00d6fd04 1037(defcustom tramp-remote-process-environment
a0a5183a 1038 `("HISTFILE=$HOME/.tramp_history" "HISTSIZE=1" "LC_ALL=C"
b533bc97 1039 ,(format "TERM=%s" tramp-terminal-type)
97c696d5
MA
1040 "EMACS=t" ;; Deprecated.
1041 ,(format "INSIDE_EMACS=%s,tramp:%s" emacs-version tramp-version)
00d6fd04
MA
1042 "CDPATH=" "HISTORY=" "MAIL=" "MAILCHECK=" "MAILPATH="
1043 "autocorrect=" "correct=")
1044
1045 "*List of environment variables to be set on the remote host.
1046
1047Each element should be a string of the form ENVVARNAME=VALUE. An
1048entry ENVVARNAME= diables the corresponding environment variable,
1049which might have been set in the init files like ~/.profile.
1050
1051Special handling is applied to the PATH environment, which should
1052not be set here. Instead of, it should be set via `tramp-remote-path'."
fb7933a3
KG
1053 :group 'tramp
1054 :type '(repeat string))
1055
1056(defcustom tramp-login-prompt-regexp
bc103d00 1057 ".*ogin\\( .*\\)?: *"
fb7933a3 1058 "*Regexp matching login-like prompts.
bc103d00
MA
1059The regexp should match at end of buffer.
1060
1061Sometimes the prompt is reported to look like \"login as:\"."
fb7933a3
KG
1062 :group 'tramp
1063 :type 'regexp)
1064
821e6e36 1065(defcustom tramp-shell-prompt-pattern
aa485f7c
MA
1066 ;; Allow a prompt to start right after a ^M since it indeed would be
1067 ;; displayed at the beginning of the line (and Zsh uses it).
dab816a9 1068 "\\(?:^\\|\r\\)[^#$%>\n]*#?[#$%>] *\\(\e\\[[0-9;]*[a-zA-Z] *\\)*"
821e6e36
KG
1069 "Regexp to match prompts from remote shell.
1070Normally, Tramp expects you to configure `shell-prompt-pattern'
1071correctly, but sometimes it happens that you are connecting to a
1072remote host which sends a different kind of shell prompt. Therefore,
1073Tramp recognizes things matched by `shell-prompt-pattern' as prompt,
1074and also things matched by this variable. The default value of this
b25a52cc 1075variable is similar to the default value of `shell-prompt-pattern',
dab816a9
MA
1076which should work well in many cases.
1077
1078This regexp must match both `tramp-initial-end-of-output' and
1079`tramp-end-of-output'."
821e6e36
KG
1080 :group 'tramp
1081 :type 'regexp)
1082
fb7933a3 1083(defcustom tramp-password-prompt-regexp
00d6fd04 1084 "^.*\\([pP]assword\\|[pP]assphrase\\).*:\^@? *"
fb7933a3 1085 "*Regexp matching password-like prompts.
ac474af1 1086The regexp should match at end of buffer.
fb7933a3
KG
1087
1088The `sudo' program appears to insert a `^@' character into the prompt."
1089 :group 'tramp
1090 :type 'regexp)
1091
1092(defcustom tramp-wrong-passwd-regexp
b1d06e75
KG
1093 (concat "^.*"
1094 ;; These strings should be on the last line
a4aeb9a4 1095 (regexp-opt '("Permission denied"
b1d06e75
KG
1096 "Login incorrect"
1097 "Login Incorrect"
1098 "Connection refused"
27e813fe 1099 "Connection closed"
7e5686f0 1100 "Timeout, server not responding."
b1d06e75
KG
1101 "Sorry, try again."
1102 "Name or service not known"
00d6fd04 1103 "Host key verification failed."
70c11b0b 1104 "No supported authentication methods left to try!") t)
b1d06e75
KG
1105 ".*"
1106 "\\|"
1107 "^.*\\("
1108 ;; Here comes a list of regexes, separated by \\|
1109 "Received signal [0-9]+"
1110 "\\).*")
fb7933a3 1111 "*Regexp matching a `login failed' message.
ac474af1
KG
1112The regexp should match at end of buffer."
1113 :group 'tramp
1114 :type 'regexp)
1115
1116(defcustom tramp-yesno-prompt-regexp
3cdaec13
KG
1117 (concat
1118 (regexp-opt '("Are you sure you want to continue connecting (yes/no)?") t)
1119 "\\s-*")
1120 "Regular expression matching all yes/no queries which need to be confirmed.
ac474af1 1121The confirmation should be done with yes or no.
3cdaec13
KG
1122The regexp should match at end of buffer.
1123See also `tramp-yn-prompt-regexp'."
fb7933a3
KG
1124 :group 'tramp
1125 :type 'regexp)
1126
3cdaec13 1127(defcustom tramp-yn-prompt-regexp
658052a2
MA
1128 (concat
1129 (regexp-opt '("Store key in cache? (y/n)"
1130 "Update cached key? (y/n, Return cancels connection)") t)
1131 "\\s-*")
3cdaec13
KG
1132 "Regular expression matching all y/n queries which need to be confirmed.
1133The confirmation should be done with y or n.
1134The regexp should match at end of buffer.
1135See also `tramp-yesno-prompt-regexp'."
1136 :group 'tramp
1137 :type 'regexp)
487f4fb7
KG
1138
1139(defcustom tramp-terminal-prompt-regexp
1140 (concat "\\("
1141 "TERM = (.*)"
1142 "\\|"
1143 "Terminal type\\? \\[.*\\]"
1144 "\\)\\s-*")
1145 "Regular expression matching all terminal setting prompts.
1146The regexp should match at end of buffer.
1147The answer will be provided by `tramp-action-terminal', which see."
1148 :group 'tramp
1149 :type 'regexp)
3cdaec13 1150
01917a18
MA
1151(defcustom tramp-operation-not-permitted-regexp
1152 (concat "\\(" "preserving times.*" "\\|" "set mode" "\\)" ":\\s-*"
1153 (regexp-opt '("Operation not permitted") t))
1154 "Regular expression matching keep-date problems in (s)cp operations.
1155Copying has been performed successfully already, so this message can
1156be ignored safely."
1157 :group 'tramp
1158 :type 'regexp)
1159
6b2633cc
LH
1160(defcustom tramp-copy-failed-regexp
1161 (concat "\\(.+: "
1162 (regexp-opt '("Permission denied"
1163 "not a regular file"
1164 "is a directory"
1165 "No such file or directory") t)
1166 "\\)\\s-*")
1167 "Regular expression matching copy problems in (s)cp operations."
1168 :group 'tramp
1169 :type 'regexp)
1170
19a87064 1171(defcustom tramp-process-alive-regexp
38c65fca 1172 ""
19a87064 1173 "Regular expression indicating a process has finished.
38c65fca
KG
1174In fact this expression is empty by intention, it will be used only to
1175check regularly the status of the associated process.
07dfe738 1176The answer will be provided by `tramp-action-process-alive',
00d6fd04 1177`tramp-action-out-of-band', which see."
38c65fca
KG
1178 :group 'tramp
1179 :type 'regexp)
1180
fb7933a3
KG
1181(defcustom tramp-temp-name-prefix "tramp."
1182 "*Prefix to use for temporary files.
1183If this is a relative file name (such as \"tramp.\"), it is considered
1184relative to the directory name returned by the function
9e6ab520 1185`tramp-compat-temporary-file-directory' (which see). It may also be an
fb7933a3
KG
1186absolute file name; don't forget to include a prefix for the filename
1187part, though."
1188 :group 'tramp
1189 :type 'string)
1190
2296b54d
MA
1191(defconst tramp-temp-buffer-name " *tramp temp*"
1192 "Buffer name for a temporary buffer.
1193It shall be used in combination with `generate-new-buffer-name'.")
1194
b88f2d0a
MA
1195(defvar tramp-temp-buffer-file-name nil
1196 "File name of a persistent local temporary file.
1197Useful for \"rsync\" like methods.")
1198(make-variable-buffer-local 'tramp-temp-buffer-file-name)
1199
4007ba5b 1200(defcustom tramp-sh-extra-args '(("/bash\\'" . "-norc -noprofile"))
c62c9d08
KG
1201 "*Alist specifying extra arguments to pass to the remote shell.
1202Entries are (REGEXP . ARGS) where REGEXP is a regular expression
1203matching the shell file name and ARGS is a string specifying the
1204arguments.
1205
1206This variable is only used when Tramp needs to start up another shell
1207for tilde expansion. The extra arguments should typically prevent the
1208shell from reading its init file."
1209 :group 'tramp
90f8dc03
KG
1210 ;; This might be the wrong way to test whether the widget type
1211 ;; `alist' is available. Who knows the right way to test it?
1212 :type (if (get 'alist 'widget-type)
1213 '(alist :key-type string :value-type string)
1214 '(repeat (cons string string))))
c62c9d08 1215
00d6fd04
MA
1216;; XEmacs is distributed with few Lisp packages. Further packages are
1217;; installed using EFS. If we use a unified filename format, then
1218;; Tramp is required in addition to EFS. (But why can't Tramp just
1219;; disable EFS when Tramp is loaded? Then XEmacs can ship with EFS
1220;; just like before.) Another reason for using a separate filename
1221;; syntax on XEmacs is that EFS hooks into XEmacs in many places, but
1222;; Tramp only knows how to deal with `file-name-handler-alist', not
1223;; the other places.
1224
1225;; Currently, we have the choice between 'ftp, 'sep, and 'url.
1226;;;###autoload
1227(defcustom tramp-syntax
1228 (if (featurep 'xemacs) 'sep 'ftp)
1229 "Tramp filename syntax to be used.
1230
1231It can have the following values:
1232
1233 'ftp -- Ange-FTP respective EFS like syntax (GNU Emacs default)
1234 'sep -- Syntax as defined for XEmacs (not available yet for GNU Emacs)
1235 'url -- URL-like syntax."
16674e4f 1236 :group 'tramp
00d6fd04
MA
1237 :type (if (featurep 'xemacs)
1238 '(choice (const :tag "EFS" ftp)
1239 (const :tag "XEmacs" sep)
1240 (const :tag "URL" url))
1241 '(choice (const :tag "Ange-FTP" ftp)
1242 (const :tag "URL" url))))
1243
1244(defconst tramp-prefix-format
1245 (cond ((equal tramp-syntax 'ftp) "/")
1246 ((equal tramp-syntax 'sep) "/[")
1247 ((equal tramp-syntax 'url) "/")
1248 (t (error "Wrong `tramp-syntax' defined")))
a4aeb9a4 1249 "*String matching the very beginning of Tramp file names.
00d6fd04 1250Used in `tramp-make-tramp-file-name'.")
16674e4f 1251
00d6fd04 1252(defconst tramp-prefix-regexp
16674e4f 1253 (concat "^" (regexp-quote tramp-prefix-format))
a4aeb9a4 1254 "*Regexp matching the very beginning of Tramp file names.
00d6fd04 1255Should always start with \"^\". Derived from `tramp-prefix-format'.")
16674e4f 1256
00d6fd04 1257(defconst tramp-method-regexp
16674e4f 1258 "[a-zA-Z_0-9-]+"
00d6fd04 1259 "*Regexp matching methods identifiers.")
16674e4f 1260
00d6fd04
MA
1261(defconst tramp-postfix-method-format
1262 (cond ((equal tramp-syntax 'ftp) ":")
1263 ((equal tramp-syntax 'sep) "/")
1264 ((equal tramp-syntax 'url) "://")
1265 (t (error "Wrong `tramp-syntax' defined")))
16674e4f 1266 "*String matching delimeter between method and user or host names.
00d6fd04 1267Used in `tramp-make-tramp-file-name'.")
16674e4f 1268
00d6fd04
MA
1269(defconst tramp-postfix-method-regexp
1270 (regexp-quote tramp-postfix-method-format)
16674e4f 1271 "*Regexp matching delimeter between method and user or host names.
00d6fd04 1272Derived from `tramp-postfix-method-format'.")
16674e4f 1273
00d6fd04
MA
1274(defconst tramp-user-regexp
1275 "[^:/ \t]+"
1276 "*Regexp matching user names.")
16674e4f 1277
b96e6899
MA
1278(defconst tramp-prefix-domain-format "%"
1279 "*String matching delimeter between user and domain names.")
1280
1281(defconst tramp-prefix-domain-regexp
1282 (regexp-quote tramp-prefix-domain-format)
1283 "*Regexp matching delimeter between user and domain names.
1284Derived from `tramp-prefix-domain-format'.")
1285
1286(defconst tramp-domain-regexp
70c11b0b 1287 "[-a-zA-Z0-9_.]+"
b96e6899
MA
1288 "*Regexp matching domain names.")
1289
1290(defconst tramp-user-with-domain-regexp
1291 (concat "\\(" tramp-user-regexp "\\)"
1292 tramp-prefix-domain-regexp
1293 "\\(" tramp-domain-regexp "\\)")
1294 "*Regexp matching user names with domain names.")
1295
00d6fd04 1296(defconst tramp-postfix-user-format
16674e4f
KG
1297 "@"
1298 "*String matching delimeter between user and host names.
00d6fd04 1299Used in `tramp-make-tramp-file-name'.")
16674e4f 1300
00d6fd04 1301(defconst tramp-postfix-user-regexp
16674e4f
KG
1302 (regexp-quote tramp-postfix-user-format)
1303 "*Regexp matching delimeter between user and host names.
00d6fd04
MA
1304Derived from `tramp-postfix-user-format'.")
1305
1306(defconst tramp-host-regexp
1307 "[a-zA-Z0-9_.-]+"
1308 "*Regexp matching host names.")
1309
b96e6899
MA
1310(defconst tramp-prefix-ipv6-format
1311 (cond ((equal tramp-syntax 'ftp) "[")
1312 ((equal tramp-syntax 'sep) "")
1313 ((equal tramp-syntax 'url) "[")
1314 (t (error "Wrong `tramp-syntax' defined")))
1315 "*String matching left hand side of IPv6 addresses.
1316Used in `tramp-make-tramp-file-name'.")
1317
1318(defconst tramp-prefix-ipv6-regexp
1319 (regexp-quote tramp-prefix-ipv6-format)
1320 "*Regexp matching left hand side of IPv6 addresses.
1321Derived from `tramp-prefix-ipv6-format'.")
1322
e0b6e3b9
MA
1323;; The following regexp is a bit sloppy. But it shall serve our
1324;; purposes. It covers also IPv4 mapped IPv6 addresses, like in
1325;; "::ffff:192.168.0.1".
b96e6899 1326(defconst tramp-ipv6-regexp
e0b6e3b9 1327 "\\(?:\\(?:[a-zA-Z0-9]+\\)?:\\)+[a-zA-Z0-9.]+"
b96e6899
MA
1328 "*Regexp matching IPv6 addresses.")
1329
1330(defconst tramp-postfix-ipv6-format
1331 (cond ((equal tramp-syntax 'ftp) "]")
1332 ((equal tramp-syntax 'sep) "")
1333 ((equal tramp-syntax 'url) "]")
1334 (t (error "Wrong `tramp-syntax' defined")))
1335 "*String matching right hand side of IPv6 addresses.
1336Used in `tramp-make-tramp-file-name'.")
1337
1338(defconst tramp-postfix-ipv6-regexp
1339 (regexp-quote tramp-postfix-ipv6-format)
1340 "*Regexp matching right hand side of IPv6 addresses.
1341Derived from `tramp-postfix-ipv6-format'.")
1342
00d6fd04
MA
1343(defconst tramp-prefix-port-format
1344 (cond ((equal tramp-syntax 'ftp) "#")
1345 ((equal tramp-syntax 'sep) "#")
1346 ((equal tramp-syntax 'url) ":")
1347 (t (error "Wrong `tramp-syntax' defined")))
1348 "*String matching delimeter between host names and port numbers.")
1349
1350(defconst tramp-prefix-port-regexp
1351 (regexp-quote tramp-prefix-port-format)
1352 "*Regexp matching delimeter between host names and port numbers.
1353Derived from `tramp-prefix-port-format'.")
1354
1355(defconst tramp-port-regexp
1356 "[0-9]+"
1357 "*Regexp matching port numbers.")
1358
1359(defconst tramp-host-with-port-regexp
1360 (concat "\\(" tramp-host-regexp "\\)"
1361 tramp-prefix-port-regexp
1362 "\\(" tramp-port-regexp "\\)")
1363 "*Regexp matching host names with port numbers.")
1364
1365(defconst tramp-postfix-host-format
1366 (cond ((equal tramp-syntax 'ftp) ":")
1367 ((equal tramp-syntax 'sep) "]")
1368 ((equal tramp-syntax 'url) "")
1369 (t (error "Wrong `tramp-syntax' defined")))
7432277c 1370 "*String matching delimeter between host names and localnames.
00d6fd04 1371Used in `tramp-make-tramp-file-name'.")
16674e4f 1372
00d6fd04 1373(defconst tramp-postfix-host-regexp
16674e4f 1374 (regexp-quote tramp-postfix-host-format)
7432277c 1375 "*Regexp matching delimeter between host names and localnames.
00d6fd04 1376Derived from `tramp-postfix-host-format'.")
16674e4f 1377
00d6fd04 1378(defconst tramp-localname-regexp
16674e4f 1379 ".*$"
00d6fd04 1380 "*Regexp matching localnames.")
16674e4f
KG
1381
1382;; File name format.
505edaeb 1383
00d6fd04 1384(defconst tramp-file-name-structure
16674e4f
KG
1385 (list
1386 (concat
1387 tramp-prefix-regexp
00d6fd04
MA
1388 "\\(" "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp "\\)?"
1389 "\\(" "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp "\\)?"
b96e6899
MA
1390 "\\(" "\\(" tramp-host-regexp
1391 "\\|"
1392 tramp-prefix-ipv6-regexp tramp-ipv6-regexp
1393 tramp-postfix-ipv6-regexp "\\)"
1394 "\\(" tramp-prefix-port-regexp tramp-port-regexp "\\)?" "\\)?"
00d6fd04
MA
1395 tramp-postfix-host-regexp
1396 "\\(" tramp-localname-regexp "\\)")
b96e6899 1397 2 4 5 8)
16674e4f 1398
fb7933a3 1399 "*List of five elements (REGEXP METHOD USER HOST FILE), detailing \
a4aeb9a4 1400the Tramp file name structure.
fb7933a3 1401
a4aeb9a4 1402The first element REGEXP is a regular expression matching a Tramp file
fb7933a3
KG
1403name. The regex should contain parentheses around the method name,
1404the user name, the host name, and the file name parts.
1405
1406The second element METHOD is a number, saying which pair of
1407parentheses matches the method name. The third element USER is
1408similar, but for the user name. The fourth element HOST is similar,
1409but for the host name. The fifth element FILE is for the file name.
1410These numbers are passed directly to `match-string', which see. That
1411means the opening parentheses are counted to identify the pair.
1412
00d6fd04 1413See also `tramp-file-name-regexp'.")
fb7933a3
KG
1414
1415;;;###autoload
505edaeb 1416(defconst tramp-file-name-regexp-unified
b96e6899 1417 "\\`/\\([^[/:]+\\|[^/]+]\\):"
505edaeb
KG
1418 "Value for `tramp-file-name-regexp' for unified remoting.
1419Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and
00d6fd04 1420Tramp. See `tramp-file-name-structure' for more explanations.")
505edaeb
KG
1421
1422;;;###autoload
1423(defconst tramp-file-name-regexp-separate
1424 "\\`/\\[.*\\]"
1425 "Value for `tramp-file-name-regexp' for separate remoting.
1426XEmacs uses a separate filename syntax for Tramp and EFS.
00d6fd04 1427See `tramp-file-name-structure' for more explanations.")
505edaeb
KG
1428
1429;;;###autoload
00d6fd04
MA
1430(defconst tramp-file-name-regexp-url
1431 "\\`/[^/:]+://"
1432 "Value for `tramp-file-name-regexp' for URL-like remoting.
1433See `tramp-file-name-structure' for more explanations.")
1434
1435;;;###autoload
1436(defconst tramp-file-name-regexp
1437 (cond ((equal tramp-syntax 'ftp) tramp-file-name-regexp-unified)
1438 ((equal tramp-syntax 'sep) tramp-file-name-regexp-separate)
1439 ((equal tramp-syntax 'url) tramp-file-name-regexp-url)
1440 (t (error "Wrong `tramp-syntax' defined")))
94be87e8 1441 "*Regular expression matching file names handled by Tramp.
a4aeb9a4 1442This regexp should match Tramp file names but no other file names.
b533bc97 1443When tramp.el is loaded, this regular expression is prepended to
fb7933a3 1444`file-name-handler-alist', and that is searched sequentially. Thus,
a4aeb9a4
MA
1445if the Tramp entry appears rather early in the `file-name-handler-alist'
1446and is a bit too general, then some files might be considered Tramp
00d6fd04 1447files which are not really Tramp files.
fb7933a3
KG
1448
1449Please note that the entry in `file-name-handler-alist' is made when
b533bc97 1450this file \(tramp.el\) is loaded. This means that this variable must be set
fb7933a3
KG
1451before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1452updated after changing this variable.
1453
00d6fd04 1454Also see `tramp-file-name-structure'.")
fb7933a3 1455
16674e4f 1456;;;###autoload
8a798e41 1457(defconst tramp-root-regexp
00d6fd04 1458 (if (memq system-type '(cygwin windows-nt))
aa485f7c
MA
1459 "\\`\\([a-zA-Z]:\\)?/"
1460 "\\`/")
8a798e41 1461 "Beginning of an incomplete Tramp file name.
aa485f7c 1462Usually, it is just \"\\\\`/\". On W32 systems, there might be a
57671b72 1463volume letter, which will be removed by `tramp-drop-volume-letter'.")
8a798e41
MA
1464
1465;;;###autoload
1466(defconst tramp-completion-file-name-regexp-unified
aa485f7c 1467 (concat tramp-root-regexp "[^/]*\\'")
16674e4f 1468 "Value for `tramp-completion-file-name-regexp' for unified remoting.
8a798e41
MA
1469GNU Emacs uses a unified filename syntax for Tramp and Ange-FTP.
1470See `tramp-file-name-structure' for more explanations.")
fb7933a3 1471
16674e4f
KG
1472;;;###autoload
1473(defconst tramp-completion-file-name-regexp-separate
aa485f7c 1474 (concat tramp-root-regexp "\\([[][^]]*\\)?\\'")
16674e4f
KG
1475 "Value for `tramp-completion-file-name-regexp' for separate remoting.
1476XEmacs uses a separate filename syntax for Tramp and EFS.
00d6fd04 1477See `tramp-file-name-structure' for more explanations.")
fb7933a3 1478
16674e4f 1479;;;###autoload
00d6fd04 1480(defconst tramp-completion-file-name-regexp-url
aa485f7c 1481 (concat tramp-root-regexp "[^/:]+\\(:\\(/\\(/[^/]*\\)?\\)?\\)?\\'")
00d6fd04
MA
1482 "Value for `tramp-completion-file-name-regexp' for URL-like remoting.
1483See `tramp-file-name-structure' for more explanations.")
1484
1485;;;###autoload
1486(defconst tramp-completion-file-name-regexp
1487 (cond ((equal tramp-syntax 'ftp) tramp-completion-file-name-regexp-unified)
1488 ((equal tramp-syntax 'sep) tramp-completion-file-name-regexp-separate)
1489 ((equal tramp-syntax 'url) tramp-completion-file-name-regexp-url)
1490 (t (error "Wrong `tramp-syntax' defined")))
a4aeb9a4
MA
1491 "*Regular expression matching file names handled by Tramp completion.
1492This regexp should match partial Tramp file names only.
16674e4f
KG
1493
1494Please note that the entry in `file-name-handler-alist' is made when
1495this file (tramp.el) is loaded. This means that this variable must be set
1496before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1497updated after changing this variable.
1498
00d6fd04 1499Also see `tramp-file-name-structure'.")
fb7933a3 1500
00d6fd04
MA
1501(defconst tramp-actions-before-shell
1502 '((tramp-login-prompt-regexp tramp-action-login)
1503 (tramp-password-prompt-regexp tramp-action-password)
1504 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
ac474af1 1505 (shell-prompt-pattern tramp-action-succeed)
821e6e36 1506 (tramp-shell-prompt-pattern tramp-action-succeed)
3cdaec13 1507 (tramp-yesno-prompt-regexp tramp-action-yesno)
487f4fb7 1508 (tramp-yn-prompt-regexp tramp-action-yn)
19a87064
MA
1509 (tramp-terminal-prompt-regexp tramp-action-terminal)
1510 (tramp-process-alive-regexp tramp-action-process-alive))
ac474af1
KG
1511 "List of pattern/action pairs.
1512Whenever a pattern matches, the corresponding action is performed.
1513Each item looks like (PATTERN ACTION).
1514
1515The PATTERN should be a symbol, a variable. The value of this
1516variable gives the regular expression to search for. Note that the
1517regexp must match at the end of the buffer, \"\\'\" is implicitly
1518appended to it.
1519
1520The ACTION should also be a symbol, but a function. When the
00d6fd04 1521corresponding PATTERN matches, the ACTION function is called.")
ac474af1 1522
00d6fd04 1523(defconst tramp-actions-copy-out-of-band
38c65fca
KG
1524 '((tramp-password-prompt-regexp tramp-action-password)
1525 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
00d6fd04 1526 (tramp-copy-failed-regexp tramp-action-permission-denied)
19a87064 1527 (tramp-process-alive-regexp tramp-action-out-of-band))
38c65fca
KG
1528 "List of pattern/action pairs.
1529This list is used for copying/renaming with out-of-band methods.
90f8dc03 1530
00d6fd04
MA
1531See `tramp-actions-before-shell' for more info.")
1532
1533;; Chunked sending kludge. We set this to 500 for black-listed constellations
7432277c 1534;; known to have a bug in `process-send-string'; some ssh connections appear
7177e2a3
MA
1535;; to drop bytes when data is sent too quickly. There is also a connection
1536;; buffer local variable, which is computed depending on remote host properties
1537;; when `tramp-chunksize' is zero or nil.
7432277c
KG
1538(defcustom tramp-chunksize
1539 (when (and (not (featurep 'xemacs))
1540 (memq system-type '(hpux)))
1541 500)
55880756
MA
1542;; Parentheses in docstring starting at beginning of line are escaped.
1543;; Fontification is messed up when
1544;; `open-paren-in-column-0-is-defun-start' set to t.
7432277c
KG
1545 "*If non-nil, chunksize for sending input to local process.
1546It is necessary only on systems which have a buggy `process-send-string'
1547implementation. The necessity, whether this variable must be set, can be
1548checked via the following code:
1549
1550 (with-temp-buffer
11948172
MA
1551 (let* ((user \"xxx\") (host \"yyy\")
1552 (init 0) (step 50)
1553 (sent init) (received init))
1554 (while (= sent received)
1555 (setq sent (+ sent step))
1556 (erase-buffer)
1557 (let ((proc (start-process (buffer-name) (current-buffer)
1558 \"ssh\" \"-l\" user host \"wc\" \"-c\")))
1559 (when (memq (process-status proc) '(run open))
1560 (process-send-string proc (make-string sent ?\\ ))
1561 (process-send-eof proc)
1562 (process-send-eof proc))
1563 (while (not (progn (goto-char (point-min))
1564 (re-search-forward \"\\\\w+\" (point-max) t)))
1565 (accept-process-output proc 1))
1566 (when (memq (process-status proc) '(run open))
1567 (setq received (string-to-number (match-string 0)))
1568 (delete-process proc)
1569 (message \"Bytes sent: %s\\tBytes received: %s\" sent received)
1570 (sit-for 0))))
1571 (if (> sent (+ init step))
1572 (message \"You should set `tramp-chunksize' to a maximum of %s\"
1573 (- sent step))
1574 (message \"Test does not work\")
1575 (display-buffer (current-buffer))
1576 (sit-for 30))))
1577
1578In the Emacs normally running Tramp, evaluate the above code
55880756 1579\(replace \"xxx\" and \"yyy\" by the remote user and host name,
b533bc97 1580respectively\). You can do this, for example, by pasting it into
11948172
MA
1581the `*scratch*' buffer and then hitting C-j with the cursor after the
1582last closing parenthesis. Note that it works only if you have configured
b533bc97 1583\"ssh\" to run without password query, see ssh-agent\(1\).
11948172
MA
1584
1585You will see the number of bytes sent successfully to the remote host.
1586If that number exceeds 1000, you can stop the execution by hitting
1587C-g, because your Emacs is likely clean.
1588
11948172 1589When it is necessary to set `tramp-chunksize', you might consider to
b533bc97
MA
1590use an out-of-the-band method \(like \"scp\"\) instead of an internal one
1591\(like \"ssh\"\), because setting `tramp-chunksize' to non-nil decreases
11948172 1592performance.
c951aecb 1593
00d6fd04
MA
1594If your Emacs is buggy, the code stops and gives you an indication
1595about the value `tramp-chunksize' should be set. Maybe you could just
1596experiment a bit, e.g. changing the values of `init' and `step'
1597in the third line of the code.
1598
7432277c
KG
1599Please raise a bug report via \"M-x tramp-bug\" if your system needs
1600this variable to be set as well."
1601 :group 'tramp
b1a2b924 1602 :type '(choice (const nil) integer))
7432277c 1603
5ec2cc41
KG
1604;; Logging in to a remote host normally requires obtaining a pty. But
1605;; Emacs on MacOS X has process-connection-type set to nil by default,
1606;; so on those systems Tramp doesn't obtain a pty. Here, we allow
1607;; for an override of the system default.
1608(defcustom tramp-process-connection-type t
1609 "Overrides `process-connection-type' for connections from Tramp.
1610Tramp binds process-connection-type to the value given here before
1611opening a connection to a remote host."
1612 :group 'tramp
1613 :type '(choice (const nil) (const t) (const pty)))
1614
b50dd0d2
MA
1615(defcustom tramp-completion-reread-directory-timeout 10
1616 "Defines seconds since last remote command before rereading a directory.
1617A remote directory might have changed its contents. In order to
1618make it visible during file name completion in the minibuffer,
1619Tramp flushes its cache and rereads the directory contents when
1620more than `tramp-completion-reread-directory-timeout' seconds
1621have been gone since last remote command execution. A value of 0
1622would require an immediate reread during filename completion, nil
1623means to use always cached values for the directory contents."
1624 :group 'tramp
1625 :type '(choice (const nil) integer))
1626
fb7933a3
KG
1627;;; Internal Variables:
1628
fb7933a3 1629(defvar tramp-current-method nil
00d6fd04 1630 "Connection method for this *tramp* buffer.")
fb7933a3
KG
1631
1632(defvar tramp-current-user nil
00d6fd04 1633 "Remote login name for this *tramp* buffer.")
fb7933a3
KG
1634
1635(defvar tramp-current-host nil
00d6fd04
MA
1636 "Remote host for this *tramp* buffer.")
1637
1638(defconst tramp-uudecode
1639 "(echo begin 600 /tmp/tramp.$$; tail +2) | uudecode
fabf2143 1640cat /tmp/tramp.$$
00d6fd04 1641rm -f /tmp/tramp.$$"
fabf2143 1642 "Shell function to implement `uudecode' to standard output.
c08e6004
MA
1643Many systems support `uudecode -o /dev/stdout' or `uudecode -o -'
1644for this or `uudecode -p', but some systems don't, and for them
1645we have this shell function.")
fabf2143 1646
293c24f9
MA
1647(defconst tramp-perl-file-truename
1648 "%s -e '
1649use File::Spec;
1650use Cwd \"realpath\";
1651
1652sub recursive {
1653 my ($volume, @dirs) = @_;
1654 my $real = realpath(File::Spec->catpath(
1655 $volume, File::Spec->catdir(@dirs), \"\"));
1656 if ($real) {
1657 my ($vol, $dir) = File::Spec->splitpath($real, 1);
1658 return ($vol, File::Spec->splitdir($dir));
1659 }
1660 else {
1661 my $last = pop(@dirs);
1662 ($volume, @dirs) = recursive($volume, @dirs);
1663 push(@dirs, $last);
1664 return ($volume, @dirs);
1665 }
1666}
1667
1668$result = realpath($ARGV[0]);
1669if (!$result) {
1670 my ($vol, $dir) = File::Spec->splitpath($ARGV[0], 1);
1671 ($vol, @dirs) = recursive($vol, File::Spec->splitdir($dir));
1672
1673 $result = File::Spec->catpath($vol, File::Spec->catdir(@dirs), \"\");
1674}
1675
1676if ($ARGV[0] =~ /\\/$/) {
1677 $result = $result . \"/\";
1678}
1679
1680print \"\\\"$result\\\"\\n\";
1681' \"$1\" 2>/dev/null"
1682 "Perl script to produce output suitable for use with `file-truename'
1683on the remote file system.
1684Escape sequence %s is replaced with name of Perl binary.
1685This string is passed to `format', so percent characters need to be doubled.")
1686
1687(defconst tramp-perl-file-name-all-completions
1688 "%s -e 'sub case {
1689 my $str = shift;
1690 if ($ARGV[2]) {
1691 return lc($str);
1692 }
1693 else {
1694 return $str;
1695 }
1696}
1697opendir(d, $ARGV[0]) || die(\"$ARGV[0]: $!\\nfail\\n\");
1698@files = readdir(d); closedir(d);
1699foreach $f (@files) {
1700 if (case(substr($f, 0, length($ARGV[1]))) eq case($ARGV[1])) {
1701 if (-d \"$ARGV[0]/$f\") {
1702 print \"$f/\\n\";
1703 }
1704 else {
1705 print \"$f\\n\";
1706 }
1707 }
1708}
1709print \"ok\\n\"
1710' \"$1\" \"$2\" \"$3\" 2>/dev/null"
1711 "Perl script to produce output suitable for use with
1712`file-name-all-completions' on the remote file system. Escape
1713sequence %s is replaced with name of Perl binary. This string is
1714passed to `format', so percent characters need to be doubled.")
1715
fabf2143
KG
1716;; Perl script to implement `file-attributes' in a Lisp `read'able
1717;; output. If you are hacking on this, note that you get *no* output
1718;; unless this spits out a complete line, including the '\n' at the
1719;; end.
8daea7fc 1720;; The device number is returned as "-1", because there will be a virtual
b946a456 1721;; device number set in `tramp-handle-file-attributes'.
00d6fd04
MA
1722(defconst tramp-perl-file-attributes
1723 "%s -e '
c82c5727 1724@stat = lstat($ARGV[0]);
680db9ac
MA
1725if (!@stat) {
1726 print \"nil\\n\";
1727 exit 0;
1728}
c82c5727
LH
1729if (($stat[2] & 0170000) == 0120000)
1730{
1731 $type = readlink($ARGV[0]);
1732 $type = \"\\\"$type\\\"\";
1733}
1734elsif (($stat[2] & 0170000) == 040000)
1735{
1736 $type = \"t\";
1737}
1738else
1739{
1740 $type = \"nil\"
1741};
1742$uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
1743$gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
1744printf(
d4443a0d 1745 \"(%%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) -1)\\n\",
c82c5727
LH
1746 $type,
1747 $stat[3],
1748 $uid,
1749 $gid,
1750 $stat[8] >> 16 & 0xffff,
1751 $stat[8] & 0xffff,
1752 $stat[9] >> 16 & 0xffff,
1753 $stat[9] & 0xffff,
1754 $stat[10] >> 16 & 0xffff,
1755 $stat[10] & 0xffff,
1756 $stat[7],
1757 $stat[2],
1758 $stat[1] >> 16 & 0xffff,
1759 $stat[1] & 0xffff
00d6fd04 1760);' \"$1\" \"$2\" \"$3\" 2>/dev/null"
fb7933a3 1761 "Perl script to produce output suitable for use with `file-attributes'
00d6fd04
MA
1762on the remote file system.
1763Escape sequence %s is replaced with name of Perl binary.
1764This string is passed to `format', so percent characters need to be doubled.")
fb7933a3 1765
00d6fd04
MA
1766(defconst tramp-perl-directory-files-and-attributes
1767 "%s -e '
8cb0a559
LH
1768chdir($ARGV[0]) or printf(\"\\\"Cannot change to $ARGV[0]: $''!''\\\"\\n\"), exit();
1769opendir(DIR,\".\") or printf(\"\\\"Cannot open directory $ARGV[0]: $''!''\\\"\\n\"), exit();
c82c5727
LH
1770@list = readdir(DIR);
1771closedir(DIR);
1772$n = scalar(@list);
1773printf(\"(\\n\");
1774for($i = 0; $i < $n; $i++)
1775{
1776 $filename = $list[$i];
1777 @stat = lstat($filename);
1778 if (($stat[2] & 0170000) == 0120000)
1779 {
1780 $type = readlink($filename);
1781 $type = \"\\\"$type\\\"\";
1782 }
1783 elsif (($stat[2] & 0170000) == 040000)
1784 {
1785 $type = \"t\";
1786 }
1787 else
1788 {
1789 $type = \"nil\"
1790 };
1791 $uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
1792 $gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
1793 printf(
b946a456 1794 \"(\\\"%%s\\\" %%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) (%%u . %%u))\\n\",
c82c5727
LH
1795 $filename,
1796 $type,
1797 $stat[3],
1798 $uid,
1799 $gid,
1800 $stat[8] >> 16 & 0xffff,
1801 $stat[8] & 0xffff,
1802 $stat[9] >> 16 & 0xffff,
1803 $stat[9] & 0xffff,
1804 $stat[10] >> 16 & 0xffff,
1805 $stat[10] & 0xffff,
1806 $stat[7],
1807 $stat[2],
1808 $stat[1] >> 16 & 0xffff,
1809 $stat[1] & 0xffff,
1810 $stat[0] >> 16 & 0xffff,
1811 $stat[0] & 0xffff);
1812}
00d6fd04 1813printf(\")\\n\");' \"$1\" \"$2\" \"$3\" 2>/dev/null"
c82c5727 1814 "Perl script implementing `directory-files-attributes' as Lisp `read'able
00d6fd04
MA
1815output.
1816Escape sequence %s is replaced with name of Perl binary.
1817This string is passed to `format', so percent characters need to be doubled.")
c82c5727 1818
ac474af1
KG
1819;; ;; These two use uu encoding.
1820;; (defvar tramp-perl-encode "%s -e'\
1821;; print qq(begin 644 xxx\n);
1822;; my $s = q();
1823;; my $res = q();
1824;; while (read(STDIN, $s, 45)) {
1825;; print pack(q(u), $s);
1826;; }
1827;; print qq(`\n);
1828;; print qq(end\n);
1829;; '"
1830;; "Perl program to use for encoding a file.
1831;; Escape sequence %s is replaced with name of Perl binary.")
1832
1833;; (defvar tramp-perl-decode "%s -ne '
1834;; print unpack q(u), $_;
1835;; '"
1836;; "Perl program to use for decoding a file.
1837;; Escape sequence %s is replaced with name of Perl binary.")
1838
1839;; These two use base64 encoding.
00d6fd04
MA
1840(defconst tramp-perl-encode-with-module
1841 "%s -MMIME::Base64 -0777 -ne 'print encode_base64($_)' 2>/dev/null"
ac474af1 1842 "Perl program to use for encoding a file.
b1d06e75 1843Escape sequence %s is replaced with name of Perl binary.
89509ea0 1844This string is passed to `format', so percent characters need to be doubled.
b1d06e75
KG
1845This implementation requires the MIME::Base64 Perl module to be installed
1846on the remote host.")
1847
00d6fd04
MA
1848(defconst tramp-perl-decode-with-module
1849 "%s -MMIME::Base64 -0777 -ne 'print decode_base64($_)' 2>/dev/null"
b1d06e75
KG
1850 "Perl program to use for decoding a file.
1851Escape sequence %s is replaced with name of Perl binary.
89509ea0 1852This string is passed to `format', so percent characters need to be doubled.
b1d06e75
KG
1853This implementation requires the MIME::Base64 Perl module to be installed
1854on the remote host.")
1855
00d6fd04 1856(defconst tramp-perl-encode
b1d06e75
KG
1857 "%s -e '
1858# This script contributed by Juanma Barranquero <lektu@terra.es>.
114f9c96 1859# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
cbd12ed7 1860# Free Software Foundation, Inc.
b1d06e75
KG
1861use strict;
1862
fa32e96a 1863my %%trans = do {
b1d06e75
KG
1864 my $i = 0;
1865 map {(substr(unpack(q(B8), chr $i++), 2, 6), $_)}
1866 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/);
1867};
1868
36541701 1869binmode(\\*STDIN);
b1d06e75
KG
1870
1871# We read in chunks of 54 bytes, to generate output lines
1872# of 72 chars (plus end of line)
36541701 1873$/ = \\54;
b1d06e75
KG
1874
1875while (my $data = <STDIN>) {
1876 my $pad = q();
1877
1878 # Only for the last chunk, and only if did not fill the last three-byte packet
1879 if (eof) {
fa32e96a 1880 my $mod = length($data) %% 3;
b1d06e75
KG
1881 $pad = q(=) x (3 - $mod) if $mod;
1882 }
1883
1884 # Not the fastest method, but it is simple: unpack to binary string, split
1885 # by groups of 6 bits and convert back from binary to byte; then map into
1886 # the translation table
1887 print
1888 join q(),
1889 map($trans{$_},
1890 (substr(unpack(q(B*), $data) . q(00000), 0, 432) =~ /....../g)),
1891 $pad,
36541701 1892 qq(\\n);
00d6fd04 1893}' 2>/dev/null"
b1d06e75 1894 "Perl program to use for encoding a file.
fa32e96a 1895Escape sequence %s is replaced with name of Perl binary.
ccf29586 1896This string is passed to `format', so percent characters need to be doubled.")
ac474af1 1897
00d6fd04 1898(defconst tramp-perl-decode
b1d06e75
KG
1899 "%s -e '
1900# This script contributed by Juanma Barranquero <lektu@terra.es>.
114f9c96 1901# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
cbd12ed7 1902# Free Software Foundation, Inc.
b1d06e75
KG
1903use strict;
1904
fa32e96a 1905my %%trans = do {
b1d06e75 1906 my $i = 0;
16674e4f 1907 map {($_, substr(unpack(q(B8), chr $i++), 2, 6))}
b1d06e75
KG
1908 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/)
1909};
1910
fa32e96a 1911my %%bytes = map {(unpack(q(B8), chr $_), chr $_)} 0 .. 255;
b1d06e75 1912
36541701 1913binmode(\\*STDOUT);
b1d06e75
KG
1914
1915# We are going to accumulate into $pending to accept any line length
1916# (we do not check they are <= 76 chars as the RFC says)
1917my $pending = q();
1918
1919while (my $data = <STDIN>) {
1920 chomp $data;
1921
1922 # If we find one or two =, we have reached the end and
1923 # any following data is to be discarded
1924 my $finished = $data =~ s/(==?).*/$1/;
1925 $pending .= $data;
1926
1927 my $len = length($pending);
16674e4f 1928 my $chunk = substr($pending, 0, $len & ~3);
414da5ab 1929 $pending = substr($pending, $len & ~3 + 1);
b1d06e75
KG
1930
1931 # Easy method: translate from chars to (pregenerated) six-bit packets, join,
1932 # split in 8-bit chunks and convert back to char.
1933 print join q(),
1934 map $bytes{$_},
1935 ((join q(), map {$trans{$_} || q()} split //, $chunk) =~ /......../g);
1936
1937 last if $finished;
00d6fd04 1938}' 2>/dev/null"
ac474af1 1939 "Perl program to use for decoding a file.
fa32e96a 1940Escape sequence %s is replaced with name of Perl binary.
ccf29586 1941This string is passed to `format', so percent characters need to be doubled.")
fb7933a3 1942
946a5aeb
MA
1943(defconst tramp-vc-registered-read-file-names
1944 "echo \"(\"
1945for file in \"$@\"; do
1946 if %s $file; then
1947 echo \"(\\\"$file\\\" \\\"file-exists-p\\\" t)\"
1948 else
1949 echo \"(\\\"$file\\\" \\\"file-exists-p\\\" nil)\"
1950 fi
1951 if %s $file; then
1952 echo \"(\\\"$file\\\" \\\"file-readable-p\\\" t)\"
1953 else
1954 echo \"(\\\"$file\\\" \\\"file-readable-p\\\" nil)\"
1955 fi
1956done
1957echo \")\""
1958 "Script to check existence of VC related files.
1959It must be send formatted with two strings; the tests for file
1960existence, and file readability.")
1961
9ce8462a
MA
1962(defconst tramp-file-mode-type-map
1963 '((0 . "-") ; Normal file (SVID-v2 and XPG2)
1964 (1 . "p") ; fifo
1965 (2 . "c") ; character device
1966 (3 . "m") ; multiplexed character device (v7)
1967 (4 . "d") ; directory
1968 (5 . "?") ; Named special file (XENIX)
1969 (6 . "b") ; block device
1970 (7 . "?") ; multiplexed block device (v7)
1971 (8 . "-") ; regular file
1972 (9 . "n") ; network special file (HP-UX)
1973 (10 . "l") ; symlink
1974 (11 . "?") ; ACL shadow inode (Solaris, not userspace)
1975 (12 . "s") ; socket
1976 (13 . "D") ; door special (Solaris)
1977 (14 . "w")) ; whiteout (BSD)
fb7933a3
KG
1978 "A list of file types returned from the `stat' system call.
1979This is used to map a mode number to a permission string.")
1980
fb7933a3 1981;; New handlers should be added here. The following operations can be
c0fc6170
MA
1982;; handled using the normal primitives: file-name-sans-versions,
1983;; get-file-buffer.
fb7933a3 1984(defconst tramp-file-name-handler-alist
00d6fd04 1985 '((load . tramp-handle-load)
fb7933a3 1986 (make-symbolic-link . tramp-handle-make-symbolic-link)
c0fc6170 1987 (file-name-as-directory . tramp-handle-file-name-as-directory)
fb7933a3
KG
1988 (file-name-directory . tramp-handle-file-name-directory)
1989 (file-name-nondirectory . tramp-handle-file-name-nondirectory)
1990 (file-truename . tramp-handle-file-truename)
1991 (file-exists-p . tramp-handle-file-exists-p)
1992 (file-directory-p . tramp-handle-file-directory-p)
1993 (file-executable-p . tramp-handle-file-executable-p)
fb7933a3
KG
1994 (file-readable-p . tramp-handle-file-readable-p)
1995 (file-regular-p . tramp-handle-file-regular-p)
1996 (file-symlink-p . tramp-handle-file-symlink-p)
1997 (file-writable-p . tramp-handle-file-writable-p)
1998 (file-ownership-preserved-p . tramp-handle-file-ownership-preserved-p)
1999 (file-newer-than-file-p . tramp-handle-file-newer-than-file-p)
2000 (file-attributes . tramp-handle-file-attributes)
2001 (file-modes . tramp-handle-file-modes)
fb7933a3 2002 (directory-files . tramp-handle-directory-files)
c82c5727 2003 (directory-files-and-attributes . tramp-handle-directory-files-and-attributes)
fb7933a3
KG
2004 (file-name-all-completions . tramp-handle-file-name-all-completions)
2005 (file-name-completion . tramp-handle-file-name-completion)
2006 (add-name-to-file . tramp-handle-add-name-to-file)
2007 (copy-file . tramp-handle-copy-file)
263c02ef 2008 (copy-directory . tramp-handle-copy-directory)
fb7933a3
KG
2009 (rename-file . tramp-handle-rename-file)
2010 (set-file-modes . tramp-handle-set-file-modes)
ce3f516f 2011 (set-file-times . tramp-handle-set-file-times)
fb7933a3
KG
2012 (make-directory . tramp-handle-make-directory)
2013 (delete-directory . tramp-handle-delete-directory)
2014 (delete-file . tramp-handle-delete-file)
2015 (directory-file-name . tramp-handle-directory-file-name)
00d6fd04
MA
2016 ;; `executable-find' is not official yet.
2017 (executable-find . tramp-handle-executable-find)
2018 (start-file-process . tramp-handle-start-file-process)
0457dd55 2019 (process-file . tramp-handle-process-file)
00d6fd04 2020 (shell-command . tramp-handle-shell-command)
fb7933a3
KG
2021 (insert-directory . tramp-handle-insert-directory)
2022 (expand-file-name . tramp-handle-expand-file-name)
00d6fd04 2023 (substitute-in-file-name . tramp-handle-substitute-in-file-name)
fb7933a3 2024 (file-local-copy . tramp-handle-file-local-copy)
19a87064 2025 (file-remote-p . tramp-handle-file-remote-p)
fb7933a3 2026 (insert-file-contents . tramp-handle-insert-file-contents)
94be87e8
MA
2027 (insert-file-contents-literally
2028 . tramp-handle-insert-file-contents-literally)
fb7933a3 2029 (write-region . tramp-handle-write-region)
38c65fca 2030 (find-backup-file-name . tramp-handle-find-backup-file-name)
c1105d05 2031 (make-auto-save-file-name . tramp-handle-make-auto-save-file-name)
fb7933a3 2032 (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
5ec2cc41 2033 (dired-compress-file . tramp-handle-dired-compress-file)
fb7933a3
KG
2034 (dired-recursive-delete-directory
2035 . tramp-handle-dired-recursive-delete-directory)
70c11b0b 2036 (dired-uncache . tramp-handle-dired-uncache)
fb7933a3 2037 (set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
49096407
MA
2038 (verify-visited-file-modtime . tramp-handle-verify-visited-file-modtime)
2039 (vc-registered . tramp-handle-vc-registered))
c1105d05 2040 "Alist of handler functions.
fb7933a3
KG
2041Operations not mentioned here will be handled by the normal Emacs functions.")
2042
a4aeb9a4 2043;; Handlers for partial Tramp file names. For Emacs just
41c8e348 2044;; `file-name-all-completions' is needed.
a01b1e22 2045;;;###autoload
16674e4f 2046(defconst tramp-completion-file-name-handler-alist
a01b1e22 2047 '((file-name-all-completions . tramp-completion-handle-file-name-all-completions)
41c8e348 2048 (file-name-completion . tramp-completion-handle-file-name-completion))
16674e4f
KG
2049 "Alist of completion handler functions.
2050Used for file names matching `tramp-file-name-regexp'. Operations not
2051mentioned here will be handled by `tramp-file-name-handler-alist' or the
2052normal Emacs functions.")
2053
4007ba5b 2054;; Handlers for foreign methods, like FTP or SMB, shall be plugged here.
ea9d1443
KG
2055(defvar tramp-foreign-file-name-handler-alist
2056 ;; (identity . tramp-sh-file-name-handler) should always be the last
b88f2d0a 2057 ;; entry, because `identity' always matches.
ea9d1443 2058 '((identity . tramp-sh-file-name-handler))
4007ba5b
KG
2059 "Alist of elements (FUNCTION . HANDLER) for foreign methods handled specially.
2060If (FUNCTION FILENAME) returns non-nil, then all I/O on that file is done by
2061calling HANDLER.")
2062
0664ff72 2063;;; Internal functions which must come first:
fb7933a3 2064
00d6fd04
MA
2065(defsubst tramp-debug-message (vec fmt-string &rest args)
2066 "Append message to debug buffer.
2067Message is formatted with FMT-STRING as control string and the remaining
2068ARGS to actually emit the message (if applicable)."
2069 (when (get-buffer (tramp-buffer-name vec))
2070 (with-current-buffer (tramp-get-debug-buffer vec)
2071 (goto-char (point-max))
70c11b0b
MA
2072 ;; Headline.
2073 (when (bobp)
2074 (insert
2075 (format
2076 ";; %sEmacs: %s Tramp: %s -*- mode: outline; -*-"
2077 (if (featurep 'sxemacs) "SX" (if (featurep 'xemacs) "X" "GNU "))
2078 emacs-version tramp-version)))
00d6fd04
MA
2079 (unless (bolp)
2080 (insert "\n"))
70c11b0b 2081 ;; Timestamp.
736ac90f
MA
2082 (let ((now (current-time)))
2083 (insert (format-time-string "%T." now))
2084 (insert (format "%06d " (nth 2 now))))
70c11b0b 2085 ;; Calling function.
00d6fd04
MA
2086 (let ((btn 1) btf fn)
2087 (while (not fn)
2088 (setq btf (nth 1 (backtrace-frame btn)))
2089 (if (not btf)
2090 (setq fn "")
2091 (when (symbolp btf)
2092 (setq fn (symbol-name btf))
2093 (unless (and (string-match "^tramp" fn)
2094 (not (string-match
2095 "^tramp\\(-debug\\)?\\(-message\\|-error\\)$"
2096 fn)))
2097 (setq fn nil)))
2098 (setq btn (1+ btn))))
2099 ;; The following code inserts filename and line number.
2100 ;; Should be deactivated by default, because it is time
2101 ;; consuming.
2102; (let ((ffn (find-function-noselect (intern fn))))
2103; (insert
2104; (format
2105; "%s:%d: "
2106; (file-name-nondirectory (buffer-file-name (car ffn)))
2107; (with-current-buffer (car ffn)
2108; (1+ (count-lines (point-min) (cdr ffn)))))))
2109 (insert (format "%s " fn)))
70c11b0b 2110 ;; The message.
00d6fd04
MA
2111 (insert (apply 'format fmt-string args)))))
2112
946a5aeb
MA
2113(defvar tramp-message-show-message t
2114 "Show Tramp message in the minibuffer.
2115This variable is used to disable messages from `tramp-error'.
2116The messages are visible anyway, because an error is raised.")
2117
00d6fd04 2118(defsubst tramp-message (vec-or-proc level fmt-string &rest args)
fb7933a3 2119 "Emit a message depending on verbosity level.
a4aeb9a4 2120VEC-OR-PROC identifies the Tramp buffer to use. It can be either a
00d6fd04
MA
2121vector or a process. LEVEL says to be quiet if `tramp-verbose' is
2122less than LEVEL. The message is emitted only if `tramp-verbose' is
2123greater than or equal to LEVEL.
2124
2125The message is also logged into the debug buffer when `tramp-verbose'
2126is greater than or equal 4.
2127
2128Calls functions `message' and `tramp-debug-message' with FMT-STRING as
2129control string and the remaining ARGS to actually emit the message (if
2130applicable)."
2131 (condition-case nil
2132 (when (<= level tramp-verbose)
2133 ;; Match data must be preserved!
2134 (save-match-data
2135 ;; Display only when there is a minimum level.
946a5aeb 2136 (when (and tramp-message-show-message (<= level 3))
00d6fd04
MA
2137 (apply 'message
2138 (concat
2139 (cond
2140 ((= level 0) "")
2141 ((= level 1) "")
2142 ((= level 2) "Warning: ")
2143 (t "Tramp: "))
2144 fmt-string)
2145 args))
2146 ;; Log only when there is a minimum level.
2147 (when (>= tramp-verbose 4)
2148 (when (and vec-or-proc
2149 (processp vec-or-proc)
2150 (buffer-name (process-buffer vec-or-proc)))
2151 (with-current-buffer (process-buffer vec-or-proc)
2152 ;; Translate proc to vec.
2153 (setq vec-or-proc (tramp-dissect-file-name default-directory))))
2154 (when (and vec-or-proc (vectorp vec-or-proc))
2155 (apply 'tramp-debug-message
2156 vec-or-proc
2157 (concat (format "(%d) # " level) fmt-string)
2158 args)))))
2159 ;; Suppress all errors.
2160 (error nil)))
2161
2162(defsubst tramp-error (vec-or-proc signal fmt-string &rest args)
2163 "Emit an error.
2164VEC-OR-PROC identifies the connection to use, SIGNAL is the
2165signal identifier to be raised, remaining args passed to
2166`tramp-message'. Finally, signal SIGNAL is raised."
946a5aeb
MA
2167 (let (tramp-message-show-message)
2168 (tramp-message
2169 vec-or-proc 1 "%s"
2170 (error-message-string
2171 (list signal
2172 (get signal 'error-message)
2173 (apply 'format fmt-string args))))
2174 (signal signal (list (apply 'format fmt-string args)))))
00d6fd04
MA
2175
2176(defsubst tramp-error-with-buffer
2177 (buffer vec-or-proc signal fmt-string &rest args)
2178 "Emit an error, and show BUFFER.
2179If BUFFER is nil, show the connection buffer. Wait for 30\", or until
2180an input event arrives. The other arguments are passed to `tramp-error'."
2181 (save-window-excursion
2182 (unwind-protect
2183 (apply 'tramp-error vec-or-proc signal fmt-string args)
4874f5e6
MA
2184 (when (and vec-or-proc
2185 (not (zerop tramp-verbose))
2186 (not (tramp-completion-mode-p)))
00d6fd04
MA
2187 (let ((enable-recursive-minibuffers t))
2188 (pop-to-buffer
2189 (or (and (bufferp buffer) buffer)
2190 (and (processp vec-or-proc) (process-buffer vec-or-proc))
2191 (tramp-get-buffer vec-or-proc)))
2192 (sit-for 30))))))
fb7933a3 2193
c62c9d08
KG
2194(defmacro with-parsed-tramp-file-name (filename var &rest body)
2195 "Parse a Tramp filename and make components available in the body.
2196
2197First arg FILENAME is evaluated and dissected into its components.
2198Second arg VAR is a symbol. It is used as a variable name to hold
2199the filename structure. It is also used as a prefix for the variables
2200holding the components. For example, if VAR is the symbol `foo', then
00d6fd04
MA
2201`foo' will be bound to the whole structure, `foo-method' will be bound to
2202the method component, and so on for `foo-user', `foo-host', `foo-localname'.
c62c9d08
KG
2203
2204Remaining args are Lisp expressions to be evaluated (inside an implicit
2205`progn').
2206
00d6fd04
MA
2207If VAR is nil, then we bind `v' to the structure and `method', `user',
2208`host', `localname' to the components."
c62c9d08 2209 `(let* ((,(or var 'v) (tramp-dissect-file-name ,filename))
c62c9d08
KG
2210 (,(if var (intern (concat (symbol-name var) "-method")) 'method)
2211 (tramp-file-name-method ,(or var 'v)))
2212 (,(if var (intern (concat (symbol-name var) "-user")) 'user)
2213 (tramp-file-name-user ,(or var 'v)))
2214 (,(if var (intern (concat (symbol-name var) "-host")) 'host)
2215 (tramp-file-name-host ,(or var 'v)))
7432277c
KG
2216 (,(if var (intern (concat (symbol-name var) "-localname")) 'localname)
2217 (tramp-file-name-localname ,(or var 'v))))
c62c9d08
KG
2218 ,@body))
2219
2220(put 'with-parsed-tramp-file-name 'lisp-indent-function 2)
00d6fd04 2221(put 'with-parsed-tramp-file-name 'edebug-form-spec '(form symbolp body))
9e6ab520 2222(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-parsed-tramp-file-name\\>"))
c62c9d08 2223
00d6fd04
MA
2224(defmacro with-file-property (vec file property &rest body)
2225 "Check in Tramp cache for PROPERTY, otherwise execute BODY and set cache.
2226FILE must be a local file name on a connection identified via VEC."
2227 `(if (file-name-absolute-p ,file)
2228 (let ((value (tramp-get-file-property ,vec ,file ,property 'undef)))
2229 (when (eq value 'undef)
2230 ;; We cannot pass @body as parameter to
2231 ;; `tramp-set-file-property' because it mangles our
2232 ;; debug messages.
2233 (setq value (progn ,@body))
2234 (tramp-set-file-property ,vec ,file ,property value))
2235 value)
2236 ,@body))
9ce8462a 2237
00d6fd04
MA
2238(put 'with-file-property 'lisp-indent-function 3)
2239(put 'with-file-property 'edebug-form-spec t)
9e6ab520 2240(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-file-property\\>"))
00d6fd04
MA
2241
2242(defmacro with-connection-property (key property &rest body)
2243 "Checks in Tramp for property PROPERTY, otherwise executes BODY and set."
2244 `(let ((value (tramp-get-connection-property ,key ,property 'undef)))
2245 (when (eq value 'undef)
2246 ;; We cannot pass ,@body as parameter to
2247 ;; `tramp-set-connection-property' because it mangles our debug
2248 ;; messages.
2249 (setq value (progn ,@body))
2250 (tramp-set-connection-property ,key ,property value))
2251 value))
9ce8462a 2252
00d6fd04
MA
2253(put 'with-connection-property 'lisp-indent-function 2)
2254(put 'with-connection-property 'edebug-form-spec t)
9e6ab520 2255(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-connection-property\\>"))
00d6fd04 2256
628c97b2
GM
2257(eval-and-compile ; silence compiler
2258 (if (memq system-type '(cygwin windows-nt))
2259 (defun tramp-drop-volume-letter (name)
2260 "Cut off unnecessary drive letter from file NAME.
2261The function `tramp-handle-expand-file-name' calls `expand-file-name'
2262locally on a remote file name. When the local system is a W32 system
2263but the remote system is Unix, this introduces a superfluous drive
2264letter into the file name. This function removes it."
2265 (save-match-data
2266 (if (string-match tramp-root-regexp name)
2267 (replace-match "/" nil t name)
2268 name)))
2269
2270 (defalias 'tramp-drop-volume-letter 'identity)))
2271
9c13938d 2272(defsubst tramp-make-tramp-temp-file (vec)
a6e96327 2273 "Create a temporary file on the remote host identified by VEC.
9c13938d
MA
2274Return the local name of the temporary file."
2275 (let ((prefix
2276 (tramp-make-tramp-file-name
2277 (tramp-file-name-method vec)
2278 (tramp-file-name-user vec)
2279 (tramp-file-name-host vec)
113e2a84
MA
2280 (tramp-drop-volume-letter
2281 (expand-file-name
2282 tramp-temp-name-prefix (tramp-get-remote-tmpdir vec)))))
9c13938d
MA
2283 result)
2284 (while (not result)
2285 ;; `make-temp-file' would be the natural choice for
2286 ;; implementation. But it calls `write-region' internally,
2287 ;; which also needs a temporary file - we would end in an
2288 ;; infinite loop.
2289 (setq result (make-temp-name prefix))
2290 (if (file-exists-p result)
2291 (setq result nil)
2292 ;; This creates the file by side effect.
2293 (set-file-times result)
2294 (set-file-modes result (tramp-octal-to-decimal "0700"))))
2295
2296 ;; Return the local part.
2297 (with-parsed-tramp-file-name result nil localname)))
8a4438b6
MA
2298
2299
16674e4f
KG
2300;;; Config Manipulation Functions:
2301
2302(defun tramp-set-completion-function (method function-list)
2303 "Sets the list of completion functions for METHOD.
2304FUNCTION-LIST is a list of entries of the form (FUNCTION FILE).
2305The FUNCTION is intended to parse FILE according its syntax.
2306It might be a predefined FUNCTION, or a user defined FUNCTION.
2307Predefined FUNCTIONs are `tramp-parse-rhosts', `tramp-parse-shosts',
8fc29035 2308`tramp-parse-sconfig', `tramp-parse-hosts', `tramp-parse-passwd',
8daea7fc
KG
2309and `tramp-parse-netrc'.
2310
16674e4f
KG
2311Example:
2312
2313 (tramp-set-completion-function
2314 \"ssh\"
8daea7fc
KG
2315 '((tramp-parse-sconfig \"/etc/ssh_config\")
2316 (tramp-parse-sconfig \"~/.ssh/config\")))"
16674e4f 2317
5ec2cc41
KG
2318 (let ((r function-list)
2319 (v function-list))
2320 (setq tramp-completion-function-alist
2321 (delete (assoc method tramp-completion-function-alist)
2322 tramp-completion-function-alist))
2323
2324 (while v
00d6fd04 2325 ;; Remove double entries.
5ec2cc41
KG
2326 (when (member (car v) (cdr v))
2327 (setcdr v (delete (car v) (cdr v))))
00d6fd04 2328 ;; Check for function and file or registry key.
5ec2cc41 2329 (unless (and (functionp (nth 0 (car v)))
00d6fd04
MA
2330 (if (string-match "^HKEY_CURRENT_USER" (nth 1 (car v)))
2331 ;; Windows registry.
2332 (and (memq system-type '(cygwin windows-nt))
a4aeb9a4
MA
2333 (zerop
2334 (tramp-local-call-process
2335 "reg" nil nil nil "query" (nth 1 (car v)))))
00d6fd04
MA
2336 ;; Configuration file.
2337 (file-exists-p (nth 1 (car v)))))
5ec2cc41
KG
2338 (setq r (delete (car v) r)))
2339 (setq v (cdr v)))
2340
2341 (when r
4007ba5b 2342 (add-to-list 'tramp-completion-function-alist
5ec2cc41 2343 (cons method r)))))
16674e4f
KG
2344
2345(defun tramp-get-completion-function (method)
00d6fd04 2346 "Returns a list of completion functions for METHOD.
16674e4f 2347For definition of that list see `tramp-set-completion-function'."
00d6fd04
MA
2348 (cons
2349 ;; Hosts visited once shall be remembered.
2350 `(tramp-parse-connection-properties ,method)
2351 ;; The method related defaults.
2352 (cdr (assoc method tramp-completion-function-alist))))
16674e4f 2353
d037d501 2354
0664ff72 2355;;; Fontification of `read-file-name':
d037d501 2356
0664ff72 2357;; rfn-eshadow.el is part of Emacs 22. It is autoloaded.
d037d501
MA
2358(defvar tramp-rfn-eshadow-overlay)
2359(make-variable-buffer-local 'tramp-rfn-eshadow-overlay)
2360
2361(defun tramp-rfn-eshadow-setup-minibuffer ()
2362 "Set up a minibuffer for `file-name-shadow-mode'.
2363Adds another overlay hiding filename parts according to Tramp's
2364special handling of `substitute-in-file-name'."
9ce8462a 2365 (when (symbol-value 'minibuffer-completing-file-name)
d037d501 2366 (setq tramp-rfn-eshadow-overlay
9e6ab520
MA
2367 (funcall (symbol-function 'make-overlay)
2368 (funcall (symbol-function 'minibuffer-prompt-end))
2369 (funcall (symbol-function 'minibuffer-prompt-end))))
d037d501 2370 ;; Copy rfn-eshadow-overlay properties.
9e6ab520
MA
2371 (let ((props (funcall (symbol-function 'overlay-properties)
2372 (symbol-value 'rfn-eshadow-overlay))))
d037d501 2373 (while props
9e6ab520
MA
2374 (funcall (symbol-function 'overlay-put)
2375 tramp-rfn-eshadow-overlay (pop props) (pop props))))))
d037d501
MA
2376
2377(when (boundp 'rfn-eshadow-setup-minibuffer-hook)
2378 (add-hook 'rfn-eshadow-setup-minibuffer-hook
48846dc5
MA
2379 'tramp-rfn-eshadow-setup-minibuffer)
2380 (add-hook 'tramp-unload-hook
aa485f7c
MA
2381 (lambda ()
2382 (remove-hook 'rfn-eshadow-setup-minibuffer-hook
2383 'tramp-rfn-eshadow-setup-minibuffer))))
d037d501 2384
adcbca53
MA
2385(defconst tramp-rfn-eshadow-update-overlay-regexp
2386 (format "[^%s/~]*\\(/\\|~\\)" tramp-postfix-host-format))
2387
d037d501
MA
2388(defun tramp-rfn-eshadow-update-overlay ()
2389 "Update `rfn-eshadow-overlay' to cover shadowed part of minibuffer input.
2390This is intended to be used as a minibuffer `post-command-hook' for
2391`file-name-shadow-mode'; the minibuffer should have already
2392been set up by `rfn-eshadow-setup-minibuffer'."
2393 ;; In remote files name, there is a shadowing just for the local part.
9e6ab520
MA
2394 (let ((end (or (funcall (symbol-function 'overlay-end)
2395 (symbol-value 'rfn-eshadow-overlay))
2396 (funcall (symbol-function 'minibuffer-prompt-end)))))
2397 (when (file-remote-p (buffer-substring-no-properties end (point-max)))
bd316474
KY
2398 (save-excursion
2399 (save-restriction
2400 (narrow-to-region
adcbca53
MA
2401 (1+ (or (string-match
2402 tramp-rfn-eshadow-update-overlay-regexp (buffer-string) end)
2403 end))
2404 (point-max))
bd316474
KY
2405 (let ((rfn-eshadow-overlay tramp-rfn-eshadow-overlay)
2406 (rfn-eshadow-update-overlay-hook nil))
dea31ca6 2407 (move-overlay rfn-eshadow-overlay (point-max) (point-max))
bd316474 2408 (funcall (symbol-function 'rfn-eshadow-update-overlay))))))))
d037d501
MA
2409
2410(when (boundp 'rfn-eshadow-update-overlay-hook)
2411 (add-hook 'rfn-eshadow-update-overlay-hook
b88f2d0a
MA
2412 'tramp-rfn-eshadow-update-overlay)
2413 (add-hook 'tramp-unload-hook
2414 (lambda ()
2415 (remove-hook 'rfn-eshadow-update-overlay-hook
2416 'tramp-rfn-eshadow-update-overlay))))
d037d501
MA
2417
2418
605a20a9
MA
2419;;; Integration of eshell.el:
2420
2421(eval-when-compile
2422 (defvar eshell-path-env))
2423
2424;; eshell.el keeps the path in `eshell-path-env'. We must change it
2425;; when `default-directory' points to another host.
2426(defun tramp-eshell-directory-change ()
2427 "Set `eshell-path-env' to $PATH of the host related to `default-directory'."
2428 (setq eshell-path-env
2429 (if (file-remote-p default-directory)
2430 (with-parsed-tramp-file-name default-directory nil
2431 (mapconcat
2432 'identity
2433 (tramp-get-remote-path v)
2434 ":"))
2435 (getenv "PATH"))))
2436
2437(eval-after-load "esh-util"
2438 '(progn
2439 (tramp-eshell-directory-change)
2440 (add-hook 'eshell-directory-change-hook
2441 'tramp-eshell-directory-change)
2442 (add-hook 'tramp-unload-hook
2443 (lambda ()
2444 (remove-hook 'eshell-directory-change-hook
2445 'tramp-eshell-directory-change)))))
2446
2447
fb7933a3
KG
2448;;; File Name Handler Functions:
2449
fb7933a3
KG
2450(defun tramp-handle-make-symbolic-link
2451 (filename linkname &optional ok-if-already-exists)
00d6fd04 2452 "Like `make-symbolic-link' for Tramp files.
cebb4ec6 2453If LINKNAME is a non-Tramp file, it is used verbatim as the target of
7432277c 2454the symlink. If LINKNAME is a Tramp file, only the localname component is
cebb4ec6
KG
2455used as the target of the symlink.
2456
7432277c
KG
2457If LINKNAME is a Tramp file and the localname component is relative, then
2458it is expanded first, before the localname component is taken. Note that
cebb4ec6
KG
2459this can give surprising results if the user/host for the source and
2460target of the symlink differ."
c62c9d08 2461 (with-parsed-tramp-file-name linkname l
00d6fd04 2462 (let ((ln (tramp-get-remote-ln l))
87bdd2c7
MA
2463 (cwd (tramp-run-real-handler
2464 'file-name-directory (list l-localname))))
c62c9d08 2465 (unless ln
00d6fd04
MA
2466 (tramp-error
2467 l 'file-error
2468 "Making a symbolic link. ln(1) does not exist on the remote host."))
c62c9d08
KG
2469
2470 ;; Do the 'confirm if exists' thing.
cebb4ec6 2471 (when (file-exists-p linkname)
c62c9d08
KG
2472 ;; What to do?
2473 (if (or (null ok-if-already-exists) ; not allowed to exist
2474 (and (numberp ok-if-already-exists)
2475 (not (yes-or-no-p
2476 (format
2477 "File %s already exists; make it a link anyway? "
7432277c 2478 l-localname)))))
00d6fd04
MA
2479 (tramp-error
2480 l 'file-already-exists "File %s already exists" l-localname)
cebb4ec6
KG
2481 (delete-file linkname)))
2482
7432277c 2483 ;; If FILENAME is a Tramp name, use just the localname component.
cebb4ec6 2484 (when (tramp-tramp-file-p filename)
1834b39f
MA
2485 (setq filename
2486 (tramp-file-name-localname
2487 (tramp-dissect-file-name (expand-file-name filename)))))
bf247b6e 2488
c62c9d08
KG
2489 ;; Right, they are on the same host, regardless of user, method, etc.
2490 ;; We now make the link on the remote machine. This will occur as the user
2491 ;; that FILENAME belongs to.
2492 (zerop
2493 (tramp-send-command-and-check
b593f105
MA
2494 l
2495 (format
2496 "cd %s && %s -sf %s %s"
2497 (tramp-shell-quote-argument cwd)
2498 ln
2499 (tramp-shell-quote-argument filename)
2500 (tramp-shell-quote-argument l-localname))
2501 t)))))
fb7933a3 2502
fb7933a3 2503(defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix)
00d6fd04
MA
2504 "Like `load' for Tramp files."
2505 (with-parsed-tramp-file-name (expand-file-name file) nil
c62c9d08
KG
2506 (unless nosuffix
2507 (cond ((file-exists-p (concat file ".elc"))
2508 (setq file (concat file ".elc")))
2509 ((file-exists-p (concat file ".el"))
2510 (setq file (concat file ".el")))))
2511 (when must-suffix
2512 ;; The first condition is always true for absolute file names.
2513 ;; Included for safety's sake.
2514 (unless (or (file-name-directory file)
2515 (string-match "\\.elc?\\'" file))
00d6fd04
MA
2516 (tramp-error
2517 v 'file-error
2518 "File `%s' does not include a `.el' or `.elc' suffix" file)))
c62c9d08
KG
2519 (unless noerror
2520 (when (not (file-exists-p file))
00d6fd04 2521 (tramp-error v 'file-error "Cannot load nonexistent file `%s'" file)))
c62c9d08
KG
2522 (if (not (file-exists-p file))
2523 nil
00d6fd04 2524 (unless nomessage (tramp-message v 0 "Loading %s..." file))
c62c9d08
KG
2525 (let ((local-copy (file-local-copy file)))
2526 ;; MUST-SUFFIX doesn't exist on XEmacs, so let it default to nil.
ce2cc728
MA
2527 (unwind-protect
2528 (load local-copy noerror t t)
2529 (delete-file local-copy)))
00d6fd04 2530 (unless nomessage (tramp-message v 0 "Loading %s...done" file))
c62c9d08 2531 t)))
fb7933a3 2532
a4aeb9a4 2533;; Localname manipulation functions that grok Tramp localnames...
c0fc6170
MA
2534(defun tramp-handle-file-name-as-directory (file)
2535 "Like `file-name-as-directory' but aware of Tramp files."
2536 ;; `file-name-as-directory' would be sufficient except localname is
2537 ;; the empty string.
2538 (let ((v (tramp-dissect-file-name file t)))
2539 ;; Run the command on the localname portion only.
2540 (tramp-make-tramp-file-name
2541 (tramp-file-name-method v)
2542 (tramp-file-name-user v)
2543 (tramp-file-name-host v)
2544 (tramp-run-real-handler
2545 'file-name-as-directory (list (or (tramp-file-name-localname v) ""))))))
2546
fb7933a3 2547(defun tramp-handle-file-name-directory (file)
00d6fd04 2548 "Like `file-name-directory' but aware of Tramp files."
9ce8462a
MA
2549 ;; Everything except the last filename thing is the directory. We
2550 ;; cannot apply `with-parsed-tramp-file-name', because this expands
2551 ;; the remote file name parts. This is a problem when we are in
2552 ;; file name completion.
2553 (let ((v (tramp-dissect-file-name file t)))
a01b1e22
MA
2554 ;; Run the command on the localname portion only.
2555 (tramp-make-tramp-file-name
9ce8462a
MA
2556 (tramp-file-name-method v)
2557 (tramp-file-name-user v)
2558 (tramp-file-name-host v)
87bdd2c7
MA
2559 (tramp-run-real-handler
2560 'file-name-directory (list (or (tramp-file-name-localname v) ""))))))
fb7933a3
KG
2561
2562(defun tramp-handle-file-name-nondirectory (file)
00d6fd04 2563 "Like `file-name-nondirectory' but aware of Tramp files."
c62c9d08 2564 (with-parsed-tramp-file-name file nil
87bdd2c7 2565 (tramp-run-real-handler 'file-name-nondirectory (list localname))))
fb7933a3
KG
2566
2567(defun tramp-handle-file-truename (filename &optional counter prev-dirs)
00d6fd04 2568 "Like `file-truename' for Tramp files."
48ddd622 2569 (with-parsed-tramp-file-name (expand-file-name filename) nil
00d6fd04 2570 (with-file-property v localname "file-truename"
293c24f9 2571 (let ((result nil)) ; result steps in reverse order
00d6fd04 2572 (tramp-message v 4 "Finding true name for `%s'" filename)
293c24f9
MA
2573 (cond
2574 ;; Use GNU readlink --canonicalize-missing where available.
2575 ((tramp-get-remote-readlink v)
2576 (setq result
2577 (tramp-send-command-and-read
2578 v
2579 (format "echo \"\\\"`%s --canonicalize-missing %s`\\\"\""
2580 (tramp-get-remote-readlink v)
2581 (tramp-shell-quote-argument localname)))))
2582
2583 ;; Use Perl implementation.
2584 ((and (tramp-get-remote-perl v)
2585 (tramp-get-connection-property v "perl-file-spec" nil)
2586 (tramp-get-connection-property v "perl-cwd-realpath" nil))
2587 (tramp-maybe-send-script
2588 v tramp-perl-file-truename "tramp_perl_file_truename")
2589 (setq result
2590 (tramp-send-command-and-read
2591 v
2592 (format "tramp_perl_file_truename %s"
2593 (tramp-shell-quote-argument localname)))))
2594
2595 ;; Do it yourself. We bind `directory-sep-char' here for
2596 ;; XEmacs on Windows, which would otherwise use backslash.
2597 (t (let* ((directory-sep-char ?/)
2598 (steps (tramp-compat-split-string localname "/"))
2599 (localnamedir (tramp-run-real-handler
2600 'file-name-as-directory (list localname)))
2601 (is-dir (string= localname localnamedir))
2602 (thisstep nil)
2603 (numchase 0)
2604 ;; Don't make the following value larger than
2605 ;; necessary. People expect an error message in a
2606 ;; timely fashion when something is wrong;
2607 ;; otherwise they might think that Emacs is hung.
2608 ;; Of course, correctness has to come first.
2609 (numchase-limit 20)
2610 symlink-target)
2611 (while (and steps (< numchase numchase-limit))
2612 (setq thisstep (pop steps))
2613 (tramp-message
2614 v 5 "Check %s"
2615 (mapconcat 'identity
2616 (append '("") (reverse result) (list thisstep))
2617 "/"))
2618 (setq symlink-target
2619 (nth 0 (file-attributes
2620 (tramp-make-tramp-file-name
2621 method user host
2622 (mapconcat 'identity
2623 (append '("")
2624 (reverse result)
2625 (list thisstep))
2626 "/")))))
2627 (cond ((string= "." thisstep)
2628 (tramp-message v 5 "Ignoring step `.'"))
2629 ((string= ".." thisstep)
2630 (tramp-message v 5 "Processing step `..'")
2631 (pop result))
2632 ((stringp symlink-target)
2633 ;; It's a symlink, follow it.
2634 (tramp-message v 5 "Follow symlink to %s" symlink-target)
2635 (setq numchase (1+ numchase))
2636 (when (file-name-absolute-p symlink-target)
2637 (setq result nil))
2638 ;; If the symlink was absolute, we'll get a string like
2639 ;; "/user@host:/some/target"; extract the
2640 ;; "/some/target" part from it.
2641 (when (tramp-tramp-file-p symlink-target)
2642 (unless (tramp-equal-remote filename symlink-target)
2643 (tramp-error
2644 v 'file-error
2645 "Symlink target `%s' on wrong host" symlink-target))
2646 (setq symlink-target localname))
2647 (setq steps
2648 (append (tramp-compat-split-string
2649 symlink-target "/")
2650 steps)))
2651 (t
2652 ;; It's a file.
2653 (setq result (cons thisstep result)))))
2654 (when (>= numchase numchase-limit)
2655 (tramp-error
2656 v 'file-error
2657 "Maximum number (%d) of symlinks exceeded" numchase-limit))
2658 (setq result (reverse result))
2659 ;; Combine list to form string.
2660 (setq result
2661 (if result
2662 (mapconcat 'identity (cons "" result) "/")
00d6fd04 2663 "/"))
293c24f9
MA
2664 (when (and is-dir (or (string= "" result)
2665 (not (string= (substring result -1) "/"))))
2666 (setq result (concat result "/"))))))
2667
2668 (tramp-message v 4 "True name of `%s' is `%s'" filename result)
2669 (tramp-make-tramp-file-name method user host result)))))
fb7933a3
KG
2670
2671;; Basic functions.
2672
2673(defun tramp-handle-file-exists-p (filename)
00d6fd04 2674 "Like `file-exists-p' for Tramp files."
c62c9d08 2675 (with-parsed-tramp-file-name filename nil
00d6fd04 2676 (with-file-property v localname "file-exists-p"
293c24f9
MA
2677 (or (not (null (tramp-get-file-property
2678 v localname "file-attributes-integer" nil)))
2679 (not (null (tramp-get-file-property
2680 v localname "file-attributes-string" nil)))
2681 (zerop (tramp-send-command-and-check
2682 v
2683 (format
2684 "%s %s"
2685 (tramp-get-file-exists-command v)
2686 (tramp-shell-quote-argument localname))))))))
fb7933a3 2687
00d6fd04
MA
2688;; Inodes don't exist for some file systems. Therefore we must
2689;; generate virtual ones. Used in `find-buffer-visiting'. The method
2690;; applied might be not so efficient (Ange-FTP uses hashes). But
2691;; performance isn't the major issue given that file transfer will
2692;; take time.
2693(defvar tramp-inodes nil
2694 "Keeps virtual inodes numbers.")
2695
8daea7fc
KG
2696;; Devices must distinguish physical file systems. The device numbers
2697;; provided by "lstat" aren't unique, because we operate on different hosts.
2698;; So we use virtual device numbers, generated by Tramp. Both Ange-FTP and
2699;; EFS use device number "-1". In order to be different, we use device number
b946a456 2700;; (-1 . x), whereby "x" is unique for a given (method user host).
8daea7fc
KG
2701(defvar tramp-devices nil
2702 "Keeps virtual device numbers.")
2703
fb7933a3
KG
2704;; CCC: This should check for an error condition and signal failure
2705;; when something goes wrong.
2706;; Daniel Pittman <daniel@danann.net>
c951aecb 2707(defun tramp-handle-file-attributes (filename &optional id-format)
00d6fd04
MA
2708 "Like `file-attributes' for Tramp files."
2709 (unless id-format (setq id-format 'integer))
aa485f7c
MA
2710 ;; Don't modify `last-coding-system-used' by accident.
2711 (let ((last-coding-system-used last-coding-system-used))
2712 (with-parsed-tramp-file-name (expand-file-name filename) nil
2713 (with-file-property v localname (format "file-attributes-%s" id-format)
7f49fe46
MA
2714 (save-excursion
2715 (tramp-convert-file-attributes
2716 v
2717 (cond
2718 ((tramp-get-remote-stat v)
2719 (tramp-do-file-attributes-with-stat v localname id-format))
2720 ((tramp-get-remote-perl v)
2721 (tramp-do-file-attributes-with-perl v localname id-format))
2722 (t
2723 (tramp-do-file-attributes-with-ls v localname id-format)))))))))
2724
2725(defun tramp-do-file-attributes-with-ls (vec localname &optional id-format)
00d6fd04 2726 "Implement `file-attributes' for Tramp files using the ls(1) command."
fb7933a3
KG
2727 (let (symlinkp dirp
2728 res-inode res-filemodes res-numlinks
2729 res-uid res-gid res-size res-symlink-target)
00d6fd04 2730 (tramp-message vec 5 "file attributes with ls: %s" localname)
fb7933a3 2731 (tramp-send-command
00d6fd04 2732 vec
680db9ac
MA
2733 (format "(%s %s || %s -h %s) && %s %s %s"
2734 (tramp-get-file-exists-command vec)
2735 (tramp-shell-quote-argument localname)
2736 (tramp-get-test-command vec)
2737 (tramp-shell-quote-argument localname)
00d6fd04 2738 (tramp-get-ls-command vec)
c82c5727 2739 (if (eq id-format 'integer) "-ildn" "-ild")
7432277c 2740 (tramp-shell-quote-argument localname)))
fb7933a3 2741 ;; parse `ls -l' output ...
00d6fd04 2742 (with-current-buffer (tramp-get-buffer vec)
680db9ac
MA
2743 (when (> (buffer-size) 0)
2744 (goto-char (point-min))
2745 ;; ... inode
2746 (setq res-inode
2747 (condition-case err
2748 (read (current-buffer))
2749 (invalid-read-syntax
2750 (when (and (equal (cadr err)
2751 "Integer constant overflow in reader")
2752 (string-match
2753 "^[0-9]+\\([0-9][0-9][0-9][0-9][0-9]\\)\\'"
2754 (car (cddr err))))
2755 (let* ((big (read (substring (car (cddr err)) 0
2756 (match-beginning 1))))
2757 (small (read (match-string 1 (car (cddr err)))))
2758 (twiddle (/ small 65536)))
2759 (cons (+ big twiddle)
2760 (- small (* twiddle 65536))))))))
2761 ;; ... file mode flags
2762 (setq res-filemodes (symbol-name (read (current-buffer))))
2763 ;; ... number links
2764 (setq res-numlinks (read (current-buffer)))
2765 ;; ... uid and gid
2766 (setq res-uid (read (current-buffer)))
2767 (setq res-gid (read (current-buffer)))
2768 (if (eq id-format 'integer)
2769 (progn
2770 (unless (numberp res-uid) (setq res-uid -1))
2771 (unless (numberp res-gid) (setq res-gid -1)))
2772 (progn
2773 (unless (stringp res-uid) (setq res-uid (symbol-name res-uid)))
2774 (unless (stringp res-gid) (setq res-gid (symbol-name res-gid)))))
2775 ;; ... size
2776 (setq res-size (read (current-buffer)))
2777 ;; From the file modes, figure out other stuff.
2778 (setq symlinkp (eq ?l (aref res-filemodes 0)))
2779 (setq dirp (eq ?d (aref res-filemodes 0)))
2780 ;; if symlink, find out file name pointed to
2781 (when symlinkp
2782 (search-forward "-> ")
2783 (setq res-symlink-target
2784 (buffer-substring (point) (tramp-compat-line-end-position))))
2785 ;; return data gathered
2786 (list
2787 ;; 0. t for directory, string (name linked to) for symbolic
2788 ;; link, or nil.
2789 (or dirp res-symlink-target)
2790 ;; 1. Number of links to file.
2791 res-numlinks
2792 ;; 2. File uid.
2793 res-uid
2794 ;; 3. File gid.
2795 res-gid
2796 ;; 4. Last access time, as a list of two integers. First
2797 ;; integer has high-order 16 bits of time, second has low 16
2798 ;; bits.
2799 ;; 5. Last modification time, likewise.
2800 ;; 6. Last status change time, likewise.
2801 '(0 0) '(0 0) '(0 0) ;CCC how to find out?
2802 ;; 7. Size in bytes (-1, if number is out of range).
2803 res-size
2804 ;; 8. File modes, as a string of ten letters or dashes as in ls -l.
2805 res-filemodes
2806 ;; 9. t if file's gid would change if file were deleted and
2807 ;; recreated. Will be set in `tramp-convert-file-attributes'
2808 t
2809 ;; 10. inode number.
2810 res-inode
2811 ;; 11. Device number. Will be replaced by a virtual device number.
2812 -1
2813 )))))
fb7933a3 2814
7f49fe46 2815(defun tramp-do-file-attributes-with-perl
00d6fd04
MA
2816 (vec localname &optional id-format)
2817 "Implement `file-attributes' for Tramp files using a Perl script."
2818 (tramp-message vec 5 "file attributes with perl: %s" localname)
2819 (tramp-maybe-send-script
2820 vec tramp-perl-file-attributes "tramp_perl_file_attributes")
2821 (tramp-send-command-and-read
2822 vec
2823 (format "tramp_perl_file_attributes %s %s"
2824 (tramp-shell-quote-argument localname) id-format)))
2825
7f49fe46 2826(defun tramp-do-file-attributes-with-stat
00d6fd04
MA
2827 (vec localname &optional id-format)
2828 "Implement `file-attributes' for Tramp files using stat(1) command."
2829 (tramp-message vec 5 "file attributes with stat: %s" localname)
2830 (tramp-send-command-and-read
2831 vec
2832 (format
680db9ac
MA
2833 "((%s %s || %s -h %s) && %s -c '((\"%%N\") %%h %s %s %%X.0 %%Y.0 %%Z.0 %%s.0 \"%%A\" t %%i.0 -1)' %s || echo nil)"
2834 (tramp-get-file-exists-command vec)
2835 (tramp-shell-quote-argument localname)
2836 (tramp-get-test-command vec)
2837 (tramp-shell-quote-argument localname)
00d6fd04
MA
2838 (tramp-get-remote-stat vec)
2839 (if (eq id-format 'integer) "%u" "\"%U\"")
2840 (if (eq id-format 'integer) "%g" "\"%G\"")
2841 (tramp-shell-quote-argument localname))))
8daea7fc 2842
fb7933a3 2843(defun tramp-handle-set-visited-file-modtime (&optional time-list)
00d6fd04 2844 "Like `set-visited-file-modtime' for Tramp files."
fb7933a3
KG
2845 (unless (buffer-file-name)
2846 (error "Can't set-visited-file-modtime: buffer `%s' not visiting a file"
2847 (buffer-name)))
48ddd622
MA
2848 (if time-list
2849 (tramp-run-real-handler 'set-visited-file-modtime (list time-list))
11948172
MA
2850 (let ((f (buffer-file-name))
2851 coding-system-used)
48ddd622
MA
2852 (with-parsed-tramp-file-name f nil
2853 (let* ((attr (file-attributes f))
2854 ;; '(-1 65535) means file doesn't exists yet.
2855 (modtime (or (nth 5 attr) '(-1 65535))))
11948172
MA
2856 (when (boundp 'last-coding-system-used)
2857 (setq coding-system-used (symbol-value 'last-coding-system-used)))
48ddd622 2858 ;; We use '(0 0) as a don't-know value. See also
7f49fe46 2859 ;; `tramp-do-file-attributes-with-ls'.
48ddd622
MA
2860 (if (not (equal modtime '(0 0)))
2861 (tramp-run-real-handler 'set-visited-file-modtime (list modtime))
00d6fd04 2862 (progn
48ddd622 2863 (tramp-send-command
00d6fd04 2864 v
48ddd622 2865 (format "%s -ild %s"
00d6fd04 2866 (tramp-get-ls-command v)
48ddd622 2867 (tramp-shell-quote-argument localname)))
48ddd622
MA
2868 (setq attr (buffer-substring (point)
2869 (progn (end-of-line) (point)))))
00d6fd04
MA
2870 (tramp-set-file-property
2871 v localname "visited-file-modtime-ild" attr))
11948172
MA
2872 (when (boundp 'last-coding-system-used)
2873 (set 'last-coding-system-used coding-system-used))
d2a2c17f 2874 nil)))))
fb7933a3 2875
c62c9d08
KG
2876;; This function makes the same assumption as
2877;; `tramp-handle-set-visited-file-modtime'.
2878(defun tramp-handle-verify-visited-file-modtime (buf)
00d6fd04 2879 "Like `verify-visited-file-modtime' for Tramp files.
c08e6004
MA
2880At the time `verify-visited-file-modtime' calls this function, we
2881already know that the buffer is visiting a file and that
2882`visited-file-modtime' does not return 0. Do not call this
2883function directly, unless those two cases are already taken care
2884of."
c62c9d08 2885 (with-current-buffer buf
b15d0c4c
MA
2886 ;; There is no file visiting the buffer, or the buffer has no
2887 ;; recorded last modification time.
2888 (if (or (not (buffer-file-name))
2889 (eq (visited-file-modtime) 0))
d2a2c17f 2890 t
b15d0c4c
MA
2891 (let ((f (buffer-file-name)))
2892 (with-parsed-tramp-file-name f nil
bce04fee 2893 (tramp-flush-file-property v localname)
b15d0c4c
MA
2894 (let* ((attr (file-attributes f))
2895 (modtime (nth 5 attr))
2896 (mt (visited-file-modtime)))
bf247b6e 2897
70c11b0b
MA
2898 (cond
2899 ;; File exists, and has a known modtime.
b15d0c4c
MA
2900 ((and attr (not (equal modtime '(0 0))))
2901 (< (abs (tramp-time-diff
2902 modtime
2903 ;; For compatibility, deal with both the old
70c11b0b
MA
2904 ;; (HIGH . LOW) and the new (HIGH LOW) return
2905 ;; values of `visited-file-modtime'.
b15d0c4c
MA
2906 (if (atom (cdr mt))
2907 (list (car mt) (cdr mt))
2908 mt)))
2909 2))
70c11b0b 2910 ;; Modtime has the don't know value.
b15d0c4c 2911 (attr
00d6fd04
MA
2912 (tramp-send-command
2913 v
2914 (format "%s -ild %s"
2915 (tramp-get-ls-command v)
2916 (tramp-shell-quote-argument localname)))
2917 (with-current-buffer (tramp-get-buffer v)
b15d0c4c
MA
2918 (setq attr (buffer-substring
2919 (point) (progn (end-of-line) (point)))))
00d6fd04
MA
2920 (equal
2921 attr
2922 (tramp-get-file-property
2923 v localname "visited-file-modtime-ild" "")))
70c11b0b
MA
2924 ;; If file does not exist, say it is not modified if and
2925 ;; only if that agrees with the buffer's record.
b15d0c4c 2926 (t (equal mt '(-1 65535))))))))))
c62c9d08 2927
fb7933a3 2928(defun tramp-handle-set-file-modes (filename mode)
00d6fd04 2929 "Like `set-file-modes' for Tramp files."
c62c9d08 2930 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2931 (tramp-flush-file-property v localname)
2932 (unless (zerop (tramp-send-command-and-check
2933 v
2934 (format "chmod %s %s"
2935 (tramp-decimal-to-octal mode)
2936 (tramp-shell-quote-argument localname))))
2937 ;; FIXME: extract the proper text from chmod's stderr.
2938 (tramp-error
2939 v 'file-error "Error while changing file's mode %s" filename))))
fb7933a3 2940
ce3f516f
MA
2941(defun tramp-handle-set-file-times (filename &optional time)
2942 "Like `set-file-times' for Tramp files."
2943 (zerop
9e6ab520 2944 (if (file-remote-p filename)
ce3f516f 2945 (with-parsed-tramp-file-name filename nil
8d60099b 2946 (tramp-flush-file-property v localname)
ce3f516f
MA
2947 (let ((time (if (or (null time) (equal time '(0 0)))
2948 (current-time)
2949 time))
2950 (utc
2951 ;; With GNU Emacs, `format-time-string' has an
2952 ;; optional parameter UNIVERSAL. This is preferred,
2953 ;; because we could handle the case when the remote
2954 ;; host is located in a different time zone as the
2955 ;; local host.
2956 (and (functionp 'subr-arity)
2957 (subrp (symbol-function 'format-time-string))
2958 (= 3 (cdr (funcall (symbol-function 'subr-arity)
2959 (symbol-function
2960 'format-time-string)))))))
2961 (tramp-send-command-and-check
2962 v (format "%s touch -t %s %s"
2963 (if utc "TZ=UTC; export TZ;" "")
2964 (if utc
2965 (format-time-string "%Y%m%d%H%M.%S" time t)
2966 (format-time-string "%Y%m%d%H%M.%S" time))
2967 (tramp-shell-quote-argument localname)))))
8d60099b 2968
ce3f516f
MA
2969 ;; We handle also the local part, because in older Emacsen,
2970 ;; without `set-file-times', this function is an alias for this.
2971 ;; We are local, so we don't need the UTC settings.
a4aeb9a4 2972 (tramp-local-call-process
ce3f516f
MA
2973 "touch" nil nil nil "-t"
2974 (format-time-string "%Y%m%d%H%M.%S" time)
2975 (tramp-shell-quote-argument filename)))))
2976
8d60099b
MA
2977(defun tramp-set-file-uid-gid (filename &optional uid gid)
2978 "Set the ownership for FILENAME.
2979If UID and GID are provided, these values are used; otherwise uid
2980and gid of the corresponding user is taken. Both parameters must be integers."
70c11b0b
MA
2981 ;; Modern Unices allow chown only for root. So we might need
2982 ;; another implementation, see `dired-do-chown'. OTOH, it is mostly
2983 ;; working with su(do)? when it is needed, so it shall succeed in
2984 ;; the majority of cases.
aa485f7c
MA
2985 ;; Don't modify `last-coding-system-used' by accident.
2986 (let ((last-coding-system-used last-coding-system-used))
2987 (if (file-remote-p filename)
2988 (with-parsed-tramp-file-name filename nil
2989 (if (and (zerop (user-uid)) (tramp-local-host-p v))
2990 ;; If we are root on the local host, we can do it directly.
2991 (tramp-set-file-uid-gid localname uid gid)
2992 (let ((uid (or (and (integerp uid) uid)
2993 (tramp-get-remote-uid v 'integer)))
2994 (gid (or (and (integerp gid) gid)
2995 (tramp-get-remote-gid v 'integer))))
2996 (tramp-send-command
2997 v (format
2998 "chown %d:%d %s" uid gid
2999 (tramp-shell-quote-argument localname))))))
3000
3001 ;; We handle also the local part, because there doesn't exist
3002 ;; `set-file-uid-gid'. On W32 "chown" might not work.
3003 (let ((uid (or (and (integerp uid) uid) (tramp-get-local-uid 'integer)))
3004 (gid (or (and (integerp gid) gid) (tramp-get-local-gid 'integer))))
3005 (tramp-local-call-process
3006 "chown" nil nil nil
3007 (format "%d:%d" uid gid) (tramp-shell-quote-argument filename))))))
8d60099b 3008
fb7933a3
KG
3009;; Simple functions using the `test' command.
3010
3011(defun tramp-handle-file-executable-p (filename)
00d6fd04 3012 "Like `file-executable-p' for Tramp files."
c62c9d08 3013 (with-parsed-tramp-file-name filename nil
00d6fd04 3014 (with-file-property v localname "file-executable-p"
293c24f9
MA
3015 ;; Examine `file-attributes' cache to see if request can be
3016 ;; satisfied without remote operation.
3017 (or (tramp-check-cached-permissions v ?x)
3018 (zerop (tramp-run-test "-x" filename))))))
fb7933a3
KG
3019
3020(defun tramp-handle-file-readable-p (filename)
00d6fd04 3021 "Like `file-readable-p' for Tramp files."
c62c9d08 3022 (with-parsed-tramp-file-name filename nil
00d6fd04 3023 (with-file-property v localname "file-readable-p"
293c24f9
MA
3024 ;; Examine `file-attributes' cache to see if request can be
3025 ;; satisfied without remote operation.
3026 (or (tramp-check-cached-permissions v ?r)
3027 (zerop (tramp-run-test "-r" filename))))))
fb7933a3
KG
3028
3029;; When the remote shell is started, it looks for a shell which groks
3030;; tilde expansion. Here, we assume that all shells which grok tilde
3031;; expansion will also provide a `test' command which groks `-nt' (for
3032;; newer than). If this breaks, tell me about it and I'll try to do
3033;; something smarter about it.
3034(defun tramp-handle-file-newer-than-file-p (file1 file2)
00d6fd04 3035 "Like `file-newer-than-file-p' for Tramp files."
fb7933a3
KG
3036 (cond ((not (file-exists-p file1))
3037 nil)
3038 ((not (file-exists-p file2))
3039 t)
91879624 3040 ;; We are sure both files exist at this point.
fb7933a3
KG
3041 (t
3042 (save-excursion
91879624
KG
3043 ;; We try to get the mtime of both files. If they are not
3044 ;; equal to the "dont-know" value, then we subtract the times
3045 ;; and obtain the result.
3046 (let ((fa1 (file-attributes file1))
3047 (fa2 (file-attributes file2)))
3048 (if (and (not (equal (nth 5 fa1) '(0 0)))
3049 (not (equal (nth 5 fa2) '(0 0))))
01917a18 3050 (> 0 (tramp-time-diff (nth 5 fa2) (nth 5 fa1)))
91879624
KG
3051 ;; If one of them is the dont-know value, then we can
3052 ;; still try to run a shell command on the remote host.
3053 ;; However, this only works if both files are Tramp
3054 ;; files and both have the same method, same user, same
3055 ;; host.
00d6fd04
MA
3056 (unless (tramp-equal-remote file1 file2)
3057 (with-parsed-tramp-file-name
3058 (if (tramp-tramp-file-p file1) file1 file2) nil
3059 (tramp-error
3060 v 'file-error
3061 "Files %s and %s must have same method, user, host"
3062 file1 file2)))
3063 (with-parsed-tramp-file-name file1 nil
3064 (zerop (tramp-run-test2
3065 (tramp-get-test-nt-command v) file1 file2)))))))))
fb7933a3
KG
3066
3067;; Functions implemented using the basic functions above.
3068
3069(defun tramp-handle-file-modes (filename)
00d6fd04 3070 "Like `file-modes' for Tramp files."
5da24108
MA
3071 (let ((truename (or (file-truename filename) filename)))
3072 (when (file-exists-p truename)
3073 (tramp-mode-string-to-int (nth 8 (file-attributes truename))))))
fb7933a3 3074
b86c1cd8
MA
3075(defun tramp-default-file-modes (filename)
3076 "Return file modes of FILENAME as integer.
3077If the file modes of FILENAME cannot be determined, return the
974647ac
MA
3078value of `default-file-modes', without execute permissions."
3079 (or (file-modes filename)
3080 (logand (default-file-modes) (tramp-octal-to-decimal "0666"))))
b86c1cd8 3081
fb7933a3 3082(defun tramp-handle-file-directory-p (filename)
00d6fd04 3083 "Like `file-directory-p' for Tramp files."
fb7933a3
KG
3084 ;; Care must be taken that this function returns `t' for symlinks
3085 ;; pointing to directories. Surely the most obvious implementation
3086 ;; would be `test -d', but that returns false for such symlinks.
3087 ;; CCC: Stefan Monnier says that `test -d' follows symlinks. And
3088 ;; I now think he's right. So we could be using `test -d', couldn't
3089 ;; we?
3090 ;;
3091 ;; Alternatives: `cd %s', `test -d %s'
c62c9d08 3092 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3093 (with-file-property v localname "file-directory-p"
3094 (zerop (tramp-run-test "-d" filename)))))
fb7933a3
KG
3095
3096(defun tramp-handle-file-regular-p (filename)
00d6fd04
MA
3097 "Like `file-regular-p' for Tramp files."
3098 (and (file-exists-p filename)
3099 (eq ?- (aref (nth 8 (file-attributes filename)) 0))))
fb7933a3
KG
3100
3101(defun tramp-handle-file-symlink-p (filename)
00d6fd04 3102 "Like `file-symlink-p' for Tramp files."
c62c9d08 3103 (with-parsed-tramp-file-name filename nil
c951aecb 3104 (let ((x (car (file-attributes filename))))
b25a52cc
KG
3105 (when (stringp x)
3106 ;; When Tramp is running on VMS, then `file-name-absolute-p'
3107 ;; might do weird things.
3108 (if (file-name-absolute-p x)
00d6fd04 3109 (tramp-make-tramp-file-name method user host x)
b25a52cc 3110 x)))))
fb7933a3
KG
3111
3112(defun tramp-handle-file-writable-p (filename)
00d6fd04 3113 "Like `file-writable-p' for Tramp files."
c62c9d08 3114 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3115 (with-file-property v localname "file-writable-p"
3116 (if (file-exists-p filename)
293c24f9
MA
3117 ;; Examine `file-attributes' cache to see if request can be
3118 ;; satisfied without remote operation.
3119 (or (tramp-check-cached-permissions v ?w)
3120 (zerop (tramp-run-test "-w" filename)))
00d6fd04
MA
3121 ;; If file doesn't exist, check if directory is writable.
3122 (and (zerop (tramp-run-test
3123 "-d" (file-name-directory filename)))
3124 (zerop (tramp-run-test
3125 "-w" (file-name-directory filename))))))))
fb7933a3
KG
3126
3127(defun tramp-handle-file-ownership-preserved-p (filename)
00d6fd04 3128 "Like `file-ownership-preserved-p' for Tramp files."
c62c9d08 3129 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3130 (with-file-property v localname "file-ownership-preserved-p"
3131 (let ((attributes (file-attributes filename)))
3132 ;; Return t if the file doesn't exist, since it's true that no
3133 ;; information would be lost by an (attempted) delete and create.
3134 (or (null attributes)
3135 (= (nth 2 attributes) (tramp-get-remote-uid v 'integer)))))))
fb7933a3
KG
3136
3137;; Other file name ops.
3138
fb7933a3 3139(defun tramp-handle-directory-file-name (directory)
00d6fd04 3140 "Like `directory-file-name' for Tramp files."
7432277c
KG
3141 ;; If localname component of filename is "/", leave it unchanged.
3142 ;; Otherwise, remove any trailing slash from localname component.
8daea7fc
KG
3143 ;; Method, host, etc, are unchanged. Does it make sense to try
3144 ;; to avoid parsing the filename?
c62c9d08 3145 (with-parsed-tramp-file-name directory nil
7432277c
KG
3146 (if (and (not (zerop (length localname)))
3147 (eq (aref localname (1- (length localname))) ?/)
3148 (not (string= localname "/")))
8daea7fc
KG
3149 (substring directory 0 -1)
3150 directory)))
fb7933a3
KG
3151
3152;; Directory listings.
3153
00d6fd04
MA
3154(defun tramp-handle-directory-files
3155 (directory &optional full match nosort files-only)
3156 "Like `directory-files' for Tramp files."
3157 ;; FILES-ONLY is valid for XEmacs only.
3158 (when (file-directory-p directory)
73a37a69 3159 (setq directory (file-name-as-directory (expand-file-name directory)))
00d6fd04
MA
3160 (let ((temp (nreverse (file-name-all-completions "" directory)))
3161 result item)
3162
3163 (while temp
3164 (setq item (directory-file-name (pop temp)))
3165 (when (and (or (null match) (string-match match item))
3166 (or (null files-only)
73a37a69 3167 ;; Files only.
00d6fd04 3168 (and (equal files-only t) (file-regular-p item))
73a37a69 3169 ;; Directories only.
00d6fd04 3170 (file-directory-p item)))
73a37a69 3171 (push (if full (concat directory item) item)
00d6fd04 3172 result)))
73a37a69 3173 (if nosort result (sort result 'string<)))))
c62c9d08 3174
c82c5727
LH
3175(defun tramp-handle-directory-files-and-attributes
3176 (directory &optional full match nosort id-format)
00d6fd04
MA
3177 "Like `directory-files-and-attributes' for Tramp files."
3178 (unless id-format (setq id-format 'integer))
3179 (when (file-directory-p directory)
3180 (setq directory (expand-file-name directory))
3181 (let* ((temp
b533bc97 3182 (copy-tree
00d6fd04
MA
3183 (with-parsed-tramp-file-name directory nil
3184 (with-file-property
3185 v localname
3186 (format "directory-files-and-attributes-%s" id-format)
3187 (save-excursion
3188 (mapcar
aa485f7c
MA
3189 (lambda (x)
3190 (cons (car x)
3191 (tramp-convert-file-attributes v (cdr x))))
7f49fe46
MA
3192 (cond
3193 ((tramp-get-remote-stat v)
3194 (tramp-do-directory-files-and-attributes-with-stat
3195 v localname id-format))
3196 ((tramp-get-remote-perl v)
3197 (tramp-do-directory-files-and-attributes-with-perl
3198 v localname id-format)))))))))
00d6fd04
MA
3199 result item)
3200
3201 (while temp
3202 (setq item (pop temp))
3203 (when (or (null match) (string-match match (car item)))
3204 (when full
3205 (setcar item (expand-file-name (car item) directory)))
3206 (push item result)))
3207
3208 (if nosort
3209 result
3210 (sort result (lambda (x y) (string< (car x) (car y))))))))
3211
7f49fe46 3212(defun tramp-do-directory-files-and-attributes-with-perl
00d6fd04
MA
3213 (vec localname &optional id-format)
3214 "Implement `directory-files-and-attributes' for Tramp files using a Perl script."
3215 (tramp-message vec 5 "directory-files-and-attributes with perl: %s" localname)
3216 (tramp-maybe-send-script
3217 vec tramp-perl-directory-files-and-attributes
3218 "tramp_perl_directory_files_and_attributes")
3219 (let ((object
3220 (tramp-send-command-and-read
3221 vec
3222 (format "tramp_perl_directory_files_and_attributes %s %s"
3223 (tramp-shell-quote-argument localname) id-format))))
3224 (when (stringp object) (tramp-error vec 'file-error object))
3225 object))
3226
7f49fe46 3227(defun tramp-do-directory-files-and-attributes-with-stat
00d6fd04
MA
3228 (vec localname &optional id-format)
3229 "Implement `directory-files-and-attributes' for Tramp files using stat(1) command."
3230 (tramp-message vec 5 "directory-files-and-attributes with stat: %s" localname)
3231 (tramp-send-command-and-read
3232 vec
3233 (format
3234 (concat
70c11b0b
MA
3235 ;; We must care about filenames with spaces, or starting with
3236 ;; "-"; this would confuse xargs. "ls -aQ" might be a solution,
3237 ;; but it does not work on all remote systems. Therefore, we
3238 ;; quote the filenames via sed.
3239 "cd %s; echo \"(\"; (%s -a | sed -e s/\\$/\\\"/g -e s/^/\\\"/g | xargs "
d4443a0d 3240 "%s -c '(\"%%n\" (\"%%N\") %%h %s %s %%X.0 %%Y.0 %%Z.0 %%s.0 \"%%A\" t %%i.0 -1)'); "
00d6fd04
MA
3241 "echo \")\"")
3242 (tramp-shell-quote-argument localname)
3243 (tramp-get-ls-command vec)
3244 (tramp-get-remote-stat vec)
3245 (if (eq id-format 'integer) "%u" "\"%U\"")
3246 (if (eq id-format 'integer) "%g" "\"%G\""))))
c82c5727 3247
c62c9d08 3248;; This function should return "foo/" for directories and "bar" for
00d6fd04 3249;; files.
c62c9d08 3250(defun tramp-handle-file-name-all-completions (filename directory)
00d6fd04
MA
3251 "Like `file-name-all-completions' for Tramp files."
3252 (unless (save-match-data (string-match "/" filename))
9c13938d 3253 (with-parsed-tramp-file-name (expand-file-name directory) nil
b50dd0d2 3254
00d6fd04
MA
3255 (all-completions
3256 filename
3257 (mapcar
3258 'list
293c24f9
MA
3259 (or
3260 ;; Try cache first
3261 (and
3262 ;; Ignore if expired
3263 (or (not (integerp tramp-completion-reread-directory-timeout))
3264 (<= (tramp-time-diff
3265 (current-time)
3266 (tramp-get-file-property
3267 v localname "last-completion" '(0 0 0)))
3268 tramp-completion-reread-directory-timeout))
3269
3270 ;; Try cache entries for filename, filename with last
3271 ;; character removed, filename with last two characters
3272 ;; removed, ..., and finally the empty string - all
3273 ;; concatenated to the local directory name
3274
3275 ;; This is inefficient for very long filenames, pity
3276 ;; `reduce' is not available...
3277 (car
3278 (apply
3279 'append
3280 (mapcar
3281 (lambda (x)
3282 (let ((cache-hit
3283 (tramp-get-file-property
3284 v
3285 (concat localname (substring filename 0 x))
3286 "file-name-all-completions"
3287 nil)))
3288 (when cache-hit (list cache-hit))))
3289 (tramp-compat-number-sequence (length filename) 0 -1)))))
3290
3291 ;; Cache expired or no matching cache entry found so we need
3292 ;; to perform a remote operation
3293 (let (result)
3294 ;; Get a list of directories and files, including reliably
3295 ;; tagging the directories with a trailing '/'. Because I
3296 ;; rock. --daniel@danann.net
3297
3298 ;; Changed to perform `cd' in the same remote op and only
3299 ;; get entries starting with `filename'. Capture any `cd'
3300 ;; error messages. Ensure any `cd' and `echo' aliases are
3301 ;; ignored.
3302 (tramp-send-command
3303 v
3304 (if (tramp-get-remote-perl v)
3305 (progn
3306 (tramp-maybe-send-script
3307 v tramp-perl-file-name-all-completions
3308 "tramp_perl_file_name_all_completions")
3309 (format "tramp_perl_file_name_all_completions %s %s %d"
3310 (tramp-shell-quote-argument localname)
3311 (tramp-shell-quote-argument filename)
3312 (if (symbol-value
b533bc97
MA
3313 ;; `read-file-name-completion-ignore-case'
3314 ;; is introduced with Emacs 22.1.
3315 (if (boundp
3316 'read-file-name-completion-ignore-case)
3317 'read-file-name-completion-ignore-case
3318 'completion-ignore-case))
293c24f9
MA
3319 1 0)))
3320
3321 (format (concat
3322 "(\\cd %s 2>&1 && (%s %s -a 2>/dev/null"
3323 ;; `ls' with wildcard might fail with `Argument
3324 ;; list too long' error in some corner cases; if
3325 ;; `ls' fails after `cd' succeeded, chances are
3326 ;; that's the case, so let's retry without
3327 ;; wildcard. This will return "too many" entries
3328 ;; but that isn't harmful.
3329 " || %s -a 2>/dev/null)"
3330 " | while read f; do"
3331 " if %s -d \"$f\" 2>/dev/null;"
3332 " then \\echo \"$f/\"; else \\echo \"$f\"; fi; done"
3333 " && \\echo ok) || \\echo fail")
3334 (tramp-shell-quote-argument localname)
3335 (tramp-get-ls-command v)
3336 ;; When `filename' is empty, just `ls' without
3337 ;; filename argument is more efficient than `ls *'
3338 ;; for very large directories and might avoid the
3339 ;; `Argument list too long' error.
3340 ;;
3341 ;; With and only with wildcard, we need to add
3342 ;; `-d' to prevent `ls' from descending into
3343 ;; sub-directories.
3344 (if (zerop (length filename))
3345 "."
3346 (concat (tramp-shell-quote-argument filename) "* -d"))
3347 (tramp-get-ls-command v)
3348 (tramp-get-test-command v))))
3349
3350 ;; Now grab the output.
3351 (with-current-buffer (tramp-get-buffer v)
3352 (goto-char (point-max))
3353
3354 ;; Check result code, found in last line of output
3355 (forward-line -1)
3356 (if (looking-at "^fail$")
3357 (progn
3358 ;; Grab error message from line before last line
3359 ;; (it was put there by `cd 2>&1')
3360 (forward-line -1)
3361 (tramp-error
3362 v 'file-error
3363 "tramp-handle-file-name-all-completions: %s"
3364 (buffer-substring
3365 (point) (tramp-compat-line-end-position))))
3366 ;; For peace of mind, if buffer doesn't end in `fail'
3367 ;; then it should end in `ok'. If neither are in the
3368 ;; buffer something went seriously wrong on the remote
3369 ;; side.
3370 (unless (looking-at "^ok$")
3371 (tramp-error
3372 v 'file-error
3373 "\
3374tramp-handle-file-name-all-completions: internal error accessing `%s': `%s'"
3375 (tramp-shell-quote-argument localname) (buffer-string))))
3376
3377 (while (zerop (forward-line -1))
3378 (push (buffer-substring
3379 (point) (tramp-compat-line-end-position))
3380 result)))
3381
3382 ;; Because the remote op went through OK we know the
3383 ;; directory we `cd'-ed to exists
3384 (tramp-set-file-property
3385 v localname "file-exists-p" t)
3386
3387 ;; Because the remote op went through OK we know every
3388 ;; file listed by `ls' exists.
3389 (mapc (lambda (entry)
3390 (tramp-set-file-property
3391 v (concat localname entry) "file-exists-p" t))
3392 result)
3393
3394 (tramp-set-file-property
3395 v localname "last-completion" (current-time))
3396
3397 ;; Store result in the cache
3398 (tramp-set-file-property
3399 v (concat localname filename)
3400 "file-name-all-completions"
3401 result))))))))
fb7933a3 3402
e1e17cae
MA
3403(defun tramp-handle-file-name-completion
3404 (filename directory &optional predicate)
00d6fd04 3405 "Like `file-name-completion' for Tramp files."
fb7933a3
KG
3406 (unless (tramp-tramp-file-p directory)
3407 (error
3408 "tramp-handle-file-name-completion invoked on non-tramp directory `%s'"
3409 directory))
83e20b5c
MA
3410 (try-completion
3411 filename
3412 (mapcar 'list (file-name-all-completions filename directory))
3413 (when predicate
3414 (lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
fb7933a3
KG
3415
3416;; cp, mv and ln
3417
3418(defun tramp-handle-add-name-to-file
3419 (filename newname &optional ok-if-already-exists)
00d6fd04
MA
3420 "Like `add-name-to-file' for Tramp files."
3421 (unless (tramp-equal-remote filename newname)
3422 (with-parsed-tramp-file-name
3423 (if (tramp-tramp-file-p filename) filename newname) nil
3424 (tramp-error
3425 v 'file-error
3426 "add-name-to-file: %s"
3427 "only implemented for same method, same user, same host")))
c62c9d08
KG
3428 (with-parsed-tramp-file-name filename v1
3429 (with-parsed-tramp-file-name newname v2
00d6fd04 3430 (let ((ln (when v1 (tramp-get-remote-ln v1))))
c62c9d08
KG
3431 (when (and (not ok-if-already-exists)
3432 (file-exists-p newname)
3433 (not (numberp ok-if-already-exists))
3434 (y-or-n-p
3435 (format
3436 "File %s already exists; make it a new name anyway? "
3437 newname)))
00d6fd04
MA
3438 (tramp-error
3439 v2 'file-error
3440 "add-name-to-file: file %s already exists" newname))
aac0b0f2 3441 (tramp-flush-file-property v2 (file-name-directory v2-localname))
00d6fd04 3442 (tramp-flush-file-property v2 v2-localname)
c62c9d08 3443 (tramp-barf-unless-okay
00d6fd04 3444 v1
7432277c
KG
3445 (format "%s %s %s" ln (tramp-shell-quote-argument v1-localname)
3446 (tramp-shell-quote-argument v2-localname))
c62c9d08
KG
3447 "error with add-name-to-file, see buffer `%s' for details"
3448 (buffer-name))))))
fb7933a3
KG
3449
3450(defun tramp-handle-copy-file
25f14cdb
MA
3451 (filename newname &optional ok-if-already-exists keep-date
3452 preserve-uid-gid preserve-selinux-context)
00d6fd04 3453 "Like `copy-file' for Tramp files."
fb7933a3 3454 ;; Check if both files are local -- invoke normal copy-file.
9e6ab520 3455 ;; Otherwise, use Tramp from local system.
fb7933a3
KG
3456 (setq filename (expand-file-name filename))
3457 (setq newname (expand-file-name newname))
9e6ab520 3458 (cond
a4aeb9a4 3459 ;; At least one file a Tramp file?
9e6ab520
MA
3460 ((or (tramp-tramp-file-p filename)
3461 (tramp-tramp-file-p newname))
3462 (tramp-do-copy-or-rename-file
3463 'copy filename newname ok-if-already-exists keep-date preserve-uid-gid))
3464 ;; Compat section.
3465 (preserve-uid-gid
fb7933a3 3466 (tramp-run-real-handler
8d60099b 3467 'copy-file
9e6ab520
MA
3468 (list filename newname ok-if-already-exists keep-date preserve-uid-gid)))
3469 (t
3470 (tramp-run-real-handler
3471 'copy-file (list filename newname ok-if-already-exists keep-date)))))
fb7933a3 3472
263c02ef
MA
3473(defun tramp-handle-copy-directory (dirname newname &optional keep-date parents)
3474 "Like `copy-directory' for Tramp files."
3475 (let ((t1 (tramp-tramp-file-p dirname))
3476 (t2 (tramp-tramp-file-p newname)))
3477 (with-parsed-tramp-file-name (if t1 dirname newname) nil
3478 (if (and (tramp-get-method-parameter method 'tramp-copy-recursive)
3479 ;; When DIRNAME and NEWNAME are remote, they must have
3480 ;; the same method.
3481 (or (null t1) (null t2)
b000a6e2
MA
3482 (string-equal
3483 (tramp-file-name-method (tramp-dissect-file-name dirname))
3484 (tramp-file-name-method (tramp-dissect-file-name newname)))))
263c02ef
MA
3485 ;; scp or rsync DTRT.
3486 (progn
3487 (setq dirname (directory-file-name (expand-file-name dirname))
3488 newname (directory-file-name (expand-file-name newname)))
3489 (if (and (file-directory-p newname)
3490 (not (string-equal (file-name-nondirectory dirname)
3491 (file-name-nondirectory newname))))
3492 (setq newname
3493 (expand-file-name
3494 (file-name-nondirectory dirname) newname)))
3495 (if (not (file-directory-p (file-name-directory newname)))
3496 (make-directory (file-name-directory newname) parents))
3497 (tramp-do-copy-or-rename-file-out-of-band
3498 'copy dirname newname keep-date))
3499 ;; We must do it file-wise.
3500 (tramp-run-real-handler
aac0b0f2
MA
3501 'copy-directory (list dirname newname keep-date parents)))
3502
3503 ;; When newname did exist, we have wrong cached values.
3504 (when t2
3505 (with-parsed-tramp-file-name newname nil
3506 (tramp-flush-file-property v (file-name-directory localname))
3507 (tramp-flush-file-property v localname))))))
263c02ef 3508
fb7933a3
KG
3509(defun tramp-handle-rename-file
3510 (filename newname &optional ok-if-already-exists)
00d6fd04 3511 "Like `rename-file' for Tramp files."
fb7933a3 3512 ;; Check if both files are local -- invoke normal rename-file.
a4aeb9a4 3513 ;; Otherwise, use Tramp from local system.
fb7933a3
KG
3514 (setq filename (expand-file-name filename))
3515 (setq newname (expand-file-name newname))
a4aeb9a4 3516 ;; At least one file a Tramp file?
fb7933a3
KG
3517 (if (or (tramp-tramp-file-p filename)
3518 (tramp-tramp-file-p newname))
3519 (tramp-do-copy-or-rename-file
8d60099b 3520 'rename filename newname ok-if-already-exists t t)
00d6fd04
MA
3521 (tramp-run-real-handler
3522 'rename-file (list filename newname ok-if-already-exists))))
fb7933a3
KG
3523
3524(defun tramp-do-copy-or-rename-file
8d60099b 3525 (op filename newname &optional ok-if-already-exists keep-date preserve-uid-gid)
fb7933a3
KG
3526 "Copy or rename a remote file.
3527OP must be `copy' or `rename' and indicates the operation to perform.
3528FILENAME specifies the file to copy or rename, NEWNAME is the name of
3529the new file (for copy) or the new name of the file (for rename).
3530OK-IF-ALREADY-EXISTS means don't barf if NEWNAME exists already.
3531KEEP-DATE means to make sure that NEWNAME has the same timestamp
8d60099b
MA
3532as FILENAME. PRESERVE-UID-GID, when non-nil, instructs to keep
3533the uid and gid if both files are on the same host.
fb7933a3
KG
3534
3535This function is invoked by `tramp-handle-copy-file' and
3536`tramp-handle-rename-file'. It is an error if OP is neither of `copy'
3537and `rename'. FILENAME and NEWNAME must be absolute file names."
3538 (unless (memq op '(copy rename))
3539 (error "Unknown operation `%s', must be `copy' or `rename'" op))
90dc758d 3540 (let ((t1 (tramp-tramp-file-p filename))
b6bbb65e
MA
3541 (t2 (tramp-tramp-file-p newname))
3542 pr tm)
5ec2cc41 3543
da1975d7
MA
3544 (when (and (not ok-if-already-exists) (file-exists-p newname))
3545 (with-parsed-tramp-file-name (if t1 filename newname) nil
3546 (tramp-error
3547 v 'file-already-exists "File %s already exists" newname)))
5ec2cc41 3548
905fb90e
MA
3549 (with-parsed-tramp-file-name (if t1 filename newname) nil
3550 (tramp-message v 0 "Transferring %s to %s..." filename newname))
3551
b6bbb65e
MA
3552 ;; We start a pulsing progress reporter. Introduced in Emacs 24.1.
3553 (when (> (nth 7 (file-attributes filename)) tramp-copy-size-limit)
3554 (condition-case nil
3555 (setq pr (funcall
3556 'make-progress-reporter
3557 (format "Transferring %s to %s..." filename newname))
3558 tm (run-at-time 0 0.1 'progress-reporter-update pr))
3559 (error nil)))
3560
3561 (unwind-protect
00d6fd04
MA
3562 (cond
3563 ;; Both are Tramp files.
3564 ((and t1 t2)
3565 (with-parsed-tramp-file-name filename v1
3566 (with-parsed-tramp-file-name newname v2
3567 (cond
3568 ;; Shortcut: if method, host, user are the same for both
3569 ;; files, we invoke `cp' or `mv' on the remote host
3570 ;; directly.
3571 ((tramp-equal-remote filename newname)
3572 (tramp-do-copy-or-rename-file-directly
8d60099b
MA
3573 op filename newname
3574 ok-if-already-exists keep-date preserve-uid-gid))
3575
905fb90e 3576 ;; Try out-of-band operation.
7f49fe46
MA
3577 ((tramp-method-out-of-band-p
3578 v1 (nth 7 (file-attributes filename)))
00d6fd04
MA
3579 (tramp-do-copy-or-rename-file-out-of-band
3580 op filename newname keep-date))
8d60099b 3581
00d6fd04
MA
3582 ;; No shortcut was possible. So we copy the
3583 ;; file first. If the operation was `rename', we go
3584 ;; back and delete the original file (if the copy was
3585 ;; successful). The approach is simple-minded: we
3586 ;; create a new buffer, insert the contents of the
3587 ;; source file into it, then write out the buffer to
3588 ;; the target file. The advantage is that it doesn't
3589 ;; matter which filename handlers are used for the
3590 ;; source and target file.
3591 (t
3592 (tramp-do-copy-or-rename-file-via-buffer
3593 op filename newname keep-date))))))
3594
3595 ;; One file is a Tramp file, the other one is local.
3596 ((or t1 t2)
3597 (with-parsed-tramp-file-name (if t1 filename newname) nil
8d60099b
MA
3598 (cond
3599 ;; Fast track on local machine.
3600 ((tramp-local-host-p v)
3601 (tramp-do-copy-or-rename-file-directly
3602 op filename newname
3603 ok-if-already-exists keep-date preserve-uid-gid))
3604
3605 ;; If the Tramp file has an out-of-band method, the corresponding
3606 ;; copy-program can be invoked.
7f49fe46 3607 ((tramp-method-out-of-band-p v (nth 7 (file-attributes filename)))
8d60099b
MA
3608 (tramp-do-copy-or-rename-file-out-of-band
3609 op filename newname keep-date))
3610
3611 ;; Use the inline method via a Tramp buffer.
3612 (t (tramp-do-copy-or-rename-file-via-buffer
3613 op filename newname keep-date)))))
00d6fd04
MA
3614
3615 (t
3616 ;; One of them must be a Tramp file.
3617 (error "Tramp implementation says this cannot happen")))
8d60099b 3618
484ea0b6
MA
3619 ;; In case of `rename', we must flush the cache of the source file.
3620 (when (and t1 (eq op 'rename))
3621 (with-parsed-tramp-file-name filename nil
aac0b0f2 3622 (tramp-flush-file-property v (file-name-directory localname))
484ea0b6
MA
3623 (tramp-flush-file-property v localname)))
3624
00d6fd04
MA
3625 ;; When newname did exist, we have wrong cached values.
3626 (when t2
3627 (with-parsed-tramp-file-name newname nil
aac0b0f2 3628 (tramp-flush-file-property v (file-name-directory localname))
905fb90e
MA
3629 (tramp-flush-file-property v localname)))
3630
b6bbb65e
MA
3631 ;; Stop progress reporter.
3632 (if tm (cancel-timer tm))
905fb90e
MA
3633 (with-parsed-tramp-file-name (if t1 filename newname) nil
3634 (tramp-message v 0 "Transferring %s to %s...done" filename newname)))))
7432277c 3635
38c65fca 3636(defun tramp-do-copy-or-rename-file-via-buffer (op filename newname keep-date)
90dc758d
KG
3637 "Use an Emacs buffer to copy or rename a file.
3638First arg OP is either `copy' or `rename' and indicates the operation.
3639FILENAME is the source file, NEWNAME the target file.
3640KEEP-DATE is non-nil if NEWNAME should have the same timestamp as FILENAME."
8a798e41
MA
3641 (with-temp-buffer
3642 ;; We must disable multibyte, because binary data shall not be
3643 ;; converted.
3644 (set-buffer-multibyte nil)
3645 (let ((coding-system-for-read 'binary)
3646 (jka-compr-inhibit t))
3647 (insert-file-contents-literally filename))
3648 ;; We don't want the target file to be compressed, so we let-bind
3649 ;; `jka-compr-inhibit' to t.
3650 (let ((coding-system-for-write 'binary)
3651 (jka-compr-inhibit t))
3652 (write-region (point-min) (point-max) newname)))
3653 ;; KEEP-DATE handling.
3654 (when keep-date (set-file-times newname (nth 5 (file-attributes filename))))
3655 ;; Set the mode.
b86c1cd8 3656 (set-file-modes newname (tramp-default-file-modes filename))
8a798e41
MA
3657 ;; If the operation was `rename', delete the original file.
3658 (unless (eq op 'copy) (delete-file filename)))
fb7933a3
KG
3659
3660(defun tramp-do-copy-or-rename-file-directly
8d60099b 3661 (op filename newname ok-if-already-exists keep-date preserve-uid-gid)
fb7933a3
KG
3662 "Invokes `cp' or `mv' on the remote system.
3663OP must be one of `copy' or `rename', indicating `cp' or `mv',
8d60099b
MA
3664respectively. FILENAME specifies the file to copy or rename,
3665NEWNAME is the name of the new file (for copy) or the new name of
3666the file (for rename). Both files must reside on the same host.
3667KEEP-DATE means to make sure that NEWNAME has the same timestamp
3668as FILENAME. PRESERVE-UID-GID, when non-nil, instructs to keep
3669the uid and gid from FILENAME."
8a4438b6 3670 (let ((t1 (tramp-tramp-file-p filename))
4f4126e6
MA
3671 (t2 (tramp-tramp-file-p newname))
3672 (file-times (nth 5 (file-attributes filename)))
3673 (file-modes (tramp-default-file-modes filename)))
8a4438b6
MA
3674 (with-parsed-tramp-file-name (if t1 filename newname) nil
3675 (let* ((cmd (cond ((and (eq op 'copy) preserve-uid-gid) "cp -f -p")
3676 ((eq op 'copy) "cp -f")
3677 ((eq op 'rename) "mv -f")
3678 (t (tramp-error
3679 v 'file-error
3680 "Unknown operation `%s', must be `copy' or `rename'"
3681 op))))
3682 (localname1
b533bc97
MA
3683 (if t1
3684 (tramp-file-name-handler 'file-remote-p filename 'localname)
3685 filename))
8a4438b6 3686 (localname2
b533bc97
MA
3687 (if t2
3688 (tramp-file-name-handler 'file-remote-p newname 'localname)
3689 newname))
293c24f9
MA
3690 (prefix (file-remote-p (if t1 filename newname)))
3691 cmd-result)
8d60099b 3692
8d60099b 3693 (cond
8a4438b6
MA
3694 ;; Both files are on a remote host, with same user.
3695 ((and t1 t2)
293c24f9
MA
3696 (setq cmd-result
3697 (tramp-send-command-and-check
3698 v
3699 (format "%s %s %s" cmd
3700 (tramp-shell-quote-argument localname1)
3701 (tramp-shell-quote-argument localname2))))
8a4438b6
MA
3702 (with-current-buffer (tramp-get-buffer v)
3703 (goto-char (point-min))
3704 (unless
3705 (or
3706 (and keep-date
3707 ;; Mask cp -f error.
3708 (re-search-forward
3709 tramp-operation-not-permitted-regexp nil t))
293c24f9 3710 (zerop cmd-result))
8a4438b6
MA
3711 (tramp-error-with-buffer
3712 nil v 'file-error
3713 "Copying directly failed, see buffer `%s' for details."
3714 (buffer-name)))))
3715
3716 ;; We are on the local host.
3717 ((or t1 t2)
8d60099b 3718 (cond
8a4438b6 3719 ;; We can do it directly.
87bdd2c7
MA
3720 ((let (file-name-handler-alist)
3721 (and (file-readable-p localname1)
3722 (file-writable-p (file-name-directory localname2))
3723 (or (file-directory-p localname2)
3724 (file-writable-p localname2))))
8d60099b 3725 (if (eq op 'copy)
9e6ab520
MA
3726 (tramp-compat-copy-file
3727 localname1 localname2 ok-if-already-exists
3728 keep-date preserve-uid-gid)
87bdd2c7
MA
3729 (tramp-run-real-handler
3730 'rename-file (list localname1 localname2 ok-if-already-exists))))
8a4438b6
MA
3731
3732 ;; We can do it directly with `tramp-send-command'
946a5aeb
MA
3733 ((and (file-readable-p (concat prefix localname1))
3734 (file-writable-p
3735 (file-name-directory (concat prefix localname2)))
3736 (or (file-directory-p (concat prefix localname2))
3737 (file-writable-p (concat prefix localname2))))
8a4438b6
MA
3738 (tramp-do-copy-or-rename-file-directly
3739 op (concat prefix localname1) (concat prefix localname2)
3740 ok-if-already-exists keep-date t)
3741 ;; We must change the ownership to the local user.
8d60099b 3742 (tramp-set-file-uid-gid
8a4438b6
MA
3743 (concat prefix localname2)
3744 (tramp-get-local-uid 'integer)
3745 (tramp-get-local-gid 'integer)))
8d60099b 3746
8a4438b6
MA
3747 ;; We need a temporary file in between.
3748 (t
2c418c5b
MA
3749 ;; Create the temporary file.
3750 (let ((tmpfile (tramp-compat-make-temp-file localname1)))
917b89a6 3751 (unwind-protect
2c418c5b
MA
3752 (progn
3753 (cond
3754 (t1
917b89a6
MA
3755 (or
3756 (zerop
3757 (tramp-send-command-and-check
3758 v (format
3759 "%s %s %s" cmd
3760 (tramp-shell-quote-argument localname1)
3761 (tramp-shell-quote-argument tmpfile))))
3762 (tramp-error-with-buffer
3763 nil v 'file-error
3764 "Copying directly failed, see buffer `%s' for details."
3765 (tramp-get-buffer v)))
2c418c5b 3766 ;; We must change the ownership as remote user.
917b89a6
MA
3767 ;; Since this does not work reliable, we also
3768 ;; give read permissions.
3769 (set-file-modes
3770 (concat prefix tmpfile) (tramp-octal-to-decimal "0777"))
2c418c5b
MA
3771 (tramp-set-file-uid-gid
3772 (concat prefix tmpfile)
3773 (tramp-get-local-uid 'integer)
3774 (tramp-get-local-gid 'integer)))
3775 (t2
3776 (if (eq op 'copy)
3777 (tramp-compat-copy-file
5ab38c3c 3778 localname1 tmpfile t
2c418c5b
MA
3779 keep-date preserve-uid-gid)
3780 (tramp-run-real-handler
3781 'rename-file
5ab38c3c 3782 (list localname1 tmpfile t)))
2c418c5b 3783 ;; We must change the ownership as local user.
917b89a6
MA
3784 ;; Since this does not work reliable, we also
3785 ;; give read permissions.
3786 (set-file-modes tmpfile (tramp-octal-to-decimal "0777"))
2c418c5b
MA
3787 (tramp-set-file-uid-gid
3788 tmpfile
3789 (tramp-get-remote-uid v 'integer)
3790 (tramp-get-remote-gid v 'integer))))
3791
3792 ;; Move the temporary file to its destination.
3793 (cond
3794 (t2
917b89a6
MA
3795 (or
3796 (zerop
3797 (tramp-send-command-and-check
3798 v (format
3799 "cp -f -p %s %s"
3800 (tramp-shell-quote-argument tmpfile)
3801 (tramp-shell-quote-argument localname2))))
3802 (tramp-error-with-buffer
3803 nil v 'file-error
3804 "Copying directly failed, see buffer `%s' for details."
3805 (tramp-get-buffer v))))
2c418c5b 3806 (t1
ce2cc728
MA
3807 (tramp-run-real-handler
3808 'rename-file
2c418c5b
MA
3809 (list tmpfile localname2 ok-if-already-exists)))))
3810
917b89a6
MA
3811 ;; Save exit.
3812 (condition-case nil
3813 (delete-file tmpfile)
3814 (error)))))))))
8d60099b
MA
3815
3816 ;; Set the time and mode. Mask possible errors.
8d60099b 3817 (condition-case nil
1f107aed 3818 (when keep-date
4f4126e6
MA
3819 (set-file-times newname file-times)
3820 (set-file-modes newname file-modes))
8d60099b
MA
3821 (error)))))
3822
5ec2cc41 3823(defun tramp-do-copy-or-rename-file-out-of-band (op filename newname keep-date)
7432277c 3824 "Invoke rcp program to copy.
905fb90e 3825The method used must be an out-of-band method."
38c65fca 3826 (let ((t1 (tramp-tramp-file-p filename))
5ec2cc41 3827 (t2 (tramp-tramp-file-p newname))
946a5aeb 3828 copy-program copy-args copy-env copy-keep-date port spec
00d6fd04
MA
3829 source target)
3830
3831 (with-parsed-tramp-file-name (if t1 filename newname) nil
905fb90e 3832 (if (and t1 t2)
00d6fd04 3833
905fb90e
MA
3834 ;; Both are Tramp files. We shall optimize it, when the
3835 ;; methods for filename and newname are the same.
9cf3544e
MA
3836 (let* ((dir-flag (file-directory-p filename))
3837 (tmpfile (tramp-compat-make-temp-file localname dir-flag)))
3838 (if dir-flag
3839 (setq tmpfile
3840 (expand-file-name
3841 (file-name-nondirectory newname) tmpfile)))
905fb90e
MA
3842 (unwind-protect
3843 (progn
3844 (tramp-do-copy-or-rename-file-out-of-band
3845 op filename tmpfile keep-date)
3846 (tramp-do-copy-or-rename-file-out-of-band
3847 'rename tmpfile newname keep-date))
3848 ;; Save exit.
3849 (condition-case nil
9cf3544e 3850 (if dir-flag
b533bc97 3851 (tramp-compat-delete-directory
9cf3544e
MA
3852 (expand-file-name ".." tmpfile) 'recursive)
3853 (delete-file tmpfile))
905fb90e
MA
3854 (error))))
3855
3856 ;; Expand hops. Might be necessary for gateway methods.
3857 (setq v (car (tramp-compute-multi-hops v)))
3858 (aset v 3 localname)
3859
3860 ;; Check which ones of source and target are Tramp files.
3861 (setq source (if t1 (tramp-make-copy-program-file-name v) filename)
263c02ef
MA
3862 target (funcall
3863 (if (and (file-directory-p filename)
3864 (string-equal
3865 (file-name-nondirectory filename)
3866 (file-name-nondirectory newname)))
3867 'file-name-directory
3868 'identity)
3869 (if t2 (tramp-make-copy-program-file-name v) newname)))
905fb90e
MA
3870
3871 ;; Check for port number. Until now, there's no need for handling
3872 ;; like method, user, host.
3873 (setq host (tramp-file-name-real-host v)
3874 port (tramp-file-name-port v)
3875 port (or (and port (number-to-string port)) ""))
3876
3877 ;; Compose copy command.
b533bc97
MA
3878 (setq spec (format-spec-make
3879 ?h host ?u user ?p port
3880 ?t (tramp-get-connection-property
3881 (tramp-get-connection-process v) "temp-file" "")
3882 ?k (if keep-date " " ""))
905fb90e
MA
3883 copy-program (tramp-get-method-parameter
3884 method 'tramp-copy-program)
3885 copy-keep-date (tramp-get-method-parameter
3886 method 'tramp-copy-keep-date)
3887 copy-args
3888 (delq
3889 nil
3890 (mapcar
aa485f7c
MA
3891 (lambda (x)
3892 (setq
3893 x
3894 ;; " " is indication for keep-date argument.
3895 (delete " " (mapcar (lambda (y) (format-spec y spec)) x)))
3896 (unless (member "" x) (mapconcat 'identity x " ")))
946a5aeb
MA
3897 (tramp-get-method-parameter method 'tramp-copy-args)))
3898 copy-env
3899 (delq
3900 nil
3901 (mapcar
aa485f7c
MA
3902 (lambda (x)
3903 (setq x (mapcar (lambda (y) (format-spec y spec)) x))
3904 (unless (member "" x) (mapconcat 'identity x " ")))
946a5aeb 3905 (tramp-get-method-parameter method 'tramp-copy-env))))
905fb90e
MA
3906
3907 ;; Check for program.
3908 (when (and (fboundp 'executable-find)
3909 (not (let ((default-directory
3910 (tramp-compat-temporary-file-directory)))
3911 (executable-find copy-program))))
3912 (tramp-error
3913 v 'file-error "Cannot find copy program: %s" copy-program))
00d6fd04 3914
4265deab
MA
3915 ;; Set variables for computing the prompt for reading
3916 ;; password.
3917 (setq tramp-current-method (tramp-file-name-method v)
3918 tramp-current-user (tramp-file-name-user v)
3919 tramp-current-host (tramp-file-name-host v))
3920
905fb90e
MA
3921 (unwind-protect
3922 (with-temp-buffer
3923 ;; The default directory must be remote.
3924 (let ((default-directory
946a5aeb
MA
3925 (file-name-directory (if t1 filename newname)))
3926 (process-environment (copy-sequence process-environment)))
905fb90e
MA
3927 ;; Set the transfer process properties.
3928 (tramp-set-connection-property
3929 v "process-name" (buffer-name (current-buffer)))
3930 (tramp-set-connection-property
3931 v "process-buffer" (current-buffer))
946a5aeb
MA
3932 (while copy-env
3933 (tramp-message v 5 "%s=\"%s\"" (car copy-env) (cadr copy-env))
3934 (setenv (pop copy-env) (pop copy-env)))
905fb90e
MA
3935
3936 ;; Use an asynchronous process. By this, password can
3937 ;; be handled. The default directory must be local, in
3938 ;; order to apply the correct `copy-program'. We don't
3939 ;; set a timeout, because the copying of large files can
3940 ;; last longer than 60 secs.
3941 (let ((p (let ((default-directory
3942 (tramp-compat-temporary-file-directory)))
3943 (apply 'start-process
3944 (tramp-get-connection-property
3945 v "process-name" nil)
3946 (tramp-get-connection-property
3947 v "process-buffer" nil)
3948 copy-program
3949 (append copy-args (list source target))))))
3950 (tramp-message
3951 v 6 "%s" (mapconcat 'identity (process-command p) " "))
3952 (tramp-set-process-query-on-exit-flag p nil)
3953 (tramp-process-actions p v tramp-actions-copy-out-of-band))))
00d6fd04 3954
905fb90e
MA
3955 ;; Reset the transfer process properties.
3956 (tramp-set-connection-property v "process-name" nil)
3957 (tramp-set-connection-property v "process-buffer" nil))
00d6fd04 3958
905fb90e
MA
3959 ;; Handle KEEP-DATE argument.
3960 (when (and keep-date (not copy-keep-date))
3961 (set-file-times newname (nth 5 (file-attributes filename))))
01917a18 3962
905fb90e
MA
3963 ;; Set the mode.
3964 (unless (and keep-date copy-keep-date)
459a5f4b
MA
3965 (ignore-errors
3966 (set-file-modes newname (tramp-default-file-modes filename)))))
5ec2cc41 3967
905fb90e
MA
3968 ;; If the operation was `rename', delete the original file.
3969 (unless (eq op 'copy)
aac0b0f2
MA
3970 (if (file-regular-p filename)
3971 (delete-file filename)
b533bc97 3972 (tramp-compat-delete-directory filename 'recursive))))))
7432277c 3973
fb7933a3 3974(defun tramp-handle-make-directory (dir &optional parents)
00d6fd04 3975 "Like `make-directory' for Tramp files."
ac474af1 3976 (setq dir (expand-file-name dir))
c62c9d08 3977 (with-parsed-tramp-file-name dir nil
c15cdf02 3978 (tramp-flush-directory-property v (file-name-directory localname))
b1d06e75
KG
3979 (save-excursion
3980 (tramp-barf-unless-okay
00d6fd04 3981 v
9c13938d 3982 (format "%s %s"
b1d06e75 3983 (if parents "mkdir -p" "mkdir")
7432277c 3984 (tramp-shell-quote-argument localname))
b1d06e75 3985 "Couldn't make directory %s" dir))))
fb7933a3 3986
c15cdf02 3987(defun tramp-handle-delete-directory (directory &optional recursive)
00d6fd04 3988 "Like `delete-directory' for Tramp files."
ac474af1 3989 (setq directory (expand-file-name directory))
c62c9d08 3990 (with-parsed-tramp-file-name directory nil
aac0b0f2 3991 (tramp-flush-file-property v (file-name-directory localname))
00d6fd04
MA
3992 (tramp-flush-directory-property v localname)
3993 (unless (zerop (tramp-send-command-and-check
3994 v
c15cdf02
MA
3995 (format
3996 "%s %s"
3997 (if recursive "rm -rf" "rmdir")
3998 (tramp-shell-quote-argument localname))))
00d6fd04 3999 (tramp-error v 'file-error "Couldn't delete %s" directory))))
fb7933a3
KG
4000
4001(defun tramp-handle-delete-file (filename)
00d6fd04 4002 "Like `delete-file' for Tramp files."
ac474af1 4003 (setq filename (expand-file-name filename))
c62c9d08 4004 (with-parsed-tramp-file-name filename nil
aac0b0f2 4005 (tramp-flush-file-property v (file-name-directory localname))
00d6fd04
MA
4006 (tramp-flush-file-property v localname)
4007 (unless (zerop (tramp-send-command-and-check
4008 v
4009 (format "rm -f %s"
4010 (tramp-shell-quote-argument localname))))
4011 (tramp-error v 'file-error "Couldn't delete %s" filename))))
fb7933a3
KG
4012
4013;; Dired.
4014
4015;; CCC: This does not seem to be enough. Something dies when
a4aeb9a4 4016;; we try and delete two directories under Tramp :/
fb7933a3
KG
4017(defun tramp-handle-dired-recursive-delete-directory (filename)
4018 "Recursively delete the directory given.
00d6fd04 4019This is like `dired-recursive-delete-directory' for Tramp files."
c62c9d08 4020 (with-parsed-tramp-file-name filename nil
00d6fd04 4021 ;; Run a shell command 'rm -r <localname>'
260821d3 4022 ;; Code shamelessly stolen from the dired implementation and, um, hacked :)
00d6fd04
MA
4023 (unless (file-exists-p filename)
4024 (tramp-error v 'file-error "No such directory: %s" filename))
fb7933a3 4025 ;; Which is better, -r or -R? (-r works for me <daniel@danann.net>)
00d6fd04
MA
4026 (tramp-send-command
4027 v
9c13938d 4028 (format "rm -rf %s" (tramp-shell-quote-argument localname))
00d6fd04
MA
4029 ;; Don't read the output, do it explicitely.
4030 nil t)
fb7933a3
KG
4031 ;; Wait for the remote system to return to us...
4032 ;; This might take a while, allow it plenty of time.
00d6fd04 4033 (tramp-wait-for-output (tramp-get-connection-process v) 120)
fb7933a3 4034 ;; Make sure that it worked...
aac0b0f2 4035 (tramp-flush-file-property v (file-name-directory localname))
c15cdf02 4036 (tramp-flush-directory-property v localname)
07dfe738 4037 (and (file-exists-p filename)
00d6fd04
MA
4038 (tramp-error
4039 v 'file-error "Failed to recursively delete %s" filename))))
bf247b6e 4040
5ec2cc41 4041(defun tramp-handle-dired-compress-file (file &rest ok-flag)
00d6fd04 4042 "Like `dired-compress-file' for Tramp files."
5ec2cc41
KG
4043 ;; OK-FLAG is valid for XEmacs only, but not implemented.
4044 ;; Code stolen mainly from dired-aux.el.
4045 (with-parsed-tramp-file-name file nil
00d6fd04 4046 (tramp-flush-file-property v localname)
5ec2cc41
KG
4047 (save-excursion
4048 (let ((suffixes
4049 (if (not (featurep 'xemacs))
4050 ;; Emacs case
4051 (symbol-value 'dired-compress-file-suffixes)
4052 ;; XEmacs has `dired-compression-method-alist', which is
4053 ;; transformed into `dired-compress-file-suffixes' structure.
4054 (mapcar
aa485f7c
MA
4055 (lambda (x)
4056 (list (concat (regexp-quote (nth 1 x)) "\\'")
4057 nil
4058 (mapconcat 'identity (nth 3 x) " ")))
5ec2cc41
KG
4059 (symbol-value 'dired-compression-method-alist))))
4060 suffix)
4061 ;; See if any suffix rule matches this file name.
4062 (while suffixes
4063 (let (case-fold-search)
4064 (if (string-match (car (car suffixes)) localname)
4065 (setq suffix (car suffixes) suffixes nil))
4066 (setq suffixes (cdr suffixes))))
4067
4068 (cond ((file-symlink-p file)
4069 nil)
4070 ((and suffix (nth 2 suffix))
4071 ;; We found an uncompression rule.
00d6fd04 4072 (tramp-message v 0 "Uncompressing %s..." file)
5ec2cc41 4073 (when (zerop (tramp-send-command-and-check
b593f105
MA
4074 v (concat (nth 2 suffix) " "
4075 (tramp-shell-quote-argument localname))))
00d6fd04 4076 (tramp-message v 0 "Uncompressing %s...done" file)
38c65fca
KG
4077 ;; `dired-remove-file' is not defined in XEmacs
4078 (funcall (symbol-function 'dired-remove-file) file)
5ec2cc41
KG
4079 (string-match (car suffix) file)
4080 (concat (substring file 0 (match-beginning 0)))))
4081 (t
4082 ;; We don't recognize the file as compressed, so compress it.
4083 ;; Try gzip.
00d6fd04 4084 (tramp-message v 0 "Compressing %s..." file)
5ec2cc41 4085 (when (zerop (tramp-send-command-and-check
b593f105
MA
4086 v (concat "gzip -f "
4087 (tramp-shell-quote-argument localname))))
00d6fd04 4088 (tramp-message v 0 "Compressing %s...done" file)
38c65fca
KG
4089 ;; `dired-remove-file' is not defined in XEmacs
4090 (funcall (symbol-function 'dired-remove-file) file)
5ec2cc41
KG
4091 (cond ((file-exists-p (concat file ".gz"))
4092 (concat file ".gz"))
4093 ((file-exists-p (concat file ".z"))
4094 (concat file ".z"))
4095 (t nil)))))))))
fb7933a3 4096
d5b3979c 4097(defun tramp-handle-dired-uncache (dir &optional dir-p)
70c11b0b 4098 "Like `dired-uncache' for Tramp files."
d5b3979c
MA
4099 ;; DIR-P is valid for XEmacs only.
4100 (with-parsed-tramp-file-name
4101 (if (or dir-p (file-directory-p dir)) dir (file-name-directory dir)) nil
70c11b0b
MA
4102 (tramp-flush-file-property v localname)))
4103
fb7933a3
KG
4104;; Pacify byte-compiler. The function is needed on XEmacs only. I'm
4105;; not sure at all that this is the right way to do it, but let's hope
4106;; it works for now, and wait for a guru to point out the Right Way to
4107;; achieve this.
4108;;(eval-when-compile
4109;; (unless (fboundp 'dired-insert-set-properties)
4110;; (fset 'dired-insert-set-properties 'ignore)))
4111;; Gerd suggests this:
4112(eval-when-compile (require 'dired))
4113;; Note that dired is required at run-time, too, when it is needed.
4114;; It is only needed on XEmacs for the function
4115;; `dired-insert-set-properties'.
4116
4117(defun tramp-handle-insert-directory
4118 (filename switches &optional wildcard full-directory-p)
00d6fd04
MA
4119 "Like `insert-directory' for Tramp files."
4120 (setq filename (expand-file-name filename))
4121 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
4122 (if (and (featurep 'ls-lisp)
4123 (not (symbol-value 'ls-lisp-use-insert-directory-program)))
4124 (tramp-run-real-handler
4125 'insert-directory (list filename switches wildcard full-directory-p))
0c0b61f1
MA
4126 (when (stringp switches)
4127 (setq switches (split-string switches)))
4128 (when (and (member "--dired" switches)
8e754ea2 4129 (not (tramp-get-ls-command-with-dired v)))
0c0b61f1 4130 (setq switches (delete "--dired" switches)))
c82c5727 4131 (when wildcard
87bdd2c7
MA
4132 (setq wildcard (tramp-run-real-handler
4133 'file-name-nondirectory (list localname)))
4134 (setq localname (tramp-run-real-handler
4135 'file-name-directory (list localname))))
c82c5727 4136 (unless full-directory-p
0c0b61f1
MA
4137 (setq switches (add-to-list 'switches "-d" 'append)))
4138 (setq switches (mapconcat 'tramp-shell-quote-argument switches " "))
c82c5727 4139 (when wildcard
0c0b61f1
MA
4140 (setq switches (concat switches " " wildcard)))
4141 (tramp-message
4142 v 4 "Inserting directory `ls %s %s', wildcard %s, fulldir %s"
4143 switches filename (if wildcard "yes" "no")
4144 (if full-directory-p "yes" "no"))
00d6fd04
MA
4145 ;; If `full-directory-p', we just say `ls -l FILENAME'.
4146 ;; Else we chdir to the parent directory, then say `ls -ld BASENAME'.
4147 (if full-directory-p
4148 (tramp-send-command
4149 v
fe5facd3 4150 (format "%s %s %s 2>/dev/null"
00d6fd04
MA
4151 (tramp-get-ls-command v)
4152 switches
4153 (if wildcard
4154 localname
4155 (tramp-shell-quote-argument (concat localname ".")))))
4156 (tramp-barf-unless-okay
4157 v
4158 (format "cd %s" (tramp-shell-quote-argument
87bdd2c7
MA
4159 (tramp-run-real-handler
4160 'file-name-directory (list localname))))
00d6fd04 4161 "Couldn't `cd %s'"
87bdd2c7
MA
4162 (tramp-shell-quote-argument
4163 (tramp-run-real-handler 'file-name-directory (list localname))))
00d6fd04
MA
4164 (tramp-send-command
4165 v
4166 (format "%s %s %s"
4167 (tramp-get-ls-command v)
4168 switches
4169 (if (or wildcard
87bdd2c7
MA
4170 (zerop (length
4171 (tramp-run-real-handler
4172 'file-name-nondirectory (list localname)))))
00d6fd04
MA
4173 ""
4174 (tramp-shell-quote-argument
87bdd2c7
MA
4175 (tramp-run-real-handler
4176 'file-name-nondirectory (list localname)))))))
8e754ea2
MA
4177 (let ((beg (point)))
4178 ;; We cannot use `insert-buffer-substring' because the Tramp
4179 ;; buffer changes its contents before insertion due to calling
4180 ;; `expand-file' and alike.
4181 (insert
4182 (with-current-buffer (tramp-get-buffer v)
4183 (buffer-string)))
4184
4185 ;; Check for "--dired" output.
8e754ea2 4186 (forward-line -2)
7f4d4a97
MA
4187 (when (looking-at "//SUBDIRED//")
4188 (forward-line -1))
8e754ea2 4189 (when (looking-at "//DIRED//")
7ba1d9c2 4190 (let ((end (tramp-compat-line-end-position))
8e754ea2
MA
4191 (linebeg (point)))
4192 ;; Now read the numeric positions of file names.
4193 (goto-char linebeg)
4194 (forward-word 1)
4195 (forward-char 3)
4196 (while (< (point) end)
4197 (let ((start (+ beg (read (current-buffer))))
4198 (end (+ beg (read (current-buffer)))))
7f49fe46 4199 (if (memq (char-after end) '(?\n ?\ ))
8e754ea2 4200 ;; End is followed by \n or by " -> ".
fe5facd3
MA
4201 (put-text-property start end 'dired-filename t))))))
4202 ;; Remove trailing lines.
4203 (goto-char (tramp-compat-line-beginning-position))
4204 (while (looking-at "//")
4205 (forward-line 1)
4206 (delete-region (match-beginning 0) (point)))
0c0b61f1
MA
4207
4208 ;; The inserted file could be from somewhere else.
4209 (when (and (not wildcard) (not full-directory-p))
4210 (goto-char (point-max))
e5c70c41
MA
4211 (when (file-symlink-p filename)
4212 (goto-char (search-backward "->" beg 'noerror)))
0c0b61f1
MA
4213 (search-backward
4214 (if (zerop (length (file-name-nondirectory filename)))
4215 "."
4216 (file-name-nondirectory filename))
4217 beg 'noerror)
4218 (replace-match (file-relative-name filename) t))
4219
fe5facd3 4220 (goto-char (point-max))))))
fb7933a3 4221
fb7933a3 4222(defun tramp-handle-unhandled-file-name-directory (filename)
00d6fd04 4223 "Like `unhandled-file-name-directory' for Tramp files."
8a798e41
MA
4224 ;; With Emacs 23, we could simply return `nil'. But we must keep it
4225 ;; for backward compatibility.
ce3f516f 4226 (expand-file-name "~/"))
fb7933a3
KG
4227
4228;; Canonicalization of file names.
4229
fb7933a3 4230(defun tramp-handle-expand-file-name (name &optional dir)
00d6fd04 4231 "Like `expand-file-name' for Tramp files.
7432277c
KG
4232If the localname part of the given filename starts with \"/../\" then
4233the result will be a local, non-Tramp, filename."
fb7933a3
KG
4234 ;; If DIR is not given, use DEFAULT-DIRECTORY or "/".
4235 (setq dir (or dir default-directory "/"))
4236 ;; Unless NAME is absolute, concat DIR and NAME.
4237 (unless (file-name-absolute-p name)
4238 (setq name (concat (file-name-as-directory dir) name)))
00d6fd04 4239 ;; If NAME is not a Tramp file, run the real handler.
acd1f317 4240 (if (not (tramp-connectable-p name))
00d6fd04 4241 (tramp-run-real-handler 'expand-file-name (list name nil))
fb7933a3 4242 ;; Dissect NAME.
c62c9d08 4243 (with-parsed-tramp-file-name name nil
87bdd2c7 4244 (unless (tramp-run-real-handler 'file-name-absolute-p (list localname))
7432277c 4245 (setq localname (concat "~/" localname)))
00d6fd04
MA
4246 ;; Tilde expansion if necessary. This needs a shell which
4247 ;; groks tilde expansion! The function `tramp-find-shell' is
4248 ;; supposed to find such a shell on the remote host. Please
4249 ;; tell me about it when this doesn't work on your system.
4250 (when (string-match "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname)
4251 (let ((uname (match-string 1 localname))
4252 (fname (match-string 2 localname)))
4253 ;; We cannot simply apply "~/", because under sudo "~/" is
4254 ;; expanded to the local user home directory but to the
4255 ;; root home directory. On the other hand, using always
4256 ;; the default user name for tilde expansion is not
4257 ;; appropriate either, because ssh and companions might
4258 ;; use a user name from the config file.
4259 (when (and (string-equal uname "~")
4260 (string-match "\\`su\\(do\\)?\\'" method))
4261 (setq uname (concat uname user)))
4262 (setq uname
b593f105
MA
4263 (with-connection-property v uname
4264 (tramp-send-command
4265 v (format "cd %s; pwd" (tramp-shell-quote-argument uname)))
4266 (with-current-buffer (tramp-get-buffer v)
4267 (goto-char (point-min))
4268 (buffer-substring
4269 (point) (tramp-compat-line-end-position)))))
00d6fd04
MA
4270 (setq localname (concat uname fname))))
4271 ;; There might be a double slash, for example when "~/"
cb85dcd0 4272 ;; expands to "/". Remove this.
00d6fd04
MA
4273 (while (string-match "//" localname)
4274 (setq localname (replace-match "/" t t localname)))
4275 ;; No tilde characters in file name, do normal
a17632c1
MA
4276 ;; `expand-file-name' (this does "/./" and "/../"). We bind
4277 ;; `directory-sep-char' here for XEmacs on Windows, which would
4278 ;; otherwise use backslash. `default-directory' is bound,
4279 ;; because on Windows there would be problems with UNC shares or
4280 ;; Cygwin mounts.
aff67808
MA
4281 (let ((directory-sep-char ?/)
4282 (default-directory (tramp-compat-temporary-file-directory)))
4283 (tramp-make-tramp-file-name
4284 method user host
4285 (tramp-drop-volume-letter
87bdd2c7
MA
4286 (tramp-run-real-handler
4287 'expand-file-name (list localname))))))))
00d6fd04 4288
c23c3394
MA
4289(defun tramp-replace-environment-variables (filename)
4290 "Replace environment variables in FILENAME.
4291Return the string with the replaced variables."
2e271195 4292 (save-match-data
ec5145d6 4293 (let ((idx (string-match "$\\(\\w+\\)" filename)))
2e271195 4294 ;; `$' is coded as `$$'.
ec5145d6
MA
4295 (when (and idx
4296 (or (zerop idx) (not (eq ?$ (aref filename (1- idx)))))
4297 (getenv (match-string 1 filename)))
2e271195
MA
4298 (setq filename
4299 (replace-match
4300 (substitute-in-file-name (match-string 0 filename))
4301 t nil filename)))
4302 filename)))
c23c3394 4303
00d6fd04
MA
4304(defun tramp-handle-substitute-in-file-name (filename)
4305 "Like `substitute-in-file-name' for Tramp files.
4306\"//\" and \"/~\" substitute only in the local filename part.
4307If the URL Tramp syntax is chosen, \"//\" as method delimeter and \"/~\" at
4308beginning of local filename are not substituted."
c23c3394
MA
4309 ;; First, we must replace environment variables.
4310 (setq filename (tramp-replace-environment-variables filename))
00d6fd04
MA
4311 (with-parsed-tramp-file-name filename nil
4312 (if (equal tramp-syntax 'url)
4313 ;; We need to check localname only. The other parts cannot contain
4314 ;; "//" or "/~".
4315 (if (and (> (length localname) 1)
4316 (or (string-match "//" localname)
4317 (string-match "/~" localname 1)))
4318 (tramp-run-real-handler 'substitute-in-file-name (list filename))
4319 (tramp-make-tramp-file-name
4320 (when method (substitute-in-file-name method))
4321 (when user (substitute-in-file-name user))
4322 (when host (substitute-in-file-name host))
87bdd2c7
MA
4323 (when localname
4324 (tramp-run-real-handler
4325 'substitute-in-file-name (list localname)))))
00d6fd04
MA
4326 ;; Ignore in LOCALNAME everything before "//" or "/~".
4327 (when (and (stringp localname) (string-match ".+?/\\(/\\|~\\)" localname))
4328 (setq filename
b08104a0
MA
4329 (concat (file-remote-p filename)
4330 (replace-match "\\1" nil nil localname)))
00d6fd04
MA
4331 ;; "/m:h:~" does not work for completion. We use "/m:h:~/".
4332 (when (string-match "~$" filename)
4333 (setq filename (concat filename "/"))))
4334 (tramp-run-real-handler 'substitute-in-file-name (list filename)))))
4335
4336;; In XEmacs, electricity is implemented via a key map for ?/ and ?~,
4337;; which calls corresponding functions (see minibuf.el).
4338(when (fboundp 'minibuffer-electric-separator)
9e6ab520 4339 (mapc
aa485f7c
MA
4340 (lambda (x)
4341 (eval
4342 `(defadvice ,x
4343 (around ,(intern (format "tramp-advice-%s" x)) activate)
4344 "Invoke `substitute-in-file-name' for Tramp files."
4345 (if (and (symbol-value 'minibuffer-electric-file-name-behavior)
4346 (tramp-tramp-file-p (buffer-substring)))
4347 ;; We don't need to handle `last-input-event', because
4348 ;; due to the key map we know it must be ?/ or ?~.
4349 (let ((s (concat (buffer-substring (point-min) (point))
4350 (string last-command-char))))
4351 (delete-region (point-min) (point))
4352 (insert (substitute-in-file-name s))
4353 (setq ad-return-value last-command-char))
d7ec1df7
MA
4354 ad-do-it)))
4355 (eval
4356 `(add-hook
4357 'tramp-unload-hook
4358 (lambda ()
4359 (ad-remove-advice ',x 'around ',(intern (format "tramp-advice-%s" x)))
4360 (ad-activate ',x)))))
00d6fd04
MA
4361
4362 '(minibuffer-electric-separator
4363 minibuffer-electric-tilde)))
4364
4365
0664ff72 4366;;; Remote commands:
fb7933a3 4367
00d6fd04
MA
4368(defun tramp-handle-executable-find (command)
4369 "Like `executable-find' for Tramp files."
4370 (with-parsed-tramp-file-name default-directory nil
f84638eb 4371 (tramp-find-executable v command (tramp-get-remote-path v) t)))
00d6fd04
MA
4372
4373;; We use BUFFER also as connection buffer during setup. Because of
4374;; this, its original contents must be saved, and restored once
4375;; connection has been setup.
4376(defun tramp-handle-start-file-process (name buffer program &rest args)
4377 "Like `start-file-process' for Tramp files."
4378 (with-parsed-tramp-file-name default-directory nil
9fb2cdc5
GM
4379 (unless (stringp program)
4380 (tramp-error
4381 v 'file-error "pty association is not supported for `%s'" name))
00d6fd04 4382 (unwind-protect
263c02ef
MA
4383 (let ((command (format "cd %s; exec %s"
4384 (tramp-shell-quote-argument localname)
4385 (mapconcat 'tramp-shell-quote-argument
4386 (cons program args) " ")))
4387 (name1 name)
38d63e6a 4388 (i 0))
2296b54d 4389 (unless buffer
6ce63faf 4390 ;; BUFFER can be nil. We use a temporary buffer.
2296b54d 4391 (setq buffer (generate-new-buffer tramp-temp-buffer-name)))
38d63e6a
MA
4392 (while (get-process name1)
4393 ;; NAME must be unique as process name.
4394 (setq i (1+ i)
4395 name1 (format "%s<%d>" name i)))
4396 (setq name name1)
00d6fd04
MA
4397 ;; Set the new process properties.
4398 (tramp-set-connection-property v "process-name" name)
2296b54d 4399 (tramp-set-connection-property v "process-buffer" buffer)
00d6fd04 4400 ;; Activate narrowing in order to save BUFFER contents.
11c71217
MA
4401 ;; Clear also the modification time; otherwise we might be
4402 ;; interrupted by `verify-visited-file-modtime'.
00d6fd04 4403 (with-current-buffer (tramp-get-connection-buffer v)
11c71217 4404 (clear-visited-file-modtime)
00d6fd04 4405 (narrow-to-region (point-max) (point-max)))
263c02ef 4406 ;; Send the command. `tramp-send-command' opens a new
00d6fd04 4407 ;; connection.
263c02ef 4408 (tramp-send-command v command nil t) ; nooutput
6ce63faf
MA
4409 ;; Set query flag for this process.
4410 (tramp-set-process-query-on-exit-flag
4411 (tramp-get-connection-process v) t)
00d6fd04
MA
4412 ;; Return process.
4413 (tramp-get-connection-process v))
4414 ;; Save exit.
ce3f516f 4415 (with-current-buffer (tramp-get-connection-buffer v)
6ce63faf
MA
4416 (if (string-match tramp-temp-buffer-name (buffer-name))
4417 (progn
4418 (set-process-buffer (tramp-get-connection-process v) nil)
4419 (kill-buffer (current-buffer)))
4420 (widen)
4421 (goto-char (point-max))))
00d6fd04
MA
4422 (tramp-set-connection-property v "process-name" nil)
4423 (tramp-set-connection-property v "process-buffer" nil))))
4424
4425(defun tramp-handle-process-file
4426 (program &optional infile destination display &rest args)
4427 "Like `process-file' for Tramp files."
4428 ;; The implementation is not complete yet.
4429 (when (and (numberp destination) (zerop destination))
4430 (error "Implementation does not handle immediate return"))
4431
4432 (with-parsed-tramp-file-name default-directory nil
a6e96327 4433 (let (command input tmpinput stderr tmpstderr outbuf ret)
00d6fd04
MA
4434 ;; Compute command.
4435 (setq command (mapconcat 'tramp-shell-quote-argument
4436 (cons program args) " "))
4437 ;; Determine input.
4438 (if (null infile)
4439 (setq input "/dev/null")
4440 (setq infile (expand-file-name infile))
4441 (if (tramp-equal-remote default-directory infile)
4442 ;; INFILE is on the same remote host.
4443 (setq input (with-parsed-tramp-file-name infile nil localname))
4444 ;; INFILE must be copied to remote host.
a6e96327
MA
4445 (setq input (tramp-make-tramp-temp-file v)
4446 tmpinput (tramp-make-tramp-file-name method user host input))
4447 (copy-file infile tmpinput t)))
00d6fd04
MA
4448 (when input (setq command (format "%s <%s" command input)))
4449
4450 ;; Determine output.
4451 (cond
bede3e9f 4452 ;; Just a buffer.
00d6fd04
MA
4453 ((bufferp destination)
4454 (setq outbuf destination))
bede3e9f 4455 ;; A buffer name.
00d6fd04
MA
4456 ((stringp destination)
4457 (setq outbuf (get-buffer-create destination)))
4458 ;; (REAL-DESTINATION ERROR-DESTINATION)
4459 ((consp destination)
bede3e9f 4460 ;; output.
00d6fd04
MA
4461 (cond
4462 ((bufferp (car destination))
4463 (setq outbuf (car destination)))
4464 ((stringp (car destination))
0664ff72
MA
4465 (setq outbuf (get-buffer-create (car destination))))
4466 ((car destination)
4467 (setq outbuf (current-buffer))))
bede3e9f 4468 ;; stderr.
00d6fd04
MA
4469 (cond
4470 ((stringp (cadr destination))
4471 (setcar (cdr destination) (expand-file-name (cadr destination)))
4472 (if (tramp-equal-remote default-directory (cadr destination))
4473 ;; stderr is on the same remote host.
4474 (setq stderr (with-parsed-tramp-file-name
4475 (cadr destination) nil localname))
4476 ;; stderr must be copied to remote host. The temporary
4477 ;; file must be deleted after execution.
a6e96327
MA
4478 (setq stderr (tramp-make-tramp-temp-file v)
4479 tmpstderr (tramp-make-tramp-file-name
4480 method user host stderr))))
bede3e9f 4481 ;; stderr to be discarded.
00d6fd04
MA
4482 ((null (cadr destination))
4483 (setq stderr "/dev/null"))))
4484 ;; 't
4485 (destination
4486 (setq outbuf (current-buffer))))
4487 (when stderr (setq command (format "%s 2>%s" command stderr)))
4488
00d6fd04
MA
4489 ;; Send the command. It might not return in time, so we protect it.
4490 (condition-case nil
4491 (unwind-protect
293c24f9
MA
4492 (setq ret
4493 (tramp-send-command-and-check
4494 v (format "\\cd %s; %s"
4495 (tramp-shell-quote-argument localname)
b593f105
MA
4496 command)
4497 nil t))
00d6fd04
MA
4498 ;; We should show the output anyway.
4499 (when outbuf
293c24f9
MA
4500 (with-current-buffer outbuf
4501 (insert
4502 (with-current-buffer (tramp-get-connection-buffer v)
4503 (buffer-string))))
00d6fd04 4504 (when display (display-buffer outbuf))))
260821d3
MA
4505 ;; When the user did interrupt, we should do it also. We use
4506 ;; return code -1 as marker.
4507 (quit
4508 (kill-buffer (tramp-get-connection-buffer v))
4509 (setq ret -1))
4510 ;; Handle errors.
00d6fd04
MA
4511 (error
4512 (kill-buffer (tramp-get-connection-buffer v))
4513 (setq ret 1)))
a6e96327 4514
a6e96327
MA
4515 ;; Provide error file.
4516 (when tmpstderr (rename-file tmpstderr (cadr destination) t))
263c02ef 4517
260821d3
MA
4518 ;; Cleanup. We remove all file cache values for the connection,
4519 ;; because the remote process could have changed them.
a6e96327 4520 (when tmpinput (delete-file tmpinput))
946a5aeb
MA
4521
4522 ;; `process-file-side-effects' has been introduced with GNU
4523 ;; Emacs 23.2. If set to `nil', no remote file will be changed
4524 ;; by `program'. If it doesn't exist, we assume its default
4525 ;; value 't'.
4526 (unless (and (boundp 'process-file-side-effects)
4527 (not (symbol-value 'process-file-side-effects)))
4528 (tramp-flush-directory-property v ""))
4529
00d6fd04 4530 ;; Return exit status.
260821d3
MA
4531 (if (equal ret -1)
4532 (keyboard-quit)
4533 ret))))
00d6fd04 4534
a4aeb9a4
MA
4535(defun tramp-local-call-process
4536 (program &optional infile destination display &rest args)
4537 "Calls `call-process' on the local host.
4538This is needed because for some Emacs flavors Tramp has
4539defadviced `call-process' to behave like `process-file'. The
4540Lisp error raised when PROGRAM is nil is trapped also, returning 1."
4541 (let ((default-directory
4542 (if (file-remote-p default-directory)
4543 (tramp-compat-temporary-file-directory)
4544 default-directory)))
4545 (if (executable-find program)
4546 (apply 'call-process program infile destination display args)
4547 1)))
4548
00d6fd04
MA
4549(defun tramp-handle-call-process-region
4550 (start end program &optional delete buffer display &rest args)
4551 "Like `call-process-region' for Tramp files."
258800f8 4552 (let ((tmpfile (tramp-compat-make-temp-file "")))
00d6fd04
MA
4553 (write-region start end tmpfile)
4554 (when delete (delete-region start end))
4555 (unwind-protect
4556 (apply 'call-process program tmpfile buffer display args)
4557 (delete-file tmpfile))))
4558
4559(defun tramp-handle-shell-command
4560 (command &optional output-buffer error-buffer)
4561 "Like `shell-command' for Tramp files."
ce3f516f 4562 (let* ((asynchronous (string-match "[ \t]*&[ \t]*\\'" command))
b8bfcf96
MA
4563 ;; We cannot use `shell-file-name' and `shell-command-switch',
4564 ;; they are variables of the local host.
4565 (args (list "/bin/sh" "-c" (substring command 0 asynchronous)))
5d2ebd96 4566 current-buffer-p
ce3f516f 4567 (output-buffer
27e813fe
MA
4568 (cond
4569 ((bufferp output-buffer) output-buffer)
4570 ((stringp output-buffer) (get-buffer-create output-buffer))
5d2ebd96
AS
4571 (output-buffer
4572 (setq current-buffer-p t)
4573 (current-buffer))
42bc9b6d 4574 (t (get-buffer-create
27e813fe
MA
4575 (if asynchronous
4576 "*Async Shell Command*"
4577 "*Shell Command Output*")))))
4578 (error-buffer
4579 (cond
4580 ((bufferp error-buffer) error-buffer)
4581 ((stringp error-buffer) (get-buffer-create error-buffer))))
ce3f516f 4582 (buffer
27e813fe 4583 (if (and (not asynchronous) error-buffer)
ce3f516f
MA
4584 (with-parsed-tramp-file-name default-directory nil
4585 (list output-buffer (tramp-make-tramp-temp-file v)))
42bc9b6d 4586 output-buffer))
cfb5c0db 4587 (p (get-buffer-process output-buffer)))
42bc9b6d
MA
4588
4589 ;; Check whether there is another process running. Tramp does not
4590 ;; support 2 (asynchronous) processes in parallel.
cfb5c0db 4591 (when p
42bc9b6d 4592 (if (yes-or-no-p "A command is running. Kill it? ")
699a11fb
GM
4593 (condition-case nil
4594 (kill-process p)
4595 (error nil))
42bc9b6d
MA
4596 (error "Shell command in progress")))
4597
f34db316
AS
4598 (if current-buffer-p
4599 (progn
4600 (barf-if-buffer-read-only)
4601 (push-mark nil t))
5d2ebd96
AS
4602 (with-current-buffer output-buffer
4603 (setq buffer-read-only nil)
4604 (erase-buffer)))
42bc9b6d 4605
5d2ebd96 4606 (if (and (not current-buffer-p) (integerp asynchronous))
42bc9b6d
MA
4607 (prog1
4608 ;; Run the process.
3412f35d 4609 (apply 'start-file-process "*Async Shell*" buffer args)
42bc9b6d 4610 ;; Display output.
cfb5c0db
MA
4611 (pop-to-buffer output-buffer)
4612 (setq mode-line-process '(":%s"))
4613 (require 'shell) (shell-mode))
42bc9b6d
MA
4614
4615 (prog1
4616 ;; Run the process.
4617 (apply 'process-file (car args) nil buffer nil (cdr args))
4618 ;; Insert error messages if they were separated.
4619 (when (listp buffer)
4620 (with-current-buffer error-buffer
4621 (insert-file-contents (cadr buffer)))
4622 (delete-file (cadr buffer)))
f34db316
AS
4623 (if current-buffer-p
4624 ;; This is like exchange-point-and-mark, but doesn't
4625 ;; activate the mark. It is cleaner to avoid activation,
4626 ;; even though the command loop would deactivate the mark
4627 ;; because we inserted text.
4628 (goto-char (prog1 (mark t)
4629 (set-marker (mark-marker) (point)
4630 (current-buffer))))
4631 ;; There's some output, display it.
4632 (when (with-current-buffer output-buffer (> (point-max) (point-min)))
4633 (if (functionp 'display-message-or-buffer)
4634 (funcall (symbol-function 'display-message-or-buffer)
4635 output-buffer)
4636 (pop-to-buffer output-buffer))))))))
00d6fd04
MA
4637
4638;; File Editing.
4639
4640(defvar tramp-handle-file-local-copy-hook nil
4641 "Normal hook to be run at the end of `tramp-handle-file-local-copy'.")
4642
fb7933a3 4643(defun tramp-handle-file-local-copy (filename)
00d6fd04 4644 "Like `file-local-copy' for Tramp files."
0f205eee 4645
c62c9d08 4646 (with-parsed-tramp-file-name filename nil
2988341a
MA
4647 (unless (file-exists-p filename)
4648 (tramp-error
4649 v 'file-error
4650 "Cannot make local copy of non-existing file `%s'" filename))
4651
0f205eee 4652 (let ((rem-enc (tramp-get-remote-coding v "remote-encoding"))
00d6fd04 4653 (loc-dec (tramp-get-local-coding v "local-decoding"))
258800f8 4654 (tmpfile (tramp-compat-make-temp-file filename)))
5ec2cc41 4655
2988341a
MA
4656 (condition-case err
4657 (cond
4658 ;; `copy-file' handles direct copy and out-of-band methods.
4659 ((or (tramp-local-host-p v)
7f49fe46
MA
4660 (tramp-method-out-of-band-p
4661 v (nth 7 (file-attributes filename))))
2988341a
MA
4662 (copy-file filename tmpfile t t))
4663
4664 ;; Use inline encoding for file transfer.
4665 (rem-enc
4666 (save-excursion
4667 (tramp-message v 5 "Encoding remote file %s..." filename)
4668 (tramp-barf-unless-okay
4669 v
4670 (format "%s < %s" rem-enc (tramp-shell-quote-argument localname))
4671 "Encoding remote file failed")
4672 (tramp-message v 5 "Encoding remote file %s...done" filename)
4673
4674 (if (and (symbolp loc-dec) (fboundp loc-dec))
4675 ;; If local decoding is a function, we call it. We
4676 ;; must disable multibyte, because
4677 ;; `uudecode-decode-region' doesn't handle it
4678 ;; correctly.
0f205eee
MA
4679 (with-temp-buffer
4680 (set-buffer-multibyte nil)
4681 (insert-buffer-substring (tramp-get-buffer v))
4682 (tramp-message
4683 v 5 "Decoding remote file %s with function %s..."
4684 filename loc-dec)
4685 (funcall loc-dec (point-min) (point-max))
aa485f7c
MA
4686 ;; Unset `file-name-handler-alist'. Otherwise,
4687 ;; epa-file gets confused.
4688 (let (file-name-handler-alist
4689 (coding-system-for-write 'binary))
2988341a
MA
4690 (write-region (point-min) (point-max) tmpfile)))
4691
4692 ;; If tramp-decoding-function is not defined for this
4693 ;; method, we invoke tramp-decoding-command instead.
4694 (let ((tmpfile2 (tramp-compat-make-temp-file filename)))
aa485f7c
MA
4695 ;; Unset `file-name-handler-alist'. Otherwise,
4696 ;; epa-file gets confused.
4697 (let (file-name-handler-alist
4698 (coding-system-for-write 'binary))
2988341a
MA
4699 (write-region (point-min) (point-max) tmpfile2))
4700 (tramp-message
4701 v 5 "Decoding remote file %s with command %s..."
4702 filename loc-dec)
4703 (unwind-protect
4704 (tramp-call-local-coding-command loc-dec tmpfile2 tmpfile)
4705 (delete-file tmpfile2))))
4706
4707 (tramp-message v 5 "Decoding remote file %s...done" filename)
4708 ;; Set proper permissions.
b86c1cd8 4709 (set-file-modes tmpfile (tramp-default-file-modes filename))
2988341a
MA
4710 ;; Set local user ownership.
4711 (tramp-set-file-uid-gid tmpfile)))
4712
4713 ;; Oops, I don't know what to do.
4714 (t (tramp-error
4715 v 'file-error "Wrong method specification for `%s'" method)))
4716
4717 ;; Error handling.
4718 ((error quit)
4719 (delete-file tmpfile)
4720 (signal (car err) (cdr err))))
0f205eee 4721
00d6fd04 4722 (run-hooks 'tramp-handle-file-local-copy-hook)
94be87e8 4723 tmpfile)))
fb7933a3 4724
bce04fee 4725(defun tramp-handle-file-remote-p (filename &optional identification connected)
00d6fd04 4726 "Like `file-remote-p' for Tramp files."
d5b3979c
MA
4727 (let ((tramp-verbose 3))
4728 (when (tramp-tramp-file-p filename)
4729 (let* ((v (tramp-dissect-file-name filename))
4730 (p (tramp-get-connection-process v))
4731 (c (and p (processp p) (memq (process-status p) '(run open)))))
4732 ;; We expand the file name only, if there is already a connection.
4733 (with-parsed-tramp-file-name
4734 (if c (expand-file-name filename) filename) nil
4735 (and (or (not connected) c)
4736 (cond
4737 ((eq identification 'method) method)
4738 ((eq identification 'user) user)
4739 ((eq identification 'host) host)
4740 ((eq identification 'localname) localname)
4741 (t (tramp-make-tramp-file-name method user host "")))))))))
fb7933a3 4742
eb562962
MA
4743(defun tramp-find-file-name-coding-system-alist (filename tmpname)
4744 "Like `find-operation-coding-system' for Tramp filenames.
4745Tramp's `insert-file-contents' and `write-region' work over
4746temporary file names. If `file-coding-system-alist' contains an
4747expression, which matches more than the file name suffix, the
4748coding system might not be determined. This function repairs it."
4749 (let (result)
4750 (dolist (elt file-coding-system-alist result)
4751 (when (and (consp elt) (string-match (car elt) filename))
4752 ;; We found a matching entry in `file-coding-system-alist'.
4753 ;; So we add a similar entry, but with the temporary file name
4754 ;; as regexp.
4755 (add-to-list
4756 'result (cons (regexp-quote tmpname) (cdr elt)) 'append)))))
4757
fb7933a3
KG
4758(defun tramp-handle-insert-file-contents
4759 (filename &optional visit beg end replace)
00d6fd04 4760 "Like `insert-file-contents' for Tramp files."
fb7933a3
KG
4761 (barf-if-buffer-read-only)
4762 (setq filename (expand-file-name filename))
736ac90f 4763 (let (coding-system-used result local-copy remote-copy)
2ac33804
MA
4764 (with-parsed-tramp-file-name filename nil
4765 (unwind-protect
70c11b0b
MA
4766 (if (not (file-exists-p filename))
4767 ;; We don't raise a Tramp error, because it might be
4768 ;; suppressed, like in `find-file-noselect-1'.
4769 (signal 'file-error
4770 (list "File not found on remote host" filename))
4771
4772 (if (and (tramp-local-host-p v)
4773 (let (file-name-handler-alist)
4774 (file-readable-p localname)))
4775 ;; Short track: if we are on the local host, we can
4776 ;; run directly.
4777 (setq result
4778 (tramp-run-real-handler
4779 'insert-file-contents
4780 (list localname visit beg end replace)))
4781
736ac90f
MA
4782 ;; When we shall insert only a part of the file, we copy
4783 ;; this part.
4784 (when (or beg end)
4785 (setq remote-copy (tramp-make-tramp-temp-file v))
4786 (tramp-send-command
4787 v
4788 (cond
4789 ((and beg end)
4790 (format "tail -c +%d %s | head -c +%d >%s"
4791 (1+ beg) (tramp-shell-quote-argument localname)
4792 (- end beg) remote-copy))
4793 (beg
4794 (format "tail -c +%d %s >%s"
4795 (1+ beg) (tramp-shell-quote-argument localname)
4796 remote-copy))
4797 (end
4798 (format "head -c +%d %s >%s"
4799 (1+ end) (tramp-shell-quote-argument localname)
4800 remote-copy)))))
4801
70c11b0b
MA
4802 ;; `insert-file-contents-literally' takes care to avoid
4803 ;; calling jka-compr. By let-binding
4804 ;; `inhibit-file-name-operation', we propagate that care
4805 ;; to the `file-local-copy' operation.
4806 (setq local-copy
4807 (let ((inhibit-file-name-operation
4808 (when (eq inhibit-file-name-operation
4809 'insert-file-contents)
4810 'file-local-copy)))
b88f2d0a
MA
4811 (cond
4812 ((stringp remote-copy)
4813 (file-local-copy
4814 (tramp-make-tramp-file-name
4815 method user host remote-copy)))
4816 ((stringp tramp-temp-buffer-file-name)
4817 (copy-file filename tramp-temp-buffer-file-name 'ok)
4818 tramp-temp-buffer-file-name)
4819 (t (file-local-copy filename)))))
4820
6e4f5731
MA
4821 ;; When the file is not readable for the owner, it
4822 ;; cannot be inserted, even it is redable for the group
4823 ;; or for everybody.
4824 (set-file-modes local-copy (tramp-octal-to-decimal "0600"))
4825
b88f2d0a
MA
4826 (when (and (null remote-copy)
4827 (tramp-get-method-parameter
4828 method 'tramp-copy-keep-tmpfile))
4829 ;; We keep the local file for performance reasons,
4830 ;; useful for "rsync".
b88f2d0a
MA
4831 (setq tramp-temp-buffer-file-name local-copy)
4832 (put 'tramp-temp-buffer-file-name 'permanent-local t))
4833
70c11b0b
MA
4834 (tramp-message
4835 v 4 "Inserting local temp file `%s'..." local-copy)
4836
4837 ;; We must ensure that `file-coding-system-alist'
4838 ;; matches `local-copy'.
4839 (let ((file-coding-system-alist
4840 (tramp-find-file-name-coding-system-alist
4841 filename local-copy)))
4842 (setq result
4843 (insert-file-contents
736ac90f 4844 local-copy nil nil nil replace))
70c11b0b
MA
4845 ;; Now `last-coding-system-used' has right value.
4846 ;; Remember it.
4847 (when (boundp 'last-coding-system-used)
4848 (setq coding-system-used
4849 (symbol-value 'last-coding-system-used))))
8d60099b 4850
70c11b0b
MA
4851 (tramp-message
4852 v 4 "Inserting local temp file `%s'...done" local-copy)
4853 (when (boundp 'last-coding-system-used)
2ac33804 4854 (set 'last-coding-system-used coding-system-used))))
70c11b0b 4855
2ac33804
MA
4856 ;; Save exit.
4857 (progn
4858 (when visit
4859 (setq buffer-file-name filename)
4860 (setq buffer-read-only (not (file-writable-p filename)))
4861 (set-visited-file-modtime)
4862 (set-buffer-modified-p nil))
b88f2d0a
MA
4863 (when (and (stringp local-copy)
4864 (or remote-copy (null tramp-temp-buffer-file-name)))
2ac33804
MA
4865 (delete-file local-copy))
4866 (when (stringp remote-copy)
4867 (delete-file
4868 (tramp-make-tramp-file-name method user host remote-copy))))))
70c11b0b
MA
4869
4870 ;; Result.
4871 (list (expand-file-name filename)
4872 (cadr result))))
fb7933a3 4873
94be87e8
MA
4874;; This is needed for XEmacs only. Code stolen from files.el.
4875(defun tramp-handle-insert-file-contents-literally
4876 (filename &optional visit beg end replace)
4877 "Like `insert-file-contents-literally' for Tramp files."
4878 (let ((format-alist nil)
4879 (after-insert-file-functions nil)
4880 (coding-system-for-read 'no-conversion)
4881 (coding-system-for-write 'no-conversion)
4882 (find-buffer-file-type-function
4883 (if (fboundp 'find-buffer-file-type)
4884 (symbol-function 'find-buffer-file-type)
4885 nil))
4886 (inhibit-file-name-handlers '(jka-compr-handler image-file-handler))
4887 (inhibit-file-name-operation 'insert-file-contents))
4888 (unwind-protect
4889 (progn
4890 (fset 'find-buffer-file-type (lambda (filename) t))
4891 (insert-file-contents filename visit beg end replace))
70c11b0b 4892 ;; Save exit.
94be87e8
MA
4893 (if find-buffer-file-type-function
4894 (fset 'find-buffer-file-type find-buffer-file-type-function)
4895 (fmakunbound 'find-buffer-file-type)))))
4896
38c65fca 4897(defun tramp-handle-find-backup-file-name (filename)
00d6fd04 4898 "Like `find-backup-file-name' for Tramp files."
07dfe738
KG
4899 (with-parsed-tramp-file-name filename nil
4900 ;; We set both variables. It doesn't matter whether it is
b533bc97 4901 ;; Emacs or XEmacs.
07dfe738 4902 (let ((backup-directory-alist
b533bc97 4903 ;; Emacs case.
07dfe738 4904 (when (boundp 'backup-directory-alist)
b86c1cd8 4905 (if (symbol-value 'tramp-backup-directory-alist)
07dfe738 4906 (mapcar
aa485f7c
MA
4907 (lambda (x)
4908 (cons
4909 (car x)
4910 (if (and (stringp (cdr x))
4911 (file-name-absolute-p (cdr x))
4912 (not (tramp-file-name-p (cdr x))))
4913 (tramp-make-tramp-file-name method user host (cdr x))
4914 (cdr x))))
07dfe738
KG
4915 (symbol-value 'tramp-backup-directory-alist))
4916 (symbol-value 'backup-directory-alist))))
4917
4918 (bkup-backup-directory-info
b533bc97 4919 ;; XEmacs case.
07dfe738 4920 (when (boundp 'bkup-backup-directory-info)
b86c1cd8 4921 (if (symbol-value 'tramp-bkup-backup-directory-info)
07dfe738 4922 (mapcar
aa485f7c
MA
4923 (lambda (x)
4924 (nconc
4925 (list (car x))
4926 (list
4927 (if (and (stringp (car (cdr x)))
4928 (file-name-absolute-p (car (cdr x)))
4929 (not (tramp-file-name-p (car (cdr x)))))
4930 (tramp-make-tramp-file-name
4931 method user host (car (cdr x)))
4932 (car (cdr x))))
4933 (cdr (cdr x))))
07dfe738
KG
4934 (symbol-value 'tramp-bkup-backup-directory-info))
4935 (symbol-value 'bkup-backup-directory-info)))))
4936
4937 (tramp-run-real-handler 'find-backup-file-name (list filename)))))
38c65fca 4938
c1105d05 4939(defun tramp-handle-make-auto-save-file-name ()
00d6fd04 4940 "Like `make-auto-save-file-name' for Tramp files.
c1105d05 4941Returns a file name in `tramp-auto-save-directory' for autosaving this file."
00d6fd04
MA
4942 (let ((tramp-auto-save-directory tramp-auto-save-directory)
4943 (buffer-file-name
4944 (tramp-subst-strs-in-string
4945 '(("_" . "|")
4946 ("/" . "_a")
4947 (":" . "_b")
4948 ("|" . "__")
4949 ("[" . "_l")
4950 ("]" . "_r"))
4951 (buffer-file-name))))
1a762140
MA
4952 ;; File name must be unique. This is ensured with Emacs 22 (see
4953 ;; UNIQUIFY element of `auto-save-file-name-transforms'); but for
4954 ;; all other cases we must do it ourselves.
4955 (when (boundp 'auto-save-file-name-transforms)
9e6ab520 4956 (mapc
aa485f7c
MA
4957 (lambda (x)
4958 (when (and (string-match (car x) buffer-file-name)
4959 (not (car (cddr x))))
4960 (setq tramp-auto-save-directory
4961 (or tramp-auto-save-directory
4962 (tramp-compat-temporary-file-directory)))))
1a762140
MA
4963 (symbol-value 'auto-save-file-name-transforms)))
4964 ;; Create directory.
4965 (when tramp-auto-save-directory
00d6fd04
MA
4966 (setq buffer-file-name
4967 (expand-file-name buffer-file-name tramp-auto-save-directory))
1a762140
MA
4968 (unless (file-exists-p tramp-auto-save-directory)
4969 (make-directory tramp-auto-save-directory t)))
00d6fd04
MA
4970 ;; Run plain `make-auto-save-file-name'. There might be an advice when
4971 ;; it is not a magic file name operation (since Emacs 22).
4972 ;; We must deactivate it temporarily.
4973 (if (not (ad-is-active 'make-auto-save-file-name))
4974 (tramp-run-real-handler 'make-auto-save-file-name nil)
4975 ;; else
4976 (ad-deactivate 'make-auto-save-file-name)
4977 (prog1
4978 (tramp-run-real-handler 'make-auto-save-file-name nil)
4979 (ad-activate 'make-auto-save-file-name)))))
4980
4981(defvar tramp-handle-write-region-hook nil
4982 "Normal hook to be run at the end of `tramp-handle-write-region'.")
4983
b88f2d0a 4984;; CCC grok LOCKNAME
fb7933a3
KG
4985(defun tramp-handle-write-region
4986 (start end filename &optional append visit lockname confirm)
00d6fd04 4987 "Like `write-region' for Tramp files."
fb7933a3 4988 (setq filename (expand-file-name filename))
c62c9d08 4989 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
4990 ;; Following part commented out because we don't know what to do about
4991 ;; file locking, and it does not appear to be a problem to ignore it.
4992 ;; Ange-ftp ignores it, too.
4993 ;; (when (and lockname (stringp lockname))
4994 ;; (setq lockname (expand-file-name lockname)))
4995 ;; (unless (or (eq lockname nil)
4996 ;; (string= lockname filename))
4997 ;; (error
4998 ;; "tramp-handle-write-region: LOCKNAME must be nil or equal FILENAME"))
8d60099b 4999
94be87e8 5000 ;; XEmacs takes a coding system as the seventh argument, not `confirm'.
00d6fd04
MA
5001 (when (and (not (featurep 'xemacs)) confirm (file-exists-p filename))
5002 (unless (y-or-n-p (format "File %s exists; overwrite anyway? " filename))
5003 (tramp-error v 'file-error "File not overwritten")))
8d60099b 5004
a4aeb9a4 5005 (let ((uid (or (nth 2 (tramp-compat-file-attributes filename 'integer))
9c13938d 5006 (tramp-get-remote-uid v 'integer)))
a4aeb9a4 5007 (gid (or (nth 3 (tramp-compat-file-attributes filename 'integer))
9c13938d
MA
5008 (tramp-get-remote-gid v 'integer))))
5009
5010 (if (and (tramp-local-host-p v)
93c3eb7c 5011 ;; `file-writable-p' calls `file-expand-file-name'. We
87bdd2c7
MA
5012 ;; cannot use `tramp-run-real-handler' therefore.
5013 (let (file-name-handler-alist)
82f3844e
MA
5014 (and
5015 (file-writable-p (file-name-directory localname))
5016 (or (file-directory-p localname)
5017 (file-writable-p localname)))))
9c13938d 5018 ;; Short track: if we are on the local host, we can run directly.
aac0b0f2
MA
5019 (tramp-run-real-handler
5020 'write-region
5021 (list start end localname append 'no-message lockname confirm))
9c13938d
MA
5022
5023 (let ((rem-dec (tramp-get-remote-coding v "remote-decoding"))
5024 (loc-enc (tramp-get-local-coding v "local-encoding"))
b86c1cd8 5025 (modes (save-excursion (tramp-default-file-modes filename)))
9c13938d
MA
5026 ;; We use this to save the value of
5027 ;; `last-coding-system-used' after writing the tmp file.
5028 ;; At the end of the function, we set
5029 ;; `last-coding-system-used' to this saved value. This
5030 ;; way, any intermediary coding systems used while
5031 ;; talking to the remote shell or suchlike won't hose
5032 ;; this variable. This approach was snarfed from
5033 ;; ange-ftp.el.
5034 coding-system-used
5035 ;; Write region into a tmp file. This isn't really
5036 ;; needed if we use an encoding function, but currently
5037 ;; we use it always because this makes the logic
293c24f9
MA
5038 ;; simpler.
5039 (tmpfile (or tramp-temp-buffer-file-name
5040 (tramp-compat-make-temp-file filename))))
5041
5042 ;; If `append' is non-nil, we copy the file locally, and let
5043 ;; the native `write-region' implementation do the job.
5044 (when append (copy-file filename tmpfile 'ok))
9c13938d
MA
5045
5046 ;; We say `no-message' here because we don't want the
5047 ;; visited file modtime data to be clobbered from the temp
5048 ;; file. We call `set-visited-file-modtime' ourselves later
eb562962
MA
5049 ;; on. We must ensure that `file-coding-system-alist'
5050 ;; matches `tmpfile'.
5051 (let ((file-coding-system-alist
5052 (tramp-find-file-name-coding-system-alist filename tmpfile)))
ce2cc728
MA
5053 (condition-case err
5054 (tramp-run-real-handler
5055 'write-region
5056 (list start end tmpfile append 'no-message lockname confirm))
2988341a 5057 ((error quit)
b88f2d0a 5058 (setq tramp-temp-buffer-file-name nil)
2988341a
MA
5059 (delete-file tmpfile)
5060 (signal (car err) (cdr err))))
ce2cc728 5061
eb562962
MA
5062 ;; Now, `last-coding-system-used' has the right value. Remember it.
5063 (when (boundp 'last-coding-system-used)
5064 (setq coding-system-used
5065 (symbol-value 'last-coding-system-used))))
5066
9c13938d
MA
5067 ;; The permissions of the temporary file should be set. If
5068 ;; filename does not exist (eq modes nil) it has been
5069 ;; renamed to the backup file. This case `save-buffer'
5070 ;; handles permissions.
459a5f4b
MA
5071 ;; Ensure, that it is still readable.
5072 (when modes
5073 (set-file-modes
5074 tmpfile (logior (or modes 0) (tramp-octal-to-decimal "0400"))))
9c13938d
MA
5075
5076 ;; This is a bit lengthy due to the different methods
5077 ;; possible for file transfer. First, we check whether the
5078 ;; method uses an rcp program. If so, we call it.
5079 ;; Otherwise, both encoding and decoding command must be
5080 ;; specified. However, if the method _also_ specifies an
5081 ;; encoding function, then that is used for encoding the
5082 ;; contents of the tmp file.
5083 (cond
00cffdeb 5084 ;; `copy-file' handles direct copy and out-of-band methods.
9c13938d 5085 ((or (tramp-local-host-p v)
7f49fe46 5086 (tramp-method-out-of-band-p
00cffdeb
MA
5087 v (nth 7 (file-attributes tmpfile))))
5088 (if (and (not (stringp start))
5089 (= (or end (point-max)) (point-max))
191bb792
MA
5090 (= (or start (point-min)) (point-min))
5091 (tramp-get-method-parameter
5092 method 'tramp-copy-keep-tmpfile))
5093 (progn
5094 (setq tramp-temp-buffer-file-name tmpfile)
5095 (condition-case err
b88f2d0a
MA
5096 ;; We keep the local file for performance
5097 ;; reasons, useful for "rsync".
191bb792
MA
5098 (copy-file tmpfile filename t)
5099 ((error quit)
5100 (setq tramp-temp-buffer-file-name nil)
5101 (delete-file tmpfile)
5102 (signal (car err) (cdr err)))))
5103 (setq tramp-temp-buffer-file-name nil)
5104 ;; Don't rename, in order to keep context in SELinux.
5105 (unwind-protect
5106 (copy-file tmpfile filename t)
5107 (delete-file tmpfile))))
9c13938d 5108
1d7e9a01 5109 ;; Use inline file transfer.
9c13938d 5110 (rem-dec
1d7e9a01 5111 ;; Encode tmpfile.
9c13938d
MA
5112 (tramp-message v 5 "Encoding region...")
5113 (unwind-protect
5114 (with-temp-buffer
5115 ;; Use encoding function or command.
5116 (if (and (symbolp loc-enc) (fboundp loc-enc))
5117 (progn
5118 (tramp-message
5119 v 5 "Encoding region using function `%s'..."
5120 (symbol-name loc-enc))
5121 (let ((coding-system-for-read 'binary))
5122 (insert-file-contents-literally tmpfile))
70c11b0b
MA
5123 ;; The following `let' is a workaround for the
5124 ;; base64.el that comes with pgnus-0.84. If
5125 ;; both of the following conditions are
5126 ;; satisfied, it tries to write to a local
5127 ;; file in default-directory, but at this
5128 ;; point, default-directory is remote.
5129 ;; (`call-process-region' can't write to
5130 ;; remote files, it seems.) The file in
5131 ;; question is a tmp file anyway.
9c13938d
MA
5132 (let ((default-directory
5133 (tramp-compat-temporary-file-directory)))
5134 (funcall loc-enc (point-min) (point-max))))
8d60099b 5135
9c13938d
MA
5136 (tramp-message
5137 v 5 "Encoding region using command `%s'..." loc-enc)
5138 (unless (equal 0 (tramp-call-local-coding-command
5139 loc-enc tmpfile t))
5140 (tramp-error
5141 v 'file-error
5142 "Cannot write to `%s', local encoding command `%s' failed"
5143 filename loc-enc)))
5144
5145 ;; Send buffer into remote decoding command which
5146 ;; writes to remote file. Because this happens on
5147 ;; the remote host, we cannot use the function.
5148 (goto-char (point-max))
5149 (unless (bolp) (newline))
8d60099b 5150 (tramp-message
9c13938d
MA
5151 v 5 "Decoding region into remote file %s..." filename)
5152 (tramp-send-command
5153 v
5154 (format
5155 "%s >%s <<'EOF'\n%sEOF"
5156 rem-dec
5157 (tramp-shell-quote-argument localname)
5158 (buffer-string)))
5159 (tramp-barf-unless-okay
5160 v nil
5161 "Couldn't write region to `%s', decode using `%s' failed"
5162 filename rem-dec)
5163 ;; When `file-precious-flag' is set, the region is
5164 ;; written to a temporary file. Check that the
5165 ;; checksum is equal to that from the local tmpfile.
5166 (when file-precious-flag
5167 (erase-buffer)
5168 (and
a4aeb9a4
MA
5169 ;; cksum runs locally, if possible.
5170 (zerop (tramp-local-call-process "cksum" tmpfile t))
5171 ;; cksum runs remotely.
9c13938d
MA
5172 (zerop
5173 (tramp-send-command-and-check
5174 v
5175 (format
5176 "cksum <%s" (tramp-shell-quote-argument localname))))
a4aeb9a4 5177 ;; ... they are different.
9c13938d
MA
5178 (not
5179 (string-equal
5180 (buffer-string)
5181 (with-current-buffer (tramp-get-buffer v)
5182 (buffer-string))))
5183 (tramp-error
5184 v 'file-error
5185 (concat "Couldn't write region to `%s',"
5186 " decode using `%s' failed")
5187 filename rem-dec)))
5188 (tramp-message
aac0b0f2 5189 v 5 "Decoding region into remote file %s...done" filename))
8d60099b 5190
9c13938d
MA
5191 ;; Save exit.
5192 (delete-file tmpfile)))
8d60099b 5193
9c13938d
MA
5194 ;; That's not expected.
5195 (t
5196 (tramp-error
5197 v 'file-error
5198 (concat "Method `%s' should specify both encoding and "
5199 "decoding command or an rcp program")
5200 method)))
258800f8 5201
9c13938d
MA
5202 ;; Make `last-coding-system-used' have the right value.
5203 (when coding-system-used
5204 (set 'last-coding-system-used coding-system-used))))
0f205eee 5205
aac0b0f2
MA
5206 (tramp-flush-file-property v (file-name-directory localname))
5207 (tramp-flush-file-property v localname)
5208
57671b72
MA
5209 ;; We must protect `last-coding-system-used', now we have set it
5210 ;; to its correct value.
293c24f9 5211 (let (last-coding-system-used (need-chown t))
57671b72
MA
5212 ;; Set file modification time.
5213 (when (or (eq visit t) (stringp visit))
293c24f9
MA
5214 (let ((file-attr (file-attributes filename)))
5215 (set-visited-file-modtime
5216 ;; We must pass modtime explicitely, because filename can
5217 ;; be different from (buffer-file-name), f.e. if
5218 ;; `file-precious-flag' is set.
5219 (nth 5 file-attr))
5220 (when (and (eq (nth 2 file-attr) uid)
5221 (eq (nth 3 file-attr) gid))
5222 (setq need-chown nil))))
57671b72
MA
5223
5224 ;; Set the ownership.
293c24f9
MA
5225 (when need-chown
5226 (tramp-set-file-uid-gid filename uid gid))
57671b72
MA
5227 (when (or (eq visit t) (null visit) (stringp visit))
5228 (tramp-message v 0 "Wrote %s" filename))
5229 (run-hooks 'tramp-handle-write-region-hook)))))
fb7933a3 5230
946a5aeb
MA
5231(defvar tramp-vc-registered-file-names nil
5232 "List used to collect file names, which are checked during `vc-registered'.")
5233
5234;; VC backends check for the existence of various different special
5235;; files. This is very time consuming, because every single check
5236;; requires a remote command (the file cache must be invalidated).
5237;; Therefore, we apply a kind of optimization. We install the file
5238;; name handler `tramp-vc-file-name-handler', which does nothing but
5239;; remembers all file names for which `file-exists-p' or
5240;; `file-readable-p' has been applied. A first run of `vc-registered'
5241;; is performed. Afterwards, a script is applied for all collected
5242;; file names, using just one remote command. The result of this
5243;; script is used to fill the file cache with actual values. Now we
5244;; can reset the file name handlers, and we make a second run of
5245;; `vc-registered', which returns the expected result without sending
5246;; any other remote command.
49096407
MA
5247(defun tramp-handle-vc-registered (file)
5248 "Like `vc-registered' for Tramp files."
946a5aeb 5249 (with-parsed-tramp-file-name file nil
7f49fe46
MA
5250
5251 ;; There could be new files, created by the vc backend. We cannot
5252 ;; reuse the old cache entries, therefore.
946a5aeb
MA
5253 (let (tramp-vc-registered-file-names
5254 (tramp-cache-inhibit-cache (current-time))
5255 (file-name-handler-alist
5256 `((,tramp-file-name-regexp . tramp-vc-file-name-handler))))
5257
5258 ;; Here we collect only file names, which need an operation.
5259 (tramp-run-real-handler 'vc-registered (list file))
5260 (tramp-message v 10 "\n%s" tramp-vc-registered-file-names)
5261
5262 ;; Send just one command, in order to fill the cache.
7f49fe46
MA
5263 (when tramp-vc-registered-file-names
5264 (tramp-maybe-send-script
5265 v
5266 (format tramp-vc-registered-read-file-names
5267 (tramp-get-file-exists-command v)
5268 (format "%s -r" (tramp-get-test-command v)))
5269 "tramp_vc_registered_read_file_names")
5270
5271 (dolist
5272 (elt
5273 (tramp-send-command-and-read
5274 v
5275 (format
5276 "tramp_vc_registered_read_file_names %s"
5277 (mapconcat 'tramp-shell-quote-argument
5278 tramp-vc-registered-file-names
5279 " "))))
946a5aeb 5280
7f49fe46 5281 (tramp-set-file-property v (car elt) (cadr elt) (cadr (cdr elt))))))
946a5aeb 5282
7f49fe46
MA
5283 ;; Second run. Now all `file-exists-p' or `file-readable-p' calls
5284 ;; shall be answered from the file cache.
5285 ;; We unset `process-file-side-effects' in order to keep the cache
5286 ;; when `process-file' calls appear.
946a5aeb
MA
5287 (let (process-file-side-effects)
5288 (tramp-run-real-handler 'vc-registered (list file)))))
49096407 5289
a01b1e22
MA
5290;;;###autoload
5291(progn (defun tramp-run-real-handler (operation args)
fb7933a3 5292 "Invoke normal file name handler for OPERATION.
c62c9d08
KG
5293First arg specifies the OPERATION, second arg is a list of arguments to
5294pass to the OPERATION."
4007ba5b
KG
5295 (let* ((inhibit-file-name-handlers
5296 `(tramp-file-name-handler
946a5aeb 5297 tramp-vc-file-name-handler
4007ba5b
KG
5298 tramp-completion-file-name-handler
5299 cygwin-mount-name-hook-function
5300 cygwin-mount-map-drive-hook-function
5301 .
5302 ,(and (eq inhibit-file-name-operation operation)
5303 inhibit-file-name-handlers)))
5304 (inhibit-file-name-operation operation))
a01b1e22 5305 (apply operation args))))
16674e4f 5306
a01b1e22
MA
5307;;;###autoload
5308(progn (defun tramp-completion-run-real-handler (operation args)
16674e4f
KG
5309 "Invoke `tramp-file-name-handler' for OPERATION.
5310First arg specifies the OPERATION, second arg is a list of arguments to
5311pass to the OPERATION."
4007ba5b
KG
5312 (let* ((inhibit-file-name-handlers
5313 `(tramp-completion-file-name-handler
5314 cygwin-mount-name-hook-function
5315 cygwin-mount-map-drive-hook-function
5316 .
5317 ,(and (eq inhibit-file-name-operation operation)
5318 inhibit-file-name-handlers)))
5319 (inhibit-file-name-operation operation))
a01b1e22 5320 (apply operation args))))
fb7933a3 5321
4007ba5b
KG
5322;; We handle here all file primitives. Most of them have the file
5323;; name as first parameter; nevertheless we check for them explicitly
04bf5b65 5324;; in order to be signaled if a new primitive appears. This
4007ba5b
KG
5325;; scenario is needed because there isn't a way to decide by
5326;; syntactical means whether a foreign method must be called. It would
19a87064 5327;; ease the life if `file-name-handler-alist' would support a decision
4007ba5b
KG
5328;; function as well but regexp only.
5329(defun tramp-file-name-for-operation (operation &rest args)
5330 "Return file name related to OPERATION file primitive.
5331ARGS are the arguments OPERATION has been called with."
5332 (cond
b533bc97 5333 ;; FILE resp DIRECTORY.
4007ba5b
KG
5334 ((member operation
5335 (list 'access-file 'byte-compiler-base-file-name 'delete-directory
5336 'delete-file 'diff-latest-backup-file 'directory-file-name
5337 'directory-files 'directory-files-and-attributes
5338 'dired-compress-file 'dired-uncache
5339 'file-accessible-directory-p 'file-attributes
5340 'file-directory-p 'file-executable-p 'file-exists-p
25f14cdb 5341 'file-local-copy 'file-remote-p 'file-modes
19a87064
MA
5342 'file-name-as-directory 'file-name-directory
5343 'file-name-nondirectory 'file-name-sans-versions
5344 'file-ownership-preserved-p 'file-readable-p
5345 'file-regular-p 'file-symlink-p 'file-truename
5346 'file-writable-p 'find-backup-file-name 'find-file-noselect
5347 'get-file-buffer 'insert-directory 'insert-file-contents
5348 'load 'make-directory 'make-directory-internal
5349 'set-file-modes 'substitute-in-file-name
5350 'unhandled-file-name-directory 'vc-registered
b533bc97 5351 ;; Emacs 22+ only.
ce3f516f 5352 'set-file-times
25f14cdb
MA
5353 ;; Emacs 24+ only.
5354 'file-selinux-context 'set-file-selinux-context
b533bc97 5355 ;; XEmacs only.
4007ba5b
KG
5356 'abbreviate-file-name 'create-file-buffer
5357 'dired-file-modtime 'dired-make-compressed-filename
5358 'dired-recursive-delete-directory 'dired-set-file-modtime
5359 'dired-shell-unhandle-file-name 'dired-uucode-file
5615d63f 5360 'insert-file-contents-literally 'make-temp-name 'recover-file
4007ba5b 5361 'vm-imap-check-mail 'vm-pop-check-mail 'vm-spool-check-mail))
8daea7fc
KG
5362 (if (file-name-absolute-p (nth 0 args))
5363 (nth 0 args)
5364 (expand-file-name (nth 0 args))))
b533bc97 5365 ;; FILE DIRECTORY resp FILE1 FILE2.
4007ba5b
KG
5366 ((member operation
5367 (list 'add-name-to-file 'copy-file 'expand-file-name
5368 'file-name-all-completions 'file-name-completion
5369 'file-newer-than-file-p 'make-symbolic-link 'rename-file
b533bc97 5370 ;; Emacs 23+ only.
263c02ef 5371 'copy-directory
b533bc97 5372 ;; XEmacs only.
4007ba5b
KG
5373 'dired-make-relative-symlink
5374 'vm-imap-move-mail 'vm-pop-move-mail 'vm-spool-move-mail))
5375 (save-match-data
5376 (cond
5377 ((string-match tramp-file-name-regexp (nth 0 args)) (nth 0 args))
5378 ((string-match tramp-file-name-regexp (nth 1 args)) (nth 1 args))
5379 (t (buffer-file-name (current-buffer))))))
b533bc97 5380 ;; START END FILE.
4007ba5b
KG
5381 ((eq operation 'write-region)
5382 (nth 2 args))
b533bc97 5383 ;; BUFFER.
4007ba5b 5384 ((member operation
00d6fd04 5385 (list 'set-visited-file-modtime 'verify-visited-file-modtime
b533bc97 5386 ;; Emacs 22+ only.
00d6fd04 5387 'make-auto-save-file-name
b533bc97 5388 ;; XEmacs only.
4007ba5b
KG
5389 'backup-buffer))
5390 (buffer-file-name
5391 (if (bufferp (nth 0 args)) (nth 0 args) (current-buffer))))
b533bc97 5392 ;; COMMAND.
4007ba5b 5393 ((member operation
b533bc97 5394 (list ;; not in Emacs 23+.
00d6fd04 5395 'dired-call-process
b533bc97 5396 ;; Emacs only.
b71c9e75 5397 'shell-command
b533bc97 5398 ;; Emacs 22+ only.
0457dd55 5399 'process-file
b533bc97 5400 ;; Emacs 23+ only.
00d6fd04 5401 'start-file-process
b533bc97 5402 ;; XEmacs only.
00d6fd04 5403 'dired-print-file 'dired-shell-call-process
b533bc97 5404 ;; nowhere yet.
00d6fd04 5405 'executable-find 'start-process 'call-process))
4007ba5b 5406 default-directory)
b533bc97 5407 ;; Unknown file primitive.
4007ba5b
KG
5408 (t (error "unknown file I/O primitive: %s" operation))))
5409
5410(defun tramp-find-foreign-file-name-handler (filename)
5411 "Return foreign file name handler if exists."
b533bc97 5412 (when (tramp-tramp-file-p filename)
9ce8462a
MA
5413 (let ((v (tramp-dissect-file-name filename t))
5414 (handler tramp-foreign-file-name-handler-alist)
5415 elt res)
5416 ;; When we are not fully sure that filename completion is safe,
5417 ;; we should not return a handler.
5418 (when (or (tramp-file-name-method v) (tramp-file-name-user v)
1834b39f
MA
5419 (and (tramp-file-name-host v)
5420 (not (member (tramp-file-name-host v)
5421 (mapcar 'car tramp-methods))))
9ce8462a
MA
5422 (not (tramp-completion-mode-p)))
5423 (while handler
5424 (setq elt (car handler)
5425 handler (cdr handler))
5426 (when (funcall (car elt) filename)
5427 (setq handler nil
5428 res (cdr elt))))
5429 res))))
4007ba5b 5430
fb7933a3
KG
5431;; Main function.
5432;;;###autoload
5433(defun tramp-file-name-handler (operation &rest args)
ea9d1443 5434 "Invoke Tramp file name handler.
a4aeb9a4 5435Falls back to normal file name handler if no Tramp file name handler exists."
2e271195
MA
5436 (if tramp-mode
5437 (save-match-data
5438 (let* ((filename
5439 (tramp-replace-environment-variables
5440 (apply 'tramp-file-name-for-operation operation args)))
5441 (completion (tramp-completion-mode-p))
5442 (foreign (tramp-find-foreign-file-name-handler filename)))
5443 (with-parsed-tramp-file-name filename nil
4874f5e6
MA
5444 ;; Call the backend function.
5445 (if foreign
5446 (condition-case err
5447 (apply foreign operation args)
5448 (error
5449 (cond
5450 ;; When we are in completion mode, some failed
5451 ;; operations shall return at least a default
5452 ;; value in order to give the user a chance to
5453 ;; correct the file name in the minibuffer.
5454 ((and completion (zerop (length localname))
5455 (memq operation '(file-exists-p file-directory-p)))
5456 t)
5457 ((and completion (zerop (length localname))
5458 (memq operation
5459 '(expand-file-name file-name-as-directory)))
5460 filename)
5461 ;; Propagate the error.
5462 (t (signal (car err) (cdr err))))))
5463 ;; Nothing to do for us.
5464 (tramp-run-real-handler operation args)))))
5465
2e271195
MA
5466 ;; When `tramp-mode' is not enabled, we don't do anything.
5467 (tramp-run-real-handler operation args)))
fb7933a3 5468
07dfe738
KG
5469;; In Emacs, there is some concurrency due to timers. If a timer
5470;; interrupts Tramp and wishes to use the same connection buffer as
5471;; the "main" Emacs, then garbage might occur in the connection
5472;; buffer. Therefore, we need to make sure that a timer does not use
5473;; the same connection buffer as the "main" Emacs. We implement a
5474;; cheap global lock, instead of locking each connection buffer
5475;; separately. The global lock is based on two variables,
5476;; `tramp-locked' and `tramp-locker'. `tramp-locked' is set to true
5477;; (with setq) to indicate a lock. But Tramp also calls itself during
5478;; processing of a single file operation, so we need to allow
5479;; recursive calls. That's where the `tramp-locker' variable comes in
5480;; -- it is let-bound to t during the execution of the current
5481;; handler. So if `tramp-locked' is t and `tramp-locker' is also t,
5482;; then we should just proceed because we have been called
5483;; recursively. But if `tramp-locker' is nil, then we are a timer
5484;; interrupting the "main" Emacs, and then we signal an error.
5485
5486(defvar tramp-locked nil
5487 "If non-nil, then Tramp is currently busy.
5488Together with `tramp-locker', this implements a locking mechanism
5489preventing reentrant calls of Tramp.")
5490
5491(defvar tramp-locker nil
5492 "If non-nil, then a caller has locked Tramp.
5493Together with `tramp-locked', this implements a locking mechanism
5494preventing reentrant calls of Tramp.")
5495
ea9d1443
KG
5496(defun tramp-sh-file-name-handler (operation &rest args)
5497 "Invoke remote-shell Tramp file name handler.
5498Fall back to normal file name handler if no Tramp handler exists."
07dfe738 5499 (when (and tramp-locked (not tramp-locker))
11c71217 5500 (setq tramp-locked nil)
00d6fd04 5501 (signal 'file-error (list "Forbidden reentrant call of Tramp")))
07dfe738
KG
5502 (let ((tl tramp-locked))
5503 (unwind-protect
5504 (progn
5505 (setq tramp-locked t)
5506 (let ((tramp-locker t))
5507 (save-match-data
5508 (let ((fn (assoc operation tramp-file-name-handler-alist)))
5509 (if fn
5510 (apply (cdr fn) args)
5511 (tramp-run-real-handler operation args))))))
5512 (setq tramp-locked tl))))
ea9d1443 5513
946a5aeb
MA
5514(defun tramp-vc-file-name-handler (operation &rest args)
5515 "Invoke special file name handler, which collects files to be handled."
5516 (save-match-data
5517 (let ((filename
5518 (tramp-replace-environment-variables
5519 (apply 'tramp-file-name-for-operation operation args)))
5520 (fn (assoc operation tramp-file-name-handler-alist)))
5521 (with-parsed-tramp-file-name filename nil
5522 (cond
5523 ;; That's what we want: file names, for which checks are
5524 ;; applied. We assume, that VC uses only `file-exists-p' and
5525 ;; `file-readable-p' checks; otherwise we must extend the
5526 ;; list. We do not perform any action, but return nil, in
5527 ;; order to keep `vc-registered' running.
5528 ((and fn (memq operation '(file-exists-p file-readable-p)))
5529 (add-to-list 'tramp-vc-registered-file-names localname 'append)
5530 nil)
5531 ;; Tramp file name handlers like `expand-file-name'. They
5532 ;; must still work.
5533 (fn
5534 (save-match-data (apply (cdr fn) args)))
5535 ;; Default file name handlers, we don't care.
5536 (t (tramp-run-real-handler operation args)))))))
5537
16674e4f 5538;;;###autoload
1ecc6145 5539(progn (defun tramp-completion-file-name-handler (operation &rest args)
a4aeb9a4
MA
5540 "Invoke Tramp file name completion handler.
5541Falls back to normal file name handler if no Tramp file name handler exists."
57671b72
MA
5542 ;; We bind `directory-sep-char' here for XEmacs on Windows, which
5543 ;; would otherwise use backslash.
aff67808
MA
5544 (let ((directory-sep-char ?/)
5545 (fn (assoc operation tramp-completion-file-name-handler-alist)))
aa485f7c
MA
5546 (if (and
5547 ;; When `tramp-mode' is not enabled, we don't do anything.
5548 fn tramp-mode
5549 ;; For other syntaxes than `sep', the regexp matches many common
5550 ;; situations where the user doesn't actually want to use Tramp.
5551 ;; So to avoid autoloading Tramp after typing just "/s", we
5552 ;; disable this part of the completion, unless the user implicitly
5553 ;; indicated his interest in using a fancier completion system.
5554 (or (eq tramp-syntax 'sep)
5f2b693f
MA
5555 (featurep 'tramp) ;; If it's loaded, we may as well use
5556 ;; it. `partial-completion-mode' does not exist in
5557 ;; XEmacs. It is obsoleted with Emacs 24.1.
aa485f7c
MA
5558 (and (boundp 'partial-completion-mode) partial-completion-mode)
5559 ;; FIXME: These may have been loaded even if the user never
5560 ;; intended to use them.
5561 (featurep 'ido)
5562 (featurep 'icicles)))
aff67808
MA
5563 (save-match-data (apply (cdr fn) args))
5564 (tramp-completion-run-real-handler operation args)))))
a01b1e22 5565
b25a52cc 5566;;;###autoload
aa485f7c
MA
5567(progn (defun tramp-register-file-name-handlers ()
5568 "Add Tramp file name handlers to `file-name-handler-alist'."
5569 ;; Remove autoloaded handlers from file name handler alist. Useful,
00d6fd04
MA
5570 ;; if `tramp-syntax' has been changed.
5571 (let ((a1 (rassq 'tramp-file-name-handler file-name-handler-alist)))
aa485f7c
MA
5572 (setq file-name-handler-alist (delq a1 file-name-handler-alist)))
5573 (let ((a1 (rassq
5574 'tramp-completion-file-name-handler file-name-handler-alist)))
5575 (setq file-name-handler-alist (delq a1 file-name-handler-alist)))
5576 ;; Add the handlers.
a01b1e22
MA
5577 (add-to-list 'file-name-handler-alist
5578 (cons tramp-file-name-regexp 'tramp-file-name-handler))
0c0b61f1 5579 (put 'tramp-file-name-handler 'safe-magic t)
aa485f7c
MA
5580 (add-to-list 'file-name-handler-alist
5581 (cons tramp-completion-file-name-regexp
5582 'tramp-completion-file-name-handler))
5583 (put 'tramp-completion-file-name-handler 'safe-magic t)
5584 ;; If jka-compr or epa-file are already loaded, move them to the
5585 ;; front of `file-name-handler-alist'.
5586 (dolist (fnh '(epa-file-handler jka-compr-handler))
5587 (let ((entry (rassoc fnh file-name-handler-alist)))
5588 (when entry
5589 (setq file-name-handler-alist
5590 (cons entry (delete entry file-name-handler-alist))))))))
69cee873 5591
00d6fd04
MA
5592;; `tramp-file-name-handler' must be registered before evaluation of
5593;; site-start and init files, because there might exist remote files
5594;; already, f.e. files kept via recentf-mode.
aa485f7c
MA
5595;;;###autoload(tramp-register-file-name-handlers)
5596(tramp-register-file-name-handlers)
b25a52cc 5597
fb7933a3 5598;;;###autoload
8c04e197 5599(defun tramp-unload-file-name-handlers ()
a69c01a0
MA
5600 (setq file-name-handler-alist
5601 (delete (rassoc 'tramp-file-name-handler
5602 file-name-handler-alist)
5603 (delete (rassoc 'tramp-completion-file-name-handler
5604 file-name-handler-alist)
5605 file-name-handler-alist))))
5606
8c04e197 5607(add-hook 'tramp-unload-hook 'tramp-unload-file-name-handlers)
a69c01a0 5608
0664ff72 5609;;; File name handler functions for completion mode:
a6e96327
MA
5610
5611(defvar tramp-completion-mode nil
5612 "If non-nil, external packages signal that they are in file name completion.
5613
5614This is necessary, because Tramp uses a heuristic depending on last
5615input event. This fails when external packages use other characters
5616but <TAB>, <SPACE> or ?\\? for file name completion. This variable
5617should never be set globally, the intention is to let-bind it.")
16674e4f
KG
5618
5619;; Necessary because `tramp-file-name-regexp-unified' and
00d6fd04
MA
5620;; `tramp-completion-file-name-regexp-unified' aren't different. If
5621;; nil, `tramp-completion-run-real-handler' is called (i.e. forwarding
5622;; to `tramp-file-name-handler'). Otherwise, it takes
5623;; `tramp-run-real-handler'. Using `last-input-event' is a little bit
5624;; risky, because completing a file might require loading other files,
5625;; like "~/.netrc", and for them it shouldn't be decided based on that
5626;; variable. On the other hand, those files shouldn't have partial
a4aeb9a4
MA
5627;; Tramp file name syntax. Maybe another variable should be introduced
5628;; overwriting this check in such cases. Or we change Tramp file name
00d6fd04 5629;; syntax in order to avoid ambiguities, like in XEmacs ...
6c4e47fa 5630(defun tramp-completion-mode-p ()
16674e4f 5631 "Checks whether method / user name / host name completion is active."
6c4e47fa 5632 (or
5f2b693f
MA
5633 ;; Signal from outside. `non-essential' has been introduced in Emacs 24.
5634 (and (boundp 'non-essential) (symbol-value 'non-essential))
a6e96327
MA
5635 tramp-completion-mode
5636 ;; Emacs.
94be87e8 5637 (equal last-input-event 'tab)
6c4e47fa 5638 (and (natnump last-input-event)
94be87e8 5639 (or
a6e96327 5640 ;; ?\t has event-modifier 'control.
800a97b8 5641 (equal last-input-event ?\t)
94be87e8 5642 (and (not (event-modifiers last-input-event))
800a97b8
SM
5643 (or (equal last-input-event ?\?)
5644 (equal last-input-event ?\ )))))
a6e96327 5645 ;; XEmacs.
6c4e47fa
MA
5646 (and (featurep 'xemacs)
5647 ;; `last-input-event' might be nil.
5648 (not (null last-input-event))
5649 ;; `last-input-event' may have no character approximation.
5650 (funcall (symbol-function 'event-to-character) last-input-event)
94be87e8 5651 (or
a6e96327 5652 ;; ?\t has event-modifier 'control.
800a97b8 5653 (equal
94be87e8
MA
5654 (funcall (symbol-function 'event-to-character)
5655 last-input-event) ?\t)
5656 (and (not (event-modifiers last-input-event))
800a97b8 5657 (or (equal
94be87e8
MA
5658 (funcall (symbol-function 'event-to-character)
5659 last-input-event) ?\?)
800a97b8 5660 (equal
94be87e8
MA
5661 (funcall (symbol-function 'event-to-character)
5662 last-input-event) ?\ )))))))
16674e4f 5663
acd1f317
MA
5664(defun tramp-connectable-p (filename)
5665 "Check, whether it is possible to connect the remote host w/o side-effects.
5666This is true, if either the remote host is already connected, or if we are
5667not in completion mode."
5668 (and (tramp-tramp-file-p filename)
5669 (with-parsed-tramp-file-name filename nil
5670 (or (get-buffer (tramp-buffer-name v))
5671 (not (tramp-completion-mode-p))))))
5672
16674e4f
KG
5673;; Method, host name and user name completion.
5674;; `tramp-completion-dissect-file-name' returns a list of
5675;; tramp-file-name structures. For all of them we return possible completions.
a01b1e22 5676;;;###autoload
16674e4f 5677(defun tramp-completion-handle-file-name-all-completions (filename directory)
00d6fd04 5678 "Like `file-name-all-completions' for partial Tramp files."
16674e4f 5679
00d6fd04
MA
5680 (let* ((fullname (tramp-drop-volume-letter
5681 (expand-file-name filename directory)))
5682 ;; Possible completion structures.
5683 (v (tramp-completion-dissect-file-name fullname))
5684 result result1)
5685
5686 (while v
5687 (let* ((car (car v))
5688 (method (tramp-file-name-method car))
5689 (user (tramp-file-name-user car))
5690 (host (tramp-file-name-host car))
5691 (localname (tramp-file-name-localname car))
5692 (m (tramp-find-method method user host))
5693 (tramp-current-user user) ; see `tramp-parse-passwd'
5694 all-user-hosts)
5695
5696 (unless localname ;; Nothing to complete.
5697
5698 (if (or user host)
5699
5700 ;; Method dependent user / host combinations.
5701 (progn
9e6ab520 5702 (mapc
00d6fd04
MA
5703 (lambda (x)
5704 (setq all-user-hosts
5705 (append all-user-hosts
5706 (funcall (nth 0 x) (nth 1 x)))))
5707 (tramp-get-completion-function m))
5708
9e6ab520
MA
5709 (setq result
5710 (append result
5711 (mapcar
5712 (lambda (x)
5713 (tramp-get-completion-user-host
5714 method user host (nth 0 x) (nth 1 x)))
5715 (delq nil all-user-hosts)))))
00d6fd04
MA
5716
5717 ;; Possible methods.
5718 (setq result
5719 (append result (tramp-get-completion-methods m)))))
5720
5721 (setq v (cdr v))))
5722
5723 ;; Unify list, remove nil elements.
5724 (while result
5725 (let ((car (car result)))
5726 (when car
5727 (add-to-list
5728 'result1
5729 (substring car (length (tramp-drop-volume-letter directory)))))
5730 (setq result (cdr result))))
5731
5732 ;; Complete local parts.
5733 (append
5734 result1
5735 (condition-case nil
489fe4c2
MA
5736 (apply (if (tramp-connectable-p fullname)
5737 'tramp-completion-run-real-handler
5738 'tramp-run-real-handler)
5739 'file-name-all-completions (list (list filename directory)))
00d6fd04 5740 (error nil)))))
16674e4f
KG
5741
5742;; Method, host name and user name completion for a file.
a01b1e22 5743;;;###autoload
e1e17cae
MA
5744(defun tramp-completion-handle-file-name-completion
5745 (filename directory &optional predicate)
00d6fd04 5746 "Like `file-name-completion' for Tramp files."
e1e17cae
MA
5747 (try-completion
5748 filename
5749 (mapcar 'list (file-name-all-completions filename directory))
acd1f317
MA
5750 (when (and predicate
5751 (tramp-connectable-p (expand-file-name filename directory)))
83e20b5c 5752 (lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
16674e4f
KG
5753
5754;; I misuse a little bit the tramp-file-name structure in order to handle
5755;; completion possibilities for partial methods / user names / host names.
5756;; Return value is a list of tramp-file-name structures according to possible
00d6fd04 5757;; completions. If "localname" is non-nil it means there
16674e4f
KG
5758;; shouldn't be a completion anymore.
5759
5760;; Expected results:
5761
00d6fd04
MA
5762;; "/x" "/[x" "/x@" "/[x@" "/x@y" "/[x@y"
5763;; [nil nil "x" nil] [nil "x" nil nil] [nil "x" "y" nil]
5764;; [nil "x" nil nil]
5765;; ["x" nil nil nil]
5766
5767;; "/x:" "/x:y" "/x:y:"
5768;; [nil nil "x" ""] [nil nil "x" "y"] ["x" nil "y" ""]
5769;; "/[x/" "/[x/y"
5770;; ["x" nil "" nil] ["x" nil "y" nil]
5771;; ["x" "" nil nil] ["x" "y" nil nil]
5772
5773;; "/x:y@" "/x:y@z" "/x:y@z:"
5774;; [nil nil "x" "y@"] [nil nil "x" "y@z"] ["x" "y" "z" ""]
5775;; "/[x/y@" "/[x/y@z"
5776;; ["x" nil "y" nil] ["x" "y" "z" nil]
16674e4f
KG
5777(defun tramp-completion-dissect-file-name (name)
5778 "Returns a list of `tramp-file-name' structures.
5779They are collected by `tramp-completion-dissect-file-name1'."
5780
5781 (let* ((result)
4007ba5b 5782 (x-nil "\\|\\(\\)")
b96e6899
MA
5783 (tramp-completion-ipv6-regexp
5784 (format
5785 "[^%s]*"
5786 (if (zerop (length tramp-postfix-ipv6-format))
5787 tramp-postfix-host-format
5788 tramp-postfix-ipv6-format)))
4007ba5b
KG
5789 ;; "/method" "/[method"
5790 (tramp-completion-file-name-structure1
5791 (list (concat tramp-prefix-regexp "\\(" tramp-method-regexp x-nil "\\)$")
5792 1 nil nil nil))
5793 ;; "/user" "/[user"
5794 (tramp-completion-file-name-structure2
5795 (list (concat tramp-prefix-regexp "\\(" tramp-user-regexp x-nil "\\)$")
5796 nil 1 nil nil))
5797 ;; "/host" "/[host"
5798 (tramp-completion-file-name-structure3
5799 (list (concat tramp-prefix-regexp "\\(" tramp-host-regexp x-nil "\\)$")
5800 nil nil 1 nil))
b96e6899 5801 ;; "/[ipv6" "/[ipv6"
4007ba5b 5802 (tramp-completion-file-name-structure4
b96e6899
MA
5803 (list (concat tramp-prefix-regexp
5804 tramp-prefix-ipv6-regexp
5805 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5806 nil nil 1 nil))
5807 ;; "/user@host" "/[user@host"
5808 (tramp-completion-file-name-structure5
4007ba5b
KG
5809 (list (concat tramp-prefix-regexp
5810 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5811 "\\(" tramp-host-regexp x-nil "\\)$")
5812 nil 1 2 nil))
b96e6899
MA
5813 ;; "/user@[ipv6" "/[user@ipv6"
5814 (tramp-completion-file-name-structure6
5815 (list (concat tramp-prefix-regexp
5816 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5817 tramp-prefix-ipv6-regexp
5818 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5819 nil 1 2 nil))
00d6fd04 5820 ;; "/method:user" "/[method/user" "/method://user"
b96e6899 5821 (tramp-completion-file-name-structure7
4007ba5b 5822 (list (concat tramp-prefix-regexp
00d6fd04 5823 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5824 "\\(" tramp-user-regexp x-nil "\\)$")
5825 1 2 nil nil))
00d6fd04 5826 ;; "/method:host" "/[method/host" "/method://host"
b96e6899 5827 (tramp-completion-file-name-structure8
4007ba5b 5828 (list (concat tramp-prefix-regexp
00d6fd04 5829 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5830 "\\(" tramp-host-regexp x-nil "\\)$")
5831 1 nil 2 nil))
b96e6899
MA
5832 ;; "/method:[ipv6" "/[method/ipv6" "/method://[ipv6"
5833 (tramp-completion-file-name-structure9
5834 (list (concat tramp-prefix-regexp
5835 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
5836 tramp-prefix-ipv6-regexp
5837 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5838 1 nil 2 nil))
00d6fd04 5839 ;; "/method:user@host" "/[method/user@host" "/method://user@host"
b96e6899 5840 (tramp-completion-file-name-structure10
4007ba5b 5841 (list (concat tramp-prefix-regexp
00d6fd04 5842 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5843 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5844 "\\(" tramp-host-regexp x-nil "\\)$")
00d6fd04 5845 1 2 3 nil))
b96e6899
MA
5846 ;; "/method:user@[ipv6" "/[method/user@ipv6" "/method://user@[ipv6"
5847 (tramp-completion-file-name-structure11
5848 (list (concat tramp-prefix-regexp
5849 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
5850 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5851 tramp-prefix-ipv6-regexp
5852 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5853 1 2 3 nil))
00d6fd04 5854 ;; "/method: "/method:/"
b96e6899 5855 (tramp-completion-file-name-structure12
00d6fd04
MA
5856 (list
5857 (if (equal tramp-syntax 'url)
5858 (concat tramp-prefix-regexp
5859 "\\(" tramp-method-regexp "\\)"
5860 "\\(" (substring tramp-postfix-method-regexp 0 1)
5861 "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)"
5862 "\\(" "\\)$")
5863 ;; Should not match if not URL syntax.
5864 (concat tramp-prefix-regexp "/$"))
5865 1 3 nil nil))
5866 ;; "/method: "/method:/"
b96e6899 5867 (tramp-completion-file-name-structure13
00d6fd04
MA
5868 (list
5869 (if (equal tramp-syntax 'url)
5870 (concat tramp-prefix-regexp
5871 "\\(" tramp-method-regexp "\\)"
5872 "\\(" (substring tramp-postfix-method-regexp 0 1)
5873 "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)"
5874 "\\(" "\\)$")
5875 ;; Should not match if not URL syntax.
5876 (concat tramp-prefix-regexp "/$"))
5877 1 nil 3 nil)))
4007ba5b 5878
9e6ab520 5879 (mapc (lambda (regexp)
16674e4f
KG
5880 (add-to-list 'result
5881 (tramp-completion-dissect-file-name1 regexp name)))
5882 (list
5883 tramp-completion-file-name-structure1
5884 tramp-completion-file-name-structure2
5885 tramp-completion-file-name-structure3
5886 tramp-completion-file-name-structure4
5887 tramp-completion-file-name-structure5
5888 tramp-completion-file-name-structure6
5889 tramp-completion-file-name-structure7
00d6fd04
MA
5890 tramp-completion-file-name-structure8
5891 tramp-completion-file-name-structure9
b96e6899
MA
5892 tramp-completion-file-name-structure10
5893 tramp-completion-file-name-structure11
5894 tramp-completion-file-name-structure12
5895 tramp-completion-file-name-structure13
16674e4f
KG
5896 tramp-file-name-structure))
5897
5898 (delq nil result)))
5899
5900(defun tramp-completion-dissect-file-name1 (structure name)
5901 "Returns a `tramp-file-name' structure matching STRUCTURE.
00d6fd04 5902The structure consists of remote method, remote user,
7432277c 5903remote host and localname (filename on remote host)."
fb7933a3 5904
00d6fd04
MA
5905 (save-match-data
5906 (when (string-match (nth 0 structure) name)
5907 (let ((method (and (nth 1 structure)
5908 (match-string (nth 1 structure) name)))
5909 (user (and (nth 2 structure)
5910 (match-string (nth 2 structure) name)))
5911 (host (and (nth 3 structure)
5912 (match-string (nth 3 structure) name)))
5913 (localname (and (nth 4 structure)
5914 (match-string (nth 4 structure) name))))
5915 (vector method user host localname)))))
16674e4f
KG
5916
5917;; This function returns all possible method completions, adding the
5918;; trailing method delimeter.
16674e4f
KG
5919(defun tramp-get-completion-methods (partial-method)
5920 "Returns all method completions for PARTIAL-METHOD."
4007ba5b
KG
5921 (mapcar
5922 (lambda (method)
5923 (and method
5924 (string-match (concat "^" (regexp-quote partial-method)) method)
00d6fd04
MA
5925 (tramp-completion-make-tramp-file-name method nil nil nil)))
5926 (mapcar 'car tramp-methods)))
16674e4f
KG
5927
5928;; Compares partial user and host names with possible completions.
5929(defun tramp-get-completion-user-host (method partial-user partial-host user host)
5930 "Returns the most expanded string for user and host name completion.
5931PARTIAL-USER must match USER, PARTIAL-HOST must match HOST."
5932 (cond
5933
5934 ((and partial-user partial-host)
5935 (if (and host
5936 (string-match (concat "^" (regexp-quote partial-host)) host)
5937 (string-equal partial-user (or user partial-user)))
5938 (setq user partial-user)
5939 (setq user nil
5940 host nil)))
5941
5942 (partial-user
5943 (setq host nil)
5944 (unless
5945 (and user (string-match (concat "^" (regexp-quote partial-user)) user))
5946 (setq user nil)))
5947
5948 (partial-host
5949 (setq user nil)
5950 (unless
5951 (and host (string-match (concat "^" (regexp-quote partial-host)) host))
5952 (setq host nil)))
5953
5954 (t (setq user nil
5955 host nil)))
5956
292ffc15 5957 (unless (zerop (+ (length user) (length host)))
00d6fd04 5958 (tramp-completion-make-tramp-file-name method user host nil)))
16674e4f
KG
5959
5960(defun tramp-parse-rhosts (filename)
5961 "Return a list of (user host) tuples allowed to access.
292ffc15 5962Either user or host may be nil."
00d6fd04
MA
5963 ;; On Windows, there are problems in completion when
5964 ;; `default-directory' is remote.
9e6ab520 5965 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5966 res)
8daea7fc 5967 (when (file-readable-p filename)
16674e4f
KG
5968 (with-temp-buffer
5969 (insert-file-contents filename)
5970 (goto-char (point-min))
5971 (while (not (eobp))
292ffc15 5972 (push (tramp-parse-rhosts-group) res))))
16674e4f
KG
5973 res))
5974
16674e4f
KG
5975(defun tramp-parse-rhosts-group ()
5976 "Return a (user host) tuple allowed to access.
292ffc15 5977Either user or host may be nil."
16674e4f
KG
5978 (let ((result)
5979 (regexp
5980 (concat
5981 "^\\(" tramp-host-regexp "\\)"
5982 "\\([ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
9e6ab520 5983 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
5984 (when (re-search-forward regexp nil t)
5985 (setq result (append (list (match-string 3) (match-string 1)))))
5986 (widen)
5987 (forward-line 1)
5988 result))
5989
5990(defun tramp-parse-shosts (filename)
5991 "Return a list of (user host) tuples allowed to access.
5992User is always nil."
00d6fd04
MA
5993 ;; On Windows, there are problems in completion when
5994 ;; `default-directory' is remote.
9e6ab520 5995 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5996 res)
8daea7fc 5997 (when (file-readable-p filename)
16674e4f
KG
5998 (with-temp-buffer
5999 (insert-file-contents filename)
6000 (goto-char (point-min))
6001 (while (not (eobp))
292ffc15 6002 (push (tramp-parse-shosts-group) res))))
16674e4f
KG
6003 res))
6004
6005(defun tramp-parse-shosts-group ()
6006 "Return a (user host) tuple allowed to access.
6007User is always nil."
16674e4f
KG
6008 (let ((result)
6009 (regexp (concat "^\\(" tramp-host-regexp "\\)")))
9e6ab520 6010 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
6011 (when (re-search-forward regexp nil t)
6012 (setq result (list nil (match-string 1))))
6013 (widen)
6014 (or
6015 (> (skip-chars-forward ",") 0)
6016 (forward-line 1))
6017 result))
6018
8daea7fc
KG
6019(defun tramp-parse-sconfig (filename)
6020 "Return a list of (user host) tuples allowed to access.
6021User is always nil."
00d6fd04
MA
6022 ;; On Windows, there are problems in completion when
6023 ;; `default-directory' is remote.
9e6ab520 6024 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 6025 res)
8daea7fc
KG
6026 (when (file-readable-p filename)
6027 (with-temp-buffer
6028 (insert-file-contents filename)
6029 (goto-char (point-min))
6030 (while (not (eobp))
6031 (push (tramp-parse-sconfig-group) res))))
6032 res))
6033
6034(defun tramp-parse-sconfig-group ()
6035 "Return a (user host) tuple allowed to access.
6036User is always nil."
8daea7fc
KG
6037 (let ((result)
6038 (regexp (concat "^[ \t]*Host[ \t]+" "\\(" tramp-host-regexp "\\)")))
9e6ab520 6039 (narrow-to-region (point) (tramp-compat-line-end-position))
8daea7fc
KG
6040 (when (re-search-forward regexp nil t)
6041 (setq result (list nil (match-string 1))))
6042 (widen)
6043 (or
6044 (> (skip-chars-forward ",") 0)
6045 (forward-line 1))
6046 result))
6047
5ec2cc41
KG
6048(defun tramp-parse-shostkeys (dirname)
6049 "Return a list of (user host) tuples allowed to access.
6050User is always nil."
00d6fd04
MA
6051 ;; On Windows, there are problems in completion when
6052 ;; `default-directory' is remote.
9e6ab520 6053 (let* ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
6054 (regexp (concat "^key_[0-9]+_\\(" tramp-host-regexp "\\)\\.pub$"))
6055 (files (when (file-directory-p dirname) (directory-files dirname)))
6056 result)
5ec2cc41
KG
6057 (while files
6058 (when (string-match regexp (car files))
6059 (push (list nil (match-string 1 (car files))) result))
6060 (setq files (cdr files)))
6061 result))
6062
6063(defun tramp-parse-sknownhosts (dirname)
6064 "Return a list of (user host) tuples allowed to access.
6065User is always nil."
00d6fd04
MA
6066 ;; On Windows, there are problems in completion when
6067 ;; `default-directory' is remote.
9e6ab520 6068 (let* ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
6069 (regexp (concat "^\\(" tramp-host-regexp
6070 "\\)\\.ssh-\\(dss\\|rsa\\)\\.pub$"))
6071 (files (when (file-directory-p dirname) (directory-files dirname)))
6072 result)
5ec2cc41
KG
6073 (while files
6074 (when (string-match regexp (car files))
6075 (push (list nil (match-string 1 (car files))) result))
6076 (setq files (cdr files)))
6077 result))
6078
16674e4f
KG
6079(defun tramp-parse-hosts (filename)
6080 "Return a list of (user host) tuples allowed to access.
6081User is always nil."
00d6fd04
MA
6082 ;; On Windows, there are problems in completion when
6083 ;; `default-directory' is remote.
9e6ab520 6084 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 6085 res)
8daea7fc 6086 (when (file-readable-p filename)
16674e4f
KG
6087 (with-temp-buffer
6088 (insert-file-contents filename)
6089 (goto-char (point-min))
6090 (while (not (eobp))
292ffc15 6091 (push (tramp-parse-hosts-group) res))))
16674e4f
KG
6092 res))
6093
6094(defun tramp-parse-hosts-group ()
6095 "Return a (user host) tuple allowed to access.
6096User is always nil."
16674e4f 6097 (let ((result)
b96e6899
MA
6098 (regexp
6099 (concat "^\\(" tramp-ipv6-regexp "\\|" tramp-host-regexp "\\)")))
9e6ab520 6100 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f 6101 (when (re-search-forward regexp nil t)
b96e6899 6102 (setq result (list nil (match-string 1))))
16674e4f
KG
6103 (widen)
6104 (or
6105 (> (skip-chars-forward " \t") 0)
6106 (forward-line 1))
6107 result))
6108
8daea7fc
KG
6109;; For su-alike methods it would be desirable to return "root@localhost"
6110;; as default. Unfortunately, we have no information whether any user name
00d6fd04 6111;; has been typed already. So we use `tramp-current-user' as indication,
8daea7fc 6112;; assuming it is set in `tramp-completion-handle-file-name-all-completions'.
16674e4f
KG
6113(defun tramp-parse-passwd (filename)
6114 "Return a list of (user host) tuples allowed to access.
6115Host is always \"localhost\"."
00d6fd04
MA
6116 ;; On Windows, there are problems in completion when
6117 ;; `default-directory' is remote.
9e6ab520 6118 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 6119 res)
8daea7fc 6120 (if (zerop (length tramp-current-user))
16674e4f 6121 '(("root" nil))
8daea7fc 6122 (when (file-readable-p filename)
16674e4f
KG
6123 (with-temp-buffer
6124 (insert-file-contents filename)
6125 (goto-char (point-min))
6126 (while (not (eobp))
292ffc15 6127 (push (tramp-parse-passwd-group) res))))
16674e4f
KG
6128 res)))
6129
6130(defun tramp-parse-passwd-group ()
6131 "Return a (user host) tuple allowed to access.
292ffc15 6132Host is always \"localhost\"."
16674e4f
KG
6133 (let ((result)
6134 (regexp (concat "^\\(" tramp-user-regexp "\\):")))
9e6ab520 6135 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
6136 (when (re-search-forward regexp nil t)
6137 (setq result (list (match-string 1) "localhost")))
6138 (widen)
6139 (forward-line 1)
6140 result))
6141
292ffc15
KG
6142(defun tramp-parse-netrc (filename)
6143 "Return a list of (user host) tuples allowed to access.
6144User may be nil."
00d6fd04
MA
6145 ;; On Windows, there are problems in completion when
6146 ;; `default-directory' is remote.
9e6ab520 6147 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 6148 res)
8daea7fc 6149 (when (file-readable-p filename)
292ffc15
KG
6150 (with-temp-buffer
6151 (insert-file-contents filename)
6152 (goto-char (point-min))
6153 (while (not (eobp))
6154 (push (tramp-parse-netrc-group) res))))
6155 res))
6156
6157(defun tramp-parse-netrc-group ()
6158 "Return a (user host) tuple allowed to access.
6159User may be nil."
292ffc15
KG
6160 (let ((result)
6161 (regexp
6162 (concat
6163 "^[ \t]*machine[ \t]+" "\\(" tramp-host-regexp "\\)"
6164 "\\([ \t]+login[ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
9e6ab520 6165 (narrow-to-region (point) (tramp-compat-line-end-position))
292ffc15
KG
6166 (when (re-search-forward regexp nil t)
6167 (setq result (list (match-string 3) (match-string 1))))
6168 (widen)
6169 (forward-line 1)
6170 result))
6171
00d6fd04
MA
6172(defun tramp-parse-putty (registry)
6173 "Return a list of (user host) tuples allowed to access.
6174User is always nil."
6175 ;; On Windows, there are problems in completion when
6176 ;; `default-directory' is remote.
9e6ab520 6177 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
6178 res)
6179 (with-temp-buffer
a4aeb9a4 6180 (when (zerop (tramp-local-call-process "reg" nil t nil "query" registry))
00d6fd04
MA
6181 (goto-char (point-min))
6182 (while (not (eobp))
6183 (push (tramp-parse-putty-group registry) res))))
6184 res))
6185
6186(defun tramp-parse-putty-group (registry)
6187 "Return a (user host) tuple allowed to access.
6188User is always nil."
6189 (let ((result)
6190 (regexp (concat (regexp-quote registry) "\\\\\\(.+\\)")))
9e6ab520 6191 (narrow-to-region (point) (tramp-compat-line-end-position))
00d6fd04
MA
6192 (when (re-search-forward regexp nil t)
6193 (setq result (list nil (match-string 1))))
6194 (widen)
6195 (forward-line 1)
6196 result))
6197
fb7933a3
KG
6198;;; Internal Functions:
6199
00d6fd04
MA
6200(defun tramp-maybe-send-script (vec script name)
6201 "Define in remote shell function NAME implemented as SCRIPT.
6202Only send the definition if it has not already been done."
6203 (let* ((p (tramp-get-connection-process vec))
6204 (scripts (tramp-get-connection-property p "scripts" nil)))
1834b39f 6205 (unless (member name scripts)
00d6fd04
MA
6206 (tramp-message vec 5 "Sending script `%s'..." name)
6207 ;; The script could contain a call of Perl. This is masked with `%s'.
6208 (tramp-send-command-and-check
6209 vec
6210 (format "%s () {\n%s\n}" name
6211 (format script (tramp-get-remote-perl vec))))
6212 (tramp-set-connection-property p "scripts" (cons name scripts))
6213 (tramp-message vec 5 "Sending script `%s'...done." name))))
c82c5727 6214
fb7933a3 6215(defun tramp-set-auto-save ()
00d6fd04 6216 (when (and ;; ange-ftp has its own auto-save mechanism
7177e2a3
MA
6217 (eq (tramp-find-foreign-file-name-handler (buffer-file-name))
6218 'tramp-sh-file-name-handler)
fb7933a3
KG
6219 auto-save-default)
6220 (auto-save-mode 1)))
6221(add-hook 'find-file-hooks 'tramp-set-auto-save t)
a69c01a0 6222(add-hook 'tramp-unload-hook
aa485f7c
MA
6223 (lambda ()
6224 (remove-hook 'find-file-hooks 'tramp-set-auto-save)))
fb7933a3
KG
6225
6226(defun tramp-run-test (switch filename)
6227 "Run `test' on the remote system, given a SWITCH and a FILENAME.
6228Returns the exit code of the `test' program."
00d6fd04
MA
6229 (with-parsed-tramp-file-name filename nil
6230 (tramp-send-command-and-check
6231 v
6232 (format
6233 "%s %s %s"
6234 (tramp-get-test-command v)
6235 switch
6236 (tramp-shell-quote-argument localname)))))
6237
6238(defun tramp-run-test2 (format-string file1 file2)
6239 "Run `test'-like program on the remote system, given FILE1, FILE2.
6240FORMAT-STRING contains the program name, switches, and place holders.
6241Returns the exit code of the `test' program. Barfs if the methods,
fb7933a3 6242hosts, or files, disagree."
00d6fd04
MA
6243 (unless (tramp-equal-remote file1 file2)
6244 (with-parsed-tramp-file-name (if (tramp-tramp-file-p file1) file1 file2) nil
6245 (tramp-error
6246 v 'file-error
6247 "tramp-run-test2 only implemented for same method, user, host")))
6248 (with-parsed-tramp-file-name file1 v1
6249 (with-parsed-tramp-file-name file1 v2
fb7933a3 6250 (tramp-send-command-and-check
00d6fd04
MA
6251 v1
6252 (format format-string
6253 (tramp-shell-quote-argument v1-localname)
6254 (tramp-shell-quote-argument v2-localname))))))
fb7933a3 6255
00d6fd04
MA
6256(defun tramp-buffer-name (vec)
6257 "A name for the connection buffer VEC."
6258 ;; We must use `tramp-file-name-real-host', because for gateway
6259 ;; methods the default port will be expanded later on, which would
6260 ;; tamper the name.
6261 (let ((method (tramp-file-name-method vec))
6262 (user (tramp-file-name-user vec))
6263 (host (tramp-file-name-real-host vec)))
6264 (if (not (zerop (length user)))
6265 (format "*tramp/%s %s@%s*" method user host)
6266 (format "*tramp/%s %s*" method host))))
6267
b88f2d0a
MA
6268(defun tramp-delete-temp-file-function ()
6269 "Remove temporary files related to current buffer."
6270 (when (stringp tramp-temp-buffer-file-name)
6271 (condition-case nil
6272 (delete-file tramp-temp-buffer-file-name)
6273 (error nil))))
6274
6275(add-hook 'kill-buffer-hook 'tramp-delete-temp-file-function)
6276(add-hook 'tramp-cache-unload-hook
6277 (lambda ()
6278 (remove-hook 'kill-buffer-hook
6279 'tramp-delete-temp-file-function)))
6280
00d6fd04
MA
6281(defun tramp-get-buffer (vec)
6282 "Get the connection buffer to be used for VEC."
6283 (or (get-buffer (tramp-buffer-name vec))
6284 (with-current-buffer (get-buffer-create (tramp-buffer-name vec))
6285 (setq buffer-undo-list t)
6286 (setq default-directory
6287 (tramp-make-tramp-file-name
6288 (tramp-file-name-method vec)
6289 (tramp-file-name-user vec)
6290 (tramp-file-name-host vec)
6291 "/"))
6292 (current-buffer))))
6293
6294(defun tramp-get-connection-buffer (vec)
6295 "Get the connection buffer to be used for VEC.
6296In case a second asynchronous communication has been started, it is different
6297from `tramp-get-buffer'."
6298 (or (tramp-get-connection-property vec "process-buffer" nil)
6299 (tramp-get-buffer vec)))
6300
6301(defun tramp-get-connection-process (vec)
6302 "Get the connection process to be used for VEC.
6303In case a second asynchronous communication has been started, it is different
6304from the default one."
6305 (get-process
6306 (or (tramp-get-connection-property vec "process-name" nil)
6307 (tramp-buffer-name vec))))
6308
6309(defun tramp-debug-buffer-name (vec)
6310 "A name for the debug buffer for VEC."
6311 ;; We must use `tramp-file-name-real-host', because for gateway
6312 ;; methods the default port will be expanded later on, which would
6313 ;; tamper the name.
6314 (let ((method (tramp-file-name-method vec))
6315 (user (tramp-file-name-user vec))
6316 (host (tramp-file-name-real-host vec)))
6317 (if (not (zerop (length user)))
6318 (format "*debug tramp/%s %s@%s*" method user host)
6319 (format "*debug tramp/%s %s*" method host))))
6320
b533bc97
MA
6321(defconst tramp-debug-outline-regexp
6322 "[0-9]+:[0-9]+:[0-9]+\\.[0-9]+ [a-z0-9-]+ (\\([0-9]+\\)) #")
6323
00d6fd04
MA
6324(defun tramp-get-debug-buffer (vec)
6325 "Get the debug buffer for VEC."
01917a18 6326 (with-current-buffer
00d6fd04
MA
6327 (get-buffer-create (tramp-debug-buffer-name vec))
6328 (when (bobp)
6329 (setq buffer-undo-list t)
b533bc97 6330 ;; Activate `outline-mode'. This runs `text-mode-hook' and
9ce8462a 6331 ;; `outline-mode-hook'. We must prevent that local processes
b533bc97
MA
6332 ;; die. Yes: I've seen `flyspell-mode', which starts "ispell".
6333 ;; Furthermore, `outline-regexp' must have the correct value
6334 ;; already, because it is used by `font-lock-compile-keywords'.
6335 (let ((default-directory (tramp-compat-temporary-file-directory))
6336 (outline-regexp tramp-debug-outline-regexp))
00d6fd04 6337 (outline-mode))
b533bc97 6338 (set (make-local-variable 'outline-regexp) tramp-debug-outline-regexp)
9ce8462a 6339 (set (make-local-variable 'outline-level) 'tramp-outline-level))
01917a18 6340 (current-buffer)))
fb7933a3 6341
00d6fd04
MA
6342(defun tramp-outline-level ()
6343 "Return the depth to which a statement is nested in the outline.
6344Point must be at the beginning of a header line.
6345
6346The outline level is equal to the verbosity of the Tramp message."
6347 (1+ (string-to-number (match-string 1))))
fb7933a3 6348
00d6fd04
MA
6349(defun tramp-find-executable
6350 (vec progname dirlist &optional ignore-tilde ignore-path)
6351 "Searches for PROGNAME in $PATH and all directories mentioned in DIRLIST.
6352First arg VEC specifies the connection, PROGNAME is the program
6353to search for, and DIRLIST gives the list of directories to
6354search. If IGNORE-TILDE is non-nil, directory names starting
6355with `~' will be ignored. If IGNORE-PATH is non-nil, searches
6356only in DIRLIST.
fb7933a3 6357
7432277c 6358Returns the absolute file name of PROGNAME, if found, and nil otherwise.
fb7933a3
KG
6359
6360This function expects to be in the right *tramp* buffer."
c0e17ff2 6361 (with-current-buffer (tramp-get-connection-buffer vec)
00d6fd04
MA
6362 (let (result)
6363 ;; Check whether the executable is in $PATH. "which(1)" does not
6364 ;; report always a correct error code; therefore we check the
6365 ;; number of words it returns.
6366 (unless ignore-path
6367 (tramp-send-command vec (format "which \\%s | wc -w" progname))
6368 (goto-char (point-min))
c0e17ff2 6369 (if (looking-at "^\\s-*1$")
00d6fd04
MA
6370 (setq result (concat "\\" progname))))
6371 (unless result
6372 (when ignore-tilde
b533bc97 6373 ;; Remove all ~/foo directories from dirlist. In XEmacs,
00d6fd04
MA
6374 ;; `remove' is in CL, and we want to avoid CL dependencies.
6375 (let (newdl d)
6376 (while dirlist
6377 (setq d (car dirlist))
6378 (setq dirlist (cdr dirlist))
6379 (unless (char-equal ?~ (aref d 0))
6380 (setq newdl (cons d newdl))))
6381 (setq dirlist (nreverse newdl))))
6382 (tramp-send-command
6383 vec
6384 (format (concat "while read d; "
6385 "do if test -x $d/%s -a -f $d/%s; "
6386 "then echo tramp_executable $d/%s; "
6387 "break; fi; done <<'EOF'\n"
6388 "%s\nEOF")
6389 progname progname progname (mapconcat 'identity dirlist "\n")))
6390 (goto-char (point-max))
6391 (when (search-backward "tramp_executable " nil t)
6392 (skip-chars-forward "^ ")
6393 (skip-chars-forward " ")
9e6ab520
MA
6394 (setq result (buffer-substring
6395 (point) (tramp-compat-line-end-position)))))
00d6fd04
MA
6396 result)))
6397
6398(defun tramp-set-remote-path (vec)
6399 "Sets the remote environment PATH to existing directories.
6400I.e., for each directory in `tramp-remote-path', it is tested
6401whether it exists and if so, it is added to the environment
6402variable PATH."
6403 (tramp-message vec 5 (format "Setting $PATH environment variable"))
f84638eb
MA
6404 (tramp-send-command
6405 vec (format "PATH=%s; export PATH"
6406 (mapconcat 'identity (tramp-get-remote-path vec) ":"))))
fb7933a3 6407
cfb5c0db
MA
6408;; ------------------------------------------------------------
6409;; -- Communication with external shell --
6410;; ------------------------------------------------------------
fb7933a3 6411
00d6fd04 6412(defun tramp-find-file-exists-command (vec)
fb7933a3
KG
6413 "Find a command on the remote host for checking if a file exists.
6414Here, we are looking for a command which has zero exit status if the
6415file exists and nonzero exit status otherwise."
00d6fd04 6416 (let ((existing "/")
fb7933a3 6417 (nonexisting
00d6fd04
MA
6418 (tramp-shell-quote-argument "/ this file does not exist "))
6419 result)
fb7933a3
KG
6420 ;; The algorithm is as follows: we try a list of several commands.
6421 ;; For each command, we first run `$cmd /' -- this should return
6422 ;; true, as the root directory always exists. And then we run
00d6fd04 6423 ;; `$cmd /this\ file\ does\ not\ exist ', hoping that the file indeed
fb7933a3
KG
6424 ;; does not exist. This should return false. We use the first
6425 ;; command we find that seems to work.
6426 ;; The list of commands to try is as follows:
00d6fd04
MA
6427 ;; `ls -d' This works on most systems, but NetBSD 1.4
6428 ;; has a bug: `ls' always returns zero exit
6429 ;; status, even for files which don't exist.
6430 ;; `test -e' Some Bourne shells have a `test' builtin
6431 ;; which does not know the `-e' option.
6432 ;; `/bin/test -e' For those, the `test' binary on disk normally
6433 ;; provides the option. Alas, the binary
6434 ;; is sometimes `/bin/test' and sometimes it's
6435 ;; `/usr/bin/test'.
6436 ;; `/usr/bin/test -e' In case `/bin/test' does not exist.
fb7933a3 6437 (unless (or
00d6fd04
MA
6438 (and (setq result (format "%s -e" (tramp-get-test-command vec)))
6439 (zerop (tramp-send-command-and-check
6440 vec (format "%s %s" result existing)))
6441 (not (zerop (tramp-send-command-and-check
6442 vec (format "%s %s" result nonexisting)))))
6443 (and (setq result "/bin/test -e")
6444 (zerop (tramp-send-command-and-check
6445 vec (format "%s %s" result existing)))
6446 (not (zerop (tramp-send-command-and-check
6447 vec (format "%s %s" result nonexisting)))))
6448 (and (setq result "/usr/bin/test -e")
6449 (zerop (tramp-send-command-and-check
6450 vec (format "%s %s" result existing)))
6451 (not (zerop (tramp-send-command-and-check
6452 vec (format "%s %s" result nonexisting)))))
6453 (and (setq result (format "%s -d" (tramp-get-ls-command vec)))
6454 (zerop (tramp-send-command-and-check
6455 vec (format "%s %s" result existing)))
6456 (not (zerop (tramp-send-command-and-check
6457 vec (format "%s %s" result nonexisting))))))
6458 (tramp-error
6459 vec 'file-error "Couldn't find command to check if file exists"))
6460 result))
bf247b6e 6461
fb7933a3 6462;; CCC test ksh or bash found for tilde expansion?
00d6fd04
MA
6463(defun tramp-find-shell (vec)
6464 "Opens a shell on the remote host which groks tilde expansion."
6465 (unless (tramp-get-connection-property vec "remote-shell" nil)
6466 (let (shell)
6467 (with-current-buffer (tramp-get-buffer vec)
7e780ff1 6468 (tramp-send-command vec "echo ~root" t)
00d6fd04 6469 (cond
c0e17ff2
MA
6470 ((or (string-match "^~root$" (buffer-string))
6471 ;; The default shell (ksh93) of OpenSolaris is buggy.
6472 (string-equal (tramp-get-connection-property vec "uname" "")
6473 "SunOS 5.11"))
00d6fd04 6474 (setq shell
f84638eb 6475 (or (tramp-find-executable
c0e17ff2 6476 vec "bash" (tramp-get-remote-path vec) t t)
f84638eb 6477 (tramp-find-executable
c0e17ff2 6478 vec "ksh" (tramp-get-remote-path vec) t t)))
00d6fd04
MA
6479 (unless shell
6480 (tramp-error
6481 vec 'file-error
6482 "Couldn't find a shell which groks tilde expansion"))
6483 ;; Find arguments for this shell.
6484 (let ((alist tramp-sh-extra-args)
6485 item extra-args)
6486 (while (and alist (null extra-args))
6487 (setq item (pop alist))
6488 (when (string-match (car item) shell)
6489 (setq extra-args (cdr item))))
6490 (when extra-args (setq shell (concat shell " " extra-args))))
6491 (tramp-message
6492 vec 5 "Starting remote shell `%s' for tilde expansion..." shell)
dab816a9 6493 (let ((tramp-end-of-output tramp-initial-end-of-output))
a4aeb9a4 6494 (tramp-send-command
b08104a0 6495 vec
70c11b0b
MA
6496 (format "PROMPT_COMMAND='' PS1=%s PS2='' PS3='' exec %s"
6497 (shell-quote-argument tramp-end-of-output) shell)
b08104a0 6498 t))
a0a5183a 6499 ;; Setting prompts.
00d6fd04 6500 (tramp-message vec 5 "Setting remote shell prompt...")
70c11b0b
MA
6501 (tramp-send-command
6502 vec (format "PS1=%s" (shell-quote-argument tramp-end-of-output)) t)
9fa0d3aa
MA
6503 (tramp-send-command vec "PS2=''" t)
6504 (tramp-send-command vec "PS3=''" t)
6505 (tramp-send-command vec "PROMPT_COMMAND=''" t)
00d6fd04 6506 (tramp-message vec 5 "Setting remote shell prompt...done"))
a0a5183a 6507
00d6fd04
MA
6508 (t (tramp-message
6509 vec 5 "Remote `%s' groks tilde expansion, good"
6510 (tramp-get-method-parameter
6511 (tramp-file-name-method vec) 'tramp-remote-sh))
6512 (tramp-set-connection-property
6513 vec "remote-shell"
6514 (tramp-get-method-parameter
6515 (tramp-file-name-method vec) 'tramp-remote-sh))))))))
fb7933a3 6516
bf247b6e
KS
6517;; ------------------------------------------------------------
6518;; -- Functions for establishing connection --
6519;; ------------------------------------------------------------
fb7933a3 6520
ac474af1
KG
6521;; The following functions are actions to be taken when seeing certain
6522;; prompts from the remote host. See the variable
6523;; `tramp-actions-before-shell' for usage of these functions.
6524
00d6fd04 6525(defun tramp-action-login (proc vec)
ac474af1 6526 "Send the login name."
00d6fd04
MA
6527 (when (not (stringp tramp-current-user))
6528 (save-window-excursion
6529 (let ((enable-recursive-minibuffers t))
6530 (pop-to-buffer (tramp-get-connection-buffer vec))
6531 (setq tramp-current-user (read-string (match-string 0))))))
6532 (tramp-message vec 3 "Sending login name `%s'" tramp-current-user)
6533 (with-current-buffer (tramp-get-connection-buffer vec)
6534 (tramp-message vec 6 "\n%s" (buffer-string)))
6535 (tramp-send-string vec tramp-current-user))
6536
6537(defun tramp-action-password (proc vec)
ac474af1 6538 "Query the user for a password."
70c11b0b
MA
6539 (with-current-buffer (process-buffer proc)
6540 (tramp-check-for-regexp proc tramp-password-prompt-regexp)
6541 (tramp-message vec 3 "Sending %s" (match-string 1)))
00d6fd04
MA
6542 (tramp-enter-password proc))
6543
6544(defun tramp-action-succeed (proc vec)
ac474af1 6545 "Signal success in finding shell prompt."
ac474af1
KG
6546 (throw 'tramp-action 'ok))
6547
00d6fd04 6548(defun tramp-action-permission-denied (proc vec)
ac474af1 6549 "Signal permission denied."
00d6fd04 6550 (kill-process proc)
ac474af1
KG
6551 (throw 'tramp-action 'permission-denied))
6552
00d6fd04 6553(defun tramp-action-yesno (proc vec)
3cdaec13
KG
6554 "Ask the user for confirmation using `yes-or-no-p'.
6555Send \"yes\" to remote process on confirmation, abort otherwise.
6556See also `tramp-action-yn'."
ac474af1 6557 (save-window-excursion
00d6fd04
MA
6558 (let ((enable-recursive-minibuffers t))
6559 (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec)))
6560 (unless (yes-or-no-p (match-string 0))
6561 (kill-process proc)
6562 (throw 'tramp-action 'permission-denied))
6563 (with-current-buffer (tramp-get-connection-buffer vec)
6564 (tramp-message vec 6 "\n%s" (buffer-string)))
6565 (tramp-send-string vec "yes"))))
6566
6567(defun tramp-action-yn (proc vec)
3cdaec13
KG
6568 "Ask the user for confirmation using `y-or-n-p'.
6569Send \"y\" to remote process on confirmation, abort otherwise.
6570See also `tramp-action-yesno'."
6571 (save-window-excursion
00d6fd04
MA
6572 (let ((enable-recursive-minibuffers t))
6573 (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec)))
6574 (unless (y-or-n-p (match-string 0))
6575 (kill-process proc)
6576 (throw 'tramp-action 'permission-denied))
6577 (with-current-buffer (tramp-get-connection-buffer vec)
6578 (tramp-message vec 6 "\n%s" (buffer-string)))
6579 (tramp-send-string vec "y"))))
6580
6581(defun tramp-action-terminal (proc vec)
487f4fb7
KG
6582 "Tell the remote host which terminal type to use.
6583The terminal type can be configured with `tramp-terminal-type'."
00d6fd04 6584 (tramp-message vec 5 "Setting `%s' as terminal type." tramp-terminal-type)
7e780ff1
MA
6585 (with-current-buffer (tramp-get-connection-buffer vec)
6586 (tramp-message vec 6 "\n%s" (buffer-string)))
00d6fd04 6587 (tramp-send-string vec tramp-terminal-type))
487f4fb7 6588
00d6fd04 6589(defun tramp-action-process-alive (proc vec)
19a87064 6590 "Check whether a process has finished."
00d6fd04 6591 (unless (memq (process-status proc) '(run open))
19a87064
MA
6592 (throw 'tramp-action 'process-died)))
6593
00d6fd04 6594(defun tramp-action-out-of-band (proc vec)
38c65fca 6595 "Check whether an out-of-band copy has finished."
00d6fd04
MA
6596 (cond ((and (memq (process-status proc) '(stop exit))
6597 (zerop (process-exit-status proc)))
6598 (tramp-message vec 3 "Process has finished.")
38c65fca 6599 (throw 'tramp-action 'ok))
00d6fd04
MA
6600 ((or (and (memq (process-status proc) '(stop exit))
6601 (not (zerop (process-exit-status proc))))
6602 (memq (process-status proc) '(signal)))
01917a18
MA
6603 ;; `scp' could have copied correctly, but set modes could have failed.
6604 ;; This can be ignored.
00d6fd04
MA
6605 (with-current-buffer (process-buffer proc)
6606 (goto-char (point-min))
6607 (if (re-search-forward tramp-operation-not-permitted-regexp nil t)
6608 (progn
6609 (tramp-message vec 5 "'set mode' error ignored.")
6610 (tramp-message vec 3 "Process has finished.")
6611 (throw 'tramp-action 'ok))
6612 (tramp-message vec 3 "Process has died.")
6613 (throw 'tramp-action 'process-died))))
38c65fca
KG
6614 (t nil)))
6615
ac474af1
KG
6616;; Functions for processing the actions.
6617
00d6fd04 6618(defun tramp-process-one-action (proc vec actions)
ac474af1 6619 "Wait for output from the shell and perform one action."
00d6fd04 6620 (let (found todo item pattern action)
e6466697 6621 (while (not found)
00d6fd04
MA
6622 ;; Reread output once all actions have been performed.
6623 ;; Obviously, the output was not complete.
6624 (tramp-accept-process-output proc 1)
e6466697
MA
6625 (setq todo actions)
6626 (while todo
e6466697 6627 (setq item (pop todo))
95d610cb 6628 (setq pattern (format "\\(%s\\)\\'" (symbol-value (nth 0 item))))
e6466697 6629 (setq action (nth 1 item))
00d6fd04
MA
6630 (tramp-message
6631 vec 5 "Looking for regexp \"%s\" from remote shell" pattern)
6632 (when (tramp-check-for-regexp proc pattern)
6633 (tramp-message vec 5 "Call `%s'" (symbol-name action))
6634 (setq found (funcall action proc vec)))))
e6466697
MA
6635 found))
6636
00d6fd04 6637(defun tramp-process-actions (proc vec actions &optional timeout)
e6466697 6638 "Perform actions until success or TIMEOUT."
263c02ef 6639 ;; Enable auth-source and password-cache.
7540f029 6640 (tramp-set-connection-property vec "first-password-request" t)
ac474af1
KG
6641 (let (exit)
6642 (while (not exit)
00d6fd04 6643 (tramp-message proc 3 "Waiting for prompts from remote shell")
ac474af1
KG
6644 (setq exit
6645 (catch 'tramp-action
e6466697
MA
6646 (if timeout
6647 (with-timeout (timeout)
00d6fd04
MA
6648 (tramp-process-one-action proc vec actions))
6649 (tramp-process-one-action proc vec actions)))))
6650 (with-current-buffer (tramp-get-connection-buffer vec)
6651 (tramp-message vec 6 "\n%s" (buffer-string)))
ac474af1 6652 (unless (eq exit 'ok)
9c13938d 6653 (tramp-clear-passwd vec)
00d6fd04
MA
6654 (tramp-error-with-buffer
6655 nil vec 'file-error
6656 (cond
6657 ((eq exit 'permission-denied) "Permission denied")
6658 ((eq exit 'process-died) "Process died")
6659 (t "Login failed"))))))
fb7933a3
KG
6660
6661;; Utility functions.
6662
00d6fd04 6663(defun tramp-accept-process-output (&optional proc timeout timeout-msecs)
d2a2c17f
MA
6664 "Like `accept-process-output' for Tramp processes.
6665This is needed in order to hide `last-coding-system-used', which is set
6666for process communication also."
00d6fd04
MA
6667 (with-current-buffer (process-buffer proc)
6668 (tramp-message proc 10 "%s %s" proc (process-status proc))
6669 (let (buffer-read-only last-coding-system-used)
6670 ;; Under Windows XP, accept-process-output doesn't return
6671 ;; sometimes. So we add an additional timeout.
6672 (with-timeout ((or timeout 1))
6673 (accept-process-output proc timeout timeout-msecs)))
6674 (tramp-message proc 10 "\n%s" (buffer-string))))
6675
6676(defun tramp-check-for-regexp (proc regexp)
6677 "Check whether REGEXP is contained in process buffer of PROC.
6678Erase echoed commands if exists."
6679 (with-current-buffer (process-buffer proc)
6680 (goto-char (point-min))
674da028 6681
00d6fd04
MA
6682 ;; Check whether we need to remove echo output.
6683 (when (and (tramp-get-connection-property proc "check-remote-echo" nil)
6684 (re-search-forward tramp-echoed-echo-mark-regexp nil t))
6685 (let ((begin (match-beginning 0)))
6686 (when (re-search-forward tramp-echoed-echo-mark-regexp nil t)
6687 ;; Discard echo from remote output.
6688 (tramp-set-connection-property proc "check-remote-echo" nil)
6689 (tramp-message proc 5 "echo-mark found")
b533bc97 6690 (forward-line 1)
00d6fd04
MA
6691 (delete-region begin (point))
6692 (goto-char (point-min)))))
674da028 6693
68712eb6
MA
6694 (when (or (not (tramp-get-connection-property proc "check-remote-echo" nil))
6695 ;; Sometimes, the echo string is suppressed on the remote side.
6696 (not (string-equal
6697 (substring-no-properties
6698 tramp-echo-mark-marker
6699 0 (min tramp-echo-mark-marker-length (1- (point-max))))
6700 (buffer-substring-no-properties
6701 1 (min (1+ tramp-echo-mark-marker-length) (point-max))))))
70c11b0b 6702 ;; No echo to be handled, now we can look for the regexp.
674da028 6703 (goto-char (point-min))
00d6fd04 6704 (re-search-forward regexp nil t))))
d2a2c17f 6705
fb7933a3
KG
6706(defun tramp-wait-for-regexp (proc timeout regexp)
6707 "Wait for a REGEXP to appear from process PROC within TIMEOUT seconds.
6708Expects the output of PROC to be sent to the current buffer. Returns
6709the string that matched, or nil. Waits indefinitely if TIMEOUT is
6710nil."
00d6fd04
MA
6711 (with-current-buffer (process-buffer proc)
6712 (let ((found (tramp-check-for-regexp proc regexp))
6713 (start-time (current-time)))
6714 (cond (timeout
6715 ;; Work around a bug in XEmacs 21, where the timeout
6716 ;; expires faster than it should. This degenerates
6717 ;; to polling for buggy XEmacsen, but oh, well.
6718 (while (and (not found)
6719 (< (tramp-time-diff (current-time) start-time)
6720 timeout))
6721 (with-timeout (timeout)
6722 (while (not found)
6723 (tramp-accept-process-output proc 1)
6724 (unless (memq (process-status proc) '(run open))
6725 (tramp-error-with-buffer
6726 nil proc 'file-error "Process has died"))
6727 (setq found (tramp-check-for-regexp proc regexp))))))
6728 (t
6729 (while (not found)
6730 (tramp-accept-process-output proc 1)
6731 (unless (memq (process-status proc) '(run open))
6732 (tramp-error-with-buffer
6733 nil proc 'file-error "Process has died"))
6734 (setq found (tramp-check-for-regexp proc regexp)))))
6735 (tramp-message proc 6 "\n%s" (buffer-string))
fb7933a3 6736 (when (not found)
00d6fd04
MA
6737 (if timeout
6738 (tramp-error
6739 proc 'file-error "[[Regexp `%s' not found in %d secs]]"
6740 regexp timeout)
6741 (tramp-error proc 'file-error "[[Regexp `%s' not found]]" regexp)))
6742 found)))
fb7933a3 6743
b25a52cc
KG
6744(defun tramp-barf-if-no-shell-prompt (proc timeout &rest error-args)
6745 "Wait for shell prompt and barf if none appears.
6746Looks at process PROC to see if a shell prompt appears in TIMEOUT
6747seconds. If not, it produces an error message with the given ERROR-ARGS."
7e780ff1
MA
6748 (unless
6749 (tramp-wait-for-regexp
6750 proc timeout
6751 (format
6752 "\\(%s\\|%s\\)\\'" shell-prompt-pattern tramp-shell-prompt-pattern))
00d6fd04
MA
6753 (apply 'tramp-error-with-buffer nil proc 'file-error error-args)))
6754
7e780ff1
MA
6755;; We don't call `tramp-send-string' in order to hide the password
6756;; from the debug buffer, and because end-of-line handling of the
6757;; string.
6758(defun tramp-enter-password (proc)
00d6fd04
MA
6759 "Prompt for a password and send it to the remote end."
6760 (process-send-string
7e780ff1
MA
6761 proc (concat (tramp-read-passwd proc)
6762 (or (tramp-get-method-parameter
6763 tramp-current-method
6764 'tramp-password-end-of-line)
6765 tramp-default-password-end-of-line))))
00d6fd04
MA
6766
6767(defun tramp-open-connection-setup-interactive-shell (proc vec)
fb7933a3 6768 "Set up an interactive shell.
00d6fd04
MA
6769Mainly sets the prompt and the echo correctly. PROC is the shell
6770process to set up. VEC specifies the connection."
dab816a9 6771 (let ((tramp-end-of-output tramp-initial-end-of-output))
8950769a
MA
6772 ;; It is useful to set the prompt in the following command because
6773 ;; some people have a setting for $PS1 which /bin/sh doesn't know
6774 ;; about and thus /bin/sh will display a strange prompt. For
6775 ;; example, if $PS1 has "${CWD}" in the value, then ksh will
6776 ;; display the current working directory but /bin/sh will display
6777 ;; a dollar sign. The following command line sets $PS1 to a sane
6778 ;; value, and works under Bourne-ish shells as well as csh-like
6779 ;; shells. Daniel Pittman reports that the unusual positioning of
6780 ;; the single quotes makes it work under `rc', too. We also unset
6781 ;; the variable $ENV because that is read by some sh
6782 ;; implementations (eg, bash when called as sh) on startup; this
6783 ;; way, we avoid the startup file clobbering $PS1. $PROMP_COMMAND
6784 ;; is another way to set the prompt in /bin/bash, it must be
6785 ;; discarded as well.
a4aeb9a4
MA
6786 (tramp-send-command
6787 vec
6788 (format
70c11b0b
MA
6789 "exec env ENV='' PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s"
6790 (shell-quote-argument tramp-end-of-output)
a4aeb9a4
MA
6791 (tramp-get-method-parameter
6792 (tramp-file-name-method vec) 'tramp-remote-sh))
8950769a
MA
6793 t)
6794
6795 ;; Disable echo.
6796 (tramp-message vec 5 "Setting up remote shell environment")
6797 (tramp-send-command vec "stty -inlcr -echo kill '^U' erase '^H'" t)
6798 ;; Check whether the echo has really been disabled. Some
6799 ;; implementations, like busybox of embedded GNU/Linux, don't
6800 ;; support disabling.
6801 (tramp-send-command vec "echo foo" t)
6802 (with-current-buffer (process-buffer proc)
6803 (goto-char (point-min))
6804 (when (looking-at "echo foo")
6805 (tramp-set-connection-property proc "remote-echo" t)
6806 (tramp-message vec 5 "Remote echo still on. Ok.")
6807 ;; Make sure backspaces and their echo are enabled and no line
6808 ;; width magic interferes with them.
6809 (tramp-send-command vec "stty icanon erase ^H cols 32767" t))))
e42c6bbc 6810
7e780ff1 6811 (tramp-message vec 5 "Setting shell prompt")
70c11b0b
MA
6812 (tramp-send-command
6813 vec (format "PS1=%s" (shell-quote-argument tramp-end-of-output)) t)
9fa0d3aa
MA
6814 (tramp-send-command vec "PS2=''" t)
6815 (tramp-send-command vec "PS3=''" t)
6816 (tramp-send-command vec "PROMPT_COMMAND=''" t)
e42c6bbc 6817
fb7933a3
KG
6818 ;; Try to set up the coding system correctly.
6819 ;; CCC this can't be the right way to do it. Hm.
00d6fd04 6820 (tramp-message vec 5 "Determining coding system")
7e780ff1 6821 (tramp-send-command vec "echo foo ; echo bar" t)
00d6fd04 6822 (with-current-buffer (process-buffer proc)
fb7933a3
KG
6823 (goto-char (point-min))
6824 (if (featurep 'mule)
00d6fd04
MA
6825 ;; Use MULE to select the right EOL convention for communicating
6826 ;; with the process.
311dd93f 6827 (let* ((cs (or (funcall (symbol-function 'process-coding-system) proc)
00d6fd04
MA
6828 (cons 'undecided 'undecided)))
6829 cs-decode cs-encode)
6830 (when (symbolp cs) (setq cs (cons cs cs)))
6831 (setq cs-decode (car cs))
6832 (setq cs-encode (cdr cs))
6833 (unless cs-decode (setq cs-decode 'undecided))
6834 (unless cs-encode (setq cs-encode 'undecided))
6835 (setq cs-encode (tramp-coding-system-change-eol-conversion
6836 cs-encode 'unix))
6837 (when (search-forward "\r" nil t)
6838 (setq cs-decode (tramp-coding-system-change-eol-conversion
6839 cs-decode 'dos)))
311dd93f 6840 (funcall (symbol-function 'set-buffer-process-coding-system)
70c11b0b
MA
6841 cs-decode cs-encode)
6842 (tramp-message
6843 vec 5 "Setting coding system to `%s' and `%s'" cs-decode cs-encode))
fb7933a3
KG
6844 ;; Look for ^M and do something useful if found.
6845 (when (search-forward "\r" nil t)
00d6fd04
MA
6846 ;; We have found a ^M but cannot frob the process coding system
6847 ;; because we're running on a non-MULE Emacs. Let's try
6848 ;; stty, instead.
7e780ff1 6849 (tramp-send-command vec "stty -onlcr" t))))
7e5686f0
MA
6850 ;; Dump stty settings in the traces.
6851 (when (>= tramp-verbose 10)
6852 (tramp-send-command vec "stty -a" t))
7e780ff1 6853 (tramp-send-command vec "set +o vi +o emacs" t)
e42c6bbc
MA
6854
6855 ;; Check whether the output of "uname -sr" has been changed. If
6856 ;; yes, this is a strong indication that we must expire all
d8ac123e
MA
6857 ;; connection properties. We start again with
6858 ;; `tramp-maybe-open-connection', it will be catched there.
e42c6bbc
MA
6859 (tramp-message vec 5 "Checking system information")
6860 (let ((old-uname (tramp-get-connection-property vec "uname" nil))
6861 (new-uname
6862 (tramp-set-connection-property
6863 vec "uname"
6864 (tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\""))))
6865 (when (and (stringp old-uname) (not (string-equal old-uname new-uname)))
d8ac123e
MA
6866 (with-current-buffer (tramp-get-debug-buffer vec)
6867 ;; Keep the debug buffer
2296b54d
MA
6868 (rename-buffer
6869 (generate-new-buffer-name tramp-temp-buffer-name) 'unique)
d8ac123e
MA
6870 (funcall (symbol-function 'tramp-cleanup-connection) vec)
6871 (if (= (point-min) (point-max))
6872 (kill-buffer nil)
6873 (rename-buffer (tramp-debug-buffer-name vec) 'unique))
6874 ;; We call `tramp-get-buffer' in order to keep the debug buffer.
6875 (tramp-get-buffer vec)
6876 (tramp-message
6877 vec 3
6878 "Connection reset, because remote host changed from `%s' to `%s'"
6879 old-uname new-uname)
6880 (throw 'uname-changed (tramp-maybe-open-connection vec)))))
e42c6bbc
MA
6881
6882 ;; Check whether the remote host suffers from buggy
6883 ;; `send-process-string'. This is known for FreeBSD (see comment in
6884 ;; `send_process', file process.c). I've tested sending 624 bytes
6885 ;; successfully, sending 625 bytes failed. Emacs makes a hack when
6886 ;; this host type is detected locally. It cannot handle remote
6887 ;; hosts, though.
00d6fd04
MA
6888 (with-connection-property proc "chunksize"
6889 (cond
6890 ((and (integerp tramp-chunksize) (> tramp-chunksize 0))
6891 tramp-chunksize)
6892 (t
6893 (tramp-message
6894 vec 5 "Checking remote host type for `send-process-string' bug")
6895 (if (string-match
e42c6bbc 6896 "^FreeBSD" (tramp-get-connection-property vec "uname" ""))
00d6fd04 6897 500 0))))
e42c6bbc 6898
00d6fd04
MA
6899 ;; Set remote PATH variable.
6900 (tramp-set-remote-path vec)
e42c6bbc 6901
fb7933a3
KG
6902 ;; Search for a good shell before searching for a command which
6903 ;; checks if a file exists. This is done because Tramp wants to use
6904 ;; "test foo; echo $?" to check if various conditions hold, and
6905 ;; there are buggy /bin/sh implementations which don't execute the
6906 ;; "echo $?" part if the "test" part has an error. In particular,
c0e17ff2
MA
6907 ;; the OpenSolaris /bin/sh is a problem. There are also other
6908 ;; problems with /bin/sh of OpenSolaris, like redirection of stderr
6909 ;; in in function declarations, or changing HISTFILE in place.
6910 ;; Therefore, OpenSolaris' /bin/sh is replaced by bash, when
6911 ;; detected.
00d6fd04 6912 (tramp-find-shell vec)
e42c6bbc 6913
00d6fd04 6914 ;; Disable unexpected output.
7e780ff1 6915 (tramp-send-command vec "mesg n; biff n" t)
e42c6bbc 6916
00d6fd04
MA
6917 ;; Set the environment.
6918 (tramp-message vec 5 "Setting default environment")
661aaece 6919
00d6fd04
MA
6920 (let ((env (copy-sequence tramp-remote-process-environment))
6921 unset item)
6922 (while env
70c11b0b 6923 (setq item (tramp-compat-split-string (car env) "="))
7e5686f0
MA
6924 (setcdr item (mapconcat 'identity (cdr item) "="))
6925 (if (and (stringp (cdr item)) (not (string-equal (cdr item) "")))
00d6fd04 6926 (tramp-send-command
7e5686f0 6927 vec (format "%s=%s; export %s" (car item) (cdr item) (car item)) t)
00d6fd04
MA
6928 (push (car item) unset))
6929 (setq env (cdr env)))
6930 (when unset
fb7933a3 6931 (tramp-send-command
7e780ff1 6932 vec (format "unset %s" (mapconcat 'identity unset " "))))) t)
fb7933a3 6933
ac474af1
KG
6934;; CCC: We should either implement a Perl version of base64 encoding
6935;; and decoding. Then we just use that in the last item. The other
6936;; alternative is to use the Perl version of UU encoding. But then
6937;; we need a Lisp version of uuencode.
16674e4f
KG
6938;;
6939;; Old text from documentation of tramp-methods:
6940;; Using a uuencode/uudecode inline method is discouraged, please use one
6941;; of the base64 methods instead since base64 encoding is much more
6942;; reliable and the commands are more standardized between the different
6943;; Unix versions. But if you can't use base64 for some reason, please
6944;; note that the default uudecode command does not work well for some
6945;; Unices, in particular AIX and Irix. For AIX, you might want to use
6946;; the following command for uudecode:
6947;;
6948;; sed '/^begin/d;/^[` ]$/d;/^end/d' | iconv -f uucode -t ISO8859-1
6949;;
6950;; For Irix, no solution is known yet.
6951
00d6fd04
MA
6952(defconst tramp-local-coding-commands
6953 '((b64 base64-encode-region base64-decode-region)
6954 (uu tramp-uuencode-region uudecode-decode-region)
6955 (pack
6956 "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
6957 "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"))
6958 "List of local coding commands for inline transfer.
16674e4f
KG
6959Each item is a list that looks like this:
6960
b533bc97 6961\(FORMAT ENCODING DECODING\)
ac474af1 6962
00d6fd04
MA
6963FORMAT is symbol describing the encoding/decoding format. It can be
6964`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
ac474af1 6965
00d6fd04
MA
6966ENCODING and DECODING can be strings, giving commands, or symbols,
6967giving functions. If they are strings, then they can contain
16674e4f
KG
6968the \"%s\" format specifier. If that specifier is present, the input
6969filename will be put into the command line at that spot. If the
6970specifier is not present, the input should be read from standard
6971input.
ac474af1 6972
16674e4f
KG
6973If they are functions, they will be called with two arguments, start
6974and end of region, and are expected to replace the region contents
6975with the encoded or decoded results, respectively.")
ac474af1 6976
00d6fd04 6977(defconst tramp-remote-coding-commands
3dc847a3
MA
6978 '((b64 "base64" "base64 -d")
6979 (b64 "mimencode -b" "mimencode -u -b")
00d6fd04
MA
6980 (b64 "mmencode -b" "mmencode -u -b")
6981 (b64 "recode data..base64" "recode base64..data")
6982 (b64 tramp-perl-encode-with-module tramp-perl-decode-with-module)
6983 (b64 tramp-perl-encode tramp-perl-decode)
6984 (uu "uuencode xxx" "uudecode -o /dev/stdout")
6985 (uu "uuencode xxx" "uudecode -o -")
6986 (uu "uuencode xxx" "uudecode -p")
6987 (uu "uuencode xxx" tramp-uudecode)
6988 (pack
6989 "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
6990 "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"))
6991 "List of remote coding commands for inline transfer.
6992Each item is a list that looks like this:
6993
b533bc97 6994\(FORMAT ENCODING DECODING\)
00d6fd04
MA
6995
6996FORMAT is symbol describing the encoding/decoding format. It can be
6997`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
6998
6999ENCODING and DECODING can be strings, giving commands, or symbols,
7000giving variables. If they are strings, then they can contain
7001the \"%s\" format specifier. If that specifier is present, the input
7002filename will be put into the command line at that spot. If the
7003specifier is not present, the input should be read from standard
7004input.
7005
7006If they are variables, this variable is a string containing a Perl
7007implementation for this functionality. This Perl program will be transferred
db9e401b 7008to the remote host, and it is available as shell function with the same name.")
00d6fd04
MA
7009
7010(defun tramp-find-inline-encoding (vec)
ac474af1 7011 "Find an inline transfer encoding that works.
00d6fd04
MA
7012Goes through the list `tramp-local-coding-commands' and
7013`tramp-remote-coding-commands'."
7014 (save-excursion
7015 (let ((local-commands tramp-local-coding-commands)
7016 (magic "xyzzy")
7017 loc-enc loc-dec rem-enc rem-dec litem ritem found)
7018 (while (and local-commands (not found))
7019 (setq litem (pop local-commands))
7020 (catch 'wont-work-local
7021 (let ((format (nth 0 litem))
7022 (remote-commands tramp-remote-coding-commands))
7023 (setq loc-enc (nth 1 litem))
7024 (setq loc-dec (nth 2 litem))
7025 ;; If the local encoder or decoder is a string, the
7026 ;; corresponding command has to work locally.
7027 (if (not (stringp loc-enc))
7028 (tramp-message
7029 vec 5 "Checking local encoding function `%s'" loc-enc)
7030 (tramp-message
7031 vec 5 "Checking local encoding command `%s' for sanity" loc-enc)
7032 (unless (zerop (tramp-call-local-coding-command
7033 loc-enc nil nil))
7034 (throw 'wont-work-local nil)))
7035 (if (not (stringp loc-dec))
7036 (tramp-message
7037 vec 5 "Checking local decoding function `%s'" loc-dec)
7038 (tramp-message
7039 vec 5 "Checking local decoding command `%s' for sanity" loc-dec)
7040 (unless (zerop (tramp-call-local-coding-command
7041 loc-dec nil nil))
7042 (throw 'wont-work-local nil)))
7043 ;; Search for remote coding commands with the same format
7044 (while (and remote-commands (not found))
7045 (setq ritem (pop remote-commands))
7046 (catch 'wont-work-remote
7047 (when (equal format (nth 0 ritem))
7048 (setq rem-enc (nth 1 ritem))
7049 (setq rem-dec (nth 2 ritem))
7050 ;; Check if remote encoding and decoding commands can be
7051 ;; called remotely with null input and output. This makes
7052 ;; sure there are no syntax errors and the command is really
7053 ;; found. Note that we do not redirect stdout to /dev/null,
7054 ;; for two reasons: when checking the decoding command, we
7055 ;; actually check the output it gives. And also, when
7056 ;; redirecting "mimencode" output to /dev/null, then as root
7057 ;; it might change the permissions of /dev/null!
7058 (when (not (stringp rem-enc))
7059 (let ((name (symbol-name rem-enc)))
7060 (while (string-match (regexp-quote "-") name)
7061 (setq name (replace-match "_" nil t name)))
7062 (tramp-maybe-send-script vec (symbol-value rem-enc) name)
7063 (setq rem-enc name)))
7064 (tramp-message
7065 vec 5
7066 "Checking remote encoding command `%s' for sanity" rem-enc)
7067 (unless (zerop (tramp-send-command-and-check
7068 vec (format "%s </dev/null" rem-enc) t))
7069 (throw 'wont-work-remote nil))
7070
7071 (when (not (stringp rem-dec))
7072 (let ((name (symbol-name rem-dec)))
7073 (while (string-match (regexp-quote "-") name)
7074 (setq name (replace-match "_" nil t name)))
7075 (tramp-maybe-send-script vec (symbol-value rem-dec) name)
7076 (setq rem-dec name)))
7077 (tramp-message
7078 vec 5
7079 "Checking remote decoding command `%s' for sanity" rem-dec)
7080 (unless (zerop (tramp-send-command-and-check
7081 vec
7082 (format "echo %s | %s | %s"
b593f105
MA
7083 magic rem-enc rem-dec)
7084 t))
00d6fd04
MA
7085 (throw 'wont-work-remote nil))
7086
7087 (with-current-buffer (tramp-get-buffer vec)
7088 (goto-char (point-min))
7089 (unless (looking-at (regexp-quote magic))
7090 (throw 'wont-work-remote nil)))
7091
7092 ;; `rem-enc' and `rem-dec' could be a string meanwhile.
7093 (setq rem-enc (nth 1 ritem))
7094 (setq rem-dec (nth 2 ritem))
7095 (setq found t)))))))
7096
1d7e9a01 7097 ;; Did we find something?
00d6fd04 7098 (unless found
7e5686f0
MA
7099 (tramp-error
7100 vec 'file-error "Couldn't find an inline transfer encoding"))
00d6fd04
MA
7101
7102 ;; Set connection properties.
7103 (tramp-message vec 5 "Using local encoding `%s'" loc-enc)
7104 (tramp-set-connection-property vec "local-encoding" loc-enc)
7105 (tramp-message vec 5 "Using local decoding `%s'" loc-dec)
7106 (tramp-set-connection-property vec "local-decoding" loc-dec)
7107 (tramp-message vec 5 "Using remote encoding `%s'" rem-enc)
7108 (tramp-set-connection-property vec "remote-encoding" rem-enc)
7109 (tramp-message vec 5 "Using remote decoding `%s'" rem-dec)
7110 (tramp-set-connection-property vec "remote-decoding" rem-dec))))
16674e4f
KG
7111
7112(defun tramp-call-local-coding-command (cmd input output)
7113 "Call the local encoding or decoding command.
7114If CMD contains \"%s\", provide input file INPUT there in command.
7115Otherwise, INPUT is passed via standard input.
7116INPUT can also be nil which means `/dev/null'.
7117OUTPUT can be a string (which specifies a filename), or t (which
7118means standard output and thus the current buffer), or nil (which
7119means discard it)."
a4aeb9a4
MA
7120 (tramp-local-call-process
7121 tramp-encoding-shell
7122 (when (and input (not (string-match "%s" cmd))) input)
7123 (if (eq output t) t nil)
7124 nil
7125 tramp-encoding-command-switch
7126 (concat
7127 (if (string-match "%s" cmd) (format cmd input) cmd)
7128 (if (stringp output) (concat "> " output) ""))))
00d6fd04
MA
7129
7130(defun tramp-compute-multi-hops (vec)
7131 "Expands VEC according to `tramp-default-proxies-alist'.
7132Gateway hops are already opened."
7133 (let ((target-alist `(,vec))
7134 (choices tramp-default-proxies-alist)
7135 item proxy)
7136
7137 ;; Look for proxy hosts to be passed.
7138 (while choices
7139 (setq item (pop choices)
70c11b0b 7140 proxy (eval (nth 2 item)))
00d6fd04
MA
7141 (when (and
7142 ;; host
70c11b0b 7143 (string-match (or (eval (nth 0 item)) "")
00d6fd04
MA
7144 (or (tramp-file-name-host (car target-alist)) ""))
7145 ;; user
70c11b0b 7146 (string-match (or (eval (nth 1 item)) "")
00d6fd04
MA
7147 (or (tramp-file-name-user (car target-alist)) "")))
7148 (if (null proxy)
7149 ;; No more hops needed.
7150 (setq choices nil)
7151 ;; Replace placeholders.
7152 (setq proxy
7153 (format-spec
7154 proxy
b533bc97
MA
7155 (format-spec-make
7156 ?u (or (tramp-file-name-user (car target-alist)) "")
7157 ?h (or (tramp-file-name-host (car target-alist)) ""))))
00d6fd04
MA
7158 (with-parsed-tramp-file-name proxy l
7159 ;; Add the hop.
7160 (add-to-list 'target-alist l)
7161 ;; Start next search.
7162 (setq choices tramp-default-proxies-alist)))))
7163
7164 ;; Handle gateways.
8a4438b6
MA
7165 (when (and (boundp 'tramp-gw-tunnel-method)
7166 (string-match (format
7167 "^\\(%s\\|%s\\)$"
7168 (symbol-value 'tramp-gw-tunnel-method)
7169 (symbol-value 'tramp-gw-socks-method))
7170 (tramp-file-name-method (car target-alist))))
00d6fd04
MA
7171 (let ((gw (pop target-alist))
7172 (hop (pop target-alist)))
7173 ;; Is the method prepared for gateways?
7174 (unless (tramp-get-method-parameter
7175 (tramp-file-name-method hop) 'tramp-default-port)
7176 (tramp-error
7177 vec 'file-error
7178 "Method `%s' is not supported for gateway access."
7179 (tramp-file-name-method hop)))
7180 ;; Add default port if needed.
7181 (unless
7182 (string-match
7183 tramp-host-with-port-regexp (tramp-file-name-host hop))
7184 (aset hop 2
7185 (concat
7186 (tramp-file-name-host hop) tramp-prefix-port-format
7187 (number-to-string
7188 (tramp-get-method-parameter
7189 (tramp-file-name-method hop) 'tramp-default-port)))))
7190 ;; Open the gateway connection.
7191 (add-to-list
7192 'target-alist
7193 (vector
7194 (tramp-file-name-method hop) (tramp-file-name-user hop)
9e6ab520 7195 (funcall (symbol-function 'tramp-gw-open-connection) vec gw hop) nil))
00d6fd04
MA
7196 ;; For the password prompt, we need the correct values.
7197 ;; Therefore, we must remember the gateway vector. But we
7198 ;; cannot do it as connection property, because it shouldn't
7199 ;; be persistent. And we have no started process yet either.
7200 (tramp-set-file-property (car target-alist) "" "gateway" hop)))
7201
7202 ;; Foreign and out-of-band methods are not supported for multi-hops.
7203 (when (cdr target-alist)
7204 (setq choices target-alist)
7205 (while choices
7206 (setq item (pop choices))
7207 (when
7208 (or
7209 (not
7210 (tramp-get-method-parameter
7211 (tramp-file-name-method item) 'tramp-login-program))
7212 (tramp-get-method-parameter
7213 (tramp-file-name-method item) 'tramp-copy-program))
7214 (tramp-error
7215 vec 'file-error
7216 "Method `%s' is not supported for multi-hops."
7217 (tramp-file-name-method item)))))
7218
2991e49f
MA
7219 ;; In case the host name is not used for the remote shell
7220 ;; command, the user could be misguided by applying a random
7221 ;; hostname.
7222 (let* ((v (car target-alist))
7223 (method (tramp-file-name-method v))
7224 (host (tramp-file-name-host v)))
7225 (unless
7226 (or
7227 ;; There are multi-hops.
7228 (cdr target-alist)
7229 ;; The host name is used for the remote shell command.
7230 (member
7231 '("%h") (tramp-get-method-parameter method 'tramp-login-args))
7232 ;; The host is local. We cannot use `tramp-local-host-p'
7233 ;; here, because it opens a connection as well.
b96e6899 7234 (string-match tramp-local-host-regexp host))
2991e49f 7235 (tramp-error
42bc9b6d
MA
7236 v 'file-error
7237 "Host `%s' looks like a remote host, `%s' can only use the local host"
7238 host method)))
2991e49f 7239
00d6fd04
MA
7240 ;; Result.
7241 target-alist))
7242
7243(defun tramp-maybe-open-connection (vec)
7244 "Maybe open a connection VEC.
fb7933a3
KG
7245Does not do anything if a connection is already open, but re-opens the
7246connection if a previous connection has died for some reason."
d8ac123e
MA
7247 (catch 'uname-changed
7248 (let ((p (tramp-get-connection-process vec))
7249 (process-environment (copy-sequence process-environment)))
7250
7251 ;; If too much time has passed since last command was sent, look
7252 ;; whether process is still alive. If it isn't, kill it. When
7253 ;; using ssh, it can sometimes happen that the remote end has
7254 ;; hung up but the local ssh client doesn't recognize this until
7255 ;; it tries to send some data to the remote end. So that's why
7256 ;; we try to send a command from time to time, then look again
7257 ;; whether the process is really alive.
7258 (condition-case nil
7259 (when (and (> (tramp-time-diff
7260 (current-time)
7261 (tramp-get-connection-property
7262 p "last-cmd-time" '(0 0 0)))
7263 60)
7264 p (processp p) (memq (process-status p) '(run open)))
7265 (tramp-send-command vec "echo are you awake" t t)
7266 (unless (and (memq (process-status p) '(run open))
7267 (tramp-wait-for-output p 10))
7268 ;; The error will be catched locally.
7269 (tramp-error vec 'file-error "Awake did fail")))
7270 (file-error
7271 (tramp-flush-connection-property vec)
7272 (tramp-flush-connection-property p)
7273 (delete-process p)
7274 (setq p nil)))
7275
7276 ;; New connection must be opened.
7277 (unless (and p (processp p) (memq (process-status p) '(run open)))
7278
7279 ;; We call `tramp-get-buffer' in order to get a debug buffer for
7280 ;; messages from the beginning.
7281 (tramp-get-buffer vec)
7282 (if (zerop (length (tramp-file-name-user vec)))
7283 (tramp-message
7284 vec 3 "Opening connection for %s using %s..."
7285 (tramp-file-name-host vec)
7286 (tramp-file-name-method vec))
00d6fd04 7287 (tramp-message
d8ac123e
MA
7288 vec 3 "Opening connection for %s@%s using %s..."
7289 (tramp-file-name-user vec)
00d6fd04 7290 (tramp-file-name-host vec)
d8ac123e
MA
7291 (tramp-file-name-method vec)))
7292
7293 ;; Start new process.
7294 (when (and p (processp p))
7295 (delete-process p))
7296 (setenv "TERM" tramp-terminal-type)
7297 (setenv "LC_ALL" "C")
7298 (setenv "PROMPT_COMMAND")
dab816a9 7299 (setenv "PS1" tramp-initial-end-of-output)
d8ac123e
MA
7300 (let* ((target-alist (tramp-compute-multi-hops vec))
7301 (process-connection-type tramp-process-connection-type)
7302 (process-adaptive-read-buffering nil)
7303 (coding-system-for-read nil)
7304 ;; This must be done in order to avoid our file name handler.
7305 (p (let ((default-directory
7306 (tramp-compat-temporary-file-directory)))
7307 (start-process
7308 (or (tramp-get-connection-property vec "process-name" nil)
7309 (tramp-buffer-name vec))
7310 (tramp-get-connection-buffer vec)
70c11b0b 7311 tramp-encoding-shell))))
00d6fd04 7312
d8ac123e
MA
7313 (tramp-message
7314 vec 6 "%s" (mapconcat 'identity (process-command p) " "))
7315
7316 ;; Check whether process is alive.
d8ac123e
MA
7317 (tramp-set-process-query-on-exit-flag p nil)
7318 (tramp-message vec 3 "Waiting 60s for local shell to come up...")
7319 (tramp-barf-if-no-shell-prompt
7320 p 60 "Couldn't find local shell prompt %s" tramp-encoding-shell)
7321
7322 ;; Now do all the connections as specified.
7323 (while target-alist
7324 (let* ((hop (car target-alist))
7325 (l-method (tramp-file-name-method hop))
7326 (l-user (tramp-file-name-user hop))
7327 (l-host (tramp-file-name-host hop))
7328 (l-port nil)
7329 (login-program
7330 (tramp-get-method-parameter l-method 'tramp-login-program))
7331 (login-args
7332 (tramp-get-method-parameter l-method 'tramp-login-args))
7333 (gw-args
7334 (tramp-get-method-parameter l-method 'tramp-gw-args))
7335 (gw (tramp-get-file-property hop "" "gateway" nil))
7336 (g-method (and gw (tramp-file-name-method gw)))
7337 (g-user (and gw (tramp-file-name-user gw)))
7338 (g-host (and gw (tramp-file-name-host gw)))
7339 (command login-program)
7340 ;; We don't create the temporary file. In fact, it
7341 ;; is just a prefix for the ControlPath option of
7342 ;; ssh; the real temporary file has another name, and
7343 ;; it is created and protected by ssh. It is also
7344 ;; removed by ssh, when the connection is closed.
7345 (tmpfile
7346 (tramp-set-connection-property
7347 p "temp-file"
7348 (make-temp-name
7349 (expand-file-name
7350 tramp-temp-name-prefix
7351 (tramp-compat-temporary-file-directory)))))
7352 spec)
7353
7354 ;; Add gateway arguments if necessary.
7355 (when (and gw gw-args)
7356 (setq login-args (append login-args gw-args)))
7357
7358 ;; Check for port number. Until now, there's no need
7359 ;; for handling like method, user, host.
7360 (when (string-match tramp-host-with-port-regexp l-host)
7361 (setq l-port (match-string 2 l-host)
7362 l-host (match-string 1 l-host)))
7363
7364 ;; Set variables for computing the prompt for reading
2296b54d 7365 ;; password. They can also be derived from a gateway.
d8ac123e
MA
7366 (setq tramp-current-method (or g-method l-method)
7367 tramp-current-user (or g-user l-user)
7368 tramp-current-host (or g-host l-host))
7369
7370 ;; Replace login-args place holders.
7371 (setq
7372 l-host (or l-host "")
7373 l-user (or l-user "")
7374 l-port (or l-port "")
b533bc97 7375 spec (format-spec-make ?h l-host ?u l-user ?p l-port ?t tmpfile)
d8ac123e
MA
7376 command
7377 (concat
e2a421af
MA
7378 ;; We do not want to see the trailing local prompt in
7379 ;; `start-file-process'.
7380 (unless (memq system-type '(windows-nt)) "exec ")
d8ac123e
MA
7381 command " "
7382 (mapconcat
aa485f7c
MA
7383 (lambda (x)
7384 (setq x (mapcar (lambda (y) (format-spec y spec)) x))
7385 (unless (member "" x) (mapconcat 'identity x " ")))
d8ac123e 7386 login-args " ")
d8ac123e
MA
7387 ;; Local shell could be a Windows COMSPEC. It doesn't
7388 ;; know the ";" syntax, but we must exit always for
70c11b0b 7389 ;; `start-file-process'. "exec" does not work either.
e2a421af 7390 (if (memq system-type '(windows-nt)) " && exit || exit")))
d8ac123e
MA
7391
7392 ;; Send the command.
7393 (tramp-message vec 3 "Sending command `%s'" command)
7394 (tramp-send-command vec command t t)
7395 (tramp-process-actions p vec tramp-actions-before-shell 60)
7396 (tramp-message vec 3 "Found remote shell prompt on `%s'" l-host))
7397 ;; Next hop.
7398 (setq target-alist (cdr target-alist)))
7399
7400 ;; Make initial shell settings.
7401 (tramp-open-connection-setup-interactive-shell p vec))))))
00d6fd04
MA
7402
7403(defun tramp-send-command (vec command &optional neveropen nooutput)
7404 "Send the COMMAND to connection VEC.
7405Erases temporary buffer before sending the command. If optional
7406arg NEVEROPEN is non-nil, never try to open the connection. This
7407is meant to be used from `tramp-maybe-open-connection' only. The
7408function waits for output unless NOOUTPUT is set."
7409 (unless neveropen (tramp-maybe-open-connection vec))
7410 (let ((p (tramp-get-connection-process vec)))
8950769a 7411 (when (tramp-get-connection-property p "remote-echo" nil)
00d6fd04
MA
7412 ;; We mark the command string that it can be erased in the output buffer.
7413 (tramp-set-connection-property p "check-remote-echo" t)
7414 (setq command (format "%s%s%s" tramp-echo-mark command tramp-echo-mark)))
7415 (tramp-message vec 6 "%s" command)
7416 (tramp-send-string vec command)
7417 (unless nooutput (tramp-wait-for-output p))))
7418
00d6fd04 7419(defun tramp-wait-for-output (proc &optional timeout)
7e5686f0
MA
7420 "Wait for output from remote command."
7421 (unless (buffer-live-p (process-buffer proc))
7422 (delete-process proc)
7423 (tramp-error proc 'file-error "Process `%s' not available, try again" proc))
00d6fd04 7424 (with-current-buffer (process-buffer proc)
dab816a9 7425 (let* (;; Initially, `tramp-end-of-output' is "#$ ". There might
bede3e9f 7426 ;; be leading escape sequences, which must be ignored.
dab816a9 7427 (regexp (format "[^#$\n]*%s\r?$" (regexp-quote tramp-end-of-output)))
bede3e9f
MA
7428 ;; Sometimes, the commands do not return a newline but a
7429 ;; null byte before the shell prompt, for example "git
7430 ;; ls-files -c -z ...".
7431 (regexp1 (format "\\(^\\|\000\\)%s" regexp))
7432 (found (tramp-wait-for-regexp proc timeout regexp1)))
00d6fd04
MA
7433 (if found
7434 (let (buffer-read-only)
7e5686f0
MA
7435 ;; A simple-minded busybox has sent " ^H" sequences.
7436 ;; Delete them.
7437 (goto-char (point-min))
7438 (when (re-search-forward
7439 "^\\(.\b\\)+$" (tramp-compat-line-end-position) t)
7440 (forward-line 1)
7441 (delete-region (point-min) (point)))
7442 ;; Delete the prompt.
00d6fd04 7443 (goto-char (point-max))
0664ff72 7444 (re-search-backward regexp nil t)
00d6fd04
MA
7445 (delete-region (point) (point-max)))
7446 (if timeout
7447 (tramp-error
7448 proc 'file-error
7449 "[[Remote prompt `%s' not found in %d secs]]"
7450 tramp-end-of-output timeout)
7451 (tramp-error
7452 proc 'file-error
7453 "[[Remote prompt `%s' not found]]" tramp-end-of-output)))
7454 ;; Return value is whether end-of-output sentinel was found.
7455 found)))
fb7933a3 7456
b593f105
MA
7457(defun tramp-send-command-and-check
7458 (vec command &optional subshell dont-suppress-err)
fb7933a3 7459 "Run COMMAND and check its exit status.
fb7933a3
KG
7460Sends `echo $?' along with the COMMAND for checking the exit status. If
7461COMMAND is nil, just sends `echo $?'. Returns the exit status found.
7462
b593f105
MA
7463If the optional argument SUBSHELL is non-nil, the command is
7464executed in a subshell, ie surrounded by parentheses. If
7465DONT-SUPPRESS-ERR is non-nil, stderr won't be sent to /dev/null."
00d6fd04
MA
7466 (tramp-send-command
7467 vec
7468 (concat (if subshell "( " "")
7469 command
b593f105 7470 (if command (if dont-suppress-err "; " " 2>/dev/null; ") "")
00d6fd04 7471 "echo tramp_exit_status $?"
b593f105 7472 (if subshell " )" "")))
00d6fd04
MA
7473 (with-current-buffer (tramp-get-connection-buffer vec)
7474 (goto-char (point-max))
7475 (unless (re-search-backward "tramp_exit_status [0-9]+" nil t)
7476 (tramp-error
7477 vec 'file-error "Couldn't find exit status of `%s'" command))
7478 (skip-chars-forward "^ ")
7479 (prog1
7480 (read (current-buffer))
7481 (let (buffer-read-only) (delete-region (match-beginning 0) (point-max))))))
7482
7483(defun tramp-barf-unless-okay (vec command fmt &rest args)
fb7933a3
KG
7484 "Run COMMAND, check exit status, throw error if exit status not okay.
7485Similar to `tramp-send-command-and-check' but accepts two more arguments
7486FMT and ARGS which are passed to `error'."
00d6fd04
MA
7487 (unless (zerop (tramp-send-command-and-check vec command))
7488 (apply 'tramp-error vec 'file-error fmt args)))
7489
7490(defun tramp-send-command-and-read (vec command)
7491 "Run COMMAND and return the output, which must be a Lisp expression.
7492In case there is no valid Lisp expression, it raises an error"
7493 (tramp-barf-unless-okay vec command "`%s' returns with error" command)
7494 (with-current-buffer (tramp-get-connection-buffer vec)
7495 ;; Read the expression.
7496 (goto-char (point-min))
7497 (condition-case nil
7498 (prog1 (read (current-buffer))
7499 ;; Error handling.
9e6ab520 7500 (when (re-search-forward "\\S-" (tramp-compat-line-end-position) t)
9ce8462a 7501 (error nil)))
00d6fd04
MA
7502 (error (tramp-error
7503 vec 'file-error
7504 "`%s' does not return a valid Lisp expression: `%s'"
7505 command (buffer-string))))))
fb7933a3 7506
7432277c
KG
7507;; It seems that Tru64 Unix does not like it if long strings are sent
7508;; to it in one go. (This happens when sending the Perl
7509;; `file-attributes' implementation, for instance.) Therefore, we
27e813fe 7510;; have this function which sends the string in chunks.
00d6fd04
MA
7511(defun tramp-send-string (vec string)
7512 "Send the STRING via connection VEC.
7432277c
KG
7513
7514The STRING is expected to use Unix line-endings, but the lines sent to
7515the remote host use line-endings as defined in the variable
00d6fd04
MA
7516`tramp-rsh-end-of-line'. The communication buffer is erased before sending."
7517 (let* ((p (tramp-get-connection-process vec))
7518 (chunksize (tramp-get-connection-property p "chunksize" nil)))
7519 (unless p
7520 (tramp-error
7521 vec 'file-error "Can't send string to remote host -- not logged in"))
7522 (tramp-set-connection-property p "last-cmd-time" (current-time))
7523 (tramp-message vec 10 "%s" string)
7524 (with-current-buffer (tramp-get-connection-buffer vec)
7525 ;; Clean up the buffer. We cannot call `erase-buffer' because
7526 ;; narrowing might be in effect.
7527 (let (buffer-read-only) (delete-region (point-min) (point-max)))
27e813fe 7528 ;; Replace "\n" by `tramp-rsh-end-of-line'.
00d6fd04
MA
7529 (setq string
7530 (mapconcat 'identity
70c11b0b 7531 (tramp-compat-split-string string "\n")
00d6fd04
MA
7532 tramp-rsh-end-of-line))
7533 (unless (or (string= string "")
7534 (string-equal (substring string -1) tramp-rsh-end-of-line))
7535 (setq string (concat string tramp-rsh-end-of-line)))
27e813fe 7536 ;; Send the string.
00d6fd04
MA
7537 (if (and chunksize (not (zerop chunksize)))
7538 (let ((pos 0)
7539 (end (length string)))
7540 (while (< pos end)
7541 (tramp-message
7542 vec 10 "Sending chunk from %s to %s"
7543 pos (min (+ pos chunksize) end))
7544 (process-send-string
7545 p (substring string pos (min (+ pos chunksize) end)))
7546 (setq pos (+ pos chunksize))))
7547 (process-send-string p string)))))
fb7933a3
KG
7548
7549(defun tramp-mode-string-to-int (mode-string)
7550 "Converts a ten-letter `drwxrwxrwx'-style mode string into mode bits."
f3c071dd
MA
7551 (let* (case-fold-search
7552 (mode-chars (string-to-vector mode-string))
fb7933a3
KG
7553 (owner-read (aref mode-chars 1))
7554 (owner-write (aref mode-chars 2))
7555 (owner-execute-or-setid (aref mode-chars 3))
7556 (group-read (aref mode-chars 4))
7557 (group-write (aref mode-chars 5))
7558 (group-execute-or-setid (aref mode-chars 6))
7559 (other-read (aref mode-chars 7))
7560 (other-write (aref mode-chars 8))
7561 (other-execute-or-sticky (aref mode-chars 9)))
7562 (save-match-data
7563 (logior
f3c071dd
MA
7564 (cond
7565 ((char-equal owner-read ?r) (tramp-octal-to-decimal "00400"))
7566 ((char-equal owner-read ?-) 0)
7567 (t (error "Second char `%c' must be one of `r-'" owner-read)))
7568 (cond
7569 ((char-equal owner-write ?w) (tramp-octal-to-decimal "00200"))
7570 ((char-equal owner-write ?-) 0)
7571 (t (error "Third char `%c' must be one of `w-'" owner-write)))
7572 (cond
7573 ((char-equal owner-execute-or-setid ?x)
7574 (tramp-octal-to-decimal "00100"))
7575 ((char-equal owner-execute-or-setid ?S)
7576 (tramp-octal-to-decimal "04000"))
7577 ((char-equal owner-execute-or-setid ?s)
7578 (tramp-octal-to-decimal "04100"))
7579 ((char-equal owner-execute-or-setid ?-) 0)
7580 (t (error "Fourth char `%c' must be one of `xsS-'"
7581 owner-execute-or-setid)))
7582 (cond
7583 ((char-equal group-read ?r) (tramp-octal-to-decimal "00040"))
7584 ((char-equal group-read ?-) 0)
7585 (t (error "Fifth char `%c' must be one of `r-'" group-read)))
7586 (cond
7587 ((char-equal group-write ?w) (tramp-octal-to-decimal "00020"))
7588 ((char-equal group-write ?-) 0)
7589 (t (error "Sixth char `%c' must be one of `w-'" group-write)))
7590 (cond
7591 ((char-equal group-execute-or-setid ?x)
7592 (tramp-octal-to-decimal "00010"))
7593 ((char-equal group-execute-or-setid ?S)
7594 (tramp-octal-to-decimal "02000"))
7595 ((char-equal group-execute-or-setid ?s)
7596 (tramp-octal-to-decimal "02010"))
7597 ((char-equal group-execute-or-setid ?-) 0)
7598 (t (error "Seventh char `%c' must be one of `xsS-'"
7599 group-execute-or-setid)))
7600 (cond
7601 ((char-equal other-read ?r)
7602 (tramp-octal-to-decimal "00004"))
7603 ((char-equal other-read ?-) 0)
7604 (t (error "Eighth char `%c' must be one of `r-'" other-read)))
7605 (cond
7606 ((char-equal other-write ?w) (tramp-octal-to-decimal "00002"))
7607 ((char-equal other-write ?-) 0)
fb7933a3 7608 (t (error "Nineth char `%c' must be one of `w-'" other-write)))
f3c071dd
MA
7609 (cond
7610 ((char-equal other-execute-or-sticky ?x)
7611 (tramp-octal-to-decimal "00001"))
7612 ((char-equal other-execute-or-sticky ?T)
7613 (tramp-octal-to-decimal "01000"))
7614 ((char-equal other-execute-or-sticky ?t)
7615 (tramp-octal-to-decimal "01001"))
7616 ((char-equal other-execute-or-sticky ?-) 0)
7617 (t (error "Tenth char `%c' must be one of `xtT-'"
7618 other-execute-or-sticky)))))))
fb7933a3 7619
00d6fd04
MA
7620(defun tramp-convert-file-attributes (vec attr)
7621 "Convert file-attributes ATTR generated by perl script, stat or ls.
c82c5727
LH
7622Convert file mode bits to string and set virtual device number.
7623Return ATTR."
680db9ac
MA
7624 (when attr
7625 ;; Convert last access time.
7626 (unless (listp (nth 4 attr))
7627 (setcar (nthcdr 4 attr)
7628 (list (floor (nth 4 attr) 65536)
7629 (floor (mod (nth 4 attr) 65536)))))
7630 ;; Convert last modification time.
7631 (unless (listp (nth 5 attr))
7632 (setcar (nthcdr 5 attr)
7633 (list (floor (nth 5 attr) 65536)
7634 (floor (mod (nth 5 attr) 65536)))))
7635 ;; Convert last status change time.
7636 (unless (listp (nth 6 attr))
7637 (setcar (nthcdr 6 attr)
7638 (list (floor (nth 6 attr) 65536)
7639 (floor (mod (nth 6 attr) 65536)))))
7640 ;; Convert file size.
7641 (when (< (nth 7 attr) 0)
7642 (setcar (nthcdr 7 attr) -1))
7643 (when (and (floatp (nth 7 attr))
7644 (<= (nth 7 attr) (tramp-compat-most-positive-fixnum)))
7645 (setcar (nthcdr 7 attr) (round (nth 7 attr))))
7646 ;; Convert file mode bits to string.
7647 (unless (stringp (nth 8 attr))
7648 (setcar (nthcdr 8 attr) (tramp-file-mode-from-int (nth 8 attr)))
7649 (when (stringp (car attr))
7650 (aset (nth 8 attr) 0 ?l)))
7651 ;; Convert directory indication bit.
7652 (when (string-match "^d" (nth 8 attr))
7653 (setcar attr t))
7654 ;; Convert symlink from `tramp-do-file-attributes-with-stat'.
7655 (when (consp (car attr))
7656 (if (and (stringp (caar attr))
7657 (string-match ".+ -> .\\(.+\\)." (caar attr)))
7658 (setcar attr (match-string 1 (caar attr)))
7659 (setcar attr nil)))
7660 ;; Set file's gid change bit.
7661 (setcar (nthcdr 9 attr)
7662 (if (numberp (nth 3 attr))
7663 (not (= (nth 3 attr)
7664 (tramp-get-remote-gid vec 'integer)))
7665 (not (string-equal
7666 (nth 3 attr)
7667 (tramp-get-remote-gid vec 'string)))))
7668 ;; Convert inode.
7669 (unless (listp (nth 10 attr))
7670 (setcar (nthcdr 10 attr)
7671 (condition-case nil
7672 (cons (floor (nth 10 attr) 65536)
7673 (floor (mod (nth 10 attr) 65536)))
7674 ;; Inodes can be incredible huge. We must hide this.
7675 (error (tramp-get-inode vec)))))
7676 ;; Set virtual device number.
7677 (setcar (nthcdr 11 attr)
7678 (tramp-get-device vec))
7679 attr))
c82c5727 7680
293c24f9
MA
7681(defun tramp-check-cached-permissions (vec access)
7682 "Check `file-attributes' caches for VEC.
7683Return t if according to the cache access type ACCESS is known to
7684be granted."
7685 (let ((result nil)
7686 (offset (cond
7687 ((eq ?r access) 1)
7688 ((eq ?w access) 2)
7689 ((eq ?x access) 3))))
7690 (dolist (suffix '("string" "integer") result)
7691 (setq
7692 result
7693 (or
7694 result
7695 (let ((file-attr
7696 (tramp-get-file-property
7697 vec (tramp-file-name-localname vec)
7698 (concat "file-attributes-" suffix) nil))
7699 (remote-uid
7700 (tramp-get-connection-property
7701 vec (concat "uid-" suffix) nil))
7702 (remote-gid
7703 (tramp-get-connection-property
7704 vec (concat "gid-" suffix) nil)))
7705 (and
7706 file-attr
7707 (or
7708 ;; Not a symlink
7709 (eq t (car file-attr))
7710 (null (car file-attr)))
7711 (or
7712 ;; World accessible.
7713 (eq access (aref (nth 8 file-attr) (+ offset 6)))
7714 ;; User accessible and owned by user.
7715 (and
7716 (eq access (aref (nth 8 file-attr) offset))
7717 (equal remote-uid (nth 2 file-attr)))
7718 ;; Group accessible and owned by user's
7719 ;; principal group.
7720 (and
7721 (eq access (aref (nth 8 file-attr) (+ offset 3)))
7722 (equal remote-gid (nth 3 file-attr)))))))))))
7723
ce3f516f 7724(defun tramp-get-inode (vec)
00d6fd04
MA
7725 "Returns the virtual inode number.
7726If it doesn't exist, generate a new one."
ce3f516f
MA
7727 (let ((string (tramp-make-tramp-file-name
7728 (tramp-file-name-method vec)
7729 (tramp-file-name-user vec)
7730 (tramp-file-name-host vec)
7731 "")))
00d6fd04
MA
7732 (unless (assoc string tramp-inodes)
7733 (add-to-list 'tramp-inodes
7734 (list string (length tramp-inodes))))
7735 (nth 1 (assoc string tramp-inodes))))
7736
7737(defun tramp-get-device (vec)
c82c5727
LH
7738 "Returns the virtual device number.
7739If it doesn't exist, generate a new one."
00d6fd04
MA
7740 (let ((string (tramp-make-tramp-file-name
7741 (tramp-file-name-method vec)
7742 (tramp-file-name-user vec)
7743 (tramp-file-name-host vec)
7744 "")))
c82c5727
LH
7745 (unless (assoc string tramp-devices)
7746 (add-to-list 'tramp-devices
7747 (list string (length tramp-devices))))
b946a456 7748 (cons -1 (nth 1 (assoc string tramp-devices)))))
fb7933a3
KG
7749
7750(defun tramp-file-mode-from-int (mode)
7751 "Turn an integer representing a file mode into an ls(1)-like string."
7752 (let ((type (cdr (assoc (logand (lsh mode -12) 15) tramp-file-mode-type-map)))
7753 (user (logand (lsh mode -6) 7))
7754 (group (logand (lsh mode -3) 7))
7755 (other (logand (lsh mode -0) 7))
7756 (suid (> (logand (lsh mode -9) 4) 0))
7757 (sgid (> (logand (lsh mode -9) 2) 0))
7758 (sticky (> (logand (lsh mode -9) 1) 0)))
7759 (setq user (tramp-file-mode-permissions user suid "s"))
7760 (setq group (tramp-file-mode-permissions group sgid "s"))
7761 (setq other (tramp-file-mode-permissions other sticky "t"))
7762 (concat type user group other)))
7763
fb7933a3
KG
7764(defun tramp-file-mode-permissions (perm suid suid-text)
7765 "Convert a permission bitset into a string.
7766This is used internally by `tramp-file-mode-from-int'."
7767 (let ((r (> (logand perm 4) 0))
7768 (w (> (logand perm 2) 0))
7769 (x (> (logand perm 1) 0)))
7770 (concat (or (and r "r") "-")
7771 (or (and w "w") "-")
7772 (or (and suid x suid-text) ; suid, execute
7773 (and suid (upcase suid-text)) ; suid, !execute
7774 (and x "x") "-")))) ; !suid
7775
fb7933a3
KG
7776(defun tramp-decimal-to-octal (i)
7777 "Return a string consisting of the octal digits of I.
7778Not actually used. Use `(format \"%o\" i)' instead?"
7779 (cond ((< i 0) (error "Cannot convert negative number to octal"))
7780 ((not (integerp i)) (error "Cannot convert non-integer to octal"))
7781 ((zerop i) "0")
7782 (t (concat (tramp-decimal-to-octal (/ i 8))
7783 (number-to-string (% i 8))))))
7784
fb7933a3
KG
7785;; Kudos to Gerd Moellmann for this suggestion.
7786(defun tramp-octal-to-decimal (ostr)
7787 "Given a string of octal digits, return a decimal number."
7788 (let ((x (or ostr "")))
7789 ;; `save-match' is in `tramp-mode-string-to-int' which calls this.
7790 (unless (string-match "\\`[0-7]*\\'" x)
7791 (error "Non-octal junk in string `%s'" x))
7792 (string-to-number ostr 8)))
7793
7794(defun tramp-shell-case-fold (string)
7795 "Converts STRING to shell glob pattern which ignores case."
7796 (mapconcat
7797 (lambda (c)
7798 (if (equal (downcase c) (upcase c))
7799 (vector c)
7800 (format "[%c%c]" (downcase c) (upcase c))))
7801 string
7802 ""))
7803
7804
bf247b6e 7805;; ------------------------------------------------------------
a4aeb9a4 7806;; -- Tramp file names --
bf247b6e 7807;; ------------------------------------------------------------
fb7933a3
KG
7808;; Conversion functions between external representation and
7809;; internal data structure. Convenience functions for internal
7810;; data structure.
7811
00d6fd04
MA
7812(defun tramp-file-name-p (vec)
7813 "Check whether VEC is a Tramp object."
7814 (and (vectorp vec) (= 4 (length vec))))
7815
7816(defun tramp-file-name-method (vec)
7817 "Return method component of VEC."
7818 (and (tramp-file-name-p vec) (aref vec 0)))
7819
7820(defun tramp-file-name-user (vec)
7821 "Return user component of VEC."
7822 (and (tramp-file-name-p vec) (aref vec 1)))
7823
7824(defun tramp-file-name-host (vec)
7825 "Return host component of VEC."
7826 (and (tramp-file-name-p vec) (aref vec 2)))
7827
7828(defun tramp-file-name-localname (vec)
7829 "Return localname component of VEC."
7830 (and (tramp-file-name-p vec) (aref vec 3)))
7831
dea31ca6 7832;; The user part of a Tramp file name vector can be of kind
b96e6899 7833;; "user%domain". Sometimes, we must extract these parts.
dea31ca6
MA
7834(defun tramp-file-name-real-user (vec)
7835 "Return the user name of VEC without domain."
a17632c1
MA
7836 (save-match-data
7837 (let ((user (tramp-file-name-user vec)))
7838 (if (and (stringp user)
7839 (string-match tramp-user-with-domain-regexp user))
7840 (match-string 1 user)
7841 user))))
dea31ca6
MA
7842
7843(defun tramp-file-name-domain (vec)
7844 "Return the domain name of VEC."
a17632c1
MA
7845 (save-match-data
7846 (let ((user (tramp-file-name-user vec)))
7847 (and (stringp user)
7848 (string-match tramp-user-with-domain-regexp user)
7849 (match-string 2 user)))))
dea31ca6 7850
00d6fd04
MA
7851;; The host part of a Tramp file name vector can be of kind
7852;; "host#port". Sometimes, we must extract these parts.
8a4438b6 7853(defun tramp-file-name-real-host (vec)
00d6fd04 7854 "Return the host name of VEC without port."
a17632c1
MA
7855 (save-match-data
7856 (let ((host (tramp-file-name-host vec)))
7857 (if (and (stringp host)
7858 (string-match tramp-host-with-port-regexp host))
7859 (match-string 1 host)
7860 host))))
00d6fd04 7861
8a4438b6 7862(defun tramp-file-name-port (vec)
00d6fd04 7863 "Return the port number of VEC."
a17632c1
MA
7864 (save-match-data
7865 (let ((host (tramp-file-name-host vec)))
7866 (and (stringp host)
7867 (string-match tramp-host-with-port-regexp host)
7868 (string-to-number (match-string 2 host))))))
fb7933a3
KG
7869
7870(defun tramp-tramp-file-p (name)
a09dc9bf 7871 "Return t if NAME is a string with Tramp file name syntax."
fb7933a3 7872 (save-match-data
a09dc9bf 7873 (and (stringp name) (string-match tramp-file-name-regexp name))))
bf247b6e 7874
8a4438b6 7875(defun tramp-find-method (method user host)
00d6fd04
MA
7876 "Return the right method string to use.
7877This is METHOD, if non-nil. Otherwise, do a lookup in
7878`tramp-default-method-alist'."
7879 (or method
7880 (let ((choices tramp-default-method-alist)
7881 lmethod item)
7882 (while choices
7883 (setq item (pop choices))
7884 (when (and (string-match (or (nth 0 item) "") (or host ""))
7885 (string-match (or (nth 1 item) "") (or user "")))
7886 (setq lmethod (nth 2 item))
7887 (setq choices nil)))
7888 lmethod)
7889 tramp-default-method))
7890
8a4438b6 7891(defun tramp-find-user (method user host)
00d6fd04
MA
7892 "Return the right user string to use.
7893This is USER, if non-nil. Otherwise, do a lookup in
7894`tramp-default-user-alist'."
7895 (or user
7896 (let ((choices tramp-default-user-alist)
7897 luser item)
7898 (while choices
7899 (setq item (pop choices))
7900 (when (and (string-match (or (nth 0 item) "") (or method ""))
7901 (string-match (or (nth 1 item) "") (or host "")))
7902 (setq luser (nth 2 item))
7903 (setq choices nil)))
7904 luser)
7905 tramp-default-user))
7906
8a4438b6 7907(defun tramp-find-host (method user host)
00d6fd04
MA
7908 "Return the right host string to use.
7909This is HOST, if non-nil. Otherwise, it is `tramp-default-host'."
7910 (or (and (> (length host) 0) host)
7911 tramp-default-host))
7912
9ce8462a 7913(defun tramp-dissect-file-name (name &optional nodefault)
00d6fd04 7914 "Return a `tramp-file-name' structure.
9ce8462a
MA
7915The structure consists of remote method, remote user, remote host
7916and localname (file name on remote host). If NODEFAULT is
7917non-nil, the file name parts are not expanded to their default
7918values."
4007ba5b 7919 (save-match-data
00d6fd04 7920 (let ((match (string-match (nth 0 tramp-file-name-structure) name)))
a4aeb9a4 7921 (unless match (error "Not a Tramp file name: %s" name))
00d6fd04
MA
7922 (let ((method (match-string (nth 1 tramp-file-name-structure) name))
7923 (user (match-string (nth 2 tramp-file-name-structure) name))
7924 (host (match-string (nth 3 tramp-file-name-structure) name))
7925 (localname (match-string (nth 4 tramp-file-name-structure) name)))
5d449a36
MA
7926 (when (member method '("multi" "multiu"))
7927 (error
7928 "`%s' method is no longer supported, see (info \"(tramp)Multi-hops\")"
7929 method))
b96e6899
MA
7930 (when host
7931 (when (string-match tramp-prefix-ipv6-regexp host)
7932 (setq host (replace-match "" nil t host)))
7933 (when (string-match tramp-postfix-ipv6-regexp host)
7934 (setq host (replace-match "" nil t host))))
9ce8462a
MA
7935 (if nodefault
7936 (vector method user host localname)
7937 (vector
7938 (tramp-find-method method user host)
7939 (tramp-find-user method user host)
7940 (tramp-find-host method user host)
7941 localname))))))
00d6fd04
MA
7942
7943(defun tramp-equal-remote (file1 file2)
7944 "Checks, whether the remote parts of FILE1 and FILE2 are identical.
7945The check depends on method, user and host name of the files. If
7946one of the components is missing, the default values are used.
7947The local file name parts of FILE1 and FILE2 are not taken into
7948account.
fb7933a3 7949
00d6fd04
MA
7950Example:
7951
7952 (tramp-equal-remote \"/ssh::/etc\" \"/<your host name>:/home\")
7953
7954would yield `t'. On the other hand, the following check results in nil:
7955
7956 (tramp-equal-remote \"/sudo::/etc\" \"/su::/etc\")"
9e6ab520
MA
7957 (and (stringp (file-remote-p file1))
7958 (stringp (file-remote-p file2))
94be87e8 7959 (string-equal (file-remote-p file1) (file-remote-p file2))))
00d6fd04
MA
7960
7961(defun tramp-make-tramp-file-name (method user host localname)
7962 "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME."
7963 (concat tramp-prefix-format
7964 (when (not (zerop (length method)))
7965 (concat method tramp-postfix-method-format))
7966 (when (not (zerop (length user)))
7967 (concat user tramp-postfix-user-format))
b96e6899
MA
7968 (when host
7969 (if (string-match tramp-ipv6-regexp host)
7970 (concat tramp-prefix-ipv6-format host tramp-postfix-ipv6-format)
7971 host))
7972 tramp-postfix-host-format
00d6fd04
MA
7973 (when localname localname)))
7974
7975(defun tramp-completion-make-tramp-file-name (method user host localname)
7976 "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME.
7977It must not be a complete Tramp file name, but as long as there are
7978necessary only. This function will be used in file name completion."
7979 (concat tramp-prefix-format
7980 (when (not (zerop (length method)))
7981 (concat method tramp-postfix-method-format))
7982 (when (not (zerop (length user)))
7983 (concat user tramp-postfix-user-format))
7984 (when (not (zerop (length host)))
b96e6899
MA
7985 (concat
7986 (if (string-match tramp-ipv6-regexp host)
7987 (concat tramp-prefix-ipv6-format host tramp-postfix-ipv6-format)
7988 host)
7989 tramp-postfix-host-format))
00d6fd04
MA
7990 (when localname localname)))
7991
7992(defun tramp-make-copy-program-file-name (vec)
7993 "Create a file name suitable to be passed to `rcp' and workalikes."
7994 (let ((user (tramp-file-name-user vec))
0f205eee 7995 (host (tramp-file-name-real-host vec))
00d6fd04
MA
7996 (localname (tramp-shell-quote-argument
7997 (tramp-file-name-localname vec))))
7998 (if (not (zerop (length user)))
7999 (format "%s@%s:%s" user host localname)
8000 (format "%s:%s" host localname))))
8001
7f49fe46 8002(defun tramp-method-out-of-band-p (vec size)
38c65fca 8003 "Return t if this is an out-of-band method, nil otherwise."
7f49fe46
MA
8004 (and
8005 ;; It shall be an out-of-band method.
8006 (tramp-get-method-parameter (tramp-file-name-method vec) 'tramp-copy-program)
8007 ;; Either the file size is large enough, or (in rare cases) there
8008 ;; does not exist a remote encoding.
8009 (or (> size tramp-copy-size-limit)
8010 (null (tramp-get-remote-coding vec "remote-encoding")))))
fb7933a3 8011
0f205eee
MA
8012(defun tramp-local-host-p (vec)
8013 "Return t if this points to the local host, nil otherwise."
c992abdb
MA
8014 ;; We cannot use `tramp-file-name-real-host'. A port is an
8015 ;; indication for an ssh tunnel or alike.
8016 (let ((host (tramp-file-name-host vec)))
0f205eee
MA
8017 (and
8018 (stringp host)
b96e6899 8019 (string-match tramp-local-host-regexp host)
46bcd78c
MA
8020 ;; The method shall be applied to one of the shell file name
8021 ;; handler. `tramp-local-host-p' is also called for "smb" and
8022 ;; alike, where it must fail.
8023 (tramp-get-method-parameter
8024 (tramp-file-name-method vec) 'tramp-login-program)
a0a5183a
MA
8025 ;; The local temp directory must be writable for the other user.
8026 (file-writable-p
8027 (tramp-make-tramp-file-name
8028 (tramp-file-name-method vec)
8029 (tramp-file-name-user vec)
8030 host
93c3eb7c
MA
8031 (tramp-compat-temporary-file-directory)))
8032 ;; On some systems, chown runs only for root.
8033 (or (zerop (user-uid))
8034 (zerop (tramp-get-remote-uid vec 'integer))))))
0f205eee 8035
fb7933a3
KG
8036;; Variables local to connection.
8037
f84638eb 8038(defun tramp-get-remote-path (vec)
70c11b0b
MA
8039 (with-connection-property
8040 ;; When `tramp-own-remote-path' is in `tramp-remote-path', we
8041 ;; cache the result for the session only. Otherwise, the result
8042 ;; is cached persistently.
8043 (if (memq 'tramp-own-remote-path tramp-remote-path)
8044 (tramp-get-connection-process vec)
8045 vec)
8046 "remote-path"
b533bc97 8047 (let* ((remote-path (copy-tree tramp-remote-path))
70c11b0b
MA
8048 (elt1 (memq 'tramp-default-remote-path remote-path))
8049 (elt2 (memq 'tramp-own-remote-path remote-path))
f84638eb 8050 (default-remote-path
70c11b0b 8051 (when elt1
f84638eb 8052 (condition-case nil
70c11b0b
MA
8053 (tramp-send-command-and-read
8054 vec "echo \\\"`getconf PATH`\\\"")
f84638eb
MA
8055 ;; Default if "getconf" is not available.
8056 (error
8057 (tramp-message
8058 vec 3
8059 "`getconf PATH' not successful, using default value \"%s\"."
8060 "/bin:/usr/bin")
70c11b0b
MA
8061 "/bin:/usr/bin"))))
8062 (own-remote-path
8063 (when elt2
8064 (condition-case nil
8065 (tramp-send-command-and-read vec "echo \\\"$PATH\\\"")
8066 ;; Default if "getconf" is not available.
8067 (error
8068 (tramp-message
8069 vec 3 "$PATH not set, ignoring `tramp-own-remote-path'.")
8070 nil)))))
8071
8072 ;; Replace place holder `tramp-default-remote-path'.
8073 (when elt1
8074 (setcdr elt1
f84638eb 8075 (append
70c11b0b
MA
8076 (tramp-compat-split-string default-remote-path ":")
8077 (cdr elt1)))
f84638eb
MA
8078 (setq remote-path (delq 'tramp-default-remote-path remote-path)))
8079
70c11b0b
MA
8080 ;; Replace place holder `tramp-own-remote-path'.
8081 (when elt2
8082 (setcdr elt2
8083 (append
8084 (tramp-compat-split-string own-remote-path ":")
8085 (cdr elt2)))
8086 (setq remote-path (delq 'tramp-own-remote-path remote-path)))
8087
8088 ;; Remove double entries.
8089 (setq elt1 remote-path)
8090 (while (consp elt1)
8091 (while (and (car elt1) (setq elt2 (member (car elt1) (cdr elt1))))
8092 (setcar elt2 nil))
8093 (setq elt1 (cdr elt1)))
8094
f84638eb
MA
8095 ;; Remove non-existing directories.
8096 (delq
8097 nil
8098 (mapcar
8099 (lambda (x)
8100 (and
70c11b0b
MA
8101 (stringp x)
8102 (file-directory-p
8103 (tramp-make-tramp-file-name
8104 (tramp-file-name-method vec)
8105 (tramp-file-name-user vec)
8106 (tramp-file-name-host vec)
8107 x))
f84638eb
MA
8108 x))
8109 remote-path)))))
8110
a4aeb9a4
MA
8111(defun tramp-get-remote-tmpdir (vec)
8112 (with-connection-property vec "tmp-directory"
8113 (let ((dir (tramp-shell-quote-argument "/tmp")))
8114 (if (and (zerop
8115 (tramp-send-command-and-check
8116 vec (format "%s -d %s" (tramp-get-test-command vec) dir)))
8117 (zerop
8118 (tramp-send-command-and-check
8119 vec (format "%s -w %s" (tramp-get-test-command vec) dir))))
8120 dir
8121 (tramp-error vec 'file-error "Directory %s not accessible" dir)))))
8122
00d6fd04
MA
8123(defun tramp-get-ls-command (vec)
8124 (with-connection-property vec "ls"
946a5aeb
MA
8125 (tramp-message vec 5 "Finding a suitable `ls' command")
8126 (or
8127 (catch 'ls-found
8128 (dolist (cmd '("ls" "gnuls" "gls"))
8129 (let ((dl (tramp-get-remote-path vec))
8130 result)
8131 (while (and dl (setq result (tramp-find-executable vec cmd dl t t)))
7e5686f0
MA
8132 ;; Check parameters. On busybox, "ls" output coloring is
8133 ;; enabled by default sometimes. So we try to disable it
8134 ;; when possible. $LS_COLORING is not supported there.
946a5aeb
MA
8135 (when (zerop (tramp-send-command-and-check
8136 vec (format "%s -lnd /" result)))
7e5686f0
MA
8137 (when (zerop (tramp-send-command-and-check
8138 vec (format "%s --color=never /" result)))
8139 (setq result (concat result " --color=never")))
946a5aeb
MA
8140 (throw 'ls-found result))
8141 (setq dl (cdr dl))))))
8142 (tramp-error vec 'file-error "Couldn't find a proper `ls' command"))))
00d6fd04 8143
8e754ea2
MA
8144(defun tramp-get-ls-command-with-dired (vec)
8145 (save-match-data
8146 (with-connection-property vec "ls-dired"
8147 (tramp-message vec 5 "Checking, whether `ls --dired' works")
8148 (zerop (tramp-send-command-and-check
7f49fe46 8149 vec (format "%s --dired /" (tramp-get-ls-command vec)))))))
8e754ea2 8150
00d6fd04
MA
8151(defun tramp-get-test-command (vec)
8152 (with-connection-property vec "test"
946a5aeb
MA
8153 (tramp-message vec 5 "Finding a suitable `test' command")
8154 (if (zerop (tramp-send-command-and-check vec "test 0"))
8155 "test"
8156 (tramp-find-executable vec "test" (tramp-get-remote-path vec)))))
00d6fd04
MA
8157
8158(defun tramp-get-test-nt-command (vec)
8159 ;; Does `test A -nt B' work? Use abominable `find' construct if it
8160 ;; doesn't. BSD/OS 4.0 wants the parentheses around the command,
8161 ;; for otherwise the shell crashes.
8162 (with-connection-property vec "test-nt"
8163 (or
8164 (progn
8165 (tramp-send-command
8166 vec (format "( %s / -nt / )" (tramp-get-test-command vec)))
8167 (with-current-buffer (tramp-get-buffer vec)
8168 (goto-char (point-min))
a0a5183a 8169 (when (looking-at (regexp-quote tramp-end-of-output))
00d6fd04
MA
8170 (format "%s %%s -nt %%s" (tramp-get-test-command vec)))))
8171 (progn
8172 (tramp-send-command
8173 vec
8174 (format
8175 "tramp_test_nt () {\n%s -n \"`find $1 -prune -newer $2 -print`\"\n}"
8176 (tramp-get-test-command vec)))
8177 "tramp_test_nt %s %s"))))
8178
8179(defun tramp-get-file-exists-command (vec)
8180 (with-connection-property vec "file-exists"
946a5aeb
MA
8181 (tramp-message vec 5 "Finding command to check if file exists")
8182 (tramp-find-file-exists-command vec)))
00d6fd04
MA
8183
8184(defun tramp-get-remote-ln (vec)
8185 (with-connection-property vec "ln"
946a5aeb
MA
8186 (tramp-message vec 5 "Finding a suitable `ln' command")
8187 (tramp-find-executable vec "ln" (tramp-get-remote-path vec))))
00d6fd04
MA
8188
8189(defun tramp-get-remote-perl (vec)
8190 (with-connection-property vec "perl"
946a5aeb 8191 (tramp-message vec 5 "Finding a suitable `perl' command")
293c24f9
MA
8192 (let ((result
8193 (or (tramp-find-executable vec "perl5" (tramp-get-remote-path vec))
8194 (tramp-find-executable
8195 vec "perl" (tramp-get-remote-path vec)))))
8196 ;; We must check also for some Perl modules.
8197 (when result
8198 (with-connection-property vec "perl-file-spec"
8199 (zerop
8200 (tramp-send-command-and-check
8201 vec (format "%s -e 'use File::Spec;'" result))))
8202 (with-connection-property vec "perl-cwd-realpath"
8203 (zerop
8204 (tramp-send-command-and-check
8205 vec (format "%s -e 'use Cwd \"realpath\";'" result)))))
8206 result)))
00d6fd04
MA
8207
8208(defun tramp-get-remote-stat (vec)
8209 (with-connection-property vec "stat"
946a5aeb
MA
8210 (tramp-message vec 5 "Finding a suitable `stat' command")
8211 (let ((result (tramp-find-executable
8212 vec "stat" (tramp-get-remote-path vec)))
8213 tmp)
8214 ;; Check whether stat(1) returns usable syntax. %s does not
8215 ;; work on older AIX systems.
8216 (when result
8217 (setq tmp
8218 ;; We don't want to display an error message.
8219 (with-temp-message (or (current-message) "")
8220 (condition-case nil
8221 (tramp-send-command-and-read
8222 vec (format "%s -c '(\"%%N\" %%s)' /" result))
8223 (error nil))))
8224 (unless (and (listp tmp) (stringp (car tmp))
8225 (string-match "^./.$" (car tmp))
8226 (integerp (cadr tmp)))
8227 (setq result nil)))
8228 result)))
fb7933a3 8229
293c24f9
MA
8230(defun tramp-get-remote-readlink (vec)
8231 (with-connection-property vec "readlink"
8232 (tramp-message vec 5 "Finding a suitable `readlink' command")
8233 (let ((result (tramp-find-executable
8234 vec "readlink" (tramp-get-remote-path vec))))
8235 (when (and result
8236 ;; We don't want to display an error message.
8237 (with-temp-message (or (current-message) "")
8238 (condition-case nil
8239 (zerop
8240 (tramp-send-command-and-check
8241 vec (format "%s --canonicalize-missing /" result)))
8242 (error nil))))
8243 result))))
8244
00d6fd04
MA
8245(defun tramp-get-remote-id (vec)
8246 (with-connection-property vec "id"
946a5aeb
MA
8247 (tramp-message vec 5 "Finding POSIX `id' command")
8248 (or
8249 (catch 'id-found
8250 (let ((dl (tramp-get-remote-path vec))
8251 result)
8252 (while (and dl (setq result (tramp-find-executable vec "id" dl t t)))
8253 ;; Check POSIX parameter.
8254 (when (zerop (tramp-send-command-and-check
8255 vec (format "%s -u" result)))
8256 (throw 'id-found result))
8257 (setq dl (cdr dl)))))
8258 (tramp-error vec 'file-error "Couldn't find a POSIX `id' command"))))
00d6fd04
MA
8259
8260(defun tramp-get-remote-uid (vec id-format)
8261 (with-connection-property vec (format "uid-%s" id-format)
8262 (let ((res (tramp-send-command-and-read
8263 vec
8264 (format "%s -u%s %s"
8265 (tramp-get-remote-id vec)
8266 (if (equal id-format 'integer) "" "n")
8267 (if (equal id-format 'integer)
8268 "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
8269 ;; The command might not always return a number.
8270 (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
8271
8272(defun tramp-get-remote-gid (vec id-format)
8273 (with-connection-property vec (format "gid-%s" id-format)
8274 (let ((res (tramp-send-command-and-read
8275 vec
8276 (format "%s -g%s %s"
8277 (tramp-get-remote-id vec)
8278 (if (equal id-format 'integer) "" "n")
8279 (if (equal id-format 'integer)
8280 "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
8281 ;; The command might not always return a number.
8282 (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
fb7933a3 8283
8d60099b
MA
8284(defun tramp-get-local-uid (id-format)
8285 (if (equal id-format 'integer) (user-uid) (user-login-name)))
8286
8287(defun tramp-get-local-gid (id-format)
9e6ab520 8288 (nth 3 (tramp-compat-file-attributes "~/" id-format)))
8d60099b 8289
00d6fd04
MA
8290;; Some predefined connection properties.
8291(defun tramp-get-remote-coding (vec prop)
8292 ;; Local coding handles properties like remote coding. So we could
8293 ;; call it without pain.
8294 (let ((ret (tramp-get-local-coding vec prop)))
8295 ;; The connection property might have been cached. So we must send
8296 ;; the script - maybe.
1d7e9a01 8297 (when (and ret (symbolp ret))
00d6fd04
MA
8298 (let ((name (symbol-name ret)))
8299 (while (string-match (regexp-quote "-") name)
8300 (setq name (replace-match "_" nil t name)))
8301 (tramp-maybe-send-script vec (symbol-value ret) name)
8302 (setq ret name)))
8303 ;; Return the value.
8304 ret))
8305
8306(defun tramp-get-local-coding (vec prop)
bf0503cb 8307 (or
00d6fd04
MA
8308 (tramp-get-connection-property vec prop nil)
8309 (progn
8310 (tramp-find-inline-encoding vec)
8311 (tramp-get-connection-property vec prop nil))))
fb7933a3 8312
00d6fd04 8313(defun tramp-get-method-parameter (method param)
c951aecb 8314 "Return the method parameter PARAM.
00d6fd04
MA
8315If the `tramp-methods' entry does not exist, return NIL."
8316 (let ((entry (assoc param (assoc method tramp-methods))))
8317 (when entry (cadr entry))))
90f8dc03 8318
fb7933a3
KG
8319;; Auto saving to a special directory.
8320
00cec167 8321(defun tramp-exists-file-name-handler (operation &rest args)
00d6fd04
MA
8322 "Checks whether OPERATION runs a file name handler."
8323 ;; The file name handler is determined on base of either an
8324 ;; argument, `buffer-file-name', or `default-directory'.
8325 (condition-case nil
8326 (let* ((buffer-file-name "/")
8327 (default-directory "/")
8328 (fnha file-name-handler-alist)
8329 (check-file-name-operation operation)
8330 (file-name-handler-alist
8331 (list
8332 (cons "/"
aa485f7c
MA
8333 (lambda (operation &rest args)
8334 "Returns OPERATION if it is the one to be checked."
8335 (if (equal check-file-name-operation operation)
8336 operation
8337 (let ((file-name-handler-alist fnha))
8338 (apply operation args))))))))
00d6fd04
MA
8339 (equal (apply operation args) operation))
8340 (error nil)))
c1105d05
MA
8341
8342(unless (tramp-exists-file-name-handler 'make-auto-save-file-name)
8343 (defadvice make-auto-save-file-name
8344 (around tramp-advice-make-auto-save-file-name () activate)
00d6fd04 8345 "Invoke `tramp-handle-make-auto-save-file-name' for Tramp files."
b533bc97 8346 (if (tramp-tramp-file-p (buffer-file-name))
7f49fe46
MA
8347 ;; We cannot call `tramp-handle-make-auto-save-file-name'
8348 ;; directly, because this would bypass the locking mechanism.
8349 (setq ad-return-value
8350 (tramp-file-name-handler 'make-auto-save-file-name))
a69c01a0 8351 ad-do-it))
191bb792
MA
8352 (add-hook
8353 'tramp-unload-hook
8354 (lambda ()
8355 (ad-remove-advice
8356 'make-auto-save-file-name
d7ec1df7
MA
8357 'around 'tramp-advice-make-auto-save-file-name)
8358 (ad-activate 'make-auto-save-file-name))))
fb7933a3 8359
b533bc97
MA
8360;; In XEmacs < 21.5, autosaved remote files have permission 0666 minus
8361;; umask. This is a security threat.
414da5ab
MA
8362
8363(defun tramp-set-auto-save-file-modes ()
8364 "Set permissions of autosaved remote files to the original permissions."
8365 (let ((bfn (buffer-file-name)))
b533bc97 8366 (when (and (tramp-tramp-file-p bfn)
b50dd0d2 8367 (buffer-modified-p)
414da5ab 8368 (stringp buffer-auto-save-file-name)
340b8d4f
MA
8369 (not (equal bfn buffer-auto-save-file-name)))
8370 (unless (file-exists-p buffer-auto-save-file-name)
8371 (write-region "" nil buffer-auto-save-file-name))
8372 ;; Permissions should be set always, because there might be an old
8373 ;; auto-saved file belonging to another original file. This could
8374 ;; be a security threat.
7177e2a3 8375 (set-file-modes buffer-auto-save-file-name
11948172 8376 (or (file-modes bfn) (tramp-octal-to-decimal "0600"))))))
414da5ab 8377
b533bc97
MA
8378(unless (and (featurep 'xemacs)
8379 (= emacs-major-version 21)
8380 (> emacs-minor-version 4))
a69c01a0
MA
8381 (add-hook 'auto-save-hook 'tramp-set-auto-save-file-modes)
8382 (add-hook 'tramp-unload-hook
aa485f7c
MA
8383 (lambda ()
8384 (remove-hook 'auto-save-hook 'tramp-set-auto-save-file-modes))))
414da5ab 8385
fb7933a3
KG
8386(defun tramp-subst-strs-in-string (alist string)
8387 "Replace all occurrences of the string FROM with TO in STRING.
8388ALIST is of the form ((FROM . TO) ...)."
8389 (save-match-data
8390 (while alist
8391 (let* ((pr (car alist))
8392 (from (car pr))
8393 (to (cdr pr)))
8394 (while (string-match (regexp-quote from) string)
8395 (setq string (replace-match to t t string)))
8396 (setq alist (cdr alist))))
8397 string))
8398
fb7933a3
KG
8399;; ------------------------------------------------------------
8400;; -- Compatibility functions section --
8401;; ------------------------------------------------------------
8402
00d6fd04 8403(defun tramp-read-passwd (proc &optional prompt)
fb7933a3 8404 "Read a password from user (compat function).
5615d63f 8405Consults the auth-source package.
5ec2cc41 8406Invokes `password-read' if available, `read-passwd' else."
00d6fd04
MA
8407 (let* ((key (tramp-make-tramp-file-name
8408 tramp-current-method tramp-current-user
8409 tramp-current-host ""))
8410 (pw-prompt
8411 (or prompt
8412 (with-current-buffer (process-buffer proc)
8413 (tramp-check-for-regexp proc tramp-password-prompt-regexp)
8414 (format "%s for %s " (capitalize (match-string 1)) key)))))
7540f029
MA
8415 (with-parsed-tramp-file-name key nil
8416 (prog1
8417 (or
8418 ;; See if auth-sources contains something useful, if it's bound.
8419 (and (boundp 'auth-sources)
8420 (tramp-get-connection-property v "first-password-request" nil)
8421 ;; Try with Tramp's current method.
8422 (funcall (symbol-function 'auth-source-user-or-password)
8423 "password" tramp-current-host tramp-current-method))
8424 ;; Try the password cache.
8425 (when (functionp 'password-read)
8426 (unless (tramp-get-connection-property
8427 v "first-password-request" nil)
8428 (funcall (symbol-function 'password-cache-remove) key))
8429 (let ((password
8430 (funcall (symbol-function 'password-read) pw-prompt key)))
8431 (funcall (symbol-function 'password-cache-add) key password)
8432 password))
8433 ;; Else, get the password interactively.
8434 (read-passwd pw-prompt))
8435 (tramp-set-connection-property v "first-password-request" nil)))))
00d6fd04 8436
9c13938d
MA
8437(defun tramp-clear-passwd (vec)
8438 "Clear password cache for connection related to VEC."
00d6fd04 8439 (when (functionp 'password-cache-remove)
9c13938d
MA
8440 (funcall
8441 (symbol-function 'password-cache-remove)
8442 (tramp-make-tramp-file-name
8443 (tramp-file-name-method vec)
8444 (tramp-file-name-user vec)
8445 (tramp-file-name-host vec)
8446 ""))))
00d6fd04
MA
8447
8448;; Snarfed code from time-date.el and parse-time.el
8449
8450(defconst tramp-half-a-year '(241 17024)
8451"Evaluated by \"(days-to-time 183)\".")
8452
8453(defconst tramp-parse-time-months
8454 '(("jan" . 1) ("feb" . 2) ("mar" . 3)
8455 ("apr" . 4) ("may" . 5) ("jun" . 6)
8456 ("jul" . 7) ("aug" . 8) ("sep" . 9)
8457 ("oct" . 10) ("nov" . 11) ("dec" . 12))
8458 "Alist mapping month names to integers.")
8459
8460(defun tramp-time-less-p (t1 t2)
8461 "Say whether time value T1 is less than time value T2."
8462 (unless t1 (setq t1 '(0 0)))
8463 (unless t2 (setq t2 '(0 0)))
8464 (or (< (car t1) (car t2))
8465 (and (= (car t1) (car t2))
8466 (< (nth 1 t1) (nth 1 t2)))))
8467
8468(defun tramp-time-subtract (t1 t2)
8469 "Subtract two time values.
8470Return the difference in the format of a time value."
8471 (unless t1 (setq t1 '(0 0)))
8472 (unless t2 (setq t2 '(0 0)))
8473 (let ((borrow (< (cadr t1) (cadr t2))))
8474 (list (- (car t1) (car t2) (if borrow 1 0))
8475 (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2)))))
fb7933a3
KG
8476
8477(defun tramp-time-diff (t1 t2)
8478 "Return the difference between the two times, in seconds.
1a762140 8479T1 and T2 are time values (as returned by `current-time' for example)."
fb7933a3 8480 ;; Pacify byte-compiler with `symbol-function'.
ea9d1443
KG
8481 (cond ((and (fboundp 'subtract-time)
8482 (fboundp 'float-time))
8483 (funcall (symbol-function 'float-time)
8484 (funcall (symbol-function 'subtract-time) t1 t2)))
8485 ((and (fboundp 'subtract-time)
8486 (fboundp 'time-to-seconds))
8487 (funcall (symbol-function 'time-to-seconds)
8488 (funcall (symbol-function 'subtract-time) t1 t2)))
fb7933a3 8489 ((fboundp 'itimer-time-difference)
1a762140
MA
8490 (funcall (symbol-function 'itimer-time-difference)
8491 (if (< (length t1) 3) (append t1 '(0)) t1)
8492 (if (< (length t2) 3) (append t2 '(0)) t2)))
fb7933a3 8493 (t
00d6fd04 8494 (let ((time (tramp-time-subtract t1 t2)))
ea9d1443
KG
8495 (+ (* (car time) 65536.0)
8496 (cadr time)
8497 (/ (or (nth 2 time) 0) 1000000.0))))))
fb7933a3
KG
8498
8499(defun tramp-coding-system-change-eol-conversion (coding-system eol-type)
8500 "Return a coding system like CODING-SYSTEM but with given EOL-TYPE.
8501EOL-TYPE can be one of `dos', `unix', or `mac'."
8502 (cond ((fboundp 'coding-system-change-eol-conversion)
9e6ab520
MA
8503 (funcall (symbol-function 'coding-system-change-eol-conversion)
8504 coding-system eol-type))
fb7933a3 8505 ((fboundp 'subsidiary-coding-system)
9e6ab520
MA
8506 (funcall (symbol-function 'subsidiary-coding-system)
8507 coding-system
8508 (cond ((eq eol-type 'dos) 'crlf)
8509 ((eq eol-type 'unix) 'lf)
8510 ((eq eol-type 'mac) 'cr)
8511 (t
8512 (error "Unknown EOL-TYPE `%s', must be %s"
8513 eol-type
8514 "`dos', `unix', or `mac'")))))
fb7933a3
KG
8515 (t (error "Can't change EOL conversion -- is MULE missing?"))))
8516
19a87064
MA
8517(defun tramp-set-process-query-on-exit-flag (process flag)
8518 "Specify if query is needed for process when Emacs is exited.
8519If the second argument flag is non-nil, Emacs will query the user before
8520exiting if process is running."
8521 (if (fboundp 'set-process-query-on-exit-flag)
00d6fd04
MA
8522 (funcall (symbol-function 'set-process-query-on-exit-flag) process flag)
8523 (funcall (symbol-function 'process-kill-without-query) process flag)))
19a87064 8524
19a87064 8525
bf247b6e
KS
8526;; ------------------------------------------------------------
8527;; -- Kludges section --
8528;; ------------------------------------------------------------
fb7933a3
KG
8529
8530;; Currently (as of Emacs 20.5), the function `shell-quote-argument'
8531;; does not deal well with newline characters. Newline is replaced by
8532;; backslash newline. But if, say, the string `a backslash newline b'
8533;; is passed to a shell, the shell will expand this into "ab",
8534;; completely omitting the newline. This is not what was intended.
8535;; It does not appear to be possible to make the function
8536;; `shell-quote-argument' work with newlines without making it
8537;; dependent on the shell used. But within this package, we know that
8538;; we will always use a Bourne-like shell, so we use an approach which
8539;; groks newlines.
8540;;
8541;; The approach is simple: we call `shell-quote-argument', then
8542;; massage the newline part of the result.
8543;;
8544;; This function should produce a string which is grokked by a Unix
8545;; shell, even if the Emacs is running on Windows. Since this is the
8546;; kludges section, we bind `system-type' in such a way that
8547;; `shell-quote-arguments' behaves as if on Unix.
8548;;
8549;; Thanks to Mario DeWeerd for the hint that it is sufficient for this
8550;; function to work with Bourne-like shells.
8551;;
8552;; CCC: This function should be rewritten so that
8553;; `shell-quote-argument' is not used. This way, we are safe from
8554;; changes in `shell-quote-argument'.
8555(defun tramp-shell-quote-argument (s)
8556 "Similar to `shell-quote-argument', but groks newlines.
8557Only works for Bourne-like shells."
8558 (let ((system-type 'not-windows))
8559 (save-match-data
8560 (let ((result (shell-quote-argument s))
8561 (nl (regexp-quote (format "\\%s" tramp-rsh-end-of-line))))
8562 (when (and (>= (length result) 2)
8563 (string= (substring result 0 2) "\\~"))
8564 (setq result (substring result 1)))
8565 (while (string-match nl result)
8566 (setq result (replace-match (format "'%s'" tramp-rsh-end-of-line)
8567 t t result)))
8568 result))))
8569
a69c01a0
MA
8570;; Checklist for `tramp-unload-hook'
8571;; - Unload all `tramp-*' packages
8572;; - Reset `file-name-handler-alist'
8573;; - Cleanup hooks where Tramp functions are in
8574;; - Cleanup advised functions
8575;; - Cleanup autoloads
8576;;;###autoload
8577(defun tramp-unload-tramp ()
08b1eb21 8578 "Discard Tramp from loading remote files."
a69c01a0
MA
8579 (interactive)
8580 ;; When Tramp is not loaded yet, its autoloads are still active.
8c04e197 8581 (tramp-unload-file-name-handlers)
a69c01a0
MA
8582 ;; ange-ftp settings must be enabled.
8583 (when (functionp 'tramp-ftp-enable-ange-ftp)
8584 (funcall (symbol-function 'tramp-ftp-enable-ange-ftp)))
00d6fd04
MA
8585 ;; Maybe its not loaded yet.
8586 (condition-case nil
8587 (unload-feature 'tramp 'force)
a69c01a0
MA
8588 (error nil)))
8589
dea31ca6
MA
8590(when (and load-in-progress
8591 (string-match "Loading tramp..." (or (current-message) "")))
ccb4a481
MA
8592 (message "Loading tramp...done"))
8593
fb7933a3
KG
8594(provide 'tramp)
8595
fb7933a3
KG
8596;;; TODO:
8597
4007ba5b 8598;; * Handle nonlocal exits such as C-g.
00d6fd04
MA
8599;; * But it would probably be better to use with-local-quit at the
8600;; place where it's actually needed: around any potentially
8601;; indefinitely blocking piece of code. In this case it would be
8602;; within Tramp around one of its calls to accept-process-output (or
8603;; around one of the loops that calls accept-process-output)
d037d501 8604;; (Stefan Monnier).
fb7933a3 8605;; * Rewrite `tramp-shell-quote-argument' to abstain from using
b1d06e75 8606;; `shell-quote-argument'.
fb7933a3
KG
8607;; * In Emacs 21, `insert-directory' shows total number of bytes used
8608;; by the files in that directory. Add this here.
8609;; * Avoid screen blanking when hitting `g' in dired. (Eli Tziperman)
8610;; * Make ffap.el grok Tramp filenames. (Eli Tziperman)
fb7933a3 8611;; * Case-insensitive filename completion. (Norbert Goevert.)
fb7933a3
KG
8612;; * Don't use globbing for directories with many files, as this is
8613;; likely to produce long command lines, and some shells choke on
8614;; long command lines.
fb7933a3 8615;; * How to deal with MULE in `insert-file-contents' and `write-region'?
fb7933a3
KG
8616;; * Test remote ksh or bash for tilde expansion in `tramp-find-shell'?
8617;; * abbreviate-file-name
8e754ea2 8618;; * Better error checking. At least whenever we see something
fb7933a3
KG
8619;; strange when doing zerop, we should kill the process and start
8620;; again. (Greg Stark)
fb7933a3 8621;; * Remove unneeded parameters from methods.
fb7933a3
KG
8622;; * Make it work for different encodings, and for different file name
8623;; encodings, too. (Daniel Pittman)
fb7933a3
KG
8624;; * Don't search for perl5 and perl. Instead, only search for perl and
8625;; then look if it's the right version (with `perl -v').
8626;; * When editing a remote CVS controlled file as a different user, VC
8627;; gets confused about the file locking status. Try to find out why
8628;; the workaround doesn't work.
3cdaec13 8629;; * Username and hostname completion.
6c4e47fa 8630;; ** Try to avoid usage of `last-input-event' in `tramp-completion-mode-p'.
8daea7fc 8631;; ** Unify `tramp-parse-{rhosts,shosts,sconfig,hosts,passwd,netrc}'.
16674e4f 8632;; Code is nearly identical.
cfb5c0db
MA
8633;; * Allow out-of-band methods as _last_ multi-hop. Open a connection
8634;; until the last but one hop via `start-file-process'. Apply it
8635;; also for ftp and smb.
00d6fd04
MA
8636;; * WIBNI if we had a command "trampclient"? If I was editing in
8637;; some shell with root priviledges, it would be nice if I could
8638;; just call
8639;; trampclient filename.c
8640;; as an editor, and the _current_ shell would connect to an Emacs
8641;; server and would be used in an existing non-priviledged Emacs
8642;; session for doing the editing in question.
8643;; That way, I need not tell Emacs my password again and be afraid
8644;; that it makes it into core dumps or other ugly stuff (I had Emacs
8645;; once display a just typed password in the context of a keyboard
8646;; sequence prompt for a question immediately following in a shell
8647;; script run within Emacs -- nasty).
8648;; And if I have some ssh session running to a different computer,
8649;; having the possibility of passing a local file there to a local
8650;; Emacs session (in case I can arrange for a connection back) would
8651;; be nice.
a4aeb9a4 8652;; Likely the corresponding Tramp server should not allow the
00d6fd04
MA
8653;; equivalent of the emacsclient -eval option in order to make this
8654;; reasonably unproblematic. And maybe trampclient should have some
8655;; way of passing credentials, like by using an SSL socket or
6e4f5731 8656;; something. (David Kastrup)
00d6fd04 8657;; * Reconnect directly to a compliant shell without first going
6e4f5731 8658;; through the user's default shell. (Pete Forman)
00d6fd04 8659;; * Make `tramp-default-user' obsolete.
11c71217 8660;; * How can I interrupt the remote process with a signal
6e4f5731 8661;; (interrupt-process seems not to work)? (Markus Triska)
2296b54d
MA
8662;; * Avoid the local shell entirely for starting remote processes. If
8663;; so, I think even a signal, when delivered directly to the local
8664;; SSH instance, would correctly be propagated to the remote process
8665;; automatically; possibly SSH would have to be started with
6e4f5731 8666;; "-t". (Markus Triska)
dea31ca6 8667;; * It makes me wonder if tramp couldn't fall back to ssh when scp
6e4f5731
MA
8668;; isn't on the remote host. (Mark A. Hershberger)
8669;; * Use lsh instead of ssh. (Alfred M. Szmidt)
3e2fa353
MA
8670;; * Implement a general server-local-variable mechanism, as there are
8671;; probably other variables that need different values for different
8672;; servers too. The user could then configure a variable (such as
8673;; tramp-server-local-variable-alist) to define any such variables
8674;; that they need to, which would then be let bound as appropriate
6e4f5731 8675;; in tramp functions. (Jason Rumney)
946a5aeb
MA
8676;; * Optimize out-of-band copying, when both methods are scp-like (not
8677;; rsync).
8678;; * Keep a second connection open for out-of-band methods like scp or
8679;; rsync.
7540f029 8680;; * Support ptys in `tramp-handle-start-file-process'. (Bug#4604)
7e5686f0
MA
8681;; * IMHO, it's a drawback that currently Tramp doesn't support
8682;; Unicode in Dired file names by default. Is it possible to
8683;; improve Tramp to set LC_ALL to "C" only for commands where Tramp
8684;; expects English? Or just to set LC_MESSAGES to "C" if Tramp
6e4f5731 8685;; expects only English messages? (Juri Linkov)
7e5686f0
MA
8686;; * Make shadowfile.el grok Tramp filenames. (Bug#4526, Bug#4846)
8687;; * Do not handle files with drive letter as remote. (Bug#5447)
b533bc97 8688;; * Load Tramp subpackages only when needed. (Bug#1529, Bug#5448, Bug#5705)
7e5686f0
MA
8689;; * Try telnet+curl as new method. It might be useful for busybox,
8690;; without built-in uuencode/uudecode.
7540f029
MA
8691;; * Let `shell-dynamic-complete-*' and `comint-dynamic-complete' work
8692;; on remote hosts.
8693;; * Use secrets.el for password handling.
5f2b693f 8694;; * Load ~/.emacs_SHELLNAME on the remote host for `shell'.
25f14cdb 8695;; * Implement selinux-context.
fb7933a3
KG
8696
8697;; Functions for file-name-handler-alist:
8698;; diff-latest-backup-file -- in diff.el
fb7933a3 8699
cdd44874 8700;; arch-tag: 3a21a994-182b-48fa-b0cd-c1d9fede424a
fb7933a3 8701;;; tramp.el ends here
57671b72
MA
8702
8703;; Local Variables:
8704;; mode: Emacs-Lisp
8705;; coding: utf-8
8706;; End: