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