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