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