Pass no argument to gnus-float-time rather than current-time.
[bpt/emacs.git] / lisp / net / tramp.el
CommitLineData
b1a2b924 1;;; tramp.el --- Transparent Remote Access, Multiple Protocol
fb7933a3 2
5fd6d89f 3;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
b96e6899 4;; 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
fb7933a3 5
cbd12ed7
GM
6;; (copyright statements below in code to be updated with the above notice)
7
cdd44874 8;; Author: Kai Großjohann <kai.grossjohann@gmx.net>
d2a2c17f 9;; Michael Albinus <michael.albinus@gmx.de>
fb7933a3
KG
10;; Keywords: comm, processes
11
12;; This file is part of GNU Emacs.
13
874a927a 14;; GNU Emacs is free software: you can redistribute it and/or modify
fb7933a3 15;; it under the terms of the GNU General Public License as published by
874a927a
GM
16;; the Free Software Foundation, either version 3 of the License, or
17;; (at your option) any later version.
fb7933a3
KG
18
19;; GNU Emacs is distributed in the hope that it will be useful,
20;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22;; GNU General Public License for more details.
23
24;; You should have received a copy of the GNU General Public License
874a927a 25;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
fb7933a3
KG
26
27;;; Commentary:
28
29;; This package provides remote file editing, similar to ange-ftp.
30;; The difference is that ange-ftp uses FTP to transfer files between
31;; the local and the remote host, whereas tramp.el uses a combination
32;; of rsh and rcp or other work-alike programs, such as ssh/scp.
33;;
b1a2b924 34;; For more detailed instructions, please see the info file.
fb7933a3
KG
35;;
36;; Notes:
37;; -----
bf247b6e 38;;
00d6fd04
MA
39;; This package only works for Emacs 21.1 and higher, and for XEmacs 21.4
40;; and higher. For XEmacs 21, you need the package `fsf-compat' for
41;; the `with-timeout' macro.)
fb7933a3 42;;
fb7933a3
KG
43;; Also see the todo list at the bottom of this file.
44;;
b1a2b924 45;; The current version of Tramp can be retrieved from the following URL:
340b8d4f 46;; http://ftp.gnu.org/gnu/tramp/
fb7933a3
KG
47;;
48;; There's a mailing list for this, as well. Its name is:
340b8d4f
MA
49;; tramp-devel@gnu.org
50;; You can use the Web to subscribe, under the following URL:
51;; http://lists.gnu.org/mailman/listinfo/tramp-devel
fb7933a3
KG
52;;
53;; For the adventurous, the current development sources are available
54;; via CVS. You can find instructions about this at the following URL:
c62c9d08 55;; http://savannah.gnu.org/projects/tramp/
fb7933a3
KG
56;; Click on "CVS" in the navigation bar near the top.
57;;
58;; Don't forget to put on your asbestos longjohns, first!
59
60;;; Code:
61
ccb4a481
MA
62;; Since Emacs 23.1, loading messages have been disabled during
63;; autoload. However, loading Tramp takes a while, and it could
64;; happen while typing a filename in the minibuffer. Therefore, Tramp
65;; shall inform about.
66(when (and load-in-progress (null (current-message)))
67 (message "Loading tramp..."))
68
b1a2b924
KG
69;; The Tramp version number and bug report address, as prepared by configure.
70(require 'trampver)
a69c01a0 71(add-hook 'tramp-unload-hook
aa485f7c
MA
72 (lambda ()
73 (when (featurep 'trampver)
74 (unload-feature 'trampver 'force))))
a69c01a0 75
9e6ab520 76(require 'tramp-compat)
94be87e8 77(add-hook 'tramp-unload-hook
aa485f7c
MA
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
aa485f7c
MA
108 (lambda ()
109 (when (featurep 'tramp-cache)
110 (unload-feature 'tramp-cache 'force))))
00d6fd04 111
16674e4f
KG
112(autoload 'tramp-uuencode-region "tramp-uu"
113 "Implementation of `uuencode' in Lisp.")
a69c01a0 114(add-hook 'tramp-unload-hook
aa485f7c
MA
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
70c11b0b 143 ;; tramp-gvfs needs D-Bus messages. Available since Emacs 23
8e754ea2
MA
144 ;; on some system types. We don't call `dbus-ping', because
145 ;; this would load dbus.el.
70c11b0b 146 (when (and (featurep 'dbusbind)
2ac33804
MA
147 (condition-case nil
148 (funcall 'dbus-get-unique-name :session)
149 (error nil))
70c11b0b
MA
150 (tramp-compat-process-running-p "gvfs-fuse-daemon"))
151 'tramp-gvfs)
152
9c13938d
MA
153 ;; Load gateways. It needs `make-network-process' from Emacs 22.
154 (when (functionp 'make-network-process) 'tramp-gw)))
155
156 (when feature
70c11b0b
MA
157 ;; We have used just some basic tests, whether a package shall
158 ;; be added. There might still be other errors during loading,
159 ;; which we will catch here.
160 (catch 'tramp-loading
161 (require feature)
162 (add-hook 'tramp-unload-hook
163 `(lambda ()
164 (when (featurep (quote ,feature))
165 (unload-feature (quote ,feature) 'force)))))
166 (unless (featurep feature)
167 (message "Loading %s failed, ignoring this package" feature)))))
fb7933a3
KG
168
169;;; User Customizable Internal Variables:
170
171(defgroup tramp nil
172 "Edit remote files with a combination of rsh and rcp or similar programs."
589d30dd 173 :group 'files
bf247b6e 174 :version "22.1")
fb7933a3 175
2e271195
MA
176;; Maybe we need once a real Tramp mode, with key bindings etc.
177;;;###autoload
178(defcustom tramp-mode t
179 "*Whether Tramp is enabled.
180If it is set to nil, all remote file names are used literally."
181 :group 'tramp
182 :type 'boolean)
183
00d6fd04 184(defcustom tramp-verbose 3
94be87e8 185 "*Verbosity level for Tramp.
00d6fd04
MA
186Any level x includes messages for all levels 1 .. x-1. The levels are
187
188 0 silent (no tramp messages at all)
189 1 errors
190 2 warnings
191 3 connection to remote hosts (default level)
192 4 activities
193 5 internal
194 6 sent and received strings
195 7 file caching
196 8 connection properties
19710 traces (huge)."
fb7933a3
KG
198 :group 'tramp
199 :type 'integer)
200
38c65fca
KG
201;; Emacs case
202(eval-and-compile
203 (when (boundp 'backup-directory-alist)
204 (defcustom tramp-backup-directory-alist nil
205 "Alist of filename patterns and backup directory names.
206Each element looks like (REGEXP . DIRECTORY), with the same meaning like
207in `backup-directory-alist'. If a Tramp file is backed up, and DIRECTORY
208is a local file name, the backup directory is prepended with Tramp file
00d6fd04 209name prefix \(method, user, host\) of file.
38c65fca
KG
210
211\(setq tramp-backup-directory-alist backup-directory-alist\)
212
213gives the same backup policy for Tramp files on their hosts like the
214policy for local files."
215 :group 'tramp
216 :type '(repeat (cons (regexp :tag "Regexp matching filename")
217 (directory :tag "Backup directory name"))))))
218
219;; XEmacs case. We cannot check for `bkup-backup-directory-info', because
220;; the package "backup-dir" might not be loaded yet.
221(eval-and-compile
222 (when (featurep 'xemacs)
223 (defcustom tramp-bkup-backup-directory-info nil
224 "*Alist of (FILE-REGEXP BACKUP-DIR OPTIONS ...))
225It has the same meaning like `bkup-backup-directory-info' from package
226`backup-dir'. If a Tramp file is backed up, and BACKUP-DIR is a local
227file name, the backup directory is prepended with Tramp file name prefix
00d6fd04 228\(method, user, host\) of file.
38c65fca
KG
229
230\(setq tramp-bkup-backup-directory-info bkup-backup-directory-info\)
231
232gives the same backup policy for Tramp files on their hosts like the
233policy for local files."
bf247b6e 234 :type '(repeat
38c65fca
KG
235 (list (regexp :tag "File regexp")
236 (string :tag "Backup Dir")
237 (set :inline t
238 (const ok-create)
239 (const full-path)
240 (const prepend-name)
241 (const search-upward))))
242 :group 'tramp)))
243
fb7933a3
KG
244(defcustom tramp-auto-save-directory nil
245 "*Put auto-save files in this directory, if set.
246The idea is to use a local directory so that auto-saving is faster."
247 :group 'tramp
00d6fd04 248 :type '(choice (const nil) string))
fb7933a3 249
16674e4f
KG
250(defcustom tramp-encoding-shell
251 (if (memq system-type '(windows-nt))
252 (getenv "COMSPEC")
253 "/bin/sh")
254 "*Use this program for encoding and decoding commands on the local host.
255This shell is used to execute the encoding and decoding command on the
256local host, so if you want to use `~' in those commands, you should
257choose a shell here which groks tilde expansion. `/bin/sh' normally
258does not understand tilde expansion.
259
260For encoding and deocding, commands like the following are executed:
261
262 /bin/sh -c COMMAND < INPUT > OUTPUT
263
264This variable can be used to change the \"/bin/sh\" part. See the
00d6fd04 265variable `tramp-encoding-command-switch' for the \"-c\" part.
fb7933a3
KG
266
267Note that this variable is not used for remote commands. There are
268mechanisms in tramp.el which automatically determine the right shell to
269use for the remote host."
270 :group 'tramp
271 :type '(file :must-match t))
272
16674e4f
KG
273(defcustom tramp-encoding-command-switch
274 (if (string-match "cmd\\.exe" tramp-encoding-shell)
275 "/c"
276 "-c")
277 "*Use this switch together with `tramp-encoding-shell' for local commands.
278See the variable `tramp-encoding-shell' for more information."
279 :group 'tramp
280 :type 'string)
281
00d6fd04
MA
282(defcustom tramp-copy-size-limit 10240
283 "*The maximum file size where inline copying is preferred over an out-of-the-band copy."
16674e4f 284 :group 'tramp
00d6fd04 285 :type 'integer)
90dc758d 286
00d6fd04
MA
287(defcustom tramp-terminal-type "dumb"
288 "*Value of TERM environment variable for logging in to remote host.
289Because Tramp wants to parse the output of the remote shell, it is easily
290confused by ANSI color escape sequences and suchlike. Often, shell init
291files conditionalize this setup based on the TERM environment variable."
90dc758d 292 :group 'tramp
00d6fd04 293 :type 'string)
90dc758d 294
00d6fd04
MA
295(defvar tramp-methods
296 `(("rcp" (tramp-login-program "rsh")
297 (tramp-login-args (("%h") ("-l" "%u")))
298 (tramp-remote-sh "/bin/sh")
299 (tramp-copy-program "rcp")
300 (tramp-copy-args (("-p" "%k")))
301 (tramp-copy-keep-date t)
302 (tramp-password-end-of-line nil))
303 ("scp" (tramp-login-program "ssh")
2296b54d 304 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
305 ("-e" "none")))
306 (tramp-remote-sh "/bin/sh")
307 (tramp-copy-program "scp")
308 (tramp-copy-args (("-P" "%p") ("-p" "%k") ("-q")))
309 (tramp-copy-keep-date t)
310 (tramp-password-end-of-line nil)
311 (tramp-gw-args (("-o"
312 "GlobalKnownHostsFile=/dev/null")
313 ("-o" "UserKnownHostsFile=/dev/null")
314 ("-o" "StrictHostKeyChecking=no")))
315 (tramp-default-port 22))
316 ("scp1" (tramp-login-program "ssh")
2296b54d 317 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
318 ("-1" "-e" "none")))
319 (tramp-remote-sh "/bin/sh")
320 (tramp-copy-program "scp")
321 (tramp-copy-args (("-1") ("-P" "%p") ("-p" "%k")
322 ("-q")))
323 (tramp-copy-keep-date t)
324 (tramp-password-end-of-line nil)
325 (tramp-gw-args (("-o"
326 "GlobalKnownHostsFile=/dev/null")
327 ("-o" "UserKnownHostsFile=/dev/null")
328 ("-o" "StrictHostKeyChecking=no")))
329 (tramp-default-port 22))
330 ("scp2" (tramp-login-program "ssh")
2296b54d 331 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
332 ("-2" "-e" "none")))
333 (tramp-remote-sh "/bin/sh")
334 (tramp-copy-program "scp")
335 (tramp-copy-args (("-2") ("-P" "%p") ("-p" "%k")
336 ("-q")))
337 (tramp-copy-keep-date t)
338 (tramp-password-end-of-line nil)
339 (tramp-gw-args (("-o"
340 "GlobalKnownHostsFile=/dev/null")
341 ("-o" "UserKnownHostsFile=/dev/null")
342 ("-o" "StrictHostKeyChecking=no")))
343 (tramp-default-port 22))
344 ("scp1_old"
345 (tramp-login-program "ssh1")
346 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
347 ("-e" "none")))
348 (tramp-remote-sh "/bin/sh")
349 (tramp-copy-program "scp1")
350 (tramp-copy-args (("-p" "%k")))
351 (tramp-copy-keep-date t)
352 (tramp-password-end-of-line nil))
353 ("scp2_old"
354 (tramp-login-program "ssh2")
355 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
356 ("-e" "none")))
357 (tramp-remote-sh "/bin/sh")
358 (tramp-copy-program "scp2")
359 (tramp-copy-args (("-p" "%k")))
360 (tramp-copy-keep-date t)
361 (tramp-password-end-of-line nil))
362 ("sftp" (tramp-login-program "ssh")
363 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
364 ("-e" "none")))
365 (tramp-remote-sh "/bin/sh")
366 (tramp-copy-program "sftp")
367 (tramp-copy-args nil)
368 (tramp-copy-keep-date nil)
369 (tramp-password-end-of-line nil))
370 ("rsync" (tramp-login-program "ssh")
371 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
372 ("-e" "none")))
373 (tramp-remote-sh "/bin/sh")
374 (tramp-copy-program "rsync")
375 (tramp-copy-args (("-e" "ssh") ("-t" "%k")))
376 (tramp-copy-keep-date t)
377 (tramp-password-end-of-line nil))
946a5aeb
MA
378 ("rsyncc" (tramp-login-program "ssh")
379 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
380 ("-o" "ControlPath=%t.%%r@%%h:%%p")
381 ("-o" "ControlMaster=yes")
382 ("-e" "none")))
383 (tramp-remote-sh "/bin/sh")
384 (tramp-copy-program "rsync")
385 (tramp-copy-args (("-t" "%k")))
386 (tramp-copy-env (("RSYNC_RSH")
387 (,(concat
388 "ssh"
389 " -o ControlPath=%t.%%r@%%h:%%p"
390 " -o ControlMaster=auto"))))
391 (tramp-copy-keep-date t)
392 (tramp-password-end-of-line nil))
00d6fd04
MA
393 ("remcp" (tramp-login-program "remsh")
394 (tramp-login-args (("%h") ("-l" "%u")))
395 (tramp-remote-sh "/bin/sh")
396 (tramp-copy-program "rcp")
397 (tramp-copy-args (("-p" "%k")))
398 (tramp-copy-keep-date t)
399 (tramp-password-end-of-line nil))
400 ("rsh" (tramp-login-program "rsh")
401 (tramp-login-args (("%h") ("-l" "%u")))
402 (tramp-remote-sh "/bin/sh")
403 (tramp-copy-program nil)
404 (tramp-copy-args nil)
405 (tramp-copy-keep-date nil)
406 (tramp-password-end-of-line nil))
407 ("ssh" (tramp-login-program "ssh")
2296b54d 408 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
409 ("-e" "none")))
410 (tramp-remote-sh "/bin/sh")
411 (tramp-copy-program nil)
412 (tramp-copy-args nil)
413 (tramp-copy-keep-date nil)
414 (tramp-password-end-of-line nil)
415 (tramp-gw-args (("-o"
416 "GlobalKnownHostsFile=/dev/null")
417 ("-o" "UserKnownHostsFile=/dev/null")
418 ("-o" "StrictHostKeyChecking=no")))
419 (tramp-default-port 22))
420 ("ssh1" (tramp-login-program "ssh")
2296b54d 421 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
422 ("-1" "-e" "none")))
423 (tramp-remote-sh "/bin/sh")
424 (tramp-copy-program nil)
425 (tramp-copy-args nil)
426 (tramp-copy-keep-date nil)
427 (tramp-password-end-of-line nil)
428 (tramp-gw-args (("-o"
429 "GlobalKnownHostsFile=/dev/null")
430 ("-o" "UserKnownHostsFile=/dev/null")
431 ("-o" "StrictHostKeyChecking=no")))
432 (tramp-default-port 22))
433 ("ssh2" (tramp-login-program "ssh")
2296b54d 434 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
435 ("-2" "-e" "none")))
436 (tramp-remote-sh "/bin/sh")
437 (tramp-copy-program nil)
438 (tramp-copy-args nil)
439 (tramp-copy-keep-date nil)
440 (tramp-password-end-of-line nil)
441 (tramp-gw-args (("-o"
442 "GlobalKnownHostsFile=/dev/null")
443 ("-o" "UserKnownHostsFile=/dev/null")
444 ("-o" "StrictHostKeyChecking=no")))
445 (tramp-default-port 22))
446 ("ssh1_old"
447 (tramp-login-program "ssh1")
448 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
449 ("-e" "none")))
450 (tramp-remote-sh "/bin/sh")
451 (tramp-copy-program nil)
452 (tramp-copy-args nil)
453 (tramp-copy-keep-date nil)
454 (tramp-password-end-of-line nil))
455 ("ssh2_old"
456 (tramp-login-program "ssh2")
457 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
458 ("-e" "none")))
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 ("remsh" (tramp-login-program "remsh")
465 (tramp-login-args (("%h") ("-l" "%u")))
466 (tramp-remote-sh "/bin/sh")
467 (tramp-copy-program nil)
468 (tramp-copy-args nil)
469 (tramp-copy-keep-date nil)
470 (tramp-password-end-of-line nil))
471 ("telnet"
472 (tramp-login-program "telnet")
473 (tramp-login-args (("%h") ("%p")))
474 (tramp-remote-sh "/bin/sh")
475 (tramp-copy-program nil)
476 (tramp-copy-args nil)
477 (tramp-copy-keep-date nil)
478 (tramp-password-end-of-line nil)
479 (tramp-default-port 23))
480 ("su" (tramp-login-program "su")
481 (tramp-login-args (("-") ("%u")))
482 (tramp-remote-sh "/bin/sh")
483 (tramp-copy-program nil)
484 (tramp-copy-args nil)
485 (tramp-copy-keep-date nil)
486 (tramp-password-end-of-line nil))
487 ("sudo" (tramp-login-program "sudo")
488 (tramp-login-args (("-u" "%u")
42bc9b6d 489 ("-s") ("-H") ("-p" "Password:")))
00d6fd04
MA
490 (tramp-remote-sh "/bin/sh")
491 (tramp-copy-program nil)
492 (tramp-copy-args nil)
493 (tramp-copy-keep-date nil)
494 (tramp-password-end-of-line nil))
495 ("scpc" (tramp-login-program "ssh")
2296b54d 496 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
497 ("-o" "ControlPath=%t.%%r@%%h:%%p")
498 ("-o" "ControlMaster=yes")
499 ("-e" "none")))
500 (tramp-remote-sh "/bin/sh")
501 (tramp-copy-program "scp")
502 (tramp-copy-args (("-P" "%p") ("-p" "%k") ("-q")
503 ("-o" "ControlPath=%t.%%r@%%h:%%p")
504 ("-o" "ControlMaster=auto")))
505 (tramp-copy-keep-date t)
506 (tramp-password-end-of-line nil)
507 (tramp-gw-args (("-o"
508 "GlobalKnownHostsFile=/dev/null")
509 ("-o" "UserKnownHostsFile=/dev/null")
510 ("-o" "StrictHostKeyChecking=no")))
511 (tramp-default-port 22))
512 ("scpx" (tramp-login-program "ssh")
2296b54d 513 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
514 ("-e" "none" "-t" "-t" "/bin/sh")))
515 (tramp-remote-sh "/bin/sh")
516 (tramp-copy-program "scp")
517 (tramp-copy-args (("-p" "%k")))
518 (tramp-copy-keep-date t)
519 (tramp-password-end-of-line nil)
520 (tramp-gw-args (("-o"
521 "GlobalKnownHostsFile=/dev/null")
522 ("-o" "UserKnownHostsFile=/dev/null")
523 ("-o" "StrictHostKeyChecking=no")))
524 (tramp-default-port 22))
525 ("sshx" (tramp-login-program "ssh")
2296b54d 526 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
527 ("-e" "none" "-t" "-t" "/bin/sh")))
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 nil)
533 (tramp-gw-args (("-o"
534 "GlobalKnownHostsFile=/dev/null")
535 ("-o" "UserKnownHostsFile=/dev/null")
536 ("-o" "StrictHostKeyChecking=no")))
537 (tramp-default-port 22))
538 ("krlogin"
539 (tramp-login-program "krlogin")
540 (tramp-login-args (("%h") ("-l" "%u") ("-x")))
541 (tramp-remote-sh "/bin/sh")
542 (tramp-copy-program nil)
543 (tramp-copy-args nil)
544 (tramp-copy-keep-date nil)
545 (tramp-password-end-of-line nil))
546 ("plink" (tramp-login-program "plink")
547 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
548 ("-ssh")))
549 (tramp-remote-sh "/bin/sh")
550 (tramp-copy-program nil)
551 (tramp-copy-args nil)
552 (tramp-copy-keep-date nil)
553 (tramp-password-end-of-line "xy") ;see docstring for "xy"
554 (tramp-default-port 22))
555 ("plink1"
556 (tramp-login-program "plink")
557 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
558 ("-1" "-ssh")))
559 (tramp-remote-sh "/bin/sh")
560 (tramp-copy-program nil)
561 (tramp-copy-args nil)
562 (tramp-copy-keep-date nil)
563 (tramp-password-end-of-line "xy") ;see docstring for "xy"
564 (tramp-default-port 22))
565 ("plinkx"
566 (tramp-login-program "plink")
42bc9b6d
MA
567 ;; ("%h") must be a single element, see
568 ;; `tramp-compute-multi-hops'.
569 (tramp-login-args (("-load") ("%h") ("-t")
ce3f516f
MA
570 (,(format
571 "env 'TERM=%s' 'PROMPT_COMMAND=' 'PS1=$ '"
572 tramp-terminal-type))
00d6fd04
MA
573 ("/bin/sh")))
574 (tramp-remote-sh "/bin/sh")
575 (tramp-copy-program nil)
576 (tramp-copy-args nil)
577 (tramp-copy-keep-date nil)
578 (tramp-password-end-of-line nil))
579 ("pscp" (tramp-login-program "plink")
580 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
581 ("-ssh")))
582 (tramp-remote-sh "/bin/sh")
583 (tramp-copy-program "pscp")
60f2c210 584 (tramp-copy-args (("-P" "%p") ("-scp") ("-p" "%k")))
00d6fd04
MA
585 (tramp-copy-keep-date t)
586 (tramp-password-end-of-line "xy") ;see docstring for "xy"
587 (tramp-default-port 22))
588 ("psftp" (tramp-login-program "plink")
589 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
590 ("-ssh")))
591 (tramp-remote-sh "/bin/sh")
592 (tramp-copy-program "pscp")
60f2c210 593 (tramp-copy-args (("-P" "%p") ("-sftp") ("-p" "%k")))
00d6fd04
MA
594 (tramp-copy-keep-date t)
595 (tramp-password-end-of-line "xy")) ;see docstring for "xy"
596 ("fcp" (tramp-login-program "fsh")
597 (tramp-login-args (("%h") ("-l" "%u") ("sh" "-i")))
598 (tramp-remote-sh "/bin/sh -i")
599 (tramp-copy-program "fcp")
600 (tramp-copy-args (("-p" "%k")))
601 (tramp-copy-keep-date t)
602 (tramp-password-end-of-line nil)))
fb7933a3
KG
603 "*Alist of methods for remote files.
604This is a list of entries of the form (NAME PARAM1 PARAM2 ...).
605Each NAME stands for a remote access method. Each PARAM is a
606pair of the form (KEY VALUE). The following KEYs are defined:
fb7933a3
KG
607 * `tramp-remote-sh'
608 This specifies the Bourne shell to use on the remote host. This
609 MUST be a Bourne-like shell. It is normally not necessary to set
a4aeb9a4 610 this to any value other than \"/bin/sh\": Tramp wants to use a shell
fb7933a3
KG
611 which groks tilde expansion, but it can search for it. Also note
612 that \"/bin/sh\" exists on all Unixen, this might not be true for
613 the value that you decide to use. You Have Been Warned.
b25a52cc
KG
614 * `tramp-login-program'
615 This specifies the name of the program to use for logging in to the
00d6fd04
MA
616 remote host. This may be the name of rsh or a workalike program,
617 or the name of telnet or a workalike, or the name of su or a workalike.
b25a52cc 618 * `tramp-login-args'
fb7933a3 619 This specifies the list of arguments to pass to the above
00d6fd04 620 mentioned program. Please note that this is a list of list of arguments,
fb7933a3 621 that is, normally you don't want to put \"-a -b\" or \"-f foo\"
00d6fd04
MA
622 here. Instead, you want a list (\"-a\" \"-b\"), or (\"-f\" \"foo\").
623 There are some patterns: \"%h\" in this list is replaced by the host
624 name, \"%u\" is replaced by the user name, \"%p\" is replaced by the
625 port number, and \"%%\" can be used to obtain a literal percent character.
626 If a list containing \"%h\", \"%u\" or \"%p\" is unchanged during
627 expansion (i.e. no host or no user specified), this list is not used as
628 argument. By this, arguments like (\"-l\" \"%u\") are optional.
629 \"%t\" is replaced by the temporary file name produced with
630 `tramp-make-tramp-temp-file'. \"%k\" indicates the keep-date
631 parameter of a program, if exists.
b25a52cc
KG
632 * `tramp-copy-program'
633 This specifies the name of the program to use for remotely copying
634 the file; this might be the absolute filename of rcp or the name of
635 a workalike program.
636 * `tramp-copy-args'
fb7933a3 637 This specifies the list of parameters to pass to the above mentioned
b25a52cc 638 program, the hints for `tramp-login-args' also apply here.
00d6fd04
MA
639 * `tramp-copy-keep-date'
640 This specifies whether the copying program when the preserves the
641 timestamp of the original file.
642 * `tramp-default-port'
643 The default port of a method is needed in case of gateway connections.
644 Additionally, it is used as indication which method is prepared for
645 passing gateways.
646 * `tramp-gw-args'
647 As the attribute name says, additional arguments are specified here
648 when a method is applied via a gateway.
90f8dc03
KG
649 * `tramp-password-end-of-line'
650 This specifies the string to use for terminating the line after
651 submitting the password. If this method parameter is nil, then the
652 value of the normal variable `tramp-default-password-end-of-line'
653 is used. This parameter is necessary because the \"plink\" program
654 requires any two characters after sending the password. These do
655 not have to be newline or carriage return characters. Other login
656 programs are happy with just one character, the newline character.
657 We use \"xy\" as the value for methods using \"plink\".
b25a52cc
KG
658
659What does all this mean? Well, you should specify `tramp-login-program'
660for all methods; this program is used to log in to the remote site. Then,
661there are two ways to actually transfer the files between the local and the
662remote side. One way is using an additional rcp-like program. If you want
663to do this, set `tramp-copy-program' in the method.
fb7933a3
KG
664
665Another possibility for file transfer is inline transfer, i.e. the
b25a52cc 666file is passed through the same buffer used by `tramp-login-program'. In
fb7933a3 667this case, the file contents need to be protected since the
b25a52cc 668`tramp-login-program' might use escape codes or the connection might not
fb7933a3 669be eight-bit clean. Therefore, file contents are encoded for transit.
00d6fd04
MA
670See the variables `tramp-local-coding-commands' and
671`tramp-remote-coding-commands' for details.
fb7933a3 672
16674e4f 673So, to summarize: if the method is an out-of-band method, then you
b25a52cc 674must specify `tramp-copy-program' and `tramp-copy-args'. If it is an
00d6fd04
MA
675inline method, then these two parameters should be nil. Methods which
676are fit for gateways must have `tramp-default-port' at least.
fb7933a3
KG
677
678Notes:
679
00d6fd04
MA
680When using `su' or `sudo' the phrase `open connection to a remote
681host' sounds strange, but it is used nevertheless, for consistency.
682No connection is opened to a remote host, but `su' or `sudo' is
683started on the local host. You should specify a remote host
684`localhost' or the name of the local host. Another host name is
685useful only in combination with `tramp-default-proxies-alist'.")
fb7933a3 686
b25a52cc 687(defcustom tramp-default-method
83e20b5c
MA
688 ;; An external copy method seems to be preferred, because it is much
689 ;; more performant for large files, and it hasn't too serious delays
690 ;; for small files. But it must be ensured that there aren't
691 ;; permanent password queries. Either a password agent like
692 ;; "ssh-agent" or "Pageant" shall run, or the optional password.el
693 ;; package shall be active for password caching. "scpc" would be
694 ;; another good choice because of the "ControlMaster" option, but
695 ;; this is a more modern alternative in OpenSSH 4, which cannot be
696 ;; taken as default.
00d6fd04
MA
697 (cond
698 ;; PuTTY is installed.
699 ((executable-find "pscp")
700 (if (or (fboundp 'password-read)
701 ;; Pageant is running.
70c11b0b 702 (tramp-compat-process-running-p "Pageant"))
00d6fd04
MA
703 "pscp"
704 "plink"))
705 ;; There is an ssh installation.
706 ((executable-find "scp")
707 (if (or (fboundp 'password-read)
708 ;; ssh-agent is running.
709 (getenv "SSH_AUTH_SOCK")
710 (getenv "SSH_AGENT_PID"))
711 "scp"
712 "ssh"))
713 ;; Fallback.
714 (t "ftp"))
fb7933a3 715 "*Default method to use for transferring files.
c62c9d08 716See `tramp-methods' for possibilities.
4007ba5b 717Also see `tramp-default-method-alist'."
c62c9d08
KG
718 :group 'tramp
719 :type 'string)
720
505edaeb 721(defcustom tramp-default-method-alist
4007ba5b 722 '(("\\`localhost\\'" "\\`root\\'" "su"))
00d6fd04 723 "*Default method to use for specific host/user pairs.
c62c9d08
KG
724This is an alist of items (HOST USER METHOD). The first matching item
725specifies the method to use for a file name which does not specify a
726method. HOST and USER are regular expressions or nil, which is
727interpreted as a regular expression which always matches. If no entry
728matches, the variable `tramp-default-method' takes effect.
729
730If the file name does not specify the user, lookup is done using the
731empty string for the user name.
732
733See `tramp-methods' for a list of possibilities for METHOD."
734 :group 'tramp
735 :type '(repeat (list (regexp :tag "Host regexp")
736 (regexp :tag "User regexp")
737 (string :tag "Method"))))
738
00d6fd04
MA
739(defcustom tramp-default-user
740 nil
741 "*Default user to use for transferring files.
742It is nil by default; otherwise settings in configuration files like
743\"~/.ssh/config\" would be overwritten. Also see `tramp-default-user-alist'.
744
745This variable is regarded as obsolete, and will be removed soon."
746 :group 'tramp
747 :type '(choice (const nil) string))
748
749(defcustom tramp-default-user-alist
750 `(("\\`su\\(do\\)?\\'" nil "root")
751 ("\\`r\\(em\\)?\\(cp\\|sh\\)\\|telnet\\|plink1?\\'"
752 nil ,(user-login-name)))
753 "*Default user to use for specific method/host pairs.
754This is an alist of items (METHOD HOST USER). The first matching item
755specifies the user to use for a file name which does not specify a
756user. METHOD and USER are regular expressions or nil, which is
757interpreted as a regular expression which always matches. If no entry
758matches, the variable `tramp-default-user' takes effect.
759
760If the file name does not specify the method, lookup is done using the
761empty string for the method name."
762 :group 'tramp
763 :type '(repeat (list (regexp :tag "Method regexp")
764 (regexp :tag "Host regexp")
765 (string :tag "User"))))
766
767(defcustom tramp-default-host
768 (system-name)
769 "*Default host to use for transferring files.
770Useful for su and sudo methods mostly."
771 :group 'tramp
772 :type 'string)
773
774(defcustom tramp-default-proxies-alist nil
775 "*Route to be followed for specific host/user pairs.
776This is an alist of items (HOST USER PROXY). The first matching
777item specifies the proxy to be passed for a file name located on
778a remote target matching USER@HOST. HOST and USER are regular
70c11b0b
MA
779expressions. PROXY must be a Tramp filename without a localname
780part. Method and user name on PROXY are optional, which is
781interpreted with the default values. PROXY can contain the
782patterns %h and %u, which are replaced by the strings matching
783HOST or USER, respectively.
784
785HOST, USER or PROXY could also be Lisp forms, which will be
786evaluated. The result must be a string or nil, which is
787interpreted as a regular expression which always matches."
00d6fd04 788 :group 'tramp
70c11b0b
MA
789 :type '(repeat (list (choice :tag "Host regexp" regexp sexp)
790 (choice :tag "User regexp" regexp sexp)
791 (choice :tag "Proxy remote name" string (const nil)))))
00d6fd04 792
b96e6899
MA
793(defconst tramp-local-host-regexp
794 (concat
795 "^" (regexp-opt (list "localhost" (system-name) "127\.0\.0\.1" "::1") t) "$")
796 "*Host names which are regarded as local host.")
797
16674e4f 798(defconst tramp-completion-function-alist-rsh
00d6fd04
MA
799 '((tramp-parse-rhosts "/etc/hosts.equiv")
800 (tramp-parse-rhosts "~/.rhosts"))
b25a52cc 801 "Default list of (FUNCTION FILE) pairs to be examined for rsh methods.")
16674e4f 802
16674e4f 803(defconst tramp-completion-function-alist-ssh
00d6fd04
MA
804 '((tramp-parse-rhosts "/etc/hosts.equiv")
805 (tramp-parse-rhosts "/etc/shosts.equiv")
806 (tramp-parse-shosts "/etc/ssh_known_hosts")
807 (tramp-parse-sconfig "/etc/ssh_config")
808 (tramp-parse-shostkeys "/etc/ssh2/hostkeys")
809 (tramp-parse-sknownhosts "/etc/ssh2/knownhosts")
810 (tramp-parse-rhosts "~/.rhosts")
811 (tramp-parse-rhosts "~/.shosts")
812 (tramp-parse-shosts "~/.ssh/known_hosts")
813 (tramp-parse-sconfig "~/.ssh/config")
814 (tramp-parse-shostkeys "~/.ssh2/hostkeys")
815 (tramp-parse-sknownhosts "~/.ssh2/knownhosts"))
b25a52cc 816 "Default list of (FUNCTION FILE) pairs to be examined for ssh methods.")
16674e4f 817
16674e4f 818(defconst tramp-completion-function-alist-telnet
00d6fd04 819 '((tramp-parse-hosts "/etc/hosts"))
b25a52cc 820 "Default list of (FUNCTION FILE) pairs to be examined for telnet methods.")
16674e4f 821
16674e4f 822(defconst tramp-completion-function-alist-su
00d6fd04 823 '((tramp-parse-passwd "/etc/passwd"))
b25a52cc 824 "Default list of (FUNCTION FILE) pairs to be examined for su methods.")
292ffc15 825
00d6fd04
MA
826(defconst tramp-completion-function-alist-putty
827 '((tramp-parse-putty
828 "HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions"))
829 "Default list of (FUNCTION REGISTRY) pairs to be examined for putty methods.")
830
5ec2cc41 831(defvar tramp-completion-function-alist nil
16674e4f
KG
832 "*Alist of methods for remote files.
833This is a list of entries of the form (NAME PAIR1 PAIR2 ...).
834Each NAME stands for a remote access method. Each PAIR is of the form
835\(FUNCTION FILE). FUNCTION is responsible to extract user names and host
836names from FILE for completion. The following predefined FUNCTIONs exists:
837
5ec2cc41
KG
838 * `tramp-parse-rhosts' for \"~/.rhosts\" like files,
839 * `tramp-parse-shosts' for \"~/.ssh/known_hosts\" like files,
840 * `tramp-parse-sconfig' for \"~/.ssh/config\" like files,
841 * `tramp-parse-shostkeys' for \"~/.ssh2/hostkeys/*\" like files,
842 * `tramp-parse-sknownhosts' for \"~/.ssh2/knownhosts/*\" like files,
843 * `tramp-parse-hosts' for \"/etc/hosts\" like files,
844 * `tramp-parse-passwd' for \"/etc/passwd\" like files.
845 * `tramp-parse-netrc' for \"~/.netrc\" like files.
00d6fd04 846 * `tramp-parse-putty' for PuTTY registry keys.
5ec2cc41
KG
847
848FUNCTION can also be a customer defined function. For more details see
849the info pages.")
850
851(eval-after-load "tramp"
852 '(progn
853 (tramp-set-completion-function
854 "rcp" tramp-completion-function-alist-rsh)
855 (tramp-set-completion-function
856 "scp" tramp-completion-function-alist-ssh)
857 (tramp-set-completion-function
858 "scp1" tramp-completion-function-alist-ssh)
859 (tramp-set-completion-function
860 "scp2" tramp-completion-function-alist-ssh)
861 (tramp-set-completion-function
862 "scp1_old" tramp-completion-function-alist-ssh)
863 (tramp-set-completion-function
864 "scp2_old" tramp-completion-function-alist-ssh)
865 (tramp-set-completion-function
70c11b0b 866 "rsync" tramp-completion-function-alist-ssh)
946a5aeb
MA
867 (tramp-set-completion-function
868 "rsyncc" tramp-completion-function-alist-ssh)
5ec2cc41
KG
869 (tramp-set-completion-function
870 "remcp" tramp-completion-function-alist-rsh)
871 (tramp-set-completion-function
872 "rsh" tramp-completion-function-alist-rsh)
873 (tramp-set-completion-function
874 "ssh" tramp-completion-function-alist-ssh)
875 (tramp-set-completion-function
876 "ssh1" tramp-completion-function-alist-ssh)
877 (tramp-set-completion-function
878 "ssh2" tramp-completion-function-alist-ssh)
879 (tramp-set-completion-function
880 "ssh1_old" tramp-completion-function-alist-ssh)
881 (tramp-set-completion-function
882 "ssh2_old" tramp-completion-function-alist-ssh)
883 (tramp-set-completion-function
884 "remsh" tramp-completion-function-alist-rsh)
885 (tramp-set-completion-function
886 "telnet" tramp-completion-function-alist-telnet)
887 (tramp-set-completion-function
888 "su" tramp-completion-function-alist-su)
889 (tramp-set-completion-function
890 "sudo" tramp-completion-function-alist-su)
bf247b6e 891 (tramp-set-completion-function
5ec2cc41
KG
892 "scpx" tramp-completion-function-alist-ssh)
893 (tramp-set-completion-function
894 "sshx" tramp-completion-function-alist-ssh)
895 (tramp-set-completion-function
896 "krlogin" tramp-completion-function-alist-rsh)
897 (tramp-set-completion-function
898 "plink" tramp-completion-function-alist-ssh)
899 (tramp-set-completion-function
900 "plink1" tramp-completion-function-alist-ssh)
00d6fd04
MA
901 (tramp-set-completion-function
902 "plinkx" tramp-completion-function-alist-putty)
5ec2cc41
KG
903 (tramp-set-completion-function
904 "pscp" tramp-completion-function-alist-ssh)
905 (tramp-set-completion-function
906 "fcp" tramp-completion-function-alist-ssh)))
16674e4f 907
674da028
MA
908(defconst tramp-echo-mark-marker "_echo"
909 "String marker to surround echoed commands.")
910
00d6fd04
MA
911(defconst tramp-echo-mark "_echo\b\b\b\b\b"
912 "String mark to be transmitted around shell commands.
913Used to separate their echo from the output they produce. This
914will only be used if we cannot disable remote echo via stty.
915This string must have no effect on the remote shell except for
916producing some echo which can later be detected by
674da028
MA
917`tramp-echoed-echo-mark-regexp'. Using `tramp-echo-mark-marker',
918followed by an equal number of backspaces to erase them will
919usually suffice.")
00d6fd04
MA
920
921(defconst tramp-echoed-echo-mark-regexp "_echo\\(\b\\( \b\\)?\\)\\{5\\}"
922 "Regexp which matches `tramp-echo-mark' as it gets echoed by
923the remote shell.")
924
fb7933a3
KG
925(defcustom tramp-rsh-end-of-line "\n"
926 "*String used for end of line in rsh connections.
927I don't think this ever needs to be changed, so please tell me about it
16674e4f 928if you need to change this.
90f8dc03
KG
929Also see the method parameter `tramp-password-end-of-line' and the normal
930variable `tramp-default-password-end-of-line'."
16674e4f
KG
931 :group 'tramp
932 :type 'string)
933
90f8dc03
KG
934(defcustom tramp-default-password-end-of-line
935 tramp-rsh-end-of-line
16674e4f 936 "*String used for end of line after sending a password.
90f8dc03
KG
937This variable provides the default value for the method parameter
938`tramp-password-end-of-line', see `tramp-methods' for more details.
939
16674e4f
KG
940It seems that people using plink under Windows need to send
941\"\\r\\n\" (carriage-return, then newline) after a password, but just
942\"\\n\" after all other lines. This variable can be used for the
943password, see `tramp-rsh-end-of-line' for the other cases.
944
945The default value is to use the same value as `tramp-rsh-end-of-line'."
fb7933a3
KG
946 :group 'tramp
947 :type 'string)
948
00d6fd04
MA
949;; "getconf PATH" yields:
950;; HP-UX: /usr/bin:/usr/ccs/bin:/opt/ansic/bin:/opt/langtools/bin:/opt/fortran/bin
951;; Solaris: /usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin
0664ff72 952;; GNU/Linux (Debian, Suse): /bin:/usr/bin
00d6fd04 953;; FreeBSD: /usr/bin:/bin:/usr/sbin:/sbin: - beware trailing ":"!
fb7933a3 954(defcustom tramp-remote-path
00d6fd04
MA
955 '(tramp-default-remote-path "/usr/sbin" "/usr/local/bin"
956 "/local/bin" "/local/freeware/bin" "/local/gnu/bin"
fb7933a3
KG
957 "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin")
958 "*List of directories to search for executables on remote host.
00d6fd04
MA
959For every remote host, this variable will be set buffer local,
960keeping the list of existing directories on that host.
fb7933a3
KG
961
962You can use `~' in this list, but when searching for a shell which groks
00d6fd04
MA
963tilde expansion, all directory names starting with `~' will be ignored.
964
965`Default Directories' represent the list of directories given by
966the command \"getconf PATH\". It is recommended to use this
967entry on top of this list, because these are the default
70c11b0b
MA
968directories for POSIX compatible commands.
969
970`Private Directories' are the settings of the $PATH environment,
971as given in your `~/.profile'."
00d6fd04
MA
972 :group 'tramp
973 :type '(repeat (choice
974 (const :tag "Default Directories" tramp-default-remote-path)
70c11b0b 975 (const :tag "Private Directories" tramp-own-remote-path)
00d6fd04
MA
976 (string :tag "Directory"))))
977
00d6fd04 978(defcustom tramp-remote-process-environment
a0a5183a 979 `("HISTFILE=$HOME/.tramp_history" "HISTSIZE=1" "LC_ALL=C"
00d6fd04 980 ,(concat "TERM=" tramp-terminal-type)
97c696d5
MA
981 "EMACS=t" ;; Deprecated.
982 ,(format "INSIDE_EMACS=%s,tramp:%s" emacs-version tramp-version)
00d6fd04
MA
983 "CDPATH=" "HISTORY=" "MAIL=" "MAILCHECK=" "MAILPATH="
984 "autocorrect=" "correct=")
985
986 "*List of environment variables to be set on the remote host.
987
988Each element should be a string of the form ENVVARNAME=VALUE. An
989entry ENVVARNAME= diables the corresponding environment variable,
990which might have been set in the init files like ~/.profile.
991
992Special handling is applied to the PATH environment, which should
993not be set here. Instead of, it should be set via `tramp-remote-path'."
fb7933a3
KG
994 :group 'tramp
995 :type '(repeat string))
996
997(defcustom tramp-login-prompt-regexp
bc103d00 998 ".*ogin\\( .*\\)?: *"
fb7933a3 999 "*Regexp matching login-like prompts.
bc103d00
MA
1000The regexp should match at end of buffer.
1001
1002Sometimes the prompt is reported to look like \"login as:\"."
fb7933a3
KG
1003 :group 'tramp
1004 :type 'regexp)
1005
821e6e36 1006(defcustom tramp-shell-prompt-pattern
aa485f7c
MA
1007 ;; Allow a prompt to start right after a ^M since it indeed would be
1008 ;; displayed at the beginning of the line (and Zsh uses it).
1009 "\\(?:^\\|\r\\)[^#$%>\n]*[#$%>] *\\(\e\\[[0-9;]*[a-zA-Z] *\\)*"
821e6e36
KG
1010 "Regexp to match prompts from remote shell.
1011Normally, Tramp expects you to configure `shell-prompt-pattern'
1012correctly, but sometimes it happens that you are connecting to a
1013remote host which sends a different kind of shell prompt. Therefore,
1014Tramp recognizes things matched by `shell-prompt-pattern' as prompt,
1015and also things matched by this variable. The default value of this
b25a52cc 1016variable is similar to the default value of `shell-prompt-pattern',
821e6e36
KG
1017which should work well in many cases."
1018 :group 'tramp
1019 :type 'regexp)
1020
fb7933a3 1021(defcustom tramp-password-prompt-regexp
00d6fd04 1022 "^.*\\([pP]assword\\|[pP]assphrase\\).*:\^@? *"
fb7933a3 1023 "*Regexp matching password-like prompts.
ac474af1 1024The regexp should match at end of buffer.
fb7933a3
KG
1025
1026The `sudo' program appears to insert a `^@' character into the prompt."
1027 :group 'tramp
1028 :type 'regexp)
1029
1030(defcustom tramp-wrong-passwd-regexp
b1d06e75
KG
1031 (concat "^.*"
1032 ;; These strings should be on the last line
a4aeb9a4 1033 (regexp-opt '("Permission denied"
b1d06e75
KG
1034 "Login incorrect"
1035 "Login Incorrect"
1036 "Connection refused"
27e813fe 1037 "Connection closed"
b1d06e75
KG
1038 "Sorry, try again."
1039 "Name or service not known"
00d6fd04 1040 "Host key verification failed."
70c11b0b 1041 "No supported authentication methods left to try!") t)
b1d06e75
KG
1042 ".*"
1043 "\\|"
1044 "^.*\\("
1045 ;; Here comes a list of regexes, separated by \\|
1046 "Received signal [0-9]+"
1047 "\\).*")
fb7933a3 1048 "*Regexp matching a `login failed' message.
ac474af1
KG
1049The regexp should match at end of buffer."
1050 :group 'tramp
1051 :type 'regexp)
1052
1053(defcustom tramp-yesno-prompt-regexp
3cdaec13
KG
1054 (concat
1055 (regexp-opt '("Are you sure you want to continue connecting (yes/no)?") t)
1056 "\\s-*")
1057 "Regular expression matching all yes/no queries which need to be confirmed.
ac474af1 1058The confirmation should be done with yes or no.
3cdaec13
KG
1059The regexp should match at end of buffer.
1060See also `tramp-yn-prompt-regexp'."
fb7933a3
KG
1061 :group 'tramp
1062 :type 'regexp)
1063
3cdaec13 1064(defcustom tramp-yn-prompt-regexp
658052a2
MA
1065 (concat
1066 (regexp-opt '("Store key in cache? (y/n)"
1067 "Update cached key? (y/n, Return cancels connection)") t)
1068 "\\s-*")
3cdaec13
KG
1069 "Regular expression matching all y/n queries which need to be confirmed.
1070The confirmation should be done with y or n.
1071The regexp should match at end of buffer.
1072See also `tramp-yesno-prompt-regexp'."
1073 :group 'tramp
1074 :type 'regexp)
487f4fb7
KG
1075
1076(defcustom tramp-terminal-prompt-regexp
1077 (concat "\\("
1078 "TERM = (.*)"
1079 "\\|"
1080 "Terminal type\\? \\[.*\\]"
1081 "\\)\\s-*")
1082 "Regular expression matching all terminal setting prompts.
1083The regexp should match at end of buffer.
1084The answer will be provided by `tramp-action-terminal', which see."
1085 :group 'tramp
1086 :type 'regexp)
3cdaec13 1087
01917a18
MA
1088(defcustom tramp-operation-not-permitted-regexp
1089 (concat "\\(" "preserving times.*" "\\|" "set mode" "\\)" ":\\s-*"
1090 (regexp-opt '("Operation not permitted") t))
1091 "Regular expression matching keep-date problems in (s)cp operations.
1092Copying has been performed successfully already, so this message can
1093be ignored safely."
1094 :group 'tramp
1095 :type 'regexp)
1096
6b2633cc
LH
1097(defcustom tramp-copy-failed-regexp
1098 (concat "\\(.+: "
1099 (regexp-opt '("Permission denied"
1100 "not a regular file"
1101 "is a directory"
1102 "No such file or directory") t)
1103 "\\)\\s-*")
1104 "Regular expression matching copy problems in (s)cp operations."
1105 :group 'tramp
1106 :type 'regexp)
1107
19a87064 1108(defcustom tramp-process-alive-regexp
38c65fca 1109 ""
19a87064 1110 "Regular expression indicating a process has finished.
38c65fca
KG
1111In fact this expression is empty by intention, it will be used only to
1112check regularly the status of the associated process.
07dfe738 1113The answer will be provided by `tramp-action-process-alive',
00d6fd04 1114`tramp-action-out-of-band', which see."
38c65fca
KG
1115 :group 'tramp
1116 :type 'regexp)
1117
fb7933a3
KG
1118(defcustom tramp-temp-name-prefix "tramp."
1119 "*Prefix to use for temporary files.
1120If this is a relative file name (such as \"tramp.\"), it is considered
1121relative to the directory name returned by the function
9e6ab520 1122`tramp-compat-temporary-file-directory' (which see). It may also be an
fb7933a3
KG
1123absolute file name; don't forget to include a prefix for the filename
1124part, though."
1125 :group 'tramp
1126 :type 'string)
1127
2296b54d
MA
1128(defconst tramp-temp-buffer-name " *tramp temp*"
1129 "Buffer name for a temporary buffer.
1130It shall be used in combination with `generate-new-buffer-name'.")
1131
4007ba5b 1132(defcustom tramp-sh-extra-args '(("/bash\\'" . "-norc -noprofile"))
c62c9d08
KG
1133 "*Alist specifying extra arguments to pass to the remote shell.
1134Entries are (REGEXP . ARGS) where REGEXP is a regular expression
1135matching the shell file name and ARGS is a string specifying the
1136arguments.
1137
1138This variable is only used when Tramp needs to start up another shell
1139for tilde expansion. The extra arguments should typically prevent the
1140shell from reading its init file."
1141 :group 'tramp
90f8dc03
KG
1142 ;; This might be the wrong way to test whether the widget type
1143 ;; `alist' is available. Who knows the right way to test it?
1144 :type (if (get 'alist 'widget-type)
1145 '(alist :key-type string :value-type string)
1146 '(repeat (cons string string))))
c62c9d08 1147
00d6fd04
MA
1148;; XEmacs is distributed with few Lisp packages. Further packages are
1149;; installed using EFS. If we use a unified filename format, then
1150;; Tramp is required in addition to EFS. (But why can't Tramp just
1151;; disable EFS when Tramp is loaded? Then XEmacs can ship with EFS
1152;; just like before.) Another reason for using a separate filename
1153;; syntax on XEmacs is that EFS hooks into XEmacs in many places, but
1154;; Tramp only knows how to deal with `file-name-handler-alist', not
1155;; the other places.
1156
1157;; Currently, we have the choice between 'ftp, 'sep, and 'url.
1158;;;###autoload
1159(defcustom tramp-syntax
1160 (if (featurep 'xemacs) 'sep 'ftp)
1161 "Tramp filename syntax to be used.
1162
1163It can have the following values:
1164
1165 'ftp -- Ange-FTP respective EFS like syntax (GNU Emacs default)
1166 'sep -- Syntax as defined for XEmacs (not available yet for GNU Emacs)
1167 'url -- URL-like syntax."
16674e4f 1168 :group 'tramp
00d6fd04
MA
1169 :type (if (featurep 'xemacs)
1170 '(choice (const :tag "EFS" ftp)
1171 (const :tag "XEmacs" sep)
1172 (const :tag "URL" url))
1173 '(choice (const :tag "Ange-FTP" ftp)
1174 (const :tag "URL" url))))
1175
1176(defconst tramp-prefix-format
1177 (cond ((equal tramp-syntax 'ftp) "/")
1178 ((equal tramp-syntax 'sep) "/[")
1179 ((equal tramp-syntax 'url) "/")
1180 (t (error "Wrong `tramp-syntax' defined")))
a4aeb9a4 1181 "*String matching the very beginning of Tramp file names.
00d6fd04 1182Used in `tramp-make-tramp-file-name'.")
16674e4f 1183
00d6fd04 1184(defconst tramp-prefix-regexp
16674e4f 1185 (concat "^" (regexp-quote tramp-prefix-format))
a4aeb9a4 1186 "*Regexp matching the very beginning of Tramp file names.
00d6fd04 1187Should always start with \"^\". Derived from `tramp-prefix-format'.")
16674e4f 1188
00d6fd04 1189(defconst tramp-method-regexp
16674e4f 1190 "[a-zA-Z_0-9-]+"
00d6fd04 1191 "*Regexp matching methods identifiers.")
16674e4f 1192
00d6fd04
MA
1193(defconst tramp-postfix-method-format
1194 (cond ((equal tramp-syntax 'ftp) ":")
1195 ((equal tramp-syntax 'sep) "/")
1196 ((equal tramp-syntax 'url) "://")
1197 (t (error "Wrong `tramp-syntax' defined")))
16674e4f 1198 "*String matching delimeter between method and user or host names.
00d6fd04 1199Used in `tramp-make-tramp-file-name'.")
16674e4f 1200
00d6fd04
MA
1201(defconst tramp-postfix-method-regexp
1202 (regexp-quote tramp-postfix-method-format)
16674e4f 1203 "*Regexp matching delimeter between method and user or host names.
00d6fd04 1204Derived from `tramp-postfix-method-format'.")
16674e4f 1205
00d6fd04
MA
1206(defconst tramp-user-regexp
1207 "[^:/ \t]+"
1208 "*Regexp matching user names.")
16674e4f 1209
b96e6899
MA
1210(defconst tramp-prefix-domain-format "%"
1211 "*String matching delimeter between user and domain names.")
1212
1213(defconst tramp-prefix-domain-regexp
1214 (regexp-quote tramp-prefix-domain-format)
1215 "*Regexp matching delimeter between user and domain names.
1216Derived from `tramp-prefix-domain-format'.")
1217
1218(defconst tramp-domain-regexp
70c11b0b 1219 "[-a-zA-Z0-9_.]+"
b96e6899
MA
1220 "*Regexp matching domain names.")
1221
1222(defconst tramp-user-with-domain-regexp
1223 (concat "\\(" tramp-user-regexp "\\)"
1224 tramp-prefix-domain-regexp
1225 "\\(" tramp-domain-regexp "\\)")
1226 "*Regexp matching user names with domain names.")
1227
00d6fd04 1228(defconst tramp-postfix-user-format
16674e4f
KG
1229 "@"
1230 "*String matching delimeter between user and host names.
00d6fd04 1231Used in `tramp-make-tramp-file-name'.")
16674e4f 1232
00d6fd04 1233(defconst tramp-postfix-user-regexp
16674e4f
KG
1234 (regexp-quote tramp-postfix-user-format)
1235 "*Regexp matching delimeter between user and host names.
00d6fd04
MA
1236Derived from `tramp-postfix-user-format'.")
1237
1238(defconst tramp-host-regexp
1239 "[a-zA-Z0-9_.-]+"
1240 "*Regexp matching host names.")
1241
b96e6899
MA
1242(defconst tramp-prefix-ipv6-format
1243 (cond ((equal tramp-syntax 'ftp) "[")
1244 ((equal tramp-syntax 'sep) "")
1245 ((equal tramp-syntax 'url) "[")
1246 (t (error "Wrong `tramp-syntax' defined")))
1247 "*String matching left hand side of IPv6 addresses.
1248Used in `tramp-make-tramp-file-name'.")
1249
1250(defconst tramp-prefix-ipv6-regexp
1251 (regexp-quote tramp-prefix-ipv6-format)
1252 "*Regexp matching left hand side of IPv6 addresses.
1253Derived from `tramp-prefix-ipv6-format'.")
1254
e0b6e3b9
MA
1255;; The following regexp is a bit sloppy. But it shall serve our
1256;; purposes. It covers also IPv4 mapped IPv6 addresses, like in
1257;; "::ffff:192.168.0.1".
b96e6899 1258(defconst tramp-ipv6-regexp
e0b6e3b9 1259 "\\(?:\\(?:[a-zA-Z0-9]+\\)?:\\)+[a-zA-Z0-9.]+"
b96e6899
MA
1260 "*Regexp matching IPv6 addresses.")
1261
1262(defconst tramp-postfix-ipv6-format
1263 (cond ((equal tramp-syntax 'ftp) "]")
1264 ((equal tramp-syntax 'sep) "")
1265 ((equal tramp-syntax 'url) "]")
1266 (t (error "Wrong `tramp-syntax' defined")))
1267 "*String matching right hand side of IPv6 addresses.
1268Used in `tramp-make-tramp-file-name'.")
1269
1270(defconst tramp-postfix-ipv6-regexp
1271 (regexp-quote tramp-postfix-ipv6-format)
1272 "*Regexp matching right hand side of IPv6 addresses.
1273Derived from `tramp-postfix-ipv6-format'.")
1274
00d6fd04
MA
1275(defconst tramp-prefix-port-format
1276 (cond ((equal tramp-syntax 'ftp) "#")
1277 ((equal tramp-syntax 'sep) "#")
1278 ((equal tramp-syntax 'url) ":")
1279 (t (error "Wrong `tramp-syntax' defined")))
1280 "*String matching delimeter between host names and port numbers.")
1281
1282(defconst tramp-prefix-port-regexp
1283 (regexp-quote tramp-prefix-port-format)
1284 "*Regexp matching delimeter between host names and port numbers.
1285Derived from `tramp-prefix-port-format'.")
1286
1287(defconst tramp-port-regexp
1288 "[0-9]+"
1289 "*Regexp matching port numbers.")
1290
1291(defconst tramp-host-with-port-regexp
1292 (concat "\\(" tramp-host-regexp "\\)"
1293 tramp-prefix-port-regexp
1294 "\\(" tramp-port-regexp "\\)")
1295 "*Regexp matching host names with port numbers.")
1296
1297(defconst tramp-postfix-host-format
1298 (cond ((equal tramp-syntax 'ftp) ":")
1299 ((equal tramp-syntax 'sep) "]")
1300 ((equal tramp-syntax 'url) "")
1301 (t (error "Wrong `tramp-syntax' defined")))
7432277c 1302 "*String matching delimeter between host names and localnames.
00d6fd04 1303Used in `tramp-make-tramp-file-name'.")
16674e4f 1304
00d6fd04 1305(defconst tramp-postfix-host-regexp
16674e4f 1306 (regexp-quote tramp-postfix-host-format)
7432277c 1307 "*Regexp matching delimeter between host names and localnames.
00d6fd04 1308Derived from `tramp-postfix-host-format'.")
16674e4f 1309
00d6fd04 1310(defconst tramp-localname-regexp
16674e4f 1311 ".*$"
00d6fd04 1312 "*Regexp matching localnames.")
16674e4f
KG
1313
1314;; File name format.
505edaeb 1315
00d6fd04 1316(defconst tramp-file-name-structure
16674e4f
KG
1317 (list
1318 (concat
1319 tramp-prefix-regexp
00d6fd04
MA
1320 "\\(" "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp "\\)?"
1321 "\\(" "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp "\\)?"
b96e6899
MA
1322 "\\(" "\\(" tramp-host-regexp
1323 "\\|"
1324 tramp-prefix-ipv6-regexp tramp-ipv6-regexp
1325 tramp-postfix-ipv6-regexp "\\)"
1326 "\\(" tramp-prefix-port-regexp tramp-port-regexp "\\)?" "\\)?"
00d6fd04
MA
1327 tramp-postfix-host-regexp
1328 "\\(" tramp-localname-regexp "\\)")
b96e6899 1329 2 4 5 8)
16674e4f 1330
fb7933a3 1331 "*List of five elements (REGEXP METHOD USER HOST FILE), detailing \
a4aeb9a4 1332the Tramp file name structure.
fb7933a3 1333
a4aeb9a4 1334The first element REGEXP is a regular expression matching a Tramp file
fb7933a3
KG
1335name. The regex should contain parentheses around the method name,
1336the user name, the host name, and the file name parts.
1337
1338The second element METHOD is a number, saying which pair of
1339parentheses matches the method name. The third element USER is
1340similar, but for the user name. The fourth element HOST is similar,
1341but for the host name. The fifth element FILE is for the file name.
1342These numbers are passed directly to `match-string', which see. That
1343means the opening parentheses are counted to identify the pair.
1344
00d6fd04 1345See also `tramp-file-name-regexp'.")
fb7933a3
KG
1346
1347;;;###autoload
505edaeb 1348(defconst tramp-file-name-regexp-unified
b96e6899 1349 "\\`/\\([^[/:]+\\|[^/]+]\\):"
505edaeb
KG
1350 "Value for `tramp-file-name-regexp' for unified remoting.
1351Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and
00d6fd04 1352Tramp. See `tramp-file-name-structure' for more explanations.")
505edaeb
KG
1353
1354;;;###autoload
1355(defconst tramp-file-name-regexp-separate
1356 "\\`/\\[.*\\]"
1357 "Value for `tramp-file-name-regexp' for separate remoting.
1358XEmacs uses a separate filename syntax for Tramp and EFS.
00d6fd04 1359See `tramp-file-name-structure' for more explanations.")
505edaeb
KG
1360
1361;;;###autoload
00d6fd04
MA
1362(defconst tramp-file-name-regexp-url
1363 "\\`/[^/:]+://"
1364 "Value for `tramp-file-name-regexp' for URL-like remoting.
1365See `tramp-file-name-structure' for more explanations.")
1366
1367;;;###autoload
1368(defconst tramp-file-name-regexp
1369 (cond ((equal tramp-syntax 'ftp) tramp-file-name-regexp-unified)
1370 ((equal tramp-syntax 'sep) tramp-file-name-regexp-separate)
1371 ((equal tramp-syntax 'url) tramp-file-name-regexp-url)
1372 (t (error "Wrong `tramp-syntax' defined")))
94be87e8 1373 "*Regular expression matching file names handled by Tramp.
a4aeb9a4 1374This regexp should match Tramp file names but no other file names.
fb7933a3
KG
1375\(When tramp.el is loaded, this regular expression is prepended to
1376`file-name-handler-alist', and that is searched sequentially. Thus,
a4aeb9a4
MA
1377if the Tramp entry appears rather early in the `file-name-handler-alist'
1378and is a bit too general, then some files might be considered Tramp
00d6fd04 1379files which are not really Tramp files.
fb7933a3
KG
1380
1381Please note that the entry in `file-name-handler-alist' is made when
1382this file (tramp.el) is loaded. This means that this variable must be set
1383before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1384updated after changing this variable.
1385
00d6fd04 1386Also see `tramp-file-name-structure'.")
fb7933a3 1387
16674e4f 1388;;;###autoload
8a798e41 1389(defconst tramp-root-regexp
00d6fd04 1390 (if (memq system-type '(cygwin windows-nt))
aa485f7c
MA
1391 "\\`\\([a-zA-Z]:\\)?/"
1392 "\\`/")
8a798e41 1393 "Beginning of an incomplete Tramp file name.
aa485f7c 1394Usually, it is just \"\\\\`/\". On W32 systems, there might be a
57671b72 1395volume letter, which will be removed by `tramp-drop-volume-letter'.")
8a798e41
MA
1396
1397;;;###autoload
1398(defconst tramp-completion-file-name-regexp-unified
aa485f7c 1399 (concat tramp-root-regexp "[^/]*\\'")
16674e4f 1400 "Value for `tramp-completion-file-name-regexp' for unified remoting.
8a798e41
MA
1401GNU Emacs uses a unified filename syntax for Tramp and Ange-FTP.
1402See `tramp-file-name-structure' for more explanations.")
fb7933a3 1403
16674e4f
KG
1404;;;###autoload
1405(defconst tramp-completion-file-name-regexp-separate
aa485f7c 1406 (concat tramp-root-regexp "\\([[][^]]*\\)?\\'")
16674e4f
KG
1407 "Value for `tramp-completion-file-name-regexp' for separate remoting.
1408XEmacs uses a separate filename syntax for Tramp and EFS.
00d6fd04 1409See `tramp-file-name-structure' for more explanations.")
fb7933a3 1410
16674e4f 1411;;;###autoload
00d6fd04 1412(defconst tramp-completion-file-name-regexp-url
aa485f7c 1413 (concat tramp-root-regexp "[^/:]+\\(:\\(/\\(/[^/]*\\)?\\)?\\)?\\'")
00d6fd04
MA
1414 "Value for `tramp-completion-file-name-regexp' for URL-like remoting.
1415See `tramp-file-name-structure' for more explanations.")
1416
1417;;;###autoload
1418(defconst tramp-completion-file-name-regexp
1419 (cond ((equal tramp-syntax 'ftp) tramp-completion-file-name-regexp-unified)
1420 ((equal tramp-syntax 'sep) tramp-completion-file-name-regexp-separate)
1421 ((equal tramp-syntax 'url) tramp-completion-file-name-regexp-url)
1422 (t (error "Wrong `tramp-syntax' defined")))
a4aeb9a4
MA
1423 "*Regular expression matching file names handled by Tramp completion.
1424This regexp should match partial Tramp file names only.
16674e4f
KG
1425
1426Please note that the entry in `file-name-handler-alist' is made when
1427this file (tramp.el) is loaded. This means that this variable must be set
1428before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1429updated after changing this variable.
1430
00d6fd04 1431Also see `tramp-file-name-structure'.")
fb7933a3 1432
00d6fd04
MA
1433(defconst tramp-actions-before-shell
1434 '((tramp-login-prompt-regexp tramp-action-login)
1435 (tramp-password-prompt-regexp tramp-action-password)
1436 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
ac474af1 1437 (shell-prompt-pattern tramp-action-succeed)
821e6e36 1438 (tramp-shell-prompt-pattern tramp-action-succeed)
3cdaec13 1439 (tramp-yesno-prompt-regexp tramp-action-yesno)
487f4fb7 1440 (tramp-yn-prompt-regexp tramp-action-yn)
19a87064
MA
1441 (tramp-terminal-prompt-regexp tramp-action-terminal)
1442 (tramp-process-alive-regexp tramp-action-process-alive))
ac474af1
KG
1443 "List of pattern/action pairs.
1444Whenever a pattern matches, the corresponding action is performed.
1445Each item looks like (PATTERN ACTION).
1446
1447The PATTERN should be a symbol, a variable. The value of this
1448variable gives the regular expression to search for. Note that the
1449regexp must match at the end of the buffer, \"\\'\" is implicitly
1450appended to it.
1451
1452The ACTION should also be a symbol, but a function. When the
00d6fd04 1453corresponding PATTERN matches, the ACTION function is called.")
ac474af1 1454
00d6fd04 1455(defconst tramp-actions-copy-out-of-band
38c65fca
KG
1456 '((tramp-password-prompt-regexp tramp-action-password)
1457 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
00d6fd04 1458 (tramp-copy-failed-regexp tramp-action-permission-denied)
19a87064 1459 (tramp-process-alive-regexp tramp-action-out-of-band))
38c65fca
KG
1460 "List of pattern/action pairs.
1461This list is used for copying/renaming with out-of-band methods.
90f8dc03 1462
00d6fd04
MA
1463See `tramp-actions-before-shell' for more info.")
1464
1465;; Chunked sending kludge. We set this to 500 for black-listed constellations
7432277c 1466;; known to have a bug in `process-send-string'; some ssh connections appear
7177e2a3
MA
1467;; to drop bytes when data is sent too quickly. There is also a connection
1468;; buffer local variable, which is computed depending on remote host properties
1469;; when `tramp-chunksize' is zero or nil.
7432277c
KG
1470(defcustom tramp-chunksize
1471 (when (and (not (featurep 'xemacs))
1472 (memq system-type '(hpux)))
1473 500)
55880756
MA
1474;; Parentheses in docstring starting at beginning of line are escaped.
1475;; Fontification is messed up when
1476;; `open-paren-in-column-0-is-defun-start' set to t.
7432277c
KG
1477 "*If non-nil, chunksize for sending input to local process.
1478It is necessary only on systems which have a buggy `process-send-string'
1479implementation. The necessity, whether this variable must be set, can be
1480checked via the following code:
1481
1482 (with-temp-buffer
11948172
MA
1483 (let* ((user \"xxx\") (host \"yyy\")
1484 (init 0) (step 50)
1485 (sent init) (received init))
1486 (while (= sent received)
1487 (setq sent (+ sent step))
1488 (erase-buffer)
1489 (let ((proc (start-process (buffer-name) (current-buffer)
1490 \"ssh\" \"-l\" user host \"wc\" \"-c\")))
1491 (when (memq (process-status proc) '(run open))
1492 (process-send-string proc (make-string sent ?\\ ))
1493 (process-send-eof proc)
1494 (process-send-eof proc))
1495 (while (not (progn (goto-char (point-min))
1496 (re-search-forward \"\\\\w+\" (point-max) t)))
1497 (accept-process-output proc 1))
1498 (when (memq (process-status proc) '(run open))
1499 (setq received (string-to-number (match-string 0)))
1500 (delete-process proc)
1501 (message \"Bytes sent: %s\\tBytes received: %s\" sent received)
1502 (sit-for 0))))
1503 (if (> sent (+ init step))
1504 (message \"You should set `tramp-chunksize' to a maximum of %s\"
1505 (- sent step))
1506 (message \"Test does not work\")
1507 (display-buffer (current-buffer))
1508 (sit-for 30))))
1509
1510In the Emacs normally running Tramp, evaluate the above code
55880756 1511\(replace \"xxx\" and \"yyy\" by the remote user and host name,
11948172
MA
1512respectively). You can do this, for example, by pasting it into
1513the `*scratch*' buffer and then hitting C-j with the cursor after the
1514last closing parenthesis. Note that it works only if you have configured
1515\"ssh\" to run without password query, see ssh-agent(1).
1516
1517You will see the number of bytes sent successfully to the remote host.
1518If that number exceeds 1000, you can stop the execution by hitting
1519C-g, because your Emacs is likely clean.
1520
11948172
MA
1521When it is necessary to set `tramp-chunksize', you might consider to
1522use an out-of-the-band method (like \"scp\") instead of an internal one
55880756 1523\(like \"ssh\"), because setting `tramp-chunksize' to non-nil decreases
11948172 1524performance.
c951aecb 1525
00d6fd04
MA
1526If your Emacs is buggy, the code stops and gives you an indication
1527about the value `tramp-chunksize' should be set. Maybe you could just
1528experiment a bit, e.g. changing the values of `init' and `step'
1529in the third line of the code.
1530
7432277c
KG
1531Please raise a bug report via \"M-x tramp-bug\" if your system needs
1532this variable to be set as well."
1533 :group 'tramp
b1a2b924 1534 :type '(choice (const nil) integer))
7432277c 1535
5ec2cc41
KG
1536;; Logging in to a remote host normally requires obtaining a pty. But
1537;; Emacs on MacOS X has process-connection-type set to nil by default,
1538;; so on those systems Tramp doesn't obtain a pty. Here, we allow
1539;; for an override of the system default.
1540(defcustom tramp-process-connection-type t
1541 "Overrides `process-connection-type' for connections from Tramp.
1542Tramp binds process-connection-type to the value given here before
1543opening a connection to a remote host."
1544 :group 'tramp
1545 :type '(choice (const nil) (const t) (const pty)))
1546
b50dd0d2
MA
1547(defcustom tramp-completion-reread-directory-timeout 10
1548 "Defines seconds since last remote command before rereading a directory.
1549A remote directory might have changed its contents. In order to
1550make it visible during file name completion in the minibuffer,
1551Tramp flushes its cache and rereads the directory contents when
1552more than `tramp-completion-reread-directory-timeout' seconds
1553have been gone since last remote command execution. A value of 0
1554would require an immediate reread during filename completion, nil
1555means to use always cached values for the directory contents."
1556 :group 'tramp
1557 :type '(choice (const nil) integer))
1558
fb7933a3
KG
1559;;; Internal Variables:
1560
4007ba5b 1561(defvar tramp-end-of-output
a0a5183a 1562 (format
70c11b0b
MA
1563 "///%s$"
1564 (md5 (concat (prin1-to-string process-environment) (current-time-string))))
1565 "String used to recognize end of output.
1566The '$' character at the end is quoted; the string cannot be
1567detected as prompt when being sent on echoing hosts, therefore.")
fb7933a3 1568
fb7933a3 1569(defvar tramp-current-method nil
00d6fd04 1570 "Connection method for this *tramp* buffer.")
fb7933a3
KG
1571
1572(defvar tramp-current-user nil
00d6fd04 1573 "Remote login name for this *tramp* buffer.")
fb7933a3
KG
1574
1575(defvar tramp-current-host nil
00d6fd04
MA
1576 "Remote host for this *tramp* buffer.")
1577
1578(defconst tramp-uudecode
1579 "(echo begin 600 /tmp/tramp.$$; tail +2) | uudecode
fabf2143 1580cat /tmp/tramp.$$
00d6fd04 1581rm -f /tmp/tramp.$$"
fabf2143 1582 "Shell function to implement `uudecode' to standard output.
c08e6004
MA
1583Many systems support `uudecode -o /dev/stdout' or `uudecode -o -'
1584for this or `uudecode -p', but some systems don't, and for them
1585we have this shell function.")
fabf2143
KG
1586
1587;; Perl script to implement `file-attributes' in a Lisp `read'able
1588;; output. If you are hacking on this, note that you get *no* output
1589;; unless this spits out a complete line, including the '\n' at the
1590;; end.
8daea7fc 1591;; The device number is returned as "-1", because there will be a virtual
b946a456 1592;; device number set in `tramp-handle-file-attributes'.
00d6fd04
MA
1593(defconst tramp-perl-file-attributes
1594 "%s -e '
c82c5727
LH
1595@stat = lstat($ARGV[0]);
1596if (($stat[2] & 0170000) == 0120000)
1597{
1598 $type = readlink($ARGV[0]);
1599 $type = \"\\\"$type\\\"\";
1600}
1601elsif (($stat[2] & 0170000) == 040000)
1602{
1603 $type = \"t\";
1604}
1605else
1606{
1607 $type = \"nil\"
1608};
1609$uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
1610$gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
1611printf(
d4443a0d 1612 \"(%%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) -1)\\n\",
c82c5727
LH
1613 $type,
1614 $stat[3],
1615 $uid,
1616 $gid,
1617 $stat[8] >> 16 & 0xffff,
1618 $stat[8] & 0xffff,
1619 $stat[9] >> 16 & 0xffff,
1620 $stat[9] & 0xffff,
1621 $stat[10] >> 16 & 0xffff,
1622 $stat[10] & 0xffff,
1623 $stat[7],
1624 $stat[2],
1625 $stat[1] >> 16 & 0xffff,
1626 $stat[1] & 0xffff
00d6fd04 1627);' \"$1\" \"$2\" \"$3\" 2>/dev/null"
fb7933a3 1628 "Perl script to produce output suitable for use with `file-attributes'
00d6fd04
MA
1629on the remote file system.
1630Escape sequence %s is replaced with name of Perl binary.
1631This string is passed to `format', so percent characters need to be doubled.")
fb7933a3 1632
00d6fd04
MA
1633(defconst tramp-perl-directory-files-and-attributes
1634 "%s -e '
8cb0a559
LH
1635chdir($ARGV[0]) or printf(\"\\\"Cannot change to $ARGV[0]: $''!''\\\"\\n\"), exit();
1636opendir(DIR,\".\") or printf(\"\\\"Cannot open directory $ARGV[0]: $''!''\\\"\\n\"), exit();
c82c5727
LH
1637@list = readdir(DIR);
1638closedir(DIR);
1639$n = scalar(@list);
1640printf(\"(\\n\");
1641for($i = 0; $i < $n; $i++)
1642{
1643 $filename = $list[$i];
1644 @stat = lstat($filename);
1645 if (($stat[2] & 0170000) == 0120000)
1646 {
1647 $type = readlink($filename);
1648 $type = \"\\\"$type\\\"\";
1649 }
1650 elsif (($stat[2] & 0170000) == 040000)
1651 {
1652 $type = \"t\";
1653 }
1654 else
1655 {
1656 $type = \"nil\"
1657 };
1658 $uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
1659 $gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
1660 printf(
b946a456 1661 \"(\\\"%%s\\\" %%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) (%%u . %%u))\\n\",
c82c5727
LH
1662 $filename,
1663 $type,
1664 $stat[3],
1665 $uid,
1666 $gid,
1667 $stat[8] >> 16 & 0xffff,
1668 $stat[8] & 0xffff,
1669 $stat[9] >> 16 & 0xffff,
1670 $stat[9] & 0xffff,
1671 $stat[10] >> 16 & 0xffff,
1672 $stat[10] & 0xffff,
1673 $stat[7],
1674 $stat[2],
1675 $stat[1] >> 16 & 0xffff,
1676 $stat[1] & 0xffff,
1677 $stat[0] >> 16 & 0xffff,
1678 $stat[0] & 0xffff);
1679}
00d6fd04 1680printf(\")\\n\");' \"$1\" \"$2\" \"$3\" 2>/dev/null"
c82c5727 1681 "Perl script implementing `directory-files-attributes' as Lisp `read'able
00d6fd04
MA
1682output.
1683Escape sequence %s is replaced with name of Perl binary.
1684This string is passed to `format', so percent characters need to be doubled.")
c82c5727 1685
ac474af1
KG
1686;; ;; These two use uu encoding.
1687;; (defvar tramp-perl-encode "%s -e'\
1688;; print qq(begin 644 xxx\n);
1689;; my $s = q();
1690;; my $res = q();
1691;; while (read(STDIN, $s, 45)) {
1692;; print pack(q(u), $s);
1693;; }
1694;; print qq(`\n);
1695;; print qq(end\n);
1696;; '"
1697;; "Perl program to use for encoding a file.
1698;; Escape sequence %s is replaced with name of Perl binary.")
1699
1700;; (defvar tramp-perl-decode "%s -ne '
1701;; print unpack q(u), $_;
1702;; '"
1703;; "Perl program to use for decoding a file.
1704;; Escape sequence %s is replaced with name of Perl binary.")
1705
1706;; These two use base64 encoding.
00d6fd04
MA
1707(defconst tramp-perl-encode-with-module
1708 "%s -MMIME::Base64 -0777 -ne 'print encode_base64($_)' 2>/dev/null"
ac474af1 1709 "Perl program to use for encoding a file.
b1d06e75 1710Escape sequence %s is replaced with name of Perl binary.
89509ea0 1711This string is passed to `format', so percent characters need to be doubled.
b1d06e75
KG
1712This implementation requires the MIME::Base64 Perl module to be installed
1713on the remote host.")
1714
00d6fd04
MA
1715(defconst tramp-perl-decode-with-module
1716 "%s -MMIME::Base64 -0777 -ne 'print decode_base64($_)' 2>/dev/null"
b1d06e75
KG
1717 "Perl program to use for decoding a file.
1718Escape sequence %s is replaced with name of Perl binary.
89509ea0 1719This string is passed to `format', so percent characters need to be doubled.
b1d06e75
KG
1720This implementation requires the MIME::Base64 Perl module to be installed
1721on the remote host.")
1722
00d6fd04 1723(defconst tramp-perl-encode
b1d06e75
KG
1724 "%s -e '
1725# This script contributed by Juanma Barranquero <lektu@terra.es>.
46932a8d 1726# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
cbd12ed7 1727# Free Software Foundation, Inc.
b1d06e75
KG
1728use strict;
1729
fa32e96a 1730my %%trans = do {
b1d06e75
KG
1731 my $i = 0;
1732 map {(substr(unpack(q(B8), chr $i++), 2, 6), $_)}
1733 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/);
1734};
1735
36541701 1736binmode(\\*STDIN);
b1d06e75
KG
1737
1738# We read in chunks of 54 bytes, to generate output lines
1739# of 72 chars (plus end of line)
36541701 1740$/ = \\54;
b1d06e75
KG
1741
1742while (my $data = <STDIN>) {
1743 my $pad = q();
1744
1745 # Only for the last chunk, and only if did not fill the last three-byte packet
1746 if (eof) {
fa32e96a 1747 my $mod = length($data) %% 3;
b1d06e75
KG
1748 $pad = q(=) x (3 - $mod) if $mod;
1749 }
1750
1751 # Not the fastest method, but it is simple: unpack to binary string, split
1752 # by groups of 6 bits and convert back from binary to byte; then map into
1753 # the translation table
1754 print
1755 join q(),
1756 map($trans{$_},
1757 (substr(unpack(q(B*), $data) . q(00000), 0, 432) =~ /....../g)),
1758 $pad,
36541701 1759 qq(\\n);
00d6fd04 1760}' 2>/dev/null"
b1d06e75 1761 "Perl program to use for encoding a file.
fa32e96a 1762Escape sequence %s is replaced with name of Perl binary.
ccf29586 1763This string is passed to `format', so percent characters need to be doubled.")
ac474af1 1764
00d6fd04 1765(defconst tramp-perl-decode
b1d06e75
KG
1766 "%s -e '
1767# This script contributed by Juanma Barranquero <lektu@terra.es>.
46932a8d 1768# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
cbd12ed7 1769# Free Software Foundation, Inc.
b1d06e75
KG
1770use strict;
1771
fa32e96a 1772my %%trans = do {
b1d06e75 1773 my $i = 0;
16674e4f 1774 map {($_, substr(unpack(q(B8), chr $i++), 2, 6))}
b1d06e75
KG
1775 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/)
1776};
1777
fa32e96a 1778my %%bytes = map {(unpack(q(B8), chr $_), chr $_)} 0 .. 255;
b1d06e75 1779
36541701 1780binmode(\\*STDOUT);
b1d06e75
KG
1781
1782# We are going to accumulate into $pending to accept any line length
1783# (we do not check they are <= 76 chars as the RFC says)
1784my $pending = q();
1785
1786while (my $data = <STDIN>) {
1787 chomp $data;
1788
1789 # If we find one or two =, we have reached the end and
1790 # any following data is to be discarded
1791 my $finished = $data =~ s/(==?).*/$1/;
1792 $pending .= $data;
1793
1794 my $len = length($pending);
16674e4f 1795 my $chunk = substr($pending, 0, $len & ~3);
414da5ab 1796 $pending = substr($pending, $len & ~3 + 1);
b1d06e75
KG
1797
1798 # Easy method: translate from chars to (pregenerated) six-bit packets, join,
1799 # split in 8-bit chunks and convert back to char.
1800 print join q(),
1801 map $bytes{$_},
1802 ((join q(), map {$trans{$_} || q()} split //, $chunk) =~ /......../g);
1803
1804 last if $finished;
00d6fd04 1805}' 2>/dev/null"
ac474af1 1806 "Perl program to use for decoding a file.
fa32e96a 1807Escape sequence %s is replaced with name of Perl binary.
ccf29586 1808This string is passed to `format', so percent characters need to be doubled.")
fb7933a3 1809
946a5aeb
MA
1810(defconst tramp-vc-registered-read-file-names
1811 "echo \"(\"
1812for file in \"$@\"; do
1813 if %s $file; then
1814 echo \"(\\\"$file\\\" \\\"file-exists-p\\\" t)\"
1815 else
1816 echo \"(\\\"$file\\\" \\\"file-exists-p\\\" nil)\"
1817 fi
1818 if %s $file; then
1819 echo \"(\\\"$file\\\" \\\"file-readable-p\\\" t)\"
1820 else
1821 echo \"(\\\"$file\\\" \\\"file-readable-p\\\" nil)\"
1822 fi
1823done
1824echo \")\""
1825 "Script to check existence of VC related files.
1826It must be send formatted with two strings; the tests for file
1827existence, and file readability.")
1828
9ce8462a
MA
1829(defconst tramp-file-mode-type-map
1830 '((0 . "-") ; Normal file (SVID-v2 and XPG2)
1831 (1 . "p") ; fifo
1832 (2 . "c") ; character device
1833 (3 . "m") ; multiplexed character device (v7)
1834 (4 . "d") ; directory
1835 (5 . "?") ; Named special file (XENIX)
1836 (6 . "b") ; block device
1837 (7 . "?") ; multiplexed block device (v7)
1838 (8 . "-") ; regular file
1839 (9 . "n") ; network special file (HP-UX)
1840 (10 . "l") ; symlink
1841 (11 . "?") ; ACL shadow inode (Solaris, not userspace)
1842 (12 . "s") ; socket
1843 (13 . "D") ; door special (Solaris)
1844 (14 . "w")) ; whiteout (BSD)
fb7933a3
KG
1845 "A list of file types returned from the `stat' system call.
1846This is used to map a mode number to a permission string.")
1847
fb7933a3 1848;; New handlers should be added here. The following operations can be
c0fc6170
MA
1849;; handled using the normal primitives: file-name-sans-versions,
1850;; get-file-buffer.
fb7933a3 1851(defconst tramp-file-name-handler-alist
00d6fd04 1852 '((load . tramp-handle-load)
fb7933a3 1853 (make-symbolic-link . tramp-handle-make-symbolic-link)
c0fc6170 1854 (file-name-as-directory . tramp-handle-file-name-as-directory)
fb7933a3
KG
1855 (file-name-directory . tramp-handle-file-name-directory)
1856 (file-name-nondirectory . tramp-handle-file-name-nondirectory)
1857 (file-truename . tramp-handle-file-truename)
1858 (file-exists-p . tramp-handle-file-exists-p)
1859 (file-directory-p . tramp-handle-file-directory-p)
1860 (file-executable-p . tramp-handle-file-executable-p)
fb7933a3
KG
1861 (file-readable-p . tramp-handle-file-readable-p)
1862 (file-regular-p . tramp-handle-file-regular-p)
1863 (file-symlink-p . tramp-handle-file-symlink-p)
1864 (file-writable-p . tramp-handle-file-writable-p)
1865 (file-ownership-preserved-p . tramp-handle-file-ownership-preserved-p)
1866 (file-newer-than-file-p . tramp-handle-file-newer-than-file-p)
1867 (file-attributes . tramp-handle-file-attributes)
1868 (file-modes . tramp-handle-file-modes)
fb7933a3 1869 (directory-files . tramp-handle-directory-files)
c82c5727 1870 (directory-files-and-attributes . tramp-handle-directory-files-and-attributes)
fb7933a3
KG
1871 (file-name-all-completions . tramp-handle-file-name-all-completions)
1872 (file-name-completion . tramp-handle-file-name-completion)
1873 (add-name-to-file . tramp-handle-add-name-to-file)
1874 (copy-file . tramp-handle-copy-file)
1875 (rename-file . tramp-handle-rename-file)
1876 (set-file-modes . tramp-handle-set-file-modes)
ce3f516f 1877 (set-file-times . tramp-handle-set-file-times)
fb7933a3
KG
1878 (make-directory . tramp-handle-make-directory)
1879 (delete-directory . tramp-handle-delete-directory)
1880 (delete-file . tramp-handle-delete-file)
1881 (directory-file-name . tramp-handle-directory-file-name)
00d6fd04
MA
1882 ;; `executable-find' is not official yet.
1883 (executable-find . tramp-handle-executable-find)
1884 (start-file-process . tramp-handle-start-file-process)
0457dd55 1885 (process-file . tramp-handle-process-file)
00d6fd04 1886 (shell-command . tramp-handle-shell-command)
fb7933a3
KG
1887 (insert-directory . tramp-handle-insert-directory)
1888 (expand-file-name . tramp-handle-expand-file-name)
00d6fd04 1889 (substitute-in-file-name . tramp-handle-substitute-in-file-name)
fb7933a3 1890 (file-local-copy . tramp-handle-file-local-copy)
19a87064 1891 (file-remote-p . tramp-handle-file-remote-p)
fb7933a3 1892 (insert-file-contents . tramp-handle-insert-file-contents)
94be87e8
MA
1893 (insert-file-contents-literally
1894 . tramp-handle-insert-file-contents-literally)
fb7933a3 1895 (write-region . tramp-handle-write-region)
38c65fca 1896 (find-backup-file-name . tramp-handle-find-backup-file-name)
c1105d05 1897 (make-auto-save-file-name . tramp-handle-make-auto-save-file-name)
fb7933a3 1898 (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
5ec2cc41 1899 (dired-compress-file . tramp-handle-dired-compress-file)
fb7933a3
KG
1900 (dired-recursive-delete-directory
1901 . tramp-handle-dired-recursive-delete-directory)
70c11b0b 1902 (dired-uncache . tramp-handle-dired-uncache)
fb7933a3 1903 (set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
49096407
MA
1904 (verify-visited-file-modtime . tramp-handle-verify-visited-file-modtime)
1905 (vc-registered . tramp-handle-vc-registered))
c1105d05 1906 "Alist of handler functions.
fb7933a3
KG
1907Operations not mentioned here will be handled by the normal Emacs functions.")
1908
a4aeb9a4 1909;; Handlers for partial Tramp file names. For Emacs just
41c8e348 1910;; `file-name-all-completions' is needed.
a01b1e22 1911;;;###autoload
16674e4f 1912(defconst tramp-completion-file-name-handler-alist
a01b1e22 1913 '((file-name-all-completions . tramp-completion-handle-file-name-all-completions)
41c8e348 1914 (file-name-completion . tramp-completion-handle-file-name-completion))
16674e4f
KG
1915 "Alist of completion handler functions.
1916Used for file names matching `tramp-file-name-regexp'. Operations not
1917mentioned here will be handled by `tramp-file-name-handler-alist' or the
1918normal Emacs functions.")
1919
4007ba5b 1920;; Handlers for foreign methods, like FTP or SMB, shall be plugged here.
ea9d1443
KG
1921(defvar tramp-foreign-file-name-handler-alist
1922 ;; (identity . tramp-sh-file-name-handler) should always be the last
1923 ;; entry, since `identity' always matches.
1924 '((identity . tramp-sh-file-name-handler))
4007ba5b
KG
1925 "Alist of elements (FUNCTION . HANDLER) for foreign methods handled specially.
1926If (FUNCTION FILENAME) returns non-nil, then all I/O on that file is done by
1927calling HANDLER.")
1928
0664ff72 1929;;; Internal functions which must come first:
fb7933a3 1930
00d6fd04
MA
1931(defsubst tramp-debug-message (vec fmt-string &rest args)
1932 "Append message to debug buffer.
1933Message is formatted with FMT-STRING as control string and the remaining
1934ARGS to actually emit the message (if applicable)."
1935 (when (get-buffer (tramp-buffer-name vec))
1936 (with-current-buffer (tramp-get-debug-buffer vec)
1937 (goto-char (point-max))
70c11b0b
MA
1938 ;; Headline.
1939 (when (bobp)
1940 (insert
1941 (format
1942 ";; %sEmacs: %s Tramp: %s -*- mode: outline; -*-"
1943 (if (featurep 'sxemacs) "SX" (if (featurep 'xemacs) "X" "GNU "))
1944 emacs-version tramp-version)))
00d6fd04
MA
1945 (unless (bolp)
1946 (insert "\n"))
70c11b0b 1947 ;; Timestamp.
736ac90f
MA
1948 (let ((now (current-time)))
1949 (insert (format-time-string "%T." now))
1950 (insert (format "%06d " (nth 2 now))))
70c11b0b 1951 ;; Calling function.
00d6fd04
MA
1952 (let ((btn 1) btf fn)
1953 (while (not fn)
1954 (setq btf (nth 1 (backtrace-frame btn)))
1955 (if (not btf)
1956 (setq fn "")
1957 (when (symbolp btf)
1958 (setq fn (symbol-name btf))
1959 (unless (and (string-match "^tramp" fn)
1960 (not (string-match
1961 "^tramp\\(-debug\\)?\\(-message\\|-error\\)$"
1962 fn)))
1963 (setq fn nil)))
1964 (setq btn (1+ btn))))
1965 ;; The following code inserts filename and line number.
1966 ;; Should be deactivated by default, because it is time
1967 ;; consuming.
1968; (let ((ffn (find-function-noselect (intern fn))))
1969; (insert
1970; (format
1971; "%s:%d: "
1972; (file-name-nondirectory (buffer-file-name (car ffn)))
1973; (with-current-buffer (car ffn)
1974; (1+ (count-lines (point-min) (cdr ffn)))))))
1975 (insert (format "%s " fn)))
70c11b0b 1976 ;; The message.
00d6fd04
MA
1977 (insert (apply 'format fmt-string args)))))
1978
946a5aeb
MA
1979(defvar tramp-message-show-message t
1980 "Show Tramp message in the minibuffer.
1981This variable is used to disable messages from `tramp-error'.
1982The messages are visible anyway, because an error is raised.")
1983
00d6fd04 1984(defsubst tramp-message (vec-or-proc level fmt-string &rest args)
fb7933a3 1985 "Emit a message depending on verbosity level.
a4aeb9a4 1986VEC-OR-PROC identifies the Tramp buffer to use. It can be either a
00d6fd04
MA
1987vector or a process. LEVEL says to be quiet if `tramp-verbose' is
1988less than LEVEL. The message is emitted only if `tramp-verbose' is
1989greater than or equal to LEVEL.
1990
1991The message is also logged into the debug buffer when `tramp-verbose'
1992is greater than or equal 4.
1993
1994Calls functions `message' and `tramp-debug-message' with FMT-STRING as
1995control string and the remaining ARGS to actually emit the message (if
1996applicable)."
1997 (condition-case nil
1998 (when (<= level tramp-verbose)
1999 ;; Match data must be preserved!
2000 (save-match-data
2001 ;; Display only when there is a minimum level.
946a5aeb 2002 (when (and tramp-message-show-message (<= level 3))
00d6fd04
MA
2003 (apply 'message
2004 (concat
2005 (cond
2006 ((= level 0) "")
2007 ((= level 1) "")
2008 ((= level 2) "Warning: ")
2009 (t "Tramp: "))
2010 fmt-string)
2011 args))
2012 ;; Log only when there is a minimum level.
2013 (when (>= tramp-verbose 4)
2014 (when (and vec-or-proc
2015 (processp vec-or-proc)
2016 (buffer-name (process-buffer vec-or-proc)))
2017 (with-current-buffer (process-buffer vec-or-proc)
2018 ;; Translate proc to vec.
2019 (setq vec-or-proc (tramp-dissect-file-name default-directory))))
2020 (when (and vec-or-proc (vectorp vec-or-proc))
2021 (apply 'tramp-debug-message
2022 vec-or-proc
2023 (concat (format "(%d) # " level) fmt-string)
2024 args)))))
2025 ;; Suppress all errors.
2026 (error nil)))
2027
2028(defsubst tramp-error (vec-or-proc signal fmt-string &rest args)
2029 "Emit an error.
2030VEC-OR-PROC identifies the connection to use, SIGNAL is the
2031signal identifier to be raised, remaining args passed to
2032`tramp-message'. Finally, signal SIGNAL is raised."
946a5aeb
MA
2033 (let (tramp-message-show-message)
2034 (tramp-message
2035 vec-or-proc 1 "%s"
2036 (error-message-string
2037 (list signal
2038 (get signal 'error-message)
2039 (apply 'format fmt-string args))))
2040 (signal signal (list (apply 'format fmt-string args)))))
00d6fd04
MA
2041
2042(defsubst tramp-error-with-buffer
2043 (buffer vec-or-proc signal fmt-string &rest args)
2044 "Emit an error, and show BUFFER.
2045If BUFFER is nil, show the connection buffer. Wait for 30\", or until
2046an input event arrives. The other arguments are passed to `tramp-error'."
2047 (save-window-excursion
2048 (unwind-protect
2049 (apply 'tramp-error vec-or-proc signal fmt-string args)
2050 (when (and vec-or-proc (not (zerop tramp-verbose)))
2051 (let ((enable-recursive-minibuffers t))
2052 (pop-to-buffer
2053 (or (and (bufferp buffer) buffer)
2054 (and (processp vec-or-proc) (process-buffer vec-or-proc))
2055 (tramp-get-buffer vec-or-proc)))
2056 (sit-for 30))))))
fb7933a3 2057
c62c9d08
KG
2058(defmacro with-parsed-tramp-file-name (filename var &rest body)
2059 "Parse a Tramp filename and make components available in the body.
2060
2061First arg FILENAME is evaluated and dissected into its components.
2062Second arg VAR is a symbol. It is used as a variable name to hold
2063the filename structure. It is also used as a prefix for the variables
2064holding the components. For example, if VAR is the symbol `foo', then
00d6fd04
MA
2065`foo' will be bound to the whole structure, `foo-method' will be bound to
2066the method component, and so on for `foo-user', `foo-host', `foo-localname'.
c62c9d08
KG
2067
2068Remaining args are Lisp expressions to be evaluated (inside an implicit
2069`progn').
2070
00d6fd04
MA
2071If VAR is nil, then we bind `v' to the structure and `method', `user',
2072`host', `localname' to the components."
c62c9d08 2073 `(let* ((,(or var 'v) (tramp-dissect-file-name ,filename))
c62c9d08
KG
2074 (,(if var (intern (concat (symbol-name var) "-method")) 'method)
2075 (tramp-file-name-method ,(or var 'v)))
2076 (,(if var (intern (concat (symbol-name var) "-user")) 'user)
2077 (tramp-file-name-user ,(or var 'v)))
2078 (,(if var (intern (concat (symbol-name var) "-host")) 'host)
2079 (tramp-file-name-host ,(or var 'v)))
7432277c
KG
2080 (,(if var (intern (concat (symbol-name var) "-localname")) 'localname)
2081 (tramp-file-name-localname ,(or var 'v))))
c62c9d08
KG
2082 ,@body))
2083
2084(put 'with-parsed-tramp-file-name 'lisp-indent-function 2)
00d6fd04 2085(put 'with-parsed-tramp-file-name 'edebug-form-spec '(form symbolp body))
9e6ab520 2086(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-parsed-tramp-file-name\\>"))
c62c9d08 2087
00d6fd04
MA
2088(defmacro with-file-property (vec file property &rest body)
2089 "Check in Tramp cache for PROPERTY, otherwise execute BODY and set cache.
2090FILE must be a local file name on a connection identified via VEC."
2091 `(if (file-name-absolute-p ,file)
2092 (let ((value (tramp-get-file-property ,vec ,file ,property 'undef)))
2093 (when (eq value 'undef)
2094 ;; We cannot pass @body as parameter to
2095 ;; `tramp-set-file-property' because it mangles our
2096 ;; debug messages.
2097 (setq value (progn ,@body))
2098 (tramp-set-file-property ,vec ,file ,property value))
2099 value)
2100 ,@body))
9ce8462a 2101
00d6fd04
MA
2102(put 'with-file-property 'lisp-indent-function 3)
2103(put 'with-file-property 'edebug-form-spec t)
9e6ab520 2104(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-file-property\\>"))
00d6fd04
MA
2105
2106(defmacro with-connection-property (key property &rest body)
2107 "Checks in Tramp for property PROPERTY, otherwise executes BODY and set."
2108 `(let ((value (tramp-get-connection-property ,key ,property 'undef)))
2109 (when (eq value 'undef)
2110 ;; We cannot pass ,@body as parameter to
2111 ;; `tramp-set-connection-property' because it mangles our debug
2112 ;; messages.
2113 (setq value (progn ,@body))
2114 (tramp-set-connection-property ,key ,property value))
2115 value))
9ce8462a 2116
00d6fd04
MA
2117(put 'with-connection-property 'lisp-indent-function 2)
2118(put 'with-connection-property 'edebug-form-spec t)
9e6ab520 2119(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-connection-property\\>"))
00d6fd04 2120
628c97b2
GM
2121(eval-and-compile ; silence compiler
2122 (if (memq system-type '(cygwin windows-nt))
2123 (defun tramp-drop-volume-letter (name)
2124 "Cut off unnecessary drive letter from file NAME.
2125The function `tramp-handle-expand-file-name' calls `expand-file-name'
2126locally on a remote file name. When the local system is a W32 system
2127but the remote system is Unix, this introduces a superfluous drive
2128letter into the file name. This function removes it."
2129 (save-match-data
2130 (if (string-match tramp-root-regexp name)
2131 (replace-match "/" nil t name)
2132 name)))
2133
2134 (defalias 'tramp-drop-volume-letter 'identity)))
2135
9c13938d 2136(defsubst tramp-make-tramp-temp-file (vec)
a6e96327 2137 "Create a temporary file on the remote host identified by VEC.
9c13938d
MA
2138Return the local name of the temporary file."
2139 (let ((prefix
2140 (tramp-make-tramp-file-name
2141 (tramp-file-name-method vec)
2142 (tramp-file-name-user vec)
2143 (tramp-file-name-host vec)
113e2a84
MA
2144 (tramp-drop-volume-letter
2145 (expand-file-name
2146 tramp-temp-name-prefix (tramp-get-remote-tmpdir vec)))))
9c13938d
MA
2147 result)
2148 (while (not result)
2149 ;; `make-temp-file' would be the natural choice for
2150 ;; implementation. But it calls `write-region' internally,
2151 ;; which also needs a temporary file - we would end in an
2152 ;; infinite loop.
2153 (setq result (make-temp-name prefix))
2154 (if (file-exists-p result)
2155 (setq result nil)
2156 ;; This creates the file by side effect.
2157 (set-file-times result)
2158 (set-file-modes result (tramp-octal-to-decimal "0700"))))
2159
2160 ;; Return the local part.
2161 (with-parsed-tramp-file-name result nil localname)))
8a4438b6
MA
2162
2163
16674e4f
KG
2164;;; Config Manipulation Functions:
2165
2166(defun tramp-set-completion-function (method function-list)
2167 "Sets the list of completion functions for METHOD.
2168FUNCTION-LIST is a list of entries of the form (FUNCTION FILE).
2169The FUNCTION is intended to parse FILE according its syntax.
2170It might be a predefined FUNCTION, or a user defined FUNCTION.
2171Predefined FUNCTIONs are `tramp-parse-rhosts', `tramp-parse-shosts',
8fc29035 2172`tramp-parse-sconfig', `tramp-parse-hosts', `tramp-parse-passwd',
8daea7fc
KG
2173and `tramp-parse-netrc'.
2174
16674e4f
KG
2175Example:
2176
2177 (tramp-set-completion-function
2178 \"ssh\"
8daea7fc
KG
2179 '((tramp-parse-sconfig \"/etc/ssh_config\")
2180 (tramp-parse-sconfig \"~/.ssh/config\")))"
16674e4f 2181
5ec2cc41
KG
2182 (let ((r function-list)
2183 (v function-list))
2184 (setq tramp-completion-function-alist
2185 (delete (assoc method tramp-completion-function-alist)
2186 tramp-completion-function-alist))
2187
2188 (while v
00d6fd04 2189 ;; Remove double entries.
5ec2cc41
KG
2190 (when (member (car v) (cdr v))
2191 (setcdr v (delete (car v) (cdr v))))
00d6fd04 2192 ;; Check for function and file or registry key.
5ec2cc41 2193 (unless (and (functionp (nth 0 (car v)))
00d6fd04
MA
2194 (if (string-match "^HKEY_CURRENT_USER" (nth 1 (car v)))
2195 ;; Windows registry.
2196 (and (memq system-type '(cygwin windows-nt))
a4aeb9a4
MA
2197 (zerop
2198 (tramp-local-call-process
2199 "reg" nil nil nil "query" (nth 1 (car v)))))
00d6fd04
MA
2200 ;; Configuration file.
2201 (file-exists-p (nth 1 (car v)))))
5ec2cc41
KG
2202 (setq r (delete (car v) r)))
2203 (setq v (cdr v)))
2204
2205 (when r
4007ba5b 2206 (add-to-list 'tramp-completion-function-alist
5ec2cc41 2207 (cons method r)))))
16674e4f
KG
2208
2209(defun tramp-get-completion-function (method)
00d6fd04 2210 "Returns a list of completion functions for METHOD.
16674e4f 2211For definition of that list see `tramp-set-completion-function'."
00d6fd04
MA
2212 (cons
2213 ;; Hosts visited once shall be remembered.
2214 `(tramp-parse-connection-properties ,method)
2215 ;; The method related defaults.
2216 (cdr (assoc method tramp-completion-function-alist))))
16674e4f 2217
d037d501 2218
0664ff72 2219;;; Fontification of `read-file-name':
d037d501 2220
0664ff72 2221;; rfn-eshadow.el is part of Emacs 22. It is autoloaded.
d037d501
MA
2222(defvar tramp-rfn-eshadow-overlay)
2223(make-variable-buffer-local 'tramp-rfn-eshadow-overlay)
2224
2225(defun tramp-rfn-eshadow-setup-minibuffer ()
2226 "Set up a minibuffer for `file-name-shadow-mode'.
2227Adds another overlay hiding filename parts according to Tramp's
2228special handling of `substitute-in-file-name'."
9ce8462a 2229 (when (symbol-value 'minibuffer-completing-file-name)
d037d501 2230 (setq tramp-rfn-eshadow-overlay
9e6ab520
MA
2231 (funcall (symbol-function 'make-overlay)
2232 (funcall (symbol-function 'minibuffer-prompt-end))
2233 (funcall (symbol-function 'minibuffer-prompt-end))))
d037d501 2234 ;; Copy rfn-eshadow-overlay properties.
9e6ab520
MA
2235 (let ((props (funcall (symbol-function 'overlay-properties)
2236 (symbol-value 'rfn-eshadow-overlay))))
d037d501 2237 (while props
9e6ab520
MA
2238 (funcall (symbol-function 'overlay-put)
2239 tramp-rfn-eshadow-overlay (pop props) (pop props))))))
d037d501
MA
2240
2241(when (boundp 'rfn-eshadow-setup-minibuffer-hook)
2242 (add-hook 'rfn-eshadow-setup-minibuffer-hook
48846dc5
MA
2243 'tramp-rfn-eshadow-setup-minibuffer)
2244 (add-hook 'tramp-unload-hook
aa485f7c
MA
2245 (lambda ()
2246 (remove-hook 'rfn-eshadow-setup-minibuffer-hook
2247 'tramp-rfn-eshadow-setup-minibuffer))))
d037d501 2248
adcbca53
MA
2249(defconst tramp-rfn-eshadow-update-overlay-regexp
2250 (format "[^%s/~]*\\(/\\|~\\)" tramp-postfix-host-format))
2251
d037d501
MA
2252(defun tramp-rfn-eshadow-update-overlay ()
2253 "Update `rfn-eshadow-overlay' to cover shadowed part of minibuffer input.
2254This is intended to be used as a minibuffer `post-command-hook' for
2255`file-name-shadow-mode'; the minibuffer should have already
2256been set up by `rfn-eshadow-setup-minibuffer'."
2257 ;; In remote files name, there is a shadowing just for the local part.
9e6ab520
MA
2258 (let ((end (or (funcall (symbol-function 'overlay-end)
2259 (symbol-value 'rfn-eshadow-overlay))
2260 (funcall (symbol-function 'minibuffer-prompt-end)))))
2261 (when (file-remote-p (buffer-substring-no-properties end (point-max)))
bd316474
KY
2262 (save-excursion
2263 (save-restriction
2264 (narrow-to-region
adcbca53
MA
2265 (1+ (or (string-match
2266 tramp-rfn-eshadow-update-overlay-regexp (buffer-string) end)
2267 end))
2268 (point-max))
bd316474
KY
2269 (let ((rfn-eshadow-overlay tramp-rfn-eshadow-overlay)
2270 (rfn-eshadow-update-overlay-hook nil))
dea31ca6 2271 (move-overlay rfn-eshadow-overlay (point-max) (point-max))
bd316474 2272 (funcall (symbol-function 'rfn-eshadow-update-overlay))))))))
d037d501
MA
2273
2274(when (boundp 'rfn-eshadow-update-overlay-hook)
2275 (add-hook 'rfn-eshadow-update-overlay-hook
2276 'tramp-rfn-eshadow-update-overlay))
2277
2278
fb7933a3
KG
2279;;; File Name Handler Functions:
2280
fb7933a3
KG
2281(defun tramp-handle-make-symbolic-link
2282 (filename linkname &optional ok-if-already-exists)
00d6fd04 2283 "Like `make-symbolic-link' for Tramp files.
cebb4ec6 2284If LINKNAME is a non-Tramp file, it is used verbatim as the target of
7432277c 2285the symlink. If LINKNAME is a Tramp file, only the localname component is
cebb4ec6
KG
2286used as the target of the symlink.
2287
7432277c
KG
2288If LINKNAME is a Tramp file and the localname component is relative, then
2289it is expanded first, before the localname component is taken. Note that
cebb4ec6
KG
2290this can give surprising results if the user/host for the source and
2291target of the symlink differ."
c62c9d08 2292 (with-parsed-tramp-file-name linkname l
00d6fd04 2293 (let ((ln (tramp-get-remote-ln l))
87bdd2c7
MA
2294 (cwd (tramp-run-real-handler
2295 'file-name-directory (list l-localname))))
c62c9d08 2296 (unless ln
00d6fd04
MA
2297 (tramp-error
2298 l 'file-error
2299 "Making a symbolic link. ln(1) does not exist on the remote host."))
c62c9d08
KG
2300
2301 ;; Do the 'confirm if exists' thing.
cebb4ec6 2302 (when (file-exists-p linkname)
c62c9d08
KG
2303 ;; What to do?
2304 (if (or (null ok-if-already-exists) ; not allowed to exist
2305 (and (numberp ok-if-already-exists)
2306 (not (yes-or-no-p
2307 (format
2308 "File %s already exists; make it a link anyway? "
7432277c 2309 l-localname)))))
00d6fd04
MA
2310 (tramp-error
2311 l 'file-already-exists "File %s already exists" l-localname)
cebb4ec6
KG
2312 (delete-file linkname)))
2313
7432277c 2314 ;; If FILENAME is a Tramp name, use just the localname component.
cebb4ec6 2315 (when (tramp-tramp-file-p filename)
1834b39f
MA
2316 (setq filename
2317 (tramp-file-name-localname
2318 (tramp-dissect-file-name (expand-file-name filename)))))
bf247b6e 2319
c62c9d08
KG
2320 ;; Right, they are on the same host, regardless of user, method, etc.
2321 ;; We now make the link on the remote machine. This will occur as the user
2322 ;; that FILENAME belongs to.
2323 (zerop
2324 (tramp-send-command-and-check
00d6fd04 2325 l (format "cd %s && %s -sf %s %s" cwd ln filename l-localname) t)))))
fb7933a3 2326
fb7933a3 2327(defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix)
00d6fd04
MA
2328 "Like `load' for Tramp files."
2329 (with-parsed-tramp-file-name (expand-file-name file) nil
c62c9d08
KG
2330 (unless nosuffix
2331 (cond ((file-exists-p (concat file ".elc"))
2332 (setq file (concat file ".elc")))
2333 ((file-exists-p (concat file ".el"))
2334 (setq file (concat file ".el")))))
2335 (when must-suffix
2336 ;; The first condition is always true for absolute file names.
2337 ;; Included for safety's sake.
2338 (unless (or (file-name-directory file)
2339 (string-match "\\.elc?\\'" file))
00d6fd04
MA
2340 (tramp-error
2341 v 'file-error
2342 "File `%s' does not include a `.el' or `.elc' suffix" file)))
c62c9d08
KG
2343 (unless noerror
2344 (when (not (file-exists-p file))
00d6fd04 2345 (tramp-error v 'file-error "Cannot load nonexistent file `%s'" file)))
c62c9d08
KG
2346 (if (not (file-exists-p file))
2347 nil
00d6fd04 2348 (unless nomessage (tramp-message v 0 "Loading %s..." file))
c62c9d08
KG
2349 (let ((local-copy (file-local-copy file)))
2350 ;; MUST-SUFFIX doesn't exist on XEmacs, so let it default to nil.
ce2cc728
MA
2351 (unwind-protect
2352 (load local-copy noerror t t)
2353 (delete-file local-copy)))
00d6fd04 2354 (unless nomessage (tramp-message v 0 "Loading %s...done" file))
c62c9d08 2355 t)))
fb7933a3 2356
a4aeb9a4 2357;; Localname manipulation functions that grok Tramp localnames...
c0fc6170
MA
2358(defun tramp-handle-file-name-as-directory (file)
2359 "Like `file-name-as-directory' but aware of Tramp files."
2360 ;; `file-name-as-directory' would be sufficient except localname is
2361 ;; the empty string.
2362 (let ((v (tramp-dissect-file-name file t)))
2363 ;; Run the command on the localname portion only.
2364 (tramp-make-tramp-file-name
2365 (tramp-file-name-method v)
2366 (tramp-file-name-user v)
2367 (tramp-file-name-host v)
2368 (tramp-run-real-handler
2369 'file-name-as-directory (list (or (tramp-file-name-localname v) ""))))))
2370
fb7933a3 2371(defun tramp-handle-file-name-directory (file)
00d6fd04 2372 "Like `file-name-directory' but aware of Tramp files."
9ce8462a
MA
2373 ;; Everything except the last filename thing is the directory. We
2374 ;; cannot apply `with-parsed-tramp-file-name', because this expands
2375 ;; the remote file name parts. This is a problem when we are in
2376 ;; file name completion.
2377 (let ((v (tramp-dissect-file-name file t)))
a01b1e22
MA
2378 ;; Run the command on the localname portion only.
2379 (tramp-make-tramp-file-name
9ce8462a
MA
2380 (tramp-file-name-method v)
2381 (tramp-file-name-user v)
2382 (tramp-file-name-host v)
87bdd2c7
MA
2383 (tramp-run-real-handler
2384 'file-name-directory (list (or (tramp-file-name-localname v) ""))))))
fb7933a3
KG
2385
2386(defun tramp-handle-file-name-nondirectory (file)
00d6fd04 2387 "Like `file-name-nondirectory' but aware of Tramp files."
c62c9d08 2388 (with-parsed-tramp-file-name file nil
87bdd2c7 2389 (tramp-run-real-handler 'file-name-nondirectory (list localname))))
fb7933a3
KG
2390
2391(defun tramp-handle-file-truename (filename &optional counter prev-dirs)
00d6fd04 2392 "Like `file-truename' for Tramp files."
48ddd622 2393 (with-parsed-tramp-file-name (expand-file-name filename) nil
00d6fd04 2394 (with-file-property v localname "file-truename"
aff67808 2395 (let* ((directory-sep-char ?/) ; for XEmacs
70c11b0b 2396 (steps (tramp-compat-split-string localname "/"))
87bdd2c7
MA
2397 (localnamedir (tramp-run-real-handler
2398 'file-name-as-directory (list localname)))
00d6fd04
MA
2399 (is-dir (string= localname localnamedir))
2400 (thisstep nil)
2401 (numchase 0)
2402 ;; Don't make the following value larger than necessary.
2403 ;; People expect an error message in a timely fashion when
2404 ;; something is wrong; otherwise they might think that Emacs
2405 ;; is hung. Of course, correctness has to come first.
2406 (numchase-limit 20)
2407 (result nil) ;result steps in reverse order
2408 symlink-target)
2409 (tramp-message v 4 "Finding true name for `%s'" filename)
2410 (while (and steps (< numchase numchase-limit))
2411 (setq thisstep (pop steps))
2412 (tramp-message
2413 v 5 "Check %s"
2414 (mapconcat 'identity
2415 (append '("") (reverse result) (list thisstep))
2416 "/"))
2417 (setq symlink-target
2418 (nth 0 (file-attributes
2419 (tramp-make-tramp-file-name
2420 method user host
2421 (mapconcat 'identity
2422 (append '("")
2423 (reverse result)
2424 (list thisstep))
2425 "/")))))
2426 (cond ((string= "." thisstep)
2427 (tramp-message v 5 "Ignoring step `.'"))
2428 ((string= ".." thisstep)
2429 (tramp-message v 5 "Processing step `..'")
2430 (pop result))
2431 ((stringp symlink-target)
2432 ;; It's a symlink, follow it.
2433 (tramp-message v 5 "Follow symlink to %s" symlink-target)
2434 (setq numchase (1+ numchase))
2435 (when (file-name-absolute-p symlink-target)
2436 (setq result nil))
2437 ;; If the symlink was absolute, we'll get a string like
2438 ;; "/user@host:/some/target"; extract the
2439 ;; "/some/target" part from it.
2440 (when (tramp-tramp-file-p symlink-target)
2441 (unless (tramp-equal-remote filename symlink-target)
2442 (tramp-error
2443 v 'file-error
2444 "Symlink target `%s' on wrong host" symlink-target))
2445 (setq symlink-target localname))
2446 (setq steps
70c11b0b 2447 (append (tramp-compat-split-string symlink-target "/")
00d6fd04
MA
2448 steps)))
2449 (t
2450 ;; It's a file.
2451 (setq result (cons thisstep result)))))
2452 (when (>= numchase numchase-limit)
2453 (tramp-error
2454 v 'file-error
2455 "Maximum number (%d) of symlinks exceeded" numchase-limit))
2456 (setq result (reverse result))
2457 ;; Combine list to form string.
2458 (setq result
2459 (if result
2460 (mapconcat 'identity (cons "" result) "/")
2461 "/"))
2462 (when (and is-dir (or (string= "" result)
2463 (not (string= (substring result -1) "/"))))
2464 (setq result (concat result "/")))
2465 (tramp-message v 4 "True name of `%s' is `%s'" filename result)
2466 (tramp-make-tramp-file-name method user host result)))))
fb7933a3
KG
2467
2468;; Basic functions.
2469
2470(defun tramp-handle-file-exists-p (filename)
00d6fd04 2471 "Like `file-exists-p' for Tramp files."
c62c9d08 2472 (with-parsed-tramp-file-name filename nil
00d6fd04 2473 (with-file-property v localname "file-exists-p"
fb7933a3 2474 (zerop (tramp-send-command-and-check
00d6fd04 2475 v
fb7933a3 2476 (format
00d6fd04
MA
2477 "%s %s"
2478 (tramp-get-file-exists-command v)
7432277c 2479 (tramp-shell-quote-argument localname)))))))
fb7933a3 2480
00d6fd04
MA
2481;; Inodes don't exist for some file systems. Therefore we must
2482;; generate virtual ones. Used in `find-buffer-visiting'. The method
2483;; applied might be not so efficient (Ange-FTP uses hashes). But
2484;; performance isn't the major issue given that file transfer will
2485;; take time.
2486(defvar tramp-inodes nil
2487 "Keeps virtual inodes numbers.")
2488
8daea7fc
KG
2489;; Devices must distinguish physical file systems. The device numbers
2490;; provided by "lstat" aren't unique, because we operate on different hosts.
2491;; So we use virtual device numbers, generated by Tramp. Both Ange-FTP and
2492;; EFS use device number "-1". In order to be different, we use device number
b946a456 2493;; (-1 . x), whereby "x" is unique for a given (method user host).
8daea7fc
KG
2494(defvar tramp-devices nil
2495 "Keeps virtual device numbers.")
2496
fb7933a3
KG
2497;; CCC: This should check for an error condition and signal failure
2498;; when something goes wrong.
2499;; Daniel Pittman <daniel@danann.net>
c951aecb 2500(defun tramp-handle-file-attributes (filename &optional id-format)
00d6fd04
MA
2501 "Like `file-attributes' for Tramp files."
2502 (unless id-format (setq id-format 'integer))
aa485f7c
MA
2503 ;; Don't modify `last-coding-system-used' by accident.
2504 (let ((last-coding-system-used last-coding-system-used))
2505 (with-parsed-tramp-file-name (expand-file-name filename) nil
2506 (with-file-property v localname (format "file-attributes-%s" id-format)
2507 (when (file-exists-p filename)
2508 ;; file exists, find out stuff
2509 (save-excursion
2510 (tramp-convert-file-attributes
2511 v
2512 (if (tramp-get-remote-stat v)
2513 (tramp-handle-file-attributes-with-stat
2514 v localname id-format)
2515 (if (tramp-get-remote-perl v)
2516 (tramp-handle-file-attributes-with-perl
2517 v localname id-format)
2518 (tramp-handle-file-attributes-with-ls
2519 v localname id-format))))))))))
00d6fd04
MA
2520
2521(defun tramp-handle-file-attributes-with-ls (vec localname &optional id-format)
2522 "Implement `file-attributes' for Tramp files using the ls(1) command."
fb7933a3
KG
2523 (let (symlinkp dirp
2524 res-inode res-filemodes res-numlinks
2525 res-uid res-gid res-size res-symlink-target)
00d6fd04 2526 (tramp-message vec 5 "file attributes with ls: %s" localname)
fb7933a3 2527 (tramp-send-command
00d6fd04 2528 vec
fb7933a3 2529 (format "%s %s %s"
00d6fd04 2530 (tramp-get-ls-command vec)
c82c5727 2531 (if (eq id-format 'integer) "-ildn" "-ild")
7432277c 2532 (tramp-shell-quote-argument localname)))
fb7933a3 2533 ;; parse `ls -l' output ...
00d6fd04
MA
2534 (with-current-buffer (tramp-get-buffer vec)
2535 (goto-char (point-min))
2536 ;; ... inode
2537 (setq res-inode
2538 (condition-case err
2539 (read (current-buffer))
2540 (invalid-read-syntax
2541 (when (and (equal (cadr err)
2542 "Integer constant overflow in reader")
2543 (string-match
2544 "^[0-9]+\\([0-9][0-9][0-9][0-9][0-9]\\)\\'"
2545 (car (cddr err))))
2546 (let* ((big (read (substring (car (cddr err)) 0
2547 (match-beginning 1))))
2548 (small (read (match-string 1 (car (cddr err)))))
2549 (twiddle (/ small 65536)))
2550 (cons (+ big twiddle)
2551 (- small (* twiddle 65536))))))))
2552 ;; ... file mode flags
2553 (setq res-filemodes (symbol-name (read (current-buffer))))
2554 ;; ... number links
2555 (setq res-numlinks (read (current-buffer)))
2556 ;; ... uid and gid
2557 (setq res-uid (read (current-buffer)))
2558 (setq res-gid (read (current-buffer)))
2559 (if (eq id-format 'integer)
2560 (progn
2561 (unless (numberp res-uid) (setq res-uid -1))
2562 (unless (numberp res-gid) (setq res-gid -1)))
2563 (progn
2564 (unless (stringp res-uid) (setq res-uid (symbol-name res-uid)))
2565 (unless (stringp res-gid) (setq res-gid (symbol-name res-gid)))))
2566 ;; ... size
2567 (setq res-size (read (current-buffer)))
2568 ;; From the file modes, figure out other stuff.
2569 (setq symlinkp (eq ?l (aref res-filemodes 0)))
2570 (setq dirp (eq ?d (aref res-filemodes 0)))
2571 ;; if symlink, find out file name pointed to
2572 (when symlinkp
2573 (search-forward "-> ")
2574 (setq res-symlink-target
9e6ab520 2575 (buffer-substring (point) (tramp-compat-line-end-position))))
00d6fd04
MA
2576 ;; return data gathered
2577 (list
2578 ;; 0. t for directory, string (name linked to) for symbolic
2579 ;; link, or nil.
2580 (or dirp res-symlink-target)
2581 ;; 1. Number of links to file.
2582 res-numlinks
2583 ;; 2. File uid.
2584 res-uid
2585 ;; 3. File gid.
2586 res-gid
2587 ;; 4. Last access time, as a list of two integers. First
2588 ;; integer has high-order 16 bits of time, second has low 16
2589 ;; bits.
2590 ;; 5. Last modification time, likewise.
2591 ;; 6. Last status change time, likewise.
2592 '(0 0) '(0 0) '(0 0) ;CCC how to find out?
2593 ;; 7. Size in bytes (-1, if number is out of range).
2594 res-size
2595 ;; 8. File modes, as a string of ten letters or dashes as in ls -l.
2596 res-filemodes
1437876c 2597 ;; 9. t if file's gid would change if file were deleted and
00d6fd04
MA
2598 ;; recreated. Will be set in `tramp-convert-file-attributes'
2599 t
2600 ;; 10. inode number.
2601 res-inode
2602 ;; 11. Device number. Will be replaced by a virtual device number.
2603 -1
2604 ))))
fb7933a3
KG
2605
2606(defun tramp-handle-file-attributes-with-perl
00d6fd04
MA
2607 (vec localname &optional id-format)
2608 "Implement `file-attributes' for Tramp files using a Perl script."
2609 (tramp-message vec 5 "file attributes with perl: %s" localname)
2610 (tramp-maybe-send-script
2611 vec tramp-perl-file-attributes "tramp_perl_file_attributes")
2612 (tramp-send-command-and-read
2613 vec
2614 (format "tramp_perl_file_attributes %s %s"
2615 (tramp-shell-quote-argument localname) id-format)))
2616
2617(defun tramp-handle-file-attributes-with-stat
2618 (vec localname &optional id-format)
2619 "Implement `file-attributes' for Tramp files using stat(1) command."
2620 (tramp-message vec 5 "file attributes with stat: %s" localname)
2621 (tramp-send-command-and-read
2622 vec
2623 (format
d4443a0d 2624 "%s -c '((\"%%N\") %%h %s %s %%X.0 %%Y.0 %%Z.0 %%s.0 \"%%A\" t %%i.0 -1)' %s"
00d6fd04
MA
2625 (tramp-get-remote-stat vec)
2626 (if (eq id-format 'integer) "%u" "\"%U\"")
2627 (if (eq id-format 'integer) "%g" "\"%G\"")
2628 (tramp-shell-quote-argument localname))))
8daea7fc 2629
fb7933a3 2630(defun tramp-handle-set-visited-file-modtime (&optional time-list)
00d6fd04 2631 "Like `set-visited-file-modtime' for Tramp files."
fb7933a3
KG
2632 (unless (buffer-file-name)
2633 (error "Can't set-visited-file-modtime: buffer `%s' not visiting a file"
2634 (buffer-name)))
48ddd622
MA
2635 (if time-list
2636 (tramp-run-real-handler 'set-visited-file-modtime (list time-list))
11948172
MA
2637 (let ((f (buffer-file-name))
2638 coding-system-used)
48ddd622
MA
2639 (with-parsed-tramp-file-name f nil
2640 (let* ((attr (file-attributes f))
2641 ;; '(-1 65535) means file doesn't exists yet.
2642 (modtime (or (nth 5 attr) '(-1 65535))))
11948172
MA
2643 (when (boundp 'last-coding-system-used)
2644 (setq coding-system-used (symbol-value 'last-coding-system-used)))
48ddd622
MA
2645 ;; We use '(0 0) as a don't-know value. See also
2646 ;; `tramp-handle-file-attributes-with-ls'.
48ddd622
MA
2647 (if (not (equal modtime '(0 0)))
2648 (tramp-run-real-handler 'set-visited-file-modtime (list modtime))
00d6fd04 2649 (progn
48ddd622 2650 (tramp-send-command
00d6fd04 2651 v
48ddd622 2652 (format "%s -ild %s"
00d6fd04 2653 (tramp-get-ls-command v)
48ddd622 2654 (tramp-shell-quote-argument localname)))
48ddd622
MA
2655 (setq attr (buffer-substring (point)
2656 (progn (end-of-line) (point)))))
00d6fd04
MA
2657 (tramp-set-file-property
2658 v localname "visited-file-modtime-ild" attr))
11948172
MA
2659 (when (boundp 'last-coding-system-used)
2660 (set 'last-coding-system-used coding-system-used))
d2a2c17f 2661 nil)))))
fb7933a3 2662
c62c9d08
KG
2663;; This function makes the same assumption as
2664;; `tramp-handle-set-visited-file-modtime'.
2665(defun tramp-handle-verify-visited-file-modtime (buf)
00d6fd04 2666 "Like `verify-visited-file-modtime' for Tramp files.
c08e6004
MA
2667At the time `verify-visited-file-modtime' calls this function, we
2668already know that the buffer is visiting a file and that
2669`visited-file-modtime' does not return 0. Do not call this
2670function directly, unless those two cases are already taken care
2671of."
c62c9d08 2672 (with-current-buffer buf
b15d0c4c
MA
2673 ;; There is no file visiting the buffer, or the buffer has no
2674 ;; recorded last modification time.
2675 (if (or (not (buffer-file-name))
2676 (eq (visited-file-modtime) 0))
d2a2c17f 2677 t
b15d0c4c
MA
2678 (let ((f (buffer-file-name)))
2679 (with-parsed-tramp-file-name f nil
bce04fee 2680 (tramp-flush-file-property v localname)
b15d0c4c
MA
2681 (let* ((attr (file-attributes f))
2682 (modtime (nth 5 attr))
2683 (mt (visited-file-modtime)))
bf247b6e 2684
70c11b0b
MA
2685 (cond
2686 ;; File exists, and has a known modtime.
b15d0c4c
MA
2687 ((and attr (not (equal modtime '(0 0))))
2688 (< (abs (tramp-time-diff
2689 modtime
2690 ;; For compatibility, deal with both the old
70c11b0b
MA
2691 ;; (HIGH . LOW) and the new (HIGH LOW) return
2692 ;; values of `visited-file-modtime'.
b15d0c4c
MA
2693 (if (atom (cdr mt))
2694 (list (car mt) (cdr mt))
2695 mt)))
2696 2))
70c11b0b 2697 ;; Modtime has the don't know value.
b15d0c4c 2698 (attr
00d6fd04
MA
2699 (tramp-send-command
2700 v
2701 (format "%s -ild %s"
2702 (tramp-get-ls-command v)
2703 (tramp-shell-quote-argument localname)))
2704 (with-current-buffer (tramp-get-buffer v)
b15d0c4c
MA
2705 (setq attr (buffer-substring
2706 (point) (progn (end-of-line) (point)))))
00d6fd04
MA
2707 (equal
2708 attr
2709 (tramp-get-file-property
2710 v localname "visited-file-modtime-ild" "")))
70c11b0b
MA
2711 ;; If file does not exist, say it is not modified if and
2712 ;; only if that agrees with the buffer's record.
b15d0c4c 2713 (t (equal mt '(-1 65535))))))))))
c62c9d08 2714
fb7933a3 2715(defun tramp-handle-set-file-modes (filename mode)
00d6fd04 2716 "Like `set-file-modes' for Tramp files."
c62c9d08 2717 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2718 (tramp-flush-file-property v localname)
2719 (unless (zerop (tramp-send-command-and-check
2720 v
2721 (format "chmod %s %s"
2722 (tramp-decimal-to-octal mode)
2723 (tramp-shell-quote-argument localname))))
2724 ;; FIXME: extract the proper text from chmod's stderr.
2725 (tramp-error
2726 v 'file-error "Error while changing file's mode %s" filename))))
fb7933a3 2727
ce3f516f
MA
2728(defun tramp-handle-set-file-times (filename &optional time)
2729 "Like `set-file-times' for Tramp files."
2730 (zerop
9e6ab520 2731 (if (file-remote-p filename)
ce3f516f 2732 (with-parsed-tramp-file-name filename nil
8d60099b 2733 (tramp-flush-file-property v localname)
ce3f516f
MA
2734 (let ((time (if (or (null time) (equal time '(0 0)))
2735 (current-time)
2736 time))
2737 (utc
2738 ;; With GNU Emacs, `format-time-string' has an
2739 ;; optional parameter UNIVERSAL. This is preferred,
2740 ;; because we could handle the case when the remote
2741 ;; host is located in a different time zone as the
2742 ;; local host.
2743 (and (functionp 'subr-arity)
2744 (subrp (symbol-function 'format-time-string))
2745 (= 3 (cdr (funcall (symbol-function 'subr-arity)
2746 (symbol-function
2747 'format-time-string)))))))
2748 (tramp-send-command-and-check
2749 v (format "%s touch -t %s %s"
2750 (if utc "TZ=UTC; export TZ;" "")
2751 (if utc
2752 (format-time-string "%Y%m%d%H%M.%S" time t)
2753 (format-time-string "%Y%m%d%H%M.%S" time))
2754 (tramp-shell-quote-argument localname)))))
8d60099b 2755
ce3f516f
MA
2756 ;; We handle also the local part, because in older Emacsen,
2757 ;; without `set-file-times', this function is an alias for this.
2758 ;; We are local, so we don't need the UTC settings.
a4aeb9a4 2759 (tramp-local-call-process
ce3f516f
MA
2760 "touch" nil nil nil "-t"
2761 (format-time-string "%Y%m%d%H%M.%S" time)
2762 (tramp-shell-quote-argument filename)))))
2763
8d60099b
MA
2764(defun tramp-set-file-uid-gid (filename &optional uid gid)
2765 "Set the ownership for FILENAME.
2766If UID and GID are provided, these values are used; otherwise uid
2767and gid of the corresponding user is taken. Both parameters must be integers."
70c11b0b
MA
2768 ;; Modern Unices allow chown only for root. So we might need
2769 ;; another implementation, see `dired-do-chown'. OTOH, it is mostly
2770 ;; working with su(do)? when it is needed, so it shall succeed in
2771 ;; the majority of cases.
aa485f7c
MA
2772 ;; Don't modify `last-coding-system-used' by accident.
2773 (let ((last-coding-system-used last-coding-system-used))
2774 (if (file-remote-p filename)
2775 (with-parsed-tramp-file-name filename nil
2776 (if (and (zerop (user-uid)) (tramp-local-host-p v))
2777 ;; If we are root on the local host, we can do it directly.
2778 (tramp-set-file-uid-gid localname uid gid)
2779 (let ((uid (or (and (integerp uid) uid)
2780 (tramp-get-remote-uid v 'integer)))
2781 (gid (or (and (integerp gid) gid)
2782 (tramp-get-remote-gid v 'integer))))
2783 (tramp-send-command
2784 v (format
2785 "chown %d:%d %s" uid gid
2786 (tramp-shell-quote-argument localname))))))
2787
2788 ;; We handle also the local part, because there doesn't exist
2789 ;; `set-file-uid-gid'. On W32 "chown" might not work.
2790 (let ((uid (or (and (integerp uid) uid) (tramp-get-local-uid 'integer)))
2791 (gid (or (and (integerp gid) gid) (tramp-get-local-gid 'integer))))
2792 (tramp-local-call-process
2793 "chown" nil nil nil
2794 (format "%d:%d" uid gid) (tramp-shell-quote-argument filename))))))
8d60099b 2795
fb7933a3
KG
2796;; Simple functions using the `test' command.
2797
2798(defun tramp-handle-file-executable-p (filename)
00d6fd04 2799 "Like `file-executable-p' for Tramp files."
c62c9d08 2800 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2801 (with-file-property v localname "file-executable-p"
2802 (zerop (tramp-run-test "-x" filename)))))
fb7933a3
KG
2803
2804(defun tramp-handle-file-readable-p (filename)
00d6fd04 2805 "Like `file-readable-p' for Tramp files."
c62c9d08 2806 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2807 (with-file-property v localname "file-readable-p"
2808 (zerop (tramp-run-test "-r" filename)))))
fb7933a3
KG
2809
2810;; When the remote shell is started, it looks for a shell which groks
2811;; tilde expansion. Here, we assume that all shells which grok tilde
2812;; expansion will also provide a `test' command which groks `-nt' (for
2813;; newer than). If this breaks, tell me about it and I'll try to do
2814;; something smarter about it.
2815(defun tramp-handle-file-newer-than-file-p (file1 file2)
00d6fd04 2816 "Like `file-newer-than-file-p' for Tramp files."
fb7933a3
KG
2817 (cond ((not (file-exists-p file1))
2818 nil)
2819 ((not (file-exists-p file2))
2820 t)
91879624 2821 ;; We are sure both files exist at this point.
fb7933a3
KG
2822 (t
2823 (save-excursion
91879624
KG
2824 ;; We try to get the mtime of both files. If they are not
2825 ;; equal to the "dont-know" value, then we subtract the times
2826 ;; and obtain the result.
2827 (let ((fa1 (file-attributes file1))
2828 (fa2 (file-attributes file2)))
2829 (if (and (not (equal (nth 5 fa1) '(0 0)))
2830 (not (equal (nth 5 fa2) '(0 0))))
01917a18 2831 (> 0 (tramp-time-diff (nth 5 fa2) (nth 5 fa1)))
91879624
KG
2832 ;; If one of them is the dont-know value, then we can
2833 ;; still try to run a shell command on the remote host.
2834 ;; However, this only works if both files are Tramp
2835 ;; files and both have the same method, same user, same
2836 ;; host.
00d6fd04
MA
2837 (unless (tramp-equal-remote file1 file2)
2838 (with-parsed-tramp-file-name
2839 (if (tramp-tramp-file-p file1) file1 file2) nil
2840 (tramp-error
2841 v 'file-error
2842 "Files %s and %s must have same method, user, host"
2843 file1 file2)))
2844 (with-parsed-tramp-file-name file1 nil
2845 (zerop (tramp-run-test2
2846 (tramp-get-test-nt-command v) file1 file2)))))))))
fb7933a3
KG
2847
2848;; Functions implemented using the basic functions above.
2849
2850(defun tramp-handle-file-modes (filename)
00d6fd04 2851 "Like `file-modes' for Tramp files."
5da24108
MA
2852 (let ((truename (or (file-truename filename) filename)))
2853 (when (file-exists-p truename)
2854 (tramp-mode-string-to-int (nth 8 (file-attributes truename))))))
fb7933a3 2855
b86c1cd8
MA
2856(defun tramp-default-file-modes (filename)
2857 "Return file modes of FILENAME as integer.
2858If the file modes of FILENAME cannot be determined, return the
974647ac
MA
2859value of `default-file-modes', without execute permissions."
2860 (or (file-modes filename)
2861 (logand (default-file-modes) (tramp-octal-to-decimal "0666"))))
b86c1cd8 2862
fb7933a3 2863(defun tramp-handle-file-directory-p (filename)
00d6fd04 2864 "Like `file-directory-p' for Tramp files."
fb7933a3
KG
2865 ;; Care must be taken that this function returns `t' for symlinks
2866 ;; pointing to directories. Surely the most obvious implementation
2867 ;; would be `test -d', but that returns false for such symlinks.
2868 ;; CCC: Stefan Monnier says that `test -d' follows symlinks. And
2869 ;; I now think he's right. So we could be using `test -d', couldn't
2870 ;; we?
2871 ;;
2872 ;; Alternatives: `cd %s', `test -d %s'
c62c9d08 2873 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2874 (with-file-property v localname "file-directory-p"
2875 (zerop (tramp-run-test "-d" filename)))))
fb7933a3
KG
2876
2877(defun tramp-handle-file-regular-p (filename)
00d6fd04
MA
2878 "Like `file-regular-p' for Tramp files."
2879 (and (file-exists-p filename)
2880 (eq ?- (aref (nth 8 (file-attributes filename)) 0))))
fb7933a3
KG
2881
2882(defun tramp-handle-file-symlink-p (filename)
00d6fd04 2883 "Like `file-symlink-p' for Tramp files."
c62c9d08 2884 (with-parsed-tramp-file-name filename nil
c951aecb 2885 (let ((x (car (file-attributes filename))))
b25a52cc
KG
2886 (when (stringp x)
2887 ;; When Tramp is running on VMS, then `file-name-absolute-p'
2888 ;; might do weird things.
2889 (if (file-name-absolute-p x)
00d6fd04 2890 (tramp-make-tramp-file-name method user host x)
b25a52cc 2891 x)))))
fb7933a3
KG
2892
2893(defun tramp-handle-file-writable-p (filename)
00d6fd04 2894 "Like `file-writable-p' for Tramp files."
c62c9d08 2895 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2896 (with-file-property v localname "file-writable-p"
2897 (if (file-exists-p filename)
2898 ;; Existing files must be writable.
2899 (zerop (tramp-run-test "-w" filename))
2900 ;; If file doesn't exist, check if directory is writable.
2901 (and (zerop (tramp-run-test
2902 "-d" (file-name-directory filename)))
2903 (zerop (tramp-run-test
2904 "-w" (file-name-directory filename))))))))
fb7933a3
KG
2905
2906(defun tramp-handle-file-ownership-preserved-p (filename)
00d6fd04 2907 "Like `file-ownership-preserved-p' for Tramp files."
c62c9d08 2908 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2909 (with-file-property v localname "file-ownership-preserved-p"
2910 (let ((attributes (file-attributes filename)))
2911 ;; Return t if the file doesn't exist, since it's true that no
2912 ;; information would be lost by an (attempted) delete and create.
2913 (or (null attributes)
2914 (= (nth 2 attributes) (tramp-get-remote-uid v 'integer)))))))
fb7933a3
KG
2915
2916;; Other file name ops.
2917
fb7933a3 2918(defun tramp-handle-directory-file-name (directory)
00d6fd04 2919 "Like `directory-file-name' for Tramp files."
7432277c
KG
2920 ;; If localname component of filename is "/", leave it unchanged.
2921 ;; Otherwise, remove any trailing slash from localname component.
8daea7fc
KG
2922 ;; Method, host, etc, are unchanged. Does it make sense to try
2923 ;; to avoid parsing the filename?
c62c9d08 2924 (with-parsed-tramp-file-name directory nil
7432277c
KG
2925 (if (and (not (zerop (length localname)))
2926 (eq (aref localname (1- (length localname))) ?/)
2927 (not (string= localname "/")))
8daea7fc
KG
2928 (substring directory 0 -1)
2929 directory)))
fb7933a3
KG
2930
2931;; Directory listings.
2932
00d6fd04
MA
2933(defun tramp-handle-directory-files
2934 (directory &optional full match nosort files-only)
2935 "Like `directory-files' for Tramp files."
2936 ;; FILES-ONLY is valid for XEmacs only.
2937 (when (file-directory-p directory)
2938 (setq directory (expand-file-name directory))
2939 (let ((temp (nreverse (file-name-all-completions "" directory)))
2940 result item)
2941
2942 (while temp
2943 (setq item (directory-file-name (pop temp)))
2944 (when (and (or (null match) (string-match match item))
2945 (or (null files-only)
2946 ;; files only
2947 (and (equal files-only t) (file-regular-p item))
2948 ;; directories only
2949 (file-directory-p item)))
2950 (push (if full (expand-file-name item directory) item)
2951 result)))
c62c9d08
KG
2952 result)))
2953
c82c5727
LH
2954(defun tramp-handle-directory-files-and-attributes
2955 (directory &optional full match nosort id-format)
00d6fd04
MA
2956 "Like `directory-files-and-attributes' for Tramp files."
2957 (unless id-format (setq id-format 'integer))
2958 (when (file-directory-p directory)
2959 (setq directory (expand-file-name directory))
2960 (let* ((temp
9e6ab520 2961 (tramp-compat-copy-tree
00d6fd04
MA
2962 (with-parsed-tramp-file-name directory nil
2963 (with-file-property
2964 v localname
2965 (format "directory-files-and-attributes-%s" id-format)
2966 (save-excursion
2967 (mapcar
aa485f7c
MA
2968 (lambda (x)
2969 (cons (car x)
2970 (tramp-convert-file-attributes v (cdr x))))
00d6fd04
MA
2971 (if (tramp-get-remote-stat v)
2972 (tramp-handle-directory-files-and-attributes-with-stat
2973 v localname id-format)
2974 (if (tramp-get-remote-perl v)
2975 (tramp-handle-directory-files-and-attributes-with-perl
2976 v localname id-format)))))))))
2977 result item)
2978
2979 (while temp
2980 (setq item (pop temp))
2981 (when (or (null match) (string-match match (car item)))
2982 (when full
2983 (setcar item (expand-file-name (car item) directory)))
2984 (push item result)))
2985
2986 (if nosort
2987 result
2988 (sort result (lambda (x y) (string< (car x) (car y))))))))
2989
2990(defun tramp-handle-directory-files-and-attributes-with-perl
2991 (vec localname &optional id-format)
2992 "Implement `directory-files-and-attributes' for Tramp files using a Perl script."
2993 (tramp-message vec 5 "directory-files-and-attributes with perl: %s" localname)
2994 (tramp-maybe-send-script
2995 vec tramp-perl-directory-files-and-attributes
2996 "tramp_perl_directory_files_and_attributes")
2997 (let ((object
2998 (tramp-send-command-and-read
2999 vec
3000 (format "tramp_perl_directory_files_and_attributes %s %s"
3001 (tramp-shell-quote-argument localname) id-format))))
3002 (when (stringp object) (tramp-error vec 'file-error object))
3003 object))
3004
3005(defun tramp-handle-directory-files-and-attributes-with-stat
3006 (vec localname &optional id-format)
3007 "Implement `directory-files-and-attributes' for Tramp files using stat(1) command."
3008 (tramp-message vec 5 "directory-files-and-attributes with stat: %s" localname)
3009 (tramp-send-command-and-read
3010 vec
3011 (format
3012 (concat
70c11b0b
MA
3013 ;; We must care about filenames with spaces, or starting with
3014 ;; "-"; this would confuse xargs. "ls -aQ" might be a solution,
3015 ;; but it does not work on all remote systems. Therefore, we
3016 ;; quote the filenames via sed.
3017 "cd %s; echo \"(\"; (%s -a | sed -e s/\\$/\\\"/g -e s/^/\\\"/g | xargs "
d4443a0d 3018 "%s -c '(\"%%n\" (\"%%N\") %%h %s %s %%X.0 %%Y.0 %%Z.0 %%s.0 \"%%A\" t %%i.0 -1)'); "
00d6fd04
MA
3019 "echo \")\"")
3020 (tramp-shell-quote-argument localname)
3021 (tramp-get-ls-command vec)
3022 (tramp-get-remote-stat vec)
3023 (if (eq id-format 'integer) "%u" "\"%U\"")
3024 (if (eq id-format 'integer) "%g" "\"%G\""))))
c82c5727 3025
c62c9d08 3026;; This function should return "foo/" for directories and "bar" for
00d6fd04 3027;; files.
c62c9d08 3028(defun tramp-handle-file-name-all-completions (filename directory)
00d6fd04
MA
3029 "Like `file-name-all-completions' for Tramp files."
3030 (unless (save-match-data (string-match "/" filename))
9c13938d 3031 (with-parsed-tramp-file-name (expand-file-name directory) nil
b50dd0d2
MA
3032 ;; Flush the directory cache. There could be changed directory
3033 ;; contents.
3034 (when (and (integerp tramp-completion-reread-directory-timeout)
3035 (> (tramp-time-diff
3036 (current-time)
3037 (tramp-get-file-property
3038 v localname "last-completion" '(0 0 0)))
3039 tramp-completion-reread-directory-timeout))
3040 (tramp-flush-file-property v localname))
3041
00d6fd04
MA
3042 (all-completions
3043 filename
3044 (mapcar
3045 'list
3046 (with-file-property v localname "file-name-all-completions"
3047 (let (result)
3048 (tramp-barf-unless-okay
3049 v
3050 (format "cd %s" (tramp-shell-quote-argument localname))
3051 "tramp-handle-file-name-all-completions: Couldn't `cd %s'"
3052 (tramp-shell-quote-argument localname))
3053
3054 ;; Get a list of directories and files, including reliably
3055 ;; tagging the directories with a trailing '/'. Because I
3056 ;; rock. --daniel@danann.net
3057 (tramp-send-command
3058 v
65a099b6 3059 (format (concat "%s -a 2>/dev/null | while read f; do "
00d6fd04
MA
3060 "if %s -d \"$f\" 2>/dev/null; "
3061 "then echo \"$f/\"; else echo \"$f\"; fi; done")
3062 (tramp-get-ls-command v)
3063 (tramp-get-test-command v)))
3064
3065 ;; Now grab the output.
3066 (with-current-buffer (tramp-get-buffer v)
3067 (goto-char (point-max))
3068 (while (zerop (forward-line -1))
9e6ab520
MA
3069 (push (buffer-substring
3070 (point) (tramp-compat-line-end-position))
00d6fd04
MA
3071 result)))
3072
b50dd0d2
MA
3073 (tramp-set-file-property
3074 v localname "last-completion" (current-time))
00d6fd04 3075 result)))))))
fb7933a3
KG
3076
3077;; The following isn't needed for Emacs 20 but for 19.34?
e1e17cae
MA
3078(defun tramp-handle-file-name-completion
3079 (filename directory &optional predicate)
00d6fd04 3080 "Like `file-name-completion' for Tramp files."
fb7933a3
KG
3081 (unless (tramp-tramp-file-p directory)
3082 (error
3083 "tramp-handle-file-name-completion invoked on non-tramp directory `%s'"
3084 directory))
83e20b5c
MA
3085 (try-completion
3086 filename
3087 (mapcar 'list (file-name-all-completions filename directory))
3088 (when predicate
3089 (lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
fb7933a3
KG
3090
3091;; cp, mv and ln
3092
3093(defun tramp-handle-add-name-to-file
3094 (filename newname &optional ok-if-already-exists)
00d6fd04
MA
3095 "Like `add-name-to-file' for Tramp files."
3096 (unless (tramp-equal-remote filename newname)
3097 (with-parsed-tramp-file-name
3098 (if (tramp-tramp-file-p filename) filename newname) nil
3099 (tramp-error
3100 v 'file-error
3101 "add-name-to-file: %s"
3102 "only implemented for same method, same user, same host")))
c62c9d08
KG
3103 (with-parsed-tramp-file-name filename v1
3104 (with-parsed-tramp-file-name newname v2
00d6fd04 3105 (let ((ln (when v1 (tramp-get-remote-ln v1))))
c62c9d08
KG
3106 (when (and (not ok-if-already-exists)
3107 (file-exists-p newname)
3108 (not (numberp ok-if-already-exists))
3109 (y-or-n-p
3110 (format
3111 "File %s already exists; make it a new name anyway? "
3112 newname)))
00d6fd04
MA
3113 (tramp-error
3114 v2 'file-error
3115 "add-name-to-file: file %s already exists" newname))
3116 (tramp-flush-file-property v2 v2-localname)
c62c9d08 3117 (tramp-barf-unless-okay
00d6fd04 3118 v1
7432277c
KG
3119 (format "%s %s %s" ln (tramp-shell-quote-argument v1-localname)
3120 (tramp-shell-quote-argument v2-localname))
c62c9d08
KG
3121 "error with add-name-to-file, see buffer `%s' for details"
3122 (buffer-name))))))
fb7933a3
KG
3123
3124(defun tramp-handle-copy-file
8d60099b 3125 (filename newname &optional ok-if-already-exists keep-date preserve-uid-gid)
00d6fd04 3126 "Like `copy-file' for Tramp files."
fb7933a3 3127 ;; Check if both files are local -- invoke normal copy-file.
9e6ab520 3128 ;; Otherwise, use Tramp from local system.
fb7933a3
KG
3129 (setq filename (expand-file-name filename))
3130 (setq newname (expand-file-name newname))
9e6ab520 3131 (cond
a4aeb9a4 3132 ;; At least one file a Tramp file?
9e6ab520
MA
3133 ((or (tramp-tramp-file-p filename)
3134 (tramp-tramp-file-p newname))
3135 (tramp-do-copy-or-rename-file
3136 'copy filename newname ok-if-already-exists keep-date preserve-uid-gid))
3137 ;; Compat section.
3138 (preserve-uid-gid
fb7933a3 3139 (tramp-run-real-handler
8d60099b 3140 'copy-file
9e6ab520
MA
3141 (list filename newname ok-if-already-exists keep-date preserve-uid-gid)))
3142 (t
3143 (tramp-run-real-handler
3144 'copy-file (list filename newname ok-if-already-exists keep-date)))))
fb7933a3
KG
3145
3146(defun tramp-handle-rename-file
3147 (filename newname &optional ok-if-already-exists)
00d6fd04 3148 "Like `rename-file' for Tramp files."
fb7933a3 3149 ;; Check if both files are local -- invoke normal rename-file.
a4aeb9a4 3150 ;; Otherwise, use Tramp from local system.
fb7933a3
KG
3151 (setq filename (expand-file-name filename))
3152 (setq newname (expand-file-name newname))
a4aeb9a4 3153 ;; At least one file a Tramp file?
fb7933a3
KG
3154 (if (or (tramp-tramp-file-p filename)
3155 (tramp-tramp-file-p newname))
3156 (tramp-do-copy-or-rename-file
8d60099b 3157 'rename filename newname ok-if-already-exists t t)
00d6fd04
MA
3158 (tramp-run-real-handler
3159 'rename-file (list filename newname ok-if-already-exists))))
fb7933a3
KG
3160
3161(defun tramp-do-copy-or-rename-file
8d60099b 3162 (op filename newname &optional ok-if-already-exists keep-date preserve-uid-gid)
fb7933a3
KG
3163 "Copy or rename a remote file.
3164OP must be `copy' or `rename' and indicates the operation to perform.
3165FILENAME specifies the file to copy or rename, NEWNAME is the name of
3166the new file (for copy) or the new name of the file (for rename).
3167OK-IF-ALREADY-EXISTS means don't barf if NEWNAME exists already.
3168KEEP-DATE means to make sure that NEWNAME has the same timestamp
8d60099b
MA
3169as FILENAME. PRESERVE-UID-GID, when non-nil, instructs to keep
3170the uid and gid if both files are on the same host.
fb7933a3
KG
3171
3172This function is invoked by `tramp-handle-copy-file' and
3173`tramp-handle-rename-file'. It is an error if OP is neither of `copy'
3174and `rename'. FILENAME and NEWNAME must be absolute file names."
3175 (unless (memq op '(copy rename))
3176 (error "Unknown operation `%s', must be `copy' or `rename'" op))
90dc758d 3177 (let ((t1 (tramp-tramp-file-p filename))
00d6fd04 3178 (t2 (tramp-tramp-file-p newname)))
5ec2cc41 3179
da1975d7
MA
3180 (when (and (not ok-if-already-exists) (file-exists-p newname))
3181 (with-parsed-tramp-file-name (if t1 filename newname) nil
3182 (tramp-error
3183 v 'file-already-exists "File %s already exists" newname)))
5ec2cc41 3184
905fb90e
MA
3185 (with-parsed-tramp-file-name (if t1 filename newname) nil
3186 (tramp-message v 0 "Transferring %s to %s..." filename newname))
3187
00d6fd04
MA
3188 (prog1
3189 (cond
3190 ;; Both are Tramp files.
3191 ((and t1 t2)
3192 (with-parsed-tramp-file-name filename v1
3193 (with-parsed-tramp-file-name newname v2
3194 (cond
3195 ;; Shortcut: if method, host, user are the same for both
3196 ;; files, we invoke `cp' or `mv' on the remote host
3197 ;; directly.
3198 ((tramp-equal-remote filename newname)
3199 (tramp-do-copy-or-rename-file-directly
8d60099b
MA
3200 op filename newname
3201 ok-if-already-exists keep-date preserve-uid-gid))
3202
905fb90e
MA
3203 ;; Try out-of-band operation.
3204 ((and (tramp-method-out-of-band-p v1)
00d6fd04
MA
3205 (> (nth 7 (file-attributes filename))
3206 tramp-copy-size-limit))
3207 (tramp-do-copy-or-rename-file-out-of-band
3208 op filename newname keep-date))
8d60099b 3209
00d6fd04
MA
3210 ;; No shortcut was possible. So we copy the
3211 ;; file first. If the operation was `rename', we go
3212 ;; back and delete the original file (if the copy was
3213 ;; successful). The approach is simple-minded: we
3214 ;; create a new buffer, insert the contents of the
3215 ;; source file into it, then write out the buffer to
3216 ;; the target file. The advantage is that it doesn't
3217 ;; matter which filename handlers are used for the
3218 ;; source and target file.
3219 (t
3220 (tramp-do-copy-or-rename-file-via-buffer
3221 op filename newname keep-date))))))
3222
3223 ;; One file is a Tramp file, the other one is local.
3224 ((or t1 t2)
3225 (with-parsed-tramp-file-name (if t1 filename newname) nil
8d60099b
MA
3226 (cond
3227 ;; Fast track on local machine.
3228 ((tramp-local-host-p v)
3229 (tramp-do-copy-or-rename-file-directly
3230 op filename newname
3231 ok-if-already-exists keep-date preserve-uid-gid))
3232
3233 ;; If the Tramp file has an out-of-band method, the corresponding
3234 ;; copy-program can be invoked.
3235 ((and (tramp-method-out-of-band-p v)
3236 (> (nth 7 (file-attributes filename))
3237 tramp-copy-size-limit))
3238 (tramp-do-copy-or-rename-file-out-of-band
3239 op filename newname keep-date))
3240
3241 ;; Use the inline method via a Tramp buffer.
3242 (t (tramp-do-copy-or-rename-file-via-buffer
3243 op filename newname keep-date)))))
00d6fd04
MA
3244
3245 (t
3246 ;; One of them must be a Tramp file.
3247 (error "Tramp implementation says this cannot happen")))
8d60099b 3248
484ea0b6
MA
3249 ;; In case of `rename', we must flush the cache of the source file.
3250 (when (and t1 (eq op 'rename))
3251 (with-parsed-tramp-file-name filename nil
3252 (tramp-flush-file-property v localname)))
3253
00d6fd04
MA
3254 ;; When newname did exist, we have wrong cached values.
3255 (when t2
3256 (with-parsed-tramp-file-name newname nil
905fb90e
MA
3257 (tramp-flush-file-property v localname)))
3258
3259 (with-parsed-tramp-file-name (if t1 filename newname) nil
3260 (tramp-message v 0 "Transferring %s to %s...done" filename newname)))))
7432277c 3261
38c65fca 3262(defun tramp-do-copy-or-rename-file-via-buffer (op filename newname keep-date)
90dc758d
KG
3263 "Use an Emacs buffer to copy or rename a file.
3264First arg OP is either `copy' or `rename' and indicates the operation.
3265FILENAME is the source file, NEWNAME the target file.
3266KEEP-DATE is non-nil if NEWNAME should have the same timestamp as FILENAME."
8a798e41
MA
3267 (with-temp-buffer
3268 ;; We must disable multibyte, because binary data shall not be
3269 ;; converted.
3270 (set-buffer-multibyte nil)
3271 (let ((coding-system-for-read 'binary)
3272 (jka-compr-inhibit t))
3273 (insert-file-contents-literally filename))
3274 ;; We don't want the target file to be compressed, so we let-bind
3275 ;; `jka-compr-inhibit' to t.
3276 (let ((coding-system-for-write 'binary)
3277 (jka-compr-inhibit t))
3278 (write-region (point-min) (point-max) newname)))
3279 ;; KEEP-DATE handling.
3280 (when keep-date (set-file-times newname (nth 5 (file-attributes filename))))
3281 ;; Set the mode.
b86c1cd8 3282 (set-file-modes newname (tramp-default-file-modes filename))
8a798e41
MA
3283 ;; If the operation was `rename', delete the original file.
3284 (unless (eq op 'copy) (delete-file filename)))
fb7933a3
KG
3285
3286(defun tramp-do-copy-or-rename-file-directly
8d60099b 3287 (op filename newname ok-if-already-exists keep-date preserve-uid-gid)
fb7933a3
KG
3288 "Invokes `cp' or `mv' on the remote system.
3289OP must be one of `copy' or `rename', indicating `cp' or `mv',
8d60099b
MA
3290respectively. FILENAME specifies the file to copy or rename,
3291NEWNAME is the name of the new file (for copy) or the new name of
3292the file (for rename). Both files must reside on the same host.
3293KEEP-DATE means to make sure that NEWNAME has the same timestamp
3294as FILENAME. PRESERVE-UID-GID, when non-nil, instructs to keep
3295the uid and gid from FILENAME."
8a4438b6 3296 (let ((t1 (tramp-tramp-file-p filename))
4f4126e6
MA
3297 (t2 (tramp-tramp-file-p newname))
3298 (file-times (nth 5 (file-attributes filename)))
3299 (file-modes (tramp-default-file-modes filename)))
8a4438b6
MA
3300 (with-parsed-tramp-file-name (if t1 filename newname) nil
3301 (let* ((cmd (cond ((and (eq op 'copy) preserve-uid-gid) "cp -f -p")
3302 ((eq op 'copy) "cp -f")
3303 ((eq op 'rename) "mv -f")
3304 (t (tramp-error
3305 v 'file-error
3306 "Unknown operation `%s', must be `copy' or `rename'"
3307 op))))
3308 (localname1
3309 (if t1 (tramp-handle-file-remote-p filename 'localname) filename))
3310 (localname2
3311 (if t2 (tramp-handle-file-remote-p newname 'localname) newname))
258800f8 3312 (prefix (file-remote-p (if t1 filename newname))))
8d60099b 3313
8d60099b 3314 (cond
8a4438b6
MA
3315 ;; Both files are on a remote host, with same user.
3316 ((and t1 t2)
3317 (tramp-send-command
3318 v
3319 (format "%s %s %s" cmd
3320 (tramp-shell-quote-argument localname1)
3321 (tramp-shell-quote-argument localname2)))
3322 (with-current-buffer (tramp-get-buffer v)
3323 (goto-char (point-min))
3324 (unless
3325 (or
3326 (and keep-date
3327 ;; Mask cp -f error.
3328 (re-search-forward
3329 tramp-operation-not-permitted-regexp nil t))
3330 (zerop (tramp-send-command-and-check v nil)))
3331 (tramp-error-with-buffer
3332 nil v 'file-error
3333 "Copying directly failed, see buffer `%s' for details."
3334 (buffer-name)))))
3335
3336 ;; We are on the local host.
3337 ((or t1 t2)
8d60099b 3338 (cond
8a4438b6 3339 ;; We can do it directly.
87bdd2c7
MA
3340 ((let (file-name-handler-alist)
3341 (and (file-readable-p localname1)
3342 (file-writable-p (file-name-directory localname2))
3343 (or (file-directory-p localname2)
3344 (file-writable-p localname2))))
8d60099b 3345 (if (eq op 'copy)
9e6ab520
MA
3346 (tramp-compat-copy-file
3347 localname1 localname2 ok-if-already-exists
3348 keep-date preserve-uid-gid)
87bdd2c7
MA
3349 (tramp-run-real-handler
3350 'rename-file (list localname1 localname2 ok-if-already-exists))))
8a4438b6
MA
3351
3352 ;; We can do it directly with `tramp-send-command'
946a5aeb
MA
3353 ((and (file-readable-p (concat prefix localname1))
3354 (file-writable-p
3355 (file-name-directory (concat prefix localname2)))
3356 (or (file-directory-p (concat prefix localname2))
3357 (file-writable-p (concat prefix localname2))))
8a4438b6
MA
3358 (tramp-do-copy-or-rename-file-directly
3359 op (concat prefix localname1) (concat prefix localname2)
3360 ok-if-already-exists keep-date t)
3361 ;; We must change the ownership to the local user.
8d60099b 3362 (tramp-set-file-uid-gid
8a4438b6
MA
3363 (concat prefix localname2)
3364 (tramp-get-local-uid 'integer)
3365 (tramp-get-local-gid 'integer)))
8d60099b 3366
8a4438b6
MA
3367 ;; We need a temporary file in between.
3368 (t
2c418c5b
MA
3369 ;; Create the temporary file.
3370 (let ((tmpfile (tramp-compat-make-temp-file localname1)))
917b89a6 3371 (unwind-protect
2c418c5b
MA
3372 (progn
3373 (cond
3374 (t1
917b89a6
MA
3375 (or
3376 (zerop
3377 (tramp-send-command-and-check
3378 v (format
3379 "%s %s %s" cmd
3380 (tramp-shell-quote-argument localname1)
3381 (tramp-shell-quote-argument tmpfile))))
3382 (tramp-error-with-buffer
3383 nil v 'file-error
3384 "Copying directly failed, see buffer `%s' for details."
3385 (tramp-get-buffer v)))
2c418c5b 3386 ;; We must change the ownership as remote user.
917b89a6
MA
3387 ;; Since this does not work reliable, we also
3388 ;; give read permissions.
3389 (set-file-modes
3390 (concat prefix tmpfile) (tramp-octal-to-decimal "0777"))
2c418c5b
MA
3391 (tramp-set-file-uid-gid
3392 (concat prefix tmpfile)
3393 (tramp-get-local-uid 'integer)
3394 (tramp-get-local-gid 'integer)))
3395 (t2
3396 (if (eq op 'copy)
3397 (tramp-compat-copy-file
5ab38c3c 3398 localname1 tmpfile t
2c418c5b
MA
3399 keep-date preserve-uid-gid)
3400 (tramp-run-real-handler
3401 'rename-file
5ab38c3c 3402 (list localname1 tmpfile t)))
2c418c5b 3403 ;; We must change the ownership as local user.
917b89a6
MA
3404 ;; Since this does not work reliable, we also
3405 ;; give read permissions.
3406 (set-file-modes tmpfile (tramp-octal-to-decimal "0777"))
2c418c5b
MA
3407 (tramp-set-file-uid-gid
3408 tmpfile
3409 (tramp-get-remote-uid v 'integer)
3410 (tramp-get-remote-gid v 'integer))))
3411
3412 ;; Move the temporary file to its destination.
3413 (cond
3414 (t2
917b89a6
MA
3415 (or
3416 (zerop
3417 (tramp-send-command-and-check
3418 v (format
3419 "cp -f -p %s %s"
3420 (tramp-shell-quote-argument tmpfile)
3421 (tramp-shell-quote-argument localname2))))
3422 (tramp-error-with-buffer
3423 nil v 'file-error
3424 "Copying directly failed, see buffer `%s' for details."
3425 (tramp-get-buffer v))))
2c418c5b 3426 (t1
ce2cc728
MA
3427 (tramp-run-real-handler
3428 'rename-file
2c418c5b
MA
3429 (list tmpfile localname2 ok-if-already-exists)))))
3430
917b89a6
MA
3431 ;; Save exit.
3432 (condition-case nil
3433 (delete-file tmpfile)
3434 (error)))))))))
8d60099b
MA
3435
3436 ;; Set the time and mode. Mask possible errors.
8d60099b 3437 (condition-case nil
1f107aed 3438 (when keep-date
4f4126e6
MA
3439 (set-file-times newname file-times)
3440 (set-file-modes newname file-modes))
8d60099b
MA
3441 (error)))))
3442
5ec2cc41 3443(defun tramp-do-copy-or-rename-file-out-of-band (op filename newname keep-date)
7432277c 3444 "Invoke rcp program to copy.
905fb90e 3445The method used must be an out-of-band method."
38c65fca 3446 (let ((t1 (tramp-tramp-file-p filename))
5ec2cc41 3447 (t2 (tramp-tramp-file-p newname))
946a5aeb 3448 copy-program copy-args copy-env copy-keep-date port spec
00d6fd04
MA
3449 source target)
3450
3451 (with-parsed-tramp-file-name (if t1 filename newname) nil
905fb90e 3452 (if (and t1 t2)
00d6fd04 3453
905fb90e
MA
3454 ;; Both are Tramp files. We shall optimize it, when the
3455 ;; methods for filename and newname are the same.
3456 (let ((tmpfile (tramp-compat-make-temp-file localname)))
3457 (unwind-protect
3458 (progn
3459 (tramp-do-copy-or-rename-file-out-of-band
3460 op filename tmpfile keep-date)
3461 (tramp-do-copy-or-rename-file-out-of-band
3462 'rename tmpfile newname keep-date))
3463 ;; Save exit.
3464 (condition-case nil
3465 (delete-file tmpfile)
3466 (error))))
3467
3468 ;; Expand hops. Might be necessary for gateway methods.
3469 (setq v (car (tramp-compute-multi-hops v)))
3470 (aset v 3 localname)
3471
3472 ;; Check which ones of source and target are Tramp files.
3473 (setq source (if t1 (tramp-make-copy-program-file-name v) filename)
3474 target (if t2 (tramp-make-copy-program-file-name v) newname))
3475
3476 ;; Check for port number. Until now, there's no need for handling
3477 ;; like method, user, host.
3478 (setq host (tramp-file-name-real-host v)
3479 port (tramp-file-name-port v)
3480 port (or (and port (number-to-string port)) ""))
3481
3482 ;; Compose copy command.
3483 (setq spec `((?h . ,host) (?u . ,user) (?p . ,port)
3484 (?t . ,(tramp-get-connection-property
3485 (tramp-get-connection-process v) "temp-file" ""))
3486 (?k . ,(if keep-date " " "")))
3487 copy-program (tramp-get-method-parameter
3488 method 'tramp-copy-program)
3489 copy-keep-date (tramp-get-method-parameter
3490 method 'tramp-copy-keep-date)
3491 copy-args
3492 (delq
3493 nil
3494 (mapcar
aa485f7c
MA
3495 (lambda (x)
3496 (setq
3497 x
3498 ;; " " is indication for keep-date argument.
3499 (delete " " (mapcar (lambda (y) (format-spec y spec)) x)))
3500 (unless (member "" x) (mapconcat 'identity x " ")))
946a5aeb
MA
3501 (tramp-get-method-parameter method 'tramp-copy-args)))
3502 copy-env
3503 (delq
3504 nil
3505 (mapcar
aa485f7c
MA
3506 (lambda (x)
3507 (setq x (mapcar (lambda (y) (format-spec y spec)) x))
3508 (unless (member "" x) (mapconcat 'identity x " ")))
946a5aeb 3509 (tramp-get-method-parameter method 'tramp-copy-env))))
905fb90e
MA
3510
3511 ;; Check for program.
3512 (when (and (fboundp 'executable-find)
3513 (not (let ((default-directory
3514 (tramp-compat-temporary-file-directory)))
3515 (executable-find copy-program))))
3516 (tramp-error
3517 v 'file-error "Cannot find copy program: %s" copy-program))
00d6fd04 3518
905fb90e
MA
3519 (unwind-protect
3520 (with-temp-buffer
3521 ;; The default directory must be remote.
3522 (let ((default-directory
946a5aeb
MA
3523 (file-name-directory (if t1 filename newname)))
3524 (process-environment (copy-sequence process-environment)))
905fb90e
MA
3525 ;; Set the transfer process properties.
3526 (tramp-set-connection-property
3527 v "process-name" (buffer-name (current-buffer)))
3528 (tramp-set-connection-property
3529 v "process-buffer" (current-buffer))
946a5aeb
MA
3530 (while copy-env
3531 (tramp-message v 5 "%s=\"%s\"" (car copy-env) (cadr copy-env))
3532 (setenv (pop copy-env) (pop copy-env)))
905fb90e
MA
3533
3534 ;; Use an asynchronous process. By this, password can
3535 ;; be handled. The default directory must be local, in
3536 ;; order to apply the correct `copy-program'. We don't
3537 ;; set a timeout, because the copying of large files can
3538 ;; last longer than 60 secs.
3539 (let ((p (let ((default-directory
3540 (tramp-compat-temporary-file-directory)))
3541 (apply 'start-process
3542 (tramp-get-connection-property
3543 v "process-name" nil)
3544 (tramp-get-connection-property
3545 v "process-buffer" nil)
3546 copy-program
3547 (append copy-args (list source target))))))
3548 (tramp-message
3549 v 6 "%s" (mapconcat 'identity (process-command p) " "))
3550 (tramp-set-process-query-on-exit-flag p nil)
3551 (tramp-process-actions p v tramp-actions-copy-out-of-band))))
00d6fd04 3552
905fb90e
MA
3553 ;; Reset the transfer process properties.
3554 (tramp-set-connection-property v "process-name" nil)
3555 (tramp-set-connection-property v "process-buffer" nil))
00d6fd04 3556
905fb90e
MA
3557 ;; Handle KEEP-DATE argument.
3558 (when (and keep-date (not copy-keep-date))
3559 (set-file-times newname (nth 5 (file-attributes filename))))
01917a18 3560
905fb90e
MA
3561 ;; Set the mode.
3562 (unless (and keep-date copy-keep-date)
3563 (set-file-modes newname (tramp-default-file-modes filename))))
5ec2cc41 3564
905fb90e
MA
3565 ;; If the operation was `rename', delete the original file.
3566 (unless (eq op 'copy)
3567 (delete-file filename)))))
7432277c 3568
fb7933a3 3569(defun tramp-handle-make-directory (dir &optional parents)
00d6fd04 3570 "Like `make-directory' for Tramp files."
ac474af1 3571 (setq dir (expand-file-name dir))
c62c9d08 3572 (with-parsed-tramp-file-name dir nil
b1d06e75
KG
3573 (save-excursion
3574 (tramp-barf-unless-okay
00d6fd04 3575 v
9c13938d 3576 (format "%s %s"
b1d06e75 3577 (if parents "mkdir -p" "mkdir")
7432277c 3578 (tramp-shell-quote-argument localname))
b1d06e75 3579 "Couldn't make directory %s" dir))))
fb7933a3 3580
fb7933a3 3581(defun tramp-handle-delete-directory (directory)
00d6fd04 3582 "Like `delete-directory' for Tramp files."
ac474af1 3583 (setq directory (expand-file-name directory))
c62c9d08 3584 (with-parsed-tramp-file-name directory nil
00d6fd04
MA
3585 (tramp-flush-directory-property v localname)
3586 (unless (zerop (tramp-send-command-and-check
3587 v
cfb5c0db 3588 (format "rmdir %s" (tramp-shell-quote-argument localname))))
00d6fd04 3589 (tramp-error v 'file-error "Couldn't delete %s" directory))))
fb7933a3
KG
3590
3591(defun tramp-handle-delete-file (filename)
00d6fd04 3592 "Like `delete-file' for Tramp files."
ac474af1 3593 (setq filename (expand-file-name filename))
c62c9d08 3594 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3595 (tramp-flush-file-property v localname)
3596 (unless (zerop (tramp-send-command-and-check
3597 v
3598 (format "rm -f %s"
3599 (tramp-shell-quote-argument localname))))
3600 (tramp-error v 'file-error "Couldn't delete %s" filename))))
fb7933a3
KG
3601
3602;; Dired.
3603
3604;; CCC: This does not seem to be enough. Something dies when
a4aeb9a4 3605;; we try and delete two directories under Tramp :/
fb7933a3
KG
3606(defun tramp-handle-dired-recursive-delete-directory (filename)
3607 "Recursively delete the directory given.
00d6fd04 3608This is like `dired-recursive-delete-directory' for Tramp files."
c62c9d08 3609 (with-parsed-tramp-file-name filename nil
260821d3 3610 (tramp-flush-directory-property v localname)
00d6fd04 3611 ;; Run a shell command 'rm -r <localname>'
260821d3 3612 ;; Code shamelessly stolen from the dired implementation and, um, hacked :)
00d6fd04
MA
3613 (unless (file-exists-p filename)
3614 (tramp-error v 'file-error "No such directory: %s" filename))
fb7933a3 3615 ;; Which is better, -r or -R? (-r works for me <daniel@danann.net>)
00d6fd04
MA
3616 (tramp-send-command
3617 v
9c13938d 3618 (format "rm -rf %s" (tramp-shell-quote-argument localname))
00d6fd04
MA
3619 ;; Don't read the output, do it explicitely.
3620 nil t)
fb7933a3
KG
3621 ;; Wait for the remote system to return to us...
3622 ;; This might take a while, allow it plenty of time.
00d6fd04 3623 (tramp-wait-for-output (tramp-get-connection-process v) 120)
fb7933a3 3624 ;; Make sure that it worked...
07dfe738 3625 (and (file-exists-p filename)
00d6fd04
MA
3626 (tramp-error
3627 v 'file-error "Failed to recursively delete %s" filename))))
bf247b6e 3628
5ec2cc41 3629(defun tramp-handle-dired-compress-file (file &rest ok-flag)
00d6fd04 3630 "Like `dired-compress-file' for Tramp files."
5ec2cc41
KG
3631 ;; OK-FLAG is valid for XEmacs only, but not implemented.
3632 ;; Code stolen mainly from dired-aux.el.
3633 (with-parsed-tramp-file-name file nil
00d6fd04 3634 (tramp-flush-file-property v localname)
5ec2cc41
KG
3635 (save-excursion
3636 (let ((suffixes
3637 (if (not (featurep 'xemacs))
3638 ;; Emacs case
3639 (symbol-value 'dired-compress-file-suffixes)
3640 ;; XEmacs has `dired-compression-method-alist', which is
3641 ;; transformed into `dired-compress-file-suffixes' structure.
3642 (mapcar
aa485f7c
MA
3643 (lambda (x)
3644 (list (concat (regexp-quote (nth 1 x)) "\\'")
3645 nil
3646 (mapconcat 'identity (nth 3 x) " ")))
5ec2cc41
KG
3647 (symbol-value 'dired-compression-method-alist))))
3648 suffix)
3649 ;; See if any suffix rule matches this file name.
3650 (while suffixes
3651 (let (case-fold-search)
3652 (if (string-match (car (car suffixes)) localname)
3653 (setq suffix (car suffixes) suffixes nil))
3654 (setq suffixes (cdr suffixes))))
3655
3656 (cond ((file-symlink-p file)
3657 nil)
3658 ((and suffix (nth 2 suffix))
3659 ;; We found an uncompression rule.
00d6fd04 3660 (tramp-message v 0 "Uncompressing %s..." file)
5ec2cc41 3661 (when (zerop (tramp-send-command-and-check
00d6fd04
MA
3662 v (concat (nth 2 suffix) " " localname)))
3663 (tramp-message v 0 "Uncompressing %s...done" file)
38c65fca
KG
3664 ;; `dired-remove-file' is not defined in XEmacs
3665 (funcall (symbol-function 'dired-remove-file) file)
5ec2cc41
KG
3666 (string-match (car suffix) file)
3667 (concat (substring file 0 (match-beginning 0)))))
3668 (t
3669 ;; We don't recognize the file as compressed, so compress it.
3670 ;; Try gzip.
00d6fd04 3671 (tramp-message v 0 "Compressing %s..." file)
5ec2cc41 3672 (when (zerop (tramp-send-command-and-check
00d6fd04
MA
3673 v (concat "gzip -f " localname)))
3674 (tramp-message v 0 "Compressing %s...done" file)
38c65fca
KG
3675 ;; `dired-remove-file' is not defined in XEmacs
3676 (funcall (symbol-function 'dired-remove-file) file)
5ec2cc41
KG
3677 (cond ((file-exists-p (concat file ".gz"))
3678 (concat file ".gz"))
3679 ((file-exists-p (concat file ".z"))
3680 (concat file ".z"))
3681 (t nil)))))))))
fb7933a3 3682
70c11b0b
MA
3683(defun tramp-handle-dired-uncache (dir)
3684 "Like `dired-uncache' for Tramp files."
3685 (with-parsed-tramp-file-name dir nil
3686 (tramp-flush-file-property v localname)))
3687
fb7933a3
KG
3688;; Pacify byte-compiler. The function is needed on XEmacs only. I'm
3689;; not sure at all that this is the right way to do it, but let's hope
3690;; it works for now, and wait for a guru to point out the Right Way to
3691;; achieve this.
3692;;(eval-when-compile
3693;; (unless (fboundp 'dired-insert-set-properties)
3694;; (fset 'dired-insert-set-properties 'ignore)))
3695;; Gerd suggests this:
3696(eval-when-compile (require 'dired))
3697;; Note that dired is required at run-time, too, when it is needed.
3698;; It is only needed on XEmacs for the function
3699;; `dired-insert-set-properties'.
3700
3701(defun tramp-handle-insert-directory
3702 (filename switches &optional wildcard full-directory-p)
00d6fd04
MA
3703 "Like `insert-directory' for Tramp files."
3704 (setq filename (expand-file-name filename))
3705 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3706 (if (and (featurep 'ls-lisp)
3707 (not (symbol-value 'ls-lisp-use-insert-directory-program)))
3708 (tramp-run-real-handler
3709 'insert-directory (list filename switches wildcard full-directory-p))
8e754ea2
MA
3710 (when (and (string-match "^--dired\\s-+" switches)
3711 (not (tramp-get-ls-command-with-dired v)))
00d6fd04
MA
3712 (setq switches (replace-match "" nil t switches)))
3713 (tramp-message
3714 v 4 "Inserting directory `ls %s %s', wildcard %s, fulldir %s"
c82c5727
LH
3715 switches filename (if wildcard "yes" "no")
3716 (if full-directory-p "yes" "no"))
3717 (when wildcard
87bdd2c7
MA
3718 (setq wildcard (tramp-run-real-handler
3719 'file-name-nondirectory (list localname)))
3720 (setq localname (tramp-run-real-handler
3721 'file-name-directory (list localname))))
c82c5727
LH
3722 (when (listp switches)
3723 (setq switches (mapconcat 'identity switches " ")))
3724 (unless full-directory-p
3725 (setq switches (concat "-d " switches)))
3726 (when wildcard
3727 (setq switches (concat switches " " wildcard)))
00d6fd04
MA
3728 ;; If `full-directory-p', we just say `ls -l FILENAME'.
3729 ;; Else we chdir to the parent directory, then say `ls -ld BASENAME'.
3730 (if full-directory-p
3731 (tramp-send-command
3732 v
3733 (format "%s %s %s"
3734 (tramp-get-ls-command v)
3735 switches
3736 (if wildcard
3737 localname
3738 (tramp-shell-quote-argument (concat localname ".")))))
3739 (tramp-barf-unless-okay
3740 v
3741 (format "cd %s" (tramp-shell-quote-argument
87bdd2c7
MA
3742 (tramp-run-real-handler
3743 'file-name-directory (list localname))))
00d6fd04 3744 "Couldn't `cd %s'"
87bdd2c7
MA
3745 (tramp-shell-quote-argument
3746 (tramp-run-real-handler 'file-name-directory (list localname))))
00d6fd04
MA
3747 (tramp-send-command
3748 v
3749 (format "%s %s %s"
3750 (tramp-get-ls-command v)
3751 switches
3752 (if (or wildcard
87bdd2c7
MA
3753 (zerop (length
3754 (tramp-run-real-handler
3755 'file-name-nondirectory (list localname)))))
00d6fd04
MA
3756 ""
3757 (tramp-shell-quote-argument
87bdd2c7
MA
3758 (tramp-run-real-handler
3759 'file-name-nondirectory (list localname)))))))
8e754ea2
MA
3760 (let ((beg (point)))
3761 ;; We cannot use `insert-buffer-substring' because the Tramp
3762 ;; buffer changes its contents before insertion due to calling
3763 ;; `expand-file' and alike.
3764 (insert
3765 (with-current-buffer (tramp-get-buffer v)
3766 (buffer-string)))
3767
3768 ;; Check for "--dired" output.
3769 (goto-char (point-max))
3770 (forward-line -2)
3771 (when (looking-at "//DIRED//")
3772 (let ((end (line-end-position))
3773 (linebeg (point)))
3774 ;; Now read the numeric positions of file names.
3775 (goto-char linebeg)
3776 (forward-word 1)
3777 (forward-char 3)
3778 (while (< (point) end)
3779 (let ((start (+ beg (read (current-buffer))))
3780 (end (+ beg (read (current-buffer)))))
3781 (if (memq (char-after end) '(?\n ?\s))
3782 ;; End is followed by \n or by " -> ".
3783 (put-text-property start end 'dired-filename t)))))
3784 ;; Reove training lines.
3785 (goto-char (point-max))
3786 (forward-line -1)
3787 (while (looking-at "//")
3788 (forward-line 1)
3789 (delete-region (match-beginning 0) (point))
3790 (forward-line -1))))
3791 (goto-char (point-max)))))
fb7933a3 3792
fb7933a3 3793(defun tramp-handle-unhandled-file-name-directory (filename)
00d6fd04 3794 "Like `unhandled-file-name-directory' for Tramp files."
8a798e41
MA
3795 ;; With Emacs 23, we could simply return `nil'. But we must keep it
3796 ;; for backward compatibility.
ce3f516f 3797 (expand-file-name "~/"))
fb7933a3
KG
3798
3799;; Canonicalization of file names.
3800
fb7933a3 3801(defun tramp-handle-expand-file-name (name &optional dir)
00d6fd04 3802 "Like `expand-file-name' for Tramp files.
7432277c
KG
3803If the localname part of the given filename starts with \"/../\" then
3804the result will be a local, non-Tramp, filename."
fb7933a3
KG
3805 ;; If DIR is not given, use DEFAULT-DIRECTORY or "/".
3806 (setq dir (or dir default-directory "/"))
3807 ;; Unless NAME is absolute, concat DIR and NAME.
3808 (unless (file-name-absolute-p name)
3809 (setq name (concat (file-name-as-directory dir) name)))
00d6fd04 3810 ;; If NAME is not a Tramp file, run the real handler.
fb7933a3 3811 (if (not (tramp-tramp-file-p name))
00d6fd04 3812 (tramp-run-real-handler 'expand-file-name (list name nil))
fb7933a3 3813 ;; Dissect NAME.
c62c9d08 3814 (with-parsed-tramp-file-name name nil
87bdd2c7 3815 (unless (tramp-run-real-handler 'file-name-absolute-p (list localname))
7432277c 3816 (setq localname (concat "~/" localname)))
00d6fd04
MA
3817 ;; Tilde expansion if necessary. This needs a shell which
3818 ;; groks tilde expansion! The function `tramp-find-shell' is
3819 ;; supposed to find such a shell on the remote host. Please
3820 ;; tell me about it when this doesn't work on your system.
3821 (when (string-match "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname)
3822 (let ((uname (match-string 1 localname))
3823 (fname (match-string 2 localname)))
3824 ;; We cannot simply apply "~/", because under sudo "~/" is
3825 ;; expanded to the local user home directory but to the
3826 ;; root home directory. On the other hand, using always
3827 ;; the default user name for tilde expansion is not
3828 ;; appropriate either, because ssh and companions might
3829 ;; use a user name from the config file.
3830 (when (and (string-equal uname "~")
3831 (string-match "\\`su\\(do\\)?\\'" method))
3832 (setq uname (concat uname user)))
3833 (setq uname
3834 (with-connection-property v uname
3835 (tramp-send-command v (format "cd %s; pwd" uname))
3836 (with-current-buffer (tramp-get-buffer v)
3837 (goto-char (point-min))
9e6ab520 3838 (buffer-substring (point) (tramp-compat-line-end-position)))))
00d6fd04
MA
3839 (setq localname (concat uname fname))))
3840 ;; There might be a double slash, for example when "~/"
cb85dcd0 3841 ;; expands to "/". Remove this.
00d6fd04
MA
3842 (while (string-match "//" localname)
3843 (setq localname (replace-match "/" t t localname)))
3844 ;; No tilde characters in file name, do normal
3845 ;; expand-file-name (this does "/./" and "/../"). We bind
3846 ;; `directory-sep-char' here for XEmacs on Windows, which
3847 ;; would otherwise use backslash. `default-directory' is
3848 ;; bound, because on Windows there would be problems with UNC
3849 ;; shares or Cygwin mounts.
aff67808
MA
3850 (let ((directory-sep-char ?/)
3851 (default-directory (tramp-compat-temporary-file-directory)))
3852 (tramp-make-tramp-file-name
3853 method user host
3854 (tramp-drop-volume-letter
87bdd2c7
MA
3855 (tramp-run-real-handler
3856 'expand-file-name (list localname))))))))
00d6fd04 3857
c23c3394
MA
3858(defun tramp-replace-environment-variables (filename)
3859 "Replace environment variables in FILENAME.
3860Return the string with the replaced variables."
2e271195
MA
3861 (save-match-data
3862 (let ((idx (string-match "$\\w+" filename)))
3863 ;; `$' is coded as `$$'.
3864 (when (and idx (or (zerop idx) (not (eq ?$ (aref filename (1- idx))))))
3865 (setq filename
3866 (replace-match
3867 (substitute-in-file-name (match-string 0 filename))
3868 t nil filename)))
3869 filename)))
c23c3394 3870
00d6fd04
MA
3871(defun tramp-handle-substitute-in-file-name (filename)
3872 "Like `substitute-in-file-name' for Tramp files.
3873\"//\" and \"/~\" substitute only in the local filename part.
3874If the URL Tramp syntax is chosen, \"//\" as method delimeter and \"/~\" at
3875beginning of local filename are not substituted."
c23c3394
MA
3876 ;; First, we must replace environment variables.
3877 (setq filename (tramp-replace-environment-variables filename))
00d6fd04
MA
3878 (with-parsed-tramp-file-name filename nil
3879 (if (equal tramp-syntax 'url)
3880 ;; We need to check localname only. The other parts cannot contain
3881 ;; "//" or "/~".
3882 (if (and (> (length localname) 1)
3883 (or (string-match "//" localname)
3884 (string-match "/~" localname 1)))
3885 (tramp-run-real-handler 'substitute-in-file-name (list filename))
3886 (tramp-make-tramp-file-name
3887 (when method (substitute-in-file-name method))
3888 (when user (substitute-in-file-name user))
3889 (when host (substitute-in-file-name host))
87bdd2c7
MA
3890 (when localname
3891 (tramp-run-real-handler
3892 'substitute-in-file-name (list localname)))))
00d6fd04
MA
3893 ;; Ignore in LOCALNAME everything before "//" or "/~".
3894 (when (and (stringp localname) (string-match ".+?/\\(/\\|~\\)" localname))
3895 (setq filename
b08104a0
MA
3896 (concat (file-remote-p filename)
3897 (replace-match "\\1" nil nil localname)))
00d6fd04
MA
3898 ;; "/m:h:~" does not work for completion. We use "/m:h:~/".
3899 (when (string-match "~$" filename)
3900 (setq filename (concat filename "/"))))
3901 (tramp-run-real-handler 'substitute-in-file-name (list filename)))))
3902
3903;; In XEmacs, electricity is implemented via a key map for ?/ and ?~,
3904;; which calls corresponding functions (see minibuf.el).
3905(when (fboundp 'minibuffer-electric-separator)
9e6ab520 3906 (mapc
aa485f7c
MA
3907 (lambda (x)
3908 (eval
3909 `(defadvice ,x
3910 (around ,(intern (format "tramp-advice-%s" x)) activate)
3911 "Invoke `substitute-in-file-name' for Tramp files."
3912 (if (and (symbol-value 'minibuffer-electric-file-name-behavior)
3913 (tramp-tramp-file-p (buffer-substring)))
3914 ;; We don't need to handle `last-input-event', because
3915 ;; due to the key map we know it must be ?/ or ?~.
3916 (let ((s (concat (buffer-substring (point-min) (point))
3917 (string last-command-char))))
3918 (delete-region (point-min) (point))
3919 (insert (substitute-in-file-name s))
3920 (setq ad-return-value last-command-char))
3921 ad-do-it))))
00d6fd04
MA
3922
3923 '(minibuffer-electric-separator
3924 minibuffer-electric-tilde)))
3925
3926
0664ff72 3927;;; Remote commands:
fb7933a3 3928
00d6fd04
MA
3929(defun tramp-handle-executable-find (command)
3930 "Like `executable-find' for Tramp files."
3931 (with-parsed-tramp-file-name default-directory nil
f84638eb 3932 (tramp-find-executable v command (tramp-get-remote-path v) t)))
00d6fd04
MA
3933
3934;; We use BUFFER also as connection buffer during setup. Because of
3935;; this, its original contents must be saved, and restored once
3936;; connection has been setup.
3937(defun tramp-handle-start-file-process (name buffer program &rest args)
3938 "Like `start-file-process' for Tramp files."
3939 (with-parsed-tramp-file-name default-directory nil
3940 (unwind-protect
38d63e6a
MA
3941 (let ((name1 name)
3942 (i 0))
2296b54d 3943 (unless buffer
6ce63faf 3944 ;; BUFFER can be nil. We use a temporary buffer.
2296b54d 3945 (setq buffer (generate-new-buffer tramp-temp-buffer-name)))
38d63e6a
MA
3946 (while (get-process name1)
3947 ;; NAME must be unique as process name.
3948 (setq i (1+ i)
3949 name1 (format "%s<%d>" name i)))
3950 (setq name name1)
00d6fd04
MA
3951 ;; Set the new process properties.
3952 (tramp-set-connection-property v "process-name" name)
2296b54d 3953 (tramp-set-connection-property v "process-buffer" buffer)
00d6fd04 3954 ;; Activate narrowing in order to save BUFFER contents.
11c71217
MA
3955 ;; Clear also the modification time; otherwise we might be
3956 ;; interrupted by `verify-visited-file-modtime'.
00d6fd04 3957 (with-current-buffer (tramp-get-connection-buffer v)
11c71217 3958 (clear-visited-file-modtime)
00d6fd04
MA
3959 (narrow-to-region (point-max) (point-max)))
3960 ;; Goto working directory. `tramp-send-command' opens a new
3961 ;; connection.
3962 (tramp-send-command
3963 v (format "cd %s" (tramp-shell-quote-argument localname)))
3964 ;; Send the command.
3965 (tramp-send-command
3966 v
2296b54d 3967 (format "exec %s"
00d6fd04 3968 (mapconcat 'tramp-shell-quote-argument
2296b54d 3969 (cons program args) " "))
00d6fd04 3970 nil t) ; nooutput
6ce63faf
MA
3971 ;; Set query flag for this process.
3972 (tramp-set-process-query-on-exit-flag
3973 (tramp-get-connection-process v) t)
00d6fd04
MA
3974 ;; Return process.
3975 (tramp-get-connection-process v))
3976 ;; Save exit.
ce3f516f 3977 (with-current-buffer (tramp-get-connection-buffer v)
6ce63faf
MA
3978 (if (string-match tramp-temp-buffer-name (buffer-name))
3979 (progn
3980 (set-process-buffer (tramp-get-connection-process v) nil)
3981 (kill-buffer (current-buffer)))
3982 (widen)
3983 (goto-char (point-max))))
00d6fd04
MA
3984 (tramp-set-connection-property v "process-name" nil)
3985 (tramp-set-connection-property v "process-buffer" nil))))
3986
3987(defun tramp-handle-process-file
3988 (program &optional infile destination display &rest args)
3989 "Like `process-file' for Tramp files."
3990 ;; The implementation is not complete yet.
3991 (when (and (numberp destination) (zerop destination))
3992 (error "Implementation does not handle immediate return"))
3993
3994 (with-parsed-tramp-file-name default-directory nil
a6e96327 3995 (let (command input tmpinput stderr tmpstderr outbuf ret)
00d6fd04
MA
3996 ;; Compute command.
3997 (setq command (mapconcat 'tramp-shell-quote-argument
3998 (cons program args) " "))
3999 ;; Determine input.
4000 (if (null infile)
4001 (setq input "/dev/null")
4002 (setq infile (expand-file-name infile))
4003 (if (tramp-equal-remote default-directory infile)
4004 ;; INFILE is on the same remote host.
4005 (setq input (with-parsed-tramp-file-name infile nil localname))
4006 ;; INFILE must be copied to remote host.
a6e96327
MA
4007 (setq input (tramp-make-tramp-temp-file v)
4008 tmpinput (tramp-make-tramp-file-name method user host input))
4009 (copy-file infile tmpinput t)))
00d6fd04
MA
4010 (when input (setq command (format "%s <%s" command input)))
4011
4012 ;; Determine output.
4013 (cond
bede3e9f 4014 ;; Just a buffer.
00d6fd04
MA
4015 ((bufferp destination)
4016 (setq outbuf destination))
bede3e9f 4017 ;; A buffer name.
00d6fd04
MA
4018 ((stringp destination)
4019 (setq outbuf (get-buffer-create destination)))
4020 ;; (REAL-DESTINATION ERROR-DESTINATION)
4021 ((consp destination)
bede3e9f 4022 ;; output.
00d6fd04
MA
4023 (cond
4024 ((bufferp (car destination))
4025 (setq outbuf (car destination)))
4026 ((stringp (car destination))
0664ff72
MA
4027 (setq outbuf (get-buffer-create (car destination))))
4028 ((car destination)
4029 (setq outbuf (current-buffer))))
bede3e9f 4030 ;; stderr.
00d6fd04
MA
4031 (cond
4032 ((stringp (cadr destination))
4033 (setcar (cdr destination) (expand-file-name (cadr destination)))
4034 (if (tramp-equal-remote default-directory (cadr destination))
4035 ;; stderr is on the same remote host.
4036 (setq stderr (with-parsed-tramp-file-name
4037 (cadr destination) nil localname))
4038 ;; stderr must be copied to remote host. The temporary
4039 ;; file must be deleted after execution.
a6e96327
MA
4040 (setq stderr (tramp-make-tramp-temp-file v)
4041 tmpstderr (tramp-make-tramp-file-name
4042 method user host stderr))))
bede3e9f 4043 ;; stderr to be discarded.
00d6fd04
MA
4044 ((null (cadr destination))
4045 (setq stderr "/dev/null"))))
4046 ;; 't
4047 (destination
4048 (setq outbuf (current-buffer))))
4049 (when stderr (setq command (format "%s 2>%s" command stderr)))
4050
00d6fd04
MA
4051 ;; Goto working directory.
4052 (tramp-send-command
4053 v (format "cd %s" (tramp-shell-quote-argument localname)))
4054 ;; Send the command. It might not return in time, so we protect it.
4055 (condition-case nil
4056 (unwind-protect
4057 (tramp-send-command v command)
4058 ;; We should show the output anyway.
4059 (when outbuf
27e813fe
MA
4060 (let ((output-string
4061 (with-current-buffer (tramp-get-connection-buffer v)
4062 (buffer-substring (point-min) (point-max)))))
4063 (with-current-buffer outbuf
4064 (insert output-string)))
00d6fd04 4065 (when display (display-buffer outbuf))))
260821d3
MA
4066 ;; When the user did interrupt, we should do it also. We use
4067 ;; return code -1 as marker.
4068 (quit
4069 (kill-buffer (tramp-get-connection-buffer v))
4070 (setq ret -1))
4071 ;; Handle errors.
00d6fd04
MA
4072 (error
4073 (kill-buffer (tramp-get-connection-buffer v))
4074 (setq ret 1)))
a6e96327
MA
4075
4076 ;; Check return code.
4077 (unless ret (setq ret (tramp-send-command-and-check v nil)))
4078 ;; Provide error file.
4079 (when tmpstderr (rename-file tmpstderr (cadr destination) t))
260821d3
MA
4080 ;; Cleanup. We remove all file cache values for the connection,
4081 ;; because the remote process could have changed them.
a6e96327 4082 (when tmpinput (delete-file tmpinput))
946a5aeb
MA
4083
4084 ;; `process-file-side-effects' has been introduced with GNU
4085 ;; Emacs 23.2. If set to `nil', no remote file will be changed
4086 ;; by `program'. If it doesn't exist, we assume its default
4087 ;; value 't'.
4088 (unless (and (boundp 'process-file-side-effects)
4089 (not (symbol-value 'process-file-side-effects)))
4090 (tramp-flush-directory-property v ""))
4091
00d6fd04 4092 ;; Return exit status.
260821d3
MA
4093 (if (equal ret -1)
4094 (keyboard-quit)
4095 ret))))
00d6fd04 4096
a4aeb9a4
MA
4097(defun tramp-local-call-process
4098 (program &optional infile destination display &rest args)
4099 "Calls `call-process' on the local host.
4100This is needed because for some Emacs flavors Tramp has
4101defadviced `call-process' to behave like `process-file'. The
4102Lisp error raised when PROGRAM is nil is trapped also, returning 1."
4103 (let ((default-directory
4104 (if (file-remote-p default-directory)
4105 (tramp-compat-temporary-file-directory)
4106 default-directory)))
4107 (if (executable-find program)
4108 (apply 'call-process program infile destination display args)
4109 1)))
4110
00d6fd04
MA
4111(defun tramp-handle-call-process-region
4112 (start end program &optional delete buffer display &rest args)
4113 "Like `call-process-region' for Tramp files."
258800f8 4114 (let ((tmpfile (tramp-compat-make-temp-file "")))
00d6fd04
MA
4115 (write-region start end tmpfile)
4116 (when delete (delete-region start end))
4117 (unwind-protect
4118 (apply 'call-process program tmpfile buffer display args)
4119 (delete-file tmpfile))))
4120
4121(defun tramp-handle-shell-command
4122 (command &optional output-buffer error-buffer)
4123 "Like `shell-command' for Tramp files."
ce3f516f 4124 (let* ((asynchronous (string-match "[ \t]*&[ \t]*\\'" command))
b8bfcf96
MA
4125 ;; We cannot use `shell-file-name' and `shell-command-switch',
4126 ;; they are variables of the local host.
4127 (args (list "/bin/sh" "-c" (substring command 0 asynchronous)))
5d2ebd96 4128 current-buffer-p
ce3f516f 4129 (output-buffer
27e813fe
MA
4130 (cond
4131 ((bufferp output-buffer) output-buffer)
4132 ((stringp output-buffer) (get-buffer-create output-buffer))
5d2ebd96
AS
4133 (output-buffer
4134 (setq current-buffer-p t)
4135 (current-buffer))
42bc9b6d 4136 (t (get-buffer-create
27e813fe
MA
4137 (if asynchronous
4138 "*Async Shell Command*"
4139 "*Shell Command Output*")))))
4140 (error-buffer
4141 (cond
4142 ((bufferp error-buffer) error-buffer)
4143 ((stringp error-buffer) (get-buffer-create error-buffer))))
ce3f516f 4144 (buffer
27e813fe 4145 (if (and (not asynchronous) error-buffer)
ce3f516f
MA
4146 (with-parsed-tramp-file-name default-directory nil
4147 (list output-buffer (tramp-make-tramp-temp-file v)))
42bc9b6d 4148 output-buffer))
cfb5c0db 4149 (p (get-buffer-process output-buffer)))
42bc9b6d
MA
4150
4151 ;; Check whether there is another process running. Tramp does not
4152 ;; support 2 (asynchronous) processes in parallel.
cfb5c0db 4153 (when p
42bc9b6d 4154 (if (yes-or-no-p "A command is running. Kill it? ")
699a11fb
GM
4155 (condition-case nil
4156 (kill-process p)
4157 (error nil))
42bc9b6d
MA
4158 (error "Shell command in progress")))
4159
f34db316
AS
4160 (if current-buffer-p
4161 (progn
4162 (barf-if-buffer-read-only)
4163 (push-mark nil t))
5d2ebd96
AS
4164 (with-current-buffer output-buffer
4165 (setq buffer-read-only nil)
4166 (erase-buffer)))
42bc9b6d 4167
5d2ebd96 4168 (if (and (not current-buffer-p) (integerp asynchronous))
42bc9b6d
MA
4169 (prog1
4170 ;; Run the process.
3412f35d 4171 (apply 'start-file-process "*Async Shell*" buffer args)
42bc9b6d 4172 ;; Display output.
cfb5c0db
MA
4173 (pop-to-buffer output-buffer)
4174 (setq mode-line-process '(":%s"))
4175 (require 'shell) (shell-mode))
42bc9b6d
MA
4176
4177 (prog1
4178 ;; Run the process.
4179 (apply 'process-file (car args) nil buffer nil (cdr args))
4180 ;; Insert error messages if they were separated.
4181 (when (listp buffer)
4182 (with-current-buffer error-buffer
4183 (insert-file-contents (cadr buffer)))
4184 (delete-file (cadr buffer)))
f34db316
AS
4185 (if current-buffer-p
4186 ;; This is like exchange-point-and-mark, but doesn't
4187 ;; activate the mark. It is cleaner to avoid activation,
4188 ;; even though the command loop would deactivate the mark
4189 ;; because we inserted text.
4190 (goto-char (prog1 (mark t)
4191 (set-marker (mark-marker) (point)
4192 (current-buffer))))
4193 ;; There's some output, display it.
4194 (when (with-current-buffer output-buffer (> (point-max) (point-min)))
4195 (if (functionp 'display-message-or-buffer)
4196 (funcall (symbol-function 'display-message-or-buffer)
4197 output-buffer)
4198 (pop-to-buffer output-buffer))))))))
00d6fd04
MA
4199
4200;; File Editing.
4201
4202(defvar tramp-handle-file-local-copy-hook nil
4203 "Normal hook to be run at the end of `tramp-handle-file-local-copy'.")
4204
fb7933a3 4205(defun tramp-handle-file-local-copy (filename)
00d6fd04 4206 "Like `file-local-copy' for Tramp files."
0f205eee 4207
c62c9d08 4208 (with-parsed-tramp-file-name filename nil
2988341a
MA
4209 (unless (file-exists-p filename)
4210 (tramp-error
4211 v 'file-error
4212 "Cannot make local copy of non-existing file `%s'" filename))
4213
0f205eee 4214 (let ((rem-enc (tramp-get-remote-coding v "remote-encoding"))
00d6fd04 4215 (loc-dec (tramp-get-local-coding v "local-decoding"))
258800f8 4216 (tmpfile (tramp-compat-make-temp-file filename)))
5ec2cc41 4217
2988341a
MA
4218 (condition-case err
4219 (cond
4220 ;; `copy-file' handles direct copy and out-of-band methods.
4221 ((or (tramp-local-host-p v)
4222 (and (tramp-method-out-of-band-p v)
4223 (> (nth 7 (file-attributes filename))
4224 tramp-copy-size-limit)))
4225 (copy-file filename tmpfile t t))
4226
4227 ;; Use inline encoding for file transfer.
4228 (rem-enc
4229 (save-excursion
4230 (tramp-message v 5 "Encoding remote file %s..." filename)
4231 (tramp-barf-unless-okay
4232 v
4233 (format "%s < %s" rem-enc (tramp-shell-quote-argument localname))
4234 "Encoding remote file failed")
4235 (tramp-message v 5 "Encoding remote file %s...done" filename)
4236
4237 (if (and (symbolp loc-dec) (fboundp loc-dec))
4238 ;; If local decoding is a function, we call it. We
4239 ;; must disable multibyte, because
4240 ;; `uudecode-decode-region' doesn't handle it
4241 ;; correctly.
0f205eee
MA
4242 (with-temp-buffer
4243 (set-buffer-multibyte nil)
4244 (insert-buffer-substring (tramp-get-buffer v))
4245 (tramp-message
4246 v 5 "Decoding remote file %s with function %s..."
4247 filename loc-dec)
4248 (funcall loc-dec (point-min) (point-max))
aa485f7c
MA
4249 ;; Unset `file-name-handler-alist'. Otherwise,
4250 ;; epa-file gets confused.
4251 (let (file-name-handler-alist
4252 (coding-system-for-write 'binary))
2988341a
MA
4253 (write-region (point-min) (point-max) tmpfile)))
4254
4255 ;; If tramp-decoding-function is not defined for this
4256 ;; method, we invoke tramp-decoding-command instead.
4257 (let ((tmpfile2 (tramp-compat-make-temp-file filename)))
aa485f7c
MA
4258 ;; Unset `file-name-handler-alist'. Otherwise,
4259 ;; epa-file gets confused.
4260 (let (file-name-handler-alist
4261 (coding-system-for-write 'binary))
2988341a
MA
4262 (write-region (point-min) (point-max) tmpfile2))
4263 (tramp-message
4264 v 5 "Decoding remote file %s with command %s..."
4265 filename loc-dec)
4266 (unwind-protect
4267 (tramp-call-local-coding-command loc-dec tmpfile2 tmpfile)
4268 (delete-file tmpfile2))))
4269
4270 (tramp-message v 5 "Decoding remote file %s...done" filename)
4271 ;; Set proper permissions.
b86c1cd8 4272 (set-file-modes tmpfile (tramp-default-file-modes filename))
2988341a
MA
4273 ;; Set local user ownership.
4274 (tramp-set-file-uid-gid tmpfile)))
4275
4276 ;; Oops, I don't know what to do.
4277 (t (tramp-error
4278 v 'file-error "Wrong method specification for `%s'" method)))
4279
4280 ;; Error handling.
4281 ((error quit)
4282 (delete-file tmpfile)
4283 (signal (car err) (cdr err))))
0f205eee 4284
00d6fd04 4285 (run-hooks 'tramp-handle-file-local-copy-hook)
94be87e8 4286 tmpfile)))
fb7933a3 4287
bce04fee 4288(defun tramp-handle-file-remote-p (filename &optional identification connected)
00d6fd04 4289 "Like `file-remote-p' for Tramp files."
15cc764c
KG
4290 (when (tramp-tramp-file-p filename)
4291 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
4292 (and (or (not connected)
4293 (let ((p (tramp-get-connection-process v)))
4294 (and p (processp p) (memq (process-status p) '(run open)))))
ce3f516f
MA
4295 (cond
4296 ((eq identification 'method) method)
4297 ((eq identification 'user) user)
4298 ((eq identification 'host) host)
8d60099b 4299 ((eq identification 'localname) localname)
ce3f516f 4300 (t (tramp-make-tramp-file-name method user host "")))))))
fb7933a3 4301
eb562962
MA
4302(defun tramp-find-file-name-coding-system-alist (filename tmpname)
4303 "Like `find-operation-coding-system' for Tramp filenames.
4304Tramp's `insert-file-contents' and `write-region' work over
4305temporary file names. If `file-coding-system-alist' contains an
4306expression, which matches more than the file name suffix, the
4307coding system might not be determined. This function repairs it."
4308 (let (result)
4309 (dolist (elt file-coding-system-alist result)
4310 (when (and (consp elt) (string-match (car elt) filename))
4311 ;; We found a matching entry in `file-coding-system-alist'.
4312 ;; So we add a similar entry, but with the temporary file name
4313 ;; as regexp.
4314 (add-to-list
4315 'result (cons (regexp-quote tmpname) (cdr elt)) 'append)))))
4316
fb7933a3
KG
4317(defun tramp-handle-insert-file-contents
4318 (filename &optional visit beg end replace)
00d6fd04 4319 "Like `insert-file-contents' for Tramp files."
fb7933a3
KG
4320 (barf-if-buffer-read-only)
4321 (setq filename (expand-file-name filename))
736ac90f 4322 (let (coding-system-used result local-copy remote-copy)
2ac33804
MA
4323 (with-parsed-tramp-file-name filename nil
4324 (unwind-protect
70c11b0b
MA
4325 (if (not (file-exists-p filename))
4326 ;; We don't raise a Tramp error, because it might be
4327 ;; suppressed, like in `find-file-noselect-1'.
4328 (signal 'file-error
4329 (list "File not found on remote host" filename))
4330
4331 (if (and (tramp-local-host-p v)
4332 (let (file-name-handler-alist)
4333 (file-readable-p localname)))
4334 ;; Short track: if we are on the local host, we can
4335 ;; run directly.
4336 (setq result
4337 (tramp-run-real-handler
4338 'insert-file-contents
4339 (list localname visit beg end replace)))
4340
736ac90f
MA
4341 ;; When we shall insert only a part of the file, we copy
4342 ;; this part.
4343 (when (or beg end)
4344 (setq remote-copy (tramp-make-tramp-temp-file v))
4345 (tramp-send-command
4346 v
4347 (cond
4348 ((and beg end)
4349 (format "tail -c +%d %s | head -c +%d >%s"
4350 (1+ beg) (tramp-shell-quote-argument localname)
4351 (- end beg) remote-copy))
4352 (beg
4353 (format "tail -c +%d %s >%s"
4354 (1+ beg) (tramp-shell-quote-argument localname)
4355 remote-copy))
4356 (end
4357 (format "head -c +%d %s >%s"
4358 (1+ end) (tramp-shell-quote-argument localname)
4359 remote-copy)))))
4360
70c11b0b
MA
4361 ;; `insert-file-contents-literally' takes care to avoid
4362 ;; calling jka-compr. By let-binding
4363 ;; `inhibit-file-name-operation', we propagate that care
4364 ;; to the `file-local-copy' operation.
4365 (setq local-copy
4366 (let ((inhibit-file-name-operation
4367 (when (eq inhibit-file-name-operation
4368 'insert-file-contents)
4369 'file-local-copy)))
736ac90f
MA
4370 (file-local-copy
4371 (if (stringp remote-copy)
4372 (tramp-make-tramp-file-name
4373 method user host remote-copy)
4374 filename))))
70c11b0b
MA
4375 (tramp-message
4376 v 4 "Inserting local temp file `%s'..." local-copy)
4377
4378 ;; We must ensure that `file-coding-system-alist'
4379 ;; matches `local-copy'.
4380 (let ((file-coding-system-alist
4381 (tramp-find-file-name-coding-system-alist
4382 filename local-copy)))
4383 (setq result
4384 (insert-file-contents
736ac90f 4385 local-copy nil nil nil replace))
70c11b0b
MA
4386 ;; Now `last-coding-system-used' has right value.
4387 ;; Remember it.
4388 (when (boundp 'last-coding-system-used)
4389 (setq coding-system-used
4390 (symbol-value 'last-coding-system-used))))
8d60099b 4391
70c11b0b
MA
4392 (tramp-message
4393 v 4 "Inserting local temp file `%s'...done" local-copy)
4394 (when (boundp 'last-coding-system-used)
2ac33804 4395 (set 'last-coding-system-used coding-system-used))))
70c11b0b 4396
2ac33804
MA
4397 ;; Save exit.
4398 (progn
4399 (when visit
4400 (setq buffer-file-name filename)
4401 (setq buffer-read-only (not (file-writable-p filename)))
4402 (set-visited-file-modtime)
4403 (set-buffer-modified-p nil))
4404 (when (stringp local-copy)
4405 (delete-file local-copy))
4406 (when (stringp remote-copy)
4407 (delete-file
4408 (tramp-make-tramp-file-name method user host remote-copy))))))
70c11b0b
MA
4409
4410 ;; Result.
4411 (list (expand-file-name filename)
4412 (cadr result))))
fb7933a3 4413
94be87e8
MA
4414;; This is needed for XEmacs only. Code stolen from files.el.
4415(defun tramp-handle-insert-file-contents-literally
4416 (filename &optional visit beg end replace)
4417 "Like `insert-file-contents-literally' for Tramp files."
4418 (let ((format-alist nil)
4419 (after-insert-file-functions nil)
4420 (coding-system-for-read 'no-conversion)
4421 (coding-system-for-write 'no-conversion)
4422 (find-buffer-file-type-function
4423 (if (fboundp 'find-buffer-file-type)
4424 (symbol-function 'find-buffer-file-type)
4425 nil))
4426 (inhibit-file-name-handlers '(jka-compr-handler image-file-handler))
4427 (inhibit-file-name-operation 'insert-file-contents))
4428 (unwind-protect
4429 (progn
4430 (fset 'find-buffer-file-type (lambda (filename) t))
4431 (insert-file-contents filename visit beg end replace))
70c11b0b 4432 ;; Save exit.
94be87e8
MA
4433 (if find-buffer-file-type-function
4434 (fset 'find-buffer-file-type find-buffer-file-type-function)
4435 (fmakunbound 'find-buffer-file-type)))))
4436
38c65fca 4437(defun tramp-handle-find-backup-file-name (filename)
00d6fd04 4438 "Like `find-backup-file-name' for Tramp files."
07dfe738
KG
4439 (with-parsed-tramp-file-name filename nil
4440 ;; We set both variables. It doesn't matter whether it is
4441 ;; Emacs or XEmacs
4442 (let ((backup-directory-alist
4443 ;; Emacs case
4444 (when (boundp 'backup-directory-alist)
b86c1cd8 4445 (if (symbol-value 'tramp-backup-directory-alist)
07dfe738 4446 (mapcar
aa485f7c
MA
4447 (lambda (x)
4448 (cons
4449 (car x)
4450 (if (and (stringp (cdr x))
4451 (file-name-absolute-p (cdr x))
4452 (not (tramp-file-name-p (cdr x))))
4453 (tramp-make-tramp-file-name method user host (cdr x))
4454 (cdr x))))
07dfe738
KG
4455 (symbol-value 'tramp-backup-directory-alist))
4456 (symbol-value 'backup-directory-alist))))
4457
4458 (bkup-backup-directory-info
4459 ;; XEmacs case
4460 (when (boundp 'bkup-backup-directory-info)
b86c1cd8 4461 (if (symbol-value 'tramp-bkup-backup-directory-info)
07dfe738 4462 (mapcar
aa485f7c
MA
4463 (lambda (x)
4464 (nconc
4465 (list (car x))
4466 (list
4467 (if (and (stringp (car (cdr x)))
4468 (file-name-absolute-p (car (cdr x)))
4469 (not (tramp-file-name-p (car (cdr x)))))
4470 (tramp-make-tramp-file-name
4471 method user host (car (cdr x)))
4472 (car (cdr x))))
4473 (cdr (cdr x))))
07dfe738
KG
4474 (symbol-value 'tramp-bkup-backup-directory-info))
4475 (symbol-value 'bkup-backup-directory-info)))))
4476
4477 (tramp-run-real-handler 'find-backup-file-name (list filename)))))
38c65fca 4478
c1105d05 4479(defun tramp-handle-make-auto-save-file-name ()
00d6fd04 4480 "Like `make-auto-save-file-name' for Tramp files.
c1105d05 4481Returns a file name in `tramp-auto-save-directory' for autosaving this file."
00d6fd04
MA
4482 (let ((tramp-auto-save-directory tramp-auto-save-directory)
4483 (buffer-file-name
4484 (tramp-subst-strs-in-string
4485 '(("_" . "|")
4486 ("/" . "_a")
4487 (":" . "_b")
4488 ("|" . "__")
4489 ("[" . "_l")
4490 ("]" . "_r"))
4491 (buffer-file-name))))
1a762140
MA
4492 ;; File name must be unique. This is ensured with Emacs 22 (see
4493 ;; UNIQUIFY element of `auto-save-file-name-transforms'); but for
4494 ;; all other cases we must do it ourselves.
4495 (when (boundp 'auto-save-file-name-transforms)
9e6ab520 4496 (mapc
aa485f7c
MA
4497 (lambda (x)
4498 (when (and (string-match (car x) buffer-file-name)
4499 (not (car (cddr x))))
4500 (setq tramp-auto-save-directory
4501 (or tramp-auto-save-directory
4502 (tramp-compat-temporary-file-directory)))))
1a762140
MA
4503 (symbol-value 'auto-save-file-name-transforms)))
4504 ;; Create directory.
4505 (when tramp-auto-save-directory
00d6fd04
MA
4506 (setq buffer-file-name
4507 (expand-file-name buffer-file-name tramp-auto-save-directory))
1a762140
MA
4508 (unless (file-exists-p tramp-auto-save-directory)
4509 (make-directory tramp-auto-save-directory t)))
00d6fd04
MA
4510 ;; Run plain `make-auto-save-file-name'. There might be an advice when
4511 ;; it is not a magic file name operation (since Emacs 22).
4512 ;; We must deactivate it temporarily.
4513 (if (not (ad-is-active 'make-auto-save-file-name))
4514 (tramp-run-real-handler 'make-auto-save-file-name nil)
4515 ;; else
4516 (ad-deactivate 'make-auto-save-file-name)
4517 (prog1
4518 (tramp-run-real-handler 'make-auto-save-file-name nil)
4519 (ad-activate 'make-auto-save-file-name)))))
4520
4521(defvar tramp-handle-write-region-hook nil
4522 "Normal hook to be run at the end of `tramp-handle-write-region'.")
4523
4524;; CCC grok APPEND, LOCKNAME
fb7933a3
KG
4525(defun tramp-handle-write-region
4526 (start end filename &optional append visit lockname confirm)
00d6fd04 4527 "Like `write-region' for Tramp files."
fb7933a3 4528 (setq filename (expand-file-name filename))
c62c9d08 4529 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
4530 (unless (null append)
4531 (tramp-error
4532 v 'file-error "Cannot append to file using Tramp (`%s')" filename))
4533 ;; Following part commented out because we don't know what to do about
4534 ;; file locking, and it does not appear to be a problem to ignore it.
4535 ;; Ange-ftp ignores it, too.
4536 ;; (when (and lockname (stringp lockname))
4537 ;; (setq lockname (expand-file-name lockname)))
4538 ;; (unless (or (eq lockname nil)
4539 ;; (string= lockname filename))
4540 ;; (error
4541 ;; "tramp-handle-write-region: LOCKNAME must be nil or equal FILENAME"))
8d60099b 4542
94be87e8 4543 ;; XEmacs takes a coding system as the seventh argument, not `confirm'.
00d6fd04
MA
4544 (when (and (not (featurep 'xemacs)) confirm (file-exists-p filename))
4545 (unless (y-or-n-p (format "File %s exists; overwrite anyway? " filename))
4546 (tramp-error v 'file-error "File not overwritten")))
8d60099b 4547
a4aeb9a4 4548 (let ((uid (or (nth 2 (tramp-compat-file-attributes filename 'integer))
9c13938d 4549 (tramp-get-remote-uid v 'integer)))
a4aeb9a4 4550 (gid (or (nth 3 (tramp-compat-file-attributes filename 'integer))
9c13938d
MA
4551 (tramp-get-remote-gid v 'integer))))
4552
4553 (if (and (tramp-local-host-p v)
93c3eb7c 4554 ;; `file-writable-p' calls `file-expand-file-name'. We
87bdd2c7
MA
4555 ;; cannot use `tramp-run-real-handler' therefore.
4556 (let (file-name-handler-alist)
82f3844e
MA
4557 (and
4558 (file-writable-p (file-name-directory localname))
4559 (or (file-directory-p localname)
4560 (file-writable-p localname)))))
9c13938d 4561 ;; Short track: if we are on the local host, we can run directly.
93c3eb7c
MA
4562 (progn
4563 (tramp-run-real-handler
4564 'write-region
4565 (list start end localname append 'no-message lockname confirm))
3e2fa353 4566 (tramp-flush-file-property v localname))
9c13938d
MA
4567
4568 (let ((rem-dec (tramp-get-remote-coding v "remote-decoding"))
4569 (loc-enc (tramp-get-local-coding v "local-encoding"))
b86c1cd8 4570 (modes (save-excursion (tramp-default-file-modes filename)))
9c13938d
MA
4571 ;; We use this to save the value of
4572 ;; `last-coding-system-used' after writing the tmp file.
4573 ;; At the end of the function, we set
4574 ;; `last-coding-system-used' to this saved value. This
4575 ;; way, any intermediary coding systems used while
4576 ;; talking to the remote shell or suchlike won't hose
4577 ;; this variable. This approach was snarfed from
4578 ;; ange-ftp.el.
4579 coding-system-used
4580 ;; Write region into a tmp file. This isn't really
4581 ;; needed if we use an encoding function, but currently
4582 ;; we use it always because this makes the logic
4583 ;; simpler.
4584 (tmpfile (tramp-compat-make-temp-file filename)))
4585
4586 ;; We say `no-message' here because we don't want the
4587 ;; visited file modtime data to be clobbered from the temp
4588 ;; file. We call `set-visited-file-modtime' ourselves later
eb562962
MA
4589 ;; on. We must ensure that `file-coding-system-alist'
4590 ;; matches `tmpfile'.
4591 (let ((file-coding-system-alist
4592 (tramp-find-file-name-coding-system-alist filename tmpfile)))
ce2cc728
MA
4593 (condition-case err
4594 (tramp-run-real-handler
4595 'write-region
4596 (list start end tmpfile append 'no-message lockname confirm))
2988341a
MA
4597 ((error quit)
4598 (delete-file tmpfile)
4599 (signal (car err) (cdr err))))
ce2cc728 4600
eb562962
MA
4601 ;; Now, `last-coding-system-used' has the right value. Remember it.
4602 (when (boundp 'last-coding-system-used)
4603 (setq coding-system-used
4604 (symbol-value 'last-coding-system-used))))
4605
9c13938d
MA
4606 ;; The permissions of the temporary file should be set. If
4607 ;; filename does not exist (eq modes nil) it has been
4608 ;; renamed to the backup file. This case `save-buffer'
4609 ;; handles permissions.
4610 (when modes (set-file-modes tmpfile modes))
4611
4612 ;; This is a bit lengthy due to the different methods
4613 ;; possible for file transfer. First, we check whether the
4614 ;; method uses an rcp program. If so, we call it.
4615 ;; Otherwise, both encoding and decoding command must be
4616 ;; specified. However, if the method _also_ specifies an
4617 ;; encoding function, then that is used for encoding the
4618 ;; contents of the tmp file.
4619 (cond
4620 ;; `rename-file' handles direct copy and out-of-band methods.
4621 ((or (tramp-local-host-p v)
4622 (and (tramp-method-out-of-band-p v)
1d7e9a01
MA
4623 (> (- (or end (point-max)) (or start (point-min)))
4624 tramp-copy-size-limit)))
ce2cc728
MA
4625 (condition-case err
4626 (rename-file tmpfile filename t)
2988341a
MA
4627 ((error quit)
4628 (delete-file tmpfile)
4629 (signal (car err) (cdr err)))))
9c13938d 4630
1d7e9a01 4631 ;; Use inline file transfer.
9c13938d 4632 (rem-dec
1d7e9a01 4633 ;; Encode tmpfile.
9c13938d
MA
4634 (tramp-message v 5 "Encoding region...")
4635 (unwind-protect
4636 (with-temp-buffer
4637 ;; Use encoding function or command.
4638 (if (and (symbolp loc-enc) (fboundp loc-enc))
4639 (progn
4640 (tramp-message
4641 v 5 "Encoding region using function `%s'..."
4642 (symbol-name loc-enc))
4643 (let ((coding-system-for-read 'binary))
4644 (insert-file-contents-literally tmpfile))
70c11b0b
MA
4645 ;; The following `let' is a workaround for the
4646 ;; base64.el that comes with pgnus-0.84. If
4647 ;; both of the following conditions are
4648 ;; satisfied, it tries to write to a local
4649 ;; file in default-directory, but at this
4650 ;; point, default-directory is remote.
4651 ;; (`call-process-region' can't write to
4652 ;; remote files, it seems.) The file in
4653 ;; question is a tmp file anyway.
9c13938d
MA
4654 (let ((default-directory
4655 (tramp-compat-temporary-file-directory)))
4656 (funcall loc-enc (point-min) (point-max))))
8d60099b 4657
9c13938d
MA
4658 (tramp-message
4659 v 5 "Encoding region using command `%s'..." loc-enc)
4660 (unless (equal 0 (tramp-call-local-coding-command
4661 loc-enc tmpfile t))
4662 (tramp-error
4663 v 'file-error
4664 "Cannot write to `%s', local encoding command `%s' failed"
4665 filename loc-enc)))
4666
4667 ;; Send buffer into remote decoding command which
4668 ;; writes to remote file. Because this happens on
4669 ;; the remote host, we cannot use the function.
4670 (goto-char (point-max))
4671 (unless (bolp) (newline))
8d60099b 4672 (tramp-message
9c13938d
MA
4673 v 5 "Decoding region into remote file %s..." filename)
4674 (tramp-send-command
4675 v
4676 (format
4677 "%s >%s <<'EOF'\n%sEOF"
4678 rem-dec
4679 (tramp-shell-quote-argument localname)
4680 (buffer-string)))
4681 (tramp-barf-unless-okay
4682 v nil
4683 "Couldn't write region to `%s', decode using `%s' failed"
4684 filename rem-dec)
4685 ;; When `file-precious-flag' is set, the region is
4686 ;; written to a temporary file. Check that the
4687 ;; checksum is equal to that from the local tmpfile.
4688 (when file-precious-flag
4689 (erase-buffer)
4690 (and
a4aeb9a4
MA
4691 ;; cksum runs locally, if possible.
4692 (zerop (tramp-local-call-process "cksum" tmpfile t))
4693 ;; cksum runs remotely.
9c13938d
MA
4694 (zerop
4695 (tramp-send-command-and-check
4696 v
4697 (format
4698 "cksum <%s" (tramp-shell-quote-argument localname))))
a4aeb9a4 4699 ;; ... they are different.
9c13938d
MA
4700 (not
4701 (string-equal
4702 (buffer-string)
4703 (with-current-buffer (tramp-get-buffer v)
4704 (buffer-string))))
4705 (tramp-error
4706 v 'file-error
4707 (concat "Couldn't write region to `%s',"
4708 " decode using `%s' failed")
4709 filename rem-dec)))
4710 (tramp-message
4711 v 5 "Decoding region into remote file %s...done" filename)
4712 (tramp-flush-file-property v localname))
8d60099b 4713
9c13938d
MA
4714 ;; Save exit.
4715 (delete-file tmpfile)))
8d60099b 4716
9c13938d
MA
4717 ;; That's not expected.
4718 (t
4719 (tramp-error
4720 v 'file-error
4721 (concat "Method `%s' should specify both encoding and "
4722 "decoding command or an rcp program")
4723 method)))
258800f8 4724
9c13938d
MA
4725 ;; Make `last-coding-system-used' have the right value.
4726 (when coding-system-used
4727 (set 'last-coding-system-used coding-system-used))))
0f205eee 4728
57671b72
MA
4729 ;; We must protect `last-coding-system-used', now we have set it
4730 ;; to its correct value.
4731 (let (last-coding-system-used)
4732 ;; Set file modification time.
4733 (when (or (eq visit t) (stringp visit))
4734 (set-visited-file-modtime
4735 ;; We must pass modtime explicitely, because filename can
4736 ;; be different from (buffer-file-name), f.e. if
4737 ;; `file-precious-flag' is set.
4738 (nth 5 (file-attributes filename))))
4739
4740 ;; Set the ownership.
4741 (tramp-set-file-uid-gid filename uid gid)
4742 (when (or (eq visit t) (null visit) (stringp visit))
4743 (tramp-message v 0 "Wrote %s" filename))
4744 (run-hooks 'tramp-handle-write-region-hook)))))
fb7933a3 4745
946a5aeb
MA
4746(defvar tramp-vc-registered-file-names nil
4747 "List used to collect file names, which are checked during `vc-registered'.")
4748
4749;; VC backends check for the existence of various different special
4750;; files. This is very time consuming, because every single check
4751;; requires a remote command (the file cache must be invalidated).
4752;; Therefore, we apply a kind of optimization. We install the file
4753;; name handler `tramp-vc-file-name-handler', which does nothing but
4754;; remembers all file names for which `file-exists-p' or
4755;; `file-readable-p' has been applied. A first run of `vc-registered'
4756;; is performed. Afterwards, a script is applied for all collected
4757;; file names, using just one remote command. The result of this
4758;; script is used to fill the file cache with actual values. Now we
4759;; can reset the file name handlers, and we make a second run of
4760;; `vc-registered', which returns the expected result without sending
4761;; any other remote command.
49096407
MA
4762(defun tramp-handle-vc-registered (file)
4763 "Like `vc-registered' for Tramp files."
946a5aeb
MA
4764 ;; There could be new files, created by the vc backend. We cannot
4765 ;; reuse the old cache entries, therefore.
4766 (with-parsed-tramp-file-name file nil
4767 (let (tramp-vc-registered-file-names
4768 (tramp-cache-inhibit-cache (current-time))
4769 (file-name-handler-alist
4770 `((,tramp-file-name-regexp . tramp-vc-file-name-handler))))
4771
4772 ;; Here we collect only file names, which need an operation.
4773 (tramp-run-real-handler 'vc-registered (list file))
4774 (tramp-message v 10 "\n%s" tramp-vc-registered-file-names)
4775
4776 ;; Send just one command, in order to fill the cache.
4777 (tramp-maybe-send-script
4778 v
4779 (format tramp-vc-registered-read-file-names
4780 (tramp-get-file-exists-command v)
4781 (format "%s -r" (tramp-get-test-command v)))
4782 "tramp_vc_registered_read_file_names")
4783
4784 (dolist
4785 (elt
4786 (tramp-send-command-and-read
4787 v
4788 (format
4789 "tramp_vc_registered_read_file_names %s"
4790 (mapconcat 'tramp-shell-quote-argument
4791 tramp-vc-registered-file-names
4792 " "))))
4793
4794 (tramp-set-file-property v (car elt) (cadr elt) (cadr (cdr elt)))))
4795
4796 ;; Second run. Now all requests shall be answered from the file
4797 ;; cache. We unset `process-file-side-effects' in order to keep
4798 ;; the cache when `process-file' calls appear.
4799 (let (process-file-side-effects)
4800 (tramp-run-real-handler 'vc-registered (list file)))))
49096407 4801
a01b1e22
MA
4802;;;###autoload
4803(progn (defun tramp-run-real-handler (operation args)
fb7933a3 4804 "Invoke normal file name handler for OPERATION.
c62c9d08
KG
4805First arg specifies the OPERATION, second arg is a list of arguments to
4806pass to the OPERATION."
4007ba5b
KG
4807 (let* ((inhibit-file-name-handlers
4808 `(tramp-file-name-handler
946a5aeb 4809 tramp-vc-file-name-handler
4007ba5b
KG
4810 tramp-completion-file-name-handler
4811 cygwin-mount-name-hook-function
4812 cygwin-mount-map-drive-hook-function
4813 .
4814 ,(and (eq inhibit-file-name-operation operation)
4815 inhibit-file-name-handlers)))
4816 (inhibit-file-name-operation operation))
a01b1e22 4817 (apply operation args))))
16674e4f 4818
a01b1e22
MA
4819;;;###autoload
4820(progn (defun tramp-completion-run-real-handler (operation args)
16674e4f
KG
4821 "Invoke `tramp-file-name-handler' for OPERATION.
4822First arg specifies the OPERATION, second arg is a list of arguments to
4823pass to the OPERATION."
4007ba5b
KG
4824 (let* ((inhibit-file-name-handlers
4825 `(tramp-completion-file-name-handler
4826 cygwin-mount-name-hook-function
4827 cygwin-mount-map-drive-hook-function
4828 .
4829 ,(and (eq inhibit-file-name-operation operation)
4830 inhibit-file-name-handlers)))
4831 (inhibit-file-name-operation operation))
a01b1e22 4832 (apply operation args))))
fb7933a3 4833
4007ba5b
KG
4834;; We handle here all file primitives. Most of them have the file
4835;; name as first parameter; nevertheless we check for them explicitly
04bf5b65 4836;; in order to be signaled if a new primitive appears. This
4007ba5b
KG
4837;; scenario is needed because there isn't a way to decide by
4838;; syntactical means whether a foreign method must be called. It would
19a87064 4839;; ease the life if `file-name-handler-alist' would support a decision
4007ba5b
KG
4840;; function as well but regexp only.
4841(defun tramp-file-name-for-operation (operation &rest args)
4842 "Return file name related to OPERATION file primitive.
4843ARGS are the arguments OPERATION has been called with."
4844 (cond
4845 ; FILE resp DIRECTORY
4846 ((member operation
4847 (list 'access-file 'byte-compiler-base-file-name 'delete-directory
4848 'delete-file 'diff-latest-backup-file 'directory-file-name
4849 'directory-files 'directory-files-and-attributes
4850 'dired-compress-file 'dired-uncache
4851 'file-accessible-directory-p 'file-attributes
4852 'file-directory-p 'file-executable-p 'file-exists-p
19a87064
MA
4853 'file-local-copy 'file-remote-p 'file-modes
4854 'file-name-as-directory 'file-name-directory
4855 'file-name-nondirectory 'file-name-sans-versions
4856 'file-ownership-preserved-p 'file-readable-p
4857 'file-regular-p 'file-symlink-p 'file-truename
4858 'file-writable-p 'find-backup-file-name 'find-file-noselect
4859 'get-file-buffer 'insert-directory 'insert-file-contents
4860 'load 'make-directory 'make-directory-internal
4861 'set-file-modes 'substitute-in-file-name
4862 'unhandled-file-name-directory 'vc-registered
ce3f516f
MA
4863 ; Emacs 22 only
4864 'set-file-times
4007ba5b
KG
4865 ; XEmacs only
4866 'abbreviate-file-name 'create-file-buffer
4867 'dired-file-modtime 'dired-make-compressed-filename
4868 'dired-recursive-delete-directory 'dired-set-file-modtime
4869 'dired-shell-unhandle-file-name 'dired-uucode-file
5615d63f 4870 'insert-file-contents-literally 'make-temp-name 'recover-file
4007ba5b 4871 'vm-imap-check-mail 'vm-pop-check-mail 'vm-spool-check-mail))
8daea7fc
KG
4872 (if (file-name-absolute-p (nth 0 args))
4873 (nth 0 args)
4874 (expand-file-name (nth 0 args))))
4007ba5b
KG
4875 ; FILE DIRECTORY resp FILE1 FILE2
4876 ((member operation
4877 (list 'add-name-to-file 'copy-file 'expand-file-name
4878 'file-name-all-completions 'file-name-completion
4879 'file-newer-than-file-p 'make-symbolic-link 'rename-file
4880 ; XEmacs only
4881 'dired-make-relative-symlink
4882 'vm-imap-move-mail 'vm-pop-move-mail 'vm-spool-move-mail))
4883 (save-match-data
4884 (cond
4885 ((string-match tramp-file-name-regexp (nth 0 args)) (nth 0 args))
4886 ((string-match tramp-file-name-regexp (nth 1 args)) (nth 1 args))
4887 (t (buffer-file-name (current-buffer))))))
4888 ; START END FILE
4889 ((eq operation 'write-region)
4890 (nth 2 args))
4891 ; BUF
4892 ((member operation
00d6fd04 4893 (list 'set-visited-file-modtime 'verify-visited-file-modtime
b50dd0d2 4894 ; since Emacs 22 only
00d6fd04
MA
4895 'make-auto-save-file-name
4896 ; XEmacs only
4007ba5b
KG
4897 'backup-buffer))
4898 (buffer-file-name
4899 (if (bufferp (nth 0 args)) (nth 0 args) (current-buffer))))
4900 ; COMMAND
4901 ((member operation
00d6fd04
MA
4902 (list ; not in Emacs 23
4903 'dired-call-process
01917a18 4904 ; Emacs only
b71c9e75 4905 'shell-command
00d6fd04 4906 ; since Emacs 22 only
0457dd55 4907 'process-file
00d6fd04
MA
4908 ; since Emacs 23 only
4909 'start-file-process
4007ba5b 4910 ; XEmacs only
00d6fd04
MA
4911 'dired-print-file 'dired-shell-call-process
4912 ; nowhere yet
4913 'executable-find 'start-process 'call-process))
4007ba5b
KG
4914 default-directory)
4915 ; unknown file primitive
4916 (t (error "unknown file I/O primitive: %s" operation))))
4917
4918(defun tramp-find-foreign-file-name-handler (filename)
4919 "Return foreign file name handler if exists."
9ce8462a
MA
4920 (when (and (stringp filename) (tramp-tramp-file-p filename))
4921 (let ((v (tramp-dissect-file-name filename t))
4922 (handler tramp-foreign-file-name-handler-alist)
4923 elt res)
4924 ;; When we are not fully sure that filename completion is safe,
4925 ;; we should not return a handler.
4926 (when (or (tramp-file-name-method v) (tramp-file-name-user v)
1834b39f
MA
4927 (and (tramp-file-name-host v)
4928 (not (member (tramp-file-name-host v)
4929 (mapcar 'car tramp-methods))))
9ce8462a
MA
4930 (not (tramp-completion-mode-p)))
4931 (while handler
4932 (setq elt (car handler)
4933 handler (cdr handler))
4934 (when (funcall (car elt) filename)
4935 (setq handler nil
4936 res (cdr elt))))
4937 res))))
4007ba5b 4938
fb7933a3
KG
4939;; Main function.
4940;;;###autoload
4941(defun tramp-file-name-handler (operation &rest args)
ea9d1443 4942 "Invoke Tramp file name handler.
a4aeb9a4 4943Falls back to normal file name handler if no Tramp file name handler exists."
2e271195
MA
4944 (if tramp-mode
4945 (save-match-data
4946 (let* ((filename
4947 (tramp-replace-environment-variables
4948 (apply 'tramp-file-name-for-operation operation args)))
4949 (completion (tramp-completion-mode-p))
4950 (foreign (tramp-find-foreign-file-name-handler filename)))
4951 (with-parsed-tramp-file-name filename nil
4952 (cond
4953 ;; When we are in completion mode, some operations
4954 ;; shouldn't be handled by backend.
4955 ((and completion (zerop (length localname))
4956 (memq operation '(file-exists-p file-directory-p)))
4957 t)
4958 ((and completion (zerop (length localname))
4959 (memq operation '(file-name-as-directory)))
4960 filename)
4961 ;; Call the backend function.
4962 (foreign (apply foreign operation args))
4963 ;; Nothing to do for us.
4964 (t (tramp-run-real-handler operation args))))))
4965 ;; When `tramp-mode' is not enabled, we don't do anything.
4966 (tramp-run-real-handler operation args)))
fb7933a3 4967
07dfe738
KG
4968;; In Emacs, there is some concurrency due to timers. If a timer
4969;; interrupts Tramp and wishes to use the same connection buffer as
4970;; the "main" Emacs, then garbage might occur in the connection
4971;; buffer. Therefore, we need to make sure that a timer does not use
4972;; the same connection buffer as the "main" Emacs. We implement a
4973;; cheap global lock, instead of locking each connection buffer
4974;; separately. The global lock is based on two variables,
4975;; `tramp-locked' and `tramp-locker'. `tramp-locked' is set to true
4976;; (with setq) to indicate a lock. But Tramp also calls itself during
4977;; processing of a single file operation, so we need to allow
4978;; recursive calls. That's where the `tramp-locker' variable comes in
4979;; -- it is let-bound to t during the execution of the current
4980;; handler. So if `tramp-locked' is t and `tramp-locker' is also t,
4981;; then we should just proceed because we have been called
4982;; recursively. But if `tramp-locker' is nil, then we are a timer
4983;; interrupting the "main" Emacs, and then we signal an error.
4984
4985(defvar tramp-locked nil
4986 "If non-nil, then Tramp is currently busy.
4987Together with `tramp-locker', this implements a locking mechanism
4988preventing reentrant calls of Tramp.")
4989
4990(defvar tramp-locker nil
4991 "If non-nil, then a caller has locked Tramp.
4992Together with `tramp-locked', this implements a locking mechanism
4993preventing reentrant calls of Tramp.")
4994
ea9d1443
KG
4995(defun tramp-sh-file-name-handler (operation &rest args)
4996 "Invoke remote-shell Tramp file name handler.
4997Fall back to normal file name handler if no Tramp handler exists."
07dfe738 4998 (when (and tramp-locked (not tramp-locker))
11c71217 4999 (setq tramp-locked nil)
00d6fd04 5000 (signal 'file-error (list "Forbidden reentrant call of Tramp")))
07dfe738
KG
5001 (let ((tl tramp-locked))
5002 (unwind-protect
5003 (progn
5004 (setq tramp-locked t)
5005 (let ((tramp-locker t))
5006 (save-match-data
5007 (let ((fn (assoc operation tramp-file-name-handler-alist)))
5008 (if fn
5009 (apply (cdr fn) args)
5010 (tramp-run-real-handler operation args))))))
5011 (setq tramp-locked tl))))
ea9d1443 5012
946a5aeb
MA
5013(defun tramp-vc-file-name-handler (operation &rest args)
5014 "Invoke special file name handler, which collects files to be handled."
5015 (save-match-data
5016 (let ((filename
5017 (tramp-replace-environment-variables
5018 (apply 'tramp-file-name-for-operation operation args)))
5019 (fn (assoc operation tramp-file-name-handler-alist)))
5020 (with-parsed-tramp-file-name filename nil
5021 (cond
5022 ;; That's what we want: file names, for which checks are
5023 ;; applied. We assume, that VC uses only `file-exists-p' and
5024 ;; `file-readable-p' checks; otherwise we must extend the
5025 ;; list. We do not perform any action, but return nil, in
5026 ;; order to keep `vc-registered' running.
5027 ((and fn (memq operation '(file-exists-p file-readable-p)))
5028 (add-to-list 'tramp-vc-registered-file-names localname 'append)
5029 nil)
5030 ;; Tramp file name handlers like `expand-file-name'. They
5031 ;; must still work.
5032 (fn
5033 (save-match-data (apply (cdr fn) args)))
5034 ;; Default file name handlers, we don't care.
5035 (t (tramp-run-real-handler operation args)))))))
5036
16674e4f 5037;;;###autoload
1ecc6145 5038(progn (defun tramp-completion-file-name-handler (operation &rest args)
a4aeb9a4
MA
5039 "Invoke Tramp file name completion handler.
5040Falls back to normal file name handler if no Tramp file name handler exists."
57671b72
MA
5041 ;; We bind `directory-sep-char' here for XEmacs on Windows, which
5042 ;; would otherwise use backslash.
aff67808
MA
5043 (let ((directory-sep-char ?/)
5044 (fn (assoc operation tramp-completion-file-name-handler-alist)))
aa485f7c
MA
5045 (if (and
5046 ;; When `tramp-mode' is not enabled, we don't do anything.
5047 fn tramp-mode
5048 ;; For other syntaxes than `sep', the regexp matches many common
5049 ;; situations where the user doesn't actually want to use Tramp.
5050 ;; So to avoid autoloading Tramp after typing just "/s", we
5051 ;; disable this part of the completion, unless the user implicitly
5052 ;; indicated his interest in using a fancier completion system.
5053 (or (eq tramp-syntax 'sep)
5054 (featurep 'tramp) ; If it's loaded, we may as well use it.
5055 (and (boundp 'partial-completion-mode) partial-completion-mode)
5056 ;; FIXME: These may have been loaded even if the user never
5057 ;; intended to use them.
5058 (featurep 'ido)
5059 (featurep 'icicles)))
aff67808
MA
5060 (save-match-data (apply (cdr fn) args))
5061 (tramp-completion-run-real-handler operation args)))))
a01b1e22 5062
b25a52cc 5063;;;###autoload
aa485f7c
MA
5064(progn (defun tramp-register-file-name-handlers ()
5065 "Add Tramp file name handlers to `file-name-handler-alist'."
5066 ;; Remove autoloaded handlers from file name handler alist. Useful,
00d6fd04
MA
5067 ;; if `tramp-syntax' has been changed.
5068 (let ((a1 (rassq 'tramp-file-name-handler file-name-handler-alist)))
aa485f7c
MA
5069 (setq file-name-handler-alist (delq a1 file-name-handler-alist)))
5070 (let ((a1 (rassq
5071 'tramp-completion-file-name-handler file-name-handler-alist)))
5072 (setq file-name-handler-alist (delq a1 file-name-handler-alist)))
5073 ;; Add the handlers.
a01b1e22
MA
5074 (add-to-list 'file-name-handler-alist
5075 (cons tramp-file-name-regexp 'tramp-file-name-handler))
aa485f7c
MA
5076 (add-to-list 'file-name-handler-alist
5077 (cons tramp-completion-file-name-regexp
5078 'tramp-completion-file-name-handler))
5079 (put 'tramp-completion-file-name-handler 'safe-magic t)
5080 ;; If jka-compr or epa-file are already loaded, move them to the
5081 ;; front of `file-name-handler-alist'.
5082 (dolist (fnh '(epa-file-handler jka-compr-handler))
5083 (let ((entry (rassoc fnh file-name-handler-alist)))
5084 (when entry
5085 (setq file-name-handler-alist
5086 (cons entry (delete entry file-name-handler-alist))))))))
69cee873 5087
00d6fd04
MA
5088;; `tramp-file-name-handler' must be registered before evaluation of
5089;; site-start and init files, because there might exist remote files
5090;; already, f.e. files kept via recentf-mode.
aa485f7c
MA
5091;;;###autoload(tramp-register-file-name-handlers)
5092(tramp-register-file-name-handlers)
b25a52cc 5093
fb7933a3 5094;;;###autoload
8c04e197 5095(defun tramp-unload-file-name-handlers ()
a69c01a0
MA
5096 (setq file-name-handler-alist
5097 (delete (rassoc 'tramp-file-name-handler
5098 file-name-handler-alist)
5099 (delete (rassoc 'tramp-completion-file-name-handler
5100 file-name-handler-alist)
5101 file-name-handler-alist))))
5102
8c04e197 5103(add-hook 'tramp-unload-hook 'tramp-unload-file-name-handlers)
a69c01a0 5104
0664ff72 5105;;; File name handler functions for completion mode:
a6e96327
MA
5106
5107(defvar tramp-completion-mode nil
5108 "If non-nil, external packages signal that they are in file name completion.
5109
5110This is necessary, because Tramp uses a heuristic depending on last
5111input event. This fails when external packages use other characters
5112but <TAB>, <SPACE> or ?\\? for file name completion. This variable
5113should never be set globally, the intention is to let-bind it.")
16674e4f
KG
5114
5115;; Necessary because `tramp-file-name-regexp-unified' and
00d6fd04
MA
5116;; `tramp-completion-file-name-regexp-unified' aren't different. If
5117;; nil, `tramp-completion-run-real-handler' is called (i.e. forwarding
5118;; to `tramp-file-name-handler'). Otherwise, it takes
5119;; `tramp-run-real-handler'. Using `last-input-event' is a little bit
5120;; risky, because completing a file might require loading other files,
5121;; like "~/.netrc", and for them it shouldn't be decided based on that
5122;; variable. On the other hand, those files shouldn't have partial
a4aeb9a4
MA
5123;; Tramp file name syntax. Maybe another variable should be introduced
5124;; overwriting this check in such cases. Or we change Tramp file name
00d6fd04 5125;; syntax in order to avoid ambiguities, like in XEmacs ...
6c4e47fa 5126(defun tramp-completion-mode-p ()
16674e4f 5127 "Checks whether method / user name / host name completion is active."
6c4e47fa 5128 (or
a6e96327
MA
5129 ;; Signal from outside.
5130 tramp-completion-mode
5131 ;; Emacs.
94be87e8 5132 (equal last-input-event 'tab)
6c4e47fa 5133 (and (natnump last-input-event)
94be87e8 5134 (or
a6e96327 5135 ;; ?\t has event-modifier 'control.
800a97b8 5136 (equal last-input-event ?\t)
94be87e8 5137 (and (not (event-modifiers last-input-event))
800a97b8
SM
5138 (or (equal last-input-event ?\?)
5139 (equal last-input-event ?\ )))))
a6e96327 5140 ;; XEmacs.
6c4e47fa
MA
5141 (and (featurep 'xemacs)
5142 ;; `last-input-event' might be nil.
5143 (not (null last-input-event))
5144 ;; `last-input-event' may have no character approximation.
5145 (funcall (symbol-function 'event-to-character) last-input-event)
94be87e8 5146 (or
a6e96327 5147 ;; ?\t has event-modifier 'control.
800a97b8 5148 (equal
94be87e8
MA
5149 (funcall (symbol-function 'event-to-character)
5150 last-input-event) ?\t)
5151 (and (not (event-modifiers last-input-event))
800a97b8 5152 (or (equal
94be87e8
MA
5153 (funcall (symbol-function 'event-to-character)
5154 last-input-event) ?\?)
800a97b8 5155 (equal
94be87e8
MA
5156 (funcall (symbol-function 'event-to-character)
5157 last-input-event) ?\ )))))))
16674e4f 5158
16674e4f
KG
5159;; Method, host name and user name completion.
5160;; `tramp-completion-dissect-file-name' returns a list of
5161;; tramp-file-name structures. For all of them we return possible completions.
a01b1e22 5162;;;###autoload
16674e4f 5163(defun tramp-completion-handle-file-name-all-completions (filename directory)
00d6fd04 5164 "Like `file-name-all-completions' for partial Tramp files."
16674e4f 5165
00d6fd04
MA
5166 (let* ((fullname (tramp-drop-volume-letter
5167 (expand-file-name filename directory)))
5168 ;; Possible completion structures.
5169 (v (tramp-completion-dissect-file-name fullname))
5170 result result1)
5171
5172 (while v
5173 (let* ((car (car v))
5174 (method (tramp-file-name-method car))
5175 (user (tramp-file-name-user car))
5176 (host (tramp-file-name-host car))
5177 (localname (tramp-file-name-localname car))
5178 (m (tramp-find-method method user host))
5179 (tramp-current-user user) ; see `tramp-parse-passwd'
5180 all-user-hosts)
5181
5182 (unless localname ;; Nothing to complete.
5183
5184 (if (or user host)
5185
5186 ;; Method dependent user / host combinations.
5187 (progn
9e6ab520 5188 (mapc
00d6fd04
MA
5189 (lambda (x)
5190 (setq all-user-hosts
5191 (append all-user-hosts
5192 (funcall (nth 0 x) (nth 1 x)))))
5193 (tramp-get-completion-function m))
5194
9e6ab520
MA
5195 (setq result
5196 (append result
5197 (mapcar
5198 (lambda (x)
5199 (tramp-get-completion-user-host
5200 method user host (nth 0 x) (nth 1 x)))
5201 (delq nil all-user-hosts)))))
00d6fd04
MA
5202
5203 ;; Possible methods.
5204 (setq result
5205 (append result (tramp-get-completion-methods m)))))
5206
5207 (setq v (cdr v))))
5208
5209 ;; Unify list, remove nil elements.
5210 (while result
5211 (let ((car (car result)))
5212 (when car
5213 (add-to-list
5214 'result1
5215 (substring car (length (tramp-drop-volume-letter directory)))))
5216 (setq result (cdr result))))
5217
5218 ;; Complete local parts.
5219 (append
5220 result1
5221 (condition-case nil
5222 (tramp-completion-run-real-handler
5223 'file-name-all-completions (list filename directory))
5224 (error nil)))))
16674e4f
KG
5225
5226;; Method, host name and user name completion for a file.
a01b1e22 5227;;;###autoload
e1e17cae
MA
5228(defun tramp-completion-handle-file-name-completion
5229 (filename directory &optional predicate)
00d6fd04 5230 "Like `file-name-completion' for Tramp files."
e1e17cae
MA
5231 (try-completion
5232 filename
5233 (mapcar 'list (file-name-all-completions filename directory))
83e20b5c
MA
5234 (when predicate
5235 (lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
16674e4f
KG
5236
5237;; I misuse a little bit the tramp-file-name structure in order to handle
5238;; completion possibilities for partial methods / user names / host names.
5239;; Return value is a list of tramp-file-name structures according to possible
00d6fd04 5240;; completions. If "localname" is non-nil it means there
16674e4f
KG
5241;; shouldn't be a completion anymore.
5242
5243;; Expected results:
5244
00d6fd04
MA
5245;; "/x" "/[x" "/x@" "/[x@" "/x@y" "/[x@y"
5246;; [nil nil "x" nil] [nil "x" nil nil] [nil "x" "y" nil]
5247;; [nil "x" nil nil]
5248;; ["x" nil nil nil]
5249
5250;; "/x:" "/x:y" "/x:y:"
5251;; [nil nil "x" ""] [nil nil "x" "y"] ["x" nil "y" ""]
5252;; "/[x/" "/[x/y"
5253;; ["x" nil "" nil] ["x" nil "y" nil]
5254;; ["x" "" nil nil] ["x" "y" nil nil]
5255
5256;; "/x:y@" "/x:y@z" "/x:y@z:"
5257;; [nil nil "x" "y@"] [nil nil "x" "y@z"] ["x" "y" "z" ""]
5258;; "/[x/y@" "/[x/y@z"
5259;; ["x" nil "y" nil] ["x" "y" "z" nil]
16674e4f
KG
5260(defun tramp-completion-dissect-file-name (name)
5261 "Returns a list of `tramp-file-name' structures.
5262They are collected by `tramp-completion-dissect-file-name1'."
5263
5264 (let* ((result)
4007ba5b 5265 (x-nil "\\|\\(\\)")
b96e6899
MA
5266 (tramp-completion-ipv6-regexp
5267 (format
5268 "[^%s]*"
5269 (if (zerop (length tramp-postfix-ipv6-format))
5270 tramp-postfix-host-format
5271 tramp-postfix-ipv6-format)))
4007ba5b
KG
5272 ;; "/method" "/[method"
5273 (tramp-completion-file-name-structure1
5274 (list (concat tramp-prefix-regexp "\\(" tramp-method-regexp x-nil "\\)$")
5275 1 nil nil nil))
5276 ;; "/user" "/[user"
5277 (tramp-completion-file-name-structure2
5278 (list (concat tramp-prefix-regexp "\\(" tramp-user-regexp x-nil "\\)$")
5279 nil 1 nil nil))
5280 ;; "/host" "/[host"
5281 (tramp-completion-file-name-structure3
5282 (list (concat tramp-prefix-regexp "\\(" tramp-host-regexp x-nil "\\)$")
5283 nil nil 1 nil))
b96e6899 5284 ;; "/[ipv6" "/[ipv6"
4007ba5b 5285 (tramp-completion-file-name-structure4
b96e6899
MA
5286 (list (concat tramp-prefix-regexp
5287 tramp-prefix-ipv6-regexp
5288 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5289 nil nil 1 nil))
5290 ;; "/user@host" "/[user@host"
5291 (tramp-completion-file-name-structure5
4007ba5b
KG
5292 (list (concat tramp-prefix-regexp
5293 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5294 "\\(" tramp-host-regexp x-nil "\\)$")
5295 nil 1 2 nil))
b96e6899
MA
5296 ;; "/user@[ipv6" "/[user@ipv6"
5297 (tramp-completion-file-name-structure6
5298 (list (concat tramp-prefix-regexp
5299 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5300 tramp-prefix-ipv6-regexp
5301 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5302 nil 1 2 nil))
00d6fd04 5303 ;; "/method:user" "/[method/user" "/method://user"
b96e6899 5304 (tramp-completion-file-name-structure7
4007ba5b 5305 (list (concat tramp-prefix-regexp
00d6fd04 5306 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5307 "\\(" tramp-user-regexp x-nil "\\)$")
5308 1 2 nil nil))
00d6fd04 5309 ;; "/method:host" "/[method/host" "/method://host"
b96e6899 5310 (tramp-completion-file-name-structure8
4007ba5b 5311 (list (concat tramp-prefix-regexp
00d6fd04 5312 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5313 "\\(" tramp-host-regexp x-nil "\\)$")
5314 1 nil 2 nil))
b96e6899
MA
5315 ;; "/method:[ipv6" "/[method/ipv6" "/method://[ipv6"
5316 (tramp-completion-file-name-structure9
5317 (list (concat tramp-prefix-regexp
5318 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
5319 tramp-prefix-ipv6-regexp
5320 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5321 1 nil 2 nil))
00d6fd04 5322 ;; "/method:user@host" "/[method/user@host" "/method://user@host"
b96e6899 5323 (tramp-completion-file-name-structure10
4007ba5b 5324 (list (concat tramp-prefix-regexp
00d6fd04 5325 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5326 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5327 "\\(" tramp-host-regexp x-nil "\\)$")
00d6fd04 5328 1 2 3 nil))
b96e6899
MA
5329 ;; "/method:user@[ipv6" "/[method/user@ipv6" "/method://user@[ipv6"
5330 (tramp-completion-file-name-structure11
5331 (list (concat tramp-prefix-regexp
5332 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
5333 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5334 tramp-prefix-ipv6-regexp
5335 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5336 1 2 3 nil))
00d6fd04 5337 ;; "/method: "/method:/"
b96e6899 5338 (tramp-completion-file-name-structure12
00d6fd04
MA
5339 (list
5340 (if (equal tramp-syntax 'url)
5341 (concat tramp-prefix-regexp
5342 "\\(" tramp-method-regexp "\\)"
5343 "\\(" (substring tramp-postfix-method-regexp 0 1)
5344 "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)"
5345 "\\(" "\\)$")
5346 ;; Should not match if not URL syntax.
5347 (concat tramp-prefix-regexp "/$"))
5348 1 3 nil nil))
5349 ;; "/method: "/method:/"
b96e6899 5350 (tramp-completion-file-name-structure13
00d6fd04
MA
5351 (list
5352 (if (equal tramp-syntax 'url)
5353 (concat tramp-prefix-regexp
5354 "\\(" tramp-method-regexp "\\)"
5355 "\\(" (substring tramp-postfix-method-regexp 0 1)
5356 "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)"
5357 "\\(" "\\)$")
5358 ;; Should not match if not URL syntax.
5359 (concat tramp-prefix-regexp "/$"))
5360 1 nil 3 nil)))
4007ba5b 5361
9e6ab520 5362 (mapc (lambda (regexp)
16674e4f
KG
5363 (add-to-list 'result
5364 (tramp-completion-dissect-file-name1 regexp name)))
5365 (list
5366 tramp-completion-file-name-structure1
5367 tramp-completion-file-name-structure2
5368 tramp-completion-file-name-structure3
5369 tramp-completion-file-name-structure4
5370 tramp-completion-file-name-structure5
5371 tramp-completion-file-name-structure6
5372 tramp-completion-file-name-structure7
00d6fd04
MA
5373 tramp-completion-file-name-structure8
5374 tramp-completion-file-name-structure9
b96e6899
MA
5375 tramp-completion-file-name-structure10
5376 tramp-completion-file-name-structure11
5377 tramp-completion-file-name-structure12
5378 tramp-completion-file-name-structure13
16674e4f
KG
5379 tramp-file-name-structure))
5380
5381 (delq nil result)))
5382
5383(defun tramp-completion-dissect-file-name1 (structure name)
5384 "Returns a `tramp-file-name' structure matching STRUCTURE.
00d6fd04 5385The structure consists of remote method, remote user,
7432277c 5386remote host and localname (filename on remote host)."
fb7933a3 5387
00d6fd04
MA
5388 (save-match-data
5389 (when (string-match (nth 0 structure) name)
5390 (let ((method (and (nth 1 structure)
5391 (match-string (nth 1 structure) name)))
5392 (user (and (nth 2 structure)
5393 (match-string (nth 2 structure) name)))
5394 (host (and (nth 3 structure)
5395 (match-string (nth 3 structure) name)))
5396 (localname (and (nth 4 structure)
5397 (match-string (nth 4 structure) name))))
5398 (vector method user host localname)))))
16674e4f
KG
5399
5400;; This function returns all possible method completions, adding the
5401;; trailing method delimeter.
16674e4f
KG
5402(defun tramp-get-completion-methods (partial-method)
5403 "Returns all method completions for PARTIAL-METHOD."
4007ba5b
KG
5404 (mapcar
5405 (lambda (method)
5406 (and method
5407 (string-match (concat "^" (regexp-quote partial-method)) method)
00d6fd04
MA
5408 (tramp-completion-make-tramp-file-name method nil nil nil)))
5409 (mapcar 'car tramp-methods)))
16674e4f
KG
5410
5411;; Compares partial user and host names with possible completions.
5412(defun tramp-get-completion-user-host (method partial-user partial-host user host)
5413 "Returns the most expanded string for user and host name completion.
5414PARTIAL-USER must match USER, PARTIAL-HOST must match HOST."
5415 (cond
5416
5417 ((and partial-user partial-host)
5418 (if (and host
5419 (string-match (concat "^" (regexp-quote partial-host)) host)
5420 (string-equal partial-user (or user partial-user)))
5421 (setq user partial-user)
5422 (setq user nil
5423 host nil)))
5424
5425 (partial-user
5426 (setq host nil)
5427 (unless
5428 (and user (string-match (concat "^" (regexp-quote partial-user)) user))
5429 (setq user nil)))
5430
5431 (partial-host
5432 (setq user nil)
5433 (unless
5434 (and host (string-match (concat "^" (regexp-quote partial-host)) host))
5435 (setq host nil)))
5436
5437 (t (setq user nil
5438 host nil)))
5439
292ffc15 5440 (unless (zerop (+ (length user) (length host)))
00d6fd04 5441 (tramp-completion-make-tramp-file-name method user host nil)))
16674e4f
KG
5442
5443(defun tramp-parse-rhosts (filename)
5444 "Return a list of (user host) tuples allowed to access.
292ffc15 5445Either user or host may be nil."
00d6fd04
MA
5446 ;; On Windows, there are problems in completion when
5447 ;; `default-directory' is remote.
9e6ab520 5448 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5449 res)
8daea7fc 5450 (when (file-readable-p filename)
16674e4f
KG
5451 (with-temp-buffer
5452 (insert-file-contents filename)
5453 (goto-char (point-min))
5454 (while (not (eobp))
292ffc15 5455 (push (tramp-parse-rhosts-group) res))))
16674e4f
KG
5456 res))
5457
16674e4f
KG
5458(defun tramp-parse-rhosts-group ()
5459 "Return a (user host) tuple allowed to access.
292ffc15 5460Either user or host may be nil."
16674e4f
KG
5461 (let ((result)
5462 (regexp
5463 (concat
5464 "^\\(" tramp-host-regexp "\\)"
5465 "\\([ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
9e6ab520 5466 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
5467 (when (re-search-forward regexp nil t)
5468 (setq result (append (list (match-string 3) (match-string 1)))))
5469 (widen)
5470 (forward-line 1)
5471 result))
5472
5473(defun tramp-parse-shosts (filename)
5474 "Return a list of (user host) tuples allowed to access.
5475User is always nil."
00d6fd04
MA
5476 ;; On Windows, there are problems in completion when
5477 ;; `default-directory' is remote.
9e6ab520 5478 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5479 res)
8daea7fc 5480 (when (file-readable-p filename)
16674e4f
KG
5481 (with-temp-buffer
5482 (insert-file-contents filename)
5483 (goto-char (point-min))
5484 (while (not (eobp))
292ffc15 5485 (push (tramp-parse-shosts-group) res))))
16674e4f
KG
5486 res))
5487
5488(defun tramp-parse-shosts-group ()
5489 "Return a (user host) tuple allowed to access.
5490User is always nil."
16674e4f
KG
5491 (let ((result)
5492 (regexp (concat "^\\(" tramp-host-regexp "\\)")))
9e6ab520 5493 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
5494 (when (re-search-forward regexp nil t)
5495 (setq result (list nil (match-string 1))))
5496 (widen)
5497 (or
5498 (> (skip-chars-forward ",") 0)
5499 (forward-line 1))
5500 result))
5501
8daea7fc
KG
5502(defun tramp-parse-sconfig (filename)
5503 "Return a list of (user host) tuples allowed to access.
5504User is always nil."
00d6fd04
MA
5505 ;; On Windows, there are problems in completion when
5506 ;; `default-directory' is remote.
9e6ab520 5507 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5508 res)
8daea7fc
KG
5509 (when (file-readable-p filename)
5510 (with-temp-buffer
5511 (insert-file-contents filename)
5512 (goto-char (point-min))
5513 (while (not (eobp))
5514 (push (tramp-parse-sconfig-group) res))))
5515 res))
5516
5517(defun tramp-parse-sconfig-group ()
5518 "Return a (user host) tuple allowed to access.
5519User is always nil."
8daea7fc
KG
5520 (let ((result)
5521 (regexp (concat "^[ \t]*Host[ \t]+" "\\(" tramp-host-regexp "\\)")))
9e6ab520 5522 (narrow-to-region (point) (tramp-compat-line-end-position))
8daea7fc
KG
5523 (when (re-search-forward regexp nil t)
5524 (setq result (list nil (match-string 1))))
5525 (widen)
5526 (or
5527 (> (skip-chars-forward ",") 0)
5528 (forward-line 1))
5529 result))
5530
5ec2cc41
KG
5531(defun tramp-parse-shostkeys (dirname)
5532 "Return a list of (user host) tuples allowed to access.
5533User is always nil."
00d6fd04
MA
5534 ;; On Windows, there are problems in completion when
5535 ;; `default-directory' is remote.
9e6ab520 5536 (let* ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
5537 (regexp (concat "^key_[0-9]+_\\(" tramp-host-regexp "\\)\\.pub$"))
5538 (files (when (file-directory-p dirname) (directory-files dirname)))
5539 result)
5ec2cc41
KG
5540 (while files
5541 (when (string-match regexp (car files))
5542 (push (list nil (match-string 1 (car files))) result))
5543 (setq files (cdr files)))
5544 result))
5545
5546(defun tramp-parse-sknownhosts (dirname)
5547 "Return a list of (user host) tuples allowed to access.
5548User is always nil."
00d6fd04
MA
5549 ;; On Windows, there are problems in completion when
5550 ;; `default-directory' is remote.
9e6ab520 5551 (let* ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
5552 (regexp (concat "^\\(" tramp-host-regexp
5553 "\\)\\.ssh-\\(dss\\|rsa\\)\\.pub$"))
5554 (files (when (file-directory-p dirname) (directory-files dirname)))
5555 result)
5ec2cc41
KG
5556 (while files
5557 (when (string-match regexp (car files))
5558 (push (list nil (match-string 1 (car files))) result))
5559 (setq files (cdr files)))
5560 result))
5561
16674e4f
KG
5562(defun tramp-parse-hosts (filename)
5563 "Return a list of (user host) tuples allowed to access.
5564User is always nil."
00d6fd04
MA
5565 ;; On Windows, there are problems in completion when
5566 ;; `default-directory' is remote.
9e6ab520 5567 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5568 res)
8daea7fc 5569 (when (file-readable-p filename)
16674e4f
KG
5570 (with-temp-buffer
5571 (insert-file-contents filename)
5572 (goto-char (point-min))
5573 (while (not (eobp))
292ffc15 5574 (push (tramp-parse-hosts-group) res))))
16674e4f
KG
5575 res))
5576
5577(defun tramp-parse-hosts-group ()
5578 "Return a (user host) tuple allowed to access.
5579User is always nil."
16674e4f 5580 (let ((result)
b96e6899
MA
5581 (regexp
5582 (concat "^\\(" tramp-ipv6-regexp "\\|" tramp-host-regexp "\\)")))
9e6ab520 5583 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f 5584 (when (re-search-forward regexp nil t)
b96e6899 5585 (setq result (list nil (match-string 1))))
16674e4f
KG
5586 (widen)
5587 (or
5588 (> (skip-chars-forward " \t") 0)
5589 (forward-line 1))
5590 result))
5591
8daea7fc
KG
5592;; For su-alike methods it would be desirable to return "root@localhost"
5593;; as default. Unfortunately, we have no information whether any user name
00d6fd04 5594;; has been typed already. So we use `tramp-current-user' as indication,
8daea7fc 5595;; assuming it is set in `tramp-completion-handle-file-name-all-completions'.
16674e4f
KG
5596(defun tramp-parse-passwd (filename)
5597 "Return a list of (user host) tuples allowed to access.
5598Host is always \"localhost\"."
00d6fd04
MA
5599 ;; On Windows, there are problems in completion when
5600 ;; `default-directory' is remote.
9e6ab520 5601 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5602 res)
8daea7fc 5603 (if (zerop (length tramp-current-user))
16674e4f 5604 '(("root" nil))
8daea7fc 5605 (when (file-readable-p filename)
16674e4f
KG
5606 (with-temp-buffer
5607 (insert-file-contents filename)
5608 (goto-char (point-min))
5609 (while (not (eobp))
292ffc15 5610 (push (tramp-parse-passwd-group) res))))
16674e4f
KG
5611 res)))
5612
5613(defun tramp-parse-passwd-group ()
5614 "Return a (user host) tuple allowed to access.
292ffc15 5615Host is always \"localhost\"."
16674e4f
KG
5616 (let ((result)
5617 (regexp (concat "^\\(" tramp-user-regexp "\\):")))
9e6ab520 5618 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
5619 (when (re-search-forward regexp nil t)
5620 (setq result (list (match-string 1) "localhost")))
5621 (widen)
5622 (forward-line 1)
5623 result))
5624
292ffc15
KG
5625(defun tramp-parse-netrc (filename)
5626 "Return a list of (user host) tuples allowed to access.
5627User may be nil."
00d6fd04
MA
5628 ;; On Windows, there are problems in completion when
5629 ;; `default-directory' is remote.
9e6ab520 5630 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5631 res)
8daea7fc 5632 (when (file-readable-p filename)
292ffc15
KG
5633 (with-temp-buffer
5634 (insert-file-contents filename)
5635 (goto-char (point-min))
5636 (while (not (eobp))
5637 (push (tramp-parse-netrc-group) res))))
5638 res))
5639
5640(defun tramp-parse-netrc-group ()
5641 "Return a (user host) tuple allowed to access.
5642User may be nil."
292ffc15
KG
5643 (let ((result)
5644 (regexp
5645 (concat
5646 "^[ \t]*machine[ \t]+" "\\(" tramp-host-regexp "\\)"
5647 "\\([ \t]+login[ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
9e6ab520 5648 (narrow-to-region (point) (tramp-compat-line-end-position))
292ffc15
KG
5649 (when (re-search-forward regexp nil t)
5650 (setq result (list (match-string 3) (match-string 1))))
5651 (widen)
5652 (forward-line 1)
5653 result))
5654
00d6fd04
MA
5655(defun tramp-parse-putty (registry)
5656 "Return a list of (user host) tuples allowed to access.
5657User is always nil."
5658 ;; On Windows, there are problems in completion when
5659 ;; `default-directory' is remote.
9e6ab520 5660 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
5661 res)
5662 (with-temp-buffer
a4aeb9a4 5663 (when (zerop (tramp-local-call-process "reg" nil t nil "query" registry))
00d6fd04
MA
5664 (goto-char (point-min))
5665 (while (not (eobp))
5666 (push (tramp-parse-putty-group registry) res))))
5667 res))
5668
5669(defun tramp-parse-putty-group (registry)
5670 "Return a (user host) tuple allowed to access.
5671User is always nil."
5672 (let ((result)
5673 (regexp (concat (regexp-quote registry) "\\\\\\(.+\\)")))
9e6ab520 5674 (narrow-to-region (point) (tramp-compat-line-end-position))
00d6fd04
MA
5675 (when (re-search-forward regexp nil t)
5676 (setq result (list nil (match-string 1))))
5677 (widen)
5678 (forward-line 1)
5679 result))
5680
fb7933a3
KG
5681;;; Internal Functions:
5682
00d6fd04
MA
5683(defun tramp-maybe-send-script (vec script name)
5684 "Define in remote shell function NAME implemented as SCRIPT.
5685Only send the definition if it has not already been done."
5686 (let* ((p (tramp-get-connection-process vec))
5687 (scripts (tramp-get-connection-property p "scripts" nil)))
1834b39f 5688 (unless (member name scripts)
00d6fd04
MA
5689 (tramp-message vec 5 "Sending script `%s'..." name)
5690 ;; The script could contain a call of Perl. This is masked with `%s'.
5691 (tramp-send-command-and-check
5692 vec
5693 (format "%s () {\n%s\n}" name
5694 (format script (tramp-get-remote-perl vec))))
5695 (tramp-set-connection-property p "scripts" (cons name scripts))
5696 (tramp-message vec 5 "Sending script `%s'...done." name))))
c82c5727 5697
fb7933a3 5698(defun tramp-set-auto-save ()
00d6fd04 5699 (when (and ;; ange-ftp has its own auto-save mechanism
7177e2a3
MA
5700 (eq (tramp-find-foreign-file-name-handler (buffer-file-name))
5701 'tramp-sh-file-name-handler)
fb7933a3
KG
5702 auto-save-default)
5703 (auto-save-mode 1)))
5704(add-hook 'find-file-hooks 'tramp-set-auto-save t)
a69c01a0 5705(add-hook 'tramp-unload-hook
aa485f7c
MA
5706 (lambda ()
5707 (remove-hook 'find-file-hooks 'tramp-set-auto-save)))
fb7933a3
KG
5708
5709(defun tramp-run-test (switch filename)
5710 "Run `test' on the remote system, given a SWITCH and a FILENAME.
5711Returns the exit code of the `test' program."
00d6fd04
MA
5712 (with-parsed-tramp-file-name filename nil
5713 (tramp-send-command-and-check
5714 v
5715 (format
5716 "%s %s %s"
5717 (tramp-get-test-command v)
5718 switch
5719 (tramp-shell-quote-argument localname)))))
5720
5721(defun tramp-run-test2 (format-string file1 file2)
5722 "Run `test'-like program on the remote system, given FILE1, FILE2.
5723FORMAT-STRING contains the program name, switches, and place holders.
5724Returns the exit code of the `test' program. Barfs if the methods,
fb7933a3 5725hosts, or files, disagree."
00d6fd04
MA
5726 (unless (tramp-equal-remote file1 file2)
5727 (with-parsed-tramp-file-name (if (tramp-tramp-file-p file1) file1 file2) nil
5728 (tramp-error
5729 v 'file-error
5730 "tramp-run-test2 only implemented for same method, user, host")))
5731 (with-parsed-tramp-file-name file1 v1
5732 (with-parsed-tramp-file-name file1 v2
fb7933a3 5733 (tramp-send-command-and-check
00d6fd04
MA
5734 v1
5735 (format format-string
5736 (tramp-shell-quote-argument v1-localname)
5737 (tramp-shell-quote-argument v2-localname))))))
fb7933a3 5738
00d6fd04
MA
5739(defun tramp-buffer-name (vec)
5740 "A name for the connection buffer VEC."
5741 ;; We must use `tramp-file-name-real-host', because for gateway
5742 ;; methods the default port will be expanded later on, which would
5743 ;; tamper the name.
5744 (let ((method (tramp-file-name-method vec))
5745 (user (tramp-file-name-user vec))
5746 (host (tramp-file-name-real-host vec)))
5747 (if (not (zerop (length user)))
5748 (format "*tramp/%s %s@%s*" method user host)
5749 (format "*tramp/%s %s*" method host))))
5750
5751(defun tramp-get-buffer (vec)
5752 "Get the connection buffer to be used for VEC."
5753 (or (get-buffer (tramp-buffer-name vec))
5754 (with-current-buffer (get-buffer-create (tramp-buffer-name vec))
5755 (setq buffer-undo-list t)
5756 (setq default-directory
5757 (tramp-make-tramp-file-name
5758 (tramp-file-name-method vec)
5759 (tramp-file-name-user vec)
5760 (tramp-file-name-host vec)
5761 "/"))
5762 (current-buffer))))
5763
5764(defun tramp-get-connection-buffer (vec)
5765 "Get the connection buffer to be used for VEC.
5766In case a second asynchronous communication has been started, it is different
5767from `tramp-get-buffer'."
5768 (or (tramp-get-connection-property vec "process-buffer" nil)
5769 (tramp-get-buffer vec)))
5770
5771(defun tramp-get-connection-process (vec)
5772 "Get the connection process to be used for VEC.
5773In case a second asynchronous communication has been started, it is different
5774from the default one."
5775 (get-process
5776 (or (tramp-get-connection-property vec "process-name" nil)
5777 (tramp-buffer-name vec))))
5778
5779(defun tramp-debug-buffer-name (vec)
5780 "A name for the debug buffer for VEC."
5781 ;; We must use `tramp-file-name-real-host', because for gateway
5782 ;; methods the default port will be expanded later on, which would
5783 ;; tamper the name.
5784 (let ((method (tramp-file-name-method vec))
5785 (user (tramp-file-name-user vec))
5786 (host (tramp-file-name-real-host vec)))
5787 (if (not (zerop (length user)))
5788 (format "*debug tramp/%s %s@%s*" method user host)
5789 (format "*debug tramp/%s %s*" method host))))
5790
5791(defun tramp-get-debug-buffer (vec)
5792 "Get the debug buffer for VEC."
01917a18 5793 (with-current-buffer
00d6fd04
MA
5794 (get-buffer-create (tramp-debug-buffer-name vec))
5795 (when (bobp)
5796 (setq buffer-undo-list t)
9ce8462a
MA
5797 ;; Activate outline-mode. This runs `text-mode-hook' and
5798 ;; `outline-mode-hook'. We must prevent that local processes
5799 ;; die. Yes: I've seen `flyspell-mode', which starts "ispell"
5800 ;; ...
9e6ab520 5801 (let ((default-directory (tramp-compat-temporary-file-directory)))
00d6fd04 5802 (outline-mode))
9ce8462a 5803 (set (make-local-variable 'outline-regexp)
736ac90f 5804 "[0-9]+:[0-9]+:[0-9]+\\.[0-9]+ [a-z0-9-]+ (\\([0-9]+\\)) #")
9ce8462a
MA
5805; (set (make-local-variable 'outline-regexp)
5806; "[a-z.-]+:[0-9]+: [a-z0-9-]+ (\\([0-9]+\\)) #")
5807 (set (make-local-variable 'outline-level) 'tramp-outline-level))
01917a18 5808 (current-buffer)))
fb7933a3 5809
00d6fd04
MA
5810(defun tramp-outline-level ()
5811 "Return the depth to which a statement is nested in the outline.
5812Point must be at the beginning of a header line.
5813
5814The outline level is equal to the verbosity of the Tramp message."
5815 (1+ (string-to-number (match-string 1))))
fb7933a3 5816
00d6fd04
MA
5817(defun tramp-find-executable
5818 (vec progname dirlist &optional ignore-tilde ignore-path)
5819 "Searches for PROGNAME in $PATH and all directories mentioned in DIRLIST.
5820First arg VEC specifies the connection, PROGNAME is the program
5821to search for, and DIRLIST gives the list of directories to
5822search. If IGNORE-TILDE is non-nil, directory names starting
5823with `~' will be ignored. If IGNORE-PATH is non-nil, searches
5824only in DIRLIST.
fb7933a3 5825
7432277c 5826Returns the absolute file name of PROGNAME, if found, and nil otherwise.
fb7933a3
KG
5827
5828This function expects to be in the right *tramp* buffer."
00d6fd04
MA
5829 (with-current-buffer (tramp-get-buffer vec)
5830 (let (result)
5831 ;; Check whether the executable is in $PATH. "which(1)" does not
5832 ;; report always a correct error code; therefore we check the
5833 ;; number of words it returns.
5834 (unless ignore-path
5835 (tramp-send-command vec (format "which \\%s | wc -w" progname))
5836 (goto-char (point-min))
5837 (if (looking-at "^1$")
5838 (setq result (concat "\\" progname))))
5839 (unless result
5840 (when ignore-tilde
5841 ;; Remove all ~/foo directories from dirlist. In Emacs 20,
5842 ;; `remove' is in CL, and we want to avoid CL dependencies.
5843 (let (newdl d)
5844 (while dirlist
5845 (setq d (car dirlist))
5846 (setq dirlist (cdr dirlist))
5847 (unless (char-equal ?~ (aref d 0))
5848 (setq newdl (cons d newdl))))
5849 (setq dirlist (nreverse newdl))))
5850 (tramp-send-command
5851 vec
5852 (format (concat "while read d; "
5853 "do if test -x $d/%s -a -f $d/%s; "
5854 "then echo tramp_executable $d/%s; "
5855 "break; fi; done <<'EOF'\n"
5856 "%s\nEOF")
5857 progname progname progname (mapconcat 'identity dirlist "\n")))
5858 (goto-char (point-max))
5859 (when (search-backward "tramp_executable " nil t)
5860 (skip-chars-forward "^ ")
5861 (skip-chars-forward " ")
9e6ab520
MA
5862 (setq result (buffer-substring
5863 (point) (tramp-compat-line-end-position)))))
00d6fd04
MA
5864 result)))
5865
5866(defun tramp-set-remote-path (vec)
5867 "Sets the remote environment PATH to existing directories.
5868I.e., for each directory in `tramp-remote-path', it is tested
5869whether it exists and if so, it is added to the environment
5870variable PATH."
5871 (tramp-message vec 5 (format "Setting $PATH environment variable"))
f84638eb
MA
5872 (tramp-send-command
5873 vec (format "PATH=%s; export PATH"
5874 (mapconcat 'identity (tramp-get-remote-path vec) ":"))))
fb7933a3 5875
cfb5c0db
MA
5876;; ------------------------------------------------------------
5877;; -- Communication with external shell --
5878;; ------------------------------------------------------------
fb7933a3 5879
00d6fd04 5880(defun tramp-find-file-exists-command (vec)
fb7933a3
KG
5881 "Find a command on the remote host for checking if a file exists.
5882Here, we are looking for a command which has zero exit status if the
5883file exists and nonzero exit status otherwise."
00d6fd04 5884 (let ((existing "/")
fb7933a3 5885 (nonexisting
00d6fd04
MA
5886 (tramp-shell-quote-argument "/ this file does not exist "))
5887 result)
fb7933a3
KG
5888 ;; The algorithm is as follows: we try a list of several commands.
5889 ;; For each command, we first run `$cmd /' -- this should return
5890 ;; true, as the root directory always exists. And then we run
00d6fd04 5891 ;; `$cmd /this\ file\ does\ not\ exist ', hoping that the file indeed
fb7933a3
KG
5892 ;; does not exist. This should return false. We use the first
5893 ;; command we find that seems to work.
5894 ;; The list of commands to try is as follows:
00d6fd04
MA
5895 ;; `ls -d' This works on most systems, but NetBSD 1.4
5896 ;; has a bug: `ls' always returns zero exit
5897 ;; status, even for files which don't exist.
5898 ;; `test -e' Some Bourne shells have a `test' builtin
5899 ;; which does not know the `-e' option.
5900 ;; `/bin/test -e' For those, the `test' binary on disk normally
5901 ;; provides the option. Alas, the binary
5902 ;; is sometimes `/bin/test' and sometimes it's
5903 ;; `/usr/bin/test'.
5904 ;; `/usr/bin/test -e' In case `/bin/test' does not exist.
fb7933a3 5905 (unless (or
00d6fd04
MA
5906 (and (setq result (format "%s -e" (tramp-get-test-command vec)))
5907 (zerop (tramp-send-command-and-check
5908 vec (format "%s %s" result existing)))
5909 (not (zerop (tramp-send-command-and-check
5910 vec (format "%s %s" result nonexisting)))))
5911 (and (setq result "/bin/test -e")
5912 (zerop (tramp-send-command-and-check
5913 vec (format "%s %s" result existing)))
5914 (not (zerop (tramp-send-command-and-check
5915 vec (format "%s %s" result nonexisting)))))
5916 (and (setq result "/usr/bin/test -e")
5917 (zerop (tramp-send-command-and-check
5918 vec (format "%s %s" result existing)))
5919 (not (zerop (tramp-send-command-and-check
5920 vec (format "%s %s" result nonexisting)))))
5921 (and (setq result (format "%s -d" (tramp-get-ls-command vec)))
5922 (zerop (tramp-send-command-and-check
5923 vec (format "%s %s" result existing)))
5924 (not (zerop (tramp-send-command-and-check
5925 vec (format "%s %s" result nonexisting))))))
5926 (tramp-error
5927 vec 'file-error "Couldn't find command to check if file exists"))
5928 result))
bf247b6e 5929
fb7933a3 5930;; CCC test ksh or bash found for tilde expansion?
00d6fd04
MA
5931(defun tramp-find-shell (vec)
5932 "Opens a shell on the remote host which groks tilde expansion."
5933 (unless (tramp-get-connection-property vec "remote-shell" nil)
5934 (let (shell)
5935 (with-current-buffer (tramp-get-buffer vec)
7e780ff1 5936 (tramp-send-command vec "echo ~root" t)
00d6fd04
MA
5937 (cond
5938 ((string-match "^~root$" (buffer-string))
5939 (setq shell
f84638eb
MA
5940 (or (tramp-find-executable
5941 vec "bash" (tramp-get-remote-path vec) t)
5942 (tramp-find-executable
5943 vec "ksh" (tramp-get-remote-path vec) t)))
00d6fd04
MA
5944 (unless shell
5945 (tramp-error
5946 vec 'file-error
5947 "Couldn't find a shell which groks tilde expansion"))
5948 ;; Find arguments for this shell.
5949 (let ((alist tramp-sh-extra-args)
5950 item extra-args)
5951 (while (and alist (null extra-args))
5952 (setq item (pop alist))
5953 (when (string-match (car item) shell)
5954 (setq extra-args (cdr item))))
5955 (when extra-args (setq shell (concat shell " " extra-args))))
5956 (tramp-message
5957 vec 5 "Starting remote shell `%s' for tilde expansion..." shell)
a4aeb9a4
MA
5958 (let ((tramp-end-of-output "$ "))
5959 (tramp-send-command
b08104a0 5960 vec
70c11b0b
MA
5961 (format "PROMPT_COMMAND='' PS1=%s PS2='' PS3='' exec %s"
5962 (shell-quote-argument tramp-end-of-output) shell)
b08104a0 5963 t))
a0a5183a 5964 ;; Setting prompts.
00d6fd04 5965 (tramp-message vec 5 "Setting remote shell prompt...")
70c11b0b
MA
5966 (tramp-send-command
5967 vec (format "PS1=%s" (shell-quote-argument tramp-end-of-output)) t)
9fa0d3aa
MA
5968 (tramp-send-command vec "PS2=''" t)
5969 (tramp-send-command vec "PS3=''" t)
5970 (tramp-send-command vec "PROMPT_COMMAND=''" t)
00d6fd04 5971 (tramp-message vec 5 "Setting remote shell prompt...done"))
a0a5183a 5972
00d6fd04
MA
5973 (t (tramp-message
5974 vec 5 "Remote `%s' groks tilde expansion, good"
5975 (tramp-get-method-parameter
5976 (tramp-file-name-method vec) 'tramp-remote-sh))
5977 (tramp-set-connection-property
5978 vec "remote-shell"
5979 (tramp-get-method-parameter
5980 (tramp-file-name-method vec) 'tramp-remote-sh))))))))
fb7933a3 5981
bf247b6e
KS
5982;; ------------------------------------------------------------
5983;; -- Functions for establishing connection --
5984;; ------------------------------------------------------------
fb7933a3 5985
ac474af1
KG
5986;; The following functions are actions to be taken when seeing certain
5987;; prompts from the remote host. See the variable
5988;; `tramp-actions-before-shell' for usage of these functions.
5989
00d6fd04 5990(defun tramp-action-login (proc vec)
ac474af1 5991 "Send the login name."
00d6fd04
MA
5992 (when (not (stringp tramp-current-user))
5993 (save-window-excursion
5994 (let ((enable-recursive-minibuffers t))
5995 (pop-to-buffer (tramp-get-connection-buffer vec))
5996 (setq tramp-current-user (read-string (match-string 0))))))
5997 (tramp-message vec 3 "Sending login name `%s'" tramp-current-user)
5998 (with-current-buffer (tramp-get-connection-buffer vec)
5999 (tramp-message vec 6 "\n%s" (buffer-string)))
6000 (tramp-send-string vec tramp-current-user))
6001
6002(defun tramp-action-password (proc vec)
ac474af1 6003 "Query the user for a password."
70c11b0b
MA
6004 (with-current-buffer (process-buffer proc)
6005 (tramp-check-for-regexp proc tramp-password-prompt-regexp)
6006 (tramp-message vec 3 "Sending %s" (match-string 1)))
00d6fd04
MA
6007 (tramp-enter-password proc))
6008
6009(defun tramp-action-succeed (proc vec)
ac474af1 6010 "Signal success in finding shell prompt."
ac474af1
KG
6011 (throw 'tramp-action 'ok))
6012
00d6fd04 6013(defun tramp-action-permission-denied (proc vec)
ac474af1 6014 "Signal permission denied."
00d6fd04 6015 (kill-process proc)
ac474af1
KG
6016 (throw 'tramp-action 'permission-denied))
6017
00d6fd04 6018(defun tramp-action-yesno (proc vec)
3cdaec13
KG
6019 "Ask the user for confirmation using `yes-or-no-p'.
6020Send \"yes\" to remote process on confirmation, abort otherwise.
6021See also `tramp-action-yn'."
ac474af1 6022 (save-window-excursion
00d6fd04
MA
6023 (let ((enable-recursive-minibuffers t))
6024 (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec)))
6025 (unless (yes-or-no-p (match-string 0))
6026 (kill-process proc)
6027 (throw 'tramp-action 'permission-denied))
6028 (with-current-buffer (tramp-get-connection-buffer vec)
6029 (tramp-message vec 6 "\n%s" (buffer-string)))
6030 (tramp-send-string vec "yes"))))
6031
6032(defun tramp-action-yn (proc vec)
3cdaec13
KG
6033 "Ask the user for confirmation using `y-or-n-p'.
6034Send \"y\" to remote process on confirmation, abort otherwise.
6035See also `tramp-action-yesno'."
6036 (save-window-excursion
00d6fd04
MA
6037 (let ((enable-recursive-minibuffers t))
6038 (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec)))
6039 (unless (y-or-n-p (match-string 0))
6040 (kill-process proc)
6041 (throw 'tramp-action 'permission-denied))
6042 (with-current-buffer (tramp-get-connection-buffer vec)
6043 (tramp-message vec 6 "\n%s" (buffer-string)))
6044 (tramp-send-string vec "y"))))
6045
6046(defun tramp-action-terminal (proc vec)
487f4fb7
KG
6047 "Tell the remote host which terminal type to use.
6048The terminal type can be configured with `tramp-terminal-type'."
00d6fd04 6049 (tramp-message vec 5 "Setting `%s' as terminal type." tramp-terminal-type)
7e780ff1
MA
6050 (with-current-buffer (tramp-get-connection-buffer vec)
6051 (tramp-message vec 6 "\n%s" (buffer-string)))
00d6fd04 6052 (tramp-send-string vec tramp-terminal-type))
487f4fb7 6053
00d6fd04 6054(defun tramp-action-process-alive (proc vec)
19a87064 6055 "Check whether a process has finished."
00d6fd04 6056 (unless (memq (process-status proc) '(run open))
19a87064
MA
6057 (throw 'tramp-action 'process-died)))
6058
00d6fd04 6059(defun tramp-action-out-of-band (proc vec)
38c65fca 6060 "Check whether an out-of-band copy has finished."
00d6fd04
MA
6061 (cond ((and (memq (process-status proc) '(stop exit))
6062 (zerop (process-exit-status proc)))
6063 (tramp-message vec 3 "Process has finished.")
38c65fca 6064 (throw 'tramp-action 'ok))
00d6fd04
MA
6065 ((or (and (memq (process-status proc) '(stop exit))
6066 (not (zerop (process-exit-status proc))))
6067 (memq (process-status proc) '(signal)))
01917a18
MA
6068 ;; `scp' could have copied correctly, but set modes could have failed.
6069 ;; This can be ignored.
00d6fd04
MA
6070 (with-current-buffer (process-buffer proc)
6071 (goto-char (point-min))
6072 (if (re-search-forward tramp-operation-not-permitted-regexp nil t)
6073 (progn
6074 (tramp-message vec 5 "'set mode' error ignored.")
6075 (tramp-message vec 3 "Process has finished.")
6076 (throw 'tramp-action 'ok))
6077 (tramp-message vec 3 "Process has died.")
6078 (throw 'tramp-action 'process-died))))
38c65fca
KG
6079 (t nil)))
6080
ac474af1
KG
6081;; Functions for processing the actions.
6082
00d6fd04 6083(defun tramp-process-one-action (proc vec actions)
ac474af1 6084 "Wait for output from the shell and perform one action."
00d6fd04 6085 (let (found todo item pattern action)
e6466697 6086 (while (not found)
00d6fd04
MA
6087 ;; Reread output once all actions have been performed.
6088 ;; Obviously, the output was not complete.
6089 (tramp-accept-process-output proc 1)
e6466697
MA
6090 (setq todo actions)
6091 (while todo
e6466697 6092 (setq item (pop todo))
95d610cb 6093 (setq pattern (format "\\(%s\\)\\'" (symbol-value (nth 0 item))))
e6466697 6094 (setq action (nth 1 item))
00d6fd04
MA
6095 (tramp-message
6096 vec 5 "Looking for regexp \"%s\" from remote shell" pattern)
6097 (when (tramp-check-for-regexp proc pattern)
6098 (tramp-message vec 5 "Call `%s'" (symbol-name action))
6099 (setq found (funcall action proc vec)))))
e6466697
MA
6100 found))
6101
00d6fd04 6102(defun tramp-process-actions (proc vec actions &optional timeout)
e6466697 6103 "Perform actions until success or TIMEOUT."
5c7043a2
MA
6104 ;; Enable auth-sorce and password-cache.
6105 (tramp-set-connection-property proc "first-password-request" t)
ac474af1
KG
6106 (let (exit)
6107 (while (not exit)
00d6fd04 6108 (tramp-message proc 3 "Waiting for prompts from remote shell")
ac474af1
KG
6109 (setq exit
6110 (catch 'tramp-action
e6466697
MA
6111 (if timeout
6112 (with-timeout (timeout)
00d6fd04
MA
6113 (tramp-process-one-action proc vec actions))
6114 (tramp-process-one-action proc vec actions)))))
6115 (with-current-buffer (tramp-get-connection-buffer vec)
6116 (tramp-message vec 6 "\n%s" (buffer-string)))
ac474af1 6117 (unless (eq exit 'ok)
9c13938d 6118 (tramp-clear-passwd vec)
00d6fd04
MA
6119 (tramp-error-with-buffer
6120 nil vec 'file-error
6121 (cond
6122 ((eq exit 'permission-denied) "Permission denied")
6123 ((eq exit 'process-died) "Process died")
6124 (t "Login failed"))))))
fb7933a3
KG
6125
6126;; Utility functions.
6127
00d6fd04 6128(defun tramp-accept-process-output (&optional proc timeout timeout-msecs)
d2a2c17f
MA
6129 "Like `accept-process-output' for Tramp processes.
6130This is needed in order to hide `last-coding-system-used', which is set
6131for process communication also."
00d6fd04
MA
6132 (with-current-buffer (process-buffer proc)
6133 (tramp-message proc 10 "%s %s" proc (process-status proc))
6134 (let (buffer-read-only last-coding-system-used)
6135 ;; Under Windows XP, accept-process-output doesn't return
6136 ;; sometimes. So we add an additional timeout.
6137 (with-timeout ((or timeout 1))
6138 (accept-process-output proc timeout timeout-msecs)))
6139 (tramp-message proc 10 "\n%s" (buffer-string))))
6140
6141(defun tramp-check-for-regexp (proc regexp)
6142 "Check whether REGEXP is contained in process buffer of PROC.
6143Erase echoed commands if exists."
6144 (with-current-buffer (process-buffer proc)
6145 (goto-char (point-min))
674da028 6146
00d6fd04
MA
6147 ;; Check whether we need to remove echo output.
6148 (when (and (tramp-get-connection-property proc "check-remote-echo" nil)
6149 (re-search-forward tramp-echoed-echo-mark-regexp nil t))
6150 (let ((begin (match-beginning 0)))
6151 (when (re-search-forward tramp-echoed-echo-mark-regexp nil t)
6152 ;; Discard echo from remote output.
6153 (tramp-set-connection-property proc "check-remote-echo" nil)
6154 (tramp-message proc 5 "echo-mark found")
6155 (forward-line)
6156 (delete-region begin (point))
6157 (goto-char (point-min)))))
674da028 6158
70c11b0b
MA
6159 (when (not (tramp-get-connection-property proc "check-remote-echo" nil))
6160 ;; No echo to be handled, now we can look for the regexp.
674da028 6161 (goto-char (point-min))
00d6fd04 6162 (re-search-forward regexp nil t))))
d2a2c17f 6163
fb7933a3
KG
6164(defun tramp-wait-for-regexp (proc timeout regexp)
6165 "Wait for a REGEXP to appear from process PROC within TIMEOUT seconds.
6166Expects the output of PROC to be sent to the current buffer. Returns
6167the string that matched, or nil. Waits indefinitely if TIMEOUT is
6168nil."
00d6fd04
MA
6169 (with-current-buffer (process-buffer proc)
6170 (let ((found (tramp-check-for-regexp proc regexp))
6171 (start-time (current-time)))
6172 (cond (timeout
6173 ;; Work around a bug in XEmacs 21, where the timeout
6174 ;; expires faster than it should. This degenerates
6175 ;; to polling for buggy XEmacsen, but oh, well.
6176 (while (and (not found)
6177 (< (tramp-time-diff (current-time) start-time)
6178 timeout))
6179 (with-timeout (timeout)
6180 (while (not found)
6181 (tramp-accept-process-output proc 1)
6182 (unless (memq (process-status proc) '(run open))
6183 (tramp-error-with-buffer
6184 nil proc 'file-error "Process has died"))
6185 (setq found (tramp-check-for-regexp proc regexp))))))
6186 (t
6187 (while (not found)
6188 (tramp-accept-process-output proc 1)
6189 (unless (memq (process-status proc) '(run open))
6190 (tramp-error-with-buffer
6191 nil proc 'file-error "Process has died"))
6192 (setq found (tramp-check-for-regexp proc regexp)))))
6193 (tramp-message proc 6 "\n%s" (buffer-string))
fb7933a3 6194 (when (not found)
00d6fd04
MA
6195 (if timeout
6196 (tramp-error
6197 proc 'file-error "[[Regexp `%s' not found in %d secs]]"
6198 regexp timeout)
6199 (tramp-error proc 'file-error "[[Regexp `%s' not found]]" regexp)))
6200 found)))
fb7933a3 6201
b25a52cc
KG
6202(defun tramp-barf-if-no-shell-prompt (proc timeout &rest error-args)
6203 "Wait for shell prompt and barf if none appears.
6204Looks at process PROC to see if a shell prompt appears in TIMEOUT
6205seconds. If not, it produces an error message with the given ERROR-ARGS."
7e780ff1
MA
6206 (unless
6207 (tramp-wait-for-regexp
6208 proc timeout
6209 (format
6210 "\\(%s\\|%s\\)\\'" shell-prompt-pattern tramp-shell-prompt-pattern))
00d6fd04
MA
6211 (apply 'tramp-error-with-buffer nil proc 'file-error error-args)))
6212
7e780ff1
MA
6213;; We don't call `tramp-send-string' in order to hide the password
6214;; from the debug buffer, and because end-of-line handling of the
6215;; string.
6216(defun tramp-enter-password (proc)
00d6fd04
MA
6217 "Prompt for a password and send it to the remote end."
6218 (process-send-string
7e780ff1
MA
6219 proc (concat (tramp-read-passwd proc)
6220 (or (tramp-get-method-parameter
6221 tramp-current-method
6222 'tramp-password-end-of-line)
6223 tramp-default-password-end-of-line))))
00d6fd04
MA
6224
6225(defun tramp-open-connection-setup-interactive-shell (proc vec)
fb7933a3 6226 "Set up an interactive shell.
00d6fd04
MA
6227Mainly sets the prompt and the echo correctly. PROC is the shell
6228process to set up. VEC specifies the connection."
a4aeb9a4 6229 (let ((tramp-end-of-output "$ "))
8950769a
MA
6230 ;; It is useful to set the prompt in the following command because
6231 ;; some people have a setting for $PS1 which /bin/sh doesn't know
6232 ;; about and thus /bin/sh will display a strange prompt. For
6233 ;; example, if $PS1 has "${CWD}" in the value, then ksh will
6234 ;; display the current working directory but /bin/sh will display
6235 ;; a dollar sign. The following command line sets $PS1 to a sane
6236 ;; value, and works under Bourne-ish shells as well as csh-like
6237 ;; shells. Daniel Pittman reports that the unusual positioning of
6238 ;; the single quotes makes it work under `rc', too. We also unset
6239 ;; the variable $ENV because that is read by some sh
6240 ;; implementations (eg, bash when called as sh) on startup; this
6241 ;; way, we avoid the startup file clobbering $PS1. $PROMP_COMMAND
6242 ;; is another way to set the prompt in /bin/bash, it must be
6243 ;; discarded as well.
a4aeb9a4
MA
6244 (tramp-send-command
6245 vec
6246 (format
70c11b0b
MA
6247 "exec env ENV='' PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s"
6248 (shell-quote-argument tramp-end-of-output)
a4aeb9a4
MA
6249 (tramp-get-method-parameter
6250 (tramp-file-name-method vec) 'tramp-remote-sh))
8950769a
MA
6251 t)
6252
6253 ;; Disable echo.
6254 (tramp-message vec 5 "Setting up remote shell environment")
6255 (tramp-send-command vec "stty -inlcr -echo kill '^U' erase '^H'" t)
6256 ;; Check whether the echo has really been disabled. Some
6257 ;; implementations, like busybox of embedded GNU/Linux, don't
6258 ;; support disabling.
6259 (tramp-send-command vec "echo foo" t)
6260 (with-current-buffer (process-buffer proc)
6261 (goto-char (point-min))
6262 (when (looking-at "echo foo")
6263 (tramp-set-connection-property proc "remote-echo" t)
6264 (tramp-message vec 5 "Remote echo still on. Ok.")
6265 ;; Make sure backspaces and their echo are enabled and no line
6266 ;; width magic interferes with them.
6267 (tramp-send-command vec "stty icanon erase ^H cols 32767" t))))
e42c6bbc 6268
7e780ff1 6269 (tramp-message vec 5 "Setting shell prompt")
70c11b0b
MA
6270 (tramp-send-command
6271 vec (format "PS1=%s" (shell-quote-argument tramp-end-of-output)) t)
9fa0d3aa
MA
6272 (tramp-send-command vec "PS2=''" t)
6273 (tramp-send-command vec "PS3=''" t)
6274 (tramp-send-command vec "PROMPT_COMMAND=''" t)
e42c6bbc 6275
fb7933a3
KG
6276 ;; Try to set up the coding system correctly.
6277 ;; CCC this can't be the right way to do it. Hm.
00d6fd04 6278 (tramp-message vec 5 "Determining coding system")
7e780ff1 6279 (tramp-send-command vec "echo foo ; echo bar" t)
00d6fd04 6280 (with-current-buffer (process-buffer proc)
fb7933a3
KG
6281 (goto-char (point-min))
6282 (if (featurep 'mule)
00d6fd04
MA
6283 ;; Use MULE to select the right EOL convention for communicating
6284 ;; with the process.
311dd93f 6285 (let* ((cs (or (funcall (symbol-function 'process-coding-system) proc)
00d6fd04
MA
6286 (cons 'undecided 'undecided)))
6287 cs-decode cs-encode)
6288 (when (symbolp cs) (setq cs (cons cs cs)))
6289 (setq cs-decode (car cs))
6290 (setq cs-encode (cdr cs))
6291 (unless cs-decode (setq cs-decode 'undecided))
6292 (unless cs-encode (setq cs-encode 'undecided))
6293 (setq cs-encode (tramp-coding-system-change-eol-conversion
6294 cs-encode 'unix))
6295 (when (search-forward "\r" nil t)
6296 (setq cs-decode (tramp-coding-system-change-eol-conversion
6297 cs-decode 'dos)))
311dd93f 6298 (funcall (symbol-function 'set-buffer-process-coding-system)
70c11b0b
MA
6299 cs-decode cs-encode)
6300 (tramp-message
6301 vec 5 "Setting coding system to `%s' and `%s'" cs-decode cs-encode))
fb7933a3
KG
6302 ;; Look for ^M and do something useful if found.
6303 (when (search-forward "\r" nil t)
00d6fd04
MA
6304 ;; We have found a ^M but cannot frob the process coding system
6305 ;; because we're running on a non-MULE Emacs. Let's try
6306 ;; stty, instead.
7e780ff1
MA
6307 (tramp-send-command vec "stty -onlcr" t))))
6308 (tramp-send-command vec "set +o vi +o emacs" t)
e42c6bbc
MA
6309
6310 ;; Check whether the output of "uname -sr" has been changed. If
6311 ;; yes, this is a strong indication that we must expire all
d8ac123e
MA
6312 ;; connection properties. We start again with
6313 ;; `tramp-maybe-open-connection', it will be catched there.
e42c6bbc
MA
6314 (tramp-message vec 5 "Checking system information")
6315 (let ((old-uname (tramp-get-connection-property vec "uname" nil))
6316 (new-uname
6317 (tramp-set-connection-property
6318 vec "uname"
6319 (tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\""))))
6320 (when (and (stringp old-uname) (not (string-equal old-uname new-uname)))
d8ac123e
MA
6321 (with-current-buffer (tramp-get-debug-buffer vec)
6322 ;; Keep the debug buffer
2296b54d
MA
6323 (rename-buffer
6324 (generate-new-buffer-name tramp-temp-buffer-name) 'unique)
d8ac123e
MA
6325 (funcall (symbol-function 'tramp-cleanup-connection) vec)
6326 (if (= (point-min) (point-max))
6327 (kill-buffer nil)
6328 (rename-buffer (tramp-debug-buffer-name vec) 'unique))
6329 ;; We call `tramp-get-buffer' in order to keep the debug buffer.
6330 (tramp-get-buffer vec)
6331 (tramp-message
6332 vec 3
6333 "Connection reset, because remote host changed from `%s' to `%s'"
6334 old-uname new-uname)
6335 (throw 'uname-changed (tramp-maybe-open-connection vec)))))
e42c6bbc
MA
6336
6337 ;; Check whether the remote host suffers from buggy
6338 ;; `send-process-string'. This is known for FreeBSD (see comment in
6339 ;; `send_process', file process.c). I've tested sending 624 bytes
6340 ;; successfully, sending 625 bytes failed. Emacs makes a hack when
6341 ;; this host type is detected locally. It cannot handle remote
6342 ;; hosts, though.
00d6fd04
MA
6343 (with-connection-property proc "chunksize"
6344 (cond
6345 ((and (integerp tramp-chunksize) (> tramp-chunksize 0))
6346 tramp-chunksize)
6347 (t
6348 (tramp-message
6349 vec 5 "Checking remote host type for `send-process-string' bug")
6350 (if (string-match
e42c6bbc 6351 "^FreeBSD" (tramp-get-connection-property vec "uname" ""))
00d6fd04 6352 500 0))))
e42c6bbc 6353
00d6fd04
MA
6354 ;; Set remote PATH variable.
6355 (tramp-set-remote-path vec)
e42c6bbc 6356
fb7933a3
KG
6357 ;; Search for a good shell before searching for a command which
6358 ;; checks if a file exists. This is done because Tramp wants to use
6359 ;; "test foo; echo $?" to check if various conditions hold, and
6360 ;; there are buggy /bin/sh implementations which don't execute the
6361 ;; "echo $?" part if the "test" part has an error. In particular,
6362 ;; the Solaris /bin/sh is a problem. I'm betting that all systems
6363 ;; with buggy /bin/sh implementations will have a working bash or
6364 ;; ksh. Whee...
00d6fd04 6365 (tramp-find-shell vec)
e42c6bbc 6366
00d6fd04 6367 ;; Disable unexpected output.
7e780ff1 6368 (tramp-send-command vec "mesg n; biff n" t)
e42c6bbc 6369
00d6fd04
MA
6370 ;; Set the environment.
6371 (tramp-message vec 5 "Setting default environment")
661aaece
MA
6372
6373 ;; On OpenSolaris, there is a bug when HISTFILE is changed in place
6374 ;; <http://bugs.opensolaris.org/view_bug.do?bug_id=6834184>. We
6375 ;; apply the workaround.
6376 (if (string-equal (tramp-get-connection-property vec "uname" "") "SunOS 5.11")
6377 (tramp-send-command vec "unset HISTFILE"))
6378
00d6fd04
MA
6379 (let ((env (copy-sequence tramp-remote-process-environment))
6380 unset item)
6381 (while env
70c11b0b 6382 (setq item (tramp-compat-split-string (car env) "="))
00d6fd04
MA
6383 (if (and (stringp (cadr item)) (not (string-equal (cadr item) "")))
6384 (tramp-send-command
7e780ff1 6385 vec (format "%s=%s; export %s" (car item) (cadr item) (car item)) t)
00d6fd04
MA
6386 (push (car item) unset))
6387 (setq env (cdr env)))
6388 (when unset
fb7933a3 6389 (tramp-send-command
7e780ff1 6390 vec (format "unset %s" (mapconcat 'identity unset " "))))) t)
fb7933a3 6391
ac474af1
KG
6392;; CCC: We should either implement a Perl version of base64 encoding
6393;; and decoding. Then we just use that in the last item. The other
6394;; alternative is to use the Perl version of UU encoding. But then
6395;; we need a Lisp version of uuencode.
16674e4f
KG
6396;;
6397;; Old text from documentation of tramp-methods:
6398;; Using a uuencode/uudecode inline method is discouraged, please use one
6399;; of the base64 methods instead since base64 encoding is much more
6400;; reliable and the commands are more standardized between the different
6401;; Unix versions. But if you can't use base64 for some reason, please
6402;; note that the default uudecode command does not work well for some
6403;; Unices, in particular AIX and Irix. For AIX, you might want to use
6404;; the following command for uudecode:
6405;;
6406;; sed '/^begin/d;/^[` ]$/d;/^end/d' | iconv -f uucode -t ISO8859-1
6407;;
6408;; For Irix, no solution is known yet.
6409
00d6fd04
MA
6410(defconst tramp-local-coding-commands
6411 '((b64 base64-encode-region base64-decode-region)
6412 (uu tramp-uuencode-region uudecode-decode-region)
6413 (pack
6414 "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
6415 "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"))
6416 "List of local coding commands for inline transfer.
16674e4f
KG
6417Each item is a list that looks like this:
6418
00d6fd04 6419\(FORMAT ENCODING DECODING)
ac474af1 6420
00d6fd04
MA
6421FORMAT is symbol describing the encoding/decoding format. It can be
6422`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
ac474af1 6423
00d6fd04
MA
6424ENCODING and DECODING can be strings, giving commands, or symbols,
6425giving functions. If they are strings, then they can contain
16674e4f
KG
6426the \"%s\" format specifier. If that specifier is present, the input
6427filename will be put into the command line at that spot. If the
6428specifier is not present, the input should be read from standard
6429input.
ac474af1 6430
16674e4f
KG
6431If they are functions, they will be called with two arguments, start
6432and end of region, and are expected to replace the region contents
6433with the encoded or decoded results, respectively.")
ac474af1 6434
00d6fd04 6435(defconst tramp-remote-coding-commands
3dc847a3
MA
6436 '((b64 "base64" "base64 -d")
6437 (b64 "mimencode -b" "mimencode -u -b")
00d6fd04
MA
6438 (b64 "mmencode -b" "mmencode -u -b")
6439 (b64 "recode data..base64" "recode base64..data")
6440 (b64 tramp-perl-encode-with-module tramp-perl-decode-with-module)
6441 (b64 tramp-perl-encode tramp-perl-decode)
6442 (uu "uuencode xxx" "uudecode -o /dev/stdout")
6443 (uu "uuencode xxx" "uudecode -o -")
6444 (uu "uuencode xxx" "uudecode -p")
6445 (uu "uuencode xxx" tramp-uudecode)
6446 (pack
6447 "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
6448 "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"))
6449 "List of remote coding commands for inline transfer.
6450Each item is a list that looks like this:
6451
6452\(FORMAT ENCODING DECODING)
6453
6454FORMAT is symbol describing the encoding/decoding format. It can be
6455`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
6456
6457ENCODING and DECODING can be strings, giving commands, or symbols,
6458giving variables. If they are strings, then they can contain
6459the \"%s\" format specifier. If that specifier is present, the input
6460filename will be put into the command line at that spot. If the
6461specifier is not present, the input should be read from standard
6462input.
6463
6464If they are variables, this variable is a string containing a Perl
6465implementation for this functionality. This Perl program will be transferred
6466to the remote host, and it is avalible as shell function with the same name.")
6467
6468(defun tramp-find-inline-encoding (vec)
ac474af1 6469 "Find an inline transfer encoding that works.
00d6fd04
MA
6470Goes through the list `tramp-local-coding-commands' and
6471`tramp-remote-coding-commands'."
6472 (save-excursion
6473 (let ((local-commands tramp-local-coding-commands)
6474 (magic "xyzzy")
6475 loc-enc loc-dec rem-enc rem-dec litem ritem found)
6476 (while (and local-commands (not found))
6477 (setq litem (pop local-commands))
6478 (catch 'wont-work-local
6479 (let ((format (nth 0 litem))
6480 (remote-commands tramp-remote-coding-commands))
6481 (setq loc-enc (nth 1 litem))
6482 (setq loc-dec (nth 2 litem))
6483 ;; If the local encoder or decoder is a string, the
6484 ;; corresponding command has to work locally.
6485 (if (not (stringp loc-enc))
6486 (tramp-message
6487 vec 5 "Checking local encoding function `%s'" loc-enc)
6488 (tramp-message
6489 vec 5 "Checking local encoding command `%s' for sanity" loc-enc)
6490 (unless (zerop (tramp-call-local-coding-command
6491 loc-enc nil nil))
6492 (throw 'wont-work-local nil)))
6493 (if (not (stringp loc-dec))
6494 (tramp-message
6495 vec 5 "Checking local decoding function `%s'" loc-dec)
6496 (tramp-message
6497 vec 5 "Checking local decoding command `%s' for sanity" loc-dec)
6498 (unless (zerop (tramp-call-local-coding-command
6499 loc-dec nil nil))
6500 (throw 'wont-work-local nil)))
6501 ;; Search for remote coding commands with the same format
6502 (while (and remote-commands (not found))
6503 (setq ritem (pop remote-commands))
6504 (catch 'wont-work-remote
6505 (when (equal format (nth 0 ritem))
6506 (setq rem-enc (nth 1 ritem))
6507 (setq rem-dec (nth 2 ritem))
6508 ;; Check if remote encoding and decoding commands can be
6509 ;; called remotely with null input and output. This makes
6510 ;; sure there are no syntax errors and the command is really
6511 ;; found. Note that we do not redirect stdout to /dev/null,
6512 ;; for two reasons: when checking the decoding command, we
6513 ;; actually check the output it gives. And also, when
6514 ;; redirecting "mimencode" output to /dev/null, then as root
6515 ;; it might change the permissions of /dev/null!
6516 (when (not (stringp rem-enc))
6517 (let ((name (symbol-name rem-enc)))
6518 (while (string-match (regexp-quote "-") name)
6519 (setq name (replace-match "_" nil t name)))
6520 (tramp-maybe-send-script vec (symbol-value rem-enc) name)
6521 (setq rem-enc name)))
6522 (tramp-message
6523 vec 5
6524 "Checking remote encoding command `%s' for sanity" rem-enc)
6525 (unless (zerop (tramp-send-command-and-check
6526 vec (format "%s </dev/null" rem-enc) t))
6527 (throw 'wont-work-remote nil))
6528
6529 (when (not (stringp rem-dec))
6530 (let ((name (symbol-name rem-dec)))
6531 (while (string-match (regexp-quote "-") name)
6532 (setq name (replace-match "_" nil t name)))
6533 (tramp-maybe-send-script vec (symbol-value rem-dec) name)
6534 (setq rem-dec name)))
6535 (tramp-message
6536 vec 5
6537 "Checking remote decoding command `%s' for sanity" rem-dec)
6538 (unless (zerop (tramp-send-command-and-check
6539 vec
6540 (format "echo %s | %s | %s"
6541 magic rem-enc rem-dec) t))
6542 (throw 'wont-work-remote nil))
6543
6544 (with-current-buffer (tramp-get-buffer vec)
6545 (goto-char (point-min))
6546 (unless (looking-at (regexp-quote magic))
6547 (throw 'wont-work-remote nil)))
6548
6549 ;; `rem-enc' and `rem-dec' could be a string meanwhile.
6550 (setq rem-enc (nth 1 ritem))
6551 (setq rem-dec (nth 2 ritem))
6552 (setq found t)))))))
6553
1d7e9a01 6554 ;; Did we find something?
00d6fd04 6555 (unless found
1d7e9a01 6556 (tramp-message vec 2 "Couldn't find an inline transfer encoding"))
00d6fd04
MA
6557
6558 ;; Set connection properties.
6559 (tramp-message vec 5 "Using local encoding `%s'" loc-enc)
6560 (tramp-set-connection-property vec "local-encoding" loc-enc)
6561 (tramp-message vec 5 "Using local decoding `%s'" loc-dec)
6562 (tramp-set-connection-property vec "local-decoding" loc-dec)
6563 (tramp-message vec 5 "Using remote encoding `%s'" rem-enc)
6564 (tramp-set-connection-property vec "remote-encoding" rem-enc)
6565 (tramp-message vec 5 "Using remote decoding `%s'" rem-dec)
6566 (tramp-set-connection-property vec "remote-decoding" rem-dec))))
16674e4f
KG
6567
6568(defun tramp-call-local-coding-command (cmd input output)
6569 "Call the local encoding or decoding command.
6570If CMD contains \"%s\", provide input file INPUT there in command.
6571Otherwise, INPUT is passed via standard input.
6572INPUT can also be nil which means `/dev/null'.
6573OUTPUT can be a string (which specifies a filename), or t (which
6574means standard output and thus the current buffer), or nil (which
6575means discard it)."
a4aeb9a4
MA
6576 (tramp-local-call-process
6577 tramp-encoding-shell
6578 (when (and input (not (string-match "%s" cmd))) input)
6579 (if (eq output t) t nil)
6580 nil
6581 tramp-encoding-command-switch
6582 (concat
6583 (if (string-match "%s" cmd) (format cmd input) cmd)
6584 (if (stringp output) (concat "> " output) ""))))
00d6fd04
MA
6585
6586(defun tramp-compute-multi-hops (vec)
6587 "Expands VEC according to `tramp-default-proxies-alist'.
6588Gateway hops are already opened."
6589 (let ((target-alist `(,vec))
6590 (choices tramp-default-proxies-alist)
6591 item proxy)
6592
6593 ;; Look for proxy hosts to be passed.
6594 (while choices
6595 (setq item (pop choices)
70c11b0b 6596 proxy (eval (nth 2 item)))
00d6fd04
MA
6597 (when (and
6598 ;; host
70c11b0b 6599 (string-match (or (eval (nth 0 item)) "")
00d6fd04
MA
6600 (or (tramp-file-name-host (car target-alist)) ""))
6601 ;; user
70c11b0b 6602 (string-match (or (eval (nth 1 item)) "")
00d6fd04
MA
6603 (or (tramp-file-name-user (car target-alist)) "")))
6604 (if (null proxy)
6605 ;; No more hops needed.
6606 (setq choices nil)
6607 ;; Replace placeholders.
6608 (setq proxy
6609 (format-spec
6610 proxy
6611 `((?u . ,(or (tramp-file-name-user (car target-alist)) ""))
6612 (?h . ,(or (tramp-file-name-host (car target-alist)) "")))))
6613 (with-parsed-tramp-file-name proxy l
6614 ;; Add the hop.
6615 (add-to-list 'target-alist l)
6616 ;; Start next search.
6617 (setq choices tramp-default-proxies-alist)))))
6618
6619 ;; Handle gateways.
8a4438b6
MA
6620 (when (and (boundp 'tramp-gw-tunnel-method)
6621 (string-match (format
6622 "^\\(%s\\|%s\\)$"
6623 (symbol-value 'tramp-gw-tunnel-method)
6624 (symbol-value 'tramp-gw-socks-method))
6625 (tramp-file-name-method (car target-alist))))
00d6fd04
MA
6626 (let ((gw (pop target-alist))
6627 (hop (pop target-alist)))
6628 ;; Is the method prepared for gateways?
6629 (unless (tramp-get-method-parameter
6630 (tramp-file-name-method hop) 'tramp-default-port)
6631 (tramp-error
6632 vec 'file-error
6633 "Method `%s' is not supported for gateway access."
6634 (tramp-file-name-method hop)))
6635 ;; Add default port if needed.
6636 (unless
6637 (string-match
6638 tramp-host-with-port-regexp (tramp-file-name-host hop))
6639 (aset hop 2
6640 (concat
6641 (tramp-file-name-host hop) tramp-prefix-port-format
6642 (number-to-string
6643 (tramp-get-method-parameter
6644 (tramp-file-name-method hop) 'tramp-default-port)))))
6645 ;; Open the gateway connection.
6646 (add-to-list
6647 'target-alist
6648 (vector
6649 (tramp-file-name-method hop) (tramp-file-name-user hop)
9e6ab520 6650 (funcall (symbol-function 'tramp-gw-open-connection) vec gw hop) nil))
00d6fd04
MA
6651 ;; For the password prompt, we need the correct values.
6652 ;; Therefore, we must remember the gateway vector. But we
6653 ;; cannot do it as connection property, because it shouldn't
6654 ;; be persistent. And we have no started process yet either.
6655 (tramp-set-file-property (car target-alist) "" "gateway" hop)))
6656
6657 ;; Foreign and out-of-band methods are not supported for multi-hops.
6658 (when (cdr target-alist)
6659 (setq choices target-alist)
6660 (while choices
6661 (setq item (pop choices))
6662 (when
6663 (or
6664 (not
6665 (tramp-get-method-parameter
6666 (tramp-file-name-method item) 'tramp-login-program))
6667 (tramp-get-method-parameter
6668 (tramp-file-name-method item) 'tramp-copy-program))
6669 (tramp-error
6670 vec 'file-error
6671 "Method `%s' is not supported for multi-hops."
6672 (tramp-file-name-method item)))))
6673
2991e49f
MA
6674 ;; In case the host name is not used for the remote shell
6675 ;; command, the user could be misguided by applying a random
6676 ;; hostname.
6677 (let* ((v (car target-alist))
6678 (method (tramp-file-name-method v))
6679 (host (tramp-file-name-host v)))
6680 (unless
6681 (or
6682 ;; There are multi-hops.
6683 (cdr target-alist)
6684 ;; The host name is used for the remote shell command.
6685 (member
6686 '("%h") (tramp-get-method-parameter method 'tramp-login-args))
6687 ;; The host is local. We cannot use `tramp-local-host-p'
6688 ;; here, because it opens a connection as well.
b96e6899 6689 (string-match tramp-local-host-regexp host))
2991e49f 6690 (tramp-error
42bc9b6d
MA
6691 v 'file-error
6692 "Host `%s' looks like a remote host, `%s' can only use the local host"
6693 host method)))
2991e49f 6694
00d6fd04
MA
6695 ;; Result.
6696 target-alist))
6697
6698(defun tramp-maybe-open-connection (vec)
6699 "Maybe open a connection VEC.
fb7933a3
KG
6700Does not do anything if a connection is already open, but re-opens the
6701connection if a previous connection has died for some reason."
d8ac123e
MA
6702 (catch 'uname-changed
6703 (let ((p (tramp-get-connection-process vec))
6704 (process-environment (copy-sequence process-environment)))
6705
6706 ;; If too much time has passed since last command was sent, look
6707 ;; whether process is still alive. If it isn't, kill it. When
6708 ;; using ssh, it can sometimes happen that the remote end has
6709 ;; hung up but the local ssh client doesn't recognize this until
6710 ;; it tries to send some data to the remote end. So that's why
6711 ;; we try to send a command from time to time, then look again
6712 ;; whether the process is really alive.
6713 (condition-case nil
6714 (when (and (> (tramp-time-diff
6715 (current-time)
6716 (tramp-get-connection-property
6717 p "last-cmd-time" '(0 0 0)))
6718 60)
6719 p (processp p) (memq (process-status p) '(run open)))
6720 (tramp-send-command vec "echo are you awake" t t)
6721 (unless (and (memq (process-status p) '(run open))
6722 (tramp-wait-for-output p 10))
6723 ;; The error will be catched locally.
6724 (tramp-error vec 'file-error "Awake did fail")))
6725 (file-error
6726 (tramp-flush-connection-property vec)
6727 (tramp-flush-connection-property p)
6728 (delete-process p)
6729 (setq p nil)))
6730
6731 ;; New connection must be opened.
6732 (unless (and p (processp p) (memq (process-status p) '(run open)))
6733
6734 ;; We call `tramp-get-buffer' in order to get a debug buffer for
6735 ;; messages from the beginning.
6736 (tramp-get-buffer vec)
6737 (if (zerop (length (tramp-file-name-user vec)))
6738 (tramp-message
6739 vec 3 "Opening connection for %s using %s..."
6740 (tramp-file-name-host vec)
6741 (tramp-file-name-method vec))
00d6fd04 6742 (tramp-message
d8ac123e
MA
6743 vec 3 "Opening connection for %s@%s using %s..."
6744 (tramp-file-name-user vec)
00d6fd04 6745 (tramp-file-name-host vec)
d8ac123e
MA
6746 (tramp-file-name-method vec)))
6747
6748 ;; Start new process.
6749 (when (and p (processp p))
6750 (delete-process p))
6751 (setenv "TERM" tramp-terminal-type)
6752 (setenv "LC_ALL" "C")
6753 (setenv "PROMPT_COMMAND")
6754 (setenv "PS1" "$ ")
6755 (let* ((target-alist (tramp-compute-multi-hops vec))
6756 (process-connection-type tramp-process-connection-type)
6757 (process-adaptive-read-buffering nil)
6758 (coding-system-for-read nil)
6759 ;; This must be done in order to avoid our file name handler.
6760 (p (let ((default-directory
6761 (tramp-compat-temporary-file-directory)))
6762 (start-process
6763 (or (tramp-get-connection-property vec "process-name" nil)
6764 (tramp-buffer-name vec))
6765 (tramp-get-connection-buffer vec)
70c11b0b 6766 tramp-encoding-shell))))
00d6fd04 6767
d8ac123e
MA
6768 (tramp-message
6769 vec 6 "%s" (mapconcat 'identity (process-command p) " "))
6770
6771 ;; Check whether process is alive.
d8ac123e
MA
6772 (tramp-set-process-query-on-exit-flag p nil)
6773 (tramp-message vec 3 "Waiting 60s for local shell to come up...")
6774 (tramp-barf-if-no-shell-prompt
6775 p 60 "Couldn't find local shell prompt %s" tramp-encoding-shell)
6776
6777 ;; Now do all the connections as specified.
6778 (while target-alist
6779 (let* ((hop (car target-alist))
6780 (l-method (tramp-file-name-method hop))
6781 (l-user (tramp-file-name-user hop))
6782 (l-host (tramp-file-name-host hop))
6783 (l-port nil)
6784 (login-program
6785 (tramp-get-method-parameter l-method 'tramp-login-program))
6786 (login-args
6787 (tramp-get-method-parameter l-method 'tramp-login-args))
6788 (gw-args
6789 (tramp-get-method-parameter l-method 'tramp-gw-args))
6790 (gw (tramp-get-file-property hop "" "gateway" nil))
6791 (g-method (and gw (tramp-file-name-method gw)))
6792 (g-user (and gw (tramp-file-name-user gw)))
6793 (g-host (and gw (tramp-file-name-host gw)))
6794 (command login-program)
6795 ;; We don't create the temporary file. In fact, it
6796 ;; is just a prefix for the ControlPath option of
6797 ;; ssh; the real temporary file has another name, and
6798 ;; it is created and protected by ssh. It is also
6799 ;; removed by ssh, when the connection is closed.
6800 (tmpfile
6801 (tramp-set-connection-property
6802 p "temp-file"
6803 (make-temp-name
6804 (expand-file-name
6805 tramp-temp-name-prefix
6806 (tramp-compat-temporary-file-directory)))))
6807 spec)
6808
6809 ;; Add gateway arguments if necessary.
6810 (when (and gw gw-args)
6811 (setq login-args (append login-args gw-args)))
6812
6813 ;; Check for port number. Until now, there's no need
6814 ;; for handling like method, user, host.
6815 (when (string-match tramp-host-with-port-regexp l-host)
6816 (setq l-port (match-string 2 l-host)
6817 l-host (match-string 1 l-host)))
6818
6819 ;; Set variables for computing the prompt for reading
2296b54d 6820 ;; password. They can also be derived from a gateway.
d8ac123e
MA
6821 (setq tramp-current-method (or g-method l-method)
6822 tramp-current-user (or g-user l-user)
6823 tramp-current-host (or g-host l-host))
6824
6825 ;; Replace login-args place holders.
6826 (setq
6827 l-host (or l-host "")
6828 l-user (or l-user "")
6829 l-port (or l-port "")
6830 spec `((?h . ,l-host) (?u . ,l-user) (?p . ,l-port)
6831 (?t . ,tmpfile))
6832 command
6833 (concat
6834 command " "
6835 (mapconcat
aa485f7c
MA
6836 (lambda (x)
6837 (setq x (mapcar (lambda (y) (format-spec y spec)) x))
6838 (unless (member "" x) (mapconcat 'identity x " ")))
d8ac123e 6839 login-args " ")
d8ac123e
MA
6840 ;; Local shell could be a Windows COMSPEC. It doesn't
6841 ;; know the ";" syntax, but we must exit always for
70c11b0b
MA
6842 ;; `start-file-process'. "exec" does not work either.
6843 " && exit || exit"))
d8ac123e
MA
6844
6845 ;; Send the command.
6846 (tramp-message vec 3 "Sending command `%s'" command)
6847 (tramp-send-command vec command t t)
6848 (tramp-process-actions p vec tramp-actions-before-shell 60)
6849 (tramp-message vec 3 "Found remote shell prompt on `%s'" l-host))
6850 ;; Next hop.
6851 (setq target-alist (cdr target-alist)))
6852
6853 ;; Make initial shell settings.
6854 (tramp-open-connection-setup-interactive-shell p vec))))))
00d6fd04
MA
6855
6856(defun tramp-send-command (vec command &optional neveropen nooutput)
6857 "Send the COMMAND to connection VEC.
6858Erases temporary buffer before sending the command. If optional
6859arg NEVEROPEN is non-nil, never try to open the connection. This
6860is meant to be used from `tramp-maybe-open-connection' only. The
6861function waits for output unless NOOUTPUT is set."
6862 (unless neveropen (tramp-maybe-open-connection vec))
6863 (let ((p (tramp-get-connection-process vec)))
8950769a 6864 (when (tramp-get-connection-property p "remote-echo" nil)
00d6fd04
MA
6865 ;; We mark the command string that it can be erased in the output buffer.
6866 (tramp-set-connection-property p "check-remote-echo" t)
6867 (setq command (format "%s%s%s" tramp-echo-mark command tramp-echo-mark)))
6868 (tramp-message vec 6 "%s" command)
6869 (tramp-send-string vec command)
6870 (unless nooutput (tramp-wait-for-output p))))
6871
00d6fd04 6872(defun tramp-wait-for-output (proc &optional timeout)
fb7933a3 6873 "Wait for output from remote rsh command."
00d6fd04 6874 (with-current-buffer (process-buffer proc)
bede3e9f
MA
6875 (let* (;; Initially, `tramp-end-of-output' is "$ ". There might
6876 ;; be leading escape sequences, which must be ignored.
6877 (regexp (format "[^$\n]*%s\r?$" (regexp-quote tramp-end-of-output)))
6878 ;; Sometimes, the commands do not return a newline but a
6879 ;; null byte before the shell prompt, for example "git
6880 ;; ls-files -c -z ...".
6881 (regexp1 (format "\\(^\\|\000\\)%s" regexp))
6882 (found (tramp-wait-for-regexp proc timeout regexp1)))
00d6fd04
MA
6883 (if found
6884 (let (buffer-read-only)
6885 (goto-char (point-max))
0664ff72 6886 (re-search-backward regexp nil t)
00d6fd04
MA
6887 (delete-region (point) (point-max)))
6888 (if timeout
6889 (tramp-error
6890 proc 'file-error
6891 "[[Remote prompt `%s' not found in %d secs]]"
6892 tramp-end-of-output timeout)
6893 (tramp-error
6894 proc 'file-error
6895 "[[Remote prompt `%s' not found]]" tramp-end-of-output)))
6896 ;; Return value is whether end-of-output sentinel was found.
6897 found)))
fb7933a3 6898
00d6fd04 6899(defun tramp-send-command-and-check (vec command &optional subshell)
fb7933a3 6900 "Run COMMAND and check its exit status.
fb7933a3
KG
6901Sends `echo $?' along with the COMMAND for checking the exit status. If
6902COMMAND is nil, just sends `echo $?'. Returns the exit status found.
6903
6904If the optional argument SUBSHELL is non-nil, the command is executed in
6905a subshell, ie surrounded by parentheses."
00d6fd04
MA
6906 (tramp-send-command
6907 vec
6908 (concat (if subshell "( " "")
6909 command
6910 (if command " 2>/dev/null; " "")
6911 "echo tramp_exit_status $?"
6912 (if subshell " )" " ")))
6913 (with-current-buffer (tramp-get-connection-buffer vec)
6914 (goto-char (point-max))
6915 (unless (re-search-backward "tramp_exit_status [0-9]+" nil t)
6916 (tramp-error
6917 vec 'file-error "Couldn't find exit status of `%s'" command))
6918 (skip-chars-forward "^ ")
6919 (prog1
6920 (read (current-buffer))
6921 (let (buffer-read-only) (delete-region (match-beginning 0) (point-max))))))
6922
6923(defun tramp-barf-unless-okay (vec command fmt &rest args)
fb7933a3
KG
6924 "Run COMMAND, check exit status, throw error if exit status not okay.
6925Similar to `tramp-send-command-and-check' but accepts two more arguments
6926FMT and ARGS which are passed to `error'."
00d6fd04
MA
6927 (unless (zerop (tramp-send-command-and-check vec command))
6928 (apply 'tramp-error vec 'file-error fmt args)))
6929
6930(defun tramp-send-command-and-read (vec command)
6931 "Run COMMAND and return the output, which must be a Lisp expression.
6932In case there is no valid Lisp expression, it raises an error"
6933 (tramp-barf-unless-okay vec command "`%s' returns with error" command)
6934 (with-current-buffer (tramp-get-connection-buffer vec)
6935 ;; Read the expression.
6936 (goto-char (point-min))
6937 (condition-case nil
6938 (prog1 (read (current-buffer))
6939 ;; Error handling.
9e6ab520 6940 (when (re-search-forward "\\S-" (tramp-compat-line-end-position) t)
9ce8462a 6941 (error nil)))
00d6fd04
MA
6942 (error (tramp-error
6943 vec 'file-error
6944 "`%s' does not return a valid Lisp expression: `%s'"
6945 command (buffer-string))))))
fb7933a3 6946
7432277c
KG
6947;; It seems that Tru64 Unix does not like it if long strings are sent
6948;; to it in one go. (This happens when sending the Perl
6949;; `file-attributes' implementation, for instance.) Therefore, we
27e813fe 6950;; have this function which sends the string in chunks.
00d6fd04
MA
6951(defun tramp-send-string (vec string)
6952 "Send the STRING via connection VEC.
7432277c
KG
6953
6954The STRING is expected to use Unix line-endings, but the lines sent to
6955the remote host use line-endings as defined in the variable
00d6fd04
MA
6956`tramp-rsh-end-of-line'. The communication buffer is erased before sending."
6957 (let* ((p (tramp-get-connection-process vec))
6958 (chunksize (tramp-get-connection-property p "chunksize" nil)))
6959 (unless p
6960 (tramp-error
6961 vec 'file-error "Can't send string to remote host -- not logged in"))
6962 (tramp-set-connection-property p "last-cmd-time" (current-time))
6963 (tramp-message vec 10 "%s" string)
6964 (with-current-buffer (tramp-get-connection-buffer vec)
6965 ;; Clean up the buffer. We cannot call `erase-buffer' because
6966 ;; narrowing might be in effect.
6967 (let (buffer-read-only) (delete-region (point-min) (point-max)))
27e813fe 6968 ;; Replace "\n" by `tramp-rsh-end-of-line'.
00d6fd04
MA
6969 (setq string
6970 (mapconcat 'identity
70c11b0b 6971 (tramp-compat-split-string string "\n")
00d6fd04
MA
6972 tramp-rsh-end-of-line))
6973 (unless (or (string= string "")
6974 (string-equal (substring string -1) tramp-rsh-end-of-line))
6975 (setq string (concat string tramp-rsh-end-of-line)))
27e813fe 6976 ;; Send the string.
00d6fd04
MA
6977 (if (and chunksize (not (zerop chunksize)))
6978 (let ((pos 0)
6979 (end (length string)))
6980 (while (< pos end)
6981 (tramp-message
6982 vec 10 "Sending chunk from %s to %s"
6983 pos (min (+ pos chunksize) end))
6984 (process-send-string
6985 p (substring string pos (min (+ pos chunksize) end)))
6986 (setq pos (+ pos chunksize))))
6987 (process-send-string p string)))))
fb7933a3
KG
6988
6989(defun tramp-mode-string-to-int (mode-string)
6990 "Converts a ten-letter `drwxrwxrwx'-style mode string into mode bits."
f3c071dd
MA
6991 (let* (case-fold-search
6992 (mode-chars (string-to-vector mode-string))
fb7933a3
KG
6993 (owner-read (aref mode-chars 1))
6994 (owner-write (aref mode-chars 2))
6995 (owner-execute-or-setid (aref mode-chars 3))
6996 (group-read (aref mode-chars 4))
6997 (group-write (aref mode-chars 5))
6998 (group-execute-or-setid (aref mode-chars 6))
6999 (other-read (aref mode-chars 7))
7000 (other-write (aref mode-chars 8))
7001 (other-execute-or-sticky (aref mode-chars 9)))
7002 (save-match-data
7003 (logior
f3c071dd
MA
7004 (cond
7005 ((char-equal owner-read ?r) (tramp-octal-to-decimal "00400"))
7006 ((char-equal owner-read ?-) 0)
7007 (t (error "Second char `%c' must be one of `r-'" owner-read)))
7008 (cond
7009 ((char-equal owner-write ?w) (tramp-octal-to-decimal "00200"))
7010 ((char-equal owner-write ?-) 0)
7011 (t (error "Third char `%c' must be one of `w-'" owner-write)))
7012 (cond
7013 ((char-equal owner-execute-or-setid ?x)
7014 (tramp-octal-to-decimal "00100"))
7015 ((char-equal owner-execute-or-setid ?S)
7016 (tramp-octal-to-decimal "04000"))
7017 ((char-equal owner-execute-or-setid ?s)
7018 (tramp-octal-to-decimal "04100"))
7019 ((char-equal owner-execute-or-setid ?-) 0)
7020 (t (error "Fourth char `%c' must be one of `xsS-'"
7021 owner-execute-or-setid)))
7022 (cond
7023 ((char-equal group-read ?r) (tramp-octal-to-decimal "00040"))
7024 ((char-equal group-read ?-) 0)
7025 (t (error "Fifth char `%c' must be one of `r-'" group-read)))
7026 (cond
7027 ((char-equal group-write ?w) (tramp-octal-to-decimal "00020"))
7028 ((char-equal group-write ?-) 0)
7029 (t (error "Sixth char `%c' must be one of `w-'" group-write)))
7030 (cond
7031 ((char-equal group-execute-or-setid ?x)
7032 (tramp-octal-to-decimal "00010"))
7033 ((char-equal group-execute-or-setid ?S)
7034 (tramp-octal-to-decimal "02000"))
7035 ((char-equal group-execute-or-setid ?s)
7036 (tramp-octal-to-decimal "02010"))
7037 ((char-equal group-execute-or-setid ?-) 0)
7038 (t (error "Seventh char `%c' must be one of `xsS-'"
7039 group-execute-or-setid)))
7040 (cond
7041 ((char-equal other-read ?r)
7042 (tramp-octal-to-decimal "00004"))
7043 ((char-equal other-read ?-) 0)
7044 (t (error "Eighth char `%c' must be one of `r-'" other-read)))
7045 (cond
7046 ((char-equal other-write ?w) (tramp-octal-to-decimal "00002"))
7047 ((char-equal other-write ?-) 0)
fb7933a3 7048 (t (error "Nineth char `%c' must be one of `w-'" other-write)))
f3c071dd
MA
7049 (cond
7050 ((char-equal other-execute-or-sticky ?x)
7051 (tramp-octal-to-decimal "00001"))
7052 ((char-equal other-execute-or-sticky ?T)
7053 (tramp-octal-to-decimal "01000"))
7054 ((char-equal other-execute-or-sticky ?t)
7055 (tramp-octal-to-decimal "01001"))
7056 ((char-equal other-execute-or-sticky ?-) 0)
7057 (t (error "Tenth char `%c' must be one of `xtT-'"
7058 other-execute-or-sticky)))))))
fb7933a3 7059
00d6fd04
MA
7060(defun tramp-convert-file-attributes (vec attr)
7061 "Convert file-attributes ATTR generated by perl script, stat or ls.
c82c5727
LH
7062Convert file mode bits to string and set virtual device number.
7063Return ATTR."
00d6fd04
MA
7064 ;; Convert last access time.
7065 (unless (listp (nth 4 attr))
7066 (setcar (nthcdr 4 attr)
7067 (list (floor (nth 4 attr) 65536)
7068 (floor (mod (nth 4 attr) 65536)))))
7069 ;; Convert last modification time.
7070 (unless (listp (nth 5 attr))
7071 (setcar (nthcdr 5 attr)
7072 (list (floor (nth 5 attr) 65536)
7073 (floor (mod (nth 5 attr) 65536)))))
7074 ;; Convert last status change time.
7075 (unless (listp (nth 6 attr))
7076 (setcar (nthcdr 6 attr)
7077 (list (floor (nth 6 attr) 65536)
7078 (floor (mod (nth 6 attr) 65536)))))
d4443a0d
MA
7079 ;; Convert file size.
7080 (when (< (nth 7 attr) 0)
7081 (setcar (nthcdr 7 attr) -1))
9e6ab520
MA
7082 (when (and (floatp (nth 7 attr))
7083 (<= (nth 7 attr) (tramp-compat-most-positive-fixnum)))
d4443a0d 7084 (setcar (nthcdr 7 attr) (round (nth 7 attr))))
ca637b2a 7085 ;; Convert file mode bits to string.
c82c5727 7086 (unless (stringp (nth 8 attr))
dea31ca6
MA
7087 (setcar (nthcdr 8 attr) (tramp-file-mode-from-int (nth 8 attr)))
7088 (when (stringp (car attr))
7089 (aset (nth 8 attr) 0 ?l)))
00d6fd04 7090 ;; Convert directory indication bit.
5da24108
MA
7091 (when (string-match "^d" (nth 8 attr))
7092 (setcar attr t))
7093 ;; Convert symlink from `tramp-handle-file-attributes-with-stat'.
7094 (when (consp (car attr))
7095 (if (and (stringp (caar attr))
00d6fd04
MA
7096 (string-match ".+ -> .\\(.+\\)." (caar attr)))
7097 (setcar attr (match-string 1 (caar attr)))
7098 (setcar attr nil)))
7099 ;; Set file's gid change bit.
7100 (setcar (nthcdr 9 attr)
7101 (if (numberp (nth 3 attr))
7102 (not (= (nth 3 attr)
7103 (tramp-get-remote-gid vec 'integer)))
7104 (not (string-equal
7105 (nth 3 attr)
7106 (tramp-get-remote-gid vec 'string)))))
7107 ;; Convert inode.
7108 (unless (listp (nth 10 attr))
7109 (setcar (nthcdr 10 attr)
ce3f516f 7110 (condition-case nil
b946a456 7111 (cons (floor (nth 10 attr) 65536)
ce3f516f
MA
7112 (floor (mod (nth 10 attr) 65536)))
7113 ;; Inodes can be incredible huge. We must hide this.
7114 (error (tramp-get-inode vec)))))
c82c5727
LH
7115 ;; Set virtual device number.
7116 (setcar (nthcdr 11 attr)
00d6fd04 7117 (tramp-get-device vec))
c82c5727
LH
7118 attr)
7119
ce3f516f 7120(defun tramp-get-inode (vec)
00d6fd04
MA
7121 "Returns the virtual inode number.
7122If it doesn't exist, generate a new one."
ce3f516f
MA
7123 (let ((string (tramp-make-tramp-file-name
7124 (tramp-file-name-method vec)
7125 (tramp-file-name-user vec)
7126 (tramp-file-name-host vec)
7127 "")))
00d6fd04
MA
7128 (unless (assoc string tramp-inodes)
7129 (add-to-list 'tramp-inodes
7130 (list string (length tramp-inodes))))
7131 (nth 1 (assoc string tramp-inodes))))
7132
7133(defun tramp-get-device (vec)
c82c5727
LH
7134 "Returns the virtual device number.
7135If it doesn't exist, generate a new one."
00d6fd04
MA
7136 (let ((string (tramp-make-tramp-file-name
7137 (tramp-file-name-method vec)
7138 (tramp-file-name-user vec)
7139 (tramp-file-name-host vec)
7140 "")))
c82c5727
LH
7141 (unless (assoc string tramp-devices)
7142 (add-to-list 'tramp-devices
7143 (list string (length tramp-devices))))
b946a456 7144 (cons -1 (nth 1 (assoc string tramp-devices)))))
fb7933a3
KG
7145
7146(defun tramp-file-mode-from-int (mode)
7147 "Turn an integer representing a file mode into an ls(1)-like string."
7148 (let ((type (cdr (assoc (logand (lsh mode -12) 15) tramp-file-mode-type-map)))
7149 (user (logand (lsh mode -6) 7))
7150 (group (logand (lsh mode -3) 7))
7151 (other (logand (lsh mode -0) 7))
7152 (suid (> (logand (lsh mode -9) 4) 0))
7153 (sgid (> (logand (lsh mode -9) 2) 0))
7154 (sticky (> (logand (lsh mode -9) 1) 0)))
7155 (setq user (tramp-file-mode-permissions user suid "s"))
7156 (setq group (tramp-file-mode-permissions group sgid "s"))
7157 (setq other (tramp-file-mode-permissions other sticky "t"))
7158 (concat type user group other)))
7159
fb7933a3
KG
7160(defun tramp-file-mode-permissions (perm suid suid-text)
7161 "Convert a permission bitset into a string.
7162This is used internally by `tramp-file-mode-from-int'."
7163 (let ((r (> (logand perm 4) 0))
7164 (w (> (logand perm 2) 0))
7165 (x (> (logand perm 1) 0)))
7166 (concat (or (and r "r") "-")
7167 (or (and w "w") "-")
7168 (or (and suid x suid-text) ; suid, execute
7169 (and suid (upcase suid-text)) ; suid, !execute
7170 (and x "x") "-")))) ; !suid
7171
fb7933a3
KG
7172(defun tramp-decimal-to-octal (i)
7173 "Return a string consisting of the octal digits of I.
7174Not actually used. Use `(format \"%o\" i)' instead?"
7175 (cond ((< i 0) (error "Cannot convert negative number to octal"))
7176 ((not (integerp i)) (error "Cannot convert non-integer to octal"))
7177 ((zerop i) "0")
7178 (t (concat (tramp-decimal-to-octal (/ i 8))
7179 (number-to-string (% i 8))))))
7180
fb7933a3
KG
7181;; Kudos to Gerd Moellmann for this suggestion.
7182(defun tramp-octal-to-decimal (ostr)
7183 "Given a string of octal digits, return a decimal number."
7184 (let ((x (or ostr "")))
7185 ;; `save-match' is in `tramp-mode-string-to-int' which calls this.
7186 (unless (string-match "\\`[0-7]*\\'" x)
7187 (error "Non-octal junk in string `%s'" x))
7188 (string-to-number ostr 8)))
7189
7190(defun tramp-shell-case-fold (string)
7191 "Converts STRING to shell glob pattern which ignores case."
7192 (mapconcat
7193 (lambda (c)
7194 (if (equal (downcase c) (upcase c))
7195 (vector c)
7196 (format "[%c%c]" (downcase c) (upcase c))))
7197 string
7198 ""))
7199
7200
bf247b6e 7201;; ------------------------------------------------------------
a4aeb9a4 7202;; -- Tramp file names --
bf247b6e 7203;; ------------------------------------------------------------
fb7933a3
KG
7204;; Conversion functions between external representation and
7205;; internal data structure. Convenience functions for internal
7206;; data structure.
7207
00d6fd04
MA
7208(defun tramp-file-name-p (vec)
7209 "Check whether VEC is a Tramp object."
7210 (and (vectorp vec) (= 4 (length vec))))
7211
7212(defun tramp-file-name-method (vec)
7213 "Return method component of VEC."
7214 (and (tramp-file-name-p vec) (aref vec 0)))
7215
7216(defun tramp-file-name-user (vec)
7217 "Return user component of VEC."
7218 (and (tramp-file-name-p vec) (aref vec 1)))
7219
7220(defun tramp-file-name-host (vec)
7221 "Return host component of VEC."
7222 (and (tramp-file-name-p vec) (aref vec 2)))
7223
7224(defun tramp-file-name-localname (vec)
7225 "Return localname component of VEC."
7226 (and (tramp-file-name-p vec) (aref vec 3)))
7227
dea31ca6 7228;; The user part of a Tramp file name vector can be of kind
b96e6899 7229;; "user%domain". Sometimes, we must extract these parts.
dea31ca6
MA
7230(defun tramp-file-name-real-user (vec)
7231 "Return the user name of VEC without domain."
7232 (let ((user (tramp-file-name-user vec)))
7233 (if (and (stringp user)
b96e6899 7234 (string-match tramp-user-with-domain-regexp user))
dea31ca6
MA
7235 (match-string 1 user)
7236 user)))
7237
7238(defun tramp-file-name-domain (vec)
7239 "Return the domain name of VEC."
7240 (let ((user (tramp-file-name-user vec)))
7241 (and (stringp user)
b96e6899 7242 (string-match tramp-user-with-domain-regexp user)
dea31ca6
MA
7243 (match-string 2 user))))
7244
00d6fd04
MA
7245;; The host part of a Tramp file name vector can be of kind
7246;; "host#port". Sometimes, we must extract these parts.
8a4438b6 7247(defun tramp-file-name-real-host (vec)
00d6fd04
MA
7248 "Return the host name of VEC without port."
7249 (let ((host (tramp-file-name-host vec)))
7250 (if (and (stringp host)
7251 (string-match tramp-host-with-port-regexp host))
7252 (match-string 1 host)
7253 host)))
7254
8a4438b6 7255(defun tramp-file-name-port (vec)
00d6fd04
MA
7256 "Return the port number of VEC."
7257 (let ((host (tramp-file-name-host vec)))
7258 (and (stringp host)
7259 (string-match tramp-host-with-port-regexp host)
7260 (string-to-number (match-string 2 host)))))
fb7933a3
KG
7261
7262(defun tramp-tramp-file-p (name)
a4aeb9a4 7263 "Return t if NAME is a Tramp file."
fb7933a3
KG
7264 (save-match-data
7265 (string-match tramp-file-name-regexp name)))
bf247b6e 7266
8a4438b6 7267(defun tramp-find-method (method user host)
00d6fd04
MA
7268 "Return the right method string to use.
7269This is METHOD, if non-nil. Otherwise, do a lookup in
7270`tramp-default-method-alist'."
7271 (or method
7272 (let ((choices tramp-default-method-alist)
7273 lmethod item)
7274 (while choices
7275 (setq item (pop choices))
7276 (when (and (string-match (or (nth 0 item) "") (or host ""))
7277 (string-match (or (nth 1 item) "") (or user "")))
7278 (setq lmethod (nth 2 item))
7279 (setq choices nil)))
7280 lmethod)
7281 tramp-default-method))
7282
8a4438b6 7283(defun tramp-find-user (method user host)
00d6fd04
MA
7284 "Return the right user string to use.
7285This is USER, if non-nil. Otherwise, do a lookup in
7286`tramp-default-user-alist'."
7287 (or user
7288 (let ((choices tramp-default-user-alist)
7289 luser item)
7290 (while choices
7291 (setq item (pop choices))
7292 (when (and (string-match (or (nth 0 item) "") (or method ""))
7293 (string-match (or (nth 1 item) "") (or host "")))
7294 (setq luser (nth 2 item))
7295 (setq choices nil)))
7296 luser)
7297 tramp-default-user))
7298
8a4438b6 7299(defun tramp-find-host (method user host)
00d6fd04
MA
7300 "Return the right host string to use.
7301This is HOST, if non-nil. Otherwise, it is `tramp-default-host'."
7302 (or (and (> (length host) 0) host)
7303 tramp-default-host))
7304
9ce8462a 7305(defun tramp-dissect-file-name (name &optional nodefault)
00d6fd04 7306 "Return a `tramp-file-name' structure.
9ce8462a
MA
7307The structure consists of remote method, remote user, remote host
7308and localname (file name on remote host). If NODEFAULT is
7309non-nil, the file name parts are not expanded to their default
7310values."
4007ba5b 7311 (save-match-data
00d6fd04 7312 (let ((match (string-match (nth 0 tramp-file-name-structure) name)))
a4aeb9a4 7313 (unless match (error "Not a Tramp file name: %s" name))
00d6fd04
MA
7314 (let ((method (match-string (nth 1 tramp-file-name-structure) name))
7315 (user (match-string (nth 2 tramp-file-name-structure) name))
7316 (host (match-string (nth 3 tramp-file-name-structure) name))
7317 (localname (match-string (nth 4 tramp-file-name-structure) name)))
5d449a36
MA
7318 (when (member method '("multi" "multiu"))
7319 (error
7320 "`%s' method is no longer supported, see (info \"(tramp)Multi-hops\")"
7321 method))
b96e6899
MA
7322 (when host
7323 (when (string-match tramp-prefix-ipv6-regexp host)
7324 (setq host (replace-match "" nil t host)))
7325 (when (string-match tramp-postfix-ipv6-regexp host)
7326 (setq host (replace-match "" nil t host))))
9ce8462a
MA
7327 (if nodefault
7328 (vector method user host localname)
7329 (vector
7330 (tramp-find-method method user host)
7331 (tramp-find-user method user host)
7332 (tramp-find-host method user host)
7333 localname))))))
00d6fd04
MA
7334
7335(defun tramp-equal-remote (file1 file2)
7336 "Checks, whether the remote parts of FILE1 and FILE2 are identical.
7337The check depends on method, user and host name of the files. If
7338one of the components is missing, the default values are used.
7339The local file name parts of FILE1 and FILE2 are not taken into
7340account.
fb7933a3 7341
00d6fd04
MA
7342Example:
7343
7344 (tramp-equal-remote \"/ssh::/etc\" \"/<your host name>:/home\")
7345
7346would yield `t'. On the other hand, the following check results in nil:
7347
7348 (tramp-equal-remote \"/sudo::/etc\" \"/su::/etc\")"
9e6ab520
MA
7349 (and (stringp (file-remote-p file1))
7350 (stringp (file-remote-p file2))
94be87e8 7351 (string-equal (file-remote-p file1) (file-remote-p file2))))
00d6fd04
MA
7352
7353(defun tramp-make-tramp-file-name (method user host localname)
7354 "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME."
7355 (concat tramp-prefix-format
7356 (when (not (zerop (length method)))
7357 (concat method tramp-postfix-method-format))
7358 (when (not (zerop (length user)))
7359 (concat user tramp-postfix-user-format))
b96e6899
MA
7360 (when host
7361 (if (string-match tramp-ipv6-regexp host)
7362 (concat tramp-prefix-ipv6-format host tramp-postfix-ipv6-format)
7363 host))
7364 tramp-postfix-host-format
00d6fd04
MA
7365 (when localname localname)))
7366
7367(defun tramp-completion-make-tramp-file-name (method user host localname)
7368 "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME.
7369It must not be a complete Tramp file name, but as long as there are
7370necessary only. This function will be used in file name completion."
7371 (concat tramp-prefix-format
7372 (when (not (zerop (length method)))
7373 (concat method tramp-postfix-method-format))
7374 (when (not (zerop (length user)))
7375 (concat user tramp-postfix-user-format))
7376 (when (not (zerop (length host)))
b96e6899
MA
7377 (concat
7378 (if (string-match tramp-ipv6-regexp host)
7379 (concat tramp-prefix-ipv6-format host tramp-postfix-ipv6-format)
7380 host)
7381 tramp-postfix-host-format))
00d6fd04
MA
7382 (when localname localname)))
7383
7384(defun tramp-make-copy-program-file-name (vec)
7385 "Create a file name suitable to be passed to `rcp' and workalikes."
7386 (let ((user (tramp-file-name-user vec))
0f205eee 7387 (host (tramp-file-name-real-host vec))
00d6fd04
MA
7388 (localname (tramp-shell-quote-argument
7389 (tramp-file-name-localname vec))))
7390 (if (not (zerop (length user)))
7391 (format "%s@%s:%s" user host localname)
7392 (format "%s:%s" host localname))))
7393
7394(defun tramp-method-out-of-band-p (vec)
38c65fca 7395 "Return t if this is an out-of-band method, nil otherwise."
00d6fd04 7396 (tramp-get-method-parameter (tramp-file-name-method vec) 'tramp-copy-program))
fb7933a3 7397
0f205eee
MA
7398(defun tramp-local-host-p (vec)
7399 "Return t if this points to the local host, nil otherwise."
c992abdb
MA
7400 ;; We cannot use `tramp-file-name-real-host'. A port is an
7401 ;; indication for an ssh tunnel or alike.
7402 (let ((host (tramp-file-name-host vec)))
0f205eee
MA
7403 (and
7404 (stringp host)
b96e6899 7405 (string-match tramp-local-host-regexp host)
a0a5183a
MA
7406 ;; The local temp directory must be writable for the other user.
7407 (file-writable-p
7408 (tramp-make-tramp-file-name
7409 (tramp-file-name-method vec)
7410 (tramp-file-name-user vec)
7411 host
93c3eb7c
MA
7412 (tramp-compat-temporary-file-directory)))
7413 ;; On some systems, chown runs only for root.
7414 (or (zerop (user-uid))
7415 (zerop (tramp-get-remote-uid vec 'integer))))))
0f205eee 7416
fb7933a3
KG
7417;; Variables local to connection.
7418
f84638eb 7419(defun tramp-get-remote-path (vec)
70c11b0b
MA
7420 (with-connection-property
7421 ;; When `tramp-own-remote-path' is in `tramp-remote-path', we
7422 ;; cache the result for the session only. Otherwise, the result
7423 ;; is cached persistently.
7424 (if (memq 'tramp-own-remote-path tramp-remote-path)
7425 (tramp-get-connection-process vec)
7426 vec)
7427 "remote-path"
9e6ab520 7428 (let* ((remote-path (tramp-compat-copy-tree tramp-remote-path))
70c11b0b
MA
7429 (elt1 (memq 'tramp-default-remote-path remote-path))
7430 (elt2 (memq 'tramp-own-remote-path remote-path))
f84638eb 7431 (default-remote-path
70c11b0b 7432 (when elt1
f84638eb 7433 (condition-case nil
70c11b0b
MA
7434 (tramp-send-command-and-read
7435 vec "echo \\\"`getconf PATH`\\\"")
f84638eb
MA
7436 ;; Default if "getconf" is not available.
7437 (error
7438 (tramp-message
7439 vec 3
7440 "`getconf PATH' not successful, using default value \"%s\"."
7441 "/bin:/usr/bin")
70c11b0b
MA
7442 "/bin:/usr/bin"))))
7443 (own-remote-path
7444 (when elt2
7445 (condition-case nil
7446 (tramp-send-command-and-read vec "echo \\\"$PATH\\\"")
7447 ;; Default if "getconf" is not available.
7448 (error
7449 (tramp-message
7450 vec 3 "$PATH not set, ignoring `tramp-own-remote-path'.")
7451 nil)))))
7452
7453 ;; Replace place holder `tramp-default-remote-path'.
7454 (when elt1
7455 (setcdr elt1
f84638eb 7456 (append
70c11b0b
MA
7457 (tramp-compat-split-string default-remote-path ":")
7458 (cdr elt1)))
f84638eb
MA
7459 (setq remote-path (delq 'tramp-default-remote-path remote-path)))
7460
70c11b0b
MA
7461 ;; Replace place holder `tramp-own-remote-path'.
7462 (when elt2
7463 (setcdr elt2
7464 (append
7465 (tramp-compat-split-string own-remote-path ":")
7466 (cdr elt2)))
7467 (setq remote-path (delq 'tramp-own-remote-path remote-path)))
7468
7469 ;; Remove double entries.
7470 (setq elt1 remote-path)
7471 (while (consp elt1)
7472 (while (and (car elt1) (setq elt2 (member (car elt1) (cdr elt1))))
7473 (setcar elt2 nil))
7474 (setq elt1 (cdr elt1)))
7475
f84638eb
MA
7476 ;; Remove non-existing directories.
7477 (delq
7478 nil
7479 (mapcar
7480 (lambda (x)
7481 (and
70c11b0b
MA
7482 (stringp x)
7483 (file-directory-p
7484 (tramp-make-tramp-file-name
7485 (tramp-file-name-method vec)
7486 (tramp-file-name-user vec)
7487 (tramp-file-name-host vec)
7488 x))
f84638eb
MA
7489 x))
7490 remote-path)))))
7491
a4aeb9a4
MA
7492(defun tramp-get-remote-tmpdir (vec)
7493 (with-connection-property vec "tmp-directory"
7494 (let ((dir (tramp-shell-quote-argument "/tmp")))
7495 (if (and (zerop
7496 (tramp-send-command-and-check
7497 vec (format "%s -d %s" (tramp-get-test-command vec) dir)))
7498 (zerop
7499 (tramp-send-command-and-check
7500 vec (format "%s -w %s" (tramp-get-test-command vec) dir))))
7501 dir
7502 (tramp-error vec 'file-error "Directory %s not accessible" dir)))))
7503
00d6fd04
MA
7504(defun tramp-get-ls-command (vec)
7505 (with-connection-property vec "ls"
946a5aeb
MA
7506 (tramp-message vec 5 "Finding a suitable `ls' command")
7507 (or
7508 (catch 'ls-found
7509 (dolist (cmd '("ls" "gnuls" "gls"))
7510 (let ((dl (tramp-get-remote-path vec))
7511 result)
7512 (while (and dl (setq result (tramp-find-executable vec cmd dl t t)))
7513 ;; Check parameter.
7514 (when (zerop (tramp-send-command-and-check
7515 vec (format "%s -lnd /" result)))
7516 (throw 'ls-found result))
7517 (setq dl (cdr dl))))))
7518 (tramp-error vec 'file-error "Couldn't find a proper `ls' command"))))
00d6fd04 7519
8e754ea2
MA
7520(defun tramp-get-ls-command-with-dired (vec)
7521 (save-match-data
7522 (with-connection-property vec "ls-dired"
7523 (tramp-message vec 5 "Checking, whether `ls --dired' works")
7524 (zerop (tramp-send-command-and-check
7525 vec (format "%s --diredd /" (tramp-get-ls-command vec)))))))
7526
00d6fd04
MA
7527(defun tramp-get-test-command (vec)
7528 (with-connection-property vec "test"
946a5aeb
MA
7529 (tramp-message vec 5 "Finding a suitable `test' command")
7530 (if (zerop (tramp-send-command-and-check vec "test 0"))
7531 "test"
7532 (tramp-find-executable vec "test" (tramp-get-remote-path vec)))))
00d6fd04
MA
7533
7534(defun tramp-get-test-nt-command (vec)
7535 ;; Does `test A -nt B' work? Use abominable `find' construct if it
7536 ;; doesn't. BSD/OS 4.0 wants the parentheses around the command,
7537 ;; for otherwise the shell crashes.
7538 (with-connection-property vec "test-nt"
7539 (or
7540 (progn
7541 (tramp-send-command
7542 vec (format "( %s / -nt / )" (tramp-get-test-command vec)))
7543 (with-current-buffer (tramp-get-buffer vec)
7544 (goto-char (point-min))
a0a5183a 7545 (when (looking-at (regexp-quote tramp-end-of-output))
00d6fd04
MA
7546 (format "%s %%s -nt %%s" (tramp-get-test-command vec)))))
7547 (progn
7548 (tramp-send-command
7549 vec
7550 (format
7551 "tramp_test_nt () {\n%s -n \"`find $1 -prune -newer $2 -print`\"\n}"
7552 (tramp-get-test-command vec)))
7553 "tramp_test_nt %s %s"))))
7554
7555(defun tramp-get-file-exists-command (vec)
7556 (with-connection-property vec "file-exists"
946a5aeb
MA
7557 (tramp-message vec 5 "Finding command to check if file exists")
7558 (tramp-find-file-exists-command vec)))
00d6fd04
MA
7559
7560(defun tramp-get-remote-ln (vec)
7561 (with-connection-property vec "ln"
946a5aeb
MA
7562 (tramp-message vec 5 "Finding a suitable `ln' command")
7563 (tramp-find-executable vec "ln" (tramp-get-remote-path vec))))
00d6fd04
MA
7564
7565(defun tramp-get-remote-perl (vec)
7566 (with-connection-property vec "perl"
946a5aeb
MA
7567 (tramp-message vec 5 "Finding a suitable `perl' command")
7568 (or (tramp-find-executable vec "perl5" (tramp-get-remote-path vec))
7569 (tramp-find-executable vec "perl" (tramp-get-remote-path vec)))))
00d6fd04
MA
7570
7571(defun tramp-get-remote-stat (vec)
7572 (with-connection-property vec "stat"
946a5aeb
MA
7573 (tramp-message vec 5 "Finding a suitable `stat' command")
7574 (let ((result (tramp-find-executable
7575 vec "stat" (tramp-get-remote-path vec)))
7576 tmp)
7577 ;; Check whether stat(1) returns usable syntax. %s does not
7578 ;; work on older AIX systems.
7579 (when result
7580 (setq tmp
7581 ;; We don't want to display an error message.
7582 (with-temp-message (or (current-message) "")
7583 (condition-case nil
7584 (tramp-send-command-and-read
7585 vec (format "%s -c '(\"%%N\" %%s)' /" result))
7586 (error nil))))
7587 (unless (and (listp tmp) (stringp (car tmp))
7588 (string-match "^./.$" (car tmp))
7589 (integerp (cadr tmp)))
7590 (setq result nil)))
7591 result)))
fb7933a3 7592
00d6fd04
MA
7593(defun tramp-get-remote-id (vec)
7594 (with-connection-property vec "id"
946a5aeb
MA
7595 (tramp-message vec 5 "Finding POSIX `id' command")
7596 (or
7597 (catch 'id-found
7598 (let ((dl (tramp-get-remote-path vec))
7599 result)
7600 (while (and dl (setq result (tramp-find-executable vec "id" dl t t)))
7601 ;; Check POSIX parameter.
7602 (when (zerop (tramp-send-command-and-check
7603 vec (format "%s -u" result)))
7604 (throw 'id-found result))
7605 (setq dl (cdr dl)))))
7606 (tramp-error vec 'file-error "Couldn't find a POSIX `id' command"))))
00d6fd04
MA
7607
7608(defun tramp-get-remote-uid (vec id-format)
7609 (with-connection-property vec (format "uid-%s" id-format)
7610 (let ((res (tramp-send-command-and-read
7611 vec
7612 (format "%s -u%s %s"
7613 (tramp-get-remote-id vec)
7614 (if (equal id-format 'integer) "" "n")
7615 (if (equal id-format 'integer)
7616 "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
7617 ;; The command might not always return a number.
7618 (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
7619
7620(defun tramp-get-remote-gid (vec id-format)
7621 (with-connection-property vec (format "gid-%s" id-format)
7622 (let ((res (tramp-send-command-and-read
7623 vec
7624 (format "%s -g%s %s"
7625 (tramp-get-remote-id vec)
7626 (if (equal id-format 'integer) "" "n")
7627 (if (equal id-format 'integer)
7628 "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
7629 ;; The command might not always return a number.
7630 (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
fb7933a3 7631
8d60099b
MA
7632(defun tramp-get-local-uid (id-format)
7633 (if (equal id-format 'integer) (user-uid) (user-login-name)))
7634
7635(defun tramp-get-local-gid (id-format)
9e6ab520 7636 (nth 3 (tramp-compat-file-attributes "~/" id-format)))
8d60099b 7637
00d6fd04
MA
7638;; Some predefined connection properties.
7639(defun tramp-get-remote-coding (vec prop)
7640 ;; Local coding handles properties like remote coding. So we could
7641 ;; call it without pain.
7642 (let ((ret (tramp-get-local-coding vec prop)))
7643 ;; The connection property might have been cached. So we must send
7644 ;; the script - maybe.
1d7e9a01 7645 (when (and ret (symbolp ret))
00d6fd04
MA
7646 (let ((name (symbol-name ret)))
7647 (while (string-match (regexp-quote "-") name)
7648 (setq name (replace-match "_" nil t name)))
7649 (tramp-maybe-send-script vec (symbol-value ret) name)
7650 (setq ret name)))
7651 ;; Return the value.
7652 ret))
7653
7654(defun tramp-get-local-coding (vec prop)
bf0503cb 7655 (or
00d6fd04
MA
7656 (tramp-get-connection-property vec prop nil)
7657 (progn
7658 (tramp-find-inline-encoding vec)
7659 (tramp-get-connection-property vec prop nil))))
fb7933a3 7660
00d6fd04 7661(defun tramp-get-method-parameter (method param)
c951aecb 7662 "Return the method parameter PARAM.
00d6fd04
MA
7663If the `tramp-methods' entry does not exist, return NIL."
7664 (let ((entry (assoc param (assoc method tramp-methods))))
7665 (when entry (cadr entry))))
90f8dc03 7666
fb7933a3
KG
7667;; Auto saving to a special directory.
7668
00cec167 7669(defun tramp-exists-file-name-handler (operation &rest args)
00d6fd04
MA
7670 "Checks whether OPERATION runs a file name handler."
7671 ;; The file name handler is determined on base of either an
7672 ;; argument, `buffer-file-name', or `default-directory'.
7673 (condition-case nil
7674 (let* ((buffer-file-name "/")
7675 (default-directory "/")
7676 (fnha file-name-handler-alist)
7677 (check-file-name-operation operation)
7678 (file-name-handler-alist
7679 (list
7680 (cons "/"
aa485f7c
MA
7681 (lambda (operation &rest args)
7682 "Returns OPERATION if it is the one to be checked."
7683 (if (equal check-file-name-operation operation)
7684 operation
7685 (let ((file-name-handler-alist fnha))
7686 (apply operation args))))))))
00d6fd04
MA
7687 (equal (apply operation args) operation))
7688 (error nil)))
c1105d05
MA
7689
7690(unless (tramp-exists-file-name-handler 'make-auto-save-file-name)
7691 (defadvice make-auto-save-file-name
7692 (around tramp-advice-make-auto-save-file-name () activate)
00d6fd04 7693 "Invoke `tramp-handle-make-auto-save-file-name' for Tramp files."
c1105d05 7694 (if (and (buffer-file-name) (tramp-tramp-file-p (buffer-file-name)))
00cec167 7695 (setq ad-return-value (tramp-handle-make-auto-save-file-name))
a69c01a0
MA
7696 ad-do-it))
7697 (add-hook 'tramp-unload-hook
aa485f7c 7698 (lambda () (ad-unadvise 'make-auto-save-file-name))))
fb7933a3 7699
340b8d4f
MA
7700;; In Emacs < 22 and XEmacs < 21.5 autosaved remote files have
7701;; permission 0666 minus umask. This is a security threat.
414da5ab
MA
7702
7703(defun tramp-set-auto-save-file-modes ()
7704 "Set permissions of autosaved remote files to the original permissions."
7705 (let ((bfn (buffer-file-name)))
7706 (when (and (stringp bfn)
7707 (tramp-tramp-file-p bfn)
b50dd0d2 7708 (buffer-modified-p)
414da5ab 7709 (stringp buffer-auto-save-file-name)
340b8d4f
MA
7710 (not (equal bfn buffer-auto-save-file-name)))
7711 (unless (file-exists-p buffer-auto-save-file-name)
7712 (write-region "" nil buffer-auto-save-file-name))
7713 ;; Permissions should be set always, because there might be an old
7714 ;; auto-saved file belonging to another original file. This could
7715 ;; be a security threat.
7177e2a3 7716 (set-file-modes buffer-auto-save-file-name
11948172 7717 (or (file-modes bfn) (tramp-octal-to-decimal "0600"))))))
414da5ab
MA
7718
7719(unless (or (> emacs-major-version 21)
7720 (and (featurep 'xemacs)
7721 (= emacs-major-version 21)
340b8d4f 7722 (> emacs-minor-version 4)))
a69c01a0
MA
7723 (add-hook 'auto-save-hook 'tramp-set-auto-save-file-modes)
7724 (add-hook 'tramp-unload-hook
aa485f7c
MA
7725 (lambda ()
7726 (remove-hook 'auto-save-hook 'tramp-set-auto-save-file-modes))))
414da5ab 7727
fb7933a3
KG
7728(defun tramp-subst-strs-in-string (alist string)
7729 "Replace all occurrences of the string FROM with TO in STRING.
7730ALIST is of the form ((FROM . TO) ...)."
7731 (save-match-data
7732 (while alist
7733 (let* ((pr (car alist))
7734 (from (car pr))
7735 (to (cdr pr)))
7736 (while (string-match (regexp-quote from) string)
7737 (setq string (replace-match to t t string)))
7738 (setq alist (cdr alist))))
7739 string))
7740
fb7933a3
KG
7741;; ------------------------------------------------------------
7742;; -- Compatibility functions section --
7743;; ------------------------------------------------------------
7744
00d6fd04 7745(defun tramp-read-passwd (proc &optional prompt)
fb7933a3 7746 "Read a password from user (compat function).
5615d63f 7747Consults the auth-source package.
5ec2cc41 7748Invokes `password-read' if available, `read-passwd' else."
00d6fd04
MA
7749 (let* ((key (tramp-make-tramp-file-name
7750 tramp-current-method tramp-current-user
7751 tramp-current-host ""))
7752 (pw-prompt
7753 (or prompt
7754 (with-current-buffer (process-buffer proc)
7755 (tramp-check-for-regexp proc tramp-password-prompt-regexp)
7756 (format "%s for %s " (capitalize (match-string 1)) key)))))
5c7043a2
MA
7757 (prog1
7758 (or
7759 ;; See if auth-sources contains something useful, if it's bound.
7760 (and (boundp 'auth-sources)
7761 (tramp-get-connection-property proc "first-password-request" nil)
7762 ;; Try with Tramp's current method.
7763 (funcall (symbol-function 'auth-source-user-or-password)
7764 "password" tramp-current-host tramp-current-method))
7765 ;; Try the password cache.
cb85dcd0
MA
7766 (when (functionp 'password-read)
7767 (unless (tramp-get-connection-property
7768 proc "first-password-request" nil)
7769 (funcall (symbol-function 'password-cache-remove) key))
7770 (let ((password
7771 (funcall (symbol-function 'password-read) pw-prompt key)))
7772 (funcall (symbol-function 'password-cache-add) key password)
7773 password))
5c7043a2
MA
7774 ;; Else, get the password interactively.
7775 (read-passwd pw-prompt))
7776 (tramp-set-connection-property proc "first-password-request" nil))))
00d6fd04 7777
9c13938d
MA
7778(defun tramp-clear-passwd (vec)
7779 "Clear password cache for connection related to VEC."
00d6fd04 7780 (when (functionp 'password-cache-remove)
9c13938d
MA
7781 (funcall
7782 (symbol-function 'password-cache-remove)
7783 (tramp-make-tramp-file-name
7784 (tramp-file-name-method vec)
7785 (tramp-file-name-user vec)
7786 (tramp-file-name-host vec)
7787 ""))))
00d6fd04
MA
7788
7789;; Snarfed code from time-date.el and parse-time.el
7790
7791(defconst tramp-half-a-year '(241 17024)
7792"Evaluated by \"(days-to-time 183)\".")
7793
7794(defconst tramp-parse-time-months
7795 '(("jan" . 1) ("feb" . 2) ("mar" . 3)
7796 ("apr" . 4) ("may" . 5) ("jun" . 6)
7797 ("jul" . 7) ("aug" . 8) ("sep" . 9)
7798 ("oct" . 10) ("nov" . 11) ("dec" . 12))
7799 "Alist mapping month names to integers.")
7800
7801(defun tramp-time-less-p (t1 t2)
7802 "Say whether time value T1 is less than time value T2."
7803 (unless t1 (setq t1 '(0 0)))
7804 (unless t2 (setq t2 '(0 0)))
7805 (or (< (car t1) (car t2))
7806 (and (= (car t1) (car t2))
7807 (< (nth 1 t1) (nth 1 t2)))))
7808
7809(defun tramp-time-subtract (t1 t2)
7810 "Subtract two time values.
7811Return the difference in the format of a time value."
7812 (unless t1 (setq t1 '(0 0)))
7813 (unless t2 (setq t2 '(0 0)))
7814 (let ((borrow (< (cadr t1) (cadr t2))))
7815 (list (- (car t1) (car t2) (if borrow 1 0))
7816 (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2)))))
fb7933a3
KG
7817
7818(defun tramp-time-diff (t1 t2)
7819 "Return the difference between the two times, in seconds.
1a762140 7820T1 and T2 are time values (as returned by `current-time' for example)."
fb7933a3 7821 ;; Pacify byte-compiler with `symbol-function'.
ea9d1443
KG
7822 (cond ((and (fboundp 'subtract-time)
7823 (fboundp 'float-time))
7824 (funcall (symbol-function 'float-time)
7825 (funcall (symbol-function 'subtract-time) t1 t2)))
7826 ((and (fboundp 'subtract-time)
7827 (fboundp 'time-to-seconds))
7828 (funcall (symbol-function 'time-to-seconds)
7829 (funcall (symbol-function 'subtract-time) t1 t2)))
fb7933a3 7830 ((fboundp 'itimer-time-difference)
1a762140
MA
7831 (funcall (symbol-function 'itimer-time-difference)
7832 (if (< (length t1) 3) (append t1 '(0)) t1)
7833 (if (< (length t2) 3) (append t2 '(0)) t2)))
fb7933a3 7834 (t
00d6fd04 7835 (let ((time (tramp-time-subtract t1 t2)))
ea9d1443
KG
7836 (+ (* (car time) 65536.0)
7837 (cadr time)
7838 (/ (or (nth 2 time) 0) 1000000.0))))))
fb7933a3
KG
7839
7840(defun tramp-coding-system-change-eol-conversion (coding-system eol-type)
7841 "Return a coding system like CODING-SYSTEM but with given EOL-TYPE.
7842EOL-TYPE can be one of `dos', `unix', or `mac'."
7843 (cond ((fboundp 'coding-system-change-eol-conversion)
9e6ab520
MA
7844 (funcall (symbol-function 'coding-system-change-eol-conversion)
7845 coding-system eol-type))
fb7933a3 7846 ((fboundp 'subsidiary-coding-system)
9e6ab520
MA
7847 (funcall (symbol-function 'subsidiary-coding-system)
7848 coding-system
7849 (cond ((eq eol-type 'dos) 'crlf)
7850 ((eq eol-type 'unix) 'lf)
7851 ((eq eol-type 'mac) 'cr)
7852 (t
7853 (error "Unknown EOL-TYPE `%s', must be %s"
7854 eol-type
7855 "`dos', `unix', or `mac'")))))
fb7933a3
KG
7856 (t (error "Can't change EOL conversion -- is MULE missing?"))))
7857
19a87064
MA
7858(defun tramp-set-process-query-on-exit-flag (process flag)
7859 "Specify if query is needed for process when Emacs is exited.
7860If the second argument flag is non-nil, Emacs will query the user before
7861exiting if process is running."
7862 (if (fboundp 'set-process-query-on-exit-flag)
00d6fd04
MA
7863 (funcall (symbol-function 'set-process-query-on-exit-flag) process flag)
7864 (funcall (symbol-function 'process-kill-without-query) process flag)))
19a87064 7865
19a87064 7866
bf247b6e
KS
7867;; ------------------------------------------------------------
7868;; -- Kludges section --
7869;; ------------------------------------------------------------
fb7933a3
KG
7870
7871;; Currently (as of Emacs 20.5), the function `shell-quote-argument'
7872;; does not deal well with newline characters. Newline is replaced by
7873;; backslash newline. But if, say, the string `a backslash newline b'
7874;; is passed to a shell, the shell will expand this into "ab",
7875;; completely omitting the newline. This is not what was intended.
7876;; It does not appear to be possible to make the function
7877;; `shell-quote-argument' work with newlines without making it
7878;; dependent on the shell used. But within this package, we know that
7879;; we will always use a Bourne-like shell, so we use an approach which
7880;; groks newlines.
7881;;
7882;; The approach is simple: we call `shell-quote-argument', then
7883;; massage the newline part of the result.
7884;;
7885;; This function should produce a string which is grokked by a Unix
7886;; shell, even if the Emacs is running on Windows. Since this is the
7887;; kludges section, we bind `system-type' in such a way that
7888;; `shell-quote-arguments' behaves as if on Unix.
7889;;
7890;; Thanks to Mario DeWeerd for the hint that it is sufficient for this
7891;; function to work with Bourne-like shells.
7892;;
7893;; CCC: This function should be rewritten so that
7894;; `shell-quote-argument' is not used. This way, we are safe from
7895;; changes in `shell-quote-argument'.
7896(defun tramp-shell-quote-argument (s)
7897 "Similar to `shell-quote-argument', but groks newlines.
7898Only works for Bourne-like shells."
7899 (let ((system-type 'not-windows))
7900 (save-match-data
7901 (let ((result (shell-quote-argument s))
7902 (nl (regexp-quote (format "\\%s" tramp-rsh-end-of-line))))
7903 (when (and (>= (length result) 2)
7904 (string= (substring result 0 2) "\\~"))
7905 (setq result (substring result 1)))
7906 (while (string-match nl result)
7907 (setq result (replace-match (format "'%s'" tramp-rsh-end-of-line)
7908 t t result)))
7909 result))))
7910
16674e4f
KG
7911;; We currently (sometimes) use "[" and "]" in the filename format.
7912;; This means that Emacs wants to expand wildcards if
fb7933a3
KG
7913;; `find-file-wildcards' is non-nil, and then barfs because no
7914;; expansion could be found. We detect this situation and do
7915;; something really awful: we have `file-expand-wildcards' return the
7916;; original filename if it can't expand anything. Let's just hope
7917;; that this doesn't break anything else.
16674e4f
KG
7918;; CCC: This check is now also really awful; we should search all
7919;; of the filename format, not just the prefix.
7920(when (string-match "\\[" tramp-prefix-format)
1834b39f
MA
7921 (defadvice file-expand-wildcards
7922 (around tramp-advice-file-expand-wildcards activate)
d2a2c17f
MA
7923 (let ((name (ad-get-arg 0)))
7924 (if (tramp-tramp-file-p name)
7925 ;; If it's a Tramp file, dissect it and look if wildcards
7926 ;; need to be expanded at all.
1834b39f
MA
7927 (if (string-match
7928 "[[*?]"
7929 (tramp-file-name-localname (tramp-dissect-file-name name)))
7930 (setq ad-return-value (or ad-do-it (list name)))
7931 (setq ad-return-value (list name)))
d2a2c17f 7932 ;; If it is not a Tramp file, just run the original function.
1834b39f 7933 (setq ad-return-value (or ad-do-it (list name))))))
a69c01a0 7934 (add-hook 'tramp-unload-hook
aa485f7c 7935 (lambda () (ad-unadvise 'file-expand-wildcards))))
fb7933a3 7936
a69c01a0
MA
7937;; Checklist for `tramp-unload-hook'
7938;; - Unload all `tramp-*' packages
7939;; - Reset `file-name-handler-alist'
7940;; - Cleanup hooks where Tramp functions are in
7941;; - Cleanup advised functions
7942;; - Cleanup autoloads
7943;;;###autoload
7944(defun tramp-unload-tramp ()
08b1eb21 7945 "Discard Tramp from loading remote files."
a69c01a0
MA
7946 (interactive)
7947 ;; When Tramp is not loaded yet, its autoloads are still active.
8c04e197 7948 (tramp-unload-file-name-handlers)
a69c01a0
MA
7949 ;; ange-ftp settings must be enabled.
7950 (when (functionp 'tramp-ftp-enable-ange-ftp)
7951 (funcall (symbol-function 'tramp-ftp-enable-ange-ftp)))
00d6fd04
MA
7952 ;; Maybe its not loaded yet.
7953 (condition-case nil
7954 (unload-feature 'tramp 'force)
a69c01a0
MA
7955 (error nil)))
7956
dea31ca6
MA
7957(when (and load-in-progress
7958 (string-match "Loading tramp..." (or (current-message) "")))
ccb4a481
MA
7959 (message "Loading tramp...done"))
7960
fb7933a3
KG
7961(provide 'tramp)
7962
fb7933a3
KG
7963;;; TODO:
7964
4007ba5b 7965;; * Handle nonlocal exits such as C-g.
00d6fd04
MA
7966;; * But it would probably be better to use with-local-quit at the
7967;; place where it's actually needed: around any potentially
7968;; indefinitely blocking piece of code. In this case it would be
7969;; within Tramp around one of its calls to accept-process-output (or
7970;; around one of the loops that calls accept-process-output)
d037d501 7971;; (Stefan Monnier).
fb7933a3 7972;; * Rewrite `tramp-shell-quote-argument' to abstain from using
b1d06e75 7973;; `shell-quote-argument'.
fb7933a3
KG
7974;; * In Emacs 21, `insert-directory' shows total number of bytes used
7975;; by the files in that directory. Add this here.
7976;; * Avoid screen blanking when hitting `g' in dired. (Eli Tziperman)
7977;; * Make ffap.el grok Tramp filenames. (Eli Tziperman)
fb7933a3 7978;; * Case-insensitive filename completion. (Norbert Goevert.)
fb7933a3
KG
7979;; * Don't use globbing for directories with many files, as this is
7980;; likely to produce long command lines, and some shells choke on
7981;; long command lines.
fb7933a3
KG
7982;; * `vc-directory' does not work. It never displays any files, even
7983;; if it does show files when run locally.
fb7933a3 7984;; * How to deal with MULE in `insert-file-contents' and `write-region'?
fb7933a3
KG
7985;; * Grok `append' parameter for `write-region'.
7986;; * Test remote ksh or bash for tilde expansion in `tramp-find-shell'?
7987;; * abbreviate-file-name
8e754ea2 7988;; * Better error checking. At least whenever we see something
fb7933a3
KG
7989;; strange when doing zerop, we should kill the process and start
7990;; again. (Greg Stark)
fb7933a3
KG
7991;; * Provide a local cache of old versions of remote files for the rsync
7992;; transfer method to use. (Greg Stark)
7993;; * Remove unneeded parameters from methods.
7994;; * Invoke rsync once for copying a whole directory hierarchy.
cdd44874 7995;; (Francesco Potortì)
fb7933a3
KG
7996;; * Make it work for different encodings, and for different file name
7997;; encodings, too. (Daniel Pittman)
fb7933a3 7998;; * Progress reports while copying files. (Michael Kifer)
fb7933a3
KG
7999;; * Don't search for perl5 and perl. Instead, only search for perl and
8000;; then look if it's the right version (with `perl -v').
8001;; * When editing a remote CVS controlled file as a different user, VC
8002;; gets confused about the file locking status. Try to find out why
8003;; the workaround doesn't work.
3cdaec13 8004;; * Username and hostname completion.
6c4e47fa 8005;; ** Try to avoid usage of `last-input-event' in `tramp-completion-mode-p'.
8daea7fc 8006;; ** Unify `tramp-parse-{rhosts,shosts,sconfig,hosts,passwd,netrc}'.
16674e4f 8007;; Code is nearly identical.
cfb5c0db
MA
8008;; * Allow out-of-band methods as _last_ multi-hop. Open a connection
8009;; until the last but one hop via `start-file-process'. Apply it
8010;; also for ftp and smb.
00d6fd04
MA
8011;; * WIBNI if we had a command "trampclient"? If I was editing in
8012;; some shell with root priviledges, it would be nice if I could
8013;; just call
8014;; trampclient filename.c
8015;; as an editor, and the _current_ shell would connect to an Emacs
8016;; server and would be used in an existing non-priviledged Emacs
8017;; session for doing the editing in question.
8018;; That way, I need not tell Emacs my password again and be afraid
8019;; that it makes it into core dumps or other ugly stuff (I had Emacs
8020;; once display a just typed password in the context of a keyboard
8021;; sequence prompt for a question immediately following in a shell
8022;; script run within Emacs -- nasty).
8023;; And if I have some ssh session running to a different computer,
8024;; having the possibility of passing a local file there to a local
8025;; Emacs session (in case I can arrange for a connection back) would
8026;; be nice.
a4aeb9a4 8027;; Likely the corresponding Tramp server should not allow the
00d6fd04
MA
8028;; equivalent of the emacsclient -eval option in order to make this
8029;; reasonably unproblematic. And maybe trampclient should have some
8030;; way of passing credentials, like by using an SSL socket or
8031;; something. (David Kastrup)
00d6fd04
MA
8032;; * Reconnect directly to a compliant shell without first going
8033;; through the user's default shell. (Pete Forman)
00d6fd04 8034;; * Make `tramp-default-user' obsolete.
adb67129
MA
8035;; * Tramp shall reconnect automatically to its ssh connection when it
8036;; detects that the process "has died". (David Reitter)
11c71217
MA
8037;; * How can I interrupt the remote process with a signal
8038;; (interrupt-process seems not to work)? (Markus Triska)
2296b54d
MA
8039;; * Avoid the local shell entirely for starting remote processes. If
8040;; so, I think even a signal, when delivered directly to the local
8041;; SSH instance, would correctly be propagated to the remote process
8042;; automatically; possibly SSH would have to be started with
8043;; "-t". (Markus Triska)
ccb4a481
MA
8044;; * Set `tramp-copy-size-limit' to 0, when there is no remote
8045;; encoding routine.
dea31ca6
MA
8046;; * It makes me wonder if tramp couldn't fall back to ssh when scp
8047;; isn't on the remote host. (Mark A. Hershberger)
65a099b6
MA
8048;; * To improve the behavior in case of things like "git status", it
8049;; might be worthwhile to add some way to indicate that a particular
8050;; use of process-file is (supposed to be) free of side-effects.
8051;; (Stefan Monnier)
3e2fa353
MA
8052;; * Use lsh instead of ssh. (Alfred M. Szmidt)
8053;; * Implement a general server-local-variable mechanism, as there are
8054;; probably other variables that need different values for different
8055;; servers too. The user could then configure a variable (such as
8056;; tramp-server-local-variable-alist) to define any such variables
8057;; that they need to, which would then be let bound as appropriate
8058;; in tramp functions. (Jason Rumney)
946a5aeb
MA
8059;; * Optimize out-of-band copying, when both methods are scp-like (not
8060;; rsync).
8061;; * Keep a second connection open for out-of-band methods like scp or
8062;; rsync.
8063;; * Partial completion completes word constituents. I find it
8064;; acceptable if method completion works only after :, so that we
8065;; have "/s: TAB" offer completion for the method first, filenames
8066;; afterwards. (David Kastrup)
8067
fb7933a3
KG
8068
8069;; Functions for file-name-handler-alist:
8070;; diff-latest-backup-file -- in diff.el
fb7933a3 8071
cdd44874 8072;; arch-tag: 3a21a994-182b-48fa-b0cd-c1d9fede424a
fb7933a3 8073;;; tramp.el ends here
57671b72
MA
8074
8075;; Local Variables:
8076;; mode: Emacs-Lisp
8077;; coding: utf-8
8078;; End: