(Rewrite Rules): Improve the example.
[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,
b96e6899 4;; 2005, 2006, 2007, 2008, 2009 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;;
00d6fd04
MA
39;; This package only works for Emacs 21.1 and higher, and for XEmacs 21.4
40;; and higher. For XEmacs 21, you need the package `fsf-compat' for
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
MA
71(add-hook 'tramp-unload-hook
72 '(lambda ()
73 (when (featurep 'trampver)
74 (unload-feature 'trampver 'force))))
75
9e6ab520 76(require 'tramp-compat)
94be87e8
MA
77(add-hook 'tramp-unload-hook
78 '(lambda ()
79 (when (featurep 'tramp-compat)
80 (unload-feature 'tramp-compat 'force))))
fb7933a3 81
9fa0d3aa 82(require 'format-spec) ; from Gnus 5.8, also in tar ball
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
108 '(lambda ()
109 (when (featurep 'tramp-cache)
110 (unload-feature 'tramp-cache 'force))))
111
16674e4f
KG
112(autoload 'tramp-uuencode-region "tramp-uu"
113 "Implementation of `uuencode' in Lisp.")
a69c01a0
MA
114(add-hook 'tramp-unload-hook
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
MA
153 ;; Load gateways. It needs `make-network-process' from Emacs 22.
154 (when (functionp 'make-network-process) 'tramp-gw)))
155
156 (when feature
70c11b0b
MA
157 ;; We have used just some basic tests, whether a package shall
158 ;; be added. There might still be other errors during loading,
159 ;; which we will catch here.
160 (catch 'tramp-loading
161 (require feature)
162 (add-hook 'tramp-unload-hook
163 `(lambda ()
164 (when (featurep (quote ,feature))
165 (unload-feature (quote ,feature) 'force)))))
166 (unless (featurep feature)
167 (message "Loading %s failed, ignoring this package" feature)))))
fb7933a3
KG
168
169;;; User Customizable Internal Variables:
170
171(defgroup tramp nil
172 "Edit remote files with a combination of rsh and rcp or similar programs."
589d30dd 173 :group 'files
bf247b6e 174 :version "22.1")
fb7933a3 175
2e271195
MA
176;; Maybe we need once a real Tramp mode, with key bindings etc.
177;;;###autoload
178(defcustom tramp-mode t
179 "*Whether Tramp is enabled.
180If it is set to nil, all remote file names are used literally."
181 :group 'tramp
182 :type 'boolean)
183
00d6fd04 184(defcustom tramp-verbose 3
94be87e8 185 "*Verbosity level for Tramp.
00d6fd04
MA
186Any level x includes messages for all levels 1 .. x-1. The levels are
187
188 0 silent (no tramp messages at all)
189 1 errors
190 2 warnings
191 3 connection to remote hosts (default level)
192 4 activities
193 5 internal
194 6 sent and received strings
195 7 file caching
196 8 connection properties
19710 traces (huge)."
fb7933a3
KG
198 :group 'tramp
199 :type 'integer)
200
38c65fca
KG
201;; Emacs case
202(eval-and-compile
203 (when (boundp 'backup-directory-alist)
204 (defcustom tramp-backup-directory-alist nil
205 "Alist of filename patterns and backup directory names.
206Each element looks like (REGEXP . DIRECTORY), with the same meaning like
207in `backup-directory-alist'. If a Tramp file is backed up, and DIRECTORY
208is a local file name, the backup directory is prepended with Tramp file
00d6fd04 209name prefix \(method, user, host\) of file.
38c65fca
KG
210
211\(setq tramp-backup-directory-alist backup-directory-alist\)
212
213gives the same backup policy for Tramp files on their hosts like the
214policy for local files."
215 :group 'tramp
216 :type '(repeat (cons (regexp :tag "Regexp matching filename")
217 (directory :tag "Backup directory name"))))))
218
219;; XEmacs case. We cannot check for `bkup-backup-directory-info', because
220;; the package "backup-dir" might not be loaded yet.
221(eval-and-compile
222 (when (featurep 'xemacs)
223 (defcustom tramp-bkup-backup-directory-info nil
224 "*Alist of (FILE-REGEXP BACKUP-DIR OPTIONS ...))
225It has the same meaning like `bkup-backup-directory-info' from package
226`backup-dir'. If a Tramp file is backed up, and BACKUP-DIR is a local
227file name, the backup directory is prepended with Tramp file name prefix
00d6fd04 228\(method, user, host\) of file.
38c65fca
KG
229
230\(setq tramp-bkup-backup-directory-info bkup-backup-directory-info\)
231
232gives the same backup policy for Tramp files on their hosts like the
233policy for local files."
bf247b6e 234 :type '(repeat
38c65fca
KG
235 (list (regexp :tag "File regexp")
236 (string :tag "Backup Dir")
237 (set :inline t
238 (const ok-create)
239 (const full-path)
240 (const prepend-name)
241 (const search-upward))))
242 :group 'tramp)))
243
fb7933a3
KG
244(defcustom tramp-auto-save-directory nil
245 "*Put auto-save files in this directory, if set.
246The idea is to use a local directory so that auto-saving is faster."
247 :group 'tramp
00d6fd04 248 :type '(choice (const nil) string))
fb7933a3 249
16674e4f
KG
250(defcustom tramp-encoding-shell
251 (if (memq system-type '(windows-nt))
252 (getenv "COMSPEC")
253 "/bin/sh")
254 "*Use this program for encoding and decoding commands on the local host.
255This shell is used to execute the encoding and decoding command on the
256local host, so if you want to use `~' in those commands, you should
257choose a shell here which groks tilde expansion. `/bin/sh' normally
258does not understand tilde expansion.
259
260For encoding and deocding, commands like the following are executed:
261
262 /bin/sh -c COMMAND < INPUT > OUTPUT
263
264This variable can be used to change the \"/bin/sh\" part. See the
00d6fd04 265variable `tramp-encoding-command-switch' for the \"-c\" part.
fb7933a3
KG
266
267Note that this variable is not used for remote commands. There are
268mechanisms in tramp.el which automatically determine the right shell to
269use for the remote host."
270 :group 'tramp
271 :type '(file :must-match t))
272
16674e4f
KG
273(defcustom tramp-encoding-command-switch
274 (if (string-match "cmd\\.exe" tramp-encoding-shell)
275 "/c"
276 "-c")
277 "*Use this switch together with `tramp-encoding-shell' for local commands.
278See the variable `tramp-encoding-shell' for more information."
279 :group 'tramp
280 :type 'string)
281
00d6fd04
MA
282(defcustom tramp-copy-size-limit 10240
283 "*The maximum file size where inline copying is preferred over an out-of-the-band copy."
16674e4f 284 :group 'tramp
00d6fd04 285 :type 'integer)
90dc758d 286
00d6fd04
MA
287(defcustom tramp-terminal-type "dumb"
288 "*Value of TERM environment variable for logging in to remote host.
289Because Tramp wants to parse the output of the remote shell, it is easily
290confused by ANSI color escape sequences and suchlike. Often, shell init
291files conditionalize this setup based on the TERM environment variable."
90dc758d 292 :group 'tramp
00d6fd04 293 :type 'string)
90dc758d 294
00d6fd04
MA
295(defvar tramp-methods
296 `(("rcp" (tramp-login-program "rsh")
297 (tramp-login-args (("%h") ("-l" "%u")))
298 (tramp-remote-sh "/bin/sh")
299 (tramp-copy-program "rcp")
300 (tramp-copy-args (("-p" "%k")))
301 (tramp-copy-keep-date t)
302 (tramp-password-end-of-line nil))
303 ("scp" (tramp-login-program "ssh")
2296b54d 304 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
305 ("-e" "none")))
306 (tramp-remote-sh "/bin/sh")
307 (tramp-copy-program "scp")
308 (tramp-copy-args (("-P" "%p") ("-p" "%k") ("-q")))
309 (tramp-copy-keep-date t)
310 (tramp-password-end-of-line nil)
311 (tramp-gw-args (("-o"
312 "GlobalKnownHostsFile=/dev/null")
313 ("-o" "UserKnownHostsFile=/dev/null")
314 ("-o" "StrictHostKeyChecking=no")))
315 (tramp-default-port 22))
316 ("scp1" (tramp-login-program "ssh")
2296b54d 317 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
318 ("-1" "-e" "none")))
319 (tramp-remote-sh "/bin/sh")
320 (tramp-copy-program "scp")
321 (tramp-copy-args (("-1") ("-P" "%p") ("-p" "%k")
322 ("-q")))
323 (tramp-copy-keep-date t)
324 (tramp-password-end-of-line nil)
325 (tramp-gw-args (("-o"
326 "GlobalKnownHostsFile=/dev/null")
327 ("-o" "UserKnownHostsFile=/dev/null")
328 ("-o" "StrictHostKeyChecking=no")))
329 (tramp-default-port 22))
330 ("scp2" (tramp-login-program "ssh")
2296b54d 331 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
332 ("-2" "-e" "none")))
333 (tramp-remote-sh "/bin/sh")
334 (tramp-copy-program "scp")
335 (tramp-copy-args (("-2") ("-P" "%p") ("-p" "%k")
336 ("-q")))
337 (tramp-copy-keep-date t)
338 (tramp-password-end-of-line nil)
339 (tramp-gw-args (("-o"
340 "GlobalKnownHostsFile=/dev/null")
341 ("-o" "UserKnownHostsFile=/dev/null")
342 ("-o" "StrictHostKeyChecking=no")))
343 (tramp-default-port 22))
344 ("scp1_old"
345 (tramp-login-program "ssh1")
346 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
347 ("-e" "none")))
348 (tramp-remote-sh "/bin/sh")
349 (tramp-copy-program "scp1")
350 (tramp-copy-args (("-p" "%k")))
351 (tramp-copy-keep-date t)
352 (tramp-password-end-of-line nil))
353 ("scp2_old"
354 (tramp-login-program "ssh2")
355 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
356 ("-e" "none")))
357 (tramp-remote-sh "/bin/sh")
358 (tramp-copy-program "scp2")
359 (tramp-copy-args (("-p" "%k")))
360 (tramp-copy-keep-date t)
361 (tramp-password-end-of-line nil))
362 ("sftp" (tramp-login-program "ssh")
363 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
364 ("-e" "none")))
365 (tramp-remote-sh "/bin/sh")
366 (tramp-copy-program "sftp")
367 (tramp-copy-args nil)
368 (tramp-copy-keep-date nil)
369 (tramp-password-end-of-line nil))
370 ("rsync" (tramp-login-program "ssh")
371 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
372 ("-e" "none")))
373 (tramp-remote-sh "/bin/sh")
374 (tramp-copy-program "rsync")
375 (tramp-copy-args (("-e" "ssh") ("-t" "%k")))
376 (tramp-copy-keep-date t)
377 (tramp-password-end-of-line nil))
378 ("remcp" (tramp-login-program "remsh")
379 (tramp-login-args (("%h") ("-l" "%u")))
380 (tramp-remote-sh "/bin/sh")
381 (tramp-copy-program "rcp")
382 (tramp-copy-args (("-p" "%k")))
383 (tramp-copy-keep-date t)
384 (tramp-password-end-of-line nil))
385 ("rsh" (tramp-login-program "rsh")
386 (tramp-login-args (("%h") ("-l" "%u")))
387 (tramp-remote-sh "/bin/sh")
388 (tramp-copy-program nil)
389 (tramp-copy-args nil)
390 (tramp-copy-keep-date nil)
391 (tramp-password-end-of-line nil))
392 ("ssh" (tramp-login-program "ssh")
2296b54d 393 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
394 ("-e" "none")))
395 (tramp-remote-sh "/bin/sh")
396 (tramp-copy-program nil)
397 (tramp-copy-args nil)
398 (tramp-copy-keep-date nil)
399 (tramp-password-end-of-line nil)
400 (tramp-gw-args (("-o"
401 "GlobalKnownHostsFile=/dev/null")
402 ("-o" "UserKnownHostsFile=/dev/null")
403 ("-o" "StrictHostKeyChecking=no")))
404 (tramp-default-port 22))
405 ("ssh1" (tramp-login-program "ssh")
2296b54d 406 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
407 ("-1" "-e" "none")))
408 (tramp-remote-sh "/bin/sh")
409 (tramp-copy-program nil)
410 (tramp-copy-args nil)
411 (tramp-copy-keep-date nil)
412 (tramp-password-end-of-line nil)
413 (tramp-gw-args (("-o"
414 "GlobalKnownHostsFile=/dev/null")
415 ("-o" "UserKnownHostsFile=/dev/null")
416 ("-o" "StrictHostKeyChecking=no")))
417 (tramp-default-port 22))
418 ("ssh2" (tramp-login-program "ssh")
2296b54d 419 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
420 ("-2" "-e" "none")))
421 (tramp-remote-sh "/bin/sh")
422 (tramp-copy-program nil)
423 (tramp-copy-args nil)
424 (tramp-copy-keep-date nil)
425 (tramp-password-end-of-line nil)
426 (tramp-gw-args (("-o"
427 "GlobalKnownHostsFile=/dev/null")
428 ("-o" "UserKnownHostsFile=/dev/null")
429 ("-o" "StrictHostKeyChecking=no")))
430 (tramp-default-port 22))
431 ("ssh1_old"
432 (tramp-login-program "ssh1")
433 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
434 ("-e" "none")))
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 ("ssh2_old"
441 (tramp-login-program "ssh2")
442 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
443 ("-e" "none")))
444 (tramp-remote-sh "/bin/sh")
445 (tramp-copy-program nil)
446 (tramp-copy-args nil)
447 (tramp-copy-keep-date nil)
448 (tramp-password-end-of-line nil))
449 ("remsh" (tramp-login-program "remsh")
450 (tramp-login-args (("%h") ("-l" "%u")))
451 (tramp-remote-sh "/bin/sh")
452 (tramp-copy-program nil)
453 (tramp-copy-args nil)
454 (tramp-copy-keep-date nil)
455 (tramp-password-end-of-line nil))
456 ("telnet"
457 (tramp-login-program "telnet")
458 (tramp-login-args (("%h") ("%p")))
459 (tramp-remote-sh "/bin/sh")
460 (tramp-copy-program nil)
461 (tramp-copy-args nil)
462 (tramp-copy-keep-date nil)
463 (tramp-password-end-of-line nil)
464 (tramp-default-port 23))
465 ("su" (tramp-login-program "su")
466 (tramp-login-args (("-") ("%u")))
467 (tramp-remote-sh "/bin/sh")
468 (tramp-copy-program nil)
469 (tramp-copy-args nil)
470 (tramp-copy-keep-date nil)
471 (tramp-password-end-of-line nil))
472 ("sudo" (tramp-login-program "sudo")
473 (tramp-login-args (("-u" "%u")
42bc9b6d 474 ("-s") ("-H") ("-p" "Password:")))
00d6fd04
MA
475 (tramp-remote-sh "/bin/sh")
476 (tramp-copy-program nil)
477 (tramp-copy-args nil)
478 (tramp-copy-keep-date nil)
479 (tramp-password-end-of-line nil))
480 ("scpc" (tramp-login-program "ssh")
2296b54d 481 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
482 ("-o" "ControlPath=%t.%%r@%%h:%%p")
483 ("-o" "ControlMaster=yes")
484 ("-e" "none")))
485 (tramp-remote-sh "/bin/sh")
486 (tramp-copy-program "scp")
487 (tramp-copy-args (("-P" "%p") ("-p" "%k") ("-q")
488 ("-o" "ControlPath=%t.%%r@%%h:%%p")
489 ("-o" "ControlMaster=auto")))
490 (tramp-copy-keep-date t)
491 (tramp-password-end-of-line nil)
492 (tramp-gw-args (("-o"
493 "GlobalKnownHostsFile=/dev/null")
494 ("-o" "UserKnownHostsFile=/dev/null")
495 ("-o" "StrictHostKeyChecking=no")))
496 (tramp-default-port 22))
497 ("scpx" (tramp-login-program "ssh")
2296b54d 498 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
499 ("-e" "none" "-t" "-t" "/bin/sh")))
500 (tramp-remote-sh "/bin/sh")
501 (tramp-copy-program "scp")
502 (tramp-copy-args (("-p" "%k")))
503 (tramp-copy-keep-date t)
504 (tramp-password-end-of-line nil)
505 (tramp-gw-args (("-o"
506 "GlobalKnownHostsFile=/dev/null")
507 ("-o" "UserKnownHostsFile=/dev/null")
508 ("-o" "StrictHostKeyChecking=no")))
509 (tramp-default-port 22))
510 ("sshx" (tramp-login-program "ssh")
2296b54d 511 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
512 ("-e" "none" "-t" "-t" "/bin/sh")))
513 (tramp-remote-sh "/bin/sh")
514 (tramp-copy-program nil)
515 (tramp-copy-args nil)
516 (tramp-copy-keep-date nil)
517 (tramp-password-end-of-line nil)
518 (tramp-gw-args (("-o"
519 "GlobalKnownHostsFile=/dev/null")
520 ("-o" "UserKnownHostsFile=/dev/null")
521 ("-o" "StrictHostKeyChecking=no")))
522 (tramp-default-port 22))
523 ("krlogin"
524 (tramp-login-program "krlogin")
525 (tramp-login-args (("%h") ("-l" "%u") ("-x")))
526 (tramp-remote-sh "/bin/sh")
527 (tramp-copy-program nil)
528 (tramp-copy-args nil)
529 (tramp-copy-keep-date nil)
530 (tramp-password-end-of-line nil))
531 ("plink" (tramp-login-program "plink")
532 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
533 ("-ssh")))
534 (tramp-remote-sh "/bin/sh")
535 (tramp-copy-program nil)
536 (tramp-copy-args nil)
537 (tramp-copy-keep-date nil)
538 (tramp-password-end-of-line "xy") ;see docstring for "xy"
539 (tramp-default-port 22))
540 ("plink1"
541 (tramp-login-program "plink")
542 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
543 ("-1" "-ssh")))
544 (tramp-remote-sh "/bin/sh")
545 (tramp-copy-program nil)
546 (tramp-copy-args nil)
547 (tramp-copy-keep-date nil)
548 (tramp-password-end-of-line "xy") ;see docstring for "xy"
549 (tramp-default-port 22))
550 ("plinkx"
551 (tramp-login-program "plink")
42bc9b6d
MA
552 ;; ("%h") must be a single element, see
553 ;; `tramp-compute-multi-hops'.
554 (tramp-login-args (("-load") ("%h") ("-t")
ce3f516f
MA
555 (,(format
556 "env 'TERM=%s' 'PROMPT_COMMAND=' 'PS1=$ '"
557 tramp-terminal-type))
00d6fd04
MA
558 ("/bin/sh")))
559 (tramp-remote-sh "/bin/sh")
560 (tramp-copy-program nil)
561 (tramp-copy-args nil)
562 (tramp-copy-keep-date nil)
563 (tramp-password-end-of-line nil))
564 ("pscp" (tramp-login-program "plink")
565 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
566 ("-ssh")))
567 (tramp-remote-sh "/bin/sh")
568 (tramp-copy-program "pscp")
60f2c210 569 (tramp-copy-args (("-P" "%p") ("-scp") ("-p" "%k")))
00d6fd04
MA
570 (tramp-copy-keep-date t)
571 (tramp-password-end-of-line "xy") ;see docstring for "xy"
572 (tramp-default-port 22))
573 ("psftp" (tramp-login-program "plink")
574 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
575 ("-ssh")))
576 (tramp-remote-sh "/bin/sh")
577 (tramp-copy-program "pscp")
60f2c210 578 (tramp-copy-args (("-P" "%p") ("-sftp") ("-p" "%k")))
00d6fd04
MA
579 (tramp-copy-keep-date t)
580 (tramp-password-end-of-line "xy")) ;see docstring for "xy"
581 ("fcp" (tramp-login-program "fsh")
582 (tramp-login-args (("%h") ("-l" "%u") ("sh" "-i")))
583 (tramp-remote-sh "/bin/sh -i")
584 (tramp-copy-program "fcp")
585 (tramp-copy-args (("-p" "%k")))
586 (tramp-copy-keep-date t)
587 (tramp-password-end-of-line nil)))
fb7933a3
KG
588 "*Alist of methods for remote files.
589This is a list of entries of the form (NAME PARAM1 PARAM2 ...).
590Each NAME stands for a remote access method. Each PARAM is a
591pair of the form (KEY VALUE). The following KEYs are defined:
fb7933a3
KG
592 * `tramp-remote-sh'
593 This specifies the Bourne shell to use on the remote host. This
594 MUST be a Bourne-like shell. It is normally not necessary to set
a4aeb9a4 595 this to any value other than \"/bin/sh\": Tramp wants to use a shell
fb7933a3
KG
596 which groks tilde expansion, but it can search for it. Also note
597 that \"/bin/sh\" exists on all Unixen, this might not be true for
598 the value that you decide to use. You Have Been Warned.
b25a52cc
KG
599 * `tramp-login-program'
600 This specifies the name of the program to use for logging in to the
00d6fd04
MA
601 remote host. This may be the name of rsh or a workalike program,
602 or the name of telnet or a workalike, or the name of su or a workalike.
b25a52cc 603 * `tramp-login-args'
fb7933a3 604 This specifies the list of arguments to pass to the above
00d6fd04 605 mentioned program. Please note that this is a list of list of arguments,
fb7933a3 606 that is, normally you don't want to put \"-a -b\" or \"-f foo\"
00d6fd04
MA
607 here. Instead, you want a list (\"-a\" \"-b\"), or (\"-f\" \"foo\").
608 There are some patterns: \"%h\" in this list is replaced by the host
609 name, \"%u\" is replaced by the user name, \"%p\" is replaced by the
610 port number, and \"%%\" can be used to obtain a literal percent character.
611 If a list containing \"%h\", \"%u\" or \"%p\" is unchanged during
612 expansion (i.e. no host or no user specified), this list is not used as
613 argument. By this, arguments like (\"-l\" \"%u\") are optional.
614 \"%t\" is replaced by the temporary file name produced with
615 `tramp-make-tramp-temp-file'. \"%k\" indicates the keep-date
616 parameter of a program, if exists.
b25a52cc
KG
617 * `tramp-copy-program'
618 This specifies the name of the program to use for remotely copying
619 the file; this might be the absolute filename of rcp or the name of
620 a workalike program.
621 * `tramp-copy-args'
fb7933a3 622 This specifies the list of parameters to pass to the above mentioned
b25a52cc 623 program, the hints for `tramp-login-args' also apply here.
00d6fd04
MA
624 * `tramp-copy-keep-date'
625 This specifies whether the copying program when the preserves the
626 timestamp of the original file.
627 * `tramp-default-port'
628 The default port of a method is needed in case of gateway connections.
629 Additionally, it is used as indication which method is prepared for
630 passing gateways.
631 * `tramp-gw-args'
632 As the attribute name says, additional arguments are specified here
633 when a method is applied via a gateway.
90f8dc03
KG
634 * `tramp-password-end-of-line'
635 This specifies the string to use for terminating the line after
636 submitting the password. If this method parameter is nil, then the
637 value of the normal variable `tramp-default-password-end-of-line'
638 is used. This parameter is necessary because the \"plink\" program
639 requires any two characters after sending the password. These do
640 not have to be newline or carriage return characters. Other login
641 programs are happy with just one character, the newline character.
642 We use \"xy\" as the value for methods using \"plink\".
b25a52cc
KG
643
644What does all this mean? Well, you should specify `tramp-login-program'
645for all methods; this program is used to log in to the remote site. Then,
646there are two ways to actually transfer the files between the local and the
647remote side. One way is using an additional rcp-like program. If you want
648to do this, set `tramp-copy-program' in the method.
fb7933a3
KG
649
650Another possibility for file transfer is inline transfer, i.e. the
b25a52cc 651file is passed through the same buffer used by `tramp-login-program'. In
fb7933a3 652this case, the file contents need to be protected since the
b25a52cc 653`tramp-login-program' might use escape codes or the connection might not
fb7933a3 654be eight-bit clean. Therefore, file contents are encoded for transit.
00d6fd04
MA
655See the variables `tramp-local-coding-commands' and
656`tramp-remote-coding-commands' for details.
fb7933a3 657
16674e4f 658So, to summarize: if the method is an out-of-band method, then you
b25a52cc 659must specify `tramp-copy-program' and `tramp-copy-args'. If it is an
00d6fd04
MA
660inline method, then these two parameters should be nil. Methods which
661are fit for gateways must have `tramp-default-port' at least.
fb7933a3
KG
662
663Notes:
664
00d6fd04
MA
665When using `su' or `sudo' the phrase `open connection to a remote
666host' sounds strange, but it is used nevertheless, for consistency.
667No connection is opened to a remote host, but `su' or `sudo' is
668started on the local host. You should specify a remote host
669`localhost' or the name of the local host. Another host name is
670useful only in combination with `tramp-default-proxies-alist'.")
fb7933a3 671
b25a52cc 672(defcustom tramp-default-method
83e20b5c
MA
673 ;; An external copy method seems to be preferred, because it is much
674 ;; more performant for large files, and it hasn't too serious delays
675 ;; for small files. But it must be ensured that there aren't
676 ;; permanent password queries. Either a password agent like
677 ;; "ssh-agent" or "Pageant" shall run, or the optional password.el
678 ;; package shall be active for password caching. "scpc" would be
679 ;; another good choice because of the "ControlMaster" option, but
680 ;; this is a more modern alternative in OpenSSH 4, which cannot be
681 ;; taken as default.
00d6fd04
MA
682 (cond
683 ;; PuTTY is installed.
684 ((executable-find "pscp")
685 (if (or (fboundp 'password-read)
686 ;; Pageant is running.
70c11b0b 687 (tramp-compat-process-running-p "Pageant"))
00d6fd04
MA
688 "pscp"
689 "plink"))
690 ;; There is an ssh installation.
691 ((executable-find "scp")
692 (if (or (fboundp 'password-read)
693 ;; ssh-agent is running.
694 (getenv "SSH_AUTH_SOCK")
695 (getenv "SSH_AGENT_PID"))
696 "scp"
697 "ssh"))
698 ;; Fallback.
699 (t "ftp"))
fb7933a3 700 "*Default method to use for transferring files.
c62c9d08 701See `tramp-methods' for possibilities.
4007ba5b 702Also see `tramp-default-method-alist'."
c62c9d08
KG
703 :group 'tramp
704 :type 'string)
705
505edaeb 706(defcustom tramp-default-method-alist
4007ba5b 707 '(("\\`localhost\\'" "\\`root\\'" "su"))
00d6fd04 708 "*Default method to use for specific host/user pairs.
c62c9d08
KG
709This is an alist of items (HOST USER METHOD). The first matching item
710specifies the method to use for a file name which does not specify a
711method. HOST and USER are regular expressions or nil, which is
712interpreted as a regular expression which always matches. If no entry
713matches, the variable `tramp-default-method' takes effect.
714
715If the file name does not specify the user, lookup is done using the
716empty string for the user name.
717
718See `tramp-methods' for a list of possibilities for METHOD."
719 :group 'tramp
720 :type '(repeat (list (regexp :tag "Host regexp")
721 (regexp :tag "User regexp")
722 (string :tag "Method"))))
723
00d6fd04
MA
724(defcustom tramp-default-user
725 nil
726 "*Default user to use for transferring files.
727It is nil by default; otherwise settings in configuration files like
728\"~/.ssh/config\" would be overwritten. Also see `tramp-default-user-alist'.
729
730This variable is regarded as obsolete, and will be removed soon."
731 :group 'tramp
732 :type '(choice (const nil) string))
733
734(defcustom tramp-default-user-alist
735 `(("\\`su\\(do\\)?\\'" nil "root")
736 ("\\`r\\(em\\)?\\(cp\\|sh\\)\\|telnet\\|plink1?\\'"
737 nil ,(user-login-name)))
738 "*Default user to use for specific method/host pairs.
739This is an alist of items (METHOD HOST USER). The first matching item
740specifies the user to use for a file name which does not specify a
741user. METHOD and USER are regular expressions or nil, which is
742interpreted as a regular expression which always matches. If no entry
743matches, the variable `tramp-default-user' takes effect.
744
745If the file name does not specify the method, lookup is done using the
746empty string for the method name."
747 :group 'tramp
748 :type '(repeat (list (regexp :tag "Method regexp")
749 (regexp :tag "Host regexp")
750 (string :tag "User"))))
751
752(defcustom tramp-default-host
753 (system-name)
754 "*Default host to use for transferring files.
755Useful for su and sudo methods mostly."
756 :group 'tramp
757 :type 'string)
758
759(defcustom tramp-default-proxies-alist nil
760 "*Route to be followed for specific host/user pairs.
761This is an alist of items (HOST USER PROXY). The first matching
762item specifies the proxy to be passed for a file name located on
763a remote target matching USER@HOST. HOST and USER are regular
70c11b0b
MA
764expressions. PROXY must be a Tramp filename without a localname
765part. Method and user name on PROXY are optional, which is
766interpreted with the default values. PROXY can contain the
767patterns %h and %u, which are replaced by the strings matching
768HOST or USER, respectively.
769
770HOST, USER or PROXY could also be Lisp forms, which will be
771evaluated. The result must be a string or nil, which is
772interpreted as a regular expression which always matches."
00d6fd04 773 :group 'tramp
70c11b0b
MA
774 :type '(repeat (list (choice :tag "Host regexp" regexp sexp)
775 (choice :tag "User regexp" regexp sexp)
776 (choice :tag "Proxy remote name" string (const nil)))))
00d6fd04 777
b96e6899
MA
778(defconst tramp-local-host-regexp
779 (concat
780 "^" (regexp-opt (list "localhost" (system-name) "127\.0\.0\.1" "::1") t) "$")
781 "*Host names which are regarded as local host.")
782
16674e4f 783(defconst tramp-completion-function-alist-rsh
00d6fd04
MA
784 '((tramp-parse-rhosts "/etc/hosts.equiv")
785 (tramp-parse-rhosts "~/.rhosts"))
b25a52cc 786 "Default list of (FUNCTION FILE) pairs to be examined for rsh methods.")
16674e4f 787
16674e4f 788(defconst tramp-completion-function-alist-ssh
00d6fd04
MA
789 '((tramp-parse-rhosts "/etc/hosts.equiv")
790 (tramp-parse-rhosts "/etc/shosts.equiv")
791 (tramp-parse-shosts "/etc/ssh_known_hosts")
792 (tramp-parse-sconfig "/etc/ssh_config")
793 (tramp-parse-shostkeys "/etc/ssh2/hostkeys")
794 (tramp-parse-sknownhosts "/etc/ssh2/knownhosts")
795 (tramp-parse-rhosts "~/.rhosts")
796 (tramp-parse-rhosts "~/.shosts")
797 (tramp-parse-shosts "~/.ssh/known_hosts")
798 (tramp-parse-sconfig "~/.ssh/config")
799 (tramp-parse-shostkeys "~/.ssh2/hostkeys")
800 (tramp-parse-sknownhosts "~/.ssh2/knownhosts"))
b25a52cc 801 "Default list of (FUNCTION FILE) pairs to be examined for ssh methods.")
16674e4f 802
16674e4f 803(defconst tramp-completion-function-alist-telnet
00d6fd04 804 '((tramp-parse-hosts "/etc/hosts"))
b25a52cc 805 "Default list of (FUNCTION FILE) pairs to be examined for telnet methods.")
16674e4f 806
16674e4f 807(defconst tramp-completion-function-alist-su
00d6fd04 808 '((tramp-parse-passwd "/etc/passwd"))
b25a52cc 809 "Default list of (FUNCTION FILE) pairs to be examined for su methods.")
292ffc15 810
00d6fd04
MA
811(defconst tramp-completion-function-alist-putty
812 '((tramp-parse-putty
813 "HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions"))
814 "Default list of (FUNCTION REGISTRY) pairs to be examined for putty methods.")
815
5ec2cc41 816(defvar tramp-completion-function-alist nil
16674e4f
KG
817 "*Alist of methods for remote files.
818This is a list of entries of the form (NAME PAIR1 PAIR2 ...).
819Each NAME stands for a remote access method. Each PAIR is of the form
820\(FUNCTION FILE). FUNCTION is responsible to extract user names and host
821names from FILE for completion. The following predefined FUNCTIONs exists:
822
5ec2cc41
KG
823 * `tramp-parse-rhosts' for \"~/.rhosts\" like files,
824 * `tramp-parse-shosts' for \"~/.ssh/known_hosts\" like files,
825 * `tramp-parse-sconfig' for \"~/.ssh/config\" like files,
826 * `tramp-parse-shostkeys' for \"~/.ssh2/hostkeys/*\" like files,
827 * `tramp-parse-sknownhosts' for \"~/.ssh2/knownhosts/*\" like files,
828 * `tramp-parse-hosts' for \"/etc/hosts\" like files,
829 * `tramp-parse-passwd' for \"/etc/passwd\" like files.
830 * `tramp-parse-netrc' for \"~/.netrc\" like files.
00d6fd04 831 * `tramp-parse-putty' for PuTTY registry keys.
5ec2cc41
KG
832
833FUNCTION can also be a customer defined function. For more details see
834the info pages.")
835
836(eval-after-load "tramp"
837 '(progn
838 (tramp-set-completion-function
839 "rcp" tramp-completion-function-alist-rsh)
840 (tramp-set-completion-function
841 "scp" tramp-completion-function-alist-ssh)
842 (tramp-set-completion-function
843 "scp1" tramp-completion-function-alist-ssh)
844 (tramp-set-completion-function
845 "scp2" tramp-completion-function-alist-ssh)
846 (tramp-set-completion-function
847 "scp1_old" tramp-completion-function-alist-ssh)
848 (tramp-set-completion-function
849 "scp2_old" tramp-completion-function-alist-ssh)
850 (tramp-set-completion-function
70c11b0b 851 "rsync" tramp-completion-function-alist-ssh)
5ec2cc41
KG
852 (tramp-set-completion-function
853 "remcp" tramp-completion-function-alist-rsh)
854 (tramp-set-completion-function
855 "rsh" tramp-completion-function-alist-rsh)
856 (tramp-set-completion-function
857 "ssh" tramp-completion-function-alist-ssh)
858 (tramp-set-completion-function
859 "ssh1" tramp-completion-function-alist-ssh)
860 (tramp-set-completion-function
861 "ssh2" tramp-completion-function-alist-ssh)
862 (tramp-set-completion-function
863 "ssh1_old" tramp-completion-function-alist-ssh)
864 (tramp-set-completion-function
865 "ssh2_old" tramp-completion-function-alist-ssh)
866 (tramp-set-completion-function
867 "remsh" tramp-completion-function-alist-rsh)
868 (tramp-set-completion-function
869 "telnet" tramp-completion-function-alist-telnet)
870 (tramp-set-completion-function
871 "su" tramp-completion-function-alist-su)
872 (tramp-set-completion-function
873 "sudo" tramp-completion-function-alist-su)
bf247b6e 874 (tramp-set-completion-function
5ec2cc41
KG
875 "scpx" tramp-completion-function-alist-ssh)
876 (tramp-set-completion-function
877 "sshx" tramp-completion-function-alist-ssh)
878 (tramp-set-completion-function
879 "krlogin" tramp-completion-function-alist-rsh)
880 (tramp-set-completion-function
881 "plink" tramp-completion-function-alist-ssh)
882 (tramp-set-completion-function
883 "plink1" tramp-completion-function-alist-ssh)
00d6fd04
MA
884 (tramp-set-completion-function
885 "plinkx" tramp-completion-function-alist-putty)
5ec2cc41
KG
886 (tramp-set-completion-function
887 "pscp" tramp-completion-function-alist-ssh)
888 (tramp-set-completion-function
889 "fcp" tramp-completion-function-alist-ssh)))
16674e4f 890
674da028
MA
891(defconst tramp-echo-mark-marker "_echo"
892 "String marker to surround echoed commands.")
893
00d6fd04
MA
894(defconst tramp-echo-mark "_echo\b\b\b\b\b"
895 "String mark to be transmitted around shell commands.
896Used to separate their echo from the output they produce. This
897will only be used if we cannot disable remote echo via stty.
898This string must have no effect on the remote shell except for
899producing some echo which can later be detected by
674da028
MA
900`tramp-echoed-echo-mark-regexp'. Using `tramp-echo-mark-marker',
901followed by an equal number of backspaces to erase them will
902usually suffice.")
00d6fd04
MA
903
904(defconst tramp-echoed-echo-mark-regexp "_echo\\(\b\\( \b\\)?\\)\\{5\\}"
905 "Regexp which matches `tramp-echo-mark' as it gets echoed by
906the remote shell.")
907
fb7933a3
KG
908(defcustom tramp-rsh-end-of-line "\n"
909 "*String used for end of line in rsh connections.
910I don't think this ever needs to be changed, so please tell me about it
16674e4f 911if you need to change this.
90f8dc03
KG
912Also see the method parameter `tramp-password-end-of-line' and the normal
913variable `tramp-default-password-end-of-line'."
16674e4f
KG
914 :group 'tramp
915 :type 'string)
916
90f8dc03
KG
917(defcustom tramp-default-password-end-of-line
918 tramp-rsh-end-of-line
16674e4f 919 "*String used for end of line after sending a password.
90f8dc03
KG
920This variable provides the default value for the method parameter
921`tramp-password-end-of-line', see `tramp-methods' for more details.
922
16674e4f
KG
923It seems that people using plink under Windows need to send
924\"\\r\\n\" (carriage-return, then newline) after a password, but just
925\"\\n\" after all other lines. This variable can be used for the
926password, see `tramp-rsh-end-of-line' for the other cases.
927
928The default value is to use the same value as `tramp-rsh-end-of-line'."
fb7933a3
KG
929 :group 'tramp
930 :type 'string)
931
00d6fd04
MA
932;; "getconf PATH" yields:
933;; HP-UX: /usr/bin:/usr/ccs/bin:/opt/ansic/bin:/opt/langtools/bin:/opt/fortran/bin
934;; Solaris: /usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin
0664ff72 935;; GNU/Linux (Debian, Suse): /bin:/usr/bin
00d6fd04 936;; FreeBSD: /usr/bin:/bin:/usr/sbin:/sbin: - beware trailing ":"!
fb7933a3 937(defcustom tramp-remote-path
00d6fd04
MA
938 '(tramp-default-remote-path "/usr/sbin" "/usr/local/bin"
939 "/local/bin" "/local/freeware/bin" "/local/gnu/bin"
fb7933a3
KG
940 "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin")
941 "*List of directories to search for executables on remote host.
00d6fd04
MA
942For every remote host, this variable will be set buffer local,
943keeping the list of existing directories on that host.
fb7933a3
KG
944
945You can use `~' in this list, but when searching for a shell which groks
00d6fd04
MA
946tilde expansion, all directory names starting with `~' will be ignored.
947
948`Default Directories' represent the list of directories given by
949the command \"getconf PATH\". It is recommended to use this
950entry on top of this list, because these are the default
70c11b0b
MA
951directories for POSIX compatible commands.
952
953`Private Directories' are the settings of the $PATH environment,
954as given in your `~/.profile'."
00d6fd04
MA
955 :group 'tramp
956 :type '(repeat (choice
957 (const :tag "Default Directories" tramp-default-remote-path)
70c11b0b 958 (const :tag "Private Directories" tramp-own-remote-path)
00d6fd04
MA
959 (string :tag "Directory"))))
960
00d6fd04 961(defcustom tramp-remote-process-environment
a0a5183a 962 `("HISTFILE=$HOME/.tramp_history" "HISTSIZE=1" "LC_ALL=C"
00d6fd04 963 ,(concat "TERM=" tramp-terminal-type)
97c696d5
MA
964 "EMACS=t" ;; Deprecated.
965 ,(format "INSIDE_EMACS=%s,tramp:%s" emacs-version tramp-version)
00d6fd04
MA
966 "CDPATH=" "HISTORY=" "MAIL=" "MAILCHECK=" "MAILPATH="
967 "autocorrect=" "correct=")
968
969 "*List of environment variables to be set on the remote host.
970
971Each element should be a string of the form ENVVARNAME=VALUE. An
972entry ENVVARNAME= diables the corresponding environment variable,
973which might have been set in the init files like ~/.profile.
974
975Special handling is applied to the PATH environment, which should
976not be set here. Instead of, it should be set via `tramp-remote-path'."
fb7933a3
KG
977 :group 'tramp
978 :type '(repeat string))
979
980(defcustom tramp-login-prompt-regexp
bc103d00 981 ".*ogin\\( .*\\)?: *"
fb7933a3 982 "*Regexp matching login-like prompts.
bc103d00
MA
983The regexp should match at end of buffer.
984
985Sometimes the prompt is reported to look like \"login as:\"."
fb7933a3
KG
986 :group 'tramp
987 :type 'regexp)
988
821e6e36 989(defcustom tramp-shell-prompt-pattern
ea9d1443 990 "^[^#$%>\n]*[#$%>] *\\(\e\\[[0-9;]*[a-zA-Z] *\\)*"
821e6e36
KG
991 "Regexp to match prompts from remote shell.
992Normally, Tramp expects you to configure `shell-prompt-pattern'
993correctly, but sometimes it happens that you are connecting to a
994remote host which sends a different kind of shell prompt. Therefore,
995Tramp recognizes things matched by `shell-prompt-pattern' as prompt,
996and also things matched by this variable. The default value of this
b25a52cc 997variable is similar to the default value of `shell-prompt-pattern',
821e6e36
KG
998which should work well in many cases."
999 :group 'tramp
1000 :type 'regexp)
1001
fb7933a3 1002(defcustom tramp-password-prompt-regexp
00d6fd04 1003 "^.*\\([pP]assword\\|[pP]assphrase\\).*:\^@? *"
fb7933a3 1004 "*Regexp matching password-like prompts.
ac474af1 1005The regexp should match at end of buffer.
fb7933a3
KG
1006
1007The `sudo' program appears to insert a `^@' character into the prompt."
1008 :group 'tramp
1009 :type 'regexp)
1010
1011(defcustom tramp-wrong-passwd-regexp
b1d06e75
KG
1012 (concat "^.*"
1013 ;; These strings should be on the last line
a4aeb9a4 1014 (regexp-opt '("Permission denied"
b1d06e75
KG
1015 "Login incorrect"
1016 "Login Incorrect"
1017 "Connection refused"
27e813fe 1018 "Connection closed"
b1d06e75
KG
1019 "Sorry, try again."
1020 "Name or service not known"
00d6fd04 1021 "Host key verification failed."
70c11b0b 1022 "No supported authentication methods left to try!") t)
b1d06e75
KG
1023 ".*"
1024 "\\|"
1025 "^.*\\("
1026 ;; Here comes a list of regexes, separated by \\|
1027 "Received signal [0-9]+"
1028 "\\).*")
fb7933a3 1029 "*Regexp matching a `login failed' message.
ac474af1
KG
1030The regexp should match at end of buffer."
1031 :group 'tramp
1032 :type 'regexp)
1033
1034(defcustom tramp-yesno-prompt-regexp
3cdaec13
KG
1035 (concat
1036 (regexp-opt '("Are you sure you want to continue connecting (yes/no)?") t)
1037 "\\s-*")
1038 "Regular expression matching all yes/no queries which need to be confirmed.
ac474af1 1039The confirmation should be done with yes or no.
3cdaec13
KG
1040The regexp should match at end of buffer.
1041See also `tramp-yn-prompt-regexp'."
fb7933a3
KG
1042 :group 'tramp
1043 :type 'regexp)
1044
3cdaec13 1045(defcustom tramp-yn-prompt-regexp
658052a2
MA
1046 (concat
1047 (regexp-opt '("Store key in cache? (y/n)"
1048 "Update cached key? (y/n, Return cancels connection)") t)
1049 "\\s-*")
3cdaec13
KG
1050 "Regular expression matching all y/n queries which need to be confirmed.
1051The confirmation should be done with y or n.
1052The regexp should match at end of buffer.
1053See also `tramp-yesno-prompt-regexp'."
1054 :group 'tramp
1055 :type 'regexp)
487f4fb7
KG
1056
1057(defcustom tramp-terminal-prompt-regexp
1058 (concat "\\("
1059 "TERM = (.*)"
1060 "\\|"
1061 "Terminal type\\? \\[.*\\]"
1062 "\\)\\s-*")
1063 "Regular expression matching all terminal setting prompts.
1064The regexp should match at end of buffer.
1065The answer will be provided by `tramp-action-terminal', which see."
1066 :group 'tramp
1067 :type 'regexp)
3cdaec13 1068
01917a18
MA
1069(defcustom tramp-operation-not-permitted-regexp
1070 (concat "\\(" "preserving times.*" "\\|" "set mode" "\\)" ":\\s-*"
1071 (regexp-opt '("Operation not permitted") t))
1072 "Regular expression matching keep-date problems in (s)cp operations.
1073Copying has been performed successfully already, so this message can
1074be ignored safely."
1075 :group 'tramp
1076 :type 'regexp)
1077
6b2633cc
LH
1078(defcustom tramp-copy-failed-regexp
1079 (concat "\\(.+: "
1080 (regexp-opt '("Permission denied"
1081 "not a regular file"
1082 "is a directory"
1083 "No such file or directory") t)
1084 "\\)\\s-*")
1085 "Regular expression matching copy problems in (s)cp operations."
1086 :group 'tramp
1087 :type 'regexp)
1088
19a87064 1089(defcustom tramp-process-alive-regexp
38c65fca 1090 ""
19a87064 1091 "Regular expression indicating a process has finished.
38c65fca
KG
1092In fact this expression is empty by intention, it will be used only to
1093check regularly the status of the associated process.
07dfe738 1094The answer will be provided by `tramp-action-process-alive',
00d6fd04 1095`tramp-action-out-of-band', which see."
38c65fca
KG
1096 :group 'tramp
1097 :type 'regexp)
1098
fb7933a3
KG
1099(defcustom tramp-temp-name-prefix "tramp."
1100 "*Prefix to use for temporary files.
1101If this is a relative file name (such as \"tramp.\"), it is considered
1102relative to the directory name returned by the function
9e6ab520 1103`tramp-compat-temporary-file-directory' (which see). It may also be an
fb7933a3
KG
1104absolute file name; don't forget to include a prefix for the filename
1105part, though."
1106 :group 'tramp
1107 :type 'string)
1108
2296b54d
MA
1109(defconst tramp-temp-buffer-name " *tramp temp*"
1110 "Buffer name for a temporary buffer.
1111It shall be used in combination with `generate-new-buffer-name'.")
1112
4007ba5b 1113(defcustom tramp-sh-extra-args '(("/bash\\'" . "-norc -noprofile"))
c62c9d08
KG
1114 "*Alist specifying extra arguments to pass to the remote shell.
1115Entries are (REGEXP . ARGS) where REGEXP is a regular expression
1116matching the shell file name and ARGS is a string specifying the
1117arguments.
1118
1119This variable is only used when Tramp needs to start up another shell
1120for tilde expansion. The extra arguments should typically prevent the
1121shell from reading its init file."
1122 :group 'tramp
90f8dc03
KG
1123 ;; This might be the wrong way to test whether the widget type
1124 ;; `alist' is available. Who knows the right way to test it?
1125 :type (if (get 'alist 'widget-type)
1126 '(alist :key-type string :value-type string)
1127 '(repeat (cons string string))))
c62c9d08 1128
00d6fd04
MA
1129;; XEmacs is distributed with few Lisp packages. Further packages are
1130;; installed using EFS. If we use a unified filename format, then
1131;; Tramp is required in addition to EFS. (But why can't Tramp just
1132;; disable EFS when Tramp is loaded? Then XEmacs can ship with EFS
1133;; just like before.) Another reason for using a separate filename
1134;; syntax on XEmacs is that EFS hooks into XEmacs in many places, but
1135;; Tramp only knows how to deal with `file-name-handler-alist', not
1136;; the other places.
1137
1138;; Currently, we have the choice between 'ftp, 'sep, and 'url.
1139;;;###autoload
1140(defcustom tramp-syntax
1141 (if (featurep 'xemacs) 'sep 'ftp)
1142 "Tramp filename syntax to be used.
1143
1144It can have the following values:
1145
1146 'ftp -- Ange-FTP respective EFS like syntax (GNU Emacs default)
1147 'sep -- Syntax as defined for XEmacs (not available yet for GNU Emacs)
1148 'url -- URL-like syntax."
16674e4f 1149 :group 'tramp
00d6fd04
MA
1150 :type (if (featurep 'xemacs)
1151 '(choice (const :tag "EFS" ftp)
1152 (const :tag "XEmacs" sep)
1153 (const :tag "URL" url))
1154 '(choice (const :tag "Ange-FTP" ftp)
1155 (const :tag "URL" url))))
1156
1157(defconst tramp-prefix-format
1158 (cond ((equal tramp-syntax 'ftp) "/")
1159 ((equal tramp-syntax 'sep) "/[")
1160 ((equal tramp-syntax 'url) "/")
1161 (t (error "Wrong `tramp-syntax' defined")))
a4aeb9a4 1162 "*String matching the very beginning of Tramp file names.
00d6fd04 1163Used in `tramp-make-tramp-file-name'.")
16674e4f 1164
00d6fd04 1165(defconst tramp-prefix-regexp
16674e4f 1166 (concat "^" (regexp-quote tramp-prefix-format))
a4aeb9a4 1167 "*Regexp matching the very beginning of Tramp file names.
00d6fd04 1168Should always start with \"^\". Derived from `tramp-prefix-format'.")
16674e4f 1169
00d6fd04 1170(defconst tramp-method-regexp
16674e4f 1171 "[a-zA-Z_0-9-]+"
00d6fd04 1172 "*Regexp matching methods identifiers.")
16674e4f 1173
00d6fd04
MA
1174(defconst tramp-postfix-method-format
1175 (cond ((equal tramp-syntax 'ftp) ":")
1176 ((equal tramp-syntax 'sep) "/")
1177 ((equal tramp-syntax 'url) "://")
1178 (t (error "Wrong `tramp-syntax' defined")))
16674e4f 1179 "*String matching delimeter between method and user or host names.
00d6fd04 1180Used in `tramp-make-tramp-file-name'.")
16674e4f 1181
00d6fd04
MA
1182(defconst tramp-postfix-method-regexp
1183 (regexp-quote tramp-postfix-method-format)
16674e4f 1184 "*Regexp matching delimeter between method and user or host names.
00d6fd04 1185Derived from `tramp-postfix-method-format'.")
16674e4f 1186
00d6fd04
MA
1187(defconst tramp-user-regexp
1188 "[^:/ \t]+"
1189 "*Regexp matching user names.")
16674e4f 1190
b96e6899
MA
1191(defconst tramp-prefix-domain-format "%"
1192 "*String matching delimeter between user and domain names.")
1193
1194(defconst tramp-prefix-domain-regexp
1195 (regexp-quote tramp-prefix-domain-format)
1196 "*Regexp matching delimeter between user and domain names.
1197Derived from `tramp-prefix-domain-format'.")
1198
1199(defconst tramp-domain-regexp
70c11b0b 1200 "[-a-zA-Z0-9_.]+"
b96e6899
MA
1201 "*Regexp matching domain names.")
1202
1203(defconst tramp-user-with-domain-regexp
1204 (concat "\\(" tramp-user-regexp "\\)"
1205 tramp-prefix-domain-regexp
1206 "\\(" tramp-domain-regexp "\\)")
1207 "*Regexp matching user names with domain names.")
1208
00d6fd04 1209(defconst tramp-postfix-user-format
16674e4f
KG
1210 "@"
1211 "*String matching delimeter between user and host names.
00d6fd04 1212Used in `tramp-make-tramp-file-name'.")
16674e4f 1213
00d6fd04 1214(defconst tramp-postfix-user-regexp
16674e4f
KG
1215 (regexp-quote tramp-postfix-user-format)
1216 "*Regexp matching delimeter between user and host names.
00d6fd04
MA
1217Derived from `tramp-postfix-user-format'.")
1218
1219(defconst tramp-host-regexp
1220 "[a-zA-Z0-9_.-]+"
1221 "*Regexp matching host names.")
1222
b96e6899
MA
1223(defconst tramp-prefix-ipv6-format
1224 (cond ((equal tramp-syntax 'ftp) "[")
1225 ((equal tramp-syntax 'sep) "")
1226 ((equal tramp-syntax 'url) "[")
1227 (t (error "Wrong `tramp-syntax' defined")))
1228 "*String matching left hand side of IPv6 addresses.
1229Used in `tramp-make-tramp-file-name'.")
1230
1231(defconst tramp-prefix-ipv6-regexp
1232 (regexp-quote tramp-prefix-ipv6-format)
1233 "*Regexp matching left hand side of IPv6 addresses.
1234Derived from `tramp-prefix-ipv6-format'.")
1235
e0b6e3b9
MA
1236;; The following regexp is a bit sloppy. But it shall serve our
1237;; purposes. It covers also IPv4 mapped IPv6 addresses, like in
1238;; "::ffff:192.168.0.1".
b96e6899 1239(defconst tramp-ipv6-regexp
e0b6e3b9 1240 "\\(?:\\(?:[a-zA-Z0-9]+\\)?:\\)+[a-zA-Z0-9.]+"
b96e6899
MA
1241 "*Regexp matching IPv6 addresses.")
1242
1243(defconst tramp-postfix-ipv6-format
1244 (cond ((equal tramp-syntax 'ftp) "]")
1245 ((equal tramp-syntax 'sep) "")
1246 ((equal tramp-syntax 'url) "]")
1247 (t (error "Wrong `tramp-syntax' defined")))
1248 "*String matching right hand side of IPv6 addresses.
1249Used in `tramp-make-tramp-file-name'.")
1250
1251(defconst tramp-postfix-ipv6-regexp
1252 (regexp-quote tramp-postfix-ipv6-format)
1253 "*Regexp matching right hand side of IPv6 addresses.
1254Derived from `tramp-postfix-ipv6-format'.")
1255
00d6fd04
MA
1256(defconst tramp-prefix-port-format
1257 (cond ((equal tramp-syntax 'ftp) "#")
1258 ((equal tramp-syntax 'sep) "#")
1259 ((equal tramp-syntax 'url) ":")
1260 (t (error "Wrong `tramp-syntax' defined")))
1261 "*String matching delimeter between host names and port numbers.")
1262
1263(defconst tramp-prefix-port-regexp
1264 (regexp-quote tramp-prefix-port-format)
1265 "*Regexp matching delimeter between host names and port numbers.
1266Derived from `tramp-prefix-port-format'.")
1267
1268(defconst tramp-port-regexp
1269 "[0-9]+"
1270 "*Regexp matching port numbers.")
1271
1272(defconst tramp-host-with-port-regexp
1273 (concat "\\(" tramp-host-regexp "\\)"
1274 tramp-prefix-port-regexp
1275 "\\(" tramp-port-regexp "\\)")
1276 "*Regexp matching host names with port numbers.")
1277
1278(defconst tramp-postfix-host-format
1279 (cond ((equal tramp-syntax 'ftp) ":")
1280 ((equal tramp-syntax 'sep) "]")
1281 ((equal tramp-syntax 'url) "")
1282 (t (error "Wrong `tramp-syntax' defined")))
7432277c 1283 "*String matching delimeter between host names and localnames.
00d6fd04 1284Used in `tramp-make-tramp-file-name'.")
16674e4f 1285
00d6fd04 1286(defconst tramp-postfix-host-regexp
16674e4f 1287 (regexp-quote tramp-postfix-host-format)
7432277c 1288 "*Regexp matching delimeter between host names and localnames.
00d6fd04 1289Derived from `tramp-postfix-host-format'.")
16674e4f 1290
00d6fd04 1291(defconst tramp-localname-regexp
16674e4f 1292 ".*$"
00d6fd04 1293 "*Regexp matching localnames.")
16674e4f
KG
1294
1295;; File name format.
505edaeb 1296
00d6fd04 1297(defconst tramp-file-name-structure
16674e4f
KG
1298 (list
1299 (concat
1300 tramp-prefix-regexp
00d6fd04
MA
1301 "\\(" "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp "\\)?"
1302 "\\(" "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp "\\)?"
b96e6899
MA
1303 "\\(" "\\(" tramp-host-regexp
1304 "\\|"
1305 tramp-prefix-ipv6-regexp tramp-ipv6-regexp
1306 tramp-postfix-ipv6-regexp "\\)"
1307 "\\(" tramp-prefix-port-regexp tramp-port-regexp "\\)?" "\\)?"
00d6fd04
MA
1308 tramp-postfix-host-regexp
1309 "\\(" tramp-localname-regexp "\\)")
b96e6899 1310 2 4 5 8)
16674e4f 1311
fb7933a3 1312 "*List of five elements (REGEXP METHOD USER HOST FILE), detailing \
a4aeb9a4 1313the Tramp file name structure.
fb7933a3 1314
a4aeb9a4 1315The first element REGEXP is a regular expression matching a Tramp file
fb7933a3
KG
1316name. The regex should contain parentheses around the method name,
1317the user name, the host name, and the file name parts.
1318
1319The second element METHOD is a number, saying which pair of
1320parentheses matches the method name. The third element USER is
1321similar, but for the user name. The fourth element HOST is similar,
1322but for the host name. The fifth element FILE is for the file name.
1323These numbers are passed directly to `match-string', which see. That
1324means the opening parentheses are counted to identify the pair.
1325
00d6fd04 1326See also `tramp-file-name-regexp'.")
fb7933a3
KG
1327
1328;;;###autoload
505edaeb 1329(defconst tramp-file-name-regexp-unified
b96e6899 1330 "\\`/\\([^[/:]+\\|[^/]+]\\):"
505edaeb
KG
1331 "Value for `tramp-file-name-regexp' for unified remoting.
1332Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and
00d6fd04 1333Tramp. See `tramp-file-name-structure' for more explanations.")
505edaeb
KG
1334
1335;;;###autoload
1336(defconst tramp-file-name-regexp-separate
1337 "\\`/\\[.*\\]"
1338 "Value for `tramp-file-name-regexp' for separate remoting.
1339XEmacs uses a separate filename syntax for Tramp and EFS.
00d6fd04 1340See `tramp-file-name-structure' for more explanations.")
505edaeb
KG
1341
1342;;;###autoload
00d6fd04
MA
1343(defconst tramp-file-name-regexp-url
1344 "\\`/[^/:]+://"
1345 "Value for `tramp-file-name-regexp' for URL-like remoting.
1346See `tramp-file-name-structure' for more explanations.")
1347
1348;;;###autoload
1349(defconst tramp-file-name-regexp
1350 (cond ((equal tramp-syntax 'ftp) tramp-file-name-regexp-unified)
1351 ((equal tramp-syntax 'sep) tramp-file-name-regexp-separate)
1352 ((equal tramp-syntax 'url) tramp-file-name-regexp-url)
1353 (t (error "Wrong `tramp-syntax' defined")))
94be87e8 1354 "*Regular expression matching file names handled by Tramp.
a4aeb9a4 1355This regexp should match Tramp file names but no other file names.
fb7933a3
KG
1356\(When tramp.el is loaded, this regular expression is prepended to
1357`file-name-handler-alist', and that is searched sequentially. Thus,
a4aeb9a4
MA
1358if the Tramp entry appears rather early in the `file-name-handler-alist'
1359and is a bit too general, then some files might be considered Tramp
00d6fd04 1360files which are not really Tramp files.
fb7933a3
KG
1361
1362Please note that the entry in `file-name-handler-alist' is made when
1363this file (tramp.el) is loaded. This means that this variable must be set
1364before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1365updated after changing this variable.
1366
00d6fd04 1367Also see `tramp-file-name-structure'.")
fb7933a3 1368
16674e4f 1369;;;###autoload
8a798e41 1370(defconst tramp-root-regexp
00d6fd04 1371 (if (memq system-type '(cygwin windows-nt))
57671b72
MA
1372 "^\\([a-zA-Z]:\\)?/"
1373 "^/")
8a798e41
MA
1374 "Beginning of an incomplete Tramp file name.
1375Usually, it is just \"^/\". On W32 systems, there might be a
57671b72 1376volume letter, which will be removed by `tramp-drop-volume-letter'.")
8a798e41
MA
1377
1378;;;###autoload
1379(defconst tramp-completion-file-name-regexp-unified
1380 (concat tramp-root-regexp "[^/]*$")
16674e4f 1381 "Value for `tramp-completion-file-name-regexp' for unified remoting.
8a798e41
MA
1382GNU Emacs uses a unified filename syntax for Tramp and Ange-FTP.
1383See `tramp-file-name-structure' for more explanations.")
fb7933a3 1384
16674e4f
KG
1385;;;###autoload
1386(defconst tramp-completion-file-name-regexp-separate
57671b72 1387 (concat tramp-root-regexp "\\([[][^]]*\\)?$")
16674e4f
KG
1388 "Value for `tramp-completion-file-name-regexp' for separate remoting.
1389XEmacs uses a separate filename syntax for Tramp and EFS.
00d6fd04 1390See `tramp-file-name-structure' for more explanations.")
fb7933a3 1391
16674e4f 1392;;;###autoload
00d6fd04 1393(defconst tramp-completion-file-name-regexp-url
8a798e41 1394 (concat tramp-root-regexp "[^/:]+\\(:\\(/\\(/[^/]*\\)?\\)?\\)?$")
00d6fd04
MA
1395 "Value for `tramp-completion-file-name-regexp' for URL-like remoting.
1396See `tramp-file-name-structure' for more explanations.")
1397
1398;;;###autoload
1399(defconst tramp-completion-file-name-regexp
1400 (cond ((equal tramp-syntax 'ftp) tramp-completion-file-name-regexp-unified)
1401 ((equal tramp-syntax 'sep) tramp-completion-file-name-regexp-separate)
1402 ((equal tramp-syntax 'url) tramp-completion-file-name-regexp-url)
1403 (t (error "Wrong `tramp-syntax' defined")))
a4aeb9a4
MA
1404 "*Regular expression matching file names handled by Tramp completion.
1405This regexp should match partial Tramp file names only.
16674e4f
KG
1406
1407Please note that the entry in `file-name-handler-alist' is made when
1408this file (tramp.el) is loaded. This means that this variable must be set
1409before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1410updated after changing this variable.
1411
00d6fd04 1412Also see `tramp-file-name-structure'.")
fb7933a3 1413
00d6fd04
MA
1414(defconst tramp-actions-before-shell
1415 '((tramp-login-prompt-regexp tramp-action-login)
1416 (tramp-password-prompt-regexp tramp-action-password)
1417 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
ac474af1 1418 (shell-prompt-pattern tramp-action-succeed)
821e6e36 1419 (tramp-shell-prompt-pattern tramp-action-succeed)
3cdaec13 1420 (tramp-yesno-prompt-regexp tramp-action-yesno)
487f4fb7 1421 (tramp-yn-prompt-regexp tramp-action-yn)
19a87064
MA
1422 (tramp-terminal-prompt-regexp tramp-action-terminal)
1423 (tramp-process-alive-regexp tramp-action-process-alive))
ac474af1
KG
1424 "List of pattern/action pairs.
1425Whenever a pattern matches, the corresponding action is performed.
1426Each item looks like (PATTERN ACTION).
1427
1428The PATTERN should be a symbol, a variable. The value of this
1429variable gives the regular expression to search for. Note that the
1430regexp must match at the end of the buffer, \"\\'\" is implicitly
1431appended to it.
1432
1433The ACTION should also be a symbol, but a function. When the
00d6fd04 1434corresponding PATTERN matches, the ACTION function is called.")
ac474af1 1435
00d6fd04 1436(defconst tramp-actions-copy-out-of-band
38c65fca
KG
1437 '((tramp-password-prompt-regexp tramp-action-password)
1438 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
00d6fd04 1439 (tramp-copy-failed-regexp tramp-action-permission-denied)
19a87064 1440 (tramp-process-alive-regexp tramp-action-out-of-band))
38c65fca
KG
1441 "List of pattern/action pairs.
1442This list is used for copying/renaming with out-of-band methods.
90f8dc03 1443
00d6fd04
MA
1444See `tramp-actions-before-shell' for more info.")
1445
1446;; Chunked sending kludge. We set this to 500 for black-listed constellations
7432277c 1447;; known to have a bug in `process-send-string'; some ssh connections appear
7177e2a3
MA
1448;; to drop bytes when data is sent too quickly. There is also a connection
1449;; buffer local variable, which is computed depending on remote host properties
1450;; when `tramp-chunksize' is zero or nil.
7432277c
KG
1451(defcustom tramp-chunksize
1452 (when (and (not (featurep 'xemacs))
1453 (memq system-type '(hpux)))
1454 500)
55880756
MA
1455;; Parentheses in docstring starting at beginning of line are escaped.
1456;; Fontification is messed up when
1457;; `open-paren-in-column-0-is-defun-start' set to t.
7432277c
KG
1458 "*If non-nil, chunksize for sending input to local process.
1459It is necessary only on systems which have a buggy `process-send-string'
1460implementation. The necessity, whether this variable must be set, can be
1461checked via the following code:
1462
1463 (with-temp-buffer
11948172
MA
1464 (let* ((user \"xxx\") (host \"yyy\")
1465 (init 0) (step 50)
1466 (sent init) (received init))
1467 (while (= sent received)
1468 (setq sent (+ sent step))
1469 (erase-buffer)
1470 (let ((proc (start-process (buffer-name) (current-buffer)
1471 \"ssh\" \"-l\" user host \"wc\" \"-c\")))
1472 (when (memq (process-status proc) '(run open))
1473 (process-send-string proc (make-string sent ?\\ ))
1474 (process-send-eof proc)
1475 (process-send-eof proc))
1476 (while (not (progn (goto-char (point-min))
1477 (re-search-forward \"\\\\w+\" (point-max) t)))
1478 (accept-process-output proc 1))
1479 (when (memq (process-status proc) '(run open))
1480 (setq received (string-to-number (match-string 0)))
1481 (delete-process proc)
1482 (message \"Bytes sent: %s\\tBytes received: %s\" sent received)
1483 (sit-for 0))))
1484 (if (> sent (+ init step))
1485 (message \"You should set `tramp-chunksize' to a maximum of %s\"
1486 (- sent step))
1487 (message \"Test does not work\")
1488 (display-buffer (current-buffer))
1489 (sit-for 30))))
1490
1491In the Emacs normally running Tramp, evaluate the above code
55880756 1492\(replace \"xxx\" and \"yyy\" by the remote user and host name,
11948172
MA
1493respectively). You can do this, for example, by pasting it into
1494the `*scratch*' buffer and then hitting C-j with the cursor after the
1495last closing parenthesis. Note that it works only if you have configured
1496\"ssh\" to run without password query, see ssh-agent(1).
1497
1498You will see the number of bytes sent successfully to the remote host.
1499If that number exceeds 1000, you can stop the execution by hitting
1500C-g, because your Emacs is likely clean.
1501
11948172
MA
1502When it is necessary to set `tramp-chunksize', you might consider to
1503use an out-of-the-band method (like \"scp\") instead of an internal one
55880756 1504\(like \"ssh\"), because setting `tramp-chunksize' to non-nil decreases
11948172 1505performance.
c951aecb 1506
00d6fd04
MA
1507If your Emacs is buggy, the code stops and gives you an indication
1508about the value `tramp-chunksize' should be set. Maybe you could just
1509experiment a bit, e.g. changing the values of `init' and `step'
1510in the third line of the code.
1511
7432277c
KG
1512Please raise a bug report via \"M-x tramp-bug\" if your system needs
1513this variable to be set as well."
1514 :group 'tramp
b1a2b924 1515 :type '(choice (const nil) integer))
7432277c 1516
5ec2cc41
KG
1517;; Logging in to a remote host normally requires obtaining a pty. But
1518;; Emacs on MacOS X has process-connection-type set to nil by default,
1519;; so on those systems Tramp doesn't obtain a pty. Here, we allow
1520;; for an override of the system default.
1521(defcustom tramp-process-connection-type t
1522 "Overrides `process-connection-type' for connections from Tramp.
1523Tramp binds process-connection-type to the value given here before
1524opening a connection to a remote host."
1525 :group 'tramp
1526 :type '(choice (const nil) (const t) (const pty)))
1527
b50dd0d2
MA
1528(defcustom tramp-completion-reread-directory-timeout 10
1529 "Defines seconds since last remote command before rereading a directory.
1530A remote directory might have changed its contents. In order to
1531make it visible during file name completion in the minibuffer,
1532Tramp flushes its cache and rereads the directory contents when
1533more than `tramp-completion-reread-directory-timeout' seconds
1534have been gone since last remote command execution. A value of 0
1535would require an immediate reread during filename completion, nil
1536means to use always cached values for the directory contents."
1537 :group 'tramp
1538 :type '(choice (const nil) integer))
1539
fb7933a3
KG
1540;;; Internal Variables:
1541
4007ba5b 1542(defvar tramp-end-of-output
a0a5183a 1543 (format
70c11b0b
MA
1544 "///%s$"
1545 (md5 (concat (prin1-to-string process-environment) (current-time-string))))
1546 "String used to recognize end of output.
1547The '$' character at the end is quoted; the string cannot be
1548detected as prompt when being sent on echoing hosts, therefore.")
fb7933a3 1549
fb7933a3 1550(defvar tramp-current-method nil
00d6fd04 1551 "Connection method for this *tramp* buffer.")
fb7933a3
KG
1552
1553(defvar tramp-current-user nil
00d6fd04 1554 "Remote login name for this *tramp* buffer.")
fb7933a3
KG
1555
1556(defvar tramp-current-host nil
00d6fd04
MA
1557 "Remote host for this *tramp* buffer.")
1558
1559(defconst tramp-uudecode
1560 "(echo begin 600 /tmp/tramp.$$; tail +2) | uudecode
fabf2143 1561cat /tmp/tramp.$$
00d6fd04 1562rm -f /tmp/tramp.$$"
fabf2143 1563 "Shell function to implement `uudecode' to standard output.
c08e6004
MA
1564Many systems support `uudecode -o /dev/stdout' or `uudecode -o -'
1565for this or `uudecode -p', but some systems don't, and for them
1566we have this shell function.")
fabf2143
KG
1567
1568;; Perl script to implement `file-attributes' in a Lisp `read'able
1569;; output. If you are hacking on this, note that you get *no* output
1570;; unless this spits out a complete line, including the '\n' at the
1571;; end.
8daea7fc 1572;; The device number is returned as "-1", because there will be a virtual
b946a456 1573;; device number set in `tramp-handle-file-attributes'.
00d6fd04
MA
1574(defconst tramp-perl-file-attributes
1575 "%s -e '
c82c5727
LH
1576@stat = lstat($ARGV[0]);
1577if (($stat[2] & 0170000) == 0120000)
1578{
1579 $type = readlink($ARGV[0]);
1580 $type = \"\\\"$type\\\"\";
1581}
1582elsif (($stat[2] & 0170000) == 040000)
1583{
1584 $type = \"t\";
1585}
1586else
1587{
1588 $type = \"nil\"
1589};
1590$uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
1591$gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
1592printf(
d4443a0d 1593 \"(%%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) -1)\\n\",
c82c5727
LH
1594 $type,
1595 $stat[3],
1596 $uid,
1597 $gid,
1598 $stat[8] >> 16 & 0xffff,
1599 $stat[8] & 0xffff,
1600 $stat[9] >> 16 & 0xffff,
1601 $stat[9] & 0xffff,
1602 $stat[10] >> 16 & 0xffff,
1603 $stat[10] & 0xffff,
1604 $stat[7],
1605 $stat[2],
1606 $stat[1] >> 16 & 0xffff,
1607 $stat[1] & 0xffff
00d6fd04 1608);' \"$1\" \"$2\" \"$3\" 2>/dev/null"
fb7933a3 1609 "Perl script to produce output suitable for use with `file-attributes'
00d6fd04
MA
1610on the remote file system.
1611Escape sequence %s is replaced with name of Perl binary.
1612This string is passed to `format', so percent characters need to be doubled.")
fb7933a3 1613
00d6fd04
MA
1614(defconst tramp-perl-directory-files-and-attributes
1615 "%s -e '
8cb0a559
LH
1616chdir($ARGV[0]) or printf(\"\\\"Cannot change to $ARGV[0]: $''!''\\\"\\n\"), exit();
1617opendir(DIR,\".\") or printf(\"\\\"Cannot open directory $ARGV[0]: $''!''\\\"\\n\"), exit();
c82c5727
LH
1618@list = readdir(DIR);
1619closedir(DIR);
1620$n = scalar(@list);
1621printf(\"(\\n\");
1622for($i = 0; $i < $n; $i++)
1623{
1624 $filename = $list[$i];
1625 @stat = lstat($filename);
1626 if (($stat[2] & 0170000) == 0120000)
1627 {
1628 $type = readlink($filename);
1629 $type = \"\\\"$type\\\"\";
1630 }
1631 elsif (($stat[2] & 0170000) == 040000)
1632 {
1633 $type = \"t\";
1634 }
1635 else
1636 {
1637 $type = \"nil\"
1638 };
1639 $uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
1640 $gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
1641 printf(
b946a456 1642 \"(\\\"%%s\\\" %%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) (%%u . %%u))\\n\",
c82c5727
LH
1643 $filename,
1644 $type,
1645 $stat[3],
1646 $uid,
1647 $gid,
1648 $stat[8] >> 16 & 0xffff,
1649 $stat[8] & 0xffff,
1650 $stat[9] >> 16 & 0xffff,
1651 $stat[9] & 0xffff,
1652 $stat[10] >> 16 & 0xffff,
1653 $stat[10] & 0xffff,
1654 $stat[7],
1655 $stat[2],
1656 $stat[1] >> 16 & 0xffff,
1657 $stat[1] & 0xffff,
1658 $stat[0] >> 16 & 0xffff,
1659 $stat[0] & 0xffff);
1660}
00d6fd04 1661printf(\")\\n\");' \"$1\" \"$2\" \"$3\" 2>/dev/null"
c82c5727 1662 "Perl script implementing `directory-files-attributes' as Lisp `read'able
00d6fd04
MA
1663output.
1664Escape sequence %s is replaced with name of Perl binary.
1665This string is passed to `format', so percent characters need to be doubled.")
c82c5727 1666
ac474af1
KG
1667;; ;; These two use uu encoding.
1668;; (defvar tramp-perl-encode "%s -e'\
1669;; print qq(begin 644 xxx\n);
1670;; my $s = q();
1671;; my $res = q();
1672;; while (read(STDIN, $s, 45)) {
1673;; print pack(q(u), $s);
1674;; }
1675;; print qq(`\n);
1676;; print qq(end\n);
1677;; '"
1678;; "Perl program to use for encoding a file.
1679;; Escape sequence %s is replaced with name of Perl binary.")
1680
1681;; (defvar tramp-perl-decode "%s -ne '
1682;; print unpack q(u), $_;
1683;; '"
1684;; "Perl program to use for decoding a file.
1685;; Escape sequence %s is replaced with name of Perl binary.")
1686
1687;; These two use base64 encoding.
00d6fd04
MA
1688(defconst tramp-perl-encode-with-module
1689 "%s -MMIME::Base64 -0777 -ne 'print encode_base64($_)' 2>/dev/null"
ac474af1 1690 "Perl program to use for encoding a file.
b1d06e75 1691Escape sequence %s is replaced with name of Perl binary.
89509ea0 1692This string is passed to `format', so percent characters need to be doubled.
b1d06e75
KG
1693This implementation requires the MIME::Base64 Perl module to be installed
1694on the remote host.")
1695
00d6fd04
MA
1696(defconst tramp-perl-decode-with-module
1697 "%s -MMIME::Base64 -0777 -ne 'print decode_base64($_)' 2>/dev/null"
b1d06e75
KG
1698 "Perl program to use for decoding a file.
1699Escape sequence %s is replaced with name of Perl binary.
89509ea0 1700This string is passed to `format', so percent characters need to be doubled.
b1d06e75
KG
1701This implementation requires the MIME::Base64 Perl module to be installed
1702on the remote host.")
1703
00d6fd04 1704(defconst tramp-perl-encode
b1d06e75
KG
1705 "%s -e '
1706# This script contributed by Juanma Barranquero <lektu@terra.es>.
46932a8d 1707# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
cbd12ed7 1708# Free Software Foundation, Inc.
b1d06e75
KG
1709use strict;
1710
fa32e96a 1711my %%trans = do {
b1d06e75
KG
1712 my $i = 0;
1713 map {(substr(unpack(q(B8), chr $i++), 2, 6), $_)}
1714 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/);
1715};
1716
36541701 1717binmode(\\*STDIN);
b1d06e75
KG
1718
1719# We read in chunks of 54 bytes, to generate output lines
1720# of 72 chars (plus end of line)
36541701 1721$/ = \\54;
b1d06e75
KG
1722
1723while (my $data = <STDIN>) {
1724 my $pad = q();
1725
1726 # Only for the last chunk, and only if did not fill the last three-byte packet
1727 if (eof) {
fa32e96a 1728 my $mod = length($data) %% 3;
b1d06e75
KG
1729 $pad = q(=) x (3 - $mod) if $mod;
1730 }
1731
1732 # Not the fastest method, but it is simple: unpack to binary string, split
1733 # by groups of 6 bits and convert back from binary to byte; then map into
1734 # the translation table
1735 print
1736 join q(),
1737 map($trans{$_},
1738 (substr(unpack(q(B*), $data) . q(00000), 0, 432) =~ /....../g)),
1739 $pad,
36541701 1740 qq(\\n);
00d6fd04 1741}' 2>/dev/null"
b1d06e75 1742 "Perl program to use for encoding a file.
fa32e96a 1743Escape sequence %s is replaced with name of Perl binary.
ccf29586 1744This string is passed to `format', so percent characters need to be doubled.")
ac474af1 1745
00d6fd04 1746(defconst tramp-perl-decode
b1d06e75
KG
1747 "%s -e '
1748# This script contributed by Juanma Barranquero <lektu@terra.es>.
46932a8d 1749# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
cbd12ed7 1750# Free Software Foundation, Inc.
b1d06e75
KG
1751use strict;
1752
fa32e96a 1753my %%trans = do {
b1d06e75 1754 my $i = 0;
16674e4f 1755 map {($_, substr(unpack(q(B8), chr $i++), 2, 6))}
b1d06e75
KG
1756 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/)
1757};
1758
fa32e96a 1759my %%bytes = map {(unpack(q(B8), chr $_), chr $_)} 0 .. 255;
b1d06e75 1760
36541701 1761binmode(\\*STDOUT);
b1d06e75
KG
1762
1763# We are going to accumulate into $pending to accept any line length
1764# (we do not check they are <= 76 chars as the RFC says)
1765my $pending = q();
1766
1767while (my $data = <STDIN>) {
1768 chomp $data;
1769
1770 # If we find one or two =, we have reached the end and
1771 # any following data is to be discarded
1772 my $finished = $data =~ s/(==?).*/$1/;
1773 $pending .= $data;
1774
1775 my $len = length($pending);
16674e4f 1776 my $chunk = substr($pending, 0, $len & ~3);
414da5ab 1777 $pending = substr($pending, $len & ~3 + 1);
b1d06e75
KG
1778
1779 # Easy method: translate from chars to (pregenerated) six-bit packets, join,
1780 # split in 8-bit chunks and convert back to char.
1781 print join q(),
1782 map $bytes{$_},
1783 ((join q(), map {$trans{$_} || q()} split //, $chunk) =~ /......../g);
1784
1785 last if $finished;
00d6fd04 1786}' 2>/dev/null"
ac474af1 1787 "Perl program to use for decoding a file.
fa32e96a 1788Escape sequence %s is replaced with name of Perl binary.
ccf29586 1789This string is passed to `format', so percent characters need to be doubled.")
fb7933a3 1790
9ce8462a
MA
1791(defconst tramp-file-mode-type-map
1792 '((0 . "-") ; Normal file (SVID-v2 and XPG2)
1793 (1 . "p") ; fifo
1794 (2 . "c") ; character device
1795 (3 . "m") ; multiplexed character device (v7)
1796 (4 . "d") ; directory
1797 (5 . "?") ; Named special file (XENIX)
1798 (6 . "b") ; block device
1799 (7 . "?") ; multiplexed block device (v7)
1800 (8 . "-") ; regular file
1801 (9 . "n") ; network special file (HP-UX)
1802 (10 . "l") ; symlink
1803 (11 . "?") ; ACL shadow inode (Solaris, not userspace)
1804 (12 . "s") ; socket
1805 (13 . "D") ; door special (Solaris)
1806 (14 . "w")) ; whiteout (BSD)
fb7933a3
KG
1807 "A list of file types returned from the `stat' system call.
1808This is used to map a mode number to a permission string.")
1809
fb7933a3 1810;; New handlers should be added here. The following operations can be
c0fc6170
MA
1811;; handled using the normal primitives: file-name-sans-versions,
1812;; get-file-buffer.
fb7933a3 1813(defconst tramp-file-name-handler-alist
00d6fd04 1814 '((load . tramp-handle-load)
fb7933a3 1815 (make-symbolic-link . tramp-handle-make-symbolic-link)
c0fc6170 1816 (file-name-as-directory . tramp-handle-file-name-as-directory)
fb7933a3
KG
1817 (file-name-directory . tramp-handle-file-name-directory)
1818 (file-name-nondirectory . tramp-handle-file-name-nondirectory)
1819 (file-truename . tramp-handle-file-truename)
1820 (file-exists-p . tramp-handle-file-exists-p)
1821 (file-directory-p . tramp-handle-file-directory-p)
1822 (file-executable-p . tramp-handle-file-executable-p)
fb7933a3
KG
1823 (file-readable-p . tramp-handle-file-readable-p)
1824 (file-regular-p . tramp-handle-file-regular-p)
1825 (file-symlink-p . tramp-handle-file-symlink-p)
1826 (file-writable-p . tramp-handle-file-writable-p)
1827 (file-ownership-preserved-p . tramp-handle-file-ownership-preserved-p)
1828 (file-newer-than-file-p . tramp-handle-file-newer-than-file-p)
1829 (file-attributes . tramp-handle-file-attributes)
1830 (file-modes . tramp-handle-file-modes)
fb7933a3 1831 (directory-files . tramp-handle-directory-files)
c82c5727 1832 (directory-files-and-attributes . tramp-handle-directory-files-and-attributes)
fb7933a3
KG
1833 (file-name-all-completions . tramp-handle-file-name-all-completions)
1834 (file-name-completion . tramp-handle-file-name-completion)
1835 (add-name-to-file . tramp-handle-add-name-to-file)
1836 (copy-file . tramp-handle-copy-file)
1837 (rename-file . tramp-handle-rename-file)
1838 (set-file-modes . tramp-handle-set-file-modes)
ce3f516f 1839 (set-file-times . tramp-handle-set-file-times)
fb7933a3
KG
1840 (make-directory . tramp-handle-make-directory)
1841 (delete-directory . tramp-handle-delete-directory)
1842 (delete-file . tramp-handle-delete-file)
1843 (directory-file-name . tramp-handle-directory-file-name)
00d6fd04
MA
1844 ;; `executable-find' is not official yet.
1845 (executable-find . tramp-handle-executable-find)
1846 (start-file-process . tramp-handle-start-file-process)
0457dd55 1847 (process-file . tramp-handle-process-file)
00d6fd04 1848 (shell-command . tramp-handle-shell-command)
fb7933a3
KG
1849 (insert-directory . tramp-handle-insert-directory)
1850 (expand-file-name . tramp-handle-expand-file-name)
00d6fd04 1851 (substitute-in-file-name . tramp-handle-substitute-in-file-name)
fb7933a3 1852 (file-local-copy . tramp-handle-file-local-copy)
19a87064 1853 (file-remote-p . tramp-handle-file-remote-p)
fb7933a3 1854 (insert-file-contents . tramp-handle-insert-file-contents)
94be87e8
MA
1855 (insert-file-contents-literally
1856 . tramp-handle-insert-file-contents-literally)
fb7933a3 1857 (write-region . tramp-handle-write-region)
38c65fca 1858 (find-backup-file-name . tramp-handle-find-backup-file-name)
c1105d05 1859 (make-auto-save-file-name . tramp-handle-make-auto-save-file-name)
fb7933a3 1860 (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
5ec2cc41 1861 (dired-compress-file . tramp-handle-dired-compress-file)
fb7933a3
KG
1862 (dired-recursive-delete-directory
1863 . tramp-handle-dired-recursive-delete-directory)
70c11b0b 1864 (dired-uncache . tramp-handle-dired-uncache)
fb7933a3 1865 (set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
49096407
MA
1866 (verify-visited-file-modtime . tramp-handle-verify-visited-file-modtime)
1867 (vc-registered . tramp-handle-vc-registered))
c1105d05 1868 "Alist of handler functions.
fb7933a3
KG
1869Operations not mentioned here will be handled by the normal Emacs functions.")
1870
a4aeb9a4 1871;; Handlers for partial Tramp file names. For Emacs just
41c8e348 1872;; `file-name-all-completions' is needed.
a01b1e22 1873;;;###autoload
16674e4f 1874(defconst tramp-completion-file-name-handler-alist
a01b1e22 1875 '((file-name-all-completions . tramp-completion-handle-file-name-all-completions)
41c8e348 1876 (file-name-completion . tramp-completion-handle-file-name-completion))
16674e4f
KG
1877 "Alist of completion handler functions.
1878Used for file names matching `tramp-file-name-regexp'. Operations not
1879mentioned here will be handled by `tramp-file-name-handler-alist' or the
1880normal Emacs functions.")
1881
4007ba5b 1882;; Handlers for foreign methods, like FTP or SMB, shall be plugged here.
ea9d1443
KG
1883(defvar tramp-foreign-file-name-handler-alist
1884 ;; (identity . tramp-sh-file-name-handler) should always be the last
1885 ;; entry, since `identity' always matches.
1886 '((identity . tramp-sh-file-name-handler))
4007ba5b
KG
1887 "Alist of elements (FUNCTION . HANDLER) for foreign methods handled specially.
1888If (FUNCTION FILENAME) returns non-nil, then all I/O on that file is done by
1889calling HANDLER.")
1890
0664ff72 1891;;; Internal functions which must come first:
fb7933a3 1892
00d6fd04
MA
1893(defsubst tramp-debug-message (vec fmt-string &rest args)
1894 "Append message to debug buffer.
1895Message is formatted with FMT-STRING as control string and the remaining
1896ARGS to actually emit the message (if applicable)."
1897 (when (get-buffer (tramp-buffer-name vec))
1898 (with-current-buffer (tramp-get-debug-buffer vec)
1899 (goto-char (point-max))
70c11b0b
MA
1900 ;; Headline.
1901 (when (bobp)
1902 (insert
1903 (format
1904 ";; %sEmacs: %s Tramp: %s -*- mode: outline; -*-"
1905 (if (featurep 'sxemacs) "SX" (if (featurep 'xemacs) "X" "GNU "))
1906 emacs-version tramp-version)))
00d6fd04
MA
1907 (unless (bolp)
1908 (insert "\n"))
70c11b0b 1909 ;; Timestamp.
736ac90f
MA
1910 (let ((now (current-time)))
1911 (insert (format-time-string "%T." now))
1912 (insert (format "%06d " (nth 2 now))))
70c11b0b 1913 ;; Calling function.
00d6fd04
MA
1914 (let ((btn 1) btf fn)
1915 (while (not fn)
1916 (setq btf (nth 1 (backtrace-frame btn)))
1917 (if (not btf)
1918 (setq fn "")
1919 (when (symbolp btf)
1920 (setq fn (symbol-name btf))
1921 (unless (and (string-match "^tramp" fn)
1922 (not (string-match
1923 "^tramp\\(-debug\\)?\\(-message\\|-error\\)$"
1924 fn)))
1925 (setq fn nil)))
1926 (setq btn (1+ btn))))
1927 ;; The following code inserts filename and line number.
1928 ;; Should be deactivated by default, because it is time
1929 ;; consuming.
1930; (let ((ffn (find-function-noselect (intern fn))))
1931; (insert
1932; (format
1933; "%s:%d: "
1934; (file-name-nondirectory (buffer-file-name (car ffn)))
1935; (with-current-buffer (car ffn)
1936; (1+ (count-lines (point-min) (cdr ffn)))))))
1937 (insert (format "%s " fn)))
70c11b0b 1938 ;; The message.
00d6fd04
MA
1939 (insert (apply 'format fmt-string args)))))
1940
1941(defsubst tramp-message (vec-or-proc level fmt-string &rest args)
fb7933a3 1942 "Emit a message depending on verbosity level.
a4aeb9a4 1943VEC-OR-PROC identifies the Tramp buffer to use. It can be either a
00d6fd04
MA
1944vector or a process. LEVEL says to be quiet if `tramp-verbose' is
1945less than LEVEL. The message is emitted only if `tramp-verbose' is
1946greater than or equal to LEVEL.
1947
1948The message is also logged into the debug buffer when `tramp-verbose'
1949is greater than or equal 4.
1950
1951Calls functions `message' and `tramp-debug-message' with FMT-STRING as
1952control string and the remaining ARGS to actually emit the message (if
1953applicable)."
1954 (condition-case nil
1955 (when (<= level tramp-verbose)
1956 ;; Match data must be preserved!
1957 (save-match-data
1958 ;; Display only when there is a minimum level.
1959 (when (<= level 3)
1960 (apply 'message
1961 (concat
1962 (cond
1963 ((= level 0) "")
1964 ((= level 1) "")
1965 ((= level 2) "Warning: ")
1966 (t "Tramp: "))
1967 fmt-string)
1968 args))
1969 ;; Log only when there is a minimum level.
1970 (when (>= tramp-verbose 4)
1971 (when (and vec-or-proc
1972 (processp vec-or-proc)
1973 (buffer-name (process-buffer vec-or-proc)))
1974 (with-current-buffer (process-buffer vec-or-proc)
1975 ;; Translate proc to vec.
1976 (setq vec-or-proc (tramp-dissect-file-name default-directory))))
1977 (when (and vec-or-proc (vectorp vec-or-proc))
1978 (apply 'tramp-debug-message
1979 vec-or-proc
1980 (concat (format "(%d) # " level) fmt-string)
1981 args)))))
1982 ;; Suppress all errors.
1983 (error nil)))
1984
1985(defsubst tramp-error (vec-or-proc signal fmt-string &rest args)
1986 "Emit an error.
1987VEC-OR-PROC identifies the connection to use, SIGNAL is the
1988signal identifier to be raised, remaining args passed to
1989`tramp-message'. Finally, signal SIGNAL is raised."
1990 (tramp-message
1991 vec-or-proc 1 "%s"
1992 (error-message-string
1993 (list signal (get signal 'error-message) (apply 'format fmt-string args))))
1994 (signal signal (list (apply 'format fmt-string args))))
1995
1996(defsubst tramp-error-with-buffer
1997 (buffer vec-or-proc signal fmt-string &rest args)
1998 "Emit an error, and show BUFFER.
1999If BUFFER is nil, show the connection buffer. Wait for 30\", or until
2000an input event arrives. The other arguments are passed to `tramp-error'."
2001 (save-window-excursion
2002 (unwind-protect
2003 (apply 'tramp-error vec-or-proc signal fmt-string args)
2004 (when (and vec-or-proc (not (zerop tramp-verbose)))
2005 (let ((enable-recursive-minibuffers t))
2006 (pop-to-buffer
2007 (or (and (bufferp buffer) buffer)
2008 (and (processp vec-or-proc) (process-buffer vec-or-proc))
2009 (tramp-get-buffer vec-or-proc)))
2010 (sit-for 30))))))
fb7933a3 2011
c62c9d08
KG
2012(defmacro with-parsed-tramp-file-name (filename var &rest body)
2013 "Parse a Tramp filename and make components available in the body.
2014
2015First arg FILENAME is evaluated and dissected into its components.
2016Second arg VAR is a symbol. It is used as a variable name to hold
2017the filename structure. It is also used as a prefix for the variables
2018holding the components. For example, if VAR is the symbol `foo', then
00d6fd04
MA
2019`foo' will be bound to the whole structure, `foo-method' will be bound to
2020the method component, and so on for `foo-user', `foo-host', `foo-localname'.
c62c9d08
KG
2021
2022Remaining args are Lisp expressions to be evaluated (inside an implicit
2023`progn').
2024
00d6fd04
MA
2025If VAR is nil, then we bind `v' to the structure and `method', `user',
2026`host', `localname' to the components."
c62c9d08 2027 `(let* ((,(or var 'v) (tramp-dissect-file-name ,filename))
c62c9d08
KG
2028 (,(if var (intern (concat (symbol-name var) "-method")) 'method)
2029 (tramp-file-name-method ,(or var 'v)))
2030 (,(if var (intern (concat (symbol-name var) "-user")) 'user)
2031 (tramp-file-name-user ,(or var 'v)))
2032 (,(if var (intern (concat (symbol-name var) "-host")) 'host)
2033 (tramp-file-name-host ,(or var 'v)))
7432277c
KG
2034 (,(if var (intern (concat (symbol-name var) "-localname")) 'localname)
2035 (tramp-file-name-localname ,(or var 'v))))
c62c9d08
KG
2036 ,@body))
2037
2038(put 'with-parsed-tramp-file-name 'lisp-indent-function 2)
00d6fd04 2039(put 'with-parsed-tramp-file-name 'edebug-form-spec '(form symbolp body))
9e6ab520 2040(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-parsed-tramp-file-name\\>"))
c62c9d08 2041
00d6fd04
MA
2042(defmacro with-file-property (vec file property &rest body)
2043 "Check in Tramp cache for PROPERTY, otherwise execute BODY and set cache.
2044FILE must be a local file name on a connection identified via VEC."
2045 `(if (file-name-absolute-p ,file)
2046 (let ((value (tramp-get-file-property ,vec ,file ,property 'undef)))
2047 (when (eq value 'undef)
2048 ;; We cannot pass @body as parameter to
2049 ;; `tramp-set-file-property' because it mangles our
2050 ;; debug messages.
2051 (setq value (progn ,@body))
2052 (tramp-set-file-property ,vec ,file ,property value))
2053 value)
2054 ,@body))
9ce8462a 2055
00d6fd04
MA
2056(put 'with-file-property 'lisp-indent-function 3)
2057(put 'with-file-property 'edebug-form-spec t)
9e6ab520 2058(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-file-property\\>"))
00d6fd04
MA
2059
2060(defmacro with-connection-property (key property &rest body)
2061 "Checks in Tramp for property PROPERTY, otherwise executes BODY and set."
2062 `(let ((value (tramp-get-connection-property ,key ,property 'undef)))
2063 (when (eq value 'undef)
2064 ;; We cannot pass ,@body as parameter to
2065 ;; `tramp-set-connection-property' because it mangles our debug
2066 ;; messages.
2067 (setq value (progn ,@body))
2068 (tramp-set-connection-property ,key ,property value))
2069 value))
9ce8462a 2070
00d6fd04
MA
2071(put 'with-connection-property 'lisp-indent-function 2)
2072(put 'with-connection-property 'edebug-form-spec t)
9e6ab520 2073(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-connection-property\\>"))
00d6fd04 2074
628c97b2
GM
2075(eval-and-compile ; silence compiler
2076 (if (memq system-type '(cygwin windows-nt))
2077 (defun tramp-drop-volume-letter (name)
2078 "Cut off unnecessary drive letter from file NAME.
2079The function `tramp-handle-expand-file-name' calls `expand-file-name'
2080locally on a remote file name. When the local system is a W32 system
2081but the remote system is Unix, this introduces a superfluous drive
2082letter into the file name. This function removes it."
2083 (save-match-data
2084 (if (string-match tramp-root-regexp name)
2085 (replace-match "/" nil t name)
2086 name)))
2087
2088 (defalias 'tramp-drop-volume-letter 'identity)))
2089
9c13938d 2090(defsubst tramp-make-tramp-temp-file (vec)
a6e96327 2091 "Create a temporary file on the remote host identified by VEC.
9c13938d
MA
2092Return the local name of the temporary file."
2093 (let ((prefix
2094 (tramp-make-tramp-file-name
2095 (tramp-file-name-method vec)
2096 (tramp-file-name-user vec)
2097 (tramp-file-name-host vec)
113e2a84
MA
2098 (tramp-drop-volume-letter
2099 (expand-file-name
2100 tramp-temp-name-prefix (tramp-get-remote-tmpdir vec)))))
9c13938d
MA
2101 result)
2102 (while (not result)
2103 ;; `make-temp-file' would be the natural choice for
2104 ;; implementation. But it calls `write-region' internally,
2105 ;; which also needs a temporary file - we would end in an
2106 ;; infinite loop.
2107 (setq result (make-temp-name prefix))
2108 (if (file-exists-p result)
2109 (setq result nil)
2110 ;; This creates the file by side effect.
2111 (set-file-times result)
2112 (set-file-modes result (tramp-octal-to-decimal "0700"))))
2113
2114 ;; Return the local part.
2115 (with-parsed-tramp-file-name result nil localname)))
8a4438b6
MA
2116
2117
16674e4f
KG
2118;;; Config Manipulation Functions:
2119
2120(defun tramp-set-completion-function (method function-list)
2121 "Sets the list of completion functions for METHOD.
2122FUNCTION-LIST is a list of entries of the form (FUNCTION FILE).
2123The FUNCTION is intended to parse FILE according its syntax.
2124It might be a predefined FUNCTION, or a user defined FUNCTION.
2125Predefined FUNCTIONs are `tramp-parse-rhosts', `tramp-parse-shosts',
8fc29035 2126`tramp-parse-sconfig', `tramp-parse-hosts', `tramp-parse-passwd',
8daea7fc
KG
2127and `tramp-parse-netrc'.
2128
16674e4f
KG
2129Example:
2130
2131 (tramp-set-completion-function
2132 \"ssh\"
8daea7fc
KG
2133 '((tramp-parse-sconfig \"/etc/ssh_config\")
2134 (tramp-parse-sconfig \"~/.ssh/config\")))"
16674e4f 2135
5ec2cc41
KG
2136 (let ((r function-list)
2137 (v function-list))
2138 (setq tramp-completion-function-alist
2139 (delete (assoc method tramp-completion-function-alist)
2140 tramp-completion-function-alist))
2141
2142 (while v
00d6fd04 2143 ;; Remove double entries.
5ec2cc41
KG
2144 (when (member (car v) (cdr v))
2145 (setcdr v (delete (car v) (cdr v))))
00d6fd04 2146 ;; Check for function and file or registry key.
5ec2cc41 2147 (unless (and (functionp (nth 0 (car v)))
00d6fd04
MA
2148 (if (string-match "^HKEY_CURRENT_USER" (nth 1 (car v)))
2149 ;; Windows registry.
2150 (and (memq system-type '(cygwin windows-nt))
a4aeb9a4
MA
2151 (zerop
2152 (tramp-local-call-process
2153 "reg" nil nil nil "query" (nth 1 (car v)))))
00d6fd04
MA
2154 ;; Configuration file.
2155 (file-exists-p (nth 1 (car v)))))
5ec2cc41
KG
2156 (setq r (delete (car v) r)))
2157 (setq v (cdr v)))
2158
2159 (when r
4007ba5b 2160 (add-to-list 'tramp-completion-function-alist
5ec2cc41 2161 (cons method r)))))
16674e4f
KG
2162
2163(defun tramp-get-completion-function (method)
00d6fd04 2164 "Returns a list of completion functions for METHOD.
16674e4f 2165For definition of that list see `tramp-set-completion-function'."
00d6fd04
MA
2166 (cons
2167 ;; Hosts visited once shall be remembered.
2168 `(tramp-parse-connection-properties ,method)
2169 ;; The method related defaults.
2170 (cdr (assoc method tramp-completion-function-alist))))
16674e4f 2171
d037d501 2172
0664ff72 2173;;; Fontification of `read-file-name':
d037d501 2174
0664ff72 2175;; rfn-eshadow.el is part of Emacs 22. It is autoloaded.
d037d501
MA
2176(defvar tramp-rfn-eshadow-overlay)
2177(make-variable-buffer-local 'tramp-rfn-eshadow-overlay)
2178
2179(defun tramp-rfn-eshadow-setup-minibuffer ()
2180 "Set up a minibuffer for `file-name-shadow-mode'.
2181Adds another overlay hiding filename parts according to Tramp's
2182special handling of `substitute-in-file-name'."
9ce8462a 2183 (when (symbol-value 'minibuffer-completing-file-name)
d037d501 2184 (setq tramp-rfn-eshadow-overlay
9e6ab520
MA
2185 (funcall (symbol-function 'make-overlay)
2186 (funcall (symbol-function 'minibuffer-prompt-end))
2187 (funcall (symbol-function 'minibuffer-prompt-end))))
d037d501 2188 ;; Copy rfn-eshadow-overlay properties.
9e6ab520
MA
2189 (let ((props (funcall (symbol-function 'overlay-properties)
2190 (symbol-value 'rfn-eshadow-overlay))))
d037d501 2191 (while props
9e6ab520
MA
2192 (funcall (symbol-function 'overlay-put)
2193 tramp-rfn-eshadow-overlay (pop props) (pop props))))))
d037d501
MA
2194
2195(when (boundp 'rfn-eshadow-setup-minibuffer-hook)
2196 (add-hook 'rfn-eshadow-setup-minibuffer-hook
48846dc5
MA
2197 'tramp-rfn-eshadow-setup-minibuffer)
2198 (add-hook 'tramp-unload-hook
2199 '(lambda ()
2200 (remove-hook 'rfn-eshadow-setup-minibuffer-hook
2201 'tramp-rfn-eshadow-setup-minibuffer))))
d037d501 2202
adcbca53
MA
2203(defconst tramp-rfn-eshadow-update-overlay-regexp
2204 (format "[^%s/~]*\\(/\\|~\\)" tramp-postfix-host-format))
2205
d037d501
MA
2206(defun tramp-rfn-eshadow-update-overlay ()
2207 "Update `rfn-eshadow-overlay' to cover shadowed part of minibuffer input.
2208This is intended to be used as a minibuffer `post-command-hook' for
2209`file-name-shadow-mode'; the minibuffer should have already
2210been set up by `rfn-eshadow-setup-minibuffer'."
2211 ;; In remote files name, there is a shadowing just for the local part.
9e6ab520
MA
2212 (let ((end (or (funcall (symbol-function 'overlay-end)
2213 (symbol-value 'rfn-eshadow-overlay))
2214 (funcall (symbol-function 'minibuffer-prompt-end)))))
2215 (when (file-remote-p (buffer-substring-no-properties end (point-max)))
bd316474
KY
2216 (save-excursion
2217 (save-restriction
2218 (narrow-to-region
adcbca53
MA
2219 (1+ (or (string-match
2220 tramp-rfn-eshadow-update-overlay-regexp (buffer-string) end)
2221 end))
2222 (point-max))
bd316474
KY
2223 (let ((rfn-eshadow-overlay tramp-rfn-eshadow-overlay)
2224 (rfn-eshadow-update-overlay-hook nil))
dea31ca6 2225 (move-overlay rfn-eshadow-overlay (point-max) (point-max))
bd316474 2226 (funcall (symbol-function 'rfn-eshadow-update-overlay))))))))
d037d501
MA
2227
2228(when (boundp 'rfn-eshadow-update-overlay-hook)
2229 (add-hook 'rfn-eshadow-update-overlay-hook
2230 'tramp-rfn-eshadow-update-overlay))
2231
2232
fb7933a3
KG
2233;;; File Name Handler Functions:
2234
fb7933a3
KG
2235(defun tramp-handle-make-symbolic-link
2236 (filename linkname &optional ok-if-already-exists)
00d6fd04 2237 "Like `make-symbolic-link' for Tramp files.
cebb4ec6 2238If LINKNAME is a non-Tramp file, it is used verbatim as the target of
7432277c 2239the symlink. If LINKNAME is a Tramp file, only the localname component is
cebb4ec6
KG
2240used as the target of the symlink.
2241
7432277c
KG
2242If LINKNAME is a Tramp file and the localname component is relative, then
2243it is expanded first, before the localname component is taken. Note that
cebb4ec6
KG
2244this can give surprising results if the user/host for the source and
2245target of the symlink differ."
c62c9d08 2246 (with-parsed-tramp-file-name linkname l
00d6fd04 2247 (let ((ln (tramp-get-remote-ln l))
87bdd2c7
MA
2248 (cwd (tramp-run-real-handler
2249 'file-name-directory (list l-localname))))
c62c9d08 2250 (unless ln
00d6fd04
MA
2251 (tramp-error
2252 l 'file-error
2253 "Making a symbolic link. ln(1) does not exist on the remote host."))
c62c9d08
KG
2254
2255 ;; Do the 'confirm if exists' thing.
cebb4ec6 2256 (when (file-exists-p linkname)
c62c9d08
KG
2257 ;; What to do?
2258 (if (or (null ok-if-already-exists) ; not allowed to exist
2259 (and (numberp ok-if-already-exists)
2260 (not (yes-or-no-p
2261 (format
2262 "File %s already exists; make it a link anyway? "
7432277c 2263 l-localname)))))
00d6fd04
MA
2264 (tramp-error
2265 l 'file-already-exists "File %s already exists" l-localname)
cebb4ec6
KG
2266 (delete-file linkname)))
2267
7432277c 2268 ;; If FILENAME is a Tramp name, use just the localname component.
cebb4ec6 2269 (when (tramp-tramp-file-p filename)
1834b39f
MA
2270 (setq filename
2271 (tramp-file-name-localname
2272 (tramp-dissect-file-name (expand-file-name filename)))))
bf247b6e 2273
c62c9d08
KG
2274 ;; Right, they are on the same host, regardless of user, method, etc.
2275 ;; We now make the link on the remote machine. This will occur as the user
2276 ;; that FILENAME belongs to.
2277 (zerop
2278 (tramp-send-command-and-check
00d6fd04 2279 l (format "cd %s && %s -sf %s %s" cwd ln filename l-localname) t)))))
fb7933a3 2280
fb7933a3 2281(defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix)
00d6fd04
MA
2282 "Like `load' for Tramp files."
2283 (with-parsed-tramp-file-name (expand-file-name file) nil
c62c9d08
KG
2284 (unless nosuffix
2285 (cond ((file-exists-p (concat file ".elc"))
2286 (setq file (concat file ".elc")))
2287 ((file-exists-p (concat file ".el"))
2288 (setq file (concat file ".el")))))
2289 (when must-suffix
2290 ;; The first condition is always true for absolute file names.
2291 ;; Included for safety's sake.
2292 (unless (or (file-name-directory file)
2293 (string-match "\\.elc?\\'" file))
00d6fd04
MA
2294 (tramp-error
2295 v 'file-error
2296 "File `%s' does not include a `.el' or `.elc' suffix" file)))
c62c9d08
KG
2297 (unless noerror
2298 (when (not (file-exists-p file))
00d6fd04 2299 (tramp-error v 'file-error "Cannot load nonexistent file `%s'" file)))
c62c9d08
KG
2300 (if (not (file-exists-p file))
2301 nil
00d6fd04 2302 (unless nomessage (tramp-message v 0 "Loading %s..." file))
c62c9d08
KG
2303 (let ((local-copy (file-local-copy file)))
2304 ;; MUST-SUFFIX doesn't exist on XEmacs, so let it default to nil.
ce2cc728
MA
2305 (unwind-protect
2306 (load local-copy noerror t t)
2307 (delete-file local-copy)))
00d6fd04 2308 (unless nomessage (tramp-message v 0 "Loading %s...done" file))
c62c9d08 2309 t)))
fb7933a3 2310
a4aeb9a4 2311;; Localname manipulation functions that grok Tramp localnames...
c0fc6170
MA
2312(defun tramp-handle-file-name-as-directory (file)
2313 "Like `file-name-as-directory' but aware of Tramp files."
2314 ;; `file-name-as-directory' would be sufficient except localname is
2315 ;; the empty string.
2316 (let ((v (tramp-dissect-file-name file t)))
2317 ;; Run the command on the localname portion only.
2318 (tramp-make-tramp-file-name
2319 (tramp-file-name-method v)
2320 (tramp-file-name-user v)
2321 (tramp-file-name-host v)
2322 (tramp-run-real-handler
2323 'file-name-as-directory (list (or (tramp-file-name-localname v) ""))))))
2324
fb7933a3 2325(defun tramp-handle-file-name-directory (file)
00d6fd04 2326 "Like `file-name-directory' but aware of Tramp files."
9ce8462a
MA
2327 ;; Everything except the last filename thing is the directory. We
2328 ;; cannot apply `with-parsed-tramp-file-name', because this expands
2329 ;; the remote file name parts. This is a problem when we are in
2330 ;; file name completion.
2331 (let ((v (tramp-dissect-file-name file t)))
a01b1e22
MA
2332 ;; Run the command on the localname portion only.
2333 (tramp-make-tramp-file-name
9ce8462a
MA
2334 (tramp-file-name-method v)
2335 (tramp-file-name-user v)
2336 (tramp-file-name-host v)
87bdd2c7
MA
2337 (tramp-run-real-handler
2338 'file-name-directory (list (or (tramp-file-name-localname v) ""))))))
fb7933a3
KG
2339
2340(defun tramp-handle-file-name-nondirectory (file)
00d6fd04 2341 "Like `file-name-nondirectory' but aware of Tramp files."
c62c9d08 2342 (with-parsed-tramp-file-name file nil
87bdd2c7 2343 (tramp-run-real-handler 'file-name-nondirectory (list localname))))
fb7933a3
KG
2344
2345(defun tramp-handle-file-truename (filename &optional counter prev-dirs)
00d6fd04 2346 "Like `file-truename' for Tramp files."
48ddd622 2347 (with-parsed-tramp-file-name (expand-file-name filename) nil
00d6fd04 2348 (with-file-property v localname "file-truename"
aff67808 2349 (let* ((directory-sep-char ?/) ; for XEmacs
70c11b0b 2350 (steps (tramp-compat-split-string localname "/"))
87bdd2c7
MA
2351 (localnamedir (tramp-run-real-handler
2352 'file-name-as-directory (list localname)))
00d6fd04
MA
2353 (is-dir (string= localname localnamedir))
2354 (thisstep nil)
2355 (numchase 0)
2356 ;; Don't make the following value larger than necessary.
2357 ;; People expect an error message in a timely fashion when
2358 ;; something is wrong; otherwise they might think that Emacs
2359 ;; is hung. Of course, correctness has to come first.
2360 (numchase-limit 20)
2361 (result nil) ;result steps in reverse order
2362 symlink-target)
2363 (tramp-message v 4 "Finding true name for `%s'" filename)
2364 (while (and steps (< numchase numchase-limit))
2365 (setq thisstep (pop steps))
2366 (tramp-message
2367 v 5 "Check %s"
2368 (mapconcat 'identity
2369 (append '("") (reverse result) (list thisstep))
2370 "/"))
2371 (setq symlink-target
2372 (nth 0 (file-attributes
2373 (tramp-make-tramp-file-name
2374 method user host
2375 (mapconcat 'identity
2376 (append '("")
2377 (reverse result)
2378 (list thisstep))
2379 "/")))))
2380 (cond ((string= "." thisstep)
2381 (tramp-message v 5 "Ignoring step `.'"))
2382 ((string= ".." thisstep)
2383 (tramp-message v 5 "Processing step `..'")
2384 (pop result))
2385 ((stringp symlink-target)
2386 ;; It's a symlink, follow it.
2387 (tramp-message v 5 "Follow symlink to %s" symlink-target)
2388 (setq numchase (1+ numchase))
2389 (when (file-name-absolute-p symlink-target)
2390 (setq result nil))
2391 ;; If the symlink was absolute, we'll get a string like
2392 ;; "/user@host:/some/target"; extract the
2393 ;; "/some/target" part from it.
2394 (when (tramp-tramp-file-p symlink-target)
2395 (unless (tramp-equal-remote filename symlink-target)
2396 (tramp-error
2397 v 'file-error
2398 "Symlink target `%s' on wrong host" symlink-target))
2399 (setq symlink-target localname))
2400 (setq steps
70c11b0b 2401 (append (tramp-compat-split-string symlink-target "/")
00d6fd04
MA
2402 steps)))
2403 (t
2404 ;; It's a file.
2405 (setq result (cons thisstep result)))))
2406 (when (>= numchase numchase-limit)
2407 (tramp-error
2408 v 'file-error
2409 "Maximum number (%d) of symlinks exceeded" numchase-limit))
2410 (setq result (reverse result))
2411 ;; Combine list to form string.
2412 (setq result
2413 (if result
2414 (mapconcat 'identity (cons "" result) "/")
2415 "/"))
2416 (when (and is-dir (or (string= "" result)
2417 (not (string= (substring result -1) "/"))))
2418 (setq result (concat result "/")))
2419 (tramp-message v 4 "True name of `%s' is `%s'" filename result)
2420 (tramp-make-tramp-file-name method user host result)))))
fb7933a3
KG
2421
2422;; Basic functions.
2423
2424(defun tramp-handle-file-exists-p (filename)
00d6fd04 2425 "Like `file-exists-p' for Tramp files."
c62c9d08 2426 (with-parsed-tramp-file-name filename nil
00d6fd04 2427 (with-file-property v localname "file-exists-p"
fb7933a3 2428 (zerop (tramp-send-command-and-check
00d6fd04 2429 v
fb7933a3 2430 (format
00d6fd04
MA
2431 "%s %s"
2432 (tramp-get-file-exists-command v)
7432277c 2433 (tramp-shell-quote-argument localname)))))))
fb7933a3 2434
00d6fd04
MA
2435;; Inodes don't exist for some file systems. Therefore we must
2436;; generate virtual ones. Used in `find-buffer-visiting'. The method
2437;; applied might be not so efficient (Ange-FTP uses hashes). But
2438;; performance isn't the major issue given that file transfer will
2439;; take time.
2440(defvar tramp-inodes nil
2441 "Keeps virtual inodes numbers.")
2442
8daea7fc
KG
2443;; Devices must distinguish physical file systems. The device numbers
2444;; provided by "lstat" aren't unique, because we operate on different hosts.
2445;; So we use virtual device numbers, generated by Tramp. Both Ange-FTP and
2446;; EFS use device number "-1". In order to be different, we use device number
b946a456 2447;; (-1 . x), whereby "x" is unique for a given (method user host).
8daea7fc
KG
2448(defvar tramp-devices nil
2449 "Keeps virtual device numbers.")
2450
fb7933a3
KG
2451;; CCC: This should check for an error condition and signal failure
2452;; when something goes wrong.
2453;; Daniel Pittman <daniel@danann.net>
c951aecb 2454(defun tramp-handle-file-attributes (filename &optional id-format)
00d6fd04
MA
2455 "Like `file-attributes' for Tramp files."
2456 (unless id-format (setq id-format 'integer))
2457 (with-parsed-tramp-file-name (expand-file-name filename) nil
2458 (with-file-property v localname (format "file-attributes-%s" id-format)
2459 (when (file-exists-p filename)
2460 ;; file exists, find out stuff
2461 (save-excursion
2462 (tramp-convert-file-attributes
2463 v
2464 (if (tramp-get-remote-stat v)
2465 (tramp-handle-file-attributes-with-stat v localname id-format)
2466 (if (tramp-get-remote-perl v)
2467 (tramp-handle-file-attributes-with-perl v localname id-format)
2468 (tramp-handle-file-attributes-with-ls
2469 v localname id-format)))))))))
2470
2471(defun tramp-handle-file-attributes-with-ls (vec localname &optional id-format)
2472 "Implement `file-attributes' for Tramp files using the ls(1) command."
fb7933a3
KG
2473 (let (symlinkp dirp
2474 res-inode res-filemodes res-numlinks
2475 res-uid res-gid res-size res-symlink-target)
00d6fd04 2476 (tramp-message vec 5 "file attributes with ls: %s" localname)
fb7933a3 2477 (tramp-send-command
00d6fd04 2478 vec
fb7933a3 2479 (format "%s %s %s"
00d6fd04 2480 (tramp-get-ls-command vec)
c82c5727 2481 (if (eq id-format 'integer) "-ildn" "-ild")
7432277c 2482 (tramp-shell-quote-argument localname)))
fb7933a3 2483 ;; parse `ls -l' output ...
00d6fd04
MA
2484 (with-current-buffer (tramp-get-buffer vec)
2485 (goto-char (point-min))
2486 ;; ... inode
2487 (setq res-inode
2488 (condition-case err
2489 (read (current-buffer))
2490 (invalid-read-syntax
2491 (when (and (equal (cadr err)
2492 "Integer constant overflow in reader")
2493 (string-match
2494 "^[0-9]+\\([0-9][0-9][0-9][0-9][0-9]\\)\\'"
2495 (car (cddr err))))
2496 (let* ((big (read (substring (car (cddr err)) 0
2497 (match-beginning 1))))
2498 (small (read (match-string 1 (car (cddr err)))))
2499 (twiddle (/ small 65536)))
2500 (cons (+ big twiddle)
2501 (- small (* twiddle 65536))))))))
2502 ;; ... file mode flags
2503 (setq res-filemodes (symbol-name (read (current-buffer))))
2504 ;; ... number links
2505 (setq res-numlinks (read (current-buffer)))
2506 ;; ... uid and gid
2507 (setq res-uid (read (current-buffer)))
2508 (setq res-gid (read (current-buffer)))
2509 (if (eq id-format 'integer)
2510 (progn
2511 (unless (numberp res-uid) (setq res-uid -1))
2512 (unless (numberp res-gid) (setq res-gid -1)))
2513 (progn
2514 (unless (stringp res-uid) (setq res-uid (symbol-name res-uid)))
2515 (unless (stringp res-gid) (setq res-gid (symbol-name res-gid)))))
2516 ;; ... size
2517 (setq res-size (read (current-buffer)))
2518 ;; From the file modes, figure out other stuff.
2519 (setq symlinkp (eq ?l (aref res-filemodes 0)))
2520 (setq dirp (eq ?d (aref res-filemodes 0)))
2521 ;; if symlink, find out file name pointed to
2522 (when symlinkp
2523 (search-forward "-> ")
2524 (setq res-symlink-target
9e6ab520 2525 (buffer-substring (point) (tramp-compat-line-end-position))))
00d6fd04
MA
2526 ;; return data gathered
2527 (list
2528 ;; 0. t for directory, string (name linked to) for symbolic
2529 ;; link, or nil.
2530 (or dirp res-symlink-target)
2531 ;; 1. Number of links to file.
2532 res-numlinks
2533 ;; 2. File uid.
2534 res-uid
2535 ;; 3. File gid.
2536 res-gid
2537 ;; 4. Last access time, as a list of two integers. First
2538 ;; integer has high-order 16 bits of time, second has low 16
2539 ;; bits.
2540 ;; 5. Last modification time, likewise.
2541 ;; 6. Last status change time, likewise.
2542 '(0 0) '(0 0) '(0 0) ;CCC how to find out?
2543 ;; 7. Size in bytes (-1, if number is out of range).
2544 res-size
2545 ;; 8. File modes, as a string of ten letters or dashes as in ls -l.
2546 res-filemodes
1437876c 2547 ;; 9. t if file's gid would change if file were deleted and
00d6fd04
MA
2548 ;; recreated. Will be set in `tramp-convert-file-attributes'
2549 t
2550 ;; 10. inode number.
2551 res-inode
2552 ;; 11. Device number. Will be replaced by a virtual device number.
2553 -1
2554 ))))
fb7933a3
KG
2555
2556(defun tramp-handle-file-attributes-with-perl
00d6fd04
MA
2557 (vec localname &optional id-format)
2558 "Implement `file-attributes' for Tramp files using a Perl script."
2559 (tramp-message vec 5 "file attributes with perl: %s" localname)
2560 (tramp-maybe-send-script
2561 vec tramp-perl-file-attributes "tramp_perl_file_attributes")
2562 (tramp-send-command-and-read
2563 vec
2564 (format "tramp_perl_file_attributes %s %s"
2565 (tramp-shell-quote-argument localname) id-format)))
2566
2567(defun tramp-handle-file-attributes-with-stat
2568 (vec localname &optional id-format)
2569 "Implement `file-attributes' for Tramp files using stat(1) command."
2570 (tramp-message vec 5 "file attributes with stat: %s" localname)
2571 (tramp-send-command-and-read
2572 vec
2573 (format
d4443a0d 2574 "%s -c '((\"%%N\") %%h %s %s %%X.0 %%Y.0 %%Z.0 %%s.0 \"%%A\" t %%i.0 -1)' %s"
00d6fd04
MA
2575 (tramp-get-remote-stat vec)
2576 (if (eq id-format 'integer) "%u" "\"%U\"")
2577 (if (eq id-format 'integer) "%g" "\"%G\"")
2578 (tramp-shell-quote-argument localname))))
8daea7fc 2579
fb7933a3 2580(defun tramp-handle-set-visited-file-modtime (&optional time-list)
00d6fd04 2581 "Like `set-visited-file-modtime' for Tramp files."
fb7933a3
KG
2582 (unless (buffer-file-name)
2583 (error "Can't set-visited-file-modtime: buffer `%s' not visiting a file"
2584 (buffer-name)))
48ddd622
MA
2585 (if time-list
2586 (tramp-run-real-handler 'set-visited-file-modtime (list time-list))
11948172
MA
2587 (let ((f (buffer-file-name))
2588 coding-system-used)
48ddd622
MA
2589 (with-parsed-tramp-file-name f nil
2590 (let* ((attr (file-attributes f))
2591 ;; '(-1 65535) means file doesn't exists yet.
2592 (modtime (or (nth 5 attr) '(-1 65535))))
11948172
MA
2593 (when (boundp 'last-coding-system-used)
2594 (setq coding-system-used (symbol-value 'last-coding-system-used)))
48ddd622
MA
2595 ;; We use '(0 0) as a don't-know value. See also
2596 ;; `tramp-handle-file-attributes-with-ls'.
48ddd622
MA
2597 (if (not (equal modtime '(0 0)))
2598 (tramp-run-real-handler 'set-visited-file-modtime (list modtime))
00d6fd04 2599 (progn
48ddd622 2600 (tramp-send-command
00d6fd04 2601 v
48ddd622 2602 (format "%s -ild %s"
00d6fd04 2603 (tramp-get-ls-command v)
48ddd622 2604 (tramp-shell-quote-argument localname)))
48ddd622
MA
2605 (setq attr (buffer-substring (point)
2606 (progn (end-of-line) (point)))))
00d6fd04
MA
2607 (tramp-set-file-property
2608 v localname "visited-file-modtime-ild" attr))
11948172
MA
2609 (when (boundp 'last-coding-system-used)
2610 (set 'last-coding-system-used coding-system-used))
d2a2c17f 2611 nil)))))
fb7933a3 2612
c62c9d08
KG
2613;; This function makes the same assumption as
2614;; `tramp-handle-set-visited-file-modtime'.
2615(defun tramp-handle-verify-visited-file-modtime (buf)
00d6fd04 2616 "Like `verify-visited-file-modtime' for Tramp files.
c08e6004
MA
2617At the time `verify-visited-file-modtime' calls this function, we
2618already know that the buffer is visiting a file and that
2619`visited-file-modtime' does not return 0. Do not call this
2620function directly, unless those two cases are already taken care
2621of."
c62c9d08 2622 (with-current-buffer buf
b15d0c4c
MA
2623 ;; There is no file visiting the buffer, or the buffer has no
2624 ;; recorded last modification time.
2625 (if (or (not (buffer-file-name))
2626 (eq (visited-file-modtime) 0))
d2a2c17f 2627 t
b15d0c4c
MA
2628 (let ((f (buffer-file-name)))
2629 (with-parsed-tramp-file-name f nil
bce04fee 2630 (tramp-flush-file-property v localname)
b15d0c4c
MA
2631 (let* ((attr (file-attributes f))
2632 (modtime (nth 5 attr))
2633 (mt (visited-file-modtime)))
bf247b6e 2634
70c11b0b
MA
2635 (cond
2636 ;; File exists, and has a known modtime.
b15d0c4c
MA
2637 ((and attr (not (equal modtime '(0 0))))
2638 (< (abs (tramp-time-diff
2639 modtime
2640 ;; For compatibility, deal with both the old
70c11b0b
MA
2641 ;; (HIGH . LOW) and the new (HIGH LOW) return
2642 ;; values of `visited-file-modtime'.
b15d0c4c
MA
2643 (if (atom (cdr mt))
2644 (list (car mt) (cdr mt))
2645 mt)))
2646 2))
70c11b0b 2647 ;; Modtime has the don't know value.
b15d0c4c 2648 (attr
00d6fd04
MA
2649 (tramp-send-command
2650 v
2651 (format "%s -ild %s"
2652 (tramp-get-ls-command v)
2653 (tramp-shell-quote-argument localname)))
2654 (with-current-buffer (tramp-get-buffer v)
b15d0c4c
MA
2655 (setq attr (buffer-substring
2656 (point) (progn (end-of-line) (point)))))
00d6fd04
MA
2657 (equal
2658 attr
2659 (tramp-get-file-property
2660 v localname "visited-file-modtime-ild" "")))
70c11b0b
MA
2661 ;; If file does not exist, say it is not modified if and
2662 ;; only if that agrees with the buffer's record.
b15d0c4c 2663 (t (equal mt '(-1 65535))))))))))
c62c9d08 2664
fb7933a3 2665(defun tramp-handle-set-file-modes (filename mode)
00d6fd04 2666 "Like `set-file-modes' for Tramp files."
c62c9d08 2667 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2668 (tramp-flush-file-property v localname)
2669 (unless (zerop (tramp-send-command-and-check
2670 v
2671 (format "chmod %s %s"
2672 (tramp-decimal-to-octal mode)
2673 (tramp-shell-quote-argument localname))))
2674 ;; FIXME: extract the proper text from chmod's stderr.
2675 (tramp-error
2676 v 'file-error "Error while changing file's mode %s" filename))))
fb7933a3 2677
ce3f516f
MA
2678(defun tramp-handle-set-file-times (filename &optional time)
2679 "Like `set-file-times' for Tramp files."
2680 (zerop
9e6ab520 2681 (if (file-remote-p filename)
ce3f516f 2682 (with-parsed-tramp-file-name filename nil
8d60099b 2683 (tramp-flush-file-property v localname)
ce3f516f
MA
2684 (let ((time (if (or (null time) (equal time '(0 0)))
2685 (current-time)
2686 time))
2687 (utc
2688 ;; With GNU Emacs, `format-time-string' has an
2689 ;; optional parameter UNIVERSAL. This is preferred,
2690 ;; because we could handle the case when the remote
2691 ;; host is located in a different time zone as the
2692 ;; local host.
2693 (and (functionp 'subr-arity)
2694 (subrp (symbol-function 'format-time-string))
2695 (= 3 (cdr (funcall (symbol-function 'subr-arity)
2696 (symbol-function
2697 'format-time-string)))))))
2698 (tramp-send-command-and-check
2699 v (format "%s touch -t %s %s"
2700 (if utc "TZ=UTC; export TZ;" "")
2701 (if utc
2702 (format-time-string "%Y%m%d%H%M.%S" time t)
2703 (format-time-string "%Y%m%d%H%M.%S" time))
2704 (tramp-shell-quote-argument localname)))))
8d60099b 2705
ce3f516f
MA
2706 ;; We handle also the local part, because in older Emacsen,
2707 ;; without `set-file-times', this function is an alias for this.
2708 ;; We are local, so we don't need the UTC settings.
a4aeb9a4 2709 (tramp-local-call-process
ce3f516f
MA
2710 "touch" nil nil nil "-t"
2711 (format-time-string "%Y%m%d%H%M.%S" time)
2712 (tramp-shell-quote-argument filename)))))
2713
8d60099b
MA
2714(defun tramp-set-file-uid-gid (filename &optional uid gid)
2715 "Set the ownership for FILENAME.
2716If UID and GID are provided, these values are used; otherwise uid
2717and gid of the corresponding user is taken. Both parameters must be integers."
70c11b0b
MA
2718 ;; Modern Unices allow chown only for root. So we might need
2719 ;; another implementation, see `dired-do-chown'. OTOH, it is mostly
2720 ;; working with su(do)? when it is needed, so it shall succeed in
2721 ;; the majority of cases.
9e6ab520 2722 (if (file-remote-p filename)
8d60099b 2723 (with-parsed-tramp-file-name filename nil
93c3eb7c
MA
2724 (if (and (zerop (user-uid)) (tramp-local-host-p v))
2725 ;; If we are root on the local host, we can do it directly.
2726 (tramp-set-file-uid-gid localname uid gid)
2727 (let ((uid (or (and (integerp uid) uid)
2728 (tramp-get-remote-uid v 'integer)))
2729 (gid (or (and (integerp gid) gid)
2730 (tramp-get-remote-gid v 'integer))))
2731 (tramp-send-command
2732 v (format
2733 "chown %d:%d %s" uid gid
2734 (tramp-shell-quote-argument localname))))))
8d60099b
MA
2735
2736 ;; We handle also the local part, because there doesn't exist
70c11b0b 2737 ;; `set-file-uid-gid'. On W32 "chown" might not work.
8d60099b 2738 (let ((uid (or (and (integerp uid) uid) (tramp-get-local-uid 'integer)))
a4aeb9a4
MA
2739 (gid (or (and (integerp gid) gid) (tramp-get-local-gid 'integer))))
2740 (tramp-local-call-process
2741 "chown" nil nil nil
2742 (format "%d:%d" uid gid) (tramp-shell-quote-argument filename)))))
8d60099b 2743
fb7933a3
KG
2744;; Simple functions using the `test' command.
2745
2746(defun tramp-handle-file-executable-p (filename)
00d6fd04 2747 "Like `file-executable-p' for Tramp files."
c62c9d08 2748 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2749 (with-file-property v localname "file-executable-p"
2750 (zerop (tramp-run-test "-x" filename)))))
fb7933a3
KG
2751
2752(defun tramp-handle-file-readable-p (filename)
00d6fd04 2753 "Like `file-readable-p' for Tramp files."
c62c9d08 2754 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2755 (with-file-property v localname "file-readable-p"
2756 (zerop (tramp-run-test "-r" filename)))))
fb7933a3
KG
2757
2758;; When the remote shell is started, it looks for a shell which groks
2759;; tilde expansion. Here, we assume that all shells which grok tilde
2760;; expansion will also provide a `test' command which groks `-nt' (for
2761;; newer than). If this breaks, tell me about it and I'll try to do
2762;; something smarter about it.
2763(defun tramp-handle-file-newer-than-file-p (file1 file2)
00d6fd04 2764 "Like `file-newer-than-file-p' for Tramp files."
fb7933a3
KG
2765 (cond ((not (file-exists-p file1))
2766 nil)
2767 ((not (file-exists-p file2))
2768 t)
91879624 2769 ;; We are sure both files exist at this point.
fb7933a3
KG
2770 (t
2771 (save-excursion
91879624
KG
2772 ;; We try to get the mtime of both files. If they are not
2773 ;; equal to the "dont-know" value, then we subtract the times
2774 ;; and obtain the result.
2775 (let ((fa1 (file-attributes file1))
2776 (fa2 (file-attributes file2)))
2777 (if (and (not (equal (nth 5 fa1) '(0 0)))
2778 (not (equal (nth 5 fa2) '(0 0))))
01917a18 2779 (> 0 (tramp-time-diff (nth 5 fa2) (nth 5 fa1)))
91879624
KG
2780 ;; If one of them is the dont-know value, then we can
2781 ;; still try to run a shell command on the remote host.
2782 ;; However, this only works if both files are Tramp
2783 ;; files and both have the same method, same user, same
2784 ;; host.
00d6fd04
MA
2785 (unless (tramp-equal-remote file1 file2)
2786 (with-parsed-tramp-file-name
2787 (if (tramp-tramp-file-p file1) file1 file2) nil
2788 (tramp-error
2789 v 'file-error
2790 "Files %s and %s must have same method, user, host"
2791 file1 file2)))
2792 (with-parsed-tramp-file-name file1 nil
2793 (zerop (tramp-run-test2
2794 (tramp-get-test-nt-command v) file1 file2)))))))))
fb7933a3
KG
2795
2796;; Functions implemented using the basic functions above.
2797
2798(defun tramp-handle-file-modes (filename)
00d6fd04 2799 "Like `file-modes' for Tramp files."
5da24108
MA
2800 (let ((truename (or (file-truename filename) filename)))
2801 (when (file-exists-p truename)
2802 (tramp-mode-string-to-int (nth 8 (file-attributes truename))))))
fb7933a3 2803
b86c1cd8
MA
2804(defun tramp-default-file-modes (filename)
2805 "Return file modes of FILENAME as integer.
2806If the file modes of FILENAME cannot be determined, return the
974647ac
MA
2807value of `default-file-modes', without execute permissions."
2808 (or (file-modes filename)
2809 (logand (default-file-modes) (tramp-octal-to-decimal "0666"))))
b86c1cd8 2810
fb7933a3 2811(defun tramp-handle-file-directory-p (filename)
00d6fd04 2812 "Like `file-directory-p' for Tramp files."
fb7933a3
KG
2813 ;; Care must be taken that this function returns `t' for symlinks
2814 ;; pointing to directories. Surely the most obvious implementation
2815 ;; would be `test -d', but that returns false for such symlinks.
2816 ;; CCC: Stefan Monnier says that `test -d' follows symlinks. And
2817 ;; I now think he's right. So we could be using `test -d', couldn't
2818 ;; we?
2819 ;;
2820 ;; Alternatives: `cd %s', `test -d %s'
c62c9d08 2821 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2822 (with-file-property v localname "file-directory-p"
2823 (zerop (tramp-run-test "-d" filename)))))
fb7933a3
KG
2824
2825(defun tramp-handle-file-regular-p (filename)
00d6fd04
MA
2826 "Like `file-regular-p' for Tramp files."
2827 (and (file-exists-p filename)
2828 (eq ?- (aref (nth 8 (file-attributes filename)) 0))))
fb7933a3
KG
2829
2830(defun tramp-handle-file-symlink-p (filename)
00d6fd04 2831 "Like `file-symlink-p' for Tramp files."
c62c9d08 2832 (with-parsed-tramp-file-name filename nil
c951aecb 2833 (let ((x (car (file-attributes filename))))
b25a52cc
KG
2834 (when (stringp x)
2835 ;; When Tramp is running on VMS, then `file-name-absolute-p'
2836 ;; might do weird things.
2837 (if (file-name-absolute-p x)
00d6fd04 2838 (tramp-make-tramp-file-name method user host x)
b25a52cc 2839 x)))))
fb7933a3
KG
2840
2841(defun tramp-handle-file-writable-p (filename)
00d6fd04 2842 "Like `file-writable-p' for Tramp files."
c62c9d08 2843 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2844 (with-file-property v localname "file-writable-p"
2845 (if (file-exists-p filename)
2846 ;; Existing files must be writable.
2847 (zerop (tramp-run-test "-w" filename))
2848 ;; If file doesn't exist, check if directory is writable.
2849 (and (zerop (tramp-run-test
2850 "-d" (file-name-directory filename)))
2851 (zerop (tramp-run-test
2852 "-w" (file-name-directory filename))))))))
fb7933a3
KG
2853
2854(defun tramp-handle-file-ownership-preserved-p (filename)
00d6fd04 2855 "Like `file-ownership-preserved-p' for Tramp files."
c62c9d08 2856 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2857 (with-file-property v localname "file-ownership-preserved-p"
2858 (let ((attributes (file-attributes filename)))
2859 ;; Return t if the file doesn't exist, since it's true that no
2860 ;; information would be lost by an (attempted) delete and create.
2861 (or (null attributes)
2862 (= (nth 2 attributes) (tramp-get-remote-uid v 'integer)))))))
fb7933a3
KG
2863
2864;; Other file name ops.
2865
fb7933a3 2866(defun tramp-handle-directory-file-name (directory)
00d6fd04 2867 "Like `directory-file-name' for Tramp files."
7432277c
KG
2868 ;; If localname component of filename is "/", leave it unchanged.
2869 ;; Otherwise, remove any trailing slash from localname component.
8daea7fc
KG
2870 ;; Method, host, etc, are unchanged. Does it make sense to try
2871 ;; to avoid parsing the filename?
c62c9d08 2872 (with-parsed-tramp-file-name directory nil
7432277c
KG
2873 (if (and (not (zerop (length localname)))
2874 (eq (aref localname (1- (length localname))) ?/)
2875 (not (string= localname "/")))
8daea7fc
KG
2876 (substring directory 0 -1)
2877 directory)))
fb7933a3
KG
2878
2879;; Directory listings.
2880
00d6fd04
MA
2881(defun tramp-handle-directory-files
2882 (directory &optional full match nosort files-only)
2883 "Like `directory-files' for Tramp files."
2884 ;; FILES-ONLY is valid for XEmacs only.
2885 (when (file-directory-p directory)
2886 (setq directory (expand-file-name directory))
2887 (let ((temp (nreverse (file-name-all-completions "" directory)))
2888 result item)
2889
2890 (while temp
2891 (setq item (directory-file-name (pop temp)))
2892 (when (and (or (null match) (string-match match item))
2893 (or (null files-only)
2894 ;; files only
2895 (and (equal files-only t) (file-regular-p item))
2896 ;; directories only
2897 (file-directory-p item)))
2898 (push (if full (expand-file-name item directory) item)
2899 result)))
c62c9d08
KG
2900 result)))
2901
c82c5727
LH
2902(defun tramp-handle-directory-files-and-attributes
2903 (directory &optional full match nosort id-format)
00d6fd04
MA
2904 "Like `directory-files-and-attributes' for Tramp files."
2905 (unless id-format (setq id-format 'integer))
2906 (when (file-directory-p directory)
2907 (setq directory (expand-file-name directory))
2908 (let* ((temp
9e6ab520 2909 (tramp-compat-copy-tree
00d6fd04
MA
2910 (with-parsed-tramp-file-name directory nil
2911 (with-file-property
2912 v localname
2913 (format "directory-files-and-attributes-%s" id-format)
2914 (save-excursion
2915 (mapcar
2916 '(lambda (x)
2917 (cons (car x)
2918 (tramp-convert-file-attributes v (cdr x))))
2919 (if (tramp-get-remote-stat v)
2920 (tramp-handle-directory-files-and-attributes-with-stat
2921 v localname id-format)
2922 (if (tramp-get-remote-perl v)
2923 (tramp-handle-directory-files-and-attributes-with-perl
2924 v localname id-format)))))))))
2925 result item)
2926
2927 (while temp
2928 (setq item (pop temp))
2929 (when (or (null match) (string-match match (car item)))
2930 (when full
2931 (setcar item (expand-file-name (car item) directory)))
2932 (push item result)))
2933
2934 (if nosort
2935 result
2936 (sort result (lambda (x y) (string< (car x) (car y))))))))
2937
2938(defun tramp-handle-directory-files-and-attributes-with-perl
2939 (vec localname &optional id-format)
2940 "Implement `directory-files-and-attributes' for Tramp files using a Perl script."
2941 (tramp-message vec 5 "directory-files-and-attributes with perl: %s" localname)
2942 (tramp-maybe-send-script
2943 vec tramp-perl-directory-files-and-attributes
2944 "tramp_perl_directory_files_and_attributes")
2945 (let ((object
2946 (tramp-send-command-and-read
2947 vec
2948 (format "tramp_perl_directory_files_and_attributes %s %s"
2949 (tramp-shell-quote-argument localname) id-format))))
2950 (when (stringp object) (tramp-error vec 'file-error object))
2951 object))
2952
2953(defun tramp-handle-directory-files-and-attributes-with-stat
2954 (vec localname &optional id-format)
2955 "Implement `directory-files-and-attributes' for Tramp files using stat(1) command."
2956 (tramp-message vec 5 "directory-files-and-attributes with stat: %s" localname)
2957 (tramp-send-command-and-read
2958 vec
2959 (format
2960 (concat
70c11b0b
MA
2961 ;; We must care about filenames with spaces, or starting with
2962 ;; "-"; this would confuse xargs. "ls -aQ" might be a solution,
2963 ;; but it does not work on all remote systems. Therefore, we
2964 ;; quote the filenames via sed.
2965 "cd %s; echo \"(\"; (%s -a | sed -e s/\\$/\\\"/g -e s/^/\\\"/g | xargs "
d4443a0d 2966 "%s -c '(\"%%n\" (\"%%N\") %%h %s %s %%X.0 %%Y.0 %%Z.0 %%s.0 \"%%A\" t %%i.0 -1)'); "
00d6fd04
MA
2967 "echo \")\"")
2968 (tramp-shell-quote-argument localname)
2969 (tramp-get-ls-command vec)
2970 (tramp-get-remote-stat vec)
2971 (if (eq id-format 'integer) "%u" "\"%U\"")
2972 (if (eq id-format 'integer) "%g" "\"%G\""))))
c82c5727 2973
c62c9d08 2974;; This function should return "foo/" for directories and "bar" for
00d6fd04 2975;; files.
c62c9d08 2976(defun tramp-handle-file-name-all-completions (filename directory)
00d6fd04
MA
2977 "Like `file-name-all-completions' for Tramp files."
2978 (unless (save-match-data (string-match "/" filename))
9c13938d 2979 (with-parsed-tramp-file-name (expand-file-name directory) nil
b50dd0d2
MA
2980 ;; Flush the directory cache. There could be changed directory
2981 ;; contents.
2982 (when (and (integerp tramp-completion-reread-directory-timeout)
2983 (> (tramp-time-diff
2984 (current-time)
2985 (tramp-get-file-property
2986 v localname "last-completion" '(0 0 0)))
2987 tramp-completion-reread-directory-timeout))
2988 (tramp-flush-file-property v localname))
2989
00d6fd04
MA
2990 (all-completions
2991 filename
2992 (mapcar
2993 'list
2994 (with-file-property v localname "file-name-all-completions"
2995 (let (result)
2996 (tramp-barf-unless-okay
2997 v
2998 (format "cd %s" (tramp-shell-quote-argument localname))
2999 "tramp-handle-file-name-all-completions: Couldn't `cd %s'"
3000 (tramp-shell-quote-argument localname))
3001
3002 ;; Get a list of directories and files, including reliably
3003 ;; tagging the directories with a trailing '/'. Because I
3004 ;; rock. --daniel@danann.net
3005 (tramp-send-command
3006 v
65a099b6 3007 (format (concat "%s -a 2>/dev/null | while read f; do "
00d6fd04
MA
3008 "if %s -d \"$f\" 2>/dev/null; "
3009 "then echo \"$f/\"; else echo \"$f\"; fi; done")
3010 (tramp-get-ls-command v)
3011 (tramp-get-test-command v)))
3012
3013 ;; Now grab the output.
3014 (with-current-buffer (tramp-get-buffer v)
3015 (goto-char (point-max))
3016 (while (zerop (forward-line -1))
9e6ab520
MA
3017 (push (buffer-substring
3018 (point) (tramp-compat-line-end-position))
00d6fd04
MA
3019 result)))
3020
b50dd0d2
MA
3021 (tramp-set-file-property
3022 v localname "last-completion" (current-time))
00d6fd04 3023 result)))))))
fb7933a3
KG
3024
3025;; The following isn't needed for Emacs 20 but for 19.34?
e1e17cae
MA
3026(defun tramp-handle-file-name-completion
3027 (filename directory &optional predicate)
00d6fd04 3028 "Like `file-name-completion' for Tramp files."
fb7933a3
KG
3029 (unless (tramp-tramp-file-p directory)
3030 (error
3031 "tramp-handle-file-name-completion invoked on non-tramp directory `%s'"
3032 directory))
83e20b5c
MA
3033 (try-completion
3034 filename
3035 (mapcar 'list (file-name-all-completions filename directory))
3036 (when predicate
3037 (lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
fb7933a3
KG
3038
3039;; cp, mv and ln
3040
3041(defun tramp-handle-add-name-to-file
3042 (filename newname &optional ok-if-already-exists)
00d6fd04
MA
3043 "Like `add-name-to-file' for Tramp files."
3044 (unless (tramp-equal-remote filename newname)
3045 (with-parsed-tramp-file-name
3046 (if (tramp-tramp-file-p filename) filename newname) nil
3047 (tramp-error
3048 v 'file-error
3049 "add-name-to-file: %s"
3050 "only implemented for same method, same user, same host")))
c62c9d08
KG
3051 (with-parsed-tramp-file-name filename v1
3052 (with-parsed-tramp-file-name newname v2
00d6fd04 3053 (let ((ln (when v1 (tramp-get-remote-ln v1))))
c62c9d08
KG
3054 (when (and (not ok-if-already-exists)
3055 (file-exists-p newname)
3056 (not (numberp ok-if-already-exists))
3057 (y-or-n-p
3058 (format
3059 "File %s already exists; make it a new name anyway? "
3060 newname)))
00d6fd04
MA
3061 (tramp-error
3062 v2 'file-error
3063 "add-name-to-file: file %s already exists" newname))
3064 (tramp-flush-file-property v2 v2-localname)
c62c9d08 3065 (tramp-barf-unless-okay
00d6fd04 3066 v1
7432277c
KG
3067 (format "%s %s %s" ln (tramp-shell-quote-argument v1-localname)
3068 (tramp-shell-quote-argument v2-localname))
c62c9d08
KG
3069 "error with add-name-to-file, see buffer `%s' for details"
3070 (buffer-name))))))
fb7933a3
KG
3071
3072(defun tramp-handle-copy-file
8d60099b 3073 (filename newname &optional ok-if-already-exists keep-date preserve-uid-gid)
00d6fd04 3074 "Like `copy-file' for Tramp files."
fb7933a3 3075 ;; Check if both files are local -- invoke normal copy-file.
9e6ab520 3076 ;; Otherwise, use Tramp from local system.
fb7933a3
KG
3077 (setq filename (expand-file-name filename))
3078 (setq newname (expand-file-name newname))
9e6ab520 3079 (cond
a4aeb9a4 3080 ;; At least one file a Tramp file?
9e6ab520
MA
3081 ((or (tramp-tramp-file-p filename)
3082 (tramp-tramp-file-p newname))
3083 (tramp-do-copy-or-rename-file
3084 'copy filename newname ok-if-already-exists keep-date preserve-uid-gid))
3085 ;; Compat section.
3086 (preserve-uid-gid
fb7933a3 3087 (tramp-run-real-handler
8d60099b 3088 'copy-file
9e6ab520
MA
3089 (list filename newname ok-if-already-exists keep-date preserve-uid-gid)))
3090 (t
3091 (tramp-run-real-handler
3092 'copy-file (list filename newname ok-if-already-exists keep-date)))))
fb7933a3
KG
3093
3094(defun tramp-handle-rename-file
3095 (filename newname &optional ok-if-already-exists)
00d6fd04 3096 "Like `rename-file' for Tramp files."
fb7933a3 3097 ;; Check if both files are local -- invoke normal rename-file.
a4aeb9a4 3098 ;; Otherwise, use Tramp from local system.
fb7933a3
KG
3099 (setq filename (expand-file-name filename))
3100 (setq newname (expand-file-name newname))
a4aeb9a4 3101 ;; At least one file a Tramp file?
fb7933a3
KG
3102 (if (or (tramp-tramp-file-p filename)
3103 (tramp-tramp-file-p newname))
3104 (tramp-do-copy-or-rename-file
8d60099b 3105 'rename filename newname ok-if-already-exists t t)
00d6fd04
MA
3106 (tramp-run-real-handler
3107 'rename-file (list filename newname ok-if-already-exists))))
fb7933a3
KG
3108
3109(defun tramp-do-copy-or-rename-file
8d60099b 3110 (op filename newname &optional ok-if-already-exists keep-date preserve-uid-gid)
fb7933a3
KG
3111 "Copy or rename a remote file.
3112OP must be `copy' or `rename' and indicates the operation to perform.
3113FILENAME specifies the file to copy or rename, NEWNAME is the name of
3114the new file (for copy) or the new name of the file (for rename).
3115OK-IF-ALREADY-EXISTS means don't barf if NEWNAME exists already.
3116KEEP-DATE means to make sure that NEWNAME has the same timestamp
8d60099b
MA
3117as FILENAME. PRESERVE-UID-GID, when non-nil, instructs to keep
3118the uid and gid if both files are on the same host.
fb7933a3
KG
3119
3120This function is invoked by `tramp-handle-copy-file' and
3121`tramp-handle-rename-file'. It is an error if OP is neither of `copy'
3122and `rename'. FILENAME and NEWNAME must be absolute file names."
3123 (unless (memq op '(copy rename))
3124 (error "Unknown operation `%s', must be `copy' or `rename'" op))
90dc758d 3125 (let ((t1 (tramp-tramp-file-p filename))
00d6fd04 3126 (t2 (tramp-tramp-file-p newname)))
5ec2cc41 3127
da1975d7
MA
3128 (when (and (not ok-if-already-exists) (file-exists-p newname))
3129 (with-parsed-tramp-file-name (if t1 filename newname) nil
3130 (tramp-error
3131 v 'file-already-exists "File %s already exists" newname)))
5ec2cc41 3132
905fb90e
MA
3133 (with-parsed-tramp-file-name (if t1 filename newname) nil
3134 (tramp-message v 0 "Transferring %s to %s..." filename newname))
3135
00d6fd04
MA
3136 (prog1
3137 (cond
3138 ;; Both are Tramp files.
3139 ((and t1 t2)
3140 (with-parsed-tramp-file-name filename v1
3141 (with-parsed-tramp-file-name newname v2
3142 (cond
3143 ;; Shortcut: if method, host, user are the same for both
3144 ;; files, we invoke `cp' or `mv' on the remote host
3145 ;; directly.
3146 ((tramp-equal-remote filename newname)
3147 (tramp-do-copy-or-rename-file-directly
8d60099b
MA
3148 op filename newname
3149 ok-if-already-exists keep-date preserve-uid-gid))
3150
905fb90e
MA
3151 ;; Try out-of-band operation.
3152 ((and (tramp-method-out-of-band-p v1)
00d6fd04
MA
3153 (> (nth 7 (file-attributes filename))
3154 tramp-copy-size-limit))
3155 (tramp-do-copy-or-rename-file-out-of-band
3156 op filename newname keep-date))
8d60099b 3157
00d6fd04
MA
3158 ;; No shortcut was possible. So we copy the
3159 ;; file first. If the operation was `rename', we go
3160 ;; back and delete the original file (if the copy was
3161 ;; successful). The approach is simple-minded: we
3162 ;; create a new buffer, insert the contents of the
3163 ;; source file into it, then write out the buffer to
3164 ;; the target file. The advantage is that it doesn't
3165 ;; matter which filename handlers are used for the
3166 ;; source and target file.
3167 (t
3168 (tramp-do-copy-or-rename-file-via-buffer
3169 op filename newname keep-date))))))
3170
3171 ;; One file is a Tramp file, the other one is local.
3172 ((or t1 t2)
3173 (with-parsed-tramp-file-name (if t1 filename newname) nil
8d60099b
MA
3174 (cond
3175 ;; Fast track on local machine.
3176 ((tramp-local-host-p v)
3177 (tramp-do-copy-or-rename-file-directly
3178 op filename newname
3179 ok-if-already-exists keep-date preserve-uid-gid))
3180
3181 ;; If the Tramp file has an out-of-band method, the corresponding
3182 ;; copy-program can be invoked.
3183 ((and (tramp-method-out-of-band-p v)
3184 (> (nth 7 (file-attributes filename))
3185 tramp-copy-size-limit))
3186 (tramp-do-copy-or-rename-file-out-of-band
3187 op filename newname keep-date))
3188
3189 ;; Use the inline method via a Tramp buffer.
3190 (t (tramp-do-copy-or-rename-file-via-buffer
3191 op filename newname keep-date)))))
00d6fd04
MA
3192
3193 (t
3194 ;; One of them must be a Tramp file.
3195 (error "Tramp implementation says this cannot happen")))
8d60099b 3196
484ea0b6
MA
3197 ;; In case of `rename', we must flush the cache of the source file.
3198 (when (and t1 (eq op 'rename))
3199 (with-parsed-tramp-file-name filename nil
3200 (tramp-flush-file-property v localname)))
3201
00d6fd04
MA
3202 ;; When newname did exist, we have wrong cached values.
3203 (when t2
3204 (with-parsed-tramp-file-name newname nil
905fb90e
MA
3205 (tramp-flush-file-property v localname)))
3206
3207 (with-parsed-tramp-file-name (if t1 filename newname) nil
3208 (tramp-message v 0 "Transferring %s to %s...done" filename newname)))))
7432277c 3209
38c65fca 3210(defun tramp-do-copy-or-rename-file-via-buffer (op filename newname keep-date)
90dc758d
KG
3211 "Use an Emacs buffer to copy or rename a file.
3212First arg OP is either `copy' or `rename' and indicates the operation.
3213FILENAME is the source file, NEWNAME the target file.
3214KEEP-DATE is non-nil if NEWNAME should have the same timestamp as FILENAME."
8a798e41
MA
3215 (with-temp-buffer
3216 ;; We must disable multibyte, because binary data shall not be
3217 ;; converted.
3218 (set-buffer-multibyte nil)
3219 (let ((coding-system-for-read 'binary)
3220 (jka-compr-inhibit t))
3221 (insert-file-contents-literally filename))
3222 ;; We don't want the target file to be compressed, so we let-bind
3223 ;; `jka-compr-inhibit' to t.
3224 (let ((coding-system-for-write 'binary)
3225 (jka-compr-inhibit t))
3226 (write-region (point-min) (point-max) newname)))
3227 ;; KEEP-DATE handling.
3228 (when keep-date (set-file-times newname (nth 5 (file-attributes filename))))
3229 ;; Set the mode.
b86c1cd8 3230 (set-file-modes newname (tramp-default-file-modes filename))
8a798e41
MA
3231 ;; If the operation was `rename', delete the original file.
3232 (unless (eq op 'copy) (delete-file filename)))
fb7933a3
KG
3233
3234(defun tramp-do-copy-or-rename-file-directly
8d60099b 3235 (op filename newname ok-if-already-exists keep-date preserve-uid-gid)
fb7933a3
KG
3236 "Invokes `cp' or `mv' on the remote system.
3237OP must be one of `copy' or `rename', indicating `cp' or `mv',
8d60099b
MA
3238respectively. FILENAME specifies the file to copy or rename,
3239NEWNAME is the name of the new file (for copy) or the new name of
3240the file (for rename). Both files must reside on the same host.
3241KEEP-DATE means to make sure that NEWNAME has the same timestamp
3242as FILENAME. PRESERVE-UID-GID, when non-nil, instructs to keep
3243the uid and gid from FILENAME."
8a4438b6 3244 (let ((t1 (tramp-tramp-file-p filename))
4f4126e6
MA
3245 (t2 (tramp-tramp-file-p newname))
3246 (file-times (nth 5 (file-attributes filename)))
3247 (file-modes (tramp-default-file-modes filename)))
8a4438b6
MA
3248 (with-parsed-tramp-file-name (if t1 filename newname) nil
3249 (let* ((cmd (cond ((and (eq op 'copy) preserve-uid-gid) "cp -f -p")
3250 ((eq op 'copy) "cp -f")
3251 ((eq op 'rename) "mv -f")
3252 (t (tramp-error
3253 v 'file-error
3254 "Unknown operation `%s', must be `copy' or `rename'"
3255 op))))
3256 (localname1
3257 (if t1 (tramp-handle-file-remote-p filename 'localname) filename))
3258 (localname2
3259 (if t2 (tramp-handle-file-remote-p newname 'localname) newname))
258800f8 3260 (prefix (file-remote-p (if t1 filename newname))))
8d60099b 3261
8d60099b 3262 (cond
8a4438b6
MA
3263 ;; Both files are on a remote host, with same user.
3264 ((and t1 t2)
3265 (tramp-send-command
3266 v
3267 (format "%s %s %s" cmd
3268 (tramp-shell-quote-argument localname1)
3269 (tramp-shell-quote-argument localname2)))
3270 (with-current-buffer (tramp-get-buffer v)
3271 (goto-char (point-min))
3272 (unless
3273 (or
3274 (and keep-date
3275 ;; Mask cp -f error.
3276 (re-search-forward
3277 tramp-operation-not-permitted-regexp nil t))
3278 (zerop (tramp-send-command-and-check v nil)))
3279 (tramp-error-with-buffer
3280 nil v 'file-error
3281 "Copying directly failed, see buffer `%s' for details."
3282 (buffer-name)))))
3283
3284 ;; We are on the local host.
3285 ((or t1 t2)
8d60099b 3286 (cond
8a4438b6 3287 ;; We can do it directly.
87bdd2c7
MA
3288 ((let (file-name-handler-alist)
3289 (and (file-readable-p localname1)
3290 (file-writable-p (file-name-directory localname2))
3291 (or (file-directory-p localname2)
3292 (file-writable-p localname2))))
8d60099b 3293 (if (eq op 'copy)
9e6ab520
MA
3294 (tramp-compat-copy-file
3295 localname1 localname2 ok-if-already-exists
3296 keep-date preserve-uid-gid)
87bdd2c7
MA
3297 (tramp-run-real-handler
3298 'rename-file (list localname1 localname2 ok-if-already-exists))))
8a4438b6
MA
3299
3300 ;; We can do it directly with `tramp-send-command'
87bdd2c7
MA
3301 ((let (file-name-handler-alist)
3302 (and (file-readable-p (concat prefix localname1))
5ab38c3c
MA
3303 (file-writable-p
3304 (file-name-directory (concat prefix localname2)))))
8a4438b6
MA
3305 (tramp-do-copy-or-rename-file-directly
3306 op (concat prefix localname1) (concat prefix localname2)
3307 ok-if-already-exists keep-date t)
3308 ;; We must change the ownership to the local user.
8d60099b 3309 (tramp-set-file-uid-gid
8a4438b6
MA
3310 (concat prefix localname2)
3311 (tramp-get-local-uid 'integer)
3312 (tramp-get-local-gid 'integer)))
8d60099b 3313
8a4438b6
MA
3314 ;; We need a temporary file in between.
3315 (t
2c418c5b
MA
3316 ;; Create the temporary file.
3317 (let ((tmpfile (tramp-compat-make-temp-file localname1)))
917b89a6 3318 (unwind-protect
2c418c5b
MA
3319 (progn
3320 (cond
3321 (t1
917b89a6
MA
3322 (or
3323 (zerop
3324 (tramp-send-command-and-check
3325 v (format
3326 "%s %s %s" cmd
3327 (tramp-shell-quote-argument localname1)
3328 (tramp-shell-quote-argument tmpfile))))
3329 (tramp-error-with-buffer
3330 nil v 'file-error
3331 "Copying directly failed, see buffer `%s' for details."
3332 (tramp-get-buffer v)))
2c418c5b 3333 ;; We must change the ownership as remote user.
917b89a6
MA
3334 ;; Since this does not work reliable, we also
3335 ;; give read permissions.
3336 (set-file-modes
3337 (concat prefix tmpfile) (tramp-octal-to-decimal "0777"))
2c418c5b
MA
3338 (tramp-set-file-uid-gid
3339 (concat prefix tmpfile)
3340 (tramp-get-local-uid 'integer)
3341 (tramp-get-local-gid 'integer)))
3342 (t2
3343 (if (eq op 'copy)
3344 (tramp-compat-copy-file
5ab38c3c 3345 localname1 tmpfile t
2c418c5b
MA
3346 keep-date preserve-uid-gid)
3347 (tramp-run-real-handler
3348 'rename-file
5ab38c3c 3349 (list localname1 tmpfile t)))
2c418c5b 3350 ;; We must change the ownership as local user.
917b89a6
MA
3351 ;; Since this does not work reliable, we also
3352 ;; give read permissions.
3353 (set-file-modes tmpfile (tramp-octal-to-decimal "0777"))
2c418c5b
MA
3354 (tramp-set-file-uid-gid
3355 tmpfile
3356 (tramp-get-remote-uid v 'integer)
3357 (tramp-get-remote-gid v 'integer))))
3358
3359 ;; Move the temporary file to its destination.
3360 (cond
3361 (t2
917b89a6
MA
3362 (or
3363 (zerop
3364 (tramp-send-command-and-check
3365 v (format
3366 "cp -f -p %s %s"
3367 (tramp-shell-quote-argument tmpfile)
3368 (tramp-shell-quote-argument localname2))))
3369 (tramp-error-with-buffer
3370 nil v 'file-error
3371 "Copying directly failed, see buffer `%s' for details."
3372 (tramp-get-buffer v))))
2c418c5b 3373 (t1
ce2cc728
MA
3374 (tramp-run-real-handler
3375 'rename-file
2c418c5b
MA
3376 (list tmpfile localname2 ok-if-already-exists)))))
3377
917b89a6
MA
3378 ;; Save exit.
3379 (condition-case nil
3380 (delete-file tmpfile)
3381 (error)))))))))
8d60099b
MA
3382
3383 ;; Set the time and mode. Mask possible errors.
8d60099b 3384 (condition-case nil
1f107aed 3385 (when keep-date
4f4126e6
MA
3386 (set-file-times newname file-times)
3387 (set-file-modes newname file-modes))
8d60099b
MA
3388 (error)))))
3389
5ec2cc41 3390(defun tramp-do-copy-or-rename-file-out-of-band (op filename newname keep-date)
7432277c 3391 "Invoke rcp program to copy.
905fb90e 3392The method used must be an out-of-band method."
38c65fca 3393 (let ((t1 (tramp-tramp-file-p filename))
5ec2cc41 3394 (t2 (tramp-tramp-file-p newname))
00d6fd04
MA
3395 copy-program copy-args copy-keep-date port spec
3396 source target)
3397
3398 (with-parsed-tramp-file-name (if t1 filename newname) nil
905fb90e 3399 (if (and t1 t2)
00d6fd04 3400
905fb90e
MA
3401 ;; Both are Tramp files. We shall optimize it, when the
3402 ;; methods for filename and newname are the same.
3403 (let ((tmpfile (tramp-compat-make-temp-file localname)))
3404 (unwind-protect
3405 (progn
3406 (tramp-do-copy-or-rename-file-out-of-band
3407 op filename tmpfile keep-date)
3408 (tramp-do-copy-or-rename-file-out-of-band
3409 'rename tmpfile newname keep-date))
3410 ;; Save exit.
3411 (condition-case nil
3412 (delete-file tmpfile)
3413 (error))))
3414
3415 ;; Expand hops. Might be necessary for gateway methods.
3416 (setq v (car (tramp-compute-multi-hops v)))
3417 (aset v 3 localname)
3418
3419 ;; Check which ones of source and target are Tramp files.
3420 (setq source (if t1 (tramp-make-copy-program-file-name v) filename)
3421 target (if t2 (tramp-make-copy-program-file-name v) newname))
3422
3423 ;; Check for port number. Until now, there's no need for handling
3424 ;; like method, user, host.
3425 (setq host (tramp-file-name-real-host v)
3426 port (tramp-file-name-port v)
3427 port (or (and port (number-to-string port)) ""))
3428
3429 ;; Compose copy command.
3430 (setq spec `((?h . ,host) (?u . ,user) (?p . ,port)
3431 (?t . ,(tramp-get-connection-property
3432 (tramp-get-connection-process v) "temp-file" ""))
3433 (?k . ,(if keep-date " " "")))
3434 copy-program (tramp-get-method-parameter
3435 method 'tramp-copy-program)
3436 copy-keep-date (tramp-get-method-parameter
3437 method 'tramp-copy-keep-date)
3438 copy-args
3439 (delq
3440 nil
3441 (mapcar
3442 '(lambda (x)
3443 (setq
3444 x
3445 ;; " " is indication for keep-date argument.
3446 (delete " " (mapcar '(lambda (y) (format-spec y spec)) x)))
3447 (unless (member "" x) (mapconcat 'identity x " ")))
3448 (tramp-get-method-parameter method 'tramp-copy-args))))
3449
3450 ;; Check for program.
3451 (when (and (fboundp 'executable-find)
3452 (not (let ((default-directory
3453 (tramp-compat-temporary-file-directory)))
3454 (executable-find copy-program))))
3455 (tramp-error
3456 v 'file-error "Cannot find copy program: %s" copy-program))
00d6fd04 3457
905fb90e
MA
3458 (unwind-protect
3459 (with-temp-buffer
3460 ;; The default directory must be remote.
3461 (let ((default-directory
3462 (file-name-directory (if t1 filename newname))))
3463 ;; Set the transfer process properties.
3464 (tramp-set-connection-property
3465 v "process-name" (buffer-name (current-buffer)))
3466 (tramp-set-connection-property
3467 v "process-buffer" (current-buffer))
3468
3469 ;; Use an asynchronous process. By this, password can
3470 ;; be handled. The default directory must be local, in
3471 ;; order to apply the correct `copy-program'. We don't
3472 ;; set a timeout, because the copying of large files can
3473 ;; last longer than 60 secs.
3474 (let ((p (let ((default-directory
3475 (tramp-compat-temporary-file-directory)))
3476 (apply 'start-process
3477 (tramp-get-connection-property
3478 v "process-name" nil)
3479 (tramp-get-connection-property
3480 v "process-buffer" nil)
3481 copy-program
3482 (append copy-args (list source target))))))
3483 (tramp-message
3484 v 6 "%s" (mapconcat 'identity (process-command p) " "))
3485 (tramp-set-process-query-on-exit-flag p nil)
3486 (tramp-process-actions p v tramp-actions-copy-out-of-band))))
00d6fd04 3487
905fb90e
MA
3488 ;; Reset the transfer process properties.
3489 (tramp-set-connection-property v "process-name" nil)
3490 (tramp-set-connection-property v "process-buffer" nil))
00d6fd04 3491
905fb90e
MA
3492 ;; Handle KEEP-DATE argument.
3493 (when (and keep-date (not copy-keep-date))
3494 (set-file-times newname (nth 5 (file-attributes filename))))
01917a18 3495
905fb90e
MA
3496 ;; Set the mode.
3497 (unless (and keep-date copy-keep-date)
3498 (set-file-modes newname (tramp-default-file-modes filename))))
5ec2cc41 3499
905fb90e
MA
3500 ;; If the operation was `rename', delete the original file.
3501 (unless (eq op 'copy)
3502 (delete-file filename)))))
7432277c 3503
fb7933a3 3504(defun tramp-handle-make-directory (dir &optional parents)
00d6fd04 3505 "Like `make-directory' for Tramp files."
ac474af1 3506 (setq dir (expand-file-name dir))
c62c9d08 3507 (with-parsed-tramp-file-name dir nil
b1d06e75
KG
3508 (save-excursion
3509 (tramp-barf-unless-okay
00d6fd04 3510 v
9c13938d 3511 (format "%s %s"
b1d06e75 3512 (if parents "mkdir -p" "mkdir")
7432277c 3513 (tramp-shell-quote-argument localname))
b1d06e75 3514 "Couldn't make directory %s" dir))))
fb7933a3 3515
fb7933a3 3516(defun tramp-handle-delete-directory (directory)
00d6fd04 3517 "Like `delete-directory' for Tramp files."
ac474af1 3518 (setq directory (expand-file-name directory))
c62c9d08 3519 (with-parsed-tramp-file-name directory nil
00d6fd04
MA
3520 (tramp-flush-directory-property v localname)
3521 (unless (zerop (tramp-send-command-and-check
3522 v
cfb5c0db 3523 (format "rmdir %s" (tramp-shell-quote-argument localname))))
00d6fd04 3524 (tramp-error v 'file-error "Couldn't delete %s" directory))))
fb7933a3
KG
3525
3526(defun tramp-handle-delete-file (filename)
00d6fd04 3527 "Like `delete-file' for Tramp files."
ac474af1 3528 (setq filename (expand-file-name filename))
c62c9d08 3529 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3530 (tramp-flush-file-property v localname)
3531 (unless (zerop (tramp-send-command-and-check
3532 v
3533 (format "rm -f %s"
3534 (tramp-shell-quote-argument localname))))
3535 (tramp-error v 'file-error "Couldn't delete %s" filename))))
fb7933a3
KG
3536
3537;; Dired.
3538
3539;; CCC: This does not seem to be enough. Something dies when
a4aeb9a4 3540;; we try and delete two directories under Tramp :/
fb7933a3
KG
3541(defun tramp-handle-dired-recursive-delete-directory (filename)
3542 "Recursively delete the directory given.
00d6fd04 3543This is like `dired-recursive-delete-directory' for Tramp files."
c62c9d08 3544 (with-parsed-tramp-file-name filename nil
260821d3 3545 (tramp-flush-directory-property v localname)
00d6fd04 3546 ;; Run a shell command 'rm -r <localname>'
260821d3 3547 ;; Code shamelessly stolen from the dired implementation and, um, hacked :)
00d6fd04
MA
3548 (unless (file-exists-p filename)
3549 (tramp-error v 'file-error "No such directory: %s" filename))
fb7933a3 3550 ;; Which is better, -r or -R? (-r works for me <daniel@danann.net>)
00d6fd04
MA
3551 (tramp-send-command
3552 v
9c13938d 3553 (format "rm -rf %s" (tramp-shell-quote-argument localname))
00d6fd04
MA
3554 ;; Don't read the output, do it explicitely.
3555 nil t)
fb7933a3
KG
3556 ;; Wait for the remote system to return to us...
3557 ;; This might take a while, allow it plenty of time.
00d6fd04 3558 (tramp-wait-for-output (tramp-get-connection-process v) 120)
fb7933a3 3559 ;; Make sure that it worked...
07dfe738 3560 (and (file-exists-p filename)
00d6fd04
MA
3561 (tramp-error
3562 v 'file-error "Failed to recursively delete %s" filename))))
bf247b6e 3563
5ec2cc41 3564(defun tramp-handle-dired-compress-file (file &rest ok-flag)
00d6fd04 3565 "Like `dired-compress-file' for Tramp files."
5ec2cc41
KG
3566 ;; OK-FLAG is valid for XEmacs only, but not implemented.
3567 ;; Code stolen mainly from dired-aux.el.
3568 (with-parsed-tramp-file-name file nil
00d6fd04 3569 (tramp-flush-file-property v localname)
5ec2cc41
KG
3570 (save-excursion
3571 (let ((suffixes
3572 (if (not (featurep 'xemacs))
3573 ;; Emacs case
3574 (symbol-value 'dired-compress-file-suffixes)
3575 ;; XEmacs has `dired-compression-method-alist', which is
3576 ;; transformed into `dired-compress-file-suffixes' structure.
3577 (mapcar
3578 '(lambda (x)
3579 (list (concat (regexp-quote (nth 1 x)) "\\'")
3580 nil
3581 (mapconcat 'identity (nth 3 x) " ")))
3582 (symbol-value 'dired-compression-method-alist))))
3583 suffix)
3584 ;; See if any suffix rule matches this file name.
3585 (while suffixes
3586 (let (case-fold-search)
3587 (if (string-match (car (car suffixes)) localname)
3588 (setq suffix (car suffixes) suffixes nil))
3589 (setq suffixes (cdr suffixes))))
3590
3591 (cond ((file-symlink-p file)
3592 nil)
3593 ((and suffix (nth 2 suffix))
3594 ;; We found an uncompression rule.
00d6fd04 3595 (tramp-message v 0 "Uncompressing %s..." file)
5ec2cc41 3596 (when (zerop (tramp-send-command-and-check
00d6fd04
MA
3597 v (concat (nth 2 suffix) " " localname)))
3598 (tramp-message v 0 "Uncompressing %s...done" file)
38c65fca
KG
3599 ;; `dired-remove-file' is not defined in XEmacs
3600 (funcall (symbol-function 'dired-remove-file) file)
5ec2cc41
KG
3601 (string-match (car suffix) file)
3602 (concat (substring file 0 (match-beginning 0)))))
3603 (t
3604 ;; We don't recognize the file as compressed, so compress it.
3605 ;; Try gzip.
00d6fd04 3606 (tramp-message v 0 "Compressing %s..." file)
5ec2cc41 3607 (when (zerop (tramp-send-command-and-check
00d6fd04
MA
3608 v (concat "gzip -f " localname)))
3609 (tramp-message v 0 "Compressing %s...done" file)
38c65fca
KG
3610 ;; `dired-remove-file' is not defined in XEmacs
3611 (funcall (symbol-function 'dired-remove-file) file)
5ec2cc41
KG
3612 (cond ((file-exists-p (concat file ".gz"))
3613 (concat file ".gz"))
3614 ((file-exists-p (concat file ".z"))
3615 (concat file ".z"))
3616 (t nil)))))))))
fb7933a3 3617
70c11b0b
MA
3618(defun tramp-handle-dired-uncache (dir)
3619 "Like `dired-uncache' for Tramp files."
3620 (with-parsed-tramp-file-name dir nil
3621 (tramp-flush-file-property v localname)))
3622
fb7933a3
KG
3623;; Pacify byte-compiler. The function is needed on XEmacs only. I'm
3624;; not sure at all that this is the right way to do it, but let's hope
3625;; it works for now, and wait for a guru to point out the Right Way to
3626;; achieve this.
3627;;(eval-when-compile
3628;; (unless (fboundp 'dired-insert-set-properties)
3629;; (fset 'dired-insert-set-properties 'ignore)))
3630;; Gerd suggests this:
3631(eval-when-compile (require 'dired))
3632;; Note that dired is required at run-time, too, when it is needed.
3633;; It is only needed on XEmacs for the function
3634;; `dired-insert-set-properties'.
3635
3636(defun tramp-handle-insert-directory
3637 (filename switches &optional wildcard full-directory-p)
00d6fd04
MA
3638 "Like `insert-directory' for Tramp files."
3639 (setq filename (expand-file-name filename))
3640 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3641 (if (and (featurep 'ls-lisp)
3642 (not (symbol-value 'ls-lisp-use-insert-directory-program)))
3643 (tramp-run-real-handler
3644 'insert-directory (list filename switches wildcard full-directory-p))
8e754ea2
MA
3645 (when (and (string-match "^--dired\\s-+" switches)
3646 (not (tramp-get-ls-command-with-dired v)))
00d6fd04
MA
3647 (setq switches (replace-match "" nil t switches)))
3648 (tramp-message
3649 v 4 "Inserting directory `ls %s %s', wildcard %s, fulldir %s"
c82c5727
LH
3650 switches filename (if wildcard "yes" "no")
3651 (if full-directory-p "yes" "no"))
3652 (when wildcard
87bdd2c7
MA
3653 (setq wildcard (tramp-run-real-handler
3654 'file-name-nondirectory (list localname)))
3655 (setq localname (tramp-run-real-handler
3656 'file-name-directory (list localname))))
c82c5727
LH
3657 (when (listp switches)
3658 (setq switches (mapconcat 'identity switches " ")))
3659 (unless full-directory-p
3660 (setq switches (concat "-d " switches)))
3661 (when wildcard
3662 (setq switches (concat switches " " wildcard)))
00d6fd04
MA
3663 ;; If `full-directory-p', we just say `ls -l FILENAME'.
3664 ;; Else we chdir to the parent directory, then say `ls -ld BASENAME'.
3665 (if full-directory-p
3666 (tramp-send-command
3667 v
3668 (format "%s %s %s"
3669 (tramp-get-ls-command v)
3670 switches
3671 (if wildcard
3672 localname
3673 (tramp-shell-quote-argument (concat localname ".")))))
3674 (tramp-barf-unless-okay
3675 v
3676 (format "cd %s" (tramp-shell-quote-argument
87bdd2c7
MA
3677 (tramp-run-real-handler
3678 'file-name-directory (list localname))))
00d6fd04 3679 "Couldn't `cd %s'"
87bdd2c7
MA
3680 (tramp-shell-quote-argument
3681 (tramp-run-real-handler 'file-name-directory (list localname))))
00d6fd04
MA
3682 (tramp-send-command
3683 v
3684 (format "%s %s %s"
3685 (tramp-get-ls-command v)
3686 switches
3687 (if (or wildcard
87bdd2c7
MA
3688 (zerop (length
3689 (tramp-run-real-handler
3690 'file-name-nondirectory (list localname)))))
00d6fd04
MA
3691 ""
3692 (tramp-shell-quote-argument
87bdd2c7
MA
3693 (tramp-run-real-handler
3694 'file-name-nondirectory (list localname)))))))
8e754ea2
MA
3695 (let ((beg (point)))
3696 ;; We cannot use `insert-buffer-substring' because the Tramp
3697 ;; buffer changes its contents before insertion due to calling
3698 ;; `expand-file' and alike.
3699 (insert
3700 (with-current-buffer (tramp-get-buffer v)
3701 (buffer-string)))
3702
3703 ;; Check for "--dired" output.
3704 (goto-char (point-max))
3705 (forward-line -2)
3706 (when (looking-at "//DIRED//")
3707 (let ((end (line-end-position))
3708 (linebeg (point)))
3709 ;; Now read the numeric positions of file names.
3710 (goto-char linebeg)
3711 (forward-word 1)
3712 (forward-char 3)
3713 (while (< (point) end)
3714 (let ((start (+ beg (read (current-buffer))))
3715 (end (+ beg (read (current-buffer)))))
3716 (if (memq (char-after end) '(?\n ?\s))
3717 ;; End is followed by \n or by " -> ".
3718 (put-text-property start end 'dired-filename t)))))
3719 ;; Reove training lines.
3720 (goto-char (point-max))
3721 (forward-line -1)
3722 (while (looking-at "//")
3723 (forward-line 1)
3724 (delete-region (match-beginning 0) (point))
3725 (forward-line -1))))
3726 (goto-char (point-max)))))
fb7933a3 3727
fb7933a3 3728(defun tramp-handle-unhandled-file-name-directory (filename)
00d6fd04 3729 "Like `unhandled-file-name-directory' for Tramp files."
8a798e41
MA
3730 ;; With Emacs 23, we could simply return `nil'. But we must keep it
3731 ;; for backward compatibility.
ce3f516f 3732 (expand-file-name "~/"))
fb7933a3
KG
3733
3734;; Canonicalization of file names.
3735
fb7933a3 3736(defun tramp-handle-expand-file-name (name &optional dir)
00d6fd04 3737 "Like `expand-file-name' for Tramp files.
7432277c
KG
3738If the localname part of the given filename starts with \"/../\" then
3739the result will be a local, non-Tramp, filename."
fb7933a3
KG
3740 ;; If DIR is not given, use DEFAULT-DIRECTORY or "/".
3741 (setq dir (or dir default-directory "/"))
3742 ;; Unless NAME is absolute, concat DIR and NAME.
3743 (unless (file-name-absolute-p name)
3744 (setq name (concat (file-name-as-directory dir) name)))
00d6fd04 3745 ;; If NAME is not a Tramp file, run the real handler.
fb7933a3 3746 (if (not (tramp-tramp-file-p name))
00d6fd04 3747 (tramp-run-real-handler 'expand-file-name (list name nil))
fb7933a3 3748 ;; Dissect NAME.
c62c9d08 3749 (with-parsed-tramp-file-name name nil
87bdd2c7 3750 (unless (tramp-run-real-handler 'file-name-absolute-p (list localname))
7432277c 3751 (setq localname (concat "~/" localname)))
00d6fd04
MA
3752 ;; Tilde expansion if necessary. This needs a shell which
3753 ;; groks tilde expansion! The function `tramp-find-shell' is
3754 ;; supposed to find such a shell on the remote host. Please
3755 ;; tell me about it when this doesn't work on your system.
3756 (when (string-match "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname)
3757 (let ((uname (match-string 1 localname))
3758 (fname (match-string 2 localname)))
3759 ;; We cannot simply apply "~/", because under sudo "~/" is
3760 ;; expanded to the local user home directory but to the
3761 ;; root home directory. On the other hand, using always
3762 ;; the default user name for tilde expansion is not
3763 ;; appropriate either, because ssh and companions might
3764 ;; use a user name from the config file.
3765 (when (and (string-equal uname "~")
3766 (string-match "\\`su\\(do\\)?\\'" method))
3767 (setq uname (concat uname user)))
3768 (setq uname
3769 (with-connection-property v uname
3770 (tramp-send-command v (format "cd %s; pwd" uname))
3771 (with-current-buffer (tramp-get-buffer v)
3772 (goto-char (point-min))
9e6ab520 3773 (buffer-substring (point) (tramp-compat-line-end-position)))))
00d6fd04
MA
3774 (setq localname (concat uname fname))))
3775 ;; There might be a double slash, for example when "~/"
cb85dcd0 3776 ;; expands to "/". Remove this.
00d6fd04
MA
3777 (while (string-match "//" localname)
3778 (setq localname (replace-match "/" t t localname)))
3779 ;; No tilde characters in file name, do normal
3780 ;; expand-file-name (this does "/./" and "/../"). We bind
3781 ;; `directory-sep-char' here for XEmacs on Windows, which
3782 ;; would otherwise use backslash. `default-directory' is
3783 ;; bound, because on Windows there would be problems with UNC
3784 ;; shares or Cygwin mounts.
aff67808
MA
3785 (let ((directory-sep-char ?/)
3786 (default-directory (tramp-compat-temporary-file-directory)))
3787 (tramp-make-tramp-file-name
3788 method user host
3789 (tramp-drop-volume-letter
87bdd2c7
MA
3790 (tramp-run-real-handler
3791 'expand-file-name (list localname))))))))
00d6fd04 3792
c23c3394
MA
3793(defun tramp-replace-environment-variables (filename)
3794 "Replace environment variables in FILENAME.
3795Return the string with the replaced variables."
2e271195
MA
3796 (save-match-data
3797 (let ((idx (string-match "$\\w+" filename)))
3798 ;; `$' is coded as `$$'.
3799 (when (and idx (or (zerop idx) (not (eq ?$ (aref filename (1- idx))))))
3800 (setq filename
3801 (replace-match
3802 (substitute-in-file-name (match-string 0 filename))
3803 t nil filename)))
3804 filename)))
c23c3394 3805
00d6fd04
MA
3806(defun tramp-handle-substitute-in-file-name (filename)
3807 "Like `substitute-in-file-name' for Tramp files.
3808\"//\" and \"/~\" substitute only in the local filename part.
3809If the URL Tramp syntax is chosen, \"//\" as method delimeter and \"/~\" at
3810beginning of local filename are not substituted."
c23c3394
MA
3811 ;; First, we must replace environment variables.
3812 (setq filename (tramp-replace-environment-variables filename))
00d6fd04
MA
3813 (with-parsed-tramp-file-name filename nil
3814 (if (equal tramp-syntax 'url)
3815 ;; We need to check localname only. The other parts cannot contain
3816 ;; "//" or "/~".
3817 (if (and (> (length localname) 1)
3818 (or (string-match "//" localname)
3819 (string-match "/~" localname 1)))
3820 (tramp-run-real-handler 'substitute-in-file-name (list filename))
3821 (tramp-make-tramp-file-name
3822 (when method (substitute-in-file-name method))
3823 (when user (substitute-in-file-name user))
3824 (when host (substitute-in-file-name host))
87bdd2c7
MA
3825 (when localname
3826 (tramp-run-real-handler
3827 'substitute-in-file-name (list localname)))))
00d6fd04
MA
3828 ;; Ignore in LOCALNAME everything before "//" or "/~".
3829 (when (and (stringp localname) (string-match ".+?/\\(/\\|~\\)" localname))
3830 (setq filename
b08104a0
MA
3831 (concat (file-remote-p filename)
3832 (replace-match "\\1" nil nil localname)))
00d6fd04
MA
3833 ;; "/m:h:~" does not work for completion. We use "/m:h:~/".
3834 (when (string-match "~$" filename)
3835 (setq filename (concat filename "/"))))
3836 (tramp-run-real-handler 'substitute-in-file-name (list filename)))))
3837
3838;; In XEmacs, electricity is implemented via a key map for ?/ and ?~,
3839;; which calls corresponding functions (see minibuf.el).
3840(when (fboundp 'minibuffer-electric-separator)
9e6ab520 3841 (mapc
00d6fd04
MA
3842 '(lambda (x)
3843 (eval
3844 `(defadvice ,x
3845 (around ,(intern (format "tramp-advice-%s" x)) activate)
3846 "Invoke `substitute-in-file-name' for Tramp files."
3847 (if (and (symbol-value 'minibuffer-electric-file-name-behavior)
3848 (tramp-tramp-file-p (buffer-substring)))
3849 ;; We don't need to handle `last-input-event', because
3850 ;; due to the key map we know it must be ?/ or ?~.
3851 (let ((s (concat (buffer-substring (point-min) (point))
c28f19e5 3852 (string last-command-char))))
00d6fd04
MA
3853 (delete-region (point-min) (point))
3854 (insert (substitute-in-file-name s))
c28f19e5 3855 (setq ad-return-value last-command-char))
00d6fd04
MA
3856 ad-do-it))))
3857
3858 '(minibuffer-electric-separator
3859 minibuffer-electric-tilde)))
3860
3861
0664ff72 3862;;; Remote commands:
fb7933a3 3863
00d6fd04
MA
3864(defun tramp-handle-executable-find (command)
3865 "Like `executable-find' for Tramp files."
3866 (with-parsed-tramp-file-name default-directory nil
f84638eb 3867 (tramp-find-executable v command (tramp-get-remote-path v) t)))
00d6fd04
MA
3868
3869;; We use BUFFER also as connection buffer during setup. Because of
3870;; this, its original contents must be saved, and restored once
3871;; connection has been setup.
3872(defun tramp-handle-start-file-process (name buffer program &rest args)
3873 "Like `start-file-process' for Tramp files."
3874 (with-parsed-tramp-file-name default-directory nil
3875 (unwind-protect
38d63e6a
MA
3876 (let ((name1 name)
3877 (i 0))
2296b54d 3878 (unless buffer
6ce63faf 3879 ;; BUFFER can be nil. We use a temporary buffer.
2296b54d 3880 (setq buffer (generate-new-buffer tramp-temp-buffer-name)))
38d63e6a
MA
3881 (while (get-process name1)
3882 ;; NAME must be unique as process name.
3883 (setq i (1+ i)
3884 name1 (format "%s<%d>" name i)))
3885 (setq name name1)
00d6fd04
MA
3886 ;; Set the new process properties.
3887 (tramp-set-connection-property v "process-name" name)
2296b54d 3888 (tramp-set-connection-property v "process-buffer" buffer)
00d6fd04 3889 ;; Activate narrowing in order to save BUFFER contents.
11c71217
MA
3890 ;; Clear also the modification time; otherwise we might be
3891 ;; interrupted by `verify-visited-file-modtime'.
00d6fd04 3892 (with-current-buffer (tramp-get-connection-buffer v)
11c71217 3893 (clear-visited-file-modtime)
00d6fd04
MA
3894 (narrow-to-region (point-max) (point-max)))
3895 ;; Goto working directory. `tramp-send-command' opens a new
3896 ;; connection.
3897 (tramp-send-command
3898 v (format "cd %s" (tramp-shell-quote-argument localname)))
3899 ;; Send the command.
3900 (tramp-send-command
3901 v
2296b54d 3902 (format "exec %s"
00d6fd04 3903 (mapconcat 'tramp-shell-quote-argument
2296b54d 3904 (cons program args) " "))
00d6fd04 3905 nil t) ; nooutput
6ce63faf
MA
3906 ;; Set query flag for this process.
3907 (tramp-set-process-query-on-exit-flag
3908 (tramp-get-connection-process v) t)
00d6fd04
MA
3909 ;; Return process.
3910 (tramp-get-connection-process v))
3911 ;; Save exit.
ce3f516f 3912 (with-current-buffer (tramp-get-connection-buffer v)
6ce63faf
MA
3913 (if (string-match tramp-temp-buffer-name (buffer-name))
3914 (progn
3915 (set-process-buffer (tramp-get-connection-process v) nil)
3916 (kill-buffer (current-buffer)))
3917 (widen)
3918 (goto-char (point-max))))
00d6fd04
MA
3919 (tramp-set-connection-property v "process-name" nil)
3920 (tramp-set-connection-property v "process-buffer" nil))))
3921
3922(defun tramp-handle-process-file
3923 (program &optional infile destination display &rest args)
3924 "Like `process-file' for Tramp files."
3925 ;; The implementation is not complete yet.
3926 (when (and (numberp destination) (zerop destination))
3927 (error "Implementation does not handle immediate return"))
3928
3929 (with-parsed-tramp-file-name default-directory nil
a6e96327 3930 (let (command input tmpinput stderr tmpstderr outbuf ret)
00d6fd04
MA
3931 ;; Compute command.
3932 (setq command (mapconcat 'tramp-shell-quote-argument
3933 (cons program args) " "))
3934 ;; Determine input.
3935 (if (null infile)
3936 (setq input "/dev/null")
3937 (setq infile (expand-file-name infile))
3938 (if (tramp-equal-remote default-directory infile)
3939 ;; INFILE is on the same remote host.
3940 (setq input (with-parsed-tramp-file-name infile nil localname))
3941 ;; INFILE must be copied to remote host.
a6e96327
MA
3942 (setq input (tramp-make-tramp-temp-file v)
3943 tmpinput (tramp-make-tramp-file-name method user host input))
3944 (copy-file infile tmpinput t)))
00d6fd04
MA
3945 (when input (setq command (format "%s <%s" command input)))
3946
3947 ;; Determine output.
3948 (cond
bede3e9f 3949 ;; Just a buffer.
00d6fd04
MA
3950 ((bufferp destination)
3951 (setq outbuf destination))
bede3e9f 3952 ;; A buffer name.
00d6fd04
MA
3953 ((stringp destination)
3954 (setq outbuf (get-buffer-create destination)))
3955 ;; (REAL-DESTINATION ERROR-DESTINATION)
3956 ((consp destination)
bede3e9f 3957 ;; output.
00d6fd04
MA
3958 (cond
3959 ((bufferp (car destination))
3960 (setq outbuf (car destination)))
3961 ((stringp (car destination))
0664ff72
MA
3962 (setq outbuf (get-buffer-create (car destination))))
3963 ((car destination)
3964 (setq outbuf (current-buffer))))
bede3e9f 3965 ;; stderr.
00d6fd04
MA
3966 (cond
3967 ((stringp (cadr destination))
3968 (setcar (cdr destination) (expand-file-name (cadr destination)))
3969 (if (tramp-equal-remote default-directory (cadr destination))
3970 ;; stderr is on the same remote host.
3971 (setq stderr (with-parsed-tramp-file-name
3972 (cadr destination) nil localname))
3973 ;; stderr must be copied to remote host. The temporary
3974 ;; file must be deleted after execution.
a6e96327
MA
3975 (setq stderr (tramp-make-tramp-temp-file v)
3976 tmpstderr (tramp-make-tramp-file-name
3977 method user host stderr))))
bede3e9f 3978 ;; stderr to be discarded.
00d6fd04
MA
3979 ((null (cadr destination))
3980 (setq stderr "/dev/null"))))
3981 ;; 't
3982 (destination
3983 (setq outbuf (current-buffer))))
3984 (when stderr (setq command (format "%s 2>%s" command stderr)))
3985
00d6fd04
MA
3986 ;; Goto working directory.
3987 (tramp-send-command
3988 v (format "cd %s" (tramp-shell-quote-argument localname)))
3989 ;; Send the command. It might not return in time, so we protect it.
3990 (condition-case nil
3991 (unwind-protect
3992 (tramp-send-command v command)
3993 ;; We should show the output anyway.
3994 (when outbuf
27e813fe
MA
3995 (let ((output-string
3996 (with-current-buffer (tramp-get-connection-buffer v)
3997 (buffer-substring (point-min) (point-max)))))
3998 (with-current-buffer outbuf
3999 (insert output-string)))
00d6fd04 4000 (when display (display-buffer outbuf))))
260821d3
MA
4001 ;; When the user did interrupt, we should do it also. We use
4002 ;; return code -1 as marker.
4003 (quit
4004 (kill-buffer (tramp-get-connection-buffer v))
4005 (setq ret -1))
4006 ;; Handle errors.
00d6fd04
MA
4007 (error
4008 (kill-buffer (tramp-get-connection-buffer v))
4009 (setq ret 1)))
a6e96327
MA
4010
4011 ;; Check return code.
4012 (unless ret (setq ret (tramp-send-command-and-check v nil)))
4013 ;; Provide error file.
4014 (when tmpstderr (rename-file tmpstderr (cadr destination) t))
260821d3
MA
4015 ;; Cleanup. We remove all file cache values for the connection,
4016 ;; because the remote process could have changed them.
a6e96327 4017 (when tmpinput (delete-file tmpinput))
260821d3 4018 (tramp-flush-directory-property v "")
00d6fd04 4019 ;; Return exit status.
260821d3
MA
4020 (if (equal ret -1)
4021 (keyboard-quit)
4022 ret))))
00d6fd04 4023
a4aeb9a4
MA
4024(defun tramp-local-call-process
4025 (program &optional infile destination display &rest args)
4026 "Calls `call-process' on the local host.
4027This is needed because for some Emacs flavors Tramp has
4028defadviced `call-process' to behave like `process-file'. The
4029Lisp error raised when PROGRAM is nil is trapped also, returning 1."
4030 (let ((default-directory
4031 (if (file-remote-p default-directory)
4032 (tramp-compat-temporary-file-directory)
4033 default-directory)))
4034 (if (executable-find program)
4035 (apply 'call-process program infile destination display args)
4036 1)))
4037
00d6fd04
MA
4038(defun tramp-handle-call-process-region
4039 (start end program &optional delete buffer display &rest args)
4040 "Like `call-process-region' for Tramp files."
258800f8 4041 (let ((tmpfile (tramp-compat-make-temp-file "")))
00d6fd04
MA
4042 (write-region start end tmpfile)
4043 (when delete (delete-region start end))
4044 (unwind-protect
4045 (apply 'call-process program tmpfile buffer display args)
4046 (delete-file tmpfile))))
4047
4048(defun tramp-handle-shell-command
4049 (command &optional output-buffer error-buffer)
4050 "Like `shell-command' for Tramp files."
ce3f516f 4051 (let* ((asynchronous (string-match "[ \t]*&[ \t]*\\'" command))
b8bfcf96
MA
4052 ;; We cannot use `shell-file-name' and `shell-command-switch',
4053 ;; they are variables of the local host.
4054 (args (list "/bin/sh" "-c" (substring command 0 asynchronous)))
5d2ebd96 4055 current-buffer-p
ce3f516f 4056 (output-buffer
27e813fe
MA
4057 (cond
4058 ((bufferp output-buffer) output-buffer)
4059 ((stringp output-buffer) (get-buffer-create output-buffer))
5d2ebd96
AS
4060 (output-buffer
4061 (setq current-buffer-p t)
4062 (current-buffer))
42bc9b6d 4063 (t (get-buffer-create
27e813fe
MA
4064 (if asynchronous
4065 "*Async Shell Command*"
4066 "*Shell Command Output*")))))
4067 (error-buffer
4068 (cond
4069 ((bufferp error-buffer) error-buffer)
4070 ((stringp error-buffer) (get-buffer-create error-buffer))))
ce3f516f 4071 (buffer
27e813fe 4072 (if (and (not asynchronous) error-buffer)
ce3f516f
MA
4073 (with-parsed-tramp-file-name default-directory nil
4074 (list output-buffer (tramp-make-tramp-temp-file v)))
42bc9b6d 4075 output-buffer))
cfb5c0db 4076 (p (get-buffer-process output-buffer)))
42bc9b6d
MA
4077
4078 ;; Check whether there is another process running. Tramp does not
4079 ;; support 2 (asynchronous) processes in parallel.
cfb5c0db 4080 (when p
42bc9b6d 4081 (if (yes-or-no-p "A command is running. Kill it? ")
699a11fb
GM
4082 (condition-case nil
4083 (kill-process p)
4084 (error nil))
42bc9b6d
MA
4085 (error "Shell command in progress")))
4086
f34db316
AS
4087 (if current-buffer-p
4088 (progn
4089 (barf-if-buffer-read-only)
4090 (push-mark nil t))
5d2ebd96
AS
4091 (with-current-buffer output-buffer
4092 (setq buffer-read-only nil)
4093 (erase-buffer)))
42bc9b6d 4094
5d2ebd96 4095 (if (and (not current-buffer-p) (integerp asynchronous))
42bc9b6d
MA
4096 (prog1
4097 ;; Run the process.
3412f35d 4098 (apply 'start-file-process "*Async Shell*" buffer args)
42bc9b6d 4099 ;; Display output.
cfb5c0db
MA
4100 (pop-to-buffer output-buffer)
4101 (setq mode-line-process '(":%s"))
4102 (require 'shell) (shell-mode))
42bc9b6d
MA
4103
4104 (prog1
4105 ;; Run the process.
4106 (apply 'process-file (car args) nil buffer nil (cdr args))
4107 ;; Insert error messages if they were separated.
4108 (when (listp buffer)
4109 (with-current-buffer error-buffer
4110 (insert-file-contents (cadr buffer)))
4111 (delete-file (cadr buffer)))
f34db316
AS
4112 (if current-buffer-p
4113 ;; This is like exchange-point-and-mark, but doesn't
4114 ;; activate the mark. It is cleaner to avoid activation,
4115 ;; even though the command loop would deactivate the mark
4116 ;; because we inserted text.
4117 (goto-char (prog1 (mark t)
4118 (set-marker (mark-marker) (point)
4119 (current-buffer))))
4120 ;; There's some output, display it.
4121 (when (with-current-buffer output-buffer (> (point-max) (point-min)))
4122 (if (functionp 'display-message-or-buffer)
4123 (funcall (symbol-function 'display-message-or-buffer)
4124 output-buffer)
4125 (pop-to-buffer output-buffer))))))))
00d6fd04
MA
4126
4127;; File Editing.
4128
4129(defvar tramp-handle-file-local-copy-hook nil
4130 "Normal hook to be run at the end of `tramp-handle-file-local-copy'.")
4131
fb7933a3 4132(defun tramp-handle-file-local-copy (filename)
00d6fd04 4133 "Like `file-local-copy' for Tramp files."
0f205eee 4134
c62c9d08 4135 (with-parsed-tramp-file-name filename nil
2988341a
MA
4136 (unless (file-exists-p filename)
4137 (tramp-error
4138 v 'file-error
4139 "Cannot make local copy of non-existing file `%s'" filename))
4140
0f205eee 4141 (let ((rem-enc (tramp-get-remote-coding v "remote-encoding"))
00d6fd04 4142 (loc-dec (tramp-get-local-coding v "local-decoding"))
258800f8 4143 (tmpfile (tramp-compat-make-temp-file filename)))
5ec2cc41 4144
2988341a
MA
4145 (condition-case err
4146 (cond
4147 ;; `copy-file' handles direct copy and out-of-band methods.
4148 ((or (tramp-local-host-p v)
4149 (and (tramp-method-out-of-band-p v)
4150 (> (nth 7 (file-attributes filename))
4151 tramp-copy-size-limit)))
4152 (copy-file filename tmpfile t t))
4153
4154 ;; Use inline encoding for file transfer.
4155 (rem-enc
4156 (save-excursion
4157 (tramp-message v 5 "Encoding remote file %s..." filename)
4158 (tramp-barf-unless-okay
4159 v
4160 (format "%s < %s" rem-enc (tramp-shell-quote-argument localname))
4161 "Encoding remote file failed")
4162 (tramp-message v 5 "Encoding remote file %s...done" filename)
4163
4164 (if (and (symbolp loc-dec) (fboundp loc-dec))
4165 ;; If local decoding is a function, we call it. We
4166 ;; must disable multibyte, because
4167 ;; `uudecode-decode-region' doesn't handle it
4168 ;; correctly.
0f205eee
MA
4169 (with-temp-buffer
4170 (set-buffer-multibyte nil)
4171 (insert-buffer-substring (tramp-get-buffer v))
4172 (tramp-message
4173 v 5 "Decoding remote file %s with function %s..."
4174 filename loc-dec)
4175 (funcall loc-dec (point-min) (point-max))
4176 (let ((coding-system-for-write 'binary))
2988341a
MA
4177 (write-region (point-min) (point-max) tmpfile)))
4178
4179 ;; If tramp-decoding-function is not defined for this
4180 ;; method, we invoke tramp-decoding-command instead.
4181 (let ((tmpfile2 (tramp-compat-make-temp-file filename)))
4182 (let ((coding-system-for-write 'binary))
4183 (write-region (point-min) (point-max) tmpfile2))
4184 (tramp-message
4185 v 5 "Decoding remote file %s with command %s..."
4186 filename loc-dec)
4187 (unwind-protect
4188 (tramp-call-local-coding-command loc-dec tmpfile2 tmpfile)
4189 (delete-file tmpfile2))))
4190
4191 (tramp-message v 5 "Decoding remote file %s...done" filename)
4192 ;; Set proper permissions.
b86c1cd8 4193 (set-file-modes tmpfile (tramp-default-file-modes filename))
2988341a
MA
4194 ;; Set local user ownership.
4195 (tramp-set-file-uid-gid tmpfile)))
4196
4197 ;; Oops, I don't know what to do.
4198 (t (tramp-error
4199 v 'file-error "Wrong method specification for `%s'" method)))
4200
4201 ;; Error handling.
4202 ((error quit)
4203 (delete-file tmpfile)
4204 (signal (car err) (cdr err))))
0f205eee 4205
00d6fd04 4206 (run-hooks 'tramp-handle-file-local-copy-hook)
94be87e8 4207 tmpfile)))
fb7933a3 4208
bce04fee 4209(defun tramp-handle-file-remote-p (filename &optional identification connected)
00d6fd04 4210 "Like `file-remote-p' for Tramp files."
15cc764c
KG
4211 (when (tramp-tramp-file-p filename)
4212 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
4213 (and (or (not connected)
4214 (let ((p (tramp-get-connection-process v)))
4215 (and p (processp p) (memq (process-status p) '(run open)))))
ce3f516f
MA
4216 (cond
4217 ((eq identification 'method) method)
4218 ((eq identification 'user) user)
4219 ((eq identification 'host) host)
8d60099b 4220 ((eq identification 'localname) localname)
ce3f516f 4221 (t (tramp-make-tramp-file-name method user host "")))))))
fb7933a3 4222
eb562962
MA
4223(defun tramp-find-file-name-coding-system-alist (filename tmpname)
4224 "Like `find-operation-coding-system' for Tramp filenames.
4225Tramp's `insert-file-contents' and `write-region' work over
4226temporary file names. If `file-coding-system-alist' contains an
4227expression, which matches more than the file name suffix, the
4228coding system might not be determined. This function repairs it."
4229 (let (result)
4230 (dolist (elt file-coding-system-alist result)
4231 (when (and (consp elt) (string-match (car elt) filename))
4232 ;; We found a matching entry in `file-coding-system-alist'.
4233 ;; So we add a similar entry, but with the temporary file name
4234 ;; as regexp.
4235 (add-to-list
4236 'result (cons (regexp-quote tmpname) (cdr elt)) 'append)))))
4237
fb7933a3
KG
4238(defun tramp-handle-insert-file-contents
4239 (filename &optional visit beg end replace)
00d6fd04 4240 "Like `insert-file-contents' for Tramp files."
fb7933a3
KG
4241 (barf-if-buffer-read-only)
4242 (setq filename (expand-file-name filename))
736ac90f 4243 (let (coding-system-used result local-copy remote-copy)
2ac33804
MA
4244 (with-parsed-tramp-file-name filename nil
4245 (unwind-protect
70c11b0b
MA
4246 (if (not (file-exists-p filename))
4247 ;; We don't raise a Tramp error, because it might be
4248 ;; suppressed, like in `find-file-noselect-1'.
4249 (signal 'file-error
4250 (list "File not found on remote host" filename))
4251
4252 (if (and (tramp-local-host-p v)
4253 (let (file-name-handler-alist)
4254 (file-readable-p localname)))
4255 ;; Short track: if we are on the local host, we can
4256 ;; run directly.
4257 (setq result
4258 (tramp-run-real-handler
4259 'insert-file-contents
4260 (list localname visit beg end replace)))
4261
736ac90f
MA
4262 ;; When we shall insert only a part of the file, we copy
4263 ;; this part.
4264 (when (or beg end)
4265 (setq remote-copy (tramp-make-tramp-temp-file v))
4266 (tramp-send-command
4267 v
4268 (cond
4269 ((and beg end)
4270 (format "tail -c +%d %s | head -c +%d >%s"
4271 (1+ beg) (tramp-shell-quote-argument localname)
4272 (- end beg) remote-copy))
4273 (beg
4274 (format "tail -c +%d %s >%s"
4275 (1+ beg) (tramp-shell-quote-argument localname)
4276 remote-copy))
4277 (end
4278 (format "head -c +%d %s >%s"
4279 (1+ end) (tramp-shell-quote-argument localname)
4280 remote-copy)))))
4281
70c11b0b
MA
4282 ;; `insert-file-contents-literally' takes care to avoid
4283 ;; calling jka-compr. By let-binding
4284 ;; `inhibit-file-name-operation', we propagate that care
4285 ;; to the `file-local-copy' operation.
4286 (setq local-copy
4287 (let ((inhibit-file-name-operation
4288 (when (eq inhibit-file-name-operation
4289 'insert-file-contents)
4290 'file-local-copy)))
736ac90f
MA
4291 (file-local-copy
4292 (if (stringp remote-copy)
4293 (tramp-make-tramp-file-name
4294 method user host remote-copy)
4295 filename))))
70c11b0b
MA
4296 (tramp-message
4297 v 4 "Inserting local temp file `%s'..." local-copy)
4298
4299 ;; We must ensure that `file-coding-system-alist'
4300 ;; matches `local-copy'.
4301 (let ((file-coding-system-alist
4302 (tramp-find-file-name-coding-system-alist
4303 filename local-copy)))
4304 (setq result
4305 (insert-file-contents
736ac90f 4306 local-copy nil nil nil replace))
70c11b0b
MA
4307 ;; Now `last-coding-system-used' has right value.
4308 ;; Remember it.
4309 (when (boundp 'last-coding-system-used)
4310 (setq coding-system-used
4311 (symbol-value 'last-coding-system-used))))
8d60099b 4312
70c11b0b
MA
4313 (tramp-message
4314 v 4 "Inserting local temp file `%s'...done" local-copy)
4315 (when (boundp 'last-coding-system-used)
2ac33804 4316 (set 'last-coding-system-used coding-system-used))))
70c11b0b 4317
2ac33804
MA
4318 ;; Save exit.
4319 (progn
4320 (when visit
4321 (setq buffer-file-name filename)
4322 (setq buffer-read-only (not (file-writable-p filename)))
4323 (set-visited-file-modtime)
4324 (set-buffer-modified-p nil))
4325 (when (stringp local-copy)
4326 (delete-file local-copy))
4327 (when (stringp remote-copy)
4328 (delete-file
4329 (tramp-make-tramp-file-name method user host remote-copy))))))
70c11b0b
MA
4330
4331 ;; Result.
4332 (list (expand-file-name filename)
4333 (cadr result))))
fb7933a3 4334
94be87e8
MA
4335;; This is needed for XEmacs only. Code stolen from files.el.
4336(defun tramp-handle-insert-file-contents-literally
4337 (filename &optional visit beg end replace)
4338 "Like `insert-file-contents-literally' for Tramp files."
4339 (let ((format-alist nil)
4340 (after-insert-file-functions nil)
4341 (coding-system-for-read 'no-conversion)
4342 (coding-system-for-write 'no-conversion)
4343 (find-buffer-file-type-function
4344 (if (fboundp 'find-buffer-file-type)
4345 (symbol-function 'find-buffer-file-type)
4346 nil))
4347 (inhibit-file-name-handlers '(jka-compr-handler image-file-handler))
4348 (inhibit-file-name-operation 'insert-file-contents))
4349 (unwind-protect
4350 (progn
4351 (fset 'find-buffer-file-type (lambda (filename) t))
4352 (insert-file-contents filename visit beg end replace))
70c11b0b 4353 ;; Save exit.
94be87e8
MA
4354 (if find-buffer-file-type-function
4355 (fset 'find-buffer-file-type find-buffer-file-type-function)
4356 (fmakunbound 'find-buffer-file-type)))))
4357
38c65fca 4358(defun tramp-handle-find-backup-file-name (filename)
00d6fd04 4359 "Like `find-backup-file-name' for Tramp files."
07dfe738
KG
4360 (with-parsed-tramp-file-name filename nil
4361 ;; We set both variables. It doesn't matter whether it is
4362 ;; Emacs or XEmacs
4363 (let ((backup-directory-alist
4364 ;; Emacs case
4365 (when (boundp 'backup-directory-alist)
b86c1cd8 4366 (if (symbol-value 'tramp-backup-directory-alist)
07dfe738
KG
4367 (mapcar
4368 '(lambda (x)
4369 (cons
4370 (car x)
4371 (if (and (stringp (cdr x))
4372 (file-name-absolute-p (cdr x))
4373 (not (tramp-file-name-p (cdr x))))
00d6fd04 4374 (tramp-make-tramp-file-name method user host (cdr x))
07dfe738
KG
4375 (cdr x))))
4376 (symbol-value 'tramp-backup-directory-alist))
4377 (symbol-value 'backup-directory-alist))))
4378
4379 (bkup-backup-directory-info
4380 ;; XEmacs case
4381 (when (boundp 'bkup-backup-directory-info)
b86c1cd8 4382 (if (symbol-value 'tramp-bkup-backup-directory-info)
07dfe738
KG
4383 (mapcar
4384 '(lambda (x)
4385 (nconc
4386 (list (car x))
4387 (list
4388 (if (and (stringp (car (cdr x)))
4389 (file-name-absolute-p (car (cdr x)))
4390 (not (tramp-file-name-p (car (cdr x)))))
4391 (tramp-make-tramp-file-name
00d6fd04 4392 method user host (car (cdr x)))
07dfe738
KG
4393 (car (cdr x))))
4394 (cdr (cdr x))))
4395 (symbol-value 'tramp-bkup-backup-directory-info))
4396 (symbol-value 'bkup-backup-directory-info)))))
4397
4398 (tramp-run-real-handler 'find-backup-file-name (list filename)))))
38c65fca 4399
c1105d05 4400(defun tramp-handle-make-auto-save-file-name ()
00d6fd04 4401 "Like `make-auto-save-file-name' for Tramp files.
c1105d05 4402Returns a file name in `tramp-auto-save-directory' for autosaving this file."
00d6fd04
MA
4403 (let ((tramp-auto-save-directory tramp-auto-save-directory)
4404 (buffer-file-name
4405 (tramp-subst-strs-in-string
4406 '(("_" . "|")
4407 ("/" . "_a")
4408 (":" . "_b")
4409 ("|" . "__")
4410 ("[" . "_l")
4411 ("]" . "_r"))
4412 (buffer-file-name))))
1a762140
MA
4413 ;; File name must be unique. This is ensured with Emacs 22 (see
4414 ;; UNIQUIFY element of `auto-save-file-name-transforms'); but for
4415 ;; all other cases we must do it ourselves.
4416 (when (boundp 'auto-save-file-name-transforms)
9e6ab520 4417 (mapc
1a762140
MA
4418 '(lambda (x)
4419 (when (and (string-match (car x) buffer-file-name)
4420 (not (car (cddr x))))
4421 (setq tramp-auto-save-directory
f3c071dd 4422 (or tramp-auto-save-directory
9e6ab520 4423 (tramp-compat-temporary-file-directory)))))
1a762140
MA
4424 (symbol-value 'auto-save-file-name-transforms)))
4425 ;; Create directory.
4426 (when tramp-auto-save-directory
00d6fd04
MA
4427 (setq buffer-file-name
4428 (expand-file-name buffer-file-name tramp-auto-save-directory))
1a762140
MA
4429 (unless (file-exists-p tramp-auto-save-directory)
4430 (make-directory tramp-auto-save-directory t)))
00d6fd04
MA
4431 ;; Run plain `make-auto-save-file-name'. There might be an advice when
4432 ;; it is not a magic file name operation (since Emacs 22).
4433 ;; We must deactivate it temporarily.
4434 (if (not (ad-is-active 'make-auto-save-file-name))
4435 (tramp-run-real-handler 'make-auto-save-file-name nil)
4436 ;; else
4437 (ad-deactivate 'make-auto-save-file-name)
4438 (prog1
4439 (tramp-run-real-handler 'make-auto-save-file-name nil)
4440 (ad-activate 'make-auto-save-file-name)))))
4441
4442(defvar tramp-handle-write-region-hook nil
4443 "Normal hook to be run at the end of `tramp-handle-write-region'.")
4444
4445;; CCC grok APPEND, LOCKNAME
fb7933a3
KG
4446(defun tramp-handle-write-region
4447 (start end filename &optional append visit lockname confirm)
00d6fd04 4448 "Like `write-region' for Tramp files."
fb7933a3 4449 (setq filename (expand-file-name filename))
c62c9d08 4450 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
4451 (unless (null append)
4452 (tramp-error
4453 v 'file-error "Cannot append to file using Tramp (`%s')" filename))
4454 ;; Following part commented out because we don't know what to do about
4455 ;; file locking, and it does not appear to be a problem to ignore it.
4456 ;; Ange-ftp ignores it, too.
4457 ;; (when (and lockname (stringp lockname))
4458 ;; (setq lockname (expand-file-name lockname)))
4459 ;; (unless (or (eq lockname nil)
4460 ;; (string= lockname filename))
4461 ;; (error
4462 ;; "tramp-handle-write-region: LOCKNAME must be nil or equal FILENAME"))
8d60099b 4463
94be87e8 4464 ;; XEmacs takes a coding system as the seventh argument, not `confirm'.
00d6fd04
MA
4465 (when (and (not (featurep 'xemacs)) confirm (file-exists-p filename))
4466 (unless (y-or-n-p (format "File %s exists; overwrite anyway? " filename))
4467 (tramp-error v 'file-error "File not overwritten")))
8d60099b 4468
a4aeb9a4 4469 (let ((uid (or (nth 2 (tramp-compat-file-attributes filename 'integer))
9c13938d 4470 (tramp-get-remote-uid v 'integer)))
a4aeb9a4 4471 (gid (or (nth 3 (tramp-compat-file-attributes filename 'integer))
9c13938d
MA
4472 (tramp-get-remote-gid v 'integer))))
4473
4474 (if (and (tramp-local-host-p v)
93c3eb7c 4475 ;; `file-writable-p' calls `file-expand-file-name'. We
87bdd2c7
MA
4476 ;; cannot use `tramp-run-real-handler' therefore.
4477 (let (file-name-handler-alist)
82f3844e
MA
4478 (and
4479 (file-writable-p (file-name-directory localname))
4480 (or (file-directory-p localname)
4481 (file-writable-p localname)))))
9c13938d 4482 ;; Short track: if we are on the local host, we can run directly.
93c3eb7c
MA
4483 (progn
4484 (tramp-run-real-handler
4485 'write-region
4486 (list start end localname append 'no-message lockname confirm))
3e2fa353 4487 (tramp-flush-file-property v localname))
9c13938d
MA
4488
4489 (let ((rem-dec (tramp-get-remote-coding v "remote-decoding"))
4490 (loc-enc (tramp-get-local-coding v "local-encoding"))
b86c1cd8 4491 (modes (save-excursion (tramp-default-file-modes filename)))
9c13938d
MA
4492 ;; We use this to save the value of
4493 ;; `last-coding-system-used' after writing the tmp file.
4494 ;; At the end of the function, we set
4495 ;; `last-coding-system-used' to this saved value. This
4496 ;; way, any intermediary coding systems used while
4497 ;; talking to the remote shell or suchlike won't hose
4498 ;; this variable. This approach was snarfed from
4499 ;; ange-ftp.el.
4500 coding-system-used
4501 ;; Write region into a tmp file. This isn't really
4502 ;; needed if we use an encoding function, but currently
4503 ;; we use it always because this makes the logic
4504 ;; simpler.
4505 (tmpfile (tramp-compat-make-temp-file filename)))
4506
4507 ;; We say `no-message' here because we don't want the
4508 ;; visited file modtime data to be clobbered from the temp
4509 ;; file. We call `set-visited-file-modtime' ourselves later
eb562962
MA
4510 ;; on. We must ensure that `file-coding-system-alist'
4511 ;; matches `tmpfile'.
4512 (let ((file-coding-system-alist
4513 (tramp-find-file-name-coding-system-alist filename tmpfile)))
ce2cc728
MA
4514 (condition-case err
4515 (tramp-run-real-handler
4516 'write-region
4517 (list start end tmpfile append 'no-message lockname confirm))
2988341a
MA
4518 ((error quit)
4519 (delete-file tmpfile)
4520 (signal (car err) (cdr err))))
ce2cc728 4521
eb562962
MA
4522 ;; Now, `last-coding-system-used' has the right value. Remember it.
4523 (when (boundp 'last-coding-system-used)
4524 (setq coding-system-used
4525 (symbol-value 'last-coding-system-used))))
4526
9c13938d
MA
4527 ;; The permissions of the temporary file should be set. If
4528 ;; filename does not exist (eq modes nil) it has been
4529 ;; renamed to the backup file. This case `save-buffer'
4530 ;; handles permissions.
4531 (when modes (set-file-modes tmpfile modes))
4532
4533 ;; This is a bit lengthy due to the different methods
4534 ;; possible for file transfer. First, we check whether the
4535 ;; method uses an rcp program. If so, we call it.
4536 ;; Otherwise, both encoding and decoding command must be
4537 ;; specified. However, if the method _also_ specifies an
4538 ;; encoding function, then that is used for encoding the
4539 ;; contents of the tmp file.
4540 (cond
4541 ;; `rename-file' handles direct copy and out-of-band methods.
4542 ((or (tramp-local-host-p v)
4543 (and (tramp-method-out-of-band-p v)
1d7e9a01
MA
4544 (> (- (or end (point-max)) (or start (point-min)))
4545 tramp-copy-size-limit)))
ce2cc728
MA
4546 (condition-case err
4547 (rename-file tmpfile filename t)
2988341a
MA
4548 ((error quit)
4549 (delete-file tmpfile)
4550 (signal (car err) (cdr err)))))
9c13938d 4551
1d7e9a01 4552 ;; Use inline file transfer.
9c13938d 4553 (rem-dec
1d7e9a01 4554 ;; Encode tmpfile.
9c13938d
MA
4555 (tramp-message v 5 "Encoding region...")
4556 (unwind-protect
4557 (with-temp-buffer
4558 ;; Use encoding function or command.
4559 (if (and (symbolp loc-enc) (fboundp loc-enc))
4560 (progn
4561 (tramp-message
4562 v 5 "Encoding region using function `%s'..."
4563 (symbol-name loc-enc))
4564 (let ((coding-system-for-read 'binary))
4565 (insert-file-contents-literally tmpfile))
70c11b0b
MA
4566 ;; The following `let' is a workaround for the
4567 ;; base64.el that comes with pgnus-0.84. If
4568 ;; both of the following conditions are
4569 ;; satisfied, it tries to write to a local
4570 ;; file in default-directory, but at this
4571 ;; point, default-directory is remote.
4572 ;; (`call-process-region' can't write to
4573 ;; remote files, it seems.) The file in
4574 ;; question is a tmp file anyway.
9c13938d
MA
4575 (let ((default-directory
4576 (tramp-compat-temporary-file-directory)))
4577 (funcall loc-enc (point-min) (point-max))))
8d60099b 4578
9c13938d
MA
4579 (tramp-message
4580 v 5 "Encoding region using command `%s'..." loc-enc)
4581 (unless (equal 0 (tramp-call-local-coding-command
4582 loc-enc tmpfile t))
4583 (tramp-error
4584 v 'file-error
4585 "Cannot write to `%s', local encoding command `%s' failed"
4586 filename loc-enc)))
4587
4588 ;; Send buffer into remote decoding command which
4589 ;; writes to remote file. Because this happens on
4590 ;; the remote host, we cannot use the function.
4591 (goto-char (point-max))
4592 (unless (bolp) (newline))
8d60099b 4593 (tramp-message
9c13938d
MA
4594 v 5 "Decoding region into remote file %s..." filename)
4595 (tramp-send-command
4596 v
4597 (format
4598 "%s >%s <<'EOF'\n%sEOF"
4599 rem-dec
4600 (tramp-shell-quote-argument localname)
4601 (buffer-string)))
4602 (tramp-barf-unless-okay
4603 v nil
4604 "Couldn't write region to `%s', decode using `%s' failed"
4605 filename rem-dec)
4606 ;; When `file-precious-flag' is set, the region is
4607 ;; written to a temporary file. Check that the
4608 ;; checksum is equal to that from the local tmpfile.
4609 (when file-precious-flag
4610 (erase-buffer)
4611 (and
a4aeb9a4
MA
4612 ;; cksum runs locally, if possible.
4613 (zerop (tramp-local-call-process "cksum" tmpfile t))
4614 ;; cksum runs remotely.
9c13938d
MA
4615 (zerop
4616 (tramp-send-command-and-check
4617 v
4618 (format
4619 "cksum <%s" (tramp-shell-quote-argument localname))))
a4aeb9a4 4620 ;; ... they are different.
9c13938d
MA
4621 (not
4622 (string-equal
4623 (buffer-string)
4624 (with-current-buffer (tramp-get-buffer v)
4625 (buffer-string))))
4626 (tramp-error
4627 v 'file-error
4628 (concat "Couldn't write region to `%s',"
4629 " decode using `%s' failed")
4630 filename rem-dec)))
4631 (tramp-message
4632 v 5 "Decoding region into remote file %s...done" filename)
4633 (tramp-flush-file-property v localname))
8d60099b 4634
9c13938d
MA
4635 ;; Save exit.
4636 (delete-file tmpfile)))
8d60099b 4637
9c13938d
MA
4638 ;; That's not expected.
4639 (t
4640 (tramp-error
4641 v 'file-error
4642 (concat "Method `%s' should specify both encoding and "
4643 "decoding command or an rcp program")
4644 method)))
258800f8 4645
9c13938d
MA
4646 ;; Make `last-coding-system-used' have the right value.
4647 (when coding-system-used
4648 (set 'last-coding-system-used coding-system-used))))
0f205eee 4649
57671b72
MA
4650 ;; We must protect `last-coding-system-used', now we have set it
4651 ;; to its correct value.
4652 (let (last-coding-system-used)
4653 ;; Set file modification time.
4654 (when (or (eq visit t) (stringp visit))
4655 (set-visited-file-modtime
4656 ;; We must pass modtime explicitely, because filename can
4657 ;; be different from (buffer-file-name), f.e. if
4658 ;; `file-precious-flag' is set.
4659 (nth 5 (file-attributes filename))))
4660
4661 ;; Set the ownership.
4662 (tramp-set-file-uid-gid filename uid gid)
4663 (when (or (eq visit t) (null visit) (stringp visit))
4664 (tramp-message v 0 "Wrote %s" filename))
4665 (run-hooks 'tramp-handle-write-region-hook)))))
fb7933a3 4666
49096407
MA
4667(defun tramp-handle-vc-registered (file)
4668 "Like `vc-registered' for Tramp files."
4669 ;; There could be new files, created by the vc backend. We disable
736ac90f
MA
4670 ;; the file cache therefore.
4671 (let ((tramp-cache-inhibit-cache t))
49096407
MA
4672 (tramp-run-real-handler 'vc-registered (list file))))
4673
a01b1e22
MA
4674;;;###autoload
4675(progn (defun tramp-run-real-handler (operation args)
fb7933a3 4676 "Invoke normal file name handler for OPERATION.
c62c9d08
KG
4677First arg specifies the OPERATION, second arg is a list of arguments to
4678pass to the OPERATION."
4007ba5b
KG
4679 (let* ((inhibit-file-name-handlers
4680 `(tramp-file-name-handler
4681 tramp-completion-file-name-handler
4682 cygwin-mount-name-hook-function
4683 cygwin-mount-map-drive-hook-function
4684 .
4685 ,(and (eq inhibit-file-name-operation operation)
4686 inhibit-file-name-handlers)))
4687 (inhibit-file-name-operation operation))
a01b1e22 4688 (apply operation args))))
16674e4f 4689
a01b1e22
MA
4690;;;###autoload
4691(progn (defun tramp-completion-run-real-handler (operation args)
16674e4f
KG
4692 "Invoke `tramp-file-name-handler' for OPERATION.
4693First arg specifies the OPERATION, second arg is a list of arguments to
4694pass to the OPERATION."
4007ba5b
KG
4695 (let* ((inhibit-file-name-handlers
4696 `(tramp-completion-file-name-handler
4697 cygwin-mount-name-hook-function
4698 cygwin-mount-map-drive-hook-function
4699 .
4700 ,(and (eq inhibit-file-name-operation operation)
4701 inhibit-file-name-handlers)))
4702 (inhibit-file-name-operation operation))
a01b1e22 4703 (apply operation args))))
fb7933a3 4704
4007ba5b
KG
4705;; We handle here all file primitives. Most of them have the file
4706;; name as first parameter; nevertheless we check for them explicitly
04bf5b65 4707;; in order to be signaled if a new primitive appears. This
4007ba5b
KG
4708;; scenario is needed because there isn't a way to decide by
4709;; syntactical means whether a foreign method must be called. It would
19a87064 4710;; ease the life if `file-name-handler-alist' would support a decision
4007ba5b
KG
4711;; function as well but regexp only.
4712(defun tramp-file-name-for-operation (operation &rest args)
4713 "Return file name related to OPERATION file primitive.
4714ARGS are the arguments OPERATION has been called with."
4715 (cond
4716 ; FILE resp DIRECTORY
4717 ((member operation
4718 (list 'access-file 'byte-compiler-base-file-name 'delete-directory
4719 'delete-file 'diff-latest-backup-file 'directory-file-name
4720 'directory-files 'directory-files-and-attributes
4721 'dired-compress-file 'dired-uncache
4722 'file-accessible-directory-p 'file-attributes
4723 'file-directory-p 'file-executable-p 'file-exists-p
19a87064
MA
4724 'file-local-copy 'file-remote-p 'file-modes
4725 'file-name-as-directory 'file-name-directory
4726 'file-name-nondirectory 'file-name-sans-versions
4727 'file-ownership-preserved-p 'file-readable-p
4728 'file-regular-p 'file-symlink-p 'file-truename
4729 'file-writable-p 'find-backup-file-name 'find-file-noselect
4730 'get-file-buffer 'insert-directory 'insert-file-contents
4731 'load 'make-directory 'make-directory-internal
4732 'set-file-modes 'substitute-in-file-name
4733 'unhandled-file-name-directory 'vc-registered
ce3f516f
MA
4734 ; Emacs 22 only
4735 'set-file-times
4007ba5b
KG
4736 ; XEmacs only
4737 'abbreviate-file-name 'create-file-buffer
4738 'dired-file-modtime 'dired-make-compressed-filename
4739 'dired-recursive-delete-directory 'dired-set-file-modtime
4740 'dired-shell-unhandle-file-name 'dired-uucode-file
5615d63f 4741 'insert-file-contents-literally 'make-temp-name 'recover-file
4007ba5b 4742 'vm-imap-check-mail 'vm-pop-check-mail 'vm-spool-check-mail))
8daea7fc
KG
4743 (if (file-name-absolute-p (nth 0 args))
4744 (nth 0 args)
4745 (expand-file-name (nth 0 args))))
4007ba5b
KG
4746 ; FILE DIRECTORY resp FILE1 FILE2
4747 ((member operation
4748 (list 'add-name-to-file 'copy-file 'expand-file-name
4749 'file-name-all-completions 'file-name-completion
4750 'file-newer-than-file-p 'make-symbolic-link 'rename-file
4751 ; XEmacs only
4752 'dired-make-relative-symlink
4753 'vm-imap-move-mail 'vm-pop-move-mail 'vm-spool-move-mail))
4754 (save-match-data
4755 (cond
4756 ((string-match tramp-file-name-regexp (nth 0 args)) (nth 0 args))
4757 ((string-match tramp-file-name-regexp (nth 1 args)) (nth 1 args))
4758 (t (buffer-file-name (current-buffer))))))
4759 ; START END FILE
4760 ((eq operation 'write-region)
4761 (nth 2 args))
4762 ; BUF
4763 ((member operation
00d6fd04 4764 (list 'set-visited-file-modtime 'verify-visited-file-modtime
b50dd0d2 4765 ; since Emacs 22 only
00d6fd04
MA
4766 'make-auto-save-file-name
4767 ; XEmacs only
4007ba5b
KG
4768 'backup-buffer))
4769 (buffer-file-name
4770 (if (bufferp (nth 0 args)) (nth 0 args) (current-buffer))))
4771 ; COMMAND
4772 ((member operation
00d6fd04
MA
4773 (list ; not in Emacs 23
4774 'dired-call-process
01917a18 4775 ; Emacs only
b71c9e75 4776 'shell-command
00d6fd04 4777 ; since Emacs 22 only
0457dd55 4778 'process-file
00d6fd04
MA
4779 ; since Emacs 23 only
4780 'start-file-process
4007ba5b 4781 ; XEmacs only
00d6fd04
MA
4782 'dired-print-file 'dired-shell-call-process
4783 ; nowhere yet
4784 'executable-find 'start-process 'call-process))
4007ba5b
KG
4785 default-directory)
4786 ; unknown file primitive
4787 (t (error "unknown file I/O primitive: %s" operation))))
4788
4789(defun tramp-find-foreign-file-name-handler (filename)
4790 "Return foreign file name handler if exists."
9ce8462a
MA
4791 (when (and (stringp filename) (tramp-tramp-file-p filename))
4792 (let ((v (tramp-dissect-file-name filename t))
4793 (handler tramp-foreign-file-name-handler-alist)
4794 elt res)
4795 ;; When we are not fully sure that filename completion is safe,
4796 ;; we should not return a handler.
4797 (when (or (tramp-file-name-method v) (tramp-file-name-user v)
1834b39f
MA
4798 (and (tramp-file-name-host v)
4799 (not (member (tramp-file-name-host v)
4800 (mapcar 'car tramp-methods))))
9ce8462a
MA
4801 (not (tramp-completion-mode-p)))
4802 (while handler
4803 (setq elt (car handler)
4804 handler (cdr handler))
4805 (when (funcall (car elt) filename)
4806 (setq handler nil
4807 res (cdr elt))))
4808 res))))
4007ba5b 4809
fb7933a3
KG
4810;; Main function.
4811;;;###autoload
4812(defun tramp-file-name-handler (operation &rest args)
ea9d1443 4813 "Invoke Tramp file name handler.
a4aeb9a4 4814Falls back to normal file name handler if no Tramp file name handler exists."
2e271195
MA
4815 (if tramp-mode
4816 (save-match-data
4817 (let* ((filename
4818 (tramp-replace-environment-variables
4819 (apply 'tramp-file-name-for-operation operation args)))
4820 (completion (tramp-completion-mode-p))
4821 (foreign (tramp-find-foreign-file-name-handler filename)))
4822 (with-parsed-tramp-file-name filename nil
4823 (cond
4824 ;; When we are in completion mode, some operations
4825 ;; shouldn't be handled by backend.
4826 ((and completion (zerop (length localname))
4827 (memq operation '(file-exists-p file-directory-p)))
4828 t)
4829 ((and completion (zerop (length localname))
4830 (memq operation '(file-name-as-directory)))
4831 filename)
4832 ;; Call the backend function.
4833 (foreign (apply foreign operation args))
4834 ;; Nothing to do for us.
4835 (t (tramp-run-real-handler operation args))))))
4836 ;; When `tramp-mode' is not enabled, we don't do anything.
4837 (tramp-run-real-handler operation args)))
fb7933a3 4838
07dfe738
KG
4839;; In Emacs, there is some concurrency due to timers. If a timer
4840;; interrupts Tramp and wishes to use the same connection buffer as
4841;; the "main" Emacs, then garbage might occur in the connection
4842;; buffer. Therefore, we need to make sure that a timer does not use
4843;; the same connection buffer as the "main" Emacs. We implement a
4844;; cheap global lock, instead of locking each connection buffer
4845;; separately. The global lock is based on two variables,
4846;; `tramp-locked' and `tramp-locker'. `tramp-locked' is set to true
4847;; (with setq) to indicate a lock. But Tramp also calls itself during
4848;; processing of a single file operation, so we need to allow
4849;; recursive calls. That's where the `tramp-locker' variable comes in
4850;; -- it is let-bound to t during the execution of the current
4851;; handler. So if `tramp-locked' is t and `tramp-locker' is also t,
4852;; then we should just proceed because we have been called
4853;; recursively. But if `tramp-locker' is nil, then we are a timer
4854;; interrupting the "main" Emacs, and then we signal an error.
4855
4856(defvar tramp-locked nil
4857 "If non-nil, then Tramp is currently busy.
4858Together with `tramp-locker', this implements a locking mechanism
4859preventing reentrant calls of Tramp.")
4860
4861(defvar tramp-locker nil
4862 "If non-nil, then a caller has locked Tramp.
4863Together with `tramp-locked', this implements a locking mechanism
4864preventing reentrant calls of Tramp.")
4865
ea9d1443
KG
4866(defun tramp-sh-file-name-handler (operation &rest args)
4867 "Invoke remote-shell Tramp file name handler.
4868Fall back to normal file name handler if no Tramp handler exists."
07dfe738 4869 (when (and tramp-locked (not tramp-locker))
11c71217 4870 (setq tramp-locked nil)
00d6fd04 4871 (signal 'file-error (list "Forbidden reentrant call of Tramp")))
07dfe738
KG
4872 (let ((tl tramp-locked))
4873 (unwind-protect
4874 (progn
4875 (setq tramp-locked t)
4876 (let ((tramp-locker t))
4877 (save-match-data
4878 (let ((fn (assoc operation tramp-file-name-handler-alist)))
4879 (if fn
4880 (apply (cdr fn) args)
4881 (tramp-run-real-handler operation args))))))
4882 (setq tramp-locked tl))))
ea9d1443 4883
16674e4f 4884;;;###autoload
1ecc6145 4885(progn (defun tramp-completion-file-name-handler (operation &rest args)
a4aeb9a4
MA
4886 "Invoke Tramp file name completion handler.
4887Falls back to normal file name handler if no Tramp file name handler exists."
57671b72
MA
4888 ;; We bind `directory-sep-char' here for XEmacs on Windows, which
4889 ;; would otherwise use backslash.
aff67808
MA
4890 (let ((directory-sep-char ?/)
4891 (fn (assoc operation tramp-completion-file-name-handler-alist)))
2e271195
MA
4892 ;; When `tramp-mode' is not enabled, we don't do anything.
4893 (if (and fn tramp-mode)
aff67808
MA
4894 (save-match-data (apply (cdr fn) args))
4895 (tramp-completion-run-real-handler operation args)))))
a01b1e22 4896
b25a52cc 4897;;;###autoload
69cee873 4898(defsubst tramp-register-file-name-handler ()
a4aeb9a4 4899 "Add Tramp file name handler to `file-name-handler-alist'."
00d6fd04
MA
4900 ;; Remove autoloaded handler from file name handler alist. Useful,
4901 ;; if `tramp-syntax' has been changed.
4902 (let ((a1 (rassq 'tramp-file-name-handler file-name-handler-alist)))
4903 (setq file-name-handler-alist (delete a1 file-name-handler-alist)))
4904 ;; Add the handler.
a01b1e22
MA
4905 (add-to-list 'file-name-handler-alist
4906 (cons tramp-file-name-regexp 'tramp-file-name-handler))
69cee873
MA
4907 ;; If jka-compr is already loaded, move it to the front of
4908 ;; `file-name-handler-alist'.
4909 (let ((jka (rassoc 'jka-compr-handler file-name-handler-alist)))
4910 (when jka
4911 (setq file-name-handler-alist
4912 (cons jka (delete jka file-name-handler-alist))))))
4913
00d6fd04
MA
4914;; `tramp-file-name-handler' must be registered before evaluation of
4915;; site-start and init files, because there might exist remote files
4916;; already, f.e. files kept via recentf-mode.
4917;;;###autoload(tramp-register-file-name-handler)
4918(tramp-register-file-name-handler)
4919
69cee873
MA
4920;;;###autoload
4921(defsubst tramp-register-completion-file-name-handler ()
a4aeb9a4 4922 "Add Tramp completion file name handler to `file-name-handler-alist'."
00d6fd04
MA
4923 ;; Remove autoloaded handler from file name handler alist. Useful,
4924 ;; if `tramp-syntax' has been changed.
4925 (let ((a1 (rassq
4926 'tramp-completion-file-name-handler file-name-handler-alist)))
4927 (setq file-name-handler-alist (delete a1 file-name-handler-alist)))
56c195af
MA
4928 ;; In XEmacs, there is another Tramp syntax, so we can enable this
4929 ;; unconditionally. In GNU Emacs <= 22, method/user/host name
4930 ;; completion shall be bound to `partial-completion-mode'. Starting
4931 ;; with GNU Emacs 23, this is replaced by `completion-styles',
4932 ;; containing symbol `partial-completion'. `ido-mode' and
4933 ;; `icy-mode' are other packages which extend file name completion.
4934 (when (or (and (boundp 'partial-completion-mode)
4935 (symbol-value 'partial-completion-mode))
4936 (and (boundp 'completion-styles)
4937 (member 'partial-completion (symbol-value 'completion-styles)))
4938 (featurep 'xemacs)
9e6ab520
MA
4939 (featurep 'ido)
4940 (featurep 'icicles))
8c04e197
MA
4941 (add-to-list 'file-name-handler-alist
4942 (cons tramp-completion-file-name-regexp
4943 'tramp-completion-file-name-handler))
a01b1e22
MA
4944 (put 'tramp-completion-file-name-handler 'safe-magic t))
4945 ;; If jka-compr is already loaded, move it to the front of
4946 ;; `file-name-handler-alist'.
4947 (let ((jka (rassoc 'jka-compr-handler file-name-handler-alist)))
4948 (when jka
4949 (setq file-name-handler-alist
4950 (cons jka (delete jka file-name-handler-alist))))))
4951
4952;; During autoload, it shall be checked whether
2ac33804 4953;; `partial-completion-mode' is active. Therefore, registering of
69cee873 4954;; `tramp-completion-file-name-handler' will be delayed.
8c04e197 4955;;;###autoload(add-hook
1ecc6145 4956;;;###autoload 'after-init-hook
343bb7bd 4957;;;###autoload 'tramp-register-completion-file-name-handler)
69cee873 4958(tramp-register-completion-file-name-handler)
b25a52cc 4959
fb7933a3 4960;;;###autoload
8c04e197 4961(defun tramp-unload-file-name-handlers ()
a69c01a0
MA
4962 (setq file-name-handler-alist
4963 (delete (rassoc 'tramp-file-name-handler
4964 file-name-handler-alist)
4965 (delete (rassoc 'tramp-completion-file-name-handler
4966 file-name-handler-alist)
4967 file-name-handler-alist))))
4968
8c04e197 4969(add-hook 'tramp-unload-hook 'tramp-unload-file-name-handlers)
a69c01a0 4970
0664ff72 4971;;; File name handler functions for completion mode:
a6e96327
MA
4972
4973(defvar tramp-completion-mode nil
4974 "If non-nil, external packages signal that they are in file name completion.
4975
4976This is necessary, because Tramp uses a heuristic depending on last
4977input event. This fails when external packages use other characters
4978but <TAB>, <SPACE> or ?\\? for file name completion. This variable
4979should never be set globally, the intention is to let-bind it.")
16674e4f
KG
4980
4981;; Necessary because `tramp-file-name-regexp-unified' and
00d6fd04
MA
4982;; `tramp-completion-file-name-regexp-unified' aren't different. If
4983;; nil, `tramp-completion-run-real-handler' is called (i.e. forwarding
4984;; to `tramp-file-name-handler'). Otherwise, it takes
4985;; `tramp-run-real-handler'. Using `last-input-event' is a little bit
4986;; risky, because completing a file might require loading other files,
4987;; like "~/.netrc", and for them it shouldn't be decided based on that
4988;; variable. On the other hand, those files shouldn't have partial
a4aeb9a4
MA
4989;; Tramp file name syntax. Maybe another variable should be introduced
4990;; overwriting this check in such cases. Or we change Tramp file name
00d6fd04 4991;; syntax in order to avoid ambiguities, like in XEmacs ...
6c4e47fa 4992(defun tramp-completion-mode-p ()
16674e4f 4993 "Checks whether method / user name / host name completion is active."
6c4e47fa 4994 (or
a6e96327
MA
4995 ;; Signal from outside.
4996 tramp-completion-mode
4997 ;; Emacs.
94be87e8 4998 (equal last-input-event 'tab)
6c4e47fa 4999 (and (natnump last-input-event)
94be87e8 5000 (or
a6e96327 5001 ;; ?\t has event-modifier 'control.
800a97b8 5002 (equal last-input-event ?\t)
94be87e8 5003 (and (not (event-modifiers last-input-event))
800a97b8
SM
5004 (or (equal last-input-event ?\?)
5005 (equal last-input-event ?\ )))))
a6e96327 5006 ;; XEmacs.
6c4e47fa
MA
5007 (and (featurep 'xemacs)
5008 ;; `last-input-event' might be nil.
5009 (not (null last-input-event))
5010 ;; `last-input-event' may have no character approximation.
5011 (funcall (symbol-function 'event-to-character) last-input-event)
94be87e8 5012 (or
a6e96327 5013 ;; ?\t has event-modifier 'control.
800a97b8 5014 (equal
94be87e8
MA
5015 (funcall (symbol-function 'event-to-character)
5016 last-input-event) ?\t)
5017 (and (not (event-modifiers last-input-event))
800a97b8 5018 (or (equal
94be87e8
MA
5019 (funcall (symbol-function 'event-to-character)
5020 last-input-event) ?\?)
800a97b8 5021 (equal
94be87e8
MA
5022 (funcall (symbol-function 'event-to-character)
5023 last-input-event) ?\ )))))))
16674e4f 5024
16674e4f
KG
5025;; Method, host name and user name completion.
5026;; `tramp-completion-dissect-file-name' returns a list of
5027;; tramp-file-name structures. For all of them we return possible completions.
a01b1e22 5028;;;###autoload
16674e4f 5029(defun tramp-completion-handle-file-name-all-completions (filename directory)
00d6fd04 5030 "Like `file-name-all-completions' for partial Tramp files."
16674e4f 5031
00d6fd04
MA
5032 (let* ((fullname (tramp-drop-volume-letter
5033 (expand-file-name filename directory)))
5034 ;; Possible completion structures.
5035 (v (tramp-completion-dissect-file-name fullname))
5036 result result1)
5037
5038 (while v
5039 (let* ((car (car v))
5040 (method (tramp-file-name-method car))
5041 (user (tramp-file-name-user car))
5042 (host (tramp-file-name-host car))
5043 (localname (tramp-file-name-localname car))
5044 (m (tramp-find-method method user host))
5045 (tramp-current-user user) ; see `tramp-parse-passwd'
5046 all-user-hosts)
5047
5048 (unless localname ;; Nothing to complete.
5049
5050 (if (or user host)
5051
5052 ;; Method dependent user / host combinations.
5053 (progn
9e6ab520 5054 (mapc
00d6fd04
MA
5055 (lambda (x)
5056 (setq all-user-hosts
5057 (append all-user-hosts
5058 (funcall (nth 0 x) (nth 1 x)))))
5059 (tramp-get-completion-function m))
5060
9e6ab520
MA
5061 (setq result
5062 (append result
5063 (mapcar
5064 (lambda (x)
5065 (tramp-get-completion-user-host
5066 method user host (nth 0 x) (nth 1 x)))
5067 (delq nil all-user-hosts)))))
00d6fd04
MA
5068
5069 ;; Possible methods.
5070 (setq result
5071 (append result (tramp-get-completion-methods m)))))
5072
5073 (setq v (cdr v))))
5074
5075 ;; Unify list, remove nil elements.
5076 (while result
5077 (let ((car (car result)))
5078 (when car
5079 (add-to-list
5080 'result1
5081 (substring car (length (tramp-drop-volume-letter directory)))))
5082 (setq result (cdr result))))
5083
5084 ;; Complete local parts.
5085 (append
5086 result1
5087 (condition-case nil
5088 (tramp-completion-run-real-handler
5089 'file-name-all-completions (list filename directory))
5090 (error nil)))))
16674e4f
KG
5091
5092;; Method, host name and user name completion for a file.
a01b1e22 5093;;;###autoload
e1e17cae
MA
5094(defun tramp-completion-handle-file-name-completion
5095 (filename directory &optional predicate)
00d6fd04 5096 "Like `file-name-completion' for Tramp files."
e1e17cae
MA
5097 (try-completion
5098 filename
5099 (mapcar 'list (file-name-all-completions filename directory))
83e20b5c
MA
5100 (when predicate
5101 (lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
16674e4f
KG
5102
5103;; I misuse a little bit the tramp-file-name structure in order to handle
5104;; completion possibilities for partial methods / user names / host names.
5105;; Return value is a list of tramp-file-name structures according to possible
00d6fd04 5106;; completions. If "localname" is non-nil it means there
16674e4f
KG
5107;; shouldn't be a completion anymore.
5108
5109;; Expected results:
5110
00d6fd04
MA
5111;; "/x" "/[x" "/x@" "/[x@" "/x@y" "/[x@y"
5112;; [nil nil "x" nil] [nil "x" nil nil] [nil "x" "y" nil]
5113;; [nil "x" nil nil]
5114;; ["x" nil nil nil]
5115
5116;; "/x:" "/x:y" "/x:y:"
5117;; [nil nil "x" ""] [nil nil "x" "y"] ["x" nil "y" ""]
5118;; "/[x/" "/[x/y"
5119;; ["x" nil "" nil] ["x" nil "y" nil]
5120;; ["x" "" nil nil] ["x" "y" nil nil]
5121
5122;; "/x:y@" "/x:y@z" "/x:y@z:"
5123;; [nil nil "x" "y@"] [nil nil "x" "y@z"] ["x" "y" "z" ""]
5124;; "/[x/y@" "/[x/y@z"
5125;; ["x" nil "y" nil] ["x" "y" "z" nil]
16674e4f
KG
5126(defun tramp-completion-dissect-file-name (name)
5127 "Returns a list of `tramp-file-name' structures.
5128They are collected by `tramp-completion-dissect-file-name1'."
5129
5130 (let* ((result)
4007ba5b 5131 (x-nil "\\|\\(\\)")
b96e6899
MA
5132 (tramp-completion-ipv6-regexp
5133 (format
5134 "[^%s]*"
5135 (if (zerop (length tramp-postfix-ipv6-format))
5136 tramp-postfix-host-format
5137 tramp-postfix-ipv6-format)))
4007ba5b
KG
5138 ;; "/method" "/[method"
5139 (tramp-completion-file-name-structure1
5140 (list (concat tramp-prefix-regexp "\\(" tramp-method-regexp x-nil "\\)$")
5141 1 nil nil nil))
5142 ;; "/user" "/[user"
5143 (tramp-completion-file-name-structure2
5144 (list (concat tramp-prefix-regexp "\\(" tramp-user-regexp x-nil "\\)$")
5145 nil 1 nil nil))
5146 ;; "/host" "/[host"
5147 (tramp-completion-file-name-structure3
5148 (list (concat tramp-prefix-regexp "\\(" tramp-host-regexp x-nil "\\)$")
5149 nil nil 1 nil))
b96e6899 5150 ;; "/[ipv6" "/[ipv6"
4007ba5b 5151 (tramp-completion-file-name-structure4
b96e6899
MA
5152 (list (concat tramp-prefix-regexp
5153 tramp-prefix-ipv6-regexp
5154 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5155 nil nil 1 nil))
5156 ;; "/user@host" "/[user@host"
5157 (tramp-completion-file-name-structure5
4007ba5b
KG
5158 (list (concat tramp-prefix-regexp
5159 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5160 "\\(" tramp-host-regexp x-nil "\\)$")
5161 nil 1 2 nil))
b96e6899
MA
5162 ;; "/user@[ipv6" "/[user@ipv6"
5163 (tramp-completion-file-name-structure6
5164 (list (concat tramp-prefix-regexp
5165 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5166 tramp-prefix-ipv6-regexp
5167 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5168 nil 1 2 nil))
00d6fd04 5169 ;; "/method:user" "/[method/user" "/method://user"
b96e6899 5170 (tramp-completion-file-name-structure7
4007ba5b 5171 (list (concat tramp-prefix-regexp
00d6fd04 5172 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5173 "\\(" tramp-user-regexp x-nil "\\)$")
5174 1 2 nil nil))
00d6fd04 5175 ;; "/method:host" "/[method/host" "/method://host"
b96e6899 5176 (tramp-completion-file-name-structure8
4007ba5b 5177 (list (concat tramp-prefix-regexp
00d6fd04 5178 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5179 "\\(" tramp-host-regexp x-nil "\\)$")
5180 1 nil 2 nil))
b96e6899
MA
5181 ;; "/method:[ipv6" "/[method/ipv6" "/method://[ipv6"
5182 (tramp-completion-file-name-structure9
5183 (list (concat tramp-prefix-regexp
5184 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
5185 tramp-prefix-ipv6-regexp
5186 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5187 1 nil 2 nil))
00d6fd04 5188 ;; "/method:user@host" "/[method/user@host" "/method://user@host"
b96e6899 5189 (tramp-completion-file-name-structure10
4007ba5b 5190 (list (concat tramp-prefix-regexp
00d6fd04 5191 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5192 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5193 "\\(" tramp-host-regexp x-nil "\\)$")
00d6fd04 5194 1 2 3 nil))
b96e6899
MA
5195 ;; "/method:user@[ipv6" "/[method/user@ipv6" "/method://user@[ipv6"
5196 (tramp-completion-file-name-structure11
5197 (list (concat tramp-prefix-regexp
5198 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
5199 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5200 tramp-prefix-ipv6-regexp
5201 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5202 1 2 3 nil))
00d6fd04 5203 ;; "/method: "/method:/"
b96e6899 5204 (tramp-completion-file-name-structure12
00d6fd04
MA
5205 (list
5206 (if (equal tramp-syntax 'url)
5207 (concat tramp-prefix-regexp
5208 "\\(" tramp-method-regexp "\\)"
5209 "\\(" (substring tramp-postfix-method-regexp 0 1)
5210 "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)"
5211 "\\(" "\\)$")
5212 ;; Should not match if not URL syntax.
5213 (concat tramp-prefix-regexp "/$"))
5214 1 3 nil nil))
5215 ;; "/method: "/method:/"
b96e6899 5216 (tramp-completion-file-name-structure13
00d6fd04
MA
5217 (list
5218 (if (equal tramp-syntax 'url)
5219 (concat tramp-prefix-regexp
5220 "\\(" tramp-method-regexp "\\)"
5221 "\\(" (substring tramp-postfix-method-regexp 0 1)
5222 "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)"
5223 "\\(" "\\)$")
5224 ;; Should not match if not URL syntax.
5225 (concat tramp-prefix-regexp "/$"))
5226 1 nil 3 nil)))
4007ba5b 5227
9e6ab520 5228 (mapc (lambda (regexp)
16674e4f
KG
5229 (add-to-list 'result
5230 (tramp-completion-dissect-file-name1 regexp name)))
5231 (list
5232 tramp-completion-file-name-structure1
5233 tramp-completion-file-name-structure2
5234 tramp-completion-file-name-structure3
5235 tramp-completion-file-name-structure4
5236 tramp-completion-file-name-structure5
5237 tramp-completion-file-name-structure6
5238 tramp-completion-file-name-structure7
00d6fd04
MA
5239 tramp-completion-file-name-structure8
5240 tramp-completion-file-name-structure9
b96e6899
MA
5241 tramp-completion-file-name-structure10
5242 tramp-completion-file-name-structure11
5243 tramp-completion-file-name-structure12
5244 tramp-completion-file-name-structure13
16674e4f
KG
5245 tramp-file-name-structure))
5246
5247 (delq nil result)))
5248
5249(defun tramp-completion-dissect-file-name1 (structure name)
5250 "Returns a `tramp-file-name' structure matching STRUCTURE.
00d6fd04 5251The structure consists of remote method, remote user,
7432277c 5252remote host and localname (filename on remote host)."
fb7933a3 5253
00d6fd04
MA
5254 (save-match-data
5255 (when (string-match (nth 0 structure) name)
5256 (let ((method (and (nth 1 structure)
5257 (match-string (nth 1 structure) name)))
5258 (user (and (nth 2 structure)
5259 (match-string (nth 2 structure) name)))
5260 (host (and (nth 3 structure)
5261 (match-string (nth 3 structure) name)))
5262 (localname (and (nth 4 structure)
5263 (match-string (nth 4 structure) name))))
5264 (vector method user host localname)))))
16674e4f
KG
5265
5266;; This function returns all possible method completions, adding the
5267;; trailing method delimeter.
16674e4f
KG
5268(defun tramp-get-completion-methods (partial-method)
5269 "Returns all method completions for PARTIAL-METHOD."
4007ba5b
KG
5270 (mapcar
5271 (lambda (method)
5272 (and method
5273 (string-match (concat "^" (regexp-quote partial-method)) method)
00d6fd04
MA
5274 (tramp-completion-make-tramp-file-name method nil nil nil)))
5275 (mapcar 'car tramp-methods)))
16674e4f
KG
5276
5277;; Compares partial user and host names with possible completions.
5278(defun tramp-get-completion-user-host (method partial-user partial-host user host)
5279 "Returns the most expanded string for user and host name completion.
5280PARTIAL-USER must match USER, PARTIAL-HOST must match HOST."
5281 (cond
5282
5283 ((and partial-user partial-host)
5284 (if (and host
5285 (string-match (concat "^" (regexp-quote partial-host)) host)
5286 (string-equal partial-user (or user partial-user)))
5287 (setq user partial-user)
5288 (setq user nil
5289 host nil)))
5290
5291 (partial-user
5292 (setq host nil)
5293 (unless
5294 (and user (string-match (concat "^" (regexp-quote partial-user)) user))
5295 (setq user nil)))
5296
5297 (partial-host
5298 (setq user nil)
5299 (unless
5300 (and host (string-match (concat "^" (regexp-quote partial-host)) host))
5301 (setq host nil)))
5302
5303 (t (setq user nil
5304 host nil)))
5305
292ffc15 5306 (unless (zerop (+ (length user) (length host)))
00d6fd04 5307 (tramp-completion-make-tramp-file-name method user host nil)))
16674e4f
KG
5308
5309(defun tramp-parse-rhosts (filename)
5310 "Return a list of (user host) tuples allowed to access.
292ffc15 5311Either user or host may be nil."
00d6fd04
MA
5312 ;; On Windows, there are problems in completion when
5313 ;; `default-directory' is remote.
9e6ab520 5314 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5315 res)
8daea7fc 5316 (when (file-readable-p filename)
16674e4f
KG
5317 (with-temp-buffer
5318 (insert-file-contents filename)
5319 (goto-char (point-min))
5320 (while (not (eobp))
292ffc15 5321 (push (tramp-parse-rhosts-group) res))))
16674e4f
KG
5322 res))
5323
16674e4f
KG
5324(defun tramp-parse-rhosts-group ()
5325 "Return a (user host) tuple allowed to access.
292ffc15 5326Either user or host may be nil."
16674e4f
KG
5327 (let ((result)
5328 (regexp
5329 (concat
5330 "^\\(" tramp-host-regexp "\\)"
5331 "\\([ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
9e6ab520 5332 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
5333 (when (re-search-forward regexp nil t)
5334 (setq result (append (list (match-string 3) (match-string 1)))))
5335 (widen)
5336 (forward-line 1)
5337 result))
5338
5339(defun tramp-parse-shosts (filename)
5340 "Return a list of (user host) tuples allowed to access.
5341User is always nil."
00d6fd04
MA
5342 ;; On Windows, there are problems in completion when
5343 ;; `default-directory' is remote.
9e6ab520 5344 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5345 res)
8daea7fc 5346 (when (file-readable-p filename)
16674e4f
KG
5347 (with-temp-buffer
5348 (insert-file-contents filename)
5349 (goto-char (point-min))
5350 (while (not (eobp))
292ffc15 5351 (push (tramp-parse-shosts-group) res))))
16674e4f
KG
5352 res))
5353
5354(defun tramp-parse-shosts-group ()
5355 "Return a (user host) tuple allowed to access.
5356User is always nil."
16674e4f
KG
5357 (let ((result)
5358 (regexp (concat "^\\(" tramp-host-regexp "\\)")))
9e6ab520 5359 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
5360 (when (re-search-forward regexp nil t)
5361 (setq result (list nil (match-string 1))))
5362 (widen)
5363 (or
5364 (> (skip-chars-forward ",") 0)
5365 (forward-line 1))
5366 result))
5367
8daea7fc
KG
5368(defun tramp-parse-sconfig (filename)
5369 "Return a list of (user host) tuples allowed to access.
5370User is always nil."
00d6fd04
MA
5371 ;; On Windows, there are problems in completion when
5372 ;; `default-directory' is remote.
9e6ab520 5373 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5374 res)
8daea7fc
KG
5375 (when (file-readable-p filename)
5376 (with-temp-buffer
5377 (insert-file-contents filename)
5378 (goto-char (point-min))
5379 (while (not (eobp))
5380 (push (tramp-parse-sconfig-group) res))))
5381 res))
5382
5383(defun tramp-parse-sconfig-group ()
5384 "Return a (user host) tuple allowed to access.
5385User is always nil."
8daea7fc
KG
5386 (let ((result)
5387 (regexp (concat "^[ \t]*Host[ \t]+" "\\(" tramp-host-regexp "\\)")))
9e6ab520 5388 (narrow-to-region (point) (tramp-compat-line-end-position))
8daea7fc
KG
5389 (when (re-search-forward regexp nil t)
5390 (setq result (list nil (match-string 1))))
5391 (widen)
5392 (or
5393 (> (skip-chars-forward ",") 0)
5394 (forward-line 1))
5395 result))
5396
5ec2cc41
KG
5397(defun tramp-parse-shostkeys (dirname)
5398 "Return a list of (user host) tuples allowed to access.
5399User is always nil."
00d6fd04
MA
5400 ;; On Windows, there are problems in completion when
5401 ;; `default-directory' is remote.
9e6ab520 5402 (let* ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
5403 (regexp (concat "^key_[0-9]+_\\(" tramp-host-regexp "\\)\\.pub$"))
5404 (files (when (file-directory-p dirname) (directory-files dirname)))
5405 result)
5ec2cc41
KG
5406 (while files
5407 (when (string-match regexp (car files))
5408 (push (list nil (match-string 1 (car files))) result))
5409 (setq files (cdr files)))
5410 result))
5411
5412(defun tramp-parse-sknownhosts (dirname)
5413 "Return a list of (user host) tuples allowed to access.
5414User is always nil."
00d6fd04
MA
5415 ;; On Windows, there are problems in completion when
5416 ;; `default-directory' is remote.
9e6ab520 5417 (let* ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
5418 (regexp (concat "^\\(" tramp-host-regexp
5419 "\\)\\.ssh-\\(dss\\|rsa\\)\\.pub$"))
5420 (files (when (file-directory-p dirname) (directory-files dirname)))
5421 result)
5ec2cc41
KG
5422 (while files
5423 (when (string-match regexp (car files))
5424 (push (list nil (match-string 1 (car files))) result))
5425 (setq files (cdr files)))
5426 result))
5427
16674e4f
KG
5428(defun tramp-parse-hosts (filename)
5429 "Return a list of (user host) tuples allowed to access.
5430User is always nil."
00d6fd04
MA
5431 ;; On Windows, there are problems in completion when
5432 ;; `default-directory' is remote.
9e6ab520 5433 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5434 res)
8daea7fc 5435 (when (file-readable-p filename)
16674e4f
KG
5436 (with-temp-buffer
5437 (insert-file-contents filename)
5438 (goto-char (point-min))
5439 (while (not (eobp))
292ffc15 5440 (push (tramp-parse-hosts-group) res))))
16674e4f
KG
5441 res))
5442
5443(defun tramp-parse-hosts-group ()
5444 "Return a (user host) tuple allowed to access.
5445User is always nil."
16674e4f 5446 (let ((result)
b96e6899
MA
5447 (regexp
5448 (concat "^\\(" tramp-ipv6-regexp "\\|" tramp-host-regexp "\\)")))
9e6ab520 5449 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f 5450 (when (re-search-forward regexp nil t)
b96e6899 5451 (setq result (list nil (match-string 1))))
16674e4f
KG
5452 (widen)
5453 (or
5454 (> (skip-chars-forward " \t") 0)
5455 (forward-line 1))
5456 result))
5457
8daea7fc
KG
5458;; For su-alike methods it would be desirable to return "root@localhost"
5459;; as default. Unfortunately, we have no information whether any user name
00d6fd04 5460;; has been typed already. So we use `tramp-current-user' as indication,
8daea7fc 5461;; assuming it is set in `tramp-completion-handle-file-name-all-completions'.
16674e4f
KG
5462(defun tramp-parse-passwd (filename)
5463 "Return a list of (user host) tuples allowed to access.
5464Host is always \"localhost\"."
00d6fd04
MA
5465 ;; On Windows, there are problems in completion when
5466 ;; `default-directory' is remote.
9e6ab520 5467 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5468 res)
8daea7fc 5469 (if (zerop (length tramp-current-user))
16674e4f 5470 '(("root" nil))
8daea7fc 5471 (when (file-readable-p filename)
16674e4f
KG
5472 (with-temp-buffer
5473 (insert-file-contents filename)
5474 (goto-char (point-min))
5475 (while (not (eobp))
292ffc15 5476 (push (tramp-parse-passwd-group) res))))
16674e4f
KG
5477 res)))
5478
5479(defun tramp-parse-passwd-group ()
5480 "Return a (user host) tuple allowed to access.
292ffc15 5481Host is always \"localhost\"."
16674e4f
KG
5482 (let ((result)
5483 (regexp (concat "^\\(" tramp-user-regexp "\\):")))
9e6ab520 5484 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
5485 (when (re-search-forward regexp nil t)
5486 (setq result (list (match-string 1) "localhost")))
5487 (widen)
5488 (forward-line 1)
5489 result))
5490
292ffc15
KG
5491(defun tramp-parse-netrc (filename)
5492 "Return a list of (user host) tuples allowed to access.
5493User may be nil."
00d6fd04
MA
5494 ;; On Windows, there are problems in completion when
5495 ;; `default-directory' is remote.
9e6ab520 5496 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5497 res)
8daea7fc 5498 (when (file-readable-p filename)
292ffc15
KG
5499 (with-temp-buffer
5500 (insert-file-contents filename)
5501 (goto-char (point-min))
5502 (while (not (eobp))
5503 (push (tramp-parse-netrc-group) res))))
5504 res))
5505
5506(defun tramp-parse-netrc-group ()
5507 "Return a (user host) tuple allowed to access.
5508User may be nil."
292ffc15
KG
5509 (let ((result)
5510 (regexp
5511 (concat
5512 "^[ \t]*machine[ \t]+" "\\(" tramp-host-regexp "\\)"
5513 "\\([ \t]+login[ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
9e6ab520 5514 (narrow-to-region (point) (tramp-compat-line-end-position))
292ffc15
KG
5515 (when (re-search-forward regexp nil t)
5516 (setq result (list (match-string 3) (match-string 1))))
5517 (widen)
5518 (forward-line 1)
5519 result))
5520
00d6fd04
MA
5521(defun tramp-parse-putty (registry)
5522 "Return a list of (user host) tuples allowed to access.
5523User is always nil."
5524 ;; On Windows, there are problems in completion when
5525 ;; `default-directory' is remote.
9e6ab520 5526 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
5527 res)
5528 (with-temp-buffer
a4aeb9a4 5529 (when (zerop (tramp-local-call-process "reg" nil t nil "query" registry))
00d6fd04
MA
5530 (goto-char (point-min))
5531 (while (not (eobp))
5532 (push (tramp-parse-putty-group registry) res))))
5533 res))
5534
5535(defun tramp-parse-putty-group (registry)
5536 "Return a (user host) tuple allowed to access.
5537User is always nil."
5538 (let ((result)
5539 (regexp (concat (regexp-quote registry) "\\\\\\(.+\\)")))
9e6ab520 5540 (narrow-to-region (point) (tramp-compat-line-end-position))
00d6fd04
MA
5541 (when (re-search-forward regexp nil t)
5542 (setq result (list nil (match-string 1))))
5543 (widen)
5544 (forward-line 1)
5545 result))
5546
fb7933a3
KG
5547;;; Internal Functions:
5548
00d6fd04
MA
5549(defun tramp-maybe-send-script (vec script name)
5550 "Define in remote shell function NAME implemented as SCRIPT.
5551Only send the definition if it has not already been done."
5552 (let* ((p (tramp-get-connection-process vec))
5553 (scripts (tramp-get-connection-property p "scripts" nil)))
1834b39f 5554 (unless (member name scripts)
00d6fd04
MA
5555 (tramp-message vec 5 "Sending script `%s'..." name)
5556 ;; The script could contain a call of Perl. This is masked with `%s'.
5557 (tramp-send-command-and-check
5558 vec
5559 (format "%s () {\n%s\n}" name
5560 (format script (tramp-get-remote-perl vec))))
5561 (tramp-set-connection-property p "scripts" (cons name scripts))
5562 (tramp-message vec 5 "Sending script `%s'...done." name))))
c82c5727 5563
fb7933a3 5564(defun tramp-set-auto-save ()
00d6fd04 5565 (when (and ;; ange-ftp has its own auto-save mechanism
7177e2a3
MA
5566 (eq (tramp-find-foreign-file-name-handler (buffer-file-name))
5567 'tramp-sh-file-name-handler)
fb7933a3
KG
5568 auto-save-default)
5569 (auto-save-mode 1)))
5570(add-hook 'find-file-hooks 'tramp-set-auto-save t)
a69c01a0
MA
5571(add-hook 'tramp-unload-hook
5572 '(lambda ()
5573 (remove-hook 'find-file-hooks 'tramp-set-auto-save)))
fb7933a3
KG
5574
5575(defun tramp-run-test (switch filename)
5576 "Run `test' on the remote system, given a SWITCH and a FILENAME.
5577Returns the exit code of the `test' program."
00d6fd04
MA
5578 (with-parsed-tramp-file-name filename nil
5579 (tramp-send-command-and-check
5580 v
5581 (format
5582 "%s %s %s"
5583 (tramp-get-test-command v)
5584 switch
5585 (tramp-shell-quote-argument localname)))))
5586
5587(defun tramp-run-test2 (format-string file1 file2)
5588 "Run `test'-like program on the remote system, given FILE1, FILE2.
5589FORMAT-STRING contains the program name, switches, and place holders.
5590Returns the exit code of the `test' program. Barfs if the methods,
fb7933a3 5591hosts, or files, disagree."
00d6fd04
MA
5592 (unless (tramp-equal-remote file1 file2)
5593 (with-parsed-tramp-file-name (if (tramp-tramp-file-p file1) file1 file2) nil
5594 (tramp-error
5595 v 'file-error
5596 "tramp-run-test2 only implemented for same method, user, host")))
5597 (with-parsed-tramp-file-name file1 v1
5598 (with-parsed-tramp-file-name file1 v2
fb7933a3 5599 (tramp-send-command-and-check
00d6fd04
MA
5600 v1
5601 (format format-string
5602 (tramp-shell-quote-argument v1-localname)
5603 (tramp-shell-quote-argument v2-localname))))))
fb7933a3 5604
00d6fd04
MA
5605(defun tramp-buffer-name (vec)
5606 "A name for the connection buffer VEC."
5607 ;; We must use `tramp-file-name-real-host', because for gateway
5608 ;; methods the default port will be expanded later on, which would
5609 ;; tamper the name.
5610 (let ((method (tramp-file-name-method vec))
5611 (user (tramp-file-name-user vec))
5612 (host (tramp-file-name-real-host vec)))
5613 (if (not (zerop (length user)))
5614 (format "*tramp/%s %s@%s*" method user host)
5615 (format "*tramp/%s %s*" method host))))
5616
5617(defun tramp-get-buffer (vec)
5618 "Get the connection buffer to be used for VEC."
5619 (or (get-buffer (tramp-buffer-name vec))
5620 (with-current-buffer (get-buffer-create (tramp-buffer-name vec))
5621 (setq buffer-undo-list t)
5622 (setq default-directory
5623 (tramp-make-tramp-file-name
5624 (tramp-file-name-method vec)
5625 (tramp-file-name-user vec)
5626 (tramp-file-name-host vec)
5627 "/"))
5628 (current-buffer))))
5629
5630(defun tramp-get-connection-buffer (vec)
5631 "Get the connection buffer to be used for VEC.
5632In case a second asynchronous communication has been started, it is different
5633from `tramp-get-buffer'."
5634 (or (tramp-get-connection-property vec "process-buffer" nil)
5635 (tramp-get-buffer vec)))
5636
5637(defun tramp-get-connection-process (vec)
5638 "Get the connection process to be used for VEC.
5639In case a second asynchronous communication has been started, it is different
5640from the default one."
5641 (get-process
5642 (or (tramp-get-connection-property vec "process-name" nil)
5643 (tramp-buffer-name vec))))
5644
5645(defun tramp-debug-buffer-name (vec)
5646 "A name for the debug buffer for VEC."
5647 ;; We must use `tramp-file-name-real-host', because for gateway
5648 ;; methods the default port will be expanded later on, which would
5649 ;; tamper the name.
5650 (let ((method (tramp-file-name-method vec))
5651 (user (tramp-file-name-user vec))
5652 (host (tramp-file-name-real-host vec)))
5653 (if (not (zerop (length user)))
5654 (format "*debug tramp/%s %s@%s*" method user host)
5655 (format "*debug tramp/%s %s*" method host))))
5656
5657(defun tramp-get-debug-buffer (vec)
5658 "Get the debug buffer for VEC."
01917a18 5659 (with-current-buffer
00d6fd04
MA
5660 (get-buffer-create (tramp-debug-buffer-name vec))
5661 (when (bobp)
5662 (setq buffer-undo-list t)
9ce8462a
MA
5663 ;; Activate outline-mode. This runs `text-mode-hook' and
5664 ;; `outline-mode-hook'. We must prevent that local processes
5665 ;; die. Yes: I've seen `flyspell-mode', which starts "ispell"
5666 ;; ...
9e6ab520 5667 (let ((default-directory (tramp-compat-temporary-file-directory)))
00d6fd04 5668 (outline-mode))
9ce8462a 5669 (set (make-local-variable 'outline-regexp)
736ac90f 5670 "[0-9]+:[0-9]+:[0-9]+\\.[0-9]+ [a-z0-9-]+ (\\([0-9]+\\)) #")
9ce8462a
MA
5671; (set (make-local-variable 'outline-regexp)
5672; "[a-z.-]+:[0-9]+: [a-z0-9-]+ (\\([0-9]+\\)) #")
5673 (set (make-local-variable 'outline-level) 'tramp-outline-level))
01917a18 5674 (current-buffer)))
fb7933a3 5675
00d6fd04
MA
5676(defun tramp-outline-level ()
5677 "Return the depth to which a statement is nested in the outline.
5678Point must be at the beginning of a header line.
5679
5680The outline level is equal to the verbosity of the Tramp message."
5681 (1+ (string-to-number (match-string 1))))
fb7933a3 5682
00d6fd04
MA
5683(defun tramp-find-executable
5684 (vec progname dirlist &optional ignore-tilde ignore-path)
5685 "Searches for PROGNAME in $PATH and all directories mentioned in DIRLIST.
5686First arg VEC specifies the connection, PROGNAME is the program
5687to search for, and DIRLIST gives the list of directories to
5688search. If IGNORE-TILDE is non-nil, directory names starting
5689with `~' will be ignored. If IGNORE-PATH is non-nil, searches
5690only in DIRLIST.
fb7933a3 5691
7432277c 5692Returns the absolute file name of PROGNAME, if found, and nil otherwise.
fb7933a3
KG
5693
5694This function expects to be in the right *tramp* buffer."
00d6fd04
MA
5695 (with-current-buffer (tramp-get-buffer vec)
5696 (let (result)
5697 ;; Check whether the executable is in $PATH. "which(1)" does not
5698 ;; report always a correct error code; therefore we check the
5699 ;; number of words it returns.
5700 (unless ignore-path
5701 (tramp-send-command vec (format "which \\%s | wc -w" progname))
5702 (goto-char (point-min))
5703 (if (looking-at "^1$")
5704 (setq result (concat "\\" progname))))
5705 (unless result
5706 (when ignore-tilde
5707 ;; Remove all ~/foo directories from dirlist. In Emacs 20,
5708 ;; `remove' is in CL, and we want to avoid CL dependencies.
5709 (let (newdl d)
5710 (while dirlist
5711 (setq d (car dirlist))
5712 (setq dirlist (cdr dirlist))
5713 (unless (char-equal ?~ (aref d 0))
5714 (setq newdl (cons d newdl))))
5715 (setq dirlist (nreverse newdl))))
5716 (tramp-send-command
5717 vec
5718 (format (concat "while read d; "
5719 "do if test -x $d/%s -a -f $d/%s; "
5720 "then echo tramp_executable $d/%s; "
5721 "break; fi; done <<'EOF'\n"
5722 "%s\nEOF")
5723 progname progname progname (mapconcat 'identity dirlist "\n")))
5724 (goto-char (point-max))
5725 (when (search-backward "tramp_executable " nil t)
5726 (skip-chars-forward "^ ")
5727 (skip-chars-forward " ")
9e6ab520
MA
5728 (setq result (buffer-substring
5729 (point) (tramp-compat-line-end-position)))))
00d6fd04
MA
5730 result)))
5731
5732(defun tramp-set-remote-path (vec)
5733 "Sets the remote environment PATH to existing directories.
5734I.e., for each directory in `tramp-remote-path', it is tested
5735whether it exists and if so, it is added to the environment
5736variable PATH."
5737 (tramp-message vec 5 (format "Setting $PATH environment variable"))
f84638eb
MA
5738 (tramp-send-command
5739 vec (format "PATH=%s; export PATH"
5740 (mapconcat 'identity (tramp-get-remote-path vec) ":"))))
fb7933a3 5741
cfb5c0db
MA
5742;; ------------------------------------------------------------
5743;; -- Communication with external shell --
5744;; ------------------------------------------------------------
fb7933a3 5745
00d6fd04 5746(defun tramp-find-file-exists-command (vec)
fb7933a3
KG
5747 "Find a command on the remote host for checking if a file exists.
5748Here, we are looking for a command which has zero exit status if the
5749file exists and nonzero exit status otherwise."
00d6fd04 5750 (let ((existing "/")
fb7933a3 5751 (nonexisting
00d6fd04
MA
5752 (tramp-shell-quote-argument "/ this file does not exist "))
5753 result)
fb7933a3
KG
5754 ;; The algorithm is as follows: we try a list of several commands.
5755 ;; For each command, we first run `$cmd /' -- this should return
5756 ;; true, as the root directory always exists. And then we run
00d6fd04 5757 ;; `$cmd /this\ file\ does\ not\ exist ', hoping that the file indeed
fb7933a3
KG
5758 ;; does not exist. This should return false. We use the first
5759 ;; command we find that seems to work.
5760 ;; The list of commands to try is as follows:
00d6fd04
MA
5761 ;; `ls -d' This works on most systems, but NetBSD 1.4
5762 ;; has a bug: `ls' always returns zero exit
5763 ;; status, even for files which don't exist.
5764 ;; `test -e' Some Bourne shells have a `test' builtin
5765 ;; which does not know the `-e' option.
5766 ;; `/bin/test -e' For those, the `test' binary on disk normally
5767 ;; provides the option. Alas, the binary
5768 ;; is sometimes `/bin/test' and sometimes it's
5769 ;; `/usr/bin/test'.
5770 ;; `/usr/bin/test -e' In case `/bin/test' does not exist.
fb7933a3 5771 (unless (or
00d6fd04
MA
5772 (and (setq result (format "%s -e" (tramp-get-test-command vec)))
5773 (zerop (tramp-send-command-and-check
5774 vec (format "%s %s" result existing)))
5775 (not (zerop (tramp-send-command-and-check
5776 vec (format "%s %s" result nonexisting)))))
5777 (and (setq result "/bin/test -e")
5778 (zerop (tramp-send-command-and-check
5779 vec (format "%s %s" result existing)))
5780 (not (zerop (tramp-send-command-and-check
5781 vec (format "%s %s" result nonexisting)))))
5782 (and (setq result "/usr/bin/test -e")
5783 (zerop (tramp-send-command-and-check
5784 vec (format "%s %s" result existing)))
5785 (not (zerop (tramp-send-command-and-check
5786 vec (format "%s %s" result nonexisting)))))
5787 (and (setq result (format "%s -d" (tramp-get-ls-command vec)))
5788 (zerop (tramp-send-command-and-check
5789 vec (format "%s %s" result existing)))
5790 (not (zerop (tramp-send-command-and-check
5791 vec (format "%s %s" result nonexisting))))))
5792 (tramp-error
5793 vec 'file-error "Couldn't find command to check if file exists"))
5794 result))
bf247b6e 5795
fb7933a3 5796;; CCC test ksh or bash found for tilde expansion?
00d6fd04
MA
5797(defun tramp-find-shell (vec)
5798 "Opens a shell on the remote host which groks tilde expansion."
5799 (unless (tramp-get-connection-property vec "remote-shell" nil)
5800 (let (shell)
5801 (with-current-buffer (tramp-get-buffer vec)
7e780ff1 5802 (tramp-send-command vec "echo ~root" t)
00d6fd04
MA
5803 (cond
5804 ((string-match "^~root$" (buffer-string))
5805 (setq shell
f84638eb
MA
5806 (or (tramp-find-executable
5807 vec "bash" (tramp-get-remote-path vec) t)
5808 (tramp-find-executable
5809 vec "ksh" (tramp-get-remote-path vec) t)))
00d6fd04
MA
5810 (unless shell
5811 (tramp-error
5812 vec 'file-error
5813 "Couldn't find a shell which groks tilde expansion"))
5814 ;; Find arguments for this shell.
5815 (let ((alist tramp-sh-extra-args)
5816 item extra-args)
5817 (while (and alist (null extra-args))
5818 (setq item (pop alist))
5819 (when (string-match (car item) shell)
5820 (setq extra-args (cdr item))))
5821 (when extra-args (setq shell (concat shell " " extra-args))))
5822 (tramp-message
5823 vec 5 "Starting remote shell `%s' for tilde expansion..." shell)
a4aeb9a4
MA
5824 (let ((tramp-end-of-output "$ "))
5825 (tramp-send-command
b08104a0 5826 vec
70c11b0b
MA
5827 (format "PROMPT_COMMAND='' PS1=%s PS2='' PS3='' exec %s"
5828 (shell-quote-argument tramp-end-of-output) shell)
b08104a0 5829 t))
a0a5183a 5830 ;; Setting prompts.
00d6fd04 5831 (tramp-message vec 5 "Setting remote shell prompt...")
70c11b0b
MA
5832 (tramp-send-command
5833 vec (format "PS1=%s" (shell-quote-argument tramp-end-of-output)) t)
9fa0d3aa
MA
5834 (tramp-send-command vec "PS2=''" t)
5835 (tramp-send-command vec "PS3=''" t)
5836 (tramp-send-command vec "PROMPT_COMMAND=''" t)
00d6fd04 5837 (tramp-message vec 5 "Setting remote shell prompt...done"))
a0a5183a 5838
00d6fd04
MA
5839 (t (tramp-message
5840 vec 5 "Remote `%s' groks tilde expansion, good"
5841 (tramp-get-method-parameter
5842 (tramp-file-name-method vec) 'tramp-remote-sh))
5843 (tramp-set-connection-property
5844 vec "remote-shell"
5845 (tramp-get-method-parameter
5846 (tramp-file-name-method vec) 'tramp-remote-sh))))))))
fb7933a3 5847
bf247b6e
KS
5848;; ------------------------------------------------------------
5849;; -- Functions for establishing connection --
5850;; ------------------------------------------------------------
fb7933a3 5851
ac474af1
KG
5852;; The following functions are actions to be taken when seeing certain
5853;; prompts from the remote host. See the variable
5854;; `tramp-actions-before-shell' for usage of these functions.
5855
00d6fd04 5856(defun tramp-action-login (proc vec)
ac474af1 5857 "Send the login name."
00d6fd04
MA
5858 (when (not (stringp tramp-current-user))
5859 (save-window-excursion
5860 (let ((enable-recursive-minibuffers t))
5861 (pop-to-buffer (tramp-get-connection-buffer vec))
5862 (setq tramp-current-user (read-string (match-string 0))))))
5863 (tramp-message vec 3 "Sending login name `%s'" tramp-current-user)
5864 (with-current-buffer (tramp-get-connection-buffer vec)
5865 (tramp-message vec 6 "\n%s" (buffer-string)))
5866 (tramp-send-string vec tramp-current-user))
5867
5868(defun tramp-action-password (proc vec)
ac474af1 5869 "Query the user for a password."
70c11b0b
MA
5870 (with-current-buffer (process-buffer proc)
5871 (tramp-check-for-regexp proc tramp-password-prompt-regexp)
5872 (tramp-message vec 3 "Sending %s" (match-string 1)))
00d6fd04
MA
5873 (tramp-enter-password proc))
5874
5875(defun tramp-action-succeed (proc vec)
ac474af1 5876 "Signal success in finding shell prompt."
ac474af1
KG
5877 (throw 'tramp-action 'ok))
5878
00d6fd04 5879(defun tramp-action-permission-denied (proc vec)
ac474af1 5880 "Signal permission denied."
00d6fd04 5881 (kill-process proc)
ac474af1
KG
5882 (throw 'tramp-action 'permission-denied))
5883
00d6fd04 5884(defun tramp-action-yesno (proc vec)
3cdaec13
KG
5885 "Ask the user for confirmation using `yes-or-no-p'.
5886Send \"yes\" to remote process on confirmation, abort otherwise.
5887See also `tramp-action-yn'."
ac474af1 5888 (save-window-excursion
00d6fd04
MA
5889 (let ((enable-recursive-minibuffers t))
5890 (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec)))
5891 (unless (yes-or-no-p (match-string 0))
5892 (kill-process proc)
5893 (throw 'tramp-action 'permission-denied))
5894 (with-current-buffer (tramp-get-connection-buffer vec)
5895 (tramp-message vec 6 "\n%s" (buffer-string)))
5896 (tramp-send-string vec "yes"))))
5897
5898(defun tramp-action-yn (proc vec)
3cdaec13
KG
5899 "Ask the user for confirmation using `y-or-n-p'.
5900Send \"y\" to remote process on confirmation, abort otherwise.
5901See also `tramp-action-yesno'."
5902 (save-window-excursion
00d6fd04
MA
5903 (let ((enable-recursive-minibuffers t))
5904 (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec)))
5905 (unless (y-or-n-p (match-string 0))
5906 (kill-process proc)
5907 (throw 'tramp-action 'permission-denied))
5908 (with-current-buffer (tramp-get-connection-buffer vec)
5909 (tramp-message vec 6 "\n%s" (buffer-string)))
5910 (tramp-send-string vec "y"))))
5911
5912(defun tramp-action-terminal (proc vec)
487f4fb7
KG
5913 "Tell the remote host which terminal type to use.
5914The terminal type can be configured with `tramp-terminal-type'."
00d6fd04 5915 (tramp-message vec 5 "Setting `%s' as terminal type." tramp-terminal-type)
7e780ff1
MA
5916 (with-current-buffer (tramp-get-connection-buffer vec)
5917 (tramp-message vec 6 "\n%s" (buffer-string)))
00d6fd04 5918 (tramp-send-string vec tramp-terminal-type))
487f4fb7 5919
00d6fd04 5920(defun tramp-action-process-alive (proc vec)
19a87064 5921 "Check whether a process has finished."
00d6fd04 5922 (unless (memq (process-status proc) '(run open))
19a87064
MA
5923 (throw 'tramp-action 'process-died)))
5924
00d6fd04 5925(defun tramp-action-out-of-band (proc vec)
38c65fca 5926 "Check whether an out-of-band copy has finished."
00d6fd04
MA
5927 (cond ((and (memq (process-status proc) '(stop exit))
5928 (zerop (process-exit-status proc)))
5929 (tramp-message vec 3 "Process has finished.")
38c65fca 5930 (throw 'tramp-action 'ok))
00d6fd04
MA
5931 ((or (and (memq (process-status proc) '(stop exit))
5932 (not (zerop (process-exit-status proc))))
5933 (memq (process-status proc) '(signal)))
01917a18
MA
5934 ;; `scp' could have copied correctly, but set modes could have failed.
5935 ;; This can be ignored.
00d6fd04
MA
5936 (with-current-buffer (process-buffer proc)
5937 (goto-char (point-min))
5938 (if (re-search-forward tramp-operation-not-permitted-regexp nil t)
5939 (progn
5940 (tramp-message vec 5 "'set mode' error ignored.")
5941 (tramp-message vec 3 "Process has finished.")
5942 (throw 'tramp-action 'ok))
5943 (tramp-message vec 3 "Process has died.")
5944 (throw 'tramp-action 'process-died))))
38c65fca
KG
5945 (t nil)))
5946
ac474af1
KG
5947;; Functions for processing the actions.
5948
00d6fd04 5949(defun tramp-process-one-action (proc vec actions)
ac474af1 5950 "Wait for output from the shell and perform one action."
00d6fd04 5951 (let (found todo item pattern action)
e6466697 5952 (while (not found)
00d6fd04
MA
5953 ;; Reread output once all actions have been performed.
5954 ;; Obviously, the output was not complete.
5955 (tramp-accept-process-output proc 1)
e6466697
MA
5956 (setq todo actions)
5957 (while todo
e6466697 5958 (setq item (pop todo))
95d610cb 5959 (setq pattern (format "\\(%s\\)\\'" (symbol-value (nth 0 item))))
e6466697 5960 (setq action (nth 1 item))
00d6fd04
MA
5961 (tramp-message
5962 vec 5 "Looking for regexp \"%s\" from remote shell" pattern)
5963 (when (tramp-check-for-regexp proc pattern)
5964 (tramp-message vec 5 "Call `%s'" (symbol-name action))
5965 (setq found (funcall action proc vec)))))
e6466697
MA
5966 found))
5967
00d6fd04 5968(defun tramp-process-actions (proc vec actions &optional timeout)
e6466697 5969 "Perform actions until success or TIMEOUT."
5c7043a2
MA
5970 ;; Enable auth-sorce and password-cache.
5971 (tramp-set-connection-property proc "first-password-request" t)
ac474af1
KG
5972 (let (exit)
5973 (while (not exit)
00d6fd04 5974 (tramp-message proc 3 "Waiting for prompts from remote shell")
ac474af1
KG
5975 (setq exit
5976 (catch 'tramp-action
e6466697
MA
5977 (if timeout
5978 (with-timeout (timeout)
00d6fd04
MA
5979 (tramp-process-one-action proc vec actions))
5980 (tramp-process-one-action proc vec actions)))))
5981 (with-current-buffer (tramp-get-connection-buffer vec)
5982 (tramp-message vec 6 "\n%s" (buffer-string)))
ac474af1 5983 (unless (eq exit 'ok)
9c13938d 5984 (tramp-clear-passwd vec)
00d6fd04
MA
5985 (tramp-error-with-buffer
5986 nil vec 'file-error
5987 (cond
5988 ((eq exit 'permission-denied) "Permission denied")
5989 ((eq exit 'process-died) "Process died")
5990 (t "Login failed"))))))
fb7933a3
KG
5991
5992;; Utility functions.
5993
00d6fd04 5994(defun tramp-accept-process-output (&optional proc timeout timeout-msecs)
d2a2c17f
MA
5995 "Like `accept-process-output' for Tramp processes.
5996This is needed in order to hide `last-coding-system-used', which is set
5997for process communication also."
00d6fd04
MA
5998 (with-current-buffer (process-buffer proc)
5999 (tramp-message proc 10 "%s %s" proc (process-status proc))
6000 (let (buffer-read-only last-coding-system-used)
6001 ;; Under Windows XP, accept-process-output doesn't return
6002 ;; sometimes. So we add an additional timeout.
6003 (with-timeout ((or timeout 1))
6004 (accept-process-output proc timeout timeout-msecs)))
6005 (tramp-message proc 10 "\n%s" (buffer-string))))
6006
6007(defun tramp-check-for-regexp (proc regexp)
6008 "Check whether REGEXP is contained in process buffer of PROC.
6009Erase echoed commands if exists."
6010 (with-current-buffer (process-buffer proc)
6011 (goto-char (point-min))
674da028 6012
00d6fd04
MA
6013 ;; Check whether we need to remove echo output.
6014 (when (and (tramp-get-connection-property proc "check-remote-echo" nil)
6015 (re-search-forward tramp-echoed-echo-mark-regexp nil t))
6016 (let ((begin (match-beginning 0)))
6017 (when (re-search-forward tramp-echoed-echo-mark-regexp nil t)
6018 ;; Discard echo from remote output.
6019 (tramp-set-connection-property proc "check-remote-echo" nil)
6020 (tramp-message proc 5 "echo-mark found")
6021 (forward-line)
6022 (delete-region begin (point))
6023 (goto-char (point-min)))))
674da028 6024
70c11b0b
MA
6025 (when (not (tramp-get-connection-property proc "check-remote-echo" nil))
6026 ;; No echo to be handled, now we can look for the regexp.
674da028 6027 (goto-char (point-min))
00d6fd04 6028 (re-search-forward regexp nil t))))
d2a2c17f 6029
fb7933a3
KG
6030(defun tramp-wait-for-regexp (proc timeout regexp)
6031 "Wait for a REGEXP to appear from process PROC within TIMEOUT seconds.
6032Expects the output of PROC to be sent to the current buffer. Returns
6033the string that matched, or nil. Waits indefinitely if TIMEOUT is
6034nil."
00d6fd04
MA
6035 (with-current-buffer (process-buffer proc)
6036 (let ((found (tramp-check-for-regexp proc regexp))
6037 (start-time (current-time)))
6038 (cond (timeout
6039 ;; Work around a bug in XEmacs 21, where the timeout
6040 ;; expires faster than it should. This degenerates
6041 ;; to polling for buggy XEmacsen, but oh, well.
6042 (while (and (not found)
6043 (< (tramp-time-diff (current-time) start-time)
6044 timeout))
6045 (with-timeout (timeout)
6046 (while (not found)
6047 (tramp-accept-process-output proc 1)
6048 (unless (memq (process-status proc) '(run open))
6049 (tramp-error-with-buffer
6050 nil proc 'file-error "Process has died"))
6051 (setq found (tramp-check-for-regexp proc regexp))))))
6052 (t
6053 (while (not found)
6054 (tramp-accept-process-output proc 1)
6055 (unless (memq (process-status proc) '(run open))
6056 (tramp-error-with-buffer
6057 nil proc 'file-error "Process has died"))
6058 (setq found (tramp-check-for-regexp proc regexp)))))
6059 (tramp-message proc 6 "\n%s" (buffer-string))
fb7933a3 6060 (when (not found)
00d6fd04
MA
6061 (if timeout
6062 (tramp-error
6063 proc 'file-error "[[Regexp `%s' not found in %d secs]]"
6064 regexp timeout)
6065 (tramp-error proc 'file-error "[[Regexp `%s' not found]]" regexp)))
6066 found)))
fb7933a3 6067
b25a52cc
KG
6068(defun tramp-barf-if-no-shell-prompt (proc timeout &rest error-args)
6069 "Wait for shell prompt and barf if none appears.
6070Looks at process PROC to see if a shell prompt appears in TIMEOUT
6071seconds. If not, it produces an error message with the given ERROR-ARGS."
7e780ff1
MA
6072 (unless
6073 (tramp-wait-for-regexp
6074 proc timeout
6075 (format
6076 "\\(%s\\|%s\\)\\'" shell-prompt-pattern tramp-shell-prompt-pattern))
00d6fd04
MA
6077 (apply 'tramp-error-with-buffer nil proc 'file-error error-args)))
6078
7e780ff1
MA
6079;; We don't call `tramp-send-string' in order to hide the password
6080;; from the debug buffer, and because end-of-line handling of the
6081;; string.
6082(defun tramp-enter-password (proc)
00d6fd04
MA
6083 "Prompt for a password and send it to the remote end."
6084 (process-send-string
7e780ff1
MA
6085 proc (concat (tramp-read-passwd proc)
6086 (or (tramp-get-method-parameter
6087 tramp-current-method
6088 'tramp-password-end-of-line)
6089 tramp-default-password-end-of-line))))
00d6fd04
MA
6090
6091(defun tramp-open-connection-setup-interactive-shell (proc vec)
fb7933a3 6092 "Set up an interactive shell.
00d6fd04
MA
6093Mainly sets the prompt and the echo correctly. PROC is the shell
6094process to set up. VEC specifies the connection."
a4aeb9a4 6095 (let ((tramp-end-of-output "$ "))
8950769a
MA
6096 ;; It is useful to set the prompt in the following command because
6097 ;; some people have a setting for $PS1 which /bin/sh doesn't know
6098 ;; about and thus /bin/sh will display a strange prompt. For
6099 ;; example, if $PS1 has "${CWD}" in the value, then ksh will
6100 ;; display the current working directory but /bin/sh will display
6101 ;; a dollar sign. The following command line sets $PS1 to a sane
6102 ;; value, and works under Bourne-ish shells as well as csh-like
6103 ;; shells. Daniel Pittman reports that the unusual positioning of
6104 ;; the single quotes makes it work under `rc', too. We also unset
6105 ;; the variable $ENV because that is read by some sh
6106 ;; implementations (eg, bash when called as sh) on startup; this
6107 ;; way, we avoid the startup file clobbering $PS1. $PROMP_COMMAND
6108 ;; is another way to set the prompt in /bin/bash, it must be
6109 ;; discarded as well.
a4aeb9a4
MA
6110 (tramp-send-command
6111 vec
6112 (format
70c11b0b
MA
6113 "exec env ENV='' PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s"
6114 (shell-quote-argument tramp-end-of-output)
a4aeb9a4
MA
6115 (tramp-get-method-parameter
6116 (tramp-file-name-method vec) 'tramp-remote-sh))
8950769a
MA
6117 t)
6118
6119 ;; Disable echo.
6120 (tramp-message vec 5 "Setting up remote shell environment")
6121 (tramp-send-command vec "stty -inlcr -echo kill '^U' erase '^H'" t)
6122 ;; Check whether the echo has really been disabled. Some
6123 ;; implementations, like busybox of embedded GNU/Linux, don't
6124 ;; support disabling.
6125 (tramp-send-command vec "echo foo" t)
6126 (with-current-buffer (process-buffer proc)
6127 (goto-char (point-min))
6128 (when (looking-at "echo foo")
6129 (tramp-set-connection-property proc "remote-echo" t)
6130 (tramp-message vec 5 "Remote echo still on. Ok.")
6131 ;; Make sure backspaces and their echo are enabled and no line
6132 ;; width magic interferes with them.
6133 (tramp-send-command vec "stty icanon erase ^H cols 32767" t))))
e42c6bbc 6134
7e780ff1 6135 (tramp-message vec 5 "Setting shell prompt")
70c11b0b
MA
6136 (tramp-send-command
6137 vec (format "PS1=%s" (shell-quote-argument tramp-end-of-output)) t)
9fa0d3aa
MA
6138 (tramp-send-command vec "PS2=''" t)
6139 (tramp-send-command vec "PS3=''" t)
6140 (tramp-send-command vec "PROMPT_COMMAND=''" t)
e42c6bbc 6141
fb7933a3
KG
6142 ;; Try to set up the coding system correctly.
6143 ;; CCC this can't be the right way to do it. Hm.
00d6fd04 6144 (tramp-message vec 5 "Determining coding system")
7e780ff1 6145 (tramp-send-command vec "echo foo ; echo bar" t)
00d6fd04 6146 (with-current-buffer (process-buffer proc)
fb7933a3
KG
6147 (goto-char (point-min))
6148 (if (featurep 'mule)
00d6fd04
MA
6149 ;; Use MULE to select the right EOL convention for communicating
6150 ;; with the process.
311dd93f 6151 (let* ((cs (or (funcall (symbol-function 'process-coding-system) proc)
00d6fd04
MA
6152 (cons 'undecided 'undecided)))
6153 cs-decode cs-encode)
6154 (when (symbolp cs) (setq cs (cons cs cs)))
6155 (setq cs-decode (car cs))
6156 (setq cs-encode (cdr cs))
6157 (unless cs-decode (setq cs-decode 'undecided))
6158 (unless cs-encode (setq cs-encode 'undecided))
6159 (setq cs-encode (tramp-coding-system-change-eol-conversion
6160 cs-encode 'unix))
6161 (when (search-forward "\r" nil t)
6162 (setq cs-decode (tramp-coding-system-change-eol-conversion
6163 cs-decode 'dos)))
311dd93f 6164 (funcall (symbol-function 'set-buffer-process-coding-system)
70c11b0b
MA
6165 cs-decode cs-encode)
6166 (tramp-message
6167 vec 5 "Setting coding system to `%s' and `%s'" cs-decode cs-encode))
fb7933a3
KG
6168 ;; Look for ^M and do something useful if found.
6169 (when (search-forward "\r" nil t)
00d6fd04
MA
6170 ;; We have found a ^M but cannot frob the process coding system
6171 ;; because we're running on a non-MULE Emacs. Let's try
6172 ;; stty, instead.
7e780ff1
MA
6173 (tramp-send-command vec "stty -onlcr" t))))
6174 (tramp-send-command vec "set +o vi +o emacs" t)
e42c6bbc
MA
6175
6176 ;; Check whether the output of "uname -sr" has been changed. If
6177 ;; yes, this is a strong indication that we must expire all
d8ac123e
MA
6178 ;; connection properties. We start again with
6179 ;; `tramp-maybe-open-connection', it will be catched there.
e42c6bbc
MA
6180 (tramp-message vec 5 "Checking system information")
6181 (let ((old-uname (tramp-get-connection-property vec "uname" nil))
6182 (new-uname
6183 (tramp-set-connection-property
6184 vec "uname"
6185 (tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\""))))
6186 (when (and (stringp old-uname) (not (string-equal old-uname new-uname)))
d8ac123e
MA
6187 (with-current-buffer (tramp-get-debug-buffer vec)
6188 ;; Keep the debug buffer
2296b54d
MA
6189 (rename-buffer
6190 (generate-new-buffer-name tramp-temp-buffer-name) 'unique)
d8ac123e
MA
6191 (funcall (symbol-function 'tramp-cleanup-connection) vec)
6192 (if (= (point-min) (point-max))
6193 (kill-buffer nil)
6194 (rename-buffer (tramp-debug-buffer-name vec) 'unique))
6195 ;; We call `tramp-get-buffer' in order to keep the debug buffer.
6196 (tramp-get-buffer vec)
6197 (tramp-message
6198 vec 3
6199 "Connection reset, because remote host changed from `%s' to `%s'"
6200 old-uname new-uname)
6201 (throw 'uname-changed (tramp-maybe-open-connection vec)))))
e42c6bbc
MA
6202
6203 ;; Check whether the remote host suffers from buggy
6204 ;; `send-process-string'. This is known for FreeBSD (see comment in
6205 ;; `send_process', file process.c). I've tested sending 624 bytes
6206 ;; successfully, sending 625 bytes failed. Emacs makes a hack when
6207 ;; this host type is detected locally. It cannot handle remote
6208 ;; hosts, though.
00d6fd04
MA
6209 (with-connection-property proc "chunksize"
6210 (cond
6211 ((and (integerp tramp-chunksize) (> tramp-chunksize 0))
6212 tramp-chunksize)
6213 (t
6214 (tramp-message
6215 vec 5 "Checking remote host type for `send-process-string' bug")
6216 (if (string-match
e42c6bbc 6217 "^FreeBSD" (tramp-get-connection-property vec "uname" ""))
00d6fd04 6218 500 0))))
e42c6bbc 6219
00d6fd04
MA
6220 ;; Set remote PATH variable.
6221 (tramp-set-remote-path vec)
e42c6bbc 6222
fb7933a3
KG
6223 ;; Search for a good shell before searching for a command which
6224 ;; checks if a file exists. This is done because Tramp wants to use
6225 ;; "test foo; echo $?" to check if various conditions hold, and
6226 ;; there are buggy /bin/sh implementations which don't execute the
6227 ;; "echo $?" part if the "test" part has an error. In particular,
6228 ;; the Solaris /bin/sh is a problem. I'm betting that all systems
6229 ;; with buggy /bin/sh implementations will have a working bash or
6230 ;; ksh. Whee...
00d6fd04 6231 (tramp-find-shell vec)
e42c6bbc 6232
00d6fd04 6233 ;; Disable unexpected output.
7e780ff1 6234 (tramp-send-command vec "mesg n; biff n" t)
e42c6bbc 6235
00d6fd04
MA
6236 ;; Set the environment.
6237 (tramp-message vec 5 "Setting default environment")
661aaece
MA
6238
6239 ;; On OpenSolaris, there is a bug when HISTFILE is changed in place
6240 ;; <http://bugs.opensolaris.org/view_bug.do?bug_id=6834184>. We
6241 ;; apply the workaround.
6242 (if (string-equal (tramp-get-connection-property vec "uname" "") "SunOS 5.11")
6243 (tramp-send-command vec "unset HISTFILE"))
6244
00d6fd04
MA
6245 (let ((env (copy-sequence tramp-remote-process-environment))
6246 unset item)
6247 (while env
70c11b0b 6248 (setq item (tramp-compat-split-string (car env) "="))
00d6fd04
MA
6249 (if (and (stringp (cadr item)) (not (string-equal (cadr item) "")))
6250 (tramp-send-command
7e780ff1 6251 vec (format "%s=%s; export %s" (car item) (cadr item) (car item)) t)
00d6fd04
MA
6252 (push (car item) unset))
6253 (setq env (cdr env)))
6254 (when unset
fb7933a3 6255 (tramp-send-command
7e780ff1 6256 vec (format "unset %s" (mapconcat 'identity unset " "))))) t)
fb7933a3 6257
ac474af1
KG
6258;; CCC: We should either implement a Perl version of base64 encoding
6259;; and decoding. Then we just use that in the last item. The other
6260;; alternative is to use the Perl version of UU encoding. But then
6261;; we need a Lisp version of uuencode.
16674e4f
KG
6262;;
6263;; Old text from documentation of tramp-methods:
6264;; Using a uuencode/uudecode inline method is discouraged, please use one
6265;; of the base64 methods instead since base64 encoding is much more
6266;; reliable and the commands are more standardized between the different
6267;; Unix versions. But if you can't use base64 for some reason, please
6268;; note that the default uudecode command does not work well for some
6269;; Unices, in particular AIX and Irix. For AIX, you might want to use
6270;; the following command for uudecode:
6271;;
6272;; sed '/^begin/d;/^[` ]$/d;/^end/d' | iconv -f uucode -t ISO8859-1
6273;;
6274;; For Irix, no solution is known yet.
6275
00d6fd04
MA
6276(defconst tramp-local-coding-commands
6277 '((b64 base64-encode-region base64-decode-region)
6278 (uu tramp-uuencode-region uudecode-decode-region)
6279 (pack
6280 "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
6281 "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"))
6282 "List of local coding commands for inline transfer.
16674e4f
KG
6283Each item is a list that looks like this:
6284
00d6fd04 6285\(FORMAT ENCODING DECODING)
ac474af1 6286
00d6fd04
MA
6287FORMAT is symbol describing the encoding/decoding format. It can be
6288`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
ac474af1 6289
00d6fd04
MA
6290ENCODING and DECODING can be strings, giving commands, or symbols,
6291giving functions. If they are strings, then they can contain
16674e4f
KG
6292the \"%s\" format specifier. If that specifier is present, the input
6293filename will be put into the command line at that spot. If the
6294specifier is not present, the input should be read from standard
6295input.
ac474af1 6296
16674e4f
KG
6297If they are functions, they will be called with two arguments, start
6298and end of region, and are expected to replace the region contents
6299with the encoded or decoded results, respectively.")
ac474af1 6300
00d6fd04 6301(defconst tramp-remote-coding-commands
3dc847a3
MA
6302 '((b64 "base64" "base64 -d")
6303 (b64 "mimencode -b" "mimencode -u -b")
00d6fd04
MA
6304 (b64 "mmencode -b" "mmencode -u -b")
6305 (b64 "recode data..base64" "recode base64..data")
6306 (b64 tramp-perl-encode-with-module tramp-perl-decode-with-module)
6307 (b64 tramp-perl-encode tramp-perl-decode)
6308 (uu "uuencode xxx" "uudecode -o /dev/stdout")
6309 (uu "uuencode xxx" "uudecode -o -")
6310 (uu "uuencode xxx" "uudecode -p")
6311 (uu "uuencode xxx" tramp-uudecode)
6312 (pack
6313 "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
6314 "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"))
6315 "List of remote coding commands for inline transfer.
6316Each item is a list that looks like this:
6317
6318\(FORMAT ENCODING DECODING)
6319
6320FORMAT is symbol describing the encoding/decoding format. It can be
6321`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
6322
6323ENCODING and DECODING can be strings, giving commands, or symbols,
6324giving variables. If they are strings, then they can contain
6325the \"%s\" format specifier. If that specifier is present, the input
6326filename will be put into the command line at that spot. If the
6327specifier is not present, the input should be read from standard
6328input.
6329
6330If they are variables, this variable is a string containing a Perl
6331implementation for this functionality. This Perl program will be transferred
6332to the remote host, and it is avalible as shell function with the same name.")
6333
6334(defun tramp-find-inline-encoding (vec)
ac474af1 6335 "Find an inline transfer encoding that works.
00d6fd04
MA
6336Goes through the list `tramp-local-coding-commands' and
6337`tramp-remote-coding-commands'."
6338 (save-excursion
6339 (let ((local-commands tramp-local-coding-commands)
6340 (magic "xyzzy")
6341 loc-enc loc-dec rem-enc rem-dec litem ritem found)
6342 (while (and local-commands (not found))
6343 (setq litem (pop local-commands))
6344 (catch 'wont-work-local
6345 (let ((format (nth 0 litem))
6346 (remote-commands tramp-remote-coding-commands))
6347 (setq loc-enc (nth 1 litem))
6348 (setq loc-dec (nth 2 litem))
6349 ;; If the local encoder or decoder is a string, the
6350 ;; corresponding command has to work locally.
6351 (if (not (stringp loc-enc))
6352 (tramp-message
6353 vec 5 "Checking local encoding function `%s'" loc-enc)
6354 (tramp-message
6355 vec 5 "Checking local encoding command `%s' for sanity" loc-enc)
6356 (unless (zerop (tramp-call-local-coding-command
6357 loc-enc nil nil))
6358 (throw 'wont-work-local nil)))
6359 (if (not (stringp loc-dec))
6360 (tramp-message
6361 vec 5 "Checking local decoding function `%s'" loc-dec)
6362 (tramp-message
6363 vec 5 "Checking local decoding command `%s' for sanity" loc-dec)
6364 (unless (zerop (tramp-call-local-coding-command
6365 loc-dec nil nil))
6366 (throw 'wont-work-local nil)))
6367 ;; Search for remote coding commands with the same format
6368 (while (and remote-commands (not found))
6369 (setq ritem (pop remote-commands))
6370 (catch 'wont-work-remote
6371 (when (equal format (nth 0 ritem))
6372 (setq rem-enc (nth 1 ritem))
6373 (setq rem-dec (nth 2 ritem))
6374 ;; Check if remote encoding and decoding commands can be
6375 ;; called remotely with null input and output. This makes
6376 ;; sure there are no syntax errors and the command is really
6377 ;; found. Note that we do not redirect stdout to /dev/null,
6378 ;; for two reasons: when checking the decoding command, we
6379 ;; actually check the output it gives. And also, when
6380 ;; redirecting "mimencode" output to /dev/null, then as root
6381 ;; it might change the permissions of /dev/null!
6382 (when (not (stringp rem-enc))
6383 (let ((name (symbol-name rem-enc)))
6384 (while (string-match (regexp-quote "-") name)
6385 (setq name (replace-match "_" nil t name)))
6386 (tramp-maybe-send-script vec (symbol-value rem-enc) name)
6387 (setq rem-enc name)))
6388 (tramp-message
6389 vec 5
6390 "Checking remote encoding command `%s' for sanity" rem-enc)
6391 (unless (zerop (tramp-send-command-and-check
6392 vec (format "%s </dev/null" rem-enc) t))
6393 (throw 'wont-work-remote nil))
6394
6395 (when (not (stringp rem-dec))
6396 (let ((name (symbol-name rem-dec)))
6397 (while (string-match (regexp-quote "-") name)
6398 (setq name (replace-match "_" nil t name)))
6399 (tramp-maybe-send-script vec (symbol-value rem-dec) name)
6400 (setq rem-dec name)))
6401 (tramp-message
6402 vec 5
6403 "Checking remote decoding command `%s' for sanity" rem-dec)
6404 (unless (zerop (tramp-send-command-and-check
6405 vec
6406 (format "echo %s | %s | %s"
6407 magic rem-enc rem-dec) t))
6408 (throw 'wont-work-remote nil))
6409
6410 (with-current-buffer (tramp-get-buffer vec)
6411 (goto-char (point-min))
6412 (unless (looking-at (regexp-quote magic))
6413 (throw 'wont-work-remote nil)))
6414
6415 ;; `rem-enc' and `rem-dec' could be a string meanwhile.
6416 (setq rem-enc (nth 1 ritem))
6417 (setq rem-dec (nth 2 ritem))
6418 (setq found t)))))))
6419
1d7e9a01 6420 ;; Did we find something?
00d6fd04 6421 (unless found
1d7e9a01 6422 (tramp-message vec 2 "Couldn't find an inline transfer encoding"))
00d6fd04
MA
6423
6424 ;; Set connection properties.
6425 (tramp-message vec 5 "Using local encoding `%s'" loc-enc)
6426 (tramp-set-connection-property vec "local-encoding" loc-enc)
6427 (tramp-message vec 5 "Using local decoding `%s'" loc-dec)
6428 (tramp-set-connection-property vec "local-decoding" loc-dec)
6429 (tramp-message vec 5 "Using remote encoding `%s'" rem-enc)
6430 (tramp-set-connection-property vec "remote-encoding" rem-enc)
6431 (tramp-message vec 5 "Using remote decoding `%s'" rem-dec)
6432 (tramp-set-connection-property vec "remote-decoding" rem-dec))))
16674e4f
KG
6433
6434(defun tramp-call-local-coding-command (cmd input output)
6435 "Call the local encoding or decoding command.
6436If CMD contains \"%s\", provide input file INPUT there in command.
6437Otherwise, INPUT is passed via standard input.
6438INPUT can also be nil which means `/dev/null'.
6439OUTPUT can be a string (which specifies a filename), or t (which
6440means standard output and thus the current buffer), or nil (which
6441means discard it)."
a4aeb9a4
MA
6442 (tramp-local-call-process
6443 tramp-encoding-shell
6444 (when (and input (not (string-match "%s" cmd))) input)
6445 (if (eq output t) t nil)
6446 nil
6447 tramp-encoding-command-switch
6448 (concat
6449 (if (string-match "%s" cmd) (format cmd input) cmd)
6450 (if (stringp output) (concat "> " output) ""))))
00d6fd04
MA
6451
6452(defun tramp-compute-multi-hops (vec)
6453 "Expands VEC according to `tramp-default-proxies-alist'.
6454Gateway hops are already opened."
6455 (let ((target-alist `(,vec))
6456 (choices tramp-default-proxies-alist)
6457 item proxy)
6458
6459 ;; Look for proxy hosts to be passed.
6460 (while choices
6461 (setq item (pop choices)
70c11b0b 6462 proxy (eval (nth 2 item)))
00d6fd04
MA
6463 (when (and
6464 ;; host
70c11b0b 6465 (string-match (or (eval (nth 0 item)) "")
00d6fd04
MA
6466 (or (tramp-file-name-host (car target-alist)) ""))
6467 ;; user
70c11b0b 6468 (string-match (or (eval (nth 1 item)) "")
00d6fd04
MA
6469 (or (tramp-file-name-user (car target-alist)) "")))
6470 (if (null proxy)
6471 ;; No more hops needed.
6472 (setq choices nil)
6473 ;; Replace placeholders.
6474 (setq proxy
6475 (format-spec
6476 proxy
6477 `((?u . ,(or (tramp-file-name-user (car target-alist)) ""))
6478 (?h . ,(or (tramp-file-name-host (car target-alist)) "")))))
6479 (with-parsed-tramp-file-name proxy l
6480 ;; Add the hop.
6481 (add-to-list 'target-alist l)
6482 ;; Start next search.
6483 (setq choices tramp-default-proxies-alist)))))
6484
6485 ;; Handle gateways.
8a4438b6
MA
6486 (when (and (boundp 'tramp-gw-tunnel-method)
6487 (string-match (format
6488 "^\\(%s\\|%s\\)$"
6489 (symbol-value 'tramp-gw-tunnel-method)
6490 (symbol-value 'tramp-gw-socks-method))
6491 (tramp-file-name-method (car target-alist))))
00d6fd04
MA
6492 (let ((gw (pop target-alist))
6493 (hop (pop target-alist)))
6494 ;; Is the method prepared for gateways?
6495 (unless (tramp-get-method-parameter
6496 (tramp-file-name-method hop) 'tramp-default-port)
6497 (tramp-error
6498 vec 'file-error
6499 "Method `%s' is not supported for gateway access."
6500 (tramp-file-name-method hop)))
6501 ;; Add default port if needed.
6502 (unless
6503 (string-match
6504 tramp-host-with-port-regexp (tramp-file-name-host hop))
6505 (aset hop 2
6506 (concat
6507 (tramp-file-name-host hop) tramp-prefix-port-format
6508 (number-to-string
6509 (tramp-get-method-parameter
6510 (tramp-file-name-method hop) 'tramp-default-port)))))
6511 ;; Open the gateway connection.
6512 (add-to-list
6513 'target-alist
6514 (vector
6515 (tramp-file-name-method hop) (tramp-file-name-user hop)
9e6ab520 6516 (funcall (symbol-function 'tramp-gw-open-connection) vec gw hop) nil))
00d6fd04
MA
6517 ;; For the password prompt, we need the correct values.
6518 ;; Therefore, we must remember the gateway vector. But we
6519 ;; cannot do it as connection property, because it shouldn't
6520 ;; be persistent. And we have no started process yet either.
6521 (tramp-set-file-property (car target-alist) "" "gateway" hop)))
6522
6523 ;; Foreign and out-of-band methods are not supported for multi-hops.
6524 (when (cdr target-alist)
6525 (setq choices target-alist)
6526 (while choices
6527 (setq item (pop choices))
6528 (when
6529 (or
6530 (not
6531 (tramp-get-method-parameter
6532 (tramp-file-name-method item) 'tramp-login-program))
6533 (tramp-get-method-parameter
6534 (tramp-file-name-method item) 'tramp-copy-program))
6535 (tramp-error
6536 vec 'file-error
6537 "Method `%s' is not supported for multi-hops."
6538 (tramp-file-name-method item)))))
6539
2991e49f
MA
6540 ;; In case the host name is not used for the remote shell
6541 ;; command, the user could be misguided by applying a random
6542 ;; hostname.
6543 (let* ((v (car target-alist))
6544 (method (tramp-file-name-method v))
6545 (host (tramp-file-name-host v)))
6546 (unless
6547 (or
6548 ;; There are multi-hops.
6549 (cdr target-alist)
6550 ;; The host name is used for the remote shell command.
6551 (member
6552 '("%h") (tramp-get-method-parameter method 'tramp-login-args))
6553 ;; The host is local. We cannot use `tramp-local-host-p'
6554 ;; here, because it opens a connection as well.
b96e6899 6555 (string-match tramp-local-host-regexp host))
2991e49f 6556 (tramp-error
42bc9b6d
MA
6557 v 'file-error
6558 "Host `%s' looks like a remote host, `%s' can only use the local host"
6559 host method)))
2991e49f 6560
00d6fd04
MA
6561 ;; Result.
6562 target-alist))
6563
6564(defun tramp-maybe-open-connection (vec)
6565 "Maybe open a connection VEC.
fb7933a3
KG
6566Does not do anything if a connection is already open, but re-opens the
6567connection if a previous connection has died for some reason."
d8ac123e
MA
6568 (catch 'uname-changed
6569 (let ((p (tramp-get-connection-process vec))
6570 (process-environment (copy-sequence process-environment)))
6571
6572 ;; If too much time has passed since last command was sent, look
6573 ;; whether process is still alive. If it isn't, kill it. When
6574 ;; using ssh, it can sometimes happen that the remote end has
6575 ;; hung up but the local ssh client doesn't recognize this until
6576 ;; it tries to send some data to the remote end. So that's why
6577 ;; we try to send a command from time to time, then look again
6578 ;; whether the process is really alive.
6579 (condition-case nil
6580 (when (and (> (tramp-time-diff
6581 (current-time)
6582 (tramp-get-connection-property
6583 p "last-cmd-time" '(0 0 0)))
6584 60)
6585 p (processp p) (memq (process-status p) '(run open)))
6586 (tramp-send-command vec "echo are you awake" t t)
6587 (unless (and (memq (process-status p) '(run open))
6588 (tramp-wait-for-output p 10))
6589 ;; The error will be catched locally.
6590 (tramp-error vec 'file-error "Awake did fail")))
6591 (file-error
6592 (tramp-flush-connection-property vec)
6593 (tramp-flush-connection-property p)
6594 (delete-process p)
6595 (setq p nil)))
6596
6597 ;; New connection must be opened.
6598 (unless (and p (processp p) (memq (process-status p) '(run open)))
6599
6600 ;; We call `tramp-get-buffer' in order to get a debug buffer for
6601 ;; messages from the beginning.
6602 (tramp-get-buffer vec)
6603 (if (zerop (length (tramp-file-name-user vec)))
6604 (tramp-message
6605 vec 3 "Opening connection for %s using %s..."
6606 (tramp-file-name-host vec)
6607 (tramp-file-name-method vec))
00d6fd04 6608 (tramp-message
d8ac123e
MA
6609 vec 3 "Opening connection for %s@%s using %s..."
6610 (tramp-file-name-user vec)
00d6fd04 6611 (tramp-file-name-host vec)
d8ac123e
MA
6612 (tramp-file-name-method vec)))
6613
6614 ;; Start new process.
6615 (when (and p (processp p))
6616 (delete-process p))
6617 (setenv "TERM" tramp-terminal-type)
6618 (setenv "LC_ALL" "C")
6619 (setenv "PROMPT_COMMAND")
6620 (setenv "PS1" "$ ")
6621 (let* ((target-alist (tramp-compute-multi-hops vec))
6622 (process-connection-type tramp-process-connection-type)
6623 (process-adaptive-read-buffering nil)
6624 (coding-system-for-read nil)
6625 ;; This must be done in order to avoid our file name handler.
6626 (p (let ((default-directory
6627 (tramp-compat-temporary-file-directory)))
6628 (start-process
6629 (or (tramp-get-connection-property vec "process-name" nil)
6630 (tramp-buffer-name vec))
6631 (tramp-get-connection-buffer vec)
70c11b0b 6632 tramp-encoding-shell))))
00d6fd04 6633
d8ac123e
MA
6634 (tramp-message
6635 vec 6 "%s" (mapconcat 'identity (process-command p) " "))
6636
6637 ;; Check whether process is alive.
d8ac123e
MA
6638 (tramp-set-process-query-on-exit-flag p nil)
6639 (tramp-message vec 3 "Waiting 60s for local shell to come up...")
6640 (tramp-barf-if-no-shell-prompt
6641 p 60 "Couldn't find local shell prompt %s" tramp-encoding-shell)
6642
6643 ;; Now do all the connections as specified.
6644 (while target-alist
6645 (let* ((hop (car target-alist))
6646 (l-method (tramp-file-name-method hop))
6647 (l-user (tramp-file-name-user hop))
6648 (l-host (tramp-file-name-host hop))
6649 (l-port nil)
6650 (login-program
6651 (tramp-get-method-parameter l-method 'tramp-login-program))
6652 (login-args
6653 (tramp-get-method-parameter l-method 'tramp-login-args))
6654 (gw-args
6655 (tramp-get-method-parameter l-method 'tramp-gw-args))
6656 (gw (tramp-get-file-property hop "" "gateway" nil))
6657 (g-method (and gw (tramp-file-name-method gw)))
6658 (g-user (and gw (tramp-file-name-user gw)))
6659 (g-host (and gw (tramp-file-name-host gw)))
6660 (command login-program)
6661 ;; We don't create the temporary file. In fact, it
6662 ;; is just a prefix for the ControlPath option of
6663 ;; ssh; the real temporary file has another name, and
6664 ;; it is created and protected by ssh. It is also
6665 ;; removed by ssh, when the connection is closed.
6666 (tmpfile
6667 (tramp-set-connection-property
6668 p "temp-file"
6669 (make-temp-name
6670 (expand-file-name
6671 tramp-temp-name-prefix
6672 (tramp-compat-temporary-file-directory)))))
6673 spec)
6674
6675 ;; Add gateway arguments if necessary.
6676 (when (and gw gw-args)
6677 (setq login-args (append login-args gw-args)))
6678
6679 ;; Check for port number. Until now, there's no need
6680 ;; for handling like method, user, host.
6681 (when (string-match tramp-host-with-port-regexp l-host)
6682 (setq l-port (match-string 2 l-host)
6683 l-host (match-string 1 l-host)))
6684
6685 ;; Set variables for computing the prompt for reading
2296b54d 6686 ;; password. They can also be derived from a gateway.
d8ac123e
MA
6687 (setq tramp-current-method (or g-method l-method)
6688 tramp-current-user (or g-user l-user)
6689 tramp-current-host (or g-host l-host))
6690
6691 ;; Replace login-args place holders.
6692 (setq
6693 l-host (or l-host "")
6694 l-user (or l-user "")
6695 l-port (or l-port "")
6696 spec `((?h . ,l-host) (?u . ,l-user) (?p . ,l-port)
6697 (?t . ,tmpfile))
6698 command
6699 (concat
6700 command " "
6701 (mapconcat
6702 '(lambda (x)
6703 (setq x (mapcar '(lambda (y) (format-spec y spec)) x))
6704 (unless (member "" x) (mapconcat 'identity x " ")))
6705 login-args " ")
d8ac123e
MA
6706 ;; Local shell could be a Windows COMSPEC. It doesn't
6707 ;; know the ";" syntax, but we must exit always for
70c11b0b
MA
6708 ;; `start-file-process'. "exec" does not work either.
6709 " && exit || exit"))
d8ac123e
MA
6710
6711 ;; Send the command.
6712 (tramp-message vec 3 "Sending command `%s'" command)
6713 (tramp-send-command vec command t t)
6714 (tramp-process-actions p vec tramp-actions-before-shell 60)
6715 (tramp-message vec 3 "Found remote shell prompt on `%s'" l-host))
6716 ;; Next hop.
6717 (setq target-alist (cdr target-alist)))
6718
6719 ;; Make initial shell settings.
6720 (tramp-open-connection-setup-interactive-shell p vec))))))
00d6fd04
MA
6721
6722(defun tramp-send-command (vec command &optional neveropen nooutput)
6723 "Send the COMMAND to connection VEC.
6724Erases temporary buffer before sending the command. If optional
6725arg NEVEROPEN is non-nil, never try to open the connection. This
6726is meant to be used from `tramp-maybe-open-connection' only. The
6727function waits for output unless NOOUTPUT is set."
6728 (unless neveropen (tramp-maybe-open-connection vec))
6729 (let ((p (tramp-get-connection-process vec)))
8950769a 6730 (when (tramp-get-connection-property p "remote-echo" nil)
00d6fd04
MA
6731 ;; We mark the command string that it can be erased in the output buffer.
6732 (tramp-set-connection-property p "check-remote-echo" t)
6733 (setq command (format "%s%s%s" tramp-echo-mark command tramp-echo-mark)))
6734 (tramp-message vec 6 "%s" command)
6735 (tramp-send-string vec command)
6736 (unless nooutput (tramp-wait-for-output p))))
6737
00d6fd04 6738(defun tramp-wait-for-output (proc &optional timeout)
fb7933a3 6739 "Wait for output from remote rsh command."
00d6fd04 6740 (with-current-buffer (process-buffer proc)
bede3e9f
MA
6741 (let* (;; Initially, `tramp-end-of-output' is "$ ". There might
6742 ;; be leading escape sequences, which must be ignored.
6743 (regexp (format "[^$\n]*%s\r?$" (regexp-quote tramp-end-of-output)))
6744 ;; Sometimes, the commands do not return a newline but a
6745 ;; null byte before the shell prompt, for example "git
6746 ;; ls-files -c -z ...".
6747 (regexp1 (format "\\(^\\|\000\\)%s" regexp))
6748 (found (tramp-wait-for-regexp proc timeout regexp1)))
00d6fd04
MA
6749 (if found
6750 (let (buffer-read-only)
6751 (goto-char (point-max))
0664ff72 6752 (re-search-backward regexp nil t)
00d6fd04
MA
6753 (delete-region (point) (point-max)))
6754 (if timeout
6755 (tramp-error
6756 proc 'file-error
6757 "[[Remote prompt `%s' not found in %d secs]]"
6758 tramp-end-of-output timeout)
6759 (tramp-error
6760 proc 'file-error
6761 "[[Remote prompt `%s' not found]]" tramp-end-of-output)))
6762 ;; Return value is whether end-of-output sentinel was found.
6763 found)))
fb7933a3 6764
00d6fd04 6765(defun tramp-send-command-and-check (vec command &optional subshell)
fb7933a3 6766 "Run COMMAND and check its exit status.
fb7933a3
KG
6767Sends `echo $?' along with the COMMAND for checking the exit status. If
6768COMMAND is nil, just sends `echo $?'. Returns the exit status found.
6769
6770If the optional argument SUBSHELL is non-nil, the command is executed in
6771a subshell, ie surrounded by parentheses."
00d6fd04
MA
6772 (tramp-send-command
6773 vec
6774 (concat (if subshell "( " "")
6775 command
6776 (if command " 2>/dev/null; " "")
6777 "echo tramp_exit_status $?"
6778 (if subshell " )" " ")))
6779 (with-current-buffer (tramp-get-connection-buffer vec)
6780 (goto-char (point-max))
6781 (unless (re-search-backward "tramp_exit_status [0-9]+" nil t)
6782 (tramp-error
6783 vec 'file-error "Couldn't find exit status of `%s'" command))
6784 (skip-chars-forward "^ ")
6785 (prog1
6786 (read (current-buffer))
6787 (let (buffer-read-only) (delete-region (match-beginning 0) (point-max))))))
6788
6789(defun tramp-barf-unless-okay (vec command fmt &rest args)
fb7933a3
KG
6790 "Run COMMAND, check exit status, throw error if exit status not okay.
6791Similar to `tramp-send-command-and-check' but accepts two more arguments
6792FMT and ARGS which are passed to `error'."
00d6fd04
MA
6793 (unless (zerop (tramp-send-command-and-check vec command))
6794 (apply 'tramp-error vec 'file-error fmt args)))
6795
6796(defun tramp-send-command-and-read (vec command)
6797 "Run COMMAND and return the output, which must be a Lisp expression.
6798In case there is no valid Lisp expression, it raises an error"
6799 (tramp-barf-unless-okay vec command "`%s' returns with error" command)
6800 (with-current-buffer (tramp-get-connection-buffer vec)
6801 ;; Read the expression.
6802 (goto-char (point-min))
6803 (condition-case nil
6804 (prog1 (read (current-buffer))
6805 ;; Error handling.
9e6ab520 6806 (when (re-search-forward "\\S-" (tramp-compat-line-end-position) t)
9ce8462a 6807 (error nil)))
00d6fd04
MA
6808 (error (tramp-error
6809 vec 'file-error
6810 "`%s' does not return a valid Lisp expression: `%s'"
6811 command (buffer-string))))))
fb7933a3 6812
7432277c
KG
6813;; It seems that Tru64 Unix does not like it if long strings are sent
6814;; to it in one go. (This happens when sending the Perl
6815;; `file-attributes' implementation, for instance.) Therefore, we
27e813fe 6816;; have this function which sends the string in chunks.
00d6fd04
MA
6817(defun tramp-send-string (vec string)
6818 "Send the STRING via connection VEC.
7432277c
KG
6819
6820The STRING is expected to use Unix line-endings, but the lines sent to
6821the remote host use line-endings as defined in the variable
00d6fd04
MA
6822`tramp-rsh-end-of-line'. The communication buffer is erased before sending."
6823 (let* ((p (tramp-get-connection-process vec))
6824 (chunksize (tramp-get-connection-property p "chunksize" nil)))
6825 (unless p
6826 (tramp-error
6827 vec 'file-error "Can't send string to remote host -- not logged in"))
6828 (tramp-set-connection-property p "last-cmd-time" (current-time))
6829 (tramp-message vec 10 "%s" string)
6830 (with-current-buffer (tramp-get-connection-buffer vec)
6831 ;; Clean up the buffer. We cannot call `erase-buffer' because
6832 ;; narrowing might be in effect.
6833 (let (buffer-read-only) (delete-region (point-min) (point-max)))
27e813fe 6834 ;; Replace "\n" by `tramp-rsh-end-of-line'.
00d6fd04
MA
6835 (setq string
6836 (mapconcat 'identity
70c11b0b 6837 (tramp-compat-split-string string "\n")
00d6fd04
MA
6838 tramp-rsh-end-of-line))
6839 (unless (or (string= string "")
6840 (string-equal (substring string -1) tramp-rsh-end-of-line))
6841 (setq string (concat string tramp-rsh-end-of-line)))
27e813fe 6842 ;; Send the string.
00d6fd04
MA
6843 (if (and chunksize (not (zerop chunksize)))
6844 (let ((pos 0)
6845 (end (length string)))
6846 (while (< pos end)
6847 (tramp-message
6848 vec 10 "Sending chunk from %s to %s"
6849 pos (min (+ pos chunksize) end))
6850 (process-send-string
6851 p (substring string pos (min (+ pos chunksize) end)))
6852 (setq pos (+ pos chunksize))))
6853 (process-send-string p string)))))
fb7933a3
KG
6854
6855(defun tramp-mode-string-to-int (mode-string)
6856 "Converts a ten-letter `drwxrwxrwx'-style mode string into mode bits."
f3c071dd
MA
6857 (let* (case-fold-search
6858 (mode-chars (string-to-vector mode-string))
fb7933a3
KG
6859 (owner-read (aref mode-chars 1))
6860 (owner-write (aref mode-chars 2))
6861 (owner-execute-or-setid (aref mode-chars 3))
6862 (group-read (aref mode-chars 4))
6863 (group-write (aref mode-chars 5))
6864 (group-execute-or-setid (aref mode-chars 6))
6865 (other-read (aref mode-chars 7))
6866 (other-write (aref mode-chars 8))
6867 (other-execute-or-sticky (aref mode-chars 9)))
6868 (save-match-data
6869 (logior
f3c071dd
MA
6870 (cond
6871 ((char-equal owner-read ?r) (tramp-octal-to-decimal "00400"))
6872 ((char-equal owner-read ?-) 0)
6873 (t (error "Second char `%c' must be one of `r-'" owner-read)))
6874 (cond
6875 ((char-equal owner-write ?w) (tramp-octal-to-decimal "00200"))
6876 ((char-equal owner-write ?-) 0)
6877 (t (error "Third char `%c' must be one of `w-'" owner-write)))
6878 (cond
6879 ((char-equal owner-execute-or-setid ?x)
6880 (tramp-octal-to-decimal "00100"))
6881 ((char-equal owner-execute-or-setid ?S)
6882 (tramp-octal-to-decimal "04000"))
6883 ((char-equal owner-execute-or-setid ?s)
6884 (tramp-octal-to-decimal "04100"))
6885 ((char-equal owner-execute-or-setid ?-) 0)
6886 (t (error "Fourth char `%c' must be one of `xsS-'"
6887 owner-execute-or-setid)))
6888 (cond
6889 ((char-equal group-read ?r) (tramp-octal-to-decimal "00040"))
6890 ((char-equal group-read ?-) 0)
6891 (t (error "Fifth char `%c' must be one of `r-'" group-read)))
6892 (cond
6893 ((char-equal group-write ?w) (tramp-octal-to-decimal "00020"))
6894 ((char-equal group-write ?-) 0)
6895 (t (error "Sixth char `%c' must be one of `w-'" group-write)))
6896 (cond
6897 ((char-equal group-execute-or-setid ?x)
6898 (tramp-octal-to-decimal "00010"))
6899 ((char-equal group-execute-or-setid ?S)
6900 (tramp-octal-to-decimal "02000"))
6901 ((char-equal group-execute-or-setid ?s)
6902 (tramp-octal-to-decimal "02010"))
6903 ((char-equal group-execute-or-setid ?-) 0)
6904 (t (error "Seventh char `%c' must be one of `xsS-'"
6905 group-execute-or-setid)))
6906 (cond
6907 ((char-equal other-read ?r)
6908 (tramp-octal-to-decimal "00004"))
6909 ((char-equal other-read ?-) 0)
6910 (t (error "Eighth char `%c' must be one of `r-'" other-read)))
6911 (cond
6912 ((char-equal other-write ?w) (tramp-octal-to-decimal "00002"))
6913 ((char-equal other-write ?-) 0)
fb7933a3 6914 (t (error "Nineth char `%c' must be one of `w-'" other-write)))
f3c071dd
MA
6915 (cond
6916 ((char-equal other-execute-or-sticky ?x)
6917 (tramp-octal-to-decimal "00001"))
6918 ((char-equal other-execute-or-sticky ?T)
6919 (tramp-octal-to-decimal "01000"))
6920 ((char-equal other-execute-or-sticky ?t)
6921 (tramp-octal-to-decimal "01001"))
6922 ((char-equal other-execute-or-sticky ?-) 0)
6923 (t (error "Tenth char `%c' must be one of `xtT-'"
6924 other-execute-or-sticky)))))))
fb7933a3 6925
00d6fd04
MA
6926(defun tramp-convert-file-attributes (vec attr)
6927 "Convert file-attributes ATTR generated by perl script, stat or ls.
c82c5727
LH
6928Convert file mode bits to string and set virtual device number.
6929Return ATTR."
00d6fd04
MA
6930 ;; Convert last access time.
6931 (unless (listp (nth 4 attr))
6932 (setcar (nthcdr 4 attr)
6933 (list (floor (nth 4 attr) 65536)
6934 (floor (mod (nth 4 attr) 65536)))))
6935 ;; Convert last modification time.
6936 (unless (listp (nth 5 attr))
6937 (setcar (nthcdr 5 attr)
6938 (list (floor (nth 5 attr) 65536)
6939 (floor (mod (nth 5 attr) 65536)))))
6940 ;; Convert last status change time.
6941 (unless (listp (nth 6 attr))
6942 (setcar (nthcdr 6 attr)
6943 (list (floor (nth 6 attr) 65536)
6944 (floor (mod (nth 6 attr) 65536)))))
d4443a0d
MA
6945 ;; Convert file size.
6946 (when (< (nth 7 attr) 0)
6947 (setcar (nthcdr 7 attr) -1))
9e6ab520
MA
6948 (when (and (floatp (nth 7 attr))
6949 (<= (nth 7 attr) (tramp-compat-most-positive-fixnum)))
d4443a0d 6950 (setcar (nthcdr 7 attr) (round (nth 7 attr))))
ca637b2a 6951 ;; Convert file mode bits to string.
c82c5727 6952 (unless (stringp (nth 8 attr))
dea31ca6
MA
6953 (setcar (nthcdr 8 attr) (tramp-file-mode-from-int (nth 8 attr)))
6954 (when (stringp (car attr))
6955 (aset (nth 8 attr) 0 ?l)))
00d6fd04 6956 ;; Convert directory indication bit.
5da24108
MA
6957 (when (string-match "^d" (nth 8 attr))
6958 (setcar attr t))
6959 ;; Convert symlink from `tramp-handle-file-attributes-with-stat'.
6960 (when (consp (car attr))
6961 (if (and (stringp (caar attr))
00d6fd04
MA
6962 (string-match ".+ -> .\\(.+\\)." (caar attr)))
6963 (setcar attr (match-string 1 (caar attr)))
6964 (setcar attr nil)))
6965 ;; Set file's gid change bit.
6966 (setcar (nthcdr 9 attr)
6967 (if (numberp (nth 3 attr))
6968 (not (= (nth 3 attr)
6969 (tramp-get-remote-gid vec 'integer)))
6970 (not (string-equal
6971 (nth 3 attr)
6972 (tramp-get-remote-gid vec 'string)))))
6973 ;; Convert inode.
6974 (unless (listp (nth 10 attr))
6975 (setcar (nthcdr 10 attr)
ce3f516f 6976 (condition-case nil
b946a456 6977 (cons (floor (nth 10 attr) 65536)
ce3f516f
MA
6978 (floor (mod (nth 10 attr) 65536)))
6979 ;; Inodes can be incredible huge. We must hide this.
6980 (error (tramp-get-inode vec)))))
c82c5727
LH
6981 ;; Set virtual device number.
6982 (setcar (nthcdr 11 attr)
00d6fd04 6983 (tramp-get-device vec))
c82c5727
LH
6984 attr)
6985
ce3f516f 6986(defun tramp-get-inode (vec)
00d6fd04
MA
6987 "Returns the virtual inode number.
6988If it doesn't exist, generate a new one."
ce3f516f
MA
6989 (let ((string (tramp-make-tramp-file-name
6990 (tramp-file-name-method vec)
6991 (tramp-file-name-user vec)
6992 (tramp-file-name-host vec)
6993 "")))
00d6fd04
MA
6994 (unless (assoc string tramp-inodes)
6995 (add-to-list 'tramp-inodes
6996 (list string (length tramp-inodes))))
6997 (nth 1 (assoc string tramp-inodes))))
6998
6999(defun tramp-get-device (vec)
c82c5727
LH
7000 "Returns the virtual device number.
7001If it doesn't exist, generate a new one."
00d6fd04
MA
7002 (let ((string (tramp-make-tramp-file-name
7003 (tramp-file-name-method vec)
7004 (tramp-file-name-user vec)
7005 (tramp-file-name-host vec)
7006 "")))
c82c5727
LH
7007 (unless (assoc string tramp-devices)
7008 (add-to-list 'tramp-devices
7009 (list string (length tramp-devices))))
b946a456 7010 (cons -1 (nth 1 (assoc string tramp-devices)))))
fb7933a3
KG
7011
7012(defun tramp-file-mode-from-int (mode)
7013 "Turn an integer representing a file mode into an ls(1)-like string."
7014 (let ((type (cdr (assoc (logand (lsh mode -12) 15) tramp-file-mode-type-map)))
7015 (user (logand (lsh mode -6) 7))
7016 (group (logand (lsh mode -3) 7))
7017 (other (logand (lsh mode -0) 7))
7018 (suid (> (logand (lsh mode -9) 4) 0))
7019 (sgid (> (logand (lsh mode -9) 2) 0))
7020 (sticky (> (logand (lsh mode -9) 1) 0)))
7021 (setq user (tramp-file-mode-permissions user suid "s"))
7022 (setq group (tramp-file-mode-permissions group sgid "s"))
7023 (setq other (tramp-file-mode-permissions other sticky "t"))
7024 (concat type user group other)))
7025
fb7933a3
KG
7026(defun tramp-file-mode-permissions (perm suid suid-text)
7027 "Convert a permission bitset into a string.
7028This is used internally by `tramp-file-mode-from-int'."
7029 (let ((r (> (logand perm 4) 0))
7030 (w (> (logand perm 2) 0))
7031 (x (> (logand perm 1) 0)))
7032 (concat (or (and r "r") "-")
7033 (or (and w "w") "-")
7034 (or (and suid x suid-text) ; suid, execute
7035 (and suid (upcase suid-text)) ; suid, !execute
7036 (and x "x") "-")))) ; !suid
7037
fb7933a3
KG
7038(defun tramp-decimal-to-octal (i)
7039 "Return a string consisting of the octal digits of I.
7040Not actually used. Use `(format \"%o\" i)' instead?"
7041 (cond ((< i 0) (error "Cannot convert negative number to octal"))
7042 ((not (integerp i)) (error "Cannot convert non-integer to octal"))
7043 ((zerop i) "0")
7044 (t (concat (tramp-decimal-to-octal (/ i 8))
7045 (number-to-string (% i 8))))))
7046
fb7933a3
KG
7047;; Kudos to Gerd Moellmann for this suggestion.
7048(defun tramp-octal-to-decimal (ostr)
7049 "Given a string of octal digits, return a decimal number."
7050 (let ((x (or ostr "")))
7051 ;; `save-match' is in `tramp-mode-string-to-int' which calls this.
7052 (unless (string-match "\\`[0-7]*\\'" x)
7053 (error "Non-octal junk in string `%s'" x))
7054 (string-to-number ostr 8)))
7055
7056(defun tramp-shell-case-fold (string)
7057 "Converts STRING to shell glob pattern which ignores case."
7058 (mapconcat
7059 (lambda (c)
7060 (if (equal (downcase c) (upcase c))
7061 (vector c)
7062 (format "[%c%c]" (downcase c) (upcase c))))
7063 string
7064 ""))
7065
7066
bf247b6e 7067;; ------------------------------------------------------------
a4aeb9a4 7068;; -- Tramp file names --
bf247b6e 7069;; ------------------------------------------------------------
fb7933a3
KG
7070;; Conversion functions between external representation and
7071;; internal data structure. Convenience functions for internal
7072;; data structure.
7073
00d6fd04
MA
7074(defun tramp-file-name-p (vec)
7075 "Check whether VEC is a Tramp object."
7076 (and (vectorp vec) (= 4 (length vec))))
7077
7078(defun tramp-file-name-method (vec)
7079 "Return method component of VEC."
7080 (and (tramp-file-name-p vec) (aref vec 0)))
7081
7082(defun tramp-file-name-user (vec)
7083 "Return user component of VEC."
7084 (and (tramp-file-name-p vec) (aref vec 1)))
7085
7086(defun tramp-file-name-host (vec)
7087 "Return host component of VEC."
7088 (and (tramp-file-name-p vec) (aref vec 2)))
7089
7090(defun tramp-file-name-localname (vec)
7091 "Return localname component of VEC."
7092 (and (tramp-file-name-p vec) (aref vec 3)))
7093
dea31ca6 7094;; The user part of a Tramp file name vector can be of kind
b96e6899 7095;; "user%domain". Sometimes, we must extract these parts.
dea31ca6
MA
7096(defun tramp-file-name-real-user (vec)
7097 "Return the user name of VEC without domain."
7098 (let ((user (tramp-file-name-user vec)))
7099 (if (and (stringp user)
b96e6899 7100 (string-match tramp-user-with-domain-regexp user))
dea31ca6
MA
7101 (match-string 1 user)
7102 user)))
7103
7104(defun tramp-file-name-domain (vec)
7105 "Return the domain name of VEC."
7106 (let ((user (tramp-file-name-user vec)))
7107 (and (stringp user)
b96e6899 7108 (string-match tramp-user-with-domain-regexp user)
dea31ca6
MA
7109 (match-string 2 user))))
7110
00d6fd04
MA
7111;; The host part of a Tramp file name vector can be of kind
7112;; "host#port". Sometimes, we must extract these parts.
8a4438b6 7113(defun tramp-file-name-real-host (vec)
00d6fd04
MA
7114 "Return the host name of VEC without port."
7115 (let ((host (tramp-file-name-host vec)))
7116 (if (and (stringp host)
7117 (string-match tramp-host-with-port-regexp host))
7118 (match-string 1 host)
7119 host)))
7120
8a4438b6 7121(defun tramp-file-name-port (vec)
00d6fd04
MA
7122 "Return the port number of VEC."
7123 (let ((host (tramp-file-name-host vec)))
7124 (and (stringp host)
7125 (string-match tramp-host-with-port-regexp host)
7126 (string-to-number (match-string 2 host)))))
fb7933a3
KG
7127
7128(defun tramp-tramp-file-p (name)
a4aeb9a4 7129 "Return t if NAME is a Tramp file."
fb7933a3
KG
7130 (save-match-data
7131 (string-match tramp-file-name-regexp name)))
bf247b6e 7132
8a4438b6 7133(defun tramp-find-method (method user host)
00d6fd04
MA
7134 "Return the right method string to use.
7135This is METHOD, if non-nil. Otherwise, do a lookup in
7136`tramp-default-method-alist'."
7137 (or method
7138 (let ((choices tramp-default-method-alist)
7139 lmethod item)
7140 (while choices
7141 (setq item (pop choices))
7142 (when (and (string-match (or (nth 0 item) "") (or host ""))
7143 (string-match (or (nth 1 item) "") (or user "")))
7144 (setq lmethod (nth 2 item))
7145 (setq choices nil)))
7146 lmethod)
7147 tramp-default-method))
7148
8a4438b6 7149(defun tramp-find-user (method user host)
00d6fd04
MA
7150 "Return the right user string to use.
7151This is USER, if non-nil. Otherwise, do a lookup in
7152`tramp-default-user-alist'."
7153 (or user
7154 (let ((choices tramp-default-user-alist)
7155 luser item)
7156 (while choices
7157 (setq item (pop choices))
7158 (when (and (string-match (or (nth 0 item) "") (or method ""))
7159 (string-match (or (nth 1 item) "") (or host "")))
7160 (setq luser (nth 2 item))
7161 (setq choices nil)))
7162 luser)
7163 tramp-default-user))
7164
8a4438b6 7165(defun tramp-find-host (method user host)
00d6fd04
MA
7166 "Return the right host string to use.
7167This is HOST, if non-nil. Otherwise, it is `tramp-default-host'."
7168 (or (and (> (length host) 0) host)
7169 tramp-default-host))
7170
9ce8462a 7171(defun tramp-dissect-file-name (name &optional nodefault)
00d6fd04 7172 "Return a `tramp-file-name' structure.
9ce8462a
MA
7173The structure consists of remote method, remote user, remote host
7174and localname (file name on remote host). If NODEFAULT is
7175non-nil, the file name parts are not expanded to their default
7176values."
4007ba5b 7177 (save-match-data
00d6fd04 7178 (let ((match (string-match (nth 0 tramp-file-name-structure) name)))
a4aeb9a4 7179 (unless match (error "Not a Tramp file name: %s" name))
00d6fd04
MA
7180 (let ((method (match-string (nth 1 tramp-file-name-structure) name))
7181 (user (match-string (nth 2 tramp-file-name-structure) name))
7182 (host (match-string (nth 3 tramp-file-name-structure) name))
7183 (localname (match-string (nth 4 tramp-file-name-structure) name)))
5d449a36
MA
7184 (when (member method '("multi" "multiu"))
7185 (error
7186 "`%s' method is no longer supported, see (info \"(tramp)Multi-hops\")"
7187 method))
b96e6899
MA
7188 (when host
7189 (when (string-match tramp-prefix-ipv6-regexp host)
7190 (setq host (replace-match "" nil t host)))
7191 (when (string-match tramp-postfix-ipv6-regexp host)
7192 (setq host (replace-match "" nil t host))))
9ce8462a
MA
7193 (if nodefault
7194 (vector method user host localname)
7195 (vector
7196 (tramp-find-method method user host)
7197 (tramp-find-user method user host)
7198 (tramp-find-host method user host)
7199 localname))))))
00d6fd04
MA
7200
7201(defun tramp-equal-remote (file1 file2)
7202 "Checks, whether the remote parts of FILE1 and FILE2 are identical.
7203The check depends on method, user and host name of the files. If
7204one of the components is missing, the default values are used.
7205The local file name parts of FILE1 and FILE2 are not taken into
7206account.
fb7933a3 7207
00d6fd04
MA
7208Example:
7209
7210 (tramp-equal-remote \"/ssh::/etc\" \"/<your host name>:/home\")
7211
7212would yield `t'. On the other hand, the following check results in nil:
7213
7214 (tramp-equal-remote \"/sudo::/etc\" \"/su::/etc\")"
9e6ab520
MA
7215 (and (stringp (file-remote-p file1))
7216 (stringp (file-remote-p file2))
94be87e8 7217 (string-equal (file-remote-p file1) (file-remote-p file2))))
00d6fd04
MA
7218
7219(defun tramp-make-tramp-file-name (method user host localname)
7220 "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME."
7221 (concat tramp-prefix-format
7222 (when (not (zerop (length method)))
7223 (concat method tramp-postfix-method-format))
7224 (when (not (zerop (length user)))
7225 (concat user tramp-postfix-user-format))
b96e6899
MA
7226 (when host
7227 (if (string-match tramp-ipv6-regexp host)
7228 (concat tramp-prefix-ipv6-format host tramp-postfix-ipv6-format)
7229 host))
7230 tramp-postfix-host-format
00d6fd04
MA
7231 (when localname localname)))
7232
7233(defun tramp-completion-make-tramp-file-name (method user host localname)
7234 "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME.
7235It must not be a complete Tramp file name, but as long as there are
7236necessary only. This function will be used in file name completion."
7237 (concat tramp-prefix-format
7238 (when (not (zerop (length method)))
7239 (concat method tramp-postfix-method-format))
7240 (when (not (zerop (length user)))
7241 (concat user tramp-postfix-user-format))
7242 (when (not (zerop (length host)))
b96e6899
MA
7243 (concat
7244 (if (string-match tramp-ipv6-regexp host)
7245 (concat tramp-prefix-ipv6-format host tramp-postfix-ipv6-format)
7246 host)
7247 tramp-postfix-host-format))
00d6fd04
MA
7248 (when localname localname)))
7249
7250(defun tramp-make-copy-program-file-name (vec)
7251 "Create a file name suitable to be passed to `rcp' and workalikes."
7252 (let ((user (tramp-file-name-user vec))
0f205eee 7253 (host (tramp-file-name-real-host vec))
00d6fd04
MA
7254 (localname (tramp-shell-quote-argument
7255 (tramp-file-name-localname vec))))
7256 (if (not (zerop (length user)))
7257 (format "%s@%s:%s" user host localname)
7258 (format "%s:%s" host localname))))
7259
7260(defun tramp-method-out-of-band-p (vec)
38c65fca 7261 "Return t if this is an out-of-band method, nil otherwise."
00d6fd04 7262 (tramp-get-method-parameter (tramp-file-name-method vec) 'tramp-copy-program))
fb7933a3 7263
0f205eee
MA
7264(defun tramp-local-host-p (vec)
7265 "Return t if this points to the local host, nil otherwise."
c992abdb
MA
7266 ;; We cannot use `tramp-file-name-real-host'. A port is an
7267 ;; indication for an ssh tunnel or alike.
7268 (let ((host (tramp-file-name-host vec)))
0f205eee
MA
7269 (and
7270 (stringp host)
b96e6899 7271 (string-match tramp-local-host-regexp host)
a0a5183a
MA
7272 ;; The local temp directory must be writable for the other user.
7273 (file-writable-p
7274 (tramp-make-tramp-file-name
7275 (tramp-file-name-method vec)
7276 (tramp-file-name-user vec)
7277 host
93c3eb7c
MA
7278 (tramp-compat-temporary-file-directory)))
7279 ;; On some systems, chown runs only for root.
7280 (or (zerop (user-uid))
7281 (zerop (tramp-get-remote-uid vec 'integer))))))
0f205eee 7282
fb7933a3
KG
7283;; Variables local to connection.
7284
f84638eb 7285(defun tramp-get-remote-path (vec)
70c11b0b
MA
7286 (with-connection-property
7287 ;; When `tramp-own-remote-path' is in `tramp-remote-path', we
7288 ;; cache the result for the session only. Otherwise, the result
7289 ;; is cached persistently.
7290 (if (memq 'tramp-own-remote-path tramp-remote-path)
7291 (tramp-get-connection-process vec)
7292 vec)
7293 "remote-path"
9e6ab520 7294 (let* ((remote-path (tramp-compat-copy-tree tramp-remote-path))
70c11b0b
MA
7295 (elt1 (memq 'tramp-default-remote-path remote-path))
7296 (elt2 (memq 'tramp-own-remote-path remote-path))
f84638eb 7297 (default-remote-path
70c11b0b 7298 (when elt1
f84638eb 7299 (condition-case nil
70c11b0b
MA
7300 (tramp-send-command-and-read
7301 vec "echo \\\"`getconf PATH`\\\"")
f84638eb
MA
7302 ;; Default if "getconf" is not available.
7303 (error
7304 (tramp-message
7305 vec 3
7306 "`getconf PATH' not successful, using default value \"%s\"."
7307 "/bin:/usr/bin")
70c11b0b
MA
7308 "/bin:/usr/bin"))))
7309 (own-remote-path
7310 (when elt2
7311 (condition-case nil
7312 (tramp-send-command-and-read vec "echo \\\"$PATH\\\"")
7313 ;; Default if "getconf" is not available.
7314 (error
7315 (tramp-message
7316 vec 3 "$PATH not set, ignoring `tramp-own-remote-path'.")
7317 nil)))))
7318
7319 ;; Replace place holder `tramp-default-remote-path'.
7320 (when elt1
7321 (setcdr elt1
f84638eb 7322 (append
70c11b0b
MA
7323 (tramp-compat-split-string default-remote-path ":")
7324 (cdr elt1)))
f84638eb
MA
7325 (setq remote-path (delq 'tramp-default-remote-path remote-path)))
7326
70c11b0b
MA
7327 ;; Replace place holder `tramp-own-remote-path'.
7328 (when elt2
7329 (setcdr elt2
7330 (append
7331 (tramp-compat-split-string own-remote-path ":")
7332 (cdr elt2)))
7333 (setq remote-path (delq 'tramp-own-remote-path remote-path)))
7334
7335 ;; Remove double entries.
7336 (setq elt1 remote-path)
7337 (while (consp elt1)
7338 (while (and (car elt1) (setq elt2 (member (car elt1) (cdr elt1))))
7339 (setcar elt2 nil))
7340 (setq elt1 (cdr elt1)))
7341
f84638eb
MA
7342 ;; Remove non-existing directories.
7343 (delq
7344 nil
7345 (mapcar
7346 (lambda (x)
7347 (and
70c11b0b
MA
7348 (stringp x)
7349 (file-directory-p
7350 (tramp-make-tramp-file-name
7351 (tramp-file-name-method vec)
7352 (tramp-file-name-user vec)
7353 (tramp-file-name-host vec)
7354 x))
f84638eb
MA
7355 x))
7356 remote-path)))))
7357
a4aeb9a4
MA
7358(defun tramp-get-remote-tmpdir (vec)
7359 (with-connection-property vec "tmp-directory"
7360 (let ((dir (tramp-shell-quote-argument "/tmp")))
7361 (if (and (zerop
7362 (tramp-send-command-and-check
7363 vec (format "%s -d %s" (tramp-get-test-command vec) dir)))
7364 (zerop
7365 (tramp-send-command-and-check
7366 vec (format "%s -w %s" (tramp-get-test-command vec) dir))))
7367 dir
7368 (tramp-error vec 'file-error "Directory %s not accessible" dir)))))
7369
00d6fd04
MA
7370(defun tramp-get-ls-command (vec)
7371 (with-connection-property vec "ls"
7372 (with-current-buffer (tramp-get-buffer vec)
7373 (tramp-message vec 5 "Finding a suitable `ls' command")
7374 (or
7375 (catch 'ls-found
7376 (dolist (cmd '("ls" "gnuls" "gls"))
f84638eb 7377 (let ((dl (tramp-get-remote-path vec))
00d6fd04
MA
7378 result)
7379 (while
7380 (and
7381 dl
7382 (setq result
7383 (tramp-find-executable vec cmd dl t t)))
7384 ;; Check parameter.
7385 (when (zerop (tramp-send-command-and-check
7386 vec (format "%s -lnd /" result)))
7387 (throw 'ls-found result))
00d6fd04
MA
7388 (setq dl (cdr dl))))))
7389 (tramp-error vec 'file-error "Couldn't find a proper `ls' command")))))
7390
8e754ea2
MA
7391(defun tramp-get-ls-command-with-dired (vec)
7392 (save-match-data
7393 (with-connection-property vec "ls-dired"
7394 (tramp-message vec 5 "Checking, whether `ls --dired' works")
7395 (zerop (tramp-send-command-and-check
7396 vec (format "%s --diredd /" (tramp-get-ls-command vec)))))))
7397
00d6fd04
MA
7398(defun tramp-get-test-command (vec)
7399 (with-connection-property vec "test"
7400 (with-current-buffer (tramp-get-buffer vec)
7401 (tramp-message vec 5 "Finding a suitable `test' command")
7402 (if (zerop (tramp-send-command-and-check vec "test 0"))
7403 "test"
f84638eb 7404 (tramp-find-executable vec "test" (tramp-get-remote-path vec))))))
00d6fd04
MA
7405
7406(defun tramp-get-test-nt-command (vec)
7407 ;; Does `test A -nt B' work? Use abominable `find' construct if it
7408 ;; doesn't. BSD/OS 4.0 wants the parentheses around the command,
7409 ;; for otherwise the shell crashes.
7410 (with-connection-property vec "test-nt"
7411 (or
7412 (progn
7413 (tramp-send-command
7414 vec (format "( %s / -nt / )" (tramp-get-test-command vec)))
7415 (with-current-buffer (tramp-get-buffer vec)
7416 (goto-char (point-min))
a0a5183a 7417 (when (looking-at (regexp-quote tramp-end-of-output))
00d6fd04
MA
7418 (format "%s %%s -nt %%s" (tramp-get-test-command vec)))))
7419 (progn
7420 (tramp-send-command
7421 vec
7422 (format
7423 "tramp_test_nt () {\n%s -n \"`find $1 -prune -newer $2 -print`\"\n}"
7424 (tramp-get-test-command vec)))
7425 "tramp_test_nt %s %s"))))
7426
7427(defun tramp-get-file-exists-command (vec)
7428 (with-connection-property vec "file-exists"
7429 (with-current-buffer (tramp-get-buffer vec)
7430 (tramp-message vec 5 "Finding command to check if file exists")
7431 (tramp-find-file-exists-command vec))))
7432
7433(defun tramp-get-remote-ln (vec)
7434 (with-connection-property vec "ln"
7435 (with-current-buffer (tramp-get-buffer vec)
7436 (tramp-message vec 5 "Finding a suitable `ln' command")
f84638eb 7437 (tramp-find-executable vec "ln" (tramp-get-remote-path vec)))))
00d6fd04
MA
7438
7439(defun tramp-get-remote-perl (vec)
7440 (with-connection-property vec "perl"
7441 (with-current-buffer (tramp-get-buffer vec)
7442 (tramp-message vec 5 "Finding a suitable `perl' command")
f84638eb
MA
7443 (or (tramp-find-executable vec "perl5" (tramp-get-remote-path vec))
7444 (tramp-find-executable vec "perl" (tramp-get-remote-path vec))))))
00d6fd04
MA
7445
7446(defun tramp-get-remote-stat (vec)
7447 (with-connection-property vec "stat"
7448 (with-current-buffer (tramp-get-buffer vec)
7449 (tramp-message vec 5 "Finding a suitable `stat' command")
f84638eb
MA
7450 (let ((result (tramp-find-executable
7451 vec "stat" (tramp-get-remote-path vec)))
00d6fd04 7452 tmp)
4ad21635
MA
7453 ;; Check whether stat(1) returns usable syntax. %s does not
7454 ;; work on older AIX systems.
00d6fd04
MA
7455 (when result
7456 (setq tmp
7457 ;; We don't want to display an error message.
7458 (with-temp-message (or (current-message) "")
7459 (condition-case nil
7460 (tramp-send-command-and-read
4ad21635 7461 vec (format "%s -c '(\"%%N\" %%s)' /" result))
00d6fd04
MA
7462 (error nil))))
7463 (unless (and (listp tmp) (stringp (car tmp))
4ad21635
MA
7464 (string-match "^./.$" (car tmp))
7465 (integerp (cadr tmp)))
00d6fd04
MA
7466 (setq result nil)))
7467 result))))
fb7933a3 7468
00d6fd04
MA
7469(defun tramp-get-remote-id (vec)
7470 (with-connection-property vec "id"
7471 (with-current-buffer (tramp-get-buffer vec)
7472 (tramp-message vec 5 "Finding POSIX `id' command")
7473 (or
7474 (catch 'id-found
f84638eb 7475 (let ((dl (tramp-get-remote-path vec))
00d6fd04
MA
7476 result)
7477 (while
7478 (and
7479 dl
7480 (setq result
7481 (tramp-find-executable vec "id" dl t t)))
7482 ;; Check POSIX parameter.
7483 (when (zerop (tramp-send-command-and-check
7484 vec (format "%s -u" result)))
7485 (throw 'id-found result))
00d6fd04
MA
7486 (setq dl (cdr dl)))))
7487 (tramp-error vec 'file-error "Couldn't find a POSIX `id' command")))))
7488
7489(defun tramp-get-remote-uid (vec id-format)
7490 (with-connection-property vec (format "uid-%s" id-format)
7491 (let ((res (tramp-send-command-and-read
7492 vec
7493 (format "%s -u%s %s"
7494 (tramp-get-remote-id vec)
7495 (if (equal id-format 'integer) "" "n")
7496 (if (equal id-format 'integer)
7497 "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
7498 ;; The command might not always return a number.
7499 (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
7500
7501(defun tramp-get-remote-gid (vec id-format)
7502 (with-connection-property vec (format "gid-%s" id-format)
7503 (let ((res (tramp-send-command-and-read
7504 vec
7505 (format "%s -g%s %s"
7506 (tramp-get-remote-id vec)
7507 (if (equal id-format 'integer) "" "n")
7508 (if (equal id-format 'integer)
7509 "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
7510 ;; The command might not always return a number.
7511 (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
fb7933a3 7512
8d60099b
MA
7513(defun tramp-get-local-uid (id-format)
7514 (if (equal id-format 'integer) (user-uid) (user-login-name)))
7515
7516(defun tramp-get-local-gid (id-format)
9e6ab520 7517 (nth 3 (tramp-compat-file-attributes "~/" id-format)))
8d60099b 7518
00d6fd04
MA
7519;; Some predefined connection properties.
7520(defun tramp-get-remote-coding (vec prop)
7521 ;; Local coding handles properties like remote coding. So we could
7522 ;; call it without pain.
7523 (let ((ret (tramp-get-local-coding vec prop)))
7524 ;; The connection property might have been cached. So we must send
7525 ;; the script - maybe.
1d7e9a01 7526 (when (and ret (symbolp ret))
00d6fd04
MA
7527 (let ((name (symbol-name ret)))
7528 (while (string-match (regexp-quote "-") name)
7529 (setq name (replace-match "_" nil t name)))
7530 (tramp-maybe-send-script vec (symbol-value ret) name)
7531 (setq ret name)))
7532 ;; Return the value.
7533 ret))
7534
7535(defun tramp-get-local-coding (vec prop)
bf0503cb 7536 (or
00d6fd04
MA
7537 (tramp-get-connection-property vec prop nil)
7538 (progn
7539 (tramp-find-inline-encoding vec)
7540 (tramp-get-connection-property vec prop nil))))
fb7933a3 7541
00d6fd04 7542(defun tramp-get-method-parameter (method param)
c951aecb 7543 "Return the method parameter PARAM.
00d6fd04
MA
7544If the `tramp-methods' entry does not exist, return NIL."
7545 (let ((entry (assoc param (assoc method tramp-methods))))
7546 (when entry (cadr entry))))
90f8dc03 7547
fb7933a3
KG
7548;; Auto saving to a special directory.
7549
00cec167 7550(defun tramp-exists-file-name-handler (operation &rest args)
00d6fd04
MA
7551 "Checks whether OPERATION runs a file name handler."
7552 ;; The file name handler is determined on base of either an
7553 ;; argument, `buffer-file-name', or `default-directory'.
7554 (condition-case nil
7555 (let* ((buffer-file-name "/")
7556 (default-directory "/")
7557 (fnha file-name-handler-alist)
7558 (check-file-name-operation operation)
7559 (file-name-handler-alist
7560 (list
7561 (cons "/"
7562 '(lambda (operation &rest args)
7563 "Returns OPERATION if it is the one to be checked."
7564 (if (equal check-file-name-operation operation)
7565 operation
7566 (let ((file-name-handler-alist fnha))
7567 (apply operation args))))))))
7568 (equal (apply operation args) operation))
7569 (error nil)))
c1105d05
MA
7570
7571(unless (tramp-exists-file-name-handler 'make-auto-save-file-name)
7572 (defadvice make-auto-save-file-name
7573 (around tramp-advice-make-auto-save-file-name () activate)
00d6fd04 7574 "Invoke `tramp-handle-make-auto-save-file-name' for Tramp files."
c1105d05 7575 (if (and (buffer-file-name) (tramp-tramp-file-p (buffer-file-name)))
00cec167 7576 (setq ad-return-value (tramp-handle-make-auto-save-file-name))
a69c01a0
MA
7577 ad-do-it))
7578 (add-hook 'tramp-unload-hook
7579 '(lambda () (ad-unadvise 'make-auto-save-file-name))))
fb7933a3 7580
340b8d4f
MA
7581;; In Emacs < 22 and XEmacs < 21.5 autosaved remote files have
7582;; permission 0666 minus umask. This is a security threat.
414da5ab
MA
7583
7584(defun tramp-set-auto-save-file-modes ()
7585 "Set permissions of autosaved remote files to the original permissions."
7586 (let ((bfn (buffer-file-name)))
7587 (when (and (stringp bfn)
7588 (tramp-tramp-file-p bfn)
b50dd0d2 7589 (buffer-modified-p)
414da5ab 7590 (stringp buffer-auto-save-file-name)
340b8d4f
MA
7591 (not (equal bfn buffer-auto-save-file-name)))
7592 (unless (file-exists-p buffer-auto-save-file-name)
7593 (write-region "" nil buffer-auto-save-file-name))
7594 ;; Permissions should be set always, because there might be an old
7595 ;; auto-saved file belonging to another original file. This could
7596 ;; be a security threat.
7177e2a3 7597 (set-file-modes buffer-auto-save-file-name
11948172 7598 (or (file-modes bfn) (tramp-octal-to-decimal "0600"))))))
414da5ab
MA
7599
7600(unless (or (> emacs-major-version 21)
7601 (and (featurep 'xemacs)
7602 (= emacs-major-version 21)
340b8d4f 7603 (> emacs-minor-version 4)))
a69c01a0
MA
7604 (add-hook 'auto-save-hook 'tramp-set-auto-save-file-modes)
7605 (add-hook 'tramp-unload-hook
7606 '(lambda ()
7607 (remove-hook 'auto-save-hook 'tramp-set-auto-save-file-modes))))
414da5ab 7608
fb7933a3
KG
7609(defun tramp-subst-strs-in-string (alist string)
7610 "Replace all occurrences of the string FROM with TO in STRING.
7611ALIST is of the form ((FROM . TO) ...)."
7612 (save-match-data
7613 (while alist
7614 (let* ((pr (car alist))
7615 (from (car pr))
7616 (to (cdr pr)))
7617 (while (string-match (regexp-quote from) string)
7618 (setq string (replace-match to t t string)))
7619 (setq alist (cdr alist))))
7620 string))
7621
fb7933a3
KG
7622;; ------------------------------------------------------------
7623;; -- Compatibility functions section --
7624;; ------------------------------------------------------------
7625
00d6fd04 7626(defun tramp-read-passwd (proc &optional prompt)
fb7933a3 7627 "Read a password from user (compat function).
5615d63f 7628Consults the auth-source package.
5ec2cc41 7629Invokes `password-read' if available, `read-passwd' else."
00d6fd04
MA
7630 (let* ((key (tramp-make-tramp-file-name
7631 tramp-current-method tramp-current-user
7632 tramp-current-host ""))
7633 (pw-prompt
7634 (or prompt
7635 (with-current-buffer (process-buffer proc)
7636 (tramp-check-for-regexp proc tramp-password-prompt-regexp)
7637 (format "%s for %s " (capitalize (match-string 1)) key)))))
5c7043a2
MA
7638 (prog1
7639 (or
7640 ;; See if auth-sources contains something useful, if it's bound.
7641 (and (boundp 'auth-sources)
7642 (tramp-get-connection-property proc "first-password-request" nil)
7643 ;; Try with Tramp's current method.
7644 (funcall (symbol-function 'auth-source-user-or-password)
7645 "password" tramp-current-host tramp-current-method))
7646 ;; Try the password cache.
cb85dcd0
MA
7647 (when (functionp 'password-read)
7648 (unless (tramp-get-connection-property
7649 proc "first-password-request" nil)
7650 (funcall (symbol-function 'password-cache-remove) key))
7651 (let ((password
7652 (funcall (symbol-function 'password-read) pw-prompt key)))
7653 (funcall (symbol-function 'password-cache-add) key password)
7654 password))
5c7043a2
MA
7655 ;; Else, get the password interactively.
7656 (read-passwd pw-prompt))
7657 (tramp-set-connection-property proc "first-password-request" nil))))
00d6fd04 7658
9c13938d
MA
7659(defun tramp-clear-passwd (vec)
7660 "Clear password cache for connection related to VEC."
00d6fd04 7661 (when (functionp 'password-cache-remove)
9c13938d
MA
7662 (funcall
7663 (symbol-function 'password-cache-remove)
7664 (tramp-make-tramp-file-name
7665 (tramp-file-name-method vec)
7666 (tramp-file-name-user vec)
7667 (tramp-file-name-host vec)
7668 ""))))
00d6fd04
MA
7669
7670;; Snarfed code from time-date.el and parse-time.el
7671
7672(defconst tramp-half-a-year '(241 17024)
7673"Evaluated by \"(days-to-time 183)\".")
7674
7675(defconst tramp-parse-time-months
7676 '(("jan" . 1) ("feb" . 2) ("mar" . 3)
7677 ("apr" . 4) ("may" . 5) ("jun" . 6)
7678 ("jul" . 7) ("aug" . 8) ("sep" . 9)
7679 ("oct" . 10) ("nov" . 11) ("dec" . 12))
7680 "Alist mapping month names to integers.")
7681
7682(defun tramp-time-less-p (t1 t2)
7683 "Say whether time value T1 is less than time value T2."
7684 (unless t1 (setq t1 '(0 0)))
7685 (unless t2 (setq t2 '(0 0)))
7686 (or (< (car t1) (car t2))
7687 (and (= (car t1) (car t2))
7688 (< (nth 1 t1) (nth 1 t2)))))
7689
7690(defun tramp-time-subtract (t1 t2)
7691 "Subtract two time values.
7692Return the difference in the format of a time value."
7693 (unless t1 (setq t1 '(0 0)))
7694 (unless t2 (setq t2 '(0 0)))
7695 (let ((borrow (< (cadr t1) (cadr t2))))
7696 (list (- (car t1) (car t2) (if borrow 1 0))
7697 (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2)))))
fb7933a3
KG
7698
7699(defun tramp-time-diff (t1 t2)
7700 "Return the difference between the two times, in seconds.
1a762140 7701T1 and T2 are time values (as returned by `current-time' for example)."
fb7933a3 7702 ;; Pacify byte-compiler with `symbol-function'.
ea9d1443
KG
7703 (cond ((and (fboundp 'subtract-time)
7704 (fboundp 'float-time))
7705 (funcall (symbol-function 'float-time)
7706 (funcall (symbol-function 'subtract-time) t1 t2)))
7707 ((and (fboundp 'subtract-time)
7708 (fboundp 'time-to-seconds))
7709 (funcall (symbol-function 'time-to-seconds)
7710 (funcall (symbol-function 'subtract-time) t1 t2)))
fb7933a3 7711 ((fboundp 'itimer-time-difference)
1a762140
MA
7712 (funcall (symbol-function 'itimer-time-difference)
7713 (if (< (length t1) 3) (append t1 '(0)) t1)
7714 (if (< (length t2) 3) (append t2 '(0)) t2)))
fb7933a3 7715 (t
00d6fd04 7716 (let ((time (tramp-time-subtract t1 t2)))
ea9d1443
KG
7717 (+ (* (car time) 65536.0)
7718 (cadr time)
7719 (/ (or (nth 2 time) 0) 1000000.0))))))
fb7933a3
KG
7720
7721(defun tramp-coding-system-change-eol-conversion (coding-system eol-type)
7722 "Return a coding system like CODING-SYSTEM but with given EOL-TYPE.
7723EOL-TYPE can be one of `dos', `unix', or `mac'."
7724 (cond ((fboundp 'coding-system-change-eol-conversion)
9e6ab520
MA
7725 (funcall (symbol-function 'coding-system-change-eol-conversion)
7726 coding-system eol-type))
fb7933a3 7727 ((fboundp 'subsidiary-coding-system)
9e6ab520
MA
7728 (funcall (symbol-function 'subsidiary-coding-system)
7729 coding-system
7730 (cond ((eq eol-type 'dos) 'crlf)
7731 ((eq eol-type 'unix) 'lf)
7732 ((eq eol-type 'mac) 'cr)
7733 (t
7734 (error "Unknown EOL-TYPE `%s', must be %s"
7735 eol-type
7736 "`dos', `unix', or `mac'")))))
fb7933a3
KG
7737 (t (error "Can't change EOL conversion -- is MULE missing?"))))
7738
19a87064
MA
7739(defun tramp-set-process-query-on-exit-flag (process flag)
7740 "Specify if query is needed for process when Emacs is exited.
7741If the second argument flag is non-nil, Emacs will query the user before
7742exiting if process is running."
7743 (if (fboundp 'set-process-query-on-exit-flag)
00d6fd04
MA
7744 (funcall (symbol-function 'set-process-query-on-exit-flag) process flag)
7745 (funcall (symbol-function 'process-kill-without-query) process flag)))
19a87064 7746
19a87064 7747
bf247b6e
KS
7748;; ------------------------------------------------------------
7749;; -- Kludges section --
7750;; ------------------------------------------------------------
fb7933a3
KG
7751
7752;; Currently (as of Emacs 20.5), the function `shell-quote-argument'
7753;; does not deal well with newline characters. Newline is replaced by
7754;; backslash newline. But if, say, the string `a backslash newline b'
7755;; is passed to a shell, the shell will expand this into "ab",
7756;; completely omitting the newline. This is not what was intended.
7757;; It does not appear to be possible to make the function
7758;; `shell-quote-argument' work with newlines without making it
7759;; dependent on the shell used. But within this package, we know that
7760;; we will always use a Bourne-like shell, so we use an approach which
7761;; groks newlines.
7762;;
7763;; The approach is simple: we call `shell-quote-argument', then
7764;; massage the newline part of the result.
7765;;
7766;; This function should produce a string which is grokked by a Unix
7767;; shell, even if the Emacs is running on Windows. Since this is the
7768;; kludges section, we bind `system-type' in such a way that
7769;; `shell-quote-arguments' behaves as if on Unix.
7770;;
7771;; Thanks to Mario DeWeerd for the hint that it is sufficient for this
7772;; function to work with Bourne-like shells.
7773;;
7774;; CCC: This function should be rewritten so that
7775;; `shell-quote-argument' is not used. This way, we are safe from
7776;; changes in `shell-quote-argument'.
7777(defun tramp-shell-quote-argument (s)
7778 "Similar to `shell-quote-argument', but groks newlines.
7779Only works for Bourne-like shells."
7780 (let ((system-type 'not-windows))
7781 (save-match-data
7782 (let ((result (shell-quote-argument s))
7783 (nl (regexp-quote (format "\\%s" tramp-rsh-end-of-line))))
7784 (when (and (>= (length result) 2)
7785 (string= (substring result 0 2) "\\~"))
7786 (setq result (substring result 1)))
7787 (while (string-match nl result)
7788 (setq result (replace-match (format "'%s'" tramp-rsh-end-of-line)
7789 t t result)))
7790 result))))
7791
16674e4f
KG
7792;; We currently (sometimes) use "[" and "]" in the filename format.
7793;; This means that Emacs wants to expand wildcards if
fb7933a3
KG
7794;; `find-file-wildcards' is non-nil, and then barfs because no
7795;; expansion could be found. We detect this situation and do
7796;; something really awful: we have `file-expand-wildcards' return the
7797;; original filename if it can't expand anything. Let's just hope
7798;; that this doesn't break anything else.
16674e4f
KG
7799;; CCC: This check is now also really awful; we should search all
7800;; of the filename format, not just the prefix.
7801(when (string-match "\\[" tramp-prefix-format)
1834b39f
MA
7802 (defadvice file-expand-wildcards
7803 (around tramp-advice-file-expand-wildcards activate)
d2a2c17f
MA
7804 (let ((name (ad-get-arg 0)))
7805 (if (tramp-tramp-file-p name)
7806 ;; If it's a Tramp file, dissect it and look if wildcards
7807 ;; need to be expanded at all.
1834b39f
MA
7808 (if (string-match
7809 "[[*?]"
7810 (tramp-file-name-localname (tramp-dissect-file-name name)))
7811 (setq ad-return-value (or ad-do-it (list name)))
7812 (setq ad-return-value (list name)))
d2a2c17f 7813 ;; If it is not a Tramp file, just run the original function.
1834b39f 7814 (setq ad-return-value (or ad-do-it (list name))))))
a69c01a0
MA
7815 (add-hook 'tramp-unload-hook
7816 '(lambda () (ad-unadvise 'file-expand-wildcards))))
fb7933a3 7817
a69c01a0
MA
7818;; Checklist for `tramp-unload-hook'
7819;; - Unload all `tramp-*' packages
7820;; - Reset `file-name-handler-alist'
7821;; - Cleanup hooks where Tramp functions are in
7822;; - Cleanup advised functions
7823;; - Cleanup autoloads
7824;;;###autoload
7825(defun tramp-unload-tramp ()
08b1eb21 7826 "Discard Tramp from loading remote files."
a69c01a0
MA
7827 (interactive)
7828 ;; When Tramp is not loaded yet, its autoloads are still active.
8c04e197 7829 (tramp-unload-file-name-handlers)
a69c01a0
MA
7830 ;; ange-ftp settings must be enabled.
7831 (when (functionp 'tramp-ftp-enable-ange-ftp)
7832 (funcall (symbol-function 'tramp-ftp-enable-ange-ftp)))
00d6fd04
MA
7833 ;; Maybe its not loaded yet.
7834 (condition-case nil
7835 (unload-feature 'tramp 'force)
a69c01a0
MA
7836 (error nil)))
7837
dea31ca6
MA
7838(when (and load-in-progress
7839 (string-match "Loading tramp..." (or (current-message) "")))
ccb4a481
MA
7840 (message "Loading tramp...done"))
7841
fb7933a3
KG
7842(provide 'tramp)
7843
fb7933a3
KG
7844;;; TODO:
7845
4007ba5b 7846;; * Handle nonlocal exits such as C-g.
00d6fd04
MA
7847;; * But it would probably be better to use with-local-quit at the
7848;; place where it's actually needed: around any potentially
7849;; indefinitely blocking piece of code. In this case it would be
7850;; within Tramp around one of its calls to accept-process-output (or
7851;; around one of the loops that calls accept-process-output)
d037d501 7852;; (Stefan Monnier).
fb7933a3 7853;; * Rewrite `tramp-shell-quote-argument' to abstain from using
b1d06e75 7854;; `shell-quote-argument'.
fb7933a3
KG
7855;; * In Emacs 21, `insert-directory' shows total number of bytes used
7856;; by the files in that directory. Add this here.
7857;; * Avoid screen blanking when hitting `g' in dired. (Eli Tziperman)
7858;; * Make ffap.el grok Tramp filenames. (Eli Tziperman)
fb7933a3 7859;; * Case-insensitive filename completion. (Norbert Goevert.)
fb7933a3
KG
7860;; * Don't use globbing for directories with many files, as this is
7861;; likely to produce long command lines, and some shells choke on
7862;; long command lines.
fb7933a3
KG
7863;; * `vc-directory' does not work. It never displays any files, even
7864;; if it does show files when run locally.
fb7933a3 7865;; * How to deal with MULE in `insert-file-contents' and `write-region'?
fb7933a3
KG
7866;; * Grok `append' parameter for `write-region'.
7867;; * Test remote ksh or bash for tilde expansion in `tramp-find-shell'?
7868;; * abbreviate-file-name
8e754ea2 7869;; * Better error checking. At least whenever we see something
fb7933a3
KG
7870;; strange when doing zerop, we should kill the process and start
7871;; again. (Greg Stark)
fb7933a3
KG
7872;; * Provide a local cache of old versions of remote files for the rsync
7873;; transfer method to use. (Greg Stark)
7874;; * Remove unneeded parameters from methods.
7875;; * Invoke rsync once for copying a whole directory hierarchy.
cdd44874 7876;; (Francesco Potortì)
fb7933a3
KG
7877;; * Make it work for different encodings, and for different file name
7878;; encodings, too. (Daniel Pittman)
fb7933a3 7879;; * Progress reports while copying files. (Michael Kifer)
fb7933a3
KG
7880;; * Don't search for perl5 and perl. Instead, only search for perl and
7881;; then look if it's the right version (with `perl -v').
7882;; * When editing a remote CVS controlled file as a different user, VC
7883;; gets confused about the file locking status. Try to find out why
7884;; the workaround doesn't work.
3cdaec13 7885;; * Username and hostname completion.
6c4e47fa 7886;; ** Try to avoid usage of `last-input-event' in `tramp-completion-mode-p'.
8daea7fc 7887;; ** Unify `tramp-parse-{rhosts,shosts,sconfig,hosts,passwd,netrc}'.
16674e4f 7888;; Code is nearly identical.
cfb5c0db
MA
7889;; * Allow out-of-band methods as _last_ multi-hop. Open a connection
7890;; until the last but one hop via `start-file-process'. Apply it
7891;; also for ftp and smb.
00d6fd04
MA
7892;; * WIBNI if we had a command "trampclient"? If I was editing in
7893;; some shell with root priviledges, it would be nice if I could
7894;; just call
7895;; trampclient filename.c
7896;; as an editor, and the _current_ shell would connect to an Emacs
7897;; server and would be used in an existing non-priviledged Emacs
7898;; session for doing the editing in question.
7899;; That way, I need not tell Emacs my password again and be afraid
7900;; that it makes it into core dumps or other ugly stuff (I had Emacs
7901;; once display a just typed password in the context of a keyboard
7902;; sequence prompt for a question immediately following in a shell
7903;; script run within Emacs -- nasty).
7904;; And if I have some ssh session running to a different computer,
7905;; having the possibility of passing a local file there to a local
7906;; Emacs session (in case I can arrange for a connection back) would
7907;; be nice.
a4aeb9a4 7908;; Likely the corresponding Tramp server should not allow the
00d6fd04
MA
7909;; equivalent of the emacsclient -eval option in order to make this
7910;; reasonably unproblematic. And maybe trampclient should have some
7911;; way of passing credentials, like by using an SSL socket or
7912;; something. (David Kastrup)
7913;; * Could Tramp reasonably look for a prompt after ^M rather than
7914;; only after ^J ? (Stefan Monnier)
00d6fd04
MA
7915;; * Reconnect directly to a compliant shell without first going
7916;; through the user's default shell. (Pete Forman)
00d6fd04 7917;; * Make `tramp-default-user' obsolete.
adb67129
MA
7918;; * Tramp shall reconnect automatically to its ssh connection when it
7919;; detects that the process "has died". (David Reitter)
11c71217
MA
7920;; * How can I interrupt the remote process with a signal
7921;; (interrupt-process seems not to work)? (Markus Triska)
2296b54d
MA
7922;; * Avoid the local shell entirely for starting remote processes. If
7923;; so, I think even a signal, when delivered directly to the local
7924;; SSH instance, would correctly be propagated to the remote process
7925;; automatically; possibly SSH would have to be started with
7926;; "-t". (Markus Triska)
ccb4a481
MA
7927;; * Set `tramp-copy-size-limit' to 0, when there is no remote
7928;; encoding routine.
dea31ca6
MA
7929;; * It makes me wonder if tramp couldn't fall back to ssh when scp
7930;; isn't on the remote host. (Mark A. Hershberger)
65a099b6
MA
7931;; * To improve the behavior in case of things like "git status", it
7932;; might be worthwhile to add some way to indicate that a particular
7933;; use of process-file is (supposed to be) free of side-effects.
7934;; (Stefan Monnier)
3e2fa353
MA
7935;; * Use lsh instead of ssh. (Alfred M. Szmidt)
7936;; * Implement a general server-local-variable mechanism, as there are
7937;; probably other variables that need different values for different
7938;; servers too. The user could then configure a variable (such as
7939;; tramp-server-local-variable-alist) to define any such variables
7940;; that they need to, which would then be let bound as appropriate
7941;; in tramp functions. (Jason Rumney)
905fb90e 7942;; * Optimize out-of-band copying, when both methods are scp-like.
fb7933a3
KG
7943
7944;; Functions for file-name-handler-alist:
7945;; diff-latest-backup-file -- in diff.el
fb7933a3 7946
cdd44874 7947;; arch-tag: 3a21a994-182b-48fa-b0cd-c1d9fede424a
fb7933a3 7948;;; tramp.el ends here
57671b72
MA
7949
7950;; Local Variables:
7951;; mode: Emacs-Lisp
7952;; coding: utf-8
7953;; End: