Version 2.0.35 of Tramp released.
[emacs.git] / lisp / net / tramp.el
blob50cd8056fde2b038e11af3d071e83e9605ea6ea5
1 ;;; -*- mode: Emacs-Lisp; coding: iso-2022-7bit; -*-
2 ;;; tramp.el --- Transparent Remote Access, Multiple Protocol
4 ;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
6 ;; Author: kai.grossjohann@gmx.net
7 ;; Keywords: comm, processes
9 ;; This file is part of GNU Emacs.
11 ;; GNU Emacs is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; any later version.
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
26 ;;; Commentary:
28 ;; This package provides remote file editing, similar to ange-ftp.
29 ;; The difference is that ange-ftp uses FTP to transfer files between
30 ;; the local and the remote host, whereas tramp.el uses a combination
31 ;; of rsh and rcp or other work-alike programs, such as ssh/scp.
33 ;; For more detailed instructions, please see the info file.
35 ;; Notes:
36 ;; -----
37 ;;
38 ;; This package only works for Emacs 20 and higher, and for XEmacs 21
39 ;; and higher. (XEmacs 20 is missing the `with-timeout' macro. Emacs
40 ;; 19 is reported to have other problems. For XEmacs 21, you need the
41 ;; package `fsf-compat' for the `with-timeout' macro.)
43 ;; This version might not work with pre-Emacs 21 VC unless VC is
44 ;; loaded before tramp.el. Could you please test this and tell me about
45 ;; the result? Thanks.
47 ;; Also see the todo list at the bottom of this file.
49 ;; The current version of Tramp can be retrieved from the following URL:
50 ;; http://savannah.nongnu.org/download/tramp/
52 ;; There's a mailing list for this, as well. Its name is:
53 ;; tramp-devel@mail.freesoftware.fsf.org
54 ;; Send a mail with `help' in the subject (!) to the administration
55 ;; address for instructions on joining the list. The administration
56 ;; address is:
57 ;; tramp-devel-request@mail.freesoftware.fsf.org
58 ;; You can also use the Web to subscribe, under the following URL:
59 ;; http://mail.freesoftware.fsf.org/mailman/listinfo/tramp-devel
61 ;; For the adventurous, the current development sources are available
62 ;; via CVS. You can find instructions about this at the following URL:
63 ;; http://savannah.gnu.org/projects/tramp/
64 ;; Click on "CVS" in the navigation bar near the top.
66 ;; Don't forget to put on your asbestos longjohns, first!
68 ;;; Code:
70 ;; The Tramp version number and bug report address, as prepared by configure.
71 (require 'trampver)
73 (require 'timer)
74 (require 'format-spec) ;from Gnus 5.8, also in tar ball
75 ;; The explicit check is not necessary in Emacs, which provides the
76 ;; feature even if implemented in C, but it appears to be necessary
77 ;; in XEmacs.
78 (unless (and (fboundp 'base64-encode-region)
79 (fboundp 'base64-decode-region))
80 (require 'base64)) ;for the mimencode methods
81 (require 'shell)
82 (require 'advice)
84 (autoload 'tramp-uuencode-region "tramp-uu"
85 "Implementation of `uuencode' in Lisp.")
87 (unless (fboundp 'uudecode-decode-region)
88 (autoload 'uudecode-decode-region "uudecode"))
90 ;; XEmacs is distributed with few Lisp packages. Further packages are
91 ;; installed using EFS. If we use a unified filename format, then
92 ;; Tramp is required in addition to EFS. (But why can't Tramp just
93 ;; disable EFS when Tramp is loaded? Then XEmacs can ship with EFS
94 ;; just like before.) Another reason for using a separate filename
95 ;; syntax on XEmacs is that EFS hooks into XEmacs in many places, but
96 ;; Tramp only knows how to deal with `file-name-handler-alist', not
97 ;; the other places.
98 ;;;###autoload
99 (defvar tramp-unified-filenames (not (featurep 'xemacs))
100 "Non-nil means to use unified Ange-FTP/Tramp filename syntax.
101 Nil means to use a separate filename syntax for Tramp.")
103 ;; Load foreign methods. Because they do require Tramp internally, this
104 ;; must be done with the `eval-after-load' trick.
106 ;; tramp-ftp supports Ange-FTP only. Not suited for XEmacs therefore.
107 (unless (featurep 'xemacs)
108 (eval-after-load "tramp"
109 '(require 'tramp-ftp)))
110 (when (and tramp-unified-filenames (featurep 'xemacs))
111 (eval-after-load "tramp"
112 '(require 'tramp-efs)))
114 ;; tramp-smb uses "smbclient" from Samba.
115 ;; Not available under Cygwin and Windows, because they don't offer
116 ;; "smbclient". And even not necessary there, because Emacs supports
117 ;; UNC file names like "//host/share/localname".
118 (unless (memq system-type '(cygwin windows-nt))
119 (eval-after-load "tramp"
120 '(require 'tramp-smb)))
122 (eval-when-compile
123 (require 'cl)
124 (require 'custom)
125 ;; Emacs 19.34 compatibility hack -- is this needed?
126 (or (>= emacs-major-version 20)
127 (load "cl-seq")))
129 (unless (boundp 'custom-print-functions)
130 (defvar custom-print-functions nil)) ; not autoloaded before Emacs 20.4
132 ;; Avoid bytecompiler warnings if the byte-compiler supports this.
133 ;; Currently, XEmacs supports this.
134 (eval-when-compile
135 (when (fboundp 'byte-compiler-options)
136 (byte-compiler-options (warnings (- unused-vars)))))
138 ;;; User Customizable Internal Variables:
140 (defgroup tramp nil
141 "Edit remote files with a combination of rsh and rcp or similar programs."
142 :group 'files)
144 (defcustom tramp-verbose 9
145 "*Verbosity level for tramp.el. 0 means be silent, 10 is most verbose."
146 :group 'tramp
147 :type 'integer)
149 (defcustom tramp-debug-buffer nil
150 "*Whether to send all commands and responses to a debug buffer."
151 :group 'tramp
152 :type 'boolean)
154 (defcustom tramp-auto-save-directory nil
155 "*Put auto-save files in this directory, if set.
156 The idea is to use a local directory so that auto-saving is faster."
157 :group 'tramp
158 :type '(choice (const nil)
159 string))
161 (defcustom tramp-encoding-shell
162 (if (memq system-type '(windows-nt))
163 (getenv "COMSPEC")
164 "/bin/sh")
165 "*Use this program for encoding and decoding commands on the local host.
166 This shell is used to execute the encoding and decoding command on the
167 local host, so if you want to use `~' in those commands, you should
168 choose a shell here which groks tilde expansion. `/bin/sh' normally
169 does not understand tilde expansion.
171 For encoding and deocding, commands like the following are executed:
173 /bin/sh -c COMMAND < INPUT > OUTPUT
175 This variable can be used to change the \"/bin/sh\" part. See the
176 variable `tramp-encoding-command-switch' for the \"-c\" part. Also, see the
177 variable `tramp-encoding-reads-stdin' to specify whether the commands read
178 standard input or a file.
180 Note that this variable is not used for remote commands. There are
181 mechanisms in tramp.el which automatically determine the right shell to
182 use for the remote host."
183 :group 'tramp
184 :type '(file :must-match t))
186 (defcustom tramp-encoding-command-switch
187 (if (string-match "cmd\\.exe" tramp-encoding-shell)
188 "/c"
189 "-c")
190 "*Use this switch together with `tramp-encoding-shell' for local commands.
191 See the variable `tramp-encoding-shell' for more information."
192 :group 'tramp
193 :type 'string)
195 (defcustom tramp-encoding-reads-stdin t
196 "*If non-nil, encoding commands read from standard input.
197 If nil, the filename is the last argument.
199 Note that the commands always must write to standard output."
200 :group 'tramp
201 :type 'boolean)
203 (defcustom tramp-multi-sh-program
204 tramp-encoding-shell
205 "*Use this program for bootstrapping multi-hop connections.
206 This variable is similar to `tramp-encoding-shell', but it is only used
207 when initializing a multi-hop connection. Therefore, the set of
208 commands sent to this shell is quite restricted, and if you are
209 careful it works to use CMD.EXE under Windows (instead of a Bourne-ish
210 shell which does not normally exist on Windows anyway).
212 To use multi-hop methods from Windows, you also need suitable entries
213 in `tramp-multi-connection-function-alist' for the first hop.
215 This variable defaults to the value of `tramp-encoding-shell'."
216 :group 'tramp
217 :type '(file :must-match t))
219 ;; CCC I have changed all occurrences of comint-quote-filename with
220 ;; tramp-shell-quote-argument, except in tramp-handle-expand-many-files.
221 ;; There, comint-quote-filename was removed altogether. If it turns
222 ;; out to be necessary there, something will need to be done.
223 ;;-(defcustom tramp-file-name-quote-list
224 ;;- '(?] ?[ ?\| ?& ?< ?> ?\( ?\) ?\; ?\ ?\* ?\? ?\! ?\" ?\' ?\` ?# ?\@ ?\+ )
225 ;;- "*Protect these characters from the remote shell.
226 ;;-Any character in this list is quoted (preceded with a backslash)
227 ;;-because it means something special to the shell. This takes effect
228 ;;-when sending file and directory names to the remote shell.
230 ;;-See `comint-file-name-quote-list' for details."
231 ;;- :group 'tramp
232 ;;- :type '(repeat character))
234 (defcustom tramp-methods
235 '( ("rcp" (tramp-connection-function tramp-open-connection-rsh)
236 (tramp-login-program "rsh")
237 (tramp-copy-program "rcp")
238 (tramp-remote-sh "/bin/sh")
239 (tramp-login-args nil)
240 (tramp-copy-args nil)
241 (tramp-copy-keep-date-arg "-p"))
242 ("scp" (tramp-connection-function tramp-open-connection-rsh)
243 (tramp-login-program "ssh")
244 (tramp-copy-program "scp")
245 (tramp-remote-sh "/bin/sh")
246 (tramp-login-args ("-e" "none"))
247 (tramp-copy-args nil)
248 (tramp-copy-keep-date-arg "-p"))
249 ("scp1" (tramp-connection-function tramp-open-connection-rsh)
250 (tramp-login-program "ssh")
251 (tramp-copy-program "scp")
252 (tramp-remote-sh "/bin/sh")
253 (tramp-login-args ("-1" "-e" "none"))
254 (tramp-copy-args ("-1"))
255 (tramp-copy-keep-date-arg "-p"))
256 ("scp2" (tramp-connection-function tramp-open-connection-rsh)
257 (tramp-login-program "ssh")
258 (tramp-copy-program "scp")
259 (tramp-remote-sh "/bin/sh")
260 (tramp-login-args ("-2" "-e" "none"))
261 (tramp-copy-args ("-2"))
262 (tramp-copy-keep-date-arg "-p"))
263 ("scp1_old"
264 (tramp-connection-function tramp-open-connection-rsh)
265 (tramp-login-program "ssh1")
266 (tramp-copy-program "scp1")
267 (tramp-remote-sh "/bin/sh")
268 (tramp-login-args ("-e" "none"))
269 (tramp-copy-args nil)
270 (tramp-copy-keep-date-arg "-p"))
271 ("scp2_old"
272 (tramp-connection-function tramp-open-connection-rsh)
273 (tramp-login-program "ssh2")
274 (tramp-copy-program "scp2")
275 (tramp-remote-sh "/bin/sh")
276 (tramp-login-args ("-e" "none"))
277 (tramp-copy-args nil)
278 (tramp-copy-keep-date-arg "-p"))
279 ("rsync" (tramp-connection-function tramp-open-connection-rsh)
280 (tramp-login-program "ssh")
281 (tramp-copy-program "rsync")
282 (tramp-remote-sh "/bin/sh")
283 (tramp-login-args ("-e" "none"))
284 (tramp-copy-args ("-e" "ssh"))
285 (tramp-copy-keep-date-arg "-t"))
286 ("remcp" (tramp-connection-function tramp-open-connection-rsh)
287 (tramp-login-program "remsh")
288 (tramp-copy-program "rcp")
289 (tramp-remote-sh "/bin/sh")
290 (tramp-login-args nil)
291 (tramp-copy-args nil)
292 (tramp-copy-keep-date-arg "-p"))
293 ("rsh" (tramp-connection-function tramp-open-connection-rsh)
294 (tramp-login-program "rsh")
295 (tramp-copy-program nil)
296 (tramp-remote-sh "/bin/sh")
297 (tramp-login-args nil)
298 (tramp-copy-args nil)
299 (tramp-copy-keep-date-arg nil))
300 ("ssh" (tramp-connection-function tramp-open-connection-rsh)
301 (tramp-login-program "ssh")
302 (tramp-copy-program nil)
303 (tramp-remote-sh "/bin/sh")
304 (tramp-login-args ("-e" "none"))
305 (tramp-copy-args nil)
306 (tramp-copy-keep-date-arg nil))
307 ("ssh1" (tramp-connection-function tramp-open-connection-rsh)
308 (tramp-login-program "ssh")
309 (tramp-copy-program nil)
310 (tramp-remote-sh "/bin/sh")
311 (tramp-login-args ("-1" "-e" "none"))
312 (tramp-copy-args ("-1"))
313 (tramp-copy-keep-date-arg nil))
314 ("ssh2" (tramp-connection-function tramp-open-connection-rsh)
315 (tramp-login-program "ssh")
316 (tramp-copy-program nil)
317 (tramp-remote-sh "/bin/sh")
318 (tramp-login-args ("-2" "-e" "none"))
319 (tramp-copy-args ("-2"))
320 (tramp-copy-keep-date-arg nil))
321 ("ssh1_old"
322 (tramp-connection-function tramp-open-connection-rsh)
323 (tramp-login-program "ssh1")
324 (tramp-copy-program nil)
325 (tramp-remote-sh "/bin/sh")
326 (tramp-login-args ("-e" "none"))
327 (tramp-copy-args nil)
328 (tramp-copy-keep-date-arg nil))
329 ("ssh2_old"
330 (tramp-connection-function tramp-open-connection-rsh)
331 (tramp-login-program "ssh2")
332 (tramp-copy-program nil)
333 (tramp-remote-sh "/bin/sh")
334 (tramp-login-args ("-e" "none"))
335 (tramp-copy-args nil)
336 (tramp-copy-keep-date-arg nil))
337 ("remsh" (tramp-connection-function tramp-open-connection-rsh)
338 (tramp-login-program "remsh")
339 (tramp-copy-program nil)
340 (tramp-remote-sh "/bin/sh")
341 (tramp-login-args nil)
342 (tramp-copy-args nil)
343 (tramp-copy-keep-date-arg nil))
344 ("telnet"
345 (tramp-connection-function tramp-open-connection-telnet)
346 (tramp-login-program "telnet")
347 (tramp-copy-program nil)
348 (tramp-remote-sh "/bin/sh")
349 (tramp-login-args nil)
350 (tramp-copy-args nil)
351 (tramp-copy-keep-date-arg nil))
352 ("su" (tramp-connection-function tramp-open-connection-su)
353 (tramp-login-program "su")
354 (tramp-copy-program nil)
355 (tramp-remote-sh "/bin/sh")
356 (tramp-login-args ("-" "%u"))
357 (tramp-copy-args nil)
358 (tramp-copy-keep-date-arg nil))
359 ("sudo" (tramp-connection-function tramp-open-connection-su)
360 (tramp-login-program "sudo")
361 (tramp-copy-program nil)
362 (tramp-remote-sh "/bin/sh")
363 (tramp-login-args ("-u" "%u" "-s"
364 "-p" "Password:"))
365 (tramp-copy-args nil)
366 (tramp-copy-keep-date-arg nil))
367 ("multi" (tramp-connection-function tramp-open-connection-multi)
368 (tramp-login-program nil)
369 (tramp-copy-program nil)
370 (tramp-remote-sh "/bin/sh")
371 (tramp-login-args nil)
372 (tramp-copy-args nil)
373 (tramp-copy-keep-date-arg nil))
374 ("scpx" (tramp-connection-function tramp-open-connection-rsh)
375 (tramp-login-program "ssh")
376 (tramp-copy-program "scp")
377 (tramp-remote-sh "/bin/sh")
378 (tramp-login-args ("-e" "none" "-t" "-t" "/bin/sh"))
379 (tramp-copy-args nil)
380 (tramp-copy-keep-date-arg "-p"))
381 ("sshx" (tramp-connection-function tramp-open-connection-rsh)
382 (tramp-login-program "ssh")
383 (tramp-copy-program nil)
384 (tramp-remote-sh "/bin/sh")
385 (tramp-login-args ("-e" "none" "-t" "-t" "/bin/sh"))
386 (tramp-copy-args nil)
387 (tramp-copy-keep-date-arg nil))
388 ("krlogin"
389 (tramp-connection-function tramp-open-connection-rsh)
390 (tramp-login-program "krlogin")
391 (tramp-copy-program nil)
392 (tramp-remote-sh "/bin/sh")
393 (tramp-login-args ("-x"))
394 (tramp-copy-args nil)
395 (tramp-copy-keep-date-arg nil))
396 ("plink"
397 (tramp-connection-function tramp-open-connection-rsh)
398 (tramp-login-program "plink")
399 (tramp-copy-program nil)
400 (tramp-remote-sh "/bin/sh")
401 (tramp-login-args ("-ssh")) ;optionally add "-v"
402 (tramp-copy-args nil)
403 (tramp-copy-keep-date-arg nil))
404 ("plink1"
405 (tramp-connection-function tramp-open-connection-rsh)
406 (tramp-login-program "plink")
407 (tramp-copy-program nil)
408 (tramp-remote-sh "/bin/sh")
409 (tramp-login-args ("-1" "-ssh")) ;optionally add "-v"
410 (tramp-copy-args nil)
411 (tramp-copy-keep-date-arg nil))
412 ("pscp"
413 (tramp-connection-function tramp-open-connection-rsh)
414 (tramp-login-program "plink")
415 (tramp-copy-program "pscp")
416 (tramp-remote-sh "/bin/sh")
417 (tramp-login-args ("-ssh"))
418 (tramp-copy-args nil)
419 (tramp-copy-keep-date-arg "-p"))
420 ("fcp"
421 (tramp-connection-function tramp-open-connection-rsh)
422 (tramp-login-program "fsh")
423 (tramp-copy-program "fcp")
424 (tramp-remote-sh "/bin/sh -i")
425 (tramp-login-args ("sh" "-i"))
426 (tramp-copy-args nil)
427 (tramp-copy-keep-date-arg "-p"))
429 "*Alist of methods for remote files.
430 This is a list of entries of the form (NAME PARAM1 PARAM2 ...).
431 Each NAME stands for a remote access method. Each PARAM is a
432 pair of the form (KEY VALUE). The following KEYs are defined:
433 * `tramp-connection-function'
434 This specifies the function to use to connect to the remote host.
435 Currently, `tramp-open-connection-rsh', `tramp-open-connection-telnet'
436 and `tramp-open-connection-su' are defined. See the documentation
437 of these functions for more details.
438 * `tramp-remote-sh'
439 This specifies the Bourne shell to use on the remote host. This
440 MUST be a Bourne-like shell. It is normally not necessary to set
441 this to any value other than \"/bin/sh\": tramp wants to use a shell
442 which groks tilde expansion, but it can search for it. Also note
443 that \"/bin/sh\" exists on all Unixen, this might not be true for
444 the value that you decide to use. You Have Been Warned.
445 * `tramp-login-program'
446 This specifies the name of the program to use for logging in to the
447 remote host. Depending on `tramp-connection-function', this may be
448 the name of rsh or a workalike program (when
449 `tramp-connection-function' is `tramp-open-connection-rsh'), or the
450 name of telnet or a workalike (for `tramp-open-connection-telnet'),
451 or the name of su or a workalike (for `tramp-open-connection-su').
452 * `tramp-login-args'
453 This specifies the list of arguments to pass to the above
454 mentioned program. Please note that this is a list of arguments,
455 that is, normally you don't want to put \"-a -b\" or \"-f foo\"
456 here. Instead, you want two list elements, one for \"-a\" and one
457 for \"-b\", or one for \"-f\" and one for \"foo\".
458 If `tramp-connection-function' is `tramp-open-connection-su', then
459 \"%u\" in this list is replaced by the user name, and \"%%\" can
460 be used to obtain a literal percent character.
461 * `tramp-copy-program'
462 This specifies the name of the program to use for remotely copying
463 the file; this might be the absolute filename of rcp or the name of
464 a workalike program.
465 * `tramp-copy-args'
466 This specifies the list of parameters to pass to the above mentioned
467 program, the hints for `tramp-login-args' also apply here.
468 * `tramp-copy-keep-date-arg'
469 This specifies the parameter to use for the copying program when the
470 timestamp of the original file should be kept. For `rcp', use `-p', for
471 `rsync', use `-t'.
473 What does all this mean? Well, you should specify `tramp-login-program'
474 for all methods; this program is used to log in to the remote site. Then,
475 there are two ways to actually transfer the files between the local and the
476 remote side. One way is using an additional rcp-like program. If you want
477 to do this, set `tramp-copy-program' in the method.
479 Another possibility for file transfer is inline transfer, i.e. the
480 file is passed through the same buffer used by `tramp-login-program'. In
481 this case, the file contents need to be protected since the
482 `tramp-login-program' might use escape codes or the connection might not
483 be eight-bit clean. Therefore, file contents are encoded for transit.
484 See the variable `tramp-coding-commands' for details.
486 So, to summarize: if the method is an out-of-band method, then you
487 must specify `tramp-copy-program' and `tramp-copy-args'. If it is an
488 inline method, then these two parameters should be nil. Every method,
489 inline or out of band, must specify `tramp-connection-function' plus
490 the associated arguments (for example, the login program if you chose
491 `tramp-open-connection-telnet').
493 Notes:
495 When using `tramp-open-connection-su' the phrase `open connection to a
496 remote host' sounds strange, but it is used nevertheless, for
497 consistency. No connection is opened to a remote host, but `su' is
498 started on the local host. You are not allowed to specify a remote
499 host other than `localhost' or the name of the local host."
500 :group 'tramp
501 :type '(repeat
502 (cons string
503 (set (list (const tramp-connection-function) function)
504 (list (const tramp-login-program)
505 (choice (const nil) string))
506 (list (const tramp-copy-program)
507 (choice (const nil) string))
508 (list (const tramp-remote-sh)
509 (choice (const nil) string))
510 (list (const tramp-login-args) (repeat string))
511 (list (const tramp-copy-args) (repeat string))
512 (list (const tramp-copy-keep-date-arg)
513 (choice (const nil) string))
514 (list (const tramp-encoding-command)
515 (choice (const nil) string))
516 (list (const tramp-decoding-command)
517 (choice (const nil) string))
518 (list (const tramp-encoding-function)
519 (choice (const nil) function))
520 (list (const tramp-decoding-function)
521 (choice (const nil) function))))))
523 (defcustom tramp-multi-methods '("multi" "multiu")
524 "*List of multi-hop methods.
525 Each entry in this list should be a method name as mentioned in the
526 variable `tramp-methods'."
527 :group 'tramp
528 :type '(repeat string))
530 (defcustom tramp-multi-connection-function-alist
531 '(("telnet" tramp-multi-connect-telnet "telnet %h%n")
532 ("rsh" tramp-multi-connect-rlogin "rsh %h -l %u%n")
533 ("remsh" tramp-multi-connect-rlogin "remsh %h -l %u%n")
534 ("ssh" tramp-multi-connect-rlogin "ssh %h -l %u%n")
535 ("su" tramp-multi-connect-su "su - %u%n")
536 ("sudo" tramp-multi-connect-su "sudo -u %u -s -p Password:%n"))
537 "*List of connection functions for multi-hop methods.
538 Each list item is a list of three items (METHOD FUNCTION COMMAND),
539 where METHOD is the name as used in the file name, FUNCTION is the
540 function to be executed, and COMMAND is the shell command used for
541 connecting.
543 COMMAND may contain percent escapes. `%u' will be replaced with the
544 user name, `%h' will be replaced with the host name, and `%n' will be
545 replaced with an end-of-line character, as specified in the variable
546 `tramp-rsh-end-of-line'. Use `%%' for a literal percent character.
547 Note that the interpretation of the percent escapes also depends on
548 the FUNCTION. For example, the `%u' escape is forbidden with the
549 function `tramp-multi-connect-telnet'. See the documentation of the
550 various functions for details."
551 :group 'tramp
552 :type '(repeat (list string function string)))
554 (defcustom tramp-default-method
555 (if (and (fboundp 'executable-find)
556 (executable-find "plink"))
557 "plink"
558 "ssh")
559 "*Default method to use for transferring files.
560 See `tramp-methods' for possibilities.
561 Also see `tramp-default-method-alist'."
562 :group 'tramp
563 :type 'string)
565 (defcustom tramp-default-method-alist
566 '(("\\`localhost\\'" "\\`root\\'" "su"))
567 "*Default method to use for specific user/host pairs.
568 This is an alist of items (HOST USER METHOD). The first matching item
569 specifies the method to use for a file name which does not specify a
570 method. HOST and USER are regular expressions or nil, which is
571 interpreted as a regular expression which always matches. If no entry
572 matches, the variable `tramp-default-method' takes effect.
574 If the file name does not specify the user, lookup is done using the
575 empty string for the user name.
577 See `tramp-methods' for a list of possibilities for METHOD."
578 :group 'tramp
579 :type '(repeat (list (regexp :tag "Host regexp")
580 (regexp :tag "User regexp")
581 (string :tag "Method"))))
583 ;; Default values for non-Unices seeked
584 (defconst tramp-completion-function-alist-rsh
585 (unless (memq system-type '(windows-nt))
586 '((tramp-parse-rhosts "/etc/hosts.equiv")
587 (tramp-parse-rhosts "~/.rhosts")))
588 "Default list of (FUNCTION FILE) pairs to be examined for rsh methods.")
590 ;; Default values for non-Unices seeked
591 (defconst tramp-completion-function-alist-ssh
592 (unless (memq system-type '(windows-nt))
593 '((tramp-parse-rhosts "/etc/hosts.equiv")
594 (tramp-parse-rhosts "/etc/shosts.equiv")
595 (tramp-parse-shosts "/etc/ssh_known_hosts")
596 (tramp-parse-sconfig "/etc/ssh_config")
597 (tramp-parse-rhosts "~/.rhosts")
598 (tramp-parse-rhosts "~/.shosts")
599 (tramp-parse-shosts "~/.ssh/known_hosts")
600 (tramp-parse-sconfig "~/.ssh/config")))
601 "Default list of (FUNCTION FILE) pairs to be examined for ssh methods.")
603 ;; Default values for non-Unices seeked
604 (defconst tramp-completion-function-alist-telnet
605 (unless (memq system-type '(windows-nt))
606 '((tramp-parse-hosts "/etc/hosts")))
607 "Default list of (FUNCTION FILE) pairs to be examined for telnet methods.")
609 ;; Default values for non-Unices seeked
610 (defconst tramp-completion-function-alist-su
611 (unless (memq system-type '(windows-nt))
612 '((tramp-parse-passwd "/etc/passwd")))
613 "Default list of (FUNCTION FILE) pairs to be examined for su methods.")
615 (defcustom tramp-completion-function-alist
616 (list (cons "rcp" tramp-completion-function-alist-rsh)
617 (cons "scp" tramp-completion-function-alist-ssh)
618 (cons "scp1" tramp-completion-function-alist-ssh)
619 (cons "scp2" tramp-completion-function-alist-ssh)
620 (cons "scp1_old" tramp-completion-function-alist-ssh)
621 (cons "scp2_old" tramp-completion-function-alist-ssh)
622 (cons "rsync" tramp-completion-function-alist-rsh)
623 (cons "remcp" tramp-completion-function-alist-rsh)
624 (cons "rsh" tramp-completion-function-alist-rsh)
625 (cons "ssh" tramp-completion-function-alist-ssh)
626 (cons "ssh1" tramp-completion-function-alist-ssh)
627 (cons "ssh2" tramp-completion-function-alist-ssh)
628 (cons "ssh1_old" tramp-completion-function-alist-ssh)
629 (cons "ssh2_old" tramp-completion-function-alist-ssh)
630 (cons "remsh" tramp-completion-function-alist-rsh)
631 (cons "telnet" tramp-completion-function-alist-telnet)
632 (cons "su" tramp-completion-function-alist-su)
633 (cons "sudo" tramp-completion-function-alist-su)
634 (cons "multi" nil)
635 (cons "scpx" tramp-completion-function-alist-ssh)
636 (cons "sshx" tramp-completion-function-alist-ssh)
637 (cons "krlogin" tramp-completion-function-alist-rsh)
638 (cons "plink" tramp-completion-function-alist-ssh)
639 (cons "plink1" tramp-completion-function-alist-ssh)
640 (cons "pscp" tramp-completion-function-alist-ssh)
641 (cons "fcp" tramp-completion-function-alist-ssh)
643 "*Alist of methods for remote files.
644 This is a list of entries of the form (NAME PAIR1 PAIR2 ...).
645 Each NAME stands for a remote access method. Each PAIR is of the form
646 \(FUNCTION FILE). FUNCTION is responsible to extract user names and host
647 names from FILE for completion. The following predefined FUNCTIONs exists:
649 * `tramp-parse-rhosts' for \"~/.rhosts\" like files,
650 * `tramp-parse-shosts' for \"~/.ssh/known_hosts\" like files,
651 * `tramp-parse-sconfig' for \"~/.ssh/config\" like files,
652 * `tramp-parse-hosts' for \"/etc/hosts\" like files, and
653 * `tramp-parse-passwd' for \"/etc/passwd\" like files.
654 * `tramp-parse-netrc' for \"~/.netrc\" like files.
656 FUNCTION can also see a customer defined function. For more details see
657 the info pages."
658 :group 'tramp
659 :type '(repeat
660 (cons string
661 (choice (const nil) (repeat (list function file))))))
663 (defcustom tramp-rsh-end-of-line "\n"
664 "*String used for end of line in rsh connections.
665 I don't think this ever needs to be changed, so please tell me about it
666 if you need to change this.
667 Also see `tramp-password-end-of-line'."
668 :group 'tramp
669 :type 'string)
671 (defcustom tramp-password-end-of-line
672 (if (string-match "plink" tramp-default-method)
673 ;; Any two characters will do for plink! Doesn't have to be
674 ;; newline characters.
675 "xy"
676 tramp-rsh-end-of-line)
677 "*String used for end of line after sending a password.
678 It seems that people using plink under Windows need to send
679 \"\\r\\n\" (carriage-return, then newline) after a password, but just
680 \"\\n\" after all other lines. This variable can be used for the
681 password, see `tramp-rsh-end-of-line' for the other cases.
683 The default value is to use the same value as `tramp-rsh-end-of-line'."
684 :group 'tramp
685 :type 'string)
687 (defcustom tramp-remote-path
688 '("/bin" "/usr/bin" "/usr/sbin" "/usr/local/bin" "/usr/ccs/bin"
689 "/local/bin" "/local/freeware/bin" "/local/gnu/bin"
690 "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin")
691 "*List of directories to search for executables on remote host.
692 Please notify me about other semi-standard directories to include here.
694 You can use `~' in this list, but when searching for a shell which groks
695 tilde expansion, all directory names starting with `~' will be ignored."
696 :group 'tramp
697 :type '(repeat string))
699 (defcustom tramp-login-prompt-regexp
700 ".*ogin: *"
701 "*Regexp matching login-like prompts.
702 The regexp should match at end of buffer."
703 :group 'tramp
704 :type 'regexp)
706 (defcustom tramp-shell-prompt-pattern
707 "^[^#$%>\n]*[#$%>] *\\(\e\\[[0-9;]*[a-zA-Z] *\\)*"
708 "Regexp to match prompts from remote shell.
709 Normally, Tramp expects you to configure `shell-prompt-pattern'
710 correctly, but sometimes it happens that you are connecting to a
711 remote host which sends a different kind of shell prompt. Therefore,
712 Tramp recognizes things matched by `shell-prompt-pattern' as prompt,
713 and also things matched by this variable. The default value of this
714 variable is similar to the default value of `shell-prompt-pattern',
715 which should work well in many cases."
716 :group 'tramp
717 :type 'regexp)
719 (defcustom tramp-password-prompt-regexp
720 "^.*\\([pP]assword\\|passphrase.*\\):\^@? *"
721 "*Regexp matching password-like prompts.
722 The regexp should match at end of buffer.
724 The `sudo' program appears to insert a `^@' character into the prompt."
725 :group 'tramp
726 :type 'regexp)
728 (defcustom tramp-wrong-passwd-regexp
729 (concat "^.*"
730 ;; These strings should be on the last line
731 (regexp-opt '("Permission denied."
732 "Login incorrect"
733 "Login Incorrect"
734 "Connection refused"
735 "Connection closed"
736 "Sorry, try again."
737 "Name or service not known"
738 "Host key verification failed.") t)
739 ".*"
740 "\\|"
741 "^.*\\("
742 ;; Here comes a list of regexes, separated by \\|
743 "Received signal [0-9]+"
744 "\\).*")
745 "*Regexp matching a `login failed' message.
746 The regexp should match at end of buffer."
747 :group 'tramp
748 :type 'regexp)
750 (defcustom tramp-yesno-prompt-regexp
751 (concat
752 (regexp-opt '("Are you sure you want to continue connecting (yes/no)?") t)
753 "\\s-*")
754 "Regular expression matching all yes/no queries which need to be confirmed.
755 The confirmation should be done with yes or no.
756 The regexp should match at end of buffer.
757 See also `tramp-yn-prompt-regexp'."
758 :group 'tramp
759 :type 'regexp)
761 (defcustom tramp-yn-prompt-regexp
762 (concat (regexp-opt '("Store key in cache? (y/n)") t)
763 "\\s-*")
764 "Regular expression matching all y/n queries which need to be confirmed.
765 The confirmation should be done with y or n.
766 The regexp should match at end of buffer.
767 See also `tramp-yesno-prompt-regexp'."
768 :group 'tramp
769 :type 'regexp)
771 (defcustom tramp-terminal-prompt-regexp
772 (concat "\\("
773 "TERM = (.*)"
774 "\\|"
775 "Terminal type\\? \\[.*\\]"
776 "\\)\\s-*")
777 "Regular expression matching all terminal setting prompts.
778 The regexp should match at end of buffer.
779 The answer will be provided by `tramp-action-terminal', which see."
780 :group 'tramp
781 :type 'regexp)
783 (defcustom tramp-temp-name-prefix "tramp."
784 "*Prefix to use for temporary files.
785 If this is a relative file name (such as \"tramp.\"), it is considered
786 relative to the directory name returned by the function
787 `tramp-temporary-file-directory' (which see). It may also be an
788 absolute file name; don't forget to include a prefix for the filename
789 part, though."
790 :group 'tramp
791 :type 'string)
793 (defcustom tramp-discard-garbage nil
794 "*If non-nil, try to discard garbage sent by remote shell.
795 Some shells send such garbage upon connection setup."
796 :group 'tramp
797 :type 'boolean)
799 (defcustom tramp-sh-extra-args '(("/bash\\'" . "-norc -noprofile"))
800 "*Alist specifying extra arguments to pass to the remote shell.
801 Entries are (REGEXP . ARGS) where REGEXP is a regular expression
802 matching the shell file name and ARGS is a string specifying the
803 arguments.
805 This variable is only used when Tramp needs to start up another shell
806 for tilde expansion. The extra arguments should typically prevent the
807 shell from reading its init file."
808 :group 'tramp
809 :type '(alist :key-type string :value-type string))
811 (defcustom tramp-prefix-format
812 (if tramp-unified-filenames "/" "/[")
813 "*String matching the very beginning of tramp file names.
814 Used in `tramp-make-tramp-file-name' and `tramp-make-tramp-multi-file-name'."
815 :group 'tramp
816 :type 'string)
818 (defcustom tramp-prefix-regexp
819 (concat "^" (regexp-quote tramp-prefix-format))
820 "*Regexp matching the very beginning of tramp file names.
821 Should always start with \"^\". Derived from `tramp-prefix-format'."
822 :group 'tramp
823 :type 'regexp)
825 (defcustom tramp-method-regexp
826 "[a-zA-Z_0-9-]+"
827 "*Regexp matching methods identifiers."
828 :group 'tramp
829 :type 'regexp)
831 ;; It is a little bit annoying that in XEmacs case this delimeter is different
832 ;; for single-hop and multi-hop cases.
833 (defcustom tramp-postfix-single-method-format
834 (if tramp-unified-filenames ":" "/")
835 "*String matching delimeter between method and user or host names.
836 Applicable for single-hop methods.
837 Used in `tramp-make-tramp-file-name'."
838 :group 'tramp
839 :type 'string)
841 (defcustom tramp-postfix-single-method-regexp
842 (regexp-quote tramp-postfix-single-method-format)
843 "*Regexp matching delimeter between method and user or host names.
844 Applicable for single-hop methods.
845 Derived from `tramp-postfix-single-method-format'."
846 :group 'tramp
847 :type 'regexp)
849 (defcustom tramp-postfix-multi-method-format
851 "*String matching delimeter between method and user or host names.
852 Applicable for multi-hop methods.
853 Used in `tramp-make-tramp-multi-file-name'."
854 :group 'tramp
855 :type 'string)
857 (defcustom tramp-postfix-multi-method-regexp
858 (regexp-quote tramp-postfix-multi-method-format)
859 "*Regexp matching delimeter between method and user or host names.
860 Applicable for multi-hop methods.
861 Derived from `tramp-postfix-multi-method-format'."
862 :group 'tramp
863 :type 'regexp)
865 (defcustom tramp-postfix-multi-hop-format
866 (if tramp-unified-filenames ":" "/")
867 "*String matching delimeter between host and next method.
868 Applicable for multi-hop methods.
869 Used in `tramp-make-tramp-multi-file-name'."
870 :group 'tramp
871 :type 'string)
873 (defcustom tramp-postfix-multi-hop-regexp
874 (regexp-quote tramp-postfix-multi-hop-format)
875 "*Regexp matching delimeter between host and next method.
876 Applicable for multi-hop methods.
877 Derived from `tramp-postfix-multi-hop-format'."
878 :group 'tramp
879 :type 'regexp)
881 (defcustom tramp-user-regexp
882 "[^:@/ \t]*"
883 "*Regexp matching user names."
884 :group 'tramp
885 :type 'regexp)
887 (defcustom tramp-postfix-user-format
889 "*String matching delimeter between user and host names.
890 Used in `tramp-make-tramp-file-name' and `tramp-make-tramp-multi-file-name'."
891 :group 'tramp
892 :type 'string)
894 (defcustom tramp-postfix-user-regexp
895 (regexp-quote tramp-postfix-user-format)
896 "*Regexp matching delimeter between user and host names.
897 Derived from `tramp-postfix-user-format'."
898 :group 'tramp
899 :type 'regexp)
901 (defcustom tramp-host-regexp
902 "[a-zA-Z0-9_.-]*"
903 "*Regexp matching host names."
904 :group 'tramp
905 :type 'regexp)
907 (defcustom tramp-host-with-port-regexp
908 "[a-zA-Z0-9_.#-]*"
909 "*Regexp matching host names."
910 :group 'tramp
911 :type 'regexp)
913 (defcustom tramp-postfix-host-format
914 (if tramp-unified-filenames ":" "]")
915 "*String matching delimeter between host names and localnames.
916 Used in `tramp-make-tramp-file-name' and `tramp-make-tramp-multi-file-name'."
917 :group 'tramp
918 :type 'string)
920 (defcustom tramp-postfix-host-regexp
921 (regexp-quote tramp-postfix-host-format)
922 "*Regexp matching delimeter between host names and localnames.
923 Derived from `tramp-postfix-host-format'."
924 :group 'tramp
925 :type 'regexp)
927 (defcustom tramp-localname-regexp
928 ".*$"
929 "*Regexp matching localnames."
930 :group 'tramp
931 :type 'regexp)
933 ;; File name format.
935 (defcustom tramp-file-name-structure
936 (list
937 (concat
938 tramp-prefix-regexp
939 "\\(" "\\(" tramp-method-regexp "\\)" tramp-postfix-single-method-regexp "\\)?"
940 "\\(" "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp "\\)?"
941 "\\(" tramp-host-with-port-regexp "\\)" tramp-postfix-host-regexp
942 "\\(" tramp-localname-regexp "\\)")
943 2 4 5 6)
945 "*List of five elements (REGEXP METHOD USER HOST FILE), detailing \
946 the tramp file name structure.
948 The first element REGEXP is a regular expression matching a tramp file
949 name. The regex should contain parentheses around the method name,
950 the user name, the host name, and the file name parts.
952 The second element METHOD is a number, saying which pair of
953 parentheses matches the method name. The third element USER is
954 similar, but for the user name. The fourth element HOST is similar,
955 but for the host name. The fifth element FILE is for the file name.
956 These numbers are passed directly to `match-string', which see. That
957 means the opening parentheses are counted to identify the pair.
959 See also `tramp-file-name-regexp'."
960 :group 'tramp
961 :type '(list (regexp :tag "File name regexp")
962 (integer :tag "Paren pair for method name")
963 (integer :tag "Paren pair for user name ")
964 (integer :tag "Paren pair for host name ")
965 (integer :tag "Paren pair for file name ")))
967 ;;;###autoload
968 (defconst tramp-file-name-regexp-unified
969 "\\`/[^/:]+:"
970 "Value for `tramp-file-name-regexp' for unified remoting.
971 Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and
972 Tramp. See `tramp-file-name-structure-unified' for more explanations.")
974 ;;;###autoload
975 (defconst tramp-file-name-regexp-separate
976 "\\`/\\[.*\\]"
977 "Value for `tramp-file-name-regexp' for separate remoting.
978 XEmacs uses a separate filename syntax for Tramp and EFS.
979 See `tramp-file-name-structure-separate' for more explanations.")
981 ;;;###autoload
982 (defcustom tramp-file-name-regexp
983 (if tramp-unified-filenames
984 tramp-file-name-regexp-unified
985 tramp-file-name-regexp-separate)
986 "*Regular expression matching file names handled by tramp.
987 This regexp should match tramp file names but no other file names.
988 \(When tramp.el is loaded, this regular expression is prepended to
989 `file-name-handler-alist', and that is searched sequentially. Thus,
990 if the tramp entry appears rather early in the `file-name-handler-alist'
991 and is a bit too general, then some files might be considered tramp
992 files which are not really tramp files.
994 Please note that the entry in `file-name-handler-alist' is made when
995 this file (tramp.el) is loaded. This means that this variable must be set
996 before loading tramp.el. Alternatively, `file-name-handler-alist' can be
997 updated after changing this variable.
999 Also see `tramp-file-name-structure'."
1000 :group 'tramp
1001 :type 'regexp)
1003 ;;;###autoload
1004 (defconst tramp-completion-file-name-regexp-unified
1005 "^/[^/]*$"
1006 "Value for `tramp-completion-file-name-regexp' for unified remoting.
1007 Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and
1008 Tramp. See `tramp-file-name-structure-unified' for more explanations.")
1010 ;;;###autoload
1011 (defconst tramp-completion-file-name-regexp-separate
1012 "^/\\([[][^]]*\\)?$"
1013 "Value for `tramp-completion-file-name-regexp' for separate remoting.
1014 XEmacs uses a separate filename syntax for Tramp and EFS.
1015 See `tramp-file-name-structure-separate' for more explanations.")
1017 ;;;###autoload
1018 (defcustom tramp-completion-file-name-regexp
1019 (if tramp-unified-filenames
1020 tramp-completion-file-name-regexp-unified
1021 tramp-completion-file-name-regexp-separate)
1022 "*Regular expression matching file names handled by tramp completion.
1023 This regexp should match partial tramp file names only.
1025 Please note that the entry in `file-name-handler-alist' is made when
1026 this file (tramp.el) is loaded. This means that this variable must be set
1027 before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1028 updated after changing this variable.
1030 Also see `tramp-file-name-structure'."
1031 :group 'tramp
1032 :type 'regexp)
1034 (defcustom tramp-multi-file-name-structure
1035 (list
1036 (concat
1037 tramp-prefix-regexp
1038 "\\(" "\\(" tramp-method-regexp "\\)" "\\)?"
1039 "\\(" "\\(" tramp-postfix-multi-hop-regexp "%s" "\\)+" "\\)?"
1040 tramp-postfix-host-regexp "\\(" tramp-localname-regexp "\\)")
1041 2 3 -1)
1042 "*Describes the file name structure of `multi' files.
1043 Multi files allow you to contact a remote host in several hops.
1044 This is a list of four elements (REGEXP METHOD HOP LOCALNAME).
1046 The first element, REGEXP, gives a regular expression to match against
1047 the file name. In this regular expression, `%s' is replaced with the
1048 value of `tramp-multi-file-name-hop-structure'. (Note: in order to
1049 allow multiple hops, you normally want to use something like
1050 \"\\\\(\\\\(%s\\\\)+\\\\)\" in the regular expression. The outer pair
1051 of parentheses is used for the HOP element, see below.)
1053 All remaining elements are numbers. METHOD gives the number of the
1054 paren pair which matches the method name. HOP gives the number of the
1055 paren pair which matches the hop sequence. LOCALNAME gives the number of
1056 the paren pair which matches the localname (pathname) on the remote host.
1058 LOCALNAME can also be negative, which means to count from the end. Ie, a
1059 value of -1 means the last paren pair.
1061 I think it would be good if the regexp matches the whole of the
1062 string, but I haven't actually tried what happens if it doesn't..."
1063 :group 'tramp
1064 :type '(list (regexp :tag "File name regexp")
1065 (integer :tag "Paren pair for method name")
1066 (integer :tag "Paren pair for hops")
1067 (integer :tag "Paren pair to match localname")))
1069 (defcustom tramp-multi-file-name-hop-structure
1070 (list
1071 (concat
1072 "\\(" tramp-method-regexp "\\)" tramp-postfix-multi-method-regexp
1073 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
1074 "\\(" tramp-host-with-port-regexp "\\)")
1075 1 2 3)
1076 "*Describes the structure of a hop in multi files.
1077 This is a list of four elements (REGEXP METHOD USER HOST). First
1078 element REGEXP is used to match against the hop. Pair number METHOD
1079 matches the method of one hop, pair number USER matches the user of
1080 one hop, pair number HOST matches the host of one hop.
1082 This regular expression should match exactly all of one hop."
1083 :group 'tramp
1084 :type '(list (regexp :tag "Hop regexp")
1085 (integer :tag "Paren pair for method name")
1086 (integer :tag "Paren pair for user name")
1087 (integer :tag "Paren pair for host name")))
1089 (defcustom tramp-make-multi-tramp-file-format
1090 (list
1091 (concat tramp-prefix-format "%m")
1092 (concat tramp-postfix-multi-hop-format
1093 "%m" tramp-postfix-multi-method-format
1094 "%u" tramp-postfix-user-format
1095 "%h")
1096 (concat tramp-postfix-host-format "%p"))
1097 "*Describes how to construct a `multi' file name.
1098 This is a list of three elements PREFIX, HOP and LOCALNAME.
1100 The first element PREFIX says how to construct the prefix, the second
1101 element HOP specifies what each hop looks like, and the final element
1102 LOCALNAME says how to construct the localname (pathname).
1104 In PREFIX, `%%' means `%' and `%m' means the method name.
1106 In HOP, `%%' means `%' and `%m', `%u', `%h' mean the hop method, hop
1107 user and hop host, respectively.
1109 In LOCALNAME, `%%' means `%' and `%p' means the localname.
1111 The resulting file name always contains one copy of PREFIX and one
1112 copy of LOCALNAME, but there is one copy of HOP for each hop in the file
1113 name.
1115 Note: the current implementation requires the prefix to contain the
1116 method name, followed by all the hops, and the localname must come
1117 last."
1118 :group 'tramp
1119 :type '(list string string string))
1121 (defcustom tramp-terminal-type "dumb"
1122 "*Value of TERM environment variable for logging in to remote host.
1123 Because Tramp wants to parse the output of the remote shell, it is easily
1124 confused by ANSI color escape sequences and suchlike. Often, shell init
1125 files conditionalize this setup based on the TERM environment variable."
1126 :group 'tramp
1127 :type 'string)
1129 (defcustom tramp-completion-without-shell-p nil
1130 "*If nil, use shell wildcards for completion, else rely on Lisp only.
1131 Using shell wildcards for completions has the advantage that it can be
1132 fast even in large directories, but completion is always
1133 case-sensitive. Relying on Lisp only means that case-insensitive
1134 completion is possible (subject to the variable `completion-ignore-case'),
1135 but it might be slow on large directories."
1136 :group 'tramp
1137 :type 'boolean)
1139 (defcustom tramp-actions-before-shell
1140 '((tramp-password-prompt-regexp tramp-action-password)
1141 (tramp-login-prompt-regexp tramp-action-login)
1142 (shell-prompt-pattern tramp-action-succeed)
1143 (tramp-shell-prompt-pattern tramp-action-succeed)
1144 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
1145 (tramp-yesno-prompt-regexp tramp-action-yesno)
1146 (tramp-yn-prompt-regexp tramp-action-yn)
1147 (tramp-terminal-prompt-regexp tramp-action-terminal))
1148 "List of pattern/action pairs.
1149 Whenever a pattern matches, the corresponding action is performed.
1150 Each item looks like (PATTERN ACTION).
1152 The PATTERN should be a symbol, a variable. The value of this
1153 variable gives the regular expression to search for. Note that the
1154 regexp must match at the end of the buffer, \"\\'\" is implicitly
1155 appended to it.
1157 The ACTION should also be a symbol, but a function. When the
1158 corresponding PATTERN matches, the ACTION function is called."
1159 :group 'tramp
1160 :type '(repeat (list variable function)))
1162 (defcustom tramp-multi-actions
1163 '((tramp-password-prompt-regexp tramp-multi-action-password)
1164 (tramp-login-prompt-regexp tramp-multi-action-login)
1165 (shell-prompt-pattern tramp-multi-action-succeed)
1166 (tramp-shell-prompt-pattern tramp-multi-action-succeed)
1167 (tramp-wrong-passwd-regexp tramp-multi-action-permission-denied))
1168 "List of pattern/action pairs.
1169 This list is used for each hop in multi-hop connections.
1170 See `tramp-actions-before-shell' for more info."
1171 :group 'tramp
1172 :type '(repeat (list variable function)))
1174 ;; Chunked sending kluge. We set this to 500 for black-listed constellations
1175 ;; known to have a bug in `process-send-string'; some ssh connections appear
1176 ;; to drop bytes when data is sent too quickly.
1177 (defcustom tramp-chunksize
1178 (when (and (not (featurep 'xemacs))
1179 (memq system-type '(hpux)))
1180 500)
1181 "*If non-nil, chunksize for sending input to local process.
1182 It is necessary only on systems which have a buggy `process-send-string'
1183 implementation. The necessity, whether this variable must be set, can be
1184 checked via the following code:
1186 (with-temp-buffer
1187 (let ((bytes 1000)
1188 (proc (start-process (buffer-name) (current-buffer) \"wc\" \"-c\")))
1189 (process-send-string proc (make-string bytes ?x))
1190 (process-send-eof proc)
1191 (process-send-eof proc)
1192 (accept-process-output proc 1)
1193 (goto-char (point-min))
1194 (re-search-forward \"\\\\w+\")
1195 (message \"Bytes sent: %s\\tBytes received: %s\" bytes (match-string 0))))
1197 Please raise a bug report via \"M-x tramp-bug\" if your system needs
1198 this variable to be set as well."
1199 :group 'tramp
1200 :type '(choice (const nil) integer))
1202 ;;; Internal Variables:
1204 (defvar tramp-buffer-file-attributes nil
1205 "Holds the `ls -ild' output for the current buffer.
1206 This variable is local to each buffer. It is not used if the remote
1207 machine groks Perl. If it is used, it's used as an emulation for
1208 the visited file modtime.")
1209 (make-variable-buffer-local 'tramp-buffer-file-attributes)
1211 (defvar tramp-md5-function
1212 (cond ((and (require 'md5) (fboundp 'md5)) 'md5)
1213 ((fboundp 'md5-encode)
1214 (lambda (x) (base64-encode-string (md5-encode x))))
1215 (t (error "Coulnd't find an `md5' function")))
1216 "Function to call for running the MD5 algorithm.")
1218 (defvar tramp-end-of-output
1219 (concat "///"
1220 (funcall tramp-md5-function
1221 (concat
1222 (prin1-to-string process-environment)
1223 (current-time-string)
1224 ;; (prin1-to-string
1225 ;; (if (fboundp 'directory-files-and-attributes)
1226 ;; (funcall 'directory-files-and-attributes
1227 ;; (or (getenv "HOME")
1228 ;; (tramp-temporary-file-directory)))
1229 ;; (mapcar
1230 ;; (lambda (x)
1231 ;; (cons x (file-attributes x)))
1232 ;; (directory-files (or (getenv "HOME")
1233 ;; (tramp-temporary-file-directory))
1234 ;; t))))
1236 "String used to recognize end of output.")
1238 (defvar tramp-connection-function nil
1239 "This internal variable holds a parameter for `tramp-methods'.
1240 In the connection buffer, this variable has the value of the like-named
1241 method parameter, as specified in `tramp-methods' (which see).")
1243 (defvar tramp-remote-sh nil
1244 "This internal variable holds a parameter for `tramp-methods'.
1245 In the connection buffer, this variable has the value of the like-named
1246 method parameter, as specified in `tramp-methods' (which see).")
1248 (defvar tramp-login-program nil
1249 "This internal variable holds a parameter for `tramp-methods'.
1250 In the connection buffer, this variable has the value of the like-named
1251 method parameter, as specified in `tramp-methods' (which see).")
1253 (defvar tramp-login-args nil
1254 "This internal variable holds a parameter for `tramp-methods'.
1255 In the connection buffer, this variable has the value of the like-named
1256 method parameter, as specified in `tramp-methods' (which see).")
1258 (defvar tramp-copy-program nil
1259 "This internal variable holds a parameter for `tramp-methods'.
1260 In the connection buffer, this variable has the value of the like-named
1261 method parameter, as specified in `tramp-methods' (which see).")
1263 (defvar tramp-copy-args nil
1264 "This internal variable holds a parameter for `tramp-methods'.
1265 In the connection buffer, this variable has the value of the like-named
1266 method parameter, as specified in `tramp-methods' (which see).")
1268 (defvar tramp-copy-keep-date-arg nil
1269 "This internal variable holds a parameter for `tramp-methods'.
1270 In the connection buffer, this variable has the value of the like-named
1271 method parameter, as specified in `tramp-methods' (which see).")
1273 (defvar tramp-encoding-command nil
1274 "This internal variable holds a parameter for `tramp-methods'.
1275 In the connection buffer, this variable has the value of the like-named
1276 method parameter, as specified in `tramp-methods' (which see).")
1278 (defvar tramp-decoding-command nil
1279 "This internal variable holds a parameter for `tramp-methods'.
1280 In the connection buffer, this variable has the value of the like-named
1281 method parameter, as specified in `tramp-methods' (which see).")
1283 (defvar tramp-encoding-function nil
1284 "This internal variable holds a parameter for `tramp-methods'.
1285 In the connection buffer, this variable has the value of the like-named
1286 method parameter, as specified in `tramp-methods' (which see).")
1288 (defvar tramp-decoding-function nil
1289 "This internal variable holds a parameter for `tramp-methods'.
1290 In the connection buffer, this variable has the value of the like-named
1291 method parameter, as specified in `tramp-methods' (which see).")
1293 ;; CCC `local in each buffer'?
1294 (defvar tramp-ls-command nil
1295 "This command is used to get a long listing with numeric user and group ids.
1296 This variable is automatically made buffer-local to each rsh process buffer
1297 upon opening the connection.")
1299 (defvar tramp-current-multi-method nil
1300 "Name of `multi' connection method for this *tramp* buffer, or nil if not multi.
1301 This variable is automatically made buffer-local to each rsh process buffer
1302 upon opening the connection.")
1304 (defvar tramp-current-method nil
1305 "Connection method for this *tramp* buffer.
1306 This variable is automatically made buffer-local to each rsh process buffer
1307 upon opening the connection.")
1309 (defvar tramp-current-user nil
1310 "Remote login name for this *tramp* buffer.
1311 This variable is automatically made buffer-local to each rsh process buffer
1312 upon opening the connection.")
1314 (defvar tramp-current-host nil
1315 "Remote host for this *tramp* buffer.
1316 This variable is automatically made buffer-local to each rsh process buffer
1317 upon opening the connection.")
1319 (defvar tramp-test-groks-nt nil
1320 "Whether the `test' command groks the `-nt' switch.
1321 \(`test A -nt B' tests if file A is newer than file B.)
1322 This variable is automatically made buffer-local to each rsh process buffer
1323 upon opening the connection.")
1325 (defvar tramp-file-exists-command nil
1326 "Command to use for checking if a file exists.
1327 This variable is automatically made buffer-local to each rsh process buffer
1328 upon opening the connection.")
1330 (defconst tramp-uudecode "\
1331 tramp_uudecode () {
1332 \(echo begin 600 /tmp/tramp.$$; tail +2) | uudecode
1333 cat /tmp/tramp.$$
1334 rm -f /tmp/tramp.$$
1336 "Shell function to implement `uudecode' to standard output.
1337 Many systems support `uudecode -o -' for this or `uudecode -p', but
1338 some systems don't, and for them we have this shell function.")
1340 ;; Perl script to implement `file-attributes' in a Lisp `read'able
1341 ;; output. If you are hacking on this, note that you get *no* output
1342 ;; unless this spits out a complete line, including the '\n' at the
1343 ;; end.
1344 ;; The device number is returned as "-1", because there will be a virtual
1345 ;; device number set in `tramp-handle-file-attributes'
1346 (defconst tramp-perl-file-attributes "\
1347 $f = $ARGV[0];
1348 @s = lstat($f);
1349 if (($s[2] & 0170000) == 0120000) { $l = readlink($f); $l = \"\\\"$l\\\"\"; }
1350 elsif (($s[2] & 0170000) == 040000) { $l = \"t\"; }
1351 else { $l = \"nil\" };
1352 printf(\"(%s %u %d %d (%u %u) (%u %u) (%u %u) %u %u t (%u . %u) -1)\\n\",
1353 $l, $s[3], $s[4], $s[5], $s[8] >> 16 & 0xffff, $s[8] & 0xffff,
1354 $s[9] >> 16 & 0xffff, $s[9] & 0xffff, $s[10] >> 16 & 0xffff, $s[10] & 0xffff,
1355 $s[7], $s[2], $s[1] >> 16 & 0xffff, $s[1] & 0xffff);"
1356 "Perl script to produce output suitable for use with `file-attributes'
1357 on the remote file system.")
1359 ;; ;; These two use uu encoding.
1360 ;; (defvar tramp-perl-encode "%s -e'\
1361 ;; print qq(begin 644 xxx\n);
1362 ;; my $s = q();
1363 ;; my $res = q();
1364 ;; while (read(STDIN, $s, 45)) {
1365 ;; print pack(q(u), $s);
1366 ;; }
1367 ;; print qq(`\n);
1368 ;; print qq(end\n);
1369 ;; '"
1370 ;; "Perl program to use for encoding a file.
1371 ;; Escape sequence %s is replaced with name of Perl binary.")
1373 ;; (defvar tramp-perl-decode "%s -ne '
1374 ;; print unpack q(u), $_;
1375 ;; '"
1376 ;; "Perl program to use for decoding a file.
1377 ;; Escape sequence %s is replaced with name of Perl binary.")
1379 ;; These two use base64 encoding.
1380 (defvar tramp-perl-encode-with-module
1381 "perl -MMIME::Base64 -0777 -ne 'print encode_base64($_)'"
1382 "Perl program to use for encoding a file.
1383 Escape sequence %s is replaced with name of Perl binary.
1384 This string is passed to `format', so percent characters need to be doubled.
1385 This implementation requires the MIME::Base64 Perl module to be installed
1386 on the remote host.")
1388 (defvar tramp-perl-decode-with-module
1389 "perl -MMIME::Base64 -0777 -ne 'print decode_base64($_)'"
1390 "Perl program to use for decoding a file.
1391 Escape sequence %s is replaced with name of Perl binary.
1392 This string is passed to `format', so percent characters need to be doubled.
1393 This implementation requires the MIME::Base64 Perl module to be installed
1394 on the remote host.")
1396 (defvar tramp-perl-encode
1397 "%s -e '
1398 # This script contributed by Juanma Barranquero <lektu@terra.es>.
1399 # Copyright (C) 2002 Free Software Foundation, Inc.
1400 use strict;
1402 my %%trans = do {
1403 my $i = 0;
1404 map {(substr(unpack(q(B8), chr $i++), 2, 6), $_)}
1405 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/);
1408 binmode(\\*STDIN);
1410 # We read in chunks of 54 bytes, to generate output lines
1411 # of 72 chars (plus end of line)
1412 $/ = \\54;
1414 while (my $data = <STDIN>) {
1415 my $pad = q();
1417 # Only for the last chunk, and only if did not fill the last three-byte packet
1418 if (eof) {
1419 my $mod = length($data) %% 3;
1420 $pad = q(=) x (3 - $mod) if $mod;
1423 # Not the fastest method, but it is simple: unpack to binary string, split
1424 # by groups of 6 bits and convert back from binary to byte; then map into
1425 # the translation table
1426 print
1427 join q(),
1428 map($trans{$_},
1429 (substr(unpack(q(B*), $data) . q(00000), 0, 432) =~ /....../g)),
1430 $pad,
1431 qq(\\n);
1434 "Perl program to use for encoding a file.
1435 Escape sequence %s is replaced with name of Perl binary.
1436 This string is passed to `format', so percent characters need to be doubled.")
1438 (defvar tramp-perl-decode
1439 "%s -e '
1440 # This script contributed by Juanma Barranquero <lektu@terra.es>.
1441 # Copyright (C) 2002 Free Software Foundation, Inc.
1442 use strict;
1444 my %%trans = do {
1445 my $i = 0;
1446 map {($_, substr(unpack(q(B8), chr $i++), 2, 6))}
1447 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/)
1450 my %%bytes = map {(unpack(q(B8), chr $_), chr $_)} 0 .. 255;
1452 binmode(\\*STDOUT);
1454 # We are going to accumulate into $pending to accept any line length
1455 # (we do not check they are <= 76 chars as the RFC says)
1456 my $pending = q();
1458 while (my $data = <STDIN>) {
1459 chomp $data;
1461 # If we find one or two =, we have reached the end and
1462 # any following data is to be discarded
1463 my $finished = $data =~ s/(==?).*/$1/;
1464 $pending .= $data;
1466 my $len = length($pending);
1467 my $chunk = substr($pending, 0, $len & ~3);
1469 # Easy method: translate from chars to (pregenerated) six-bit packets, join,
1470 # split in 8-bit chunks and convert back to char.
1471 print join q(),
1472 map $bytes{$_},
1473 ((join q(), map {$trans{$_} || q()} split //, $chunk) =~ /......../g);
1475 last if $finished;
1478 "Perl program to use for decoding a file.
1479 Escape sequence %s is replaced with name of Perl binary.
1480 This string is passed to `format', so percent characters need to be doubled.")
1482 ; These values conform to `file-attributes' from XEmacs 21.2.
1483 ; GNU Emacs and other tools not checked.
1484 (defconst tramp-file-mode-type-map '((0 . "-") ; Normal file (SVID-v2 and XPG2)
1485 (1 . "p") ; fifo
1486 (2 . "c") ; character device
1487 (3 . "m") ; multiplexed character device (v7)
1488 (4 . "d") ; directory
1489 (5 . "?") ; Named special file (XENIX)
1490 (6 . "b") ; block device
1491 (7 . "?") ; multiplexed block device (v7)
1492 (8 . "-") ; regular file
1493 (9 . "n") ; network special file (HP-UX)
1494 (10 . "l") ; symlink
1495 (11 . "?") ; ACL shadow inode (Solaris, not userspace)
1496 (12 . "s") ; socket
1497 (13 . "D") ; door special (Solaris)
1498 (14 . "w")) ; whiteout (BSD)
1499 "A list of file types returned from the `stat' system call.
1500 This is used to map a mode number to a permission string.")
1502 (defvar tramp-dos-coding-system
1503 (if (and (fboundp 'coding-system-p)
1504 (funcall 'coding-system-p '(dos)))
1505 'dos
1506 'undecided-dos)
1507 "Some Emacsen know the `dos' coding system, others need `undecided-dos'.")
1509 (defvar tramp-last-cmd-time nil
1510 "Internal Tramp variable recording the time when the last cmd was sent.
1511 This variable is buffer-local in every buffer.")
1512 (make-variable-buffer-local 'tramp-last-cmd-time)
1514 ;; This variable does not have the right value in XEmacs. What should
1515 ;; I use instead of find-operation-coding-system in XEmacs?
1516 (defvar tramp-feature-write-region-fix
1517 (when (fboundp 'find-operation-coding-system)
1518 (let ((file-coding-system-alist '(("test" emacs-mule))))
1519 (find-operation-coding-system 'write-region 0 0 "" nil "test")))
1520 "Internal variable to say if `write-region' chooses the right coding.
1521 Older versions of Emacs chose the coding system for `write-region' based
1522 on the FILENAME argument, even if VISIT was a string.")
1524 ;; New handlers should be added here. The following operations can be
1525 ;; handled using the normal primitives: file-name-as-directory,
1526 ;; file-name-directory, file-name-nondirectory,
1527 ;; file-name-sans-versions, get-file-buffer.
1528 (defconst tramp-file-name-handler-alist
1530 (load . tramp-handle-load)
1531 (make-symbolic-link . tramp-handle-make-symbolic-link)
1532 (file-name-directory . tramp-handle-file-name-directory)
1533 (file-name-nondirectory . tramp-handle-file-name-nondirectory)
1534 (file-truename . tramp-handle-file-truename)
1535 (file-exists-p . tramp-handle-file-exists-p)
1536 (file-directory-p . tramp-handle-file-directory-p)
1537 (file-executable-p . tramp-handle-file-executable-p)
1538 (file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
1539 (file-readable-p . tramp-handle-file-readable-p)
1540 (file-regular-p . tramp-handle-file-regular-p)
1541 (file-symlink-p . tramp-handle-file-symlink-p)
1542 (file-writable-p . tramp-handle-file-writable-p)
1543 (file-ownership-preserved-p . tramp-handle-file-ownership-preserved-p)
1544 (file-newer-than-file-p . tramp-handle-file-newer-than-file-p)
1545 (file-attributes . tramp-handle-file-attributes)
1546 (file-modes . tramp-handle-file-modes)
1547 (file-directory-files . tramp-handle-file-directory-files)
1548 (directory-files . tramp-handle-directory-files)
1549 (file-name-all-completions . tramp-handle-file-name-all-completions)
1550 (file-name-completion . tramp-handle-file-name-completion)
1551 (add-name-to-file . tramp-handle-add-name-to-file)
1552 (copy-file . tramp-handle-copy-file)
1553 (rename-file . tramp-handle-rename-file)
1554 (set-file-modes . tramp-handle-set-file-modes)
1555 (make-directory . tramp-handle-make-directory)
1556 (delete-directory . tramp-handle-delete-directory)
1557 (delete-file . tramp-handle-delete-file)
1558 (directory-file-name . tramp-handle-directory-file-name)
1559 (shell-command . tramp-handle-shell-command)
1560 (insert-directory . tramp-handle-insert-directory)
1561 (expand-file-name . tramp-handle-expand-file-name)
1562 (file-local-copy . tramp-handle-file-local-copy)
1563 (insert-file-contents . tramp-handle-insert-file-contents)
1564 (write-region . tramp-handle-write-region)
1565 (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
1566 (dired-call-process . tramp-handle-dired-call-process)
1567 (dired-recursive-delete-directory
1568 . tramp-handle-dired-recursive-delete-directory)
1569 (set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
1570 (verify-visited-file-modtime . tramp-handle-verify-visited-file-modtime))
1571 "Alist of handler functions.
1572 Operations not mentioned here will be handled by the normal Emacs functions.")
1574 ;; Handlers for partial tramp file names. For GNU Emacs just
1575 ;; `file-name-all-completions' is needed. The other ones are necessary
1576 ;; for XEmacs.
1577 (defconst tramp-completion-file-name-handler-alist
1579 (file-name-directory . tramp-completion-handle-file-name-directory)
1580 (file-name-nondirectory . tramp-completion-handle-file-name-nondirectory)
1581 (file-exists-p . tramp-completion-handle-file-exists-p)
1582 (file-name-all-completions . tramp-completion-handle-file-name-all-completions)
1583 (file-name-completion . tramp-completion-handle-file-name-completion)
1584 (expand-file-name . tramp-completion-handle-expand-file-name))
1585 "Alist of completion handler functions.
1586 Used for file names matching `tramp-file-name-regexp'. Operations not
1587 mentioned here will be handled by `tramp-file-name-handler-alist' or the
1588 normal Emacs functions.")
1590 ;; Handlers for foreign methods, like FTP or SMB, shall be plugged here.
1591 (defvar tramp-foreign-file-name-handler-alist
1592 ;; (identity . tramp-sh-file-name-handler) should always be the last
1593 ;; entry, since `identity' always matches.
1594 '((identity . tramp-sh-file-name-handler))
1595 "Alist of elements (FUNCTION . HANDLER) for foreign methods handled specially.
1596 If (FUNCTION FILENAME) returns non-nil, then all I/O on that file is done by
1597 calling HANDLER.")
1599 ;;; Internal functions which must come first.
1601 (defsubst tramp-message (level fmt-string &rest args)
1602 "Emit a message depending on verbosity level.
1603 First arg LEVEL says to be quiet if `tramp-verbose' is less than LEVEL. The
1604 message is emitted only if `tramp-verbose' is greater than or equal to LEVEL.
1605 Calls function `message' with FMT-STRING as control string and the remaining
1606 ARGS to actually emit the message (if applicable).
1608 This function expects to be called from the tramp buffer only!"
1609 (when (<= level tramp-verbose)
1610 (apply #'message (concat "tramp: " fmt-string) args)
1611 (when tramp-debug-buffer
1612 (save-excursion
1613 (set-buffer
1614 (tramp-get-debug-buffer
1615 tramp-current-multi-method tramp-current-method
1616 tramp-current-user tramp-current-host))
1617 (goto-char (point-max))
1618 (tramp-insert-with-face
1619 'italic
1620 (concat "# " (apply #'format fmt-string args) "\n"))))))
1622 (defun tramp-message-for-buffer
1623 (multi-method method user host level fmt-string &rest args)
1624 "Like `tramp-message' but temporarily switches to the tramp buffer.
1625 First three args METHOD, USER, and HOST identify the tramp buffer to use,
1626 remaining args passed to `tramp-message'."
1627 (save-excursion
1628 (set-buffer (tramp-get-buffer multi-method method user host))
1629 (apply 'tramp-message level fmt-string args)))
1631 (defsubst tramp-line-end-position nil
1632 "Return point at end of line.
1633 Calls `line-end-position' or `point-at-eol' if defined, else
1634 own implementation."
1635 (cond
1636 ((fboundp 'line-end-position) (funcall 'line-end-position))
1637 ((fboundp 'point-at-eol) (funcall 'point-at-eol))
1638 (t (save-excursion (end-of-line) (point)))))
1640 (defmacro with-parsed-tramp-file-name (filename var &rest body)
1641 "Parse a Tramp filename and make components available in the body.
1643 First arg FILENAME is evaluated and dissected into its components.
1644 Second arg VAR is a symbol. It is used as a variable name to hold
1645 the filename structure. It is also used as a prefix for the variables
1646 holding the components. For example, if VAR is the symbol `foo', then
1647 `foo' will be bound to the whole structure, `foo-multi-method' will
1648 be bound to the multi-method component, and so on for `foo-method',
1649 `foo-user', `foo-host', `foo-localname'.
1651 Remaining args are Lisp expressions to be evaluated (inside an implicit
1652 `progn').
1654 If VAR is nil, then we bind `v' to the structure and `multi-method',
1655 `method', `user', `host', `localname' to the components."
1656 `(let* ((,(or var 'v) (tramp-dissect-file-name ,filename))
1657 (,(if var (intern (concat (symbol-name var) "-multi-method")) 'multi-method)
1658 (tramp-file-name-multi-method ,(or var 'v)))
1659 (,(if var (intern (concat (symbol-name var) "-method")) 'method)
1660 (tramp-file-name-method ,(or var 'v)))
1661 (,(if var (intern (concat (symbol-name var) "-user")) 'user)
1662 (tramp-file-name-user ,(or var 'v)))
1663 (,(if var (intern (concat (symbol-name var) "-host")) 'host)
1664 (tramp-file-name-host ,(or var 'v)))
1665 (,(if var (intern (concat (symbol-name var) "-localname")) 'localname)
1666 (tramp-file-name-localname ,(or var 'v))))
1667 ,@body))
1669 (put 'with-parsed-tramp-file-name 'lisp-indent-function 2)
1671 ;;; Config Manipulation Functions:
1673 (defun tramp-set-completion-function (method function-list)
1674 "Sets the list of completion functions for METHOD.
1675 FUNCTION-LIST is a list of entries of the form (FUNCTION FILE).
1676 The FUNCTION is intended to parse FILE according its syntax.
1677 It might be a predefined FUNCTION, or a user defined FUNCTION.
1678 Predefined FUNCTIONs are `tramp-parse-rhosts', `tramp-parse-shosts',
1679 `tramp-parse-sconfig',`tramp-parse-hosts', `tramp-parse-passwd',
1680 and `tramp-parse-netrc'.
1682 Example:
1684 (tramp-set-completion-function
1685 \"ssh\"
1686 '((tramp-parse-sconfig \"/etc/ssh_config\")
1687 (tramp-parse-sconfig \"~/.ssh/config\")))"
1689 (let ((v (cdr (assoc method tramp-completion-function-alist))))
1690 (if v (setcdr v function-list)
1691 (add-to-list 'tramp-completion-function-alist
1692 (cons method function-list)))))
1694 (defun tramp-get-completion-function (method)
1695 "Returns list of completion functions for METHOD.
1696 For definition of that list see `tramp-set-completion-function'."
1697 (cdr (assoc method tramp-completion-function-alist)))
1699 ;;; File Name Handler Functions:
1701 (defun tramp-handle-make-symbolic-link
1702 (filename linkname &optional ok-if-already-exists)
1703 "Like `make-symbolic-link' for tramp files.
1704 If LINKNAME is a non-Tramp file, it is used verbatim as the target of
1705 the symlink. If LINKNAME is a Tramp file, only the localname component is
1706 used as the target of the symlink.
1708 If LINKNAME is a Tramp file and the localname component is relative, then
1709 it is expanded first, before the localname component is taken. Note that
1710 this can give surprising results if the user/host for the source and
1711 target of the symlink differ."
1712 (with-parsed-tramp-file-name linkname l
1713 (let ((ln (tramp-get-remote-ln l-multi-method l-method l-user l-host))
1714 (cwd (file-name-directory l-localname)))
1715 (unless ln
1716 (signal 'file-error
1717 (list "Making a symbolic link."
1718 "ln(1) does not exist on the remote host.")))
1720 ;; Do the 'confirm if exists' thing.
1721 (when (file-exists-p linkname)
1722 ;; What to do?
1723 (if (or (null ok-if-already-exists) ; not allowed to exist
1724 (and (numberp ok-if-already-exists)
1725 (not (yes-or-no-p
1726 (format
1727 "File %s already exists; make it a link anyway? "
1728 l-localname)))))
1729 (signal 'file-already-exists (list "File already exists" l-localname))
1730 (delete-file linkname)))
1732 ;; If FILENAME is a Tramp name, use just the localname component.
1733 (when (tramp-tramp-file-p filename)
1734 (setq filename (tramp-file-name-localname
1735 (tramp-dissect-file-name
1736 (expand-file-name filename)))))
1738 ;; Right, they are on the same host, regardless of user, method, etc.
1739 ;; We now make the link on the remote machine. This will occur as the user
1740 ;; that FILENAME belongs to.
1741 (zerop
1742 (tramp-send-command-and-check
1743 l-multi-method l-method l-user l-host
1744 (format "cd %s && %s -sf %s %s"
1745 cwd ln
1746 filename
1747 l-localname)
1748 t)))))
1751 (defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix)
1752 "Like `load' for tramp files. Not implemented!"
1753 (unless (file-name-absolute-p file)
1754 (error "Tramp cannot `load' files without absolute file name"))
1755 (with-parsed-tramp-file-name file nil
1756 (unless nosuffix
1757 (cond ((file-exists-p (concat file ".elc"))
1758 (setq file (concat file ".elc")))
1759 ((file-exists-p (concat file ".el"))
1760 (setq file (concat file ".el")))))
1761 (when must-suffix
1762 ;; The first condition is always true for absolute file names.
1763 ;; Included for safety's sake.
1764 (unless (or (file-name-directory file)
1765 (string-match "\\.elc?\\'" file))
1766 (error "File `%s' does not include a `.el' or `.elc' suffix"
1767 file)))
1768 (unless noerror
1769 (when (not (file-exists-p file))
1770 (error "Cannot load nonexistant file `%s'" file)))
1771 (if (not (file-exists-p file))
1773 (unless nomessage
1774 (message "Loading %s..." file))
1775 (let ((local-copy (file-local-copy file)))
1776 ;; MUST-SUFFIX doesn't exist on XEmacs, so let it default to nil.
1777 (load local-copy noerror t t)
1778 (delete-file local-copy))
1779 (unless nomessage
1780 (message "Loading %s...done" file))
1781 t)))
1783 ;; Localname manipulation functions that grok TRAMP localnames...
1784 (defun tramp-handle-file-name-directory (file)
1785 "Like `file-name-directory' but aware of TRAMP files."
1786 ;; everything except the last filename thing is the directory
1787 (with-parsed-tramp-file-name file nil
1788 ;; For the following condition, two possibilities should be tried:
1789 ;; (1) (string= localname "")
1790 ;; (2) (or (string= localname "") (string= localname "/"))
1791 ;; The second variant fails when completing a "/" directory on
1792 ;; the remote host, that is a filename which looks like
1793 ;; "/user@host:/". But maybe wildcards fail with the first variant.
1794 ;; We should do some investigation.
1795 (if (string= localname "")
1796 ;; For a filename like "/[foo]", we return "/". The `else'
1797 ;; case would return "/[foo]" unchanged. But if we do that,
1798 ;; then `file-expand-wildcards' ceases to work. It's not
1799 ;; quite clear to me what's the intuition that tells that this
1800 ;; behavior is the right behavior, but oh, well.
1802 ;; run the command on the localname portion only
1803 ;; CCC: This should take into account the remote machine type, no?
1804 ;; --daniel <daniel@danann.net>
1805 (tramp-make-tramp-file-name multi-method method user host
1806 ;; This will not recurse...
1807 (or (file-name-directory localname) "")))))
1809 (defun tramp-handle-file-name-nondirectory (file)
1810 "Like `file-name-nondirectory' but aware of TRAMP files."
1811 (with-parsed-tramp-file-name file nil
1812 (file-name-nondirectory localname)))
1814 (defun tramp-handle-file-truename (filename &optional counter prev-dirs)
1815 "Like `file-truename' for tramp files."
1816 (with-parsed-tramp-file-name filename nil
1817 (let* ((steps (tramp-split-string localname "/"))
1818 (localnamedir (let ((directory-sep-char ?/))
1819 (file-name-as-directory localname)))
1820 (is-dir (string= localname localnamedir))
1821 (thisstep nil)
1822 (numchase 0)
1823 ;; Don't make the following value larger than necessary.
1824 ;; People expect an error message in a timely fashion when
1825 ;; something is wrong; otherwise they might think that Emacs
1826 ;; is hung. Of course, correctness has to come first.
1827 (numchase-limit 20)
1828 (result nil) ;result steps in reverse order
1829 symlink-target)
1830 (tramp-message-for-buffer
1831 multi-method method user host
1832 10 "Finding true name for `%s'" filename)
1833 (while (and steps (< numchase numchase-limit))
1834 (setq thisstep (pop steps))
1835 (tramp-message-for-buffer
1836 multi-method method user host
1837 10 "Check %s"
1838 (mapconcat 'identity
1839 (append '("") (reverse result) (list thisstep))
1840 "/"))
1841 (setq symlink-target
1842 (nth 0 (tramp-handle-file-attributes
1843 (tramp-make-tramp-file-name
1844 multi-method method user host
1845 (mapconcat 'identity
1846 (append '("")
1847 (reverse result)
1848 (list thisstep))
1849 "/")))))
1850 (cond ((string= "." thisstep)
1851 (tramp-message-for-buffer multi-method method user host
1852 10 "Ignoring step `.'"))
1853 ((string= ".." thisstep)
1854 (tramp-message-for-buffer multi-method method user host
1855 10 "Processing step `..'")
1856 (pop result))
1857 ((stringp symlink-target)
1858 ;; It's a symlink, follow it.
1859 (tramp-message-for-buffer
1860 multi-method method user host
1861 10 "Follow symlink to %s" symlink-target)
1862 (setq numchase (1+ numchase))
1863 (when (file-name-absolute-p symlink-target)
1864 (setq result nil))
1865 ;; If the symlink was absolute, we'll get a string like
1866 ;; "/user@host:/some/target"; extract the
1867 ;; "/some/target" part from it.
1868 (when (tramp-tramp-file-p symlink-target)
1869 (with-parsed-tramp-file-name symlink-target sym
1870 (unless (equal (list multi-method method user host)
1871 (list sym-multi-method sym-method
1872 sym-user sym-host))
1873 (error "Symlink target `%s' on wrong host"
1874 symlink-target))
1875 (setq symlink-target localname)))
1876 (setq steps
1877 (append (tramp-split-string symlink-target "/") steps)))
1879 ;; It's a file.
1880 (setq result (cons thisstep result)))))
1881 (when (>= numchase numchase-limit)
1882 (error "Maximum number (%d) of symlinks exceeded" numchase-limit))
1883 (setq result (reverse result))
1884 ;; Combine list to form string.
1885 (setq result
1886 (if result
1887 (mapconcat 'identity (cons "" result) "/")
1888 "/"))
1889 (when (and is-dir (or (string= "" result)
1890 (not (string= (substring result -1) "/"))))
1891 (setq result (concat result "/")))
1892 (tramp-message-for-buffer
1893 multi-method method user host
1894 10 "True name of `%s' is `%s'" filename result)
1895 (tramp-make-tramp-file-name
1896 multi-method method user host result))))
1898 ;; Basic functions.
1900 (defun tramp-handle-file-exists-p (filename)
1901 "Like `file-exists-p' for tramp files."
1902 (with-parsed-tramp-file-name filename nil
1903 (save-excursion
1904 (zerop (tramp-send-command-and-check
1905 multi-method method user host
1906 (format
1907 (tramp-get-file-exists-command multi-method method user host)
1908 (tramp-shell-quote-argument localname)))))))
1910 ;; Devices must distinguish physical file systems. The device numbers
1911 ;; provided by "lstat" aren't unique, because we operate on different hosts.
1912 ;; So we use virtual device numbers, generated by Tramp. Both Ange-FTP and
1913 ;; EFS use device number "-1". In order to be different, we use device number
1914 ;; (-1 x), whereby "x" is unique for a given (multi-method method user host).
1915 (defvar tramp-devices nil
1916 "Keeps virtual device numbers.")
1918 ;; CCC: This should check for an error condition and signal failure
1919 ;; when something goes wrong.
1920 ;; Daniel Pittman <daniel@danann.net>
1921 (defun tramp-handle-file-attributes (filename &optional nonnumeric)
1922 "Like `file-attributes' for tramp files.
1923 Optional argument NONNUMERIC means return user and group name
1924 rather than as numbers."
1925 (let (result)
1926 (with-parsed-tramp-file-name filename nil
1927 (when (tramp-handle-file-exists-p filename)
1928 ;; file exists, find out stuff
1929 (save-excursion
1930 (if (tramp-get-remote-perl multi-method method user host)
1931 (setq result
1932 (tramp-handle-file-attributes-with-perl
1933 multi-method method user host localname nonnumeric))
1934 (setq result
1935 (tramp-handle-file-attributes-with-ls
1936 multi-method method user host localname nonnumeric)))
1937 ;; set virtual device number
1938 (setcar (nthcdr 11 result)
1939 (tramp-get-device multi-method method user host)))))
1940 result))
1942 (defun tramp-handle-file-attributes-with-ls
1943 (multi-method method user host localname &optional nonnumeric)
1944 "Implement `file-attributes' for tramp files using the ls(1) command."
1945 (let (symlinkp dirp
1946 res-inode res-filemodes res-numlinks
1947 res-uid res-gid res-size res-symlink-target)
1948 (tramp-message-for-buffer multi-method method user host 10
1949 "file attributes with ls: %s"
1950 (tramp-make-tramp-file-name
1951 multi-method method user host localname))
1952 (tramp-send-command
1953 multi-method method user host
1954 (format "%s %s %s"
1955 (tramp-get-ls-command multi-method method user host)
1956 (if nonnumeric "-ild" "-ildn")
1957 (tramp-shell-quote-argument localname)))
1958 (tramp-wait-for-output)
1959 ;; parse `ls -l' output ...
1960 ;; ... inode
1961 (setq res-inode
1962 (condition-case err
1963 (read (current-buffer))
1964 (invalid-read-syntax
1965 (when (and (equal (cadr err)
1966 "Integer constant overflow in reader")
1967 (string-match
1968 "^[0-9]+\\([0-9][0-9][0-9][0-9][0-9]\\)\\'"
1969 (caddr err)))
1970 (let* ((big (read (substring (caddr err) 0
1971 (match-beginning 1))))
1972 (small (read (match-string 1 (caddr err))))
1973 (twiddle (/ small 65536)))
1974 (cons (+ big twiddle)
1975 (- small (* twiddle 65536))))))))
1976 ;; ... file mode flags
1977 (setq res-filemodes (symbol-name (read (current-buffer))))
1978 ;; ... number links
1979 (setq res-numlinks (read (current-buffer)))
1980 ;; ... uid and gid
1981 (setq res-uid (read (current-buffer)))
1982 (setq res-gid (read (current-buffer)))
1983 (unless nonnumeric
1984 (unless (numberp res-uid) (setq res-uid -1))
1985 (unless (numberp res-gid) (setq res-gid -1)))
1986 ;; ... size
1987 (setq res-size (read (current-buffer)))
1988 ;; From the file modes, figure out other stuff.
1989 (setq symlinkp (eq ?l (aref res-filemodes 0)))
1990 (setq dirp (eq ?d (aref res-filemodes 0)))
1991 ;; if symlink, find out file name pointed to
1992 (when symlinkp
1993 (search-forward "-> ")
1994 (setq res-symlink-target
1995 (buffer-substring (point)
1996 (tramp-line-end-position))))
1997 ;; return data gathered
1998 (list
1999 ;; 0. t for directory, string (name linked to) for symbolic
2000 ;; link, or nil.
2001 (or dirp res-symlink-target nil)
2002 ;; 1. Number of links to file.
2003 res-numlinks
2004 ;; 2. File uid.
2005 res-uid
2006 ;; 3. File gid.
2007 res-gid
2008 ;; 4. Last access time, as a list of two integers. First
2009 ;; integer has high-order 16 bits of time, second has low 16
2010 ;; bits.
2011 ;; 5. Last modification time, likewise.
2012 ;; 6. Last status change time, likewise.
2013 '(0 0) '(0 0) '(0 0) ;CCC how to find out?
2014 ;; 7. Size in bytes (-1, if number is out of range).
2015 res-size
2016 ;; 8. File modes, as a string of ten letters or dashes as in ls -l.
2017 res-filemodes
2018 ;; 9. t iff file's gid would change if file were deleted and
2019 ;; recreated.
2020 nil ;hm?
2021 ;; 10. inode number.
2022 res-inode
2023 ;; 11. Device number. Will be replaced by a virtual device number.
2027 (defun tramp-handle-file-attributes-with-perl
2028 (multi-method method user host localname &optional nonnumeric)
2029 "Implement `file-attributes' for tramp files using a Perl script.
2031 The Perl command is sent to the remote machine when the connection
2032 is initially created and is kept cached by the remote shell."
2033 (tramp-message-for-buffer multi-method method user host 10
2034 "file attributes with perl: %s"
2035 (tramp-make-tramp-file-name
2036 multi-method method user host localname))
2037 (tramp-send-command
2038 multi-method method user host
2039 (format "tramp_file_attributes %s"
2040 (tramp-shell-quote-argument localname)))
2041 (tramp-wait-for-output)
2042 (let ((result (read (current-buffer))))
2043 (setcar (nthcdr 8 result)
2044 (tramp-file-mode-from-int (nth 8 result)))
2045 result))
2047 (defun tramp-get-device (multi-method method user host)
2048 "Returns the virtual device number.
2049 If it doesn't exist, generate a new one."
2050 (let ((string (tramp-make-tramp-file-name multi-method method user host "")))
2051 (unless (assoc string tramp-devices)
2052 (add-to-list 'tramp-devices
2053 (list string (length tramp-devices))))
2054 (list -1 (nth 1 (assoc string tramp-devices)))))
2056 (defun tramp-handle-set-visited-file-modtime (&optional time-list)
2057 "Like `set-visited-file-modtime' for tramp files."
2058 (unless (buffer-file-name)
2059 (error "Can't set-visited-file-modtime: buffer `%s' not visiting a file"
2060 (buffer-name)))
2061 (when time-list
2062 (tramp-run-real-handler 'set-visited-file-modtime (list time-list)))
2063 (let ((f (buffer-file-name))
2064 (coding-system-used nil))
2065 (with-parsed-tramp-file-name f nil
2066 (let* ((attr (file-attributes f))
2067 (modtime (nth 5 attr)))
2068 ;; We use '(0 0) as a don't-know value. See also
2069 ;; `tramp-handle-file-attributes-with-ls'.
2070 (when (boundp 'last-coding-system-used)
2071 (setq coding-system-used last-coding-system-used))
2072 (if (not (equal modtime '(0 0)))
2073 (tramp-run-real-handler 'set-visited-file-modtime (list modtime))
2074 (save-excursion
2075 (tramp-send-command
2076 multi-method method user host
2077 (format "%s -ild %s"
2078 (tramp-get-ls-command multi-method method user host)
2079 (tramp-shell-quote-argument localname)))
2080 (tramp-wait-for-output)
2081 (setq attr (buffer-substring (point)
2082 (progn (end-of-line) (point)))))
2083 (setq tramp-buffer-file-attributes attr))
2084 (when (boundp 'last-coding-system-used)
2085 (setq last-coding-system-used coding-system-used))
2086 nil))))
2088 ;; CCC continue here
2090 ;; This function makes the same assumption as
2091 ;; `tramp-handle-set-visited-file-modtime'.
2092 (defun tramp-handle-verify-visited-file-modtime (buf)
2093 "Like `verify-visited-file-modtime' for tramp files."
2094 (with-current-buffer buf
2095 (let ((f (buffer-file-name)))
2096 (with-parsed-tramp-file-name f nil
2097 (let* ((attr (file-attributes f))
2098 (modtime (nth 5 attr)))
2099 (cond ((and attr (not (equal modtime '(0 0))))
2100 ;; Why does `file-attributes' return a list (HIGH
2101 ;; LOW), but `visited-file-modtime' returns a cons
2102 ;; (HIGH . LOW)?
2103 (let ((mt (visited-file-modtime)))
2104 (< (abs (tramp-time-diff
2105 modtime (list (car mt) (cdr mt)))) 2)))
2106 (attr
2107 (save-excursion
2108 (tramp-send-command
2109 multi-method method user host
2110 (format "%s -ild %s"
2111 (tramp-get-ls-command multi-method method
2112 user host)
2113 (tramp-shell-quote-argument localname)))
2114 (tramp-wait-for-output)
2115 (setq attr (buffer-substring
2116 (point) (progn (end-of-line) (point)))))
2117 (equal tramp-buffer-file-attributes attr))
2118 ;; If file does not exist, say it is not modified.
2119 (t nil)))))))
2121 (defadvice clear-visited-file-modtime (after tramp activate)
2122 "Set `tramp-buffer-file-attributes' back to nil.
2123 Tramp uses this variable as an emulation for the actual modtime of the file,
2124 if the remote host can't provide the modtime."
2125 (setq tramp-buffer-file-attributes nil))
2127 (defun tramp-handle-set-file-modes (filename mode)
2128 "Like `set-file-modes' for tramp files."
2129 (with-parsed-tramp-file-name filename nil
2130 (save-excursion
2131 (unless (zerop (tramp-send-command-and-check
2132 multi-method method user host
2133 (format "chmod %s %s"
2134 (tramp-decimal-to-octal mode)
2135 (tramp-shell-quote-argument localname))))
2136 (signal 'file-error
2137 (list "Doing chmod"
2138 ;; FIXME: extract the proper text from chmod's stderr.
2139 "error while changing file's mode"
2140 filename))))))
2142 ;; Simple functions using the `test' command.
2144 (defun tramp-handle-file-executable-p (filename)
2145 "Like `file-executable-p' for tramp files."
2146 (with-parsed-tramp-file-name filename nil
2147 (zerop (tramp-run-test "-x" filename))))
2149 (defun tramp-handle-file-readable-p (filename)
2150 "Like `file-readable-p' for tramp files."
2151 (with-parsed-tramp-file-name filename nil
2152 (zerop (tramp-run-test "-r" filename))))
2154 (defun tramp-handle-file-accessible-directory-p (filename)
2155 "Like `file-accessible-directory-p' for tramp files."
2156 (with-parsed-tramp-file-name filename nil
2157 (and (zerop (tramp-run-test "-d" filename))
2158 (zerop (tramp-run-test "-r" filename))
2159 (zerop (tramp-run-test "-x" filename)))))
2161 ;; When the remote shell is started, it looks for a shell which groks
2162 ;; tilde expansion. Here, we assume that all shells which grok tilde
2163 ;; expansion will also provide a `test' command which groks `-nt' (for
2164 ;; newer than). If this breaks, tell me about it and I'll try to do
2165 ;; something smarter about it.
2166 (defun tramp-handle-file-newer-than-file-p (file1 file2)
2167 "Like `file-newer-than-file-p' for tramp files."
2168 (cond ((not (file-exists-p file1))
2169 nil)
2170 ((not (file-exists-p file2))
2172 ;; We are sure both files exist at this point.
2174 (save-excursion
2175 ;; We try to get the mtime of both files. If they are not
2176 ;; equal to the "dont-know" value, then we subtract the times
2177 ;; and obtain the result.
2178 (let ((fa1 (file-attributes file1))
2179 (fa2 (file-attributes file2)))
2180 (if (and (not (equal (nth 5 fa1) '(0 0)))
2181 (not (equal (nth 5 fa2) '(0 0))))
2182 (> 0 (tramp-time-diff (nth 5 fa1) (nth 5 fa2)))
2183 ;; If one of them is the dont-know value, then we can
2184 ;; still try to run a shell command on the remote host.
2185 ;; However, this only works if both files are Tramp
2186 ;; files and both have the same method, same user, same
2187 ;; host.
2188 (unless (and (tramp-tramp-file-p file1)
2189 (tramp-tramp-file-p file2))
2190 (signal
2191 'file-error
2192 (list
2193 "Cannot check if Tramp file is newer than non-Tramp file"
2194 file1 file2)))
2195 (with-parsed-tramp-file-name file1 v1
2196 (with-parsed-tramp-file-name file2 v2
2197 (unless (and (equal v1-multi-method v2-multi-method)
2198 (equal v1-method v2-method)
2199 (equal v1-user v2-user)
2200 (equal v1-host v2-host))
2201 (signal 'file-error
2202 (list "Files must have same method, user, host"
2203 file1 file2)))
2204 (unless (and (tramp-tramp-file-p file1)
2205 (tramp-tramp-file-p file2))
2206 (signal 'file-error
2207 (list "Files must be tramp files on same host"
2208 file1 file2)))
2209 (if (tramp-get-test-groks-nt
2210 v1-multi-method v1-method v1-user v1-host)
2211 (zerop (tramp-run-test2 "test" file1 file2 "-nt"))
2212 (zerop (tramp-run-test2
2213 "tramp_test_nt" file1 file2)))))))))))
2215 ;; Functions implemented using the basic functions above.
2217 (defun tramp-handle-file-modes (filename)
2218 "Like `file-modes' for tramp files."
2219 (with-parsed-tramp-file-name filename nil
2220 (when (file-exists-p filename)
2221 (tramp-mode-string-to-int
2222 (nth 8 (file-attributes filename))))))
2224 (defun tramp-handle-file-directory-p (filename)
2225 "Like `file-directory-p' for tramp files."
2226 ;; Care must be taken that this function returns `t' for symlinks
2227 ;; pointing to directories. Surely the most obvious implementation
2228 ;; would be `test -d', but that returns false for such symlinks.
2229 ;; CCC: Stefan Monnier says that `test -d' follows symlinks. And
2230 ;; I now think he's right. So we could be using `test -d', couldn't
2231 ;; we?
2233 ;; Alternatives: `cd %s', `test -d %s'
2234 (with-parsed-tramp-file-name filename nil
2235 (save-excursion
2236 (zerop
2237 (tramp-send-command-and-check
2238 multi-method method user host
2239 (format "test -d %s"
2240 (tramp-shell-quote-argument localname))
2241 t))))) ;run command in subshell
2243 (defun tramp-handle-file-regular-p (filename)
2244 "Like `file-regular-p' for tramp files."
2245 (with-parsed-tramp-file-name filename nil
2246 (and (file-exists-p filename)
2247 (eq ?- (aref (nth 8 (file-attributes filename)) 0)))))
2249 (defun tramp-handle-file-symlink-p (filename)
2250 "Like `file-symlink-p' for tramp files."
2251 (with-parsed-tramp-file-name filename nil
2252 (let ((x (car (tramp-handle-file-attributes filename))))
2253 (when (stringp x)
2254 ;; When Tramp is running on VMS, then `file-name-absolute-p'
2255 ;; might do weird things.
2256 (if (file-name-absolute-p x)
2257 (tramp-make-tramp-file-name
2258 multi-method method user host x)
2259 x)))))
2261 (defun tramp-handle-file-writable-p (filename)
2262 "Like `file-writable-p' for tramp files."
2263 (with-parsed-tramp-file-name filename nil
2264 (if (tramp-handle-file-exists-p filename)
2265 ;; Existing files must be writable.
2266 (zerop (tramp-run-test "-w" filename))
2267 ;; If file doesn't exist, check if directory is writable.
2268 (and (zerop (tramp-run-test
2269 "-d" (tramp-handle-file-name-directory filename)))
2270 (zerop (tramp-run-test
2271 "-w" (tramp-handle-file-name-directory filename)))))))
2273 (defun tramp-handle-file-ownership-preserved-p (filename)
2274 "Like `file-ownership-preserved-p' for tramp files."
2275 (with-parsed-tramp-file-name filename nil
2276 (or (not (tramp-handle-file-exists-p filename))
2277 ;; Existing files must be writable.
2278 (zerop (tramp-run-test "-O" filename)))))
2280 ;; Other file name ops.
2282 ;; ;; Matthias K\e,Av\e(Bppe <mkoeppe@mail.math.uni-magdeburg.de>
2283 ;; (defun tramp-handle-directory-file-name (directory)
2284 ;; "Like `directory-file-name' for tramp files."
2285 ;; (if (and (eq (aref directory (- (length directory) 1)) ?/)
2286 ;; (not (eq (aref directory (- (length directory) 2)) ?:)))
2287 ;; (substring directory 0 (- (length directory) 1))
2288 ;; directory))
2290 ;; ;; Philippe Troin <phil@fifi.org>
2291 ;; (defun tramp-handle-directory-file-name (directory)
2292 ;; "Like `directory-file-name' for tramp files."
2293 ;; (with-parsed-tramp-file-name directory nil
2294 ;; (let ((directory-length-1 (1- (length directory))))
2295 ;; (save-match-data
2296 ;; (if (and (eq (aref directory directory-length-1) ?/)
2297 ;; (eq (string-match tramp-file-name-regexp directory) 0)
2298 ;; (/= (match-end 0) directory-length-1))
2299 ;; (substring directory 0 directory-length-1)
2300 ;; directory)))))
2302 (defun tramp-handle-directory-file-name (directory)
2303 "Like `directory-file-name' for tramp files."
2304 ;; If localname component of filename is "/", leave it unchanged.
2305 ;; Otherwise, remove any trailing slash from localname component.
2306 ;; Method, host, etc, are unchanged. Does it make sense to try
2307 ;; to avoid parsing the filename?
2308 (with-parsed-tramp-file-name directory nil
2309 (if (and (not (zerop (length localname)))
2310 (eq (aref localname (1- (length localname))) ?/)
2311 (not (string= localname "/")))
2312 (substring directory 0 -1)
2313 directory)))
2315 ;; Directory listings.
2317 (defun tramp-handle-directory-files (directory
2318 &optional full match nosort files-only)
2319 "Like `directory-files' for tramp files."
2320 (with-parsed-tramp-file-name directory nil
2321 (let (result x)
2322 (save-excursion
2323 (tramp-barf-unless-okay
2324 multi-method method user host
2325 (concat "cd " (tramp-shell-quote-argument localname))
2327 'file-error
2328 "tramp-handle-directory-files: couldn't `cd %s'"
2329 (tramp-shell-quote-argument localname))
2330 (tramp-send-command
2331 multi-method method user host
2332 (concat (tramp-get-ls-command multi-method method user host)
2333 " -a | cat"))
2334 (tramp-wait-for-output)
2335 (goto-char (point-max))
2336 (while (zerop (forward-line -1))
2337 (setq x (buffer-substring (point)
2338 (tramp-line-end-position)))
2339 (when (or (not match) (string-match match x))
2340 (if full
2341 (push (concat (file-name-as-directory directory)
2343 result)
2344 (push x result))))
2345 (tramp-send-command multi-method method user host "cd")
2346 (tramp-wait-for-output)
2347 ;; Remove non-files or non-directories if necessary. Using
2348 ;; the remote shell for this would probably be way faster.
2349 ;; Maybe something could be adapted from
2350 ;; tramp-handle-file-name-all-completions.
2351 (when files-only
2352 (let ((temp (nreverse result))
2353 item)
2354 (setq result nil)
2355 (if (equal files-only t)
2356 ;; files only
2357 (while temp
2358 (setq item (pop temp))
2359 (when (file-regular-p item)
2360 (push item result)))
2361 ;; directories only
2362 (while temp
2363 (setq item (pop temp))
2364 (when (file-directory-p item)
2365 (push item result)))))))
2366 result)))
2368 ;; This function should return "foo/" for directories and "bar" for
2369 ;; files. We use `ls -ad' to get a list of files (including
2370 ;; directories), and `find . -type d \! -name . -prune' to get a list
2371 ;; of directories.
2372 (defun tramp-handle-file-name-all-completions (filename directory)
2373 "Like `file-name-all-completions' for tramp files."
2374 (with-parsed-tramp-file-name directory nil
2375 (unless (save-match-data (string-match "/" filename))
2376 (let* ((nowild tramp-completion-without-shell-p)
2377 result)
2378 (save-excursion
2379 (tramp-barf-unless-okay
2380 multi-method method user host
2381 (format "cd %s" (tramp-shell-quote-argument localname))
2382 nil 'file-error
2383 "tramp-handle-file-name-all-completions: Couldn't `cd %s'"
2384 (tramp-shell-quote-argument localname))
2386 ;; Get a list of directories and files, including reliably
2387 ;; tagging the directories with a trailing '/'. Because I
2388 ;; rock. --daniel@danann.net
2389 (tramp-send-command
2390 multi-method method user host
2391 (format (concat "%s -a %s 2>/dev/null | while read f; do "
2392 "if test -d \"$f\" 2>/dev/null; "
2393 "then echo \"$f/\"; else echo \"$f\"; fi; done")
2394 (tramp-get-ls-command multi-method method user host)
2395 (if (or nowild (zerop (length filename)))
2397 (format "-d %s*"
2398 (tramp-shell-quote-argument filename)))))
2400 ;; Now grab the output.
2401 (tramp-wait-for-output)
2402 (goto-char (point-max))
2403 (while (zerop (forward-line -1))
2404 (push (buffer-substring (point)
2405 (tramp-line-end-position))
2406 result))
2408 (tramp-send-command multi-method method user host "cd")
2409 (tramp-wait-for-output)
2411 ;; Return the list.
2412 (if nowild
2413 (all-completions filename (mapcar 'list result))
2414 result))))))
2417 ;; The following isn't needed for Emacs 20 but for 19.34?
2418 (defun tramp-handle-file-name-completion (filename directory)
2419 "Like `file-name-completion' for tramp files."
2420 (unless (tramp-tramp-file-p directory)
2421 (error
2422 "tramp-handle-file-name-completion invoked on non-tramp directory `%s'"
2423 directory))
2424 (with-parsed-tramp-file-name directory nil
2425 (try-completion
2426 filename
2427 (mapcar (lambda (x) (cons x nil))
2428 (file-name-all-completions filename directory)))))
2430 ;; cp, mv and ln
2432 (defun tramp-handle-add-name-to-file
2433 (filename newname &optional ok-if-already-exists)
2434 "Like `add-name-to-file' for tramp files."
2435 (with-parsed-tramp-file-name filename v1
2436 (with-parsed-tramp-file-name newname v2
2437 (let ((ln (when v1 (tramp-get-remote-ln
2438 v1-multi-method v1-method v1-user v1-host))))
2439 (unless (and v1-method v2-method v1-user v2-user v1-host v2-host
2440 (equal v1-multi-method v2-multi-method)
2441 (equal v1-method v2-method)
2442 (equal v1-user v2-user)
2443 (equal v1-host v2-host))
2444 (error "add-name-to-file: %s"
2445 "only implemented for same method, same user, same host"))
2446 (when (and (not ok-if-already-exists)
2447 (file-exists-p newname)
2448 (not (numberp ok-if-already-exists))
2449 (y-or-n-p
2450 (format
2451 "File %s already exists; make it a new name anyway? "
2452 newname)))
2453 (error "add-name-to-file: file %s already exists" newname))
2454 (tramp-barf-unless-okay
2455 v1-multi-method v1-method v1-user v1-host
2456 (format "%s %s %s" ln (tramp-shell-quote-argument v1-localname)
2457 (tramp-shell-quote-argument v2-localname))
2458 nil 'file-error
2459 "error with add-name-to-file, see buffer `%s' for details"
2460 (buffer-name))))))
2462 (defun tramp-handle-copy-file
2463 (filename newname &optional ok-if-already-exists keep-date)
2464 "Like `copy-file' for tramp files."
2465 ;; Check if both files are local -- invoke normal copy-file.
2466 ;; Otherwise, use tramp from local system.
2467 (setq filename (expand-file-name filename))
2468 (setq newname (expand-file-name newname))
2469 ;; At least one file a tramp file?
2470 (if (or (tramp-tramp-file-p filename)
2471 (tramp-tramp-file-p newname))
2472 (let ((modes (file-modes filename)))
2473 (tramp-do-copy-or-rename-file
2474 'copy filename newname ok-if-already-exists keep-date)
2475 (set-file-modes newname modes))
2476 (tramp-run-real-handler
2477 'copy-file
2478 (list filename newname ok-if-already-exists keep-date))))
2480 (defun tramp-handle-rename-file
2481 (filename newname &optional ok-if-already-exists)
2482 "Like `rename-file' for tramp files."
2483 ;; Check if both files are local -- invoke normal rename-file.
2484 ;; Otherwise, use tramp from local system.
2485 (setq filename (expand-file-name filename))
2486 (setq newname (expand-file-name newname))
2487 ;; At least one file a tramp file?
2488 (if (or (tramp-tramp-file-p filename)
2489 (tramp-tramp-file-p newname))
2490 (tramp-do-copy-or-rename-file
2491 'rename filename newname ok-if-already-exists)
2492 (tramp-run-real-handler 'rename-file
2493 (list filename newname ok-if-already-exists))))
2495 (defun tramp-do-copy-or-rename-file
2496 (op filename newname &optional ok-if-already-exists keep-date)
2497 "Copy or rename a remote file.
2498 OP must be `copy' or `rename' and indicates the operation to perform.
2499 FILENAME specifies the file to copy or rename, NEWNAME is the name of
2500 the new file (for copy) or the new name of the file (for rename).
2501 OK-IF-ALREADY-EXISTS means don't barf if NEWNAME exists already.
2502 KEEP-DATE means to make sure that NEWNAME has the same timestamp
2503 as FILENAME.
2505 This function is invoked by `tramp-handle-copy-file' and
2506 `tramp-handle-rename-file'. It is an error if OP is neither of `copy'
2507 and `rename'. FILENAME and NEWNAME must be absolute file names."
2508 (unless (memq op '(copy rename))
2509 (error "Unknown operation `%s', must be `copy' or `rename'" op))
2510 (unless ok-if-already-exists
2511 (when (file-exists-p newname)
2512 (signal 'file-already-exists
2513 (list newname))))
2514 (let ((t1 (tramp-tramp-file-p filename))
2515 (t2 (tramp-tramp-file-p newname)))
2516 ;; Check which ones of source and target are Tramp files.
2517 (cond
2518 ((and t1 t2)
2519 ;; Both are Tramp files.
2520 (with-parsed-tramp-file-name filename v1
2521 (with-parsed-tramp-file-name newname v2
2522 ;; Check if we can use a shortcut.
2523 (if (and (equal v1-multi-method v2-multi-method)
2524 (equal v1-method v2-method)
2525 (equal v1-host v2-host)
2526 (equal v1-user v2-user))
2527 ;; Shortcut: if method, host, user are the same for both
2528 ;; files, we invoke `cp' or `mv' on the remote host
2529 ;; directly.
2530 (tramp-do-copy-or-rename-file-directly
2531 op v1-multi-method v1-method v1-user v1-host
2532 v1-localname v2-localname keep-date)
2533 ;; The shortcut was not possible. So we copy the
2534 ;; file first. If the operation was `rename', we go
2535 ;; back and delete the original file (if the copy was
2536 ;; successful). The approach is simple-minded: we
2537 ;; create a new buffer, insert the contents of the
2538 ;; source file into it, then write out the buffer to
2539 ;; the target file. The advantage is that it doesn't
2540 ;; matter which filename handlers are used for the
2541 ;; source and target file.
2543 ;; CCC: If both source and target are Tramp files,
2544 ;; and both are using the same copy-program, then we
2545 ;; can invoke rcp directly. Note that
2546 ;; default-directory should point to a local
2547 ;; directory if we want to invoke rcp.
2548 (tramp-do-copy-or-rename-via-buffer
2549 op filename newname keep-date)))))
2550 ((or t1 t2)
2551 ;; Use the generic method via a Tramp buffer.
2552 (tramp-do-copy-or-rename-via-buffer op filename newname keep-date))
2554 ;; One of them must be a Tramp file.
2555 (error "Tramp implementation says this cannot happen")))))
2557 ;; CCC: implement keep-date if possible -- via touch?
2558 (defun tramp-do-copy-or-rename-via-buffer (op filename newname keep-date)
2559 "Use an Emacs buffer to copy or rename a file.
2560 First arg OP is either `copy' or `rename' and indicates the operation.
2561 FILENAME is the source file, NEWNAME the target file.
2562 KEEP-DATE is non-nil if NEWNAME should have the same timestamp as FILENAME."
2563 (let ((trampbuf (get-buffer-create "*tramp output*")))
2564 (when keep-date
2565 (tramp-message
2566 1 (concat "Warning: cannot preserve file time stamp"
2567 " with inline copying across machines")))
2568 (save-excursion
2569 (set-buffer trampbuf) (erase-buffer)
2570 (insert-file-contents-literally filename)
2571 ;; We don't want the target file to be compressed, so we let-bind
2572 ;; `jka-compr-inhibit' to t.
2573 (let ((coding-system-for-write 'binary)
2574 (jka-compr-inhibit t))
2575 (write-region (point-min) (point-max) newname)))
2576 ;; If the operation was `rename', delete the original file.
2577 (unless (eq op 'copy)
2578 (delete-file filename))))
2580 (defun tramp-do-copy-or-rename-file-directly
2581 (op multi-method method user host localname1 localname2 keep-date)
2582 "Invokes `cp' or `mv' on the remote system.
2583 OP must be one of `copy' or `rename', indicating `cp' or `mv',
2584 respectively. METHOD, USER, and HOST specify the connection.
2585 LOCALNAME1 and LOCALNAME2 specify the two arguments of `cp' or `mv'.
2586 If KEEP-DATE is non-nil, preserve the time stamp when copying."
2587 ;; CCC: What happens to the timestamp when renaming?
2588 (let ((cmd (cond ((and (eq op 'copy) keep-date) "cp -f -p")
2589 ((eq op 'copy) "cp -f")
2590 ((eq op 'rename) "mv -f")
2591 (t (error
2592 "Unknown operation `%s', must be `copy' or `rename'"
2593 op)))))
2594 (save-excursion
2595 (tramp-barf-unless-okay
2596 multi-method method user host
2597 (format "%s %s %s"
2599 (tramp-shell-quote-argument localname1)
2600 (tramp-shell-quote-argument localname2))
2601 nil 'file-error
2602 "Copying directly failed, see buffer `%s' for details."
2603 (buffer-name)))))
2605 (defun tramp-do-copy-or-rename-file-one-local
2606 (op filename newname keep-date)
2607 "Invoke rcp program to copy.
2608 One of FILENAME and NEWNAME must be a Tramp name, the other must
2609 be a local filename. The method used must be an out-of-band method."
2610 ;; CCC
2613 ;; mkdir
2614 (defun tramp-handle-make-directory (dir &optional parents)
2615 "Like `make-directory' for tramp files."
2616 (setq dir (expand-file-name dir))
2617 (with-parsed-tramp-file-name dir nil
2618 (save-excursion
2619 (tramp-barf-unless-okay
2620 multi-method method user host
2621 (format " %s %s"
2622 (if parents "mkdir -p" "mkdir")
2623 (tramp-shell-quote-argument localname))
2624 nil 'file-error
2625 "Couldn't make directory %s" dir))))
2627 ;; CCC error checking?
2628 (defun tramp-handle-delete-directory (directory)
2629 "Like `delete-directory' for tramp files."
2630 (setq directory (expand-file-name directory))
2631 (with-parsed-tramp-file-name directory nil
2632 (save-excursion
2633 (tramp-send-command
2634 multi-method method user host
2635 (format "rmdir %s ; echo ok"
2636 (tramp-shell-quote-argument localname)))
2637 (tramp-wait-for-output))))
2639 (defun tramp-handle-delete-file (filename)
2640 "Like `delete-file' for tramp files."
2641 (setq filename (expand-file-name filename))
2642 (with-parsed-tramp-file-name filename nil
2643 (save-excursion
2644 (unless (zerop (tramp-send-command-and-check
2645 multi-method method user host
2646 (format "rm -f %s"
2647 (tramp-shell-quote-argument localname))))
2648 (signal 'file-error "Couldn't delete Tramp file")))))
2650 ;; Dired.
2652 ;; CCC: This does not seem to be enough. Something dies when
2653 ;; we try and delete two directories under TRAMP :/
2654 (defun tramp-handle-dired-recursive-delete-directory (filename)
2655 "Recursively delete the directory given.
2656 This is like `dired-recursive-delete-directory' for tramp files."
2657 (with-parsed-tramp-file-name filename nil
2658 ;; run a shell command 'rm -r <localname>'
2659 ;; Code shamelessly stolen for the dired implementation and, um, hacked :)
2660 (or (tramp-handle-file-exists-p filename)
2661 (signal
2662 'file-error
2663 (list "Removing old file name" "no such directory" filename)))
2664 ;; Which is better, -r or -R? (-r works for me <daniel@danann.net>)
2665 (tramp-send-command multi-method method user host
2666 (format "rm -r %s" (tramp-shell-quote-argument localname)))
2667 ;; Wait for the remote system to return to us...
2668 ;; This might take a while, allow it plenty of time.
2669 (tramp-wait-for-output 120)
2670 ;; Make sure that it worked...
2671 (and (tramp-handle-file-exists-p filename)
2672 (error "Failed to recusively delete %s" filename))))
2675 (defun tramp-handle-dired-call-process (program discard &rest arguments)
2676 "Like `dired-call-process' for tramp files."
2677 (with-parsed-tramp-file-name default-directory nil
2678 (save-excursion
2679 (tramp-barf-unless-okay
2680 multi-method method user host
2681 (format "cd %s" (tramp-shell-quote-argument localname))
2682 nil 'file-error
2683 "tramp-handle-dired-call-process: Couldn't `cd %s'"
2684 (tramp-shell-quote-argument localname))
2685 (tramp-send-command
2686 multi-method method user host
2687 (mapconcat #'tramp-shell-quote-argument (cons program arguments) " "))
2688 (tramp-wait-for-output))
2689 (unless discard
2690 (insert-buffer (tramp-get-buffer multi-method method user host)))
2691 (save-excursion
2692 (prog1
2693 (tramp-send-command-and-check multi-method method user host nil)
2694 (tramp-send-command multi-method method user host "cd")
2695 (tramp-wait-for-output)))))
2697 ;; Pacify byte-compiler. The function is needed on XEmacs only. I'm
2698 ;; not sure at all that this is the right way to do it, but let's hope
2699 ;; it works for now, and wait for a guru to point out the Right Way to
2700 ;; achieve this.
2701 ;;(eval-when-compile
2702 ;; (unless (fboundp 'dired-insert-set-properties)
2703 ;; (fset 'dired-insert-set-properties 'ignore)))
2704 ;; Gerd suggests this:
2705 (eval-when-compile (require 'dired))
2706 ;; Note that dired is required at run-time, too, when it is needed.
2707 ;; It is only needed on XEmacs for the function
2708 ;; `dired-insert-set-properties'.
2710 (defun tramp-handle-insert-directory
2711 (filename switches &optional wildcard full-directory-p)
2712 "Like `insert-directory' for tramp files."
2713 ;; For the moment, we assume that the remote "ls" program does not
2714 ;; grok "--dired". In the future, we should detect this on
2715 ;; connection setup.
2716 (when (string-match "^--dired\\s-+" switches)
2717 (setq switches (replace-match "" nil t switches)))
2718 (setq filename (expand-file-name filename))
2719 (with-parsed-tramp-file-name filename nil
2720 (tramp-message-for-buffer
2721 multi-method method user host 10
2722 "Inserting directory `ls %s %s', wildcard %s, fulldir %s"
2723 switches filename (if wildcard "yes" "no")
2724 (if full-directory-p "yes" "no"))
2725 (when wildcard
2726 (setq wildcard (file-name-nondirectory localname))
2727 (setq localname (file-name-directory localname)))
2728 (when (listp switches)
2729 (setq switches (mapconcat 'identity switches " ")))
2730 (unless full-directory-p
2731 (setq switches (concat "-d " switches)))
2732 (when wildcard
2733 (setq switches (concat switches " " wildcard)))
2734 (save-excursion
2735 ;; If `full-directory-p', we just say `ls -l FILENAME'.
2736 ;; Else we chdir to the parent directory, then say `ls -ld BASENAME'.
2737 (if full-directory-p
2738 (tramp-send-command
2739 multi-method method user host
2740 (format "%s %s %s"
2741 (tramp-get-ls-command multi-method method user host)
2742 switches
2743 (if wildcard
2744 localname
2745 (tramp-shell-quote-argument (concat localname ".")))))
2746 (tramp-barf-unless-okay
2747 multi-method method user host
2748 (format "cd %s" (tramp-shell-quote-argument
2749 (file-name-directory localname)))
2750 nil 'file-error
2751 "Couldn't `cd %s'"
2752 (tramp-shell-quote-argument (file-name-directory localname)))
2753 (tramp-send-command
2754 multi-method method user host
2755 (format "%s %s %s"
2756 (tramp-get-ls-command multi-method method user host)
2757 switches
2758 (if full-directory-p
2759 ;; Add "/." to make sure we got complete dir
2760 ;; listing for symlinks, too.
2761 (concat (file-name-as-directory
2762 (file-name-nondirectory localname)) ".")
2763 (file-name-nondirectory localname)))))
2764 (sit-for 1) ;needed for rsh but not ssh?
2765 (tramp-wait-for-output))
2766 ;; The following let-binding is used by code that's commented
2767 ;; out. Let's leave the let-binding in for a while to see
2768 ;; that the commented-out code is really not needed. Commenting-out
2769 ;; happened on 2003-03-13.
2770 (let ((old-pos (point)))
2771 (insert-buffer-substring
2772 (tramp-get-buffer multi-method method user host))
2773 ;; On XEmacs, we want to call (exchange-point-and-mark t), but
2774 ;; that doesn't exist on Emacs, so we use this workaround instead.
2775 ;; Since zmacs-region-stays doesn't exist in Emacs, this ought to
2776 ;; be safe. Thanks to Daniel Pittman <daniel@danann.net>.
2777 ;; (let ((zmacs-region-stays t))
2778 ;; (exchange-point-and-mark))
2779 (save-excursion
2780 (tramp-send-command multi-method method user host "cd")
2781 (tramp-wait-for-output))
2782 ;; For the time being, the XEmacs kludge is commented out.
2783 ;; Please test it on various XEmacs versions to see if it works.
2784 ;; ;; Another XEmacs specialty follows. What's the right way to do
2785 ;; ;; it?
2786 ;; (when (and (featurep 'xemacs)
2787 ;; (eq major-mode 'dired-mode))
2788 ;; (save-excursion
2789 ;; (require 'dired)
2790 ;; (dired-insert-set-properties old-pos (point))))
2793 ;; Continuation of kluge to pacify byte-compiler.
2794 ;;(eval-when-compile
2795 ;; (when (eq (symbol-function 'dired-insert-set-properties) 'ignore)
2796 ;; (fmakunbound 'dired-insert-set-properties)))
2798 ;; CCC is this the right thing to do?
2799 (defun tramp-handle-unhandled-file-name-directory (filename)
2800 "Like `unhandled-file-name-directory' for tramp files."
2801 (with-parsed-tramp-file-name filename nil
2802 (expand-file-name "~/")))
2804 ;; Canonicalization of file names.
2806 (defun tramp-drop-volume-letter (name)
2807 "Cut off unnecessary drive letter from file NAME.
2808 The function `tramp-handle-expand-file-name' calls `expand-file-name'
2809 locally on a remote file name. When the local system is a W32 system
2810 but the remote system is Unix, this introduces a superfluous drive
2811 letter into the file name. This function removes it.
2813 Doesn't do anything if the NAME does not start with a drive letter."
2814 (if (and (> (length name) 1)
2815 (char-equal (aref name 1) ?:)
2816 (let ((c1 (aref name 0)))
2817 (or (and (>= c1 ?A) (<= c1 ?Z))
2818 (and (>= c1 ?a) (<= c1 ?z)))))
2819 (substring name 2)
2820 name))
2822 (defun tramp-handle-expand-file-name (name &optional dir)
2823 "Like `expand-file-name' for tramp files.
2824 If the localname part of the given filename starts with \"/../\" then
2825 the result will be a local, non-Tramp, filename."
2826 ;; If DIR is not given, use DEFAULT-DIRECTORY or "/".
2827 (setq dir (or dir default-directory "/"))
2828 ;; Unless NAME is absolute, concat DIR and NAME.
2829 (unless (file-name-absolute-p name)
2830 (setq name (concat (file-name-as-directory dir) name)))
2831 ;; If NAME is not a tramp file, run the real handler
2832 (if (not (tramp-tramp-file-p name))
2833 (tramp-run-real-handler 'expand-file-name
2834 (list name nil))
2835 ;; Dissect NAME.
2836 (with-parsed-tramp-file-name name nil
2837 (unless (file-name-absolute-p localname)
2838 (setq localname (concat "~/" localname)))
2839 (save-excursion
2840 ;; Tilde expansion if necessary. This needs a shell which
2841 ;; groks tilde expansion! The function `tramp-find-shell' is
2842 ;; supposed to find such a shell on the remote host. Please
2843 ;; tell me about it when this doesn't work on your system.
2844 (when (string-match "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname)
2845 (let ((uname (match-string 1 localname))
2846 (fname (match-string 2 localname)))
2847 ;; CCC fanatic error checking?
2848 (set-buffer (tramp-get-buffer multi-method method user host))
2849 (erase-buffer)
2850 (tramp-send-command
2851 multi-method method user host
2852 (format "cd %s; pwd" uname)
2854 (tramp-wait-for-output)
2855 (goto-char (point-min))
2856 (setq uname (buffer-substring (point) (tramp-line-end-position)))
2857 (setq localname (concat uname fname))
2858 (erase-buffer)))
2859 ;; No tilde characters in file name, do normal
2860 ;; expand-file-name (this does "/./" and "/../"). We bind
2861 ;; directory-sep-char here for XEmacs on Windows, which
2862 ;; would otherwise use backslash.
2863 (let ((directory-sep-char ?/))
2864 (tramp-make-tramp-file-name
2865 multi-method (or method (tramp-find-default-method user host))
2866 user host
2867 (tramp-drop-volume-letter
2868 (tramp-run-real-handler 'expand-file-name
2869 (list localname)))))))))
2871 ;; old version follows. it uses ".." to cross file handler
2872 ;; boundaries.
2873 ;; ;; Look if localname starts with "/../" construct. If this is
2874 ;; ;; the case, then we return a local name instead of a remote name.
2875 ;; (if (string-match "^/\\.\\./" localname)
2876 ;; (expand-file-name (substring localname 3))
2877 ;; ;; No tilde characters in file name, do normal
2878 ;; ;; expand-file-name (this does "/./" and "/../"). We bind
2879 ;; ;; directory-sep-char here for XEmacs on Windows, which
2880 ;; ;; would otherwise use backslash.
2881 ;; (let ((directory-sep-char ?/))
2882 ;; (tramp-make-tramp-file-name
2883 ;; multi-method method user host
2884 ;; (tramp-drop-volume-letter
2885 ;; (tramp-run-real-handler 'expand-file-name
2886 ;; (list localname))))))))))
2888 ;; Remote commands.
2890 (defun tramp-handle-shell-command (command &optional output-buffer error-buffer)
2891 "Like `shell-command' for tramp files.
2892 This will break if COMMAND prints a newline, followed by the value of
2893 `tramp-end-of-output', followed by another newline."
2894 (if (tramp-tramp-file-p default-directory)
2895 (with-parsed-tramp-file-name default-directory nil
2896 (let (status)
2897 (when (string-match "&[ \t]*\\'" command)
2898 (error "Tramp doesn't grok asynchronous shell commands, yet"))
2899 (when error-buffer
2900 (error "Tramp doesn't grok optional third arg ERROR-BUFFER, yet"))
2901 (save-excursion
2902 (tramp-barf-unless-okay
2903 multi-method method user host
2904 (format "cd %s" (tramp-shell-quote-argument localname))
2905 nil 'file-error
2906 "tramp-handle-shell-command: Couldn't `cd %s'"
2907 (tramp-shell-quote-argument localname))
2908 (tramp-send-command multi-method method user host
2909 (concat command "; tramp_old_status=$?"))
2910 ;; This will break if the shell command prints "/////"
2911 ;; somewhere. Let's just hope for the best...
2912 (tramp-wait-for-output))
2913 (unless output-buffer
2914 (setq output-buffer (get-buffer-create "*Shell Command Output*"))
2915 (set-buffer output-buffer)
2916 (erase-buffer))
2917 (unless (bufferp output-buffer)
2918 (setq output-buffer (current-buffer)))
2919 (set-buffer output-buffer)
2920 (insert-buffer (tramp-get-buffer multi-method method user host))
2921 (save-excursion
2922 (tramp-send-command multi-method method user host "cd")
2923 (tramp-wait-for-output)
2924 (tramp-send-command
2925 multi-method method user host
2926 (concat "tramp_set_exit_status $tramp_old_status;"
2927 " echo tramp_exit_status $?"))
2928 (tramp-wait-for-output)
2929 (goto-char (point-max))
2930 (unless (search-backward "tramp_exit_status " nil t)
2931 (error "Couldn't find exit status of `%s'" command))
2932 (skip-chars-forward "^ ")
2933 (setq status (read (current-buffer))))
2934 (unless (zerop (buffer-size))
2935 (display-buffer output-buffer))
2936 status))
2937 ;; The following is only executed if something strange was
2938 ;; happening. Emit a helpful message and do it anyway.
2939 (message "tramp-handle-shell-command called with non-tramp directory: `%s'"
2940 default-directory)
2941 (tramp-run-real-handler 'shell-command
2942 (list command output-buffer error-buffer))))
2944 ;; File Editing.
2946 (defsubst tramp-make-temp-file ()
2947 (funcall (if (fboundp 'make-temp-file) 'make-temp-file 'make-temp-name)
2948 (expand-file-name tramp-temp-name-prefix
2949 (tramp-temporary-file-directory))))
2951 (defun tramp-handle-file-local-copy (filename)
2952 "Like `file-local-copy' for tramp files."
2953 (with-parsed-tramp-file-name filename nil
2954 (let ((output-buf (get-buffer-create "*tramp output*"))
2955 (tramp-buf (tramp-get-buffer multi-method method user host))
2956 (copy-program (tramp-get-copy-program
2957 multi-method
2958 (tramp-find-method multi-method method user host)
2959 user host))
2960 (copy-args (tramp-get-copy-args
2961 multi-method
2962 (tramp-find-method multi-method method user host)
2963 user host))
2964 ;; We used to bind the following as late as possible.
2965 ;; loc-enc and loc-dec were bound directly before the if
2966 ;; statement that checks them. But the functions
2967 ;; tramp-get-* might invoke the "are you awake" check in
2968 ;; tramp-maybe-open-connection, which is an unfortunate time
2969 ;; since we rely on the buffer contents at that spot.
2970 (rem-enc (tramp-get-remote-encoding multi-method method user host))
2971 (rem-dec (tramp-get-remote-decoding multi-method method user host))
2972 (loc-enc (tramp-get-local-encoding multi-method method user host))
2973 (loc-dec (tramp-get-local-decoding multi-method method user host))
2974 tmpfil)
2975 (unless (file-exists-p filename)
2976 (error "Cannot make local copy of non-existing file `%s'"
2977 filename))
2978 (setq tmpfil (tramp-make-temp-file))
2979 (cond (copy-program
2980 ;; The following should be changed. We need a more general
2981 ;; mechanism to parse extra host args.
2982 (when (string-match "\\([^#]*\\)#\\(.*\\)" host)
2983 (setq copy-args (cons "-p" (cons (match-string 2 host)
2984 rsh-args)))
2985 (setq host (match-string 1 host)))
2986 ;; Use rcp-like program for file transfer.
2987 (tramp-message-for-buffer
2988 multi-method method user host
2989 5 "Fetching %s to tmp file %s..." filename tmpfil)
2990 (save-excursion (set-buffer output-buf) (erase-buffer))
2991 (unless (equal
2993 (apply #'call-process
2994 copy-program
2995 nil output-buf nil
2996 (append copy-args
2997 (list
2998 (tramp-make-copy-program-file-name
2999 user host
3000 (tramp-shell-quote-argument localname))
3001 tmpfil))))
3002 (pop-to-buffer output-buf)
3003 (error
3004 (concat "tramp-handle-file-local-copy: `%s' didn't work, "
3005 "see buffer `%s' for details")
3006 copy-program output-buf))
3007 (tramp-message-for-buffer
3008 multi-method method user host
3009 5 "Fetching %s to tmp file %s...done" filename tmpfil))
3010 ((and rem-enc rem-dec)
3011 ;; Use inline encoding for file transfer.
3012 (save-excursion
3013 ;; Following line for setting tramp-current-method,
3014 ;; tramp-current-user, tramp-current-host.
3015 (set-buffer tramp-buf)
3016 (tramp-message 5 "Encoding remote file %s..." filename)
3017 (tramp-barf-unless-okay
3018 multi-method method user host
3019 (concat rem-enc " < " (tramp-shell-quote-argument localname))
3020 nil 'file-error
3021 "Encoding remote file failed, see buffer `%s' for details"
3022 tramp-buf)
3023 ;; Remove trailing status code
3024 (goto-char (point-max))
3025 (delete-region (point) (progn (forward-line -1) (point)))
3027 (tramp-message 5 "Decoding remote file %s..." filename)
3029 ;; Here is where loc-enc and loc-dec used to be let-bound.
3030 (if (and (symbolp loc-dec) (fboundp loc-dec))
3031 ;; If local decoding is a function, we call it.
3032 (let ((tmpbuf (get-buffer-create " *tramp tmp*")))
3033 (set-buffer tmpbuf)
3034 (erase-buffer)
3035 (insert-buffer tramp-buf)
3036 (tramp-message-for-buffer
3037 multi-method method user host
3038 6 "Decoding remote file %s with function %s..."
3039 filename loc-dec)
3040 (set-buffer tmpbuf)
3041 ;; Douglas Gray Stephens <DGrayStephens@slb.com>
3042 ;; says that we need to strip tramp_exit_status
3043 ;; line from the output here. Go to point-max,
3044 ;; search backward for tramp_exit_status, delete
3045 ;; between point and point-max if found.
3046 (let ((coding-system-for-write 'binary))
3047 (funcall loc-dec (point-min) (point-max))
3048 (write-region (point-min) (point-max) tmpfil))
3049 (kill-buffer tmpbuf))
3050 ;; If tramp-decoding-function is not defined for this
3051 ;; method, we invoke tramp-decoding-command instead.
3052 (let ((tmpfil2 (tramp-make-temp-file)))
3053 (write-region (point-min) (point-max) tmpfil2)
3054 (tramp-message
3055 6 "Decoding remote file %s with command %s..."
3056 filename loc-dec)
3057 (tramp-call-local-coding-command
3058 loc-dec tmpfil2 tmpfil)
3059 (delete-file tmpfil2)))
3060 (tramp-message-for-buffer
3061 multi-method method user host
3062 5 "Decoding remote file %s...done" filename)))
3064 (t (error "Wrong method specification for `%s'" method)))
3065 tmpfil)))
3068 (defun tramp-handle-insert-file-contents
3069 (filename &optional visit beg end replace)
3070 "Like `insert-file-contents' for tramp files."
3071 (barf-if-buffer-read-only)
3072 (setq filename (expand-file-name filename))
3073 (with-parsed-tramp-file-name filename nil
3074 (if (not (file-exists-p filename))
3075 (progn
3076 (when visit
3077 (setq buffer-file-name filename)
3078 (set-visited-file-modtime)
3079 (set-buffer-modified-p nil))
3080 (signal 'file-error
3081 (format "File `%s' not found on remote host" filename))
3082 (list (expand-file-name filename) 0))
3083 ;; `insert-file-contents-literally' takes care to avoid calling
3084 ;; jka-compr. By let-binding inhibit-file-name-operation, we
3085 ;; propagate that care to the file-local-copy operation.
3086 (let ((local-copy
3087 (let ((inhibit-file-name-operation 'file-local-copy))
3088 (file-local-copy filename)))
3089 (coding-system-used nil)
3090 (result nil))
3091 (when visit
3092 (setq buffer-file-name filename)
3093 (set-visited-file-modtime)
3094 (set-buffer-modified-p nil))
3095 (tramp-message-for-buffer
3096 multi-method method user host
3097 9 "Inserting local temp file `%s'..." local-copy)
3098 (setq result (insert-file-contents local-copy nil beg end replace))
3099 ;; Now `last-coding-system-used' has right value. Remember it.
3100 (when (boundp 'last-coding-system-used)
3101 (setq coding-system-used last-coding-system-used))
3102 (tramp-message-for-buffer
3103 multi-method method user host
3104 9 "Inserting local temp file `%s'...done" local-copy)
3105 (delete-file local-copy)
3106 (when (boundp 'last-coding-system-used)
3107 (setq last-coding-system-used coding-system-used))
3108 (list (expand-file-name filename)
3109 (second result))))))
3111 ;; CCC grok APPEND, LOCKNAME, CONFIRM
3112 (defun tramp-handle-write-region
3113 (start end filename &optional append visit lockname confirm)
3114 "Like `write-region' for tramp files."
3115 (unless (eq append nil)
3116 (error "Cannot append to file using tramp (`%s')" filename))
3117 (setq filename (expand-file-name filename))
3118 ;; Following part commented out because we don't know what to do about
3119 ;; file locking, and it does not appear to be a problem to ignore it.
3120 ;; Ange-ftp ignores it, too.
3121 ;; (when (and lockname (stringp lockname))
3122 ;; (setq lockname (expand-file-name lockname)))
3123 ;; (unless (or (eq lockname nil)
3124 ;; (string= lockname filename))
3125 ;; (error
3126 ;; "tramp-handle-write-region: LOCKNAME must be nil or equal FILENAME"))
3127 ;; XEmacs takes a coding system as the sevent argument, not `confirm'
3128 (when (and (not (featurep 'xemacs))
3129 confirm (file-exists-p filename))
3130 (unless (y-or-n-p (format "File %s exists; overwrite anyway? "
3131 filename))
3132 (error "File not overwritten")))
3133 (with-parsed-tramp-file-name filename nil
3134 (let ((curbuf (current-buffer))
3135 (copy-program (tramp-get-copy-program
3136 multi-method
3137 (tramp-find-method multi-method method user host)
3138 user host))
3139 (copy-args (tramp-get-copy-args
3140 multi-method
3141 (tramp-find-method multi-method method user host)
3142 user host))
3143 (rem-enc (tramp-get-remote-encoding multi-method method user host))
3144 (rem-dec (tramp-get-remote-decoding multi-method method user host))
3145 (loc-enc (tramp-get-local-encoding multi-method method user host))
3146 (loc-dec (tramp-get-local-decoding multi-method method user host))
3147 (trampbuf (get-buffer-create "*tramp output*"))
3148 ;; We use this to save the value of `last-coding-system-used'
3149 ;; after writing the tmp file. At the end of the function,
3150 ;; we set `last-coding-system-used' to this saved value.
3151 ;; This way, any intermediary coding systems used while
3152 ;; talking to the remote shell or suchlike won't hose this
3153 ;; variable. This approach was snarfed from ange-ftp.el.
3154 coding-system-used
3155 tmpfil)
3156 ;; Write region into a tmp file. This isn't really needed if we
3157 ;; use an encoding function, but currently we use it always
3158 ;; because this makes the logic simpler.
3159 (setq tmpfil (tramp-make-temp-file))
3160 ;; We say `no-message' here because we don't want the visited file
3161 ;; modtime data to be clobbered from the temp file. We call
3162 ;; `set-visited-file-modtime' ourselves later on.
3163 (tramp-run-real-handler
3164 'write-region
3165 (if confirm ; don't pass this arg unless defined for backward compat.
3166 (list start end tmpfil append 'no-message lockname confirm)
3167 (list start end tmpfil append 'no-message lockname)))
3168 ;; Now, `last-coding-system-used' has the right value. Remember it.
3169 (when (boundp 'last-coding-system-used)
3170 (setq coding-system-used last-coding-system-used))
3171 ;; This is a bit lengthy due to the different methods possible for
3172 ;; file transfer. First, we check whether the method uses an rcp
3173 ;; program. If so, we call it. Otherwise, both encoding and
3174 ;; decoding command must be specified. However, if the method
3175 ;; _also_ specifies an encoding function, then that is used for
3176 ;; encoding the contents of the tmp file.
3177 (cond (copy-program
3178 ;; The following should be changed. We need a more general
3179 ;; mechanism to parse extra host args.
3180 (when (string-match "\\([^#]*\\)#\\(.*\\)" host)
3181 (setq copy-args (cons "-p" (cons (match-string 2 host)
3182 rsh-args)))
3183 (setq host (match-string 1 host)))
3185 ;; use rcp-like program for file transfer
3186 (let ((argl (append copy-args
3187 (list
3188 tmpfil
3189 (tramp-make-copy-program-file-name
3190 user host
3191 (tramp-shell-quote-argument localname))))))
3192 (tramp-message-for-buffer
3193 multi-method method user host
3194 6 "Writing tmp file using `%s'..." copy-program)
3195 (save-excursion (set-buffer trampbuf) (erase-buffer))
3196 (when tramp-debug-buffer
3197 (save-excursion
3198 (set-buffer (tramp-get-debug-buffer multi-method
3199 method user host))
3200 (goto-char (point-max))
3201 (tramp-insert-with-face
3202 'bold (format "$ %s %s\n" copy-program
3203 (mapconcat 'identity argl " ")))))
3204 (unless (equal 0
3205 (apply #'call-process
3206 copy-program nil trampbuf nil argl))
3207 (pop-to-buffer trampbuf)
3208 (error
3209 "Cannot write region to file `%s', command `%s' failed"
3210 filename copy-program))
3211 (tramp-message-for-buffer
3212 multi-method method user host
3213 6 "Transferring file using `%s'...done"
3214 copy-program)))
3215 ((and rem-enc rem-dec)
3216 ;; Use inline file transfer
3217 (let ((tmpbuf (get-buffer-create " *tramp file transfer*")))
3218 (save-excursion
3219 ;; Encode tmpfil into tmpbuf
3220 (tramp-message-for-buffer multi-method method user host
3221 5 "Encoding region...")
3222 (set-buffer tmpbuf)
3223 (erase-buffer)
3224 ;; Use encoding function or command.
3225 (if (and (symbolp loc-enc) (fboundp loc-enc))
3226 (progn
3227 (tramp-message-for-buffer
3228 multi-method method user host
3229 6 "Encoding region using function...")
3230 (insert-file-contents-literally tmpfil)
3231 ;; CCC. The following `let' is a workaround for
3232 ;; the base64.el that comes with pgnus-0.84. If
3233 ;; both of the following conditions are
3234 ;; satisfied, it tries to write to a local file
3235 ;; in default-directory, but at this point,
3236 ;; default-directory is remote.
3237 ;; (CALL-PROCESS-REGION can't write to remote
3238 ;; files, it seems.) The file in question is a
3239 ;; tmp file anyway.
3240 (let ((default-directory
3241 (tramp-temporary-file-directory)))
3242 (funcall loc-enc (point-min) (point-max)))
3243 (goto-char (point-max))
3244 (unless (bolp)
3245 (newline)))
3246 (tramp-message-for-buffer
3247 multi-method method user host
3248 6 "Encoding region using command `%s'..." loc-enc)
3249 (unless (equal 0 (tramp-call-local-coding-command
3250 loc-enc tmpfil t))
3251 (pop-to-buffer trampbuf)
3252 (error (concat "Cannot write to `%s', local encoding"
3253 " command `%s' failed")
3254 filename loc-enc)))
3255 ;; Send tmpbuf into remote decoding command which
3256 ;; writes to remote file. Because this happens on the
3257 ;; remote host, we cannot use the function.
3258 (tramp-message-for-buffer
3259 multi-method method user host
3260 5 "Decoding region into remote file %s..." filename)
3261 (tramp-send-command
3262 multi-method method user host
3263 (format "%s >%s <<'EOF'"
3264 rem-dec
3265 (tramp-shell-quote-argument localname)))
3266 (set-buffer tmpbuf)
3267 (tramp-message-for-buffer
3268 multi-method method user host
3269 6 "Sending data to remote host...")
3270 (tramp-send-string multi-method method user host
3271 (buffer-string))
3272 ;; wait for remote decoding to complete
3273 (tramp-message-for-buffer
3274 multi-method method user host
3275 6 "Sending end of data token...")
3276 (tramp-send-command
3277 multi-method method user host "EOF" nil t)
3278 (tramp-message-for-buffer
3279 multi-method method user host 6
3280 "Waiting for remote host to process data...")
3281 (set-buffer (tramp-get-buffer multi-method method user host))
3282 (tramp-wait-for-output)
3283 (tramp-barf-unless-okay
3284 multi-method method user host nil nil 'file-error
3285 (concat "Couldn't write region to `%s',"
3286 " decode using `%s' failed")
3287 filename rem-dec)
3288 (tramp-message 5 "Decoding region into remote file %s...done"
3289 filename)
3290 (kill-buffer tmpbuf))))
3292 (error
3293 (concat "Method `%s' should specify both encoding and "
3294 "decoding command or an rcp program")
3295 method)))
3296 (delete-file tmpfil)
3297 (unless (equal curbuf (current-buffer))
3298 (error "Buffer has changed from `%s' to `%s'"
3299 curbuf (current-buffer)))
3300 (when (eq visit t)
3301 (set-visited-file-modtime))
3302 ;; Make `last-coding-system-used' have the right value.
3303 (when (boundp 'last-coding-system-used)
3304 (setq last-coding-system-used coding-system-used))
3305 (when (or (eq visit t)
3306 (eq visit nil)
3307 (stringp visit))
3308 (message "Wrote %s" filename)))))
3310 ;; Call down to the real handler.
3311 ;; Because EFS does not play nicely with TRAMP (both systems match a
3312 ;; TRAMP file name) it is needed to disable efs as well as tramp for the
3313 ;; operation.
3315 ;; Other than that, this is the canon file-handler code that the doco
3316 ;; says should be used here. Which is nice.
3318 ;; Under XEmacs current, EFS also hooks in as
3319 ;; efs-sifn-handler-function to handle any filename with environment
3320 ;; variables. This has two implications:
3321 ;; 1) That EFS may not be completely dead (yet) for TRAMP filenames
3322 ;; 2) That TRAMP might want to do the same thing.
3323 ;; Details as they come in.
3325 ;; Daniel Pittman <daniel@danann.net>
3327 ;; (defun tramp-run-real-handler (operation args)
3328 ;; "Invoke normal file name handler for OPERATION.
3329 ;; This inhibits EFS and Ange-FTP, too, because they conflict with tramp.
3330 ;; First arg specifies the OPERATION, remaining ARGS are passed to the
3331 ;; OPERATION."
3332 ;; (let ((inhibit-file-name-handlers
3333 ;; (list 'tramp-file-name-handler
3334 ;; 'efs-file-handler-function
3335 ;; 'ange-ftp-hook-function
3336 ;; (and (eq inhibit-file-name-operation operation)
3337 ;; inhibit-file-name-handlers)))
3338 ;; (inhibit-file-name-operation operation))
3339 ;; (apply operation args)))
3341 (defun tramp-run-real-handler (operation args)
3342 "Invoke normal file name handler for OPERATION.
3343 First arg specifies the OPERATION, second arg is a list of arguments to
3344 pass to the OPERATION."
3345 (let* ((inhibit-file-name-handlers
3346 `(tramp-file-name-handler
3347 tramp-completion-file-name-handler
3348 cygwin-mount-name-hook-function
3349 cygwin-mount-map-drive-hook-function
3351 ,(and (eq inhibit-file-name-operation operation)
3352 inhibit-file-name-handlers)))
3353 (inhibit-file-name-operation operation))
3354 (apply operation args)))
3356 ;; This function is used from `tramp-completion-file-name-handler' functions
3357 ;; only, if `tramp-completion-mode' is true. But this cannot be checked here
3358 ;; because the check is based on a full filename, not available for all
3359 ;; basic I/O operations.
3360 (defun tramp-completion-run-real-handler (operation args)
3361 "Invoke `tramp-file-name-handler' for OPERATION.
3362 First arg specifies the OPERATION, second arg is a list of arguments to
3363 pass to the OPERATION."
3364 (let* ((inhibit-file-name-handlers
3365 `(tramp-completion-file-name-handler
3366 cygwin-mount-name-hook-function
3367 cygwin-mount-map-drive-hook-function
3369 ,(and (eq inhibit-file-name-operation operation)
3370 inhibit-file-name-handlers)))
3371 (inhibit-file-name-operation operation))
3372 (apply operation args)))
3374 ;; We handle here all file primitives. Most of them have the file
3375 ;; name as first parameter; nevertheless we check for them explicitly
3376 ;; in order to be be signalled if a new primitive appears. This
3377 ;; scenario is needed because there isn't a way to decide by
3378 ;; syntactical means whether a foreign method must be called. It would
3379 ;; ease the live if `file-name-handler-alist' would support a decision
3380 ;; function as well but regexp only.
3381 (defun tramp-file-name-for-operation (operation &rest args)
3382 "Return file name related to OPERATION file primitive.
3383 ARGS are the arguments OPERATION has been called with."
3384 (cond
3385 ; FILE resp DIRECTORY
3386 ((member operation
3387 (list 'access-file 'byte-compiler-base-file-name 'delete-directory
3388 'delete-file 'diff-latest-backup-file 'directory-file-name
3389 'directory-files 'directory-files-and-attributes
3390 'dired-compress-file 'dired-uncache
3391 'file-accessible-directory-p 'file-attributes
3392 'file-directory-p 'file-executable-p 'file-exists-p
3393 'file-local-copy 'file-modes 'file-name-as-directory
3394 'file-name-directory 'file-name-nondirectory
3395 'file-name-sans-versions 'file-ownership-preserved-p
3396 'file-readable-p 'file-regular-p 'file-symlink-p
3397 'file-truename 'file-writable-p 'find-backup-file-name
3398 'find-file-noselect 'get-file-buffer 'insert-directory
3399 'insert-file-contents 'load 'make-directory
3400 'make-directory-internal 'set-file-modes
3401 'substitute-in-file-name 'unhandled-file-name-directory
3402 'vc-registered
3403 ; XEmacs only
3404 'abbreviate-file-name 'create-file-buffer
3405 'dired-file-modtime 'dired-make-compressed-filename
3406 'dired-recursive-delete-directory 'dired-set-file-modtime
3407 'dired-shell-unhandle-file-name 'dired-uucode-file
3408 'insert-file-contents-literally 'recover-file
3409 'vm-imap-check-mail 'vm-pop-check-mail 'vm-spool-check-mail))
3410 (if (file-name-absolute-p (nth 0 args))
3411 (nth 0 args)
3412 (expand-file-name (nth 0 args))))
3413 ; FILE DIRECTORY resp FILE1 FILE2
3414 ((member operation
3415 (list 'add-name-to-file 'copy-file 'expand-file-name
3416 'file-name-all-completions 'file-name-completion
3417 'file-newer-than-file-p 'make-symbolic-link 'rename-file
3418 ; XEmacs only
3419 'dired-make-relative-symlink
3420 'vm-imap-move-mail 'vm-pop-move-mail 'vm-spool-move-mail))
3421 (save-match-data
3422 (cond
3423 ((string-match tramp-file-name-regexp (nth 0 args)) (nth 0 args))
3424 ((string-match tramp-file-name-regexp (nth 1 args)) (nth 1 args))
3425 (t (buffer-file-name (current-buffer))))))
3426 ; START END FILE
3427 ((eq operation 'write-region)
3428 (nth 2 args))
3429 ; BUF
3430 ((member operation
3431 (list 'set-visited-file-modtime 'verify-visited-file-modtime
3432 ; XEmacs only
3433 'backup-buffer))
3434 (buffer-file-name
3435 (if (bufferp (nth 0 args)) (nth 0 args) (current-buffer))))
3436 ; COMMAND
3437 ((member operation
3438 (list 'dired-call-process 'shell-command
3439 ; XEmacs only
3440 'dired-print-file 'dired-shell-call-process))
3441 default-directory)
3442 ; unknown file primitive
3443 (t (error "unknown file I/O primitive: %s" operation))))
3445 (defun tramp-find-foreign-file-name-handler (filename)
3446 "Return foreign file name handler if exists."
3447 (when (tramp-tramp-file-p filename)
3448 (let (elt
3450 (handler-alist tramp-foreign-file-name-handler-alist))
3451 (while handler-alist
3452 (setq elt (car handler-alist)
3453 handler-alist (cdr handler-alist))
3454 (when (funcall (car elt) filename)
3455 (setq handler-alist nil)
3456 (setq res (cdr elt))))
3457 res)))
3459 ;; Main function.
3460 ;;;###autoload
3461 (defun tramp-file-name-handler (operation &rest args)
3462 "Invoke Tramp file name handler.
3463 Falls back to normal file name handler if no tramp file name handler exists."
3464 (save-match-data
3465 (let* ((filename (apply 'tramp-file-name-for-operation operation args))
3466 (foreign (tramp-find-foreign-file-name-handler filename)))
3467 (cond
3468 (foreign (apply foreign operation args))
3469 (t (tramp-run-real-handler operation args))))))
3471 ;;;###autoload
3472 (put 'tramp-file-name-handler 'file-remote-p t) ;for file-remote-p
3474 (defun tramp-sh-file-name-handler (operation &rest args)
3475 "Invoke remote-shell Tramp file name handler.
3476 Fall back to normal file name handler if no Tramp handler exists."
3477 (save-match-data
3478 (let ((fn (assoc operation tramp-file-name-handler-alist)))
3479 (if fn
3480 (apply (cdr fn) args)
3481 (tramp-run-real-handler operation args)))))
3483 ;;;###autoload
3484 (defun tramp-completion-file-name-handler (operation &rest args)
3485 "Invoke tramp file name completion handler.
3486 Falls back to normal file name handler if no tramp file name handler exists."
3487 ;; (setq tramp-debug-buffer t)
3488 ;; (tramp-message 1 "%s %s" operation args)
3489 ;; (tramp-message 1 "%s %s\n%s"
3490 ;; operation args (with-output-to-string (backtrace)))
3491 (let ((fn (assoc operation tramp-completion-file-name-handler-alist)))
3492 (if fn
3493 (save-match-data (apply (cdr fn) args))
3494 (tramp-completion-run-real-handler operation args))))
3496 ;;;###autoload
3497 (put 'tramp-completion-file-name-handler 'safe-magic t)
3499 ;; Register in file name handler alist
3500 ;;;###autoload
3501 (add-to-list 'file-name-handler-alist
3502 (cons tramp-file-name-regexp 'tramp-file-name-handler))
3503 (add-to-list 'file-name-handler-alist
3504 (cons tramp-completion-file-name-regexp
3505 'tramp-completion-file-name-handler))
3507 (defun tramp-repair-jka-compr ()
3508 "If jka-compr is already loaded, move it to the front of
3509 `file-name-handler-alist'. On Emacs 21.4 or so this will not be
3510 necessary anymore."
3511 (let ((jka (rassoc 'jka-compr-handler file-name-handler-alist)))
3512 (when jka
3513 (setq file-name-handler-alist
3514 (cons jka (delete jka file-name-handler-alist))))))
3515 (tramp-repair-jka-compr)
3518 ;;; Interactions with other packages:
3520 ;; -- complete.el --
3522 ;; This function contributed by Ed Sabol
3523 (defun tramp-handle-expand-many-files (name)
3524 "Like `PC-expand-many-files' for tramp files."
3525 (with-parsed-tramp-file-name name nil
3526 (save-match-data
3527 (if (or (string-match "\\*" name)
3528 (string-match "\\?" name)
3529 (string-match "\\[.*\\]" name))
3530 (save-excursion
3531 (let (bufstr)
3532 ;; CCC: To do it right, we should quote certain characters
3533 ;; in the file name, but since the echo command is going to
3534 ;; break anyway when there are spaces in the file names, we
3535 ;; don't bother.
3536 ;;-(let ((comint-file-name-quote-list
3537 ;;- (set-difference tramp-file-name-quote-list
3538 ;;- '(?\* ?\? ?[ ?]))))
3539 ;;- (tramp-send-command
3540 ;;- multi-method method user host
3541 ;;- (format "echo %s" (comint-quote-filename localname)))
3542 ;;- (tramp-wait-for-output))
3543 (tramp-send-command multi-method method user host
3544 (format "echo %s" localname))
3545 (tramp-wait-for-output)
3546 (setq bufstr (buffer-substring (point-min)
3547 (tramp-line-end-position)))
3548 (goto-char (point-min))
3549 (if (string-equal localname bufstr)
3551 (insert "(\"")
3552 (while (search-forward " " nil t)
3553 (delete-backward-char 1)
3554 (insert "\" \""))
3555 (goto-char (point-max))
3556 (delete-backward-char 1)
3557 (insert "\")")
3558 (goto-char (point-min))
3559 (mapcar
3560 (function (lambda (x)
3561 (tramp-make-tramp-file-name multi-method method
3562 user host x)))
3563 (read (current-buffer))))))
3564 (list (tramp-handle-expand-file-name name))))))
3566 ;; Check for complete.el and override PC-expand-many-files if appropriate.
3567 (eval-when-compile
3568 (defun tramp-save-PC-expand-many-files (name))); avoid compiler warning
3570 (defun tramp-setup-complete ()
3571 (fset 'tramp-save-PC-expand-many-files
3572 (symbol-function 'PC-expand-many-files))
3573 (defun PC-expand-many-files (name)
3574 (if (tramp-tramp-file-p name)
3575 (tramp-handle-expand-many-files name)
3576 (tramp-save-PC-expand-many-files name))))
3578 ;; Why isn't eval-after-load sufficient?
3579 (if (fboundp 'PC-expand-many-files)
3580 (tramp-setup-complete)
3581 (eval-after-load "complete" '(tramp-setup-complete)))
3583 ;;; File name handler functions for completion mode
3585 ;; Necessary because `tramp-file-name-regexp-unified' and
3586 ;; `tramp-completion-file-name-regexp-unified' aren't different.
3587 ;; If nil, `tramp-completion-run-real-handler' is called (i.e. forwarding to
3588 ;; `tramp-file-name-handler'). Otherwise, it takes `tramp-run-real-handler'.
3589 ;; Using `last-input-event' is a little bit risky, because completing a file
3590 ;; might require loading other files, like "~/.netrc", and for them it
3591 ;; shouldn't be decided based on that variable. On the other hand, those files
3592 ;; shouldn't have partial tramp file name syntax. Maybe another variable should
3593 ;; be introduced overwriting this check in such cases. Or we change tramp
3594 ;; file name syntax in order to avoid ambiguities, like in XEmacs ...
3595 ;; In case of XEmacs it can be always true (and wouldn't be necessary).
3596 (defun tramp-completion-mode (file)
3597 "Checks whether method / user name / host name completion is active."
3598 (cond
3599 ((featurep 'xemacs) t)
3600 ((string-match "^/.*:.*:$" file) nil)
3601 ((string-match
3602 (concat tramp-prefix-regexp
3603 "\\(" tramp-method-regexp "\\)" tramp-postfix-single-method-regexp "$")
3604 file)
3605 (member (match-string 1 file) (mapcar 'car tramp-methods)))
3606 ((or (equal last-input-event 'tab)
3607 (and (integerp last-input-event)
3608 (not (event-modifiers last-input-event))
3609 (or (char-equal last-input-event ?\?)
3610 (char-equal last-input-event ?\t) ; handled by 'tab already?
3611 (char-equal last-input-event ?\ ))))
3612 t)))
3614 (defun tramp-completion-handle-file-exists-p (filename)
3615 "Like `file-exists-p' for tramp files."
3616 (if (tramp-completion-mode filename)
3617 (tramp-run-real-handler
3618 'file-exists-p (list filename))
3619 (tramp-completion-run-real-handler
3620 'file-exists-p (list filename))))
3622 ;; Localname manipulation in case of partial TRAMP file names.
3623 (defun tramp-completion-handle-file-name-directory (file)
3624 "Like `file-name-directory' but aware of TRAMP files."
3625 (if (tramp-completion-mode file)
3627 (tramp-completion-run-real-handler
3628 'file-name-directory (list file))))
3630 ;; Localname manipulation in case of partial TRAMP file names.
3631 (defun tramp-completion-handle-file-name-nondirectory (file)
3632 "Like `file-name-nondirectory' but aware of TRAMP files."
3633 (substring
3634 file (length (tramp-completion-handle-file-name-directory file))))
3636 ;; Method, host name and user name completion.
3637 ;; `tramp-completion-dissect-file-name' returns a list of
3638 ;; tramp-file-name structures. For all of them we return possible completions.
3639 (defun tramp-completion-handle-file-name-all-completions (filename directory)
3640 "Like `file-name-all-completions' for partial tramp files."
3642 (let*
3643 ((fullname (concat directory filename))
3644 ;; local files
3645 (result
3646 (if (tramp-completion-mode fullname)
3647 (tramp-run-real-handler
3648 'file-name-all-completions (list filename directory))
3649 (tramp-completion-run-real-handler
3650 'file-name-all-completions (list filename directory))))
3651 ;; possible completion structures
3652 (v (tramp-completion-dissect-file-name fullname)))
3654 (while v
3655 (let* ((car (car v))
3656 (multi-method (tramp-file-name-multi-method car))
3657 (method (tramp-file-name-method car))
3658 (user (tramp-file-name-user car))
3659 (host (tramp-file-name-host car))
3660 (localname (tramp-file-name-localname car))
3661 (m (tramp-find-method multi-method method user host))
3662 (tramp-current-user user) ; see `tramp-parse-passwd'
3663 all-user-hosts)
3665 (unless (or multi-method ;; Not handled (yet).
3666 localname) ;; Nothing to complete
3668 (if (or user host)
3670 ;; Method dependent user / host combinations
3671 (progn
3672 (mapcar
3673 (lambda (x)
3674 (setq all-user-hosts
3675 (append all-user-hosts
3676 (funcall (nth 0 x) (nth 1 x)))))
3677 (tramp-get-completion-function m))
3679 (setq result (append result
3680 (mapcar
3681 (lambda (x)
3682 (tramp-get-completion-user-host
3683 method user host (nth 0 x) (nth 1 x)))
3684 (delq nil all-user-hosts)))))
3686 ;; Possible methods
3687 (setq result
3688 (append result (tramp-get-completion-methods m)))))
3690 (setq v (delq car v))))
3692 ;;; unify list, remove nil elements
3693 (let (result1)
3694 (while result
3695 (let ((car (car result)))
3696 (when car (add-to-list 'result1 car))
3697 (setq result (delq car result))))
3699 result1)))
3701 ;; Method, host name and user name completion for a file.
3702 (defun tramp-completion-handle-file-name-completion (filename directory)
3703 "Like `file-name-completion' for tramp files."
3704 (try-completion filename
3705 (mapcar 'list (file-name-all-completions filename directory))))
3707 ;; I misuse a little bit the tramp-file-name structure in order to handle
3708 ;; completion possibilities for partial methods / user names / host names.
3709 ;; Return value is a list of tramp-file-name structures according to possible
3710 ;; completions. If "multi-method" or "localname" is non-nil it means there
3711 ;; shouldn't be a completion anymore.
3713 ;; Expected results:
3715 ;; "/x" "/[x" "/x@" "/[x@" "/x@y" "/[x@y"
3716 ;; [nil nil nil "x" nil] [nil nil "x" nil nil] [nil nil "x" "y" nil]
3717 ;; [nil nil "x" nil nil]
3718 ;; [nil "x" nil nil nil]
3720 ;; "/x:" "/x:y" "/x:y:"
3721 ;; [nil nil nil "x" ""] [nil nil nil "x" "y"] [nil "x" nil "y" ""]
3722 ;; "/[x/" "/[x/y"
3723 ;; [nil "x" nil "" nil] [nil "x" nil "y" nil]
3724 ;; [nil "x" "" nil nil] [nil "x" "y" nil nil]
3726 ;; "/x:y@" "/x:y@z" "/x:y@z:"
3727 ;; [nil nil nil "x" "y@"] [nil nil nil "x" "y@z"] [nil "x" "y" "z" ""]
3728 ;; "/[x/y@" "/[x/y@z"
3729 ;; [nil "x" nil "y" nil] [nil "x" "y" "z" nil]
3730 (defun tramp-completion-dissect-file-name (name)
3731 "Returns a list of `tramp-file-name' structures.
3732 They are collected by `tramp-completion-dissect-file-name1'."
3734 (let* ((result)
3735 (x-nil "\\|\\(\\)")
3736 ;; "/method" "/[method"
3737 (tramp-completion-file-name-structure1
3738 (list (concat tramp-prefix-regexp "\\(" tramp-method-regexp x-nil "\\)$")
3739 1 nil nil nil))
3740 ;; "/user" "/[user"
3741 (tramp-completion-file-name-structure2
3742 (list (concat tramp-prefix-regexp "\\(" tramp-user-regexp x-nil "\\)$")
3743 nil 1 nil nil))
3744 ;; "/host" "/[host"
3745 (tramp-completion-file-name-structure3
3746 (list (concat tramp-prefix-regexp "\\(" tramp-host-regexp x-nil "\\)$")
3747 nil nil 1 nil))
3748 ;; "/user@host" "/[user@host"
3749 (tramp-completion-file-name-structure4
3750 (list (concat tramp-prefix-regexp
3751 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
3752 "\\(" tramp-host-regexp x-nil "\\)$")
3753 nil 1 2 nil))
3754 ;; "/method:user" "/[method/user"
3755 (tramp-completion-file-name-structure5
3756 (list (concat tramp-prefix-regexp
3757 "\\(" tramp-method-regexp "\\)" tramp-postfix-single-method-regexp
3758 "\\(" tramp-user-regexp x-nil "\\)$")
3759 1 2 nil nil))
3760 ;; "/method:host" "/[method/host"
3761 (tramp-completion-file-name-structure6
3762 (list (concat tramp-prefix-regexp
3763 "\\(" tramp-method-regexp "\\)" tramp-postfix-single-method-regexp
3764 "\\(" tramp-host-regexp x-nil "\\)$")
3765 1 nil 2 nil))
3766 ;; "/method:user@host" "/[method/user@host"
3767 (tramp-completion-file-name-structure7
3768 (list (concat tramp-prefix-regexp
3769 "\\(" tramp-method-regexp "\\)" tramp-postfix-single-method-regexp
3770 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
3771 "\\(" tramp-host-regexp x-nil "\\)$")
3772 1 2 3 nil)))
3774 (mapcar (lambda (regexp)
3775 (add-to-list 'result
3776 (tramp-completion-dissect-file-name1 regexp name)))
3777 (list
3778 tramp-completion-file-name-structure1
3779 tramp-completion-file-name-structure2
3780 tramp-completion-file-name-structure3
3781 tramp-completion-file-name-structure4
3782 tramp-completion-file-name-structure5
3783 tramp-completion-file-name-structure6
3784 tramp-completion-file-name-structure7
3785 tramp-file-name-structure))
3787 (delq nil result)))
3789 (defun tramp-completion-dissect-file-name1 (structure name)
3790 "Returns a `tramp-file-name' structure matching STRUCTURE.
3791 The structure consists of multi-method, remote method, remote user,
3792 remote host and localname (filename on remote host)."
3794 (let (method)
3795 (save-match-data
3796 (when (string-match (nth 0 structure) name)
3797 (setq method (and (nth 1 structure)
3798 (match-string (nth 1 structure) name)))
3799 (if (and method (member method tramp-multi-methods))
3800 ;; Not handled (yet).
3801 (make-tramp-file-name
3802 :multi-method method
3803 :method nil
3804 :user nil
3805 :host nil
3806 :localname nil)
3807 (let ((user (and (nth 2 structure)
3808 (match-string (nth 2 structure) name)))
3809 (host (and (nth 3 structure)
3810 (match-string (nth 3 structure) name)))
3811 (localname (and (nth 4 structure)
3812 (match-string (nth 4 structure) name))))
3813 (make-tramp-file-name
3814 :multi-method nil
3815 :method method
3816 :user user
3817 :host host
3818 :localname localname)))))))
3820 ;; This function returns all possible method completions, adding the
3821 ;; trailing method delimeter.
3822 (defun tramp-get-completion-methods (partial-method)
3823 "Returns all method completions for PARTIAL-METHOD."
3824 (mapcar
3825 (lambda (method)
3826 (and method
3827 (string-match (concat "^" (regexp-quote partial-method)) method)
3828 ;; we must remove leading "/".
3829 (substring (tramp-make-tramp-file-name nil method nil nil nil) 1)))
3830 (delete "multi" (mapcar 'car tramp-methods))))
3832 ;; Compares partial user and host names with possible completions.
3833 (defun tramp-get-completion-user-host (method partial-user partial-host user host)
3834 "Returns the most expanded string for user and host name completion.
3835 PARTIAL-USER must match USER, PARTIAL-HOST must match HOST."
3836 (cond
3838 ((and partial-user partial-host)
3839 (if (and host
3840 (string-match (concat "^" (regexp-quote partial-host)) host)
3841 (string-equal partial-user (or user partial-user)))
3842 (setq user partial-user)
3843 (setq user nil
3844 host nil)))
3846 (partial-user
3847 (setq host nil)
3848 (unless
3849 (and user (string-match (concat "^" (regexp-quote partial-user)) user))
3850 (setq user nil)))
3852 (partial-host
3853 (setq user nil)
3854 (unless
3855 (and host (string-match (concat "^" (regexp-quote partial-host)) host))
3856 (setq host nil)))
3858 (t (setq user nil
3859 host nil)))
3861 (unless (zerop (+ (length user) (length host)))
3862 ;; we must remove leading "/".
3863 (substring (tramp-make-tramp-file-name nil method user host nil) 1)))
3865 (defun tramp-parse-rhosts (filename)
3866 "Return a list of (user host) tuples allowed to access.
3867 Either user or host may be nil."
3869 (let (res)
3870 (when (file-readable-p filename)
3871 (with-temp-buffer
3872 (insert-file-contents filename)
3873 (goto-char (point-min))
3874 (while (not (eobp))
3875 (push (tramp-parse-rhosts-group) res))))
3876 res))
3878 ;; Taken from gnus/netrc.el
3879 (eval-and-compile
3880 (defalias 'tramp-point-at-eol
3881 (if (fboundp 'point-at-eol)
3882 'point-at-eol
3883 'line-end-position)))
3885 (defun tramp-parse-rhosts-group ()
3886 "Return a (user host) tuple allowed to access.
3887 Either user or host may be nil."
3889 (let ((result)
3890 (regexp
3891 (concat
3892 "^\\(" tramp-host-regexp "\\)"
3893 "\\([ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
3895 (narrow-to-region (point) (tramp-point-at-eol))
3896 (when (re-search-forward regexp nil t)
3897 (setq result (append (list (match-string 3) (match-string 1)))))
3898 (widen)
3899 (forward-line 1)
3900 result))
3902 (defun tramp-parse-shosts (filename)
3903 "Return a list of (user host) tuples allowed to access.
3904 User is always nil."
3906 (let (res)
3907 (when (file-readable-p filename)
3908 (with-temp-buffer
3909 (insert-file-contents filename)
3910 (goto-char (point-min))
3911 (while (not (eobp))
3912 (push (tramp-parse-shosts-group) res))))
3913 res))
3915 (defun tramp-parse-shosts-group ()
3916 "Return a (user host) tuple allowed to access.
3917 User is always nil."
3919 (let ((result)
3920 (regexp (concat "^\\(" tramp-host-regexp "\\)")))
3922 (narrow-to-region (point) (tramp-point-at-eol))
3923 (when (re-search-forward regexp nil t)
3924 (setq result (list nil (match-string 1))))
3925 (widen)
3927 (> (skip-chars-forward ",") 0)
3928 (forward-line 1))
3929 result))
3931 (defun tramp-parse-sconfig (filename)
3932 "Return a list of (user host) tuples allowed to access.
3933 User is always nil."
3935 (let (res)
3936 (when (file-readable-p filename)
3937 (with-temp-buffer
3938 (insert-file-contents filename)
3939 (goto-char (point-min))
3940 (while (not (eobp))
3941 (push (tramp-parse-sconfig-group) res))))
3942 res))
3944 (defun tramp-parse-sconfig-group ()
3945 "Return a (user host) tuple allowed to access.
3946 User is always nil."
3948 (let ((result)
3949 (regexp (concat "^[ \t]*Host[ \t]+" "\\(" tramp-host-regexp "\\)")))
3951 (narrow-to-region (point) (tramp-point-at-eol))
3952 (when (re-search-forward regexp nil t)
3953 (setq result (list nil (match-string 1))))
3954 (widen)
3956 (> (skip-chars-forward ",") 0)
3957 (forward-line 1))
3958 result))
3960 (defun tramp-parse-hosts (filename)
3961 "Return a list of (user host) tuples allowed to access.
3962 User is always nil."
3964 (let (res)
3965 (when (file-readable-p filename)
3966 (with-temp-buffer
3967 (insert-file-contents filename)
3968 (goto-char (point-min))
3969 (while (not (eobp))
3970 (push (tramp-parse-hosts-group) res))))
3971 res))
3973 (defun tramp-parse-hosts-group ()
3974 "Return a (user host) tuple allowed to access.
3975 User is always nil."
3977 (let ((result)
3978 (regexp (concat "^\\(" tramp-host-regexp "\\)")))
3980 (narrow-to-region (point) (tramp-point-at-eol))
3981 (when (re-search-forward regexp nil t)
3982 (unless (char-equal (or (char-after) ?\n) ?:) ; no IPv6
3983 (setq result (list nil (match-string 1)))))
3984 (widen)
3986 (> (skip-chars-forward " \t") 0)
3987 (forward-line 1))
3988 result))
3990 ;; For su-alike methods it would be desirable to return "root@localhost"
3991 ;; as default. Unfortunately, we have no information whether any user name
3992 ;; has been typed already. So we (mis-)use tramp-current-user as indication,
3993 ;; assuming it is set in `tramp-completion-handle-file-name-all-completions'.
3994 (defun tramp-parse-passwd (filename)
3995 "Return a list of (user host) tuples allowed to access.
3996 Host is always \"localhost\"."
3998 (let (res)
3999 (if (zerop (length tramp-current-user))
4000 '(("root" nil))
4001 (when (file-readable-p filename)
4002 (with-temp-buffer
4003 (insert-file-contents filename)
4004 (goto-char (point-min))
4005 (while (not (eobp))
4006 (push (tramp-parse-passwd-group) res))))
4007 res)))
4009 (defun tramp-parse-passwd-group ()
4010 "Return a (user host) tuple allowed to access.
4011 Host is always \"localhost\"."
4013 (let ((result)
4014 (regexp (concat "^\\(" tramp-user-regexp "\\):")))
4016 (narrow-to-region (point) (tramp-point-at-eol))
4017 (when (re-search-forward regexp nil t)
4018 (setq result (list (match-string 1) "localhost")))
4019 (widen)
4020 (forward-line 1)
4021 result))
4023 (defun tramp-parse-netrc (filename)
4024 "Return a list of (user host) tuples allowed to access.
4025 User may be nil."
4027 (let (res)
4028 (when (file-readable-p filename)
4029 (with-temp-buffer
4030 (insert-file-contents filename)
4031 (goto-char (point-min))
4032 (while (not (eobp))
4033 (push (tramp-parse-netrc-group) res))))
4034 res))
4036 (defun tramp-parse-netrc-group ()
4037 "Return a (user host) tuple allowed to access.
4038 User may be nil."
4040 (let ((result)
4041 (regexp
4042 (concat
4043 "^[ \t]*machine[ \t]+" "\\(" tramp-host-regexp "\\)"
4044 "\\([ \t]+login[ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
4046 (narrow-to-region (point) (tramp-point-at-eol))
4047 (when (re-search-forward regexp nil t)
4048 (setq result (list (match-string 3) (match-string 1))))
4049 (widen)
4050 (forward-line 1)
4051 result))
4053 (defun tramp-completion-handle-expand-file-name (name &optional dir)
4054 "Like `expand-file-name' for tramp files."
4055 (let ((fullname (concat (or dir default-directory) name)))
4056 (tramp-drop-volume-letter
4057 (if (tramp-completion-mode fullname)
4058 (tramp-run-real-handler
4059 'expand-file-name (list name dir))
4060 (tramp-completion-run-real-handler
4061 'expand-file-name (list name dir))))))
4063 ;;; Internal Functions:
4065 (defun tramp-set-auto-save ()
4066 (when (and (buffer-file-name)
4067 (tramp-tramp-file-p (buffer-file-name))
4068 auto-save-default)
4069 (auto-save-mode 1)))
4070 (add-hook 'find-file-hooks 'tramp-set-auto-save t)
4072 (defun tramp-run-test (switch filename)
4073 "Run `test' on the remote system, given a SWITCH and a FILENAME.
4074 Returns the exit code of the `test' program."
4075 (let ((v (tramp-dissect-file-name filename)))
4076 (save-excursion
4077 (tramp-send-command-and-check
4078 (tramp-file-name-multi-method v) (tramp-file-name-method v)
4079 (tramp-file-name-user v) (tramp-file-name-host v)
4080 (format "test %s %s" switch
4081 (tramp-shell-quote-argument (tramp-file-name-localname v)))))))
4083 (defun tramp-run-test2 (program file1 file2 &optional switch)
4084 "Run `test'-like PROGRAM on the remote system, given FILE1, FILE2.
4085 The optional SWITCH is inserted between the two files.
4086 Returns the exit code of the `test' PROGRAM. Barfs if the methods,
4087 hosts, or files, disagree."
4088 (let* ((v1 (tramp-dissect-file-name file1))
4089 (v2 (tramp-dissect-file-name file2))
4090 (mmethod1 (tramp-file-name-multi-method v1))
4091 (mmethod2 (tramp-file-name-multi-method v2))
4092 (method1 (tramp-file-name-method v1))
4093 (method2 (tramp-file-name-method v2))
4094 (user1 (tramp-file-name-user v1))
4095 (user2 (tramp-file-name-user v2))
4096 (host1 (tramp-file-name-host v1))
4097 (host2 (tramp-file-name-host v2))
4098 (localname1 (tramp-file-name-localname v1))
4099 (localname2 (tramp-file-name-localname v2)))
4100 (unless (and method1 method2 host1 host2
4101 (equal mmethod1 mmethod2)
4102 (equal method1 method2)
4103 (equal user1 user2)
4104 (equal host1 host2))
4105 (error "tramp-run-test2: %s"
4106 "only implemented for same method, same user, same host"))
4107 (save-excursion
4108 (tramp-send-command-and-check
4109 mmethod1 method1 user1 host1
4110 (format "%s %s %s %s"
4111 program
4112 (tramp-shell-quote-argument localname1)
4113 (or switch "")
4114 (tramp-shell-quote-argument localname2))))))
4116 (defun tramp-buffer-name (multi-method method user host)
4117 "A name for the connection buffer for USER at HOST using METHOD."
4118 (cond (multi-method
4119 (tramp-buffer-name-multi-method "tramp" multi-method method user host))
4120 (user
4121 (format "*tramp/%s %s@%s*" method user host))
4123 (format "*tramp/%s %s*" method host))))
4125 (defun tramp-buffer-name-multi-method (prefix multi-method method user host)
4126 "A name for the multi method connection buffer.
4127 MULTI-METHOD gives the multi method, METHOD the array of methods,
4128 USER the array of user names, HOST the array of host names."
4129 (unless (and (= (length method) (length user))
4130 (= (length method) (length host)))
4131 (error "Syntax error in multi method (implementation error)"))
4132 (let ((len (length method))
4133 (i 0)
4134 string-list)
4135 (while (< i len)
4136 (setq string-list
4137 (cons (if (aref user i)
4138 (format "%s#%s@%s:" (aref method i)
4139 (aref user i) (aref host i))
4140 (format "%s@%s:" (aref method i) (aref host i)))
4141 string-list))
4142 (incf i))
4143 (format "*%s/%s %s*"
4144 prefix multi-method
4145 (apply 'concat (reverse string-list)))))
4147 (defun tramp-get-buffer (multi-method method user host)
4148 "Get the connection buffer to be used for USER at HOST using METHOD."
4149 (get-buffer-create (tramp-buffer-name multi-method method user host)))
4151 (defun tramp-debug-buffer-name (multi-method method user host)
4152 "A name for the debug buffer for USER at HOST using METHOD."
4153 (cond (multi-method
4154 (tramp-buffer-name-multi-method "debug tramp"
4155 multi-method method user host))
4156 (user
4157 (format "*debug tramp/%s %s@%s*" method user host))
4159 (format "*debug tramp/%s %s*" method host))))
4161 (defun tramp-get-debug-buffer (multi-method method user host)
4162 "Get the debug buffer for USER at HOST using METHOD."
4163 (get-buffer-create (tramp-debug-buffer-name multi-method method user host)))
4165 (defun tramp-find-executable (multi-method method user host
4166 progname dirlist ignore-tilde)
4167 "Searches for PROGNAME in all directories mentioned in DIRLIST.
4168 First args METHOD, USER and HOST specify the connection, PROGNAME
4169 is the program to search for, and DIRLIST gives the list of directories
4170 to search. If IGNORE-TILDE is non-nil, directory names starting
4171 with `~' will be ignored.
4173 Returns the absolute file name of PROGNAME, if found, and nil otherwise.
4175 This function expects to be in the right *tramp* buffer."
4176 (let (result)
4177 (when ignore-tilde
4178 ;; Remove all ~/foo directories from dirlist. In Emacs 20,
4179 ;; `remove' is in CL, and we want to avoid CL dependencies.
4180 (let (newdl d)
4181 (while dirlist
4182 (setq d (car dirlist))
4183 (setq dirlist (cdr dirlist))
4184 (unless (char-equal ?~ (aref d 0))
4185 (setq newdl (cons d newdl))))
4186 (setq dirlist (nreverse newdl))))
4187 (tramp-send-command
4188 multi-method method user host
4189 (format (concat "while read d; "
4190 "do if test -x $d/%s -a -f $d/%s; "
4191 "then echo tramp_executable $d/%s; "
4192 "break; fi; done <<'EOF'")
4193 progname progname progname))
4194 (mapcar (lambda (d)
4195 (tramp-send-command multi-method method user host d))
4196 dirlist)
4197 (tramp-send-command multi-method method user host "EOF")
4198 (tramp-wait-for-output)
4199 (goto-char (point-max))
4200 (when (search-backward "tramp_executable " nil t)
4201 (skip-chars-forward "^ ")
4202 (skip-chars-forward " ")
4203 (buffer-substring (point) (tramp-line-end-position)))))
4205 (defun tramp-set-remote-path (multi-method method user host var dirlist)
4206 "Sets the remote environment VAR to existing directories from DIRLIST.
4207 I.e., for each directory in DIRLIST, it is tested whether it exists and if
4208 so, it is added to the environment variable VAR."
4209 (let ((existing-dirs
4210 (mapcar
4211 (lambda (x)
4212 (when (and
4213 (file-exists-p
4214 (tramp-make-tramp-file-name multi-method method user host x))
4215 (file-directory-p
4216 (tramp-make-tramp-file-name multi-method method user host x)))
4218 dirlist)))
4219 (tramp-send-command
4220 multi-method method user host
4221 (concat var "="
4222 (mapconcat 'identity (delq nil existing-dirs) ":")
4223 "; export " var))
4224 (tramp-wait-for-output)))
4226 ;; -- communication with external shell --
4228 (defun tramp-find-file-exists-command (multi-method method user host)
4229 "Find a command on the remote host for checking if a file exists.
4230 Here, we are looking for a command which has zero exit status if the
4231 file exists and nonzero exit status otherwise."
4232 (make-local-variable 'tramp-file-exists-command)
4233 (tramp-message 9 "Finding command to check if file exists")
4234 (let ((existing
4235 (tramp-make-tramp-file-name
4236 multi-method method user host
4237 "/")) ;assume this file always exists
4238 (nonexisting
4239 (tramp-make-tramp-file-name
4240 multi-method method user host
4241 "/ this file does not exist "))) ;assume this never exists
4242 ;; The algorithm is as follows: we try a list of several commands.
4243 ;; For each command, we first run `$cmd /' -- this should return
4244 ;; true, as the root directory always exists. And then we run
4245 ;; `$cmd /this\ file\ does\ not\ exist', hoping that the file indeed
4246 ;; does not exist. This should return false. We use the first
4247 ;; command we find that seems to work.
4248 ;; The list of commands to try is as follows:
4249 ;; `ls -d' This works on most systems, but NetBSD 1.4
4250 ;; has a bug: `ls' always returns zero exit
4251 ;; status, even for files which don't exist.
4252 ;; `test -e' Some Bourne shells have a `test' builtin
4253 ;; which does not know the `-e' option.
4254 ;; `/bin/test -e' For those, the `test' binary on disk normally
4255 ;; provides the option. Alas, the binary
4256 ;; is sometimes `/bin/test' and sometimes it's
4257 ;; `/usr/bin/test'.
4258 ;; `/usr/bin/test -e' In case `/bin/test' does not exist.
4259 (unless (or
4260 (and (setq tramp-file-exists-command "test -e %s")
4261 (tramp-handle-file-exists-p existing)
4262 (not (tramp-handle-file-exists-p nonexisting)))
4263 (and (setq tramp-file-exists-command "/bin/test -e %s")
4264 (tramp-handle-file-exists-p existing)
4265 (not (tramp-handle-file-exists-p nonexisting)))
4266 (and (setq tramp-file-exists-command "/usr/bin/test -e %s")
4267 (tramp-handle-file-exists-p existing)
4268 (not (tramp-handle-file-exists-p nonexisting)))
4269 (and (setq tramp-file-exists-command "ls -d %s")
4270 (tramp-handle-file-exists-p existing)
4271 (not (tramp-handle-file-exists-p nonexisting))))
4272 (error "Couldn't find command to check if file exists."))))
4275 ;; CCC test ksh or bash found for tilde expansion?
4276 (defun tramp-find-shell (multi-method method user host)
4277 "Find a shell on the remote host which groks tilde expansion."
4278 (let ((shell nil))
4279 (tramp-send-command multi-method method user host "echo ~root")
4280 (tramp-wait-for-output)
4281 (cond
4282 ((string-match "^~root$" (buffer-string))
4283 (setq shell
4284 (or (tramp-find-executable multi-method method user host
4285 "bash" tramp-remote-path t)
4286 (tramp-find-executable multi-method method user host
4287 "ksh" tramp-remote-path t)))
4288 (unless shell
4289 (error "Couldn't find a shell which groks tilde expansion"))
4290 ;; Find arguments for this shell.
4291 (let ((alist tramp-sh-extra-args)
4292 item extra-args)
4293 (while (and alist (null extra-args))
4294 (setq item (pop alist))
4295 (when (string-match (car item) shell)
4296 (setq extra-args (cdr item))))
4297 (when extra-args (setq shell (concat shell " " extra-args))))
4298 (tramp-message
4299 5 "Starting remote shell `%s' for tilde expansion..." shell)
4300 (tramp-send-command
4301 multi-method method user host
4302 (concat "PS1='$ ' exec " shell)) ;
4303 (unless (tramp-wait-for-regexp
4304 (get-buffer-process (current-buffer))
4305 60 (format "\\(\\(%s\\)\\|\\(%s\\)\\)\\'"
4306 tramp-shell-prompt-pattern shell-prompt-pattern))
4307 (pop-to-buffer (buffer-name))
4308 (error "Couldn't find remote `%s' prompt." shell))
4309 (tramp-message
4310 9 "Setting remote shell prompt...")
4311 ;; Douglas Gray Stephens <DGrayStephens@slb.com> says that we
4312 ;; must use "\n" here, not tramp-rsh-end-of-line. Kai left the
4313 ;; last tramp-rsh-end-of-line, Douglas wanted to replace that,
4314 ;; as well.
4315 (process-send-string nil (format "PS1='%s%s%s'; PS2=''; PS3=''%s"
4316 tramp-rsh-end-of-line
4317 tramp-end-of-output
4318 tramp-rsh-end-of-line
4319 tramp-rsh-end-of-line))
4320 (tramp-wait-for-output)
4321 (tramp-message
4322 9 "Setting remote shell prompt...done")
4324 (t (tramp-message 5 "Remote `%s' groks tilde expansion, good"
4325 (tramp-get-remote-sh multi-method method user host))))))
4327 (defun tramp-check-ls-command (multi-method method user host cmd)
4328 "Checks whether the given `ls' executable groks `-n'.
4329 METHOD, USER and HOST specify the connection, CMD (the absolute file name of)
4330 the `ls' executable. Returns t if CMD supports the `-n' option, nil
4331 otherwise."
4332 (tramp-message 9 "Checking remote `%s' command for `-n' option"
4333 cmd)
4334 (when (tramp-handle-file-executable-p
4335 (tramp-make-tramp-file-name multi-method method user host cmd))
4336 (let ((result nil))
4337 (tramp-message 7 "Testing remote command `%s' for -n..." cmd)
4338 (setq result
4339 (tramp-send-command-and-check
4340 multi-method method user host
4341 (format "%s -lnd / >/dev/null"
4342 cmd)))
4343 (tramp-message 7 "Testing remote command `%s' for -n...%s"
4345 (if (zerop result) "okay" "failed"))
4346 (zerop result))))
4348 (defun tramp-check-ls-commands (multi-method method user host cmd dirlist)
4349 "Checks whether the given `ls' executable in one of the dirs groks `-n'.
4350 Returns nil if none was found, else the command is returned."
4351 (let ((dl dirlist)
4352 (result nil)
4353 (directory-sep-char ?/)) ;for XEmacs
4354 ;; It would be better to use the CL function `find', but
4355 ;; we don't want run-time dependencies on CL.
4356 (while (and dl (not result))
4357 (let ((x (concat (file-name-as-directory (car dl)) cmd)))
4358 (when (tramp-check-ls-command multi-method method user host x)
4359 (setq result x)))
4360 (setq dl (cdr dl)))
4361 result))
4363 (defun tramp-find-ls-command (multi-method method user host)
4364 "Finds an `ls' command which groks the `-n' option, returning nil if failed.
4365 \(This option prints numeric user and group ids in a long listing.)"
4366 (tramp-message 9 "Finding a suitable `ls' command")
4368 (tramp-check-ls-commands multi-method method user host "ls" tramp-remote-path)
4369 (tramp-check-ls-commands multi-method method user host "gnuls" tramp-remote-path)
4370 (tramp-check-ls-commands multi-method method user host "gls" tramp-remote-path)))
4372 ;; ------------------------------------------------------------
4373 ;; -- Functions for establishing connection --
4374 ;; ------------------------------------------------------------
4376 ;; The following functions are actions to be taken when seeing certain
4377 ;; prompts from the remote host. See the variable
4378 ;; `tramp-actions-before-shell' for usage of these functions.
4380 (defun tramp-action-login (p multi-method method user host)
4381 "Send the login name."
4382 (tramp-message 9 "Sending login name `%s'"
4383 (or user (user-login-name)))
4384 (erase-buffer)
4385 (process-send-string nil (concat (or user (user-login-name))
4386 tramp-rsh-end-of-line)))
4388 (defun tramp-action-password (p multi-method method user host)
4389 "Query the user for a password."
4390 (let ((pw-prompt (match-string 0)))
4391 (when (tramp-method-out-of-band-p multi-method method user host)
4392 (kill-process (get-buffer-process (current-buffer)))
4393 (error (concat "Out of band method `%s' not applicable "
4394 "for remote shell asking for a password")
4395 method))
4396 (tramp-message 9 "Sending password")
4397 (tramp-enter-password p pw-prompt)))
4399 (defun tramp-action-succeed (p multi-method method user host)
4400 "Signal success in finding shell prompt."
4401 (tramp-message 9 "Found remote shell prompt.")
4402 (erase-buffer)
4403 (throw 'tramp-action 'ok))
4405 (defun tramp-action-permission-denied (p multi-method method user host)
4406 "Signal permission denied."
4407 (pop-to-buffer (tramp-get-buffer multi-method method user host))
4408 (tramp-message 9 "Permission denied by remote host.")
4409 (kill-process p)
4410 (throw 'tramp-action 'permission-denied))
4412 (defun tramp-action-yesno (p multi-method method user host)
4413 "Ask the user for confirmation using `yes-or-no-p'.
4414 Send \"yes\" to remote process on confirmation, abort otherwise.
4415 See also `tramp-action-yn'."
4416 (save-window-excursion
4417 (pop-to-buffer (tramp-get-buffer multi-method method user host))
4418 (unless (yes-or-no-p (match-string 0))
4419 (kill-process p)
4420 (erase-buffer)
4421 (throw 'tramp-action 'permission-denied))
4422 (process-send-string p (concat "yes" tramp-rsh-end-of-line))
4423 (erase-buffer)))
4425 (defun tramp-action-yn (p multi-method method user host)
4426 "Ask the user for confirmation using `y-or-n-p'.
4427 Send \"y\" to remote process on confirmation, abort otherwise.
4428 See also `tramp-action-yesno'."
4429 (save-window-excursion
4430 (pop-to-buffer (tramp-get-buffer multi-method method user host))
4431 (unless (y-or-n-p (match-string 0))
4432 (kill-process p)
4433 (throw 'tramp-action 'permission-denied))
4434 (erase-buffer)
4435 (process-send-string p (concat "y" tramp-rsh-end-of-line))))
4437 (defun tramp-action-terminal (p multi-method method user host)
4438 "Tell the remote host which terminal type to use.
4439 The terminal type can be configured with `tramp-terminal-type'."
4440 (tramp-message 9 "Setting `%s' as terminal type."
4441 tramp-terminal-type)
4442 (erase-buffer)
4443 (process-send-string nil (concat tramp-terminal-type
4444 tramp-rsh-end-of-line)))
4446 ;; The following functions are specifically for multi connections.
4448 (defun tramp-multi-action-login (p method user host)
4449 "Send the login name."
4450 (tramp-message 9 "Sending login name `%s'" user)
4451 (erase-buffer)
4452 (process-send-string p (concat user tramp-rsh-end-of-line)))
4454 (defun tramp-multi-action-password (p method user host)
4455 "Query the user for a password."
4456 (tramp-message 9 "Sending password")
4457 (tramp-enter-password p (match-string 0)))
4459 (defun tramp-multi-action-succeed (p method user host)
4460 "Signal success in finding shell prompt."
4461 (tramp-message 9 "Found shell prompt on `%s'" host)
4462 (erase-buffer)
4463 (throw 'tramp-action 'ok))
4465 (defun tramp-multi-action-permission-denied (p method user host)
4466 "Signal permission denied."
4467 (tramp-message 9 "Permission denied by remote host `%s'" host)
4468 (kill-process p)
4469 (erase-buffer)
4470 (throw 'tramp-action 'permission-denied))
4472 ;; Functions for processing the actions.
4474 (defun tramp-process-one-action (p multi-method method user host actions)
4475 "Wait for output from the shell and perform one action."
4476 (let (found item pattern action todo)
4477 (erase-buffer)
4478 (tramp-message 9 "Waiting 60s for prompt from remote shell")
4479 (with-timeout (60 (throw 'tramp-action 'timeout))
4480 (while (not found)
4481 (accept-process-output p 1)
4482 (goto-char (point-min))
4483 (setq todo actions)
4484 (while todo
4485 (goto-char (point-min))
4486 (setq item (pop todo))
4487 (setq pattern (symbol-value (nth 0 item)))
4488 (setq action (nth 1 item))
4489 (tramp-message 10 "Looking for regexp \"%s\" from remote shell"
4490 pattern)
4491 (when (re-search-forward (concat pattern "\\'") nil t)
4492 (setq found (funcall action p multi-method method user host)))))
4493 found)))
4495 (defun tramp-process-actions (p multi-method method user host actions)
4496 "Perform actions until success."
4497 (let (exit)
4498 (while (not exit)
4499 (tramp-message 9 "Waiting for prompts from remote shell")
4500 (setq exit
4501 (catch 'tramp-action
4502 (tramp-process-one-action
4503 p multi-method method user host actions)
4504 nil)))
4505 (unless (eq exit 'ok)
4506 (error "Login failed"))))
4508 ;; For multi-actions.
4510 (defun tramp-process-one-multi-action (p method user host actions)
4511 "Wait for output from the shell and perform one action."
4512 (let (found item pattern action todo)
4513 (erase-buffer)
4514 (tramp-message 9 "Waiting 60s for prompt from remote shell")
4515 (with-timeout (60 (throw 'tramp-action 'timeout))
4516 (while (not found)
4517 (accept-process-output p 1)
4518 (setq todo actions)
4519 (goto-char (point-min))
4520 (while todo
4521 (goto-char (point-min))
4522 (setq item (pop todo))
4523 (setq pattern (symbol-value (nth 0 item)))
4524 (setq action (nth 1 item))
4525 (tramp-message 10 "Looking for regexp \"%s\" from remote shell"
4526 pattern)
4527 (when (re-search-forward (concat pattern "\\'") nil t)
4528 (setq found (funcall action p method user host)))))
4529 found)))
4531 (defun tramp-process-multi-actions (p method user host actions)
4532 "Perform actions until success."
4533 (let (exit)
4534 (while (not exit)
4535 (tramp-message 9 "Waiting for prompts from remote shell")
4536 (setq exit
4537 (catch 'tramp-action
4538 (tramp-process-one-multi-action p method user host actions)
4539 nil)))
4540 (unless (eq exit 'ok)
4541 (error "Login failed"))))
4543 ;; The actual functions for opening connections.
4545 (defun tramp-open-connection-telnet (multi-method method user host)
4546 "Open a connection using a telnet METHOD.
4547 This starts the command `telnet HOST ARGS'[*], then waits for a remote
4548 login prompt, then sends the user name USER, then waits for a remote
4549 password prompt. It queries the user for the password, then sends the
4550 password to the remote host.
4552 If USER is nil, uses value returned by `(user-login-name)' instead.
4554 Recognition of the remote shell prompt is based on the variables
4555 `shell-prompt-pattern' and `tramp-shell-prompt-pattern' which must be
4556 set up correctly.
4558 Please note that it is NOT possible to use this connection method
4559 together with an out-of-band transfer method! You must use an inline
4560 transfer method.
4562 Maybe the different regular expressions need to be tuned.
4564 * Actually, the telnet program as well as the args to be used can be
4565 specified in the method parameters, see the variable `tramp-methods'."
4566 (save-match-data
4567 (when (tramp-method-out-of-band-p multi-method method user host)
4568 (error "Cannot use out-of-band method `%s' with telnet connection method"
4569 method))
4570 (when multi-method
4571 (error "Cannot multi-connect using telnet connection method"))
4572 (tramp-pre-connection multi-method method user host)
4573 (tramp-message 7 "Opening connection for %s@%s using %s..."
4574 (or user (user-login-name)) host method)
4575 (let ((process-environment (copy-sequence process-environment)))
4576 (setenv "TERM" tramp-terminal-type)
4577 (let* ((default-directory (tramp-temporary-file-directory))
4578 ;; If we omit the conditional here, then we would use
4579 ;; `undecided-dos' in some cases. With the conditional,
4580 ;; we use nil in these cases. Which one is right?
4581 (coding-system-for-read (unless (and (not (featurep 'xemacs))
4582 (> emacs-major-version 20))
4583 tramp-dos-coding-system))
4584 (p (apply 'start-process
4585 (tramp-buffer-name multi-method method user host)
4586 (tramp-get-buffer multi-method method user host)
4587 (tramp-get-login-program
4588 multi-method
4589 (tramp-find-method multi-method method user host)
4590 user host)
4591 host
4592 (tramp-get-login-args
4593 multi-method
4594 (tramp-find-method multi-method method user host)
4595 user host)))
4596 (found nil)
4597 (pw nil))
4598 (process-kill-without-query p)
4599 (set-buffer (tramp-get-buffer multi-method method user host))
4600 (erase-buffer)
4601 (tramp-process-actions p multi-method method user host
4602 tramp-actions-before-shell)
4603 (tramp-open-connection-setup-interactive-shell
4604 p multi-method method user host)
4605 (tramp-post-connection multi-method method user host)))))
4608 (defun tramp-open-connection-rsh (multi-method method user host)
4609 "Open a connection using an rsh METHOD.
4610 This starts the command `rsh HOST -l USER'[*], then waits for a remote
4611 password or shell prompt. If a password prompt is seen, the user is
4612 queried for a password, this function sends the password to the remote
4613 host and waits for a shell prompt.
4615 If USER is nil, start the command `rsh HOST'[*] instead
4617 Recognition of the remote shell prompt is based on the variables
4618 `shell-prompt-pattern' and `tramp-shell-prompt-pattern' which must be
4619 set up correctly.
4621 Please note that it is NOT possible to use this connection method with
4622 an out-of-band transfer method if this function asks the user for a
4623 password! You must use an inline transfer method in this case.
4624 Sadly, the transfer method cannot be switched on the fly, instead you
4625 must specify the right method in the file name.
4627 Kludgy feature: if HOST has the form \"xx#yy\", then yy is assumed to
4628 be a port number for ssh, and \"-p yy\" will be added to the list of
4629 arguments, and xx will be used as the host name to connect to.
4631 * Actually, the rsh program to be used can be specified in the
4632 method parameters, see the variable `tramp-methods'."
4633 (save-match-data
4634 (when multi-method
4635 (error "Cannot multi-connect using rsh connection method"))
4636 (tramp-pre-connection multi-method method user host)
4637 (if (and user (not (string= user "")))
4638 (tramp-message 7 "Opening connection for %s@%s using %s..."
4639 user host method)
4640 (tramp-message 7 "Opening connection at %s using %s..." host method))
4641 (let ((process-environment (copy-sequence process-environment))
4642 (bufnam (tramp-buffer-name multi-method method user host))
4643 (buf (tramp-get-buffer multi-method method user host))
4644 (login-program (tramp-get-login-program
4645 multi-method
4646 (tramp-find-method multi-method method user host)
4647 user host))
4648 (login-args (tramp-get-login-args
4649 multi-method
4650 (tramp-find-method multi-method method user host)
4651 user host)))
4652 ;; The following should be changed. We need a more general
4653 ;; mechanism to parse extra host args.
4654 (when (string-match "\\([^#]*\\)#\\(.*\\)" host)
4655 (setq login-args (cons "-p" (cons (match-string 2 host) rsh-args)))
4656 (setq host (match-string 1 host)))
4657 (setenv "TERM" tramp-terminal-type)
4658 (let* ((default-directory (tramp-temporary-file-directory))
4659 ;; If we omit the conditional, we would use
4660 ;; `undecided-dos' in some cases. With the conditional,
4661 ;; we use nil in these cases. Which one is right?
4662 (coding-system-for-read (unless (and (not (featurep 'xemacs))
4663 (> emacs-major-version 20))
4664 tramp-dos-coding-system))
4665 (p (if (and user (not (string= user "")))
4666 (apply #'start-process bufnam buf login-program
4667 host "-l" user login-args)
4668 (apply #'start-process bufnam buf login-program
4669 host login-args)))
4670 (found nil))
4671 (process-kill-without-query p)
4673 (set-buffer buf)
4674 (tramp-process-actions p multi-method method user host
4675 tramp-actions-before-shell)
4676 (tramp-message 7 "Initializing remote shell")
4677 (tramp-open-connection-setup-interactive-shell
4678 p multi-method method user host)
4679 (tramp-post-connection multi-method method user host)))))
4681 (defun tramp-open-connection-su (multi-method method user host)
4682 "Open a connection using the `su' program with METHOD.
4683 This starts `su - USER', then waits for a password prompt. The HOST
4684 name must be equal to the local host name or to `localhost'.
4686 If USER is nil, uses value returned by user-login-name instead.
4688 Recognition of the remote shell prompt is based on the variables
4689 `shell-prompt-pattern' and `tramp-shell-prompt-pattern' which must be
4690 set up correctly. Note that the other user may have a different shell
4691 prompt than you do, so it is not at all unlikely that the variable
4692 `shell-prompt-pattern' is set up wrongly!"
4693 (save-match-data
4694 (when (tramp-method-out-of-band-p multi-method method user host)
4695 (error "Cannot use out-of-band method `%s' with `su' connection method"
4696 method))
4697 (unless (or (string-match (concat "^" (regexp-quote host))
4698 (system-name))
4699 (string= "localhost" host)
4700 (string= "" host))
4701 (error
4702 "Cannot connect to different host `%s' with `su' connection method"
4703 host))
4704 (tramp-pre-connection multi-method method user host)
4705 (tramp-message 7 "Opening connection for `%s' using `%s'..."
4706 (or user "<root>") method)
4707 (let ((process-environment (copy-sequence process-environment)))
4708 (setenv "TERM" tramp-terminal-type)
4709 (let* ((default-directory (tramp-temporary-file-directory))
4710 ;; If we omit the conditional, we use `undecided-dos' in
4711 ;; some cases. With the conditional, we use nil in these
4712 ;; cases. What's the difference? Which one is right?
4713 (coding-system-for-read (unless (and (not (featurep 'xemacs))
4714 (> emacs-major-version 20))
4715 tramp-dos-coding-system))
4716 (p (apply 'start-process
4717 (tramp-buffer-name multi-method method user host)
4718 (tramp-get-buffer multi-method method user host)
4719 (tramp-get-login-program
4720 multi-method
4721 (tramp-find-method multi-method method user host)
4722 user host)
4723 (mapcar
4724 (lambda (x)
4725 (format-spec x `((?u . ,(or user "root")))))
4726 (tramp-get-login-args
4727 multi-method
4728 (tramp-find-method multi-method method user host)
4729 user host))))
4730 (found nil)
4731 (pw nil))
4732 (process-kill-without-query p)
4733 (set-buffer (tramp-get-buffer multi-method method user host))
4734 (tramp-process-actions p multi-method method user host
4735 tramp-actions-before-shell)
4736 (tramp-open-connection-setup-interactive-shell
4737 p multi-method method user host)
4738 (tramp-post-connection multi-method method
4739 user host)))))
4741 ;; HHH: Not Changed. Multi method. It is not clear to me how this can
4742 ;; handle not giving a user name in the "file name".
4744 ;; This is more difficult than for the single-hop method. In the
4745 ;; multi-hop-method, the desired behaviour should be that the
4746 ;; user must specify names for the telnet hops of which the user
4747 ;; name is different than the "original" name (or different from
4748 ;; the previous hop.
4749 (defun tramp-open-connection-multi (multi-method method user host)
4750 "Open a multi-hop connection using METHOD.
4751 This uses a slightly changed file name syntax. The idea is to say
4752 [multi/telnet:u1@h1/rsh:u2@h2]/path/to/file
4753 This will use telnet to log in as u1 to h1, then use rsh from there to
4754 log in as u2 to h2."
4755 (save-match-data
4756 (unless multi-method
4757 (error "Multi-hop open connection function called on non-multi method"))
4758 (when (tramp-method-out-of-band-p multi-method method user host)
4759 (error "No out of band multi-hop connections"))
4760 (unless (and (arrayp method) (not (stringp method)))
4761 (error "METHOD must be an array of strings for multi methods"))
4762 (unless (and (arrayp user) (not (stringp user)))
4763 (error "USER must be an array of strings for multi methods"))
4764 (unless (and (arrayp host) (not (stringp host)))
4765 (error "HOST must be an array of strings for multi methods"))
4766 (unless (and (= (length method) (length user))
4767 (= (length method) (length host)))
4768 (error "Arrays METHOD, USER, HOST must have equal length"))
4769 (tramp-pre-connection multi-method method user host)
4770 (tramp-message 7 "Opening `%s' connection..." multi-method)
4771 (let ((process-environment (copy-sequence process-environment)))
4772 (setenv "TERM" tramp-terminal-type)
4773 (let* ((default-directory (tramp-temporary-file-directory))
4774 ;; If we omit the conditional, we use `undecided-dos' in
4775 ;; some cases. With the conditional, we use nil in these
4776 ;; cases. What's the difference? Which one is right?
4777 (coding-system-for-read (unless (and (not (featurep 'xemacs))
4778 (> emacs-major-version 20))
4779 tramp-dos-coding-system))
4780 (p (start-process (tramp-buffer-name multi-method method user host)
4781 (tramp-get-buffer multi-method method user host)
4782 tramp-multi-sh-program))
4783 (num-hops (length method))
4784 (i 0))
4785 (process-kill-without-query p)
4786 (tramp-message 9 "Waiting 60s for local shell to come up...")
4787 (unless (tramp-wait-for-regexp
4788 p 60 (format "\\(%s\\)\\'\\|\\(%s\\)\\'"
4789 shell-prompt-pattern tramp-shell-prompt-pattern))
4790 (pop-to-buffer (buffer-name))
4791 (kill-process p)
4792 (error "Couldn't find local shell prompt"))
4793 ;; Now do all the connections as specified.
4794 (while (< i num-hops)
4795 (let* ((m (aref method i))
4796 (u (aref user i))
4797 (h (aref host i))
4798 (entry (assoc m tramp-multi-connection-function-alist))
4799 (multi-func (nth 1 entry))
4800 (command (nth 2 entry)))
4801 ;; The multi-funcs don't need to do save-match-data, as that
4802 ;; is done here.
4803 (funcall multi-func p m u h command)
4804 (erase-buffer)
4805 (incf i)))
4806 (tramp-open-connection-setup-interactive-shell
4807 p multi-method method user host)
4808 (tramp-post-connection multi-method method user host)))))
4810 ;; HHH: Changed. Multi method. Don't know how to handle this in the case
4811 ;; of no user name provided. Hack to make it work as it did before:
4812 ;; changed `user' to `(or user (user-login-name))' in the places where
4813 ;; the value is actually used.
4814 (defun tramp-multi-connect-telnet (p method user host command)
4815 "Issue `telnet' command.
4816 Uses shell COMMAND to issue a `telnet' command to log in as USER to
4817 HOST. You can use percent escapes in COMMAND: `%h' is replaced with
4818 the host name, and `%n' is replaced with an end of line character, as
4819 set in `tramp-rsh-end-of-line'. Use `%%' if you want a literal percent
4820 character.
4822 If USER is nil, uses the return value of (user-login-name) instead."
4823 (let ((cmd (format-spec command
4824 `((?h . ,host) (?n . ,tramp-rsh-end-of-line))))
4825 (cmd1 (format-spec command `((?h . ,host) (?n . ""))))
4826 found pw)
4827 (erase-buffer)
4828 (tramp-message 9 "Sending telnet command `%s'" cmd1)
4829 (process-send-string p cmd)
4830 (tramp-process-multi-actions p method user host
4831 tramp-multi-actions)))
4833 ;; HHH: Changed. Multi method. Don't know how to handle this in the case
4834 ;; of no user name provided. Hack to make it work as it did before:
4835 ;; changed `user' to `(or user (user-login-name))' in the places where
4836 ;; the value is actually used.
4837 (defun tramp-multi-connect-rlogin (p method user host command)
4838 "Issue `rlogin' command.
4839 Uses shell COMMAND to issue an `rlogin' command to log in as USER to
4840 HOST. You can use percent escapes in COMMAND. `%u' will be replaced
4841 with the user name, `%h' will be replaced with the host name, and `%n'
4842 will be replaced with the value of `tramp-rsh-end-of-line'. You can use
4843 `%%' if you want to use a literal percent character.
4845 If USER is nil, uses the return value of (user-login-name) instead."
4846 (let ((cmd (format-spec command `((?h . ,host)
4847 (?u . ,(or user (user-login-name)))
4848 (?n . ,tramp-rsh-end-of-line))))
4849 (cmd1 (format-spec command `((?h . ,host)
4850 (?u . ,(or user (user-login-name)))
4851 (?n . ""))))
4852 found)
4853 (erase-buffer)
4854 (tramp-message 9 "Sending rlogin command `%s'" cmd1)
4855 (process-send-string p cmd)
4856 (tramp-process-multi-actions p method user host
4857 tramp-multi-actions)))
4859 ;; HHH: Changed. Multi method. Don't know how to handle this in the case
4860 ;; of no user name provided. Hack to make it work as it did before:
4861 ;; changed `user' to `(or user (user-login-name))' in the places where
4862 ;; the value is actually used.
4863 (defun tramp-multi-connect-su (p method user host command)
4864 "Issue `su' command.
4865 Uses shell COMMAND to issue a `su' command to log in as USER on
4866 HOST. The HOST name is ignored, this just changes the user id on the
4867 host currently logged in to.
4869 If USER is nil, uses the return value of (user-login-name) instead.
4871 You can use percent escapes in the COMMAND. `%u' is replaced with the
4872 user name, and `%n' is replaced with the value of
4873 `tramp-rsh-end-of-line'. Use `%%' if you want a literal percent
4874 character."
4875 (let ((cmd (format-spec command `((?u . ,(or user (user-login-name)))
4876 (?n . ,tramp-rsh-end-of-line))))
4877 (cmd1 (format-spec command `((?u . ,(or user (user-login-name)))
4878 (?n . ""))))
4879 found)
4880 (erase-buffer)
4881 (tramp-message 9 "Sending su command `%s'" cmd1)
4882 (process-send-string p cmd)
4883 (tramp-process-multi-actions p method user host
4884 tramp-multi-actions)))
4886 ;; Utility functions.
4888 (defun tramp-wait-for-regexp (proc timeout regexp)
4889 "Wait for a REGEXP to appear from process PROC within TIMEOUT seconds.
4890 Expects the output of PROC to be sent to the current buffer. Returns
4891 the string that matched, or nil. Waits indefinitely if TIMEOUT is
4892 nil."
4893 (let ((found nil)
4894 (start-time (current-time)))
4895 (cond (timeout
4896 ;; Work around a bug in XEmacs 21, where the timeout
4897 ;; expires faster than it should. This degenerates
4898 ;; to polling for buggy XEmacsen, but oh, well.
4899 (while (and (not found)
4900 (< (tramp-time-diff (current-time) start-time)
4901 timeout))
4902 (with-timeout (timeout)
4903 (while (not found)
4904 (accept-process-output proc 1)
4905 (goto-char (point-min))
4906 (setq found (when (re-search-forward regexp nil t)
4907 (tramp-match-string-list)))))))
4909 (while (not found)
4910 (accept-process-output proc 1)
4911 (goto-char (point-min))
4912 (setq found (when (re-search-forward regexp nil t)
4913 (tramp-match-string-list))))))
4914 (when tramp-debug-buffer
4915 (append-to-buffer
4916 (tramp-get-debug-buffer tramp-current-multi-method tramp-current-method
4917 tramp-current-user tramp-current-host)
4918 (point-min) (point-max))
4919 (when (not found)
4920 (save-excursion
4921 (set-buffer
4922 (tramp-get-debug-buffer tramp-current-multi-method tramp-current-method
4923 tramp-current-user tramp-current-host))
4924 (goto-char (point-max))
4925 (insert "[[Regexp `" regexp "' not found"
4926 (if timeout (format " in %d secs" timeout) "")
4927 "]]"))))
4928 found))
4930 (defun tramp-wait-for-shell-prompt (proc timeout)
4931 "Wait for the shell prompt to appear from process PROC within TIMEOUT seconds.
4932 See `tramp-wait-for-regexp' for more details.
4933 Shell prompt pattern is determined by variables `shell-prompt-pattern'
4934 and `tramp-shell-prompt-pattern'."
4935 (tramp-wait-for-regexp
4936 proc timeout
4937 (format "\\(%s\\|%s\\)\\'"
4938 shell-prompt-pattern tramp-shell-prompt-pattern)))
4940 (defun tramp-barf-if-no-shell-prompt (proc timeout &rest error-args)
4941 "Wait for shell prompt and barf if none appears.
4942 Looks at process PROC to see if a shell prompt appears in TIMEOUT
4943 seconds. If not, it produces an error message with the given ERROR-ARGS."
4944 (unless (tramp-wait-for-shell-prompt proc timeout)
4945 (pop-to-buffer (buffer-name))
4946 (apply 'error error-args)))
4948 (defun tramp-enter-password (p prompt)
4949 "Prompt for a password and send it to the remote end.
4950 Uses PROMPT as a prompt and sends the password to process P."
4951 (let ((pw (tramp-read-passwd prompt)))
4952 (erase-buffer)
4953 (process-send-string p (concat pw tramp-password-end-of-line))))
4955 ;; HHH: Not Changed. This might handle the case where USER is not
4956 ;; given in the "File name" very poorly. Then, the local
4957 ;; variable tramp-current user will be set to nil.
4958 (defun tramp-pre-connection (multi-method method user host)
4959 "Do some setup before actually logging in.
4960 METHOD, USER and HOST specify the connection."
4961 (set-buffer (tramp-get-buffer multi-method method user host))
4962 (set (make-local-variable 'tramp-current-multi-method) multi-method)
4963 (set (make-local-variable 'tramp-current-method) method)
4964 (set (make-local-variable 'tramp-current-user) user)
4965 (set (make-local-variable 'tramp-current-host) host)
4966 (set (make-local-variable 'inhibit-eol-conversion) nil)
4967 (erase-buffer))
4969 (defun tramp-open-connection-setup-interactive-shell
4970 (p multi-method method user host)
4971 "Set up an interactive shell.
4972 Mainly sets the prompt and the echo correctly. P is the shell process
4973 to set up. METHOD, USER and HOST specify the connection."
4974 ;; Wait a bit in case the remote end feels like sending a little
4975 ;; junk first. It seems that fencepost.gnu.org does this when doing
4976 ;; a Kerberos login.
4977 (sit-for 1)
4978 (tramp-discard-garbage-erase-buffer p multi-method method user host)
4979 ;; It is useful to set the prompt in the following command because
4980 ;; some people have a setting for $PS1 which /bin/sh doesn't know
4981 ;; about and thus /bin/sh will display a strange prompt. For
4982 ;; example, if $PS1 has "${CWD}" in the value, then ksh will display
4983 ;; the current working directory but /bin/sh will display a dollar
4984 ;; sign. The following command line sets $PS1 to a sane value, and
4985 ;; works under Bourne-ish shells as well as csh-like shells. Daniel
4986 ;; Pittman reports that the unusual positioning of the single quotes
4987 ;; makes it work under `rc', too. We also unset the variable $ENV
4988 ;; because that is read by some sh implementations (eg, bash when
4989 ;; called as sh) on startup; this way, we avoid the startup file
4990 ;; clobbering $PS1.
4991 (tramp-send-command-internal
4992 multi-method method user host
4993 (format "exec env 'ENV=' 'PS1=$ ' %s"
4994 (tramp-get-remote-sh multi-method method user host))
4995 (format "remote `%s' to come up"
4996 (tramp-get-remote-sh multi-method method user host)))
4997 (tramp-barf-if-no-shell-prompt
4998 p 30
4999 "Remote `%s' didn't come up. See buffer `%s' for details"
5000 (tramp-get-remote-sh multi-method method user host)
5001 (buffer-name))
5002 (tramp-message 8 "Setting up remote shell environment")
5003 (tramp-discard-garbage-erase-buffer p multi-method method user host)
5004 (tramp-send-command-internal multi-method method user host
5005 "stty -inlcr -echo kill '^U'")
5006 (erase-buffer)
5007 (tramp-send-command-internal multi-method method user host
5008 "TERM=dumb; export TERM")
5009 ;; Try to set up the coding system correctly.
5010 ;; CCC this can't be the right way to do it. Hm.
5011 (save-excursion
5012 (erase-buffer)
5013 (tramp-message 9 "Determining coding system")
5014 (tramp-send-command-internal multi-method method user host
5015 "echo foo ; echo bar")
5016 (goto-char (point-min))
5017 (if (featurep 'mule)
5018 ;; Use MULE to select the right EOL convention for communicating
5019 ;; with the process.
5020 (let* ((cs (or (process-coding-system p) (cons 'undecided 'undecided)))
5021 cs-decode cs-encode)
5022 (when (symbolp cs) (setq cs (cons cs cs)))
5023 (setq cs-decode (car cs))
5024 (setq cs-encode (cdr cs))
5025 (unless cs-decode (setq cs-decode 'undecided))
5026 (unless cs-encode (setq cs-encode 'undecided))
5027 (setq cs-encode (tramp-coding-system-change-eol-conversion
5028 cs-encode 'unix))
5029 (when (search-forward "\r" nil t)
5030 (setq cs-decode (tramp-coding-system-change-eol-conversion
5031 cs-decode 'dos)))
5032 (set-buffer-process-coding-system cs-decode cs-encode))
5033 ;; Look for ^M and do something useful if found.
5034 (when (search-forward "\r" nil t)
5035 ;; We have found a ^M but cannot frob the process coding system
5036 ;; because we're running on a non-MULE Emacs. Let's try
5037 ;; stty, instead.
5038 (tramp-message 9 "Trying `stty -onlcr'")
5039 (tramp-send-command-internal multi-method method user host
5040 "stty -onlcr"))))
5041 (erase-buffer)
5042 (tramp-message
5043 9 "Waiting 30s for `HISTFILE=$HOME/.tramp_history; HISTSIZE=1'")
5044 (tramp-send-command-internal multi-method method user host
5045 "HISTFILE=$HOME/.tramp_history; HISTSIZE=1")
5046 (erase-buffer)
5047 (tramp-message 9 "Waiting 30s for `set +o vi +o emacs'")
5048 (tramp-send-command-internal multi-method method user host
5049 "set +o vi +o emacs")
5050 (erase-buffer)
5051 (tramp-message 9 "Waiting 30s for `unset MAIL MAILCHECK MAILPATH'")
5052 (tramp-send-command-internal
5053 multi-method method user host
5054 "unset MAIL MAILCHECK MAILPATH 1>/dev/null 2>/dev/null")
5055 (erase-buffer)
5056 (tramp-message 9 "Waiting 30s for `unset CDPATH'")
5057 (tramp-send-command-internal multi-method method user host
5058 "unset CDPATH")
5059 (erase-buffer)
5060 (tramp-message 9 "Setting shell prompt")
5061 ;; Douglas Gray Stephens <DGrayStephens@slb.com> says that we must
5062 ;; use "\n" here, not tramp-rsh-end-of-line. We also manually frob
5063 ;; the last time we sent a command, to avoid tramp-send-command to send
5064 ;; "echo are you awake".
5065 (setq tramp-last-cmd-time (current-time))
5066 (tramp-send-command
5067 multi-method method user host
5068 (format "PS1='%s%s%s'; PS2=''; PS3=''"
5069 tramp-rsh-end-of-line
5070 tramp-end-of-output
5071 tramp-rsh-end-of-line))
5072 (tramp-wait-for-output))
5074 (defun tramp-post-connection (multi-method method user host)
5075 "Prepare a remote shell before being able to work on it.
5076 METHOD, USER and HOST specify the connection.
5077 Among other things, this finds a shell which groks tilde expansion,
5078 tries to find an `ls' command which groks the `-n' option, sets the
5079 locale to C and sets up the remote shell search path."
5080 ;; Search for a good shell before searching for a command which
5081 ;; checks if a file exists. This is done because Tramp wants to use
5082 ;; "test foo; echo $?" to check if various conditions hold, and
5083 ;; there are buggy /bin/sh implementations which don't execute the
5084 ;; "echo $?" part if the "test" part has an error. In particular,
5085 ;; the Solaris /bin/sh is a problem. I'm betting that all systems
5086 ;; with buggy /bin/sh implementations will have a working bash or
5087 ;; ksh. Whee...
5088 (tramp-find-shell multi-method method user host)
5089 ;; Without (sit-for 0.1) at least, my machine will almost always blow
5090 ;; up on 'not numberp /root' - a race that causes the 'echo ~root'
5091 ;; output of (tramp-find-shell) to show up along with the output of
5092 ;; (tramp-find-ls-command) testing.
5094 ;; I can't work out why this is a problem though. The (tramp-wait-for-output)
5095 ;; call in (tramp-find-shell) *should* make this not happen, I thought.
5097 ;; After much debugging I couldn't find any problem with the implementation
5098 ;; of that function though. The workaround stays for me at least. :/
5100 ;; Daniel Pittman <daniel@danann.net>
5101 (sleep-for 1)
5102 (erase-buffer)
5103 (tramp-find-file-exists-command multi-method method user host)
5104 (make-local-variable 'tramp-ls-command)
5105 (setq tramp-ls-command (tramp-find-ls-command multi-method method user host))
5106 (unless tramp-ls-command
5107 (tramp-message
5109 "Danger! Couldn't find ls which groks -n. Muddling through anyway")
5110 (setq tramp-ls-command
5111 (tramp-find-executable multi-method method user host
5112 "ls" tramp-remote-path nil)))
5113 (unless tramp-ls-command
5114 (error "Fatal error: Couldn't find remote executable `ls'"))
5115 (tramp-message 5 "Using remote command `%s' for getting directory listings"
5116 tramp-ls-command)
5117 (tramp-send-command multi-method method user host
5118 (concat "tramp_set_exit_status () {" tramp-rsh-end-of-line
5119 "return $1" tramp-rsh-end-of-line
5120 "}"))
5121 (tramp-wait-for-output)
5122 ;; Set remote PATH variable.
5123 (tramp-set-remote-path multi-method method user host "PATH" tramp-remote-path)
5124 ;; Tell remote shell to use standard time format, needed for
5125 ;; parsing `ls -l' output.
5126 (tramp-send-command multi-method method user host
5127 "LC_TIME=C; export LC_TIME; echo huhu")
5128 (tramp-wait-for-output)
5129 (tramp-send-command multi-method method user host
5130 "mesg n; echo huhu")
5131 (tramp-wait-for-output)
5132 (tramp-send-command multi-method method user host
5133 "biff n ; echo huhu")
5134 (tramp-wait-for-output)
5135 ;; Unalias ls(1) to work around issues with those silly people who make it
5136 ;; spit out ANSI escapes or whatever.
5137 (tramp-send-command multi-method method user host
5138 "unalias ls; echo huhu")
5139 (tramp-wait-for-output)
5140 ;; Does `test A -nt B' work? Use abominable `find' construct if it
5141 ;; doesn't. BSD/OS 4.0 wants the parentheses around the command,
5142 ;; for otherwise the shell crashes.
5143 (erase-buffer)
5144 (make-local-variable 'tramp-test-groks-nt)
5145 (tramp-send-command multi-method method user host
5146 "( test / -nt / )")
5147 (tramp-wait-for-output)
5148 (goto-char (point-min))
5149 (setq tramp-test-groks-nt
5150 (looking-at (format "\n%s\r?\n" (regexp-quote tramp-end-of-output))))
5151 (unless tramp-test-groks-nt
5152 (tramp-send-command
5153 multi-method method user host
5154 (concat "tramp_test_nt () {" tramp-rsh-end-of-line
5155 "test -n \"`find $1 -prune -newer $2 -print`\"" tramp-rsh-end-of-line
5156 "}")))
5157 (tramp-wait-for-output)
5158 ;; Send the fallback `uudecode' script.
5159 (erase-buffer)
5160 (tramp-send-string multi-method method user host tramp-uudecode)
5161 (tramp-wait-for-output)
5162 ;; Find a `perl'.
5163 (erase-buffer)
5164 (let ((tramp-remote-perl
5165 (or (tramp-find-executable multi-method method user host
5166 "perl5" tramp-remote-path nil)
5167 (tramp-find-executable multi-method method user host
5168 "perl" tramp-remote-path nil))))
5169 (when tramp-remote-perl
5170 (tramp-set-connection-property "perl" tramp-remote-perl
5171 multi-method method user host)
5172 ;; Set up stat in Perl if we can.
5173 (when tramp-remote-perl
5174 (tramp-message 5 "Sending the Perl `file-attributes' implementation.")
5175 (tramp-send-string
5176 multi-method method user host
5177 (concat "tramp_file_attributes () {\n"
5178 tramp-remote-perl
5179 " -e '" tramp-perl-file-attributes "' $1 2>/dev/null\n"
5180 "}"))
5181 (tramp-wait-for-output)
5182 (unless (tramp-get-copy-program
5183 multi-method
5184 (tramp-find-method multi-method method user host)
5185 user host)
5186 (tramp-message 5 "Sending the Perl `mime-encode' implementations.")
5187 (tramp-send-string
5188 multi-method method user host
5189 (concat "tramp_encode () {\n"
5190 (format tramp-perl-encode tramp-remote-perl)
5191 " 2>/dev/null"
5192 "\n}"))
5193 (tramp-wait-for-output)
5194 (tramp-send-string
5195 multi-method method user host
5196 (concat "tramp_encode_with_module () {\n"
5197 (format tramp-perl-encode-with-module tramp-remote-perl)
5198 " 2>/dev/null"
5199 "\n}"))
5200 (tramp-wait-for-output)
5201 (tramp-message 5 "Sending the Perl `mime-decode' implementations.")
5202 (tramp-send-string
5203 multi-method method user host
5204 (concat "tramp_decode () {\n"
5205 (format tramp-perl-decode tramp-remote-perl)
5206 " 2>/dev/null"
5207 "\n}"))
5208 (tramp-wait-for-output)
5209 (tramp-send-string
5210 multi-method method user host
5211 (concat "tramp_decode_with_module () {\n"
5212 (format tramp-perl-decode-with-module tramp-remote-perl)
5213 " 2>/dev/null"
5214 "\n}"))
5215 (tramp-wait-for-output)))))
5216 ;; Find ln(1)
5217 (erase-buffer)
5218 (let ((ln (tramp-find-executable multi-method method user host
5219 "ln" tramp-remote-path nil)))
5220 (when ln
5221 (tramp-set-connection-property "ln" ln multi-method method user host)))
5222 (erase-buffer)
5223 ;; Find the right encoding/decoding commands to use.
5224 (unless (tramp-get-copy-program
5225 multi-method
5226 (tramp-find-method multi-method method user host)
5227 user host)
5228 (tramp-find-inline-encoding multi-method method user host))
5229 ;; If encoding/decoding command are given, test to see if they work.
5230 ;; CCC: Maybe it would be useful to run the encoder both locally and
5231 ;; remotely to see if they produce the same result.
5232 (let ((rem-enc (tramp-get-remote-encoding multi-method method user host))
5233 (rem-dec (tramp-get-remote-decoding multi-method method user host))
5234 (magic-string "xyzzy"))
5235 (when (and (or rem-dec rem-enc) (not (and rem-dec rem-enc)))
5236 (tramp-kill-process multi-method method user host)
5237 ;; Improve error message and/or error check.
5238 (error
5239 "Must give both decoding and encoding command in method definition"))
5240 (when (and rem-enc rem-dec)
5241 (tramp-message
5243 "Checking to see if encoding/decoding commands work on remote host...")
5244 (tramp-send-command
5245 multi-method method user host
5246 (format "echo %s | %s | %s"
5247 (tramp-shell-quote-argument magic-string) rem-enc rem-dec))
5248 (tramp-wait-for-output)
5249 (unless (looking-at (regexp-quote magic-string))
5250 (tramp-kill-process multi-method method user host)
5251 (error "Remote host cannot execute de/encoding commands. See buffer `%s' for details"
5252 (buffer-name)))
5253 (erase-buffer)
5254 (tramp-message
5255 5 "Checking to see if encoding/decoding commands work on remote host...done"))))
5257 ;; CCC: We should either implement a Perl version of base64 encoding
5258 ;; and decoding. Then we just use that in the last item. The other
5259 ;; alternative is to use the Perl version of UU encoding. But then
5260 ;; we need a Lisp version of uuencode.
5262 ;; Old text from documentation of tramp-methods:
5263 ;; Using a uuencode/uudecode inline method is discouraged, please use one
5264 ;; of the base64 methods instead since base64 encoding is much more
5265 ;; reliable and the commands are more standardized between the different
5266 ;; Unix versions. But if you can't use base64 for some reason, please
5267 ;; note that the default uudecode command does not work well for some
5268 ;; Unices, in particular AIX and Irix. For AIX, you might want to use
5269 ;; the following command for uudecode:
5271 ;; sed '/^begin/d;/^[` ]$/d;/^end/d' | iconv -f uucode -t ISO8859-1
5273 ;; For Irix, no solution is known yet.
5275 (defvar tramp-coding-commands
5276 '(("mimencode -b" "mimencode -u -b"
5277 base64-encode-region base64-decode-region)
5278 ("mmencode -b" "mmencode -u -b"
5279 base64-encode-region base64-decode-region)
5280 ("recode data..base64" "recode base64..data"
5281 base64-encode-region base64-decode-region)
5282 ("uuencode xxx" "uudecode -o -"
5283 tramp-uuencode-region uudecode-decode-region)
5284 ("uuencode xxx" "uudecode -p"
5285 tramp-uuencode-region uudecode-decode-region)
5286 ("uuencode xxx" "tramp_uudecode"
5287 tramp-uuencode-region uudecode-decode-region)
5288 ("tramp_encode_with_module" "tramp_decode_with_module"
5289 base64-encode-region base64-decode-region)
5290 ("tramp_encode" "tramp_decode"
5291 base64-encode-region base64-decode-region))
5292 "List of coding commands for inline transfer.
5293 Each item is a list that looks like this:
5295 \(REMOTE-ENCODING REMOTE-DECODING LOCAL-ENCODING LOCAL-DECODING)
5297 The REMOTE-ENCODING should be a string, giving a command accepting a
5298 plain file on standard input and writing the encoded file to standard
5299 output. The REMOTE-DECODING should also be a string, giving a command
5300 accepting an encoded file on standard input and writing the decoded
5301 file to standard output.
5303 LOCAL-ENCODING and LOCAL-DECODING can be strings, giving commands, or
5304 symbols, giving functions. If they are strings, then they can contain
5305 the \"%s\" format specifier. If that specifier is present, the input
5306 filename will be put into the command line at that spot. If the
5307 specifier is not present, the input should be read from standard
5308 input.
5310 If they are functions, they will be called with two arguments, start
5311 and end of region, and are expected to replace the region contents
5312 with the encoded or decoded results, respectively.")
5314 (defun tramp-find-inline-encoding (multi-method method user host)
5315 "Find an inline transfer encoding that works.
5316 Goes through the list `tramp-coding-commands'."
5317 (let ((commands tramp-coding-commands)
5318 (magic "xyzzy")
5319 item found)
5320 (while (and commands (null found))
5321 (setq item (pop commands))
5322 (catch 'wont-work
5323 (let ((rem-enc (nth 0 item))
5324 (rem-dec (nth 1 item))
5325 (loc-enc (nth 2 item))
5326 (loc-dec (nth 3 item)))
5327 ;; Check if remote encoding and decoding commands can be
5328 ;; called remotely with null input and output. This makes
5329 ;; sure there are no syntax errors and the command is really
5330 ;; found. Note that we do not redirect stdout to /dev/null,
5331 ;; for two reaons: when checking the decoding command, we
5332 ;; actually check the output it gives. And also, when
5333 ;; redirecting "mimencode" output to /dev/null, then as root
5334 ;; it might change the permissions of /dev/null!
5335 (tramp-message-for-buffer
5336 multi-method method user host 9
5337 "Checking remote encoding command `%s' for sanity" rem-enc)
5338 (unless (zerop (tramp-send-command-and-check
5339 multi-method method user host
5340 (format "%s </dev/null" rem-enc) t))
5341 (throw 'wont-work nil))
5342 (tramp-message-for-buffer
5343 multi-method method user host 9
5344 "Checking remote decoding command `%s' for sanity" rem-dec)
5345 (unless (zerop (tramp-send-command-and-check
5346 multi-method method user host
5347 (format "echo %s | %s | %s"
5348 magic rem-enc rem-dec) t))
5349 (throw 'wont-work nil))
5350 (save-excursion
5351 (goto-char (point-min))
5352 (unless (looking-at (regexp-quote magic))
5353 (throw 'wont-work nil)))
5354 ;; If the local encoder or decoder is a string, the
5355 ;; corresponding command has to work locally.
5356 (when (stringp loc-enc)
5357 (tramp-message-for-buffer
5358 multi-method method user host 9
5359 "Checking local encoding command `%s' for sanity" loc-enc)
5360 (unless (zerop (tramp-call-local-coding-command
5361 loc-enc nil nil))
5362 (throw 'wont-work nil)))
5363 (when (stringp loc-dec)
5364 (tramp-message-for-buffer
5365 multi-method method user host 9
5366 "Checking local decoding command `%s' for sanity" loc-dec)
5367 (unless (zerop (tramp-call-local-coding-command
5368 loc-dec nil nil))
5369 (throw 'wont-work nil)))
5370 ;; CCC: At this point, maybe we should check that the output
5371 ;; of the commands is correct. But for the moment we will
5372 ;; assume that commands working on empty input will also
5373 ;; work in practice.
5374 (setq found item))))
5375 ;; Did we find something? If not, issue error. If so,
5376 ;; set connection properties.
5377 (unless found
5378 (error "Couldn't find an inline transfer encoding"))
5379 (let ((rem-enc (nth 0 found))
5380 (rem-dec (nth 1 found))
5381 (loc-enc (nth 2 found))
5382 (loc-dec (nth 3 found)))
5383 (tramp-message 10 "Using remote encoding %s" rem-enc)
5384 (tramp-set-remote-encoding multi-method method user host rem-enc)
5385 (tramp-message 10 "Using remote decoding %s" rem-dec)
5386 (tramp-set-remote-decoding multi-method method user host rem-dec)
5387 (tramp-message 10 "Using local encoding %s" loc-enc)
5388 (tramp-set-local-encoding multi-method method user host loc-enc)
5389 (tramp-message 10 "Using local decoding %s" loc-dec)
5390 (tramp-set-local-decoding multi-method method user host loc-dec))))
5392 (defun tramp-call-local-coding-command (cmd input output)
5393 "Call the local encoding or decoding command.
5394 If CMD contains \"%s\", provide input file INPUT there in command.
5395 Otherwise, INPUT is passed via standard input.
5396 INPUT can also be nil which means `/dev/null'.
5397 OUTPUT can be a string (which specifies a filename), or t (which
5398 means standard output and thus the current buffer), or nil (which
5399 means discard it)."
5400 (call-process
5401 tramp-encoding-shell ;program
5402 (when (and input (not (string-match "%s" cmd)))
5403 input) ;input
5404 (if (eq output t) t nil) ;output
5405 nil ;redisplay
5406 tramp-encoding-command-switch
5407 ;; actual shell command
5408 (concat
5409 (if (string-match "%s" cmd) (format cmd input) cmd)
5410 (if (stringp output) (concat "> " output) ""))))
5412 (defun tramp-maybe-open-connection (multi-method method user host)
5413 "Maybe open a connection to HOST, logging in as USER, using METHOD.
5414 Does not do anything if a connection is already open, but re-opens the
5415 connection if a previous connection has died for some reason."
5416 (let ((p (get-buffer-process
5417 (tramp-get-buffer multi-method method user host)))
5418 last-cmd-time)
5419 ;; If too much time has passed since last command was sent, look
5420 ;; whether process is still alive. If it isn't, kill it. When
5421 ;; using ssh, it can sometimes happen that the remote end has hung
5422 ;; up but the local ssh client doesn't recognize this until it
5423 ;; tries to send some data to the remote end. So that's why we
5424 ;; try to send a command from time to time, then look again
5425 ;; whether the process is really alive.
5426 (save-excursion
5427 (set-buffer (tramp-get-buffer multi-method method user host))
5428 (when (and tramp-last-cmd-time
5429 (> (tramp-time-diff (current-time) tramp-last-cmd-time) 60)
5430 p (processp p) (memq (process-status p) '(run open)))
5431 (tramp-send-command
5432 multi-method method user host "echo are you awake" nil t)
5433 (unless (tramp-wait-for-output 10)
5434 (delete-process p)
5435 (setq p nil))
5436 (erase-buffer)))
5437 (unless (and p (processp p) (memq (process-status p) '(run open)))
5438 (when (and p (processp p))
5439 (delete-process p))
5440 (funcall (tramp-get-connection-function
5441 multi-method
5442 (tramp-find-method multi-method method user host)
5443 user host)
5444 multi-method method user host))))
5446 (defun tramp-send-command
5447 (multi-method method user host command &optional noerase neveropen)
5448 "Send the COMMAND to USER at HOST (logged in using METHOD).
5449 Erases temporary buffer before sending the command (unless NOERASE
5450 is true).
5451 If optional seventh arg NEVEROPEN is non-nil, never try to open the
5452 connection. This is meant to be used from
5453 `tramp-maybe-open-connection' only."
5454 (or neveropen
5455 (tramp-maybe-open-connection multi-method method user host))
5456 (setq tramp-last-cmd-time (current-time))
5457 (when tramp-debug-buffer
5458 (save-excursion
5459 (set-buffer (tramp-get-debug-buffer multi-method method user host))
5460 (goto-char (point-max))
5461 (tramp-insert-with-face 'bold (format "$ %s\n" command))))
5462 (let ((proc nil))
5463 (set-buffer (tramp-get-buffer multi-method method user host))
5464 (unless noerase (erase-buffer))
5465 (setq proc (get-buffer-process (current-buffer)))
5466 (process-send-string proc
5467 (concat command tramp-rsh-end-of-line))))
5469 (defun tramp-send-command-internal
5470 (multi-method method user host command &optional msg)
5471 "Send command to remote host and wait for success.
5472 Sends COMMAND, then waits 30 seconds for shell prompt."
5473 (tramp-send-command multi-method method user host command t t)
5474 (when msg
5475 (tramp-message 9 "Waiting 30s for %s..." msg))
5476 (tramp-barf-if-no-shell-prompt
5477 nil 30
5478 "Couldn't `%s', see buffer `%s'" command (buffer-name)))
5480 (defun tramp-wait-for-output (&optional timeout)
5481 "Wait for output from remote rsh command."
5482 (let ((proc (get-buffer-process (current-buffer)))
5483 (found nil)
5484 (start-time (current-time))
5485 (end-of-output (concat "^"
5486 (regexp-quote tramp-end-of-output)
5487 "\r?$")))
5488 ;; Algorithm: get waiting output. See if last line contains
5489 ;; end-of-output sentinel. If not, wait a bit and again get
5490 ;; waiting output. Repeat until timeout expires or end-of-output
5491 ;; sentinel is seen. Will hang if timeout is nil and
5492 ;; end-of-output sentinel never appears.
5493 (save-match-data
5494 (cond (timeout
5495 ;; Work around an XEmacs bug, where the timeout expires
5496 ;; faster than it should. This degenerates into polling
5497 ;; for buggy XEmacsen, but oh, well.
5498 (while (and (not found)
5499 (< (tramp-time-diff (current-time) start-time)
5500 timeout))
5501 (with-timeout (timeout)
5502 (while (not found)
5503 (accept-process-output proc 1)
5504 (goto-char (point-max))
5505 (forward-line -1)
5506 (setq found (looking-at end-of-output))))))
5508 (while (not found)
5509 (accept-process-output proc 1)
5510 (goto-char (point-max))
5511 (forward-line -1)
5512 (setq found (looking-at end-of-output))))))
5513 ;; At this point, either the timeout has expired or we have found
5514 ;; the end-of-output sentinel.
5515 (when found
5516 (goto-char (point-max))
5517 (forward-line -2)
5518 (delete-region (point) (point-max)))
5519 ;; Add output to debug buffer if appropriate.
5520 (when tramp-debug-buffer
5521 (append-to-buffer
5522 (tramp-get-debug-buffer tramp-current-multi-method tramp-current-method
5523 tramp-current-user tramp-current-host)
5524 (point-min) (point-max))
5525 (when (not found)
5526 (save-excursion
5527 (set-buffer
5528 (tramp-get-debug-buffer tramp-current-multi-method tramp-current-method
5529 tramp-current-user tramp-current-host))
5530 (goto-char (point-max))
5531 (insert "[[Remote prompt `" end-of-output "' not found"
5532 (if timeout (format " in %d secs" timeout) "")
5533 "]]"))))
5534 (goto-char (point-min))
5535 ;; Return value is whether end-of-output sentinel was found.
5536 found))
5538 (defun tramp-match-string-list (&optional string)
5539 "Returns list of all match strings.
5540 That is, (list (match-string 0) (match-string 1) ...), according to the
5541 number of matches."
5542 (let* ((nmatches (/ (length (match-data)) 2))
5543 (i (- nmatches 1))
5544 (res nil))
5545 (while (>= i 0)
5546 (setq res (cons (match-string i string) res))
5547 (setq i (- i 1)))
5548 res))
5550 (defun tramp-send-command-and-check (multi-method method user host command
5551 &optional subshell)
5552 "Run COMMAND and check its exit status.
5553 MULTI-METHOD and METHOD specify how to log in (as USER) to the remote HOST.
5554 Sends `echo $?' along with the COMMAND for checking the exit status. If
5555 COMMAND is nil, just sends `echo $?'. Returns the exit status found.
5557 If the optional argument SUBSHELL is non-nil, the command is executed in
5558 a subshell, ie surrounded by parentheses."
5559 (tramp-send-command multi-method method user host
5560 (concat (if subshell "( " "")
5561 command
5562 (if command " 2>/dev/null; " "")
5563 "echo tramp_exit_status $?"
5564 (if subshell " )" " ")))
5565 (tramp-wait-for-output)
5566 (goto-char (point-max))
5567 (unless (search-backward "tramp_exit_status " nil t)
5568 (error "Couldn't find exit status of `%s'" command))
5569 (skip-chars-forward "^ ")
5570 (read (current-buffer)))
5572 (defun tramp-barf-unless-okay (multi-method method user host command subshell
5573 signal fmt &rest args)
5574 "Run COMMAND, check exit status, throw error if exit status not okay.
5575 Similar to `tramp-send-command-and-check' but accepts two more arguments
5576 FMT and ARGS which are passed to `error'."
5577 (unless (zerop (tramp-send-command-and-check
5578 multi-method method user host command subshell))
5579 ;; CCC: really pop-to-buffer? Maybe it's appropriate to be more
5580 ;; silent.
5581 (pop-to-buffer (current-buffer))
5582 (funcall 'signal signal (apply 'format fmt args))))
5584 ;; It seems that Tru64 Unix does not like it if long strings are sent
5585 ;; to it in one go. (This happens when sending the Perl
5586 ;; `file-attributes' implementation, for instance.) Therefore, we
5587 ;; have this function which waits a bit at each line.
5588 (defun tramp-send-string
5589 (multi-method method user host string)
5590 "Send the STRING to USER at HOST using METHOD.
5592 The STRING is expected to use Unix line-endings, but the lines sent to
5593 the remote host use line-endings as defined in the variable
5594 `tramp-rsh-end-of-line'."
5595 (let ((proc (get-buffer-process
5596 (tramp-get-buffer multi-method method user host))))
5597 (unless proc
5598 (error "Can't send string to remote host -- not logged in"))
5599 ;; debug message
5600 (when tramp-debug-buffer
5601 (save-excursion
5602 (set-buffer (tramp-get-debug-buffer multi-method method user host))
5603 (goto-char (point-max))
5604 (tramp-insert-with-face 'bold (format "$ %s\n" string))))
5605 ;; replace "\n" by `tramp-rsh-end-of-line'
5606 (setq string
5607 (mapconcat 'identity
5608 (split-string string "\n")
5609 tramp-rsh-end-of-line))
5610 (unless (or (string= string "")
5611 (string-equal (substring string -1) tramp-rsh-end-of-line))
5612 (setq string (concat string tramp-rsh-end-of-line)))
5613 ;; send the string
5614 (if (and tramp-chunksize (not (zerop tramp-chunksize)))
5615 (let ((pos 0)
5616 (end (length string)))
5617 (while (< pos end)
5618 (tramp-message-for-buffer
5619 multi-method method user host 10
5620 "Sending chunk from %s to %s"
5621 pos (min (+ pos tramp-chunksize) end))
5622 (process-send-string
5623 proc (substring string pos (min (+ pos tramp-chunksize) end)))
5624 (setq pos (+ pos tramp-chunksize))
5625 (sleep-for 0.1)))
5626 (process-send-string proc string))))
5628 (defun tramp-send-eof (multi-method method user host)
5629 "Send EOF to the remote end.
5630 METHOD, HOST and USER specify the connection."
5631 (let ((proc (get-buffer-process
5632 (tramp-get-buffer multi-method method user host))))
5633 (unless proc
5634 (error "Can't send EOF to remote host -- not logged in"))
5635 (process-send-eof proc)))
5636 ; (process-send-string proc "\^D")))
5638 (defun tramp-kill-process (multi-method method user host)
5639 "Kill the connection process used by Tramp.
5640 MULTI-METHOD, METHOD, USER, and HOST specify the connection."
5641 (let ((proc (get-buffer-process
5642 (tramp-get-buffer multi-method method user host))))
5643 (kill-process proc)))
5645 (defun tramp-discard-garbage-erase-buffer (p multi-method method user host)
5646 "Erase buffer, then discard subsequent garbage.
5647 If `tramp-discard-garbage' is nil, just erase buffer."
5648 (if (not tramp-discard-garbage)
5649 (erase-buffer)
5650 (while (prog1 (erase-buffer) (accept-process-output p 0.25))
5651 (when tramp-debug-buffer
5652 (save-excursion
5653 (set-buffer (tramp-get-debug-buffer multi-method method user host))
5654 (goto-char (point-max))
5655 (tramp-insert-with-face
5656 'bold (format "Additional characters detected\n")))))))
5658 (defun tramp-mode-string-to-int (mode-string)
5659 "Converts a ten-letter `drwxrwxrwx'-style mode string into mode bits."
5660 (let* ((mode-chars (string-to-vector mode-string))
5661 (owner-read (aref mode-chars 1))
5662 (owner-write (aref mode-chars 2))
5663 (owner-execute-or-setid (aref mode-chars 3))
5664 (group-read (aref mode-chars 4))
5665 (group-write (aref mode-chars 5))
5666 (group-execute-or-setid (aref mode-chars 6))
5667 (other-read (aref mode-chars 7))
5668 (other-write (aref mode-chars 8))
5669 (other-execute-or-sticky (aref mode-chars 9)))
5670 (save-match-data
5671 (logior
5672 (case owner-read
5673 (?r (tramp-octal-to-decimal "00400")) (?- 0)
5674 (t (error "Second char `%c' must be one of `r-'" owner-read)))
5675 (case owner-write
5676 (?w (tramp-octal-to-decimal "00200")) (?- 0)
5677 (t (error "Third char `%c' must be one of `w-'" owner-write)))
5678 (case owner-execute-or-setid
5679 (?x (tramp-octal-to-decimal "00100"))
5680 (?S (tramp-octal-to-decimal "04000"))
5681 (?s (tramp-octal-to-decimal "04100"))
5682 (?- 0)
5683 (t (error "Fourth char `%c' must be one of `xsS-'"
5684 owner-execute-or-setid)))
5685 (case group-read
5686 (?r (tramp-octal-to-decimal "00040")) (?- 0)
5687 (t (error "Fifth char `%c' must be one of `r-'" group-read)))
5688 (case group-write
5689 (?w (tramp-octal-to-decimal "00020")) (?- 0)
5690 (t (error "Sixth char `%c' must be one of `w-'" group-write)))
5691 (case group-execute-or-setid
5692 (?x (tramp-octal-to-decimal "00010"))
5693 (?S (tramp-octal-to-decimal "02000"))
5694 (?s (tramp-octal-to-decimal "02010"))
5695 (?- 0)
5696 (t (error "Seventh char `%c' must be one of `xsS-'"
5697 group-execute-or-setid)))
5698 (case other-read
5699 (?r (tramp-octal-to-decimal "00004")) (?- 0)
5700 (t (error "Eighth char `%c' must be one of `r-'" other-read)))
5701 (case other-write
5702 (?w (tramp-octal-to-decimal "00002")) (?- 0)
5703 (t (error "Nineth char `%c' must be one of `w-'" other-write)))
5704 (case other-execute-or-sticky
5705 (?x (tramp-octal-to-decimal "00001"))
5706 (?T (tramp-octal-to-decimal "01000"))
5707 (?t (tramp-octal-to-decimal "01001"))
5708 (?- 0)
5709 (t (error "Tenth char `%c' must be one of `xtT-'"
5710 other-execute-or-sticky)))))))
5713 (defun tramp-file-mode-from-int (mode)
5714 "Turn an integer representing a file mode into an ls(1)-like string."
5715 (let ((type (cdr (assoc (logand (lsh mode -12) 15) tramp-file-mode-type-map)))
5716 (user (logand (lsh mode -6) 7))
5717 (group (logand (lsh mode -3) 7))
5718 (other (logand (lsh mode -0) 7))
5719 (suid (> (logand (lsh mode -9) 4) 0))
5720 (sgid (> (logand (lsh mode -9) 2) 0))
5721 (sticky (> (logand (lsh mode -9) 1) 0)))
5722 (setq user (tramp-file-mode-permissions user suid "s"))
5723 (setq group (tramp-file-mode-permissions group sgid "s"))
5724 (setq other (tramp-file-mode-permissions other sticky "t"))
5725 (concat type user group other)))
5728 (defun tramp-file-mode-permissions (perm suid suid-text)
5729 "Convert a permission bitset into a string.
5730 This is used internally by `tramp-file-mode-from-int'."
5731 (let ((r (> (logand perm 4) 0))
5732 (w (> (logand perm 2) 0))
5733 (x (> (logand perm 1) 0)))
5734 (concat (or (and r "r") "-")
5735 (or (and w "w") "-")
5736 (or (and suid x suid-text) ; suid, execute
5737 (and suid (upcase suid-text)) ; suid, !execute
5738 (and x "x") "-")))) ; !suid
5741 (defun tramp-decimal-to-octal (i)
5742 "Return a string consisting of the octal digits of I.
5743 Not actually used. Use `(format \"%o\" i)' instead?"
5744 (cond ((< i 0) (error "Cannot convert negative number to octal"))
5745 ((not (integerp i)) (error "Cannot convert non-integer to octal"))
5746 ((zerop i) "0")
5747 (t (concat (tramp-decimal-to-octal (/ i 8))
5748 (number-to-string (% i 8))))))
5751 ;;(defun tramp-octal-to-decimal (ostr)
5752 ;; "Given a string of octal digits, return a decimal number."
5753 ;; (cond ((null ostr) 0)
5754 ;; ((string= "" ostr) 0)
5755 ;; (t (let ((last (aref ostr (1- (length ostr))))
5756 ;; (rest (substring ostr 0 (1- (length ostr)))))
5757 ;; (unless (and (>= last ?0)
5758 ;; (<= last ?7))
5759 ;; (error "Not an octal digit: %c" last))
5760 ;; (+ (- last ?0) (* 8 (tramp-octal-to-decimal rest)))))))
5761 ;; Kudos to Gerd Moellmann for this suggestion.
5762 (defun tramp-octal-to-decimal (ostr)
5763 "Given a string of octal digits, return a decimal number."
5764 (let ((x (or ostr "")))
5765 ;; `save-match' is in `tramp-mode-string-to-int' which calls this.
5766 (unless (string-match "\\`[0-7]*\\'" x)
5767 (error "Non-octal junk in string `%s'" x))
5768 (string-to-number ostr 8)))
5770 (defun tramp-shell-case-fold (string)
5771 "Converts STRING to shell glob pattern which ignores case."
5772 (mapconcat
5773 (lambda (c)
5774 (if (equal (downcase c) (upcase c))
5775 (vector c)
5776 (format "[%c%c]" (downcase c) (upcase c))))
5777 string
5778 ""))
5781 ;; ------------------------------------------------------------
5782 ;; -- TRAMP file names --
5783 ;; ------------------------------------------------------------
5784 ;; Conversion functions between external representation and
5785 ;; internal data structure. Convenience functions for internal
5786 ;; data structure.
5788 (defstruct tramp-file-name multi-method method user host localname)
5790 (defun tramp-tramp-file-p (name)
5791 "Return t iff NAME is a tramp file."
5792 (save-match-data
5793 (string-match tramp-file-name-regexp name)))
5795 ;; HHH: Changed. Used to assign the return value of (user-login-name)
5796 ;; to the `user' part of the structure if a user name was not
5797 ;; provided, now it assigns nil.
5798 (defun tramp-dissect-file-name (name)
5799 "Return an `tramp-file-name' structure.
5800 The structure consists of remote method, remote user, remote host and
5801 localname (file name on remote host)."
5802 (save-match-data
5803 (let* ((match (string-match (nth 0 tramp-file-name-structure) name))
5804 (method
5805 ; single-hop
5806 (if match (match-string (nth 1 tramp-file-name-structure) name)
5807 ; maybe multi-hop
5808 (string-match
5809 (format (nth 0 tramp-multi-file-name-structure)
5810 (nth 0 tramp-multi-file-name-hop-structure)) name)
5811 (match-string (nth 1 tramp-multi-file-name-structure) name))))
5812 (if (and method (member method tramp-multi-methods))
5813 ;; If it's a multi method, the file name structure contains
5814 ;; arrays of method, user and host.
5815 (tramp-dissect-multi-file-name name)
5816 ;; Normal method. First, find out default method.
5817 (unless match (error "Not a tramp file name: %s" name))
5818 (let ((user (match-string (nth 2 tramp-file-name-structure) name))
5819 (host (match-string (nth 3 tramp-file-name-structure) name))
5820 (localname (match-string (nth 4 tramp-file-name-structure) name)))
5821 (make-tramp-file-name
5822 :multi-method nil
5823 :method method
5824 :user (or user nil)
5825 :host host
5826 :localname localname))))))
5828 (defun tramp-find-default-method (user host)
5829 "Look up the right method to use in `tramp-default-method-alist'."
5830 (let ((choices tramp-default-method-alist)
5831 (method tramp-default-method)
5832 item)
5833 (while choices
5834 (setq item (pop choices))
5835 (when (and (string-match (nth 0 item) (or host ""))
5836 (string-match (nth 1 item) (or user "")))
5837 (setq method (nth 2 item))
5838 (setq choices nil)))
5839 method))
5841 (defun tramp-find-method (multi-method method user host)
5842 "Return the right method string to use.
5843 This is MULTI-METHOD, if non-nil. Otherwise, it is METHOD, if non-nil.
5844 If both MULTI-METHOD and METHOD are nil, do a lookup in
5845 `tramp-default-method-alist'."
5846 (or multi-method method (tramp-find-default-method user host)))
5848 ;; HHH: Not Changed. Multi method. Will probably not handle the case where
5849 ;; a user name is not provided in the "file name" very well.
5850 (defun tramp-dissect-multi-file-name (name)
5851 "Not implemented yet."
5852 (let ((regexp (nth 0 tramp-multi-file-name-structure))
5853 (method-index (nth 1 tramp-multi-file-name-structure))
5854 (hops-index (nth 2 tramp-multi-file-name-structure))
5855 (localname-index (nth 3 tramp-multi-file-name-structure))
5856 (hop-regexp (nth 0 tramp-multi-file-name-hop-structure))
5857 (hop-method-index (nth 1 tramp-multi-file-name-hop-structure))
5858 (hop-user-index (nth 2 tramp-multi-file-name-hop-structure))
5859 (hop-host-index (nth 3 tramp-multi-file-name-hop-structure))
5860 method hops len hop-methods hop-users hop-hosts localname)
5861 (unless (string-match (format regexp hop-regexp) name)
5862 (error "Not a multi tramp file name: %s" name))
5863 (setq method (match-string method-index name))
5864 (setq hops (match-string hops-index name))
5865 (setq len (/ (length (match-data t)) 2))
5866 (when (< localname-index 0) (incf localname-index len))
5867 (setq localname (match-string localname-index name))
5868 (let ((index 0))
5869 (while (string-match hop-regexp hops index)
5870 (setq index (match-end 0))
5871 (setq hop-methods
5872 (cons (match-string hop-method-index hops) hop-methods))
5873 (setq hop-users
5874 (cons (match-string hop-user-index hops) hop-users))
5875 (setq hop-hosts
5876 (cons (match-string hop-host-index hops) hop-hosts))))
5877 (make-tramp-file-name
5878 :multi-method method
5879 :method (apply 'vector (reverse hop-methods))
5880 :user (apply 'vector (reverse hop-users))
5881 :host (apply 'vector (reverse hop-hosts))
5882 :localname localname)))
5884 (defun tramp-make-tramp-file-name (multi-method method user host localname)
5885 "Constructs a tramp file name from METHOD, USER, HOST and LOCALNAME."
5886 (if multi-method
5887 (tramp-make-tramp-multi-file-name multi-method method user host localname)
5888 (format-spec
5889 (concat tramp-prefix-format
5890 (when method (concat "%m" tramp-postfix-single-method-format))
5891 (when user (concat "%u" tramp-postfix-user-format))
5892 (when host (concat "%h" tramp-postfix-host-format))
5893 (when localname (concat "%p")))
5894 `((?m . ,method) (?u . ,user) (?h . ,host) (?p . ,localname)))))
5896 ;; CCC: Henrik Holm: Not Changed. Multi Method. What should be done
5897 ;; with this when USER is nil?
5898 (defun tramp-make-tramp-multi-file-name (multi-method method user host localname)
5899 "Constructs a tramp file name for a multi-hop method."
5900 (unless tramp-make-multi-tramp-file-format
5901 (error "`tramp-make-multi-tramp-file-format' is nil"))
5902 (let* ((prefix-format (nth 0 tramp-make-multi-tramp-file-format))
5903 (hop-format (nth 1 tramp-make-multi-tramp-file-format))
5904 (localname-format (nth 2 tramp-make-multi-tramp-file-format))
5905 (prefix (format-spec prefix-format `((?m . ,multi-method))))
5906 (hops "")
5907 (localname (format-spec localname-format `((?p . ,localname))))
5908 (i 0)
5909 (len (length method)))
5910 (while (< i len)
5911 (let ((m (aref method i)) (u (aref user i)) (h (aref host i)))
5912 (setq hops (concat hops (format-spec hop-format
5913 `((?m . ,m) (?u . ,u) (?h . ,h)))))
5914 (incf i)))
5915 (concat prefix hops localname)))
5917 (defun tramp-make-copy-program-file-name (user host localname)
5918 "Create a file name suitable to be passed to `rcp' and workalikes."
5919 (if user
5920 (format "%s@%s:%s" user host localname)
5921 (format "%s:%s" host localname)))
5923 (defun tramp-method-out-of-band-p (multi-method method user host)
5924 "Return t if this is an out-of-band method, nil otherwise.
5925 It is important to check for this condition, since it is not possible
5926 to enter a password for the `tramp-copy-program'."
5927 (tramp-get-copy-program
5928 multi-method
5929 (tramp-find-method multi-method method user host)
5930 user host))
5932 ;; Variables local to connection.
5934 (defun tramp-get-ls-command (multi-method method user host)
5935 (save-excursion
5936 (tramp-maybe-open-connection multi-method method user host)
5937 (set-buffer (tramp-get-buffer multi-method method user host))
5938 tramp-ls-command))
5940 (defun tramp-get-test-groks-nt (multi-method method user host)
5941 (save-excursion
5942 (tramp-maybe-open-connection multi-method method user host)
5943 (set-buffer (tramp-get-buffer multi-method method user host))
5944 tramp-test-groks-nt))
5946 (defun tramp-get-file-exists-command (multi-method method user host)
5947 (save-excursion
5948 (tramp-maybe-open-connection multi-method method user host)
5949 (set-buffer (tramp-get-buffer multi-method method user host))
5950 tramp-file-exists-command))
5952 (defun tramp-get-remote-perl (multi-method method user host)
5953 (tramp-get-connection-property "perl" nil multi-method method user host))
5955 (defun tramp-get-remote-ln (multi-method method user host)
5956 (tramp-get-connection-property "ln" nil multi-method method user host))
5958 ;; Get a property of a TRAMP connection.
5959 (defun tramp-get-connection-property
5960 (property default multi-method method user host)
5961 "Get the named property for the connection.
5962 If the value is not set for the connection, return `default'"
5963 (tramp-maybe-open-connection multi-method method user host)
5964 (with-current-buffer (tramp-get-buffer multi-method method user host)
5965 (let (error)
5966 (condition-case nil
5967 (symbol-value (intern (concat "tramp-connection-property-" property)))
5968 (error default)))))
5970 ;; Set a property of a TRAMP connection.
5971 (defun tramp-set-connection-property
5972 (property value multi-method method user host)
5973 "Set the named property of a TRAMP connection."
5974 (tramp-maybe-open-connection multi-method method user host)
5975 (with-current-buffer (tramp-get-buffer multi-method method user host)
5976 (set (make-local-variable
5977 (intern (concat "tramp-connection-property-" property)))
5978 value)))
5980 ;; Some predefined connection properties.
5981 (defun tramp-set-remote-encoding (multi-method method user host rem-enc)
5982 (tramp-set-connection-property "remote-encoding" rem-enc
5983 multi-method method user host))
5984 (defun tramp-get-remote-encoding (multi-method method user host)
5985 (tramp-get-connection-property "remote-encoding" nil
5986 multi-method method user host))
5988 (defun tramp-set-remote-decoding (multi-method method user host rem-dec)
5989 (tramp-set-connection-property "remote-decoding" rem-dec
5990 multi-method method user host))
5991 (defun tramp-get-remote-decoding (multi-method method user host)
5992 (tramp-get-connection-property "remote-decoding" nil
5993 multi-method method user host))
5995 (defun tramp-set-local-encoding (multi-method method user host loc-enc)
5996 (tramp-set-connection-property "local-encoding" loc-enc
5997 multi-method method user host))
5998 (defun tramp-get-local-encoding (multi-method method user host)
5999 (tramp-get-connection-property "local-encoding" nil
6000 multi-method method user host))
6002 (defun tramp-set-local-decoding (multi-method method user host loc-dec)
6003 (tramp-set-connection-property "local-decoding" loc-dec
6004 multi-method method user host))
6005 (defun tramp-get-local-decoding (multi-method method user host)
6006 (tramp-get-connection-property "local-decoding" nil
6007 multi-method method user host))
6011 (defun tramp-get-connection-function (multi-method method user host)
6012 (second (or (assoc 'tramp-connection-function
6013 (assoc (tramp-find-method multi-method method user host)
6014 tramp-methods))
6015 (error "Method `%s' didn't specify a connection function"
6016 (or multi-method method)))))
6018 (defun tramp-get-remote-sh (multi-method method user host)
6019 (second (or (assoc 'tramp-remote-sh
6020 (assoc (tramp-find-method multi-method method user host)
6021 tramp-methods))
6022 (error "Method `%s' didn't specify a remote shell"
6023 (or multi-method method)))))
6025 (defun tramp-get-login-program (multi-method method user host)
6026 (second (or (assoc 'tramp-login-program
6027 (assoc (tramp-find-method multi-method method user host)
6028 tramp-methods))
6029 (error "Method `%s' didn't specify a login program"
6030 (or multi-method method)))))
6032 (defun tramp-get-login-args (multi-method method user host)
6033 (second (or (assoc 'tramp-login-args
6034 (assoc (tramp-find-method multi-method method user host)
6035 tramp-methods))
6036 (error "Method `%s' didn't specify login args"
6037 (or multi-method method)))))
6039 (defun tramp-get-copy-program (multi-method method user host)
6040 (second (or (assoc 'tramp-copy-program
6041 (assoc (tramp-find-method multi-method method user host)
6042 tramp-methods))
6043 (error "Method `%s' didn't specify a copy program"
6044 (or multi-method method)))))
6046 (defun tramp-get-copy-args (multi-method method user host)
6047 (second (or (assoc 'tramp-copy-args
6048 (assoc (tramp-find-method multi-method method user host)
6049 tramp-methods))
6050 (error "Method `%s' didn't specify copy args"
6051 (or multi-method method)))))
6053 (defun tramp-get-copy-keep-date-arg (multi-method method user host)
6054 (second (or (assoc 'tramp-copy-keep-date-arg
6055 (assoc (tramp-find-method multi-method method user host)
6056 tramp-methods))
6057 (error "Method `%s' didn't specify `keep-date' arg for tramp"
6058 (or multi-method method)))))
6060 ;; Auto saving to a special directory.
6062 (defun tramp-make-auto-save-file-name (fn)
6063 "Returns a file name in `tramp-auto-save-directory' for autosaving this file."
6064 (when tramp-auto-save-directory
6065 (unless (file-exists-p tramp-auto-save-directory)
6066 (make-directory tramp-auto-save-directory t)))
6067 ;; jka-compr doesn't like auto-saving, so by appending "~" to the
6068 ;; file name we make sure that jka-compr isn't used for the
6069 ;; auto-save file.
6070 (let ((buffer-file-name (expand-file-name
6071 (tramp-subst-strs-in-string '(("_" . "|")
6072 ("/" . "_a")
6073 (":" . "_b")
6074 ("|" . "__")
6075 ("[" . "_l")
6076 ("]" . "_r"))
6078 tramp-auto-save-directory)))
6079 (make-auto-save-file-name)))
6081 (defadvice make-auto-save-file-name
6082 (around tramp-advice-make-auto-save-file-name () activate)
6083 "Invoke `tramp-make-auto-save-file-name' for tramp files."
6084 (if (and (buffer-file-name) (tramp-tramp-file-p (buffer-file-name))
6085 tramp-auto-save-directory)
6086 (setq ad-return-value
6087 (tramp-make-auto-save-file-name (buffer-file-name)))
6088 ad-do-it))
6090 (defun tramp-subst-strs-in-string (alist string)
6091 "Replace all occurrences of the string FROM with TO in STRING.
6092 ALIST is of the form ((FROM . TO) ...)."
6093 (save-match-data
6094 (while alist
6095 (let* ((pr (car alist))
6096 (from (car pr))
6097 (to (cdr pr)))
6098 (while (string-match (regexp-quote from) string)
6099 (setq string (replace-match to t t string)))
6100 (setq alist (cdr alist))))
6101 string))
6103 (defun tramp-insert-with-face (face string)
6104 "Insert text with a specific face."
6105 (let ((start (point)))
6106 (insert string)
6107 (add-text-properties start (point) (list 'face face))))
6109 ;; ------------------------------------------------------------
6110 ;; -- Compatibility functions section --
6111 ;; ------------------------------------------------------------
6113 (defun tramp-temporary-file-directory ()
6114 "Return name of directory for temporary files (compat function).
6115 For Emacs, this is the variable `temporary-file-directory', for XEmacs
6116 this is the function `temp-directory'."
6117 (cond ((boundp 'temporary-file-directory)
6118 (symbol-value 'temporary-file-directory))
6119 ((fboundp 'temp-directory)
6120 (funcall (symbol-function 'temp-directory))) ;pacify byte-compiler
6121 ((let ((d (getenv "TEMP"))) (and d (file-directory-p d)))
6122 (file-name-as-directory (getenv "TEMP")))
6123 ((let ((d (getenv "TMP"))) (and d (file-directory-p d)))
6124 (file-name-as-directory (getenv "TMP")))
6125 ((let ((d (getenv "TMPDIR"))) (and d (file-directory-p d)))
6126 (file-name-as-directory (getenv "TMPDIR")))
6127 ((file-exists-p "c:/temp") (file-name-as-directory "c:/temp"))
6128 (t (message (concat "Neither `temporary-file-directory' nor "
6129 "`temp-directory' is defined -- using /tmp."))
6130 (file-name-as-directory "/tmp"))))
6132 (defun tramp-read-passwd (prompt)
6133 "Read a password from user (compat function).
6134 Invokes `read-passwd' if that is defined, else `ange-ftp-read-passwd'."
6135 (apply
6136 (if (fboundp 'read-passwd) #'read-passwd #'ange-ftp-read-passwd)
6137 (list prompt)))
6139 (defun tramp-time-diff (t1 t2)
6140 "Return the difference between the two times, in seconds.
6141 T1 and T2 are time values (as returned by `current-time' for example).
6143 NOTE: This function will fail if the time difference is too large to
6144 fit in an integer."
6145 ;; Pacify byte-compiler with `symbol-function'.
6146 (cond ((and (fboundp 'subtract-time)
6147 (fboundp 'float-time))
6148 (funcall (symbol-function 'float-time)
6149 (funcall (symbol-function 'subtract-time) t1 t2)))
6150 ((and (fboundp 'subtract-time)
6151 (fboundp 'time-to-seconds))
6152 (funcall (symbol-function 'time-to-seconds)
6153 (funcall (symbol-function 'subtract-time) t1 t2)))
6154 ((fboundp 'itimer-time-difference)
6155 (floor (funcall
6156 (symbol-function 'itimer-time-difference)
6157 (if (< (length t1) 3) (append t1 '(0)) t1)
6158 (if (< (length t2) 3) (append t2 '(0)) t2))))
6160 ;; snarfed from Emacs 21 time-date.el; combining
6161 ;; time-to-seconds and subtract-time
6162 (let ((time (let ((borrow (< (cadr t1) (cadr t2))))
6163 (list (- (car t1) (car t2) (if borrow 1 0))
6164 (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2))))))
6165 (+ (* (car time) 65536.0)
6166 (cadr time)
6167 (/ (or (nth 2 time) 0) 1000000.0))))))
6169 (defun tramp-coding-system-change-eol-conversion (coding-system eol-type)
6170 "Return a coding system like CODING-SYSTEM but with given EOL-TYPE.
6171 EOL-TYPE can be one of `dos', `unix', or `mac'."
6172 (cond ((fboundp 'coding-system-change-eol-conversion)
6173 (apply #'coding-system-change-eol-conversion
6174 (list coding-system eol-type)))
6175 ((fboundp 'subsidiary-coding-system)
6176 (apply
6177 #'subsidiary-coding-system
6178 (list coding-system
6179 (cond ((eq eol-type 'dos) 'crlf)
6180 ((eq eol-type 'unix) 'lf)
6181 ((eq eol-type 'mac) 'cr)
6183 (error "Unknown EOL-TYPE `%s', must be %s"
6184 eol-type
6185 "`dos', `unix', or `mac'"))))))
6186 (t (error "Can't change EOL conversion -- is MULE missing?"))))
6188 (defun tramp-split-string (string pattern)
6189 "Like `split-string' but omit empty strings.
6190 In Emacs, (split-string \"/foo/bar\" \"/\") returns (\"foo\" \"bar\").
6191 This is, the first, empty, element is omitted. In XEmacs, the first
6192 element is not omitted.
6194 Note: this function has been written for `tramp-handle-file-truename'.
6195 If you want to use it for something else, you'll have to check whether
6196 it does the right thing."
6197 (delete "" (split-string string pattern)))
6199 ;; ------------------------------------------------------------
6200 ;; -- Kludges section --
6201 ;; ------------------------------------------------------------
6203 ;; Currently (as of Emacs 20.5), the function `shell-quote-argument'
6204 ;; does not deal well with newline characters. Newline is replaced by
6205 ;; backslash newline. But if, say, the string `a backslash newline b'
6206 ;; is passed to a shell, the shell will expand this into "ab",
6207 ;; completely omitting the newline. This is not what was intended.
6208 ;; It does not appear to be possible to make the function
6209 ;; `shell-quote-argument' work with newlines without making it
6210 ;; dependent on the shell used. But within this package, we know that
6211 ;; we will always use a Bourne-like shell, so we use an approach which
6212 ;; groks newlines.
6214 ;; The approach is simple: we call `shell-quote-argument', then
6215 ;; massage the newline part of the result.
6217 ;; This function should produce a string which is grokked by a Unix
6218 ;; shell, even if the Emacs is running on Windows. Since this is the
6219 ;; kludges section, we bind `system-type' in such a way that
6220 ;; `shell-quote-arguments' behaves as if on Unix.
6222 ;; Thanks to Mario DeWeerd for the hint that it is sufficient for this
6223 ;; function to work with Bourne-like shells.
6225 ;; CCC: This function should be rewritten so that
6226 ;; `shell-quote-argument' is not used. This way, we are safe from
6227 ;; changes in `shell-quote-argument'.
6228 (defun tramp-shell-quote-argument (s)
6229 "Similar to `shell-quote-argument', but groks newlines.
6230 Only works for Bourne-like shells."
6231 (let ((system-type 'not-windows))
6232 (save-match-data
6233 (let ((result (shell-quote-argument s))
6234 (nl (regexp-quote (format "\\%s" tramp-rsh-end-of-line))))
6235 (when (and (>= (length result) 2)
6236 (string= (substring result 0 2) "\\~"))
6237 (setq result (substring result 1)))
6238 (while (string-match nl result)
6239 (setq result (replace-match (format "'%s'" tramp-rsh-end-of-line)
6240 t t result)))
6241 result))))
6243 ;; ;; EFS hooks itself into the file name handling stuff in more places
6244 ;; ;; than just `file-name-handler-alist'. The following tells EFS to stay
6245 ;; ;; away from tramp.el file names.
6246 ;; ;;
6247 ;; ;; This is needed because EFS installs (efs-dired-before-readin) into
6248 ;; ;; 'dired-before-readin-hook'. This prevents EFS from opening an FTP
6249 ;; ;; connection to help it's dired process. Not that I have any real
6250 ;; ;; idea *why* this is helpful to dired.
6251 ;; ;;
6252 ;; ;; Anyway, this advice fixes the problem (with a sledgehammer :)
6253 ;; ;;
6254 ;; ;; Daniel Pittman <daniel@danann.net>
6255 ;; ;;
6256 ;; ;; CCC: when the other defadvice calls have disappeared, make sure
6257 ;; ;; not to call defadvice unless it's necessary. How do we find out whether
6258 ;; ;; it is necessary? (featurep 'efs) is surely the wrong way --
6259 ;; ;; EFS might nicht be loaded yet.
6260 ;; (defadvice efs-ftp-path (around dont-match-tramp-localname activate protect)
6261 ;; "Cause efs-ftp-path to fail when the path is a TRAMP localname."
6262 ;; (if (tramp-tramp-file-p (ad-get-arg 0))
6263 ;; nil
6264 ;; ad-do-it))
6266 ;; We currently (sometimes) use "[" and "]" in the filename format.
6267 ;; This means that Emacs wants to expand wildcards if
6268 ;; `find-file-wildcards' is non-nil, and then barfs because no
6269 ;; expansion could be found. We detect this situation and do
6270 ;; something really awful: we have `file-expand-wildcards' return the
6271 ;; original filename if it can't expand anything. Let's just hope
6272 ;; that this doesn't break anything else.
6273 ;; CCC: This check is now also really awful; we should search all
6274 ;; of the filename format, not just the prefix.
6275 (when (string-match "\\[" tramp-prefix-format)
6276 (defadvice file-expand-wildcards (around tramp-fix activate)
6277 (let ((name (ad-get-arg 0)))
6278 (if (tramp-tramp-file-p name)
6279 ;; If it's a Tramp file, dissect it and look if wildcards
6280 ;; need to be expanded at all.
6281 (let ((v (tramp-dissect-file-name name)))
6282 (if (string-match "[[*?]" (tramp-file-name-localname v))
6283 (let ((res ad-do-it))
6284 (setq ad-return-value (or res (list name))))
6285 (setq ad-return-value (list name))))
6286 ;; If it is not a Tramp file, just run the original function.
6287 (let ((res ad-do-it))
6288 (setq ad-return-value (or res (list name)))))))
6291 ;; Tramp version is useful in a number of situations.
6293 (defun tramp-version (arg)
6294 "Print version number of tramp.el in minibuffer or current buffer."
6295 (interactive "P")
6296 (if arg (insert tramp-version) (message tramp-version)))
6298 ;; Make the `reporter` functionality available for making bug reports about
6299 ;; the package. A most useful piece of code.
6301 (unless (fboundp 'reporter-submit-bug-report)
6302 (autoload 'reporter-submit-bug-report "reporter"))
6304 (defun tramp-bug ()
6305 "Submit a bug report to the TRAMP developers."
6306 (interactive)
6307 (require 'reporter)
6308 (let ((reporter-prompt-for-summary-p t))
6309 (reporter-submit-bug-report
6310 tramp-bug-report-address ; to-address
6311 (format "tramp (%s)" tramp-version) ; package name and version
6312 `(;; Current state
6313 tramp-ls-command
6314 tramp-test-groks-nt
6315 tramp-file-exists-command
6316 tramp-current-multi-method
6317 tramp-current-method
6318 tramp-current-user
6319 tramp-current-host
6321 ;; System defaults
6322 tramp-auto-save-directory ; vars to dump
6323 tramp-default-method
6324 tramp-rsh-end-of-line
6325 tramp-password-end-of-line
6326 tramp-remote-path
6327 tramp-login-prompt-regexp
6328 tramp-password-prompt-regexp
6329 tramp-wrong-passwd-regexp
6330 tramp-yesno-prompt-regexp
6331 tramp-yn-prompt-regexp
6332 tramp-temp-name-prefix
6333 tramp-file-name-structure
6334 tramp-file-name-regexp
6335 tramp-multi-file-name-structure
6336 tramp-multi-file-name-hop-structure
6337 tramp-multi-methods
6338 tramp-multi-connection-function-alist
6339 tramp-methods
6340 tramp-end-of-output
6341 tramp-coding-commands
6342 tramp-actions-before-shell
6343 tramp-multi-actions
6344 tramp-terminal-type
6345 tramp-shell-prompt-pattern
6346 tramp-chunksize
6348 ;; Non-tramp variables of interest
6349 shell-prompt-pattern
6350 backup-by-copying
6351 backup-by-copying-when-linked
6352 backup-by-copying-when-mismatch
6353 ,(when (boundp 'backup-by-copying-when-privileged-mismatch)
6354 'backup-by-copying-when-privileged-mismatch)
6355 file-name-handler-alist)
6356 nil ; pre-hook
6357 nil ; post-hook
6359 Enter your bug report in this message, including as much detail as you
6360 possibly can about the problem, what you did to cause it and what the
6361 local and remote machines are.
6363 If you can give a simple set of instructions to make this bug happen
6364 reliably, please include those. Thank you for helping kill bugs in
6365 TRAMP.
6367 Another useful thing to do is to put (setq tramp-debug-buffer t) in
6368 the ~/.emacs file and to repeat the bug. Then, include the contents
6369 of the *tramp/foo* buffer and the *debug tramp/foo* buffer in your bug
6370 report.
6372 --bug report follows this line--
6373 ")))
6375 (defalias 'tramp-submit-bug 'tramp-bug)
6377 (provide 'tramp)
6379 ;; Make sure that we get integration with the VC package.
6380 ;; When it is loaded, we need to pull in the integration module.
6381 ;; This must come after (provide 'tramp) because tramp-vc.el
6382 ;; requires tramp.
6383 (eval-after-load "vc"
6384 '(require 'tramp-vc))
6386 ;;; TODO:
6388 ;; * Allow putting passwords in the filename.
6389 ;; This should be implemented via a general mechanism to add
6390 ;; parameters in filenames. There is currently a kludge for
6391 ;; putting the port number into the filename for ssh and ftp
6392 ;; files. This could be subsumed by the new mechanism as well.
6393 ;; Another approach is to read a netrc file like ~/.authinfo
6394 ;; from Gnus.
6395 ;; * Handle nonlocal exits such as C-g.
6396 ;; * Autodetect if remote `ls' groks the "--dired" switch.
6397 ;; * Add fallback for inline encodings. This should be used
6398 ;; if the remote end doesn't support mimencode or a similar program.
6399 ;; For reading files from the remote host, we can just parse the output
6400 ;; of `od -b'. For writing files to the remote host, we construct
6401 ;; a shell program which contains only "safe" ascii characters
6402 ;; and which writes the right bytes to the file. We can use printf(1)
6403 ;; or "echo -e" or the printf function in awk and use octal escapes
6404 ;; for the "dangerous" characters. The null byte might be a problem.
6405 ;; On some systems, the octal escape doesn't work. So we try the following
6406 ;; two commands to write a null byte:
6407 ;; dd if=/dev/zero bs=1 count=1
6408 ;; echo | tr '\n' '\000'
6409 ;; * Separate local `tramp-coding-commands' from remote ones. Connect
6410 ;; the two via a format which can be `uu' or `b64'. Then we can search
6411 ;; for the right local commands and the right remote commands separately.
6412 ;; * Cooperate with PCL-CVS. It uses start-process, which doesn't
6413 ;; work for remote files.
6414 ;; * Rewrite `tramp-shell-quote-argument' to abstain from using
6415 ;; `shell-quote-argument'.
6416 ;; * Completion gets confused when you leave out the method name.
6417 ;; * Support `dired-compress-file' filename handler.
6418 ;; * In Emacs 21, `insert-directory' shows total number of bytes used
6419 ;; by the files in that directory. Add this here.
6420 ;; * Avoid screen blanking when hitting `g' in dired. (Eli Tziperman)
6421 ;; * Make ffap.el grok Tramp filenames. (Eli Tziperman)
6422 ;; * When logging in, keep looking for questions according to an alist
6423 ;; and then invoke the right function.
6424 ;; * Case-insensitive filename completion. (Norbert Goevert.)
6425 ;; * Running CVS remotely doesn't appear to work right. It thinks
6426 ;; files are locked by somebody else even if I'm the locking user.
6427 ;; Sometimes, one gets `No CVSROOT specified' errors from CVS.
6428 ;; (Skip Montanaro)
6429 ;; * Don't use globbing for directories with many files, as this is
6430 ;; likely to produce long command lines, and some shells choke on
6431 ;; long command lines.
6432 ;; * Find out about the new auto-save mechanism in Emacs 21 and
6433 ;; do the right thing.
6434 ;; * `vc-directory' does not work. It never displays any files, even
6435 ;; if it does show files when run locally.
6436 ;; * Allow correction of passwords, if the remote end allows this.
6437 ;; (Mark Hershberger)
6438 ;; * Make sure permissions of tmp file are good.
6439 ;; (Nelson Minar <nelson@media.mit.edu>)
6440 ;; * Grok passwd prompts with scp? (David Winter
6441 ;; <winter@nevis1.nevis.columbia.edu>). Maybe just do `ssh -l user
6442 ;; host', then wait a while for the passwd or passphrase prompt. If
6443 ;; there is one, remember the passwd/phrase.
6444 ;; * How to deal with MULE in `insert-file-contents' and `write-region'?
6445 ;; * Do asynchronous `shell-command's.
6446 ;; * Grok `append' parameter for `write-region'.
6447 ;; * Test remote ksh or bash for tilde expansion in `tramp-find-shell'?
6448 ;; * abbreviate-file-name
6449 ;; * grok ~ in tramp-remote-path (Henrik Holm <henrikh@tele.ntnu.no>)
6450 ;; * `C' in dired gives error `not tramp file name'.
6451 ;; * Also allow to omit user names when doing multi-hop. Not sure yet
6452 ;; what the user names should default to, though.
6453 ;; * better error checking. At least whenever we see something
6454 ;; strange when doing zerop, we should kill the process and start
6455 ;; again. (Greg Stark)
6456 ;; * Add caching for filename completion. (Greg Stark)
6457 ;; Of course, this has issues with usability (stale cache bites)
6458 ;; -- <daniel@danann.net>
6459 ;; * Provide a local cache of old versions of remote files for the rsync
6460 ;; transfer method to use. (Greg Stark)
6461 ;; * Remove unneeded parameters from methods.
6462 ;; * Invoke rsync once for copying a whole directory hierarchy.
6463 ;; (Francesco Potort\e,Al\e(B)
6464 ;; * Should we set PATH ourselves or should we rely on the remote end
6465 ;; to do it?
6466 ;; * Do the autoconf thing.
6467 ;; * Make it work for XEmacs 20, which is missing `with-timeout'.
6468 ;; * Allow non-Unix remote systems. (More a long-term thing.)
6469 ;; * Make it work for different encodings, and for different file name
6470 ;; encodings, too. (Daniel Pittman)
6471 ;; * Change applicable functions to pass a struct tramp-file-name rather
6472 ;; than the individual items MULTI-METHOD, METHOD, USER, HOST, LOCALNAME.
6473 ;; * Implement asynchronous shell commands.
6474 ;; * Clean up unused *tramp/foo* buffers after a while. (Pete Forman)
6475 ;; * Progress reports while copying files. (Michael Kifer)
6476 ;; * `Smart' connection method that uses inline for small and out of
6477 ;; band for large files. (Michael Kifer)
6478 ;; * Don't search for perl5 and perl. Instead, only search for perl and
6479 ;; then look if it's the right version (with `perl -v').
6480 ;; * When editing a remote CVS controlled file as a different user, VC
6481 ;; gets confused about the file locking status. Try to find out why
6482 ;; the workaround doesn't work.
6483 ;; * When user is running ssh-agent, it would be useful to add the
6484 ;; passwords typed by the user to that agent. This way, the next time
6485 ;; round, the users don't have to type all this in again.
6486 ;; This would be especially useful for start-process, I think.
6487 ;; An easy way to implement start-process is to open a second shell
6488 ;; connection which is inconvenient if the user has to reenter
6489 ;; passwords.
6490 ;; * Change `copy-file' to grok the case where the filename handler
6491 ;; for the source and the target file are different. Right now,
6492 ;; it looks at the source file and then calls that handler, if
6493 ;; there is one. But since ange-ftp, for instance, does not know
6494 ;; about Tramp, it does not do the right thing if the target file
6495 ;; name is a Tramp name.
6496 ;; * Username and hostname completion.
6497 ;; ** If `partial-completion-mode' isn't loaded, "/foo:bla" tries to
6498 ;; connect to host "blabla" already if that host is unique. No idea
6499 ;; how to suppress. Maybe not an essential problem.
6500 ;; ** Try to avoid usage of `last-input-event' in `tramp-completion-mode'.
6501 ;; ** Extend `tramp-get-completion-su' for NIS and shadow passwords.
6502 ;; ** Unify `tramp-parse-{rhosts,shosts,sconfig,hosts,passwd,netrc}'.
6503 ;; Code is nearly identical.
6504 ;; ** Decide whiche files to take for searching user/host names depending on
6505 ;; operating system (windows-nt) in `tramp-completion-function-alist'.
6506 ;; ** Enhance variables for debug.
6507 ;; ** Implement "/multi:" completion.
6508 ;; ** Add a learning mode for completion. Make results persistent.
6510 ;; Functions for file-name-handler-alist:
6511 ;; diff-latest-backup-file -- in diff.el
6512 ;; dired-compress-file
6513 ;; dired-uncache -- this will be needed when we do insert-directory caching
6514 ;; file-name-as-directory -- use primitive?
6515 ;; file-name-directory -- use primitive?
6516 ;; file-name-nondirectory -- use primitive?
6517 ;; file-name-sans-versions -- use primitive?
6518 ;; file-newer-than-file-p
6519 ;; find-backup-file-name
6520 ;; get-file-buffer -- use primitive
6521 ;; load
6522 ;; unhandled-file-name-directory
6523 ;; vc-registered
6525 ;;; tramp.el ends here