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