Regenerate.
[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 153 ;; Load gateways. It needs `make-network-process' from Emacs 22.
03db0efc
MA
154 (when (functionp 'make-network-process) 'tramp-gw)
155
156 ;; tramp-imap needs both epa (from Emacs 23.1) and imap-hash
157 ;; (from Emacs 23.2).
158 (when (and (locate-library "epa") (locate-library "imap-hash"))
159 'tramp-imap)))
9c13938d
MA
160
161 (when feature
70c11b0b
MA
162 ;; We have used just some basic tests, whether a package shall
163 ;; be added. There might still be other errors during loading,
164 ;; which we will catch here.
165 (catch 'tramp-loading
166 (require feature)
167 (add-hook 'tramp-unload-hook
168 `(lambda ()
169 (when (featurep (quote ,feature))
170 (unload-feature (quote ,feature) 'force)))))
171 (unless (featurep feature)
172 (message "Loading %s failed, ignoring this package" feature)))))
fb7933a3
KG
173
174;;; User Customizable Internal Variables:
175
176(defgroup tramp nil
177 "Edit remote files with a combination of rsh and rcp or similar programs."
589d30dd 178 :group 'files
bf247b6e 179 :version "22.1")
fb7933a3 180
2e271195
MA
181;; Maybe we need once a real Tramp mode, with key bindings etc.
182;;;###autoload
183(defcustom tramp-mode t
184 "*Whether Tramp is enabled.
185If it is set to nil, all remote file names are used literally."
186 :group 'tramp
187 :type 'boolean)
188
00d6fd04 189(defcustom tramp-verbose 3
263c02ef 190 "*Verbosity level for Tramp messages.
00d6fd04
MA
191Any level x includes messages for all levels 1 .. x-1. The levels are
192
193 0 silent (no tramp messages at all)
194 1 errors
195 2 warnings
196 3 connection to remote hosts (default level)
197 4 activities
198 5 internal
199 6 sent and received strings
200 7 file caching
201 8 connection properties
20210 traces (huge)."
fb7933a3
KG
203 :group 'tramp
204 :type 'integer)
205
263c02ef 206;; Emacs case.
38c65fca
KG
207(eval-and-compile
208 (when (boundp 'backup-directory-alist)
209 (defcustom tramp-backup-directory-alist nil
210 "Alist of filename patterns and backup directory names.
211Each element looks like (REGEXP . DIRECTORY), with the same meaning like
212in `backup-directory-alist'. If a Tramp file is backed up, and DIRECTORY
213is a local file name, the backup directory is prepended with Tramp file
00d6fd04 214name prefix \(method, user, host\) of file.
38c65fca
KG
215
216\(setq tramp-backup-directory-alist backup-directory-alist\)
217
218gives the same backup policy for Tramp files on their hosts like the
219policy for local files."
220 :group 'tramp
221 :type '(repeat (cons (regexp :tag "Regexp matching filename")
222 (directory :tag "Backup directory name"))))))
223
224;; XEmacs case. We cannot check for `bkup-backup-directory-info', because
225;; the package "backup-dir" might not be loaded yet.
226(eval-and-compile
227 (when (featurep 'xemacs)
228 (defcustom tramp-bkup-backup-directory-info nil
229 "*Alist of (FILE-REGEXP BACKUP-DIR OPTIONS ...))
230It has the same meaning like `bkup-backup-directory-info' from package
231`backup-dir'. If a Tramp file is backed up, and BACKUP-DIR is a local
232file name, the backup directory is prepended with Tramp file name prefix
00d6fd04 233\(method, user, host\) of file.
38c65fca
KG
234
235\(setq tramp-bkup-backup-directory-info bkup-backup-directory-info\)
236
237gives the same backup policy for Tramp files on their hosts like the
238policy for local files."
bf247b6e 239 :type '(repeat
38c65fca
KG
240 (list (regexp :tag "File regexp")
241 (string :tag "Backup Dir")
242 (set :inline t
243 (const ok-create)
244 (const full-path)
245 (const prepend-name)
246 (const search-upward))))
247 :group 'tramp)))
248
fb7933a3
KG
249(defcustom tramp-auto-save-directory nil
250 "*Put auto-save files in this directory, if set.
251The idea is to use a local directory so that auto-saving is faster."
252 :group 'tramp
00d6fd04 253 :type '(choice (const nil) string))
fb7933a3 254
16674e4f
KG
255(defcustom tramp-encoding-shell
256 (if (memq system-type '(windows-nt))
257 (getenv "COMSPEC")
258 "/bin/sh")
259 "*Use this program for encoding and decoding commands on the local host.
260This shell is used to execute the encoding and decoding command on the
261local host, so if you want to use `~' in those commands, you should
262choose a shell here which groks tilde expansion. `/bin/sh' normally
263does not understand tilde expansion.
264
265For encoding and deocding, commands like the following are executed:
266
267 /bin/sh -c COMMAND < INPUT > OUTPUT
268
269This variable can be used to change the \"/bin/sh\" part. See the
00d6fd04 270variable `tramp-encoding-command-switch' for the \"-c\" part.
fb7933a3
KG
271
272Note that this variable is not used for remote commands. There are
273mechanisms in tramp.el which automatically determine the right shell to
274use for the remote host."
275 :group 'tramp
276 :type '(file :must-match t))
277
16674e4f
KG
278(defcustom tramp-encoding-command-switch
279 (if (string-match "cmd\\.exe" tramp-encoding-shell)
280 "/c"
281 "-c")
282 "*Use this switch together with `tramp-encoding-shell' for local commands.
283See the variable `tramp-encoding-shell' for more information."
284 :group 'tramp
285 :type 'string)
286
00d6fd04
MA
287(defcustom tramp-copy-size-limit 10240
288 "*The maximum file size where inline copying is preferred over an out-of-the-band copy."
16674e4f 289 :group 'tramp
00d6fd04 290 :type 'integer)
90dc758d 291
00d6fd04
MA
292(defcustom tramp-terminal-type "dumb"
293 "*Value of TERM environment variable for logging in to remote host.
294Because Tramp wants to parse the output of the remote shell, it is easily
295confused by ANSI color escape sequences and suchlike. Often, shell init
296files conditionalize this setup based on the TERM environment variable."
90dc758d 297 :group 'tramp
00d6fd04 298 :type 'string)
90dc758d 299
00d6fd04
MA
300(defvar tramp-methods
301 `(("rcp" (tramp-login-program "rsh")
302 (tramp-login-args (("%h") ("-l" "%u")))
303 (tramp-remote-sh "/bin/sh")
304 (tramp-copy-program "rcp")
263c02ef 305 (tramp-copy-args (("-p" "%k") ("-r")))
00d6fd04 306 (tramp-copy-keep-date t)
263c02ef 307 (tramp-copy-recursive t)
00d6fd04
MA
308 (tramp-password-end-of-line nil))
309 ("scp" (tramp-login-program "ssh")
2296b54d 310 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
311 ("-e" "none")))
312 (tramp-remote-sh "/bin/sh")
313 (tramp-copy-program "scp")
263c02ef
MA
314 (tramp-copy-args (("-P" "%p") ("-p" "%k")
315 ("-q") ("-r")))
00d6fd04 316 (tramp-copy-keep-date t)
263c02ef 317 (tramp-copy-recursive t)
00d6fd04
MA
318 (tramp-password-end-of-line nil)
319 (tramp-gw-args (("-o"
320 "GlobalKnownHostsFile=/dev/null")
321 ("-o" "UserKnownHostsFile=/dev/null")
322 ("-o" "StrictHostKeyChecking=no")))
323 (tramp-default-port 22))
324 ("scp1" (tramp-login-program "ssh")
2296b54d 325 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
326 ("-1" "-e" "none")))
327 (tramp-remote-sh "/bin/sh")
328 (tramp-copy-program "scp")
329 (tramp-copy-args (("-1") ("-P" "%p") ("-p" "%k")
263c02ef 330 ("-q") ("-r")))
00d6fd04 331 (tramp-copy-keep-date t)
263c02ef 332 (tramp-copy-recursive t)
00d6fd04
MA
333 (tramp-password-end-of-line nil)
334 (tramp-gw-args (("-o"
335 "GlobalKnownHostsFile=/dev/null")
336 ("-o" "UserKnownHostsFile=/dev/null")
337 ("-o" "StrictHostKeyChecking=no")))
338 (tramp-default-port 22))
339 ("scp2" (tramp-login-program "ssh")
2296b54d 340 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
341 ("-2" "-e" "none")))
342 (tramp-remote-sh "/bin/sh")
343 (tramp-copy-program "scp")
344 (tramp-copy-args (("-2") ("-P" "%p") ("-p" "%k")
263c02ef 345 ("-q") ("-r")))
00d6fd04 346 (tramp-copy-keep-date t)
263c02ef 347 (tramp-copy-recursive t)
00d6fd04
MA
348 (tramp-password-end-of-line nil)
349 (tramp-gw-args (("-o"
350 "GlobalKnownHostsFile=/dev/null")
351 ("-o" "UserKnownHostsFile=/dev/null")
352 ("-o" "StrictHostKeyChecking=no")))
353 (tramp-default-port 22))
354 ("scp1_old"
355 (tramp-login-program "ssh1")
356 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
357 ("-e" "none")))
358 (tramp-remote-sh "/bin/sh")
359 (tramp-copy-program "scp1")
263c02ef 360 (tramp-copy-args (("-p" "%k") ("-r")))
00d6fd04 361 (tramp-copy-keep-date t)
263c02ef 362 (tramp-copy-recursive t)
00d6fd04
MA
363 (tramp-password-end-of-line nil))
364 ("scp2_old"
365 (tramp-login-program "ssh2")
366 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
367 ("-e" "none")))
368 (tramp-remote-sh "/bin/sh")
369 (tramp-copy-program "scp2")
263c02ef 370 (tramp-copy-args (("-p" "%k") ("-r")))
00d6fd04 371 (tramp-copy-keep-date t)
263c02ef 372 (tramp-copy-recursive t)
00d6fd04
MA
373 (tramp-password-end-of-line nil))
374 ("sftp" (tramp-login-program "ssh")
375 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
376 ("-e" "none")))
377 (tramp-remote-sh "/bin/sh")
378 (tramp-copy-program "sftp")
379 (tramp-copy-args nil)
380 (tramp-copy-keep-date nil)
381 (tramp-password-end-of-line nil))
382 ("rsync" (tramp-login-program "ssh")
383 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
384 ("-e" "none")))
385 (tramp-remote-sh "/bin/sh")
386 (tramp-copy-program "rsync")
263c02ef 387 (tramp-copy-args (("-e" "ssh") ("-t" "%k") ("-r")))
00d6fd04 388 (tramp-copy-keep-date t)
b88f2d0a 389 (tramp-copy-keep-tmpfile t)
263c02ef 390 (tramp-copy-recursive t)
00d6fd04 391 (tramp-password-end-of-line nil))
263c02ef
MA
392 ("rsyncc"
393 (tramp-login-program "ssh")
946a5aeb
MA
394 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
395 ("-o" "ControlPath=%t.%%r@%%h:%%p")
396 ("-o" "ControlMaster=yes")
397 ("-e" "none")))
398 (tramp-remote-sh "/bin/sh")
399 (tramp-copy-program "rsync")
263c02ef 400 (tramp-copy-args (("-t" "%k") ("-r")))
946a5aeb
MA
401 (tramp-copy-env (("RSYNC_RSH")
402 (,(concat
403 "ssh"
404 " -o ControlPath=%t.%%r@%%h:%%p"
405 " -o ControlMaster=auto"))))
406 (tramp-copy-keep-date t)
b88f2d0a 407 (tramp-copy-keep-tmpfile t)
263c02ef 408 (tramp-copy-recursive t)
946a5aeb 409 (tramp-password-end-of-line nil))
00d6fd04
MA
410 ("remcp" (tramp-login-program "remsh")
411 (tramp-login-args (("%h") ("-l" "%u")))
412 (tramp-remote-sh "/bin/sh")
413 (tramp-copy-program "rcp")
414 (tramp-copy-args (("-p" "%k")))
415 (tramp-copy-keep-date t)
416 (tramp-password-end-of-line nil))
417 ("rsh" (tramp-login-program "rsh")
418 (tramp-login-args (("%h") ("-l" "%u")))
419 (tramp-remote-sh "/bin/sh")
420 (tramp-copy-program nil)
421 (tramp-copy-args nil)
422 (tramp-copy-keep-date nil)
423 (tramp-password-end-of-line nil))
424 ("ssh" (tramp-login-program "ssh")
2296b54d 425 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
426 ("-e" "none")))
427 (tramp-remote-sh "/bin/sh")
428 (tramp-copy-program nil)
429 (tramp-copy-args nil)
430 (tramp-copy-keep-date nil)
431 (tramp-password-end-of-line nil)
432 (tramp-gw-args (("-o"
433 "GlobalKnownHostsFile=/dev/null")
434 ("-o" "UserKnownHostsFile=/dev/null")
435 ("-o" "StrictHostKeyChecking=no")))
436 (tramp-default-port 22))
437 ("ssh1" (tramp-login-program "ssh")
2296b54d 438 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
439 ("-1" "-e" "none")))
440 (tramp-remote-sh "/bin/sh")
441 (tramp-copy-program nil)
442 (tramp-copy-args nil)
443 (tramp-copy-keep-date nil)
444 (tramp-password-end-of-line nil)
445 (tramp-gw-args (("-o"
446 "GlobalKnownHostsFile=/dev/null")
447 ("-o" "UserKnownHostsFile=/dev/null")
448 ("-o" "StrictHostKeyChecking=no")))
449 (tramp-default-port 22))
450 ("ssh2" (tramp-login-program "ssh")
2296b54d 451 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
452 ("-2" "-e" "none")))
453 (tramp-remote-sh "/bin/sh")
454 (tramp-copy-program nil)
455 (tramp-copy-args nil)
456 (tramp-copy-keep-date nil)
457 (tramp-password-end-of-line nil)
458 (tramp-gw-args (("-o"
459 "GlobalKnownHostsFile=/dev/null")
460 ("-o" "UserKnownHostsFile=/dev/null")
461 ("-o" "StrictHostKeyChecking=no")))
462 (tramp-default-port 22))
463 ("ssh1_old"
464 (tramp-login-program "ssh1")
465 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
466 ("-e" "none")))
467 (tramp-remote-sh "/bin/sh")
468 (tramp-copy-program nil)
469 (tramp-copy-args nil)
470 (tramp-copy-keep-date nil)
471 (tramp-password-end-of-line nil))
472 ("ssh2_old"
473 (tramp-login-program "ssh2")
474 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
475 ("-e" "none")))
476 (tramp-remote-sh "/bin/sh")
477 (tramp-copy-program nil)
478 (tramp-copy-args nil)
479 (tramp-copy-keep-date nil)
480 (tramp-password-end-of-line nil))
481 ("remsh" (tramp-login-program "remsh")
482 (tramp-login-args (("%h") ("-l" "%u")))
483 (tramp-remote-sh "/bin/sh")
484 (tramp-copy-program nil)
485 (tramp-copy-args nil)
486 (tramp-copy-keep-date nil)
487 (tramp-password-end-of-line nil))
488 ("telnet"
489 (tramp-login-program "telnet")
490 (tramp-login-args (("%h") ("%p")))
491 (tramp-remote-sh "/bin/sh")
492 (tramp-copy-program nil)
493 (tramp-copy-args nil)
494 (tramp-copy-keep-date nil)
495 (tramp-password-end-of-line nil)
496 (tramp-default-port 23))
497 ("su" (tramp-login-program "su")
498 (tramp-login-args (("-") ("%u")))
499 (tramp-remote-sh "/bin/sh")
500 (tramp-copy-program nil)
501 (tramp-copy-args nil)
502 (tramp-copy-keep-date nil)
503 (tramp-password-end-of-line nil))
504 ("sudo" (tramp-login-program "sudo")
505 (tramp-login-args (("-u" "%u")
42bc9b6d 506 ("-s") ("-H") ("-p" "Password:")))
00d6fd04
MA
507 (tramp-remote-sh "/bin/sh")
508 (tramp-copy-program nil)
509 (tramp-copy-args nil)
510 (tramp-copy-keep-date nil)
511 (tramp-password-end-of-line nil))
512 ("scpc" (tramp-login-program "ssh")
2296b54d 513 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
514 ("-o" "ControlPath=%t.%%r@%%h:%%p")
515 ("-o" "ControlMaster=yes")
516 ("-e" "none")))
517 (tramp-remote-sh "/bin/sh")
518 (tramp-copy-program "scp")
519 (tramp-copy-args (("-P" "%p") ("-p" "%k") ("-q")
520 ("-o" "ControlPath=%t.%%r@%%h:%%p")
521 ("-o" "ControlMaster=auto")))
522 (tramp-copy-keep-date t)
523 (tramp-password-end-of-line nil)
524 (tramp-gw-args (("-o"
525 "GlobalKnownHostsFile=/dev/null")
526 ("-o" "UserKnownHostsFile=/dev/null")
527 ("-o" "StrictHostKeyChecking=no")))
528 (tramp-default-port 22))
529 ("scpx" (tramp-login-program "ssh")
2296b54d 530 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
531 ("-e" "none" "-t" "-t" "/bin/sh")))
532 (tramp-remote-sh "/bin/sh")
533 (tramp-copy-program "scp")
534 (tramp-copy-args (("-p" "%k")))
535 (tramp-copy-keep-date t)
536 (tramp-password-end-of-line nil)
537 (tramp-gw-args (("-o"
538 "GlobalKnownHostsFile=/dev/null")
539 ("-o" "UserKnownHostsFile=/dev/null")
540 ("-o" "StrictHostKeyChecking=no")))
541 (tramp-default-port 22))
542 ("sshx" (tramp-login-program "ssh")
2296b54d 543 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
544 ("-e" "none" "-t" "-t" "/bin/sh")))
545 (tramp-remote-sh "/bin/sh")
546 (tramp-copy-program nil)
547 (tramp-copy-args nil)
548 (tramp-copy-keep-date nil)
549 (tramp-password-end-of-line nil)
550 (tramp-gw-args (("-o"
551 "GlobalKnownHostsFile=/dev/null")
552 ("-o" "UserKnownHostsFile=/dev/null")
553 ("-o" "StrictHostKeyChecking=no")))
554 (tramp-default-port 22))
555 ("krlogin"
556 (tramp-login-program "krlogin")
557 (tramp-login-args (("%h") ("-l" "%u") ("-x")))
558 (tramp-remote-sh "/bin/sh")
559 (tramp-copy-program nil)
560 (tramp-copy-args nil)
561 (tramp-copy-keep-date nil)
562 (tramp-password-end-of-line nil))
563 ("plink" (tramp-login-program "plink")
564 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
565 ("-ssh")))
566 (tramp-remote-sh "/bin/sh")
567 (tramp-copy-program nil)
568 (tramp-copy-args nil)
569 (tramp-copy-keep-date nil)
570 (tramp-password-end-of-line "xy") ;see docstring for "xy"
571 (tramp-default-port 22))
572 ("plink1"
573 (tramp-login-program "plink")
574 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
575 ("-1" "-ssh")))
576 (tramp-remote-sh "/bin/sh")
577 (tramp-copy-program nil)
578 (tramp-copy-args nil)
579 (tramp-copy-keep-date nil)
580 (tramp-password-end-of-line "xy") ;see docstring for "xy"
581 (tramp-default-port 22))
582 ("plinkx"
583 (tramp-login-program "plink")
42bc9b6d
MA
584 ;; ("%h") must be a single element, see
585 ;; `tramp-compute-multi-hops'.
586 (tramp-login-args (("-load") ("%h") ("-t")
ce3f516f
MA
587 (,(format
588 "env 'TERM=%s' 'PROMPT_COMMAND=' 'PS1=$ '"
589 tramp-terminal-type))
00d6fd04
MA
590 ("/bin/sh")))
591 (tramp-remote-sh "/bin/sh")
592 (tramp-copy-program nil)
593 (tramp-copy-args nil)
594 (tramp-copy-keep-date nil)
595 (tramp-password-end-of-line nil))
596 ("pscp" (tramp-login-program "plink")
597 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
598 ("-ssh")))
599 (tramp-remote-sh "/bin/sh")
600 (tramp-copy-program "pscp")
60f2c210 601 (tramp-copy-args (("-P" "%p") ("-scp") ("-p" "%k")))
00d6fd04
MA
602 (tramp-copy-keep-date t)
603 (tramp-password-end-of-line "xy") ;see docstring for "xy"
604 (tramp-default-port 22))
605 ("psftp" (tramp-login-program "plink")
606 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
607 ("-ssh")))
608 (tramp-remote-sh "/bin/sh")
609 (tramp-copy-program "pscp")
60f2c210 610 (tramp-copy-args (("-P" "%p") ("-sftp") ("-p" "%k")))
00d6fd04
MA
611 (tramp-copy-keep-date t)
612 (tramp-password-end-of-line "xy")) ;see docstring for "xy"
613 ("fcp" (tramp-login-program "fsh")
614 (tramp-login-args (("%h") ("-l" "%u") ("sh" "-i")))
615 (tramp-remote-sh "/bin/sh -i")
616 (tramp-copy-program "fcp")
617 (tramp-copy-args (("-p" "%k")))
618 (tramp-copy-keep-date t)
619 (tramp-password-end-of-line nil)))
fb7933a3
KG
620 "*Alist of methods for remote files.
621This is a list of entries of the form (NAME PARAM1 PARAM2 ...).
622Each NAME stands for a remote access method. Each PARAM is a
623pair of the form (KEY VALUE). The following KEYs are defined:
fb7933a3
KG
624 * `tramp-remote-sh'
625 This specifies the Bourne shell to use on the remote host. This
626 MUST be a Bourne-like shell. It is normally not necessary to set
a4aeb9a4 627 this to any value other than \"/bin/sh\": Tramp wants to use a shell
fb7933a3
KG
628 which groks tilde expansion, but it can search for it. Also note
629 that \"/bin/sh\" exists on all Unixen, this might not be true for
630 the value that you decide to use. You Have Been Warned.
b25a52cc
KG
631 * `tramp-login-program'
632 This specifies the name of the program to use for logging in to the
00d6fd04
MA
633 remote host. This may be the name of rsh or a workalike program,
634 or the name of telnet or a workalike, or the name of su or a workalike.
b25a52cc 635 * `tramp-login-args'
fb7933a3 636 This specifies the list of arguments to pass to the above
00d6fd04 637 mentioned program. Please note that this is a list of list of arguments,
fb7933a3 638 that is, normally you don't want to put \"-a -b\" or \"-f foo\"
00d6fd04
MA
639 here. Instead, you want a list (\"-a\" \"-b\"), or (\"-f\" \"foo\").
640 There are some patterns: \"%h\" in this list is replaced by the host
641 name, \"%u\" is replaced by the user name, \"%p\" is replaced by the
642 port number, and \"%%\" can be used to obtain a literal percent character.
643 If a list containing \"%h\", \"%u\" or \"%p\" is unchanged during
644 expansion (i.e. no host or no user specified), this list is not used as
645 argument. By this, arguments like (\"-l\" \"%u\") are optional.
646 \"%t\" is replaced by the temporary file name produced with
647 `tramp-make-tramp-temp-file'. \"%k\" indicates the keep-date
648 parameter of a program, if exists.
b25a52cc
KG
649 * `tramp-copy-program'
650 This specifies the name of the program to use for remotely copying
651 the file; this might be the absolute filename of rcp or the name of
652 a workalike program.
653 * `tramp-copy-args'
fb7933a3 654 This specifies the list of parameters to pass to the above mentioned
b25a52cc 655 program, the hints for `tramp-login-args' also apply here.
00d6fd04
MA
656 * `tramp-copy-keep-date'
657 This specifies whether the copying program when the preserves the
658 timestamp of the original file.
b88f2d0a
MA
659 * `tramp-copy-keep-tmpfile'
660 This specifies whether a temporary local file shall be kept
661 for optimization reasons (useful for \"rsync\" methods).
662 * `tramp-copy-recursive'
663 Whether the operation copies directories recursively.
00d6fd04
MA
664 * `tramp-default-port'
665 The default port of a method is needed in case of gateway connections.
666 Additionally, it is used as indication which method is prepared for
667 passing gateways.
668 * `tramp-gw-args'
669 As the attribute name says, additional arguments are specified here
670 when a method is applied via a gateway.
90f8dc03
KG
671 * `tramp-password-end-of-line'
672 This specifies the string to use for terminating the line after
673 submitting the password. If this method parameter is nil, then the
674 value of the normal variable `tramp-default-password-end-of-line'
675 is used. This parameter is necessary because the \"plink\" program
676 requires any two characters after sending the password. These do
677 not have to be newline or carriage return characters. Other login
678 programs are happy with just one character, the newline character.
679 We use \"xy\" as the value for methods using \"plink\".
b25a52cc
KG
680
681What does all this mean? Well, you should specify `tramp-login-program'
682for all methods; this program is used to log in to the remote site. Then,
683there are two ways to actually transfer the files between the local and the
684remote side. One way is using an additional rcp-like program. If you want
685to do this, set `tramp-copy-program' in the method.
fb7933a3
KG
686
687Another possibility for file transfer is inline transfer, i.e. the
b25a52cc 688file is passed through the same buffer used by `tramp-login-program'. In
fb7933a3 689this case, the file contents need to be protected since the
b25a52cc 690`tramp-login-program' might use escape codes or the connection might not
fb7933a3 691be eight-bit clean. Therefore, file contents are encoded for transit.
00d6fd04
MA
692See the variables `tramp-local-coding-commands' and
693`tramp-remote-coding-commands' for details.
fb7933a3 694
16674e4f 695So, to summarize: if the method is an out-of-band method, then you
b25a52cc 696must specify `tramp-copy-program' and `tramp-copy-args'. If it is an
00d6fd04
MA
697inline method, then these two parameters should be nil. Methods which
698are fit for gateways must have `tramp-default-port' at least.
fb7933a3
KG
699
700Notes:
701
00d6fd04
MA
702When using `su' or `sudo' the phrase `open connection to a remote
703host' sounds strange, but it is used nevertheless, for consistency.
704No connection is opened to a remote host, but `su' or `sudo' is
705started on the local host. You should specify a remote host
706`localhost' or the name of the local host. Another host name is
707useful only in combination with `tramp-default-proxies-alist'.")
fb7933a3 708
b25a52cc 709(defcustom tramp-default-method
83e20b5c
MA
710 ;; An external copy method seems to be preferred, because it is much
711 ;; more performant for large files, and it hasn't too serious delays
712 ;; for small files. But it must be ensured that there aren't
713 ;; permanent password queries. Either a password agent like
263c02ef
MA
714 ;; "ssh-agent" or "Pageant" shall run, or the optional
715 ;; password-cache.el or auth-sources.el packages shall be active for
716 ;; password caching. "scpc" would be another good choice because of
717 ;; the "ControlMaster" option, but this is a more modern alternative
718 ;; in OpenSSH 4, which cannot be taken as default.
00d6fd04
MA
719 (cond
720 ;; PuTTY is installed.
721 ((executable-find "pscp")
722 (if (or (fboundp 'password-read)
263c02ef 723 (fboundp 'auth-source-user-or-password)
00d6fd04 724 ;; Pageant is running.
70c11b0b 725 (tramp-compat-process-running-p "Pageant"))
00d6fd04
MA
726 "pscp"
727 "plink"))
728 ;; There is an ssh installation.
729 ((executable-find "scp")
730 (if (or (fboundp 'password-read)
263c02ef 731 (fboundp 'auth-source-user-or-password)
00d6fd04
MA
732 ;; ssh-agent is running.
733 (getenv "SSH_AUTH_SOCK")
734 (getenv "SSH_AGENT_PID"))
735 "scp"
736 "ssh"))
737 ;; Fallback.
738 (t "ftp"))
fb7933a3 739 "*Default method to use for transferring files.
c62c9d08 740See `tramp-methods' for possibilities.
4007ba5b 741Also see `tramp-default-method-alist'."
c62c9d08
KG
742 :group 'tramp
743 :type 'string)
744
505edaeb 745(defcustom tramp-default-method-alist
4007ba5b 746 '(("\\`localhost\\'" "\\`root\\'" "su"))
00d6fd04 747 "*Default method to use for specific host/user pairs.
c62c9d08
KG
748This is an alist of items (HOST USER METHOD). The first matching item
749specifies the method to use for a file name which does not specify a
750method. HOST and USER are regular expressions or nil, which is
751interpreted as a regular expression which always matches. If no entry
752matches, the variable `tramp-default-method' takes effect.
753
754If the file name does not specify the user, lookup is done using the
755empty string for the user name.
756
757See `tramp-methods' for a list of possibilities for METHOD."
758 :group 'tramp
759 :type '(repeat (list (regexp :tag "Host regexp")
760 (regexp :tag "User regexp")
761 (string :tag "Method"))))
762
00d6fd04
MA
763(defcustom tramp-default-user
764 nil
765 "*Default user to use for transferring files.
766It is nil by default; otherwise settings in configuration files like
767\"~/.ssh/config\" would be overwritten. Also see `tramp-default-user-alist'.
768
769This variable is regarded as obsolete, and will be removed soon."
770 :group 'tramp
771 :type '(choice (const nil) string))
772
773(defcustom tramp-default-user-alist
774 `(("\\`su\\(do\\)?\\'" nil "root")
775 ("\\`r\\(em\\)?\\(cp\\|sh\\)\\|telnet\\|plink1?\\'"
776 nil ,(user-login-name)))
777 "*Default user to use for specific method/host pairs.
778This is an alist of items (METHOD HOST USER). The first matching item
779specifies the user to use for a file name which does not specify a
780user. METHOD and USER are regular expressions or nil, which is
781interpreted as a regular expression which always matches. If no entry
782matches, the variable `tramp-default-user' takes effect.
783
784If the file name does not specify the method, lookup is done using the
785empty string for the method name."
786 :group 'tramp
787 :type '(repeat (list (regexp :tag "Method regexp")
788 (regexp :tag "Host regexp")
789 (string :tag "User"))))
790
791(defcustom tramp-default-host
792 (system-name)
793 "*Default host to use for transferring files.
794Useful for su and sudo methods mostly."
795 :group 'tramp
796 :type 'string)
797
798(defcustom tramp-default-proxies-alist nil
799 "*Route to be followed for specific host/user pairs.
800This is an alist of items (HOST USER PROXY). The first matching
801item specifies the proxy to be passed for a file name located on
802a remote target matching USER@HOST. HOST and USER are regular
70c11b0b
MA
803expressions. PROXY must be a Tramp filename without a localname
804part. Method and user name on PROXY are optional, which is
805interpreted with the default values. PROXY can contain the
806patterns %h and %u, which are replaced by the strings matching
807HOST or USER, respectively.
808
809HOST, USER or PROXY could also be Lisp forms, which will be
810evaluated. The result must be a string or nil, which is
811interpreted as a regular expression which always matches."
00d6fd04 812 :group 'tramp
70c11b0b
MA
813 :type '(repeat (list (choice :tag "Host regexp" regexp sexp)
814 (choice :tag "User regexp" regexp sexp)
815 (choice :tag "Proxy remote name" string (const nil)))))
00d6fd04 816
b96e6899
MA
817(defconst tramp-local-host-regexp
818 (concat
819 "^" (regexp-opt (list "localhost" (system-name) "127\.0\.0\.1" "::1") t) "$")
820 "*Host names which are regarded as local host.")
821
16674e4f 822(defconst tramp-completion-function-alist-rsh
00d6fd04
MA
823 '((tramp-parse-rhosts "/etc/hosts.equiv")
824 (tramp-parse-rhosts "~/.rhosts"))
b25a52cc 825 "Default list of (FUNCTION FILE) pairs to be examined for rsh methods.")
16674e4f 826
16674e4f 827(defconst tramp-completion-function-alist-ssh
00d6fd04
MA
828 '((tramp-parse-rhosts "/etc/hosts.equiv")
829 (tramp-parse-rhosts "/etc/shosts.equiv")
830 (tramp-parse-shosts "/etc/ssh_known_hosts")
831 (tramp-parse-sconfig "/etc/ssh_config")
832 (tramp-parse-shostkeys "/etc/ssh2/hostkeys")
833 (tramp-parse-sknownhosts "/etc/ssh2/knownhosts")
834 (tramp-parse-rhosts "~/.rhosts")
835 (tramp-parse-rhosts "~/.shosts")
836 (tramp-parse-shosts "~/.ssh/known_hosts")
837 (tramp-parse-sconfig "~/.ssh/config")
838 (tramp-parse-shostkeys "~/.ssh2/hostkeys")
839 (tramp-parse-sknownhosts "~/.ssh2/knownhosts"))
b25a52cc 840 "Default list of (FUNCTION FILE) pairs to be examined for ssh methods.")
16674e4f 841
16674e4f 842(defconst tramp-completion-function-alist-telnet
00d6fd04 843 '((tramp-parse-hosts "/etc/hosts"))
b25a52cc 844 "Default list of (FUNCTION FILE) pairs to be examined for telnet methods.")
16674e4f 845
16674e4f 846(defconst tramp-completion-function-alist-su
00d6fd04 847 '((tramp-parse-passwd "/etc/passwd"))
b25a52cc 848 "Default list of (FUNCTION FILE) pairs to be examined for su methods.")
292ffc15 849
00d6fd04
MA
850(defconst tramp-completion-function-alist-putty
851 '((tramp-parse-putty
852 "HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions"))
853 "Default list of (FUNCTION REGISTRY) pairs to be examined for putty methods.")
854
5ec2cc41 855(defvar tramp-completion-function-alist nil
16674e4f
KG
856 "*Alist of methods for remote files.
857This is a list of entries of the form (NAME PAIR1 PAIR2 ...).
858Each NAME stands for a remote access method. Each PAIR is of the form
859\(FUNCTION FILE). FUNCTION is responsible to extract user names and host
860names from FILE for completion. The following predefined FUNCTIONs exists:
861
5ec2cc41
KG
862 * `tramp-parse-rhosts' for \"~/.rhosts\" like files,
863 * `tramp-parse-shosts' for \"~/.ssh/known_hosts\" like files,
864 * `tramp-parse-sconfig' for \"~/.ssh/config\" like files,
865 * `tramp-parse-shostkeys' for \"~/.ssh2/hostkeys/*\" like files,
866 * `tramp-parse-sknownhosts' for \"~/.ssh2/knownhosts/*\" like files,
867 * `tramp-parse-hosts' for \"/etc/hosts\" like files,
868 * `tramp-parse-passwd' for \"/etc/passwd\" like files.
869 * `tramp-parse-netrc' for \"~/.netrc\" like files.
00d6fd04 870 * `tramp-parse-putty' for PuTTY registry keys.
5ec2cc41
KG
871
872FUNCTION can also be a customer defined function. For more details see
873the info pages.")
874
875(eval-after-load "tramp"
876 '(progn
877 (tramp-set-completion-function
878 "rcp" tramp-completion-function-alist-rsh)
879 (tramp-set-completion-function
880 "scp" tramp-completion-function-alist-ssh)
881 (tramp-set-completion-function
882 "scp1" tramp-completion-function-alist-ssh)
883 (tramp-set-completion-function
884 "scp2" tramp-completion-function-alist-ssh)
885 (tramp-set-completion-function
886 "scp1_old" tramp-completion-function-alist-ssh)
887 (tramp-set-completion-function
888 "scp2_old" tramp-completion-function-alist-ssh)
889 (tramp-set-completion-function
70c11b0b 890 "rsync" tramp-completion-function-alist-ssh)
946a5aeb
MA
891 (tramp-set-completion-function
892 "rsyncc" tramp-completion-function-alist-ssh)
5ec2cc41
KG
893 (tramp-set-completion-function
894 "remcp" tramp-completion-function-alist-rsh)
895 (tramp-set-completion-function
896 "rsh" tramp-completion-function-alist-rsh)
897 (tramp-set-completion-function
898 "ssh" tramp-completion-function-alist-ssh)
899 (tramp-set-completion-function
900 "ssh1" tramp-completion-function-alist-ssh)
901 (tramp-set-completion-function
902 "ssh2" tramp-completion-function-alist-ssh)
903 (tramp-set-completion-function
904 "ssh1_old" tramp-completion-function-alist-ssh)
905 (tramp-set-completion-function
906 "ssh2_old" tramp-completion-function-alist-ssh)
907 (tramp-set-completion-function
908 "remsh" tramp-completion-function-alist-rsh)
909 (tramp-set-completion-function
910 "telnet" tramp-completion-function-alist-telnet)
911 (tramp-set-completion-function
912 "su" tramp-completion-function-alist-su)
913 (tramp-set-completion-function
914 "sudo" tramp-completion-function-alist-su)
bf247b6e 915 (tramp-set-completion-function
5ec2cc41
KG
916 "scpx" tramp-completion-function-alist-ssh)
917 (tramp-set-completion-function
918 "sshx" tramp-completion-function-alist-ssh)
919 (tramp-set-completion-function
920 "krlogin" tramp-completion-function-alist-rsh)
921 (tramp-set-completion-function
922 "plink" tramp-completion-function-alist-ssh)
923 (tramp-set-completion-function
924 "plink1" tramp-completion-function-alist-ssh)
00d6fd04
MA
925 (tramp-set-completion-function
926 "plinkx" tramp-completion-function-alist-putty)
5ec2cc41
KG
927 (tramp-set-completion-function
928 "pscp" tramp-completion-function-alist-ssh)
929 (tramp-set-completion-function
930 "fcp" tramp-completion-function-alist-ssh)))
16674e4f 931
674da028
MA
932(defconst tramp-echo-mark-marker "_echo"
933 "String marker to surround echoed commands.")
934
00d6fd04
MA
935(defconst tramp-echo-mark "_echo\b\b\b\b\b"
936 "String mark to be transmitted around shell commands.
937Used to separate their echo from the output they produce. This
938will only be used if we cannot disable remote echo via stty.
939This string must have no effect on the remote shell except for
940producing some echo which can later be detected by
674da028
MA
941`tramp-echoed-echo-mark-regexp'. Using `tramp-echo-mark-marker',
942followed by an equal number of backspaces to erase them will
943usually suffice.")
00d6fd04
MA
944
945(defconst tramp-echoed-echo-mark-regexp "_echo\\(\b\\( \b\\)?\\)\\{5\\}"
946 "Regexp which matches `tramp-echo-mark' as it gets echoed by
947the remote shell.")
948
fb7933a3
KG
949(defcustom tramp-rsh-end-of-line "\n"
950 "*String used for end of line in rsh connections.
951I don't think this ever needs to be changed, so please tell me about it
16674e4f 952if you need to change this.
90f8dc03
KG
953Also see the method parameter `tramp-password-end-of-line' and the normal
954variable `tramp-default-password-end-of-line'."
16674e4f
KG
955 :group 'tramp
956 :type 'string)
957
90f8dc03
KG
958(defcustom tramp-default-password-end-of-line
959 tramp-rsh-end-of-line
16674e4f 960 "*String used for end of line after sending a password.
90f8dc03
KG
961This variable provides the default value for the method parameter
962`tramp-password-end-of-line', see `tramp-methods' for more details.
963
16674e4f
KG
964It seems that people using plink under Windows need to send
965\"\\r\\n\" (carriage-return, then newline) after a password, but just
966\"\\n\" after all other lines. This variable can be used for the
967password, see `tramp-rsh-end-of-line' for the other cases.
968
969The default value is to use the same value as `tramp-rsh-end-of-line'."
fb7933a3
KG
970 :group 'tramp
971 :type 'string)
972
00d6fd04
MA
973;; "getconf PATH" yields:
974;; HP-UX: /usr/bin:/usr/ccs/bin:/opt/ansic/bin:/opt/langtools/bin:/opt/fortran/bin
975;; Solaris: /usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin
0664ff72 976;; GNU/Linux (Debian, Suse): /bin:/usr/bin
00d6fd04 977;; FreeBSD: /usr/bin:/bin:/usr/sbin:/sbin: - beware trailing ":"!
fb7933a3 978(defcustom tramp-remote-path
00d6fd04
MA
979 '(tramp-default-remote-path "/usr/sbin" "/usr/local/bin"
980 "/local/bin" "/local/freeware/bin" "/local/gnu/bin"
fb7933a3
KG
981 "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin")
982 "*List of directories to search for executables on remote host.
00d6fd04
MA
983For every remote host, this variable will be set buffer local,
984keeping the list of existing directories on that host.
fb7933a3
KG
985
986You can use `~' in this list, but when searching for a shell which groks
00d6fd04
MA
987tilde expansion, all directory names starting with `~' will be ignored.
988
989`Default Directories' represent the list of directories given by
990the command \"getconf PATH\". It is recommended to use this
991entry on top of this list, because these are the default
70c11b0b
MA
992directories for POSIX compatible commands.
993
994`Private Directories' are the settings of the $PATH environment,
995as given in your `~/.profile'."
00d6fd04
MA
996 :group 'tramp
997 :type '(repeat (choice
998 (const :tag "Default Directories" tramp-default-remote-path)
70c11b0b 999 (const :tag "Private Directories" tramp-own-remote-path)
00d6fd04
MA
1000 (string :tag "Directory"))))
1001
00d6fd04 1002(defcustom tramp-remote-process-environment
a0a5183a 1003 `("HISTFILE=$HOME/.tramp_history" "HISTSIZE=1" "LC_ALL=C"
00d6fd04 1004 ,(concat "TERM=" tramp-terminal-type)
97c696d5
MA
1005 "EMACS=t" ;; Deprecated.
1006 ,(format "INSIDE_EMACS=%s,tramp:%s" emacs-version tramp-version)
00d6fd04
MA
1007 "CDPATH=" "HISTORY=" "MAIL=" "MAILCHECK=" "MAILPATH="
1008 "autocorrect=" "correct=")
1009
1010 "*List of environment variables to be set on the remote host.
1011
1012Each element should be a string of the form ENVVARNAME=VALUE. An
1013entry ENVVARNAME= diables the corresponding environment variable,
1014which might have been set in the init files like ~/.profile.
1015
1016Special handling is applied to the PATH environment, which should
1017not be set here. Instead of, it should be set via `tramp-remote-path'."
fb7933a3
KG
1018 :group 'tramp
1019 :type '(repeat string))
1020
1021(defcustom tramp-login-prompt-regexp
bc103d00 1022 ".*ogin\\( .*\\)?: *"
fb7933a3 1023 "*Regexp matching login-like prompts.
bc103d00
MA
1024The regexp should match at end of buffer.
1025
1026Sometimes the prompt is reported to look like \"login as:\"."
fb7933a3
KG
1027 :group 'tramp
1028 :type 'regexp)
1029
821e6e36 1030(defcustom tramp-shell-prompt-pattern
aa485f7c
MA
1031 ;; Allow a prompt to start right after a ^M since it indeed would be
1032 ;; displayed at the beginning of the line (and Zsh uses it).
1033 "\\(?:^\\|\r\\)[^#$%>\n]*[#$%>] *\\(\e\\[[0-9;]*[a-zA-Z] *\\)*"
821e6e36
KG
1034 "Regexp to match prompts from remote shell.
1035Normally, Tramp expects you to configure `shell-prompt-pattern'
1036correctly, but sometimes it happens that you are connecting to a
1037remote host which sends a different kind of shell prompt. Therefore,
1038Tramp recognizes things matched by `shell-prompt-pattern' as prompt,
1039and also things matched by this variable. The default value of this
b25a52cc 1040variable is similar to the default value of `shell-prompt-pattern',
821e6e36
KG
1041which should work well in many cases."
1042 :group 'tramp
1043 :type 'regexp)
1044
fb7933a3 1045(defcustom tramp-password-prompt-regexp
00d6fd04 1046 "^.*\\([pP]assword\\|[pP]assphrase\\).*:\^@? *"
fb7933a3 1047 "*Regexp matching password-like prompts.
ac474af1 1048The regexp should match at end of buffer.
fb7933a3
KG
1049
1050The `sudo' program appears to insert a `^@' character into the prompt."
1051 :group 'tramp
1052 :type 'regexp)
1053
1054(defcustom tramp-wrong-passwd-regexp
b1d06e75
KG
1055 (concat "^.*"
1056 ;; These strings should be on the last line
a4aeb9a4 1057 (regexp-opt '("Permission denied"
b1d06e75
KG
1058 "Login incorrect"
1059 "Login Incorrect"
1060 "Connection refused"
27e813fe 1061 "Connection closed"
b1d06e75
KG
1062 "Sorry, try again."
1063 "Name or service not known"
00d6fd04 1064 "Host key verification failed."
70c11b0b 1065 "No supported authentication methods left to try!") t)
b1d06e75
KG
1066 ".*"
1067 "\\|"
1068 "^.*\\("
1069 ;; Here comes a list of regexes, separated by \\|
1070 "Received signal [0-9]+"
1071 "\\).*")
fb7933a3 1072 "*Regexp matching a `login failed' message.
ac474af1
KG
1073The regexp should match at end of buffer."
1074 :group 'tramp
1075 :type 'regexp)
1076
1077(defcustom tramp-yesno-prompt-regexp
3cdaec13
KG
1078 (concat
1079 (regexp-opt '("Are you sure you want to continue connecting (yes/no)?") t)
1080 "\\s-*")
1081 "Regular expression matching all yes/no queries which need to be confirmed.
ac474af1 1082The confirmation should be done with yes or no.
3cdaec13
KG
1083The regexp should match at end of buffer.
1084See also `tramp-yn-prompt-regexp'."
fb7933a3
KG
1085 :group 'tramp
1086 :type 'regexp)
1087
3cdaec13 1088(defcustom tramp-yn-prompt-regexp
658052a2
MA
1089 (concat
1090 (regexp-opt '("Store key in cache? (y/n)"
1091 "Update cached key? (y/n, Return cancels connection)") t)
1092 "\\s-*")
3cdaec13
KG
1093 "Regular expression matching all y/n queries which need to be confirmed.
1094The confirmation should be done with y or n.
1095The regexp should match at end of buffer.
1096See also `tramp-yesno-prompt-regexp'."
1097 :group 'tramp
1098 :type 'regexp)
487f4fb7
KG
1099
1100(defcustom tramp-terminal-prompt-regexp
1101 (concat "\\("
1102 "TERM = (.*)"
1103 "\\|"
1104 "Terminal type\\? \\[.*\\]"
1105 "\\)\\s-*")
1106 "Regular expression matching all terminal setting prompts.
1107The regexp should match at end of buffer.
1108The answer will be provided by `tramp-action-terminal', which see."
1109 :group 'tramp
1110 :type 'regexp)
3cdaec13 1111
01917a18
MA
1112(defcustom tramp-operation-not-permitted-regexp
1113 (concat "\\(" "preserving times.*" "\\|" "set mode" "\\)" ":\\s-*"
1114 (regexp-opt '("Operation not permitted") t))
1115 "Regular expression matching keep-date problems in (s)cp operations.
1116Copying has been performed successfully already, so this message can
1117be ignored safely."
1118 :group 'tramp
1119 :type 'regexp)
1120
6b2633cc
LH
1121(defcustom tramp-copy-failed-regexp
1122 (concat "\\(.+: "
1123 (regexp-opt '("Permission denied"
1124 "not a regular file"
1125 "is a directory"
1126 "No such file or directory") t)
1127 "\\)\\s-*")
1128 "Regular expression matching copy problems in (s)cp operations."
1129 :group 'tramp
1130 :type 'regexp)
1131
19a87064 1132(defcustom tramp-process-alive-regexp
38c65fca 1133 ""
19a87064 1134 "Regular expression indicating a process has finished.
38c65fca
KG
1135In fact this expression is empty by intention, it will be used only to
1136check regularly the status of the associated process.
07dfe738 1137The answer will be provided by `tramp-action-process-alive',
00d6fd04 1138`tramp-action-out-of-band', which see."
38c65fca
KG
1139 :group 'tramp
1140 :type 'regexp)
1141
fb7933a3
KG
1142(defcustom tramp-temp-name-prefix "tramp."
1143 "*Prefix to use for temporary files.
1144If this is a relative file name (such as \"tramp.\"), it is considered
1145relative to the directory name returned by the function
9e6ab520 1146`tramp-compat-temporary-file-directory' (which see). It may also be an
fb7933a3
KG
1147absolute file name; don't forget to include a prefix for the filename
1148part, though."
1149 :group 'tramp
1150 :type 'string)
1151
2296b54d
MA
1152(defconst tramp-temp-buffer-name " *tramp temp*"
1153 "Buffer name for a temporary buffer.
1154It shall be used in combination with `generate-new-buffer-name'.")
1155
b88f2d0a
MA
1156(defvar tramp-temp-buffer-file-name nil
1157 "File name of a persistent local temporary file.
1158Useful for \"rsync\" like methods.")
1159(make-variable-buffer-local 'tramp-temp-buffer-file-name)
1160
4007ba5b 1161(defcustom tramp-sh-extra-args '(("/bash\\'" . "-norc -noprofile"))
c62c9d08
KG
1162 "*Alist specifying extra arguments to pass to the remote shell.
1163Entries are (REGEXP . ARGS) where REGEXP is a regular expression
1164matching the shell file name and ARGS is a string specifying the
1165arguments.
1166
1167This variable is only used when Tramp needs to start up another shell
1168for tilde expansion. The extra arguments should typically prevent the
1169shell from reading its init file."
1170 :group 'tramp
90f8dc03
KG
1171 ;; This might be the wrong way to test whether the widget type
1172 ;; `alist' is available. Who knows the right way to test it?
1173 :type (if (get 'alist 'widget-type)
1174 '(alist :key-type string :value-type string)
1175 '(repeat (cons string string))))
c62c9d08 1176
00d6fd04
MA
1177;; XEmacs is distributed with few Lisp packages. Further packages are
1178;; installed using EFS. If we use a unified filename format, then
1179;; Tramp is required in addition to EFS. (But why can't Tramp just
1180;; disable EFS when Tramp is loaded? Then XEmacs can ship with EFS
1181;; just like before.) Another reason for using a separate filename
1182;; syntax on XEmacs is that EFS hooks into XEmacs in many places, but
1183;; Tramp only knows how to deal with `file-name-handler-alist', not
1184;; the other places.
1185
1186;; Currently, we have the choice between 'ftp, 'sep, and 'url.
1187;;;###autoload
1188(defcustom tramp-syntax
1189 (if (featurep 'xemacs) 'sep 'ftp)
1190 "Tramp filename syntax to be used.
1191
1192It can have the following values:
1193
1194 'ftp -- Ange-FTP respective EFS like syntax (GNU Emacs default)
1195 'sep -- Syntax as defined for XEmacs (not available yet for GNU Emacs)
1196 'url -- URL-like syntax."
16674e4f 1197 :group 'tramp
00d6fd04
MA
1198 :type (if (featurep 'xemacs)
1199 '(choice (const :tag "EFS" ftp)
1200 (const :tag "XEmacs" sep)
1201 (const :tag "URL" url))
1202 '(choice (const :tag "Ange-FTP" ftp)
1203 (const :tag "URL" url))))
1204
1205(defconst tramp-prefix-format
1206 (cond ((equal tramp-syntax 'ftp) "/")
1207 ((equal tramp-syntax 'sep) "/[")
1208 ((equal tramp-syntax 'url) "/")
1209 (t (error "Wrong `tramp-syntax' defined")))
a4aeb9a4 1210 "*String matching the very beginning of Tramp file names.
00d6fd04 1211Used in `tramp-make-tramp-file-name'.")
16674e4f 1212
00d6fd04 1213(defconst tramp-prefix-regexp
16674e4f 1214 (concat "^" (regexp-quote tramp-prefix-format))
a4aeb9a4 1215 "*Regexp matching the very beginning of Tramp file names.
00d6fd04 1216Should always start with \"^\". Derived from `tramp-prefix-format'.")
16674e4f 1217
00d6fd04 1218(defconst tramp-method-regexp
16674e4f 1219 "[a-zA-Z_0-9-]+"
00d6fd04 1220 "*Regexp matching methods identifiers.")
16674e4f 1221
00d6fd04
MA
1222(defconst tramp-postfix-method-format
1223 (cond ((equal tramp-syntax 'ftp) ":")
1224 ((equal tramp-syntax 'sep) "/")
1225 ((equal tramp-syntax 'url) "://")
1226 (t (error "Wrong `tramp-syntax' defined")))
16674e4f 1227 "*String matching delimeter between method and user or host names.
00d6fd04 1228Used in `tramp-make-tramp-file-name'.")
16674e4f 1229
00d6fd04
MA
1230(defconst tramp-postfix-method-regexp
1231 (regexp-quote tramp-postfix-method-format)
16674e4f 1232 "*Regexp matching delimeter between method and user or host names.
00d6fd04 1233Derived from `tramp-postfix-method-format'.")
16674e4f 1234
00d6fd04
MA
1235(defconst tramp-user-regexp
1236 "[^:/ \t]+"
1237 "*Regexp matching user names.")
16674e4f 1238
b96e6899
MA
1239(defconst tramp-prefix-domain-format "%"
1240 "*String matching delimeter between user and domain names.")
1241
1242(defconst tramp-prefix-domain-regexp
1243 (regexp-quote tramp-prefix-domain-format)
1244 "*Regexp matching delimeter between user and domain names.
1245Derived from `tramp-prefix-domain-format'.")
1246
1247(defconst tramp-domain-regexp
70c11b0b 1248 "[-a-zA-Z0-9_.]+"
b96e6899
MA
1249 "*Regexp matching domain names.")
1250
1251(defconst tramp-user-with-domain-regexp
1252 (concat "\\(" tramp-user-regexp "\\)"
1253 tramp-prefix-domain-regexp
1254 "\\(" tramp-domain-regexp "\\)")
1255 "*Regexp matching user names with domain names.")
1256
00d6fd04 1257(defconst tramp-postfix-user-format
16674e4f
KG
1258 "@"
1259 "*String matching delimeter between user and host names.
00d6fd04 1260Used in `tramp-make-tramp-file-name'.")
16674e4f 1261
00d6fd04 1262(defconst tramp-postfix-user-regexp
16674e4f
KG
1263 (regexp-quote tramp-postfix-user-format)
1264 "*Regexp matching delimeter between user and host names.
00d6fd04
MA
1265Derived from `tramp-postfix-user-format'.")
1266
1267(defconst tramp-host-regexp
1268 "[a-zA-Z0-9_.-]+"
1269 "*Regexp matching host names.")
1270
b96e6899
MA
1271(defconst tramp-prefix-ipv6-format
1272 (cond ((equal tramp-syntax 'ftp) "[")
1273 ((equal tramp-syntax 'sep) "")
1274 ((equal tramp-syntax 'url) "[")
1275 (t (error "Wrong `tramp-syntax' defined")))
1276 "*String matching left hand side of IPv6 addresses.
1277Used in `tramp-make-tramp-file-name'.")
1278
1279(defconst tramp-prefix-ipv6-regexp
1280 (regexp-quote tramp-prefix-ipv6-format)
1281 "*Regexp matching left hand side of IPv6 addresses.
1282Derived from `tramp-prefix-ipv6-format'.")
1283
e0b6e3b9
MA
1284;; The following regexp is a bit sloppy. But it shall serve our
1285;; purposes. It covers also IPv4 mapped IPv6 addresses, like in
1286;; "::ffff:192.168.0.1".
b96e6899 1287(defconst tramp-ipv6-regexp
e0b6e3b9 1288 "\\(?:\\(?:[a-zA-Z0-9]+\\)?:\\)+[a-zA-Z0-9.]+"
b96e6899
MA
1289 "*Regexp matching IPv6 addresses.")
1290
1291(defconst tramp-postfix-ipv6-format
1292 (cond ((equal tramp-syntax 'ftp) "]")
1293 ((equal tramp-syntax 'sep) "")
1294 ((equal tramp-syntax 'url) "]")
1295 (t (error "Wrong `tramp-syntax' defined")))
1296 "*String matching right hand side of IPv6 addresses.
1297Used in `tramp-make-tramp-file-name'.")
1298
1299(defconst tramp-postfix-ipv6-regexp
1300 (regexp-quote tramp-postfix-ipv6-format)
1301 "*Regexp matching right hand side of IPv6 addresses.
1302Derived from `tramp-postfix-ipv6-format'.")
1303
00d6fd04
MA
1304(defconst tramp-prefix-port-format
1305 (cond ((equal tramp-syntax 'ftp) "#")
1306 ((equal tramp-syntax 'sep) "#")
1307 ((equal tramp-syntax 'url) ":")
1308 (t (error "Wrong `tramp-syntax' defined")))
1309 "*String matching delimeter between host names and port numbers.")
1310
1311(defconst tramp-prefix-port-regexp
1312 (regexp-quote tramp-prefix-port-format)
1313 "*Regexp matching delimeter between host names and port numbers.
1314Derived from `tramp-prefix-port-format'.")
1315
1316(defconst tramp-port-regexp
1317 "[0-9]+"
1318 "*Regexp matching port numbers.")
1319
1320(defconst tramp-host-with-port-regexp
1321 (concat "\\(" tramp-host-regexp "\\)"
1322 tramp-prefix-port-regexp
1323 "\\(" tramp-port-regexp "\\)")
1324 "*Regexp matching host names with port numbers.")
1325
1326(defconst tramp-postfix-host-format
1327 (cond ((equal tramp-syntax 'ftp) ":")
1328 ((equal tramp-syntax 'sep) "]")
1329 ((equal tramp-syntax 'url) "")
1330 (t (error "Wrong `tramp-syntax' defined")))
7432277c 1331 "*String matching delimeter between host names and localnames.
00d6fd04 1332Used in `tramp-make-tramp-file-name'.")
16674e4f 1333
00d6fd04 1334(defconst tramp-postfix-host-regexp
16674e4f 1335 (regexp-quote tramp-postfix-host-format)
7432277c 1336 "*Regexp matching delimeter between host names and localnames.
00d6fd04 1337Derived from `tramp-postfix-host-format'.")
16674e4f 1338
00d6fd04 1339(defconst tramp-localname-regexp
16674e4f 1340 ".*$"
00d6fd04 1341 "*Regexp matching localnames.")
16674e4f
KG
1342
1343;; File name format.
505edaeb 1344
00d6fd04 1345(defconst tramp-file-name-structure
16674e4f
KG
1346 (list
1347 (concat
1348 tramp-prefix-regexp
00d6fd04
MA
1349 "\\(" "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp "\\)?"
1350 "\\(" "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp "\\)?"
b96e6899
MA
1351 "\\(" "\\(" tramp-host-regexp
1352 "\\|"
1353 tramp-prefix-ipv6-regexp tramp-ipv6-regexp
1354 tramp-postfix-ipv6-regexp "\\)"
1355 "\\(" tramp-prefix-port-regexp tramp-port-regexp "\\)?" "\\)?"
00d6fd04
MA
1356 tramp-postfix-host-regexp
1357 "\\(" tramp-localname-regexp "\\)")
b96e6899 1358 2 4 5 8)
16674e4f 1359
fb7933a3 1360 "*List of five elements (REGEXP METHOD USER HOST FILE), detailing \
a4aeb9a4 1361the Tramp file name structure.
fb7933a3 1362
a4aeb9a4 1363The first element REGEXP is a regular expression matching a Tramp file
fb7933a3
KG
1364name. The regex should contain parentheses around the method name,
1365the user name, the host name, and the file name parts.
1366
1367The second element METHOD is a number, saying which pair of
1368parentheses matches the method name. The third element USER is
1369similar, but for the user name. The fourth element HOST is similar,
1370but for the host name. The fifth element FILE is for the file name.
1371These numbers are passed directly to `match-string', which see. That
1372means the opening parentheses are counted to identify the pair.
1373
00d6fd04 1374See also `tramp-file-name-regexp'.")
fb7933a3
KG
1375
1376;;;###autoload
505edaeb 1377(defconst tramp-file-name-regexp-unified
b96e6899 1378 "\\`/\\([^[/:]+\\|[^/]+]\\):"
505edaeb
KG
1379 "Value for `tramp-file-name-regexp' for unified remoting.
1380Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and
00d6fd04 1381Tramp. See `tramp-file-name-structure' for more explanations.")
505edaeb
KG
1382
1383;;;###autoload
1384(defconst tramp-file-name-regexp-separate
1385 "\\`/\\[.*\\]"
1386 "Value for `tramp-file-name-regexp' for separate remoting.
1387XEmacs uses a separate filename syntax for Tramp and EFS.
00d6fd04 1388See `tramp-file-name-structure' for more explanations.")
505edaeb
KG
1389
1390;;;###autoload
00d6fd04
MA
1391(defconst tramp-file-name-regexp-url
1392 "\\`/[^/:]+://"
1393 "Value for `tramp-file-name-regexp' for URL-like remoting.
1394See `tramp-file-name-structure' for more explanations.")
1395
1396;;;###autoload
1397(defconst tramp-file-name-regexp
1398 (cond ((equal tramp-syntax 'ftp) tramp-file-name-regexp-unified)
1399 ((equal tramp-syntax 'sep) tramp-file-name-regexp-separate)
1400 ((equal tramp-syntax 'url) tramp-file-name-regexp-url)
1401 (t (error "Wrong `tramp-syntax' defined")))
94be87e8 1402 "*Regular expression matching file names handled by Tramp.
a4aeb9a4 1403This regexp should match Tramp file names but no other file names.
fb7933a3
KG
1404\(When tramp.el is loaded, this regular expression is prepended to
1405`file-name-handler-alist', and that is searched sequentially. Thus,
a4aeb9a4
MA
1406if the Tramp entry appears rather early in the `file-name-handler-alist'
1407and is a bit too general, then some files might be considered Tramp
00d6fd04 1408files which are not really Tramp files.
fb7933a3
KG
1409
1410Please note that the entry in `file-name-handler-alist' is made when
1411this file (tramp.el) is loaded. This means that this variable must be set
1412before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1413updated after changing this variable.
1414
00d6fd04 1415Also see `tramp-file-name-structure'.")
fb7933a3 1416
16674e4f 1417;;;###autoload
8a798e41 1418(defconst tramp-root-regexp
00d6fd04 1419 (if (memq system-type '(cygwin windows-nt))
aa485f7c
MA
1420 "\\`\\([a-zA-Z]:\\)?/"
1421 "\\`/")
8a798e41 1422 "Beginning of an incomplete Tramp file name.
aa485f7c 1423Usually, it is just \"\\\\`/\". On W32 systems, there might be a
57671b72 1424volume letter, which will be removed by `tramp-drop-volume-letter'.")
8a798e41
MA
1425
1426;;;###autoload
1427(defconst tramp-completion-file-name-regexp-unified
aa485f7c 1428 (concat tramp-root-regexp "[^/]*\\'")
16674e4f 1429 "Value for `tramp-completion-file-name-regexp' for unified remoting.
8a798e41
MA
1430GNU Emacs uses a unified filename syntax for Tramp and Ange-FTP.
1431See `tramp-file-name-structure' for more explanations.")
fb7933a3 1432
16674e4f
KG
1433;;;###autoload
1434(defconst tramp-completion-file-name-regexp-separate
aa485f7c 1435 (concat tramp-root-regexp "\\([[][^]]*\\)?\\'")
16674e4f
KG
1436 "Value for `tramp-completion-file-name-regexp' for separate remoting.
1437XEmacs uses a separate filename syntax for Tramp and EFS.
00d6fd04 1438See `tramp-file-name-structure' for more explanations.")
fb7933a3 1439
16674e4f 1440;;;###autoload
00d6fd04 1441(defconst tramp-completion-file-name-regexp-url
aa485f7c 1442 (concat tramp-root-regexp "[^/:]+\\(:\\(/\\(/[^/]*\\)?\\)?\\)?\\'")
00d6fd04
MA
1443 "Value for `tramp-completion-file-name-regexp' for URL-like remoting.
1444See `tramp-file-name-structure' for more explanations.")
1445
1446;;;###autoload
1447(defconst tramp-completion-file-name-regexp
1448 (cond ((equal tramp-syntax 'ftp) tramp-completion-file-name-regexp-unified)
1449 ((equal tramp-syntax 'sep) tramp-completion-file-name-regexp-separate)
1450 ((equal tramp-syntax 'url) tramp-completion-file-name-regexp-url)
1451 (t (error "Wrong `tramp-syntax' defined")))
a4aeb9a4
MA
1452 "*Regular expression matching file names handled by Tramp completion.
1453This regexp should match partial Tramp file names only.
16674e4f
KG
1454
1455Please note that the entry in `file-name-handler-alist' is made when
1456this file (tramp.el) is loaded. This means that this variable must be set
1457before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1458updated after changing this variable.
1459
00d6fd04 1460Also see `tramp-file-name-structure'.")
fb7933a3 1461
00d6fd04
MA
1462(defconst tramp-actions-before-shell
1463 '((tramp-login-prompt-regexp tramp-action-login)
1464 (tramp-password-prompt-regexp tramp-action-password)
1465 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
ac474af1 1466 (shell-prompt-pattern tramp-action-succeed)
821e6e36 1467 (tramp-shell-prompt-pattern tramp-action-succeed)
3cdaec13 1468 (tramp-yesno-prompt-regexp tramp-action-yesno)
487f4fb7 1469 (tramp-yn-prompt-regexp tramp-action-yn)
19a87064
MA
1470 (tramp-terminal-prompt-regexp tramp-action-terminal)
1471 (tramp-process-alive-regexp tramp-action-process-alive))
ac474af1
KG
1472 "List of pattern/action pairs.
1473Whenever a pattern matches, the corresponding action is performed.
1474Each item looks like (PATTERN ACTION).
1475
1476The PATTERN should be a symbol, a variable. The value of this
1477variable gives the regular expression to search for. Note that the
1478regexp must match at the end of the buffer, \"\\'\" is implicitly
1479appended to it.
1480
1481The ACTION should also be a symbol, but a function. When the
00d6fd04 1482corresponding PATTERN matches, the ACTION function is called.")
ac474af1 1483
00d6fd04 1484(defconst tramp-actions-copy-out-of-band
38c65fca
KG
1485 '((tramp-password-prompt-regexp tramp-action-password)
1486 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
00d6fd04 1487 (tramp-copy-failed-regexp tramp-action-permission-denied)
19a87064 1488 (tramp-process-alive-regexp tramp-action-out-of-band))
38c65fca
KG
1489 "List of pattern/action pairs.
1490This list is used for copying/renaming with out-of-band methods.
90f8dc03 1491
00d6fd04
MA
1492See `tramp-actions-before-shell' for more info.")
1493
1494;; Chunked sending kludge. We set this to 500 for black-listed constellations
7432277c 1495;; known to have a bug in `process-send-string'; some ssh connections appear
7177e2a3
MA
1496;; to drop bytes when data is sent too quickly. There is also a connection
1497;; buffer local variable, which is computed depending on remote host properties
1498;; when `tramp-chunksize' is zero or nil.
7432277c
KG
1499(defcustom tramp-chunksize
1500 (when (and (not (featurep 'xemacs))
1501 (memq system-type '(hpux)))
1502 500)
55880756
MA
1503;; Parentheses in docstring starting at beginning of line are escaped.
1504;; Fontification is messed up when
1505;; `open-paren-in-column-0-is-defun-start' set to t.
7432277c
KG
1506 "*If non-nil, chunksize for sending input to local process.
1507It is necessary only on systems which have a buggy `process-send-string'
1508implementation. The necessity, whether this variable must be set, can be
1509checked via the following code:
1510
1511 (with-temp-buffer
11948172
MA
1512 (let* ((user \"xxx\") (host \"yyy\")
1513 (init 0) (step 50)
1514 (sent init) (received init))
1515 (while (= sent received)
1516 (setq sent (+ sent step))
1517 (erase-buffer)
1518 (let ((proc (start-process (buffer-name) (current-buffer)
1519 \"ssh\" \"-l\" user host \"wc\" \"-c\")))
1520 (when (memq (process-status proc) '(run open))
1521 (process-send-string proc (make-string sent ?\\ ))
1522 (process-send-eof proc)
1523 (process-send-eof proc))
1524 (while (not (progn (goto-char (point-min))
1525 (re-search-forward \"\\\\w+\" (point-max) t)))
1526 (accept-process-output proc 1))
1527 (when (memq (process-status proc) '(run open))
1528 (setq received (string-to-number (match-string 0)))
1529 (delete-process proc)
1530 (message \"Bytes sent: %s\\tBytes received: %s\" sent received)
1531 (sit-for 0))))
1532 (if (> sent (+ init step))
1533 (message \"You should set `tramp-chunksize' to a maximum of %s\"
1534 (- sent step))
1535 (message \"Test does not work\")
1536 (display-buffer (current-buffer))
1537 (sit-for 30))))
1538
1539In the Emacs normally running Tramp, evaluate the above code
55880756 1540\(replace \"xxx\" and \"yyy\" by the remote user and host name,
11948172
MA
1541respectively). You can do this, for example, by pasting it into
1542the `*scratch*' buffer and then hitting C-j with the cursor after the
1543last closing parenthesis. Note that it works only if you have configured
1544\"ssh\" to run without password query, see ssh-agent(1).
1545
1546You will see the number of bytes sent successfully to the remote host.
1547If that number exceeds 1000, you can stop the execution by hitting
1548C-g, because your Emacs is likely clean.
1549
11948172
MA
1550When it is necessary to set `tramp-chunksize', you might consider to
1551use an out-of-the-band method (like \"scp\") instead of an internal one
55880756 1552\(like \"ssh\"), because setting `tramp-chunksize' to non-nil decreases
11948172 1553performance.
c951aecb 1554
00d6fd04
MA
1555If your Emacs is buggy, the code stops and gives you an indication
1556about the value `tramp-chunksize' should be set. Maybe you could just
1557experiment a bit, e.g. changing the values of `init' and `step'
1558in the third line of the code.
1559
7432277c
KG
1560Please raise a bug report via \"M-x tramp-bug\" if your system needs
1561this variable to be set as well."
1562 :group 'tramp
b1a2b924 1563 :type '(choice (const nil) integer))
7432277c 1564
5ec2cc41
KG
1565;; Logging in to a remote host normally requires obtaining a pty. But
1566;; Emacs on MacOS X has process-connection-type set to nil by default,
1567;; so on those systems Tramp doesn't obtain a pty. Here, we allow
1568;; for an override of the system default.
1569(defcustom tramp-process-connection-type t
1570 "Overrides `process-connection-type' for connections from Tramp.
1571Tramp binds process-connection-type to the value given here before
1572opening a connection to a remote host."
1573 :group 'tramp
1574 :type '(choice (const nil) (const t) (const pty)))
1575
b50dd0d2
MA
1576(defcustom tramp-completion-reread-directory-timeout 10
1577 "Defines seconds since last remote command before rereading a directory.
1578A remote directory might have changed its contents. In order to
1579make it visible during file name completion in the minibuffer,
1580Tramp flushes its cache and rereads the directory contents when
1581more than `tramp-completion-reread-directory-timeout' seconds
1582have been gone since last remote command execution. A value of 0
1583would require an immediate reread during filename completion, nil
1584means to use always cached values for the directory contents."
1585 :group 'tramp
1586 :type '(choice (const nil) integer))
1587
fb7933a3
KG
1588;;; Internal Variables:
1589
4007ba5b 1590(defvar tramp-end-of-output
a0a5183a 1591 (format
70c11b0b
MA
1592 "///%s$"
1593 (md5 (concat (prin1-to-string process-environment) (current-time-string))))
1594 "String used to recognize end of output.
1595The '$' character at the end is quoted; the string cannot be
1596detected as prompt when being sent on echoing hosts, therefore.")
fb7933a3 1597
fb7933a3 1598(defvar tramp-current-method nil
00d6fd04 1599 "Connection method for this *tramp* buffer.")
fb7933a3
KG
1600
1601(defvar tramp-current-user nil
00d6fd04 1602 "Remote login name for this *tramp* buffer.")
fb7933a3
KG
1603
1604(defvar tramp-current-host nil
00d6fd04
MA
1605 "Remote host for this *tramp* buffer.")
1606
1607(defconst tramp-uudecode
1608 "(echo begin 600 /tmp/tramp.$$; tail +2) | uudecode
fabf2143 1609cat /tmp/tramp.$$
00d6fd04 1610rm -f /tmp/tramp.$$"
fabf2143 1611 "Shell function to implement `uudecode' to standard output.
c08e6004
MA
1612Many systems support `uudecode -o /dev/stdout' or `uudecode -o -'
1613for this or `uudecode -p', but some systems don't, and for them
1614we have this shell function.")
fabf2143 1615
293c24f9
MA
1616(defconst tramp-perl-file-truename
1617 "%s -e '
1618use File::Spec;
1619use Cwd \"realpath\";
1620
1621sub recursive {
1622 my ($volume, @dirs) = @_;
1623 my $real = realpath(File::Spec->catpath(
1624 $volume, File::Spec->catdir(@dirs), \"\"));
1625 if ($real) {
1626 my ($vol, $dir) = File::Spec->splitpath($real, 1);
1627 return ($vol, File::Spec->splitdir($dir));
1628 }
1629 else {
1630 my $last = pop(@dirs);
1631 ($volume, @dirs) = recursive($volume, @dirs);
1632 push(@dirs, $last);
1633 return ($volume, @dirs);
1634 }
1635}
1636
1637$result = realpath($ARGV[0]);
1638if (!$result) {
1639 my ($vol, $dir) = File::Spec->splitpath($ARGV[0], 1);
1640 ($vol, @dirs) = recursive($vol, File::Spec->splitdir($dir));
1641
1642 $result = File::Spec->catpath($vol, File::Spec->catdir(@dirs), \"\");
1643}
1644
1645if ($ARGV[0] =~ /\\/$/) {
1646 $result = $result . \"/\";
1647}
1648
1649print \"\\\"$result\\\"\\n\";
1650' \"$1\" 2>/dev/null"
1651 "Perl script to produce output suitable for use with `file-truename'
1652on the remote file system.
1653Escape sequence %s is replaced with name of Perl binary.
1654This string is passed to `format', so percent characters need to be doubled.")
1655
1656(defconst tramp-perl-file-name-all-completions
1657 "%s -e 'sub case {
1658 my $str = shift;
1659 if ($ARGV[2]) {
1660 return lc($str);
1661 }
1662 else {
1663 return $str;
1664 }
1665}
1666opendir(d, $ARGV[0]) || die(\"$ARGV[0]: $!\\nfail\\n\");
1667@files = readdir(d); closedir(d);
1668foreach $f (@files) {
1669 if (case(substr($f, 0, length($ARGV[1]))) eq case($ARGV[1])) {
1670 if (-d \"$ARGV[0]/$f\") {
1671 print \"$f/\\n\";
1672 }
1673 else {
1674 print \"$f\\n\";
1675 }
1676 }
1677}
1678print \"ok\\n\"
1679' \"$1\" \"$2\" \"$3\" 2>/dev/null"
1680 "Perl script to produce output suitable for use with
1681`file-name-all-completions' on the remote file system. Escape
1682sequence %s is replaced with name of Perl binary. This string is
1683passed to `format', so percent characters need to be doubled.")
1684
fabf2143
KG
1685;; Perl script to implement `file-attributes' in a Lisp `read'able
1686;; output. If you are hacking on this, note that you get *no* output
1687;; unless this spits out a complete line, including the '\n' at the
1688;; end.
8daea7fc 1689;; The device number is returned as "-1", because there will be a virtual
b946a456 1690;; device number set in `tramp-handle-file-attributes'.
00d6fd04
MA
1691(defconst tramp-perl-file-attributes
1692 "%s -e '
c82c5727 1693@stat = lstat($ARGV[0]);
680db9ac
MA
1694if (!@stat) {
1695 print \"nil\\n\";
1696 exit 0;
1697}
c82c5727
LH
1698if (($stat[2] & 0170000) == 0120000)
1699{
1700 $type = readlink($ARGV[0]);
1701 $type = \"\\\"$type\\\"\";
1702}
1703elsif (($stat[2] & 0170000) == 040000)
1704{
1705 $type = \"t\";
1706}
1707else
1708{
1709 $type = \"nil\"
1710};
1711$uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
1712$gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
1713printf(
d4443a0d 1714 \"(%%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) -1)\\n\",
c82c5727
LH
1715 $type,
1716 $stat[3],
1717 $uid,
1718 $gid,
1719 $stat[8] >> 16 & 0xffff,
1720 $stat[8] & 0xffff,
1721 $stat[9] >> 16 & 0xffff,
1722 $stat[9] & 0xffff,
1723 $stat[10] >> 16 & 0xffff,
1724 $stat[10] & 0xffff,
1725 $stat[7],
1726 $stat[2],
1727 $stat[1] >> 16 & 0xffff,
1728 $stat[1] & 0xffff
00d6fd04 1729);' \"$1\" \"$2\" \"$3\" 2>/dev/null"
fb7933a3 1730 "Perl script to produce output suitable for use with `file-attributes'
00d6fd04
MA
1731on the remote file system.
1732Escape sequence %s is replaced with name of Perl binary.
1733This string is passed to `format', so percent characters need to be doubled.")
fb7933a3 1734
00d6fd04
MA
1735(defconst tramp-perl-directory-files-and-attributes
1736 "%s -e '
8cb0a559
LH
1737chdir($ARGV[0]) or printf(\"\\\"Cannot change to $ARGV[0]: $''!''\\\"\\n\"), exit();
1738opendir(DIR,\".\") or printf(\"\\\"Cannot open directory $ARGV[0]: $''!''\\\"\\n\"), exit();
c82c5727
LH
1739@list = readdir(DIR);
1740closedir(DIR);
1741$n = scalar(@list);
1742printf(\"(\\n\");
1743for($i = 0; $i < $n; $i++)
1744{
1745 $filename = $list[$i];
1746 @stat = lstat($filename);
1747 if (($stat[2] & 0170000) == 0120000)
1748 {
1749 $type = readlink($filename);
1750 $type = \"\\\"$type\\\"\";
1751 }
1752 elsif (($stat[2] & 0170000) == 040000)
1753 {
1754 $type = \"t\";
1755 }
1756 else
1757 {
1758 $type = \"nil\"
1759 };
1760 $uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
1761 $gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
1762 printf(
b946a456 1763 \"(\\\"%%s\\\" %%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) (%%u . %%u))\\n\",
c82c5727
LH
1764 $filename,
1765 $type,
1766 $stat[3],
1767 $uid,
1768 $gid,
1769 $stat[8] >> 16 & 0xffff,
1770 $stat[8] & 0xffff,
1771 $stat[9] >> 16 & 0xffff,
1772 $stat[9] & 0xffff,
1773 $stat[10] >> 16 & 0xffff,
1774 $stat[10] & 0xffff,
1775 $stat[7],
1776 $stat[2],
1777 $stat[1] >> 16 & 0xffff,
1778 $stat[1] & 0xffff,
1779 $stat[0] >> 16 & 0xffff,
1780 $stat[0] & 0xffff);
1781}
00d6fd04 1782printf(\")\\n\");' \"$1\" \"$2\" \"$3\" 2>/dev/null"
c82c5727 1783 "Perl script implementing `directory-files-attributes' as Lisp `read'able
00d6fd04
MA
1784output.
1785Escape sequence %s is replaced with name of Perl binary.
1786This string is passed to `format', so percent characters need to be doubled.")
c82c5727 1787
ac474af1
KG
1788;; ;; These two use uu encoding.
1789;; (defvar tramp-perl-encode "%s -e'\
1790;; print qq(begin 644 xxx\n);
1791;; my $s = q();
1792;; my $res = q();
1793;; while (read(STDIN, $s, 45)) {
1794;; print pack(q(u), $s);
1795;; }
1796;; print qq(`\n);
1797;; print qq(end\n);
1798;; '"
1799;; "Perl program to use for encoding a file.
1800;; Escape sequence %s is replaced with name of Perl binary.")
1801
1802;; (defvar tramp-perl-decode "%s -ne '
1803;; print unpack q(u), $_;
1804;; '"
1805;; "Perl program to use for decoding a file.
1806;; Escape sequence %s is replaced with name of Perl binary.")
1807
1808;; These two use base64 encoding.
00d6fd04
MA
1809(defconst tramp-perl-encode-with-module
1810 "%s -MMIME::Base64 -0777 -ne 'print encode_base64($_)' 2>/dev/null"
ac474af1 1811 "Perl program to use for encoding a file.
b1d06e75 1812Escape sequence %s is replaced with name of Perl binary.
89509ea0 1813This string is passed to `format', so percent characters need to be doubled.
b1d06e75
KG
1814This implementation requires the MIME::Base64 Perl module to be installed
1815on the remote host.")
1816
00d6fd04
MA
1817(defconst tramp-perl-decode-with-module
1818 "%s -MMIME::Base64 -0777 -ne 'print decode_base64($_)' 2>/dev/null"
b1d06e75
KG
1819 "Perl program to use for decoding a file.
1820Escape sequence %s is replaced with name of Perl binary.
89509ea0 1821This string is passed to `format', so percent characters need to be doubled.
b1d06e75
KG
1822This implementation requires the MIME::Base64 Perl module to be installed
1823on the remote host.")
1824
00d6fd04 1825(defconst tramp-perl-encode
b1d06e75
KG
1826 "%s -e '
1827# This script contributed by Juanma Barranquero <lektu@terra.es>.
46932a8d 1828# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
cbd12ed7 1829# Free Software Foundation, Inc.
b1d06e75
KG
1830use strict;
1831
fa32e96a 1832my %%trans = do {
b1d06e75
KG
1833 my $i = 0;
1834 map {(substr(unpack(q(B8), chr $i++), 2, 6), $_)}
1835 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/);
1836};
1837
36541701 1838binmode(\\*STDIN);
b1d06e75
KG
1839
1840# We read in chunks of 54 bytes, to generate output lines
1841# of 72 chars (plus end of line)
36541701 1842$/ = \\54;
b1d06e75
KG
1843
1844while (my $data = <STDIN>) {
1845 my $pad = q();
1846
1847 # Only for the last chunk, and only if did not fill the last three-byte packet
1848 if (eof) {
fa32e96a 1849 my $mod = length($data) %% 3;
b1d06e75
KG
1850 $pad = q(=) x (3 - $mod) if $mod;
1851 }
1852
1853 # Not the fastest method, but it is simple: unpack to binary string, split
1854 # by groups of 6 bits and convert back from binary to byte; then map into
1855 # the translation table
1856 print
1857 join q(),
1858 map($trans{$_},
1859 (substr(unpack(q(B*), $data) . q(00000), 0, 432) =~ /....../g)),
1860 $pad,
36541701 1861 qq(\\n);
00d6fd04 1862}' 2>/dev/null"
b1d06e75 1863 "Perl program to use for encoding a file.
fa32e96a 1864Escape sequence %s is replaced with name of Perl binary.
ccf29586 1865This string is passed to `format', so percent characters need to be doubled.")
ac474af1 1866
00d6fd04 1867(defconst tramp-perl-decode
b1d06e75
KG
1868 "%s -e '
1869# This script contributed by Juanma Barranquero <lektu@terra.es>.
46932a8d 1870# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
cbd12ed7 1871# Free Software Foundation, Inc.
b1d06e75
KG
1872use strict;
1873
fa32e96a 1874my %%trans = do {
b1d06e75 1875 my $i = 0;
16674e4f 1876 map {($_, substr(unpack(q(B8), chr $i++), 2, 6))}
b1d06e75
KG
1877 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/)
1878};
1879
fa32e96a 1880my %%bytes = map {(unpack(q(B8), chr $_), chr $_)} 0 .. 255;
b1d06e75 1881
36541701 1882binmode(\\*STDOUT);
b1d06e75
KG
1883
1884# We are going to accumulate into $pending to accept any line length
1885# (we do not check they are <= 76 chars as the RFC says)
1886my $pending = q();
1887
1888while (my $data = <STDIN>) {
1889 chomp $data;
1890
1891 # If we find one or two =, we have reached the end and
1892 # any following data is to be discarded
1893 my $finished = $data =~ s/(==?).*/$1/;
1894 $pending .= $data;
1895
1896 my $len = length($pending);
16674e4f 1897 my $chunk = substr($pending, 0, $len & ~3);
414da5ab 1898 $pending = substr($pending, $len & ~3 + 1);
b1d06e75
KG
1899
1900 # Easy method: translate from chars to (pregenerated) six-bit packets, join,
1901 # split in 8-bit chunks and convert back to char.
1902 print join q(),
1903 map $bytes{$_},
1904 ((join q(), map {$trans{$_} || q()} split //, $chunk) =~ /......../g);
1905
1906 last if $finished;
00d6fd04 1907}' 2>/dev/null"
ac474af1 1908 "Perl program to use for decoding a file.
fa32e96a 1909Escape sequence %s is replaced with name of Perl binary.
ccf29586 1910This string is passed to `format', so percent characters need to be doubled.")
fb7933a3 1911
946a5aeb
MA
1912(defconst tramp-vc-registered-read-file-names
1913 "echo \"(\"
1914for file in \"$@\"; do
1915 if %s $file; then
1916 echo \"(\\\"$file\\\" \\\"file-exists-p\\\" t)\"
1917 else
1918 echo \"(\\\"$file\\\" \\\"file-exists-p\\\" nil)\"
1919 fi
1920 if %s $file; then
1921 echo \"(\\\"$file\\\" \\\"file-readable-p\\\" t)\"
1922 else
1923 echo \"(\\\"$file\\\" \\\"file-readable-p\\\" nil)\"
1924 fi
1925done
1926echo \")\""
1927 "Script to check existence of VC related files.
1928It must be send formatted with two strings; the tests for file
1929existence, and file readability.")
1930
9ce8462a
MA
1931(defconst tramp-file-mode-type-map
1932 '((0 . "-") ; Normal file (SVID-v2 and XPG2)
1933 (1 . "p") ; fifo
1934 (2 . "c") ; character device
1935 (3 . "m") ; multiplexed character device (v7)
1936 (4 . "d") ; directory
1937 (5 . "?") ; Named special file (XENIX)
1938 (6 . "b") ; block device
1939 (7 . "?") ; multiplexed block device (v7)
1940 (8 . "-") ; regular file
1941 (9 . "n") ; network special file (HP-UX)
1942 (10 . "l") ; symlink
1943 (11 . "?") ; ACL shadow inode (Solaris, not userspace)
1944 (12 . "s") ; socket
1945 (13 . "D") ; door special (Solaris)
1946 (14 . "w")) ; whiteout (BSD)
fb7933a3
KG
1947 "A list of file types returned from the `stat' system call.
1948This is used to map a mode number to a permission string.")
1949
fb7933a3 1950;; New handlers should be added here. The following operations can be
c0fc6170
MA
1951;; handled using the normal primitives: file-name-sans-versions,
1952;; get-file-buffer.
fb7933a3 1953(defconst tramp-file-name-handler-alist
00d6fd04 1954 '((load . tramp-handle-load)
fb7933a3 1955 (make-symbolic-link . tramp-handle-make-symbolic-link)
c0fc6170 1956 (file-name-as-directory . tramp-handle-file-name-as-directory)
fb7933a3
KG
1957 (file-name-directory . tramp-handle-file-name-directory)
1958 (file-name-nondirectory . tramp-handle-file-name-nondirectory)
1959 (file-truename . tramp-handle-file-truename)
1960 (file-exists-p . tramp-handle-file-exists-p)
1961 (file-directory-p . tramp-handle-file-directory-p)
1962 (file-executable-p . tramp-handle-file-executable-p)
fb7933a3
KG
1963 (file-readable-p . tramp-handle-file-readable-p)
1964 (file-regular-p . tramp-handle-file-regular-p)
1965 (file-symlink-p . tramp-handle-file-symlink-p)
1966 (file-writable-p . tramp-handle-file-writable-p)
1967 (file-ownership-preserved-p . tramp-handle-file-ownership-preserved-p)
1968 (file-newer-than-file-p . tramp-handle-file-newer-than-file-p)
1969 (file-attributes . tramp-handle-file-attributes)
1970 (file-modes . tramp-handle-file-modes)
fb7933a3 1971 (directory-files . tramp-handle-directory-files)
c82c5727 1972 (directory-files-and-attributes . tramp-handle-directory-files-and-attributes)
fb7933a3
KG
1973 (file-name-all-completions . tramp-handle-file-name-all-completions)
1974 (file-name-completion . tramp-handle-file-name-completion)
1975 (add-name-to-file . tramp-handle-add-name-to-file)
1976 (copy-file . tramp-handle-copy-file)
263c02ef 1977 (copy-directory . tramp-handle-copy-directory)
fb7933a3
KG
1978 (rename-file . tramp-handle-rename-file)
1979 (set-file-modes . tramp-handle-set-file-modes)
ce3f516f 1980 (set-file-times . tramp-handle-set-file-times)
fb7933a3
KG
1981 (make-directory . tramp-handle-make-directory)
1982 (delete-directory . tramp-handle-delete-directory)
1983 (delete-file . tramp-handle-delete-file)
1984 (directory-file-name . tramp-handle-directory-file-name)
00d6fd04
MA
1985 ;; `executable-find' is not official yet.
1986 (executable-find . tramp-handle-executable-find)
1987 (start-file-process . tramp-handle-start-file-process)
0457dd55 1988 (process-file . tramp-handle-process-file)
00d6fd04 1989 (shell-command . tramp-handle-shell-command)
fb7933a3
KG
1990 (insert-directory . tramp-handle-insert-directory)
1991 (expand-file-name . tramp-handle-expand-file-name)
00d6fd04 1992 (substitute-in-file-name . tramp-handle-substitute-in-file-name)
fb7933a3 1993 (file-local-copy . tramp-handle-file-local-copy)
19a87064 1994 (file-remote-p . tramp-handle-file-remote-p)
fb7933a3 1995 (insert-file-contents . tramp-handle-insert-file-contents)
94be87e8
MA
1996 (insert-file-contents-literally
1997 . tramp-handle-insert-file-contents-literally)
fb7933a3 1998 (write-region . tramp-handle-write-region)
38c65fca 1999 (find-backup-file-name . tramp-handle-find-backup-file-name)
c1105d05 2000 (make-auto-save-file-name . tramp-handle-make-auto-save-file-name)
fb7933a3 2001 (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
5ec2cc41 2002 (dired-compress-file . tramp-handle-dired-compress-file)
fb7933a3
KG
2003 (dired-recursive-delete-directory
2004 . tramp-handle-dired-recursive-delete-directory)
70c11b0b 2005 (dired-uncache . tramp-handle-dired-uncache)
fb7933a3 2006 (set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
49096407
MA
2007 (verify-visited-file-modtime . tramp-handle-verify-visited-file-modtime)
2008 (vc-registered . tramp-handle-vc-registered))
c1105d05 2009 "Alist of handler functions.
fb7933a3
KG
2010Operations not mentioned here will be handled by the normal Emacs functions.")
2011
a4aeb9a4 2012;; Handlers for partial Tramp file names. For Emacs just
41c8e348 2013;; `file-name-all-completions' is needed.
a01b1e22 2014;;;###autoload
16674e4f 2015(defconst tramp-completion-file-name-handler-alist
a01b1e22 2016 '((file-name-all-completions . tramp-completion-handle-file-name-all-completions)
41c8e348 2017 (file-name-completion . tramp-completion-handle-file-name-completion))
16674e4f
KG
2018 "Alist of completion handler functions.
2019Used for file names matching `tramp-file-name-regexp'. Operations not
2020mentioned here will be handled by `tramp-file-name-handler-alist' or the
2021normal Emacs functions.")
2022
4007ba5b 2023;; Handlers for foreign methods, like FTP or SMB, shall be plugged here.
ea9d1443
KG
2024(defvar tramp-foreign-file-name-handler-alist
2025 ;; (identity . tramp-sh-file-name-handler) should always be the last
b88f2d0a 2026 ;; entry, because `identity' always matches.
ea9d1443 2027 '((identity . tramp-sh-file-name-handler))
4007ba5b
KG
2028 "Alist of elements (FUNCTION . HANDLER) for foreign methods handled specially.
2029If (FUNCTION FILENAME) returns non-nil, then all I/O on that file is done by
2030calling HANDLER.")
2031
0664ff72 2032;;; Internal functions which must come first:
fb7933a3 2033
00d6fd04
MA
2034(defsubst tramp-debug-message (vec fmt-string &rest args)
2035 "Append message to debug buffer.
2036Message is formatted with FMT-STRING as control string and the remaining
2037ARGS to actually emit the message (if applicable)."
2038 (when (get-buffer (tramp-buffer-name vec))
2039 (with-current-buffer (tramp-get-debug-buffer vec)
2040 (goto-char (point-max))
70c11b0b
MA
2041 ;; Headline.
2042 (when (bobp)
2043 (insert
2044 (format
2045 ";; %sEmacs: %s Tramp: %s -*- mode: outline; -*-"
2046 (if (featurep 'sxemacs) "SX" (if (featurep 'xemacs) "X" "GNU "))
2047 emacs-version tramp-version)))
00d6fd04
MA
2048 (unless (bolp)
2049 (insert "\n"))
70c11b0b 2050 ;; Timestamp.
736ac90f
MA
2051 (let ((now (current-time)))
2052 (insert (format-time-string "%T." now))
2053 (insert (format "%06d " (nth 2 now))))
70c11b0b 2054 ;; Calling function.
00d6fd04
MA
2055 (let ((btn 1) btf fn)
2056 (while (not fn)
2057 (setq btf (nth 1 (backtrace-frame btn)))
2058 (if (not btf)
2059 (setq fn "")
2060 (when (symbolp btf)
2061 (setq fn (symbol-name btf))
2062 (unless (and (string-match "^tramp" fn)
2063 (not (string-match
2064 "^tramp\\(-debug\\)?\\(-message\\|-error\\)$"
2065 fn)))
2066 (setq fn nil)))
2067 (setq btn (1+ btn))))
2068 ;; The following code inserts filename and line number.
2069 ;; Should be deactivated by default, because it is time
2070 ;; consuming.
2071; (let ((ffn (find-function-noselect (intern fn))))
2072; (insert
2073; (format
2074; "%s:%d: "
2075; (file-name-nondirectory (buffer-file-name (car ffn)))
2076; (with-current-buffer (car ffn)
2077; (1+ (count-lines (point-min) (cdr ffn)))))))
2078 (insert (format "%s " fn)))
70c11b0b 2079 ;; The message.
00d6fd04
MA
2080 (insert (apply 'format fmt-string args)))))
2081
946a5aeb
MA
2082(defvar tramp-message-show-message t
2083 "Show Tramp message in the minibuffer.
2084This variable is used to disable messages from `tramp-error'.
2085The messages are visible anyway, because an error is raised.")
2086
00d6fd04 2087(defsubst tramp-message (vec-or-proc level fmt-string &rest args)
fb7933a3 2088 "Emit a message depending on verbosity level.
a4aeb9a4 2089VEC-OR-PROC identifies the Tramp buffer to use. It can be either a
00d6fd04
MA
2090vector or a process. LEVEL says to be quiet if `tramp-verbose' is
2091less than LEVEL. The message is emitted only if `tramp-verbose' is
2092greater than or equal to LEVEL.
2093
2094The message is also logged into the debug buffer when `tramp-verbose'
2095is greater than or equal 4.
2096
2097Calls functions `message' and `tramp-debug-message' with FMT-STRING as
2098control string and the remaining ARGS to actually emit the message (if
2099applicable)."
2100 (condition-case nil
2101 (when (<= level tramp-verbose)
2102 ;; Match data must be preserved!
2103 (save-match-data
2104 ;; Display only when there is a minimum level.
946a5aeb 2105 (when (and tramp-message-show-message (<= level 3))
00d6fd04
MA
2106 (apply 'message
2107 (concat
2108 (cond
2109 ((= level 0) "")
2110 ((= level 1) "")
2111 ((= level 2) "Warning: ")
2112 (t "Tramp: "))
2113 fmt-string)
2114 args))
2115 ;; Log only when there is a minimum level.
2116 (when (>= tramp-verbose 4)
2117 (when (and vec-or-proc
2118 (processp vec-or-proc)
2119 (buffer-name (process-buffer vec-or-proc)))
2120 (with-current-buffer (process-buffer vec-or-proc)
2121 ;; Translate proc to vec.
2122 (setq vec-or-proc (tramp-dissect-file-name default-directory))))
2123 (when (and vec-or-proc (vectorp vec-or-proc))
2124 (apply 'tramp-debug-message
2125 vec-or-proc
2126 (concat (format "(%d) # " level) fmt-string)
2127 args)))))
2128 ;; Suppress all errors.
2129 (error nil)))
2130
2131(defsubst tramp-error (vec-or-proc signal fmt-string &rest args)
2132 "Emit an error.
2133VEC-OR-PROC identifies the connection to use, SIGNAL is the
2134signal identifier to be raised, remaining args passed to
2135`tramp-message'. Finally, signal SIGNAL is raised."
946a5aeb
MA
2136 (let (tramp-message-show-message)
2137 (tramp-message
2138 vec-or-proc 1 "%s"
2139 (error-message-string
2140 (list signal
2141 (get signal 'error-message)
2142 (apply 'format fmt-string args))))
2143 (signal signal (list (apply 'format fmt-string args)))))
00d6fd04
MA
2144
2145(defsubst tramp-error-with-buffer
2146 (buffer vec-or-proc signal fmt-string &rest args)
2147 "Emit an error, and show BUFFER.
2148If BUFFER is nil, show the connection buffer. Wait for 30\", or until
2149an input event arrives. The other arguments are passed to `tramp-error'."
2150 (save-window-excursion
2151 (unwind-protect
2152 (apply 'tramp-error vec-or-proc signal fmt-string args)
2153 (when (and vec-or-proc (not (zerop tramp-verbose)))
2154 (let ((enable-recursive-minibuffers t))
2155 (pop-to-buffer
2156 (or (and (bufferp buffer) buffer)
2157 (and (processp vec-or-proc) (process-buffer vec-or-proc))
2158 (tramp-get-buffer vec-or-proc)))
2159 (sit-for 30))))))
fb7933a3 2160
c62c9d08
KG
2161(defmacro with-parsed-tramp-file-name (filename var &rest body)
2162 "Parse a Tramp filename and make components available in the body.
2163
2164First arg FILENAME is evaluated and dissected into its components.
2165Second arg VAR is a symbol. It is used as a variable name to hold
2166the filename structure. It is also used as a prefix for the variables
2167holding the components. For example, if VAR is the symbol `foo', then
00d6fd04
MA
2168`foo' will be bound to the whole structure, `foo-method' will be bound to
2169the method component, and so on for `foo-user', `foo-host', `foo-localname'.
c62c9d08
KG
2170
2171Remaining args are Lisp expressions to be evaluated (inside an implicit
2172`progn').
2173
00d6fd04
MA
2174If VAR is nil, then we bind `v' to the structure and `method', `user',
2175`host', `localname' to the components."
c62c9d08 2176 `(let* ((,(or var 'v) (tramp-dissect-file-name ,filename))
c62c9d08
KG
2177 (,(if var (intern (concat (symbol-name var) "-method")) 'method)
2178 (tramp-file-name-method ,(or var 'v)))
2179 (,(if var (intern (concat (symbol-name var) "-user")) 'user)
2180 (tramp-file-name-user ,(or var 'v)))
2181 (,(if var (intern (concat (symbol-name var) "-host")) 'host)
2182 (tramp-file-name-host ,(or var 'v)))
7432277c
KG
2183 (,(if var (intern (concat (symbol-name var) "-localname")) 'localname)
2184 (tramp-file-name-localname ,(or var 'v))))
c62c9d08
KG
2185 ,@body))
2186
2187(put 'with-parsed-tramp-file-name 'lisp-indent-function 2)
00d6fd04 2188(put 'with-parsed-tramp-file-name 'edebug-form-spec '(form symbolp body))
9e6ab520 2189(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-parsed-tramp-file-name\\>"))
c62c9d08 2190
00d6fd04
MA
2191(defmacro with-file-property (vec file property &rest body)
2192 "Check in Tramp cache for PROPERTY, otherwise execute BODY and set cache.
2193FILE must be a local file name on a connection identified via VEC."
2194 `(if (file-name-absolute-p ,file)
2195 (let ((value (tramp-get-file-property ,vec ,file ,property 'undef)))
2196 (when (eq value 'undef)
2197 ;; We cannot pass @body as parameter to
2198 ;; `tramp-set-file-property' because it mangles our
2199 ;; debug messages.
2200 (setq value (progn ,@body))
2201 (tramp-set-file-property ,vec ,file ,property value))
2202 value)
2203 ,@body))
9ce8462a 2204
00d6fd04
MA
2205(put 'with-file-property 'lisp-indent-function 3)
2206(put 'with-file-property 'edebug-form-spec t)
9e6ab520 2207(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-file-property\\>"))
00d6fd04
MA
2208
2209(defmacro with-connection-property (key property &rest body)
2210 "Checks in Tramp for property PROPERTY, otherwise executes BODY and set."
2211 `(let ((value (tramp-get-connection-property ,key ,property 'undef)))
2212 (when (eq value 'undef)
2213 ;; We cannot pass ,@body as parameter to
2214 ;; `tramp-set-connection-property' because it mangles our debug
2215 ;; messages.
2216 (setq value (progn ,@body))
2217 (tramp-set-connection-property ,key ,property value))
2218 value))
9ce8462a 2219
00d6fd04
MA
2220(put 'with-connection-property 'lisp-indent-function 2)
2221(put 'with-connection-property 'edebug-form-spec t)
9e6ab520 2222(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-connection-property\\>"))
00d6fd04 2223
628c97b2
GM
2224(eval-and-compile ; silence compiler
2225 (if (memq system-type '(cygwin windows-nt))
2226 (defun tramp-drop-volume-letter (name)
2227 "Cut off unnecessary drive letter from file NAME.
2228The function `tramp-handle-expand-file-name' calls `expand-file-name'
2229locally on a remote file name. When the local system is a W32 system
2230but the remote system is Unix, this introduces a superfluous drive
2231letter into the file name. This function removes it."
2232 (save-match-data
2233 (if (string-match tramp-root-regexp name)
2234 (replace-match "/" nil t name)
2235 name)))
2236
2237 (defalias 'tramp-drop-volume-letter 'identity)))
2238
9c13938d 2239(defsubst tramp-make-tramp-temp-file (vec)
a6e96327 2240 "Create a temporary file on the remote host identified by VEC.
9c13938d
MA
2241Return the local name of the temporary file."
2242 (let ((prefix
2243 (tramp-make-tramp-file-name
2244 (tramp-file-name-method vec)
2245 (tramp-file-name-user vec)
2246 (tramp-file-name-host vec)
113e2a84
MA
2247 (tramp-drop-volume-letter
2248 (expand-file-name
2249 tramp-temp-name-prefix (tramp-get-remote-tmpdir vec)))))
9c13938d
MA
2250 result)
2251 (while (not result)
2252 ;; `make-temp-file' would be the natural choice for
2253 ;; implementation. But it calls `write-region' internally,
2254 ;; which also needs a temporary file - we would end in an
2255 ;; infinite loop.
2256 (setq result (make-temp-name prefix))
2257 (if (file-exists-p result)
2258 (setq result nil)
2259 ;; This creates the file by side effect.
2260 (set-file-times result)
2261 (set-file-modes result (tramp-octal-to-decimal "0700"))))
2262
2263 ;; Return the local part.
2264 (with-parsed-tramp-file-name result nil localname)))
8a4438b6
MA
2265
2266
16674e4f
KG
2267;;; Config Manipulation Functions:
2268
2269(defun tramp-set-completion-function (method function-list)
2270 "Sets the list of completion functions for METHOD.
2271FUNCTION-LIST is a list of entries of the form (FUNCTION FILE).
2272The FUNCTION is intended to parse FILE according its syntax.
2273It might be a predefined FUNCTION, or a user defined FUNCTION.
2274Predefined FUNCTIONs are `tramp-parse-rhosts', `tramp-parse-shosts',
8fc29035 2275`tramp-parse-sconfig', `tramp-parse-hosts', `tramp-parse-passwd',
8daea7fc
KG
2276and `tramp-parse-netrc'.
2277
16674e4f
KG
2278Example:
2279
2280 (tramp-set-completion-function
2281 \"ssh\"
8daea7fc
KG
2282 '((tramp-parse-sconfig \"/etc/ssh_config\")
2283 (tramp-parse-sconfig \"~/.ssh/config\")))"
16674e4f 2284
5ec2cc41
KG
2285 (let ((r function-list)
2286 (v function-list))
2287 (setq tramp-completion-function-alist
2288 (delete (assoc method tramp-completion-function-alist)
2289 tramp-completion-function-alist))
2290
2291 (while v
00d6fd04 2292 ;; Remove double entries.
5ec2cc41
KG
2293 (when (member (car v) (cdr v))
2294 (setcdr v (delete (car v) (cdr v))))
00d6fd04 2295 ;; Check for function and file or registry key.
5ec2cc41 2296 (unless (and (functionp (nth 0 (car v)))
00d6fd04
MA
2297 (if (string-match "^HKEY_CURRENT_USER" (nth 1 (car v)))
2298 ;; Windows registry.
2299 (and (memq system-type '(cygwin windows-nt))
a4aeb9a4
MA
2300 (zerop
2301 (tramp-local-call-process
2302 "reg" nil nil nil "query" (nth 1 (car v)))))
00d6fd04
MA
2303 ;; Configuration file.
2304 (file-exists-p (nth 1 (car v)))))
5ec2cc41
KG
2305 (setq r (delete (car v) r)))
2306 (setq v (cdr v)))
2307
2308 (when r
4007ba5b 2309 (add-to-list 'tramp-completion-function-alist
5ec2cc41 2310 (cons method r)))))
16674e4f
KG
2311
2312(defun tramp-get-completion-function (method)
00d6fd04 2313 "Returns a list of completion functions for METHOD.
16674e4f 2314For definition of that list see `tramp-set-completion-function'."
00d6fd04
MA
2315 (cons
2316 ;; Hosts visited once shall be remembered.
2317 `(tramp-parse-connection-properties ,method)
2318 ;; The method related defaults.
2319 (cdr (assoc method tramp-completion-function-alist))))
16674e4f 2320
d037d501 2321
0664ff72 2322;;; Fontification of `read-file-name':
d037d501 2323
0664ff72 2324;; rfn-eshadow.el is part of Emacs 22. It is autoloaded.
d037d501
MA
2325(defvar tramp-rfn-eshadow-overlay)
2326(make-variable-buffer-local 'tramp-rfn-eshadow-overlay)
2327
2328(defun tramp-rfn-eshadow-setup-minibuffer ()
2329 "Set up a minibuffer for `file-name-shadow-mode'.
2330Adds another overlay hiding filename parts according to Tramp's
2331special handling of `substitute-in-file-name'."
9ce8462a 2332 (when (symbol-value 'minibuffer-completing-file-name)
d037d501 2333 (setq tramp-rfn-eshadow-overlay
9e6ab520
MA
2334 (funcall (symbol-function 'make-overlay)
2335 (funcall (symbol-function 'minibuffer-prompt-end))
2336 (funcall (symbol-function 'minibuffer-prompt-end))))
d037d501 2337 ;; Copy rfn-eshadow-overlay properties.
9e6ab520
MA
2338 (let ((props (funcall (symbol-function 'overlay-properties)
2339 (symbol-value 'rfn-eshadow-overlay))))
d037d501 2340 (while props
9e6ab520
MA
2341 (funcall (symbol-function 'overlay-put)
2342 tramp-rfn-eshadow-overlay (pop props) (pop props))))))
d037d501
MA
2343
2344(when (boundp 'rfn-eshadow-setup-minibuffer-hook)
2345 (add-hook 'rfn-eshadow-setup-minibuffer-hook
48846dc5
MA
2346 'tramp-rfn-eshadow-setup-minibuffer)
2347 (add-hook 'tramp-unload-hook
aa485f7c
MA
2348 (lambda ()
2349 (remove-hook 'rfn-eshadow-setup-minibuffer-hook
2350 'tramp-rfn-eshadow-setup-minibuffer))))
d037d501 2351
adcbca53
MA
2352(defconst tramp-rfn-eshadow-update-overlay-regexp
2353 (format "[^%s/~]*\\(/\\|~\\)" tramp-postfix-host-format))
2354
d037d501
MA
2355(defun tramp-rfn-eshadow-update-overlay ()
2356 "Update `rfn-eshadow-overlay' to cover shadowed part of minibuffer input.
2357This is intended to be used as a minibuffer `post-command-hook' for
2358`file-name-shadow-mode'; the minibuffer should have already
2359been set up by `rfn-eshadow-setup-minibuffer'."
2360 ;; In remote files name, there is a shadowing just for the local part.
9e6ab520
MA
2361 (let ((end (or (funcall (symbol-function 'overlay-end)
2362 (symbol-value 'rfn-eshadow-overlay))
2363 (funcall (symbol-function 'minibuffer-prompt-end)))))
2364 (when (file-remote-p (buffer-substring-no-properties end (point-max)))
bd316474
KY
2365 (save-excursion
2366 (save-restriction
2367 (narrow-to-region
adcbca53
MA
2368 (1+ (or (string-match
2369 tramp-rfn-eshadow-update-overlay-regexp (buffer-string) end)
2370 end))
2371 (point-max))
bd316474
KY
2372 (let ((rfn-eshadow-overlay tramp-rfn-eshadow-overlay)
2373 (rfn-eshadow-update-overlay-hook nil))
dea31ca6 2374 (move-overlay rfn-eshadow-overlay (point-max) (point-max))
bd316474 2375 (funcall (symbol-function 'rfn-eshadow-update-overlay))))))))
d037d501
MA
2376
2377(when (boundp 'rfn-eshadow-update-overlay-hook)
2378 (add-hook 'rfn-eshadow-update-overlay-hook
b88f2d0a
MA
2379 'tramp-rfn-eshadow-update-overlay)
2380 (add-hook 'tramp-unload-hook
2381 (lambda ()
2382 (remove-hook 'rfn-eshadow-update-overlay-hook
2383 'tramp-rfn-eshadow-update-overlay))))
d037d501
MA
2384
2385
fb7933a3
KG
2386;;; File Name Handler Functions:
2387
fb7933a3
KG
2388(defun tramp-handle-make-symbolic-link
2389 (filename linkname &optional ok-if-already-exists)
00d6fd04 2390 "Like `make-symbolic-link' for Tramp files.
cebb4ec6 2391If LINKNAME is a non-Tramp file, it is used verbatim as the target of
7432277c 2392the symlink. If LINKNAME is a Tramp file, only the localname component is
cebb4ec6
KG
2393used as the target of the symlink.
2394
7432277c
KG
2395If LINKNAME is a Tramp file and the localname component is relative, then
2396it is expanded first, before the localname component is taken. Note that
cebb4ec6
KG
2397this can give surprising results if the user/host for the source and
2398target of the symlink differ."
c62c9d08 2399 (with-parsed-tramp-file-name linkname l
00d6fd04 2400 (let ((ln (tramp-get-remote-ln l))
87bdd2c7
MA
2401 (cwd (tramp-run-real-handler
2402 'file-name-directory (list l-localname))))
c62c9d08 2403 (unless ln
00d6fd04
MA
2404 (tramp-error
2405 l 'file-error
2406 "Making a symbolic link. ln(1) does not exist on the remote host."))
c62c9d08
KG
2407
2408 ;; Do the 'confirm if exists' thing.
cebb4ec6 2409 (when (file-exists-p linkname)
c62c9d08
KG
2410 ;; What to do?
2411 (if (or (null ok-if-already-exists) ; not allowed to exist
2412 (and (numberp ok-if-already-exists)
2413 (not (yes-or-no-p
2414 (format
2415 "File %s already exists; make it a link anyway? "
7432277c 2416 l-localname)))))
00d6fd04
MA
2417 (tramp-error
2418 l 'file-already-exists "File %s already exists" l-localname)
cebb4ec6
KG
2419 (delete-file linkname)))
2420
7432277c 2421 ;; If FILENAME is a Tramp name, use just the localname component.
cebb4ec6 2422 (when (tramp-tramp-file-p filename)
1834b39f
MA
2423 (setq filename
2424 (tramp-file-name-localname
2425 (tramp-dissect-file-name (expand-file-name filename)))))
bf247b6e 2426
c62c9d08
KG
2427 ;; Right, they are on the same host, regardless of user, method, etc.
2428 ;; We now make the link on the remote machine. This will occur as the user
2429 ;; that FILENAME belongs to.
2430 (zerop
2431 (tramp-send-command-and-check
00d6fd04 2432 l (format "cd %s && %s -sf %s %s" cwd ln filename l-localname) t)))))
fb7933a3 2433
fb7933a3 2434(defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix)
00d6fd04
MA
2435 "Like `load' for Tramp files."
2436 (with-parsed-tramp-file-name (expand-file-name file) nil
c62c9d08
KG
2437 (unless nosuffix
2438 (cond ((file-exists-p (concat file ".elc"))
2439 (setq file (concat file ".elc")))
2440 ((file-exists-p (concat file ".el"))
2441 (setq file (concat file ".el")))))
2442 (when must-suffix
2443 ;; The first condition is always true for absolute file names.
2444 ;; Included for safety's sake.
2445 (unless (or (file-name-directory file)
2446 (string-match "\\.elc?\\'" file))
00d6fd04
MA
2447 (tramp-error
2448 v 'file-error
2449 "File `%s' does not include a `.el' or `.elc' suffix" file)))
c62c9d08
KG
2450 (unless noerror
2451 (when (not (file-exists-p file))
00d6fd04 2452 (tramp-error v 'file-error "Cannot load nonexistent file `%s'" file)))
c62c9d08
KG
2453 (if (not (file-exists-p file))
2454 nil
00d6fd04 2455 (unless nomessage (tramp-message v 0 "Loading %s..." file))
c62c9d08
KG
2456 (let ((local-copy (file-local-copy file)))
2457 ;; MUST-SUFFIX doesn't exist on XEmacs, so let it default to nil.
ce2cc728
MA
2458 (unwind-protect
2459 (load local-copy noerror t t)
2460 (delete-file local-copy)))
00d6fd04 2461 (unless nomessage (tramp-message v 0 "Loading %s...done" file))
c62c9d08 2462 t)))
fb7933a3 2463
a4aeb9a4 2464;; Localname manipulation functions that grok Tramp localnames...
c0fc6170
MA
2465(defun tramp-handle-file-name-as-directory (file)
2466 "Like `file-name-as-directory' but aware of Tramp files."
2467 ;; `file-name-as-directory' would be sufficient except localname is
2468 ;; the empty string.
2469 (let ((v (tramp-dissect-file-name file t)))
2470 ;; Run the command on the localname portion only.
2471 (tramp-make-tramp-file-name
2472 (tramp-file-name-method v)
2473 (tramp-file-name-user v)
2474 (tramp-file-name-host v)
2475 (tramp-run-real-handler
2476 'file-name-as-directory (list (or (tramp-file-name-localname v) ""))))))
2477
fb7933a3 2478(defun tramp-handle-file-name-directory (file)
00d6fd04 2479 "Like `file-name-directory' but aware of Tramp files."
9ce8462a
MA
2480 ;; Everything except the last filename thing is the directory. We
2481 ;; cannot apply `with-parsed-tramp-file-name', because this expands
2482 ;; the remote file name parts. This is a problem when we are in
2483 ;; file name completion.
2484 (let ((v (tramp-dissect-file-name file t)))
a01b1e22
MA
2485 ;; Run the command on the localname portion only.
2486 (tramp-make-tramp-file-name
9ce8462a
MA
2487 (tramp-file-name-method v)
2488 (tramp-file-name-user v)
2489 (tramp-file-name-host v)
87bdd2c7
MA
2490 (tramp-run-real-handler
2491 'file-name-directory (list (or (tramp-file-name-localname v) ""))))))
fb7933a3
KG
2492
2493(defun tramp-handle-file-name-nondirectory (file)
00d6fd04 2494 "Like `file-name-nondirectory' but aware of Tramp files."
c62c9d08 2495 (with-parsed-tramp-file-name file nil
87bdd2c7 2496 (tramp-run-real-handler 'file-name-nondirectory (list localname))))
fb7933a3
KG
2497
2498(defun tramp-handle-file-truename (filename &optional counter prev-dirs)
00d6fd04 2499 "Like `file-truename' for Tramp files."
48ddd622 2500 (with-parsed-tramp-file-name (expand-file-name filename) nil
00d6fd04 2501 (with-file-property v localname "file-truename"
293c24f9 2502 (let ((result nil)) ; result steps in reverse order
00d6fd04 2503 (tramp-message v 4 "Finding true name for `%s'" filename)
293c24f9
MA
2504 (cond
2505 ;; Use GNU readlink --canonicalize-missing where available.
2506 ((tramp-get-remote-readlink v)
2507 (setq result
2508 (tramp-send-command-and-read
2509 v
2510 (format "echo \"\\\"`%s --canonicalize-missing %s`\\\"\""
2511 (tramp-get-remote-readlink v)
2512 (tramp-shell-quote-argument localname)))))
2513
2514 ;; Use Perl implementation.
2515 ((and (tramp-get-remote-perl v)
2516 (tramp-get-connection-property v "perl-file-spec" nil)
2517 (tramp-get-connection-property v "perl-cwd-realpath" nil))
2518 (tramp-maybe-send-script
2519 v tramp-perl-file-truename "tramp_perl_file_truename")
2520 (setq result
2521 (tramp-send-command-and-read
2522 v
2523 (format "tramp_perl_file_truename %s"
2524 (tramp-shell-quote-argument localname)))))
2525
2526 ;; Do it yourself. We bind `directory-sep-char' here for
2527 ;; XEmacs on Windows, which would otherwise use backslash.
2528 (t (let* ((directory-sep-char ?/)
2529 (steps (tramp-compat-split-string localname "/"))
2530 (localnamedir (tramp-run-real-handler
2531 'file-name-as-directory (list localname)))
2532 (is-dir (string= localname localnamedir))
2533 (thisstep nil)
2534 (numchase 0)
2535 ;; Don't make the following value larger than
2536 ;; necessary. People expect an error message in a
2537 ;; timely fashion when something is wrong;
2538 ;; otherwise they might think that Emacs is hung.
2539 ;; Of course, correctness has to come first.
2540 (numchase-limit 20)
2541 symlink-target)
2542 (while (and steps (< numchase numchase-limit))
2543 (setq thisstep (pop steps))
2544 (tramp-message
2545 v 5 "Check %s"
2546 (mapconcat 'identity
2547 (append '("") (reverse result) (list thisstep))
2548 "/"))
2549 (setq symlink-target
2550 (nth 0 (file-attributes
2551 (tramp-make-tramp-file-name
2552 method user host
2553 (mapconcat 'identity
2554 (append '("")
2555 (reverse result)
2556 (list thisstep))
2557 "/")))))
2558 (cond ((string= "." thisstep)
2559 (tramp-message v 5 "Ignoring step `.'"))
2560 ((string= ".." thisstep)
2561 (tramp-message v 5 "Processing step `..'")
2562 (pop result))
2563 ((stringp symlink-target)
2564 ;; It's a symlink, follow it.
2565 (tramp-message v 5 "Follow symlink to %s" symlink-target)
2566 (setq numchase (1+ numchase))
2567 (when (file-name-absolute-p symlink-target)
2568 (setq result nil))
2569 ;; If the symlink was absolute, we'll get a string like
2570 ;; "/user@host:/some/target"; extract the
2571 ;; "/some/target" part from it.
2572 (when (tramp-tramp-file-p symlink-target)
2573 (unless (tramp-equal-remote filename symlink-target)
2574 (tramp-error
2575 v 'file-error
2576 "Symlink target `%s' on wrong host" symlink-target))
2577 (setq symlink-target localname))
2578 (setq steps
2579 (append (tramp-compat-split-string
2580 symlink-target "/")
2581 steps)))
2582 (t
2583 ;; It's a file.
2584 (setq result (cons thisstep result)))))
2585 (when (>= numchase numchase-limit)
2586 (tramp-error
2587 v 'file-error
2588 "Maximum number (%d) of symlinks exceeded" numchase-limit))
2589 (setq result (reverse result))
2590 ;; Combine list to form string.
2591 (setq result
2592 (if result
2593 (mapconcat 'identity (cons "" result) "/")
00d6fd04 2594 "/"))
293c24f9
MA
2595 (when (and is-dir (or (string= "" result)
2596 (not (string= (substring result -1) "/"))))
2597 (setq result (concat result "/"))))))
2598
2599 (tramp-message v 4 "True name of `%s' is `%s'" filename result)
2600 (tramp-make-tramp-file-name method user host result)))))
fb7933a3
KG
2601
2602;; Basic functions.
2603
2604(defun tramp-handle-file-exists-p (filename)
00d6fd04 2605 "Like `file-exists-p' for Tramp files."
c62c9d08 2606 (with-parsed-tramp-file-name filename nil
00d6fd04 2607 (with-file-property v localname "file-exists-p"
293c24f9
MA
2608 (or (not (null (tramp-get-file-property
2609 v localname "file-attributes-integer" nil)))
2610 (not (null (tramp-get-file-property
2611 v localname "file-attributes-string" nil)))
2612 (zerop (tramp-send-command-and-check
2613 v
2614 (format
2615 "%s %s"
2616 (tramp-get-file-exists-command v)
2617 (tramp-shell-quote-argument localname))))))))
fb7933a3 2618
00d6fd04
MA
2619;; Inodes don't exist for some file systems. Therefore we must
2620;; generate virtual ones. Used in `find-buffer-visiting'. The method
2621;; applied might be not so efficient (Ange-FTP uses hashes). But
2622;; performance isn't the major issue given that file transfer will
2623;; take time.
2624(defvar tramp-inodes nil
2625 "Keeps virtual inodes numbers.")
2626
8daea7fc
KG
2627;; Devices must distinguish physical file systems. The device numbers
2628;; provided by "lstat" aren't unique, because we operate on different hosts.
2629;; So we use virtual device numbers, generated by Tramp. Both Ange-FTP and
2630;; EFS use device number "-1". In order to be different, we use device number
b946a456 2631;; (-1 . x), whereby "x" is unique for a given (method user host).
8daea7fc
KG
2632(defvar tramp-devices nil
2633 "Keeps virtual device numbers.")
2634
fb7933a3
KG
2635;; CCC: This should check for an error condition and signal failure
2636;; when something goes wrong.
2637;; Daniel Pittman <daniel@danann.net>
c951aecb 2638(defun tramp-handle-file-attributes (filename &optional id-format)
00d6fd04
MA
2639 "Like `file-attributes' for Tramp files."
2640 (unless id-format (setq id-format 'integer))
aa485f7c
MA
2641 ;; Don't modify `last-coding-system-used' by accident.
2642 (let ((last-coding-system-used last-coding-system-used))
2643 (with-parsed-tramp-file-name (expand-file-name filename) nil
2644 (with-file-property v localname (format "file-attributes-%s" id-format)
7f49fe46
MA
2645 (save-excursion
2646 (tramp-convert-file-attributes
2647 v
2648 (cond
2649 ((tramp-get-remote-stat v)
2650 (tramp-do-file-attributes-with-stat v localname id-format))
2651 ((tramp-get-remote-perl v)
2652 (tramp-do-file-attributes-with-perl v localname id-format))
2653 (t
2654 (tramp-do-file-attributes-with-ls v localname id-format)))))))))
2655
2656(defun tramp-do-file-attributes-with-ls (vec localname &optional id-format)
00d6fd04 2657 "Implement `file-attributes' for Tramp files using the ls(1) command."
fb7933a3
KG
2658 (let (symlinkp dirp
2659 res-inode res-filemodes res-numlinks
2660 res-uid res-gid res-size res-symlink-target)
00d6fd04 2661 (tramp-message vec 5 "file attributes with ls: %s" localname)
fb7933a3 2662 (tramp-send-command
00d6fd04 2663 vec
680db9ac
MA
2664 (format "(%s %s || %s -h %s) && %s %s %s"
2665 (tramp-get-file-exists-command vec)
2666 (tramp-shell-quote-argument localname)
2667 (tramp-get-test-command vec)
2668 (tramp-shell-quote-argument localname)
00d6fd04 2669 (tramp-get-ls-command vec)
c82c5727 2670 (if (eq id-format 'integer) "-ildn" "-ild")
7432277c 2671 (tramp-shell-quote-argument localname)))
fb7933a3 2672 ;; parse `ls -l' output ...
00d6fd04 2673 (with-current-buffer (tramp-get-buffer vec)
680db9ac
MA
2674 (when (> (buffer-size) 0)
2675 (goto-char (point-min))
2676 ;; ... inode
2677 (setq res-inode
2678 (condition-case err
2679 (read (current-buffer))
2680 (invalid-read-syntax
2681 (when (and (equal (cadr err)
2682 "Integer constant overflow in reader")
2683 (string-match
2684 "^[0-9]+\\([0-9][0-9][0-9][0-9][0-9]\\)\\'"
2685 (car (cddr err))))
2686 (let* ((big (read (substring (car (cddr err)) 0
2687 (match-beginning 1))))
2688 (small (read (match-string 1 (car (cddr err)))))
2689 (twiddle (/ small 65536)))
2690 (cons (+ big twiddle)
2691 (- small (* twiddle 65536))))))))
2692 ;; ... file mode flags
2693 (setq res-filemodes (symbol-name (read (current-buffer))))
2694 ;; ... number links
2695 (setq res-numlinks (read (current-buffer)))
2696 ;; ... uid and gid
2697 (setq res-uid (read (current-buffer)))
2698 (setq res-gid (read (current-buffer)))
2699 (if (eq id-format 'integer)
2700 (progn
2701 (unless (numberp res-uid) (setq res-uid -1))
2702 (unless (numberp res-gid) (setq res-gid -1)))
2703 (progn
2704 (unless (stringp res-uid) (setq res-uid (symbol-name res-uid)))
2705 (unless (stringp res-gid) (setq res-gid (symbol-name res-gid)))))
2706 ;; ... size
2707 (setq res-size (read (current-buffer)))
2708 ;; From the file modes, figure out other stuff.
2709 (setq symlinkp (eq ?l (aref res-filemodes 0)))
2710 (setq dirp (eq ?d (aref res-filemodes 0)))
2711 ;; if symlink, find out file name pointed to
2712 (when symlinkp
2713 (search-forward "-> ")
2714 (setq res-symlink-target
2715 (buffer-substring (point) (tramp-compat-line-end-position))))
2716 ;; return data gathered
2717 (list
2718 ;; 0. t for directory, string (name linked to) for symbolic
2719 ;; link, or nil.
2720 (or dirp res-symlink-target)
2721 ;; 1. Number of links to file.
2722 res-numlinks
2723 ;; 2. File uid.
2724 res-uid
2725 ;; 3. File gid.
2726 res-gid
2727 ;; 4. Last access time, as a list of two integers. First
2728 ;; integer has high-order 16 bits of time, second has low 16
2729 ;; bits.
2730 ;; 5. Last modification time, likewise.
2731 ;; 6. Last status change time, likewise.
2732 '(0 0) '(0 0) '(0 0) ;CCC how to find out?
2733 ;; 7. Size in bytes (-1, if number is out of range).
2734 res-size
2735 ;; 8. File modes, as a string of ten letters or dashes as in ls -l.
2736 res-filemodes
2737 ;; 9. t if file's gid would change if file were deleted and
2738 ;; recreated. Will be set in `tramp-convert-file-attributes'
2739 t
2740 ;; 10. inode number.
2741 res-inode
2742 ;; 11. Device number. Will be replaced by a virtual device number.
2743 -1
2744 )))))
fb7933a3 2745
7f49fe46 2746(defun tramp-do-file-attributes-with-perl
00d6fd04
MA
2747 (vec localname &optional id-format)
2748 "Implement `file-attributes' for Tramp files using a Perl script."
2749 (tramp-message vec 5 "file attributes with perl: %s" localname)
2750 (tramp-maybe-send-script
2751 vec tramp-perl-file-attributes "tramp_perl_file_attributes")
2752 (tramp-send-command-and-read
2753 vec
2754 (format "tramp_perl_file_attributes %s %s"
2755 (tramp-shell-quote-argument localname) id-format)))
2756
7f49fe46 2757(defun tramp-do-file-attributes-with-stat
00d6fd04
MA
2758 (vec localname &optional id-format)
2759 "Implement `file-attributes' for Tramp files using stat(1) command."
2760 (tramp-message vec 5 "file attributes with stat: %s" localname)
2761 (tramp-send-command-and-read
2762 vec
2763 (format
680db9ac
MA
2764 "((%s %s || %s -h %s) && %s -c '((\"%%N\") %%h %s %s %%X.0 %%Y.0 %%Z.0 %%s.0 \"%%A\" t %%i.0 -1)' %s || echo nil)"
2765 (tramp-get-file-exists-command vec)
2766 (tramp-shell-quote-argument localname)
2767 (tramp-get-test-command vec)
2768 (tramp-shell-quote-argument localname)
00d6fd04
MA
2769 (tramp-get-remote-stat vec)
2770 (if (eq id-format 'integer) "%u" "\"%U\"")
2771 (if (eq id-format 'integer) "%g" "\"%G\"")
2772 (tramp-shell-quote-argument localname))))
8daea7fc 2773
fb7933a3 2774(defun tramp-handle-set-visited-file-modtime (&optional time-list)
00d6fd04 2775 "Like `set-visited-file-modtime' for Tramp files."
fb7933a3
KG
2776 (unless (buffer-file-name)
2777 (error "Can't set-visited-file-modtime: buffer `%s' not visiting a file"
2778 (buffer-name)))
48ddd622
MA
2779 (if time-list
2780 (tramp-run-real-handler 'set-visited-file-modtime (list time-list))
11948172
MA
2781 (let ((f (buffer-file-name))
2782 coding-system-used)
48ddd622
MA
2783 (with-parsed-tramp-file-name f nil
2784 (let* ((attr (file-attributes f))
2785 ;; '(-1 65535) means file doesn't exists yet.
2786 (modtime (or (nth 5 attr) '(-1 65535))))
11948172
MA
2787 (when (boundp 'last-coding-system-used)
2788 (setq coding-system-used (symbol-value 'last-coding-system-used)))
48ddd622 2789 ;; We use '(0 0) as a don't-know value. See also
7f49fe46 2790 ;; `tramp-do-file-attributes-with-ls'.
48ddd622
MA
2791 (if (not (equal modtime '(0 0)))
2792 (tramp-run-real-handler 'set-visited-file-modtime (list modtime))
00d6fd04 2793 (progn
48ddd622 2794 (tramp-send-command
00d6fd04 2795 v
48ddd622 2796 (format "%s -ild %s"
00d6fd04 2797 (tramp-get-ls-command v)
48ddd622 2798 (tramp-shell-quote-argument localname)))
48ddd622
MA
2799 (setq attr (buffer-substring (point)
2800 (progn (end-of-line) (point)))))
00d6fd04
MA
2801 (tramp-set-file-property
2802 v localname "visited-file-modtime-ild" attr))
11948172
MA
2803 (when (boundp 'last-coding-system-used)
2804 (set 'last-coding-system-used coding-system-used))
d2a2c17f 2805 nil)))))
fb7933a3 2806
c62c9d08
KG
2807;; This function makes the same assumption as
2808;; `tramp-handle-set-visited-file-modtime'.
2809(defun tramp-handle-verify-visited-file-modtime (buf)
00d6fd04 2810 "Like `verify-visited-file-modtime' for Tramp files.
c08e6004
MA
2811At the time `verify-visited-file-modtime' calls this function, we
2812already know that the buffer is visiting a file and that
2813`visited-file-modtime' does not return 0. Do not call this
2814function directly, unless those two cases are already taken care
2815of."
c62c9d08 2816 (with-current-buffer buf
b15d0c4c
MA
2817 ;; There is no file visiting the buffer, or the buffer has no
2818 ;; recorded last modification time.
2819 (if (or (not (buffer-file-name))
2820 (eq (visited-file-modtime) 0))
d2a2c17f 2821 t
b15d0c4c
MA
2822 (let ((f (buffer-file-name)))
2823 (with-parsed-tramp-file-name f nil
bce04fee 2824 (tramp-flush-file-property v localname)
b15d0c4c
MA
2825 (let* ((attr (file-attributes f))
2826 (modtime (nth 5 attr))
2827 (mt (visited-file-modtime)))
bf247b6e 2828
70c11b0b
MA
2829 (cond
2830 ;; File exists, and has a known modtime.
b15d0c4c
MA
2831 ((and attr (not (equal modtime '(0 0))))
2832 (< (abs (tramp-time-diff
2833 modtime
2834 ;; For compatibility, deal with both the old
70c11b0b
MA
2835 ;; (HIGH . LOW) and the new (HIGH LOW) return
2836 ;; values of `visited-file-modtime'.
b15d0c4c
MA
2837 (if (atom (cdr mt))
2838 (list (car mt) (cdr mt))
2839 mt)))
2840 2))
70c11b0b 2841 ;; Modtime has the don't know value.
b15d0c4c 2842 (attr
00d6fd04
MA
2843 (tramp-send-command
2844 v
2845 (format "%s -ild %s"
2846 (tramp-get-ls-command v)
2847 (tramp-shell-quote-argument localname)))
2848 (with-current-buffer (tramp-get-buffer v)
b15d0c4c
MA
2849 (setq attr (buffer-substring
2850 (point) (progn (end-of-line) (point)))))
00d6fd04
MA
2851 (equal
2852 attr
2853 (tramp-get-file-property
2854 v localname "visited-file-modtime-ild" "")))
70c11b0b
MA
2855 ;; If file does not exist, say it is not modified if and
2856 ;; only if that agrees with the buffer's record.
b15d0c4c 2857 (t (equal mt '(-1 65535))))))))))
c62c9d08 2858
fb7933a3 2859(defun tramp-handle-set-file-modes (filename mode)
00d6fd04 2860 "Like `set-file-modes' for Tramp files."
c62c9d08 2861 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2862 (tramp-flush-file-property v localname)
2863 (unless (zerop (tramp-send-command-and-check
2864 v
2865 (format "chmod %s %s"
2866 (tramp-decimal-to-octal mode)
2867 (tramp-shell-quote-argument localname))))
2868 ;; FIXME: extract the proper text from chmod's stderr.
2869 (tramp-error
2870 v 'file-error "Error while changing file's mode %s" filename))))
fb7933a3 2871
ce3f516f
MA
2872(defun tramp-handle-set-file-times (filename &optional time)
2873 "Like `set-file-times' for Tramp files."
2874 (zerop
9e6ab520 2875 (if (file-remote-p filename)
ce3f516f 2876 (with-parsed-tramp-file-name filename nil
8d60099b 2877 (tramp-flush-file-property v localname)
ce3f516f
MA
2878 (let ((time (if (or (null time) (equal time '(0 0)))
2879 (current-time)
2880 time))
2881 (utc
2882 ;; With GNU Emacs, `format-time-string' has an
2883 ;; optional parameter UNIVERSAL. This is preferred,
2884 ;; because we could handle the case when the remote
2885 ;; host is located in a different time zone as the
2886 ;; local host.
2887 (and (functionp 'subr-arity)
2888 (subrp (symbol-function 'format-time-string))
2889 (= 3 (cdr (funcall (symbol-function 'subr-arity)
2890 (symbol-function
2891 'format-time-string)))))))
2892 (tramp-send-command-and-check
2893 v (format "%s touch -t %s %s"
2894 (if utc "TZ=UTC; export TZ;" "")
2895 (if utc
2896 (format-time-string "%Y%m%d%H%M.%S" time t)
2897 (format-time-string "%Y%m%d%H%M.%S" time))
2898 (tramp-shell-quote-argument localname)))))
8d60099b 2899
ce3f516f
MA
2900 ;; We handle also the local part, because in older Emacsen,
2901 ;; without `set-file-times', this function is an alias for this.
2902 ;; We are local, so we don't need the UTC settings.
a4aeb9a4 2903 (tramp-local-call-process
ce3f516f
MA
2904 "touch" nil nil nil "-t"
2905 (format-time-string "%Y%m%d%H%M.%S" time)
2906 (tramp-shell-quote-argument filename)))))
2907
8d60099b
MA
2908(defun tramp-set-file-uid-gid (filename &optional uid gid)
2909 "Set the ownership for FILENAME.
2910If UID and GID are provided, these values are used; otherwise uid
2911and gid of the corresponding user is taken. Both parameters must be integers."
70c11b0b
MA
2912 ;; Modern Unices allow chown only for root. So we might need
2913 ;; another implementation, see `dired-do-chown'. OTOH, it is mostly
2914 ;; working with su(do)? when it is needed, so it shall succeed in
2915 ;; the majority of cases.
aa485f7c
MA
2916 ;; Don't modify `last-coding-system-used' by accident.
2917 (let ((last-coding-system-used last-coding-system-used))
2918 (if (file-remote-p filename)
2919 (with-parsed-tramp-file-name filename nil
2920 (if (and (zerop (user-uid)) (tramp-local-host-p v))
2921 ;; If we are root on the local host, we can do it directly.
2922 (tramp-set-file-uid-gid localname uid gid)
2923 (let ((uid (or (and (integerp uid) uid)
2924 (tramp-get-remote-uid v 'integer)))
2925 (gid (or (and (integerp gid) gid)
2926 (tramp-get-remote-gid v 'integer))))
2927 (tramp-send-command
2928 v (format
2929 "chown %d:%d %s" uid gid
2930 (tramp-shell-quote-argument localname))))))
2931
2932 ;; We handle also the local part, because there doesn't exist
2933 ;; `set-file-uid-gid'. On W32 "chown" might not work.
2934 (let ((uid (or (and (integerp uid) uid) (tramp-get-local-uid 'integer)))
2935 (gid (or (and (integerp gid) gid) (tramp-get-local-gid 'integer))))
2936 (tramp-local-call-process
2937 "chown" nil nil nil
2938 (format "%d:%d" uid gid) (tramp-shell-quote-argument filename))))))
8d60099b 2939
fb7933a3
KG
2940;; Simple functions using the `test' command.
2941
2942(defun tramp-handle-file-executable-p (filename)
00d6fd04 2943 "Like `file-executable-p' for Tramp files."
c62c9d08 2944 (with-parsed-tramp-file-name filename nil
00d6fd04 2945 (with-file-property v localname "file-executable-p"
293c24f9
MA
2946 ;; Examine `file-attributes' cache to see if request can be
2947 ;; satisfied without remote operation.
2948 (or (tramp-check-cached-permissions v ?x)
2949 (zerop (tramp-run-test "-x" filename))))))
fb7933a3
KG
2950
2951(defun tramp-handle-file-readable-p (filename)
00d6fd04 2952 "Like `file-readable-p' for Tramp files."
c62c9d08 2953 (with-parsed-tramp-file-name filename nil
00d6fd04 2954 (with-file-property v localname "file-readable-p"
293c24f9
MA
2955 ;; Examine `file-attributes' cache to see if request can be
2956 ;; satisfied without remote operation.
2957 (or (tramp-check-cached-permissions v ?r)
2958 (zerop (tramp-run-test "-r" filename))))))
fb7933a3
KG
2959
2960;; When the remote shell is started, it looks for a shell which groks
2961;; tilde expansion. Here, we assume that all shells which grok tilde
2962;; expansion will also provide a `test' command which groks `-nt' (for
2963;; newer than). If this breaks, tell me about it and I'll try to do
2964;; something smarter about it.
2965(defun tramp-handle-file-newer-than-file-p (file1 file2)
00d6fd04 2966 "Like `file-newer-than-file-p' for Tramp files."
fb7933a3
KG
2967 (cond ((not (file-exists-p file1))
2968 nil)
2969 ((not (file-exists-p file2))
2970 t)
91879624 2971 ;; We are sure both files exist at this point.
fb7933a3
KG
2972 (t
2973 (save-excursion
91879624
KG
2974 ;; We try to get the mtime of both files. If they are not
2975 ;; equal to the "dont-know" value, then we subtract the times
2976 ;; and obtain the result.
2977 (let ((fa1 (file-attributes file1))
2978 (fa2 (file-attributes file2)))
2979 (if (and (not (equal (nth 5 fa1) '(0 0)))
2980 (not (equal (nth 5 fa2) '(0 0))))
01917a18 2981 (> 0 (tramp-time-diff (nth 5 fa2) (nth 5 fa1)))
91879624
KG
2982 ;; If one of them is the dont-know value, then we can
2983 ;; still try to run a shell command on the remote host.
2984 ;; However, this only works if both files are Tramp
2985 ;; files and both have the same method, same user, same
2986 ;; host.
00d6fd04
MA
2987 (unless (tramp-equal-remote file1 file2)
2988 (with-parsed-tramp-file-name
2989 (if (tramp-tramp-file-p file1) file1 file2) nil
2990 (tramp-error
2991 v 'file-error
2992 "Files %s and %s must have same method, user, host"
2993 file1 file2)))
2994 (with-parsed-tramp-file-name file1 nil
2995 (zerop (tramp-run-test2
2996 (tramp-get-test-nt-command v) file1 file2)))))))))
fb7933a3
KG
2997
2998;; Functions implemented using the basic functions above.
2999
3000(defun tramp-handle-file-modes (filename)
00d6fd04 3001 "Like `file-modes' for Tramp files."
5da24108
MA
3002 (let ((truename (or (file-truename filename) filename)))
3003 (when (file-exists-p truename)
3004 (tramp-mode-string-to-int (nth 8 (file-attributes truename))))))
fb7933a3 3005
b86c1cd8
MA
3006(defun tramp-default-file-modes (filename)
3007 "Return file modes of FILENAME as integer.
3008If the file modes of FILENAME cannot be determined, return the
974647ac
MA
3009value of `default-file-modes', without execute permissions."
3010 (or (file-modes filename)
3011 (logand (default-file-modes) (tramp-octal-to-decimal "0666"))))
b86c1cd8 3012
fb7933a3 3013(defun tramp-handle-file-directory-p (filename)
00d6fd04 3014 "Like `file-directory-p' for Tramp files."
fb7933a3
KG
3015 ;; Care must be taken that this function returns `t' for symlinks
3016 ;; pointing to directories. Surely the most obvious implementation
3017 ;; would be `test -d', but that returns false for such symlinks.
3018 ;; CCC: Stefan Monnier says that `test -d' follows symlinks. And
3019 ;; I now think he's right. So we could be using `test -d', couldn't
3020 ;; we?
3021 ;;
3022 ;; Alternatives: `cd %s', `test -d %s'
c62c9d08 3023 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3024 (with-file-property v localname "file-directory-p"
3025 (zerop (tramp-run-test "-d" filename)))))
fb7933a3
KG
3026
3027(defun tramp-handle-file-regular-p (filename)
00d6fd04
MA
3028 "Like `file-regular-p' for Tramp files."
3029 (and (file-exists-p filename)
3030 (eq ?- (aref (nth 8 (file-attributes filename)) 0))))
fb7933a3
KG
3031
3032(defun tramp-handle-file-symlink-p (filename)
00d6fd04 3033 "Like `file-symlink-p' for Tramp files."
c62c9d08 3034 (with-parsed-tramp-file-name filename nil
c951aecb 3035 (let ((x (car (file-attributes filename))))
b25a52cc
KG
3036 (when (stringp x)
3037 ;; When Tramp is running on VMS, then `file-name-absolute-p'
3038 ;; might do weird things.
3039 (if (file-name-absolute-p x)
00d6fd04 3040 (tramp-make-tramp-file-name method user host x)
b25a52cc 3041 x)))))
fb7933a3
KG
3042
3043(defun tramp-handle-file-writable-p (filename)
00d6fd04 3044 "Like `file-writable-p' for Tramp files."
c62c9d08 3045 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3046 (with-file-property v localname "file-writable-p"
3047 (if (file-exists-p filename)
293c24f9
MA
3048 ;; Examine `file-attributes' cache to see if request can be
3049 ;; satisfied without remote operation.
3050 (or (tramp-check-cached-permissions v ?w)
3051 (zerop (tramp-run-test "-w" filename)))
00d6fd04
MA
3052 ;; If file doesn't exist, check if directory is writable.
3053 (and (zerop (tramp-run-test
3054 "-d" (file-name-directory filename)))
3055 (zerop (tramp-run-test
3056 "-w" (file-name-directory filename))))))))
fb7933a3
KG
3057
3058(defun tramp-handle-file-ownership-preserved-p (filename)
00d6fd04 3059 "Like `file-ownership-preserved-p' for Tramp files."
c62c9d08 3060 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3061 (with-file-property v localname "file-ownership-preserved-p"
3062 (let ((attributes (file-attributes filename)))
3063 ;; Return t if the file doesn't exist, since it's true that no
3064 ;; information would be lost by an (attempted) delete and create.
3065 (or (null attributes)
3066 (= (nth 2 attributes) (tramp-get-remote-uid v 'integer)))))))
fb7933a3
KG
3067
3068;; Other file name ops.
3069
fb7933a3 3070(defun tramp-handle-directory-file-name (directory)
00d6fd04 3071 "Like `directory-file-name' for Tramp files."
7432277c
KG
3072 ;; If localname component of filename is "/", leave it unchanged.
3073 ;; Otherwise, remove any trailing slash from localname component.
8daea7fc
KG
3074 ;; Method, host, etc, are unchanged. Does it make sense to try
3075 ;; to avoid parsing the filename?
c62c9d08 3076 (with-parsed-tramp-file-name directory nil
7432277c
KG
3077 (if (and (not (zerop (length localname)))
3078 (eq (aref localname (1- (length localname))) ?/)
3079 (not (string= localname "/")))
8daea7fc
KG
3080 (substring directory 0 -1)
3081 directory)))
fb7933a3
KG
3082
3083;; Directory listings.
3084
00d6fd04
MA
3085(defun tramp-handle-directory-files
3086 (directory &optional full match nosort files-only)
3087 "Like `directory-files' for Tramp files."
3088 ;; FILES-ONLY is valid for XEmacs only.
3089 (when (file-directory-p directory)
3090 (setq directory (expand-file-name directory))
3091 (let ((temp (nreverse (file-name-all-completions "" directory)))
3092 result item)
3093
3094 (while temp
3095 (setq item (directory-file-name (pop temp)))
3096 (when (and (or (null match) (string-match match item))
3097 (or (null files-only)
3098 ;; files only
3099 (and (equal files-only t) (file-regular-p item))
3100 ;; directories only
3101 (file-directory-p item)))
3102 (push (if full (expand-file-name item directory) item)
3103 result)))
c62c9d08
KG
3104 result)))
3105
c82c5727
LH
3106(defun tramp-handle-directory-files-and-attributes
3107 (directory &optional full match nosort id-format)
00d6fd04
MA
3108 "Like `directory-files-and-attributes' for Tramp files."
3109 (unless id-format (setq id-format 'integer))
3110 (when (file-directory-p directory)
3111 (setq directory (expand-file-name directory))
3112 (let* ((temp
9e6ab520 3113 (tramp-compat-copy-tree
00d6fd04
MA
3114 (with-parsed-tramp-file-name directory nil
3115 (with-file-property
3116 v localname
3117 (format "directory-files-and-attributes-%s" id-format)
3118 (save-excursion
3119 (mapcar
aa485f7c
MA
3120 (lambda (x)
3121 (cons (car x)
3122 (tramp-convert-file-attributes v (cdr x))))
7f49fe46
MA
3123 (cond
3124 ((tramp-get-remote-stat v)
3125 (tramp-do-directory-files-and-attributes-with-stat
3126 v localname id-format))
3127 ((tramp-get-remote-perl v)
3128 (tramp-do-directory-files-and-attributes-with-perl
3129 v localname id-format)))))))))
00d6fd04
MA
3130 result item)
3131
3132 (while temp
3133 (setq item (pop temp))
3134 (when (or (null match) (string-match match (car item)))
3135 (when full
3136 (setcar item (expand-file-name (car item) directory)))
3137 (push item result)))
3138
3139 (if nosort
3140 result
3141 (sort result (lambda (x y) (string< (car x) (car y))))))))
3142
7f49fe46 3143(defun tramp-do-directory-files-and-attributes-with-perl
00d6fd04
MA
3144 (vec localname &optional id-format)
3145 "Implement `directory-files-and-attributes' for Tramp files using a Perl script."
3146 (tramp-message vec 5 "directory-files-and-attributes with perl: %s" localname)
3147 (tramp-maybe-send-script
3148 vec tramp-perl-directory-files-and-attributes
3149 "tramp_perl_directory_files_and_attributes")
3150 (let ((object
3151 (tramp-send-command-and-read
3152 vec
3153 (format "tramp_perl_directory_files_and_attributes %s %s"
3154 (tramp-shell-quote-argument localname) id-format))))
3155 (when (stringp object) (tramp-error vec 'file-error object))
3156 object))
3157
7f49fe46 3158(defun tramp-do-directory-files-and-attributes-with-stat
00d6fd04
MA
3159 (vec localname &optional id-format)
3160 "Implement `directory-files-and-attributes' for Tramp files using stat(1) command."
3161 (tramp-message vec 5 "directory-files-and-attributes with stat: %s" localname)
3162 (tramp-send-command-and-read
3163 vec
3164 (format
3165 (concat
70c11b0b
MA
3166 ;; We must care about filenames with spaces, or starting with
3167 ;; "-"; this would confuse xargs. "ls -aQ" might be a solution,
3168 ;; but it does not work on all remote systems. Therefore, we
3169 ;; quote the filenames via sed.
3170 "cd %s; echo \"(\"; (%s -a | sed -e s/\\$/\\\"/g -e s/^/\\\"/g | xargs "
d4443a0d 3171 "%s -c '(\"%%n\" (\"%%N\") %%h %s %s %%X.0 %%Y.0 %%Z.0 %%s.0 \"%%A\" t %%i.0 -1)'); "
00d6fd04
MA
3172 "echo \")\"")
3173 (tramp-shell-quote-argument localname)
3174 (tramp-get-ls-command vec)
3175 (tramp-get-remote-stat vec)
3176 (if (eq id-format 'integer) "%u" "\"%U\"")
3177 (if (eq id-format 'integer) "%g" "\"%G\""))))
c82c5727 3178
c62c9d08 3179;; This function should return "foo/" for directories and "bar" for
00d6fd04 3180;; files.
c62c9d08 3181(defun tramp-handle-file-name-all-completions (filename directory)
00d6fd04
MA
3182 "Like `file-name-all-completions' for Tramp files."
3183 (unless (save-match-data (string-match "/" filename))
9c13938d 3184 (with-parsed-tramp-file-name (expand-file-name directory) nil
b50dd0d2 3185
00d6fd04
MA
3186 (all-completions
3187 filename
3188 (mapcar
3189 'list
293c24f9
MA
3190 (or
3191 ;; Try cache first
3192 (and
3193 ;; Ignore if expired
3194 (or (not (integerp tramp-completion-reread-directory-timeout))
3195 (<= (tramp-time-diff
3196 (current-time)
3197 (tramp-get-file-property
3198 v localname "last-completion" '(0 0 0)))
3199 tramp-completion-reread-directory-timeout))
3200
3201 ;; Try cache entries for filename, filename with last
3202 ;; character removed, filename with last two characters
3203 ;; removed, ..., and finally the empty string - all
3204 ;; concatenated to the local directory name
3205
3206 ;; This is inefficient for very long filenames, pity
3207 ;; `reduce' is not available...
3208 (car
3209 (apply
3210 'append
3211 (mapcar
3212 (lambda (x)
3213 (let ((cache-hit
3214 (tramp-get-file-property
3215 v
3216 (concat localname (substring filename 0 x))
3217 "file-name-all-completions"
3218 nil)))
3219 (when cache-hit (list cache-hit))))
3220 (tramp-compat-number-sequence (length filename) 0 -1)))))
3221
3222 ;; Cache expired or no matching cache entry found so we need
3223 ;; to perform a remote operation
3224 (let (result)
3225 ;; Get a list of directories and files, including reliably
3226 ;; tagging the directories with a trailing '/'. Because I
3227 ;; rock. --daniel@danann.net
3228
3229 ;; Changed to perform `cd' in the same remote op and only
3230 ;; get entries starting with `filename'. Capture any `cd'
3231 ;; error messages. Ensure any `cd' and `echo' aliases are
3232 ;; ignored.
3233 (tramp-send-command
3234 v
3235 (if (tramp-get-remote-perl v)
3236 (progn
3237 (tramp-maybe-send-script
3238 v tramp-perl-file-name-all-completions
3239 "tramp_perl_file_name_all_completions")
3240 (format "tramp_perl_file_name_all_completions %s %s %d"
3241 (tramp-shell-quote-argument localname)
3242 (tramp-shell-quote-argument filename)
3243 (if (symbol-value
3244 'read-file-name-completion-ignore-case)
3245 1 0)))
3246
3247 (format (concat
3248 "(\\cd %s 2>&1 && (%s %s -a 2>/dev/null"
3249 ;; `ls' with wildcard might fail with `Argument
3250 ;; list too long' error in some corner cases; if
3251 ;; `ls' fails after `cd' succeeded, chances are
3252 ;; that's the case, so let's retry without
3253 ;; wildcard. This will return "too many" entries
3254 ;; but that isn't harmful.
3255 " || %s -a 2>/dev/null)"
3256 " | while read f; do"
3257 " if %s -d \"$f\" 2>/dev/null;"
3258 " then \\echo \"$f/\"; else \\echo \"$f\"; fi; done"
3259 " && \\echo ok) || \\echo fail")
3260 (tramp-shell-quote-argument localname)
3261 (tramp-get-ls-command v)
3262 ;; When `filename' is empty, just `ls' without
3263 ;; filename argument is more efficient than `ls *'
3264 ;; for very large directories and might avoid the
3265 ;; `Argument list too long' error.
3266 ;;
3267 ;; With and only with wildcard, we need to add
3268 ;; `-d' to prevent `ls' from descending into
3269 ;; sub-directories.
3270 (if (zerop (length filename))
3271 "."
3272 (concat (tramp-shell-quote-argument filename) "* -d"))
3273 (tramp-get-ls-command v)
3274 (tramp-get-test-command v))))
3275
3276 ;; Now grab the output.
3277 (with-current-buffer (tramp-get-buffer v)
3278 (goto-char (point-max))
3279
3280 ;; Check result code, found in last line of output
3281 (forward-line -1)
3282 (if (looking-at "^fail$")
3283 (progn
3284 ;; Grab error message from line before last line
3285 ;; (it was put there by `cd 2>&1')
3286 (forward-line -1)
3287 (tramp-error
3288 v 'file-error
3289 "tramp-handle-file-name-all-completions: %s"
3290 (buffer-substring
3291 (point) (tramp-compat-line-end-position))))
3292 ;; For peace of mind, if buffer doesn't end in `fail'
3293 ;; then it should end in `ok'. If neither are in the
3294 ;; buffer something went seriously wrong on the remote
3295 ;; side.
3296 (unless (looking-at "^ok$")
3297 (tramp-error
3298 v 'file-error
3299 "\
3300tramp-handle-file-name-all-completions: internal error accessing `%s': `%s'"
3301 (tramp-shell-quote-argument localname) (buffer-string))))
3302
3303 (while (zerop (forward-line -1))
3304 (push (buffer-substring
3305 (point) (tramp-compat-line-end-position))
3306 result)))
3307
3308 ;; Because the remote op went through OK we know the
3309 ;; directory we `cd'-ed to exists
3310 (tramp-set-file-property
3311 v localname "file-exists-p" t)
3312
3313 ;; Because the remote op went through OK we know every
3314 ;; file listed by `ls' exists.
3315 (mapc (lambda (entry)
3316 (tramp-set-file-property
3317 v (concat localname entry) "file-exists-p" t))
3318 result)
3319
3320 (tramp-set-file-property
3321 v localname "last-completion" (current-time))
3322
3323 ;; Store result in the cache
3324 (tramp-set-file-property
3325 v (concat localname filename)
3326 "file-name-all-completions"
3327 result))))))))
fb7933a3
KG
3328
3329;; The following isn't needed for Emacs 20 but for 19.34?
e1e17cae
MA
3330(defun tramp-handle-file-name-completion
3331 (filename directory &optional predicate)
00d6fd04 3332 "Like `file-name-completion' for Tramp files."
fb7933a3
KG
3333 (unless (tramp-tramp-file-p directory)
3334 (error
3335 "tramp-handle-file-name-completion invoked on non-tramp directory `%s'"
3336 directory))
83e20b5c
MA
3337 (try-completion
3338 filename
3339 (mapcar 'list (file-name-all-completions filename directory))
3340 (when predicate
3341 (lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
fb7933a3
KG
3342
3343;; cp, mv and ln
3344
3345(defun tramp-handle-add-name-to-file
3346 (filename newname &optional ok-if-already-exists)
00d6fd04
MA
3347 "Like `add-name-to-file' for Tramp files."
3348 (unless (tramp-equal-remote filename newname)
3349 (with-parsed-tramp-file-name
3350 (if (tramp-tramp-file-p filename) filename newname) nil
3351 (tramp-error
3352 v 'file-error
3353 "add-name-to-file: %s"
3354 "only implemented for same method, same user, same host")))
c62c9d08
KG
3355 (with-parsed-tramp-file-name filename v1
3356 (with-parsed-tramp-file-name newname v2
00d6fd04 3357 (let ((ln (when v1 (tramp-get-remote-ln v1))))
c62c9d08
KG
3358 (when (and (not ok-if-already-exists)
3359 (file-exists-p newname)
3360 (not (numberp ok-if-already-exists))
3361 (y-or-n-p
3362 (format
3363 "File %s already exists; make it a new name anyway? "
3364 newname)))
00d6fd04
MA
3365 (tramp-error
3366 v2 'file-error
3367 "add-name-to-file: file %s already exists" newname))
3368 (tramp-flush-file-property v2 v2-localname)
c62c9d08 3369 (tramp-barf-unless-okay
00d6fd04 3370 v1
7432277c
KG
3371 (format "%s %s %s" ln (tramp-shell-quote-argument v1-localname)
3372 (tramp-shell-quote-argument v2-localname))
c62c9d08
KG
3373 "error with add-name-to-file, see buffer `%s' for details"
3374 (buffer-name))))))
fb7933a3
KG
3375
3376(defun tramp-handle-copy-file
8d60099b 3377 (filename newname &optional ok-if-already-exists keep-date preserve-uid-gid)
00d6fd04 3378 "Like `copy-file' for Tramp files."
fb7933a3 3379 ;; Check if both files are local -- invoke normal copy-file.
9e6ab520 3380 ;; Otherwise, use Tramp from local system.
fb7933a3
KG
3381 (setq filename (expand-file-name filename))
3382 (setq newname (expand-file-name newname))
9e6ab520 3383 (cond
a4aeb9a4 3384 ;; At least one file a Tramp file?
9e6ab520
MA
3385 ((or (tramp-tramp-file-p filename)
3386 (tramp-tramp-file-p newname))
3387 (tramp-do-copy-or-rename-file
3388 'copy filename newname ok-if-already-exists keep-date preserve-uid-gid))
3389 ;; Compat section.
3390 (preserve-uid-gid
fb7933a3 3391 (tramp-run-real-handler
8d60099b 3392 'copy-file
9e6ab520
MA
3393 (list filename newname ok-if-already-exists keep-date preserve-uid-gid)))
3394 (t
3395 (tramp-run-real-handler
3396 'copy-file (list filename newname ok-if-already-exists keep-date)))))
fb7933a3 3397
263c02ef
MA
3398(defun tramp-handle-copy-directory (dirname newname &optional keep-date parents)
3399 "Like `copy-directory' for Tramp files."
3400 (let ((t1 (tramp-tramp-file-p dirname))
3401 (t2 (tramp-tramp-file-p newname)))
3402 (with-parsed-tramp-file-name (if t1 dirname newname) nil
3403 (if (and (tramp-get-method-parameter method 'tramp-copy-recursive)
3404 ;; When DIRNAME and NEWNAME are remote, they must have
3405 ;; the same method.
3406 (or (null t1) (null t2)
b000a6e2
MA
3407 (string-equal
3408 (tramp-file-name-method (tramp-dissect-file-name dirname))
3409 (tramp-file-name-method (tramp-dissect-file-name newname)))))
263c02ef
MA
3410 ;; scp or rsync DTRT.
3411 (progn
3412 (setq dirname (directory-file-name (expand-file-name dirname))
3413 newname (directory-file-name (expand-file-name newname)))
3414 (if (and (file-directory-p newname)
3415 (not (string-equal (file-name-nondirectory dirname)
3416 (file-name-nondirectory newname))))
3417 (setq newname
3418 (expand-file-name
3419 (file-name-nondirectory dirname) newname)))
3420 (if (not (file-directory-p (file-name-directory newname)))
3421 (make-directory (file-name-directory newname) parents))
3422 (tramp-do-copy-or-rename-file-out-of-band
3423 'copy dirname newname keep-date))
3424 ;; We must do it file-wise.
3425 (tramp-run-real-handler
3426 'copy-directory (list dirname newname keep-date parents))))))
3427
fb7933a3
KG
3428(defun tramp-handle-rename-file
3429 (filename newname &optional ok-if-already-exists)
00d6fd04 3430 "Like `rename-file' for Tramp files."
fb7933a3 3431 ;; Check if both files are local -- invoke normal rename-file.
a4aeb9a4 3432 ;; Otherwise, use Tramp from local system.
fb7933a3
KG
3433 (setq filename (expand-file-name filename))
3434 (setq newname (expand-file-name newname))
a4aeb9a4 3435 ;; At least one file a Tramp file?
fb7933a3
KG
3436 (if (or (tramp-tramp-file-p filename)
3437 (tramp-tramp-file-p newname))
3438 (tramp-do-copy-or-rename-file
8d60099b 3439 'rename filename newname ok-if-already-exists t t)
00d6fd04
MA
3440 (tramp-run-real-handler
3441 'rename-file (list filename newname ok-if-already-exists))))
fb7933a3
KG
3442
3443(defun tramp-do-copy-or-rename-file
8d60099b 3444 (op filename newname &optional ok-if-already-exists keep-date preserve-uid-gid)
fb7933a3
KG
3445 "Copy or rename a remote file.
3446OP must be `copy' or `rename' and indicates the operation to perform.
3447FILENAME specifies the file to copy or rename, NEWNAME is the name of
3448the new file (for copy) or the new name of the file (for rename).
3449OK-IF-ALREADY-EXISTS means don't barf if NEWNAME exists already.
3450KEEP-DATE means to make sure that NEWNAME has the same timestamp
8d60099b
MA
3451as FILENAME. PRESERVE-UID-GID, when non-nil, instructs to keep
3452the uid and gid if both files are on the same host.
fb7933a3
KG
3453
3454This function is invoked by `tramp-handle-copy-file' and
3455`tramp-handle-rename-file'. It is an error if OP is neither of `copy'
3456and `rename'. FILENAME and NEWNAME must be absolute file names."
3457 (unless (memq op '(copy rename))
3458 (error "Unknown operation `%s', must be `copy' or `rename'" op))
90dc758d 3459 (let ((t1 (tramp-tramp-file-p filename))
00d6fd04 3460 (t2 (tramp-tramp-file-p newname)))
5ec2cc41 3461
da1975d7
MA
3462 (when (and (not ok-if-already-exists) (file-exists-p newname))
3463 (with-parsed-tramp-file-name (if t1 filename newname) nil
3464 (tramp-error
3465 v 'file-already-exists "File %s already exists" newname)))
5ec2cc41 3466
905fb90e
MA
3467 (with-parsed-tramp-file-name (if t1 filename newname) nil
3468 (tramp-message v 0 "Transferring %s to %s..." filename newname))
3469
00d6fd04
MA
3470 (prog1
3471 (cond
3472 ;; Both are Tramp files.
3473 ((and t1 t2)
3474 (with-parsed-tramp-file-name filename v1
3475 (with-parsed-tramp-file-name newname v2
3476 (cond
3477 ;; Shortcut: if method, host, user are the same for both
3478 ;; files, we invoke `cp' or `mv' on the remote host
3479 ;; directly.
3480 ((tramp-equal-remote filename newname)
3481 (tramp-do-copy-or-rename-file-directly
8d60099b
MA
3482 op filename newname
3483 ok-if-already-exists keep-date preserve-uid-gid))
3484
905fb90e 3485 ;; Try out-of-band operation.
7f49fe46
MA
3486 ((tramp-method-out-of-band-p
3487 v1 (nth 7 (file-attributes filename)))
00d6fd04
MA
3488 (tramp-do-copy-or-rename-file-out-of-band
3489 op filename newname keep-date))
8d60099b 3490
00d6fd04
MA
3491 ;; No shortcut was possible. So we copy the
3492 ;; file first. If the operation was `rename', we go
3493 ;; back and delete the original file (if the copy was
3494 ;; successful). The approach is simple-minded: we
3495 ;; create a new buffer, insert the contents of the
3496 ;; source file into it, then write out the buffer to
3497 ;; the target file. The advantage is that it doesn't
3498 ;; matter which filename handlers are used for the
3499 ;; source and target file.
3500 (t
3501 (tramp-do-copy-or-rename-file-via-buffer
3502 op filename newname keep-date))))))
3503
3504 ;; One file is a Tramp file, the other one is local.
3505 ((or t1 t2)
3506 (with-parsed-tramp-file-name (if t1 filename newname) nil
8d60099b
MA
3507 (cond
3508 ;; Fast track on local machine.
3509 ((tramp-local-host-p v)
3510 (tramp-do-copy-or-rename-file-directly
3511 op filename newname
3512 ok-if-already-exists keep-date preserve-uid-gid))
3513
3514 ;; If the Tramp file has an out-of-band method, the corresponding
3515 ;; copy-program can be invoked.
7f49fe46 3516 ((tramp-method-out-of-band-p v (nth 7 (file-attributes filename)))
8d60099b
MA
3517 (tramp-do-copy-or-rename-file-out-of-band
3518 op filename newname keep-date))
3519
3520 ;; Use the inline method via a Tramp buffer.
3521 (t (tramp-do-copy-or-rename-file-via-buffer
3522 op filename newname keep-date)))))
00d6fd04
MA
3523
3524 (t
3525 ;; One of them must be a Tramp file.
3526 (error "Tramp implementation says this cannot happen")))
8d60099b 3527
484ea0b6
MA
3528 ;; In case of `rename', we must flush the cache of the source file.
3529 (when (and t1 (eq op 'rename))
3530 (with-parsed-tramp-file-name filename nil
3531 (tramp-flush-file-property v localname)))
3532
00d6fd04
MA
3533 ;; When newname did exist, we have wrong cached values.
3534 (when t2
3535 (with-parsed-tramp-file-name newname nil
905fb90e
MA
3536 (tramp-flush-file-property v localname)))
3537
3538 (with-parsed-tramp-file-name (if t1 filename newname) nil
3539 (tramp-message v 0 "Transferring %s to %s...done" filename newname)))))
7432277c 3540
38c65fca 3541(defun tramp-do-copy-or-rename-file-via-buffer (op filename newname keep-date)
90dc758d
KG
3542 "Use an Emacs buffer to copy or rename a file.
3543First arg OP is either `copy' or `rename' and indicates the operation.
3544FILENAME is the source file, NEWNAME the target file.
3545KEEP-DATE is non-nil if NEWNAME should have the same timestamp as FILENAME."
8a798e41
MA
3546 (with-temp-buffer
3547 ;; We must disable multibyte, because binary data shall not be
3548 ;; converted.
3549 (set-buffer-multibyte nil)
3550 (let ((coding-system-for-read 'binary)
3551 (jka-compr-inhibit t))
3552 (insert-file-contents-literally filename))
3553 ;; We don't want the target file to be compressed, so we let-bind
3554 ;; `jka-compr-inhibit' to t.
3555 (let ((coding-system-for-write 'binary)
3556 (jka-compr-inhibit t))
3557 (write-region (point-min) (point-max) newname)))
3558 ;; KEEP-DATE handling.
3559 (when keep-date (set-file-times newname (nth 5 (file-attributes filename))))
3560 ;; Set the mode.
b86c1cd8 3561 (set-file-modes newname (tramp-default-file-modes filename))
8a798e41
MA
3562 ;; If the operation was `rename', delete the original file.
3563 (unless (eq op 'copy) (delete-file filename)))
fb7933a3
KG
3564
3565(defun tramp-do-copy-or-rename-file-directly
8d60099b 3566 (op filename newname ok-if-already-exists keep-date preserve-uid-gid)
fb7933a3
KG
3567 "Invokes `cp' or `mv' on the remote system.
3568OP must be one of `copy' or `rename', indicating `cp' or `mv',
8d60099b
MA
3569respectively. FILENAME specifies the file to copy or rename,
3570NEWNAME is the name of the new file (for copy) or the new name of
3571the file (for rename). Both files must reside on the same host.
3572KEEP-DATE means to make sure that NEWNAME has the same timestamp
3573as FILENAME. PRESERVE-UID-GID, when non-nil, instructs to keep
3574the uid and gid from FILENAME."
8a4438b6 3575 (let ((t1 (tramp-tramp-file-p filename))
4f4126e6
MA
3576 (t2 (tramp-tramp-file-p newname))
3577 (file-times (nth 5 (file-attributes filename)))
3578 (file-modes (tramp-default-file-modes filename)))
8a4438b6
MA
3579 (with-parsed-tramp-file-name (if t1 filename newname) nil
3580 (let* ((cmd (cond ((and (eq op 'copy) preserve-uid-gid) "cp -f -p")
3581 ((eq op 'copy) "cp -f")
3582 ((eq op 'rename) "mv -f")
3583 (t (tramp-error
3584 v 'file-error
3585 "Unknown operation `%s', must be `copy' or `rename'"
3586 op))))
3587 (localname1
3588 (if t1 (tramp-handle-file-remote-p filename 'localname) filename))
3589 (localname2
3590 (if t2 (tramp-handle-file-remote-p newname 'localname) newname))
293c24f9
MA
3591 (prefix (file-remote-p (if t1 filename newname)))
3592 cmd-result)
8d60099b 3593
8d60099b 3594 (cond
8a4438b6
MA
3595 ;; Both files are on a remote host, with same user.
3596 ((and t1 t2)
293c24f9
MA
3597 (setq cmd-result
3598 (tramp-send-command-and-check
3599 v
3600 (format "%s %s %s" cmd
3601 (tramp-shell-quote-argument localname1)
3602 (tramp-shell-quote-argument localname2))))
8a4438b6
MA
3603 (with-current-buffer (tramp-get-buffer v)
3604 (goto-char (point-min))
3605 (unless
3606 (or
3607 (and keep-date
3608 ;; Mask cp -f error.
3609 (re-search-forward
3610 tramp-operation-not-permitted-regexp nil t))
293c24f9 3611 (zerop cmd-result))
8a4438b6
MA
3612 (tramp-error-with-buffer
3613 nil v 'file-error
3614 "Copying directly failed, see buffer `%s' for details."
3615 (buffer-name)))))
3616
3617 ;; We are on the local host.
3618 ((or t1 t2)
8d60099b 3619 (cond
8a4438b6 3620 ;; We can do it directly.
87bdd2c7
MA
3621 ((let (file-name-handler-alist)
3622 (and (file-readable-p localname1)
3623 (file-writable-p (file-name-directory localname2))
3624 (or (file-directory-p localname2)
3625 (file-writable-p localname2))))
8d60099b 3626 (if (eq op 'copy)
9e6ab520
MA
3627 (tramp-compat-copy-file
3628 localname1 localname2 ok-if-already-exists
3629 keep-date preserve-uid-gid)
87bdd2c7
MA
3630 (tramp-run-real-handler
3631 'rename-file (list localname1 localname2 ok-if-already-exists))))
8a4438b6
MA
3632
3633 ;; We can do it directly with `tramp-send-command'
946a5aeb
MA
3634 ((and (file-readable-p (concat prefix localname1))
3635 (file-writable-p
3636 (file-name-directory (concat prefix localname2)))
3637 (or (file-directory-p (concat prefix localname2))
3638 (file-writable-p (concat prefix localname2))))
8a4438b6
MA
3639 (tramp-do-copy-or-rename-file-directly
3640 op (concat prefix localname1) (concat prefix localname2)
3641 ok-if-already-exists keep-date t)
3642 ;; We must change the ownership to the local user.
8d60099b 3643 (tramp-set-file-uid-gid
8a4438b6
MA
3644 (concat prefix localname2)
3645 (tramp-get-local-uid 'integer)
3646 (tramp-get-local-gid 'integer)))
8d60099b 3647
8a4438b6
MA
3648 ;; We need a temporary file in between.
3649 (t
2c418c5b
MA
3650 ;; Create the temporary file.
3651 (let ((tmpfile (tramp-compat-make-temp-file localname1)))
917b89a6 3652 (unwind-protect
2c418c5b
MA
3653 (progn
3654 (cond
3655 (t1
917b89a6
MA
3656 (or
3657 (zerop
3658 (tramp-send-command-and-check
3659 v (format
3660 "%s %s %s" cmd
3661 (tramp-shell-quote-argument localname1)
3662 (tramp-shell-quote-argument tmpfile))))
3663 (tramp-error-with-buffer
3664 nil v 'file-error
3665 "Copying directly failed, see buffer `%s' for details."
3666 (tramp-get-buffer v)))
2c418c5b 3667 ;; We must change the ownership as remote user.
917b89a6
MA
3668 ;; Since this does not work reliable, we also
3669 ;; give read permissions.
3670 (set-file-modes
3671 (concat prefix tmpfile) (tramp-octal-to-decimal "0777"))
2c418c5b
MA
3672 (tramp-set-file-uid-gid
3673 (concat prefix tmpfile)
3674 (tramp-get-local-uid 'integer)
3675 (tramp-get-local-gid 'integer)))
3676 (t2
3677 (if (eq op 'copy)
3678 (tramp-compat-copy-file
5ab38c3c 3679 localname1 tmpfile t
2c418c5b
MA
3680 keep-date preserve-uid-gid)
3681 (tramp-run-real-handler
3682 'rename-file
5ab38c3c 3683 (list localname1 tmpfile t)))
2c418c5b 3684 ;; We must change the ownership as local user.
917b89a6
MA
3685 ;; Since this does not work reliable, we also
3686 ;; give read permissions.
3687 (set-file-modes tmpfile (tramp-octal-to-decimal "0777"))
2c418c5b
MA
3688 (tramp-set-file-uid-gid
3689 tmpfile
3690 (tramp-get-remote-uid v 'integer)
3691 (tramp-get-remote-gid v 'integer))))
3692
3693 ;; Move the temporary file to its destination.
3694 (cond
3695 (t2
917b89a6
MA
3696 (or
3697 (zerop
3698 (tramp-send-command-and-check
3699 v (format
3700 "cp -f -p %s %s"
3701 (tramp-shell-quote-argument tmpfile)
3702 (tramp-shell-quote-argument localname2))))
3703 (tramp-error-with-buffer
3704 nil v 'file-error
3705 "Copying directly failed, see buffer `%s' for details."
3706 (tramp-get-buffer v))))
2c418c5b 3707 (t1
ce2cc728
MA
3708 (tramp-run-real-handler
3709 'rename-file
2c418c5b
MA
3710 (list tmpfile localname2 ok-if-already-exists)))))
3711
917b89a6
MA
3712 ;; Save exit.
3713 (condition-case nil
3714 (delete-file tmpfile)
3715 (error)))))))))
8d60099b
MA
3716
3717 ;; Set the time and mode. Mask possible errors.
8d60099b 3718 (condition-case nil
1f107aed 3719 (when keep-date
4f4126e6
MA
3720 (set-file-times newname file-times)
3721 (set-file-modes newname file-modes))
8d60099b
MA
3722 (error)))))
3723
5ec2cc41 3724(defun tramp-do-copy-or-rename-file-out-of-band (op filename newname keep-date)
7432277c 3725 "Invoke rcp program to copy.
905fb90e 3726The method used must be an out-of-band method."
38c65fca 3727 (let ((t1 (tramp-tramp-file-p filename))
5ec2cc41 3728 (t2 (tramp-tramp-file-p newname))
946a5aeb 3729 copy-program copy-args copy-env copy-keep-date port spec
00d6fd04
MA
3730 source target)
3731
3732 (with-parsed-tramp-file-name (if t1 filename newname) nil
905fb90e 3733 (if (and t1 t2)
00d6fd04 3734
905fb90e
MA
3735 ;; Both are Tramp files. We shall optimize it, when the
3736 ;; methods for filename and newname are the same.
3737 (let ((tmpfile (tramp-compat-make-temp-file localname)))
3738 (unwind-protect
3739 (progn
3740 (tramp-do-copy-or-rename-file-out-of-band
3741 op filename tmpfile keep-date)
3742 (tramp-do-copy-or-rename-file-out-of-band
3743 'rename tmpfile newname keep-date))
3744 ;; Save exit.
3745 (condition-case nil
3746 (delete-file tmpfile)
3747 (error))))
3748
3749 ;; Expand hops. Might be necessary for gateway methods.
3750 (setq v (car (tramp-compute-multi-hops v)))
3751 (aset v 3 localname)
3752
3753 ;; Check which ones of source and target are Tramp files.
3754 (setq source (if t1 (tramp-make-copy-program-file-name v) filename)
263c02ef
MA
3755 target (funcall
3756 (if (and (file-directory-p filename)
3757 (string-equal
3758 (file-name-nondirectory filename)
3759 (file-name-nondirectory newname)))
3760 'file-name-directory
3761 'identity)
3762 (if t2 (tramp-make-copy-program-file-name v) newname)))
905fb90e
MA
3763
3764 ;; Check for port number. Until now, there's no need for handling
3765 ;; like method, user, host.
3766 (setq host (tramp-file-name-real-host v)
3767 port (tramp-file-name-port v)
3768 port (or (and port (number-to-string port)) ""))
3769
3770 ;; Compose copy command.
3771 (setq spec `((?h . ,host) (?u . ,user) (?p . ,port)
3772 (?t . ,(tramp-get-connection-property
3773 (tramp-get-connection-process v) "temp-file" ""))
3774 (?k . ,(if keep-date " " "")))
3775 copy-program (tramp-get-method-parameter
3776 method 'tramp-copy-program)
3777 copy-keep-date (tramp-get-method-parameter
3778 method 'tramp-copy-keep-date)
3779 copy-args
3780 (delq
3781 nil
3782 (mapcar
aa485f7c
MA
3783 (lambda (x)
3784 (setq
3785 x
3786 ;; " " is indication for keep-date argument.
3787 (delete " " (mapcar (lambda (y) (format-spec y spec)) x)))
3788 (unless (member "" x) (mapconcat 'identity x " ")))
946a5aeb
MA
3789 (tramp-get-method-parameter method 'tramp-copy-args)))
3790 copy-env
3791 (delq
3792 nil
3793 (mapcar
aa485f7c
MA
3794 (lambda (x)
3795 (setq x (mapcar (lambda (y) (format-spec y spec)) x))
3796 (unless (member "" x) (mapconcat 'identity x " ")))
946a5aeb 3797 (tramp-get-method-parameter method 'tramp-copy-env))))
905fb90e
MA
3798
3799 ;; Check for program.
3800 (when (and (fboundp 'executable-find)
3801 (not (let ((default-directory
3802 (tramp-compat-temporary-file-directory)))
3803 (executable-find copy-program))))
3804 (tramp-error
3805 v 'file-error "Cannot find copy program: %s" copy-program))
00d6fd04 3806
905fb90e
MA
3807 (unwind-protect
3808 (with-temp-buffer
3809 ;; The default directory must be remote.
3810 (let ((default-directory
946a5aeb
MA
3811 (file-name-directory (if t1 filename newname)))
3812 (process-environment (copy-sequence process-environment)))
905fb90e
MA
3813 ;; Set the transfer process properties.
3814 (tramp-set-connection-property
3815 v "process-name" (buffer-name (current-buffer)))
3816 (tramp-set-connection-property
3817 v "process-buffer" (current-buffer))
946a5aeb
MA
3818 (while copy-env
3819 (tramp-message v 5 "%s=\"%s\"" (car copy-env) (cadr copy-env))
3820 (setenv (pop copy-env) (pop copy-env)))
905fb90e
MA
3821
3822 ;; Use an asynchronous process. By this, password can
3823 ;; be handled. The default directory must be local, in
3824 ;; order to apply the correct `copy-program'. We don't
3825 ;; set a timeout, because the copying of large files can
3826 ;; last longer than 60 secs.
3827 (let ((p (let ((default-directory
3828 (tramp-compat-temporary-file-directory)))
3829 (apply 'start-process
3830 (tramp-get-connection-property
3831 v "process-name" nil)
3832 (tramp-get-connection-property
3833 v "process-buffer" nil)
3834 copy-program
3835 (append copy-args (list source target))))))
3836 (tramp-message
3837 v 6 "%s" (mapconcat 'identity (process-command p) " "))
3838 (tramp-set-process-query-on-exit-flag p nil)
3839 (tramp-process-actions p v tramp-actions-copy-out-of-band))))
00d6fd04 3840
905fb90e
MA
3841 ;; Reset the transfer process properties.
3842 (tramp-set-connection-property v "process-name" nil)
3843 (tramp-set-connection-property v "process-buffer" nil))
00d6fd04 3844
905fb90e
MA
3845 ;; Handle KEEP-DATE argument.
3846 (when (and keep-date (not copy-keep-date))
3847 (set-file-times newname (nth 5 (file-attributes filename))))
01917a18 3848
905fb90e
MA
3849 ;; Set the mode.
3850 (unless (and keep-date copy-keep-date)
3851 (set-file-modes newname (tramp-default-file-modes filename))))
5ec2cc41 3852
905fb90e
MA
3853 ;; If the operation was `rename', delete the original file.
3854 (unless (eq op 'copy)
3855 (delete-file filename)))))
7432277c 3856
fb7933a3 3857(defun tramp-handle-make-directory (dir &optional parents)
00d6fd04 3858 "Like `make-directory' for Tramp files."
ac474af1 3859 (setq dir (expand-file-name dir))
c62c9d08 3860 (with-parsed-tramp-file-name dir nil
c15cdf02 3861 (tramp-flush-directory-property v (file-name-directory localname))
b1d06e75
KG
3862 (save-excursion
3863 (tramp-barf-unless-okay
00d6fd04 3864 v
9c13938d 3865 (format "%s %s"
b1d06e75 3866 (if parents "mkdir -p" "mkdir")
7432277c 3867 (tramp-shell-quote-argument localname))
b1d06e75 3868 "Couldn't make directory %s" dir))))
fb7933a3 3869
c15cdf02 3870(defun tramp-handle-delete-directory (directory &optional recursive)
00d6fd04 3871 "Like `delete-directory' for Tramp files."
ac474af1 3872 (setq directory (expand-file-name directory))
c62c9d08 3873 (with-parsed-tramp-file-name directory nil
00d6fd04
MA
3874 (tramp-flush-directory-property v localname)
3875 (unless (zerop (tramp-send-command-and-check
3876 v
c15cdf02
MA
3877 (format
3878 "%s %s"
3879 (if recursive "rm -rf" "rmdir")
3880 (tramp-shell-quote-argument localname))))
00d6fd04 3881 (tramp-error v 'file-error "Couldn't delete %s" directory))))
fb7933a3
KG
3882
3883(defun tramp-handle-delete-file (filename)
00d6fd04 3884 "Like `delete-file' for Tramp files."
ac474af1 3885 (setq filename (expand-file-name filename))
c62c9d08 3886 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3887 (tramp-flush-file-property v localname)
3888 (unless (zerop (tramp-send-command-and-check
3889 v
3890 (format "rm -f %s"
3891 (tramp-shell-quote-argument localname))))
3892 (tramp-error v 'file-error "Couldn't delete %s" filename))))
fb7933a3
KG
3893
3894;; Dired.
3895
3896;; CCC: This does not seem to be enough. Something dies when
a4aeb9a4 3897;; we try and delete two directories under Tramp :/
fb7933a3
KG
3898(defun tramp-handle-dired-recursive-delete-directory (filename)
3899 "Recursively delete the directory given.
00d6fd04 3900This is like `dired-recursive-delete-directory' for Tramp files."
c62c9d08 3901 (with-parsed-tramp-file-name filename nil
00d6fd04 3902 ;; Run a shell command 'rm -r <localname>'
260821d3 3903 ;; Code shamelessly stolen from the dired implementation and, um, hacked :)
00d6fd04
MA
3904 (unless (file-exists-p filename)
3905 (tramp-error v 'file-error "No such directory: %s" filename))
fb7933a3 3906 ;; Which is better, -r or -R? (-r works for me <daniel@danann.net>)
00d6fd04
MA
3907 (tramp-send-command
3908 v
9c13938d 3909 (format "rm -rf %s" (tramp-shell-quote-argument localname))
00d6fd04
MA
3910 ;; Don't read the output, do it explicitely.
3911 nil t)
fb7933a3
KG
3912 ;; Wait for the remote system to return to us...
3913 ;; This might take a while, allow it plenty of time.
00d6fd04 3914 (tramp-wait-for-output (tramp-get-connection-process v) 120)
fb7933a3 3915 ;; Make sure that it worked...
c15cdf02 3916 (tramp-flush-directory-property v localname)
07dfe738 3917 (and (file-exists-p filename)
00d6fd04
MA
3918 (tramp-error
3919 v 'file-error "Failed to recursively delete %s" filename))))
bf247b6e 3920
5ec2cc41 3921(defun tramp-handle-dired-compress-file (file &rest ok-flag)
00d6fd04 3922 "Like `dired-compress-file' for Tramp files."
5ec2cc41
KG
3923 ;; OK-FLAG is valid for XEmacs only, but not implemented.
3924 ;; Code stolen mainly from dired-aux.el.
3925 (with-parsed-tramp-file-name file nil
00d6fd04 3926 (tramp-flush-file-property v localname)
5ec2cc41
KG
3927 (save-excursion
3928 (let ((suffixes
3929 (if (not (featurep 'xemacs))
3930 ;; Emacs case
3931 (symbol-value 'dired-compress-file-suffixes)
3932 ;; XEmacs has `dired-compression-method-alist', which is
3933 ;; transformed into `dired-compress-file-suffixes' structure.
3934 (mapcar
aa485f7c
MA
3935 (lambda (x)
3936 (list (concat (regexp-quote (nth 1 x)) "\\'")
3937 nil
3938 (mapconcat 'identity (nth 3 x) " ")))
5ec2cc41
KG
3939 (symbol-value 'dired-compression-method-alist))))
3940 suffix)
3941 ;; See if any suffix rule matches this file name.
3942 (while suffixes
3943 (let (case-fold-search)
3944 (if (string-match (car (car suffixes)) localname)
3945 (setq suffix (car suffixes) suffixes nil))
3946 (setq suffixes (cdr suffixes))))
3947
3948 (cond ((file-symlink-p file)
3949 nil)
3950 ((and suffix (nth 2 suffix))
3951 ;; We found an uncompression rule.
00d6fd04 3952 (tramp-message v 0 "Uncompressing %s..." file)
5ec2cc41 3953 (when (zerop (tramp-send-command-and-check
00d6fd04
MA
3954 v (concat (nth 2 suffix) " " localname)))
3955 (tramp-message v 0 "Uncompressing %s...done" file)
38c65fca
KG
3956 ;; `dired-remove-file' is not defined in XEmacs
3957 (funcall (symbol-function 'dired-remove-file) file)
5ec2cc41
KG
3958 (string-match (car suffix) file)
3959 (concat (substring file 0 (match-beginning 0)))))
3960 (t
3961 ;; We don't recognize the file as compressed, so compress it.
3962 ;; Try gzip.
00d6fd04 3963 (tramp-message v 0 "Compressing %s..." file)
5ec2cc41 3964 (when (zerop (tramp-send-command-and-check
00d6fd04
MA
3965 v (concat "gzip -f " localname)))
3966 (tramp-message v 0 "Compressing %s...done" file)
38c65fca
KG
3967 ;; `dired-remove-file' is not defined in XEmacs
3968 (funcall (symbol-function 'dired-remove-file) file)
5ec2cc41
KG
3969 (cond ((file-exists-p (concat file ".gz"))
3970 (concat file ".gz"))
3971 ((file-exists-p (concat file ".z"))
3972 (concat file ".z"))
3973 (t nil)))))))))
fb7933a3 3974
70c11b0b
MA
3975(defun tramp-handle-dired-uncache (dir)
3976 "Like `dired-uncache' for Tramp files."
3977 (with-parsed-tramp-file-name dir nil
3978 (tramp-flush-file-property v localname)))
3979
fb7933a3
KG
3980;; Pacify byte-compiler. The function is needed on XEmacs only. I'm
3981;; not sure at all that this is the right way to do it, but let's hope
3982;; it works for now, and wait for a guru to point out the Right Way to
3983;; achieve this.
3984;;(eval-when-compile
3985;; (unless (fboundp 'dired-insert-set-properties)
3986;; (fset 'dired-insert-set-properties 'ignore)))
3987;; Gerd suggests this:
3988(eval-when-compile (require 'dired))
3989;; Note that dired is required at run-time, too, when it is needed.
3990;; It is only needed on XEmacs for the function
3991;; `dired-insert-set-properties'.
3992
3993(defun tramp-handle-insert-directory
3994 (filename switches &optional wildcard full-directory-p)
00d6fd04
MA
3995 "Like `insert-directory' for Tramp files."
3996 (setq filename (expand-file-name filename))
3997 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3998 (if (and (featurep 'ls-lisp)
3999 (not (symbol-value 'ls-lisp-use-insert-directory-program)))
4000 (tramp-run-real-handler
4001 'insert-directory (list filename switches wildcard full-directory-p))
8e754ea2
MA
4002 (when (and (string-match "^--dired\\s-+" switches)
4003 (not (tramp-get-ls-command-with-dired v)))
00d6fd04
MA
4004 (setq switches (replace-match "" nil t switches)))
4005 (tramp-message
4006 v 4 "Inserting directory `ls %s %s', wildcard %s, fulldir %s"
c82c5727
LH
4007 switches filename (if wildcard "yes" "no")
4008 (if full-directory-p "yes" "no"))
4009 (when wildcard
87bdd2c7
MA
4010 (setq wildcard (tramp-run-real-handler
4011 'file-name-nondirectory (list localname)))
4012 (setq localname (tramp-run-real-handler
4013 'file-name-directory (list localname))))
c82c5727
LH
4014 (when (listp switches)
4015 (setq switches (mapconcat 'identity switches " ")))
4016 (unless full-directory-p
4017 (setq switches (concat "-d " switches)))
4018 (when wildcard
4019 (setq switches (concat switches " " wildcard)))
00d6fd04
MA
4020 ;; If `full-directory-p', we just say `ls -l FILENAME'.
4021 ;; Else we chdir to the parent directory, then say `ls -ld BASENAME'.
4022 (if full-directory-p
4023 (tramp-send-command
4024 v
4025 (format "%s %s %s"
4026 (tramp-get-ls-command v)
4027 switches
4028 (if wildcard
4029 localname
4030 (tramp-shell-quote-argument (concat localname ".")))))
4031 (tramp-barf-unless-okay
4032 v
4033 (format "cd %s" (tramp-shell-quote-argument
87bdd2c7
MA
4034 (tramp-run-real-handler
4035 'file-name-directory (list localname))))
00d6fd04 4036 "Couldn't `cd %s'"
87bdd2c7
MA
4037 (tramp-shell-quote-argument
4038 (tramp-run-real-handler 'file-name-directory (list localname))))
00d6fd04
MA
4039 (tramp-send-command
4040 v
4041 (format "%s %s %s"
4042 (tramp-get-ls-command v)
4043 switches
4044 (if (or wildcard
87bdd2c7
MA
4045 (zerop (length
4046 (tramp-run-real-handler
4047 'file-name-nondirectory (list localname)))))
00d6fd04
MA
4048 ""
4049 (tramp-shell-quote-argument
87bdd2c7
MA
4050 (tramp-run-real-handler
4051 'file-name-nondirectory (list localname)))))))
8e754ea2
MA
4052 (let ((beg (point)))
4053 ;; We cannot use `insert-buffer-substring' because the Tramp
4054 ;; buffer changes its contents before insertion due to calling
4055 ;; `expand-file' and alike.
4056 (insert
4057 (with-current-buffer (tramp-get-buffer v)
4058 (buffer-string)))
4059
4060 ;; Check for "--dired" output.
8e754ea2
MA
4061 (forward-line -2)
4062 (when (looking-at "//DIRED//")
7ba1d9c2 4063 (let ((end (tramp-compat-line-end-position))
8e754ea2
MA
4064 (linebeg (point)))
4065 ;; Now read the numeric positions of file names.
4066 (goto-char linebeg)
4067 (forward-word 1)
4068 (forward-char 3)
4069 (while (< (point) end)
4070 (let ((start (+ beg (read (current-buffer))))
4071 (end (+ beg (read (current-buffer)))))
7f49fe46 4072 (if (memq (char-after end) '(?\n ?\ ))
8e754ea2
MA
4073 ;; End is followed by \n or by " -> ".
4074 (put-text-property start end 'dired-filename t)))))
03db0efc 4075 ;; Remove trailing lines.
7ba1d9c2 4076 (goto-char (tramp-compat-line-beginning-position))
8e754ea2
MA
4077 (while (looking-at "//")
4078 (forward-line 1)
7ba1d9c2 4079 (delete-region (match-beginning 0) (point)))))
8e754ea2 4080 (goto-char (point-max)))))
fb7933a3 4081
fb7933a3 4082(defun tramp-handle-unhandled-file-name-directory (filename)
00d6fd04 4083 "Like `unhandled-file-name-directory' for Tramp files."
8a798e41
MA
4084 ;; With Emacs 23, we could simply return `nil'. But we must keep it
4085 ;; for backward compatibility.
ce3f516f 4086 (expand-file-name "~/"))
fb7933a3
KG
4087
4088;; Canonicalization of file names.
4089
fb7933a3 4090(defun tramp-handle-expand-file-name (name &optional dir)
00d6fd04 4091 "Like `expand-file-name' for Tramp files.
7432277c
KG
4092If the localname part of the given filename starts with \"/../\" then
4093the result will be a local, non-Tramp, filename."
fb7933a3
KG
4094 ;; If DIR is not given, use DEFAULT-DIRECTORY or "/".
4095 (setq dir (or dir default-directory "/"))
4096 ;; Unless NAME is absolute, concat DIR and NAME.
4097 (unless (file-name-absolute-p name)
4098 (setq name (concat (file-name-as-directory dir) name)))
00d6fd04 4099 ;; If NAME is not a Tramp file, run the real handler.
fb7933a3 4100 (if (not (tramp-tramp-file-p name))
00d6fd04 4101 (tramp-run-real-handler 'expand-file-name (list name nil))
fb7933a3 4102 ;; Dissect NAME.
c62c9d08 4103 (with-parsed-tramp-file-name name nil
87bdd2c7 4104 (unless (tramp-run-real-handler 'file-name-absolute-p (list localname))
7432277c 4105 (setq localname (concat "~/" localname)))
00d6fd04
MA
4106 ;; Tilde expansion if necessary. This needs a shell which
4107 ;; groks tilde expansion! The function `tramp-find-shell' is
4108 ;; supposed to find such a shell on the remote host. Please
4109 ;; tell me about it when this doesn't work on your system.
4110 (when (string-match "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname)
4111 (let ((uname (match-string 1 localname))
4112 (fname (match-string 2 localname)))
4113 ;; We cannot simply apply "~/", because under sudo "~/" is
4114 ;; expanded to the local user home directory but to the
4115 ;; root home directory. On the other hand, using always
4116 ;; the default user name for tilde expansion is not
4117 ;; appropriate either, because ssh and companions might
4118 ;; use a user name from the config file.
4119 (when (and (string-equal uname "~")
4120 (string-match "\\`su\\(do\\)?\\'" method))
4121 (setq uname (concat uname user)))
4122 (setq uname
4123 (with-connection-property v uname
4124 (tramp-send-command v (format "cd %s; pwd" uname))
4125 (with-current-buffer (tramp-get-buffer v)
4126 (goto-char (point-min))
9e6ab520 4127 (buffer-substring (point) (tramp-compat-line-end-position)))))
00d6fd04
MA
4128 (setq localname (concat uname fname))))
4129 ;; There might be a double slash, for example when "~/"
cb85dcd0 4130 ;; expands to "/". Remove this.
00d6fd04
MA
4131 (while (string-match "//" localname)
4132 (setq localname (replace-match "/" t t localname)))
4133 ;; No tilde characters in file name, do normal
a17632c1
MA
4134 ;; `expand-file-name' (this does "/./" and "/../"). We bind
4135 ;; `directory-sep-char' here for XEmacs on Windows, which would
4136 ;; otherwise use backslash. `default-directory' is bound,
4137 ;; because on Windows there would be problems with UNC shares or
4138 ;; Cygwin mounts.
aff67808
MA
4139 (let ((directory-sep-char ?/)
4140 (default-directory (tramp-compat-temporary-file-directory)))
4141 (tramp-make-tramp-file-name
4142 method user host
4143 (tramp-drop-volume-letter
87bdd2c7
MA
4144 (tramp-run-real-handler
4145 'expand-file-name (list localname))))))))
00d6fd04 4146
c23c3394
MA
4147(defun tramp-replace-environment-variables (filename)
4148 "Replace environment variables in FILENAME.
4149Return the string with the replaced variables."
2e271195 4150 (save-match-data
ec5145d6 4151 (let ((idx (string-match "$\\(\\w+\\)" filename)))
2e271195 4152 ;; `$' is coded as `$$'.
ec5145d6
MA
4153 (when (and idx
4154 (or (zerop idx) (not (eq ?$ (aref filename (1- idx)))))
4155 (getenv (match-string 1 filename)))
2e271195
MA
4156 (setq filename
4157 (replace-match
4158 (substitute-in-file-name (match-string 0 filename))
4159 t nil filename)))
4160 filename)))
c23c3394 4161
00d6fd04
MA
4162(defun tramp-handle-substitute-in-file-name (filename)
4163 "Like `substitute-in-file-name' for Tramp files.
4164\"//\" and \"/~\" substitute only in the local filename part.
4165If the URL Tramp syntax is chosen, \"//\" as method delimeter and \"/~\" at
4166beginning of local filename are not substituted."
c23c3394
MA
4167 ;; First, we must replace environment variables.
4168 (setq filename (tramp-replace-environment-variables filename))
00d6fd04
MA
4169 (with-parsed-tramp-file-name filename nil
4170 (if (equal tramp-syntax 'url)
4171 ;; We need to check localname only. The other parts cannot contain
4172 ;; "//" or "/~".
4173 (if (and (> (length localname) 1)
4174 (or (string-match "//" localname)
4175 (string-match "/~" localname 1)))
4176 (tramp-run-real-handler 'substitute-in-file-name (list filename))
4177 (tramp-make-tramp-file-name
4178 (when method (substitute-in-file-name method))
4179 (when user (substitute-in-file-name user))
4180 (when host (substitute-in-file-name host))
87bdd2c7
MA
4181 (when localname
4182 (tramp-run-real-handler
4183 'substitute-in-file-name (list localname)))))
00d6fd04
MA
4184 ;; Ignore in LOCALNAME everything before "//" or "/~".
4185 (when (and (stringp localname) (string-match ".+?/\\(/\\|~\\)" localname))
4186 (setq filename
b08104a0
MA
4187 (concat (file-remote-p filename)
4188 (replace-match "\\1" nil nil localname)))
00d6fd04
MA
4189 ;; "/m:h:~" does not work for completion. We use "/m:h:~/".
4190 (when (string-match "~$" filename)
4191 (setq filename (concat filename "/"))))
4192 (tramp-run-real-handler 'substitute-in-file-name (list filename)))))
4193
4194;; In XEmacs, electricity is implemented via a key map for ?/ and ?~,
4195;; which calls corresponding functions (see minibuf.el).
4196(when (fboundp 'minibuffer-electric-separator)
9e6ab520 4197 (mapc
aa485f7c
MA
4198 (lambda (x)
4199 (eval
4200 `(defadvice ,x
4201 (around ,(intern (format "tramp-advice-%s" x)) activate)
4202 "Invoke `substitute-in-file-name' for Tramp files."
4203 (if (and (symbol-value 'minibuffer-electric-file-name-behavior)
4204 (tramp-tramp-file-p (buffer-substring)))
4205 ;; We don't need to handle `last-input-event', because
4206 ;; due to the key map we know it must be ?/ or ?~.
4207 (let ((s (concat (buffer-substring (point-min) (point))
4208 (string last-command-char))))
4209 (delete-region (point-min) (point))
4210 (insert (substitute-in-file-name s))
4211 (setq ad-return-value last-command-char))
4212 ad-do-it))))
00d6fd04
MA
4213
4214 '(minibuffer-electric-separator
4215 minibuffer-electric-tilde)))
4216
4217
0664ff72 4218;;; Remote commands:
fb7933a3 4219
00d6fd04
MA
4220(defun tramp-handle-executable-find (command)
4221 "Like `executable-find' for Tramp files."
4222 (with-parsed-tramp-file-name default-directory nil
f84638eb 4223 (tramp-find-executable v command (tramp-get-remote-path v) t)))
00d6fd04
MA
4224
4225;; We use BUFFER also as connection buffer during setup. Because of
4226;; this, its original contents must be saved, and restored once
4227;; connection has been setup.
4228(defun tramp-handle-start-file-process (name buffer program &rest args)
4229 "Like `start-file-process' for Tramp files."
4230 (with-parsed-tramp-file-name default-directory nil
9fb2cdc5
GM
4231 (unless (stringp program)
4232 (tramp-error
4233 v 'file-error "pty association is not supported for `%s'" name))
00d6fd04 4234 (unwind-protect
263c02ef
MA
4235 (let ((command (format "cd %s; exec %s"
4236 (tramp-shell-quote-argument localname)
4237 (mapconcat 'tramp-shell-quote-argument
4238 (cons program args) " ")))
4239 (name1 name)
38d63e6a 4240 (i 0))
2296b54d 4241 (unless buffer
6ce63faf 4242 ;; BUFFER can be nil. We use a temporary buffer.
2296b54d 4243 (setq buffer (generate-new-buffer tramp-temp-buffer-name)))
38d63e6a
MA
4244 (while (get-process name1)
4245 ;; NAME must be unique as process name.
4246 (setq i (1+ i)
4247 name1 (format "%s<%d>" name i)))
4248 (setq name name1)
00d6fd04
MA
4249 ;; Set the new process properties.
4250 (tramp-set-connection-property v "process-name" name)
2296b54d 4251 (tramp-set-connection-property v "process-buffer" buffer)
00d6fd04 4252 ;; Activate narrowing in order to save BUFFER contents.
11c71217
MA
4253 ;; Clear also the modification time; otherwise we might be
4254 ;; interrupted by `verify-visited-file-modtime'.
00d6fd04 4255 (with-current-buffer (tramp-get-connection-buffer v)
11c71217 4256 (clear-visited-file-modtime)
00d6fd04 4257 (narrow-to-region (point-max) (point-max)))
263c02ef 4258 ;; Send the command. `tramp-send-command' opens a new
00d6fd04 4259 ;; connection.
263c02ef 4260 (tramp-send-command v command nil t) ; nooutput
6ce63faf
MA
4261 ;; Set query flag for this process.
4262 (tramp-set-process-query-on-exit-flag
4263 (tramp-get-connection-process v) t)
00d6fd04
MA
4264 ;; Return process.
4265 (tramp-get-connection-process v))
4266 ;; Save exit.
ce3f516f 4267 (with-current-buffer (tramp-get-connection-buffer v)
6ce63faf
MA
4268 (if (string-match tramp-temp-buffer-name (buffer-name))
4269 (progn
4270 (set-process-buffer (tramp-get-connection-process v) nil)
4271 (kill-buffer (current-buffer)))
4272 (widen)
4273 (goto-char (point-max))))
00d6fd04
MA
4274 (tramp-set-connection-property v "process-name" nil)
4275 (tramp-set-connection-property v "process-buffer" nil))))
4276
4277(defun tramp-handle-process-file
4278 (program &optional infile destination display &rest args)
4279 "Like `process-file' for Tramp files."
4280 ;; The implementation is not complete yet.
4281 (when (and (numberp destination) (zerop destination))
4282 (error "Implementation does not handle immediate return"))
4283
4284 (with-parsed-tramp-file-name default-directory nil
a6e96327 4285 (let (command input tmpinput stderr tmpstderr outbuf ret)
00d6fd04
MA
4286 ;; Compute command.
4287 (setq command (mapconcat 'tramp-shell-quote-argument
4288 (cons program args) " "))
4289 ;; Determine input.
4290 (if (null infile)
4291 (setq input "/dev/null")
4292 (setq infile (expand-file-name infile))
4293 (if (tramp-equal-remote default-directory infile)
4294 ;; INFILE is on the same remote host.
4295 (setq input (with-parsed-tramp-file-name infile nil localname))
4296 ;; INFILE must be copied to remote host.
a6e96327
MA
4297 (setq input (tramp-make-tramp-temp-file v)
4298 tmpinput (tramp-make-tramp-file-name method user host input))
4299 (copy-file infile tmpinput t)))
00d6fd04
MA
4300 (when input (setq command (format "%s <%s" command input)))
4301
4302 ;; Determine output.
4303 (cond
bede3e9f 4304 ;; Just a buffer.
00d6fd04
MA
4305 ((bufferp destination)
4306 (setq outbuf destination))
bede3e9f 4307 ;; A buffer name.
00d6fd04
MA
4308 ((stringp destination)
4309 (setq outbuf (get-buffer-create destination)))
4310 ;; (REAL-DESTINATION ERROR-DESTINATION)
4311 ((consp destination)
bede3e9f 4312 ;; output.
00d6fd04
MA
4313 (cond
4314 ((bufferp (car destination))
4315 (setq outbuf (car destination)))
4316 ((stringp (car destination))
0664ff72
MA
4317 (setq outbuf (get-buffer-create (car destination))))
4318 ((car destination)
4319 (setq outbuf (current-buffer))))
bede3e9f 4320 ;; stderr.
00d6fd04
MA
4321 (cond
4322 ((stringp (cadr destination))
4323 (setcar (cdr destination) (expand-file-name (cadr destination)))
4324 (if (tramp-equal-remote default-directory (cadr destination))
4325 ;; stderr is on the same remote host.
4326 (setq stderr (with-parsed-tramp-file-name
4327 (cadr destination) nil localname))
4328 ;; stderr must be copied to remote host. The temporary
4329 ;; file must be deleted after execution.
a6e96327
MA
4330 (setq stderr (tramp-make-tramp-temp-file v)
4331 tmpstderr (tramp-make-tramp-file-name
4332 method user host stderr))))
bede3e9f 4333 ;; stderr to be discarded.
00d6fd04
MA
4334 ((null (cadr destination))
4335 (setq stderr "/dev/null"))))
4336 ;; 't
4337 (destination
4338 (setq outbuf (current-buffer))))
4339 (when stderr (setq command (format "%s 2>%s" command stderr)))
4340
00d6fd04
MA
4341 ;; Send the command. It might not return in time, so we protect it.
4342 (condition-case nil
4343 (unwind-protect
293c24f9
MA
4344 (setq ret
4345 (tramp-send-command-and-check
4346 v (format "\\cd %s; %s"
4347 (tramp-shell-quote-argument localname)
4348 command)))
00d6fd04
MA
4349 ;; We should show the output anyway.
4350 (when outbuf
293c24f9
MA
4351 (with-current-buffer outbuf
4352 (insert
4353 (with-current-buffer (tramp-get-connection-buffer v)
4354 (buffer-string))))
00d6fd04 4355 (when display (display-buffer outbuf))))
260821d3
MA
4356 ;; When the user did interrupt, we should do it also. We use
4357 ;; return code -1 as marker.
4358 (quit
4359 (kill-buffer (tramp-get-connection-buffer v))
4360 (setq ret -1))
4361 ;; Handle errors.
00d6fd04
MA
4362 (error
4363 (kill-buffer (tramp-get-connection-buffer v))
4364 (setq ret 1)))
a6e96327 4365
a6e96327
MA
4366 ;; Provide error file.
4367 (when tmpstderr (rename-file tmpstderr (cadr destination) t))
263c02ef 4368
260821d3
MA
4369 ;; Cleanup. We remove all file cache values for the connection,
4370 ;; because the remote process could have changed them.
a6e96327 4371 (when tmpinput (delete-file tmpinput))
946a5aeb
MA
4372
4373 ;; `process-file-side-effects' has been introduced with GNU
4374 ;; Emacs 23.2. If set to `nil', no remote file will be changed
4375 ;; by `program'. If it doesn't exist, we assume its default
4376 ;; value 't'.
4377 (unless (and (boundp 'process-file-side-effects)
4378 (not (symbol-value 'process-file-side-effects)))
4379 (tramp-flush-directory-property v ""))
4380
00d6fd04 4381 ;; Return exit status.
260821d3
MA
4382 (if (equal ret -1)
4383 (keyboard-quit)
4384 ret))))
00d6fd04 4385
a4aeb9a4
MA
4386(defun tramp-local-call-process
4387 (program &optional infile destination display &rest args)
4388 "Calls `call-process' on the local host.
4389This is needed because for some Emacs flavors Tramp has
4390defadviced `call-process' to behave like `process-file'. The
4391Lisp error raised when PROGRAM is nil is trapped also, returning 1."
4392 (let ((default-directory
4393 (if (file-remote-p default-directory)
4394 (tramp-compat-temporary-file-directory)
4395 default-directory)))
4396 (if (executable-find program)
4397 (apply 'call-process program infile destination display args)
4398 1)))
4399
00d6fd04
MA
4400(defun tramp-handle-call-process-region
4401 (start end program &optional delete buffer display &rest args)
4402 "Like `call-process-region' for Tramp files."
258800f8 4403 (let ((tmpfile (tramp-compat-make-temp-file "")))
00d6fd04
MA
4404 (write-region start end tmpfile)
4405 (when delete (delete-region start end))
4406 (unwind-protect
4407 (apply 'call-process program tmpfile buffer display args)
4408 (delete-file tmpfile))))
4409
4410(defun tramp-handle-shell-command
4411 (command &optional output-buffer error-buffer)
4412 "Like `shell-command' for Tramp files."
ce3f516f 4413 (let* ((asynchronous (string-match "[ \t]*&[ \t]*\\'" command))
b8bfcf96
MA
4414 ;; We cannot use `shell-file-name' and `shell-command-switch',
4415 ;; they are variables of the local host.
4416 (args (list "/bin/sh" "-c" (substring command 0 asynchronous)))
5d2ebd96 4417 current-buffer-p
ce3f516f 4418 (output-buffer
27e813fe
MA
4419 (cond
4420 ((bufferp output-buffer) output-buffer)
4421 ((stringp output-buffer) (get-buffer-create output-buffer))
5d2ebd96
AS
4422 (output-buffer
4423 (setq current-buffer-p t)
4424 (current-buffer))
42bc9b6d 4425 (t (get-buffer-create
27e813fe
MA
4426 (if asynchronous
4427 "*Async Shell Command*"
4428 "*Shell Command Output*")))))
4429 (error-buffer
4430 (cond
4431 ((bufferp error-buffer) error-buffer)
4432 ((stringp error-buffer) (get-buffer-create error-buffer))))
ce3f516f 4433 (buffer
27e813fe 4434 (if (and (not asynchronous) error-buffer)
ce3f516f
MA
4435 (with-parsed-tramp-file-name default-directory nil
4436 (list output-buffer (tramp-make-tramp-temp-file v)))
42bc9b6d 4437 output-buffer))
cfb5c0db 4438 (p (get-buffer-process output-buffer)))
42bc9b6d
MA
4439
4440 ;; Check whether there is another process running. Tramp does not
4441 ;; support 2 (asynchronous) processes in parallel.
cfb5c0db 4442 (when p
42bc9b6d 4443 (if (yes-or-no-p "A command is running. Kill it? ")
699a11fb
GM
4444 (condition-case nil
4445 (kill-process p)
4446 (error nil))
42bc9b6d
MA
4447 (error "Shell command in progress")))
4448
f34db316
AS
4449 (if current-buffer-p
4450 (progn
4451 (barf-if-buffer-read-only)
4452 (push-mark nil t))
5d2ebd96
AS
4453 (with-current-buffer output-buffer
4454 (setq buffer-read-only nil)
4455 (erase-buffer)))
42bc9b6d 4456
5d2ebd96 4457 (if (and (not current-buffer-p) (integerp asynchronous))
42bc9b6d
MA
4458 (prog1
4459 ;; Run the process.
3412f35d 4460 (apply 'start-file-process "*Async Shell*" buffer args)
42bc9b6d 4461 ;; Display output.
cfb5c0db
MA
4462 (pop-to-buffer output-buffer)
4463 (setq mode-line-process '(":%s"))
4464 (require 'shell) (shell-mode))
42bc9b6d
MA
4465
4466 (prog1
4467 ;; Run the process.
4468 (apply 'process-file (car args) nil buffer nil (cdr args))
4469 ;; Insert error messages if they were separated.
4470 (when (listp buffer)
4471 (with-current-buffer error-buffer
4472 (insert-file-contents (cadr buffer)))
4473 (delete-file (cadr buffer)))
f34db316
AS
4474 (if current-buffer-p
4475 ;; This is like exchange-point-and-mark, but doesn't
4476 ;; activate the mark. It is cleaner to avoid activation,
4477 ;; even though the command loop would deactivate the mark
4478 ;; because we inserted text.
4479 (goto-char (prog1 (mark t)
4480 (set-marker (mark-marker) (point)
4481 (current-buffer))))
4482 ;; There's some output, display it.
4483 (when (with-current-buffer output-buffer (> (point-max) (point-min)))
4484 (if (functionp 'display-message-or-buffer)
4485 (funcall (symbol-function 'display-message-or-buffer)
4486 output-buffer)
4487 (pop-to-buffer output-buffer))))))))
00d6fd04
MA
4488
4489;; File Editing.
4490
4491(defvar tramp-handle-file-local-copy-hook nil
4492 "Normal hook to be run at the end of `tramp-handle-file-local-copy'.")
4493
fb7933a3 4494(defun tramp-handle-file-local-copy (filename)
00d6fd04 4495 "Like `file-local-copy' for Tramp files."
0f205eee 4496
c62c9d08 4497 (with-parsed-tramp-file-name filename nil
2988341a
MA
4498 (unless (file-exists-p filename)
4499 (tramp-error
4500 v 'file-error
4501 "Cannot make local copy of non-existing file `%s'" filename))
4502
0f205eee 4503 (let ((rem-enc (tramp-get-remote-coding v "remote-encoding"))
00d6fd04 4504 (loc-dec (tramp-get-local-coding v "local-decoding"))
258800f8 4505 (tmpfile (tramp-compat-make-temp-file filename)))
5ec2cc41 4506
2988341a
MA
4507 (condition-case err
4508 (cond
4509 ;; `copy-file' handles direct copy and out-of-band methods.
4510 ((or (tramp-local-host-p v)
7f49fe46
MA
4511 (tramp-method-out-of-band-p
4512 v (nth 7 (file-attributes filename))))
2988341a
MA
4513 (copy-file filename tmpfile t t))
4514
4515 ;; Use inline encoding for file transfer.
4516 (rem-enc
4517 (save-excursion
4518 (tramp-message v 5 "Encoding remote file %s..." filename)
4519 (tramp-barf-unless-okay
4520 v
4521 (format "%s < %s" rem-enc (tramp-shell-quote-argument localname))
4522 "Encoding remote file failed")
4523 (tramp-message v 5 "Encoding remote file %s...done" filename)
4524
4525 (if (and (symbolp loc-dec) (fboundp loc-dec))
4526 ;; If local decoding is a function, we call it. We
4527 ;; must disable multibyte, because
4528 ;; `uudecode-decode-region' doesn't handle it
4529 ;; correctly.
0f205eee
MA
4530 (with-temp-buffer
4531 (set-buffer-multibyte nil)
4532 (insert-buffer-substring (tramp-get-buffer v))
4533 (tramp-message
4534 v 5 "Decoding remote file %s with function %s..."
4535 filename loc-dec)
4536 (funcall loc-dec (point-min) (point-max))
aa485f7c
MA
4537 ;; Unset `file-name-handler-alist'. Otherwise,
4538 ;; epa-file gets confused.
4539 (let (file-name-handler-alist
4540 (coding-system-for-write 'binary))
2988341a
MA
4541 (write-region (point-min) (point-max) tmpfile)))
4542
4543 ;; If tramp-decoding-function is not defined for this
4544 ;; method, we invoke tramp-decoding-command instead.
4545 (let ((tmpfile2 (tramp-compat-make-temp-file filename)))
aa485f7c
MA
4546 ;; Unset `file-name-handler-alist'. Otherwise,
4547 ;; epa-file gets confused.
4548 (let (file-name-handler-alist
4549 (coding-system-for-write 'binary))
2988341a
MA
4550 (write-region (point-min) (point-max) tmpfile2))
4551 (tramp-message
4552 v 5 "Decoding remote file %s with command %s..."
4553 filename loc-dec)
4554 (unwind-protect
4555 (tramp-call-local-coding-command loc-dec tmpfile2 tmpfile)
4556 (delete-file tmpfile2))))
4557
4558 (tramp-message v 5 "Decoding remote file %s...done" filename)
4559 ;; Set proper permissions.
b86c1cd8 4560 (set-file-modes tmpfile (tramp-default-file-modes filename))
2988341a
MA
4561 ;; Set local user ownership.
4562 (tramp-set-file-uid-gid tmpfile)))
4563
4564 ;; Oops, I don't know what to do.
4565 (t (tramp-error
4566 v 'file-error "Wrong method specification for `%s'" method)))
4567
4568 ;; Error handling.
4569 ((error quit)
4570 (delete-file tmpfile)
4571 (signal (car err) (cdr err))))
0f205eee 4572
00d6fd04 4573 (run-hooks 'tramp-handle-file-local-copy-hook)
94be87e8 4574 tmpfile)))
fb7933a3 4575
bce04fee 4576(defun tramp-handle-file-remote-p (filename &optional identification connected)
00d6fd04 4577 "Like `file-remote-p' for Tramp files."
15cc764c
KG
4578 (when (tramp-tramp-file-p filename)
4579 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
4580 (and (or (not connected)
4581 (let ((p (tramp-get-connection-process v)))
4582 (and p (processp p) (memq (process-status p) '(run open)))))
ce3f516f
MA
4583 (cond
4584 ((eq identification 'method) method)
4585 ((eq identification 'user) user)
4586 ((eq identification 'host) host)
8d60099b 4587 ((eq identification 'localname) localname)
ce3f516f 4588 (t (tramp-make-tramp-file-name method user host "")))))))
fb7933a3 4589
eb562962
MA
4590(defun tramp-find-file-name-coding-system-alist (filename tmpname)
4591 "Like `find-operation-coding-system' for Tramp filenames.
4592Tramp's `insert-file-contents' and `write-region' work over
4593temporary file names. If `file-coding-system-alist' contains an
4594expression, which matches more than the file name suffix, the
4595coding system might not be determined. This function repairs it."
4596 (let (result)
4597 (dolist (elt file-coding-system-alist result)
4598 (when (and (consp elt) (string-match (car elt) filename))
4599 ;; We found a matching entry in `file-coding-system-alist'.
4600 ;; So we add a similar entry, but with the temporary file name
4601 ;; as regexp.
4602 (add-to-list
4603 'result (cons (regexp-quote tmpname) (cdr elt)) 'append)))))
4604
fb7933a3
KG
4605(defun tramp-handle-insert-file-contents
4606 (filename &optional visit beg end replace)
00d6fd04 4607 "Like `insert-file-contents' for Tramp files."
fb7933a3
KG
4608 (barf-if-buffer-read-only)
4609 (setq filename (expand-file-name filename))
736ac90f 4610 (let (coding-system-used result local-copy remote-copy)
2ac33804
MA
4611 (with-parsed-tramp-file-name filename nil
4612 (unwind-protect
70c11b0b
MA
4613 (if (not (file-exists-p filename))
4614 ;; We don't raise a Tramp error, because it might be
4615 ;; suppressed, like in `find-file-noselect-1'.
4616 (signal 'file-error
4617 (list "File not found on remote host" filename))
4618
4619 (if (and (tramp-local-host-p v)
4620 (let (file-name-handler-alist)
4621 (file-readable-p localname)))
4622 ;; Short track: if we are on the local host, we can
4623 ;; run directly.
4624 (setq result
4625 (tramp-run-real-handler
4626 'insert-file-contents
4627 (list localname visit beg end replace)))
4628
736ac90f
MA
4629 ;; When we shall insert only a part of the file, we copy
4630 ;; this part.
4631 (when (or beg end)
4632 (setq remote-copy (tramp-make-tramp-temp-file v))
4633 (tramp-send-command
4634 v
4635 (cond
4636 ((and beg end)
4637 (format "tail -c +%d %s | head -c +%d >%s"
4638 (1+ beg) (tramp-shell-quote-argument localname)
4639 (- end beg) remote-copy))
4640 (beg
4641 (format "tail -c +%d %s >%s"
4642 (1+ beg) (tramp-shell-quote-argument localname)
4643 remote-copy))
4644 (end
4645 (format "head -c +%d %s >%s"
4646 (1+ end) (tramp-shell-quote-argument localname)
4647 remote-copy)))))
4648
70c11b0b
MA
4649 ;; `insert-file-contents-literally' takes care to avoid
4650 ;; calling jka-compr. By let-binding
4651 ;; `inhibit-file-name-operation', we propagate that care
4652 ;; to the `file-local-copy' operation.
4653 (setq local-copy
4654 (let ((inhibit-file-name-operation
4655 (when (eq inhibit-file-name-operation
4656 'insert-file-contents)
4657 'file-local-copy)))
b88f2d0a
MA
4658 (cond
4659 ((stringp remote-copy)
4660 (file-local-copy
4661 (tramp-make-tramp-file-name
4662 method user host remote-copy)))
4663 ((stringp tramp-temp-buffer-file-name)
4664 (copy-file filename tramp-temp-buffer-file-name 'ok)
4665 tramp-temp-buffer-file-name)
4666 (t (file-local-copy filename)))))
4667
4668 (when (and (null remote-copy)
4669 (tramp-get-method-parameter
4670 method 'tramp-copy-keep-tmpfile))
4671 ;; We keep the local file for performance reasons,
4672 ;; useful for "rsync".
4673 (set-file-modes local-copy (tramp-octal-to-decimal "0600"))
4674 (setq tramp-temp-buffer-file-name local-copy)
4675 (put 'tramp-temp-buffer-file-name 'permanent-local t))
4676
70c11b0b
MA
4677 (tramp-message
4678 v 4 "Inserting local temp file `%s'..." local-copy)
4679
4680 ;; We must ensure that `file-coding-system-alist'
4681 ;; matches `local-copy'.
4682 (let ((file-coding-system-alist
4683 (tramp-find-file-name-coding-system-alist
4684 filename local-copy)))
4685 (setq result
4686 (insert-file-contents
736ac90f 4687 local-copy nil nil nil replace))
70c11b0b
MA
4688 ;; Now `last-coding-system-used' has right value.
4689 ;; Remember it.
4690 (when (boundp 'last-coding-system-used)
4691 (setq coding-system-used
4692 (symbol-value 'last-coding-system-used))))
8d60099b 4693
70c11b0b
MA
4694 (tramp-message
4695 v 4 "Inserting local temp file `%s'...done" local-copy)
4696 (when (boundp 'last-coding-system-used)
2ac33804 4697 (set 'last-coding-system-used coding-system-used))))
70c11b0b 4698
2ac33804
MA
4699 ;; Save exit.
4700 (progn
4701 (when visit
4702 (setq buffer-file-name filename)
4703 (setq buffer-read-only (not (file-writable-p filename)))
4704 (set-visited-file-modtime)
4705 (set-buffer-modified-p nil))
b88f2d0a
MA
4706 (when (and (stringp local-copy)
4707 (or remote-copy (null tramp-temp-buffer-file-name)))
2ac33804
MA
4708 (delete-file local-copy))
4709 (when (stringp remote-copy)
4710 (delete-file
4711 (tramp-make-tramp-file-name method user host remote-copy))))))
70c11b0b
MA
4712
4713 ;; Result.
4714 (list (expand-file-name filename)
4715 (cadr result))))
fb7933a3 4716
94be87e8
MA
4717;; This is needed for XEmacs only. Code stolen from files.el.
4718(defun tramp-handle-insert-file-contents-literally
4719 (filename &optional visit beg end replace)
4720 "Like `insert-file-contents-literally' for Tramp files."
4721 (let ((format-alist nil)
4722 (after-insert-file-functions nil)
4723 (coding-system-for-read 'no-conversion)
4724 (coding-system-for-write 'no-conversion)
4725 (find-buffer-file-type-function
4726 (if (fboundp 'find-buffer-file-type)
4727 (symbol-function 'find-buffer-file-type)
4728 nil))
4729 (inhibit-file-name-handlers '(jka-compr-handler image-file-handler))
4730 (inhibit-file-name-operation 'insert-file-contents))
4731 (unwind-protect
4732 (progn
4733 (fset 'find-buffer-file-type (lambda (filename) t))
4734 (insert-file-contents filename visit beg end replace))
70c11b0b 4735 ;; Save exit.
94be87e8
MA
4736 (if find-buffer-file-type-function
4737 (fset 'find-buffer-file-type find-buffer-file-type-function)
4738 (fmakunbound 'find-buffer-file-type)))))
4739
38c65fca 4740(defun tramp-handle-find-backup-file-name (filename)
00d6fd04 4741 "Like `find-backup-file-name' for Tramp files."
07dfe738
KG
4742 (with-parsed-tramp-file-name filename nil
4743 ;; We set both variables. It doesn't matter whether it is
4744 ;; Emacs or XEmacs
4745 (let ((backup-directory-alist
4746 ;; Emacs case
4747 (when (boundp 'backup-directory-alist)
b86c1cd8 4748 (if (symbol-value 'tramp-backup-directory-alist)
07dfe738 4749 (mapcar
aa485f7c
MA
4750 (lambda (x)
4751 (cons
4752 (car x)
4753 (if (and (stringp (cdr x))
4754 (file-name-absolute-p (cdr x))
4755 (not (tramp-file-name-p (cdr x))))
4756 (tramp-make-tramp-file-name method user host (cdr x))
4757 (cdr x))))
07dfe738
KG
4758 (symbol-value 'tramp-backup-directory-alist))
4759 (symbol-value 'backup-directory-alist))))
4760
4761 (bkup-backup-directory-info
4762 ;; XEmacs case
4763 (when (boundp 'bkup-backup-directory-info)
b86c1cd8 4764 (if (symbol-value 'tramp-bkup-backup-directory-info)
07dfe738 4765 (mapcar
aa485f7c
MA
4766 (lambda (x)
4767 (nconc
4768 (list (car x))
4769 (list
4770 (if (and (stringp (car (cdr x)))
4771 (file-name-absolute-p (car (cdr x)))
4772 (not (tramp-file-name-p (car (cdr x)))))
4773 (tramp-make-tramp-file-name
4774 method user host (car (cdr x)))
4775 (car (cdr x))))
4776 (cdr (cdr x))))
07dfe738
KG
4777 (symbol-value 'tramp-bkup-backup-directory-info))
4778 (symbol-value 'bkup-backup-directory-info)))))
4779
4780 (tramp-run-real-handler 'find-backup-file-name (list filename)))))
38c65fca 4781
c1105d05 4782(defun tramp-handle-make-auto-save-file-name ()
00d6fd04 4783 "Like `make-auto-save-file-name' for Tramp files.
c1105d05 4784Returns a file name in `tramp-auto-save-directory' for autosaving this file."
00d6fd04
MA
4785 (let ((tramp-auto-save-directory tramp-auto-save-directory)
4786 (buffer-file-name
4787 (tramp-subst-strs-in-string
4788 '(("_" . "|")
4789 ("/" . "_a")
4790 (":" . "_b")
4791 ("|" . "__")
4792 ("[" . "_l")
4793 ("]" . "_r"))
4794 (buffer-file-name))))
1a762140
MA
4795 ;; File name must be unique. This is ensured with Emacs 22 (see
4796 ;; UNIQUIFY element of `auto-save-file-name-transforms'); but for
4797 ;; all other cases we must do it ourselves.
4798 (when (boundp 'auto-save-file-name-transforms)
9e6ab520 4799 (mapc
aa485f7c
MA
4800 (lambda (x)
4801 (when (and (string-match (car x) buffer-file-name)
4802 (not (car (cddr x))))
4803 (setq tramp-auto-save-directory
4804 (or tramp-auto-save-directory
4805 (tramp-compat-temporary-file-directory)))))
1a762140
MA
4806 (symbol-value 'auto-save-file-name-transforms)))
4807 ;; Create directory.
4808 (when tramp-auto-save-directory
00d6fd04
MA
4809 (setq buffer-file-name
4810 (expand-file-name buffer-file-name tramp-auto-save-directory))
1a762140
MA
4811 (unless (file-exists-p tramp-auto-save-directory)
4812 (make-directory tramp-auto-save-directory t)))
00d6fd04
MA
4813 ;; Run plain `make-auto-save-file-name'. There might be an advice when
4814 ;; it is not a magic file name operation (since Emacs 22).
4815 ;; We must deactivate it temporarily.
4816 (if (not (ad-is-active 'make-auto-save-file-name))
4817 (tramp-run-real-handler 'make-auto-save-file-name nil)
4818 ;; else
4819 (ad-deactivate 'make-auto-save-file-name)
4820 (prog1
4821 (tramp-run-real-handler 'make-auto-save-file-name nil)
4822 (ad-activate 'make-auto-save-file-name)))))
4823
4824(defvar tramp-handle-write-region-hook nil
4825 "Normal hook to be run at the end of `tramp-handle-write-region'.")
4826
b88f2d0a 4827;; CCC grok LOCKNAME
fb7933a3
KG
4828(defun tramp-handle-write-region
4829 (start end filename &optional append visit lockname confirm)
00d6fd04 4830 "Like `write-region' for Tramp files."
fb7933a3 4831 (setq filename (expand-file-name filename))
c62c9d08 4832 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
4833 ;; Following part commented out because we don't know what to do about
4834 ;; file locking, and it does not appear to be a problem to ignore it.
4835 ;; Ange-ftp ignores it, too.
4836 ;; (when (and lockname (stringp lockname))
4837 ;; (setq lockname (expand-file-name lockname)))
4838 ;; (unless (or (eq lockname nil)
4839 ;; (string= lockname filename))
4840 ;; (error
4841 ;; "tramp-handle-write-region: LOCKNAME must be nil or equal FILENAME"))
8d60099b 4842
94be87e8 4843 ;; XEmacs takes a coding system as the seventh argument, not `confirm'.
00d6fd04
MA
4844 (when (and (not (featurep 'xemacs)) confirm (file-exists-p filename))
4845 (unless (y-or-n-p (format "File %s exists; overwrite anyway? " filename))
4846 (tramp-error v 'file-error "File not overwritten")))
8d60099b 4847
a4aeb9a4 4848 (let ((uid (or (nth 2 (tramp-compat-file-attributes filename 'integer))
9c13938d 4849 (tramp-get-remote-uid v 'integer)))
a4aeb9a4 4850 (gid (or (nth 3 (tramp-compat-file-attributes filename 'integer))
9c13938d
MA
4851 (tramp-get-remote-gid v 'integer))))
4852
4853 (if (and (tramp-local-host-p v)
93c3eb7c 4854 ;; `file-writable-p' calls `file-expand-file-name'. We
87bdd2c7
MA
4855 ;; cannot use `tramp-run-real-handler' therefore.
4856 (let (file-name-handler-alist)
82f3844e
MA
4857 (and
4858 (file-writable-p (file-name-directory localname))
4859 (or (file-directory-p localname)
4860 (file-writable-p localname)))))
9c13938d 4861 ;; Short track: if we are on the local host, we can run directly.
93c3eb7c
MA
4862 (progn
4863 (tramp-run-real-handler
4864 'write-region
4865 (list start end localname append 'no-message lockname confirm))
3e2fa353 4866 (tramp-flush-file-property v localname))
9c13938d
MA
4867
4868 (let ((rem-dec (tramp-get-remote-coding v "remote-decoding"))
4869 (loc-enc (tramp-get-local-coding v "local-encoding"))
b86c1cd8 4870 (modes (save-excursion (tramp-default-file-modes filename)))
9c13938d
MA
4871 ;; We use this to save the value of
4872 ;; `last-coding-system-used' after writing the tmp file.
4873 ;; At the end of the function, we set
4874 ;; `last-coding-system-used' to this saved value. This
4875 ;; way, any intermediary coding systems used while
4876 ;; talking to the remote shell or suchlike won't hose
4877 ;; this variable. This approach was snarfed from
4878 ;; ange-ftp.el.
4879 coding-system-used
4880 ;; Write region into a tmp file. This isn't really
4881 ;; needed if we use an encoding function, but currently
4882 ;; we use it always because this makes the logic
293c24f9
MA
4883 ;; simpler.
4884 (tmpfile (or tramp-temp-buffer-file-name
4885 (tramp-compat-make-temp-file filename))))
4886
4887 ;; If `append' is non-nil, we copy the file locally, and let
4888 ;; the native `write-region' implementation do the job.
4889 (when append (copy-file filename tmpfile 'ok))
9c13938d
MA
4890
4891 ;; We say `no-message' here because we don't want the
4892 ;; visited file modtime data to be clobbered from the temp
4893 ;; file. We call `set-visited-file-modtime' ourselves later
eb562962
MA
4894 ;; on. We must ensure that `file-coding-system-alist'
4895 ;; matches `tmpfile'.
4896 (let ((file-coding-system-alist
4897 (tramp-find-file-name-coding-system-alist filename tmpfile)))
ce2cc728
MA
4898 (condition-case err
4899 (tramp-run-real-handler
4900 'write-region
4901 (list start end tmpfile append 'no-message lockname confirm))
2988341a 4902 ((error quit)
b88f2d0a 4903 (setq tramp-temp-buffer-file-name nil)
2988341a
MA
4904 (delete-file tmpfile)
4905 (signal (car err) (cdr err))))
ce2cc728 4906
eb562962
MA
4907 ;; Now, `last-coding-system-used' has the right value. Remember it.
4908 (when (boundp 'last-coding-system-used)
4909 (setq coding-system-used
4910 (symbol-value 'last-coding-system-used))))
4911
9c13938d
MA
4912 ;; The permissions of the temporary file should be set. If
4913 ;; filename does not exist (eq modes nil) it has been
4914 ;; renamed to the backup file. This case `save-buffer'
4915 ;; handles permissions.
4916 (when modes (set-file-modes tmpfile modes))
4917
4918 ;; This is a bit lengthy due to the different methods
4919 ;; possible for file transfer. First, we check whether the
4920 ;; method uses an rcp program. If so, we call it.
4921 ;; Otherwise, both encoding and decoding command must be
4922 ;; specified. However, if the method _also_ specifies an
4923 ;; encoding function, then that is used for encoding the
4924 ;; contents of the tmp file.
4925 (cond
4926 ;; `rename-file' handles direct copy and out-of-band methods.
4927 ((or (tramp-local-host-p v)
7f49fe46
MA
4928 (tramp-method-out-of-band-p
4929 v (- (or end (point-max)) (or start (point-min)))))
ce2cc728 4930 (condition-case err
b88f2d0a
MA
4931 (if (and (= (or end (point-max)) (point-max))
4932 (= (or start (point-min)) (point-min))
4933 (tramp-get-method-parameter
4934 method 'tramp-copy-keep-tmpfile))
4935 (progn
4936 ;; We keep the local file for performance
4937 ;; reasons, useful for "rsync".
4938 (setq tramp-temp-buffer-file-name tmpfile)
4939 (copy-file tmpfile filename t))
4940 (setq tramp-temp-buffer-file-name nil)
4941 (rename-file tmpfile filename t))
2988341a 4942 ((error quit)
b88f2d0a 4943 (setq tramp-temp-buffer-file-name nil)
2988341a
MA
4944 (delete-file tmpfile)
4945 (signal (car err) (cdr err)))))
9c13938d 4946
1d7e9a01 4947 ;; Use inline file transfer.
9c13938d 4948 (rem-dec
1d7e9a01 4949 ;; Encode tmpfile.
9c13938d
MA
4950 (tramp-message v 5 "Encoding region...")
4951 (unwind-protect
4952 (with-temp-buffer
4953 ;; Use encoding function or command.
4954 (if (and (symbolp loc-enc) (fboundp loc-enc))
4955 (progn
4956 (tramp-message
4957 v 5 "Encoding region using function `%s'..."
4958 (symbol-name loc-enc))
4959 (let ((coding-system-for-read 'binary))
4960 (insert-file-contents-literally tmpfile))
70c11b0b
MA
4961 ;; The following `let' is a workaround for the
4962 ;; base64.el that comes with pgnus-0.84. If
4963 ;; both of the following conditions are
4964 ;; satisfied, it tries to write to a local
4965 ;; file in default-directory, but at this
4966 ;; point, default-directory is remote.
4967 ;; (`call-process-region' can't write to
4968 ;; remote files, it seems.) The file in
4969 ;; question is a tmp file anyway.
9c13938d
MA
4970 (let ((default-directory
4971 (tramp-compat-temporary-file-directory)))
4972 (funcall loc-enc (point-min) (point-max))))
8d60099b 4973
9c13938d
MA
4974 (tramp-message
4975 v 5 "Encoding region using command `%s'..." loc-enc)
4976 (unless (equal 0 (tramp-call-local-coding-command
4977 loc-enc tmpfile t))
4978 (tramp-error
4979 v 'file-error
4980 "Cannot write to `%s', local encoding command `%s' failed"
4981 filename loc-enc)))
4982
4983 ;; Send buffer into remote decoding command which
4984 ;; writes to remote file. Because this happens on
4985 ;; the remote host, we cannot use the function.
4986 (goto-char (point-max))
4987 (unless (bolp) (newline))
8d60099b 4988 (tramp-message
9c13938d
MA
4989 v 5 "Decoding region into remote file %s..." filename)
4990 (tramp-send-command
4991 v
4992 (format
4993 "%s >%s <<'EOF'\n%sEOF"
4994 rem-dec
4995 (tramp-shell-quote-argument localname)
4996 (buffer-string)))
4997 (tramp-barf-unless-okay
4998 v nil
4999 "Couldn't write region to `%s', decode using `%s' failed"
5000 filename rem-dec)
5001 ;; When `file-precious-flag' is set, the region is
5002 ;; written to a temporary file. Check that the
5003 ;; checksum is equal to that from the local tmpfile.
5004 (when file-precious-flag
5005 (erase-buffer)
5006 (and
a4aeb9a4
MA
5007 ;; cksum runs locally, if possible.
5008 (zerop (tramp-local-call-process "cksum" tmpfile t))
5009 ;; cksum runs remotely.
9c13938d
MA
5010 (zerop
5011 (tramp-send-command-and-check
5012 v
5013 (format
5014 "cksum <%s" (tramp-shell-quote-argument localname))))
a4aeb9a4 5015 ;; ... they are different.
9c13938d
MA
5016 (not
5017 (string-equal
5018 (buffer-string)
5019 (with-current-buffer (tramp-get-buffer v)
5020 (buffer-string))))
5021 (tramp-error
5022 v 'file-error
5023 (concat "Couldn't write region to `%s',"
5024 " decode using `%s' failed")
5025 filename rem-dec)))
5026 (tramp-message
5027 v 5 "Decoding region into remote file %s...done" filename)
5028 (tramp-flush-file-property v localname))
8d60099b 5029
9c13938d
MA
5030 ;; Save exit.
5031 (delete-file tmpfile)))
8d60099b 5032
9c13938d
MA
5033 ;; That's not expected.
5034 (t
5035 (tramp-error
5036 v 'file-error
5037 (concat "Method `%s' should specify both encoding and "
5038 "decoding command or an rcp program")
5039 method)))
258800f8 5040
9c13938d
MA
5041 ;; Make `last-coding-system-used' have the right value.
5042 (when coding-system-used
5043 (set 'last-coding-system-used coding-system-used))))
0f205eee 5044
57671b72
MA
5045 ;; We must protect `last-coding-system-used', now we have set it
5046 ;; to its correct value.
293c24f9 5047 (let (last-coding-system-used (need-chown t))
57671b72
MA
5048 ;; Set file modification time.
5049 (when (or (eq visit t) (stringp visit))
293c24f9
MA
5050 (let ((file-attr (file-attributes filename)))
5051 (set-visited-file-modtime
5052 ;; We must pass modtime explicitely, because filename can
5053 ;; be different from (buffer-file-name), f.e. if
5054 ;; `file-precious-flag' is set.
5055 (nth 5 file-attr))
5056 (when (and (eq (nth 2 file-attr) uid)
5057 (eq (nth 3 file-attr) gid))
5058 (setq need-chown nil))))
57671b72
MA
5059
5060 ;; Set the ownership.
293c24f9
MA
5061 (when need-chown
5062 (tramp-set-file-uid-gid filename uid gid))
57671b72
MA
5063 (when (or (eq visit t) (null visit) (stringp visit))
5064 (tramp-message v 0 "Wrote %s" filename))
5065 (run-hooks 'tramp-handle-write-region-hook)))))
fb7933a3 5066
946a5aeb
MA
5067(defvar tramp-vc-registered-file-names nil
5068 "List used to collect file names, which are checked during `vc-registered'.")
5069
5070;; VC backends check for the existence of various different special
5071;; files. This is very time consuming, because every single check
5072;; requires a remote command (the file cache must be invalidated).
5073;; Therefore, we apply a kind of optimization. We install the file
5074;; name handler `tramp-vc-file-name-handler', which does nothing but
5075;; remembers all file names for which `file-exists-p' or
5076;; `file-readable-p' has been applied. A first run of `vc-registered'
5077;; is performed. Afterwards, a script is applied for all collected
5078;; file names, using just one remote command. The result of this
5079;; script is used to fill the file cache with actual values. Now we
5080;; can reset the file name handlers, and we make a second run of
5081;; `vc-registered', which returns the expected result without sending
5082;; any other remote command.
49096407
MA
5083(defun tramp-handle-vc-registered (file)
5084 "Like `vc-registered' for Tramp files."
946a5aeb 5085 (with-parsed-tramp-file-name file nil
7f49fe46
MA
5086
5087 ;; There could be new files, created by the vc backend. We cannot
5088 ;; reuse the old cache entries, therefore.
946a5aeb
MA
5089 (let (tramp-vc-registered-file-names
5090 (tramp-cache-inhibit-cache (current-time))
5091 (file-name-handler-alist
5092 `((,tramp-file-name-regexp . tramp-vc-file-name-handler))))
5093
5094 ;; Here we collect only file names, which need an operation.
5095 (tramp-run-real-handler 'vc-registered (list file))
5096 (tramp-message v 10 "\n%s" tramp-vc-registered-file-names)
5097
5098 ;; Send just one command, in order to fill the cache.
7f49fe46
MA
5099 (when tramp-vc-registered-file-names
5100 (tramp-maybe-send-script
5101 v
5102 (format tramp-vc-registered-read-file-names
5103 (tramp-get-file-exists-command v)
5104 (format "%s -r" (tramp-get-test-command v)))
5105 "tramp_vc_registered_read_file_names")
5106
5107 (dolist
5108 (elt
5109 (tramp-send-command-and-read
5110 v
5111 (format
5112 "tramp_vc_registered_read_file_names %s"
5113 (mapconcat 'tramp-shell-quote-argument
5114 tramp-vc-registered-file-names
5115 " "))))
946a5aeb 5116
7f49fe46 5117 (tramp-set-file-property v (car elt) (cadr elt) (cadr (cdr elt))))))
946a5aeb 5118
7f49fe46
MA
5119 ;; Second run. Now all `file-exists-p' or `file-readable-p' calls
5120 ;; shall be answered from the file cache.
5121 ;; We unset `process-file-side-effects' in order to keep the cache
5122 ;; when `process-file' calls appear.
946a5aeb
MA
5123 (let (process-file-side-effects)
5124 (tramp-run-real-handler 'vc-registered (list file)))))
49096407 5125
a01b1e22
MA
5126;;;###autoload
5127(progn (defun tramp-run-real-handler (operation args)
fb7933a3 5128 "Invoke normal file name handler for OPERATION.
c62c9d08
KG
5129First arg specifies the OPERATION, second arg is a list of arguments to
5130pass to the OPERATION."
4007ba5b
KG
5131 (let* ((inhibit-file-name-handlers
5132 `(tramp-file-name-handler
946a5aeb 5133 tramp-vc-file-name-handler
4007ba5b
KG
5134 tramp-completion-file-name-handler
5135 cygwin-mount-name-hook-function
5136 cygwin-mount-map-drive-hook-function
5137 .
5138 ,(and (eq inhibit-file-name-operation operation)
5139 inhibit-file-name-handlers)))
5140 (inhibit-file-name-operation operation))
a01b1e22 5141 (apply operation args))))
16674e4f 5142
a01b1e22
MA
5143;;;###autoload
5144(progn (defun tramp-completion-run-real-handler (operation args)
16674e4f
KG
5145 "Invoke `tramp-file-name-handler' for OPERATION.
5146First arg specifies the OPERATION, second arg is a list of arguments to
5147pass to the OPERATION."
4007ba5b
KG
5148 (let* ((inhibit-file-name-handlers
5149 `(tramp-completion-file-name-handler
5150 cygwin-mount-name-hook-function
5151 cygwin-mount-map-drive-hook-function
5152 .
5153 ,(and (eq inhibit-file-name-operation operation)
5154 inhibit-file-name-handlers)))
5155 (inhibit-file-name-operation operation))
a01b1e22 5156 (apply operation args))))
fb7933a3 5157
4007ba5b
KG
5158;; We handle here all file primitives. Most of them have the file
5159;; name as first parameter; nevertheless we check for them explicitly
04bf5b65 5160;; in order to be signaled if a new primitive appears. This
4007ba5b
KG
5161;; scenario is needed because there isn't a way to decide by
5162;; syntactical means whether a foreign method must be called. It would
19a87064 5163;; ease the life if `file-name-handler-alist' would support a decision
4007ba5b
KG
5164;; function as well but regexp only.
5165(defun tramp-file-name-for-operation (operation &rest args)
5166 "Return file name related to OPERATION file primitive.
5167ARGS are the arguments OPERATION has been called with."
5168 (cond
5169 ; FILE resp DIRECTORY
5170 ((member operation
5171 (list 'access-file 'byte-compiler-base-file-name 'delete-directory
5172 'delete-file 'diff-latest-backup-file 'directory-file-name
5173 'directory-files 'directory-files-and-attributes
5174 'dired-compress-file 'dired-uncache
5175 'file-accessible-directory-p 'file-attributes
5176 'file-directory-p 'file-executable-p 'file-exists-p
19a87064
MA
5177 'file-local-copy 'file-remote-p 'file-modes
5178 'file-name-as-directory 'file-name-directory
5179 'file-name-nondirectory 'file-name-sans-versions
5180 'file-ownership-preserved-p 'file-readable-p
5181 'file-regular-p 'file-symlink-p 'file-truename
5182 'file-writable-p 'find-backup-file-name 'find-file-noselect
5183 'get-file-buffer 'insert-directory 'insert-file-contents
5184 'load 'make-directory 'make-directory-internal
5185 'set-file-modes 'substitute-in-file-name
5186 'unhandled-file-name-directory 'vc-registered
ce3f516f
MA
5187 ; Emacs 22 only
5188 'set-file-times
4007ba5b
KG
5189 ; XEmacs only
5190 'abbreviate-file-name 'create-file-buffer
5191 'dired-file-modtime 'dired-make-compressed-filename
5192 'dired-recursive-delete-directory 'dired-set-file-modtime
5193 'dired-shell-unhandle-file-name 'dired-uucode-file
5615d63f 5194 'insert-file-contents-literally 'make-temp-name 'recover-file
4007ba5b 5195 'vm-imap-check-mail 'vm-pop-check-mail 'vm-spool-check-mail))
8daea7fc
KG
5196 (if (file-name-absolute-p (nth 0 args))
5197 (nth 0 args)
5198 (expand-file-name (nth 0 args))))
4007ba5b
KG
5199 ; FILE DIRECTORY resp FILE1 FILE2
5200 ((member operation
5201 (list 'add-name-to-file 'copy-file 'expand-file-name
5202 'file-name-all-completions 'file-name-completion
5203 'file-newer-than-file-p 'make-symbolic-link 'rename-file
263c02ef
MA
5204 ; Emacs 23 only
5205 'copy-directory
4007ba5b
KG
5206 ; XEmacs only
5207 'dired-make-relative-symlink
5208 'vm-imap-move-mail 'vm-pop-move-mail 'vm-spool-move-mail))
5209 (save-match-data
5210 (cond
5211 ((string-match tramp-file-name-regexp (nth 0 args)) (nth 0 args))
5212 ((string-match tramp-file-name-regexp (nth 1 args)) (nth 1 args))
5213 (t (buffer-file-name (current-buffer))))))
5214 ; START END FILE
5215 ((eq operation 'write-region)
5216 (nth 2 args))
5217 ; BUF
5218 ((member operation
00d6fd04 5219 (list 'set-visited-file-modtime 'verify-visited-file-modtime
b50dd0d2 5220 ; since Emacs 22 only
00d6fd04
MA
5221 'make-auto-save-file-name
5222 ; XEmacs only
4007ba5b
KG
5223 'backup-buffer))
5224 (buffer-file-name
5225 (if (bufferp (nth 0 args)) (nth 0 args) (current-buffer))))
5226 ; COMMAND
5227 ((member operation
00d6fd04
MA
5228 (list ; not in Emacs 23
5229 'dired-call-process
01917a18 5230 ; Emacs only
b71c9e75 5231 'shell-command
00d6fd04 5232 ; since Emacs 22 only
0457dd55 5233 'process-file
00d6fd04
MA
5234 ; since Emacs 23 only
5235 'start-file-process
4007ba5b 5236 ; XEmacs only
00d6fd04
MA
5237 'dired-print-file 'dired-shell-call-process
5238 ; nowhere yet
5239 'executable-find 'start-process 'call-process))
4007ba5b
KG
5240 default-directory)
5241 ; unknown file primitive
5242 (t (error "unknown file I/O primitive: %s" operation))))
5243
5244(defun tramp-find-foreign-file-name-handler (filename)
5245 "Return foreign file name handler if exists."
9ce8462a
MA
5246 (when (and (stringp filename) (tramp-tramp-file-p filename))
5247 (let ((v (tramp-dissect-file-name filename t))
5248 (handler tramp-foreign-file-name-handler-alist)
5249 elt res)
5250 ;; When we are not fully sure that filename completion is safe,
5251 ;; we should not return a handler.
5252 (when (or (tramp-file-name-method v) (tramp-file-name-user v)
1834b39f
MA
5253 (and (tramp-file-name-host v)
5254 (not (member (tramp-file-name-host v)
5255 (mapcar 'car tramp-methods))))
9ce8462a
MA
5256 (not (tramp-completion-mode-p)))
5257 (while handler
5258 (setq elt (car handler)
5259 handler (cdr handler))
5260 (when (funcall (car elt) filename)
5261 (setq handler nil
5262 res (cdr elt))))
5263 res))))
4007ba5b 5264
fb7933a3
KG
5265;; Main function.
5266;;;###autoload
5267(defun tramp-file-name-handler (operation &rest args)
ea9d1443 5268 "Invoke Tramp file name handler.
a4aeb9a4 5269Falls back to normal file name handler if no Tramp file name handler exists."
2e271195
MA
5270 (if tramp-mode
5271 (save-match-data
5272 (let* ((filename
5273 (tramp-replace-environment-variables
5274 (apply 'tramp-file-name-for-operation operation args)))
5275 (completion (tramp-completion-mode-p))
5276 (foreign (tramp-find-foreign-file-name-handler filename)))
5277 (with-parsed-tramp-file-name filename nil
5278 (cond
5279 ;; When we are in completion mode, some operations
5280 ;; shouldn't be handled by backend.
5281 ((and completion (zerop (length localname))
5282 (memq operation '(file-exists-p file-directory-p)))
5283 t)
5284 ((and completion (zerop (length localname))
5285 (memq operation '(file-name-as-directory)))
5286 filename)
5287 ;; Call the backend function.
5288 (foreign (apply foreign operation args))
5289 ;; Nothing to do for us.
5290 (t (tramp-run-real-handler operation args))))))
5291 ;; When `tramp-mode' is not enabled, we don't do anything.
5292 (tramp-run-real-handler operation args)))
fb7933a3 5293
07dfe738
KG
5294;; In Emacs, there is some concurrency due to timers. If a timer
5295;; interrupts Tramp and wishes to use the same connection buffer as
5296;; the "main" Emacs, then garbage might occur in the connection
5297;; buffer. Therefore, we need to make sure that a timer does not use
5298;; the same connection buffer as the "main" Emacs. We implement a
5299;; cheap global lock, instead of locking each connection buffer
5300;; separately. The global lock is based on two variables,
5301;; `tramp-locked' and `tramp-locker'. `tramp-locked' is set to true
5302;; (with setq) to indicate a lock. But Tramp also calls itself during
5303;; processing of a single file operation, so we need to allow
5304;; recursive calls. That's where the `tramp-locker' variable comes in
5305;; -- it is let-bound to t during the execution of the current
5306;; handler. So if `tramp-locked' is t and `tramp-locker' is also t,
5307;; then we should just proceed because we have been called
5308;; recursively. But if `tramp-locker' is nil, then we are a timer
5309;; interrupting the "main" Emacs, and then we signal an error.
5310
5311(defvar tramp-locked nil
5312 "If non-nil, then Tramp is currently busy.
5313Together with `tramp-locker', this implements a locking mechanism
5314preventing reentrant calls of Tramp.")
5315
5316(defvar tramp-locker nil
5317 "If non-nil, then a caller has locked Tramp.
5318Together with `tramp-locked', this implements a locking mechanism
5319preventing reentrant calls of Tramp.")
5320
ea9d1443
KG
5321(defun tramp-sh-file-name-handler (operation &rest args)
5322 "Invoke remote-shell Tramp file name handler.
5323Fall back to normal file name handler if no Tramp handler exists."
07dfe738 5324 (when (and tramp-locked (not tramp-locker))
11c71217 5325 (setq tramp-locked nil)
00d6fd04 5326 (signal 'file-error (list "Forbidden reentrant call of Tramp")))
07dfe738
KG
5327 (let ((tl tramp-locked))
5328 (unwind-protect
5329 (progn
5330 (setq tramp-locked t)
5331 (let ((tramp-locker t))
5332 (save-match-data
5333 (let ((fn (assoc operation tramp-file-name-handler-alist)))
5334 (if fn
5335 (apply (cdr fn) args)
5336 (tramp-run-real-handler operation args))))))
5337 (setq tramp-locked tl))))
ea9d1443 5338
946a5aeb
MA
5339(defun tramp-vc-file-name-handler (operation &rest args)
5340 "Invoke special file name handler, which collects files to be handled."
5341 (save-match-data
5342 (let ((filename
5343 (tramp-replace-environment-variables
5344 (apply 'tramp-file-name-for-operation operation args)))
5345 (fn (assoc operation tramp-file-name-handler-alist)))
5346 (with-parsed-tramp-file-name filename nil
5347 (cond
5348 ;; That's what we want: file names, for which checks are
5349 ;; applied. We assume, that VC uses only `file-exists-p' and
5350 ;; `file-readable-p' checks; otherwise we must extend the
5351 ;; list. We do not perform any action, but return nil, in
5352 ;; order to keep `vc-registered' running.
5353 ((and fn (memq operation '(file-exists-p file-readable-p)))
5354 (add-to-list 'tramp-vc-registered-file-names localname 'append)
5355 nil)
5356 ;; Tramp file name handlers like `expand-file-name'. They
5357 ;; must still work.
5358 (fn
5359 (save-match-data (apply (cdr fn) args)))
5360 ;; Default file name handlers, we don't care.
5361 (t (tramp-run-real-handler operation args)))))))
5362
16674e4f 5363;;;###autoload
1ecc6145 5364(progn (defun tramp-completion-file-name-handler (operation &rest args)
a4aeb9a4
MA
5365 "Invoke Tramp file name completion handler.
5366Falls back to normal file name handler if no Tramp file name handler exists."
57671b72
MA
5367 ;; We bind `directory-sep-char' here for XEmacs on Windows, which
5368 ;; would otherwise use backslash.
aff67808
MA
5369 (let ((directory-sep-char ?/)
5370 (fn (assoc operation tramp-completion-file-name-handler-alist)))
aa485f7c
MA
5371 (if (and
5372 ;; When `tramp-mode' is not enabled, we don't do anything.
5373 fn tramp-mode
5374 ;; For other syntaxes than `sep', the regexp matches many common
5375 ;; situations where the user doesn't actually want to use Tramp.
5376 ;; So to avoid autoloading Tramp after typing just "/s", we
5377 ;; disable this part of the completion, unless the user implicitly
5378 ;; indicated his interest in using a fancier completion system.
5379 (or (eq tramp-syntax 'sep)
5380 (featurep 'tramp) ; If it's loaded, we may as well use it.
5381 (and (boundp 'partial-completion-mode) partial-completion-mode)
5382 ;; FIXME: These may have been loaded even if the user never
5383 ;; intended to use them.
5384 (featurep 'ido)
5385 (featurep 'icicles)))
aff67808
MA
5386 (save-match-data (apply (cdr fn) args))
5387 (tramp-completion-run-real-handler operation args)))))
a01b1e22 5388
b25a52cc 5389;;;###autoload
aa485f7c
MA
5390(progn (defun tramp-register-file-name-handlers ()
5391 "Add Tramp file name handlers to `file-name-handler-alist'."
5392 ;; Remove autoloaded handlers from file name handler alist. Useful,
00d6fd04
MA
5393 ;; if `tramp-syntax' has been changed.
5394 (let ((a1 (rassq 'tramp-file-name-handler file-name-handler-alist)))
aa485f7c
MA
5395 (setq file-name-handler-alist (delq a1 file-name-handler-alist)))
5396 (let ((a1 (rassq
5397 'tramp-completion-file-name-handler file-name-handler-alist)))
5398 (setq file-name-handler-alist (delq a1 file-name-handler-alist)))
5399 ;; Add the handlers.
a01b1e22
MA
5400 (add-to-list 'file-name-handler-alist
5401 (cons tramp-file-name-regexp 'tramp-file-name-handler))
aa485f7c
MA
5402 (add-to-list 'file-name-handler-alist
5403 (cons tramp-completion-file-name-regexp
5404 'tramp-completion-file-name-handler))
5405 (put 'tramp-completion-file-name-handler 'safe-magic t)
5406 ;; If jka-compr or epa-file are already loaded, move them to the
5407 ;; front of `file-name-handler-alist'.
5408 (dolist (fnh '(epa-file-handler jka-compr-handler))
5409 (let ((entry (rassoc fnh file-name-handler-alist)))
5410 (when entry
5411 (setq file-name-handler-alist
5412 (cons entry (delete entry file-name-handler-alist))))))))
69cee873 5413
00d6fd04
MA
5414;; `tramp-file-name-handler' must be registered before evaluation of
5415;; site-start and init files, because there might exist remote files
5416;; already, f.e. files kept via recentf-mode.
aa485f7c
MA
5417;;;###autoload(tramp-register-file-name-handlers)
5418(tramp-register-file-name-handlers)
b25a52cc 5419
fb7933a3 5420;;;###autoload
8c04e197 5421(defun tramp-unload-file-name-handlers ()
a69c01a0
MA
5422 (setq file-name-handler-alist
5423 (delete (rassoc 'tramp-file-name-handler
5424 file-name-handler-alist)
5425 (delete (rassoc 'tramp-completion-file-name-handler
5426 file-name-handler-alist)
5427 file-name-handler-alist))))
5428
8c04e197 5429(add-hook 'tramp-unload-hook 'tramp-unload-file-name-handlers)
a69c01a0 5430
0664ff72 5431;;; File name handler functions for completion mode:
a6e96327
MA
5432
5433(defvar tramp-completion-mode nil
5434 "If non-nil, external packages signal that they are in file name completion.
5435
5436This is necessary, because Tramp uses a heuristic depending on last
5437input event. This fails when external packages use other characters
5438but <TAB>, <SPACE> or ?\\? for file name completion. This variable
5439should never be set globally, the intention is to let-bind it.")
16674e4f
KG
5440
5441;; Necessary because `tramp-file-name-regexp-unified' and
00d6fd04
MA
5442;; `tramp-completion-file-name-regexp-unified' aren't different. If
5443;; nil, `tramp-completion-run-real-handler' is called (i.e. forwarding
5444;; to `tramp-file-name-handler'). Otherwise, it takes
5445;; `tramp-run-real-handler'. Using `last-input-event' is a little bit
5446;; risky, because completing a file might require loading other files,
5447;; like "~/.netrc", and for them it shouldn't be decided based on that
5448;; variable. On the other hand, those files shouldn't have partial
a4aeb9a4
MA
5449;; Tramp file name syntax. Maybe another variable should be introduced
5450;; overwriting this check in such cases. Or we change Tramp file name
00d6fd04 5451;; syntax in order to avoid ambiguities, like in XEmacs ...
6c4e47fa 5452(defun tramp-completion-mode-p ()
16674e4f 5453 "Checks whether method / user name / host name completion is active."
6c4e47fa 5454 (or
a6e96327
MA
5455 ;; Signal from outside.
5456 tramp-completion-mode
5457 ;; Emacs.
94be87e8 5458 (equal last-input-event 'tab)
6c4e47fa 5459 (and (natnump last-input-event)
94be87e8 5460 (or
a6e96327 5461 ;; ?\t has event-modifier 'control.
800a97b8 5462 (equal last-input-event ?\t)
94be87e8 5463 (and (not (event-modifiers last-input-event))
800a97b8
SM
5464 (or (equal last-input-event ?\?)
5465 (equal last-input-event ?\ )))))
a6e96327 5466 ;; XEmacs.
6c4e47fa
MA
5467 (and (featurep 'xemacs)
5468 ;; `last-input-event' might be nil.
5469 (not (null last-input-event))
5470 ;; `last-input-event' may have no character approximation.
5471 (funcall (symbol-function 'event-to-character) last-input-event)
94be87e8 5472 (or
a6e96327 5473 ;; ?\t has event-modifier 'control.
800a97b8 5474 (equal
94be87e8
MA
5475 (funcall (symbol-function 'event-to-character)
5476 last-input-event) ?\t)
5477 (and (not (event-modifiers last-input-event))
800a97b8 5478 (or (equal
94be87e8
MA
5479 (funcall (symbol-function 'event-to-character)
5480 last-input-event) ?\?)
800a97b8 5481 (equal
94be87e8
MA
5482 (funcall (symbol-function 'event-to-character)
5483 last-input-event) ?\ )))))))
16674e4f 5484
16674e4f
KG
5485;; Method, host name and user name completion.
5486;; `tramp-completion-dissect-file-name' returns a list of
5487;; tramp-file-name structures. For all of them we return possible completions.
a01b1e22 5488;;;###autoload
16674e4f 5489(defun tramp-completion-handle-file-name-all-completions (filename directory)
00d6fd04 5490 "Like `file-name-all-completions' for partial Tramp files."
16674e4f 5491
00d6fd04
MA
5492 (let* ((fullname (tramp-drop-volume-letter
5493 (expand-file-name filename directory)))
5494 ;; Possible completion structures.
5495 (v (tramp-completion-dissect-file-name fullname))
5496 result result1)
5497
5498 (while v
5499 (let* ((car (car v))
5500 (method (tramp-file-name-method car))
5501 (user (tramp-file-name-user car))
5502 (host (tramp-file-name-host car))
5503 (localname (tramp-file-name-localname car))
5504 (m (tramp-find-method method user host))
5505 (tramp-current-user user) ; see `tramp-parse-passwd'
5506 all-user-hosts)
5507
5508 (unless localname ;; Nothing to complete.
5509
5510 (if (or user host)
5511
5512 ;; Method dependent user / host combinations.
5513 (progn
9e6ab520 5514 (mapc
00d6fd04
MA
5515 (lambda (x)
5516 (setq all-user-hosts
5517 (append all-user-hosts
5518 (funcall (nth 0 x) (nth 1 x)))))
5519 (tramp-get-completion-function m))
5520
9e6ab520
MA
5521 (setq result
5522 (append result
5523 (mapcar
5524 (lambda (x)
5525 (tramp-get-completion-user-host
5526 method user host (nth 0 x) (nth 1 x)))
5527 (delq nil all-user-hosts)))))
00d6fd04
MA
5528
5529 ;; Possible methods.
5530 (setq result
5531 (append result (tramp-get-completion-methods m)))))
5532
5533 (setq v (cdr v))))
5534
5535 ;; Unify list, remove nil elements.
5536 (while result
5537 (let ((car (car result)))
5538 (when car
5539 (add-to-list
5540 'result1
5541 (substring car (length (tramp-drop-volume-letter directory)))))
5542 (setq result (cdr result))))
5543
5544 ;; Complete local parts.
5545 (append
5546 result1
5547 (condition-case nil
5548 (tramp-completion-run-real-handler
5549 'file-name-all-completions (list filename directory))
5550 (error nil)))))
16674e4f
KG
5551
5552;; Method, host name and user name completion for a file.
a01b1e22 5553;;;###autoload
e1e17cae
MA
5554(defun tramp-completion-handle-file-name-completion
5555 (filename directory &optional predicate)
00d6fd04 5556 "Like `file-name-completion' for Tramp files."
e1e17cae
MA
5557 (try-completion
5558 filename
5559 (mapcar 'list (file-name-all-completions filename directory))
83e20b5c
MA
5560 (when predicate
5561 (lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
16674e4f
KG
5562
5563;; I misuse a little bit the tramp-file-name structure in order to handle
5564;; completion possibilities for partial methods / user names / host names.
5565;; Return value is a list of tramp-file-name structures according to possible
00d6fd04 5566;; completions. If "localname" is non-nil it means there
16674e4f
KG
5567;; shouldn't be a completion anymore.
5568
5569;; Expected results:
5570
00d6fd04
MA
5571;; "/x" "/[x" "/x@" "/[x@" "/x@y" "/[x@y"
5572;; [nil nil "x" nil] [nil "x" nil nil] [nil "x" "y" nil]
5573;; [nil "x" nil nil]
5574;; ["x" nil nil nil]
5575
5576;; "/x:" "/x:y" "/x:y:"
5577;; [nil nil "x" ""] [nil nil "x" "y"] ["x" nil "y" ""]
5578;; "/[x/" "/[x/y"
5579;; ["x" nil "" nil] ["x" nil "y" nil]
5580;; ["x" "" nil nil] ["x" "y" nil nil]
5581
5582;; "/x:y@" "/x:y@z" "/x:y@z:"
5583;; [nil nil "x" "y@"] [nil nil "x" "y@z"] ["x" "y" "z" ""]
5584;; "/[x/y@" "/[x/y@z"
5585;; ["x" nil "y" nil] ["x" "y" "z" nil]
16674e4f
KG
5586(defun tramp-completion-dissect-file-name (name)
5587 "Returns a list of `tramp-file-name' structures.
5588They are collected by `tramp-completion-dissect-file-name1'."
5589
5590 (let* ((result)
4007ba5b 5591 (x-nil "\\|\\(\\)")
b96e6899
MA
5592 (tramp-completion-ipv6-regexp
5593 (format
5594 "[^%s]*"
5595 (if (zerop (length tramp-postfix-ipv6-format))
5596 tramp-postfix-host-format
5597 tramp-postfix-ipv6-format)))
4007ba5b
KG
5598 ;; "/method" "/[method"
5599 (tramp-completion-file-name-structure1
5600 (list (concat tramp-prefix-regexp "\\(" tramp-method-regexp x-nil "\\)$")
5601 1 nil nil nil))
5602 ;; "/user" "/[user"
5603 (tramp-completion-file-name-structure2
5604 (list (concat tramp-prefix-regexp "\\(" tramp-user-regexp x-nil "\\)$")
5605 nil 1 nil nil))
5606 ;; "/host" "/[host"
5607 (tramp-completion-file-name-structure3
5608 (list (concat tramp-prefix-regexp "\\(" tramp-host-regexp x-nil "\\)$")
5609 nil nil 1 nil))
b96e6899 5610 ;; "/[ipv6" "/[ipv6"
4007ba5b 5611 (tramp-completion-file-name-structure4
b96e6899
MA
5612 (list (concat tramp-prefix-regexp
5613 tramp-prefix-ipv6-regexp
5614 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5615 nil nil 1 nil))
5616 ;; "/user@host" "/[user@host"
5617 (tramp-completion-file-name-structure5
4007ba5b
KG
5618 (list (concat tramp-prefix-regexp
5619 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5620 "\\(" tramp-host-regexp x-nil "\\)$")
5621 nil 1 2 nil))
b96e6899
MA
5622 ;; "/user@[ipv6" "/[user@ipv6"
5623 (tramp-completion-file-name-structure6
5624 (list (concat tramp-prefix-regexp
5625 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5626 tramp-prefix-ipv6-regexp
5627 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5628 nil 1 2 nil))
00d6fd04 5629 ;; "/method:user" "/[method/user" "/method://user"
b96e6899 5630 (tramp-completion-file-name-structure7
4007ba5b 5631 (list (concat tramp-prefix-regexp
00d6fd04 5632 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5633 "\\(" tramp-user-regexp x-nil "\\)$")
5634 1 2 nil nil))
00d6fd04 5635 ;; "/method:host" "/[method/host" "/method://host"
b96e6899 5636 (tramp-completion-file-name-structure8
4007ba5b 5637 (list (concat tramp-prefix-regexp
00d6fd04 5638 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5639 "\\(" tramp-host-regexp x-nil "\\)$")
5640 1 nil 2 nil))
b96e6899
MA
5641 ;; "/method:[ipv6" "/[method/ipv6" "/method://[ipv6"
5642 (tramp-completion-file-name-structure9
5643 (list (concat tramp-prefix-regexp
5644 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
5645 tramp-prefix-ipv6-regexp
5646 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5647 1 nil 2 nil))
00d6fd04 5648 ;; "/method:user@host" "/[method/user@host" "/method://user@host"
b96e6899 5649 (tramp-completion-file-name-structure10
4007ba5b 5650 (list (concat tramp-prefix-regexp
00d6fd04 5651 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5652 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5653 "\\(" tramp-host-regexp x-nil "\\)$")
00d6fd04 5654 1 2 3 nil))
b96e6899
MA
5655 ;; "/method:user@[ipv6" "/[method/user@ipv6" "/method://user@[ipv6"
5656 (tramp-completion-file-name-structure11
5657 (list (concat tramp-prefix-regexp
5658 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
5659 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5660 tramp-prefix-ipv6-regexp
5661 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5662 1 2 3 nil))
00d6fd04 5663 ;; "/method: "/method:/"
b96e6899 5664 (tramp-completion-file-name-structure12
00d6fd04
MA
5665 (list
5666 (if (equal tramp-syntax 'url)
5667 (concat tramp-prefix-regexp
5668 "\\(" tramp-method-regexp "\\)"
5669 "\\(" (substring tramp-postfix-method-regexp 0 1)
5670 "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)"
5671 "\\(" "\\)$")
5672 ;; Should not match if not URL syntax.
5673 (concat tramp-prefix-regexp "/$"))
5674 1 3 nil nil))
5675 ;; "/method: "/method:/"
b96e6899 5676 (tramp-completion-file-name-structure13
00d6fd04
MA
5677 (list
5678 (if (equal tramp-syntax 'url)
5679 (concat tramp-prefix-regexp
5680 "\\(" tramp-method-regexp "\\)"
5681 "\\(" (substring tramp-postfix-method-regexp 0 1)
5682 "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)"
5683 "\\(" "\\)$")
5684 ;; Should not match if not URL syntax.
5685 (concat tramp-prefix-regexp "/$"))
5686 1 nil 3 nil)))
4007ba5b 5687
9e6ab520 5688 (mapc (lambda (regexp)
16674e4f
KG
5689 (add-to-list 'result
5690 (tramp-completion-dissect-file-name1 regexp name)))
5691 (list
5692 tramp-completion-file-name-structure1
5693 tramp-completion-file-name-structure2
5694 tramp-completion-file-name-structure3
5695 tramp-completion-file-name-structure4
5696 tramp-completion-file-name-structure5
5697 tramp-completion-file-name-structure6
5698 tramp-completion-file-name-structure7
00d6fd04
MA
5699 tramp-completion-file-name-structure8
5700 tramp-completion-file-name-structure9
b96e6899
MA
5701 tramp-completion-file-name-structure10
5702 tramp-completion-file-name-structure11
5703 tramp-completion-file-name-structure12
5704 tramp-completion-file-name-structure13
16674e4f
KG
5705 tramp-file-name-structure))
5706
5707 (delq nil result)))
5708
5709(defun tramp-completion-dissect-file-name1 (structure name)
5710 "Returns a `tramp-file-name' structure matching STRUCTURE.
00d6fd04 5711The structure consists of remote method, remote user,
7432277c 5712remote host and localname (filename on remote host)."
fb7933a3 5713
00d6fd04
MA
5714 (save-match-data
5715 (when (string-match (nth 0 structure) name)
5716 (let ((method (and (nth 1 structure)
5717 (match-string (nth 1 structure) name)))
5718 (user (and (nth 2 structure)
5719 (match-string (nth 2 structure) name)))
5720 (host (and (nth 3 structure)
5721 (match-string (nth 3 structure) name)))
5722 (localname (and (nth 4 structure)
5723 (match-string (nth 4 structure) name))))
5724 (vector method user host localname)))))
16674e4f
KG
5725
5726;; This function returns all possible method completions, adding the
5727;; trailing method delimeter.
16674e4f
KG
5728(defun tramp-get-completion-methods (partial-method)
5729 "Returns all method completions for PARTIAL-METHOD."
4007ba5b
KG
5730 (mapcar
5731 (lambda (method)
5732 (and method
5733 (string-match (concat "^" (regexp-quote partial-method)) method)
00d6fd04
MA
5734 (tramp-completion-make-tramp-file-name method nil nil nil)))
5735 (mapcar 'car tramp-methods)))
16674e4f
KG
5736
5737;; Compares partial user and host names with possible completions.
5738(defun tramp-get-completion-user-host (method partial-user partial-host user host)
5739 "Returns the most expanded string for user and host name completion.
5740PARTIAL-USER must match USER, PARTIAL-HOST must match HOST."
5741 (cond
5742
5743 ((and partial-user partial-host)
5744 (if (and host
5745 (string-match (concat "^" (regexp-quote partial-host)) host)
5746 (string-equal partial-user (or user partial-user)))
5747 (setq user partial-user)
5748 (setq user nil
5749 host nil)))
5750
5751 (partial-user
5752 (setq host nil)
5753 (unless
5754 (and user (string-match (concat "^" (regexp-quote partial-user)) user))
5755 (setq user nil)))
5756
5757 (partial-host
5758 (setq user nil)
5759 (unless
5760 (and host (string-match (concat "^" (regexp-quote partial-host)) host))
5761 (setq host nil)))
5762
5763 (t (setq user nil
5764 host nil)))
5765
292ffc15 5766 (unless (zerop (+ (length user) (length host)))
00d6fd04 5767 (tramp-completion-make-tramp-file-name method user host nil)))
16674e4f
KG
5768
5769(defun tramp-parse-rhosts (filename)
5770 "Return a list of (user host) tuples allowed to access.
292ffc15 5771Either user or host may be nil."
00d6fd04
MA
5772 ;; On Windows, there are problems in completion when
5773 ;; `default-directory' is remote.
9e6ab520 5774 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5775 res)
8daea7fc 5776 (when (file-readable-p filename)
16674e4f
KG
5777 (with-temp-buffer
5778 (insert-file-contents filename)
5779 (goto-char (point-min))
5780 (while (not (eobp))
292ffc15 5781 (push (tramp-parse-rhosts-group) res))))
16674e4f
KG
5782 res))
5783
16674e4f
KG
5784(defun tramp-parse-rhosts-group ()
5785 "Return a (user host) tuple allowed to access.
292ffc15 5786Either user or host may be nil."
16674e4f
KG
5787 (let ((result)
5788 (regexp
5789 (concat
5790 "^\\(" tramp-host-regexp "\\)"
5791 "\\([ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
9e6ab520 5792 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
5793 (when (re-search-forward regexp nil t)
5794 (setq result (append (list (match-string 3) (match-string 1)))))
5795 (widen)
5796 (forward-line 1)
5797 result))
5798
5799(defun tramp-parse-shosts (filename)
5800 "Return a list of (user host) tuples allowed to access.
5801User is always nil."
00d6fd04
MA
5802 ;; On Windows, there are problems in completion when
5803 ;; `default-directory' is remote.
9e6ab520 5804 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5805 res)
8daea7fc 5806 (when (file-readable-p filename)
16674e4f
KG
5807 (with-temp-buffer
5808 (insert-file-contents filename)
5809 (goto-char (point-min))
5810 (while (not (eobp))
292ffc15 5811 (push (tramp-parse-shosts-group) res))))
16674e4f
KG
5812 res))
5813
5814(defun tramp-parse-shosts-group ()
5815 "Return a (user host) tuple allowed to access.
5816User is always nil."
16674e4f
KG
5817 (let ((result)
5818 (regexp (concat "^\\(" tramp-host-regexp "\\)")))
9e6ab520 5819 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
5820 (when (re-search-forward regexp nil t)
5821 (setq result (list nil (match-string 1))))
5822 (widen)
5823 (or
5824 (> (skip-chars-forward ",") 0)
5825 (forward-line 1))
5826 result))
5827
8daea7fc
KG
5828(defun tramp-parse-sconfig (filename)
5829 "Return a list of (user host) tuples allowed to access.
5830User is always nil."
00d6fd04
MA
5831 ;; On Windows, there are problems in completion when
5832 ;; `default-directory' is remote.
9e6ab520 5833 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5834 res)
8daea7fc
KG
5835 (when (file-readable-p filename)
5836 (with-temp-buffer
5837 (insert-file-contents filename)
5838 (goto-char (point-min))
5839 (while (not (eobp))
5840 (push (tramp-parse-sconfig-group) res))))
5841 res))
5842
5843(defun tramp-parse-sconfig-group ()
5844 "Return a (user host) tuple allowed to access.
5845User is always nil."
8daea7fc
KG
5846 (let ((result)
5847 (regexp (concat "^[ \t]*Host[ \t]+" "\\(" tramp-host-regexp "\\)")))
9e6ab520 5848 (narrow-to-region (point) (tramp-compat-line-end-position))
8daea7fc
KG
5849 (when (re-search-forward regexp nil t)
5850 (setq result (list nil (match-string 1))))
5851 (widen)
5852 (or
5853 (> (skip-chars-forward ",") 0)
5854 (forward-line 1))
5855 result))
5856
5ec2cc41
KG
5857(defun tramp-parse-shostkeys (dirname)
5858 "Return a list of (user host) tuples allowed to access.
5859User is always nil."
00d6fd04
MA
5860 ;; On Windows, there are problems in completion when
5861 ;; `default-directory' is remote.
9e6ab520 5862 (let* ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
5863 (regexp (concat "^key_[0-9]+_\\(" tramp-host-regexp "\\)\\.pub$"))
5864 (files (when (file-directory-p dirname) (directory-files dirname)))
5865 result)
5ec2cc41
KG
5866 (while files
5867 (when (string-match regexp (car files))
5868 (push (list nil (match-string 1 (car files))) result))
5869 (setq files (cdr files)))
5870 result))
5871
5872(defun tramp-parse-sknownhosts (dirname)
5873 "Return a list of (user host) tuples allowed to access.
5874User is always nil."
00d6fd04
MA
5875 ;; On Windows, there are problems in completion when
5876 ;; `default-directory' is remote.
9e6ab520 5877 (let* ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
5878 (regexp (concat "^\\(" tramp-host-regexp
5879 "\\)\\.ssh-\\(dss\\|rsa\\)\\.pub$"))
5880 (files (when (file-directory-p dirname) (directory-files dirname)))
5881 result)
5ec2cc41
KG
5882 (while files
5883 (when (string-match regexp (car files))
5884 (push (list nil (match-string 1 (car files))) result))
5885 (setq files (cdr files)))
5886 result))
5887
16674e4f
KG
5888(defun tramp-parse-hosts (filename)
5889 "Return a list of (user host) tuples allowed to access.
5890User is always nil."
00d6fd04
MA
5891 ;; On Windows, there are problems in completion when
5892 ;; `default-directory' is remote.
9e6ab520 5893 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5894 res)
8daea7fc 5895 (when (file-readable-p filename)
16674e4f
KG
5896 (with-temp-buffer
5897 (insert-file-contents filename)
5898 (goto-char (point-min))
5899 (while (not (eobp))
292ffc15 5900 (push (tramp-parse-hosts-group) res))))
16674e4f
KG
5901 res))
5902
5903(defun tramp-parse-hosts-group ()
5904 "Return a (user host) tuple allowed to access.
5905User is always nil."
16674e4f 5906 (let ((result)
b96e6899
MA
5907 (regexp
5908 (concat "^\\(" tramp-ipv6-regexp "\\|" tramp-host-regexp "\\)")))
9e6ab520 5909 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f 5910 (when (re-search-forward regexp nil t)
b96e6899 5911 (setq result (list nil (match-string 1))))
16674e4f
KG
5912 (widen)
5913 (or
5914 (> (skip-chars-forward " \t") 0)
5915 (forward-line 1))
5916 result))
5917
8daea7fc
KG
5918;; For su-alike methods it would be desirable to return "root@localhost"
5919;; as default. Unfortunately, we have no information whether any user name
00d6fd04 5920;; has been typed already. So we use `tramp-current-user' as indication,
8daea7fc 5921;; assuming it is set in `tramp-completion-handle-file-name-all-completions'.
16674e4f
KG
5922(defun tramp-parse-passwd (filename)
5923 "Return a list of (user host) tuples allowed to access.
5924Host is always \"localhost\"."
00d6fd04
MA
5925 ;; On Windows, there are problems in completion when
5926 ;; `default-directory' is remote.
9e6ab520 5927 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5928 res)
8daea7fc 5929 (if (zerop (length tramp-current-user))
16674e4f 5930 '(("root" nil))
8daea7fc 5931 (when (file-readable-p filename)
16674e4f
KG
5932 (with-temp-buffer
5933 (insert-file-contents filename)
5934 (goto-char (point-min))
5935 (while (not (eobp))
292ffc15 5936 (push (tramp-parse-passwd-group) res))))
16674e4f
KG
5937 res)))
5938
5939(defun tramp-parse-passwd-group ()
5940 "Return a (user host) tuple allowed to access.
292ffc15 5941Host is always \"localhost\"."
16674e4f
KG
5942 (let ((result)
5943 (regexp (concat "^\\(" tramp-user-regexp "\\):")))
9e6ab520 5944 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
5945 (when (re-search-forward regexp nil t)
5946 (setq result (list (match-string 1) "localhost")))
5947 (widen)
5948 (forward-line 1)
5949 result))
5950
292ffc15
KG
5951(defun tramp-parse-netrc (filename)
5952 "Return a list of (user host) tuples allowed to access.
5953User may be nil."
00d6fd04
MA
5954 ;; On Windows, there are problems in completion when
5955 ;; `default-directory' is remote.
9e6ab520 5956 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5957 res)
8daea7fc 5958 (when (file-readable-p filename)
292ffc15
KG
5959 (with-temp-buffer
5960 (insert-file-contents filename)
5961 (goto-char (point-min))
5962 (while (not (eobp))
5963 (push (tramp-parse-netrc-group) res))))
5964 res))
5965
5966(defun tramp-parse-netrc-group ()
5967 "Return a (user host) tuple allowed to access.
5968User may be nil."
292ffc15
KG
5969 (let ((result)
5970 (regexp
5971 (concat
5972 "^[ \t]*machine[ \t]+" "\\(" tramp-host-regexp "\\)"
5973 "\\([ \t]+login[ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
9e6ab520 5974 (narrow-to-region (point) (tramp-compat-line-end-position))
292ffc15
KG
5975 (when (re-search-forward regexp nil t)
5976 (setq result (list (match-string 3) (match-string 1))))
5977 (widen)
5978 (forward-line 1)
5979 result))
5980
00d6fd04
MA
5981(defun tramp-parse-putty (registry)
5982 "Return a list of (user host) tuples allowed to access.
5983User is always nil."
5984 ;; On Windows, there are problems in completion when
5985 ;; `default-directory' is remote.
9e6ab520 5986 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
5987 res)
5988 (with-temp-buffer
a4aeb9a4 5989 (when (zerop (tramp-local-call-process "reg" nil t nil "query" registry))
00d6fd04
MA
5990 (goto-char (point-min))
5991 (while (not (eobp))
5992 (push (tramp-parse-putty-group registry) res))))
5993 res))
5994
5995(defun tramp-parse-putty-group (registry)
5996 "Return a (user host) tuple allowed to access.
5997User is always nil."
5998 (let ((result)
5999 (regexp (concat (regexp-quote registry) "\\\\\\(.+\\)")))
9e6ab520 6000 (narrow-to-region (point) (tramp-compat-line-end-position))
00d6fd04
MA
6001 (when (re-search-forward regexp nil t)
6002 (setq result (list nil (match-string 1))))
6003 (widen)
6004 (forward-line 1)
6005 result))
6006
fb7933a3
KG
6007;;; Internal Functions:
6008
00d6fd04
MA
6009(defun tramp-maybe-send-script (vec script name)
6010 "Define in remote shell function NAME implemented as SCRIPT.
6011Only send the definition if it has not already been done."
6012 (let* ((p (tramp-get-connection-process vec))
6013 (scripts (tramp-get-connection-property p "scripts" nil)))
1834b39f 6014 (unless (member name scripts)
00d6fd04
MA
6015 (tramp-message vec 5 "Sending script `%s'..." name)
6016 ;; The script could contain a call of Perl. This is masked with `%s'.
6017 (tramp-send-command-and-check
6018 vec
6019 (format "%s () {\n%s\n}" name
6020 (format script (tramp-get-remote-perl vec))))
6021 (tramp-set-connection-property p "scripts" (cons name scripts))
6022 (tramp-message vec 5 "Sending script `%s'...done." name))))
c82c5727 6023
fb7933a3 6024(defun tramp-set-auto-save ()
00d6fd04 6025 (when (and ;; ange-ftp has its own auto-save mechanism
7177e2a3
MA
6026 (eq (tramp-find-foreign-file-name-handler (buffer-file-name))
6027 'tramp-sh-file-name-handler)
fb7933a3
KG
6028 auto-save-default)
6029 (auto-save-mode 1)))
6030(add-hook 'find-file-hooks 'tramp-set-auto-save t)
a69c01a0 6031(add-hook 'tramp-unload-hook
aa485f7c
MA
6032 (lambda ()
6033 (remove-hook 'find-file-hooks 'tramp-set-auto-save)))
fb7933a3
KG
6034
6035(defun tramp-run-test (switch filename)
6036 "Run `test' on the remote system, given a SWITCH and a FILENAME.
6037Returns the exit code of the `test' program."
00d6fd04
MA
6038 (with-parsed-tramp-file-name filename nil
6039 (tramp-send-command-and-check
6040 v
6041 (format
6042 "%s %s %s"
6043 (tramp-get-test-command v)
6044 switch
6045 (tramp-shell-quote-argument localname)))))
6046
6047(defun tramp-run-test2 (format-string file1 file2)
6048 "Run `test'-like program on the remote system, given FILE1, FILE2.
6049FORMAT-STRING contains the program name, switches, and place holders.
6050Returns the exit code of the `test' program. Barfs if the methods,
fb7933a3 6051hosts, or files, disagree."
00d6fd04
MA
6052 (unless (tramp-equal-remote file1 file2)
6053 (with-parsed-tramp-file-name (if (tramp-tramp-file-p file1) file1 file2) nil
6054 (tramp-error
6055 v 'file-error
6056 "tramp-run-test2 only implemented for same method, user, host")))
6057 (with-parsed-tramp-file-name file1 v1
6058 (with-parsed-tramp-file-name file1 v2
fb7933a3 6059 (tramp-send-command-and-check
00d6fd04
MA
6060 v1
6061 (format format-string
6062 (tramp-shell-quote-argument v1-localname)
6063 (tramp-shell-quote-argument v2-localname))))))
fb7933a3 6064
00d6fd04
MA
6065(defun tramp-buffer-name (vec)
6066 "A name for the connection buffer VEC."
6067 ;; We must use `tramp-file-name-real-host', because for gateway
6068 ;; methods the default port will be expanded later on, which would
6069 ;; tamper the name.
6070 (let ((method (tramp-file-name-method vec))
6071 (user (tramp-file-name-user vec))
6072 (host (tramp-file-name-real-host vec)))
6073 (if (not (zerop (length user)))
6074 (format "*tramp/%s %s@%s*" method user host)
6075 (format "*tramp/%s %s*" method host))))
6076
b88f2d0a
MA
6077(defun tramp-delete-temp-file-function ()
6078 "Remove temporary files related to current buffer."
6079 (when (stringp tramp-temp-buffer-file-name)
6080 (condition-case nil
6081 (delete-file tramp-temp-buffer-file-name)
6082 (error nil))))
6083
6084(add-hook 'kill-buffer-hook 'tramp-delete-temp-file-function)
6085(add-hook 'tramp-cache-unload-hook
6086 (lambda ()
6087 (remove-hook 'kill-buffer-hook
6088 'tramp-delete-temp-file-function)))
6089
00d6fd04
MA
6090(defun tramp-get-buffer (vec)
6091 "Get the connection buffer to be used for VEC."
6092 (or (get-buffer (tramp-buffer-name vec))
6093 (with-current-buffer (get-buffer-create (tramp-buffer-name vec))
6094 (setq buffer-undo-list t)
6095 (setq default-directory
6096 (tramp-make-tramp-file-name
6097 (tramp-file-name-method vec)
6098 (tramp-file-name-user vec)
6099 (tramp-file-name-host vec)
6100 "/"))
6101 (current-buffer))))
6102
6103(defun tramp-get-connection-buffer (vec)
6104 "Get the connection buffer to be used for VEC.
6105In case a second asynchronous communication has been started, it is different
6106from `tramp-get-buffer'."
6107 (or (tramp-get-connection-property vec "process-buffer" nil)
6108 (tramp-get-buffer vec)))
6109
6110(defun tramp-get-connection-process (vec)
6111 "Get the connection process to be used for VEC.
6112In case a second asynchronous communication has been started, it is different
6113from the default one."
6114 (get-process
6115 (or (tramp-get-connection-property vec "process-name" nil)
6116 (tramp-buffer-name vec))))
6117
6118(defun tramp-debug-buffer-name (vec)
6119 "A name for the debug buffer for VEC."
6120 ;; We must use `tramp-file-name-real-host', because for gateway
6121 ;; methods the default port will be expanded later on, which would
6122 ;; tamper the name.
6123 (let ((method (tramp-file-name-method vec))
6124 (user (tramp-file-name-user vec))
6125 (host (tramp-file-name-real-host vec)))
6126 (if (not (zerop (length user)))
6127 (format "*debug tramp/%s %s@%s*" method user host)
6128 (format "*debug tramp/%s %s*" method host))))
6129
6130(defun tramp-get-debug-buffer (vec)
6131 "Get the debug buffer for VEC."
01917a18 6132 (with-current-buffer
00d6fd04
MA
6133 (get-buffer-create (tramp-debug-buffer-name vec))
6134 (when (bobp)
6135 (setq buffer-undo-list t)
9ce8462a
MA
6136 ;; Activate outline-mode. This runs `text-mode-hook' and
6137 ;; `outline-mode-hook'. We must prevent that local processes
6138 ;; die. Yes: I've seen `flyspell-mode', which starts "ispell"
6139 ;; ...
9e6ab520 6140 (let ((default-directory (tramp-compat-temporary-file-directory)))
00d6fd04 6141 (outline-mode))
9ce8462a 6142 (set (make-local-variable 'outline-regexp)
736ac90f 6143 "[0-9]+:[0-9]+:[0-9]+\\.[0-9]+ [a-z0-9-]+ (\\([0-9]+\\)) #")
9ce8462a
MA
6144; (set (make-local-variable 'outline-regexp)
6145; "[a-z.-]+:[0-9]+: [a-z0-9-]+ (\\([0-9]+\\)) #")
6146 (set (make-local-variable 'outline-level) 'tramp-outline-level))
01917a18 6147 (current-buffer)))
fb7933a3 6148
00d6fd04
MA
6149(defun tramp-outline-level ()
6150 "Return the depth to which a statement is nested in the outline.
6151Point must be at the beginning of a header line.
6152
6153The outline level is equal to the verbosity of the Tramp message."
6154 (1+ (string-to-number (match-string 1))))
fb7933a3 6155
00d6fd04
MA
6156(defun tramp-find-executable
6157 (vec progname dirlist &optional ignore-tilde ignore-path)
6158 "Searches for PROGNAME in $PATH and all directories mentioned in DIRLIST.
6159First arg VEC specifies the connection, PROGNAME is the program
6160to search for, and DIRLIST gives the list of directories to
6161search. If IGNORE-TILDE is non-nil, directory names starting
6162with `~' will be ignored. If IGNORE-PATH is non-nil, searches
6163only in DIRLIST.
fb7933a3 6164
7432277c 6165Returns the absolute file name of PROGNAME, if found, and nil otherwise.
fb7933a3
KG
6166
6167This function expects to be in the right *tramp* buffer."
00d6fd04
MA
6168 (with-current-buffer (tramp-get-buffer vec)
6169 (let (result)
6170 ;; Check whether the executable is in $PATH. "which(1)" does not
6171 ;; report always a correct error code; therefore we check the
6172 ;; number of words it returns.
6173 (unless ignore-path
6174 (tramp-send-command vec (format "which \\%s | wc -w" progname))
6175 (goto-char (point-min))
6176 (if (looking-at "^1$")
6177 (setq result (concat "\\" progname))))
6178 (unless result
6179 (when ignore-tilde
6180 ;; Remove all ~/foo directories from dirlist. In Emacs 20,
6181 ;; `remove' is in CL, and we want to avoid CL dependencies.
6182 (let (newdl d)
6183 (while dirlist
6184 (setq d (car dirlist))
6185 (setq dirlist (cdr dirlist))
6186 (unless (char-equal ?~ (aref d 0))
6187 (setq newdl (cons d newdl))))
6188 (setq dirlist (nreverse newdl))))
6189 (tramp-send-command
6190 vec
6191 (format (concat "while read d; "
6192 "do if test -x $d/%s -a -f $d/%s; "
6193 "then echo tramp_executable $d/%s; "
6194 "break; fi; done <<'EOF'\n"
6195 "%s\nEOF")
6196 progname progname progname (mapconcat 'identity dirlist "\n")))
6197 (goto-char (point-max))
6198 (when (search-backward "tramp_executable " nil t)
6199 (skip-chars-forward "^ ")
6200 (skip-chars-forward " ")
9e6ab520
MA
6201 (setq result (buffer-substring
6202 (point) (tramp-compat-line-end-position)))))
00d6fd04
MA
6203 result)))
6204
6205(defun tramp-set-remote-path (vec)
6206 "Sets the remote environment PATH to existing directories.
6207I.e., for each directory in `tramp-remote-path', it is tested
6208whether it exists and if so, it is added to the environment
6209variable PATH."
6210 (tramp-message vec 5 (format "Setting $PATH environment variable"))
f84638eb
MA
6211 (tramp-send-command
6212 vec (format "PATH=%s; export PATH"
6213 (mapconcat 'identity (tramp-get-remote-path vec) ":"))))
fb7933a3 6214
cfb5c0db
MA
6215;; ------------------------------------------------------------
6216;; -- Communication with external shell --
6217;; ------------------------------------------------------------
fb7933a3 6218
00d6fd04 6219(defun tramp-find-file-exists-command (vec)
fb7933a3
KG
6220 "Find a command on the remote host for checking if a file exists.
6221Here, we are looking for a command which has zero exit status if the
6222file exists and nonzero exit status otherwise."
00d6fd04 6223 (let ((existing "/")
fb7933a3 6224 (nonexisting
00d6fd04
MA
6225 (tramp-shell-quote-argument "/ this file does not exist "))
6226 result)
fb7933a3
KG
6227 ;; The algorithm is as follows: we try a list of several commands.
6228 ;; For each command, we first run `$cmd /' -- this should return
6229 ;; true, as the root directory always exists. And then we run
00d6fd04 6230 ;; `$cmd /this\ file\ does\ not\ exist ', hoping that the file indeed
fb7933a3
KG
6231 ;; does not exist. This should return false. We use the first
6232 ;; command we find that seems to work.
6233 ;; The list of commands to try is as follows:
00d6fd04
MA
6234 ;; `ls -d' This works on most systems, but NetBSD 1.4
6235 ;; has a bug: `ls' always returns zero exit
6236 ;; status, even for files which don't exist.
6237 ;; `test -e' Some Bourne shells have a `test' builtin
6238 ;; which does not know the `-e' option.
6239 ;; `/bin/test -e' For those, the `test' binary on disk normally
6240 ;; provides the option. Alas, the binary
6241 ;; is sometimes `/bin/test' and sometimes it's
6242 ;; `/usr/bin/test'.
6243 ;; `/usr/bin/test -e' In case `/bin/test' does not exist.
fb7933a3 6244 (unless (or
00d6fd04
MA
6245 (and (setq result (format "%s -e" (tramp-get-test-command vec)))
6246 (zerop (tramp-send-command-and-check
6247 vec (format "%s %s" result existing)))
6248 (not (zerop (tramp-send-command-and-check
6249 vec (format "%s %s" result nonexisting)))))
6250 (and (setq result "/bin/test -e")
6251 (zerop (tramp-send-command-and-check
6252 vec (format "%s %s" result existing)))
6253 (not (zerop (tramp-send-command-and-check
6254 vec (format "%s %s" result nonexisting)))))
6255 (and (setq result "/usr/bin/test -e")
6256 (zerop (tramp-send-command-and-check
6257 vec (format "%s %s" result existing)))
6258 (not (zerop (tramp-send-command-and-check
6259 vec (format "%s %s" result nonexisting)))))
6260 (and (setq result (format "%s -d" (tramp-get-ls-command vec)))
6261 (zerop (tramp-send-command-and-check
6262 vec (format "%s %s" result existing)))
6263 (not (zerop (tramp-send-command-and-check
6264 vec (format "%s %s" result nonexisting))))))
6265 (tramp-error
6266 vec 'file-error "Couldn't find command to check if file exists"))
6267 result))
bf247b6e 6268
fb7933a3 6269;; CCC test ksh or bash found for tilde expansion?
00d6fd04
MA
6270(defun tramp-find-shell (vec)
6271 "Opens a shell on the remote host which groks tilde expansion."
6272 (unless (tramp-get-connection-property vec "remote-shell" nil)
6273 (let (shell)
6274 (with-current-buffer (tramp-get-buffer vec)
7e780ff1 6275 (tramp-send-command vec "echo ~root" t)
00d6fd04
MA
6276 (cond
6277 ((string-match "^~root$" (buffer-string))
6278 (setq shell
f84638eb
MA
6279 (or (tramp-find-executable
6280 vec "bash" (tramp-get-remote-path vec) t)
6281 (tramp-find-executable
6282 vec "ksh" (tramp-get-remote-path vec) t)))
00d6fd04
MA
6283 (unless shell
6284 (tramp-error
6285 vec 'file-error
6286 "Couldn't find a shell which groks tilde expansion"))
6287 ;; Find arguments for this shell.
6288 (let ((alist tramp-sh-extra-args)
6289 item extra-args)
6290 (while (and alist (null extra-args))
6291 (setq item (pop alist))
6292 (when (string-match (car item) shell)
6293 (setq extra-args (cdr item))))
6294 (when extra-args (setq shell (concat shell " " extra-args))))
6295 (tramp-message
6296 vec 5 "Starting remote shell `%s' for tilde expansion..." shell)
a4aeb9a4
MA
6297 (let ((tramp-end-of-output "$ "))
6298 (tramp-send-command
b08104a0 6299 vec
70c11b0b
MA
6300 (format "PROMPT_COMMAND='' PS1=%s PS2='' PS3='' exec %s"
6301 (shell-quote-argument tramp-end-of-output) shell)
b08104a0 6302 t))
a0a5183a 6303 ;; Setting prompts.
00d6fd04 6304 (tramp-message vec 5 "Setting remote shell prompt...")
70c11b0b
MA
6305 (tramp-send-command
6306 vec (format "PS1=%s" (shell-quote-argument tramp-end-of-output)) t)
9fa0d3aa
MA
6307 (tramp-send-command vec "PS2=''" t)
6308 (tramp-send-command vec "PS3=''" t)
6309 (tramp-send-command vec "PROMPT_COMMAND=''" t)
00d6fd04 6310 (tramp-message vec 5 "Setting remote shell prompt...done"))
a0a5183a 6311
00d6fd04
MA
6312 (t (tramp-message
6313 vec 5 "Remote `%s' groks tilde expansion, good"
6314 (tramp-get-method-parameter
6315 (tramp-file-name-method vec) 'tramp-remote-sh))
6316 (tramp-set-connection-property
6317 vec "remote-shell"
6318 (tramp-get-method-parameter
6319 (tramp-file-name-method vec) 'tramp-remote-sh))))))))
fb7933a3 6320
bf247b6e
KS
6321;; ------------------------------------------------------------
6322;; -- Functions for establishing connection --
6323;; ------------------------------------------------------------
fb7933a3 6324
ac474af1
KG
6325;; The following functions are actions to be taken when seeing certain
6326;; prompts from the remote host. See the variable
6327;; `tramp-actions-before-shell' for usage of these functions.
6328
00d6fd04 6329(defun tramp-action-login (proc vec)
ac474af1 6330 "Send the login name."
00d6fd04
MA
6331 (when (not (stringp tramp-current-user))
6332 (save-window-excursion
6333 (let ((enable-recursive-minibuffers t))
6334 (pop-to-buffer (tramp-get-connection-buffer vec))
6335 (setq tramp-current-user (read-string (match-string 0))))))
6336 (tramp-message vec 3 "Sending login name `%s'" tramp-current-user)
6337 (with-current-buffer (tramp-get-connection-buffer vec)
6338 (tramp-message vec 6 "\n%s" (buffer-string)))
6339 (tramp-send-string vec tramp-current-user))
6340
6341(defun tramp-action-password (proc vec)
ac474af1 6342 "Query the user for a password."
70c11b0b
MA
6343 (with-current-buffer (process-buffer proc)
6344 (tramp-check-for-regexp proc tramp-password-prompt-regexp)
6345 (tramp-message vec 3 "Sending %s" (match-string 1)))
00d6fd04
MA
6346 (tramp-enter-password proc))
6347
6348(defun tramp-action-succeed (proc vec)
ac474af1 6349 "Signal success in finding shell prompt."
ac474af1
KG
6350 (throw 'tramp-action 'ok))
6351
00d6fd04 6352(defun tramp-action-permission-denied (proc vec)
ac474af1 6353 "Signal permission denied."
00d6fd04 6354 (kill-process proc)
ac474af1
KG
6355 (throw 'tramp-action 'permission-denied))
6356
00d6fd04 6357(defun tramp-action-yesno (proc vec)
3cdaec13
KG
6358 "Ask the user for confirmation using `yes-or-no-p'.
6359Send \"yes\" to remote process on confirmation, abort otherwise.
6360See also `tramp-action-yn'."
ac474af1 6361 (save-window-excursion
00d6fd04
MA
6362 (let ((enable-recursive-minibuffers t))
6363 (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec)))
6364 (unless (yes-or-no-p (match-string 0))
6365 (kill-process proc)
6366 (throw 'tramp-action 'permission-denied))
6367 (with-current-buffer (tramp-get-connection-buffer vec)
6368 (tramp-message vec 6 "\n%s" (buffer-string)))
6369 (tramp-send-string vec "yes"))))
6370
6371(defun tramp-action-yn (proc vec)
3cdaec13
KG
6372 "Ask the user for confirmation using `y-or-n-p'.
6373Send \"y\" to remote process on confirmation, abort otherwise.
6374See also `tramp-action-yesno'."
6375 (save-window-excursion
00d6fd04
MA
6376 (let ((enable-recursive-minibuffers t))
6377 (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec)))
6378 (unless (y-or-n-p (match-string 0))
6379 (kill-process proc)
6380 (throw 'tramp-action 'permission-denied))
6381 (with-current-buffer (tramp-get-connection-buffer vec)
6382 (tramp-message vec 6 "\n%s" (buffer-string)))
6383 (tramp-send-string vec "y"))))
6384
6385(defun tramp-action-terminal (proc vec)
487f4fb7
KG
6386 "Tell the remote host which terminal type to use.
6387The terminal type can be configured with `tramp-terminal-type'."
00d6fd04 6388 (tramp-message vec 5 "Setting `%s' as terminal type." tramp-terminal-type)
7e780ff1
MA
6389 (with-current-buffer (tramp-get-connection-buffer vec)
6390 (tramp-message vec 6 "\n%s" (buffer-string)))
00d6fd04 6391 (tramp-send-string vec tramp-terminal-type))
487f4fb7 6392
00d6fd04 6393(defun tramp-action-process-alive (proc vec)
19a87064 6394 "Check whether a process has finished."
00d6fd04 6395 (unless (memq (process-status proc) '(run open))
19a87064
MA
6396 (throw 'tramp-action 'process-died)))
6397
00d6fd04 6398(defun tramp-action-out-of-band (proc vec)
38c65fca 6399 "Check whether an out-of-band copy has finished."
00d6fd04
MA
6400 (cond ((and (memq (process-status proc) '(stop exit))
6401 (zerop (process-exit-status proc)))
6402 (tramp-message vec 3 "Process has finished.")
38c65fca 6403 (throw 'tramp-action 'ok))
00d6fd04
MA
6404 ((or (and (memq (process-status proc) '(stop exit))
6405 (not (zerop (process-exit-status proc))))
6406 (memq (process-status proc) '(signal)))
01917a18
MA
6407 ;; `scp' could have copied correctly, but set modes could have failed.
6408 ;; This can be ignored.
00d6fd04
MA
6409 (with-current-buffer (process-buffer proc)
6410 (goto-char (point-min))
6411 (if (re-search-forward tramp-operation-not-permitted-regexp nil t)
6412 (progn
6413 (tramp-message vec 5 "'set mode' error ignored.")
6414 (tramp-message vec 3 "Process has finished.")
6415 (throw 'tramp-action 'ok))
6416 (tramp-message vec 3 "Process has died.")
6417 (throw 'tramp-action 'process-died))))
38c65fca
KG
6418 (t nil)))
6419
ac474af1
KG
6420;; Functions for processing the actions.
6421
00d6fd04 6422(defun tramp-process-one-action (proc vec actions)
ac474af1 6423 "Wait for output from the shell and perform one action."
00d6fd04 6424 (let (found todo item pattern action)
e6466697 6425 (while (not found)
00d6fd04
MA
6426 ;; Reread output once all actions have been performed.
6427 ;; Obviously, the output was not complete.
6428 (tramp-accept-process-output proc 1)
e6466697
MA
6429 (setq todo actions)
6430 (while todo
e6466697 6431 (setq item (pop todo))
95d610cb 6432 (setq pattern (format "\\(%s\\)\\'" (symbol-value (nth 0 item))))
e6466697 6433 (setq action (nth 1 item))
00d6fd04
MA
6434 (tramp-message
6435 vec 5 "Looking for regexp \"%s\" from remote shell" pattern)
6436 (when (tramp-check-for-regexp proc pattern)
6437 (tramp-message vec 5 "Call `%s'" (symbol-name action))
6438 (setq found (funcall action proc vec)))))
e6466697
MA
6439 found))
6440
00d6fd04 6441(defun tramp-process-actions (proc vec actions &optional timeout)
e6466697 6442 "Perform actions until success or TIMEOUT."
263c02ef 6443 ;; Enable auth-source and password-cache.
5c7043a2 6444 (tramp-set-connection-property proc "first-password-request" t)
ac474af1
KG
6445 (let (exit)
6446 (while (not exit)
00d6fd04 6447 (tramp-message proc 3 "Waiting for prompts from remote shell")
ac474af1
KG
6448 (setq exit
6449 (catch 'tramp-action
e6466697
MA
6450 (if timeout
6451 (with-timeout (timeout)
00d6fd04
MA
6452 (tramp-process-one-action proc vec actions))
6453 (tramp-process-one-action proc vec actions)))))
6454 (with-current-buffer (tramp-get-connection-buffer vec)
6455 (tramp-message vec 6 "\n%s" (buffer-string)))
ac474af1 6456 (unless (eq exit 'ok)
9c13938d 6457 (tramp-clear-passwd vec)
00d6fd04
MA
6458 (tramp-error-with-buffer
6459 nil vec 'file-error
6460 (cond
6461 ((eq exit 'permission-denied) "Permission denied")
6462 ((eq exit 'process-died) "Process died")
6463 (t "Login failed"))))))
fb7933a3
KG
6464
6465;; Utility functions.
6466
00d6fd04 6467(defun tramp-accept-process-output (&optional proc timeout timeout-msecs)
d2a2c17f
MA
6468 "Like `accept-process-output' for Tramp processes.
6469This is needed in order to hide `last-coding-system-used', which is set
6470for process communication also."
00d6fd04
MA
6471 (with-current-buffer (process-buffer proc)
6472 (tramp-message proc 10 "%s %s" proc (process-status proc))
6473 (let (buffer-read-only last-coding-system-used)
6474 ;; Under Windows XP, accept-process-output doesn't return
6475 ;; sometimes. So we add an additional timeout.
6476 (with-timeout ((or timeout 1))
6477 (accept-process-output proc timeout timeout-msecs)))
6478 (tramp-message proc 10 "\n%s" (buffer-string))))
6479
6480(defun tramp-check-for-regexp (proc regexp)
6481 "Check whether REGEXP is contained in process buffer of PROC.
6482Erase echoed commands if exists."
6483 (with-current-buffer (process-buffer proc)
6484 (goto-char (point-min))
674da028 6485
00d6fd04
MA
6486 ;; Check whether we need to remove echo output.
6487 (when (and (tramp-get-connection-property proc "check-remote-echo" nil)
6488 (re-search-forward tramp-echoed-echo-mark-regexp nil t))
6489 (let ((begin (match-beginning 0)))
6490 (when (re-search-forward tramp-echoed-echo-mark-regexp nil t)
6491 ;; Discard echo from remote output.
6492 (tramp-set-connection-property proc "check-remote-echo" nil)
6493 (tramp-message proc 5 "echo-mark found")
6494 (forward-line)
6495 (delete-region begin (point))
6496 (goto-char (point-min)))))
674da028 6497
70c11b0b
MA
6498 (when (not (tramp-get-connection-property proc "check-remote-echo" nil))
6499 ;; No echo to be handled, now we can look for the regexp.
674da028 6500 (goto-char (point-min))
00d6fd04 6501 (re-search-forward regexp nil t))))
d2a2c17f 6502
fb7933a3
KG
6503(defun tramp-wait-for-regexp (proc timeout regexp)
6504 "Wait for a REGEXP to appear from process PROC within TIMEOUT seconds.
6505Expects the output of PROC to be sent to the current buffer. Returns
6506the string that matched, or nil. Waits indefinitely if TIMEOUT is
6507nil."
00d6fd04
MA
6508 (with-current-buffer (process-buffer proc)
6509 (let ((found (tramp-check-for-regexp proc regexp))
6510 (start-time (current-time)))
6511 (cond (timeout
6512 ;; Work around a bug in XEmacs 21, where the timeout
6513 ;; expires faster than it should. This degenerates
6514 ;; to polling for buggy XEmacsen, but oh, well.
6515 (while (and (not found)
6516 (< (tramp-time-diff (current-time) start-time)
6517 timeout))
6518 (with-timeout (timeout)
6519 (while (not found)
6520 (tramp-accept-process-output proc 1)
6521 (unless (memq (process-status proc) '(run open))
6522 (tramp-error-with-buffer
6523 nil proc 'file-error "Process has died"))
6524 (setq found (tramp-check-for-regexp proc regexp))))))
6525 (t
6526 (while (not found)
6527 (tramp-accept-process-output proc 1)
6528 (unless (memq (process-status proc) '(run open))
6529 (tramp-error-with-buffer
6530 nil proc 'file-error "Process has died"))
6531 (setq found (tramp-check-for-regexp proc regexp)))))
6532 (tramp-message proc 6 "\n%s" (buffer-string))
fb7933a3 6533 (when (not found)
00d6fd04
MA
6534 (if timeout
6535 (tramp-error
6536 proc 'file-error "[[Regexp `%s' not found in %d secs]]"
6537 regexp timeout)
6538 (tramp-error proc 'file-error "[[Regexp `%s' not found]]" regexp)))
6539 found)))
fb7933a3 6540
b25a52cc
KG
6541(defun tramp-barf-if-no-shell-prompt (proc timeout &rest error-args)
6542 "Wait for shell prompt and barf if none appears.
6543Looks at process PROC to see if a shell prompt appears in TIMEOUT
6544seconds. If not, it produces an error message with the given ERROR-ARGS."
7e780ff1
MA
6545 (unless
6546 (tramp-wait-for-regexp
6547 proc timeout
6548 (format
6549 "\\(%s\\|%s\\)\\'" shell-prompt-pattern tramp-shell-prompt-pattern))
00d6fd04
MA
6550 (apply 'tramp-error-with-buffer nil proc 'file-error error-args)))
6551
7e780ff1
MA
6552;; We don't call `tramp-send-string' in order to hide the password
6553;; from the debug buffer, and because end-of-line handling of the
6554;; string.
6555(defun tramp-enter-password (proc)
00d6fd04
MA
6556 "Prompt for a password and send it to the remote end."
6557 (process-send-string
7e780ff1
MA
6558 proc (concat (tramp-read-passwd proc)
6559 (or (tramp-get-method-parameter
6560 tramp-current-method
6561 'tramp-password-end-of-line)
6562 tramp-default-password-end-of-line))))
00d6fd04
MA
6563
6564(defun tramp-open-connection-setup-interactive-shell (proc vec)
fb7933a3 6565 "Set up an interactive shell.
00d6fd04
MA
6566Mainly sets the prompt and the echo correctly. PROC is the shell
6567process to set up. VEC specifies the connection."
a4aeb9a4 6568 (let ((tramp-end-of-output "$ "))
8950769a
MA
6569 ;; It is useful to set the prompt in the following command because
6570 ;; some people have a setting for $PS1 which /bin/sh doesn't know
6571 ;; about and thus /bin/sh will display a strange prompt. For
6572 ;; example, if $PS1 has "${CWD}" in the value, then ksh will
6573 ;; display the current working directory but /bin/sh will display
6574 ;; a dollar sign. The following command line sets $PS1 to a sane
6575 ;; value, and works under Bourne-ish shells as well as csh-like
6576 ;; shells. Daniel Pittman reports that the unusual positioning of
6577 ;; the single quotes makes it work under `rc', too. We also unset
6578 ;; the variable $ENV because that is read by some sh
6579 ;; implementations (eg, bash when called as sh) on startup; this
6580 ;; way, we avoid the startup file clobbering $PS1. $PROMP_COMMAND
6581 ;; is another way to set the prompt in /bin/bash, it must be
6582 ;; discarded as well.
a4aeb9a4
MA
6583 (tramp-send-command
6584 vec
6585 (format
70c11b0b
MA
6586 "exec env ENV='' PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s"
6587 (shell-quote-argument tramp-end-of-output)
a4aeb9a4
MA
6588 (tramp-get-method-parameter
6589 (tramp-file-name-method vec) 'tramp-remote-sh))
8950769a
MA
6590 t)
6591
6592 ;; Disable echo.
6593 (tramp-message vec 5 "Setting up remote shell environment")
6594 (tramp-send-command vec "stty -inlcr -echo kill '^U' erase '^H'" t)
6595 ;; Check whether the echo has really been disabled. Some
6596 ;; implementations, like busybox of embedded GNU/Linux, don't
6597 ;; support disabling.
6598 (tramp-send-command vec "echo foo" t)
6599 (with-current-buffer (process-buffer proc)
6600 (goto-char (point-min))
6601 (when (looking-at "echo foo")
6602 (tramp-set-connection-property proc "remote-echo" t)
6603 (tramp-message vec 5 "Remote echo still on. Ok.")
6604 ;; Make sure backspaces and their echo are enabled and no line
6605 ;; width magic interferes with them.
6606 (tramp-send-command vec "stty icanon erase ^H cols 32767" t))))
e42c6bbc 6607
7e780ff1 6608 (tramp-message vec 5 "Setting shell prompt")
70c11b0b
MA
6609 (tramp-send-command
6610 vec (format "PS1=%s" (shell-quote-argument tramp-end-of-output)) t)
9fa0d3aa
MA
6611 (tramp-send-command vec "PS2=''" t)
6612 (tramp-send-command vec "PS3=''" t)
6613 (tramp-send-command vec "PROMPT_COMMAND=''" t)
e42c6bbc 6614
fb7933a3
KG
6615 ;; Try to set up the coding system correctly.
6616 ;; CCC this can't be the right way to do it. Hm.
00d6fd04 6617 (tramp-message vec 5 "Determining coding system")
7e780ff1 6618 (tramp-send-command vec "echo foo ; echo bar" t)
00d6fd04 6619 (with-current-buffer (process-buffer proc)
fb7933a3
KG
6620 (goto-char (point-min))
6621 (if (featurep 'mule)
00d6fd04
MA
6622 ;; Use MULE to select the right EOL convention for communicating
6623 ;; with the process.
311dd93f 6624 (let* ((cs (or (funcall (symbol-function 'process-coding-system) proc)
00d6fd04
MA
6625 (cons 'undecided 'undecided)))
6626 cs-decode cs-encode)
6627 (when (symbolp cs) (setq cs (cons cs cs)))
6628 (setq cs-decode (car cs))
6629 (setq cs-encode (cdr cs))
6630 (unless cs-decode (setq cs-decode 'undecided))
6631 (unless cs-encode (setq cs-encode 'undecided))
6632 (setq cs-encode (tramp-coding-system-change-eol-conversion
6633 cs-encode 'unix))
6634 (when (search-forward "\r" nil t)
6635 (setq cs-decode (tramp-coding-system-change-eol-conversion
6636 cs-decode 'dos)))
311dd93f 6637 (funcall (symbol-function 'set-buffer-process-coding-system)
70c11b0b
MA
6638 cs-decode cs-encode)
6639 (tramp-message
6640 vec 5 "Setting coding system to `%s' and `%s'" cs-decode cs-encode))
fb7933a3
KG
6641 ;; Look for ^M and do something useful if found.
6642 (when (search-forward "\r" nil t)
00d6fd04
MA
6643 ;; We have found a ^M but cannot frob the process coding system
6644 ;; because we're running on a non-MULE Emacs. Let's try
6645 ;; stty, instead.
7e780ff1
MA
6646 (tramp-send-command vec "stty -onlcr" t))))
6647 (tramp-send-command vec "set +o vi +o emacs" t)
e42c6bbc
MA
6648
6649 ;; Check whether the output of "uname -sr" has been changed. If
6650 ;; yes, this is a strong indication that we must expire all
d8ac123e
MA
6651 ;; connection properties. We start again with
6652 ;; `tramp-maybe-open-connection', it will be catched there.
e42c6bbc
MA
6653 (tramp-message vec 5 "Checking system information")
6654 (let ((old-uname (tramp-get-connection-property vec "uname" nil))
6655 (new-uname
6656 (tramp-set-connection-property
6657 vec "uname"
6658 (tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\""))))
6659 (when (and (stringp old-uname) (not (string-equal old-uname new-uname)))
d8ac123e
MA
6660 (with-current-buffer (tramp-get-debug-buffer vec)
6661 ;; Keep the debug buffer
2296b54d
MA
6662 (rename-buffer
6663 (generate-new-buffer-name tramp-temp-buffer-name) 'unique)
d8ac123e
MA
6664 (funcall (symbol-function 'tramp-cleanup-connection) vec)
6665 (if (= (point-min) (point-max))
6666 (kill-buffer nil)
6667 (rename-buffer (tramp-debug-buffer-name vec) 'unique))
6668 ;; We call `tramp-get-buffer' in order to keep the debug buffer.
6669 (tramp-get-buffer vec)
6670 (tramp-message
6671 vec 3
6672 "Connection reset, because remote host changed from `%s' to `%s'"
6673 old-uname new-uname)
6674 (throw 'uname-changed (tramp-maybe-open-connection vec)))))
e42c6bbc
MA
6675
6676 ;; Check whether the remote host suffers from buggy
6677 ;; `send-process-string'. This is known for FreeBSD (see comment in
6678 ;; `send_process', file process.c). I've tested sending 624 bytes
6679 ;; successfully, sending 625 bytes failed. Emacs makes a hack when
6680 ;; this host type is detected locally. It cannot handle remote
6681 ;; hosts, though.
00d6fd04
MA
6682 (with-connection-property proc "chunksize"
6683 (cond
6684 ((and (integerp tramp-chunksize) (> tramp-chunksize 0))
6685 tramp-chunksize)
6686 (t
6687 (tramp-message
6688 vec 5 "Checking remote host type for `send-process-string' bug")
6689 (if (string-match
e42c6bbc 6690 "^FreeBSD" (tramp-get-connection-property vec "uname" ""))
00d6fd04 6691 500 0))))
e42c6bbc 6692
00d6fd04
MA
6693 ;; Set remote PATH variable.
6694 (tramp-set-remote-path vec)
e42c6bbc 6695
fb7933a3
KG
6696 ;; Search for a good shell before searching for a command which
6697 ;; checks if a file exists. This is done because Tramp wants to use
6698 ;; "test foo; echo $?" to check if various conditions hold, and
6699 ;; there are buggy /bin/sh implementations which don't execute the
6700 ;; "echo $?" part if the "test" part has an error. In particular,
6701 ;; the Solaris /bin/sh is a problem. I'm betting that all systems
6702 ;; with buggy /bin/sh implementations will have a working bash or
6703 ;; ksh. Whee...
00d6fd04 6704 (tramp-find-shell vec)
e42c6bbc 6705
00d6fd04 6706 ;; Disable unexpected output.
7e780ff1 6707 (tramp-send-command vec "mesg n; biff n" t)
e42c6bbc 6708
00d6fd04
MA
6709 ;; Set the environment.
6710 (tramp-message vec 5 "Setting default environment")
661aaece
MA
6711
6712 ;; On OpenSolaris, there is a bug when HISTFILE is changed in place
6713 ;; <http://bugs.opensolaris.org/view_bug.do?bug_id=6834184>. We
6714 ;; apply the workaround.
6715 (if (string-equal (tramp-get-connection-property vec "uname" "") "SunOS 5.11")
6716 (tramp-send-command vec "unset HISTFILE"))
6717
00d6fd04
MA
6718 (let ((env (copy-sequence tramp-remote-process-environment))
6719 unset item)
6720 (while env
70c11b0b 6721 (setq item (tramp-compat-split-string (car env) "="))
00d6fd04
MA
6722 (if (and (stringp (cadr item)) (not (string-equal (cadr item) "")))
6723 (tramp-send-command
7e780ff1 6724 vec (format "%s=%s; export %s" (car item) (cadr item) (car item)) t)
00d6fd04
MA
6725 (push (car item) unset))
6726 (setq env (cdr env)))
6727 (when unset
fb7933a3 6728 (tramp-send-command
7e780ff1 6729 vec (format "unset %s" (mapconcat 'identity unset " "))))) t)
fb7933a3 6730
ac474af1
KG
6731;; CCC: We should either implement a Perl version of base64 encoding
6732;; and decoding. Then we just use that in the last item. The other
6733;; alternative is to use the Perl version of UU encoding. But then
6734;; we need a Lisp version of uuencode.
16674e4f
KG
6735;;
6736;; Old text from documentation of tramp-methods:
6737;; Using a uuencode/uudecode inline method is discouraged, please use one
6738;; of the base64 methods instead since base64 encoding is much more
6739;; reliable and the commands are more standardized between the different
6740;; Unix versions. But if you can't use base64 for some reason, please
6741;; note that the default uudecode command does not work well for some
6742;; Unices, in particular AIX and Irix. For AIX, you might want to use
6743;; the following command for uudecode:
6744;;
6745;; sed '/^begin/d;/^[` ]$/d;/^end/d' | iconv -f uucode -t ISO8859-1
6746;;
6747;; For Irix, no solution is known yet.
6748
00d6fd04
MA
6749(defconst tramp-local-coding-commands
6750 '((b64 base64-encode-region base64-decode-region)
6751 (uu tramp-uuencode-region uudecode-decode-region)
6752 (pack
6753 "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
6754 "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"))
6755 "List of local coding commands for inline transfer.
16674e4f
KG
6756Each item is a list that looks like this:
6757
00d6fd04 6758\(FORMAT ENCODING DECODING)
ac474af1 6759
00d6fd04
MA
6760FORMAT is symbol describing the encoding/decoding format. It can be
6761`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
ac474af1 6762
00d6fd04
MA
6763ENCODING and DECODING can be strings, giving commands, or symbols,
6764giving functions. If they are strings, then they can contain
16674e4f
KG
6765the \"%s\" format specifier. If that specifier is present, the input
6766filename will be put into the command line at that spot. If the
6767specifier is not present, the input should be read from standard
6768input.
ac474af1 6769
16674e4f
KG
6770If they are functions, they will be called with two arguments, start
6771and end of region, and are expected to replace the region contents
6772with the encoded or decoded results, respectively.")
ac474af1 6773
00d6fd04 6774(defconst tramp-remote-coding-commands
3dc847a3
MA
6775 '((b64 "base64" "base64 -d")
6776 (b64 "mimencode -b" "mimencode -u -b")
00d6fd04
MA
6777 (b64 "mmencode -b" "mmencode -u -b")
6778 (b64 "recode data..base64" "recode base64..data")
6779 (b64 tramp-perl-encode-with-module tramp-perl-decode-with-module)
6780 (b64 tramp-perl-encode tramp-perl-decode)
6781 (uu "uuencode xxx" "uudecode -o /dev/stdout")
6782 (uu "uuencode xxx" "uudecode -o -")
6783 (uu "uuencode xxx" "uudecode -p")
6784 (uu "uuencode xxx" tramp-uudecode)
6785 (pack
6786 "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
6787 "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"))
6788 "List of remote coding commands for inline transfer.
6789Each item is a list that looks like this:
6790
6791\(FORMAT ENCODING DECODING)
6792
6793FORMAT is symbol describing the encoding/decoding format. It can be
6794`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
6795
6796ENCODING and DECODING can be strings, giving commands, or symbols,
6797giving variables. If they are strings, then they can contain
6798the \"%s\" format specifier. If that specifier is present, the input
6799filename will be put into the command line at that spot. If the
6800specifier is not present, the input should be read from standard
6801input.
6802
6803If they are variables, this variable is a string containing a Perl
6804implementation for this functionality. This Perl program will be transferred
6805to the remote host, and it is avalible as shell function with the same name.")
6806
6807(defun tramp-find-inline-encoding (vec)
ac474af1 6808 "Find an inline transfer encoding that works.
00d6fd04
MA
6809Goes through the list `tramp-local-coding-commands' and
6810`tramp-remote-coding-commands'."
6811 (save-excursion
6812 (let ((local-commands tramp-local-coding-commands)
6813 (magic "xyzzy")
6814 loc-enc loc-dec rem-enc rem-dec litem ritem found)
6815 (while (and local-commands (not found))
6816 (setq litem (pop local-commands))
6817 (catch 'wont-work-local
6818 (let ((format (nth 0 litem))
6819 (remote-commands tramp-remote-coding-commands))
6820 (setq loc-enc (nth 1 litem))
6821 (setq loc-dec (nth 2 litem))
6822 ;; If the local encoder or decoder is a string, the
6823 ;; corresponding command has to work locally.
6824 (if (not (stringp loc-enc))
6825 (tramp-message
6826 vec 5 "Checking local encoding function `%s'" loc-enc)
6827 (tramp-message
6828 vec 5 "Checking local encoding command `%s' for sanity" loc-enc)
6829 (unless (zerop (tramp-call-local-coding-command
6830 loc-enc nil nil))
6831 (throw 'wont-work-local nil)))
6832 (if (not (stringp loc-dec))
6833 (tramp-message
6834 vec 5 "Checking local decoding function `%s'" loc-dec)
6835 (tramp-message
6836 vec 5 "Checking local decoding command `%s' for sanity" loc-dec)
6837 (unless (zerop (tramp-call-local-coding-command
6838 loc-dec nil nil))
6839 (throw 'wont-work-local nil)))
6840 ;; Search for remote coding commands with the same format
6841 (while (and remote-commands (not found))
6842 (setq ritem (pop remote-commands))
6843 (catch 'wont-work-remote
6844 (when (equal format (nth 0 ritem))
6845 (setq rem-enc (nth 1 ritem))
6846 (setq rem-dec (nth 2 ritem))
6847 ;; Check if remote encoding and decoding commands can be
6848 ;; called remotely with null input and output. This makes
6849 ;; sure there are no syntax errors and the command is really
6850 ;; found. Note that we do not redirect stdout to /dev/null,
6851 ;; for two reasons: when checking the decoding command, we
6852 ;; actually check the output it gives. And also, when
6853 ;; redirecting "mimencode" output to /dev/null, then as root
6854 ;; it might change the permissions of /dev/null!
6855 (when (not (stringp rem-enc))
6856 (let ((name (symbol-name rem-enc)))
6857 (while (string-match (regexp-quote "-") name)
6858 (setq name (replace-match "_" nil t name)))
6859 (tramp-maybe-send-script vec (symbol-value rem-enc) name)
6860 (setq rem-enc name)))
6861 (tramp-message
6862 vec 5
6863 "Checking remote encoding command `%s' for sanity" rem-enc)
6864 (unless (zerop (tramp-send-command-and-check
6865 vec (format "%s </dev/null" rem-enc) t))
6866 (throw 'wont-work-remote nil))
6867
6868 (when (not (stringp rem-dec))
6869 (let ((name (symbol-name rem-dec)))
6870 (while (string-match (regexp-quote "-") name)
6871 (setq name (replace-match "_" nil t name)))
6872 (tramp-maybe-send-script vec (symbol-value rem-dec) name)
6873 (setq rem-dec name)))
6874 (tramp-message
6875 vec 5
6876 "Checking remote decoding command `%s' for sanity" rem-dec)
6877 (unless (zerop (tramp-send-command-and-check
6878 vec
6879 (format "echo %s | %s | %s"
6880 magic rem-enc rem-dec) t))
6881 (throw 'wont-work-remote nil))
6882
6883 (with-current-buffer (tramp-get-buffer vec)
6884 (goto-char (point-min))
6885 (unless (looking-at (regexp-quote magic))
6886 (throw 'wont-work-remote nil)))
6887
6888 ;; `rem-enc' and `rem-dec' could be a string meanwhile.
6889 (setq rem-enc (nth 1 ritem))
6890 (setq rem-dec (nth 2 ritem))
6891 (setq found t)))))))
6892
1d7e9a01 6893 ;; Did we find something?
00d6fd04 6894 (unless found
1d7e9a01 6895 (tramp-message vec 2 "Couldn't find an inline transfer encoding"))
00d6fd04
MA
6896
6897 ;; Set connection properties.
6898 (tramp-message vec 5 "Using local encoding `%s'" loc-enc)
6899 (tramp-set-connection-property vec "local-encoding" loc-enc)
6900 (tramp-message vec 5 "Using local decoding `%s'" loc-dec)
6901 (tramp-set-connection-property vec "local-decoding" loc-dec)
6902 (tramp-message vec 5 "Using remote encoding `%s'" rem-enc)
6903 (tramp-set-connection-property vec "remote-encoding" rem-enc)
6904 (tramp-message vec 5 "Using remote decoding `%s'" rem-dec)
6905 (tramp-set-connection-property vec "remote-decoding" rem-dec))))
16674e4f
KG
6906
6907(defun tramp-call-local-coding-command (cmd input output)
6908 "Call the local encoding or decoding command.
6909If CMD contains \"%s\", provide input file INPUT there in command.
6910Otherwise, INPUT is passed via standard input.
6911INPUT can also be nil which means `/dev/null'.
6912OUTPUT can be a string (which specifies a filename), or t (which
6913means standard output and thus the current buffer), or nil (which
6914means discard it)."
a4aeb9a4
MA
6915 (tramp-local-call-process
6916 tramp-encoding-shell
6917 (when (and input (not (string-match "%s" cmd))) input)
6918 (if (eq output t) t nil)
6919 nil
6920 tramp-encoding-command-switch
6921 (concat
6922 (if (string-match "%s" cmd) (format cmd input) cmd)
6923 (if (stringp output) (concat "> " output) ""))))
00d6fd04
MA
6924
6925(defun tramp-compute-multi-hops (vec)
6926 "Expands VEC according to `tramp-default-proxies-alist'.
6927Gateway hops are already opened."
6928 (let ((target-alist `(,vec))
6929 (choices tramp-default-proxies-alist)
6930 item proxy)
6931
6932 ;; Look for proxy hosts to be passed.
6933 (while choices
6934 (setq item (pop choices)
70c11b0b 6935 proxy (eval (nth 2 item)))
00d6fd04
MA
6936 (when (and
6937 ;; host
70c11b0b 6938 (string-match (or (eval (nth 0 item)) "")
00d6fd04
MA
6939 (or (tramp-file-name-host (car target-alist)) ""))
6940 ;; user
70c11b0b 6941 (string-match (or (eval (nth 1 item)) "")
00d6fd04
MA
6942 (or (tramp-file-name-user (car target-alist)) "")))
6943 (if (null proxy)
6944 ;; No more hops needed.
6945 (setq choices nil)
6946 ;; Replace placeholders.
6947 (setq proxy
6948 (format-spec
6949 proxy
6950 `((?u . ,(or (tramp-file-name-user (car target-alist)) ""))
6951 (?h . ,(or (tramp-file-name-host (car target-alist)) "")))))
6952 (with-parsed-tramp-file-name proxy l
6953 ;; Add the hop.
6954 (add-to-list 'target-alist l)
6955 ;; Start next search.
6956 (setq choices tramp-default-proxies-alist)))))
6957
6958 ;; Handle gateways.
8a4438b6
MA
6959 (when (and (boundp 'tramp-gw-tunnel-method)
6960 (string-match (format
6961 "^\\(%s\\|%s\\)$"
6962 (symbol-value 'tramp-gw-tunnel-method)
6963 (symbol-value 'tramp-gw-socks-method))
6964 (tramp-file-name-method (car target-alist))))
00d6fd04
MA
6965 (let ((gw (pop target-alist))
6966 (hop (pop target-alist)))
6967 ;; Is the method prepared for gateways?
6968 (unless (tramp-get-method-parameter
6969 (tramp-file-name-method hop) 'tramp-default-port)
6970 (tramp-error
6971 vec 'file-error
6972 "Method `%s' is not supported for gateway access."
6973 (tramp-file-name-method hop)))
6974 ;; Add default port if needed.
6975 (unless
6976 (string-match
6977 tramp-host-with-port-regexp (tramp-file-name-host hop))
6978 (aset hop 2
6979 (concat
6980 (tramp-file-name-host hop) tramp-prefix-port-format
6981 (number-to-string
6982 (tramp-get-method-parameter
6983 (tramp-file-name-method hop) 'tramp-default-port)))))
6984 ;; Open the gateway connection.
6985 (add-to-list
6986 'target-alist
6987 (vector
6988 (tramp-file-name-method hop) (tramp-file-name-user hop)
9e6ab520 6989 (funcall (symbol-function 'tramp-gw-open-connection) vec gw hop) nil))
00d6fd04
MA
6990 ;; For the password prompt, we need the correct values.
6991 ;; Therefore, we must remember the gateway vector. But we
6992 ;; cannot do it as connection property, because it shouldn't
6993 ;; be persistent. And we have no started process yet either.
6994 (tramp-set-file-property (car target-alist) "" "gateway" hop)))
6995
6996 ;; Foreign and out-of-band methods are not supported for multi-hops.
6997 (when (cdr target-alist)
6998 (setq choices target-alist)
6999 (while choices
7000 (setq item (pop choices))
7001 (when
7002 (or
7003 (not
7004 (tramp-get-method-parameter
7005 (tramp-file-name-method item) 'tramp-login-program))
7006 (tramp-get-method-parameter
7007 (tramp-file-name-method item) 'tramp-copy-program))
7008 (tramp-error
7009 vec 'file-error
7010 "Method `%s' is not supported for multi-hops."
7011 (tramp-file-name-method item)))))
7012
2991e49f
MA
7013 ;; In case the host name is not used for the remote shell
7014 ;; command, the user could be misguided by applying a random
7015 ;; hostname.
7016 (let* ((v (car target-alist))
7017 (method (tramp-file-name-method v))
7018 (host (tramp-file-name-host v)))
7019 (unless
7020 (or
7021 ;; There are multi-hops.
7022 (cdr target-alist)
7023 ;; The host name is used for the remote shell command.
7024 (member
7025 '("%h") (tramp-get-method-parameter method 'tramp-login-args))
7026 ;; The host is local. We cannot use `tramp-local-host-p'
7027 ;; here, because it opens a connection as well.
b96e6899 7028 (string-match tramp-local-host-regexp host))
2991e49f 7029 (tramp-error
42bc9b6d
MA
7030 v 'file-error
7031 "Host `%s' looks like a remote host, `%s' can only use the local host"
7032 host method)))
2991e49f 7033
00d6fd04
MA
7034 ;; Result.
7035 target-alist))
7036
7037(defun tramp-maybe-open-connection (vec)
7038 "Maybe open a connection VEC.
fb7933a3
KG
7039Does not do anything if a connection is already open, but re-opens the
7040connection if a previous connection has died for some reason."
d8ac123e
MA
7041 (catch 'uname-changed
7042 (let ((p (tramp-get-connection-process vec))
7043 (process-environment (copy-sequence process-environment)))
7044
7045 ;; If too much time has passed since last command was sent, look
7046 ;; whether process is still alive. If it isn't, kill it. When
7047 ;; using ssh, it can sometimes happen that the remote end has
7048 ;; hung up but the local ssh client doesn't recognize this until
7049 ;; it tries to send some data to the remote end. So that's why
7050 ;; we try to send a command from time to time, then look again
7051 ;; whether the process is really alive.
7052 (condition-case nil
7053 (when (and (> (tramp-time-diff
7054 (current-time)
7055 (tramp-get-connection-property
7056 p "last-cmd-time" '(0 0 0)))
7057 60)
7058 p (processp p) (memq (process-status p) '(run open)))
7059 (tramp-send-command vec "echo are you awake" t t)
7060 (unless (and (memq (process-status p) '(run open))
7061 (tramp-wait-for-output p 10))
7062 ;; The error will be catched locally.
7063 (tramp-error vec 'file-error "Awake did fail")))
7064 (file-error
7065 (tramp-flush-connection-property vec)
7066 (tramp-flush-connection-property p)
7067 (delete-process p)
7068 (setq p nil)))
7069
7070 ;; New connection must be opened.
7071 (unless (and p (processp p) (memq (process-status p) '(run open)))
7072
7073 ;; We call `tramp-get-buffer' in order to get a debug buffer for
7074 ;; messages from the beginning.
7075 (tramp-get-buffer vec)
7076 (if (zerop (length (tramp-file-name-user vec)))
7077 (tramp-message
7078 vec 3 "Opening connection for %s using %s..."
7079 (tramp-file-name-host vec)
7080 (tramp-file-name-method vec))
00d6fd04 7081 (tramp-message
d8ac123e
MA
7082 vec 3 "Opening connection for %s@%s using %s..."
7083 (tramp-file-name-user vec)
00d6fd04 7084 (tramp-file-name-host vec)
d8ac123e
MA
7085 (tramp-file-name-method vec)))
7086
7087 ;; Start new process.
7088 (when (and p (processp p))
7089 (delete-process p))
7090 (setenv "TERM" tramp-terminal-type)
7091 (setenv "LC_ALL" "C")
7092 (setenv "PROMPT_COMMAND")
7093 (setenv "PS1" "$ ")
7094 (let* ((target-alist (tramp-compute-multi-hops vec))
7095 (process-connection-type tramp-process-connection-type)
7096 (process-adaptive-read-buffering nil)
7097 (coding-system-for-read nil)
7098 ;; This must be done in order to avoid our file name handler.
7099 (p (let ((default-directory
7100 (tramp-compat-temporary-file-directory)))
7101 (start-process
7102 (or (tramp-get-connection-property vec "process-name" nil)
7103 (tramp-buffer-name vec))
7104 (tramp-get-connection-buffer vec)
70c11b0b 7105 tramp-encoding-shell))))
00d6fd04 7106
d8ac123e
MA
7107 (tramp-message
7108 vec 6 "%s" (mapconcat 'identity (process-command p) " "))
7109
7110 ;; Check whether process is alive.
d8ac123e
MA
7111 (tramp-set-process-query-on-exit-flag p nil)
7112 (tramp-message vec 3 "Waiting 60s for local shell to come up...")
7113 (tramp-barf-if-no-shell-prompt
7114 p 60 "Couldn't find local shell prompt %s" tramp-encoding-shell)
7115
7116 ;; Now do all the connections as specified.
7117 (while target-alist
7118 (let* ((hop (car target-alist))
7119 (l-method (tramp-file-name-method hop))
7120 (l-user (tramp-file-name-user hop))
7121 (l-host (tramp-file-name-host hop))
7122 (l-port nil)
7123 (login-program
7124 (tramp-get-method-parameter l-method 'tramp-login-program))
7125 (login-args
7126 (tramp-get-method-parameter l-method 'tramp-login-args))
7127 (gw-args
7128 (tramp-get-method-parameter l-method 'tramp-gw-args))
7129 (gw (tramp-get-file-property hop "" "gateway" nil))
7130 (g-method (and gw (tramp-file-name-method gw)))
7131 (g-user (and gw (tramp-file-name-user gw)))
7132 (g-host (and gw (tramp-file-name-host gw)))
7133 (command login-program)
7134 ;; We don't create the temporary file. In fact, it
7135 ;; is just a prefix for the ControlPath option of
7136 ;; ssh; the real temporary file has another name, and
7137 ;; it is created and protected by ssh. It is also
7138 ;; removed by ssh, when the connection is closed.
7139 (tmpfile
7140 (tramp-set-connection-property
7141 p "temp-file"
7142 (make-temp-name
7143 (expand-file-name
7144 tramp-temp-name-prefix
7145 (tramp-compat-temporary-file-directory)))))
7146 spec)
7147
7148 ;; Add gateway arguments if necessary.
7149 (when (and gw gw-args)
7150 (setq login-args (append login-args gw-args)))
7151
7152 ;; Check for port number. Until now, there's no need
7153 ;; for handling like method, user, host.
7154 (when (string-match tramp-host-with-port-regexp l-host)
7155 (setq l-port (match-string 2 l-host)
7156 l-host (match-string 1 l-host)))
7157
7158 ;; Set variables for computing the prompt for reading
2296b54d 7159 ;; password. They can also be derived from a gateway.
d8ac123e
MA
7160 (setq tramp-current-method (or g-method l-method)
7161 tramp-current-user (or g-user l-user)
7162 tramp-current-host (or g-host l-host))
7163
7164 ;; Replace login-args place holders.
7165 (setq
7166 l-host (or l-host "")
7167 l-user (or l-user "")
7168 l-port (or l-port "")
7169 spec `((?h . ,l-host) (?u . ,l-user) (?p . ,l-port)
7170 (?t . ,tmpfile))
7171 command
7172 (concat
7173 command " "
7174 (mapconcat
aa485f7c
MA
7175 (lambda (x)
7176 (setq x (mapcar (lambda (y) (format-spec y spec)) x))
7177 (unless (member "" x) (mapconcat 'identity x " ")))
d8ac123e 7178 login-args " ")
d8ac123e
MA
7179 ;; Local shell could be a Windows COMSPEC. It doesn't
7180 ;; know the ";" syntax, but we must exit always for
70c11b0b
MA
7181 ;; `start-file-process'. "exec" does not work either.
7182 " && exit || exit"))
d8ac123e
MA
7183
7184 ;; Send the command.
7185 (tramp-message vec 3 "Sending command `%s'" command)
7186 (tramp-send-command vec command t t)
7187 (tramp-process-actions p vec tramp-actions-before-shell 60)
7188 (tramp-message vec 3 "Found remote shell prompt on `%s'" l-host))
7189 ;; Next hop.
7190 (setq target-alist (cdr target-alist)))
7191
7192 ;; Make initial shell settings.
7193 (tramp-open-connection-setup-interactive-shell p vec))))))
00d6fd04
MA
7194
7195(defun tramp-send-command (vec command &optional neveropen nooutput)
7196 "Send the COMMAND to connection VEC.
7197Erases temporary buffer before sending the command. If optional
7198arg NEVEROPEN is non-nil, never try to open the connection. This
7199is meant to be used from `tramp-maybe-open-connection' only. The
7200function waits for output unless NOOUTPUT is set."
7201 (unless neveropen (tramp-maybe-open-connection vec))
7202 (let ((p (tramp-get-connection-process vec)))
8950769a 7203 (when (tramp-get-connection-property p "remote-echo" nil)
00d6fd04
MA
7204 ;; We mark the command string that it can be erased in the output buffer.
7205 (tramp-set-connection-property p "check-remote-echo" t)
7206 (setq command (format "%s%s%s" tramp-echo-mark command tramp-echo-mark)))
7207 (tramp-message vec 6 "%s" command)
7208 (tramp-send-string vec command)
7209 (unless nooutput (tramp-wait-for-output p))))
7210
00d6fd04 7211(defun tramp-wait-for-output (proc &optional timeout)
fb7933a3 7212 "Wait for output from remote rsh command."
00d6fd04 7213 (with-current-buffer (process-buffer proc)
bede3e9f
MA
7214 (let* (;; Initially, `tramp-end-of-output' is "$ ". There might
7215 ;; be leading escape sequences, which must be ignored.
7216 (regexp (format "[^$\n]*%s\r?$" (regexp-quote tramp-end-of-output)))
7217 ;; Sometimes, the commands do not return a newline but a
7218 ;; null byte before the shell prompt, for example "git
7219 ;; ls-files -c -z ...".
7220 (regexp1 (format "\\(^\\|\000\\)%s" regexp))
7221 (found (tramp-wait-for-regexp proc timeout regexp1)))
00d6fd04
MA
7222 (if found
7223 (let (buffer-read-only)
7224 (goto-char (point-max))
0664ff72 7225 (re-search-backward regexp nil t)
00d6fd04
MA
7226 (delete-region (point) (point-max)))
7227 (if timeout
7228 (tramp-error
7229 proc 'file-error
7230 "[[Remote prompt `%s' not found in %d secs]]"
7231 tramp-end-of-output timeout)
7232 (tramp-error
7233 proc 'file-error
7234 "[[Remote prompt `%s' not found]]" tramp-end-of-output)))
7235 ;; Return value is whether end-of-output sentinel was found.
7236 found)))
fb7933a3 7237
00d6fd04 7238(defun tramp-send-command-and-check (vec command &optional subshell)
fb7933a3 7239 "Run COMMAND and check its exit status.
fb7933a3
KG
7240Sends `echo $?' along with the COMMAND for checking the exit status. If
7241COMMAND is nil, just sends `echo $?'. Returns the exit status found.
7242
7243If the optional argument SUBSHELL is non-nil, the command is executed in
7244a subshell, ie surrounded by parentheses."
00d6fd04
MA
7245 (tramp-send-command
7246 vec
7247 (concat (if subshell "( " "")
7248 command
7249 (if command " 2>/dev/null; " "")
7250 "echo tramp_exit_status $?"
7251 (if subshell " )" " ")))
7252 (with-current-buffer (tramp-get-connection-buffer vec)
7253 (goto-char (point-max))
7254 (unless (re-search-backward "tramp_exit_status [0-9]+" nil t)
7255 (tramp-error
7256 vec 'file-error "Couldn't find exit status of `%s'" command))
7257 (skip-chars-forward "^ ")
7258 (prog1
7259 (read (current-buffer))
7260 (let (buffer-read-only) (delete-region (match-beginning 0) (point-max))))))
7261
7262(defun tramp-barf-unless-okay (vec command fmt &rest args)
fb7933a3
KG
7263 "Run COMMAND, check exit status, throw error if exit status not okay.
7264Similar to `tramp-send-command-and-check' but accepts two more arguments
7265FMT and ARGS which are passed to `error'."
00d6fd04
MA
7266 (unless (zerop (tramp-send-command-and-check vec command))
7267 (apply 'tramp-error vec 'file-error fmt args)))
7268
7269(defun tramp-send-command-and-read (vec command)
7270 "Run COMMAND and return the output, which must be a Lisp expression.
7271In case there is no valid Lisp expression, it raises an error"
7272 (tramp-barf-unless-okay vec command "`%s' returns with error" command)
7273 (with-current-buffer (tramp-get-connection-buffer vec)
7274 ;; Read the expression.
7275 (goto-char (point-min))
7276 (condition-case nil
7277 (prog1 (read (current-buffer))
7278 ;; Error handling.
9e6ab520 7279 (when (re-search-forward "\\S-" (tramp-compat-line-end-position) t)
9ce8462a 7280 (error nil)))
00d6fd04
MA
7281 (error (tramp-error
7282 vec 'file-error
7283 "`%s' does not return a valid Lisp expression: `%s'"
7284 command (buffer-string))))))
fb7933a3 7285
7432277c
KG
7286;; It seems that Tru64 Unix does not like it if long strings are sent
7287;; to it in one go. (This happens when sending the Perl
7288;; `file-attributes' implementation, for instance.) Therefore, we
27e813fe 7289;; have this function which sends the string in chunks.
00d6fd04
MA
7290(defun tramp-send-string (vec string)
7291 "Send the STRING via connection VEC.
7432277c
KG
7292
7293The STRING is expected to use Unix line-endings, but the lines sent to
7294the remote host use line-endings as defined in the variable
00d6fd04
MA
7295`tramp-rsh-end-of-line'. The communication buffer is erased before sending."
7296 (let* ((p (tramp-get-connection-process vec))
7297 (chunksize (tramp-get-connection-property p "chunksize" nil)))
7298 (unless p
7299 (tramp-error
7300 vec 'file-error "Can't send string to remote host -- not logged in"))
7301 (tramp-set-connection-property p "last-cmd-time" (current-time))
7302 (tramp-message vec 10 "%s" string)
7303 (with-current-buffer (tramp-get-connection-buffer vec)
7304 ;; Clean up the buffer. We cannot call `erase-buffer' because
7305 ;; narrowing might be in effect.
7306 (let (buffer-read-only) (delete-region (point-min) (point-max)))
27e813fe 7307 ;; Replace "\n" by `tramp-rsh-end-of-line'.
00d6fd04
MA
7308 (setq string
7309 (mapconcat 'identity
70c11b0b 7310 (tramp-compat-split-string string "\n")
00d6fd04
MA
7311 tramp-rsh-end-of-line))
7312 (unless (or (string= string "")
7313 (string-equal (substring string -1) tramp-rsh-end-of-line))
7314 (setq string (concat string tramp-rsh-end-of-line)))
27e813fe 7315 ;; Send the string.
00d6fd04
MA
7316 (if (and chunksize (not (zerop chunksize)))
7317 (let ((pos 0)
7318 (end (length string)))
7319 (while (< pos end)
7320 (tramp-message
7321 vec 10 "Sending chunk from %s to %s"
7322 pos (min (+ pos chunksize) end))
7323 (process-send-string
7324 p (substring string pos (min (+ pos chunksize) end)))
7325 (setq pos (+ pos chunksize))))
7326 (process-send-string p string)))))
fb7933a3
KG
7327
7328(defun tramp-mode-string-to-int (mode-string)
7329 "Converts a ten-letter `drwxrwxrwx'-style mode string into mode bits."
f3c071dd
MA
7330 (let* (case-fold-search
7331 (mode-chars (string-to-vector mode-string))
fb7933a3
KG
7332 (owner-read (aref mode-chars 1))
7333 (owner-write (aref mode-chars 2))
7334 (owner-execute-or-setid (aref mode-chars 3))
7335 (group-read (aref mode-chars 4))
7336 (group-write (aref mode-chars 5))
7337 (group-execute-or-setid (aref mode-chars 6))
7338 (other-read (aref mode-chars 7))
7339 (other-write (aref mode-chars 8))
7340 (other-execute-or-sticky (aref mode-chars 9)))
7341 (save-match-data
7342 (logior
f3c071dd
MA
7343 (cond
7344 ((char-equal owner-read ?r) (tramp-octal-to-decimal "00400"))
7345 ((char-equal owner-read ?-) 0)
7346 (t (error "Second char `%c' must be one of `r-'" owner-read)))
7347 (cond
7348 ((char-equal owner-write ?w) (tramp-octal-to-decimal "00200"))
7349 ((char-equal owner-write ?-) 0)
7350 (t (error "Third char `%c' must be one of `w-'" owner-write)))
7351 (cond
7352 ((char-equal owner-execute-or-setid ?x)
7353 (tramp-octal-to-decimal "00100"))
7354 ((char-equal owner-execute-or-setid ?S)
7355 (tramp-octal-to-decimal "04000"))
7356 ((char-equal owner-execute-or-setid ?s)
7357 (tramp-octal-to-decimal "04100"))
7358 ((char-equal owner-execute-or-setid ?-) 0)
7359 (t (error "Fourth char `%c' must be one of `xsS-'"
7360 owner-execute-or-setid)))
7361 (cond
7362 ((char-equal group-read ?r) (tramp-octal-to-decimal "00040"))
7363 ((char-equal group-read ?-) 0)
7364 (t (error "Fifth char `%c' must be one of `r-'" group-read)))
7365 (cond
7366 ((char-equal group-write ?w) (tramp-octal-to-decimal "00020"))
7367 ((char-equal group-write ?-) 0)
7368 (t (error "Sixth char `%c' must be one of `w-'" group-write)))
7369 (cond
7370 ((char-equal group-execute-or-setid ?x)
7371 (tramp-octal-to-decimal "00010"))
7372 ((char-equal group-execute-or-setid ?S)
7373 (tramp-octal-to-decimal "02000"))
7374 ((char-equal group-execute-or-setid ?s)
7375 (tramp-octal-to-decimal "02010"))
7376 ((char-equal group-execute-or-setid ?-) 0)
7377 (t (error "Seventh char `%c' must be one of `xsS-'"
7378 group-execute-or-setid)))
7379 (cond
7380 ((char-equal other-read ?r)
7381 (tramp-octal-to-decimal "00004"))
7382 ((char-equal other-read ?-) 0)
7383 (t (error "Eighth char `%c' must be one of `r-'" other-read)))
7384 (cond
7385 ((char-equal other-write ?w) (tramp-octal-to-decimal "00002"))
7386 ((char-equal other-write ?-) 0)
fb7933a3 7387 (t (error "Nineth char `%c' must be one of `w-'" other-write)))
f3c071dd
MA
7388 (cond
7389 ((char-equal other-execute-or-sticky ?x)
7390 (tramp-octal-to-decimal "00001"))
7391 ((char-equal other-execute-or-sticky ?T)
7392 (tramp-octal-to-decimal "01000"))
7393 ((char-equal other-execute-or-sticky ?t)
7394 (tramp-octal-to-decimal "01001"))
7395 ((char-equal other-execute-or-sticky ?-) 0)
7396 (t (error "Tenth char `%c' must be one of `xtT-'"
7397 other-execute-or-sticky)))))))
fb7933a3 7398
00d6fd04
MA
7399(defun tramp-convert-file-attributes (vec attr)
7400 "Convert file-attributes ATTR generated by perl script, stat or ls.
c82c5727
LH
7401Convert file mode bits to string and set virtual device number.
7402Return ATTR."
680db9ac
MA
7403 (when attr
7404 ;; Convert last access time.
7405 (unless (listp (nth 4 attr))
7406 (setcar (nthcdr 4 attr)
7407 (list (floor (nth 4 attr) 65536)
7408 (floor (mod (nth 4 attr) 65536)))))
7409 ;; Convert last modification time.
7410 (unless (listp (nth 5 attr))
7411 (setcar (nthcdr 5 attr)
7412 (list (floor (nth 5 attr) 65536)
7413 (floor (mod (nth 5 attr) 65536)))))
7414 ;; Convert last status change time.
7415 (unless (listp (nth 6 attr))
7416 (setcar (nthcdr 6 attr)
7417 (list (floor (nth 6 attr) 65536)
7418 (floor (mod (nth 6 attr) 65536)))))
7419 ;; Convert file size.
7420 (when (< (nth 7 attr) 0)
7421 (setcar (nthcdr 7 attr) -1))
7422 (when (and (floatp (nth 7 attr))
7423 (<= (nth 7 attr) (tramp-compat-most-positive-fixnum)))
7424 (setcar (nthcdr 7 attr) (round (nth 7 attr))))
7425 ;; Convert file mode bits to string.
7426 (unless (stringp (nth 8 attr))
7427 (setcar (nthcdr 8 attr) (tramp-file-mode-from-int (nth 8 attr)))
7428 (when (stringp (car attr))
7429 (aset (nth 8 attr) 0 ?l)))
7430 ;; Convert directory indication bit.
7431 (when (string-match "^d" (nth 8 attr))
7432 (setcar attr t))
7433 ;; Convert symlink from `tramp-do-file-attributes-with-stat'.
7434 (when (consp (car attr))
7435 (if (and (stringp (caar attr))
7436 (string-match ".+ -> .\\(.+\\)." (caar attr)))
7437 (setcar attr (match-string 1 (caar attr)))
7438 (setcar attr nil)))
7439 ;; Set file's gid change bit.
7440 (setcar (nthcdr 9 attr)
7441 (if (numberp (nth 3 attr))
7442 (not (= (nth 3 attr)
7443 (tramp-get-remote-gid vec 'integer)))
7444 (not (string-equal
7445 (nth 3 attr)
7446 (tramp-get-remote-gid vec 'string)))))
7447 ;; Convert inode.
7448 (unless (listp (nth 10 attr))
7449 (setcar (nthcdr 10 attr)
7450 (condition-case nil
7451 (cons (floor (nth 10 attr) 65536)
7452 (floor (mod (nth 10 attr) 65536)))
7453 ;; Inodes can be incredible huge. We must hide this.
7454 (error (tramp-get-inode vec)))))
7455 ;; Set virtual device number.
7456 (setcar (nthcdr 11 attr)
7457 (tramp-get-device vec))
7458 attr))
c82c5727 7459
293c24f9
MA
7460(defun tramp-check-cached-permissions (vec access)
7461 "Check `file-attributes' caches for VEC.
7462Return t if according to the cache access type ACCESS is known to
7463be granted."
7464 (let ((result nil)
7465 (offset (cond
7466 ((eq ?r access) 1)
7467 ((eq ?w access) 2)
7468 ((eq ?x access) 3))))
7469 (dolist (suffix '("string" "integer") result)
7470 (setq
7471 result
7472 (or
7473 result
7474 (let ((file-attr
7475 (tramp-get-file-property
7476 vec (tramp-file-name-localname vec)
7477 (concat "file-attributes-" suffix) nil))
7478 (remote-uid
7479 (tramp-get-connection-property
7480 vec (concat "uid-" suffix) nil))
7481 (remote-gid
7482 (tramp-get-connection-property
7483 vec (concat "gid-" suffix) nil)))
7484 (and
7485 file-attr
7486 (or
7487 ;; Not a symlink
7488 (eq t (car file-attr))
7489 (null (car file-attr)))
7490 (or
7491 ;; World accessible.
7492 (eq access (aref (nth 8 file-attr) (+ offset 6)))
7493 ;; User accessible and owned by user.
7494 (and
7495 (eq access (aref (nth 8 file-attr) offset))
7496 (equal remote-uid (nth 2 file-attr)))
7497 ;; Group accessible and owned by user's
7498 ;; principal group.
7499 (and
7500 (eq access (aref (nth 8 file-attr) (+ offset 3)))
7501 (equal remote-gid (nth 3 file-attr)))))))))))
7502
ce3f516f 7503(defun tramp-get-inode (vec)
00d6fd04
MA
7504 "Returns the virtual inode number.
7505If it doesn't exist, generate a new one."
ce3f516f
MA
7506 (let ((string (tramp-make-tramp-file-name
7507 (tramp-file-name-method vec)
7508 (tramp-file-name-user vec)
7509 (tramp-file-name-host vec)
7510 "")))
00d6fd04
MA
7511 (unless (assoc string tramp-inodes)
7512 (add-to-list 'tramp-inodes
7513 (list string (length tramp-inodes))))
7514 (nth 1 (assoc string tramp-inodes))))
7515
7516(defun tramp-get-device (vec)
c82c5727
LH
7517 "Returns the virtual device number.
7518If it doesn't exist, generate a new one."
00d6fd04
MA
7519 (let ((string (tramp-make-tramp-file-name
7520 (tramp-file-name-method vec)
7521 (tramp-file-name-user vec)
7522 (tramp-file-name-host vec)
7523 "")))
c82c5727
LH
7524 (unless (assoc string tramp-devices)
7525 (add-to-list 'tramp-devices
7526 (list string (length tramp-devices))))
b946a456 7527 (cons -1 (nth 1 (assoc string tramp-devices)))))
fb7933a3
KG
7528
7529(defun tramp-file-mode-from-int (mode)
7530 "Turn an integer representing a file mode into an ls(1)-like string."
7531 (let ((type (cdr (assoc (logand (lsh mode -12) 15) tramp-file-mode-type-map)))
7532 (user (logand (lsh mode -6) 7))
7533 (group (logand (lsh mode -3) 7))
7534 (other (logand (lsh mode -0) 7))
7535 (suid (> (logand (lsh mode -9) 4) 0))
7536 (sgid (> (logand (lsh mode -9) 2) 0))
7537 (sticky (> (logand (lsh mode -9) 1) 0)))
7538 (setq user (tramp-file-mode-permissions user suid "s"))
7539 (setq group (tramp-file-mode-permissions group sgid "s"))
7540 (setq other (tramp-file-mode-permissions other sticky "t"))
7541 (concat type user group other)))
7542
fb7933a3
KG
7543(defun tramp-file-mode-permissions (perm suid suid-text)
7544 "Convert a permission bitset into a string.
7545This is used internally by `tramp-file-mode-from-int'."
7546 (let ((r (> (logand perm 4) 0))
7547 (w (> (logand perm 2) 0))
7548 (x (> (logand perm 1) 0)))
7549 (concat (or (and r "r") "-")
7550 (or (and w "w") "-")
7551 (or (and suid x suid-text) ; suid, execute
7552 (and suid (upcase suid-text)) ; suid, !execute
7553 (and x "x") "-")))) ; !suid
7554
fb7933a3
KG
7555(defun tramp-decimal-to-octal (i)
7556 "Return a string consisting of the octal digits of I.
7557Not actually used. Use `(format \"%o\" i)' instead?"
7558 (cond ((< i 0) (error "Cannot convert negative number to octal"))
7559 ((not (integerp i)) (error "Cannot convert non-integer to octal"))
7560 ((zerop i) "0")
7561 (t (concat (tramp-decimal-to-octal (/ i 8))
7562 (number-to-string (% i 8))))))
7563
fb7933a3
KG
7564;; Kudos to Gerd Moellmann for this suggestion.
7565(defun tramp-octal-to-decimal (ostr)
7566 "Given a string of octal digits, return a decimal number."
7567 (let ((x (or ostr "")))
7568 ;; `save-match' is in `tramp-mode-string-to-int' which calls this.
7569 (unless (string-match "\\`[0-7]*\\'" x)
7570 (error "Non-octal junk in string `%s'" x))
7571 (string-to-number ostr 8)))
7572
7573(defun tramp-shell-case-fold (string)
7574 "Converts STRING to shell glob pattern which ignores case."
7575 (mapconcat
7576 (lambda (c)
7577 (if (equal (downcase c) (upcase c))
7578 (vector c)
7579 (format "[%c%c]" (downcase c) (upcase c))))
7580 string
7581 ""))
7582
7583
bf247b6e 7584;; ------------------------------------------------------------
a4aeb9a4 7585;; -- Tramp file names --
bf247b6e 7586;; ------------------------------------------------------------
fb7933a3
KG
7587;; Conversion functions between external representation and
7588;; internal data structure. Convenience functions for internal
7589;; data structure.
7590
00d6fd04
MA
7591(defun tramp-file-name-p (vec)
7592 "Check whether VEC is a Tramp object."
7593 (and (vectorp vec) (= 4 (length vec))))
7594
7595(defun tramp-file-name-method (vec)
7596 "Return method component of VEC."
7597 (and (tramp-file-name-p vec) (aref vec 0)))
7598
7599(defun tramp-file-name-user (vec)
7600 "Return user component of VEC."
7601 (and (tramp-file-name-p vec) (aref vec 1)))
7602
7603(defun tramp-file-name-host (vec)
7604 "Return host component of VEC."
7605 (and (tramp-file-name-p vec) (aref vec 2)))
7606
7607(defun tramp-file-name-localname (vec)
7608 "Return localname component of VEC."
7609 (and (tramp-file-name-p vec) (aref vec 3)))
7610
dea31ca6 7611;; The user part of a Tramp file name vector can be of kind
b96e6899 7612;; "user%domain". Sometimes, we must extract these parts.
dea31ca6
MA
7613(defun tramp-file-name-real-user (vec)
7614 "Return the user name of VEC without domain."
a17632c1
MA
7615 (save-match-data
7616 (let ((user (tramp-file-name-user vec)))
7617 (if (and (stringp user)
7618 (string-match tramp-user-with-domain-regexp user))
7619 (match-string 1 user)
7620 user))))
dea31ca6
MA
7621
7622(defun tramp-file-name-domain (vec)
7623 "Return the domain name of VEC."
a17632c1
MA
7624 (save-match-data
7625 (let ((user (tramp-file-name-user vec)))
7626 (and (stringp user)
7627 (string-match tramp-user-with-domain-regexp user)
7628 (match-string 2 user)))))
dea31ca6 7629
00d6fd04
MA
7630;; The host part of a Tramp file name vector can be of kind
7631;; "host#port". Sometimes, we must extract these parts.
8a4438b6 7632(defun tramp-file-name-real-host (vec)
00d6fd04 7633 "Return the host name of VEC without port."
a17632c1
MA
7634 (save-match-data
7635 (let ((host (tramp-file-name-host vec)))
7636 (if (and (stringp host)
7637 (string-match tramp-host-with-port-regexp host))
7638 (match-string 1 host)
7639 host))))
00d6fd04 7640
8a4438b6 7641(defun tramp-file-name-port (vec)
00d6fd04 7642 "Return the port number of VEC."
a17632c1
MA
7643 (save-match-data
7644 (let ((host (tramp-file-name-host vec)))
7645 (and (stringp host)
7646 (string-match tramp-host-with-port-regexp host)
7647 (string-to-number (match-string 2 host))))))
fb7933a3
KG
7648
7649(defun tramp-tramp-file-p (name)
a4aeb9a4 7650 "Return t if NAME is a Tramp file."
fb7933a3
KG
7651 (save-match-data
7652 (string-match tramp-file-name-regexp name)))
bf247b6e 7653
8a4438b6 7654(defun tramp-find-method (method user host)
00d6fd04
MA
7655 "Return the right method string to use.
7656This is METHOD, if non-nil. Otherwise, do a lookup in
7657`tramp-default-method-alist'."
7658 (or method
7659 (let ((choices tramp-default-method-alist)
7660 lmethod item)
7661 (while choices
7662 (setq item (pop choices))
7663 (when (and (string-match (or (nth 0 item) "") (or host ""))
7664 (string-match (or (nth 1 item) "") (or user "")))
7665 (setq lmethod (nth 2 item))
7666 (setq choices nil)))
7667 lmethod)
7668 tramp-default-method))
7669
8a4438b6 7670(defun tramp-find-user (method user host)
00d6fd04
MA
7671 "Return the right user string to use.
7672This is USER, if non-nil. Otherwise, do a lookup in
7673`tramp-default-user-alist'."
7674 (or user
7675 (let ((choices tramp-default-user-alist)
7676 luser item)
7677 (while choices
7678 (setq item (pop choices))
7679 (when (and (string-match (or (nth 0 item) "") (or method ""))
7680 (string-match (or (nth 1 item) "") (or host "")))
7681 (setq luser (nth 2 item))
7682 (setq choices nil)))
7683 luser)
7684 tramp-default-user))
7685
8a4438b6 7686(defun tramp-find-host (method user host)
00d6fd04
MA
7687 "Return the right host string to use.
7688This is HOST, if non-nil. Otherwise, it is `tramp-default-host'."
7689 (or (and (> (length host) 0) host)
7690 tramp-default-host))
7691
9ce8462a 7692(defun tramp-dissect-file-name (name &optional nodefault)
00d6fd04 7693 "Return a `tramp-file-name' structure.
9ce8462a
MA
7694The structure consists of remote method, remote user, remote host
7695and localname (file name on remote host). If NODEFAULT is
7696non-nil, the file name parts are not expanded to their default
7697values."
4007ba5b 7698 (save-match-data
00d6fd04 7699 (let ((match (string-match (nth 0 tramp-file-name-structure) name)))
a4aeb9a4 7700 (unless match (error "Not a Tramp file name: %s" name))
00d6fd04
MA
7701 (let ((method (match-string (nth 1 tramp-file-name-structure) name))
7702 (user (match-string (nth 2 tramp-file-name-structure) name))
7703 (host (match-string (nth 3 tramp-file-name-structure) name))
7704 (localname (match-string (nth 4 tramp-file-name-structure) name)))
5d449a36
MA
7705 (when (member method '("multi" "multiu"))
7706 (error
7707 "`%s' method is no longer supported, see (info \"(tramp)Multi-hops\")"
7708 method))
b96e6899
MA
7709 (when host
7710 (when (string-match tramp-prefix-ipv6-regexp host)
7711 (setq host (replace-match "" nil t host)))
7712 (when (string-match tramp-postfix-ipv6-regexp host)
7713 (setq host (replace-match "" nil t host))))
9ce8462a
MA
7714 (if nodefault
7715 (vector method user host localname)
7716 (vector
7717 (tramp-find-method method user host)
7718 (tramp-find-user method user host)
7719 (tramp-find-host method user host)
7720 localname))))))
00d6fd04
MA
7721
7722(defun tramp-equal-remote (file1 file2)
7723 "Checks, whether the remote parts of FILE1 and FILE2 are identical.
7724The check depends on method, user and host name of the files. If
7725one of the components is missing, the default values are used.
7726The local file name parts of FILE1 and FILE2 are not taken into
7727account.
fb7933a3 7728
00d6fd04
MA
7729Example:
7730
7731 (tramp-equal-remote \"/ssh::/etc\" \"/<your host name>:/home\")
7732
7733would yield `t'. On the other hand, the following check results in nil:
7734
7735 (tramp-equal-remote \"/sudo::/etc\" \"/su::/etc\")"
9e6ab520
MA
7736 (and (stringp (file-remote-p file1))
7737 (stringp (file-remote-p file2))
94be87e8 7738 (string-equal (file-remote-p file1) (file-remote-p file2))))
00d6fd04
MA
7739
7740(defun tramp-make-tramp-file-name (method user host localname)
7741 "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME."
7742 (concat tramp-prefix-format
7743 (when (not (zerop (length method)))
7744 (concat method tramp-postfix-method-format))
7745 (when (not (zerop (length user)))
7746 (concat user tramp-postfix-user-format))
b96e6899
MA
7747 (when host
7748 (if (string-match tramp-ipv6-regexp host)
7749 (concat tramp-prefix-ipv6-format host tramp-postfix-ipv6-format)
7750 host))
7751 tramp-postfix-host-format
00d6fd04
MA
7752 (when localname localname)))
7753
7754(defun tramp-completion-make-tramp-file-name (method user host localname)
7755 "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME.
7756It must not be a complete Tramp file name, but as long as there are
7757necessary only. This function will be used in file name completion."
7758 (concat tramp-prefix-format
7759 (when (not (zerop (length method)))
7760 (concat method tramp-postfix-method-format))
7761 (when (not (zerop (length user)))
7762 (concat user tramp-postfix-user-format))
7763 (when (not (zerop (length host)))
b96e6899
MA
7764 (concat
7765 (if (string-match tramp-ipv6-regexp host)
7766 (concat tramp-prefix-ipv6-format host tramp-postfix-ipv6-format)
7767 host)
7768 tramp-postfix-host-format))
00d6fd04
MA
7769 (when localname localname)))
7770
7771(defun tramp-make-copy-program-file-name (vec)
7772 "Create a file name suitable to be passed to `rcp' and workalikes."
7773 (let ((user (tramp-file-name-user vec))
0f205eee 7774 (host (tramp-file-name-real-host vec))
00d6fd04
MA
7775 (localname (tramp-shell-quote-argument
7776 (tramp-file-name-localname vec))))
7777 (if (not (zerop (length user)))
7778 (format "%s@%s:%s" user host localname)
7779 (format "%s:%s" host localname))))
7780
7f49fe46 7781(defun tramp-method-out-of-band-p (vec size)
38c65fca 7782 "Return t if this is an out-of-band method, nil otherwise."
7f49fe46
MA
7783 (and
7784 ;; It shall be an out-of-band method.
7785 (tramp-get-method-parameter (tramp-file-name-method vec) 'tramp-copy-program)
7786 ;; Either the file size is large enough, or (in rare cases) there
7787 ;; does not exist a remote encoding.
7788 (or (> size tramp-copy-size-limit)
7789 (null (tramp-get-remote-coding vec "remote-encoding")))))
fb7933a3 7790
0f205eee
MA
7791(defun tramp-local-host-p (vec)
7792 "Return t if this points to the local host, nil otherwise."
c992abdb
MA
7793 ;; We cannot use `tramp-file-name-real-host'. A port is an
7794 ;; indication for an ssh tunnel or alike.
7795 (let ((host (tramp-file-name-host vec)))
0f205eee
MA
7796 (and
7797 (stringp host)
b96e6899 7798 (string-match tramp-local-host-regexp host)
46bcd78c
MA
7799 ;; The method shall be applied to one of the shell file name
7800 ;; handler. `tramp-local-host-p' is also called for "smb" and
7801 ;; alike, where it must fail.
7802 (tramp-get-method-parameter
7803 (tramp-file-name-method vec) 'tramp-login-program)
a0a5183a
MA
7804 ;; The local temp directory must be writable for the other user.
7805 (file-writable-p
7806 (tramp-make-tramp-file-name
7807 (tramp-file-name-method vec)
7808 (tramp-file-name-user vec)
7809 host
93c3eb7c
MA
7810 (tramp-compat-temporary-file-directory)))
7811 ;; On some systems, chown runs only for root.
7812 (or (zerop (user-uid))
7813 (zerop (tramp-get-remote-uid vec 'integer))))))
0f205eee 7814
fb7933a3
KG
7815;; Variables local to connection.
7816
f84638eb 7817(defun tramp-get-remote-path (vec)
70c11b0b
MA
7818 (with-connection-property
7819 ;; When `tramp-own-remote-path' is in `tramp-remote-path', we
7820 ;; cache the result for the session only. Otherwise, the result
7821 ;; is cached persistently.
7822 (if (memq 'tramp-own-remote-path tramp-remote-path)
7823 (tramp-get-connection-process vec)
7824 vec)
7825 "remote-path"
9e6ab520 7826 (let* ((remote-path (tramp-compat-copy-tree tramp-remote-path))
70c11b0b
MA
7827 (elt1 (memq 'tramp-default-remote-path remote-path))
7828 (elt2 (memq 'tramp-own-remote-path remote-path))
f84638eb 7829 (default-remote-path
70c11b0b 7830 (when elt1
f84638eb 7831 (condition-case nil
70c11b0b
MA
7832 (tramp-send-command-and-read
7833 vec "echo \\\"`getconf PATH`\\\"")
f84638eb
MA
7834 ;; Default if "getconf" is not available.
7835 (error
7836 (tramp-message
7837 vec 3
7838 "`getconf PATH' not successful, using default value \"%s\"."
7839 "/bin:/usr/bin")
70c11b0b
MA
7840 "/bin:/usr/bin"))))
7841 (own-remote-path
7842 (when elt2
7843 (condition-case nil
7844 (tramp-send-command-and-read vec "echo \\\"$PATH\\\"")
7845 ;; Default if "getconf" is not available.
7846 (error
7847 (tramp-message
7848 vec 3 "$PATH not set, ignoring `tramp-own-remote-path'.")
7849 nil)))))
7850
7851 ;; Replace place holder `tramp-default-remote-path'.
7852 (when elt1
7853 (setcdr elt1
f84638eb 7854 (append
70c11b0b
MA
7855 (tramp-compat-split-string default-remote-path ":")
7856 (cdr elt1)))
f84638eb
MA
7857 (setq remote-path (delq 'tramp-default-remote-path remote-path)))
7858
70c11b0b
MA
7859 ;; Replace place holder `tramp-own-remote-path'.
7860 (when elt2
7861 (setcdr elt2
7862 (append
7863 (tramp-compat-split-string own-remote-path ":")
7864 (cdr elt2)))
7865 (setq remote-path (delq 'tramp-own-remote-path remote-path)))
7866
7867 ;; Remove double entries.
7868 (setq elt1 remote-path)
7869 (while (consp elt1)
7870 (while (and (car elt1) (setq elt2 (member (car elt1) (cdr elt1))))
7871 (setcar elt2 nil))
7872 (setq elt1 (cdr elt1)))
7873
f84638eb
MA
7874 ;; Remove non-existing directories.
7875 (delq
7876 nil
7877 (mapcar
7878 (lambda (x)
7879 (and
70c11b0b
MA
7880 (stringp x)
7881 (file-directory-p
7882 (tramp-make-tramp-file-name
7883 (tramp-file-name-method vec)
7884 (tramp-file-name-user vec)
7885 (tramp-file-name-host vec)
7886 x))
f84638eb
MA
7887 x))
7888 remote-path)))))
7889
a4aeb9a4
MA
7890(defun tramp-get-remote-tmpdir (vec)
7891 (with-connection-property vec "tmp-directory"
7892 (let ((dir (tramp-shell-quote-argument "/tmp")))
7893 (if (and (zerop
7894 (tramp-send-command-and-check
7895 vec (format "%s -d %s" (tramp-get-test-command vec) dir)))
7896 (zerop
7897 (tramp-send-command-and-check
7898 vec (format "%s -w %s" (tramp-get-test-command vec) dir))))
7899 dir
7900 (tramp-error vec 'file-error "Directory %s not accessible" dir)))))
7901
00d6fd04
MA
7902(defun tramp-get-ls-command (vec)
7903 (with-connection-property vec "ls"
946a5aeb
MA
7904 (tramp-message vec 5 "Finding a suitable `ls' command")
7905 (or
7906 (catch 'ls-found
7907 (dolist (cmd '("ls" "gnuls" "gls"))
7908 (let ((dl (tramp-get-remote-path vec))
7909 result)
7910 (while (and dl (setq result (tramp-find-executable vec cmd dl t t)))
7911 ;; Check parameter.
7912 (when (zerop (tramp-send-command-and-check
7913 vec (format "%s -lnd /" result)))
7914 (throw 'ls-found result))
7915 (setq dl (cdr dl))))))
7916 (tramp-error vec 'file-error "Couldn't find a proper `ls' command"))))
00d6fd04 7917
8e754ea2
MA
7918(defun tramp-get-ls-command-with-dired (vec)
7919 (save-match-data
7920 (with-connection-property vec "ls-dired"
7921 (tramp-message vec 5 "Checking, whether `ls --dired' works")
7922 (zerop (tramp-send-command-and-check
7f49fe46 7923 vec (format "%s --dired /" (tramp-get-ls-command vec)))))))
8e754ea2 7924
00d6fd04
MA
7925(defun tramp-get-test-command (vec)
7926 (with-connection-property vec "test"
946a5aeb
MA
7927 (tramp-message vec 5 "Finding a suitable `test' command")
7928 (if (zerop (tramp-send-command-and-check vec "test 0"))
7929 "test"
7930 (tramp-find-executable vec "test" (tramp-get-remote-path vec)))))
00d6fd04
MA
7931
7932(defun tramp-get-test-nt-command (vec)
7933 ;; Does `test A -nt B' work? Use abominable `find' construct if it
7934 ;; doesn't. BSD/OS 4.0 wants the parentheses around the command,
7935 ;; for otherwise the shell crashes.
7936 (with-connection-property vec "test-nt"
7937 (or
7938 (progn
7939 (tramp-send-command
7940 vec (format "( %s / -nt / )" (tramp-get-test-command vec)))
7941 (with-current-buffer (tramp-get-buffer vec)
7942 (goto-char (point-min))
a0a5183a 7943 (when (looking-at (regexp-quote tramp-end-of-output))
00d6fd04
MA
7944 (format "%s %%s -nt %%s" (tramp-get-test-command vec)))))
7945 (progn
7946 (tramp-send-command
7947 vec
7948 (format
7949 "tramp_test_nt () {\n%s -n \"`find $1 -prune -newer $2 -print`\"\n}"
7950 (tramp-get-test-command vec)))
7951 "tramp_test_nt %s %s"))))
7952
7953(defun tramp-get-file-exists-command (vec)
7954 (with-connection-property vec "file-exists"
946a5aeb
MA
7955 (tramp-message vec 5 "Finding command to check if file exists")
7956 (tramp-find-file-exists-command vec)))
00d6fd04
MA
7957
7958(defun tramp-get-remote-ln (vec)
7959 (with-connection-property vec "ln"
946a5aeb
MA
7960 (tramp-message vec 5 "Finding a suitable `ln' command")
7961 (tramp-find-executable vec "ln" (tramp-get-remote-path vec))))
00d6fd04
MA
7962
7963(defun tramp-get-remote-perl (vec)
7964 (with-connection-property vec "perl"
946a5aeb 7965 (tramp-message vec 5 "Finding a suitable `perl' command")
293c24f9
MA
7966 (let ((result
7967 (or (tramp-find-executable vec "perl5" (tramp-get-remote-path vec))
7968 (tramp-find-executable
7969 vec "perl" (tramp-get-remote-path vec)))))
7970 ;; We must check also for some Perl modules.
7971 (when result
7972 (with-connection-property vec "perl-file-spec"
7973 (zerop
7974 (tramp-send-command-and-check
7975 vec (format "%s -e 'use File::Spec;'" result))))
7976 (with-connection-property vec "perl-cwd-realpath"
7977 (zerop
7978 (tramp-send-command-and-check
7979 vec (format "%s -e 'use Cwd \"realpath\";'" result)))))
7980 result)))
00d6fd04
MA
7981
7982(defun tramp-get-remote-stat (vec)
7983 (with-connection-property vec "stat"
946a5aeb
MA
7984 (tramp-message vec 5 "Finding a suitable `stat' command")
7985 (let ((result (tramp-find-executable
7986 vec "stat" (tramp-get-remote-path vec)))
7987 tmp)
7988 ;; Check whether stat(1) returns usable syntax. %s does not
7989 ;; work on older AIX systems.
7990 (when result
7991 (setq tmp
7992 ;; We don't want to display an error message.
7993 (with-temp-message (or (current-message) "")
7994 (condition-case nil
7995 (tramp-send-command-and-read
7996 vec (format "%s -c '(\"%%N\" %%s)' /" result))
7997 (error nil))))
7998 (unless (and (listp tmp) (stringp (car tmp))
7999 (string-match "^./.$" (car tmp))
8000 (integerp (cadr tmp)))
8001 (setq result nil)))
8002 result)))
fb7933a3 8003
293c24f9
MA
8004(defun tramp-get-remote-readlink (vec)
8005 (with-connection-property vec "readlink"
8006 (tramp-message vec 5 "Finding a suitable `readlink' command")
8007 (let ((result (tramp-find-executable
8008 vec "readlink" (tramp-get-remote-path vec))))
8009 (when (and result
8010 ;; We don't want to display an error message.
8011 (with-temp-message (or (current-message) "")
8012 (condition-case nil
8013 (zerop
8014 (tramp-send-command-and-check
8015 vec (format "%s --canonicalize-missing /" result)))
8016 (error nil))))
8017 result))))
8018
00d6fd04
MA
8019(defun tramp-get-remote-id (vec)
8020 (with-connection-property vec "id"
946a5aeb
MA
8021 (tramp-message vec 5 "Finding POSIX `id' command")
8022 (or
8023 (catch 'id-found
8024 (let ((dl (tramp-get-remote-path vec))
8025 result)
8026 (while (and dl (setq result (tramp-find-executable vec "id" dl t t)))
8027 ;; Check POSIX parameter.
8028 (when (zerop (tramp-send-command-and-check
8029 vec (format "%s -u" result)))
8030 (throw 'id-found result))
8031 (setq dl (cdr dl)))))
8032 (tramp-error vec 'file-error "Couldn't find a POSIX `id' command"))))
00d6fd04
MA
8033
8034(defun tramp-get-remote-uid (vec id-format)
8035 (with-connection-property vec (format "uid-%s" id-format)
8036 (let ((res (tramp-send-command-and-read
8037 vec
8038 (format "%s -u%s %s"
8039 (tramp-get-remote-id vec)
8040 (if (equal id-format 'integer) "" "n")
8041 (if (equal id-format 'integer)
8042 "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
8043 ;; The command might not always return a number.
8044 (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
8045
8046(defun tramp-get-remote-gid (vec id-format)
8047 (with-connection-property vec (format "gid-%s" id-format)
8048 (let ((res (tramp-send-command-and-read
8049 vec
8050 (format "%s -g%s %s"
8051 (tramp-get-remote-id vec)
8052 (if (equal id-format 'integer) "" "n")
8053 (if (equal id-format 'integer)
8054 "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
8055 ;; The command might not always return a number.
8056 (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
fb7933a3 8057
8d60099b
MA
8058(defun tramp-get-local-uid (id-format)
8059 (if (equal id-format 'integer) (user-uid) (user-login-name)))
8060
8061(defun tramp-get-local-gid (id-format)
9e6ab520 8062 (nth 3 (tramp-compat-file-attributes "~/" id-format)))
8d60099b 8063
00d6fd04
MA
8064;; Some predefined connection properties.
8065(defun tramp-get-remote-coding (vec prop)
8066 ;; Local coding handles properties like remote coding. So we could
8067 ;; call it without pain.
8068 (let ((ret (tramp-get-local-coding vec prop)))
8069 ;; The connection property might have been cached. So we must send
8070 ;; the script - maybe.
1d7e9a01 8071 (when (and ret (symbolp ret))
00d6fd04
MA
8072 (let ((name (symbol-name ret)))
8073 (while (string-match (regexp-quote "-") name)
8074 (setq name (replace-match "_" nil t name)))
8075 (tramp-maybe-send-script vec (symbol-value ret) name)
8076 (setq ret name)))
8077 ;; Return the value.
8078 ret))
8079
8080(defun tramp-get-local-coding (vec prop)
bf0503cb 8081 (or
00d6fd04
MA
8082 (tramp-get-connection-property vec prop nil)
8083 (progn
8084 (tramp-find-inline-encoding vec)
8085 (tramp-get-connection-property vec prop nil))))
fb7933a3 8086
00d6fd04 8087(defun tramp-get-method-parameter (method param)
c951aecb 8088 "Return the method parameter PARAM.
00d6fd04
MA
8089If the `tramp-methods' entry does not exist, return NIL."
8090 (let ((entry (assoc param (assoc method tramp-methods))))
8091 (when entry (cadr entry))))
90f8dc03 8092
fb7933a3
KG
8093;; Auto saving to a special directory.
8094
00cec167 8095(defun tramp-exists-file-name-handler (operation &rest args)
00d6fd04
MA
8096 "Checks whether OPERATION runs a file name handler."
8097 ;; The file name handler is determined on base of either an
8098 ;; argument, `buffer-file-name', or `default-directory'.
8099 (condition-case nil
8100 (let* ((buffer-file-name "/")
8101 (default-directory "/")
8102 (fnha file-name-handler-alist)
8103 (check-file-name-operation operation)
8104 (file-name-handler-alist
8105 (list
8106 (cons "/"
aa485f7c
MA
8107 (lambda (operation &rest args)
8108 "Returns OPERATION if it is the one to be checked."
8109 (if (equal check-file-name-operation operation)
8110 operation
8111 (let ((file-name-handler-alist fnha))
8112 (apply operation args))))))))
00d6fd04
MA
8113 (equal (apply operation args) operation))
8114 (error nil)))
c1105d05
MA
8115
8116(unless (tramp-exists-file-name-handler 'make-auto-save-file-name)
8117 (defadvice make-auto-save-file-name
8118 (around tramp-advice-make-auto-save-file-name () activate)
00d6fd04 8119 "Invoke `tramp-handle-make-auto-save-file-name' for Tramp files."
c1105d05 8120 (if (and (buffer-file-name) (tramp-tramp-file-p (buffer-file-name)))
7f49fe46
MA
8121 ;; We cannot call `tramp-handle-make-auto-save-file-name'
8122 ;; directly, because this would bypass the locking mechanism.
8123 (setq ad-return-value
8124 (tramp-file-name-handler 'make-auto-save-file-name))
a69c01a0
MA
8125 ad-do-it))
8126 (add-hook 'tramp-unload-hook
aa485f7c 8127 (lambda () (ad-unadvise 'make-auto-save-file-name))))
fb7933a3 8128
340b8d4f
MA
8129;; In Emacs < 22 and XEmacs < 21.5 autosaved remote files have
8130;; permission 0666 minus umask. This is a security threat.
414da5ab
MA
8131
8132(defun tramp-set-auto-save-file-modes ()
8133 "Set permissions of autosaved remote files to the original permissions."
8134 (let ((bfn (buffer-file-name)))
8135 (when (and (stringp bfn)
8136 (tramp-tramp-file-p bfn)
b50dd0d2 8137 (buffer-modified-p)
414da5ab 8138 (stringp buffer-auto-save-file-name)
340b8d4f
MA
8139 (not (equal bfn buffer-auto-save-file-name)))
8140 (unless (file-exists-p buffer-auto-save-file-name)
8141 (write-region "" nil buffer-auto-save-file-name))
8142 ;; Permissions should be set always, because there might be an old
8143 ;; auto-saved file belonging to another original file. This could
8144 ;; be a security threat.
7177e2a3 8145 (set-file-modes buffer-auto-save-file-name
11948172 8146 (or (file-modes bfn) (tramp-octal-to-decimal "0600"))))))
414da5ab
MA
8147
8148(unless (or (> emacs-major-version 21)
8149 (and (featurep 'xemacs)
8150 (= emacs-major-version 21)
340b8d4f 8151 (> emacs-minor-version 4)))
a69c01a0
MA
8152 (add-hook 'auto-save-hook 'tramp-set-auto-save-file-modes)
8153 (add-hook 'tramp-unload-hook
aa485f7c
MA
8154 (lambda ()
8155 (remove-hook 'auto-save-hook 'tramp-set-auto-save-file-modes))))
414da5ab 8156
fb7933a3
KG
8157(defun tramp-subst-strs-in-string (alist string)
8158 "Replace all occurrences of the string FROM with TO in STRING.
8159ALIST is of the form ((FROM . TO) ...)."
8160 (save-match-data
8161 (while alist
8162 (let* ((pr (car alist))
8163 (from (car pr))
8164 (to (cdr pr)))
8165 (while (string-match (regexp-quote from) string)
8166 (setq string (replace-match to t t string)))
8167 (setq alist (cdr alist))))
8168 string))
8169
fb7933a3
KG
8170;; ------------------------------------------------------------
8171;; -- Compatibility functions section --
8172;; ------------------------------------------------------------
8173
00d6fd04 8174(defun tramp-read-passwd (proc &optional prompt)
fb7933a3 8175 "Read a password from user (compat function).
5615d63f 8176Consults the auth-source package.
5ec2cc41 8177Invokes `password-read' if available, `read-passwd' else."
00d6fd04
MA
8178 (let* ((key (tramp-make-tramp-file-name
8179 tramp-current-method tramp-current-user
8180 tramp-current-host ""))
8181 (pw-prompt
8182 (or prompt
8183 (with-current-buffer (process-buffer proc)
8184 (tramp-check-for-regexp proc tramp-password-prompt-regexp)
8185 (format "%s for %s " (capitalize (match-string 1)) key)))))
5c7043a2
MA
8186 (prog1
8187 (or
8188 ;; See if auth-sources contains something useful, if it's bound.
8189 (and (boundp 'auth-sources)
8190 (tramp-get-connection-property proc "first-password-request" nil)
8191 ;; Try with Tramp's current method.
8192 (funcall (symbol-function 'auth-source-user-or-password)
8193 "password" tramp-current-host tramp-current-method))
8194 ;; Try the password cache.
cb85dcd0
MA
8195 (when (functionp 'password-read)
8196 (unless (tramp-get-connection-property
8197 proc "first-password-request" nil)
8198 (funcall (symbol-function 'password-cache-remove) key))
8199 (let ((password
8200 (funcall (symbol-function 'password-read) pw-prompt key)))
8201 (funcall (symbol-function 'password-cache-add) key password)
8202 password))
5c7043a2
MA
8203 ;; Else, get the password interactively.
8204 (read-passwd pw-prompt))
8205 (tramp-set-connection-property proc "first-password-request" nil))))
00d6fd04 8206
9c13938d
MA
8207(defun tramp-clear-passwd (vec)
8208 "Clear password cache for connection related to VEC."
00d6fd04 8209 (when (functionp 'password-cache-remove)
9c13938d
MA
8210 (funcall
8211 (symbol-function 'password-cache-remove)
8212 (tramp-make-tramp-file-name
8213 (tramp-file-name-method vec)
8214 (tramp-file-name-user vec)
8215 (tramp-file-name-host vec)
8216 ""))))
00d6fd04
MA
8217
8218;; Snarfed code from time-date.el and parse-time.el
8219
8220(defconst tramp-half-a-year '(241 17024)
8221"Evaluated by \"(days-to-time 183)\".")
8222
8223(defconst tramp-parse-time-months
8224 '(("jan" . 1) ("feb" . 2) ("mar" . 3)
8225 ("apr" . 4) ("may" . 5) ("jun" . 6)
8226 ("jul" . 7) ("aug" . 8) ("sep" . 9)
8227 ("oct" . 10) ("nov" . 11) ("dec" . 12))
8228 "Alist mapping month names to integers.")
8229
8230(defun tramp-time-less-p (t1 t2)
8231 "Say whether time value T1 is less than time value T2."
8232 (unless t1 (setq t1 '(0 0)))
8233 (unless t2 (setq t2 '(0 0)))
8234 (or (< (car t1) (car t2))
8235 (and (= (car t1) (car t2))
8236 (< (nth 1 t1) (nth 1 t2)))))
8237
8238(defun tramp-time-subtract (t1 t2)
8239 "Subtract two time values.
8240Return the difference in the format of a time value."
8241 (unless t1 (setq t1 '(0 0)))
8242 (unless t2 (setq t2 '(0 0)))
8243 (let ((borrow (< (cadr t1) (cadr t2))))
8244 (list (- (car t1) (car t2) (if borrow 1 0))
8245 (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2)))))
fb7933a3
KG
8246
8247(defun tramp-time-diff (t1 t2)
8248 "Return the difference between the two times, in seconds.
1a762140 8249T1 and T2 are time values (as returned by `current-time' for example)."
fb7933a3 8250 ;; Pacify byte-compiler with `symbol-function'.
ea9d1443
KG
8251 (cond ((and (fboundp 'subtract-time)
8252 (fboundp 'float-time))
8253 (funcall (symbol-function 'float-time)
8254 (funcall (symbol-function 'subtract-time) t1 t2)))
8255 ((and (fboundp 'subtract-time)
8256 (fboundp 'time-to-seconds))
8257 (funcall (symbol-function 'time-to-seconds)
8258 (funcall (symbol-function 'subtract-time) t1 t2)))
fb7933a3 8259 ((fboundp 'itimer-time-difference)
1a762140
MA
8260 (funcall (symbol-function 'itimer-time-difference)
8261 (if (< (length t1) 3) (append t1 '(0)) t1)
8262 (if (< (length t2) 3) (append t2 '(0)) t2)))
fb7933a3 8263 (t
00d6fd04 8264 (let ((time (tramp-time-subtract t1 t2)))
ea9d1443
KG
8265 (+ (* (car time) 65536.0)
8266 (cadr time)
8267 (/ (or (nth 2 time) 0) 1000000.0))))))
fb7933a3
KG
8268
8269(defun tramp-coding-system-change-eol-conversion (coding-system eol-type)
8270 "Return a coding system like CODING-SYSTEM but with given EOL-TYPE.
8271EOL-TYPE can be one of `dos', `unix', or `mac'."
8272 (cond ((fboundp 'coding-system-change-eol-conversion)
9e6ab520
MA
8273 (funcall (symbol-function 'coding-system-change-eol-conversion)
8274 coding-system eol-type))
fb7933a3 8275 ((fboundp 'subsidiary-coding-system)
9e6ab520
MA
8276 (funcall (symbol-function 'subsidiary-coding-system)
8277 coding-system
8278 (cond ((eq eol-type 'dos) 'crlf)
8279 ((eq eol-type 'unix) 'lf)
8280 ((eq eol-type 'mac) 'cr)
8281 (t
8282 (error "Unknown EOL-TYPE `%s', must be %s"
8283 eol-type
8284 "`dos', `unix', or `mac'")))))
fb7933a3
KG
8285 (t (error "Can't change EOL conversion -- is MULE missing?"))))
8286
19a87064
MA
8287(defun tramp-set-process-query-on-exit-flag (process flag)
8288 "Specify if query is needed for process when Emacs is exited.
8289If the second argument flag is non-nil, Emacs will query the user before
8290exiting if process is running."
8291 (if (fboundp 'set-process-query-on-exit-flag)
00d6fd04
MA
8292 (funcall (symbol-function 'set-process-query-on-exit-flag) process flag)
8293 (funcall (symbol-function 'process-kill-without-query) process flag)))
19a87064 8294
19a87064 8295
bf247b6e
KS
8296;; ------------------------------------------------------------
8297;; -- Kludges section --
8298;; ------------------------------------------------------------
fb7933a3
KG
8299
8300;; Currently (as of Emacs 20.5), the function `shell-quote-argument'
8301;; does not deal well with newline characters. Newline is replaced by
8302;; backslash newline. But if, say, the string `a backslash newline b'
8303;; is passed to a shell, the shell will expand this into "ab",
8304;; completely omitting the newline. This is not what was intended.
8305;; It does not appear to be possible to make the function
8306;; `shell-quote-argument' work with newlines without making it
8307;; dependent on the shell used. But within this package, we know that
8308;; we will always use a Bourne-like shell, so we use an approach which
8309;; groks newlines.
8310;;
8311;; The approach is simple: we call `shell-quote-argument', then
8312;; massage the newline part of the result.
8313;;
8314;; This function should produce a string which is grokked by a Unix
8315;; shell, even if the Emacs is running on Windows. Since this is the
8316;; kludges section, we bind `system-type' in such a way that
8317;; `shell-quote-arguments' behaves as if on Unix.
8318;;
8319;; Thanks to Mario DeWeerd for the hint that it is sufficient for this
8320;; function to work with Bourne-like shells.
8321;;
8322;; CCC: This function should be rewritten so that
8323;; `shell-quote-argument' is not used. This way, we are safe from
8324;; changes in `shell-quote-argument'.
8325(defun tramp-shell-quote-argument (s)
8326 "Similar to `shell-quote-argument', but groks newlines.
8327Only works for Bourne-like shells."
8328 (let ((system-type 'not-windows))
8329 (save-match-data
8330 (let ((result (shell-quote-argument s))
8331 (nl (regexp-quote (format "\\%s" tramp-rsh-end-of-line))))
8332 (when (and (>= (length result) 2)
8333 (string= (substring result 0 2) "\\~"))
8334 (setq result (substring result 1)))
8335 (while (string-match nl result)
8336 (setq result (replace-match (format "'%s'" tramp-rsh-end-of-line)
8337 t t result)))
8338 result))))
8339
16674e4f
KG
8340;; We currently (sometimes) use "[" and "]" in the filename format.
8341;; This means that Emacs wants to expand wildcards if
fb7933a3
KG
8342;; `find-file-wildcards' is non-nil, and then barfs because no
8343;; expansion could be found. We detect this situation and do
8344;; something really awful: we have `file-expand-wildcards' return the
8345;; original filename if it can't expand anything. Let's just hope
8346;; that this doesn't break anything else.
16674e4f
KG
8347;; CCC: This check is now also really awful; we should search all
8348;; of the filename format, not just the prefix.
8349(when (string-match "\\[" tramp-prefix-format)
1834b39f
MA
8350 (defadvice file-expand-wildcards
8351 (around tramp-advice-file-expand-wildcards activate)
d2a2c17f
MA
8352 (let ((name (ad-get-arg 0)))
8353 (if (tramp-tramp-file-p name)
8354 ;; If it's a Tramp file, dissect it and look if wildcards
8355 ;; need to be expanded at all.
1834b39f
MA
8356 (if (string-match
8357 "[[*?]"
8358 (tramp-file-name-localname (tramp-dissect-file-name name)))
8359 (setq ad-return-value (or ad-do-it (list name)))
8360 (setq ad-return-value (list name)))
d2a2c17f 8361 ;; If it is not a Tramp file, just run the original function.
1834b39f 8362 (setq ad-return-value (or ad-do-it (list name))))))
a69c01a0 8363 (add-hook 'tramp-unload-hook
aa485f7c 8364 (lambda () (ad-unadvise 'file-expand-wildcards))))
fb7933a3 8365
a69c01a0
MA
8366;; Checklist for `tramp-unload-hook'
8367;; - Unload all `tramp-*' packages
8368;; - Reset `file-name-handler-alist'
8369;; - Cleanup hooks where Tramp functions are in
8370;; - Cleanup advised functions
8371;; - Cleanup autoloads
8372;;;###autoload
8373(defun tramp-unload-tramp ()
08b1eb21 8374 "Discard Tramp from loading remote files."
a69c01a0
MA
8375 (interactive)
8376 ;; When Tramp is not loaded yet, its autoloads are still active.
8c04e197 8377 (tramp-unload-file-name-handlers)
a69c01a0
MA
8378 ;; ange-ftp settings must be enabled.
8379 (when (functionp 'tramp-ftp-enable-ange-ftp)
8380 (funcall (symbol-function 'tramp-ftp-enable-ange-ftp)))
00d6fd04
MA
8381 ;; Maybe its not loaded yet.
8382 (condition-case nil
8383 (unload-feature 'tramp 'force)
a69c01a0
MA
8384 (error nil)))
8385
dea31ca6
MA
8386(when (and load-in-progress
8387 (string-match "Loading tramp..." (or (current-message) "")))
ccb4a481
MA
8388 (message "Loading tramp...done"))
8389
fb7933a3
KG
8390(provide 'tramp)
8391
fb7933a3
KG
8392;;; TODO:
8393
4007ba5b 8394;; * Handle nonlocal exits such as C-g.
00d6fd04
MA
8395;; * But it would probably be better to use with-local-quit at the
8396;; place where it's actually needed: around any potentially
8397;; indefinitely blocking piece of code. In this case it would be
8398;; within Tramp around one of its calls to accept-process-output (or
8399;; around one of the loops that calls accept-process-output)
d037d501 8400;; (Stefan Monnier).
fb7933a3 8401;; * Rewrite `tramp-shell-quote-argument' to abstain from using
b1d06e75 8402;; `shell-quote-argument'.
fb7933a3
KG
8403;; * In Emacs 21, `insert-directory' shows total number of bytes used
8404;; by the files in that directory. Add this here.
8405;; * Avoid screen blanking when hitting `g' in dired. (Eli Tziperman)
8406;; * Make ffap.el grok Tramp filenames. (Eli Tziperman)
fb7933a3 8407;; * Case-insensitive filename completion. (Norbert Goevert.)
fb7933a3
KG
8408;; * Don't use globbing for directories with many files, as this is
8409;; likely to produce long command lines, and some shells choke on
8410;; long command lines.
fb7933a3
KG
8411;; * `vc-directory' does not work. It never displays any files, even
8412;; if it does show files when run locally.
fb7933a3 8413;; * How to deal with MULE in `insert-file-contents' and `write-region'?
fb7933a3
KG
8414;; * Test remote ksh or bash for tilde expansion in `tramp-find-shell'?
8415;; * abbreviate-file-name
8e754ea2 8416;; * Better error checking. At least whenever we see something
fb7933a3
KG
8417;; strange when doing zerop, we should kill the process and start
8418;; again. (Greg Stark)
fb7933a3 8419;; * Remove unneeded parameters from methods.
fb7933a3
KG
8420;; * Make it work for different encodings, and for different file name
8421;; encodings, too. (Daniel Pittman)
fb7933a3 8422;; * Progress reports while copying files. (Michael Kifer)
fb7933a3
KG
8423;; * Don't search for perl5 and perl. Instead, only search for perl and
8424;; then look if it's the right version (with `perl -v').
8425;; * When editing a remote CVS controlled file as a different user, VC
8426;; gets confused about the file locking status. Try to find out why
8427;; the workaround doesn't work.
3cdaec13 8428;; * Username and hostname completion.
6c4e47fa 8429;; ** Try to avoid usage of `last-input-event' in `tramp-completion-mode-p'.
8daea7fc 8430;; ** Unify `tramp-parse-{rhosts,shosts,sconfig,hosts,passwd,netrc}'.
16674e4f 8431;; Code is nearly identical.
cfb5c0db
MA
8432;; * Allow out-of-band methods as _last_ multi-hop. Open a connection
8433;; until the last but one hop via `start-file-process'. Apply it
8434;; also for ftp and smb.
00d6fd04
MA
8435;; * WIBNI if we had a command "trampclient"? If I was editing in
8436;; some shell with root priviledges, it would be nice if I could
8437;; just call
8438;; trampclient filename.c
8439;; as an editor, and the _current_ shell would connect to an Emacs
8440;; server and would be used in an existing non-priviledged Emacs
8441;; session for doing the editing in question.
8442;; That way, I need not tell Emacs my password again and be afraid
8443;; that it makes it into core dumps or other ugly stuff (I had Emacs
8444;; once display a just typed password in the context of a keyboard
8445;; sequence prompt for a question immediately following in a shell
8446;; script run within Emacs -- nasty).
8447;; And if I have some ssh session running to a different computer,
8448;; having the possibility of passing a local file there to a local
8449;; Emacs session (in case I can arrange for a connection back) would
8450;; be nice.
a4aeb9a4 8451;; Likely the corresponding Tramp server should not allow the
00d6fd04
MA
8452;; equivalent of the emacsclient -eval option in order to make this
8453;; reasonably unproblematic. And maybe trampclient should have some
8454;; way of passing credentials, like by using an SSL socket or
8455;; something. (David Kastrup)
00d6fd04
MA
8456;; * Reconnect directly to a compliant shell without first going
8457;; through the user's default shell. (Pete Forman)
00d6fd04 8458;; * Make `tramp-default-user' obsolete.
adb67129
MA
8459;; * Tramp shall reconnect automatically to its ssh connection when it
8460;; detects that the process "has died". (David Reitter)
11c71217
MA
8461;; * How can I interrupt the remote process with a signal
8462;; (interrupt-process seems not to work)? (Markus Triska)
2296b54d
MA
8463;; * Avoid the local shell entirely for starting remote processes. If
8464;; so, I think even a signal, when delivered directly to the local
8465;; SSH instance, would correctly be propagated to the remote process
8466;; automatically; possibly SSH would have to be started with
8467;; "-t". (Markus Triska)
dea31ca6
MA
8468;; * It makes me wonder if tramp couldn't fall back to ssh when scp
8469;; isn't on the remote host. (Mark A. Hershberger)
3e2fa353
MA
8470;; * Use lsh instead of ssh. (Alfred M. Szmidt)
8471;; * Implement a general server-local-variable mechanism, as there are
8472;; probably other variables that need different values for different
8473;; servers too. The user could then configure a variable (such as
8474;; tramp-server-local-variable-alist) to define any such variables
8475;; that they need to, which would then be let bound as appropriate
8476;; in tramp functions. (Jason Rumney)
946a5aeb
MA
8477;; * Optimize out-of-band copying, when both methods are scp-like (not
8478;; rsync).
8479;; * Keep a second connection open for out-of-band methods like scp or
8480;; rsync.
263c02ef 8481;; * Support ptys in `tramp-handle-start-file-process'.
fb7933a3
KG
8482
8483;; Functions for file-name-handler-alist:
8484;; diff-latest-backup-file -- in diff.el
fb7933a3 8485
cdd44874 8486;; arch-tag: 3a21a994-182b-48fa-b0cd-c1d9fede424a
fb7933a3 8487;;; tramp.el ends here
57671b72
MA
8488
8489;; Local Variables:
8490;; mode: Emacs-Lisp
8491;; coding: utf-8
8492;; End: