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