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