Use correct match group (bug#8438).
[bpt/emacs.git] / lisp / net / tramp.el
CommitLineData
b1a2b924 1;;; tramp.el --- Transparent Remote Access, Multiple Protocol
fb7933a3 2
6a0ecd86
MA
3;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
4;; 2007, 2008, 2009, 2010, 2011 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;;
20b8ac83 39;; This package only works for Emacs 22.1 and higher, and for XEmacs 21.4
00d6fd04 40;; and higher. For XEmacs 21, you need the package `fsf-compat' for
7f4d4a97 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
20b8ac83 82(require 'format-spec)
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 147 (condition-case nil
20b8ac83 148 (tramp-compat-funcall 'dbus-get-unique-name :session)
2ac33804 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
20b8ac83 179 :group 'comm
bf247b6e 180 :version "22.1")
fb7933a3 181
2e271195
MA
182;; Maybe we need once a real Tramp mode, with key bindings etc.
183;;;###autoload
184(defcustom tramp-mode t
185 "*Whether Tramp is enabled.
186If it is set to nil, all remote file names are used literally."
187 :group 'tramp
188 :type 'boolean)
189
00d6fd04 190(defcustom tramp-verbose 3
263c02ef 191 "*Verbosity level for Tramp messages.
00d6fd04
MA
192Any level x includes messages for all levels 1 .. x-1. The levels are
193
194 0 silent (no tramp messages at all)
195 1 errors
196 2 warnings
197 3 connection to remote hosts (default level)
198 4 activities
199 5 internal
200 6 sent and received strings
201 7 file caching
202 8 connection properties
20b8ac83 203 9 test commands
00d6fd04 20410 traces (huge)."
fb7933a3
KG
205 :group 'tramp
206 :type 'integer)
207
263c02ef 208;; Emacs case.
38c65fca
KG
209(eval-and-compile
210 (when (boundp 'backup-directory-alist)
211 (defcustom tramp-backup-directory-alist nil
212 "Alist of filename patterns and backup directory names.
213Each element looks like (REGEXP . DIRECTORY), with the same meaning like
214in `backup-directory-alist'. If a Tramp file is backed up, and DIRECTORY
215is a local file name, the backup directory is prepended with Tramp file
00d6fd04 216name prefix \(method, user, host\) of file.
38c65fca
KG
217
218\(setq tramp-backup-directory-alist backup-directory-alist\)
219
220gives the same backup policy for Tramp files on their hosts like the
221policy for local files."
222 :group 'tramp
223 :type '(repeat (cons (regexp :tag "Regexp matching filename")
224 (directory :tag "Backup directory name"))))))
225
226;; XEmacs case. We cannot check for `bkup-backup-directory-info', because
227;; the package "backup-dir" might not be loaded yet.
228(eval-and-compile
229 (when (featurep 'xemacs)
230 (defcustom tramp-bkup-backup-directory-info nil
231 "*Alist of (FILE-REGEXP BACKUP-DIR OPTIONS ...))
232It has the same meaning like `bkup-backup-directory-info' from package
233`backup-dir'. If a Tramp file is backed up, and BACKUP-DIR is a local
234file name, the backup directory is prepended with Tramp file name prefix
00d6fd04 235\(method, user, host\) of file.
38c65fca
KG
236
237\(setq tramp-bkup-backup-directory-info bkup-backup-directory-info\)
238
239gives the same backup policy for Tramp files on their hosts like the
240policy for local files."
bf247b6e 241 :type '(repeat
38c65fca
KG
242 (list (regexp :tag "File regexp")
243 (string :tag "Backup Dir")
244 (set :inline t
245 (const ok-create)
246 (const full-path)
247 (const prepend-name)
248 (const search-upward))))
249 :group 'tramp)))
250
fb7933a3
KG
251(defcustom tramp-auto-save-directory nil
252 "*Put auto-save files in this directory, if set.
253The idea is to use a local directory so that auto-saving is faster."
254 :group 'tramp
00d6fd04 255 :type '(choice (const nil) string))
fb7933a3 256
16674e4f
KG
257(defcustom tramp-encoding-shell
258 (if (memq system-type '(windows-nt))
259 (getenv "COMSPEC")
260 "/bin/sh")
261 "*Use this program for encoding and decoding commands on the local host.
262This shell is used to execute the encoding and decoding command on the
263local host, so if you want to use `~' in those commands, you should
264choose a shell here which groks tilde expansion. `/bin/sh' normally
265does not understand tilde expansion.
266
267For encoding and deocding, commands like the following are executed:
268
269 /bin/sh -c COMMAND < INPUT > OUTPUT
270
271This variable can be used to change the \"/bin/sh\" part. See the
00d6fd04 272variable `tramp-encoding-command-switch' for the \"-c\" part.
fb7933a3
KG
273
274Note that this variable is not used for remote commands. There are
275mechanisms in tramp.el which automatically determine the right shell to
276use for the remote host."
277 :group 'tramp
278 :type '(file :must-match t))
279
16674e4f
KG
280(defcustom tramp-encoding-command-switch
281 (if (string-match "cmd\\.exe" tramp-encoding-shell)
282 "/c"
283 "-c")
284 "*Use this switch together with `tramp-encoding-shell' for local commands.
285See the variable `tramp-encoding-shell' for more information."
286 :group 'tramp
287 :type 'string)
288
20b8ac83
MA
289(defcustom tramp-inline-compress-start-size 4096
290 "*The minimum size of compressing where inline transfer.
291When inline transfer, compress transfered data of file
292whose size is this value or above (up to `tramp-copy-size-limit').
293If it is nil, no compression at all will be applied."
294 :group 'tramp
295 :type '(choice (const nil) integer))
296
00d6fd04 297(defcustom tramp-copy-size-limit 10240
20b8ac83
MA
298 "*The maximum file size where inline copying is preferred over an out-of-the-band copy.
299If it is nil, inline out-of-the-band copy will be used without a check."
16674e4f 300 :group 'tramp
20b8ac83 301 :type '(choice (const nil) integer))
90dc758d 302
00d6fd04
MA
303(defcustom tramp-terminal-type "dumb"
304 "*Value of TERM environment variable for logging in to remote host.
305Because Tramp wants to parse the output of the remote shell, it is easily
306confused by ANSI color escape sequences and suchlike. Often, shell init
307files conditionalize this setup based on the TERM environment variable."
90dc758d 308 :group 'tramp
00d6fd04 309 :type 'string)
90dc758d 310
dab816a9
MA
311;; ksh on OpenBSD 4.5 requires, that PS1 contains a `#' character for
312;; root users. It uses the `$' character for other users. In order
313;; to guarantee a proper prompt, we use "#$" for the prompt.
314
315(defvar tramp-end-of-output
316 (format
317 "///%s#$"
318 (md5 (concat (prin1-to-string process-environment) (current-time-string))))
319 "String used to recognize end of output.
320The '$' character at the end is quoted; the string cannot be
321detected as prompt when being sent on echoing hosts, therefore.")
322
323(defconst tramp-initial-end-of-output "#$ "
324 "Prompt when establishing a connection.")
325
00d6fd04
MA
326(defvar tramp-methods
327 `(("rcp" (tramp-login-program "rsh")
328 (tramp-login-args (("%h") ("-l" "%u")))
329 (tramp-remote-sh "/bin/sh")
330 (tramp-copy-program "rcp")
263c02ef 331 (tramp-copy-args (("-p" "%k") ("-r")))
00d6fd04 332 (tramp-copy-keep-date t)
263c02ef 333 (tramp-copy-recursive t)
00d6fd04
MA
334 (tramp-password-end-of-line nil))
335 ("scp" (tramp-login-program "ssh")
20b8ac83
MA
336 (tramp-login-args (("-l" "%u") ("-p" "%p")
337 ("-e" "none") ("%h")))
338 (tramp-async-args (("-q")))
00d6fd04
MA
339 (tramp-remote-sh "/bin/sh")
340 (tramp-copy-program "scp")
263c02ef
MA
341 (tramp-copy-args (("-P" "%p") ("-p" "%k")
342 ("-q") ("-r")))
00d6fd04 343 (tramp-copy-keep-date t)
263c02ef 344 (tramp-copy-recursive t)
00d6fd04
MA
345 (tramp-password-end-of-line nil)
346 (tramp-gw-args (("-o"
347 "GlobalKnownHostsFile=/dev/null")
348 ("-o" "UserKnownHostsFile=/dev/null")
349 ("-o" "StrictHostKeyChecking=no")))
350 (tramp-default-port 22))
351 ("scp1" (tramp-login-program "ssh")
20b8ac83
MA
352 (tramp-login-args (("-l" "%u") ("-p" "%p")
353 ("-1") ("-e" "none") ("%h")))
354 (tramp-async-args (("-q")))
00d6fd04
MA
355 (tramp-remote-sh "/bin/sh")
356 (tramp-copy-program "scp")
357 (tramp-copy-args (("-1") ("-P" "%p") ("-p" "%k")
263c02ef 358 ("-q") ("-r")))
00d6fd04 359 (tramp-copy-keep-date t)
263c02ef 360 (tramp-copy-recursive t)
00d6fd04
MA
361 (tramp-password-end-of-line nil)
362 (tramp-gw-args (("-o"
363 "GlobalKnownHostsFile=/dev/null")
364 ("-o" "UserKnownHostsFile=/dev/null")
365 ("-o" "StrictHostKeyChecking=no")))
366 (tramp-default-port 22))
367 ("scp2" (tramp-login-program "ssh")
20b8ac83
MA
368 (tramp-login-args (("-l" "%u") ("-p" "%p")
369 ("-2") ("-e" "none") ("%h")))
370 (tramp-async-args (("-q")))
00d6fd04
MA
371 (tramp-remote-sh "/bin/sh")
372 (tramp-copy-program "scp")
373 (tramp-copy-args (("-2") ("-P" "%p") ("-p" "%k")
263c02ef 374 ("-q") ("-r")))
00d6fd04 375 (tramp-copy-keep-date t)
263c02ef 376 (tramp-copy-recursive t)
00d6fd04
MA
377 (tramp-password-end-of-line nil)
378 (tramp-gw-args (("-o"
379 "GlobalKnownHostsFile=/dev/null")
380 ("-o" "UserKnownHostsFile=/dev/null")
381 ("-o" "StrictHostKeyChecking=no")))
382 (tramp-default-port 22))
383 ("scp1_old"
384 (tramp-login-program "ssh1")
385 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
386 ("-e" "none")))
387 (tramp-remote-sh "/bin/sh")
388 (tramp-copy-program "scp1")
263c02ef 389 (tramp-copy-args (("-p" "%k") ("-r")))
00d6fd04 390 (tramp-copy-keep-date t)
263c02ef 391 (tramp-copy-recursive t)
00d6fd04
MA
392 (tramp-password-end-of-line nil))
393 ("scp2_old"
394 (tramp-login-program "ssh2")
395 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
396 ("-e" "none")))
397 (tramp-remote-sh "/bin/sh")
398 (tramp-copy-program "scp2")
263c02ef 399 (tramp-copy-args (("-p" "%k") ("-r")))
00d6fd04 400 (tramp-copy-keep-date t)
263c02ef 401 (tramp-copy-recursive t)
00d6fd04
MA
402 (tramp-password-end-of-line nil))
403 ("sftp" (tramp-login-program "ssh")
20b8ac83
MA
404 (tramp-login-args (("-l" "%u") ("-p" "%p")
405 ("-e" "none") ("%h")))
406 (tramp-async-args (("-q")))
00d6fd04
MA
407 (tramp-remote-sh "/bin/sh")
408 (tramp-copy-program "sftp")
409 (tramp-copy-args nil)
410 (tramp-copy-keep-date nil)
411 (tramp-password-end-of-line nil))
412 ("rsync" (tramp-login-program "ssh")
20b8ac83
MA
413 (tramp-login-args (("-l" "%u") ("-p" "%p")
414 ("-e" "none") ("%h")))
415 (tramp-async-args (("-q")))
00d6fd04
MA
416 (tramp-remote-sh "/bin/sh")
417 (tramp-copy-program "rsync")
263c02ef 418 (tramp-copy-args (("-e" "ssh") ("-t" "%k") ("-r")))
00d6fd04 419 (tramp-copy-keep-date t)
b88f2d0a 420 (tramp-copy-keep-tmpfile t)
263c02ef 421 (tramp-copy-recursive t)
00d6fd04 422 (tramp-password-end-of-line nil))
263c02ef
MA
423 ("rsyncc"
424 (tramp-login-program "ssh")
20b8ac83 425 (tramp-login-args (("-l" "%u") ("-p" "%p")
946a5aeb
MA
426 ("-o" "ControlPath=%t.%%r@%%h:%%p")
427 ("-o" "ControlMaster=yes")
20b8ac83
MA
428 ("-e" "none") ("%h")))
429 (tramp-async-args (("-q")))
946a5aeb
MA
430 (tramp-remote-sh "/bin/sh")
431 (tramp-copy-program "rsync")
263c02ef 432 (tramp-copy-args (("-t" "%k") ("-r")))
946a5aeb
MA
433 (tramp-copy-env (("RSYNC_RSH")
434 (,(concat
435 "ssh"
436 " -o ControlPath=%t.%%r@%%h:%%p"
437 " -o ControlMaster=auto"))))
438 (tramp-copy-keep-date t)
b88f2d0a 439 (tramp-copy-keep-tmpfile t)
263c02ef 440 (tramp-copy-recursive t)
946a5aeb 441 (tramp-password-end-of-line nil))
00d6fd04
MA
442 ("remcp" (tramp-login-program "remsh")
443 (tramp-login-args (("%h") ("-l" "%u")))
444 (tramp-remote-sh "/bin/sh")
445 (tramp-copy-program "rcp")
446 (tramp-copy-args (("-p" "%k")))
447 (tramp-copy-keep-date t)
448 (tramp-password-end-of-line nil))
449 ("rsh" (tramp-login-program "rsh")
450 (tramp-login-args (("%h") ("-l" "%u")))
451 (tramp-remote-sh "/bin/sh")
452 (tramp-copy-program nil)
453 (tramp-copy-args nil)
454 (tramp-copy-keep-date nil)
455 (tramp-password-end-of-line nil))
456 ("ssh" (tramp-login-program "ssh")
20b8ac83
MA
457 (tramp-login-args (("-l" "%u") ("-p" "%p")
458 ("-e" "none") ("%h")))
459 (tramp-async-args (("-q")))
00d6fd04
MA
460 (tramp-remote-sh "/bin/sh")
461 (tramp-copy-program nil)
462 (tramp-copy-args nil)
463 (tramp-copy-keep-date nil)
464 (tramp-password-end-of-line nil)
465 (tramp-gw-args (("-o"
466 "GlobalKnownHostsFile=/dev/null")
467 ("-o" "UserKnownHostsFile=/dev/null")
468 ("-o" "StrictHostKeyChecking=no")))
469 (tramp-default-port 22))
470 ("ssh1" (tramp-login-program "ssh")
20b8ac83
MA
471 (tramp-login-args (("-l" "%u") ("-p" "%p")
472 ("-1") ("-e" "none") ("%h")))
473 (tramp-async-args (("-q")))
00d6fd04
MA
474 (tramp-remote-sh "/bin/sh")
475 (tramp-copy-program nil)
476 (tramp-copy-args nil)
477 (tramp-copy-keep-date nil)
478 (tramp-password-end-of-line nil)
479 (tramp-gw-args (("-o"
480 "GlobalKnownHostsFile=/dev/null")
481 ("-o" "UserKnownHostsFile=/dev/null")
482 ("-o" "StrictHostKeyChecking=no")))
483 (tramp-default-port 22))
484 ("ssh2" (tramp-login-program "ssh")
20b8ac83
MA
485 (tramp-login-args (("-l" "%u") ("-p" "%p")
486 ("-2") ("-e" "none") ("%h")))
487 (tramp-async-args (("-q")))
00d6fd04
MA
488 (tramp-remote-sh "/bin/sh")
489 (tramp-copy-program nil)
490 (tramp-copy-args nil)
491 (tramp-copy-keep-date nil)
492 (tramp-password-end-of-line nil)
493 (tramp-gw-args (("-o"
494 "GlobalKnownHostsFile=/dev/null")
495 ("-o" "UserKnownHostsFile=/dev/null")
496 ("-o" "StrictHostKeyChecking=no")))
497 (tramp-default-port 22))
498 ("ssh1_old"
499 (tramp-login-program "ssh1")
500 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
501 ("-e" "none")))
20b8ac83 502 (tramp-async-args (("-q")))
00d6fd04
MA
503 (tramp-remote-sh "/bin/sh")
504 (tramp-copy-program nil)
505 (tramp-copy-args nil)
506 (tramp-copy-keep-date nil)
507 (tramp-password-end-of-line nil))
508 ("ssh2_old"
509 (tramp-login-program "ssh2")
510 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
511 ("-e" "none")))
512 (tramp-remote-sh "/bin/sh")
513 (tramp-copy-program nil)
514 (tramp-copy-args nil)
515 (tramp-copy-keep-date nil)
516 (tramp-password-end-of-line nil))
517 ("remsh" (tramp-login-program "remsh")
518 (tramp-login-args (("%h") ("-l" "%u")))
519 (tramp-remote-sh "/bin/sh")
520 (tramp-copy-program nil)
521 (tramp-copy-args nil)
522 (tramp-copy-keep-date nil)
523 (tramp-password-end-of-line nil))
524 ("telnet"
525 (tramp-login-program "telnet")
526 (tramp-login-args (("%h") ("%p")))
527 (tramp-remote-sh "/bin/sh")
528 (tramp-copy-program nil)
529 (tramp-copy-args nil)
530 (tramp-copy-keep-date nil)
531 (tramp-password-end-of-line nil)
532 (tramp-default-port 23))
533 ("su" (tramp-login-program "su")
534 (tramp-login-args (("-") ("%u")))
535 (tramp-remote-sh "/bin/sh")
536 (tramp-copy-program nil)
537 (tramp-copy-args nil)
538 (tramp-copy-keep-date nil)
539 (tramp-password-end-of-line nil))
540 ("sudo" (tramp-login-program "sudo")
541 (tramp-login-args (("-u" "%u")
42bc9b6d 542 ("-s") ("-H") ("-p" "Password:")))
00d6fd04
MA
543 (tramp-remote-sh "/bin/sh")
544 (tramp-copy-program nil)
545 (tramp-copy-args nil)
546 (tramp-copy-keep-date nil)
547 (tramp-password-end-of-line nil))
548 ("scpc" (tramp-login-program "ssh")
20b8ac83 549 (tramp-login-args (("-l" "%u") ("-p" "%p")
00d6fd04
MA
550 ("-o" "ControlPath=%t.%%r@%%h:%%p")
551 ("-o" "ControlMaster=yes")
20b8ac83
MA
552 ("-e" "none") ("%h")))
553 (tramp-async-args (("-q")))
00d6fd04
MA
554 (tramp-remote-sh "/bin/sh")
555 (tramp-copy-program "scp")
01e62600 556 (tramp-copy-args (("-P" "%p") ("-p" "%k") ("-q") ("-r")
00d6fd04
MA
557 ("-o" "ControlPath=%t.%%r@%%h:%%p")
558 ("-o" "ControlMaster=auto")))
559 (tramp-copy-keep-date t)
01e62600 560 (tramp-copy-recursive t)
00d6fd04
MA
561 (tramp-password-end-of-line nil)
562 (tramp-gw-args (("-o"
563 "GlobalKnownHostsFile=/dev/null")
564 ("-o" "UserKnownHostsFile=/dev/null")
565 ("-o" "StrictHostKeyChecking=no")))
566 (tramp-default-port 22))
567 ("scpx" (tramp-login-program "ssh")
20b8ac83
MA
568 (tramp-login-args (("-l" "%u") ("-p" "%p")
569 ("-e" "none") ("-t" "-t")
570 ("%h") ("/bin/sh")))
571 (tramp-async-args (("-q")))
00d6fd04
MA
572 (tramp-remote-sh "/bin/sh")
573 (tramp-copy-program "scp")
01e62600
MA
574 (tramp-copy-args (("-P" "%p") ("-p" "%k")
575 ("-q") ("-r")))
00d6fd04 576 (tramp-copy-keep-date t)
01e62600 577 (tramp-copy-recursive t)
00d6fd04
MA
578 (tramp-password-end-of-line nil)
579 (tramp-gw-args (("-o"
580 "GlobalKnownHostsFile=/dev/null")
581 ("-o" "UserKnownHostsFile=/dev/null")
582 ("-o" "StrictHostKeyChecking=no")))
583 (tramp-default-port 22))
584 ("sshx" (tramp-login-program "ssh")
20b8ac83
MA
585 (tramp-login-args (("-l" "%u") ("-p" "%p")
586 ("-e" "none") ("-t" "-t")
587 ("%h") ("/bin/sh")))
588 (tramp-async-args (("-q")))
00d6fd04
MA
589 (tramp-remote-sh "/bin/sh")
590 (tramp-copy-program nil)
591 (tramp-copy-args nil)
592 (tramp-copy-keep-date nil)
593 (tramp-password-end-of-line nil)
594 (tramp-gw-args (("-o"
595 "GlobalKnownHostsFile=/dev/null")
596 ("-o" "UserKnownHostsFile=/dev/null")
597 ("-o" "StrictHostKeyChecking=no")))
598 (tramp-default-port 22))
599 ("krlogin"
600 (tramp-login-program "krlogin")
601 (tramp-login-args (("%h") ("-l" "%u") ("-x")))
602 (tramp-remote-sh "/bin/sh")
603 (tramp-copy-program nil)
604 (tramp-copy-args nil)
605 (tramp-copy-keep-date nil)
606 (tramp-password-end-of-line nil))
607 ("plink" (tramp-login-program "plink")
20b8ac83
MA
608 (tramp-login-args (("-l" "%u") ("-P" "%p")
609 ("-ssh") ("%h")))
00d6fd04
MA
610 (tramp-remote-sh "/bin/sh")
611 (tramp-copy-program nil)
612 (tramp-copy-args nil)
613 (tramp-copy-keep-date nil)
614 (tramp-password-end-of-line "xy") ;see docstring for "xy"
615 (tramp-default-port 22))
616 ("plink1"
617 (tramp-login-program "plink")
20b8ac83
MA
618 (tramp-login-args (("-l" "%u") ("-P" "%p")
619 ("-1" "-ssh") ("%h")))
00d6fd04
MA
620 (tramp-remote-sh "/bin/sh")
621 (tramp-copy-program nil)
622 (tramp-copy-args nil)
623 (tramp-copy-keep-date nil)
624 (tramp-password-end-of-line "xy") ;see docstring for "xy"
625 (tramp-default-port 22))
626 ("plinkx"
627 (tramp-login-program "plink")
42bc9b6d
MA
628 ;; ("%h") must be a single element, see
629 ;; `tramp-compute-multi-hops'.
630 (tramp-login-args (("-load") ("%h") ("-t")
ce3f516f 631 (,(format
dab816a9
MA
632 "env 'TERM=%s' 'PROMPT_COMMAND=' 'PS1=%s'"
633 tramp-terminal-type
634 tramp-initial-end-of-output))
00d6fd04
MA
635 ("/bin/sh")))
636 (tramp-remote-sh "/bin/sh")
637 (tramp-copy-program nil)
638 (tramp-copy-args nil)
639 (tramp-copy-keep-date nil)
640 (tramp-password-end-of-line nil))
641 ("pscp" (tramp-login-program "plink")
20b8ac83
MA
642 (tramp-login-args (("-l" "%u") ("-P" "%p")
643 ("-ssh") ("%h")))
00d6fd04
MA
644 (tramp-remote-sh "/bin/sh")
645 (tramp-copy-program "pscp")
01e62600
MA
646 (tramp-copy-args (("-P" "%p") ("-scp") ("-p" "%k")
647 ("-r")))
00d6fd04 648 (tramp-copy-keep-date t)
01e62600 649 (tramp-copy-recursive t)
00d6fd04
MA
650 (tramp-password-end-of-line "xy") ;see docstring for "xy"
651 (tramp-default-port 22))
652 ("psftp" (tramp-login-program "plink")
20b8ac83
MA
653 (tramp-login-args (("-l" "%u") ("-P" "%p")
654 ("-ssh") ("%h")))
00d6fd04
MA
655 (tramp-remote-sh "/bin/sh")
656 (tramp-copy-program "pscp")
01e62600
MA
657 (tramp-copy-args (("-P" "%p") ("-sftp") ("-p" "%k")
658 ("-r")))
00d6fd04 659 (tramp-copy-keep-date t)
01e62600 660 (tramp-copy-recursive t)
00d6fd04
MA
661 (tramp-password-end-of-line "xy")) ;see docstring for "xy"
662 ("fcp" (tramp-login-program "fsh")
663 (tramp-login-args (("%h") ("-l" "%u") ("sh" "-i")))
664 (tramp-remote-sh "/bin/sh -i")
665 (tramp-copy-program "fcp")
666 (tramp-copy-args (("-p" "%k")))
667 (tramp-copy-keep-date t)
668 (tramp-password-end-of-line nil)))
fb7933a3
KG
669 "*Alist of methods for remote files.
670This is a list of entries of the form (NAME PARAM1 PARAM2 ...).
671Each NAME stands for a remote access method. Each PARAM is a
672pair of the form (KEY VALUE). The following KEYs are defined:
fb7933a3
KG
673 * `tramp-remote-sh'
674 This specifies the Bourne shell to use on the remote host. This
675 MUST be a Bourne-like shell. It is normally not necessary to set
a4aeb9a4 676 this to any value other than \"/bin/sh\": Tramp wants to use a shell
fb7933a3
KG
677 which groks tilde expansion, but it can search for it. Also note
678 that \"/bin/sh\" exists on all Unixen, this might not be true for
679 the value that you decide to use. You Have Been Warned.
b25a52cc
KG
680 * `tramp-login-program'
681 This specifies the name of the program to use for logging in to the
00d6fd04
MA
682 remote host. This may be the name of rsh or a workalike program,
683 or the name of telnet or a workalike, or the name of su or a workalike.
b25a52cc 684 * `tramp-login-args'
fb7933a3 685 This specifies the list of arguments to pass to the above
00d6fd04 686 mentioned program. Please note that this is a list of list of arguments,
fb7933a3 687 that is, normally you don't want to put \"-a -b\" or \"-f foo\"
00d6fd04
MA
688 here. Instead, you want a list (\"-a\" \"-b\"), or (\"-f\" \"foo\").
689 There are some patterns: \"%h\" in this list is replaced by the host
690 name, \"%u\" is replaced by the user name, \"%p\" is replaced by the
691 port number, and \"%%\" can be used to obtain a literal percent character.
692 If a list containing \"%h\", \"%u\" or \"%p\" is unchanged during
693 expansion (i.e. no host or no user specified), this list is not used as
694 argument. By this, arguments like (\"-l\" \"%u\") are optional.
695 \"%t\" is replaced by the temporary file name produced with
696 `tramp-make-tramp-temp-file'. \"%k\" indicates the keep-date
697 parameter of a program, if exists.
20b8ac83
MA
698 * `tramp-async-args'
699 When an asynchronous process is started, we know already that
700 the connection works. Therefore, we can pass additional
701 parameters to suppress diagnostic messages, in order not to
702 tamper the process output.
b25a52cc
KG
703 * `tramp-copy-program'
704 This specifies the name of the program to use for remotely copying
705 the file; this might be the absolute filename of rcp or the name of
706 a workalike program.
707 * `tramp-copy-args'
fb7933a3 708 This specifies the list of parameters to pass to the above mentioned
b25a52cc 709 program, the hints for `tramp-login-args' also apply here.
00d6fd04
MA
710 * `tramp-copy-keep-date'
711 This specifies whether the copying program when the preserves the
712 timestamp of the original file.
b88f2d0a
MA
713 * `tramp-copy-keep-tmpfile'
714 This specifies whether a temporary local file shall be kept
715 for optimization reasons (useful for \"rsync\" methods).
716 * `tramp-copy-recursive'
717 Whether the operation copies directories recursively.
00d6fd04
MA
718 * `tramp-default-port'
719 The default port of a method is needed in case of gateway connections.
720 Additionally, it is used as indication which method is prepared for
721 passing gateways.
722 * `tramp-gw-args'
723 As the attribute name says, additional arguments are specified here
724 when a method is applied via a gateway.
90f8dc03
KG
725 * `tramp-password-end-of-line'
726 This specifies the string to use for terminating the line after
727 submitting the password. If this method parameter is nil, then the
728 value of the normal variable `tramp-default-password-end-of-line'
729 is used. This parameter is necessary because the \"plink\" program
730 requires any two characters after sending the password. These do
731 not have to be newline or carriage return characters. Other login
732 programs are happy with just one character, the newline character.
733 We use \"xy\" as the value for methods using \"plink\".
b25a52cc
KG
734
735What does all this mean? Well, you should specify `tramp-login-program'
736for all methods; this program is used to log in to the remote site. Then,
737there are two ways to actually transfer the files between the local and the
738remote side. One way is using an additional rcp-like program. If you want
739to do this, set `tramp-copy-program' in the method.
fb7933a3
KG
740
741Another possibility for file transfer is inline transfer, i.e. the
b25a52cc 742file is passed through the same buffer used by `tramp-login-program'. In
fb7933a3 743this case, the file contents need to be protected since the
b25a52cc 744`tramp-login-program' might use escape codes or the connection might not
fb7933a3 745be eight-bit clean. Therefore, file contents are encoded for transit.
00d6fd04
MA
746See the variables `tramp-local-coding-commands' and
747`tramp-remote-coding-commands' for details.
fb7933a3 748
16674e4f 749So, to summarize: if the method is an out-of-band method, then you
b25a52cc 750must specify `tramp-copy-program' and `tramp-copy-args'. If it is an
00d6fd04
MA
751inline method, then these two parameters should be nil. Methods which
752are fit for gateways must have `tramp-default-port' at least.
fb7933a3
KG
753
754Notes:
755
00d6fd04
MA
756When using `su' or `sudo' the phrase `open connection to a remote
757host' sounds strange, but it is used nevertheless, for consistency.
758No connection is opened to a remote host, but `su' or `sudo' is
759started on the local host. You should specify a remote host
760`localhost' or the name of the local host. Another host name is
761useful only in combination with `tramp-default-proxies-alist'.")
fb7933a3 762
20b8ac83
MA
763(defun tramp-detect-ssh-controlmaster ()
764 "Call ssh to detect whether it supports the ControlMaster argument.
765This function may return nil when the argument is supported, but
766shouldn't return t when it isn't."
767 (ignore-errors
768 (with-temp-buffer
769 (call-process "ssh" nil t nil "-o" "ControlMaster")
770 (goto-char (point-min))
771 (search-forward-regexp "Missing ControlMaster argument" nil t))))
772
b25a52cc 773(defcustom tramp-default-method
83e20b5c
MA
774 ;; An external copy method seems to be preferred, because it is much
775 ;; more performant for large files, and it hasn't too serious delays
776 ;; for small files. But it must be ensured that there aren't
777 ;; permanent password queries. Either a password agent like
263c02ef
MA
778 ;; "ssh-agent" or "Pageant" shall run, or the optional
779 ;; password-cache.el or auth-sources.el packages shall be active for
20b8ac83
MA
780 ;; password caching. "scpc" is chosen if we detect that the user is
781 ;; running OpenSSH 4.0 or newer.
00d6fd04 782 (cond
6a0ecd86
MA
783 ;; PuTTY is installed. We don't take it, if it is installed on a
784 ;; non-windows system, or pscp from the pssh (parallel ssh) package
785 ;; is found.
786 ((and (eq system-type 'windows-nt)
787 (executable-find "pscp"))
00d6fd04 788 (if (or (fboundp 'password-read)
263c02ef 789 (fboundp 'auth-source-user-or-password)
00d6fd04 790 ;; Pageant is running.
70c11b0b 791 (tramp-compat-process-running-p "Pageant"))
00d6fd04
MA
792 "pscp"
793 "plink"))
794 ;; There is an ssh installation.
795 ((executable-find "scp")
20b8ac83
MA
796 (cond
797 ((tramp-detect-ssh-controlmaster) "scpc")
798 ((or (fboundp 'password-read)
799 (fboundp 'auth-source-user-or-password)
800 ;; ssh-agent is running.
801 (getenv "SSH_AUTH_SOCK")
802 (getenv "SSH_AGENT_PID"))
803 "scp")
804 (t "ssh")))
00d6fd04
MA
805 ;; Fallback.
806 (t "ftp"))
fb7933a3 807 "*Default method to use for transferring files.
c62c9d08 808See `tramp-methods' for possibilities.
4007ba5b 809Also see `tramp-default-method-alist'."
c62c9d08
KG
810 :group 'tramp
811 :type 'string)
812
505edaeb 813(defcustom tramp-default-method-alist
4007ba5b 814 '(("\\`localhost\\'" "\\`root\\'" "su"))
00d6fd04 815 "*Default method to use for specific host/user pairs.
c62c9d08
KG
816This is an alist of items (HOST USER METHOD). The first matching item
817specifies the method to use for a file name which does not specify a
818method. HOST and USER are regular expressions or nil, which is
819interpreted as a regular expression which always matches. If no entry
820matches, the variable `tramp-default-method' takes effect.
821
822If the file name does not specify the user, lookup is done using the
823empty string for the user name.
824
825See `tramp-methods' for a list of possibilities for METHOD."
826 :group 'tramp
e40fc745
MA
827 :type '(repeat (list (choice :tag "Host regexp" regexp sexp)
828 (choice :tag "User regexp" regexp sexp)
829 (choice :tag "Method name" string (const nil)))))
c62c9d08 830
00d6fd04
MA
831(defcustom tramp-default-user
832 nil
833 "*Default user to use for transferring files.
834It is nil by default; otherwise settings in configuration files like
835\"~/.ssh/config\" would be overwritten. Also see `tramp-default-user-alist'.
836
837This variable is regarded as obsolete, and will be removed soon."
838 :group 'tramp
839 :type '(choice (const nil) string))
840
841(defcustom tramp-default-user-alist
842 `(("\\`su\\(do\\)?\\'" nil "root")
843 ("\\`r\\(em\\)?\\(cp\\|sh\\)\\|telnet\\|plink1?\\'"
844 nil ,(user-login-name)))
845 "*Default user to use for specific method/host pairs.
846This is an alist of items (METHOD HOST USER). The first matching item
847specifies the user to use for a file name which does not specify a
848user. METHOD and USER are regular expressions or nil, which is
849interpreted as a regular expression which always matches. If no entry
850matches, the variable `tramp-default-user' takes effect.
851
852If the file name does not specify the method, lookup is done using the
853empty string for the method name."
854 :group 'tramp
e40fc745
MA
855 :type '(repeat (list (choice :tag "Method regexp" regexp sexp)
856 (choice :tag " Host regexp" regexp sexp)
857 (choice :tag " User name" string (const nil)))))
00d6fd04
MA
858
859(defcustom tramp-default-host
860 (system-name)
861 "*Default host to use for transferring files.
862Useful for su and sudo methods mostly."
863 :group 'tramp
864 :type 'string)
865
866(defcustom tramp-default-proxies-alist nil
867 "*Route to be followed for specific host/user pairs.
868This is an alist of items (HOST USER PROXY). The first matching
869item specifies the proxy to be passed for a file name located on
870a remote target matching USER@HOST. HOST and USER are regular
70c11b0b
MA
871expressions. PROXY must be a Tramp filename without a localname
872part. Method and user name on PROXY are optional, which is
873interpreted with the default values. PROXY can contain the
874patterns %h and %u, which are replaced by the strings matching
875HOST or USER, respectively.
876
877HOST, USER or PROXY could also be Lisp forms, which will be
878evaluated. The result must be a string or nil, which is
879interpreted as a regular expression which always matches."
00d6fd04 880 :group 'tramp
70c11b0b
MA
881 :type '(repeat (list (choice :tag "Host regexp" regexp sexp)
882 (choice :tag "User regexp" regexp sexp)
e40fc745 883 (choice :tag " Proxy name" string (const nil)))))
00d6fd04 884
b96e6899
MA
885(defconst tramp-local-host-regexp
886 (concat
887 "^" (regexp-opt (list "localhost" (system-name) "127\.0\.0\.1" "::1") t) "$")
888 "*Host names which are regarded as local host.")
889
16674e4f 890(defconst tramp-completion-function-alist-rsh
00d6fd04
MA
891 '((tramp-parse-rhosts "/etc/hosts.equiv")
892 (tramp-parse-rhosts "~/.rhosts"))
b25a52cc 893 "Default list of (FUNCTION FILE) pairs to be examined for rsh methods.")
16674e4f 894
16674e4f 895(defconst tramp-completion-function-alist-ssh
00d6fd04
MA
896 '((tramp-parse-rhosts "/etc/hosts.equiv")
897 (tramp-parse-rhosts "/etc/shosts.equiv")
898 (tramp-parse-shosts "/etc/ssh_known_hosts")
899 (tramp-parse-sconfig "/etc/ssh_config")
900 (tramp-parse-shostkeys "/etc/ssh2/hostkeys")
901 (tramp-parse-sknownhosts "/etc/ssh2/knownhosts")
902 (tramp-parse-rhosts "~/.rhosts")
903 (tramp-parse-rhosts "~/.shosts")
904 (tramp-parse-shosts "~/.ssh/known_hosts")
905 (tramp-parse-sconfig "~/.ssh/config")
906 (tramp-parse-shostkeys "~/.ssh2/hostkeys")
907 (tramp-parse-sknownhosts "~/.ssh2/knownhosts"))
b25a52cc 908 "Default list of (FUNCTION FILE) pairs to be examined for ssh methods.")
16674e4f 909
16674e4f 910(defconst tramp-completion-function-alist-telnet
00d6fd04 911 '((tramp-parse-hosts "/etc/hosts"))
b25a52cc 912 "Default list of (FUNCTION FILE) pairs to be examined for telnet methods.")
16674e4f 913
16674e4f 914(defconst tramp-completion-function-alist-su
00d6fd04 915 '((tramp-parse-passwd "/etc/passwd"))
b25a52cc 916 "Default list of (FUNCTION FILE) pairs to be examined for su methods.")
292ffc15 917
00d6fd04
MA
918(defconst tramp-completion-function-alist-putty
919 '((tramp-parse-putty
920 "HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions"))
921 "Default list of (FUNCTION REGISTRY) pairs to be examined for putty methods.")
922
5ec2cc41 923(defvar tramp-completion-function-alist nil
16674e4f 924 "*Alist of methods for remote files.
20b8ac83 925This is a list of entries of the form \(NAME PAIR1 PAIR2 ...\).
16674e4f 926Each NAME stands for a remote access method. Each PAIR is of the form
20b8ac83 927\(FUNCTION FILE\). FUNCTION is responsible to extract user names and host
16674e4f
KG
928names from FILE for completion. The following predefined FUNCTIONs exists:
929
5ec2cc41
KG
930 * `tramp-parse-rhosts' for \"~/.rhosts\" like files,
931 * `tramp-parse-shosts' for \"~/.ssh/known_hosts\" like files,
932 * `tramp-parse-sconfig' for \"~/.ssh/config\" like files,
933 * `tramp-parse-shostkeys' for \"~/.ssh2/hostkeys/*\" like files,
934 * `tramp-parse-sknownhosts' for \"~/.ssh2/knownhosts/*\" like files,
935 * `tramp-parse-hosts' for \"/etc/hosts\" like files,
936 * `tramp-parse-passwd' for \"/etc/passwd\" like files.
937 * `tramp-parse-netrc' for \"~/.netrc\" like files.
00d6fd04 938 * `tramp-parse-putty' for PuTTY registry keys.
5ec2cc41
KG
939
940FUNCTION can also be a customer defined function. For more details see
941the info pages.")
942
943(eval-after-load "tramp"
944 '(progn
945 (tramp-set-completion-function
946 "rcp" tramp-completion-function-alist-rsh)
947 (tramp-set-completion-function
948 "scp" tramp-completion-function-alist-ssh)
949 (tramp-set-completion-function
950 "scp1" tramp-completion-function-alist-ssh)
951 (tramp-set-completion-function
952 "scp2" tramp-completion-function-alist-ssh)
953 (tramp-set-completion-function
954 "scp1_old" tramp-completion-function-alist-ssh)
955 (tramp-set-completion-function
956 "scp2_old" tramp-completion-function-alist-ssh)
957 (tramp-set-completion-function
70c11b0b 958 "rsync" tramp-completion-function-alist-ssh)
946a5aeb
MA
959 (tramp-set-completion-function
960 "rsyncc" tramp-completion-function-alist-ssh)
5ec2cc41
KG
961 (tramp-set-completion-function
962 "remcp" tramp-completion-function-alist-rsh)
963 (tramp-set-completion-function
964 "rsh" tramp-completion-function-alist-rsh)
965 (tramp-set-completion-function
966 "ssh" tramp-completion-function-alist-ssh)
967 (tramp-set-completion-function
968 "ssh1" tramp-completion-function-alist-ssh)
969 (tramp-set-completion-function
970 "ssh2" tramp-completion-function-alist-ssh)
971 (tramp-set-completion-function
972 "ssh1_old" tramp-completion-function-alist-ssh)
973 (tramp-set-completion-function
974 "ssh2_old" tramp-completion-function-alist-ssh)
975 (tramp-set-completion-function
976 "remsh" tramp-completion-function-alist-rsh)
977 (tramp-set-completion-function
978 "telnet" tramp-completion-function-alist-telnet)
979 (tramp-set-completion-function
980 "su" tramp-completion-function-alist-su)
981 (tramp-set-completion-function
982 "sudo" tramp-completion-function-alist-su)
bf247b6e 983 (tramp-set-completion-function
5ec2cc41
KG
984 "scpx" tramp-completion-function-alist-ssh)
985 (tramp-set-completion-function
986 "sshx" tramp-completion-function-alist-ssh)
987 (tramp-set-completion-function
988 "krlogin" tramp-completion-function-alist-rsh)
989 (tramp-set-completion-function
990 "plink" tramp-completion-function-alist-ssh)
991 (tramp-set-completion-function
992 "plink1" tramp-completion-function-alist-ssh)
00d6fd04
MA
993 (tramp-set-completion-function
994 "plinkx" tramp-completion-function-alist-putty)
5ec2cc41
KG
995 (tramp-set-completion-function
996 "pscp" tramp-completion-function-alist-ssh)
997 (tramp-set-completion-function
998 "fcp" tramp-completion-function-alist-ssh)))
16674e4f 999
674da028
MA
1000(defconst tramp-echo-mark-marker "_echo"
1001 "String marker to surround echoed commands.")
1002
68712eb6
MA
1003(defconst tramp-echo-mark-marker-length (length tramp-echo-mark-marker)
1004 "String length of `tramp-echo-mark-marker'.")
1005
1006(defconst tramp-echo-mark
1007 (concat tramp-echo-mark-marker
1008 (make-string tramp-echo-mark-marker-length ?\b))
00d6fd04
MA
1009 "String mark to be transmitted around shell commands.
1010Used to separate their echo from the output they produce. This
1011will only be used if we cannot disable remote echo via stty.
1012This string must have no effect on the remote shell except for
1013producing some echo which can later be detected by
674da028
MA
1014`tramp-echoed-echo-mark-regexp'. Using `tramp-echo-mark-marker',
1015followed by an equal number of backspaces to erase them will
1016usually suffice.")
00d6fd04 1017
68712eb6
MA
1018(defconst tramp-echoed-echo-mark-regexp
1019 (format "%s\\(\b\\( \b\\)?\\)\\{%d\\}"
1020 tramp-echo-mark-marker tramp-echo-mark-marker-length)
00d6fd04
MA
1021 "Regexp which matches `tramp-echo-mark' as it gets echoed by
1022the remote shell.")
1023
fb7933a3
KG
1024(defcustom tramp-rsh-end-of-line "\n"
1025 "*String used for end of line in rsh connections.
1026I don't think this ever needs to be changed, so please tell me about it
16674e4f 1027if you need to change this.
90f8dc03
KG
1028Also see the method parameter `tramp-password-end-of-line' and the normal
1029variable `tramp-default-password-end-of-line'."
16674e4f
KG
1030 :group 'tramp
1031 :type 'string)
1032
90f8dc03
KG
1033(defcustom tramp-default-password-end-of-line
1034 tramp-rsh-end-of-line
16674e4f 1035 "*String used for end of line after sending a password.
90f8dc03
KG
1036This variable provides the default value for the method parameter
1037`tramp-password-end-of-line', see `tramp-methods' for more details.
1038
16674e4f
KG
1039It seems that people using plink under Windows need to send
1040\"\\r\\n\" (carriage-return, then newline) after a password, but just
1041\"\\n\" after all other lines. This variable can be used for the
1042password, see `tramp-rsh-end-of-line' for the other cases.
1043
1044The default value is to use the same value as `tramp-rsh-end-of-line'."
fb7933a3
KG
1045 :group 'tramp
1046 :type 'string)
1047
00d6fd04
MA
1048;; "getconf PATH" yields:
1049;; HP-UX: /usr/bin:/usr/ccs/bin:/opt/ansic/bin:/opt/langtools/bin:/opt/fortran/bin
1050;; Solaris: /usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin
0664ff72 1051;; GNU/Linux (Debian, Suse): /bin:/usr/bin
00d6fd04 1052;; FreeBSD: /usr/bin:/bin:/usr/sbin:/sbin: - beware trailing ":"!
20b8ac83 1053;; IRIX64: /usr/bin
fb7933a3 1054(defcustom tramp-remote-path
00d6fd04
MA
1055 '(tramp-default-remote-path "/usr/sbin" "/usr/local/bin"
1056 "/local/bin" "/local/freeware/bin" "/local/gnu/bin"
fb7933a3
KG
1057 "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin")
1058 "*List of directories to search for executables on remote host.
00d6fd04
MA
1059For every remote host, this variable will be set buffer local,
1060keeping the list of existing directories on that host.
fb7933a3
KG
1061
1062You can use `~' in this list, but when searching for a shell which groks
00d6fd04
MA
1063tilde expansion, all directory names starting with `~' will be ignored.
1064
1065`Default Directories' represent the list of directories given by
1066the command \"getconf PATH\". It is recommended to use this
1067entry on top of this list, because these are the default
70c11b0b
MA
1068directories for POSIX compatible commands.
1069
1070`Private Directories' are the settings of the $PATH environment,
1071as given in your `~/.profile'."
00d6fd04
MA
1072 :group 'tramp
1073 :type '(repeat (choice
1074 (const :tag "Default Directories" tramp-default-remote-path)
70c11b0b 1075 (const :tag "Private Directories" tramp-own-remote-path)
00d6fd04
MA
1076 (string :tag "Directory"))))
1077
00d6fd04 1078(defcustom tramp-remote-process-environment
a0a5183a 1079 `("HISTFILE=$HOME/.tramp_history" "HISTSIZE=1" "LC_ALL=C"
20b8ac83 1080 ,(format "TERM=%s" tramp-terminal-type)
97c696d5 1081 "EMACS=t" ;; Deprecated.
20b8ac83 1082 ,(format "INSIDE_EMACS='%s,tramp:%s'" emacs-version tramp-version)
00d6fd04
MA
1083 "CDPATH=" "HISTORY=" "MAIL=" "MAILCHECK=" "MAILPATH="
1084 "autocorrect=" "correct=")
1085
1086 "*List of environment variables to be set on the remote host.
1087
1088Each element should be a string of the form ENVVARNAME=VALUE. An
1089entry ENVVARNAME= diables the corresponding environment variable,
1090which might have been set in the init files like ~/.profile.
1091
1092Special handling is applied to the PATH environment, which should
1093not be set here. Instead of, it should be set via `tramp-remote-path'."
fb7933a3
KG
1094 :group 'tramp
1095 :type '(repeat string))
1096
1097(defcustom tramp-login-prompt-regexp
bc103d00 1098 ".*ogin\\( .*\\)?: *"
fb7933a3 1099 "*Regexp matching login-like prompts.
bc103d00
MA
1100The regexp should match at end of buffer.
1101
1102Sometimes the prompt is reported to look like \"login as:\"."
fb7933a3
KG
1103 :group 'tramp
1104 :type 'regexp)
1105
821e6e36 1106(defcustom tramp-shell-prompt-pattern
aa485f7c 1107 ;; Allow a prompt to start right after a ^M since it indeed would be
20b8ac83
MA
1108 ;; displayed at the beginning of the line (and Zsh uses it). This
1109 ;; regexp works only for GNU Emacs.
1110 (concat (if (featurep 'xemacs) "" "\\(?:^\\|\r\\)")
1111 "[^#$%>\n]*#?[#$%>] *\\(\e\\[[0-9;]*[a-zA-Z] *\\)*")
821e6e36
KG
1112 "Regexp to match prompts from remote shell.
1113Normally, Tramp expects you to configure `shell-prompt-pattern'
1114correctly, but sometimes it happens that you are connecting to a
1115remote host which sends a different kind of shell prompt. Therefore,
1116Tramp recognizes things matched by `shell-prompt-pattern' as prompt,
1117and also things matched by this variable. The default value of this
b25a52cc 1118variable is similar to the default value of `shell-prompt-pattern',
dab816a9
MA
1119which should work well in many cases.
1120
1121This regexp must match both `tramp-initial-end-of-output' and
1122`tramp-end-of-output'."
821e6e36
KG
1123 :group 'tramp
1124 :type 'regexp)
1125
fb7933a3 1126(defcustom tramp-password-prompt-regexp
00d6fd04 1127 "^.*\\([pP]assword\\|[pP]assphrase\\).*:\^@? *"
fb7933a3 1128 "*Regexp matching password-like prompts.
ac474af1 1129The regexp should match at end of buffer.
fb7933a3
KG
1130
1131The `sudo' program appears to insert a `^@' character into the prompt."
1132 :group 'tramp
1133 :type 'regexp)
1134
1135(defcustom tramp-wrong-passwd-regexp
b1d06e75
KG
1136 (concat "^.*"
1137 ;; These strings should be on the last line
a4aeb9a4 1138 (regexp-opt '("Permission denied"
b1d06e75
KG
1139 "Login incorrect"
1140 "Login Incorrect"
1141 "Connection refused"
27e813fe 1142 "Connection closed"
7e5686f0 1143 "Timeout, server not responding."
b1d06e75
KG
1144 "Sorry, try again."
1145 "Name or service not known"
00d6fd04 1146 "Host key verification failed."
70c11b0b 1147 "No supported authentication methods left to try!") t)
b1d06e75
KG
1148 ".*"
1149 "\\|"
1150 "^.*\\("
1151 ;; Here comes a list of regexes, separated by \\|
1152 "Received signal [0-9]+"
1153 "\\).*")
fb7933a3 1154 "*Regexp matching a `login failed' message.
ac474af1
KG
1155The regexp should match at end of buffer."
1156 :group 'tramp
1157 :type 'regexp)
1158
1159(defcustom tramp-yesno-prompt-regexp
3cdaec13
KG
1160 (concat
1161 (regexp-opt '("Are you sure you want to continue connecting (yes/no)?") t)
1162 "\\s-*")
1163 "Regular expression matching all yes/no queries which need to be confirmed.
ac474af1 1164The confirmation should be done with yes or no.
3cdaec13
KG
1165The regexp should match at end of buffer.
1166See also `tramp-yn-prompt-regexp'."
fb7933a3
KG
1167 :group 'tramp
1168 :type 'regexp)
1169
3cdaec13 1170(defcustom tramp-yn-prompt-regexp
658052a2
MA
1171 (concat
1172 (regexp-opt '("Store key in cache? (y/n)"
1173 "Update cached key? (y/n, Return cancels connection)") t)
1174 "\\s-*")
3cdaec13
KG
1175 "Regular expression matching all y/n queries which need to be confirmed.
1176The confirmation should be done with y or n.
1177The regexp should match at end of buffer.
1178See also `tramp-yesno-prompt-regexp'."
1179 :group 'tramp
1180 :type 'regexp)
487f4fb7
KG
1181
1182(defcustom tramp-terminal-prompt-regexp
1183 (concat "\\("
1184 "TERM = (.*)"
1185 "\\|"
1186 "Terminal type\\? \\[.*\\]"
1187 "\\)\\s-*")
1188 "Regular expression matching all terminal setting prompts.
1189The regexp should match at end of buffer.
1190The answer will be provided by `tramp-action-terminal', which see."
1191 :group 'tramp
1192 :type 'regexp)
3cdaec13 1193
01917a18
MA
1194(defcustom tramp-operation-not-permitted-regexp
1195 (concat "\\(" "preserving times.*" "\\|" "set mode" "\\)" ":\\s-*"
1196 (regexp-opt '("Operation not permitted") t))
1197 "Regular expression matching keep-date problems in (s)cp operations.
1198Copying has been performed successfully already, so this message can
1199be ignored safely."
1200 :group 'tramp
1201 :type 'regexp)
1202
6b2633cc
LH
1203(defcustom tramp-copy-failed-regexp
1204 (concat "\\(.+: "
1205 (regexp-opt '("Permission denied"
1206 "not a regular file"
1207 "is a directory"
1208 "No such file or directory") t)
1209 "\\)\\s-*")
1210 "Regular expression matching copy problems in (s)cp operations."
1211 :group 'tramp
1212 :type 'regexp)
1213
19a87064 1214(defcustom tramp-process-alive-regexp
38c65fca 1215 ""
19a87064 1216 "Regular expression indicating a process has finished.
38c65fca
KG
1217In fact this expression is empty by intention, it will be used only to
1218check regularly the status of the associated process.
07dfe738 1219The answer will be provided by `tramp-action-process-alive',
00d6fd04 1220`tramp-action-out-of-band', which see."
38c65fca
KG
1221 :group 'tramp
1222 :type 'regexp)
1223
fb7933a3
KG
1224(defcustom tramp-temp-name-prefix "tramp."
1225 "*Prefix to use for temporary files.
1226If this is a relative file name (such as \"tramp.\"), it is considered
1227relative to the directory name returned by the function
9e6ab520 1228`tramp-compat-temporary-file-directory' (which see). It may also be an
fb7933a3
KG
1229absolute file name; don't forget to include a prefix for the filename
1230part, though."
1231 :group 'tramp
1232 :type 'string)
1233
2296b54d
MA
1234(defconst tramp-temp-buffer-name " *tramp temp*"
1235 "Buffer name for a temporary buffer.
1236It shall be used in combination with `generate-new-buffer-name'.")
1237
b88f2d0a
MA
1238(defvar tramp-temp-buffer-file-name nil
1239 "File name of a persistent local temporary file.
1240Useful for \"rsync\" like methods.")
1241(make-variable-buffer-local 'tramp-temp-buffer-file-name)
1242
4007ba5b 1243(defcustom tramp-sh-extra-args '(("/bash\\'" . "-norc -noprofile"))
c62c9d08
KG
1244 "*Alist specifying extra arguments to pass to the remote shell.
1245Entries are (REGEXP . ARGS) where REGEXP is a regular expression
1246matching the shell file name and ARGS is a string specifying the
1247arguments.
1248
1249This variable is only used when Tramp needs to start up another shell
1250for tilde expansion. The extra arguments should typically prevent the
1251shell from reading its init file."
1252 :group 'tramp
90f8dc03
KG
1253 ;; This might be the wrong way to test whether the widget type
1254 ;; `alist' is available. Who knows the right way to test it?
1255 :type (if (get 'alist 'widget-type)
1256 '(alist :key-type string :value-type string)
1257 '(repeat (cons string string))))
c62c9d08 1258
00d6fd04
MA
1259;; XEmacs is distributed with few Lisp packages. Further packages are
1260;; installed using EFS. If we use a unified filename format, then
1261;; Tramp is required in addition to EFS. (But why can't Tramp just
1262;; disable EFS when Tramp is loaded? Then XEmacs can ship with EFS
1263;; just like before.) Another reason for using a separate filename
1264;; syntax on XEmacs is that EFS hooks into XEmacs in many places, but
1265;; Tramp only knows how to deal with `file-name-handler-alist', not
1266;; the other places.
1267
1268;; Currently, we have the choice between 'ftp, 'sep, and 'url.
1269;;;###autoload
1270(defcustom tramp-syntax
1271 (if (featurep 'xemacs) 'sep 'ftp)
1272 "Tramp filename syntax to be used.
1273
1274It can have the following values:
1275
1276 'ftp -- Ange-FTP respective EFS like syntax (GNU Emacs default)
1277 'sep -- Syntax as defined for XEmacs (not available yet for GNU Emacs)
1278 'url -- URL-like syntax."
16674e4f 1279 :group 'tramp
00d6fd04
MA
1280 :type (if (featurep 'xemacs)
1281 '(choice (const :tag "EFS" ftp)
1282 (const :tag "XEmacs" sep)
1283 (const :tag "URL" url))
1284 '(choice (const :tag "Ange-FTP" ftp)
1285 (const :tag "URL" url))))
1286
1287(defconst tramp-prefix-format
1288 (cond ((equal tramp-syntax 'ftp) "/")
1289 ((equal tramp-syntax 'sep) "/[")
1290 ((equal tramp-syntax 'url) "/")
1291 (t (error "Wrong `tramp-syntax' defined")))
a4aeb9a4 1292 "*String matching the very beginning of Tramp file names.
00d6fd04 1293Used in `tramp-make-tramp-file-name'.")
16674e4f 1294
00d6fd04 1295(defconst tramp-prefix-regexp
16674e4f 1296 (concat "^" (regexp-quote tramp-prefix-format))
a4aeb9a4 1297 "*Regexp matching the very beginning of Tramp file names.
00d6fd04 1298Should always start with \"^\". Derived from `tramp-prefix-format'.")
16674e4f 1299
00d6fd04 1300(defconst tramp-method-regexp
16674e4f 1301 "[a-zA-Z_0-9-]+"
00d6fd04 1302 "*Regexp matching methods identifiers.")
16674e4f 1303
00d6fd04
MA
1304(defconst tramp-postfix-method-format
1305 (cond ((equal tramp-syntax 'ftp) ":")
1306 ((equal tramp-syntax 'sep) "/")
1307 ((equal tramp-syntax 'url) "://")
1308 (t (error "Wrong `tramp-syntax' defined")))
16674e4f 1309 "*String matching delimeter between method and user or host names.
00d6fd04 1310Used in `tramp-make-tramp-file-name'.")
16674e4f 1311
00d6fd04
MA
1312(defconst tramp-postfix-method-regexp
1313 (regexp-quote tramp-postfix-method-format)
16674e4f 1314 "*Regexp matching delimeter between method and user or host names.
00d6fd04 1315Derived from `tramp-postfix-method-format'.")
16674e4f 1316
00d6fd04
MA
1317(defconst tramp-user-regexp
1318 "[^:/ \t]+"
1319 "*Regexp matching user names.")
16674e4f 1320
b96e6899
MA
1321(defconst tramp-prefix-domain-format "%"
1322 "*String matching delimeter between user and domain names.")
1323
1324(defconst tramp-prefix-domain-regexp
1325 (regexp-quote tramp-prefix-domain-format)
1326 "*Regexp matching delimeter between user and domain names.
1327Derived from `tramp-prefix-domain-format'.")
1328
1329(defconst tramp-domain-regexp
70c11b0b 1330 "[-a-zA-Z0-9_.]+"
b96e6899
MA
1331 "*Regexp matching domain names.")
1332
1333(defconst tramp-user-with-domain-regexp
1334 (concat "\\(" tramp-user-regexp "\\)"
1335 tramp-prefix-domain-regexp
1336 "\\(" tramp-domain-regexp "\\)")
1337 "*Regexp matching user names with domain names.")
1338
00d6fd04 1339(defconst tramp-postfix-user-format
16674e4f
KG
1340 "@"
1341 "*String matching delimeter between user and host names.
00d6fd04 1342Used in `tramp-make-tramp-file-name'.")
16674e4f 1343
00d6fd04 1344(defconst tramp-postfix-user-regexp
16674e4f
KG
1345 (regexp-quote tramp-postfix-user-format)
1346 "*Regexp matching delimeter between user and host names.
00d6fd04
MA
1347Derived from `tramp-postfix-user-format'.")
1348
1349(defconst tramp-host-regexp
1350 "[a-zA-Z0-9_.-]+"
1351 "*Regexp matching host names.")
1352
b96e6899
MA
1353(defconst tramp-prefix-ipv6-format
1354 (cond ((equal tramp-syntax 'ftp) "[")
1355 ((equal tramp-syntax 'sep) "")
1356 ((equal tramp-syntax 'url) "[")
1357 (t (error "Wrong `tramp-syntax' defined")))
1358 "*String matching left hand side of IPv6 addresses.
1359Used in `tramp-make-tramp-file-name'.")
1360
1361(defconst tramp-prefix-ipv6-regexp
1362 (regexp-quote tramp-prefix-ipv6-format)
1363 "*Regexp matching left hand side of IPv6 addresses.
1364Derived from `tramp-prefix-ipv6-format'.")
1365
e0b6e3b9
MA
1366;; The following regexp is a bit sloppy. But it shall serve our
1367;; purposes. It covers also IPv4 mapped IPv6 addresses, like in
1368;; "::ffff:192.168.0.1".
b96e6899 1369(defconst tramp-ipv6-regexp
e0b6e3b9 1370 "\\(?:\\(?:[a-zA-Z0-9]+\\)?:\\)+[a-zA-Z0-9.]+"
b96e6899
MA
1371 "*Regexp matching IPv6 addresses.")
1372
1373(defconst tramp-postfix-ipv6-format
1374 (cond ((equal tramp-syntax 'ftp) "]")
1375 ((equal tramp-syntax 'sep) "")
1376 ((equal tramp-syntax 'url) "]")
1377 (t (error "Wrong `tramp-syntax' defined")))
1378 "*String matching right hand side of IPv6 addresses.
1379Used in `tramp-make-tramp-file-name'.")
1380
1381(defconst tramp-postfix-ipv6-regexp
1382 (regexp-quote tramp-postfix-ipv6-format)
1383 "*Regexp matching right hand side of IPv6 addresses.
1384Derived from `tramp-postfix-ipv6-format'.")
1385
00d6fd04
MA
1386(defconst tramp-prefix-port-format
1387 (cond ((equal tramp-syntax 'ftp) "#")
1388 ((equal tramp-syntax 'sep) "#")
1389 ((equal tramp-syntax 'url) ":")
1390 (t (error "Wrong `tramp-syntax' defined")))
1391 "*String matching delimeter between host names and port numbers.")
1392
1393(defconst tramp-prefix-port-regexp
1394 (regexp-quote tramp-prefix-port-format)
1395 "*Regexp matching delimeter between host names and port numbers.
1396Derived from `tramp-prefix-port-format'.")
1397
1398(defconst tramp-port-regexp
1399 "[0-9]+"
1400 "*Regexp matching port numbers.")
1401
1402(defconst tramp-host-with-port-regexp
1403 (concat "\\(" tramp-host-regexp "\\)"
1404 tramp-prefix-port-regexp
1405 "\\(" tramp-port-regexp "\\)")
1406 "*Regexp matching host names with port numbers.")
1407
1408(defconst tramp-postfix-host-format
1409 (cond ((equal tramp-syntax 'ftp) ":")
1410 ((equal tramp-syntax 'sep) "]")
1411 ((equal tramp-syntax 'url) "")
1412 (t (error "Wrong `tramp-syntax' defined")))
7432277c 1413 "*String matching delimeter between host names and localnames.
00d6fd04 1414Used in `tramp-make-tramp-file-name'.")
16674e4f 1415
00d6fd04 1416(defconst tramp-postfix-host-regexp
16674e4f 1417 (regexp-quote tramp-postfix-host-format)
7432277c 1418 "*Regexp matching delimeter between host names and localnames.
00d6fd04 1419Derived from `tramp-postfix-host-format'.")
16674e4f 1420
00d6fd04 1421(defconst tramp-localname-regexp
16674e4f 1422 ".*$"
00d6fd04 1423 "*Regexp matching localnames.")
16674e4f
KG
1424
1425;; File name format.
505edaeb 1426
00d6fd04 1427(defconst tramp-file-name-structure
16674e4f
KG
1428 (list
1429 (concat
1430 tramp-prefix-regexp
00d6fd04
MA
1431 "\\(" "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp "\\)?"
1432 "\\(" "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp "\\)?"
b96e6899
MA
1433 "\\(" "\\(" tramp-host-regexp
1434 "\\|"
1435 tramp-prefix-ipv6-regexp tramp-ipv6-regexp
1436 tramp-postfix-ipv6-regexp "\\)"
1437 "\\(" tramp-prefix-port-regexp tramp-port-regexp "\\)?" "\\)?"
00d6fd04
MA
1438 tramp-postfix-host-regexp
1439 "\\(" tramp-localname-regexp "\\)")
b96e6899 1440 2 4 5 8)
16674e4f 1441
fb7933a3 1442 "*List of five elements (REGEXP METHOD USER HOST FILE), detailing \
a4aeb9a4 1443the Tramp file name structure.
fb7933a3 1444
a4aeb9a4 1445The first element REGEXP is a regular expression matching a Tramp file
fb7933a3
KG
1446name. The regex should contain parentheses around the method name,
1447the user name, the host name, and the file name parts.
1448
1449The second element METHOD is a number, saying which pair of
1450parentheses matches the method name. The third element USER is
1451similar, but for the user name. The fourth element HOST is similar,
1452but for the host name. The fifth element FILE is for the file name.
1453These numbers are passed directly to `match-string', which see. That
1454means the opening parentheses are counted to identify the pair.
1455
00d6fd04 1456See also `tramp-file-name-regexp'.")
fb7933a3
KG
1457
1458;;;###autoload
505edaeb 1459(defconst tramp-file-name-regexp-unified
20b8ac83
MA
1460 (if (memq system-type '(cygwin windows-nt))
1461 "\\`/\\([^[/:]\\{2,\\}\\|[^/]\\{2,\\}]\\):"
1462 "\\`/\\([^[/:]+\\|[^/]+]\\):")
505edaeb
KG
1463 "Value for `tramp-file-name-regexp' for unified remoting.
1464Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and
20b8ac83
MA
1465Tramp. See `tramp-file-name-structure' for more explanations.
1466
1467On W32 systems, the volume letter must be ignored.")
505edaeb
KG
1468
1469;;;###autoload
1470(defconst tramp-file-name-regexp-separate
1471 "\\`/\\[.*\\]"
1472 "Value for `tramp-file-name-regexp' for separate remoting.
1473XEmacs uses a separate filename syntax for Tramp and EFS.
00d6fd04 1474See `tramp-file-name-structure' for more explanations.")
505edaeb
KG
1475
1476;;;###autoload
00d6fd04
MA
1477(defconst tramp-file-name-regexp-url
1478 "\\`/[^/:]+://"
1479 "Value for `tramp-file-name-regexp' for URL-like remoting.
1480See `tramp-file-name-structure' for more explanations.")
1481
1482;;;###autoload
1483(defconst tramp-file-name-regexp
1484 (cond ((equal tramp-syntax 'ftp) tramp-file-name-regexp-unified)
1485 ((equal tramp-syntax 'sep) tramp-file-name-regexp-separate)
1486 ((equal tramp-syntax 'url) tramp-file-name-regexp-url)
1487 (t (error "Wrong `tramp-syntax' defined")))
94be87e8 1488 "*Regular expression matching file names handled by Tramp.
a4aeb9a4 1489This regexp should match Tramp file names but no other file names.
20b8ac83 1490When tramp.el is loaded, this regular expression is prepended to
fb7933a3 1491`file-name-handler-alist', and that is searched sequentially. Thus,
a4aeb9a4
MA
1492if the Tramp entry appears rather early in the `file-name-handler-alist'
1493and is a bit too general, then some files might be considered Tramp
00d6fd04 1494files which are not really Tramp files.
fb7933a3
KG
1495
1496Please note that the entry in `file-name-handler-alist' is made when
20b8ac83 1497this file \(tramp.el\) is loaded. This means that this variable must be set
fb7933a3
KG
1498before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1499updated after changing this variable.
1500
00d6fd04 1501Also see `tramp-file-name-structure'.")
fb7933a3 1502
16674e4f 1503;;;###autoload
8a798e41 1504(defconst tramp-root-regexp
00d6fd04 1505 (if (memq system-type '(cygwin windows-nt))
aa485f7c
MA
1506 "\\`\\([a-zA-Z]:\\)?/"
1507 "\\`/")
8a798e41 1508 "Beginning of an incomplete Tramp file name.
aa485f7c 1509Usually, it is just \"\\\\`/\". On W32 systems, there might be a
57671b72 1510volume letter, which will be removed by `tramp-drop-volume-letter'.")
8a798e41
MA
1511
1512;;;###autoload
1513(defconst tramp-completion-file-name-regexp-unified
20b8ac83
MA
1514 (if (memq system-type '(cygwin windows-nt))
1515 (concat tramp-root-regexp "[^/]\\{2,\\}\\'")
1516 (concat tramp-root-regexp "[^/]*\\'"))
16674e4f 1517 "Value for `tramp-completion-file-name-regexp' for unified remoting.
8a798e41 1518GNU Emacs uses a unified filename syntax for Tramp and Ange-FTP.
20b8ac83
MA
1519See `tramp-file-name-structure' for more explanations.
1520
1521On W32 systems, the volume letter must be ignored.")
fb7933a3 1522
16674e4f
KG
1523;;;###autoload
1524(defconst tramp-completion-file-name-regexp-separate
aa485f7c 1525 (concat tramp-root-regexp "\\([[][^]]*\\)?\\'")
16674e4f
KG
1526 "Value for `tramp-completion-file-name-regexp' for separate remoting.
1527XEmacs uses a separate filename syntax for Tramp and EFS.
00d6fd04 1528See `tramp-file-name-structure' for more explanations.")
fb7933a3 1529
16674e4f 1530;;;###autoload
00d6fd04 1531(defconst tramp-completion-file-name-regexp-url
aa485f7c 1532 (concat tramp-root-regexp "[^/:]+\\(:\\(/\\(/[^/]*\\)?\\)?\\)?\\'")
00d6fd04
MA
1533 "Value for `tramp-completion-file-name-regexp' for URL-like remoting.
1534See `tramp-file-name-structure' for more explanations.")
1535
1536;;;###autoload
1537(defconst tramp-completion-file-name-regexp
1538 (cond ((equal tramp-syntax 'ftp) tramp-completion-file-name-regexp-unified)
1539 ((equal tramp-syntax 'sep) tramp-completion-file-name-regexp-separate)
1540 ((equal tramp-syntax 'url) tramp-completion-file-name-regexp-url)
1541 (t (error "Wrong `tramp-syntax' defined")))
a4aeb9a4
MA
1542 "*Regular expression matching file names handled by Tramp completion.
1543This regexp should match partial Tramp file names only.
16674e4f
KG
1544
1545Please note that the entry in `file-name-handler-alist' is made when
1546this file (tramp.el) is loaded. This means that this variable must be set
1547before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1548updated after changing this variable.
1549
00d6fd04 1550Also see `tramp-file-name-structure'.")
fb7933a3 1551
00d6fd04
MA
1552(defconst tramp-actions-before-shell
1553 '((tramp-login-prompt-regexp tramp-action-login)
1554 (tramp-password-prompt-regexp tramp-action-password)
1555 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
ac474af1 1556 (shell-prompt-pattern tramp-action-succeed)
821e6e36 1557 (tramp-shell-prompt-pattern tramp-action-succeed)
3cdaec13 1558 (tramp-yesno-prompt-regexp tramp-action-yesno)
487f4fb7 1559 (tramp-yn-prompt-regexp tramp-action-yn)
19a87064
MA
1560 (tramp-terminal-prompt-regexp tramp-action-terminal)
1561 (tramp-process-alive-regexp tramp-action-process-alive))
ac474af1
KG
1562 "List of pattern/action pairs.
1563Whenever a pattern matches, the corresponding action is performed.
1564Each item looks like (PATTERN ACTION).
1565
1566The PATTERN should be a symbol, a variable. The value of this
1567variable gives the regular expression to search for. Note that the
1568regexp must match at the end of the buffer, \"\\'\" is implicitly
1569appended to it.
1570
1571The ACTION should also be a symbol, but a function. When the
00d6fd04 1572corresponding PATTERN matches, the ACTION function is called.")
ac474af1 1573
00d6fd04 1574(defconst tramp-actions-copy-out-of-band
38c65fca
KG
1575 '((tramp-password-prompt-regexp tramp-action-password)
1576 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
00d6fd04 1577 (tramp-copy-failed-regexp tramp-action-permission-denied)
19a87064 1578 (tramp-process-alive-regexp tramp-action-out-of-band))
38c65fca
KG
1579 "List of pattern/action pairs.
1580This list is used for copying/renaming with out-of-band methods.
90f8dc03 1581
00d6fd04
MA
1582See `tramp-actions-before-shell' for more info.")
1583
1584;; Chunked sending kludge. We set this to 500 for black-listed constellations
7432277c 1585;; known to have a bug in `process-send-string'; some ssh connections appear
7177e2a3
MA
1586;; to drop bytes when data is sent too quickly. There is also a connection
1587;; buffer local variable, which is computed depending on remote host properties
1588;; when `tramp-chunksize' is zero or nil.
7432277c
KG
1589(defcustom tramp-chunksize
1590 (when (and (not (featurep 'xemacs))
1591 (memq system-type '(hpux)))
1592 500)
55880756
MA
1593;; Parentheses in docstring starting at beginning of line are escaped.
1594;; Fontification is messed up when
1595;; `open-paren-in-column-0-is-defun-start' set to t.
7432277c
KG
1596 "*If non-nil, chunksize for sending input to local process.
1597It is necessary only on systems which have a buggy `process-send-string'
1598implementation. The necessity, whether this variable must be set, can be
1599checked via the following code:
1600
1601 (with-temp-buffer
11948172
MA
1602 (let* ((user \"xxx\") (host \"yyy\")
1603 (init 0) (step 50)
1604 (sent init) (received init))
1605 (while (= sent received)
1606 (setq sent (+ sent step))
1607 (erase-buffer)
1608 (let ((proc (start-process (buffer-name) (current-buffer)
1609 \"ssh\" \"-l\" user host \"wc\" \"-c\")))
1610 (when (memq (process-status proc) '(run open))
1611 (process-send-string proc (make-string sent ?\\ ))
1612 (process-send-eof proc)
1613 (process-send-eof proc))
1614 (while (not (progn (goto-char (point-min))
1615 (re-search-forward \"\\\\w+\" (point-max) t)))
1616 (accept-process-output proc 1))
1617 (when (memq (process-status proc) '(run open))
1618 (setq received (string-to-number (match-string 0)))
1619 (delete-process proc)
1620 (message \"Bytes sent: %s\\tBytes received: %s\" sent received)
1621 (sit-for 0))))
1622 (if (> sent (+ init step))
1623 (message \"You should set `tramp-chunksize' to a maximum of %s\"
1624 (- sent step))
1625 (message \"Test does not work\")
1626 (display-buffer (current-buffer))
1627 (sit-for 30))))
1628
1629In the Emacs normally running Tramp, evaluate the above code
55880756 1630\(replace \"xxx\" and \"yyy\" by the remote user and host name,
20b8ac83 1631respectively\). You can do this, for example, by pasting it into
11948172
MA
1632the `*scratch*' buffer and then hitting C-j with the cursor after the
1633last closing parenthesis. Note that it works only if you have configured
20b8ac83 1634\"ssh\" to run without password query, see ssh-agent\(1\).
11948172
MA
1635
1636You will see the number of bytes sent successfully to the remote host.
1637If that number exceeds 1000, you can stop the execution by hitting
1638C-g, because your Emacs is likely clean.
1639
11948172 1640When it is necessary to set `tramp-chunksize', you might consider to
20b8ac83
MA
1641use an out-of-the-band method \(like \"scp\"\) instead of an internal one
1642\(like \"ssh\"\), because setting `tramp-chunksize' to non-nil decreases
11948172 1643performance.
c951aecb 1644
00d6fd04
MA
1645If your Emacs is buggy, the code stops and gives you an indication
1646about the value `tramp-chunksize' should be set. Maybe you could just
1647experiment a bit, e.g. changing the values of `init' and `step'
1648in the third line of the code.
1649
7432277c
KG
1650Please raise a bug report via \"M-x tramp-bug\" if your system needs
1651this variable to be set as well."
1652 :group 'tramp
b1a2b924 1653 :type '(choice (const nil) integer))
7432277c 1654
5ec2cc41
KG
1655;; Logging in to a remote host normally requires obtaining a pty. But
1656;; Emacs on MacOS X has process-connection-type set to nil by default,
1657;; so on those systems Tramp doesn't obtain a pty. Here, we allow
1658;; for an override of the system default.
1659(defcustom tramp-process-connection-type t
1660 "Overrides `process-connection-type' for connections from Tramp.
1661Tramp binds process-connection-type to the value given here before
1662opening a connection to a remote host."
1663 :group 'tramp
1664 :type '(choice (const nil) (const t) (const pty)))
1665
b50dd0d2
MA
1666(defcustom tramp-completion-reread-directory-timeout 10
1667 "Defines seconds since last remote command before rereading a directory.
1668A remote directory might have changed its contents. In order to
1669make it visible during file name completion in the minibuffer,
1670Tramp flushes its cache and rereads the directory contents when
1671more than `tramp-completion-reread-directory-timeout' seconds
1672have been gone since last remote command execution. A value of 0
1673would require an immediate reread during filename completion, nil
1674means to use always cached values for the directory contents."
1675 :group 'tramp
1676 :type '(choice (const nil) integer))
1677
fb7933a3
KG
1678;;; Internal Variables:
1679
fb7933a3 1680(defvar tramp-current-method nil
00d6fd04 1681 "Connection method for this *tramp* buffer.")
fb7933a3
KG
1682
1683(defvar tramp-current-user nil
00d6fd04 1684 "Remote login name for this *tramp* buffer.")
fb7933a3
KG
1685
1686(defvar tramp-current-host nil
00d6fd04
MA
1687 "Remote host for this *tramp* buffer.")
1688
1689(defconst tramp-uudecode
1690 "(echo begin 600 /tmp/tramp.$$; tail +2) | uudecode
fabf2143 1691cat /tmp/tramp.$$
00d6fd04 1692rm -f /tmp/tramp.$$"
fabf2143 1693 "Shell function to implement `uudecode' to standard output.
c08e6004
MA
1694Many systems support `uudecode -o /dev/stdout' or `uudecode -o -'
1695for this or `uudecode -p', but some systems don't, and for them
1696we have this shell function.")
fabf2143 1697
293c24f9
MA
1698(defconst tramp-perl-file-truename
1699 "%s -e '
1700use File::Spec;
1701use Cwd \"realpath\";
1702
1703sub recursive {
1704 my ($volume, @dirs) = @_;
1705 my $real = realpath(File::Spec->catpath(
1706 $volume, File::Spec->catdir(@dirs), \"\"));
1707 if ($real) {
1708 my ($vol, $dir) = File::Spec->splitpath($real, 1);
1709 return ($vol, File::Spec->splitdir($dir));
1710 }
1711 else {
1712 my $last = pop(@dirs);
1713 ($volume, @dirs) = recursive($volume, @dirs);
1714 push(@dirs, $last);
1715 return ($volume, @dirs);
1716 }
1717}
1718
1719$result = realpath($ARGV[0]);
1720if (!$result) {
1721 my ($vol, $dir) = File::Spec->splitpath($ARGV[0], 1);
1722 ($vol, @dirs) = recursive($vol, File::Spec->splitdir($dir));
1723
1724 $result = File::Spec->catpath($vol, File::Spec->catdir(@dirs), \"\");
1725}
1726
1727if ($ARGV[0] =~ /\\/$/) {
1728 $result = $result . \"/\";
1729}
1730
1731print \"\\\"$result\\\"\\n\";
1732' \"$1\" 2>/dev/null"
1733 "Perl script to produce output suitable for use with `file-truename'
1734on the remote file system.
1735Escape sequence %s is replaced with name of Perl binary.
1736This string is passed to `format', so percent characters need to be doubled.")
1737
1738(defconst tramp-perl-file-name-all-completions
1739 "%s -e 'sub case {
1740 my $str = shift;
1741 if ($ARGV[2]) {
1742 return lc($str);
1743 }
1744 else {
1745 return $str;
1746 }
1747}
1748opendir(d, $ARGV[0]) || die(\"$ARGV[0]: $!\\nfail\\n\");
1749@files = readdir(d); closedir(d);
1750foreach $f (@files) {
1751 if (case(substr($f, 0, length($ARGV[1]))) eq case($ARGV[1])) {
1752 if (-d \"$ARGV[0]/$f\") {
1753 print \"$f/\\n\";
1754 }
1755 else {
1756 print \"$f\\n\";
1757 }
1758 }
1759}
1760print \"ok\\n\"
1761' \"$1\" \"$2\" \"$3\" 2>/dev/null"
1762 "Perl script to produce output suitable for use with
1763`file-name-all-completions' on the remote file system. Escape
1764sequence %s is replaced with name of Perl binary. This string is
1765passed to `format', so percent characters need to be doubled.")
1766
fabf2143
KG
1767;; Perl script to implement `file-attributes' in a Lisp `read'able
1768;; output. If you are hacking on this, note that you get *no* output
1769;; unless this spits out a complete line, including the '\n' at the
1770;; end.
8daea7fc 1771;; The device number is returned as "-1", because there will be a virtual
b946a456 1772;; device number set in `tramp-handle-file-attributes'.
00d6fd04
MA
1773(defconst tramp-perl-file-attributes
1774 "%s -e '
c82c5727 1775@stat = lstat($ARGV[0]);
680db9ac
MA
1776if (!@stat) {
1777 print \"nil\\n\";
1778 exit 0;
1779}
c82c5727
LH
1780if (($stat[2] & 0170000) == 0120000)
1781{
1782 $type = readlink($ARGV[0]);
1783 $type = \"\\\"$type\\\"\";
1784}
1785elsif (($stat[2] & 0170000) == 040000)
1786{
1787 $type = \"t\";
1788}
1789else
1790{
1791 $type = \"nil\"
1792};
1793$uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
1794$gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
1795printf(
d4443a0d 1796 \"(%%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) -1)\\n\",
c82c5727
LH
1797 $type,
1798 $stat[3],
1799 $uid,
1800 $gid,
1801 $stat[8] >> 16 & 0xffff,
1802 $stat[8] & 0xffff,
1803 $stat[9] >> 16 & 0xffff,
1804 $stat[9] & 0xffff,
1805 $stat[10] >> 16 & 0xffff,
1806 $stat[10] & 0xffff,
1807 $stat[7],
1808 $stat[2],
1809 $stat[1] >> 16 & 0xffff,
1810 $stat[1] & 0xffff
20b8ac83 1811);' \"$1\" \"$2\" 2>/dev/null"
fb7933a3 1812 "Perl script to produce output suitable for use with `file-attributes'
00d6fd04
MA
1813on the remote file system.
1814Escape sequence %s is replaced with name of Perl binary.
1815This string is passed to `format', so percent characters need to be doubled.")
fb7933a3 1816
00d6fd04
MA
1817(defconst tramp-perl-directory-files-and-attributes
1818 "%s -e '
8cb0a559
LH
1819chdir($ARGV[0]) or printf(\"\\\"Cannot change to $ARGV[0]: $''!''\\\"\\n\"), exit();
1820opendir(DIR,\".\") or printf(\"\\\"Cannot open directory $ARGV[0]: $''!''\\\"\\n\"), exit();
c82c5727
LH
1821@list = readdir(DIR);
1822closedir(DIR);
1823$n = scalar(@list);
1824printf(\"(\\n\");
1825for($i = 0; $i < $n; $i++)
1826{
1827 $filename = $list[$i];
1828 @stat = lstat($filename);
1829 if (($stat[2] & 0170000) == 0120000)
1830 {
1831 $type = readlink($filename);
1832 $type = \"\\\"$type\\\"\";
1833 }
1834 elsif (($stat[2] & 0170000) == 040000)
1835 {
1836 $type = \"t\";
1837 }
1838 else
1839 {
1840 $type = \"nil\"
1841 };
1842 $uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
1843 $gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
1844 printf(
b946a456 1845 \"(\\\"%%s\\\" %%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) (%%u . %%u))\\n\",
c82c5727
LH
1846 $filename,
1847 $type,
1848 $stat[3],
1849 $uid,
1850 $gid,
1851 $stat[8] >> 16 & 0xffff,
1852 $stat[8] & 0xffff,
1853 $stat[9] >> 16 & 0xffff,
1854 $stat[9] & 0xffff,
1855 $stat[10] >> 16 & 0xffff,
1856 $stat[10] & 0xffff,
1857 $stat[7],
1858 $stat[2],
1859 $stat[1] >> 16 & 0xffff,
1860 $stat[1] & 0xffff,
1861 $stat[0] >> 16 & 0xffff,
1862 $stat[0] & 0xffff);
1863}
20b8ac83 1864printf(\")\\n\");' \"$1\" \"$2\" 2>/dev/null"
c82c5727 1865 "Perl script implementing `directory-files-attributes' as Lisp `read'able
00d6fd04
MA
1866output.
1867Escape sequence %s is replaced with name of Perl binary.
1868This string is passed to `format', so percent characters need to be doubled.")
c82c5727 1869
ac474af1
KG
1870;; ;; These two use uu encoding.
1871;; (defvar tramp-perl-encode "%s -e'\
1872;; print qq(begin 644 xxx\n);
1873;; my $s = q();
1874;; my $res = q();
1875;; while (read(STDIN, $s, 45)) {
1876;; print pack(q(u), $s);
1877;; }
1878;; print qq(`\n);
1879;; print qq(end\n);
1880;; '"
1881;; "Perl program to use for encoding a file.
1882;; Escape sequence %s is replaced with name of Perl binary.")
1883
1884;; (defvar tramp-perl-decode "%s -ne '
1885;; print unpack q(u), $_;
1886;; '"
1887;; "Perl program to use for decoding a file.
1888;; Escape sequence %s is replaced with name of Perl binary.")
1889
1890;; These two use base64 encoding.
00d6fd04
MA
1891(defconst tramp-perl-encode-with-module
1892 "%s -MMIME::Base64 -0777 -ne 'print encode_base64($_)' 2>/dev/null"
ac474af1 1893 "Perl program to use for encoding a file.
b1d06e75 1894Escape sequence %s is replaced with name of Perl binary.
89509ea0 1895This string is passed to `format', so percent characters need to be doubled.
b1d06e75
KG
1896This implementation requires the MIME::Base64 Perl module to be installed
1897on the remote host.")
1898
00d6fd04
MA
1899(defconst tramp-perl-decode-with-module
1900 "%s -MMIME::Base64 -0777 -ne 'print decode_base64($_)' 2>/dev/null"
b1d06e75
KG
1901 "Perl program to use for decoding a file.
1902Escape sequence %s is replaced with name of Perl binary.
89509ea0 1903This string is passed to `format', so percent characters need to be doubled.
b1d06e75
KG
1904This implementation requires the MIME::Base64 Perl module to be installed
1905on the remote host.")
1906
00d6fd04 1907(defconst tramp-perl-encode
b1d06e75
KG
1908 "%s -e '
1909# This script contributed by Juanma Barranquero <lektu@terra.es>.
6a0ecd86
MA
1910# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
1911# 2011 Free Software Foundation, Inc.
b1d06e75
KG
1912use strict;
1913
fa32e96a 1914my %%trans = do {
b1d06e75
KG
1915 my $i = 0;
1916 map {(substr(unpack(q(B8), chr $i++), 2, 6), $_)}
1917 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/);
1918};
1919
36541701 1920binmode(\\*STDIN);
b1d06e75
KG
1921
1922# We read in chunks of 54 bytes, to generate output lines
1923# of 72 chars (plus end of line)
36541701 1924$/ = \\54;
b1d06e75
KG
1925
1926while (my $data = <STDIN>) {
1927 my $pad = q();
1928
1929 # Only for the last chunk, and only if did not fill the last three-byte packet
1930 if (eof) {
fa32e96a 1931 my $mod = length($data) %% 3;
b1d06e75
KG
1932 $pad = q(=) x (3 - $mod) if $mod;
1933 }
1934
1935 # Not the fastest method, but it is simple: unpack to binary string, split
1936 # by groups of 6 bits and convert back from binary to byte; then map into
1937 # the translation table
1938 print
1939 join q(),
1940 map($trans{$_},
1941 (substr(unpack(q(B*), $data) . q(00000), 0, 432) =~ /....../g)),
1942 $pad,
36541701 1943 qq(\\n);
00d6fd04 1944}' 2>/dev/null"
b1d06e75 1945 "Perl program to use for encoding a file.
fa32e96a 1946Escape sequence %s is replaced with name of Perl binary.
ccf29586 1947This string is passed to `format', so percent characters need to be doubled.")
ac474af1 1948
00d6fd04 1949(defconst tramp-perl-decode
b1d06e75
KG
1950 "%s -e '
1951# This script contributed by Juanma Barranquero <lektu@terra.es>.
6a0ecd86
MA
1952# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
1953# 2011 Free Software Foundation, Inc.
b1d06e75
KG
1954use strict;
1955
fa32e96a 1956my %%trans = do {
b1d06e75 1957 my $i = 0;
16674e4f 1958 map {($_, substr(unpack(q(B8), chr $i++), 2, 6))}
b1d06e75
KG
1959 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/)
1960};
1961
fa32e96a 1962my %%bytes = map {(unpack(q(B8), chr $_), chr $_)} 0 .. 255;
b1d06e75 1963
36541701 1964binmode(\\*STDOUT);
b1d06e75
KG
1965
1966# We are going to accumulate into $pending to accept any line length
1967# (we do not check they are <= 76 chars as the RFC says)
1968my $pending = q();
1969
1970while (my $data = <STDIN>) {
1971 chomp $data;
1972
1973 # If we find one or two =, we have reached the end and
1974 # any following data is to be discarded
1975 my $finished = $data =~ s/(==?).*/$1/;
1976 $pending .= $data;
1977
1978 my $len = length($pending);
16674e4f 1979 my $chunk = substr($pending, 0, $len & ~3);
414da5ab 1980 $pending = substr($pending, $len & ~3 + 1);
b1d06e75
KG
1981
1982 # Easy method: translate from chars to (pregenerated) six-bit packets, join,
1983 # split in 8-bit chunks and convert back to char.
1984 print join q(),
1985 map $bytes{$_},
1986 ((join q(), map {$trans{$_} || q()} split //, $chunk) =~ /......../g);
1987
1988 last if $finished;
00d6fd04 1989}' 2>/dev/null"
ac474af1 1990 "Perl program to use for decoding a file.
fa32e96a 1991Escape sequence %s is replaced with name of Perl binary.
ccf29586 1992This string is passed to `format', so percent characters need to be doubled.")
fb7933a3 1993
946a5aeb
MA
1994(defconst tramp-vc-registered-read-file-names
1995 "echo \"(\"
20b8ac83
MA
1996while read file; do
1997 if %s \"$file\"; then
946a5aeb
MA
1998 echo \"(\\\"$file\\\" \\\"file-exists-p\\\" t)\"
1999 else
2000 echo \"(\\\"$file\\\" \\\"file-exists-p\\\" nil)\"
2001 fi
20b8ac83 2002 if %s \"$file\"; then
946a5aeb
MA
2003 echo \"(\\\"$file\\\" \\\"file-readable-p\\\" t)\"
2004 else
2005 echo \"(\\\"$file\\\" \\\"file-readable-p\\\" nil)\"
2006 fi
2007done
2008echo \")\""
2009 "Script to check existence of VC related files.
2010It must be send formatted with two strings; the tests for file
20b8ac83
MA
2011existence, and file readability. Input shall be read via
2012here-document, otherwise the command could exceed maximum length
2013of command line.")
946a5aeb 2014
9ce8462a
MA
2015(defconst tramp-file-mode-type-map
2016 '((0 . "-") ; Normal file (SVID-v2 and XPG2)
2017 (1 . "p") ; fifo
2018 (2 . "c") ; character device
2019 (3 . "m") ; multiplexed character device (v7)
2020 (4 . "d") ; directory
2021 (5 . "?") ; Named special file (XENIX)
2022 (6 . "b") ; block device
2023 (7 . "?") ; multiplexed block device (v7)
2024 (8 . "-") ; regular file
2025 (9 . "n") ; network special file (HP-UX)
2026 (10 . "l") ; symlink
2027 (11 . "?") ; ACL shadow inode (Solaris, not userspace)
2028 (12 . "s") ; socket
2029 (13 . "D") ; door special (Solaris)
2030 (14 . "w")) ; whiteout (BSD)
fb7933a3
KG
2031 "A list of file types returned from the `stat' system call.
2032This is used to map a mode number to a permission string.")
2033
fb7933a3 2034;; New handlers should be added here. The following operations can be
c0fc6170
MA
2035;; handled using the normal primitives: file-name-sans-versions,
2036;; get-file-buffer.
fb7933a3 2037(defconst tramp-file-name-handler-alist
00d6fd04 2038 '((load . tramp-handle-load)
fb7933a3 2039 (make-symbolic-link . tramp-handle-make-symbolic-link)
c0fc6170 2040 (file-name-as-directory . tramp-handle-file-name-as-directory)
fb7933a3
KG
2041 (file-name-directory . tramp-handle-file-name-directory)
2042 (file-name-nondirectory . tramp-handle-file-name-nondirectory)
2043 (file-truename . tramp-handle-file-truename)
2044 (file-exists-p . tramp-handle-file-exists-p)
2045 (file-directory-p . tramp-handle-file-directory-p)
2046 (file-executable-p . tramp-handle-file-executable-p)
fb7933a3
KG
2047 (file-readable-p . tramp-handle-file-readable-p)
2048 (file-regular-p . tramp-handle-file-regular-p)
2049 (file-symlink-p . tramp-handle-file-symlink-p)
2050 (file-writable-p . tramp-handle-file-writable-p)
2051 (file-ownership-preserved-p . tramp-handle-file-ownership-preserved-p)
2052 (file-newer-than-file-p . tramp-handle-file-newer-than-file-p)
2053 (file-attributes . tramp-handle-file-attributes)
2054 (file-modes . tramp-handle-file-modes)
fb7933a3 2055 (directory-files . tramp-handle-directory-files)
c82c5727 2056 (directory-files-and-attributes . tramp-handle-directory-files-and-attributes)
fb7933a3
KG
2057 (file-name-all-completions . tramp-handle-file-name-all-completions)
2058 (file-name-completion . tramp-handle-file-name-completion)
2059 (add-name-to-file . tramp-handle-add-name-to-file)
2060 (copy-file . tramp-handle-copy-file)
263c02ef 2061 (copy-directory . tramp-handle-copy-directory)
fb7933a3
KG
2062 (rename-file . tramp-handle-rename-file)
2063 (set-file-modes . tramp-handle-set-file-modes)
ce3f516f 2064 (set-file-times . tramp-handle-set-file-times)
fb7933a3
KG
2065 (make-directory . tramp-handle-make-directory)
2066 (delete-directory . tramp-handle-delete-directory)
2067 (delete-file . tramp-handle-delete-file)
2068 (directory-file-name . tramp-handle-directory-file-name)
00d6fd04
MA
2069 ;; `executable-find' is not official yet.
2070 (executable-find . tramp-handle-executable-find)
2071 (start-file-process . tramp-handle-start-file-process)
0457dd55 2072 (process-file . tramp-handle-process-file)
00d6fd04 2073 (shell-command . tramp-handle-shell-command)
fb7933a3
KG
2074 (insert-directory . tramp-handle-insert-directory)
2075 (expand-file-name . tramp-handle-expand-file-name)
00d6fd04 2076 (substitute-in-file-name . tramp-handle-substitute-in-file-name)
fb7933a3 2077 (file-local-copy . tramp-handle-file-local-copy)
19a87064 2078 (file-remote-p . tramp-handle-file-remote-p)
fb7933a3 2079 (insert-file-contents . tramp-handle-insert-file-contents)
94be87e8
MA
2080 (insert-file-contents-literally
2081 . tramp-handle-insert-file-contents-literally)
fb7933a3 2082 (write-region . tramp-handle-write-region)
38c65fca 2083 (find-backup-file-name . tramp-handle-find-backup-file-name)
c1105d05 2084 (make-auto-save-file-name . tramp-handle-make-auto-save-file-name)
fb7933a3 2085 (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
5ec2cc41 2086 (dired-compress-file . tramp-handle-dired-compress-file)
fb7933a3
KG
2087 (dired-recursive-delete-directory
2088 . tramp-handle-dired-recursive-delete-directory)
70c11b0b 2089 (dired-uncache . tramp-handle-dired-uncache)
fb7933a3 2090 (set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
49096407 2091 (verify-visited-file-modtime . tramp-handle-verify-visited-file-modtime)
20b8ac83
MA
2092 (file-selinux-context . tramp-handle-file-selinux-context)
2093 (set-file-selinux-context . tramp-handle-set-file-selinux-context)
49096407 2094 (vc-registered . tramp-handle-vc-registered))
c1105d05 2095 "Alist of handler functions.
fb7933a3
KG
2096Operations not mentioned here will be handled by the normal Emacs functions.")
2097
a4aeb9a4 2098;; Handlers for partial Tramp file names. For Emacs just
41c8e348 2099;; `file-name-all-completions' is needed.
a01b1e22 2100;;;###autoload
16674e4f 2101(defconst tramp-completion-file-name-handler-alist
a01b1e22 2102 '((file-name-all-completions . tramp-completion-handle-file-name-all-completions)
41c8e348 2103 (file-name-completion . tramp-completion-handle-file-name-completion))
16674e4f
KG
2104 "Alist of completion handler functions.
2105Used for file names matching `tramp-file-name-regexp'. Operations not
2106mentioned here will be handled by `tramp-file-name-handler-alist' or the
2107normal Emacs functions.")
2108
4007ba5b 2109;; Handlers for foreign methods, like FTP or SMB, shall be plugged here.
ea9d1443
KG
2110(defvar tramp-foreign-file-name-handler-alist
2111 ;; (identity . tramp-sh-file-name-handler) should always be the last
b88f2d0a 2112 ;; entry, because `identity' always matches.
ea9d1443 2113 '((identity . tramp-sh-file-name-handler))
4007ba5b
KG
2114 "Alist of elements (FUNCTION . HANDLER) for foreign methods handled specially.
2115If (FUNCTION FILENAME) returns non-nil, then all I/O on that file is done by
2116calling HANDLER.")
2117
0664ff72 2118;;; Internal functions which must come first:
fb7933a3 2119
00d6fd04
MA
2120(defsubst tramp-debug-message (vec fmt-string &rest args)
2121 "Append message to debug buffer.
2122Message is formatted with FMT-STRING as control string and the remaining
2123ARGS to actually emit the message (if applicable)."
2124 (when (get-buffer (tramp-buffer-name vec))
2125 (with-current-buffer (tramp-get-debug-buffer vec)
2126 (goto-char (point-max))
70c11b0b
MA
2127 ;; Headline.
2128 (when (bobp)
2129 (insert
2130 (format
2131 ";; %sEmacs: %s Tramp: %s -*- mode: outline; -*-"
2132 (if (featurep 'sxemacs) "SX" (if (featurep 'xemacs) "X" "GNU "))
2133 emacs-version tramp-version)))
00d6fd04
MA
2134 (unless (bolp)
2135 (insert "\n"))
70c11b0b 2136 ;; Timestamp.
736ac90f
MA
2137 (let ((now (current-time)))
2138 (insert (format-time-string "%T." now))
2139 (insert (format "%06d " (nth 2 now))))
70c11b0b 2140 ;; Calling function.
00d6fd04
MA
2141 (let ((btn 1) btf fn)
2142 (while (not fn)
2143 (setq btf (nth 1 (backtrace-frame btn)))
2144 (if (not btf)
2145 (setq fn "")
2146 (when (symbolp btf)
2147 (setq fn (symbol-name btf))
2148 (unless (and (string-match "^tramp" fn)
2149 (not (string-match
20b8ac83 2150 "^tramp\\(-debug\\)?\\(-message\\|-error\\|-compat-funcall\\)$"
00d6fd04
MA
2151 fn)))
2152 (setq fn nil)))
2153 (setq btn (1+ btn))))
2154 ;; The following code inserts filename and line number.
2155 ;; Should be deactivated by default, because it is time
2156 ;; consuming.
2157; (let ((ffn (find-function-noselect (intern fn))))
2158; (insert
2159; (format
2160; "%s:%d: "
2161; (file-name-nondirectory (buffer-file-name (car ffn)))
2162; (with-current-buffer (car ffn)
2163; (1+ (count-lines (point-min) (cdr ffn)))))))
2164 (insert (format "%s " fn)))
70c11b0b 2165 ;; The message.
00d6fd04
MA
2166 (insert (apply 'format fmt-string args)))))
2167
946a5aeb
MA
2168(defvar tramp-message-show-message t
2169 "Show Tramp message in the minibuffer.
2170This variable is used to disable messages from `tramp-error'.
2171The messages are visible anyway, because an error is raised.")
2172
00d6fd04 2173(defsubst tramp-message (vec-or-proc level fmt-string &rest args)
fb7933a3 2174 "Emit a message depending on verbosity level.
a4aeb9a4 2175VEC-OR-PROC identifies the Tramp buffer to use. It can be either a
00d6fd04
MA
2176vector or a process. LEVEL says to be quiet if `tramp-verbose' is
2177less than LEVEL. The message is emitted only if `tramp-verbose' is
2178greater than or equal to LEVEL.
2179
2180The message is also logged into the debug buffer when `tramp-verbose'
2181is greater than or equal 4.
2182
2183Calls functions `message' and `tramp-debug-message' with FMT-STRING as
2184control string and the remaining ARGS to actually emit the message (if
2185applicable)."
2186 (condition-case nil
2187 (when (<= level tramp-verbose)
2188 ;; Match data must be preserved!
2189 (save-match-data
2190 ;; Display only when there is a minimum level.
946a5aeb 2191 (when (and tramp-message-show-message (<= level 3))
00d6fd04
MA
2192 (apply 'message
2193 (concat
2194 (cond
2195 ((= level 0) "")
2196 ((= level 1) "")
2197 ((= level 2) "Warning: ")
2198 (t "Tramp: "))
2199 fmt-string)
2200 args))
2201 ;; Log only when there is a minimum level.
2202 (when (>= tramp-verbose 4)
2203 (when (and vec-or-proc
2204 (processp vec-or-proc)
2205 (buffer-name (process-buffer vec-or-proc)))
2206 (with-current-buffer (process-buffer vec-or-proc)
2207 ;; Translate proc to vec.
2208 (setq vec-or-proc (tramp-dissect-file-name default-directory))))
2209 (when (and vec-or-proc (vectorp vec-or-proc))
2210 (apply 'tramp-debug-message
2211 vec-or-proc
2212 (concat (format "(%d) # " level) fmt-string)
2213 args)))))
2214 ;; Suppress all errors.
2215 (error nil)))
2216
2217(defsubst tramp-error (vec-or-proc signal fmt-string &rest args)
2218 "Emit an error.
2219VEC-OR-PROC identifies the connection to use, SIGNAL is the
2220signal identifier to be raised, remaining args passed to
2221`tramp-message'. Finally, signal SIGNAL is raised."
946a5aeb
MA
2222 (let (tramp-message-show-message)
2223 (tramp-message
2224 vec-or-proc 1 "%s"
2225 (error-message-string
2226 (list signal
2227 (get signal 'error-message)
2228 (apply 'format fmt-string args))))
2229 (signal signal (list (apply 'format fmt-string args)))))
00d6fd04
MA
2230
2231(defsubst tramp-error-with-buffer
2232 (buffer vec-or-proc signal fmt-string &rest args)
2233 "Emit an error, and show BUFFER.
2234If BUFFER is nil, show the connection buffer. Wait for 30\", or until
2235an input event arrives. The other arguments are passed to `tramp-error'."
2236 (save-window-excursion
2237 (unwind-protect
2238 (apply 'tramp-error vec-or-proc signal fmt-string args)
20b8ac83
MA
2239 (when (and vec-or-proc
2240 (not (zerop tramp-verbose))
2241 (not (tramp-completion-mode-p)))
00d6fd04
MA
2242 (let ((enable-recursive-minibuffers t))
2243 (pop-to-buffer
2244 (or (and (bufferp buffer) buffer)
2245 (and (processp vec-or-proc) (process-buffer vec-or-proc))
2246 (tramp-get-buffer vec-or-proc)))
2247 (sit-for 30))))))
fb7933a3 2248
c62c9d08
KG
2249(defmacro with-parsed-tramp-file-name (filename var &rest body)
2250 "Parse a Tramp filename and make components available in the body.
2251
2252First arg FILENAME is evaluated and dissected into its components.
2253Second arg VAR is a symbol. It is used as a variable name to hold
2254the filename structure. It is also used as a prefix for the variables
2255holding the components. For example, if VAR is the symbol `foo', then
00d6fd04
MA
2256`foo' will be bound to the whole structure, `foo-method' will be bound to
2257the method component, and so on for `foo-user', `foo-host', `foo-localname'.
c62c9d08
KG
2258
2259Remaining args are Lisp expressions to be evaluated (inside an implicit
2260`progn').
2261
00d6fd04
MA
2262If VAR is nil, then we bind `v' to the structure and `method', `user',
2263`host', `localname' to the components."
c62c9d08 2264 `(let* ((,(or var 'v) (tramp-dissect-file-name ,filename))
c62c9d08
KG
2265 (,(if var (intern (concat (symbol-name var) "-method")) 'method)
2266 (tramp-file-name-method ,(or var 'v)))
2267 (,(if var (intern (concat (symbol-name var) "-user")) 'user)
2268 (tramp-file-name-user ,(or var 'v)))
2269 (,(if var (intern (concat (symbol-name var) "-host")) 'host)
2270 (tramp-file-name-host ,(or var 'v)))
7432277c
KG
2271 (,(if var (intern (concat (symbol-name var) "-localname")) 'localname)
2272 (tramp-file-name-localname ,(or var 'v))))
c62c9d08
KG
2273 ,@body))
2274
2275(put 'with-parsed-tramp-file-name 'lisp-indent-function 2)
00d6fd04 2276(put 'with-parsed-tramp-file-name 'edebug-form-spec '(form symbolp body))
9e6ab520 2277(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-parsed-tramp-file-name\\>"))
c62c9d08 2278
00d6fd04
MA
2279(defmacro with-file-property (vec file property &rest body)
2280 "Check in Tramp cache for PROPERTY, otherwise execute BODY and set cache.
2281FILE must be a local file name on a connection identified via VEC."
2282 `(if (file-name-absolute-p ,file)
2283 (let ((value (tramp-get-file-property ,vec ,file ,property 'undef)))
2284 (when (eq value 'undef)
2285 ;; We cannot pass @body as parameter to
2286 ;; `tramp-set-file-property' because it mangles our
2287 ;; debug messages.
2288 (setq value (progn ,@body))
2289 (tramp-set-file-property ,vec ,file ,property value))
2290 value)
2291 ,@body))
9ce8462a 2292
00d6fd04
MA
2293(put 'with-file-property 'lisp-indent-function 3)
2294(put 'with-file-property 'edebug-form-spec t)
9e6ab520 2295(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-file-property\\>"))
00d6fd04
MA
2296
2297(defmacro with-connection-property (key property &rest body)
20b8ac83 2298 "Check in Tramp for property PROPERTY, otherwise executes BODY and set."
00d6fd04
MA
2299 `(let ((value (tramp-get-connection-property ,key ,property 'undef)))
2300 (when (eq value 'undef)
2301 ;; We cannot pass ,@body as parameter to
2302 ;; `tramp-set-connection-property' because it mangles our debug
2303 ;; messages.
2304 (setq value (progn ,@body))
2305 (tramp-set-connection-property ,key ,property value))
2306 value))
9ce8462a 2307
00d6fd04
MA
2308(put 'with-connection-property 'lisp-indent-function 2)
2309(put 'with-connection-property 'edebug-form-spec t)
9e6ab520 2310(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-connection-property\\>"))
00d6fd04 2311
20b8ac83
MA
2312(defun tramp-progress-reporter-update (reporter &optional value)
2313 (let* ((parameters (cdr reporter))
2314 (message (aref parameters 3)))
2315 (when (string-match message (or (current-message) ""))
6efb972c 2316 (tramp-compat-funcall 'progress-reporter-update reporter value))))
20b8ac83
MA
2317
2318(defmacro with-progress-reporter (vec level message &rest body)
2319 "Executes BODY, spinning a progress reporter with MESSAGE.
2320If LEVEL does not fit for visible messages, or if this is a
2321nested call of the macro, there are only traces without a visible
2322progress reporter."
2323 `(let (pr tm)
2324 (tramp-message ,vec ,level "%s..." ,message)
2325 ;; We start a pulsing progress reporter after 3 seconds. Feature
2326 ;; introduced in Emacs 24.1.
2327 (when (and tramp-message-show-message
2328 ;; Display only when there is a minimum level.
2329 (<= ,level (min tramp-verbose 3)))
2330 (condition-case nil
2331 (setq pr (tramp-compat-funcall 'make-progress-reporter ,message)
2332 tm (when pr
2333 (run-at-time 3 0.1 'tramp-progress-reporter-update pr)))
2334 (error nil)))
2335 (unwind-protect
2336 ;; Execute the body. Unset `tramp-message-show-message' when
2337 ;; the timer object is created, in order to suppress
2338 ;; concurrent timers.
2339 (let ((tramp-message-show-message
2340 (and tramp-message-show-message (not tm))))
2341 ,@body)
2342 ;; Stop progress reporter.
2343 (if tm (tramp-compat-funcall 'cancel-timer tm))
2344 (tramp-message ,vec ,level "%s...done" ,message))))
2345
2346(put 'with-progress-reporter 'lisp-indent-function 3)
2347(put 'with-progress-reporter 'edebug-form-spec t)
2348(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-progress-reporter\\>"))
2349
2350(eval-and-compile ;; Silence compiler.
628c97b2
GM
2351 (if (memq system-type '(cygwin windows-nt))
2352 (defun tramp-drop-volume-letter (name)
2353 "Cut off unnecessary drive letter from file NAME.
2354The function `tramp-handle-expand-file-name' calls `expand-file-name'
2355locally on a remote file name. When the local system is a W32 system
2356but the remote system is Unix, this introduces a superfluous drive
2357letter into the file name. This function removes it."
2358 (save-match-data
2359 (if (string-match tramp-root-regexp name)
2360 (replace-match "/" nil t name)
2361 name)))
2362
2363 (defalias 'tramp-drop-volume-letter 'identity)))
2364
9c13938d 2365(defsubst tramp-make-tramp-temp-file (vec)
a6e96327 2366 "Create a temporary file on the remote host identified by VEC.
9c13938d
MA
2367Return the local name of the temporary file."
2368 (let ((prefix
2369 (tramp-make-tramp-file-name
2370 (tramp-file-name-method vec)
2371 (tramp-file-name-user vec)
2372 (tramp-file-name-host vec)
113e2a84
MA
2373 (tramp-drop-volume-letter
2374 (expand-file-name
2375 tramp-temp-name-prefix (tramp-get-remote-tmpdir vec)))))
9c13938d
MA
2376 result)
2377 (while (not result)
2378 ;; `make-temp-file' would be the natural choice for
2379 ;; implementation. But it calls `write-region' internally,
2380 ;; which also needs a temporary file - we would end in an
2381 ;; infinite loop.
2382 (setq result (make-temp-name prefix))
2383 (if (file-exists-p result)
2384 (setq result nil)
2385 ;; This creates the file by side effect.
2386 (set-file-times result)
2387 (set-file-modes result (tramp-octal-to-decimal "0700"))))
2388
2389 ;; Return the local part.
2390 (with-parsed-tramp-file-name result nil localname)))
8a4438b6
MA
2391
2392
16674e4f
KG
2393;;; Config Manipulation Functions:
2394
2395(defun tramp-set-completion-function (method function-list)
2396 "Sets the list of completion functions for METHOD.
2397FUNCTION-LIST is a list of entries of the form (FUNCTION FILE).
2398The FUNCTION is intended to parse FILE according its syntax.
2399It might be a predefined FUNCTION, or a user defined FUNCTION.
2400Predefined FUNCTIONs are `tramp-parse-rhosts', `tramp-parse-shosts',
8fc29035 2401`tramp-parse-sconfig', `tramp-parse-hosts', `tramp-parse-passwd',
8daea7fc
KG
2402and `tramp-parse-netrc'.
2403
16674e4f
KG
2404Example:
2405
2406 (tramp-set-completion-function
2407 \"ssh\"
8daea7fc
KG
2408 '((tramp-parse-sconfig \"/etc/ssh_config\")
2409 (tramp-parse-sconfig \"~/.ssh/config\")))"
16674e4f 2410
5ec2cc41
KG
2411 (let ((r function-list)
2412 (v function-list))
2413 (setq tramp-completion-function-alist
2414 (delete (assoc method tramp-completion-function-alist)
2415 tramp-completion-function-alist))
2416
2417 (while v
00d6fd04 2418 ;; Remove double entries.
5ec2cc41
KG
2419 (when (member (car v) (cdr v))
2420 (setcdr v (delete (car v) (cdr v))))
00d6fd04 2421 ;; Check for function and file or registry key.
5ec2cc41 2422 (unless (and (functionp (nth 0 (car v)))
00d6fd04
MA
2423 (if (string-match "^HKEY_CURRENT_USER" (nth 1 (car v)))
2424 ;; Windows registry.
2425 (and (memq system-type '(cygwin windows-nt))
a4aeb9a4
MA
2426 (zerop
2427 (tramp-local-call-process
2428 "reg" nil nil nil "query" (nth 1 (car v)))))
00d6fd04
MA
2429 ;; Configuration file.
2430 (file-exists-p (nth 1 (car v)))))
5ec2cc41
KG
2431 (setq r (delete (car v) r)))
2432 (setq v (cdr v)))
2433
2434 (when r
4007ba5b 2435 (add-to-list 'tramp-completion-function-alist
5ec2cc41 2436 (cons method r)))))
16674e4f
KG
2437
2438(defun tramp-get-completion-function (method)
00d6fd04 2439 "Returns a list of completion functions for METHOD.
16674e4f 2440For definition of that list see `tramp-set-completion-function'."
00d6fd04
MA
2441 (cons
2442 ;; Hosts visited once shall be remembered.
2443 `(tramp-parse-connection-properties ,method)
2444 ;; The method related defaults.
2445 (cdr (assoc method tramp-completion-function-alist))))
16674e4f 2446
d037d501 2447
0664ff72 2448;;; Fontification of `read-file-name':
d037d501 2449
0664ff72 2450;; rfn-eshadow.el is part of Emacs 22. It is autoloaded.
d037d501
MA
2451(defvar tramp-rfn-eshadow-overlay)
2452(make-variable-buffer-local 'tramp-rfn-eshadow-overlay)
2453
2454(defun tramp-rfn-eshadow-setup-minibuffer ()
2455 "Set up a minibuffer for `file-name-shadow-mode'.
2456Adds another overlay hiding filename parts according to Tramp's
2457special handling of `substitute-in-file-name'."
9ce8462a 2458 (when (symbol-value 'minibuffer-completing-file-name)
d037d501 2459 (setq tramp-rfn-eshadow-overlay
20b8ac83
MA
2460 (tramp-compat-funcall
2461 'make-overlay
2462 (tramp-compat-funcall 'minibuffer-prompt-end)
2463 (tramp-compat-funcall 'minibuffer-prompt-end)))
d037d501 2464 ;; Copy rfn-eshadow-overlay properties.
20b8ac83
MA
2465 (let ((props (tramp-compat-funcall
2466 'overlay-properties (symbol-value 'rfn-eshadow-overlay))))
d037d501 2467 (while props
20b8ac83
MA
2468 (tramp-compat-funcall
2469 'overlay-put tramp-rfn-eshadow-overlay (pop props) (pop props))))))
d037d501
MA
2470
2471(when (boundp 'rfn-eshadow-setup-minibuffer-hook)
2472 (add-hook 'rfn-eshadow-setup-minibuffer-hook
48846dc5
MA
2473 'tramp-rfn-eshadow-setup-minibuffer)
2474 (add-hook 'tramp-unload-hook
aa485f7c
MA
2475 (lambda ()
2476 (remove-hook 'rfn-eshadow-setup-minibuffer-hook
2477 'tramp-rfn-eshadow-setup-minibuffer))))
d037d501 2478
adcbca53
MA
2479(defconst tramp-rfn-eshadow-update-overlay-regexp
2480 (format "[^%s/~]*\\(/\\|~\\)" tramp-postfix-host-format))
2481
d037d501
MA
2482(defun tramp-rfn-eshadow-update-overlay ()
2483 "Update `rfn-eshadow-overlay' to cover shadowed part of minibuffer input.
2484This is intended to be used as a minibuffer `post-command-hook' for
2485`file-name-shadow-mode'; the minibuffer should have already
2486been set up by `rfn-eshadow-setup-minibuffer'."
2487 ;; In remote files name, there is a shadowing just for the local part.
20b8ac83
MA
2488 (let ((end (or (tramp-compat-funcall
2489 'overlay-end (symbol-value 'rfn-eshadow-overlay))
2490 (tramp-compat-funcall 'minibuffer-prompt-end))))
2491 (when
2492 (file-remote-p
2493 (tramp-compat-funcall 'buffer-substring-no-properties end (point-max)))
bd316474
KY
2494 (save-excursion
2495 (save-restriction
2496 (narrow-to-region
adcbca53
MA
2497 (1+ (or (string-match
2498 tramp-rfn-eshadow-update-overlay-regexp (buffer-string) end)
2499 end))
2500 (point-max))
bd316474
KY
2501 (let ((rfn-eshadow-overlay tramp-rfn-eshadow-overlay)
2502 (rfn-eshadow-update-overlay-hook nil))
20b8ac83
MA
2503 (tramp-compat-funcall
2504 'move-overlay rfn-eshadow-overlay (point-max) (point-max))
2505 (tramp-compat-funcall 'rfn-eshadow-update-overlay)))))))
d037d501
MA
2506
2507(when (boundp 'rfn-eshadow-update-overlay-hook)
2508 (add-hook 'rfn-eshadow-update-overlay-hook
b88f2d0a
MA
2509 'tramp-rfn-eshadow-update-overlay)
2510 (add-hook 'tramp-unload-hook
2511 (lambda ()
2512 (remove-hook 'rfn-eshadow-update-overlay-hook
2513 'tramp-rfn-eshadow-update-overlay))))
d037d501
MA
2514
2515
605a20a9
MA
2516;;; Integration of eshell.el:
2517
2518(eval-when-compile
2519 (defvar eshell-path-env))
2520
2521;; eshell.el keeps the path in `eshell-path-env'. We must change it
2522;; when `default-directory' points to another host.
2523(defun tramp-eshell-directory-change ()
2524 "Set `eshell-path-env' to $PATH of the host related to `default-directory'."
2525 (setq eshell-path-env
2526 (if (file-remote-p default-directory)
2527 (with-parsed-tramp-file-name default-directory nil
2528 (mapconcat
2529 'identity
2530 (tramp-get-remote-path v)
2531 ":"))
2532 (getenv "PATH"))))
2533
2534(eval-after-load "esh-util"
2535 '(progn
2536 (tramp-eshell-directory-change)
2537 (add-hook 'eshell-directory-change-hook
2538 'tramp-eshell-directory-change)
2539 (add-hook 'tramp-unload-hook
2540 (lambda ()
2541 (remove-hook 'eshell-directory-change-hook
2542 'tramp-eshell-directory-change)))))
2543
2544
fb7933a3
KG
2545;;; File Name Handler Functions:
2546
fb7933a3
KG
2547(defun tramp-handle-make-symbolic-link
2548 (filename linkname &optional ok-if-already-exists)
00d6fd04 2549 "Like `make-symbolic-link' for Tramp files.
cebb4ec6 2550If LINKNAME is a non-Tramp file, it is used verbatim as the target of
7432277c 2551the symlink. If LINKNAME is a Tramp file, only the localname component is
cebb4ec6
KG
2552used as the target of the symlink.
2553
7432277c
KG
2554If LINKNAME is a Tramp file and the localname component is relative, then
2555it is expanded first, before the localname component is taken. Note that
cebb4ec6
KG
2556this can give surprising results if the user/host for the source and
2557target of the symlink differ."
c62c9d08 2558 (with-parsed-tramp-file-name linkname l
00d6fd04 2559 (let ((ln (tramp-get-remote-ln l))
87bdd2c7
MA
2560 (cwd (tramp-run-real-handler
2561 'file-name-directory (list l-localname))))
c62c9d08 2562 (unless ln
00d6fd04
MA
2563 (tramp-error
2564 l 'file-error
20b8ac83 2565 "Making a symbolic link. ln(1) does not exist on the remote host."))
c62c9d08
KG
2566
2567 ;; Do the 'confirm if exists' thing.
cebb4ec6 2568 (when (file-exists-p linkname)
c62c9d08
KG
2569 ;; What to do?
2570 (if (or (null ok-if-already-exists) ; not allowed to exist
2571 (and (numberp ok-if-already-exists)
2572 (not (yes-or-no-p
2573 (format
2574 "File %s already exists; make it a link anyway? "
7432277c 2575 l-localname)))))
00d6fd04
MA
2576 (tramp-error
2577 l 'file-already-exists "File %s already exists" l-localname)
cebb4ec6
KG
2578 (delete-file linkname)))
2579
7432277c 2580 ;; If FILENAME is a Tramp name, use just the localname component.
cebb4ec6 2581 (when (tramp-tramp-file-p filename)
1834b39f
MA
2582 (setq filename
2583 (tramp-file-name-localname
2584 (tramp-dissect-file-name (expand-file-name filename)))))
bf247b6e 2585
20b8ac83
MA
2586 (tramp-flush-file-property l (file-name-directory l-localname))
2587 (tramp-flush-file-property l l-localname)
2588
c62c9d08
KG
2589 ;; Right, they are on the same host, regardless of user, method, etc.
2590 ;; We now make the link on the remote machine. This will occur as the user
2591 ;; that FILENAME belongs to.
2592 (zerop
2593 (tramp-send-command-and-check
b593f105
MA
2594 l
2595 (format
2596 "cd %s && %s -sf %s %s"
2597 (tramp-shell-quote-argument cwd)
2598 ln
2599 (tramp-shell-quote-argument filename)
2600 (tramp-shell-quote-argument l-localname))
2601 t)))))
fb7933a3 2602
fb7933a3 2603(defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix)
00d6fd04
MA
2604 "Like `load' for Tramp files."
2605 (with-parsed-tramp-file-name (expand-file-name file) nil
c62c9d08
KG
2606 (unless nosuffix
2607 (cond ((file-exists-p (concat file ".elc"))
2608 (setq file (concat file ".elc")))
2609 ((file-exists-p (concat file ".el"))
2610 (setq file (concat file ".el")))))
2611 (when must-suffix
2612 ;; The first condition is always true for absolute file names.
2613 ;; Included for safety's sake.
2614 (unless (or (file-name-directory file)
2615 (string-match "\\.elc?\\'" file))
00d6fd04
MA
2616 (tramp-error
2617 v 'file-error
2618 "File `%s' does not include a `.el' or `.elc' suffix" file)))
c62c9d08
KG
2619 (unless noerror
2620 (when (not (file-exists-p file))
00d6fd04 2621 (tramp-error v 'file-error "Cannot load nonexistent file `%s'" file)))
c62c9d08
KG
2622 (if (not (file-exists-p file))
2623 nil
20b8ac83
MA
2624 (let ((tramp-message-show-message (not nomessage)))
2625 (with-progress-reporter v 0 (format "Loading %s" file)
2626 (let ((local-copy (file-local-copy file)))
2627 ;; MUST-SUFFIX doesn't exist on XEmacs, so let it default to nil.
2628 (unwind-protect
2629 (load local-copy noerror t t)
2630 (delete-file local-copy)))))
c62c9d08 2631 t)))
fb7933a3 2632
a4aeb9a4 2633;; Localname manipulation functions that grok Tramp localnames...
c0fc6170
MA
2634(defun tramp-handle-file-name-as-directory (file)
2635 "Like `file-name-as-directory' but aware of Tramp files."
2636 ;; `file-name-as-directory' would be sufficient except localname is
2637 ;; the empty string.
2638 (let ((v (tramp-dissect-file-name file t)))
2639 ;; Run the command on the localname portion only.
2640 (tramp-make-tramp-file-name
2641 (tramp-file-name-method v)
2642 (tramp-file-name-user v)
2643 (tramp-file-name-host v)
2644 (tramp-run-real-handler
2645 'file-name-as-directory (list (or (tramp-file-name-localname v) ""))))))
2646
fb7933a3 2647(defun tramp-handle-file-name-directory (file)
00d6fd04 2648 "Like `file-name-directory' but aware of Tramp files."
9ce8462a
MA
2649 ;; Everything except the last filename thing is the directory. We
2650 ;; cannot apply `with-parsed-tramp-file-name', because this expands
2651 ;; the remote file name parts. This is a problem when we are in
2652 ;; file name completion.
2653 (let ((v (tramp-dissect-file-name file t)))
a01b1e22
MA
2654 ;; Run the command on the localname portion only.
2655 (tramp-make-tramp-file-name
9ce8462a
MA
2656 (tramp-file-name-method v)
2657 (tramp-file-name-user v)
2658 (tramp-file-name-host v)
87bdd2c7
MA
2659 (tramp-run-real-handler
2660 'file-name-directory (list (or (tramp-file-name-localname v) ""))))))
fb7933a3
KG
2661
2662(defun tramp-handle-file-name-nondirectory (file)
00d6fd04 2663 "Like `file-name-nondirectory' but aware of Tramp files."
c62c9d08 2664 (with-parsed-tramp-file-name file nil
87bdd2c7 2665 (tramp-run-real-handler 'file-name-nondirectory (list localname))))
fb7933a3
KG
2666
2667(defun tramp-handle-file-truename (filename &optional counter prev-dirs)
00d6fd04 2668 "Like `file-truename' for Tramp files."
48ddd622 2669 (with-parsed-tramp-file-name (expand-file-name filename) nil
00d6fd04 2670 (with-file-property v localname "file-truename"
293c24f9 2671 (let ((result nil)) ; result steps in reverse order
00d6fd04 2672 (tramp-message v 4 "Finding true name for `%s'" filename)
293c24f9
MA
2673 (cond
2674 ;; Use GNU readlink --canonicalize-missing where available.
2675 ((tramp-get-remote-readlink v)
2676 (setq result
2677 (tramp-send-command-and-read
2678 v
2679 (format "echo \"\\\"`%s --canonicalize-missing %s`\\\"\""
2680 (tramp-get-remote-readlink v)
2681 (tramp-shell-quote-argument localname)))))
2682
2683 ;; Use Perl implementation.
2684 ((and (tramp-get-remote-perl v)
2685 (tramp-get-connection-property v "perl-file-spec" nil)
2686 (tramp-get-connection-property v "perl-cwd-realpath" nil))
2687 (tramp-maybe-send-script
2688 v tramp-perl-file-truename "tramp_perl_file_truename")
2689 (setq result
2690 (tramp-send-command-and-read
2691 v
2692 (format "tramp_perl_file_truename %s"
2693 (tramp-shell-quote-argument localname)))))
2694
2695 ;; Do it yourself. We bind `directory-sep-char' here for
2696 ;; XEmacs on Windows, which would otherwise use backslash.
2697 (t (let* ((directory-sep-char ?/)
2698 (steps (tramp-compat-split-string localname "/"))
2699 (localnamedir (tramp-run-real-handler
2700 'file-name-as-directory (list localname)))
2701 (is-dir (string= localname localnamedir))
2702 (thisstep nil)
2703 (numchase 0)
2704 ;; Don't make the following value larger than
2705 ;; necessary. People expect an error message in a
2706 ;; timely fashion when something is wrong;
2707 ;; otherwise they might think that Emacs is hung.
2708 ;; Of course, correctness has to come first.
2709 (numchase-limit 20)
2710 symlink-target)
2711 (while (and steps (< numchase numchase-limit))
2712 (setq thisstep (pop steps))
2713 (tramp-message
2714 v 5 "Check %s"
2715 (mapconcat 'identity
2716 (append '("") (reverse result) (list thisstep))
2717 "/"))
2718 (setq symlink-target
2719 (nth 0 (file-attributes
2720 (tramp-make-tramp-file-name
2721 method user host
2722 (mapconcat 'identity
2723 (append '("")
2724 (reverse result)
2725 (list thisstep))
2726 "/")))))
2727 (cond ((string= "." thisstep)
2728 (tramp-message v 5 "Ignoring step `.'"))
2729 ((string= ".." thisstep)
2730 (tramp-message v 5 "Processing step `..'")
2731 (pop result))
2732 ((stringp symlink-target)
2733 ;; It's a symlink, follow it.
2734 (tramp-message v 5 "Follow symlink to %s" symlink-target)
2735 (setq numchase (1+ numchase))
2736 (when (file-name-absolute-p symlink-target)
2737 (setq result nil))
2738 ;; If the symlink was absolute, we'll get a string like
2739 ;; "/user@host:/some/target"; extract the
2740 ;; "/some/target" part from it.
2741 (when (tramp-tramp-file-p symlink-target)
2742 (unless (tramp-equal-remote filename symlink-target)
2743 (tramp-error
2744 v 'file-error
2745 "Symlink target `%s' on wrong host" symlink-target))
2746 (setq symlink-target localname))
2747 (setq steps
2748 (append (tramp-compat-split-string
2749 symlink-target "/")
2750 steps)))
2751 (t
2752 ;; It's a file.
2753 (setq result (cons thisstep result)))))
2754 (when (>= numchase numchase-limit)
2755 (tramp-error
2756 v 'file-error
2757 "Maximum number (%d) of symlinks exceeded" numchase-limit))
2758 (setq result (reverse result))
2759 ;; Combine list to form string.
2760 (setq result
2761 (if result
2762 (mapconcat 'identity (cons "" result) "/")
00d6fd04 2763 "/"))
293c24f9
MA
2764 (when (and is-dir (or (string= "" result)
2765 (not (string= (substring result -1) "/"))))
2766 (setq result (concat result "/"))))))
2767
2768 (tramp-message v 4 "True name of `%s' is `%s'" filename result)
2769 (tramp-make-tramp-file-name method user host result)))))
fb7933a3
KG
2770
2771;; Basic functions.
2772
2773(defun tramp-handle-file-exists-p (filename)
00d6fd04 2774 "Like `file-exists-p' for Tramp files."
c62c9d08 2775 (with-parsed-tramp-file-name filename nil
00d6fd04 2776 (with-file-property v localname "file-exists-p"
293c24f9
MA
2777 (or (not (null (tramp-get-file-property
2778 v localname "file-attributes-integer" nil)))
2779 (not (null (tramp-get-file-property
2780 v localname "file-attributes-string" nil)))
2781 (zerop (tramp-send-command-and-check
2782 v
2783 (format
2784 "%s %s"
2785 (tramp-get-file-exists-command v)
2786 (tramp-shell-quote-argument localname))))))))
fb7933a3 2787
00d6fd04
MA
2788;; Inodes don't exist for some file systems. Therefore we must
2789;; generate virtual ones. Used in `find-buffer-visiting'. The method
2790;; applied might be not so efficient (Ange-FTP uses hashes). But
2791;; performance isn't the major issue given that file transfer will
2792;; take time.
2793(defvar tramp-inodes nil
2794 "Keeps virtual inodes numbers.")
2795
8daea7fc
KG
2796;; Devices must distinguish physical file systems. The device numbers
2797;; provided by "lstat" aren't unique, because we operate on different hosts.
2798;; So we use virtual device numbers, generated by Tramp. Both Ange-FTP and
2799;; EFS use device number "-1". In order to be different, we use device number
b946a456 2800;; (-1 . x), whereby "x" is unique for a given (method user host).
8daea7fc
KG
2801(defvar tramp-devices nil
2802 "Keeps virtual device numbers.")
2803
fb7933a3
KG
2804;; CCC: This should check for an error condition and signal failure
2805;; when something goes wrong.
2806;; Daniel Pittman <daniel@danann.net>
c951aecb 2807(defun tramp-handle-file-attributes (filename &optional id-format)
00d6fd04
MA
2808 "Like `file-attributes' for Tramp files."
2809 (unless id-format (setq id-format 'integer))
aa485f7c
MA
2810 ;; Don't modify `last-coding-system-used' by accident.
2811 (let ((last-coding-system-used last-coding-system-used))
2812 (with-parsed-tramp-file-name (expand-file-name filename) nil
2813 (with-file-property v localname (format "file-attributes-%s" id-format)
7f49fe46
MA
2814 (save-excursion
2815 (tramp-convert-file-attributes
2816 v
2817 (cond
2818 ((tramp-get-remote-stat v)
2819 (tramp-do-file-attributes-with-stat v localname id-format))
2820 ((tramp-get-remote-perl v)
2821 (tramp-do-file-attributes-with-perl v localname id-format))
2822 (t
2823 (tramp-do-file-attributes-with-ls v localname id-format)))))))))
2824
2825(defun tramp-do-file-attributes-with-ls (vec localname &optional id-format)
00d6fd04 2826 "Implement `file-attributes' for Tramp files using the ls(1) command."
fb7933a3
KG
2827 (let (symlinkp dirp
2828 res-inode res-filemodes res-numlinks
2829 res-uid res-gid res-size res-symlink-target)
00d6fd04 2830 (tramp-message vec 5 "file attributes with ls: %s" localname)
fb7933a3 2831 (tramp-send-command
00d6fd04 2832 vec
680db9ac
MA
2833 (format "(%s %s || %s -h %s) && %s %s %s"
2834 (tramp-get-file-exists-command vec)
2835 (tramp-shell-quote-argument localname)
2836 (tramp-get-test-command vec)
2837 (tramp-shell-quote-argument localname)
00d6fd04 2838 (tramp-get-ls-command vec)
c82c5727 2839 (if (eq id-format 'integer) "-ildn" "-ild")
7432277c 2840 (tramp-shell-quote-argument localname)))
fb7933a3 2841 ;; parse `ls -l' output ...
00d6fd04 2842 (with-current-buffer (tramp-get-buffer vec)
680db9ac
MA
2843 (when (> (buffer-size) 0)
2844 (goto-char (point-min))
2845 ;; ... inode
2846 (setq res-inode
2847 (condition-case err
2848 (read (current-buffer))
2849 (invalid-read-syntax
2850 (when (and (equal (cadr err)
2851 "Integer constant overflow in reader")
2852 (string-match
2853 "^[0-9]+\\([0-9][0-9][0-9][0-9][0-9]\\)\\'"
2854 (car (cddr err))))
2855 (let* ((big (read (substring (car (cddr err)) 0
2856 (match-beginning 1))))
2857 (small (read (match-string 1 (car (cddr err)))))
2858 (twiddle (/ small 65536)))
2859 (cons (+ big twiddle)
2860 (- small (* twiddle 65536))))))))
2861 ;; ... file mode flags
2862 (setq res-filemodes (symbol-name (read (current-buffer))))
2863 ;; ... number links
2864 (setq res-numlinks (read (current-buffer)))
2865 ;; ... uid and gid
2866 (setq res-uid (read (current-buffer)))
2867 (setq res-gid (read (current-buffer)))
2868 (if (eq id-format 'integer)
2869 (progn
2870 (unless (numberp res-uid) (setq res-uid -1))
2871 (unless (numberp res-gid) (setq res-gid -1)))
2872 (progn
2873 (unless (stringp res-uid) (setq res-uid (symbol-name res-uid)))
2874 (unless (stringp res-gid) (setq res-gid (symbol-name res-gid)))))
2875 ;; ... size
2876 (setq res-size (read (current-buffer)))
2877 ;; From the file modes, figure out other stuff.
2878 (setq symlinkp (eq ?l (aref res-filemodes 0)))
2879 (setq dirp (eq ?d (aref res-filemodes 0)))
2880 ;; if symlink, find out file name pointed to
2881 (when symlinkp
2882 (search-forward "-> ")
2883 (setq res-symlink-target
2884 (buffer-substring (point) (tramp-compat-line-end-position))))
2885 ;; return data gathered
2886 (list
2887 ;; 0. t for directory, string (name linked to) for symbolic
2888 ;; link, or nil.
2889 (or dirp res-symlink-target)
2890 ;; 1. Number of links to file.
2891 res-numlinks
2892 ;; 2. File uid.
2893 res-uid
2894 ;; 3. File gid.
2895 res-gid
2896 ;; 4. Last access time, as a list of two integers. First
2897 ;; integer has high-order 16 bits of time, second has low 16
2898 ;; bits.
2899 ;; 5. Last modification time, likewise.
2900 ;; 6. Last status change time, likewise.
2901 '(0 0) '(0 0) '(0 0) ;CCC how to find out?
2902 ;; 7. Size in bytes (-1, if number is out of range).
2903 res-size
2904 ;; 8. File modes, as a string of ten letters or dashes as in ls -l.
2905 res-filemodes
2906 ;; 9. t if file's gid would change if file were deleted and
2907 ;; recreated. Will be set in `tramp-convert-file-attributes'
2908 t
2909 ;; 10. inode number.
2910 res-inode
2911 ;; 11. Device number. Will be replaced by a virtual device number.
2912 -1
2913 )))))
fb7933a3 2914
7f49fe46 2915(defun tramp-do-file-attributes-with-perl
00d6fd04
MA
2916 (vec localname &optional id-format)
2917 "Implement `file-attributes' for Tramp files using a Perl script."
2918 (tramp-message vec 5 "file attributes with perl: %s" localname)
2919 (tramp-maybe-send-script
2920 vec tramp-perl-file-attributes "tramp_perl_file_attributes")
2921 (tramp-send-command-and-read
2922 vec
2923 (format "tramp_perl_file_attributes %s %s"
2924 (tramp-shell-quote-argument localname) id-format)))
2925
7f49fe46 2926(defun tramp-do-file-attributes-with-stat
00d6fd04
MA
2927 (vec localname &optional id-format)
2928 "Implement `file-attributes' for Tramp files using stat(1) command."
2929 (tramp-message vec 5 "file attributes with stat: %s" localname)
2930 (tramp-send-command-and-read
2931 vec
2932 (format
20b8ac83
MA
2933 ;; On Opsware, pdksh (which is the true name of ksh there) doesn't
2934 ;; parse correctly the sequence "((". Therefore, we add a space.
bca0f839 2935 "( (%s %s || %s -h %s) && %s -c '( (\"%%N\") %%h %s %s %%Xe0 %%Ye0 %%Ze0 %%se0 \"%%A\" t %%ie0 -1)' %s || echo nil)"
680db9ac
MA
2936 (tramp-get-file-exists-command vec)
2937 (tramp-shell-quote-argument localname)
2938 (tramp-get-test-command vec)
2939 (tramp-shell-quote-argument localname)
00d6fd04
MA
2940 (tramp-get-remote-stat vec)
2941 (if (eq id-format 'integer) "%u" "\"%U\"")
2942 (if (eq id-format 'integer) "%g" "\"%G\"")
2943 (tramp-shell-quote-argument localname))))
8daea7fc 2944
fb7933a3 2945(defun tramp-handle-set-visited-file-modtime (&optional time-list)
00d6fd04 2946 "Like `set-visited-file-modtime' for Tramp files."
fb7933a3
KG
2947 (unless (buffer-file-name)
2948 (error "Can't set-visited-file-modtime: buffer `%s' not visiting a file"
2949 (buffer-name)))
48ddd622
MA
2950 (if time-list
2951 (tramp-run-real-handler 'set-visited-file-modtime (list time-list))
11948172
MA
2952 (let ((f (buffer-file-name))
2953 coding-system-used)
48ddd622
MA
2954 (with-parsed-tramp-file-name f nil
2955 (let* ((attr (file-attributes f))
2956 ;; '(-1 65535) means file doesn't exists yet.
2957 (modtime (or (nth 5 attr) '(-1 65535))))
11948172
MA
2958 (when (boundp 'last-coding-system-used)
2959 (setq coding-system-used (symbol-value 'last-coding-system-used)))
48ddd622 2960 ;; We use '(0 0) as a don't-know value. See also
7f49fe46 2961 ;; `tramp-do-file-attributes-with-ls'.
48ddd622
MA
2962 (if (not (equal modtime '(0 0)))
2963 (tramp-run-real-handler 'set-visited-file-modtime (list modtime))
00d6fd04 2964 (progn
48ddd622 2965 (tramp-send-command
00d6fd04 2966 v
48ddd622 2967 (format "%s -ild %s"
00d6fd04 2968 (tramp-get-ls-command v)
48ddd622 2969 (tramp-shell-quote-argument localname)))
48ddd622
MA
2970 (setq attr (buffer-substring (point)
2971 (progn (end-of-line) (point)))))
00d6fd04
MA
2972 (tramp-set-file-property
2973 v localname "visited-file-modtime-ild" attr))
11948172
MA
2974 (when (boundp 'last-coding-system-used)
2975 (set 'last-coding-system-used coding-system-used))
d2a2c17f 2976 nil)))))
fb7933a3 2977
c62c9d08
KG
2978;; This function makes the same assumption as
2979;; `tramp-handle-set-visited-file-modtime'.
2980(defun tramp-handle-verify-visited-file-modtime (buf)
00d6fd04 2981 "Like `verify-visited-file-modtime' for Tramp files.
c08e6004
MA
2982At the time `verify-visited-file-modtime' calls this function, we
2983already know that the buffer is visiting a file and that
2984`visited-file-modtime' does not return 0. Do not call this
2985function directly, unless those two cases are already taken care
2986of."
c62c9d08 2987 (with-current-buffer buf
20b8ac83
MA
2988 (let ((f (buffer-file-name)))
2989 ;; There is no file visiting the buffer, or the buffer has no
2990 ;; recorded last modification time, or there is no established
2991 ;; connection.
2992 (if (or (not f)
2993 (eq (visited-file-modtime) 0)
2994 (not (tramp-file-name-handler 'file-remote-p f nil 'connected)))
2995 t
b15d0c4c 2996 (with-parsed-tramp-file-name f nil
bce04fee 2997 (tramp-flush-file-property v localname)
b15d0c4c
MA
2998 (let* ((attr (file-attributes f))
2999 (modtime (nth 5 attr))
3000 (mt (visited-file-modtime)))
bf247b6e 3001
70c11b0b
MA
3002 (cond
3003 ;; File exists, and has a known modtime.
b15d0c4c
MA
3004 ((and attr (not (equal modtime '(0 0))))
3005 (< (abs (tramp-time-diff
3006 modtime
3007 ;; For compatibility, deal with both the old
70c11b0b
MA
3008 ;; (HIGH . LOW) and the new (HIGH LOW) return
3009 ;; values of `visited-file-modtime'.
b15d0c4c
MA
3010 (if (atom (cdr mt))
3011 (list (car mt) (cdr mt))
3012 mt)))
3013 2))
70c11b0b 3014 ;; Modtime has the don't know value.
b15d0c4c 3015 (attr
00d6fd04
MA
3016 (tramp-send-command
3017 v
3018 (format "%s -ild %s"
3019 (tramp-get-ls-command v)
3020 (tramp-shell-quote-argument localname)))
3021 (with-current-buffer (tramp-get-buffer v)
b15d0c4c
MA
3022 (setq attr (buffer-substring
3023 (point) (progn (end-of-line) (point)))))
00d6fd04
MA
3024 (equal
3025 attr
3026 (tramp-get-file-property
3027 v localname "visited-file-modtime-ild" "")))
70c11b0b
MA
3028 ;; If file does not exist, say it is not modified if and
3029 ;; only if that agrees with the buffer's record.
b15d0c4c 3030 (t (equal mt '(-1 65535))))))))))
c62c9d08 3031
fb7933a3 3032(defun tramp-handle-set-file-modes (filename mode)
00d6fd04 3033 "Like `set-file-modes' for Tramp files."
c62c9d08 3034 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3035 (tramp-flush-file-property v localname)
3036 (unless (zerop (tramp-send-command-and-check
3037 v
3038 (format "chmod %s %s"
3039 (tramp-decimal-to-octal mode)
3040 (tramp-shell-quote-argument localname))))
3041 ;; FIXME: extract the proper text from chmod's stderr.
3042 (tramp-error
3043 v 'file-error "Error while changing file's mode %s" filename))))
fb7933a3 3044
ce3f516f
MA
3045(defun tramp-handle-set-file-times (filename &optional time)
3046 "Like `set-file-times' for Tramp files."
3047 (zerop
9e6ab520 3048 (if (file-remote-p filename)
ce3f516f 3049 (with-parsed-tramp-file-name filename nil
8d60099b 3050 (tramp-flush-file-property v localname)
ce3f516f
MA
3051 (let ((time (if (or (null time) (equal time '(0 0)))
3052 (current-time)
3053 time))
20b8ac83
MA
3054 ;; With GNU Emacs, `format-time-string' has an optional
3055 ;; parameter UNIVERSAL. This is preferred, because we
3056 ;; could handle the case when the remote host is
3057 ;; located in a different time zone as the local host.
3058 (utc (not (featurep 'xemacs))))
ce3f516f
MA
3059 (tramp-send-command-and-check
3060 v (format "%s touch -t %s %s"
3061 (if utc "TZ=UTC; export TZ;" "")
3062 (if utc
3063 (format-time-string "%Y%m%d%H%M.%S" time t)
3064 (format-time-string "%Y%m%d%H%M.%S" time))
3065 (tramp-shell-quote-argument localname)))))
8d60099b 3066
ce3f516f
MA
3067 ;; We handle also the local part, because in older Emacsen,
3068 ;; without `set-file-times', this function is an alias for this.
3069 ;; We are local, so we don't need the UTC settings.
a4aeb9a4 3070 (tramp-local-call-process
ce3f516f
MA
3071 "touch" nil nil nil "-t"
3072 (format-time-string "%Y%m%d%H%M.%S" time)
3073 (tramp-shell-quote-argument filename)))))
3074
8d60099b
MA
3075(defun tramp-set-file-uid-gid (filename &optional uid gid)
3076 "Set the ownership for FILENAME.
3077If UID and GID are provided, these values are used; otherwise uid
3078and gid of the corresponding user is taken. Both parameters must be integers."
70c11b0b
MA
3079 ;; Modern Unices allow chown only for root. So we might need
3080 ;; another implementation, see `dired-do-chown'. OTOH, it is mostly
3081 ;; working with su(do)? when it is needed, so it shall succeed in
3082 ;; the majority of cases.
aa485f7c
MA
3083 ;; Don't modify `last-coding-system-used' by accident.
3084 (let ((last-coding-system-used last-coding-system-used))
3085 (if (file-remote-p filename)
3086 (with-parsed-tramp-file-name filename nil
3087 (if (and (zerop (user-uid)) (tramp-local-host-p v))
3088 ;; If we are root on the local host, we can do it directly.
3089 (tramp-set-file-uid-gid localname uid gid)
3090 (let ((uid (or (and (integerp uid) uid)
3091 (tramp-get-remote-uid v 'integer)))
3092 (gid (or (and (integerp gid) gid)
3093 (tramp-get-remote-gid v 'integer))))
3094 (tramp-send-command
3095 v (format
3096 "chown %d:%d %s" uid gid
3097 (tramp-shell-quote-argument localname))))))
3098
3099 ;; We handle also the local part, because there doesn't exist
3100 ;; `set-file-uid-gid'. On W32 "chown" might not work.
3101 (let ((uid (or (and (integerp uid) uid) (tramp-get-local-uid 'integer)))
3102 (gid (or (and (integerp gid) gid) (tramp-get-local-gid 'integer))))
3103 (tramp-local-call-process
3104 "chown" nil nil nil
3105 (format "%d:%d" uid gid) (tramp-shell-quote-argument filename))))))
8d60099b 3106
20b8ac83
MA
3107(defun tramp-remote-selinux-p (vec)
3108 "Check, whether SELINUX is enabled on the remote host."
3109 (with-connection-property (tramp-get-connection-process vec) "selinux-p"
3110 (let ((result (tramp-find-executable
3111 vec "getenforce" (tramp-get-remote-path vec) t t)))
3112 (and result
3113 (string-equal
3114 (tramp-send-command-and-read
3115 vec (format "echo \\\"`%S`\\\"" result))
3116 "Enforcing")))))
3117
3118(defun tramp-handle-file-selinux-context (filename)
3119 "Like `file-selinux-context' for Tramp files."
3120 (with-parsed-tramp-file-name filename nil
3121 (with-file-property v localname "file-selinux-context"
3122 (let ((context '(nil nil nil nil))
3123 (regexp (concat "\\([a-z0-9_]+\\):" "\\([a-z0-9_]+\\):"
3124 "\\([a-z0-9_]+\\):" "\\([a-z0-9_]+\\)")))
3125 (when (and (tramp-remote-selinux-p v)
3126 (zerop (tramp-send-command-and-check
3127 v (format
3128 "%s -d -Z %s"
3129 (tramp-get-ls-command v)
3130 (tramp-shell-quote-argument localname)))))
3131 (with-current-buffer (tramp-get-connection-buffer v)
3132 (goto-char (point-min))
3133 (when (re-search-forward regexp (tramp-compat-line-end-position) t)
3134 (setq context (list (match-string 1) (match-string 2)
3135 (match-string 3) (match-string 4))))))
3136 ;; Return the context.
3137 context))))
3138
3139(defun tramp-handle-set-file-selinux-context (filename context)
3140 "Like `set-file-selinux-context' for Tramp files."
3141 (with-parsed-tramp-file-name filename nil
3142 (if (and (consp context)
3143 (tramp-remote-selinux-p v)
3144 (zerop (tramp-send-command-and-check
3145 v (format "chcon %s %s %s %s %s"
3146 (if (stringp (nth 0 context))
3147 (format "--user=%s" (nth 0 context)) "")
3148 (if (stringp (nth 1 context))
3149 (format "--role=%s" (nth 1 context)) "")
3150 (if (stringp (nth 2 context))
3151 (format "--type=%s" (nth 2 context)) "")
3152 (if (stringp (nth 3 context))
3153 (format "--range=%s" (nth 3 context)) "")
3154 (tramp-shell-quote-argument localname)))))
3155 (tramp-set-file-property v localname "file-selinux-context" context)
3156 (tramp-set-file-property v localname "file-selinux-context" 'undef)))
3157 ;; We always return nil.
3158 nil)
3159
fb7933a3
KG
3160;; Simple functions using the `test' command.
3161
3162(defun tramp-handle-file-executable-p (filename)
00d6fd04 3163 "Like `file-executable-p' for Tramp files."
c62c9d08 3164 (with-parsed-tramp-file-name filename nil
00d6fd04 3165 (with-file-property v localname "file-executable-p"
293c24f9
MA
3166 ;; Examine `file-attributes' cache to see if request can be
3167 ;; satisfied without remote operation.
3168 (or (tramp-check-cached-permissions v ?x)
3169 (zerop (tramp-run-test "-x" filename))))))
fb7933a3
KG
3170
3171(defun tramp-handle-file-readable-p (filename)
00d6fd04 3172 "Like `file-readable-p' for Tramp files."
c62c9d08 3173 (with-parsed-tramp-file-name filename nil
00d6fd04 3174 (with-file-property v localname "file-readable-p"
293c24f9
MA
3175 ;; Examine `file-attributes' cache to see if request can be
3176 ;; satisfied without remote operation.
3177 (or (tramp-check-cached-permissions v ?r)
3178 (zerop (tramp-run-test "-r" filename))))))
fb7933a3
KG
3179
3180;; When the remote shell is started, it looks for a shell which groks
3181;; tilde expansion. Here, we assume that all shells which grok tilde
3182;; expansion will also provide a `test' command which groks `-nt' (for
3183;; newer than). If this breaks, tell me about it and I'll try to do
3184;; something smarter about it.
3185(defun tramp-handle-file-newer-than-file-p (file1 file2)
00d6fd04 3186 "Like `file-newer-than-file-p' for Tramp files."
fb7933a3
KG
3187 (cond ((not (file-exists-p file1))
3188 nil)
3189 ((not (file-exists-p file2))
3190 t)
91879624 3191 ;; We are sure both files exist at this point.
fb7933a3
KG
3192 (t
3193 (save-excursion
91879624
KG
3194 ;; We try to get the mtime of both files. If they are not
3195 ;; equal to the "dont-know" value, then we subtract the times
3196 ;; and obtain the result.
3197 (let ((fa1 (file-attributes file1))
3198 (fa2 (file-attributes file2)))
3199 (if (and (not (equal (nth 5 fa1) '(0 0)))
3200 (not (equal (nth 5 fa2) '(0 0))))
01917a18 3201 (> 0 (tramp-time-diff (nth 5 fa2) (nth 5 fa1)))
91879624
KG
3202 ;; If one of them is the dont-know value, then we can
3203 ;; still try to run a shell command on the remote host.
3204 ;; However, this only works if both files are Tramp
3205 ;; files and both have the same method, same user, same
3206 ;; host.
00d6fd04
MA
3207 (unless (tramp-equal-remote file1 file2)
3208 (with-parsed-tramp-file-name
3209 (if (tramp-tramp-file-p file1) file1 file2) nil
3210 (tramp-error
3211 v 'file-error
3212 "Files %s and %s must have same method, user, host"
3213 file1 file2)))
3214 (with-parsed-tramp-file-name file1 nil
3215 (zerop (tramp-run-test2
3216 (tramp-get-test-nt-command v) file1 file2)))))))))
fb7933a3
KG
3217
3218;; Functions implemented using the basic functions above.
3219
3220(defun tramp-handle-file-modes (filename)
00d6fd04 3221 "Like `file-modes' for Tramp files."
5da24108
MA
3222 (let ((truename (or (file-truename filename) filename)))
3223 (when (file-exists-p truename)
3224 (tramp-mode-string-to-int (nth 8 (file-attributes truename))))))
fb7933a3 3225
b86c1cd8
MA
3226(defun tramp-default-file-modes (filename)
3227 "Return file modes of FILENAME as integer.
3228If the file modes of FILENAME cannot be determined, return the
974647ac
MA
3229value of `default-file-modes', without execute permissions."
3230 (or (file-modes filename)
3231 (logand (default-file-modes) (tramp-octal-to-decimal "0666"))))
b86c1cd8 3232
fb7933a3 3233(defun tramp-handle-file-directory-p (filename)
00d6fd04 3234 "Like `file-directory-p' for Tramp files."
fb7933a3
KG
3235 ;; Care must be taken that this function returns `t' for symlinks
3236 ;; pointing to directories. Surely the most obvious implementation
3237 ;; would be `test -d', but that returns false for such symlinks.
3238 ;; CCC: Stefan Monnier says that `test -d' follows symlinks. And
3239 ;; I now think he's right. So we could be using `test -d', couldn't
3240 ;; we?
3241 ;;
3242 ;; Alternatives: `cd %s', `test -d %s'
c62c9d08 3243 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3244 (with-file-property v localname "file-directory-p"
3245 (zerop (tramp-run-test "-d" filename)))))
fb7933a3
KG
3246
3247(defun tramp-handle-file-regular-p (filename)
00d6fd04
MA
3248 "Like `file-regular-p' for Tramp files."
3249 (and (file-exists-p filename)
3250 (eq ?- (aref (nth 8 (file-attributes filename)) 0))))
fb7933a3
KG
3251
3252(defun tramp-handle-file-symlink-p (filename)
00d6fd04 3253 "Like `file-symlink-p' for Tramp files."
c62c9d08 3254 (with-parsed-tramp-file-name filename nil
c951aecb 3255 (let ((x (car (file-attributes filename))))
b25a52cc
KG
3256 (when (stringp x)
3257 ;; When Tramp is running on VMS, then `file-name-absolute-p'
3258 ;; might do weird things.
3259 (if (file-name-absolute-p x)
00d6fd04 3260 (tramp-make-tramp-file-name method user host x)
b25a52cc 3261 x)))))
fb7933a3
KG
3262
3263(defun tramp-handle-file-writable-p (filename)
00d6fd04 3264 "Like `file-writable-p' for Tramp files."
c62c9d08 3265 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3266 (with-file-property v localname "file-writable-p"
3267 (if (file-exists-p filename)
293c24f9
MA
3268 ;; Examine `file-attributes' cache to see if request can be
3269 ;; satisfied without remote operation.
3270 (or (tramp-check-cached-permissions v ?w)
3271 (zerop (tramp-run-test "-w" filename)))
00d6fd04
MA
3272 ;; If file doesn't exist, check if directory is writable.
3273 (and (zerop (tramp-run-test
3274 "-d" (file-name-directory filename)))
3275 (zerop (tramp-run-test
3276 "-w" (file-name-directory filename))))))))
fb7933a3
KG
3277
3278(defun tramp-handle-file-ownership-preserved-p (filename)
00d6fd04 3279 "Like `file-ownership-preserved-p' for Tramp files."
c62c9d08 3280 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3281 (with-file-property v localname "file-ownership-preserved-p"
3282 (let ((attributes (file-attributes filename)))
3283 ;; Return t if the file doesn't exist, since it's true that no
3284 ;; information would be lost by an (attempted) delete and create.
3285 (or (null attributes)
3286 (= (nth 2 attributes) (tramp-get-remote-uid v 'integer)))))))
fb7933a3
KG
3287
3288;; Other file name ops.
3289
fb7933a3 3290(defun tramp-handle-directory-file-name (directory)
00d6fd04 3291 "Like `directory-file-name' for Tramp files."
7432277c
KG
3292 ;; If localname component of filename is "/", leave it unchanged.
3293 ;; Otherwise, remove any trailing slash from localname component.
8daea7fc
KG
3294 ;; Method, host, etc, are unchanged. Does it make sense to try
3295 ;; to avoid parsing the filename?
c62c9d08 3296 (with-parsed-tramp-file-name directory nil
7432277c
KG
3297 (if (and (not (zerop (length localname)))
3298 (eq (aref localname (1- (length localname))) ?/)
3299 (not (string= localname "/")))
8daea7fc
KG
3300 (substring directory 0 -1)
3301 directory)))
fb7933a3
KG
3302
3303;; Directory listings.
3304
00d6fd04
MA
3305(defun tramp-handle-directory-files
3306 (directory &optional full match nosort files-only)
3307 "Like `directory-files' for Tramp files."
3308 ;; FILES-ONLY is valid for XEmacs only.
3309 (when (file-directory-p directory)
73a37a69 3310 (setq directory (file-name-as-directory (expand-file-name directory)))
00d6fd04
MA
3311 (let ((temp (nreverse (file-name-all-completions "" directory)))
3312 result item)
3313
3314 (while temp
3315 (setq item (directory-file-name (pop temp)))
3316 (when (and (or (null match) (string-match match item))
3317 (or (null files-only)
73a37a69 3318 ;; Files only.
00d6fd04 3319 (and (equal files-only t) (file-regular-p item))
73a37a69 3320 ;; Directories only.
00d6fd04 3321 (file-directory-p item)))
73a37a69 3322 (push (if full (concat directory item) item)
00d6fd04 3323 result)))
73a37a69 3324 (if nosort result (sort result 'string<)))))
c62c9d08 3325
c82c5727
LH
3326(defun tramp-handle-directory-files-and-attributes
3327 (directory &optional full match nosort id-format)
00d6fd04
MA
3328 "Like `directory-files-and-attributes' for Tramp files."
3329 (unless id-format (setq id-format 'integer))
3330 (when (file-directory-p directory)
3331 (setq directory (expand-file-name directory))
3332 (let* ((temp
20b8ac83 3333 (copy-tree
00d6fd04
MA
3334 (with-parsed-tramp-file-name directory nil
3335 (with-file-property
3336 v localname
3337 (format "directory-files-and-attributes-%s" id-format)
3338 (save-excursion
3339 (mapcar
aa485f7c
MA
3340 (lambda (x)
3341 (cons (car x)
3342 (tramp-convert-file-attributes v (cdr x))))
7f49fe46
MA
3343 (cond
3344 ((tramp-get-remote-stat v)
3345 (tramp-do-directory-files-and-attributes-with-stat
3346 v localname id-format))
3347 ((tramp-get-remote-perl v)
3348 (tramp-do-directory-files-and-attributes-with-perl
3349 v localname id-format)))))))))
00d6fd04
MA
3350 result item)
3351
3352 (while temp
3353 (setq item (pop temp))
3354 (when (or (null match) (string-match match (car item)))
3355 (when full
3356 (setcar item (expand-file-name (car item) directory)))
3357 (push item result)))
3358
3359 (if nosort
3360 result
3361 (sort result (lambda (x y) (string< (car x) (car y))))))))
3362
7f49fe46 3363(defun tramp-do-directory-files-and-attributes-with-perl
00d6fd04
MA
3364 (vec localname &optional id-format)
3365 "Implement `directory-files-and-attributes' for Tramp files using a Perl script."
3366 (tramp-message vec 5 "directory-files-and-attributes with perl: %s" localname)
3367 (tramp-maybe-send-script
3368 vec tramp-perl-directory-files-and-attributes
3369 "tramp_perl_directory_files_and_attributes")
3370 (let ((object
3371 (tramp-send-command-and-read
3372 vec
3373 (format "tramp_perl_directory_files_and_attributes %s %s"
3374 (tramp-shell-quote-argument localname) id-format))))
3375 (when (stringp object) (tramp-error vec 'file-error object))
3376 object))
3377
7f49fe46 3378(defun tramp-do-directory-files-and-attributes-with-stat
00d6fd04
MA
3379 (vec localname &optional id-format)
3380 "Implement `directory-files-and-attributes' for Tramp files using stat(1) command."
3381 (tramp-message vec 5 "directory-files-and-attributes with stat: %s" localname)
3382 (tramp-send-command-and-read
3383 vec
3384 (format
3385 (concat
70c11b0b
MA
3386 ;; We must care about filenames with spaces, or starting with
3387 ;; "-"; this would confuse xargs. "ls -aQ" might be a solution,
3388 ;; but it does not work on all remote systems. Therefore, we
3389 ;; quote the filenames via sed.
3390 "cd %s; echo \"(\"; (%s -a | sed -e s/\\$/\\\"/g -e s/^/\\\"/g | xargs "
bca0f839 3391 "%s -c '(\"%%n\" (\"%%N\") %%h %s %s %%Xe0 %%Ye0 %%Ze0 %%se0 \"%%A\" t %%ie0 -1)'); "
00d6fd04
MA
3392 "echo \")\"")
3393 (tramp-shell-quote-argument localname)
3394 (tramp-get-ls-command vec)
3395 (tramp-get-remote-stat vec)
3396 (if (eq id-format 'integer) "%u" "\"%U\"")
3397 (if (eq id-format 'integer) "%g" "\"%G\""))))
c82c5727 3398
c62c9d08 3399;; This function should return "foo/" for directories and "bar" for
00d6fd04 3400;; files.
c62c9d08 3401(defun tramp-handle-file-name-all-completions (filename directory)
00d6fd04
MA
3402 "Like `file-name-all-completions' for Tramp files."
3403 (unless (save-match-data (string-match "/" filename))
9c13938d 3404 (with-parsed-tramp-file-name (expand-file-name directory) nil
b50dd0d2 3405
00d6fd04
MA
3406 (all-completions
3407 filename
3408 (mapcar
3409 'list
293c24f9
MA
3410 (or
3411 ;; Try cache first
3412 (and
3413 ;; Ignore if expired
3414 (or (not (integerp tramp-completion-reread-directory-timeout))
3415 (<= (tramp-time-diff
3416 (current-time)
3417 (tramp-get-file-property
3418 v localname "last-completion" '(0 0 0)))
3419 tramp-completion-reread-directory-timeout))
3420
3421 ;; Try cache entries for filename, filename with last
3422 ;; character removed, filename with last two characters
3423 ;; removed, ..., and finally the empty string - all
3424 ;; concatenated to the local directory name
3425
3426 ;; This is inefficient for very long filenames, pity
3427 ;; `reduce' is not available...
3428 (car
3429 (apply
3430 'append
3431 (mapcar
3432 (lambda (x)
3433 (let ((cache-hit
3434 (tramp-get-file-property
3435 v
3436 (concat localname (substring filename 0 x))
3437 "file-name-all-completions"
3438 nil)))
3439 (when cache-hit (list cache-hit))))
3440 (tramp-compat-number-sequence (length filename) 0 -1)))))
3441
3442 ;; Cache expired or no matching cache entry found so we need
3443 ;; to perform a remote operation
3444 (let (result)
3445 ;; Get a list of directories and files, including reliably
3446 ;; tagging the directories with a trailing '/'. Because I
3447 ;; rock. --daniel@danann.net
3448
3449 ;; Changed to perform `cd' in the same remote op and only
3450 ;; get entries starting with `filename'. Capture any `cd'
3451 ;; error messages. Ensure any `cd' and `echo' aliases are
3452 ;; ignored.
3453 (tramp-send-command
3454 v
3455 (if (tramp-get-remote-perl v)
3456 (progn
3457 (tramp-maybe-send-script
3458 v tramp-perl-file-name-all-completions
3459 "tramp_perl_file_name_all_completions")
3460 (format "tramp_perl_file_name_all_completions %s %s %d"
3461 (tramp-shell-quote-argument localname)
3462 (tramp-shell-quote-argument filename)
3463 (if (symbol-value
20b8ac83
MA
3464 ;; `read-file-name-completion-ignore-case'
3465 ;; is introduced with Emacs 22.1.
3466 (if (boundp
3467 'read-file-name-completion-ignore-case)
3468 'read-file-name-completion-ignore-case
3469 'completion-ignore-case))
293c24f9
MA
3470 1 0)))
3471
3472 (format (concat
3473 "(\\cd %s 2>&1 && (%s %s -a 2>/dev/null"
3474 ;; `ls' with wildcard might fail with `Argument
3475 ;; list too long' error in some corner cases; if
3476 ;; `ls' fails after `cd' succeeded, chances are
3477 ;; that's the case, so let's retry without
3478 ;; wildcard. This will return "too many" entries
3479 ;; but that isn't harmful.
3480 " || %s -a 2>/dev/null)"
3481 " | while read f; do"
3482 " if %s -d \"$f\" 2>/dev/null;"
3483 " then \\echo \"$f/\"; else \\echo \"$f\"; fi; done"
3484 " && \\echo ok) || \\echo fail")
3485 (tramp-shell-quote-argument localname)
3486 (tramp-get-ls-command v)
3487 ;; When `filename' is empty, just `ls' without
3488 ;; filename argument is more efficient than `ls *'
3489 ;; for very large directories and might avoid the
3490 ;; `Argument list too long' error.
3491 ;;
3492 ;; With and only with wildcard, we need to add
3493 ;; `-d' to prevent `ls' from descending into
3494 ;; sub-directories.
3495 (if (zerop (length filename))
3496 "."
3497 (concat (tramp-shell-quote-argument filename) "* -d"))
3498 (tramp-get-ls-command v)
3499 (tramp-get-test-command v))))
3500
3501 ;; Now grab the output.
3502 (with-current-buffer (tramp-get-buffer v)
3503 (goto-char (point-max))
3504
3505 ;; Check result code, found in last line of output
3506 (forward-line -1)
3507 (if (looking-at "^fail$")
3508 (progn
3509 ;; Grab error message from line before last line
3510 ;; (it was put there by `cd 2>&1')
3511 (forward-line -1)
3512 (tramp-error
3513 v 'file-error
3514 "tramp-handle-file-name-all-completions: %s"
3515 (buffer-substring
3516 (point) (tramp-compat-line-end-position))))
3517 ;; For peace of mind, if buffer doesn't end in `fail'
3518 ;; then it should end in `ok'. If neither are in the
3519 ;; buffer something went seriously wrong on the remote
3520 ;; side.
3521 (unless (looking-at "^ok$")
3522 (tramp-error
3523 v 'file-error
3524 "\
3525tramp-handle-file-name-all-completions: internal error accessing `%s': `%s'"
3526 (tramp-shell-quote-argument localname) (buffer-string))))
3527
3528 (while (zerop (forward-line -1))
3529 (push (buffer-substring
3530 (point) (tramp-compat-line-end-position))
3531 result)))
3532
3533 ;; Because the remote op went through OK we know the
3534 ;; directory we `cd'-ed to exists
3535 (tramp-set-file-property
3536 v localname "file-exists-p" t)
3537
3538 ;; Because the remote op went through OK we know every
3539 ;; file listed by `ls' exists.
3540 (mapc (lambda (entry)
3541 (tramp-set-file-property
3542 v (concat localname entry) "file-exists-p" t))
3543 result)
3544
3545 (tramp-set-file-property
3546 v localname "last-completion" (current-time))
3547
3548 ;; Store result in the cache
3549 (tramp-set-file-property
3550 v (concat localname filename)
3551 "file-name-all-completions"
3552 result))))))))
fb7933a3 3553
e1e17cae
MA
3554(defun tramp-handle-file-name-completion
3555 (filename directory &optional predicate)
00d6fd04 3556 "Like `file-name-completion' for Tramp files."
fb7933a3
KG
3557 (unless (tramp-tramp-file-p directory)
3558 (error
3559 "tramp-handle-file-name-completion invoked on non-tramp directory `%s'"
3560 directory))
83e20b5c
MA
3561 (try-completion
3562 filename
3563 (mapcar 'list (file-name-all-completions filename directory))
3564 (when predicate
3565 (lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
fb7933a3
KG
3566
3567;; cp, mv and ln
3568
3569(defun tramp-handle-add-name-to-file
3570 (filename newname &optional ok-if-already-exists)
00d6fd04
MA
3571 "Like `add-name-to-file' for Tramp files."
3572 (unless (tramp-equal-remote filename newname)
3573 (with-parsed-tramp-file-name
3574 (if (tramp-tramp-file-p filename) filename newname) nil
3575 (tramp-error
3576 v 'file-error
3577 "add-name-to-file: %s"
3578 "only implemented for same method, same user, same host")))
c62c9d08
KG
3579 (with-parsed-tramp-file-name filename v1
3580 (with-parsed-tramp-file-name newname v2
00d6fd04 3581 (let ((ln (when v1 (tramp-get-remote-ln v1))))
c62c9d08
KG
3582 (when (and (not ok-if-already-exists)
3583 (file-exists-p newname)
3584 (not (numberp ok-if-already-exists))
3585 (y-or-n-p
3586 (format
3587 "File %s already exists; make it a new name anyway? "
3588 newname)))
00d6fd04
MA
3589 (tramp-error
3590 v2 'file-error
3591 "add-name-to-file: file %s already exists" newname))
aac0b0f2 3592 (tramp-flush-file-property v2 (file-name-directory v2-localname))
00d6fd04 3593 (tramp-flush-file-property v2 v2-localname)
c62c9d08 3594 (tramp-barf-unless-okay
00d6fd04 3595 v1
7432277c
KG
3596 (format "%s %s %s" ln (tramp-shell-quote-argument v1-localname)
3597 (tramp-shell-quote-argument v2-localname))
c62c9d08
KG
3598 "error with add-name-to-file, see buffer `%s' for details"
3599 (buffer-name))))))
fb7933a3
KG
3600
3601(defun tramp-handle-copy-file
20b8ac83
MA
3602 (filename newname &optional ok-if-already-exists keep-date
3603 preserve-uid-gid preserve-selinux-context)
00d6fd04 3604 "Like `copy-file' for Tramp files."
fb7933a3
KG
3605 (setq filename (expand-file-name filename))
3606 (setq newname (expand-file-name newname))
9e6ab520 3607 (cond
a4aeb9a4 3608 ;; At least one file a Tramp file?
9e6ab520
MA
3609 ((or (tramp-tramp-file-p filename)
3610 (tramp-tramp-file-p newname))
3611 (tramp-do-copy-or-rename-file
20b8ac83
MA
3612 'copy filename newname ok-if-already-exists keep-date
3613 preserve-uid-gid preserve-selinux-context))
9e6ab520 3614 ;; Compat section.
20b8ac83
MA
3615 (preserve-selinux-context
3616 (tramp-run-real-handler
3617 'copy-file
3618 (list filename newname ok-if-already-exists keep-date
3619 preserve-uid-gid preserve-selinux-context)))
9e6ab520 3620 (preserve-uid-gid
fb7933a3 3621 (tramp-run-real-handler
8d60099b 3622 'copy-file
9e6ab520
MA
3623 (list filename newname ok-if-already-exists keep-date preserve-uid-gid)))
3624 (t
3625 (tramp-run-real-handler
3626 'copy-file (list filename newname ok-if-already-exists keep-date)))))
fb7933a3 3627
263c02ef
MA
3628(defun tramp-handle-copy-directory (dirname newname &optional keep-date parents)
3629 "Like `copy-directory' for Tramp files."
3630 (let ((t1 (tramp-tramp-file-p dirname))
3631 (t2 (tramp-tramp-file-p newname)))
3632 (with-parsed-tramp-file-name (if t1 dirname newname) nil
3633 (if (and (tramp-get-method-parameter method 'tramp-copy-recursive)
3634 ;; When DIRNAME and NEWNAME are remote, they must have
3635 ;; the same method.
3636 (or (null t1) (null t2)
b000a6e2
MA
3637 (string-equal
3638 (tramp-file-name-method (tramp-dissect-file-name dirname))
3639 (tramp-file-name-method (tramp-dissect-file-name newname)))))
263c02ef
MA
3640 ;; scp or rsync DTRT.
3641 (progn
3642 (setq dirname (directory-file-name (expand-file-name dirname))
3643 newname (directory-file-name (expand-file-name newname)))
3644 (if (and (file-directory-p newname)
3645 (not (string-equal (file-name-nondirectory dirname)
3646 (file-name-nondirectory newname))))
3647 (setq newname
3648 (expand-file-name
3649 (file-name-nondirectory dirname) newname)))
3650 (if (not (file-directory-p (file-name-directory newname)))
3651 (make-directory (file-name-directory newname) parents))
3652 (tramp-do-copy-or-rename-file-out-of-band
3653 'copy dirname newname keep-date))
3654 ;; We must do it file-wise.
3655 (tramp-run-real-handler
aac0b0f2
MA
3656 'copy-directory (list dirname newname keep-date parents)))
3657
3658 ;; When newname did exist, we have wrong cached values.
3659 (when t2
3660 (with-parsed-tramp-file-name newname nil
3661 (tramp-flush-file-property v (file-name-directory localname))
3662 (tramp-flush-file-property v localname))))))
263c02ef 3663
fb7933a3
KG
3664(defun tramp-handle-rename-file
3665 (filename newname &optional ok-if-already-exists)
00d6fd04 3666 "Like `rename-file' for Tramp files."
fb7933a3 3667 ;; Check if both files are local -- invoke normal rename-file.
a4aeb9a4 3668 ;; Otherwise, use Tramp from local system.
fb7933a3
KG
3669 (setq filename (expand-file-name filename))
3670 (setq newname (expand-file-name newname))
a4aeb9a4 3671 ;; At least one file a Tramp file?
fb7933a3
KG
3672 (if (or (tramp-tramp-file-p filename)
3673 (tramp-tramp-file-p newname))
3674 (tramp-do-copy-or-rename-file
8d60099b 3675 'rename filename newname ok-if-already-exists t t)
00d6fd04
MA
3676 (tramp-run-real-handler
3677 'rename-file (list filename newname ok-if-already-exists))))
fb7933a3
KG
3678
3679(defun tramp-do-copy-or-rename-file
20b8ac83
MA
3680 (op filename newname &optional ok-if-already-exists keep-date
3681 preserve-uid-gid preserve-selinux-context)
fb7933a3
KG
3682 "Copy or rename a remote file.
3683OP must be `copy' or `rename' and indicates the operation to perform.
3684FILENAME specifies the file to copy or rename, NEWNAME is the name of
3685the new file (for copy) or the new name of the file (for rename).
3686OK-IF-ALREADY-EXISTS means don't barf if NEWNAME exists already.
3687KEEP-DATE means to make sure that NEWNAME has the same timestamp
8d60099b
MA
3688as FILENAME. PRESERVE-UID-GID, when non-nil, instructs to keep
3689the uid and gid if both files are on the same host.
20b8ac83 3690PRESERVE-SELINUX-CONTEXT activates selinux commands.
fb7933a3
KG
3691
3692This function is invoked by `tramp-handle-copy-file' and
3693`tramp-handle-rename-file'. It is an error if OP is neither of `copy'
3694and `rename'. FILENAME and NEWNAME must be absolute file names."
3695 (unless (memq op '(copy rename))
3696 (error "Unknown operation `%s', must be `copy' or `rename'" op))
90dc758d 3697 (let ((t1 (tramp-tramp-file-p filename))
20b8ac83
MA
3698 (t2 (tramp-tramp-file-p newname))
3699 (context (and preserve-selinux-context
3700 (apply 'file-selinux-context (list filename))))
3701 pr tm)
5ec2cc41 3702
20b8ac83
MA
3703 (with-parsed-tramp-file-name (if t1 filename newname) nil
3704 (when (and (not ok-if-already-exists) (file-exists-p newname))
da1975d7 3705 (tramp-error
20b8ac83 3706 v 'file-already-exists "File %s already exists" newname))
5ec2cc41 3707
20b8ac83
MA
3708 (with-progress-reporter
3709 v 0 (format "%s %s to %s"
3710 (if (eq op 'copy) "Copying" "Renaming")
3711 filename newname)
905fb90e 3712
00d6fd04
MA
3713 (cond
3714 ;; Both are Tramp files.
3715 ((and t1 t2)
3716 (with-parsed-tramp-file-name filename v1
3717 (with-parsed-tramp-file-name newname v2
3718 (cond
20b8ac83
MA
3719 ;; Shortcut: if method, host, user are the same for
3720 ;; both files, we invoke `cp' or `mv' on the remote
3721 ;; host directly.
00d6fd04
MA
3722 ((tramp-equal-remote filename newname)
3723 (tramp-do-copy-or-rename-file-directly
8d60099b
MA
3724 op filename newname
3725 ok-if-already-exists keep-date preserve-uid-gid))
3726
905fb90e 3727 ;; Try out-of-band operation.
7f49fe46
MA
3728 ((tramp-method-out-of-band-p
3729 v1 (nth 7 (file-attributes filename)))
00d6fd04
MA
3730 (tramp-do-copy-or-rename-file-out-of-band
3731 op filename newname keep-date))
8d60099b 3732
20b8ac83
MA
3733 ;; No shortcut was possible. So we copy the file
3734 ;; first. If the operation was `rename', we go back
3735 ;; and delete the original file (if the copy was
00d6fd04
MA
3736 ;; successful). The approach is simple-minded: we
3737 ;; create a new buffer, insert the contents of the
3738 ;; source file into it, then write out the buffer to
3739 ;; the target file. The advantage is that it doesn't
3740 ;; matter which filename handlers are used for the
3741 ;; source and target file.
3742 (t
3743 (tramp-do-copy-or-rename-file-via-buffer
3744 op filename newname keep-date))))))
3745
3746 ;; One file is a Tramp file, the other one is local.
3747 ((or t1 t2)
20b8ac83
MA
3748 (cond
3749 ;; Fast track on local machine.
3750 ((tramp-local-host-p v)
3751 (tramp-do-copy-or-rename-file-directly
3752 op filename newname
3753 ok-if-already-exists keep-date preserve-uid-gid))
3754
3755 ;; If the Tramp file has an out-of-band method, the
3756 ;; corresponding copy-program can be invoked.
3757 ((tramp-method-out-of-band-p v (nth 7 (file-attributes filename)))
3758 (tramp-do-copy-or-rename-file-out-of-band
3759 op filename newname keep-date))
3760
3761 ;; Use the inline method via a Tramp buffer.
3762 (t (tramp-do-copy-or-rename-file-via-buffer
3763 op filename newname keep-date))))
00d6fd04
MA
3764
3765 (t
3766 ;; One of them must be a Tramp file.
3767 (error "Tramp implementation says this cannot happen")))
8d60099b 3768
20b8ac83
MA
3769 ;; Handle `preserve-selinux-context'.
3770 (when context (apply 'set-file-selinux-context (list newname context)))
484ea0b6 3771
20b8ac83
MA
3772 ;; In case of `rename', we must flush the cache of the source file.
3773 (when (and t1 (eq op 'rename))
3774 (with-parsed-tramp-file-name filename v1
3775 (tramp-flush-file-property v1 (file-name-directory localname))
3776 (tramp-flush-file-property v1 localname)))
905fb90e 3777
20b8ac83
MA
3778 ;; When newname did exist, we have wrong cached values.
3779 (when t2
3780 (with-parsed-tramp-file-name newname v2
3781 (tramp-flush-file-property v2 (file-name-directory localname))
3782 (tramp-flush-file-property v2 localname)))))))
7432277c 3783
38c65fca 3784(defun tramp-do-copy-or-rename-file-via-buffer (op filename newname keep-date)
90dc758d
KG
3785 "Use an Emacs buffer to copy or rename a file.
3786First arg OP is either `copy' or `rename' and indicates the operation.
3787FILENAME is the source file, NEWNAME the target file.
3788KEEP-DATE is non-nil if NEWNAME should have the same timestamp as FILENAME."
8a798e41
MA
3789 (with-temp-buffer
3790 ;; We must disable multibyte, because binary data shall not be
3791 ;; converted.
3792 (set-buffer-multibyte nil)
3793 (let ((coding-system-for-read 'binary)
3794 (jka-compr-inhibit t))
3795 (insert-file-contents-literally filename))
3796 ;; We don't want the target file to be compressed, so we let-bind
3797 ;; `jka-compr-inhibit' to t.
3798 (let ((coding-system-for-write 'binary)
3799 (jka-compr-inhibit t))
3800 (write-region (point-min) (point-max) newname)))
3801 ;; KEEP-DATE handling.
3802 (when keep-date (set-file-times newname (nth 5 (file-attributes filename))))
3803 ;; Set the mode.
b86c1cd8 3804 (set-file-modes newname (tramp-default-file-modes filename))
8a798e41
MA
3805 ;; If the operation was `rename', delete the original file.
3806 (unless (eq op 'copy) (delete-file filename)))
fb7933a3
KG
3807
3808(defun tramp-do-copy-or-rename-file-directly
8d60099b 3809 (op filename newname ok-if-already-exists keep-date preserve-uid-gid)
fb7933a3
KG
3810 "Invokes `cp' or `mv' on the remote system.
3811OP must be one of `copy' or `rename', indicating `cp' or `mv',
8d60099b
MA
3812respectively. FILENAME specifies the file to copy or rename,
3813NEWNAME is the name of the new file (for copy) or the new name of
3814the file (for rename). Both files must reside on the same host.
3815KEEP-DATE means to make sure that NEWNAME has the same timestamp
3816as FILENAME. PRESERVE-UID-GID, when non-nil, instructs to keep
3817the uid and gid from FILENAME."
8a4438b6 3818 (let ((t1 (tramp-tramp-file-p filename))
4f4126e6
MA
3819 (t2 (tramp-tramp-file-p newname))
3820 (file-times (nth 5 (file-attributes filename)))
3821 (file-modes (tramp-default-file-modes filename)))
8a4438b6
MA
3822 (with-parsed-tramp-file-name (if t1 filename newname) nil
3823 (let* ((cmd (cond ((and (eq op 'copy) preserve-uid-gid) "cp -f -p")
3824 ((eq op 'copy) "cp -f")
3825 ((eq op 'rename) "mv -f")
3826 (t (tramp-error
3827 v 'file-error
3828 "Unknown operation `%s', must be `copy' or `rename'"
3829 op))))
3830 (localname1
20b8ac83
MA
3831 (if t1
3832 (tramp-file-name-handler 'file-remote-p filename 'localname)
3833 filename))
8a4438b6 3834 (localname2
20b8ac83
MA
3835 (if t2
3836 (tramp-file-name-handler 'file-remote-p newname 'localname)
3837 newname))
293c24f9
MA
3838 (prefix (file-remote-p (if t1 filename newname)))
3839 cmd-result)
8d60099b 3840
8d60099b 3841 (cond
8a4438b6
MA
3842 ;; Both files are on a remote host, with same user.
3843 ((and t1 t2)
293c24f9
MA
3844 (setq cmd-result
3845 (tramp-send-command-and-check
3846 v
3847 (format "%s %s %s" cmd
3848 (tramp-shell-quote-argument localname1)
3849 (tramp-shell-quote-argument localname2))))
8a4438b6
MA
3850 (with-current-buffer (tramp-get-buffer v)
3851 (goto-char (point-min))
3852 (unless
3853 (or
3854 (and keep-date
3855 ;; Mask cp -f error.
3856 (re-search-forward
3857 tramp-operation-not-permitted-regexp nil t))
293c24f9 3858 (zerop cmd-result))
8a4438b6
MA
3859 (tramp-error-with-buffer
3860 nil v 'file-error
3861 "Copying directly failed, see buffer `%s' for details."
3862 (buffer-name)))))
3863
3864 ;; We are on the local host.
3865 ((or t1 t2)
8d60099b 3866 (cond
8a4438b6 3867 ;; We can do it directly.
87bdd2c7
MA
3868 ((let (file-name-handler-alist)
3869 (and (file-readable-p localname1)
3870 (file-writable-p (file-name-directory localname2))
3871 (or (file-directory-p localname2)
3872 (file-writable-p localname2))))
8d60099b 3873 (if (eq op 'copy)
9e6ab520
MA
3874 (tramp-compat-copy-file
3875 localname1 localname2 ok-if-already-exists
3876 keep-date preserve-uid-gid)
87bdd2c7
MA
3877 (tramp-run-real-handler
3878 'rename-file (list localname1 localname2 ok-if-already-exists))))
8a4438b6
MA
3879
3880 ;; We can do it directly with `tramp-send-command'
946a5aeb
MA
3881 ((and (file-readable-p (concat prefix localname1))
3882 (file-writable-p
3883 (file-name-directory (concat prefix localname2)))
3884 (or (file-directory-p (concat prefix localname2))
3885 (file-writable-p (concat prefix localname2))))
8a4438b6
MA
3886 (tramp-do-copy-or-rename-file-directly
3887 op (concat prefix localname1) (concat prefix localname2)
3888 ok-if-already-exists keep-date t)
3889 ;; We must change the ownership to the local user.
8d60099b 3890 (tramp-set-file-uid-gid
8a4438b6
MA
3891 (concat prefix localname2)
3892 (tramp-get-local-uid 'integer)
3893 (tramp-get-local-gid 'integer)))
8d60099b 3894
8a4438b6
MA
3895 ;; We need a temporary file in between.
3896 (t
2c418c5b
MA
3897 ;; Create the temporary file.
3898 (let ((tmpfile (tramp-compat-make-temp-file localname1)))
917b89a6 3899 (unwind-protect
2c418c5b
MA
3900 (progn
3901 (cond
3902 (t1
917b89a6
MA
3903 (or
3904 (zerop
3905 (tramp-send-command-and-check
3906 v (format
3907 "%s %s %s" cmd
3908 (tramp-shell-quote-argument localname1)
3909 (tramp-shell-quote-argument tmpfile))))
3910 (tramp-error-with-buffer
3911 nil v 'file-error
3912 "Copying directly failed, see buffer `%s' for details."
3913 (tramp-get-buffer v)))
2c418c5b 3914 ;; We must change the ownership as remote user.
917b89a6
MA
3915 ;; Since this does not work reliable, we also
3916 ;; give read permissions.
3917 (set-file-modes
3918 (concat prefix tmpfile) (tramp-octal-to-decimal "0777"))
2c418c5b
MA
3919 (tramp-set-file-uid-gid
3920 (concat prefix tmpfile)
3921 (tramp-get-local-uid 'integer)
3922 (tramp-get-local-gid 'integer)))
3923 (t2
3924 (if (eq op 'copy)
3925 (tramp-compat-copy-file
5ab38c3c 3926 localname1 tmpfile t
2c418c5b
MA
3927 keep-date preserve-uid-gid)
3928 (tramp-run-real-handler
3929 'rename-file
5ab38c3c 3930 (list localname1 tmpfile t)))
2c418c5b 3931 ;; We must change the ownership as local user.
917b89a6
MA
3932 ;; Since this does not work reliable, we also
3933 ;; give read permissions.
3934 (set-file-modes tmpfile (tramp-octal-to-decimal "0777"))
2c418c5b
MA
3935 (tramp-set-file-uid-gid
3936 tmpfile
3937 (tramp-get-remote-uid v 'integer)
3938 (tramp-get-remote-gid v 'integer))))
3939
3940 ;; Move the temporary file to its destination.
3941 (cond
3942 (t2
917b89a6
MA
3943 (or
3944 (zerop
3945 (tramp-send-command-and-check
3946 v (format
3947 "cp -f -p %s %s"
3948 (tramp-shell-quote-argument tmpfile)
3949 (tramp-shell-quote-argument localname2))))
3950 (tramp-error-with-buffer
3951 nil v 'file-error
3952 "Copying directly failed, see buffer `%s' for details."
3953 (tramp-get-buffer v))))
2c418c5b 3954 (t1
ce2cc728
MA
3955 (tramp-run-real-handler
3956 'rename-file
2c418c5b
MA
3957 (list tmpfile localname2 ok-if-already-exists)))))
3958
917b89a6
MA
3959 ;; Save exit.
3960 (condition-case nil
3961 (delete-file tmpfile)
3962 (error)))))))))
8d60099b
MA
3963
3964 ;; Set the time and mode. Mask possible errors.
8d60099b 3965 (condition-case nil
1f107aed 3966 (when keep-date
4f4126e6
MA
3967 (set-file-times newname file-times)
3968 (set-file-modes newname file-modes))
8d60099b
MA
3969 (error)))))
3970
5ec2cc41 3971(defun tramp-do-copy-or-rename-file-out-of-band (op filename newname keep-date)
7432277c 3972 "Invoke rcp program to copy.
905fb90e 3973The method used must be an out-of-band method."
38c65fca 3974 (let ((t1 (tramp-tramp-file-p filename))
5ec2cc41 3975 (t2 (tramp-tramp-file-p newname))
946a5aeb 3976 copy-program copy-args copy-env copy-keep-date port spec
00d6fd04
MA
3977 source target)
3978
3979 (with-parsed-tramp-file-name (if t1 filename newname) nil
905fb90e 3980 (if (and t1 t2)
00d6fd04 3981
905fb90e
MA
3982 ;; Both are Tramp files. We shall optimize it, when the
3983 ;; methods for filename and newname are the same.
9cf3544e
MA
3984 (let* ((dir-flag (file-directory-p filename))
3985 (tmpfile (tramp-compat-make-temp-file localname dir-flag)))
3986 (if dir-flag
3987 (setq tmpfile
3988 (expand-file-name
3989 (file-name-nondirectory newname) tmpfile)))
905fb90e
MA
3990 (unwind-protect
3991 (progn
3992 (tramp-do-copy-or-rename-file-out-of-band
3993 op filename tmpfile keep-date)
3994 (tramp-do-copy-or-rename-file-out-of-band
3995 'rename tmpfile newname keep-date))
3996 ;; Save exit.
3997 (condition-case nil
9cf3544e 3998 (if dir-flag
20b8ac83 3999 (tramp-compat-delete-directory
9cf3544e
MA
4000 (expand-file-name ".." tmpfile) 'recursive)
4001 (delete-file tmpfile))
905fb90e
MA
4002 (error))))
4003
4004 ;; Expand hops. Might be necessary for gateway methods.
4005 (setq v (car (tramp-compute-multi-hops v)))
4006 (aset v 3 localname)
4007
4008 ;; Check which ones of source and target are Tramp files.
4009 (setq source (if t1 (tramp-make-copy-program-file-name v) filename)
263c02ef
MA
4010 target (funcall
4011 (if (and (file-directory-p filename)
4012 (string-equal
4013 (file-name-nondirectory filename)
4014 (file-name-nondirectory newname)))
4015 'file-name-directory
4016 'identity)
4017 (if t2 (tramp-make-copy-program-file-name v) newname)))
905fb90e
MA
4018
4019 ;; Check for port number. Until now, there's no need for handling
4020 ;; like method, user, host.
4021 (setq host (tramp-file-name-real-host v)
4022 port (tramp-file-name-port v)
4023 port (or (and port (number-to-string port)) ""))
4024
4025 ;; Compose copy command.
20b8ac83
MA
4026 (setq spec (format-spec-make
4027 ?h host ?u user ?p port
4028 ?t (tramp-get-connection-property
4029 (tramp-get-connection-process v) "temp-file" "")
4030 ?k (if keep-date " " ""))
905fb90e
MA
4031 copy-program (tramp-get-method-parameter
4032 method 'tramp-copy-program)
4033 copy-keep-date (tramp-get-method-parameter
4034 method 'tramp-copy-keep-date)
4035 copy-args
4036 (delq
4037 nil
4038 (mapcar
aa485f7c
MA
4039 (lambda (x)
4040 (setq
4041 x
4042 ;; " " is indication for keep-date argument.
4043 (delete " " (mapcar (lambda (y) (format-spec y spec)) x)))
4044 (unless (member "" x) (mapconcat 'identity x " ")))
946a5aeb
MA
4045 (tramp-get-method-parameter method 'tramp-copy-args)))
4046 copy-env
4047 (delq
4048 nil
4049 (mapcar
aa485f7c
MA
4050 (lambda (x)
4051 (setq x (mapcar (lambda (y) (format-spec y spec)) x))
4052 (unless (member "" x) (mapconcat 'identity x " ")))
946a5aeb 4053 (tramp-get-method-parameter method 'tramp-copy-env))))
905fb90e
MA
4054
4055 ;; Check for program.
4056 (when (and (fboundp 'executable-find)
4057 (not (let ((default-directory
4058 (tramp-compat-temporary-file-directory)))
4059 (executable-find copy-program))))
4060 (tramp-error
4061 v 'file-error "Cannot find copy program: %s" copy-program))
00d6fd04 4062
4265deab
MA
4063 ;; Set variables for computing the prompt for reading
4064 ;; password.
4065 (setq tramp-current-method (tramp-file-name-method v)
4066 tramp-current-user (tramp-file-name-user v)
4067 tramp-current-host (tramp-file-name-host v))
4068
905fb90e
MA
4069 (unwind-protect
4070 (with-temp-buffer
4071 ;; The default directory must be remote.
4072 (let ((default-directory
946a5aeb
MA
4073 (file-name-directory (if t1 filename newname)))
4074 (process-environment (copy-sequence process-environment)))
905fb90e
MA
4075 ;; Set the transfer process properties.
4076 (tramp-set-connection-property
4077 v "process-name" (buffer-name (current-buffer)))
4078 (tramp-set-connection-property
4079 v "process-buffer" (current-buffer))
946a5aeb
MA
4080 (while copy-env
4081 (tramp-message v 5 "%s=\"%s\"" (car copy-env) (cadr copy-env))
4082 (setenv (pop copy-env) (pop copy-env)))
905fb90e
MA
4083
4084 ;; Use an asynchronous process. By this, password can
4085 ;; be handled. The default directory must be local, in
4086 ;; order to apply the correct `copy-program'. We don't
4087 ;; set a timeout, because the copying of large files can
4088 ;; last longer than 60 secs.
4089 (let ((p (let ((default-directory
4090 (tramp-compat-temporary-file-directory)))
4091 (apply 'start-process
4092 (tramp-get-connection-property
4093 v "process-name" nil)
4094 (tramp-get-connection-property
4095 v "process-buffer" nil)
4096 copy-program
4097 (append copy-args (list source target))))))
4098 (tramp-message
4099 v 6 "%s" (mapconcat 'identity (process-command p) " "))
4100 (tramp-set-process-query-on-exit-flag p nil)
4101 (tramp-process-actions p v tramp-actions-copy-out-of-band))))
00d6fd04 4102
905fb90e
MA
4103 ;; Reset the transfer process properties.
4104 (tramp-set-connection-property v "process-name" nil)
4105 (tramp-set-connection-property v "process-buffer" nil))
00d6fd04 4106
905fb90e
MA
4107 ;; Handle KEEP-DATE argument.
4108 (when (and keep-date (not copy-keep-date))
4109 (set-file-times newname (nth 5 (file-attributes filename))))
01917a18 4110
905fb90e
MA
4111 ;; Set the mode.
4112 (unless (and keep-date copy-keep-date)
459a5f4b
MA
4113 (ignore-errors
4114 (set-file-modes newname (tramp-default-file-modes filename)))))
5ec2cc41 4115
905fb90e
MA
4116 ;; If the operation was `rename', delete the original file.
4117 (unless (eq op 'copy)
aac0b0f2
MA
4118 (if (file-regular-p filename)
4119 (delete-file filename)
20b8ac83 4120 (tramp-compat-delete-directory filename 'recursive))))))
7432277c 4121
fb7933a3 4122(defun tramp-handle-make-directory (dir &optional parents)
00d6fd04 4123 "Like `make-directory' for Tramp files."
ac474af1 4124 (setq dir (expand-file-name dir))
c62c9d08 4125 (with-parsed-tramp-file-name dir nil
c15cdf02 4126 (tramp-flush-directory-property v (file-name-directory localname))
b1d06e75
KG
4127 (save-excursion
4128 (tramp-barf-unless-okay
00d6fd04 4129 v
9c13938d 4130 (format "%s %s"
b1d06e75 4131 (if parents "mkdir -p" "mkdir")
7432277c 4132 (tramp-shell-quote-argument localname))
b1d06e75 4133 "Couldn't make directory %s" dir))))
fb7933a3 4134
c15cdf02 4135(defun tramp-handle-delete-directory (directory &optional recursive)
00d6fd04 4136 "Like `delete-directory' for Tramp files."
ac474af1 4137 (setq directory (expand-file-name directory))
c62c9d08 4138 (with-parsed-tramp-file-name directory nil
aac0b0f2 4139 (tramp-flush-file-property v (file-name-directory localname))
00d6fd04
MA
4140 (tramp-flush-directory-property v localname)
4141 (unless (zerop (tramp-send-command-and-check
4142 v
c15cdf02
MA
4143 (format
4144 "%s %s"
4145 (if recursive "rm -rf" "rmdir")
4146 (tramp-shell-quote-argument localname))))
00d6fd04 4147 (tramp-error v 'file-error "Couldn't delete %s" directory))))
fb7933a3 4148
20b8ac83 4149(defun tramp-handle-delete-file (filename &optional trash)
00d6fd04 4150 "Like `delete-file' for Tramp files."
ac474af1 4151 (setq filename (expand-file-name filename))
c62c9d08 4152 (with-parsed-tramp-file-name filename nil
aac0b0f2 4153 (tramp-flush-file-property v (file-name-directory localname))
00d6fd04 4154 (tramp-flush-file-property v localname)
20b8ac83
MA
4155 (unless
4156 (zerop
4157 (tramp-send-command-and-check
4158 v (format "%s %s"
4159 (or (and trash (tramp-get-remote-trash v)) "rm -f")
4160 (tramp-shell-quote-argument localname))))
00d6fd04 4161 (tramp-error v 'file-error "Couldn't delete %s" filename))))
fb7933a3
KG
4162
4163;; Dired.
4164
4165;; CCC: This does not seem to be enough. Something dies when
a4aeb9a4 4166;; we try and delete two directories under Tramp :/
fb7933a3
KG
4167(defun tramp-handle-dired-recursive-delete-directory (filename)
4168 "Recursively delete the directory given.
00d6fd04 4169This is like `dired-recursive-delete-directory' for Tramp files."
c62c9d08 4170 (with-parsed-tramp-file-name filename nil
00d6fd04 4171 ;; Run a shell command 'rm -r <localname>'
260821d3 4172 ;; Code shamelessly stolen from the dired implementation and, um, hacked :)
00d6fd04
MA
4173 (unless (file-exists-p filename)
4174 (tramp-error v 'file-error "No such directory: %s" filename))
fb7933a3 4175 ;; Which is better, -r or -R? (-r works for me <daniel@danann.net>)
00d6fd04
MA
4176 (tramp-send-command
4177 v
9c13938d 4178 (format "rm -rf %s" (tramp-shell-quote-argument localname))
00d6fd04
MA
4179 ;; Don't read the output, do it explicitely.
4180 nil t)
fb7933a3
KG
4181 ;; Wait for the remote system to return to us...
4182 ;; This might take a while, allow it plenty of time.
00d6fd04 4183 (tramp-wait-for-output (tramp-get-connection-process v) 120)
fb7933a3 4184 ;; Make sure that it worked...
aac0b0f2 4185 (tramp-flush-file-property v (file-name-directory localname))
c15cdf02 4186 (tramp-flush-directory-property v localname)
07dfe738 4187 (and (file-exists-p filename)
00d6fd04
MA
4188 (tramp-error
4189 v 'file-error "Failed to recursively delete %s" filename))))
bf247b6e 4190
5ec2cc41 4191(defun tramp-handle-dired-compress-file (file &rest ok-flag)
00d6fd04 4192 "Like `dired-compress-file' for Tramp files."
5ec2cc41
KG
4193 ;; OK-FLAG is valid for XEmacs only, but not implemented.
4194 ;; Code stolen mainly from dired-aux.el.
4195 (with-parsed-tramp-file-name file nil
00d6fd04 4196 (tramp-flush-file-property v localname)
5ec2cc41
KG
4197 (save-excursion
4198 (let ((suffixes
4199 (if (not (featurep 'xemacs))
4200 ;; Emacs case
4201 (symbol-value 'dired-compress-file-suffixes)
4202 ;; XEmacs has `dired-compression-method-alist', which is
4203 ;; transformed into `dired-compress-file-suffixes' structure.
4204 (mapcar
aa485f7c
MA
4205 (lambda (x)
4206 (list (concat (regexp-quote (nth 1 x)) "\\'")
4207 nil
4208 (mapconcat 'identity (nth 3 x) " ")))
5ec2cc41
KG
4209 (symbol-value 'dired-compression-method-alist))))
4210 suffix)
4211 ;; See if any suffix rule matches this file name.
4212 (while suffixes
4213 (let (case-fold-search)
4214 (if (string-match (car (car suffixes)) localname)
4215 (setq suffix (car suffixes) suffixes nil))
4216 (setq suffixes (cdr suffixes))))
4217
4218 (cond ((file-symlink-p file)
4219 nil)
4220 ((and suffix (nth 2 suffix))
4221 ;; We found an uncompression rule.
20b8ac83
MA
4222 (with-progress-reporter v 0 (format "Uncompressing %s" file)
4223 (when (zerop
4224 (tramp-send-command-and-check
4225 v (concat (nth 2 suffix) " "
4226 (tramp-shell-quote-argument localname))))
4227 ;; `dired-remove-file' is not defined in XEmacs.
4228 (tramp-compat-funcall 'dired-remove-file file)
4229 (string-match (car suffix) file)
4230 (concat (substring file 0 (match-beginning 0))))))
5ec2cc41
KG
4231 (t
4232 ;; We don't recognize the file as compressed, so compress it.
4233 ;; Try gzip.
20b8ac83
MA
4234 (with-progress-reporter v 0 (format "Compressing %s" file)
4235 (when (zerop
4236 (tramp-send-command-and-check
4237 v (concat "gzip -f "
4238 (tramp-shell-quote-argument localname))))
4239 ;; `dired-remove-file' is not defined in XEmacs.
4240 (tramp-compat-funcall 'dired-remove-file file)
4241 (cond ((file-exists-p (concat file ".gz"))
4242 (concat file ".gz"))
4243 ((file-exists-p (concat file ".z"))
4244 (concat file ".z"))
4245 (t nil))))))))))
fb7933a3 4246
d5b3979c 4247(defun tramp-handle-dired-uncache (dir &optional dir-p)
70c11b0b 4248 "Like `dired-uncache' for Tramp files."
d5b3979c
MA
4249 ;; DIR-P is valid for XEmacs only.
4250 (with-parsed-tramp-file-name
4251 (if (or dir-p (file-directory-p dir)) dir (file-name-directory dir)) nil
20b8ac83 4252 (tramp-flush-directory-property v localname)))
70c11b0b 4253
fb7933a3
KG
4254;; Pacify byte-compiler. The function is needed on XEmacs only. I'm
4255;; not sure at all that this is the right way to do it, but let's hope
4256;; it works for now, and wait for a guru to point out the Right Way to
4257;; achieve this.
4258;;(eval-when-compile
4259;; (unless (fboundp 'dired-insert-set-properties)
4260;; (fset 'dired-insert-set-properties 'ignore)))
4261;; Gerd suggests this:
4262(eval-when-compile (require 'dired))
4263;; Note that dired is required at run-time, too, when it is needed.
4264;; It is only needed on XEmacs for the function
4265;; `dired-insert-set-properties'.
4266
4267(defun tramp-handle-insert-directory
4268 (filename switches &optional wildcard full-directory-p)
00d6fd04
MA
4269 "Like `insert-directory' for Tramp files."
4270 (setq filename (expand-file-name filename))
4271 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
4272 (if (and (featurep 'ls-lisp)
4273 (not (symbol-value 'ls-lisp-use-insert-directory-program)))
4274 (tramp-run-real-handler
4275 'insert-directory (list filename switches wildcard full-directory-p))
0c0b61f1
MA
4276 (when (stringp switches)
4277 (setq switches (split-string switches)))
4278 (when (and (member "--dired" switches)
8e754ea2 4279 (not (tramp-get-ls-command-with-dired v)))
0c0b61f1 4280 (setq switches (delete "--dired" switches)))
c82c5727 4281 (when wildcard
87bdd2c7
MA
4282 (setq wildcard (tramp-run-real-handler
4283 'file-name-nondirectory (list localname)))
4284 (setq localname (tramp-run-real-handler
4285 'file-name-directory (list localname))))
c82c5727 4286 (unless full-directory-p
0c0b61f1
MA
4287 (setq switches (add-to-list 'switches "-d" 'append)))
4288 (setq switches (mapconcat 'tramp-shell-quote-argument switches " "))
c82c5727 4289 (when wildcard
0c0b61f1
MA
4290 (setq switches (concat switches " " wildcard)))
4291 (tramp-message
4292 v 4 "Inserting directory `ls %s %s', wildcard %s, fulldir %s"
4293 switches filename (if wildcard "yes" "no")
4294 (if full-directory-p "yes" "no"))
00d6fd04
MA
4295 ;; If `full-directory-p', we just say `ls -l FILENAME'.
4296 ;; Else we chdir to the parent directory, then say `ls -ld BASENAME'.
4297 (if full-directory-p
4298 (tramp-send-command
4299 v
fe5facd3 4300 (format "%s %s %s 2>/dev/null"
00d6fd04
MA
4301 (tramp-get-ls-command v)
4302 switches
4303 (if wildcard
4304 localname
4305 (tramp-shell-quote-argument (concat localname ".")))))
4306 (tramp-barf-unless-okay
4307 v
4308 (format "cd %s" (tramp-shell-quote-argument
87bdd2c7
MA
4309 (tramp-run-real-handler
4310 'file-name-directory (list localname))))
00d6fd04 4311 "Couldn't `cd %s'"
87bdd2c7
MA
4312 (tramp-shell-quote-argument
4313 (tramp-run-real-handler 'file-name-directory (list localname))))
00d6fd04
MA
4314 (tramp-send-command
4315 v
4316 (format "%s %s %s"
4317 (tramp-get-ls-command v)
4318 switches
4319 (if (or wildcard
87bdd2c7
MA
4320 (zerop (length
4321 (tramp-run-real-handler
4322 'file-name-nondirectory (list localname)))))
00d6fd04
MA
4323 ""
4324 (tramp-shell-quote-argument
87bdd2c7
MA
4325 (tramp-run-real-handler
4326 'file-name-nondirectory (list localname)))))))
8e754ea2
MA
4327 (let ((beg (point)))
4328 ;; We cannot use `insert-buffer-substring' because the Tramp
4329 ;; buffer changes its contents before insertion due to calling
4330 ;; `expand-file' and alike.
4331 (insert
4332 (with-current-buffer (tramp-get-buffer v)
4333 (buffer-string)))
4334
4335 ;; Check for "--dired" output.
8e754ea2 4336 (forward-line -2)
7f4d4a97
MA
4337 (when (looking-at "//SUBDIRED//")
4338 (forward-line -1))
20b8ac83
MA
4339 (when (looking-at "//DIRED//\\s-+")
4340 (let ((databeg (match-end 0))
4341 (end (tramp-compat-line-end-position)))
8e754ea2 4342 ;; Now read the numeric positions of file names.
20b8ac83 4343 (goto-char databeg)
8e754ea2
MA
4344 (while (< (point) end)
4345 (let ((start (+ beg (read (current-buffer))))
4346 (end (+ beg (read (current-buffer)))))
7f49fe46 4347 (if (memq (char-after end) '(?\n ?\ ))
8e754ea2 4348 ;; End is followed by \n or by " -> ".
fe5facd3
MA
4349 (put-text-property start end 'dired-filename t))))))
4350 ;; Remove trailing lines.
4351 (goto-char (tramp-compat-line-beginning-position))
4352 (while (looking-at "//")
4353 (forward-line 1)
4354 (delete-region (match-beginning 0) (point)))
0c0b61f1
MA
4355
4356 ;; The inserted file could be from somewhere else.
4357 (when (and (not wildcard) (not full-directory-p))
4358 (goto-char (point-max))
e5c70c41
MA
4359 (when (file-symlink-p filename)
4360 (goto-char (search-backward "->" beg 'noerror)))
0c0b61f1
MA
4361 (search-backward
4362 (if (zerop (length (file-name-nondirectory filename)))
4363 "."
4364 (file-name-nondirectory filename))
4365 beg 'noerror)
4366 (replace-match (file-relative-name filename) t))
4367
fe5facd3 4368 (goto-char (point-max))))))
fb7933a3 4369
fb7933a3 4370(defun tramp-handle-unhandled-file-name-directory (filename)
00d6fd04 4371 "Like `unhandled-file-name-directory' for Tramp files."
8a798e41
MA
4372 ;; With Emacs 23, we could simply return `nil'. But we must keep it
4373 ;; for backward compatibility.
ce3f516f 4374 (expand-file-name "~/"))
fb7933a3
KG
4375
4376;; Canonicalization of file names.
4377
fb7933a3 4378(defun tramp-handle-expand-file-name (name &optional dir)
00d6fd04 4379 "Like `expand-file-name' for Tramp files.
7432277c
KG
4380If the localname part of the given filename starts with \"/../\" then
4381the result will be a local, non-Tramp, filename."
fb7933a3
KG
4382 ;; If DIR is not given, use DEFAULT-DIRECTORY or "/".
4383 (setq dir (or dir default-directory "/"))
4384 ;; Unless NAME is absolute, concat DIR and NAME.
4385 (unless (file-name-absolute-p name)
4386 (setq name (concat (file-name-as-directory dir) name)))
00d6fd04 4387 ;; If NAME is not a Tramp file, run the real handler.
20b8ac83 4388 (if (not (tramp-connectable-p name))
00d6fd04 4389 (tramp-run-real-handler 'expand-file-name (list name nil))
fb7933a3 4390 ;; Dissect NAME.
c62c9d08 4391 (with-parsed-tramp-file-name name nil
87bdd2c7 4392 (unless (tramp-run-real-handler 'file-name-absolute-p (list localname))
7432277c 4393 (setq localname (concat "~/" localname)))
00d6fd04
MA
4394 ;; Tilde expansion if necessary. This needs a shell which
4395 ;; groks tilde expansion! The function `tramp-find-shell' is
4396 ;; supposed to find such a shell on the remote host. Please
4397 ;; tell me about it when this doesn't work on your system.
4398 (when (string-match "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname)
4399 (let ((uname (match-string 1 localname))
4400 (fname (match-string 2 localname)))
4401 ;; We cannot simply apply "~/", because under sudo "~/" is
4402 ;; expanded to the local user home directory but to the
4403 ;; root home directory. On the other hand, using always
4404 ;; the default user name for tilde expansion is not
4405 ;; appropriate either, because ssh and companions might
4406 ;; use a user name from the config file.
4407 (when (and (string-equal uname "~")
4408 (string-match "\\`su\\(do\\)?\\'" method))
4409 (setq uname (concat uname user)))
4410 (setq uname
b593f105
MA
4411 (with-connection-property v uname
4412 (tramp-send-command
4413 v (format "cd %s; pwd" (tramp-shell-quote-argument uname)))
4414 (with-current-buffer (tramp-get-buffer v)
4415 (goto-char (point-min))
4416 (buffer-substring
4417 (point) (tramp-compat-line-end-position)))))
00d6fd04
MA
4418 (setq localname (concat uname fname))))
4419 ;; There might be a double slash, for example when "~/"
cb85dcd0 4420 ;; expands to "/". Remove this.
00d6fd04
MA
4421 (while (string-match "//" localname)
4422 (setq localname (replace-match "/" t t localname)))
4423 ;; No tilde characters in file name, do normal
a17632c1
MA
4424 ;; `expand-file-name' (this does "/./" and "/../"). We bind
4425 ;; `directory-sep-char' here for XEmacs on Windows, which would
4426 ;; otherwise use backslash. `default-directory' is bound,
4427 ;; because on Windows there would be problems with UNC shares or
4428 ;; Cygwin mounts.
aff67808
MA
4429 (let ((directory-sep-char ?/)
4430 (default-directory (tramp-compat-temporary-file-directory)))
4431 (tramp-make-tramp-file-name
4432 method user host
4433 (tramp-drop-volume-letter
87bdd2c7
MA
4434 (tramp-run-real-handler
4435 'expand-file-name (list localname))))))))
00d6fd04 4436
c23c3394
MA
4437(defun tramp-replace-environment-variables (filename)
4438 "Replace environment variables in FILENAME.
4439Return the string with the replaced variables."
2e271195 4440 (save-match-data
ec5145d6 4441 (let ((idx (string-match "$\\(\\w+\\)" filename)))
2e271195 4442 ;; `$' is coded as `$$'.
ec5145d6
MA
4443 (when (and idx
4444 (or (zerop idx) (not (eq ?$ (aref filename (1- idx)))))
4445 (getenv (match-string 1 filename)))
2e271195
MA
4446 (setq filename
4447 (replace-match
4448 (substitute-in-file-name (match-string 0 filename))
4449 t nil filename)))
4450 filename)))
c23c3394 4451
00d6fd04
MA
4452(defun tramp-handle-substitute-in-file-name (filename)
4453 "Like `substitute-in-file-name' for Tramp files.
4454\"//\" and \"/~\" substitute only in the local filename part.
4455If the URL Tramp syntax is chosen, \"//\" as method delimeter and \"/~\" at
4456beginning of local filename are not substituted."
c23c3394
MA
4457 ;; First, we must replace environment variables.
4458 (setq filename (tramp-replace-environment-variables filename))
00d6fd04
MA
4459 (with-parsed-tramp-file-name filename nil
4460 (if (equal tramp-syntax 'url)
4461 ;; We need to check localname only. The other parts cannot contain
4462 ;; "//" or "/~".
4463 (if (and (> (length localname) 1)
4464 (or (string-match "//" localname)
4465 (string-match "/~" localname 1)))
4466 (tramp-run-real-handler 'substitute-in-file-name (list filename))
4467 (tramp-make-tramp-file-name
4468 (when method (substitute-in-file-name method))
4469 (when user (substitute-in-file-name user))
4470 (when host (substitute-in-file-name host))
87bdd2c7
MA
4471 (when localname
4472 (tramp-run-real-handler
4473 'substitute-in-file-name (list localname)))))
00d6fd04
MA
4474 ;; Ignore in LOCALNAME everything before "//" or "/~".
4475 (when (and (stringp localname) (string-match ".+?/\\(/\\|~\\)" localname))
4476 (setq filename
b08104a0
MA
4477 (concat (file-remote-p filename)
4478 (replace-match "\\1" nil nil localname)))
00d6fd04
MA
4479 ;; "/m:h:~" does not work for completion. We use "/m:h:~/".
4480 (when (string-match "~$" filename)
4481 (setq filename (concat filename "/"))))
4482 (tramp-run-real-handler 'substitute-in-file-name (list filename)))))
4483
4484;; In XEmacs, electricity is implemented via a key map for ?/ and ?~,
4485;; which calls corresponding functions (see minibuf.el).
4486(when (fboundp 'minibuffer-electric-separator)
9e6ab520 4487 (mapc
aa485f7c
MA
4488 (lambda (x)
4489 (eval
4490 `(defadvice ,x
4491 (around ,(intern (format "tramp-advice-%s" x)) activate)
4492 "Invoke `substitute-in-file-name' for Tramp files."
4493 (if (and (symbol-value 'minibuffer-electric-file-name-behavior)
4494 (tramp-tramp-file-p (buffer-substring)))
4495 ;; We don't need to handle `last-input-event', because
4496 ;; due to the key map we know it must be ?/ or ?~.
4497 (let ((s (concat (buffer-substring (point-min) (point))
4498 (string last-command-char))))
4499 (delete-region (point-min) (point))
4500 (insert (substitute-in-file-name s))
4501 (setq ad-return-value last-command-char))
d7ec1df7
MA
4502 ad-do-it)))
4503 (eval
4504 `(add-hook
4505 'tramp-unload-hook
4506 (lambda ()
4507 (ad-remove-advice ',x 'around ',(intern (format "tramp-advice-%s" x)))
4508 (ad-activate ',x)))))
00d6fd04
MA
4509
4510 '(minibuffer-electric-separator
4511 minibuffer-electric-tilde)))
4512
4513
0664ff72 4514;;; Remote commands:
fb7933a3 4515
00d6fd04
MA
4516(defun tramp-handle-executable-find (command)
4517 "Like `executable-find' for Tramp files."
4518 (with-parsed-tramp-file-name default-directory nil
f84638eb 4519 (tramp-find-executable v command (tramp-get-remote-path v) t)))
00d6fd04 4520
20b8ac83
MA
4521(defun tramp-process-sentinel (proc event)
4522 "Flush file caches."
4523 (unless (memq (process-status proc) '(run open))
4524 (let ((vec (tramp-get-connection-property proc "vector" nil)))
4525 (when vec
4526 (tramp-message vec 5 "Sentinel called: `%s' `%s'" proc event)
4527 (tramp-flush-directory-property vec "")))))
4528
00d6fd04
MA
4529;; We use BUFFER also as connection buffer during setup. Because of
4530;; this, its original contents must be saved, and restored once
4531;; connection has been setup.
4532(defun tramp-handle-start-file-process (name buffer program &rest args)
4533 "Like `start-file-process' for Tramp files."
4534 (with-parsed-tramp-file-name default-directory nil
32802ee1
MA
4535 ;; When PROGRAM is nil, we just provide a tty.
4536 (let ((command
4537 (when (stringp program)
4538 (format "cd %s; exec %s"
4539 (tramp-shell-quote-argument localname)
4540 (mapconcat 'tramp-shell-quote-argument
4541 (cons program args) " "))))
4542 (tramp-process-connection-type
4543 (or (null program) tramp-process-connection-type))
4544 (bmp (and (buffer-live-p buffer) (buffer-modified-p buffer)))
4545 (name1 name)
4546 (i 0))
4547 (unwind-protect
4548 (save-excursion
4549 (save-restriction
4550 (unless buffer
4551 ;; BUFFER can be nil. We use a temporary buffer.
4552 (setq buffer (generate-new-buffer tramp-temp-buffer-name)))
4553 (while (get-process name1)
4554 ;; NAME must be unique as process name.
4555 (setq i (1+ i)
4556 name1 (format "%s<%d>" name i)))
4557 (setq name name1)
4558 ;; Set the new process properties.
4559 (tramp-set-connection-property v "process-name" name)
4560 (tramp-set-connection-property v "process-buffer" buffer)
4561 ;; Activate narrowing in order to save BUFFER contents.
4562 ;; Clear also the modification time; otherwise we might
4563 ;; be interrupted by `verify-visited-file-modtime'.
4564 (with-current-buffer (tramp-get-connection-buffer v)
4565 (let ((buffer-undo-list t))
4566 (clear-visited-file-modtime)
4567 (narrow-to-region (point-max) (point-max))
4568 (if command
4569 ;; Send the command.
4570 (tramp-send-command v command nil t) ; nooutput
4571 ;; Check, whether a pty is associated.
4572 (tramp-maybe-open-connection v)
6efb972c 4573 (unless (tramp-compat-process-get
32802ee1
MA
4574 (tramp-get-connection-process v) 'remote-tty)
4575 (tramp-error
4576 v 'file-error
4577 "pty association is not supported for `%s'" name)))))
4578 (let ((p (tramp-get-connection-process v)))
4579 ;; Set sentinel and query flag for this process.
4580 (tramp-set-connection-property p "vector" v)
4581 (set-process-sentinel p 'tramp-process-sentinel)
4582 (tramp-set-process-query-on-exit-flag p t)
4583 ;; Return process.
4584 p)))
4585 ;; Save exit.
4586 (with-current-buffer (tramp-get-connection-buffer v)
4587 (if (string-match tramp-temp-buffer-name (buffer-name))
4588 (progn
4589 (set-process-buffer (tramp-get-connection-process v) nil)
4590 (kill-buffer (current-buffer)))
4591 (set-buffer-modified-p bmp)))
4592 (tramp-set-connection-property v "process-name" nil)
4593 (tramp-set-connection-property v "process-buffer" nil)))))
00d6fd04
MA
4594
4595(defun tramp-handle-process-file
4596 (program &optional infile destination display &rest args)
4597 "Like `process-file' for Tramp files."
4598 ;; The implementation is not complete yet.
4599 (when (and (numberp destination) (zerop destination))
4600 (error "Implementation does not handle immediate return"))
4601
4602 (with-parsed-tramp-file-name default-directory nil
a6e96327 4603 (let (command input tmpinput stderr tmpstderr outbuf ret)
00d6fd04
MA
4604 ;; Compute command.
4605 (setq command (mapconcat 'tramp-shell-quote-argument
4606 (cons program args) " "))
4607 ;; Determine input.
4608 (if (null infile)
4609 (setq input "/dev/null")
4610 (setq infile (expand-file-name infile))
4611 (if (tramp-equal-remote default-directory infile)
4612 ;; INFILE is on the same remote host.
4613 (setq input (with-parsed-tramp-file-name infile nil localname))
4614 ;; INFILE must be copied to remote host.
a6e96327
MA
4615 (setq input (tramp-make-tramp-temp-file v)
4616 tmpinput (tramp-make-tramp-file-name method user host input))
4617 (copy-file infile tmpinput t)))
00d6fd04
MA
4618 (when input (setq command (format "%s <%s" command input)))
4619
4620 ;; Determine output.
4621 (cond
bede3e9f 4622 ;; Just a buffer.
00d6fd04
MA
4623 ((bufferp destination)
4624 (setq outbuf destination))
bede3e9f 4625 ;; A buffer name.
00d6fd04
MA
4626 ((stringp destination)
4627 (setq outbuf (get-buffer-create destination)))
4628 ;; (REAL-DESTINATION ERROR-DESTINATION)
4629 ((consp destination)
bede3e9f 4630 ;; output.
00d6fd04
MA
4631 (cond
4632 ((bufferp (car destination))
4633 (setq outbuf (car destination)))
4634 ((stringp (car destination))
0664ff72
MA
4635 (setq outbuf (get-buffer-create (car destination))))
4636 ((car destination)
4637 (setq outbuf (current-buffer))))
bede3e9f 4638 ;; stderr.
00d6fd04
MA
4639 (cond
4640 ((stringp (cadr destination))
4641 (setcar (cdr destination) (expand-file-name (cadr destination)))
4642 (if (tramp-equal-remote default-directory (cadr destination))
4643 ;; stderr is on the same remote host.
4644 (setq stderr (with-parsed-tramp-file-name
4645 (cadr destination) nil localname))
4646 ;; stderr must be copied to remote host. The temporary
4647 ;; file must be deleted after execution.
a6e96327
MA
4648 (setq stderr (tramp-make-tramp-temp-file v)
4649 tmpstderr (tramp-make-tramp-file-name
4650 method user host stderr))))
bede3e9f 4651 ;; stderr to be discarded.
00d6fd04
MA
4652 ((null (cadr destination))
4653 (setq stderr "/dev/null"))))
4654 ;; 't
4655 (destination
4656 (setq outbuf (current-buffer))))
4657 (when stderr (setq command (format "%s 2>%s" command stderr)))
4658
20b8ac83
MA
4659 ;; Send the command. It might not return in time, so we protect
4660 ;; it. Call it in a subshell, in order to preserve working
4661 ;; directory.
00d6fd04
MA
4662 (condition-case nil
4663 (unwind-protect
293c24f9
MA
4664 (setq ret
4665 (tramp-send-command-and-check
4666 v (format "\\cd %s; %s"
4667 (tramp-shell-quote-argument localname)
b593f105 4668 command)
20b8ac83 4669 t t))
00d6fd04
MA
4670 ;; We should show the output anyway.
4671 (when outbuf
293c24f9
MA
4672 (with-current-buffer outbuf
4673 (insert
4674 (with-current-buffer (tramp-get-connection-buffer v)
4675 (buffer-string))))
00d6fd04 4676 (when display (display-buffer outbuf))))
260821d3
MA
4677 ;; When the user did interrupt, we should do it also. We use
4678 ;; return code -1 as marker.
4679 (quit
4680 (kill-buffer (tramp-get-connection-buffer v))
4681 (setq ret -1))
4682 ;; Handle errors.
00d6fd04
MA
4683 (error
4684 (kill-buffer (tramp-get-connection-buffer v))
4685 (setq ret 1)))
a6e96327 4686
a6e96327
MA
4687 ;; Provide error file.
4688 (when tmpstderr (rename-file tmpstderr (cadr destination) t))
263c02ef 4689
260821d3
MA
4690 ;; Cleanup. We remove all file cache values for the connection,
4691 ;; because the remote process could have changed them.
a6e96327 4692 (when tmpinput (delete-file tmpinput))
946a5aeb
MA
4693
4694 ;; `process-file-side-effects' has been introduced with GNU
4695 ;; Emacs 23.2. If set to `nil', no remote file will be changed
4696 ;; by `program'. If it doesn't exist, we assume its default
4697 ;; value 't'.
4698 (unless (and (boundp 'process-file-side-effects)
4699 (not (symbol-value 'process-file-side-effects)))
4700 (tramp-flush-directory-property v ""))
4701
00d6fd04 4702 ;; Return exit status.
260821d3
MA
4703 (if (equal ret -1)
4704 (keyboard-quit)
4705 ret))))
00d6fd04 4706
a4aeb9a4
MA
4707(defun tramp-local-call-process
4708 (program &optional infile destination display &rest args)
4709 "Calls `call-process' on the local host.
4710This is needed because for some Emacs flavors Tramp has
4711defadviced `call-process' to behave like `process-file'. The
4712Lisp error raised when PROGRAM is nil is trapped also, returning 1."
4713 (let ((default-directory
4714 (if (file-remote-p default-directory)
4715 (tramp-compat-temporary-file-directory)
4716 default-directory)))
4717 (if (executable-find program)
4718 (apply 'call-process program infile destination display args)
4719 1)))
4720
00d6fd04
MA
4721(defun tramp-handle-call-process-region
4722 (start end program &optional delete buffer display &rest args)
4723 "Like `call-process-region' for Tramp files."
258800f8 4724 (let ((tmpfile (tramp-compat-make-temp-file "")))
00d6fd04
MA
4725 (write-region start end tmpfile)
4726 (when delete (delete-region start end))
4727 (unwind-protect
4728 (apply 'call-process program tmpfile buffer display args)
4729 (delete-file tmpfile))))
4730
4731(defun tramp-handle-shell-command
4732 (command &optional output-buffer error-buffer)
4733 "Like `shell-command' for Tramp files."
ce3f516f 4734 (let* ((asynchronous (string-match "[ \t]*&[ \t]*\\'" command))
b8bfcf96
MA
4735 ;; We cannot use `shell-file-name' and `shell-command-switch',
4736 ;; they are variables of the local host.
20b8ac83
MA
4737 (args (list
4738 (tramp-get-method-parameter
4739 (tramp-file-name-method
4740 (tramp-dissect-file-name default-directory))
4741 'tramp-remote-sh)
4742 "-c" (substring command 0 asynchronous)))
5d2ebd96 4743 current-buffer-p
ce3f516f 4744 (output-buffer
27e813fe
MA
4745 (cond
4746 ((bufferp output-buffer) output-buffer)
4747 ((stringp output-buffer) (get-buffer-create output-buffer))
5d2ebd96
AS
4748 (output-buffer
4749 (setq current-buffer-p t)
4750 (current-buffer))
42bc9b6d 4751 (t (get-buffer-create
27e813fe
MA
4752 (if asynchronous
4753 "*Async Shell Command*"
4754 "*Shell Command Output*")))))
4755 (error-buffer
4756 (cond
4757 ((bufferp error-buffer) error-buffer)
4758 ((stringp error-buffer) (get-buffer-create error-buffer))))
ce3f516f 4759 (buffer
27e813fe 4760 (if (and (not asynchronous) error-buffer)
ce3f516f
MA
4761 (with-parsed-tramp-file-name default-directory nil
4762 (list output-buffer (tramp-make-tramp-temp-file v)))
42bc9b6d 4763 output-buffer))
cfb5c0db 4764 (p (get-buffer-process output-buffer)))
42bc9b6d
MA
4765
4766 ;; Check whether there is another process running. Tramp does not
4767 ;; support 2 (asynchronous) processes in parallel.
cfb5c0db 4768 (when p
42bc9b6d 4769 (if (yes-or-no-p "A command is running. Kill it? ")
699a11fb
GM
4770 (condition-case nil
4771 (kill-process p)
4772 (error nil))
42bc9b6d
MA
4773 (error "Shell command in progress")))
4774
f34db316
AS
4775 (if current-buffer-p
4776 (progn
4777 (barf-if-buffer-read-only)
4778 (push-mark nil t))
5d2ebd96
AS
4779 (with-current-buffer output-buffer
4780 (setq buffer-read-only nil)
4781 (erase-buffer)))
42bc9b6d 4782
5d2ebd96 4783 (if (and (not current-buffer-p) (integerp asynchronous))
42bc9b6d
MA
4784 (prog1
4785 ;; Run the process.
3412f35d 4786 (apply 'start-file-process "*Async Shell*" buffer args)
42bc9b6d 4787 ;; Display output.
cfb5c0db
MA
4788 (pop-to-buffer output-buffer)
4789 (setq mode-line-process '(":%s"))
4790 (require 'shell) (shell-mode))
42bc9b6d
MA
4791
4792 (prog1
4793 ;; Run the process.
4794 (apply 'process-file (car args) nil buffer nil (cdr args))
4795 ;; Insert error messages if they were separated.
4796 (when (listp buffer)
4797 (with-current-buffer error-buffer
4798 (insert-file-contents (cadr buffer)))
4799 (delete-file (cadr buffer)))
f34db316
AS
4800 (if current-buffer-p
4801 ;; This is like exchange-point-and-mark, but doesn't
4802 ;; activate the mark. It is cleaner to avoid activation,
4803 ;; even though the command loop would deactivate the mark
4804 ;; because we inserted text.
4805 (goto-char (prog1 (mark t)
4806 (set-marker (mark-marker) (point)
4807 (current-buffer))))
4808 ;; There's some output, display it.
4809 (when (with-current-buffer output-buffer (> (point-max) (point-min)))
4810 (if (functionp 'display-message-or-buffer)
20b8ac83 4811 (tramp-compat-funcall 'display-message-or-buffer output-buffer)
f34db316 4812 (pop-to-buffer output-buffer))))))))
00d6fd04
MA
4813
4814;; File Editing.
4815
4816(defvar tramp-handle-file-local-copy-hook nil
4817 "Normal hook to be run at the end of `tramp-handle-file-local-copy'.")
4818
fb7933a3 4819(defun tramp-handle-file-local-copy (filename)
00d6fd04 4820 "Like `file-local-copy' for Tramp files."
0f205eee 4821
c62c9d08 4822 (with-parsed-tramp-file-name filename nil
2988341a
MA
4823 (unless (file-exists-p filename)
4824 (tramp-error
4825 v 'file-error
4826 "Cannot make local copy of non-existing file `%s'" filename))
4827
20b8ac83
MA
4828 (let* ((size (nth 7 (file-attributes filename)))
4829 (rem-enc (tramp-get-inline-coding v "remote-encoding" size))
4830 (loc-dec (tramp-get-inline-coding v "local-decoding" size))
4831 (tmpfile (tramp-compat-make-temp-file filename)))
5ec2cc41 4832
2988341a
MA
4833 (condition-case err
4834 (cond
4835 ;; `copy-file' handles direct copy and out-of-band methods.
4836 ((or (tramp-local-host-p v)
20b8ac83 4837 (tramp-method-out-of-band-p v size))
2988341a
MA
4838 (copy-file filename tmpfile t t))
4839
4840 ;; Use inline encoding for file transfer.
4841 (rem-enc
4842 (save-excursion
20b8ac83
MA
4843 (with-progress-reporter
4844 v 3 (format "Encoding remote file %s" filename)
4845 (tramp-barf-unless-okay
4846 v (format rem-enc (tramp-shell-quote-argument localname))
4847 "Encoding remote file failed"))
2988341a 4848
20b8ac83 4849 (if (functionp loc-dec)
2988341a
MA
4850 ;; If local decoding is a function, we call it. We
4851 ;; must disable multibyte, because
4852 ;; `uudecode-decode-region' doesn't handle it
4853 ;; correctly.
0f205eee
MA
4854 (with-temp-buffer
4855 (set-buffer-multibyte nil)
4856 (insert-buffer-substring (tramp-get-buffer v))
20b8ac83
MA
4857 (with-progress-reporter
4858 v 3 (format "Decoding remote file %s with function %s"
4859 filename loc-dec)
4860 (funcall loc-dec (point-min) (point-max))
4861 ;; Unset `file-name-handler-alist'. Otherwise,
4862 ;; epa-file gets confused.
4863 (let (file-name-handler-alist
4864 (coding-system-for-write 'binary))
4865 (write-region (point-min) (point-max) tmpfile))))
2988341a
MA
4866
4867 ;; If tramp-decoding-function is not defined for this
4868 ;; method, we invoke tramp-decoding-command instead.
4869 (let ((tmpfile2 (tramp-compat-make-temp-file filename)))
aa485f7c
MA
4870 ;; Unset `file-name-handler-alist'. Otherwise,
4871 ;; epa-file gets confused.
4872 (let (file-name-handler-alist
4873 (coding-system-for-write 'binary))
2988341a 4874 (write-region (point-min) (point-max) tmpfile2))
20b8ac83
MA
4875 (with-progress-reporter
4876 v 3 (format "Decoding remote file %s with command %s"
4877 filename loc-dec)
4878 (unwind-protect
4879 (tramp-call-local-coding-command
4880 loc-dec tmpfile2 tmpfile)
4881 (delete-file tmpfile2)))))
2988341a 4882
2988341a 4883 ;; Set proper permissions.
b86c1cd8 4884 (set-file-modes tmpfile (tramp-default-file-modes filename))
2988341a
MA
4885 ;; Set local user ownership.
4886 (tramp-set-file-uid-gid tmpfile)))
4887
4888 ;; Oops, I don't know what to do.
4889 (t (tramp-error
4890 v 'file-error "Wrong method specification for `%s'" method)))
4891
4892 ;; Error handling.
4893 ((error quit)
4894 (delete-file tmpfile)
4895 (signal (car err) (cdr err))))
0f205eee 4896
00d6fd04 4897 (run-hooks 'tramp-handle-file-local-copy-hook)
94be87e8 4898 tmpfile)))
fb7933a3 4899
bce04fee 4900(defun tramp-handle-file-remote-p (filename &optional identification connected)
00d6fd04 4901 "Like `file-remote-p' for Tramp files."
d5b3979c
MA
4902 (let ((tramp-verbose 3))
4903 (when (tramp-tramp-file-p filename)
4904 (let* ((v (tramp-dissect-file-name filename))
4905 (p (tramp-get-connection-process v))
4906 (c (and p (processp p) (memq (process-status p) '(run open)))))
4907 ;; We expand the file name only, if there is already a connection.
4908 (with-parsed-tramp-file-name
4909 (if c (expand-file-name filename) filename) nil
4910 (and (or (not connected) c)
4911 (cond
4912 ((eq identification 'method) method)
4913 ((eq identification 'user) user)
4914 ((eq identification 'host) host)
4915 ((eq identification 'localname) localname)
4916 (t (tramp-make-tramp-file-name method user host "")))))))))
fb7933a3 4917
eb562962
MA
4918(defun tramp-find-file-name-coding-system-alist (filename tmpname)
4919 "Like `find-operation-coding-system' for Tramp filenames.
4920Tramp's `insert-file-contents' and `write-region' work over
4921temporary file names. If `file-coding-system-alist' contains an
4922expression, which matches more than the file name suffix, the
4923coding system might not be determined. This function repairs it."
4924 (let (result)
4925 (dolist (elt file-coding-system-alist result)
4926 (when (and (consp elt) (string-match (car elt) filename))
4927 ;; We found a matching entry in `file-coding-system-alist'.
4928 ;; So we add a similar entry, but with the temporary file name
4929 ;; as regexp.
4930 (add-to-list
4931 'result (cons (regexp-quote tmpname) (cdr elt)) 'append)))))
4932
fb7933a3
KG
4933(defun tramp-handle-insert-file-contents
4934 (filename &optional visit beg end replace)
00d6fd04 4935 "Like `insert-file-contents' for Tramp files."
fb7933a3
KG
4936 (barf-if-buffer-read-only)
4937 (setq filename (expand-file-name filename))
20b8ac83 4938 (let (result local-copy remote-copy)
2ac33804
MA
4939 (with-parsed-tramp-file-name filename nil
4940 (unwind-protect
70c11b0b
MA
4941 (if (not (file-exists-p filename))
4942 ;; We don't raise a Tramp error, because it might be
4943 ;; suppressed, like in `find-file-noselect-1'.
4944 (signal 'file-error
4945 (list "File not found on remote host" filename))
4946
4947 (if (and (tramp-local-host-p v)
4948 (let (file-name-handler-alist)
4949 (file-readable-p localname)))
4950 ;; Short track: if we are on the local host, we can
4951 ;; run directly.
4952 (setq result
4953 (tramp-run-real-handler
4954 'insert-file-contents
4955 (list localname visit beg end replace)))
4956
736ac90f
MA
4957 ;; When we shall insert only a part of the file, we copy
4958 ;; this part.
4959 (when (or beg end)
4960 (setq remote-copy (tramp-make-tramp-temp-file v))
4961 (tramp-send-command
4962 v
4963 (cond
4964 ((and beg end)
4965 (format "tail -c +%d %s | head -c +%d >%s"
4966 (1+ beg) (tramp-shell-quote-argument localname)
4967 (- end beg) remote-copy))
4968 (beg
4969 (format "tail -c +%d %s >%s"
4970 (1+ beg) (tramp-shell-quote-argument localname)
4971 remote-copy))
4972 (end
4973 (format "head -c +%d %s >%s"
4974 (1+ end) (tramp-shell-quote-argument localname)
4975 remote-copy)))))
4976
70c11b0b
MA
4977 ;; `insert-file-contents-literally' takes care to avoid
4978 ;; calling jka-compr. By let-binding
4979 ;; `inhibit-file-name-operation', we propagate that care
4980 ;; to the `file-local-copy' operation.
4981 (setq local-copy
4982 (let ((inhibit-file-name-operation
4983 (when (eq inhibit-file-name-operation
4984 'insert-file-contents)
4985 'file-local-copy)))
b88f2d0a
MA
4986 (cond
4987 ((stringp remote-copy)
4988 (file-local-copy
4989 (tramp-make-tramp-file-name
4990 method user host remote-copy)))
4991 ((stringp tramp-temp-buffer-file-name)
4992 (copy-file filename tramp-temp-buffer-file-name 'ok)
4993 tramp-temp-buffer-file-name)
4994 (t (file-local-copy filename)))))
4995
6e4f5731
MA
4996 ;; When the file is not readable for the owner, it
4997 ;; cannot be inserted, even it is redable for the group
4998 ;; or for everybody.
4999 (set-file-modes local-copy (tramp-octal-to-decimal "0600"))
5000
b88f2d0a
MA
5001 (when (and (null remote-copy)
5002 (tramp-get-method-parameter
5003 method 'tramp-copy-keep-tmpfile))
5004 ;; We keep the local file for performance reasons,
5005 ;; useful for "rsync".
b88f2d0a
MA
5006 (setq tramp-temp-buffer-file-name local-copy)
5007 (put 'tramp-temp-buffer-file-name 'permanent-local t))
5008
20b8ac83
MA
5009 (with-progress-reporter
5010 v 3 (format "Inserting local temp file `%s'" local-copy)
5011 ;; We must ensure that `file-coding-system-alist'
5012 ;; matches `local-copy'.
5013 (let ((file-coding-system-alist
5014 (tramp-find-file-name-coding-system-alist
5015 filename local-copy)))
5016 (setq result
5017 (insert-file-contents
5018 local-copy nil nil nil replace))))))
70c11b0b 5019
2ac33804
MA
5020 ;; Save exit.
5021 (progn
5022 (when visit
5023 (setq buffer-file-name filename)
5024 (setq buffer-read-only (not (file-writable-p filename)))
5025 (set-visited-file-modtime)
a057950d
MA
5026 (set-buffer-modified-p nil)
5027 ;; For root, preserve owner and group when editing files.
6efb972c
MA
5028 (when (string-equal
5029 (tramp-file-name-handler 'file-remote-p filename 'user)
5030 "root")
6ce78fdc 5031 (set (make-local-variable 'backup-by-copying-when-mismatch) t)))
b88f2d0a
MA
5032 (when (and (stringp local-copy)
5033 (or remote-copy (null tramp-temp-buffer-file-name)))
2ac33804
MA
5034 (delete-file local-copy))
5035 (when (stringp remote-copy)
5036 (delete-file
5037 (tramp-make-tramp-file-name method user host remote-copy))))))
70c11b0b
MA
5038
5039 ;; Result.
5040 (list (expand-file-name filename)
5041 (cadr result))))
fb7933a3 5042
94be87e8
MA
5043;; This is needed for XEmacs only. Code stolen from files.el.
5044(defun tramp-handle-insert-file-contents-literally
5045 (filename &optional visit beg end replace)
5046 "Like `insert-file-contents-literally' for Tramp files."
5047 (let ((format-alist nil)
5048 (after-insert-file-functions nil)
5049 (coding-system-for-read 'no-conversion)
5050 (coding-system-for-write 'no-conversion)
5051 (find-buffer-file-type-function
5052 (if (fboundp 'find-buffer-file-type)
5053 (symbol-function 'find-buffer-file-type)
5054 nil))
5055 (inhibit-file-name-handlers '(jka-compr-handler image-file-handler))
5056 (inhibit-file-name-operation 'insert-file-contents))
5057 (unwind-protect
5058 (progn
5059 (fset 'find-buffer-file-type (lambda (filename) t))
5060 (insert-file-contents filename visit beg end replace))
70c11b0b 5061 ;; Save exit.
94be87e8
MA
5062 (if find-buffer-file-type-function
5063 (fset 'find-buffer-file-type find-buffer-file-type-function)
5064 (fmakunbound 'find-buffer-file-type)))))
5065
38c65fca 5066(defun tramp-handle-find-backup-file-name (filename)
00d6fd04 5067 "Like `find-backup-file-name' for Tramp files."
07dfe738
KG
5068 (with-parsed-tramp-file-name filename nil
5069 ;; We set both variables. It doesn't matter whether it is
20b8ac83 5070 ;; Emacs or XEmacs.
07dfe738 5071 (let ((backup-directory-alist
20b8ac83 5072 ;; Emacs case.
07dfe738 5073 (when (boundp 'backup-directory-alist)
b86c1cd8 5074 (if (symbol-value 'tramp-backup-directory-alist)
07dfe738 5075 (mapcar
aa485f7c
MA
5076 (lambda (x)
5077 (cons
5078 (car x)
5079 (if (and (stringp (cdr x))
5080 (file-name-absolute-p (cdr x))
5081 (not (tramp-file-name-p (cdr x))))
5082 (tramp-make-tramp-file-name method user host (cdr x))
5083 (cdr x))))
07dfe738
KG
5084 (symbol-value 'tramp-backup-directory-alist))
5085 (symbol-value 'backup-directory-alist))))
5086
5087 (bkup-backup-directory-info
20b8ac83 5088 ;; XEmacs case.
07dfe738 5089 (when (boundp 'bkup-backup-directory-info)
b86c1cd8 5090 (if (symbol-value 'tramp-bkup-backup-directory-info)
07dfe738 5091 (mapcar
aa485f7c
MA
5092 (lambda (x)
5093 (nconc
5094 (list (car x))
5095 (list
5096 (if (and (stringp (car (cdr x)))
5097 (file-name-absolute-p (car (cdr x)))
5098 (not (tramp-file-name-p (car (cdr x)))))
5099 (tramp-make-tramp-file-name
5100 method user host (car (cdr x)))
5101 (car (cdr x))))
5102 (cdr (cdr x))))
07dfe738
KG
5103 (symbol-value 'tramp-bkup-backup-directory-info))
5104 (symbol-value 'bkup-backup-directory-info)))))
5105
5106 (tramp-run-real-handler 'find-backup-file-name (list filename)))))
38c65fca 5107
c1105d05 5108(defun tramp-handle-make-auto-save-file-name ()
00d6fd04 5109 "Like `make-auto-save-file-name' for Tramp files.
c1105d05 5110Returns a file name in `tramp-auto-save-directory' for autosaving this file."
00d6fd04
MA
5111 (let ((tramp-auto-save-directory tramp-auto-save-directory)
5112 (buffer-file-name
5113 (tramp-subst-strs-in-string
5114 '(("_" . "|")
5115 ("/" . "_a")
5116 (":" . "_b")
5117 ("|" . "__")
5118 ("[" . "_l")
5119 ("]" . "_r"))
5120 (buffer-file-name))))
1a762140
MA
5121 ;; File name must be unique. This is ensured with Emacs 22 (see
5122 ;; UNIQUIFY element of `auto-save-file-name-transforms'); but for
5123 ;; all other cases we must do it ourselves.
5124 (when (boundp 'auto-save-file-name-transforms)
9e6ab520 5125 (mapc
aa485f7c
MA
5126 (lambda (x)
5127 (when (and (string-match (car x) buffer-file-name)
5128 (not (car (cddr x))))
5129 (setq tramp-auto-save-directory
5130 (or tramp-auto-save-directory
5131 (tramp-compat-temporary-file-directory)))))
1a762140
MA
5132 (symbol-value 'auto-save-file-name-transforms)))
5133 ;; Create directory.
5134 (when tramp-auto-save-directory
00d6fd04
MA
5135 (setq buffer-file-name
5136 (expand-file-name buffer-file-name tramp-auto-save-directory))
1a762140
MA
5137 (unless (file-exists-p tramp-auto-save-directory)
5138 (make-directory tramp-auto-save-directory t)))
00d6fd04
MA
5139 ;; Run plain `make-auto-save-file-name'. There might be an advice when
5140 ;; it is not a magic file name operation (since Emacs 22).
5141 ;; We must deactivate it temporarily.
5142 (if (not (ad-is-active 'make-auto-save-file-name))
5143 (tramp-run-real-handler 'make-auto-save-file-name nil)
5144 ;; else
5145 (ad-deactivate 'make-auto-save-file-name)
5146 (prog1
5147 (tramp-run-real-handler 'make-auto-save-file-name nil)
5148 (ad-activate 'make-auto-save-file-name)))))
5149
5150(defvar tramp-handle-write-region-hook nil
5151 "Normal hook to be run at the end of `tramp-handle-write-region'.")
5152
b88f2d0a 5153;; CCC grok LOCKNAME
fb7933a3
KG
5154(defun tramp-handle-write-region
5155 (start end filename &optional append visit lockname confirm)
00d6fd04 5156 "Like `write-region' for Tramp files."
fb7933a3 5157 (setq filename (expand-file-name filename))
c62c9d08 5158 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
5159 ;; Following part commented out because we don't know what to do about
5160 ;; file locking, and it does not appear to be a problem to ignore it.
5161 ;; Ange-ftp ignores it, too.
5162 ;; (when (and lockname (stringp lockname))
5163 ;; (setq lockname (expand-file-name lockname)))
5164 ;; (unless (or (eq lockname nil)
5165 ;; (string= lockname filename))
5166 ;; (error
5167 ;; "tramp-handle-write-region: LOCKNAME must be nil or equal FILENAME"))
8d60099b 5168
94be87e8 5169 ;; XEmacs takes a coding system as the seventh argument, not `confirm'.
00d6fd04
MA
5170 (when (and (not (featurep 'xemacs)) confirm (file-exists-p filename))
5171 (unless (y-or-n-p (format "File %s exists; overwrite anyway? " filename))
5172 (tramp-error v 'file-error "File not overwritten")))
8d60099b 5173
a4aeb9a4 5174 (let ((uid (or (nth 2 (tramp-compat-file-attributes filename 'integer))
9c13938d 5175 (tramp-get-remote-uid v 'integer)))
a4aeb9a4 5176 (gid (or (nth 3 (tramp-compat-file-attributes filename 'integer))
9c13938d
MA
5177 (tramp-get-remote-gid v 'integer))))
5178
5179 (if (and (tramp-local-host-p v)
93c3eb7c 5180 ;; `file-writable-p' calls `file-expand-file-name'. We
87bdd2c7
MA
5181 ;; cannot use `tramp-run-real-handler' therefore.
5182 (let (file-name-handler-alist)
82f3844e
MA
5183 (and
5184 (file-writable-p (file-name-directory localname))
5185 (or (file-directory-p localname)
5186 (file-writable-p localname)))))
9c13938d 5187 ;; Short track: if we are on the local host, we can run directly.
aac0b0f2
MA
5188 (tramp-run-real-handler
5189 'write-region
5190 (list start end localname append 'no-message lockname confirm))
9c13938d 5191
20b8ac83 5192 (let ((modes (save-excursion (tramp-default-file-modes filename)))
9c13938d 5193 ;; We use this to save the value of
20b8ac83
MA
5194 ;; `last-coding-system-used' after writing the tmp
5195 ;; file. At the end of the function, we set
9c13938d
MA
5196 ;; `last-coding-system-used' to this saved value. This
5197 ;; way, any intermediary coding systems used while
5198 ;; talking to the remote shell or suchlike won't hose
5199 ;; this variable. This approach was snarfed from
5200 ;; ange-ftp.el.
5201 coding-system-used
5202 ;; Write region into a tmp file. This isn't really
5203 ;; needed if we use an encoding function, but currently
5204 ;; we use it always because this makes the logic
293c24f9
MA
5205 ;; simpler.
5206 (tmpfile (or tramp-temp-buffer-file-name
5207 (tramp-compat-make-temp-file filename))))
5208
5209 ;; If `append' is non-nil, we copy the file locally, and let
5210 ;; the native `write-region' implementation do the job.
5211 (when append (copy-file filename tmpfile 'ok))
9c13938d
MA
5212
5213 ;; We say `no-message' here because we don't want the
5214 ;; visited file modtime data to be clobbered from the temp
5215 ;; file. We call `set-visited-file-modtime' ourselves later
eb562962
MA
5216 ;; on. We must ensure that `file-coding-system-alist'
5217 ;; matches `tmpfile'.
20b8ac83
MA
5218 (let (file-name-handler-alist
5219 (file-coding-system-alist
eb562962 5220 (tramp-find-file-name-coding-system-alist filename tmpfile)))
ce2cc728
MA
5221 (condition-case err
5222 (tramp-run-real-handler
5223 'write-region
5224 (list start end tmpfile append 'no-message lockname confirm))
2988341a 5225 ((error quit)
b88f2d0a 5226 (setq tramp-temp-buffer-file-name nil)
2988341a
MA
5227 (delete-file tmpfile)
5228 (signal (car err) (cdr err))))
ce2cc728 5229
eb562962
MA
5230 ;; Now, `last-coding-system-used' has the right value. Remember it.
5231 (when (boundp 'last-coding-system-used)
5232 (setq coding-system-used
5233 (symbol-value 'last-coding-system-used))))
5234
9c13938d
MA
5235 ;; The permissions of the temporary file should be set. If
5236 ;; filename does not exist (eq modes nil) it has been
5237 ;; renamed to the backup file. This case `save-buffer'
5238 ;; handles permissions.
459a5f4b
MA
5239 ;; Ensure, that it is still readable.
5240 (when modes
5241 (set-file-modes
5242 tmpfile (logior (or modes 0) (tramp-octal-to-decimal "0400"))))
9c13938d
MA
5243
5244 ;; This is a bit lengthy due to the different methods
5245 ;; possible for file transfer. First, we check whether the
5246 ;; method uses an rcp program. If so, we call it.
5247 ;; Otherwise, both encoding and decoding command must be
5248 ;; specified. However, if the method _also_ specifies an
5249 ;; encoding function, then that is used for encoding the
5250 ;; contents of the tmp file.
20b8ac83
MA
5251 (let* ((size (nth 7 (file-attributes tmpfile)))
5252 (rem-dec (tramp-get-inline-coding v "remote-decoding" size))
5253 (loc-enc (tramp-get-inline-coding v "local-encoding" size)))
5254 (cond
5255 ;; `copy-file' handles direct copy and out-of-band methods.
5256 ((or (tramp-local-host-p v)
5257 (tramp-method-out-of-band-p v size))
5258 (if (and (not (stringp start))
5259 (= (or end (point-max)) (point-max))
5260 (= (or start (point-min)) (point-min))
5261 (tramp-get-method-parameter
5262 method 'tramp-copy-keep-tmpfile))
5263 (progn
5264 (setq tramp-temp-buffer-file-name tmpfile)
5265 (condition-case err
5266 ;; We keep the local file for performance
5267 ;; reasons, useful for "rsync".
5268 (copy-file tmpfile filename t)
5269 ((error quit)
5270 (setq tramp-temp-buffer-file-name nil)
5271 (delete-file tmpfile)
5272 (signal (car err) (cdr err)))))
5273 (setq tramp-temp-buffer-file-name nil)
5274 ;; Don't rename, in order to keep context in SELinux.
5275 (unwind-protect
5276 (copy-file tmpfile filename t)
5277 (delete-file tmpfile))))
5278
5279 ;; Use inline file transfer.
5280 (rem-dec
5281 ;; Encode tmpfile.
191bb792 5282 (unwind-protect
20b8ac83
MA
5283 (with-temp-buffer
5284 (set-buffer-multibyte nil)
5285 ;; Use encoding function or command.
5286 (if (functionp loc-enc)
5287 (with-progress-reporter
5288 v 3 (format "Encoding region using function `%s'"
5289 loc-enc)
5290 (let ((coding-system-for-read 'binary))
5291 (insert-file-contents-literally tmpfile))
5292 ;; The following `let' is a workaround for the
5293 ;; base64.el that comes with pgnus-0.84. If
5294 ;; both of the following conditions are
5295 ;; satisfied, it tries to write to a local
5296 ;; file in default-directory, but at this
5297 ;; point, default-directory is remote.
5298 ;; (`call-process-region' can't write to
5299 ;; remote files, it seems.) The file in
5300 ;; question is a tmp file anyway.
5301 (let ((default-directory
5302 (tramp-compat-temporary-file-directory)))
5303 (funcall loc-enc (point-min) (point-max))))
5304
5305 (with-progress-reporter
5306 v 3 (format "Encoding region using command `%s'"
5307 loc-enc)
5308 (unless (zerop (tramp-call-local-coding-command
5309 loc-enc tmpfile t))
5310 (tramp-error
5311 v 'file-error
5312 (concat "Cannot write to `%s', "
5313 "local encoding command `%s' failed")
5314 filename loc-enc))))
5315
5316 ;; Send buffer into remote decoding command which
5317 ;; writes to remote file. Because this happens on
5318 ;; the remote host, we cannot use the function.
5319 (with-progress-reporter
5320 v 3
5321 (format "Decoding region into remote file %s" filename)
5322 (goto-char (point-max))
5323 (unless (bolp) (newline))
5324 (tramp-send-command
9c13938d
MA
5325 v
5326 (format
20b8ac83
MA
5327 (concat rem-dec " <<'EOF'\n%sEOF")
5328 (tramp-shell-quote-argument localname)
5329 (buffer-string)))
5330 (tramp-barf-unless-okay
5331 v nil
5332 "Couldn't write region to `%s', decode using `%s' failed"
5333 filename rem-dec)
5334 ;; When `file-precious-flag' is set, the region is
5335 ;; written to a temporary file. Check that the
5336 ;; checksum is equal to that from the local tmpfile.
5337 (when file-precious-flag
5338 (erase-buffer)
5339 (and
5340 ;; cksum runs locally, if possible.
5341 (zerop (tramp-local-call-process "cksum" tmpfile t))
5342 ;; cksum runs remotely.
5343 (zerop
5344 (tramp-send-command-and-check
5345 v
5346 (format
5347 "cksum <%s"
5348 (tramp-shell-quote-argument localname))))
5349 ;; ... they are different.
5350 (not
5351 (string-equal
5352 (buffer-string)
5353 (with-current-buffer (tramp-get-buffer v)
5354 (buffer-string))))
5355 (tramp-error
5356 v 'file-error
5357 (concat "Couldn't write region to `%s',"
5358 " decode using `%s' failed")
5359 filename rem-dec)))))
8d60099b 5360
20b8ac83
MA
5361 ;; Save exit.
5362 (delete-file tmpfile)))
8d60099b 5363
20b8ac83
MA
5364 ;; That's not expected.
5365 (t
5366 (tramp-error
5367 v 'file-error
5368 (concat "Method `%s' should specify both encoding and "
5369 "decoding command or an rcp program")
5370 method))))
258800f8 5371
9c13938d
MA
5372 ;; Make `last-coding-system-used' have the right value.
5373 (when coding-system-used
5374 (set 'last-coding-system-used coding-system-used))))
0f205eee 5375
aac0b0f2
MA
5376 (tramp-flush-file-property v (file-name-directory localname))
5377 (tramp-flush-file-property v localname)
5378
57671b72
MA
5379 ;; We must protect `last-coding-system-used', now we have set it
5380 ;; to its correct value.
293c24f9 5381 (let (last-coding-system-used (need-chown t))
57671b72
MA
5382 ;; Set file modification time.
5383 (when (or (eq visit t) (stringp visit))
293c24f9
MA
5384 (let ((file-attr (file-attributes filename)))
5385 (set-visited-file-modtime
5386 ;; We must pass modtime explicitely, because filename can
5387 ;; be different from (buffer-file-name), f.e. if
5388 ;; `file-precious-flag' is set.
5389 (nth 5 file-attr))
5390 (when (and (eq (nth 2 file-attr) uid)
5391 (eq (nth 3 file-attr) gid))
5392 (setq need-chown nil))))
57671b72
MA
5393
5394 ;; Set the ownership.
293c24f9
MA
5395 (when need-chown
5396 (tramp-set-file-uid-gid filename uid gid))
57671b72
MA
5397 (when (or (eq visit t) (null visit) (stringp visit))
5398 (tramp-message v 0 "Wrote %s" filename))
5399 (run-hooks 'tramp-handle-write-region-hook)))))
fb7933a3 5400
946a5aeb
MA
5401(defvar tramp-vc-registered-file-names nil
5402 "List used to collect file names, which are checked during `vc-registered'.")
5403
5404;; VC backends check for the existence of various different special
5405;; files. This is very time consuming, because every single check
5406;; requires a remote command (the file cache must be invalidated).
5407;; Therefore, we apply a kind of optimization. We install the file
5408;; name handler `tramp-vc-file-name-handler', which does nothing but
5409;; remembers all file names for which `file-exists-p' or
5410;; `file-readable-p' has been applied. A first run of `vc-registered'
5411;; is performed. Afterwards, a script is applied for all collected
5412;; file names, using just one remote command. The result of this
5413;; script is used to fill the file cache with actual values. Now we
5414;; can reset the file name handlers, and we make a second run of
5415;; `vc-registered', which returns the expected result without sending
5416;; any other remote command.
49096407
MA
5417(defun tramp-handle-vc-registered (file)
5418 "Like `vc-registered' for Tramp files."
20b8ac83
MA
5419 (with-temp-message ""
5420 (with-parsed-tramp-file-name file nil
5421 (with-progress-reporter
5422 v 3 (format "Checking `vc-registered' for %s" file)
5423
5424 ;; There could be new files, created by the vc backend. We
5425 ;; cannot reuse the old cache entries, therefore.
5426 (let (tramp-vc-registered-file-names
5427 (tramp-cache-inhibit-cache (current-time))
5428 (file-name-handler-alist
5429 `((,tramp-file-name-regexp . tramp-vc-file-name-handler))))
5430
5431 ;; Here we collect only file names, which need an operation.
5432 (tramp-run-real-handler 'vc-registered (list file))
5433 (tramp-message v 10 "\n%s" tramp-vc-registered-file-names)
5434
5435 ;; Send just one command, in order to fill the cache.
5436 (when tramp-vc-registered-file-names
5437 (tramp-maybe-send-script
5438 v
5439 (format tramp-vc-registered-read-file-names
5440 (tramp-get-file-exists-command v)
5441 (format "%s -r" (tramp-get-test-command v)))
5442 "tramp_vc_registered_read_file_names")
5443
5444 (dolist
5445 (elt
5446 (tramp-send-command-and-read
5447 v
5448 (format
5449 "tramp_vc_registered_read_file_names <<'EOF'\n%s\nEOF\n"
5450 (mapconcat 'tramp-shell-quote-argument
5451 tramp-vc-registered-file-names
5452 "\n"))))
5453
5454 (tramp-set-file-property
5455 v (car elt) (cadr elt) (cadr (cdr elt))))))
5456
5457 ;; Second run. Now all `file-exists-p' or `file-readable-p'
5458 ;; calls shall be answered from the file cache. We unset
5459 ;; `process-file-side-effects' in order to keep the cache when
5460 ;; `process-file' calls appear.
5461 (let (process-file-side-effects)
5462 (tramp-run-real-handler 'vc-registered (list file)))))))
49096407 5463
a01b1e22
MA
5464;;;###autoload
5465(progn (defun tramp-run-real-handler (operation args)
fb7933a3 5466 "Invoke normal file name handler for OPERATION.
c62c9d08
KG
5467First arg specifies the OPERATION, second arg is a list of arguments to
5468pass to the OPERATION."
4007ba5b
KG
5469 (let* ((inhibit-file-name-handlers
5470 `(tramp-file-name-handler
946a5aeb 5471 tramp-vc-file-name-handler
4007ba5b
KG
5472 tramp-completion-file-name-handler
5473 cygwin-mount-name-hook-function
5474 cygwin-mount-map-drive-hook-function
5475 .
5476 ,(and (eq inhibit-file-name-operation operation)
5477 inhibit-file-name-handlers)))
5478 (inhibit-file-name-operation operation))
a01b1e22 5479 (apply operation args))))
16674e4f 5480
a01b1e22
MA
5481;;;###autoload
5482(progn (defun tramp-completion-run-real-handler (operation args)
16674e4f
KG
5483 "Invoke `tramp-file-name-handler' for OPERATION.
5484First arg specifies the OPERATION, second arg is a list of arguments to
5485pass to the OPERATION."
4007ba5b
KG
5486 (let* ((inhibit-file-name-handlers
5487 `(tramp-completion-file-name-handler
5488 cygwin-mount-name-hook-function
5489 cygwin-mount-map-drive-hook-function
5490 .
5491 ,(and (eq inhibit-file-name-operation operation)
5492 inhibit-file-name-handlers)))
5493 (inhibit-file-name-operation operation))
a01b1e22 5494 (apply operation args))))
fb7933a3 5495
4007ba5b
KG
5496;; We handle here all file primitives. Most of them have the file
5497;; name as first parameter; nevertheless we check for them explicitly
04bf5b65 5498;; in order to be signaled if a new primitive appears. This
4007ba5b
KG
5499;; scenario is needed because there isn't a way to decide by
5500;; syntactical means whether a foreign method must be called. It would
19a87064 5501;; ease the life if `file-name-handler-alist' would support a decision
4007ba5b
KG
5502;; function as well but regexp only.
5503(defun tramp-file-name-for-operation (operation &rest args)
5504 "Return file name related to OPERATION file primitive.
5505ARGS are the arguments OPERATION has been called with."
5506 (cond
20b8ac83 5507 ;; FILE resp DIRECTORY.
4007ba5b
KG
5508 ((member operation
5509 (list 'access-file 'byte-compiler-base-file-name 'delete-directory
5510 'delete-file 'diff-latest-backup-file 'directory-file-name
5511 'directory-files 'directory-files-and-attributes
5512 'dired-compress-file 'dired-uncache
5513 'file-accessible-directory-p 'file-attributes
5514 'file-directory-p 'file-executable-p 'file-exists-p
19a87064
MA
5515 'file-local-copy 'file-remote-p 'file-modes
5516 'file-name-as-directory 'file-name-directory
5517 'file-name-nondirectory 'file-name-sans-versions
5518 'file-ownership-preserved-p 'file-readable-p
5519 'file-regular-p 'file-symlink-p 'file-truename
5520 'file-writable-p 'find-backup-file-name 'find-file-noselect
5521 'get-file-buffer 'insert-directory 'insert-file-contents
5522 'load 'make-directory 'make-directory-internal
5523 'set-file-modes 'substitute-in-file-name
5524 'unhandled-file-name-directory 'vc-registered
20b8ac83 5525 ;; Emacs 22+ only.
ce3f516f 5526 'set-file-times
20b8ac83
MA
5527 ;; Emacs 24+ only.
5528 'file-selinux-context 'set-file-selinux-context
5529 ;; XEmacs only.
4007ba5b
KG
5530 'abbreviate-file-name 'create-file-buffer
5531 'dired-file-modtime 'dired-make-compressed-filename
5532 'dired-recursive-delete-directory 'dired-set-file-modtime
5533 'dired-shell-unhandle-file-name 'dired-uucode-file
5615d63f 5534 'insert-file-contents-literally 'make-temp-name 'recover-file
4007ba5b 5535 'vm-imap-check-mail 'vm-pop-check-mail 'vm-spool-check-mail))
8daea7fc
KG
5536 (if (file-name-absolute-p (nth 0 args))
5537 (nth 0 args)
5538 (expand-file-name (nth 0 args))))
20b8ac83 5539 ;; FILE DIRECTORY resp FILE1 FILE2.
4007ba5b
KG
5540 ((member operation
5541 (list 'add-name-to-file 'copy-file 'expand-file-name
5542 'file-name-all-completions 'file-name-completion
5543 'file-newer-than-file-p 'make-symbolic-link 'rename-file
20b8ac83 5544 ;; Emacs 23+ only.
263c02ef 5545 'copy-directory
20b8ac83 5546 ;; XEmacs only.
4007ba5b
KG
5547 'dired-make-relative-symlink
5548 'vm-imap-move-mail 'vm-pop-move-mail 'vm-spool-move-mail))
5549 (save-match-data
5550 (cond
5551 ((string-match tramp-file-name-regexp (nth 0 args)) (nth 0 args))
5552 ((string-match tramp-file-name-regexp (nth 1 args)) (nth 1 args))
5553 (t (buffer-file-name (current-buffer))))))
20b8ac83 5554 ;; START END FILE.
4007ba5b
KG
5555 ((eq operation 'write-region)
5556 (nth 2 args))
20b8ac83 5557 ;; BUFFER.
4007ba5b 5558 ((member operation
00d6fd04 5559 (list 'set-visited-file-modtime 'verify-visited-file-modtime
20b8ac83 5560 ;; Emacs 22+ only.
00d6fd04 5561 'make-auto-save-file-name
20b8ac83 5562 ;; XEmacs only.
4007ba5b
KG
5563 'backup-buffer))
5564 (buffer-file-name
5565 (if (bufferp (nth 0 args)) (nth 0 args) (current-buffer))))
20b8ac83 5566 ;; COMMAND.
4007ba5b 5567 ((member operation
20b8ac83 5568 (list ;; not in Emacs 23+.
00d6fd04 5569 'dired-call-process
20b8ac83 5570 ;; Emacs only.
b71c9e75 5571 'shell-command
20b8ac83 5572 ;; Emacs 22+ only.
0457dd55 5573 'process-file
20b8ac83 5574 ;; Emacs 23+ only.
00d6fd04 5575 'start-file-process
20b8ac83 5576 ;; XEmacs only.
00d6fd04 5577 'dired-print-file 'dired-shell-call-process
20b8ac83
MA
5578 ;; nowhere yet.
5579 'executable-find 'start-process
5580 'call-process 'call-process-region))
4007ba5b 5581 default-directory)
20b8ac83 5582 ;; Unknown file primitive.
4007ba5b
KG
5583 (t (error "unknown file I/O primitive: %s" operation))))
5584
5585(defun tramp-find-foreign-file-name-handler (filename)
5586 "Return foreign file name handler if exists."
20b8ac83 5587 (when (tramp-tramp-file-p filename)
9ce8462a
MA
5588 (let ((v (tramp-dissect-file-name filename t))
5589 (handler tramp-foreign-file-name-handler-alist)
5590 elt res)
5591 ;; When we are not fully sure that filename completion is safe,
5592 ;; we should not return a handler.
5593 (when (or (tramp-file-name-method v) (tramp-file-name-user v)
1834b39f
MA
5594 (and (tramp-file-name-host v)
5595 (not (member (tramp-file-name-host v)
5596 (mapcar 'car tramp-methods))))
9ce8462a
MA
5597 (not (tramp-completion-mode-p)))
5598 (while handler
5599 (setq elt (car handler)
5600 handler (cdr handler))
5601 (when (funcall (car elt) filename)
5602 (setq handler nil
5603 res (cdr elt))))
5604 res))))
4007ba5b 5605
fb7933a3
KG
5606;; Main function.
5607;;;###autoload
5608(defun tramp-file-name-handler (operation &rest args)
ea9d1443 5609 "Invoke Tramp file name handler.
a4aeb9a4 5610Falls back to normal file name handler if no Tramp file name handler exists."
2e271195
MA
5611 (if tramp-mode
5612 (save-match-data
5613 (let* ((filename
5614 (tramp-replace-environment-variables
5615 (apply 'tramp-file-name-for-operation operation args)))
5616 (completion (tramp-completion-mode-p))
5617 (foreign (tramp-find-foreign-file-name-handler filename)))
5618 (with-parsed-tramp-file-name filename nil
20b8ac83
MA
5619 ;; Call the backend function.
5620 (if foreign
5621 (condition-case err
5622 (apply foreign operation args)
5623
5624 ;; Trace that somebody has interrupted the
5625 ;; operation.
5626 (quit
5627 (let (tramp-message-show-message)
5628 (tramp-message
5629 v 1 "Interrupt received in operation %s"
5630 (append (list operation) args)))
5631 ;; Propagate the quit signal.
5632 (signal (car err) (cdr err)))
5633
5634 ;; When we are in completion mode, some failed
5635 ;; operations shall return at least a default value
5636 ;; in order to give the user a chance to correct the
5637 ;; file name in the minibuffer.
5638 (error
5639 (cond
5640 ((and completion (zerop (length localname))
5641 (memq operation '(file-exists-p file-directory-p)))
5642 t)
5643 ((and completion (zerop (length localname))
5644 (memq operation
5645 '(expand-file-name file-name-as-directory)))
5646 filename)
5647 ;; Propagate the error.
5648 (t (signal (car err) (cdr err))))))
5649
5650 ;; Nothing to do for us.
5651 (tramp-run-real-handler operation args)))))
5652
2e271195
MA
5653 ;; When `tramp-mode' is not enabled, we don't do anything.
5654 (tramp-run-real-handler operation args)))
fb7933a3 5655
07dfe738
KG
5656;; In Emacs, there is some concurrency due to timers. If a timer
5657;; interrupts Tramp and wishes to use the same connection buffer as
5658;; the "main" Emacs, then garbage might occur in the connection
5659;; buffer. Therefore, we need to make sure that a timer does not use
5660;; the same connection buffer as the "main" Emacs. We implement a
5661;; cheap global lock, instead of locking each connection buffer
5662;; separately. The global lock is based on two variables,
5663;; `tramp-locked' and `tramp-locker'. `tramp-locked' is set to true
5664;; (with setq) to indicate a lock. But Tramp also calls itself during
5665;; processing of a single file operation, so we need to allow
5666;; recursive calls. That's where the `tramp-locker' variable comes in
5667;; -- it is let-bound to t during the execution of the current
5668;; handler. So if `tramp-locked' is t and `tramp-locker' is also t,
5669;; then we should just proceed because we have been called
5670;; recursively. But if `tramp-locker' is nil, then we are a timer
5671;; interrupting the "main" Emacs, and then we signal an error.
5672
5673(defvar tramp-locked nil
5674 "If non-nil, then Tramp is currently busy.
5675Together with `tramp-locker', this implements a locking mechanism
5676preventing reentrant calls of Tramp.")
5677
5678(defvar tramp-locker nil
5679 "If non-nil, then a caller has locked Tramp.
5680Together with `tramp-locked', this implements a locking mechanism
5681preventing reentrant calls of Tramp.")
5682
ea9d1443
KG
5683(defun tramp-sh-file-name-handler (operation &rest args)
5684 "Invoke remote-shell Tramp file name handler.
5685Fall back to normal file name handler if no Tramp handler exists."
07dfe738 5686 (when (and tramp-locked (not tramp-locker))
11c71217 5687 (setq tramp-locked nil)
00d6fd04 5688 (signal 'file-error (list "Forbidden reentrant call of Tramp")))
07dfe738
KG
5689 (let ((tl tramp-locked))
5690 (unwind-protect
5691 (progn
5692 (setq tramp-locked t)
5693 (let ((tramp-locker t))
5694 (save-match-data
5695 (let ((fn (assoc operation tramp-file-name-handler-alist)))
5696 (if fn
5697 (apply (cdr fn) args)
5698 (tramp-run-real-handler operation args))))))
5699 (setq tramp-locked tl))))
ea9d1443 5700
946a5aeb
MA
5701(defun tramp-vc-file-name-handler (operation &rest args)
5702 "Invoke special file name handler, which collects files to be handled."
5703 (save-match-data
5704 (let ((filename
5705 (tramp-replace-environment-variables
5706 (apply 'tramp-file-name-for-operation operation args)))
5707 (fn (assoc operation tramp-file-name-handler-alist)))
5708 (with-parsed-tramp-file-name filename nil
5709 (cond
5710 ;; That's what we want: file names, for which checks are
5711 ;; applied. We assume, that VC uses only `file-exists-p' and
5712 ;; `file-readable-p' checks; otherwise we must extend the
5713 ;; list. We do not perform any action, but return nil, in
5714 ;; order to keep `vc-registered' running.
5715 ((and fn (memq operation '(file-exists-p file-readable-p)))
5716 (add-to-list 'tramp-vc-registered-file-names localname 'append)
5717 nil)
5718 ;; Tramp file name handlers like `expand-file-name'. They
5719 ;; must still work.
5720 (fn
5721 (save-match-data (apply (cdr fn) args)))
5722 ;; Default file name handlers, we don't care.
5723 (t (tramp-run-real-handler operation args)))))))
5724
16674e4f 5725;;;###autoload
1ecc6145 5726(progn (defun tramp-completion-file-name-handler (operation &rest args)
a4aeb9a4
MA
5727 "Invoke Tramp file name completion handler.
5728Falls back to normal file name handler if no Tramp file name handler exists."
57671b72
MA
5729 ;; We bind `directory-sep-char' here for XEmacs on Windows, which
5730 ;; would otherwise use backslash.
aff67808
MA
5731 (let ((directory-sep-char ?/)
5732 (fn (assoc operation tramp-completion-file-name-handler-alist)))
aa485f7c
MA
5733 (if (and
5734 ;; When `tramp-mode' is not enabled, we don't do anything.
5735 fn tramp-mode
5736 ;; For other syntaxes than `sep', the regexp matches many common
5737 ;; situations where the user doesn't actually want to use Tramp.
5738 ;; So to avoid autoloading Tramp after typing just "/s", we
5739 ;; disable this part of the completion, unless the user implicitly
5740 ;; indicated his interest in using a fancier completion system.
5741 (or (eq tramp-syntax 'sep)
20b8ac83
MA
5742 (featurep 'tramp) ;; If it's loaded, we may as well use it.
5743 ;; `partial-completion-mode' does not exist in XEmacs.
5744 ;; It is obsoleted with Emacs 24.1.
5745 (and (boundp 'partial-completion-mode)
5746 (symbol-value 'partial-completion-mode))
aa485f7c
MA
5747 ;; FIXME: These may have been loaded even if the user never
5748 ;; intended to use them.
5749 (featurep 'ido)
5750 (featurep 'icicles)))
aff67808
MA
5751 (save-match-data (apply (cdr fn) args))
5752 (tramp-completion-run-real-handler operation args)))))
a01b1e22 5753
b25a52cc 5754;;;###autoload
aa485f7c
MA
5755(progn (defun tramp-register-file-name-handlers ()
5756 "Add Tramp file name handlers to `file-name-handler-alist'."
5757 ;; Remove autoloaded handlers from file name handler alist. Useful,
00d6fd04
MA
5758 ;; if `tramp-syntax' has been changed.
5759 (let ((a1 (rassq 'tramp-file-name-handler file-name-handler-alist)))
aa485f7c
MA
5760 (setq file-name-handler-alist (delq a1 file-name-handler-alist)))
5761 (let ((a1 (rassq
5762 'tramp-completion-file-name-handler file-name-handler-alist)))
5763 (setq file-name-handler-alist (delq a1 file-name-handler-alist)))
5764 ;; Add the handlers.
a01b1e22
MA
5765 (add-to-list 'file-name-handler-alist
5766 (cons tramp-file-name-regexp 'tramp-file-name-handler))
0c0b61f1 5767 (put 'tramp-file-name-handler 'safe-magic t)
aa485f7c
MA
5768 (add-to-list 'file-name-handler-alist
5769 (cons tramp-completion-file-name-regexp
5770 'tramp-completion-file-name-handler))
5771 (put 'tramp-completion-file-name-handler 'safe-magic t)
5772 ;; If jka-compr or epa-file are already loaded, move them to the
5773 ;; front of `file-name-handler-alist'.
5774 (dolist (fnh '(epa-file-handler jka-compr-handler))
5775 (let ((entry (rassoc fnh file-name-handler-alist)))
5776 (when entry
5777 (setq file-name-handler-alist
5778 (cons entry (delete entry file-name-handler-alist))))))))
69cee873 5779
00d6fd04
MA
5780;; `tramp-file-name-handler' must be registered before evaluation of
5781;; site-start and init files, because there might exist remote files
5782;; already, f.e. files kept via recentf-mode.
aa485f7c
MA
5783;;;###autoload(tramp-register-file-name-handlers)
5784(tramp-register-file-name-handlers)
b25a52cc 5785
fb7933a3 5786;;;###autoload
8c04e197 5787(defun tramp-unload-file-name-handlers ()
a69c01a0
MA
5788 (setq file-name-handler-alist
5789 (delete (rassoc 'tramp-file-name-handler
5790 file-name-handler-alist)
5791 (delete (rassoc 'tramp-completion-file-name-handler
5792 file-name-handler-alist)
5793 file-name-handler-alist))))
5794
8c04e197 5795(add-hook 'tramp-unload-hook 'tramp-unload-file-name-handlers)
a69c01a0 5796
0664ff72 5797;;; File name handler functions for completion mode:
a6e96327
MA
5798
5799(defvar tramp-completion-mode nil
5800 "If non-nil, external packages signal that they are in file name completion.
5801
5802This is necessary, because Tramp uses a heuristic depending on last
5803input event. This fails when external packages use other characters
5804but <TAB>, <SPACE> or ?\\? for file name completion. This variable
5805should never be set globally, the intention is to let-bind it.")
16674e4f
KG
5806
5807;; Necessary because `tramp-file-name-regexp-unified' and
00d6fd04
MA
5808;; `tramp-completion-file-name-regexp-unified' aren't different. If
5809;; nil, `tramp-completion-run-real-handler' is called (i.e. forwarding
5810;; to `tramp-file-name-handler'). Otherwise, it takes
5811;; `tramp-run-real-handler'. Using `last-input-event' is a little bit
5812;; risky, because completing a file might require loading other files,
5813;; like "~/.netrc", and for them it shouldn't be decided based on that
5814;; variable. On the other hand, those files shouldn't have partial
a4aeb9a4
MA
5815;; Tramp file name syntax. Maybe another variable should be introduced
5816;; overwriting this check in such cases. Or we change Tramp file name
00d6fd04 5817;; syntax in order to avoid ambiguities, like in XEmacs ...
6c4e47fa 5818(defun tramp-completion-mode-p ()
20b8ac83 5819 "Check, whether method / user name / host name completion is active."
6c4e47fa 5820 (or
20b8ac83
MA
5821 ;; Signal from outside. `non-essential' has been introduced in Emacs 24.
5822 (and (boundp 'non-essential) (symbol-value 'non-essential))
a6e96327
MA
5823 tramp-completion-mode
5824 ;; Emacs.
94be87e8 5825 (equal last-input-event 'tab)
6c4e47fa 5826 (and (natnump last-input-event)
94be87e8 5827 (or
a6e96327 5828 ;; ?\t has event-modifier 'control.
800a97b8 5829 (equal last-input-event ?\t)
94be87e8 5830 (and (not (event-modifiers last-input-event))
800a97b8
SM
5831 (or (equal last-input-event ?\?)
5832 (equal last-input-event ?\ )))))
a6e96327 5833 ;; XEmacs.
6c4e47fa
MA
5834 (and (featurep 'xemacs)
5835 ;; `last-input-event' might be nil.
5836 (not (null last-input-event))
5837 ;; `last-input-event' may have no character approximation.
20b8ac83 5838 (tramp-compat-funcall 'event-to-character last-input-event)
94be87e8 5839 (or
a6e96327 5840 ;; ?\t has event-modifier 'control.
800a97b8 5841 (equal
20b8ac83 5842 (tramp-compat-funcall 'event-to-character last-input-event) ?\t)
94be87e8 5843 (and (not (event-modifiers last-input-event))
800a97b8 5844 (or (equal
20b8ac83
MA
5845 (tramp-compat-funcall 'event-to-character last-input-event)
5846 ?\?)
800a97b8 5847 (equal
20b8ac83
MA
5848 (tramp-compat-funcall 'event-to-character last-input-event)
5849 ?\ )))))))
5850
5851(defun tramp-connectable-p (filename)
5852 "Check, whether it is possible to connect the remote host w/o side-effects.
5853This is true, if either the remote host is already connected, or if we are
5854not in completion mode."
5855 (and (tramp-tramp-file-p filename)
5856 (with-parsed-tramp-file-name filename nil
5857 (or (get-buffer (tramp-buffer-name v))
5858 (not (tramp-completion-mode-p))))))
16674e4f 5859
16674e4f
KG
5860;; Method, host name and user name completion.
5861;; `tramp-completion-dissect-file-name' returns a list of
5862;; tramp-file-name structures. For all of them we return possible completions.
a01b1e22 5863;;;###autoload
16674e4f 5864(defun tramp-completion-handle-file-name-all-completions (filename directory)
00d6fd04 5865 "Like `file-name-all-completions' for partial Tramp files."
16674e4f 5866
00d6fd04
MA
5867 (let* ((fullname (tramp-drop-volume-letter
5868 (expand-file-name filename directory)))
5869 ;; Possible completion structures.
5870 (v (tramp-completion-dissect-file-name fullname))
5871 result result1)
5872
5873 (while v
5874 (let* ((car (car v))
5875 (method (tramp-file-name-method car))
5876 (user (tramp-file-name-user car))
5877 (host (tramp-file-name-host car))
5878 (localname (tramp-file-name-localname car))
5879 (m (tramp-find-method method user host))
5880 (tramp-current-user user) ; see `tramp-parse-passwd'
5881 all-user-hosts)
5882
5883 (unless localname ;; Nothing to complete.
5884
5885 (if (or user host)
5886
5887 ;; Method dependent user / host combinations.
5888 (progn
9e6ab520 5889 (mapc
00d6fd04
MA
5890 (lambda (x)
5891 (setq all-user-hosts
5892 (append all-user-hosts
5893 (funcall (nth 0 x) (nth 1 x)))))
5894 (tramp-get-completion-function m))
5895
9e6ab520
MA
5896 (setq result
5897 (append result
5898 (mapcar
5899 (lambda (x)
5900 (tramp-get-completion-user-host
5901 method user host (nth 0 x) (nth 1 x)))
5902 (delq nil all-user-hosts)))))
00d6fd04
MA
5903
5904 ;; Possible methods.
5905 (setq result
5906 (append result (tramp-get-completion-methods m)))))
5907
5908 (setq v (cdr v))))
5909
5910 ;; Unify list, remove nil elements.
5911 (while result
5912 (let ((car (car result)))
5913 (when car
5914 (add-to-list
5915 'result1
5916 (substring car (length (tramp-drop-volume-letter directory)))))
5917 (setq result (cdr result))))
5918
5919 ;; Complete local parts.
5920 (append
5921 result1
5922 (condition-case nil
20b8ac83
MA
5923 (apply (if (tramp-connectable-p fullname)
5924 'tramp-completion-run-real-handler
5925 'tramp-run-real-handler)
5926 'file-name-all-completions (list (list filename directory)))
00d6fd04 5927 (error nil)))))
16674e4f
KG
5928
5929;; Method, host name and user name completion for a file.
a01b1e22 5930;;;###autoload
e1e17cae
MA
5931(defun tramp-completion-handle-file-name-completion
5932 (filename directory &optional predicate)
00d6fd04 5933 "Like `file-name-completion' for Tramp files."
e1e17cae
MA
5934 (try-completion
5935 filename
5936 (mapcar 'list (file-name-all-completions filename directory))
20b8ac83
MA
5937 (when (and predicate
5938 (tramp-connectable-p (expand-file-name filename directory)))
83e20b5c 5939 (lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
16674e4f
KG
5940
5941;; I misuse a little bit the tramp-file-name structure in order to handle
5942;; completion possibilities for partial methods / user names / host names.
5943;; Return value is a list of tramp-file-name structures according to possible
00d6fd04 5944;; completions. If "localname" is non-nil it means there
16674e4f
KG
5945;; shouldn't be a completion anymore.
5946
5947;; Expected results:
5948
00d6fd04
MA
5949;; "/x" "/[x" "/x@" "/[x@" "/x@y" "/[x@y"
5950;; [nil nil "x" nil] [nil "x" nil nil] [nil "x" "y" nil]
5951;; [nil "x" nil nil]
5952;; ["x" nil nil nil]
5953
5954;; "/x:" "/x:y" "/x:y:"
5955;; [nil nil "x" ""] [nil nil "x" "y"] ["x" nil "y" ""]
5956;; "/[x/" "/[x/y"
5957;; ["x" nil "" nil] ["x" nil "y" nil]
5958;; ["x" "" nil nil] ["x" "y" nil nil]
5959
5960;; "/x:y@" "/x:y@z" "/x:y@z:"
5961;; [nil nil "x" "y@"] [nil nil "x" "y@z"] ["x" "y" "z" ""]
5962;; "/[x/y@" "/[x/y@z"
5963;; ["x" nil "y" nil] ["x" "y" "z" nil]
16674e4f
KG
5964(defun tramp-completion-dissect-file-name (name)
5965 "Returns a list of `tramp-file-name' structures.
5966They are collected by `tramp-completion-dissect-file-name1'."
5967
5968 (let* ((result)
4007ba5b 5969 (x-nil "\\|\\(\\)")
b96e6899
MA
5970 (tramp-completion-ipv6-regexp
5971 (format
5972 "[^%s]*"
5973 (if (zerop (length tramp-postfix-ipv6-format))
5974 tramp-postfix-host-format
5975 tramp-postfix-ipv6-format)))
4007ba5b
KG
5976 ;; "/method" "/[method"
5977 (tramp-completion-file-name-structure1
5978 (list (concat tramp-prefix-regexp "\\(" tramp-method-regexp x-nil "\\)$")
5979 1 nil nil nil))
5980 ;; "/user" "/[user"
5981 (tramp-completion-file-name-structure2
5982 (list (concat tramp-prefix-regexp "\\(" tramp-user-regexp x-nil "\\)$")
5983 nil 1 nil nil))
5984 ;; "/host" "/[host"
5985 (tramp-completion-file-name-structure3
5986 (list (concat tramp-prefix-regexp "\\(" tramp-host-regexp x-nil "\\)$")
5987 nil nil 1 nil))
b96e6899 5988 ;; "/[ipv6" "/[ipv6"
4007ba5b 5989 (tramp-completion-file-name-structure4
b96e6899
MA
5990 (list (concat tramp-prefix-regexp
5991 tramp-prefix-ipv6-regexp
5992 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5993 nil nil 1 nil))
5994 ;; "/user@host" "/[user@host"
5995 (tramp-completion-file-name-structure5
4007ba5b
KG
5996 (list (concat tramp-prefix-regexp
5997 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5998 "\\(" tramp-host-regexp x-nil "\\)$")
5999 nil 1 2 nil))
b96e6899
MA
6000 ;; "/user@[ipv6" "/[user@ipv6"
6001 (tramp-completion-file-name-structure6
6002 (list (concat tramp-prefix-regexp
6003 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
6004 tramp-prefix-ipv6-regexp
6005 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
6006 nil 1 2 nil))
00d6fd04 6007 ;; "/method:user" "/[method/user" "/method://user"
b96e6899 6008 (tramp-completion-file-name-structure7
4007ba5b 6009 (list (concat tramp-prefix-regexp
00d6fd04 6010 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
6011 "\\(" tramp-user-regexp x-nil "\\)$")
6012 1 2 nil nil))
00d6fd04 6013 ;; "/method:host" "/[method/host" "/method://host"
b96e6899 6014 (tramp-completion-file-name-structure8
4007ba5b 6015 (list (concat tramp-prefix-regexp
00d6fd04 6016 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
6017 "\\(" tramp-host-regexp x-nil "\\)$")
6018 1 nil 2 nil))
b96e6899
MA
6019 ;; "/method:[ipv6" "/[method/ipv6" "/method://[ipv6"
6020 (tramp-completion-file-name-structure9
6021 (list (concat tramp-prefix-regexp
6022 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
6023 tramp-prefix-ipv6-regexp
6024 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
6025 1 nil 2 nil))
00d6fd04 6026 ;; "/method:user@host" "/[method/user@host" "/method://user@host"
b96e6899 6027 (tramp-completion-file-name-structure10
4007ba5b 6028 (list (concat tramp-prefix-regexp
00d6fd04 6029 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
6030 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
6031 "\\(" tramp-host-regexp x-nil "\\)$")
00d6fd04 6032 1 2 3 nil))
b96e6899
MA
6033 ;; "/method:user@[ipv6" "/[method/user@ipv6" "/method://user@[ipv6"
6034 (tramp-completion-file-name-structure11
6035 (list (concat tramp-prefix-regexp
6036 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
6037 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
6038 tramp-prefix-ipv6-regexp
6039 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
6040 1 2 3 nil))
00d6fd04 6041 ;; "/method: "/method:/"
b96e6899 6042 (tramp-completion-file-name-structure12
00d6fd04
MA
6043 (list
6044 (if (equal tramp-syntax 'url)
6045 (concat tramp-prefix-regexp
6046 "\\(" tramp-method-regexp "\\)"
6047 "\\(" (substring tramp-postfix-method-regexp 0 1)
6048 "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)"
6049 "\\(" "\\)$")
6050 ;; Should not match if not URL syntax.
6051 (concat tramp-prefix-regexp "/$"))
6052 1 3 nil nil))
6053 ;; "/method: "/method:/"
b96e6899 6054 (tramp-completion-file-name-structure13
00d6fd04
MA
6055 (list
6056 (if (equal tramp-syntax 'url)
6057 (concat tramp-prefix-regexp
6058 "\\(" tramp-method-regexp "\\)"
6059 "\\(" (substring tramp-postfix-method-regexp 0 1)
6060 "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)"
6061 "\\(" "\\)$")
6062 ;; Should not match if not URL syntax.
6063 (concat tramp-prefix-regexp "/$"))
6064 1 nil 3 nil)))
4007ba5b 6065
9e6ab520 6066 (mapc (lambda (regexp)
16674e4f
KG
6067 (add-to-list 'result
6068 (tramp-completion-dissect-file-name1 regexp name)))
6069 (list
6070 tramp-completion-file-name-structure1
6071 tramp-completion-file-name-structure2
6072 tramp-completion-file-name-structure3
6073 tramp-completion-file-name-structure4
6074 tramp-completion-file-name-structure5
6075 tramp-completion-file-name-structure6
6076 tramp-completion-file-name-structure7
00d6fd04
MA
6077 tramp-completion-file-name-structure8
6078 tramp-completion-file-name-structure9
b96e6899
MA
6079 tramp-completion-file-name-structure10
6080 tramp-completion-file-name-structure11
6081 tramp-completion-file-name-structure12
6082 tramp-completion-file-name-structure13
16674e4f
KG
6083 tramp-file-name-structure))
6084
6085 (delq nil result)))
6086
6087(defun tramp-completion-dissect-file-name1 (structure name)
6088 "Returns a `tramp-file-name' structure matching STRUCTURE.
00d6fd04 6089The structure consists of remote method, remote user,
7432277c 6090remote host and localname (filename on remote host)."
fb7933a3 6091
00d6fd04
MA
6092 (save-match-data
6093 (when (string-match (nth 0 structure) name)
6094 (let ((method (and (nth 1 structure)
6095 (match-string (nth 1 structure) name)))
6096 (user (and (nth 2 structure)
6097 (match-string (nth 2 structure) name)))
6098 (host (and (nth 3 structure)
6099 (match-string (nth 3 structure) name)))
6100 (localname (and (nth 4 structure)
6101 (match-string (nth 4 structure) name))))
6102 (vector method user host localname)))))
16674e4f
KG
6103
6104;; This function returns all possible method completions, adding the
6105;; trailing method delimeter.
16674e4f
KG
6106(defun tramp-get-completion-methods (partial-method)
6107 "Returns all method completions for PARTIAL-METHOD."
4007ba5b
KG
6108 (mapcar
6109 (lambda (method)
6110 (and method
6111 (string-match (concat "^" (regexp-quote partial-method)) method)
00d6fd04
MA
6112 (tramp-completion-make-tramp-file-name method nil nil nil)))
6113 (mapcar 'car tramp-methods)))
16674e4f
KG
6114
6115;; Compares partial user and host names with possible completions.
6116(defun tramp-get-completion-user-host (method partial-user partial-host user host)
6117 "Returns the most expanded string for user and host name completion.
6118PARTIAL-USER must match USER, PARTIAL-HOST must match HOST."
6119 (cond
6120
6121 ((and partial-user partial-host)
6122 (if (and host
6123 (string-match (concat "^" (regexp-quote partial-host)) host)
6124 (string-equal partial-user (or user partial-user)))
6125 (setq user partial-user)
6126 (setq user nil
6127 host nil)))
6128
6129 (partial-user
6130 (setq host nil)
6131 (unless
6132 (and user (string-match (concat "^" (regexp-quote partial-user)) user))
6133 (setq user nil)))
6134
6135 (partial-host
6136 (setq user nil)
6137 (unless
6138 (and host (string-match (concat "^" (regexp-quote partial-host)) host))
6139 (setq host nil)))
6140
6141 (t (setq user nil
6142 host nil)))
6143
292ffc15 6144 (unless (zerop (+ (length user) (length host)))
00d6fd04 6145 (tramp-completion-make-tramp-file-name method user host nil)))
16674e4f
KG
6146
6147(defun tramp-parse-rhosts (filename)
6148 "Return a list of (user host) tuples allowed to access.
292ffc15 6149Either user or host may be nil."
00d6fd04
MA
6150 ;; On Windows, there are problems in completion when
6151 ;; `default-directory' is remote.
9e6ab520 6152 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 6153 res)
8daea7fc 6154 (when (file-readable-p filename)
16674e4f
KG
6155 (with-temp-buffer
6156 (insert-file-contents filename)
6157 (goto-char (point-min))
6158 (while (not (eobp))
292ffc15 6159 (push (tramp-parse-rhosts-group) res))))
16674e4f
KG
6160 res))
6161
16674e4f
KG
6162(defun tramp-parse-rhosts-group ()
6163 "Return a (user host) tuple allowed to access.
292ffc15 6164Either user or host may be nil."
16674e4f
KG
6165 (let ((result)
6166 (regexp
6167 (concat
6168 "^\\(" tramp-host-regexp "\\)"
6169 "\\([ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
9e6ab520 6170 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
6171 (when (re-search-forward regexp nil t)
6172 (setq result (append (list (match-string 3) (match-string 1)))))
6173 (widen)
6174 (forward-line 1)
6175 result))
6176
6177(defun tramp-parse-shosts (filename)
6178 "Return a list of (user host) tuples allowed to access.
6179User is always nil."
00d6fd04
MA
6180 ;; On Windows, there are problems in completion when
6181 ;; `default-directory' is remote.
9e6ab520 6182 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 6183 res)
8daea7fc 6184 (when (file-readable-p filename)
16674e4f
KG
6185 (with-temp-buffer
6186 (insert-file-contents filename)
6187 (goto-char (point-min))
6188 (while (not (eobp))
292ffc15 6189 (push (tramp-parse-shosts-group) res))))
16674e4f
KG
6190 res))
6191
6192(defun tramp-parse-shosts-group ()
6193 "Return a (user host) tuple allowed to access.
6194User is always nil."
16674e4f
KG
6195 (let ((result)
6196 (regexp (concat "^\\(" tramp-host-regexp "\\)")))
9e6ab520 6197 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
6198 (when (re-search-forward regexp nil t)
6199 (setq result (list nil (match-string 1))))
6200 (widen)
6201 (or
6202 (> (skip-chars-forward ",") 0)
6203 (forward-line 1))
6204 result))
6205
8daea7fc
KG
6206(defun tramp-parse-sconfig (filename)
6207 "Return a list of (user host) tuples allowed to access.
6208User is always nil."
00d6fd04
MA
6209 ;; On Windows, there are problems in completion when
6210 ;; `default-directory' is remote.
9e6ab520 6211 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 6212 res)
8daea7fc
KG
6213 (when (file-readable-p filename)
6214 (with-temp-buffer
6215 (insert-file-contents filename)
6216 (goto-char (point-min))
6217 (while (not (eobp))
6218 (push (tramp-parse-sconfig-group) res))))
6219 res))
6220
6221(defun tramp-parse-sconfig-group ()
6222 "Return a (user host) tuple allowed to access.
6223User is always nil."
8daea7fc
KG
6224 (let ((result)
6225 (regexp (concat "^[ \t]*Host[ \t]+" "\\(" tramp-host-regexp "\\)")))
9e6ab520 6226 (narrow-to-region (point) (tramp-compat-line-end-position))
8daea7fc
KG
6227 (when (re-search-forward regexp nil t)
6228 (setq result (list nil (match-string 1))))
6229 (widen)
6230 (or
6231 (> (skip-chars-forward ",") 0)
6232 (forward-line 1))
6233 result))
6234
5ec2cc41
KG
6235(defun tramp-parse-shostkeys (dirname)
6236 "Return a list of (user host) tuples allowed to access.
6237User is always nil."
00d6fd04
MA
6238 ;; On Windows, there are problems in completion when
6239 ;; `default-directory' is remote.
9e6ab520 6240 (let* ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
6241 (regexp (concat "^key_[0-9]+_\\(" tramp-host-regexp "\\)\\.pub$"))
6242 (files (when (file-directory-p dirname) (directory-files dirname)))
6243 result)
5ec2cc41
KG
6244 (while files
6245 (when (string-match regexp (car files))
6246 (push (list nil (match-string 1 (car files))) result))
6247 (setq files (cdr files)))
6248 result))
6249
6250(defun tramp-parse-sknownhosts (dirname)
6251 "Return a list of (user host) tuples allowed to access.
6252User is always nil."
00d6fd04
MA
6253 ;; On Windows, there are problems in completion when
6254 ;; `default-directory' is remote.
9e6ab520 6255 (let* ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
6256 (regexp (concat "^\\(" tramp-host-regexp
6257 "\\)\\.ssh-\\(dss\\|rsa\\)\\.pub$"))
6258 (files (when (file-directory-p dirname) (directory-files dirname)))
6259 result)
5ec2cc41
KG
6260 (while files
6261 (when (string-match regexp (car files))
6262 (push (list nil (match-string 1 (car files))) result))
6263 (setq files (cdr files)))
6264 result))
6265
16674e4f
KG
6266(defun tramp-parse-hosts (filename)
6267 "Return a list of (user host) tuples allowed to access.
6268User is always nil."
00d6fd04
MA
6269 ;; On Windows, there are problems in completion when
6270 ;; `default-directory' is remote.
9e6ab520 6271 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 6272 res)
8daea7fc 6273 (when (file-readable-p filename)
16674e4f
KG
6274 (with-temp-buffer
6275 (insert-file-contents filename)
6276 (goto-char (point-min))
6277 (while (not (eobp))
292ffc15 6278 (push (tramp-parse-hosts-group) res))))
16674e4f
KG
6279 res))
6280
6281(defun tramp-parse-hosts-group ()
6282 "Return a (user host) tuple allowed to access.
6283User is always nil."
16674e4f 6284 (let ((result)
b96e6899
MA
6285 (regexp
6286 (concat "^\\(" tramp-ipv6-regexp "\\|" tramp-host-regexp "\\)")))
9e6ab520 6287 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f 6288 (when (re-search-forward regexp nil t)
b96e6899 6289 (setq result (list nil (match-string 1))))
16674e4f
KG
6290 (widen)
6291 (or
6292 (> (skip-chars-forward " \t") 0)
6293 (forward-line 1))
6294 result))
6295
8daea7fc
KG
6296;; For su-alike methods it would be desirable to return "root@localhost"
6297;; as default. Unfortunately, we have no information whether any user name
00d6fd04 6298;; has been typed already. So we use `tramp-current-user' as indication,
8daea7fc 6299;; assuming it is set in `tramp-completion-handle-file-name-all-completions'.
16674e4f
KG
6300(defun tramp-parse-passwd (filename)
6301 "Return a list of (user host) tuples allowed to access.
6302Host is always \"localhost\"."
00d6fd04
MA
6303 ;; On Windows, there are problems in completion when
6304 ;; `default-directory' is remote.
9e6ab520 6305 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 6306 res)
8daea7fc 6307 (if (zerop (length tramp-current-user))
16674e4f 6308 '(("root" nil))
8daea7fc 6309 (when (file-readable-p filename)
16674e4f
KG
6310 (with-temp-buffer
6311 (insert-file-contents filename)
6312 (goto-char (point-min))
6313 (while (not (eobp))
292ffc15 6314 (push (tramp-parse-passwd-group) res))))
16674e4f
KG
6315 res)))
6316
6317(defun tramp-parse-passwd-group ()
6318 "Return a (user host) tuple allowed to access.
292ffc15 6319Host is always \"localhost\"."
16674e4f
KG
6320 (let ((result)
6321 (regexp (concat "^\\(" tramp-user-regexp "\\):")))
9e6ab520 6322 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
6323 (when (re-search-forward regexp nil t)
6324 (setq result (list (match-string 1) "localhost")))
6325 (widen)
6326 (forward-line 1)
6327 result))
6328
292ffc15
KG
6329(defun tramp-parse-netrc (filename)
6330 "Return a list of (user host) tuples allowed to access.
6331User may be nil."
00d6fd04
MA
6332 ;; On Windows, there are problems in completion when
6333 ;; `default-directory' is remote.
9e6ab520 6334 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 6335 res)
8daea7fc 6336 (when (file-readable-p filename)
292ffc15
KG
6337 (with-temp-buffer
6338 (insert-file-contents filename)
6339 (goto-char (point-min))
6340 (while (not (eobp))
6341 (push (tramp-parse-netrc-group) res))))
6342 res))
6343
6344(defun tramp-parse-netrc-group ()
6345 "Return a (user host) tuple allowed to access.
6346User may be nil."
292ffc15
KG
6347 (let ((result)
6348 (regexp
6349 (concat
6350 "^[ \t]*machine[ \t]+" "\\(" tramp-host-regexp "\\)"
6351 "\\([ \t]+login[ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
9e6ab520 6352 (narrow-to-region (point) (tramp-compat-line-end-position))
292ffc15
KG
6353 (when (re-search-forward regexp nil t)
6354 (setq result (list (match-string 3) (match-string 1))))
6355 (widen)
6356 (forward-line 1)
6357 result))
6358
00d6fd04
MA
6359(defun tramp-parse-putty (registry)
6360 "Return a list of (user host) tuples allowed to access.
6361User is always nil."
6362 ;; On Windows, there are problems in completion when
6363 ;; `default-directory' is remote.
9e6ab520 6364 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
6365 res)
6366 (with-temp-buffer
a4aeb9a4 6367 (when (zerop (tramp-local-call-process "reg" nil t nil "query" registry))
00d6fd04
MA
6368 (goto-char (point-min))
6369 (while (not (eobp))
6370 (push (tramp-parse-putty-group registry) res))))
6371 res))
6372
6373(defun tramp-parse-putty-group (registry)
6374 "Return a (user host) tuple allowed to access.
6375User is always nil."
6376 (let ((result)
6377 (regexp (concat (regexp-quote registry) "\\\\\\(.+\\)")))
9e6ab520 6378 (narrow-to-region (point) (tramp-compat-line-end-position))
00d6fd04
MA
6379 (when (re-search-forward regexp nil t)
6380 (setq result (list nil (match-string 1))))
6381 (widen)
6382 (forward-line 1)
6383 result))
6384
fb7933a3
KG
6385;;; Internal Functions:
6386
00d6fd04
MA
6387(defun tramp-maybe-send-script (vec script name)
6388 "Define in remote shell function NAME implemented as SCRIPT.
6389Only send the definition if it has not already been done."
6390 (let* ((p (tramp-get-connection-process vec))
6391 (scripts (tramp-get-connection-property p "scripts" nil)))
1834b39f 6392 (unless (member name scripts)
20b8ac83
MA
6393 (with-progress-reporter vec 5 (format "Sending script `%s'" name)
6394 ;; The script could contain a call of Perl. This is masked with `%s'.
6395 (tramp-send-command-and-check
6396 vec
6397 (format "%s () {\n%s\n}" name
6398 (format script (tramp-get-remote-perl vec))))
6399 (tramp-set-connection-property p "scripts" (cons name scripts))))))
c82c5727 6400
fb7933a3 6401(defun tramp-set-auto-save ()
00d6fd04 6402 (when (and ;; ange-ftp has its own auto-save mechanism
7177e2a3
MA
6403 (eq (tramp-find-foreign-file-name-handler (buffer-file-name))
6404 'tramp-sh-file-name-handler)
fb7933a3
KG
6405 auto-save-default)
6406 (auto-save-mode 1)))
6407(add-hook 'find-file-hooks 'tramp-set-auto-save t)
a69c01a0 6408(add-hook 'tramp-unload-hook
aa485f7c
MA
6409 (lambda ()
6410 (remove-hook 'find-file-hooks 'tramp-set-auto-save)))
fb7933a3
KG
6411
6412(defun tramp-run-test (switch filename)
6413 "Run `test' on the remote system, given a SWITCH and a FILENAME.
6414Returns the exit code of the `test' program."
00d6fd04
MA
6415 (with-parsed-tramp-file-name filename nil
6416 (tramp-send-command-and-check
6417 v
6418 (format
6419 "%s %s %s"
6420 (tramp-get-test-command v)
6421 switch
6422 (tramp-shell-quote-argument localname)))))
6423
6424(defun tramp-run-test2 (format-string file1 file2)
6425 "Run `test'-like program on the remote system, given FILE1, FILE2.
6426FORMAT-STRING contains the program name, switches, and place holders.
6427Returns the exit code of the `test' program. Barfs if the methods,
fb7933a3 6428hosts, or files, disagree."
00d6fd04
MA
6429 (unless (tramp-equal-remote file1 file2)
6430 (with-parsed-tramp-file-name (if (tramp-tramp-file-p file1) file1 file2) nil
6431 (tramp-error
6432 v 'file-error
6433 "tramp-run-test2 only implemented for same method, user, host")))
6434 (with-parsed-tramp-file-name file1 v1
6435 (with-parsed-tramp-file-name file1 v2
fb7933a3 6436 (tramp-send-command-and-check
00d6fd04
MA
6437 v1
6438 (format format-string
6439 (tramp-shell-quote-argument v1-localname)
6440 (tramp-shell-quote-argument v2-localname))))))
fb7933a3 6441
00d6fd04
MA
6442(defun tramp-buffer-name (vec)
6443 "A name for the connection buffer VEC."
6444 ;; We must use `tramp-file-name-real-host', because for gateway
6445 ;; methods the default port will be expanded later on, which would
6446 ;; tamper the name.
6447 (let ((method (tramp-file-name-method vec))
6448 (user (tramp-file-name-user vec))
6449 (host (tramp-file-name-real-host vec)))
6450 (if (not (zerop (length user)))
6451 (format "*tramp/%s %s@%s*" method user host)
6452 (format "*tramp/%s %s*" method host))))
6453
b88f2d0a
MA
6454(defun tramp-delete-temp-file-function ()
6455 "Remove temporary files related to current buffer."
6456 (when (stringp tramp-temp-buffer-file-name)
6457 (condition-case nil
6458 (delete-file tramp-temp-buffer-file-name)
6459 (error nil))))
6460
6461(add-hook 'kill-buffer-hook 'tramp-delete-temp-file-function)
6462(add-hook 'tramp-cache-unload-hook
6463 (lambda ()
6464 (remove-hook 'kill-buffer-hook
6465 'tramp-delete-temp-file-function)))
6466
00d6fd04
MA
6467(defun tramp-get-buffer (vec)
6468 "Get the connection buffer to be used for VEC."
6469 (or (get-buffer (tramp-buffer-name vec))
6470 (with-current-buffer (get-buffer-create (tramp-buffer-name vec))
6471 (setq buffer-undo-list t)
6472 (setq default-directory
6473 (tramp-make-tramp-file-name
6474 (tramp-file-name-method vec)
6475 (tramp-file-name-user vec)
6476 (tramp-file-name-host vec)
6477 "/"))
6478 (current-buffer))))
6479
6480(defun tramp-get-connection-buffer (vec)
6481 "Get the connection buffer to be used for VEC.
6482In case a second asynchronous communication has been started, it is different
6483from `tramp-get-buffer'."
6484 (or (tramp-get-connection-property vec "process-buffer" nil)
6485 (tramp-get-buffer vec)))
6486
6487(defun tramp-get-connection-process (vec)
6488 "Get the connection process to be used for VEC.
6489In case a second asynchronous communication has been started, it is different
6490from the default one."
6491 (get-process
6492 (or (tramp-get-connection-property vec "process-name" nil)
6493 (tramp-buffer-name vec))))
6494
6495(defun tramp-debug-buffer-name (vec)
6496 "A name for the debug buffer for VEC."
6497 ;; We must use `tramp-file-name-real-host', because for gateway
6498 ;; methods the default port will be expanded later on, which would
6499 ;; tamper the name.
6500 (let ((method (tramp-file-name-method vec))
6501 (user (tramp-file-name-user vec))
6502 (host (tramp-file-name-real-host vec)))
6503 (if (not (zerop (length user)))
6504 (format "*debug tramp/%s %s@%s*" method user host)
6505 (format "*debug tramp/%s %s*" method host))))
6506
20b8ac83
MA
6507(defconst tramp-debug-outline-regexp
6508 "[0-9]+:[0-9]+:[0-9]+\\.[0-9]+ [a-z0-9-]+ (\\([0-9]+\\)) #")
6509
00d6fd04
MA
6510(defun tramp-get-debug-buffer (vec)
6511 "Get the debug buffer for VEC."
01917a18 6512 (with-current-buffer
00d6fd04
MA
6513 (get-buffer-create (tramp-debug-buffer-name vec))
6514 (when (bobp)
6515 (setq buffer-undo-list t)
20b8ac83 6516 ;; Activate `outline-mode'. This runs `text-mode-hook' and
9ce8462a 6517 ;; `outline-mode-hook'. We must prevent that local processes
20b8ac83
MA
6518 ;; die. Yes: I've seen `flyspell-mode', which starts "ispell".
6519 ;; Furthermore, `outline-regexp' must have the correct value
6520 ;; already, because it is used by `font-lock-compile-keywords'.
6521 (let ((default-directory (tramp-compat-temporary-file-directory))
6522 (outline-regexp tramp-debug-outline-regexp))
00d6fd04 6523 (outline-mode))
20b8ac83 6524 (set (make-local-variable 'outline-regexp) tramp-debug-outline-regexp)
9ce8462a 6525 (set (make-local-variable 'outline-level) 'tramp-outline-level))
01917a18 6526 (current-buffer)))
fb7933a3 6527
00d6fd04
MA
6528(defun tramp-outline-level ()
6529 "Return the depth to which a statement is nested in the outline.
6530Point must be at the beginning of a header line.
6531
6532The outline level is equal to the verbosity of the Tramp message."
6533 (1+ (string-to-number (match-string 1))))
fb7933a3 6534
00d6fd04
MA
6535(defun tramp-find-executable
6536 (vec progname dirlist &optional ignore-tilde ignore-path)
6537 "Searches for PROGNAME in $PATH and all directories mentioned in DIRLIST.
6538First arg VEC specifies the connection, PROGNAME is the program
6539to search for, and DIRLIST gives the list of directories to
6540search. If IGNORE-TILDE is non-nil, directory names starting
6541with `~' will be ignored. If IGNORE-PATH is non-nil, searches
6542only in DIRLIST.
fb7933a3 6543
7432277c 6544Returns the absolute file name of PROGNAME, if found, and nil otherwise.
fb7933a3
KG
6545
6546This function expects to be in the right *tramp* buffer."
c0e17ff2 6547 (with-current-buffer (tramp-get-connection-buffer vec)
00d6fd04
MA
6548 (let (result)
6549 ;; Check whether the executable is in $PATH. "which(1)" does not
6550 ;; report always a correct error code; therefore we check the
6551 ;; number of words it returns.
6552 (unless ignore-path
6553 (tramp-send-command vec (format "which \\%s | wc -w" progname))
6554 (goto-char (point-min))
c0e17ff2 6555 (if (looking-at "^\\s-*1$")
00d6fd04
MA
6556 (setq result (concat "\\" progname))))
6557 (unless result
6558 (when ignore-tilde
20b8ac83 6559 ;; Remove all ~/foo directories from dirlist. In XEmacs,
00d6fd04
MA
6560 ;; `remove' is in CL, and we want to avoid CL dependencies.
6561 (let (newdl d)
6562 (while dirlist
6563 (setq d (car dirlist))
6564 (setq dirlist (cdr dirlist))
6565 (unless (char-equal ?~ (aref d 0))
6566 (setq newdl (cons d newdl))))
6567 (setq dirlist (nreverse newdl))))
6568 (tramp-send-command
6569 vec
6570 (format (concat "while read d; "
6571 "do if test -x $d/%s -a -f $d/%s; "
6572 "then echo tramp_executable $d/%s; "
6573 "break; fi; done <<'EOF'\n"
6574 "%s\nEOF")
6575 progname progname progname (mapconcat 'identity dirlist "\n")))
6576 (goto-char (point-max))
6577 (when (search-backward "tramp_executable " nil t)
6578 (skip-chars-forward "^ ")
6579 (skip-chars-forward " ")
9e6ab520
MA
6580 (setq result (buffer-substring
6581 (point) (tramp-compat-line-end-position)))))
00d6fd04
MA
6582 result)))
6583
6584(defun tramp-set-remote-path (vec)
6585 "Sets the remote environment PATH to existing directories.
6586I.e., for each directory in `tramp-remote-path', it is tested
6587whether it exists and if so, it is added to the environment
6588variable PATH."
6589 (tramp-message vec 5 (format "Setting $PATH environment variable"))
f84638eb
MA
6590 (tramp-send-command
6591 vec (format "PATH=%s; export PATH"
6592 (mapconcat 'identity (tramp-get-remote-path vec) ":"))))
fb7933a3 6593
cfb5c0db
MA
6594;; ------------------------------------------------------------
6595;; -- Communication with external shell --
6596;; ------------------------------------------------------------
fb7933a3 6597
00d6fd04 6598(defun tramp-find-file-exists-command (vec)
fb7933a3
KG
6599 "Find a command on the remote host for checking if a file exists.
6600Here, we are looking for a command which has zero exit status if the
6601file exists and nonzero exit status otherwise."
00d6fd04 6602 (let ((existing "/")
fb7933a3 6603 (nonexisting
00d6fd04
MA
6604 (tramp-shell-quote-argument "/ this file does not exist "))
6605 result)
fb7933a3
KG
6606 ;; The algorithm is as follows: we try a list of several commands.
6607 ;; For each command, we first run `$cmd /' -- this should return
6608 ;; true, as the root directory always exists. And then we run
00d6fd04 6609 ;; `$cmd /this\ file\ does\ not\ exist ', hoping that the file indeed
fb7933a3
KG
6610 ;; does not exist. This should return false. We use the first
6611 ;; command we find that seems to work.
6612 ;; The list of commands to try is as follows:
00d6fd04
MA
6613 ;; `ls -d' This works on most systems, but NetBSD 1.4
6614 ;; has a bug: `ls' always returns zero exit
6615 ;; status, even for files which don't exist.
6616 ;; `test -e' Some Bourne shells have a `test' builtin
6617 ;; which does not know the `-e' option.
6618 ;; `/bin/test -e' For those, the `test' binary on disk normally
6619 ;; provides the option. Alas, the binary
6620 ;; is sometimes `/bin/test' and sometimes it's
6621 ;; `/usr/bin/test'.
6622 ;; `/usr/bin/test -e' In case `/bin/test' does not exist.
fb7933a3 6623 (unless (or
00d6fd04
MA
6624 (and (setq result (format "%s -e" (tramp-get-test-command vec)))
6625 (zerop (tramp-send-command-and-check
6626 vec (format "%s %s" result existing)))
6627 (not (zerop (tramp-send-command-and-check
6628 vec (format "%s %s" result nonexisting)))))
6629 (and (setq result "/bin/test -e")
6630 (zerop (tramp-send-command-and-check
6631 vec (format "%s %s" result existing)))
6632 (not (zerop (tramp-send-command-and-check
6633 vec (format "%s %s" result nonexisting)))))
6634 (and (setq result "/usr/bin/test -e")
6635 (zerop (tramp-send-command-and-check
6636 vec (format "%s %s" result existing)))
6637 (not (zerop (tramp-send-command-and-check
6638 vec (format "%s %s" result nonexisting)))))
6639 (and (setq result (format "%s -d" (tramp-get-ls-command vec)))
6640 (zerop (tramp-send-command-and-check
6641 vec (format "%s %s" result existing)))
6642 (not (zerop (tramp-send-command-and-check
6643 vec (format "%s %s" result nonexisting))))))
6644 (tramp-error
6645 vec 'file-error "Couldn't find command to check if file exists"))
6646 result))
bf247b6e 6647
20b8ac83
MA
6648(defun tramp-open-shell (vec shell)
6649 "Opens shell SHELL."
6650 (with-progress-reporter vec 5 (format "Opening remote shell `%s'" shell)
6651 ;; Find arguments for this shell.
6652 (let ((tramp-end-of-output tramp-initial-end-of-output)
6653 (alist tramp-sh-extra-args)
6654 item extra-args)
6655 (while (and alist (null extra-args))
6656 (setq item (pop alist))
6657 (when (string-match (car item) shell)
6658 (setq extra-args (cdr item))))
6659 (when extra-args (setq shell (concat shell " " extra-args)))
6660 (tramp-send-command
6661 vec (format "exec env ENV='' PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s"
6662 (shell-quote-argument tramp-end-of-output) shell)
6663 t))
6664 ;; Setting prompts.
6665 (tramp-send-command
6666 vec (format "PS1=%s" (shell-quote-argument tramp-end-of-output)) t)
6667 (tramp-send-command vec "PS2=''" t)
6668 (tramp-send-command vec "PS3=''" t)
6669 (tramp-send-command vec "PROMPT_COMMAND=''" t)))
6670
00d6fd04
MA
6671(defun tramp-find-shell (vec)
6672 "Opens a shell on the remote host which groks tilde expansion."
6673 (unless (tramp-get-connection-property vec "remote-shell" nil)
6674 (let (shell)
6675 (with-current-buffer (tramp-get-buffer vec)
7e780ff1 6676 (tramp-send-command vec "echo ~root" t)
00d6fd04 6677 (cond
c0e17ff2
MA
6678 ((or (string-match "^~root$" (buffer-string))
6679 ;; The default shell (ksh93) of OpenSolaris is buggy.
6680 (string-equal (tramp-get-connection-property vec "uname" "")
6681 "SunOS 5.11"))
00d6fd04 6682 (setq shell
f84638eb 6683 (or (tramp-find-executable
c0e17ff2 6684 vec "bash" (tramp-get-remote-path vec) t t)
f84638eb 6685 (tramp-find-executable
c0e17ff2 6686 vec "ksh" (tramp-get-remote-path vec) t t)))
00d6fd04
MA
6687 (unless shell
6688 (tramp-error
6689 vec 'file-error
6690 "Couldn't find a shell which groks tilde expansion"))
00d6fd04 6691 (tramp-message
20b8ac83
MA
6692 vec 5 "Starting remote shell `%s' for tilde expansion" shell)
6693 (tramp-open-shell vec shell))
a0a5183a 6694
00d6fd04
MA
6695 (t (tramp-message
6696 vec 5 "Remote `%s' groks tilde expansion, good"
20b8ac83
MA
6697 (tramp-set-connection-property
6698 vec "remote-shell"
6699 (tramp-get-method-parameter
6700 (tramp-file-name-method vec) 'tramp-remote-sh)))))))))
fb7933a3 6701
bf247b6e
KS
6702;; ------------------------------------------------------------
6703;; -- Functions for establishing connection --
6704;; ------------------------------------------------------------
fb7933a3 6705
ac474af1
KG
6706;; The following functions are actions to be taken when seeing certain
6707;; prompts from the remote host. See the variable
6708;; `tramp-actions-before-shell' for usage of these functions.
6709
00d6fd04 6710(defun tramp-action-login (proc vec)
ac474af1 6711 "Send the login name."
00d6fd04
MA
6712 (when (not (stringp tramp-current-user))
6713 (save-window-excursion
6714 (let ((enable-recursive-minibuffers t))
6715 (pop-to-buffer (tramp-get-connection-buffer vec))
6716 (setq tramp-current-user (read-string (match-string 0))))))
6717 (tramp-message vec 3 "Sending login name `%s'" tramp-current-user)
6718 (with-current-buffer (tramp-get-connection-buffer vec)
6719 (tramp-message vec 6 "\n%s" (buffer-string)))
6720 (tramp-send-string vec tramp-current-user))
6721
6722(defun tramp-action-password (proc vec)
ac474af1 6723 "Query the user for a password."
70c11b0b
MA
6724 (with-current-buffer (process-buffer proc)
6725 (tramp-check-for-regexp proc tramp-password-prompt-regexp)
20b8ac83
MA
6726 (tramp-message vec 3 "Sending %s" (match-string 1))
6727 (tramp-enter-password proc)
158d5945
MA
6728 ;; Hide password prompt.
6729 (narrow-to-region (point-max) (point-max))))
00d6fd04
MA
6730
6731(defun tramp-action-succeed (proc vec)
ac474af1 6732 "Signal success in finding shell prompt."
ac474af1
KG
6733 (throw 'tramp-action 'ok))
6734
00d6fd04 6735(defun tramp-action-permission-denied (proc vec)
ac474af1 6736 "Signal permission denied."
00d6fd04 6737 (kill-process proc)
ac474af1
KG
6738 (throw 'tramp-action 'permission-denied))
6739
00d6fd04 6740(defun tramp-action-yesno (proc vec)
3cdaec13
KG
6741 "Ask the user for confirmation using `yes-or-no-p'.
6742Send \"yes\" to remote process on confirmation, abort otherwise.
6743See also `tramp-action-yn'."
ac474af1 6744 (save-window-excursion
00d6fd04
MA
6745 (let ((enable-recursive-minibuffers t))
6746 (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec)))
6747 (unless (yes-or-no-p (match-string 0))
6748 (kill-process proc)
6749 (throw 'tramp-action 'permission-denied))
6750 (with-current-buffer (tramp-get-connection-buffer vec)
6751 (tramp-message vec 6 "\n%s" (buffer-string)))
6752 (tramp-send-string vec "yes"))))
6753
6754(defun tramp-action-yn (proc vec)
3cdaec13
KG
6755 "Ask the user for confirmation using `y-or-n-p'.
6756Send \"y\" to remote process on confirmation, abort otherwise.
6757See also `tramp-action-yesno'."
6758 (save-window-excursion
00d6fd04
MA
6759 (let ((enable-recursive-minibuffers t))
6760 (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec)))
6761 (unless (y-or-n-p (match-string 0))
6762 (kill-process proc)
6763 (throw 'tramp-action 'permission-denied))
6764 (with-current-buffer (tramp-get-connection-buffer vec)
6765 (tramp-message vec 6 "\n%s" (buffer-string)))
6766 (tramp-send-string vec "y"))))
6767
6768(defun tramp-action-terminal (proc vec)
487f4fb7
KG
6769 "Tell the remote host which terminal type to use.
6770The terminal type can be configured with `tramp-terminal-type'."
00d6fd04 6771 (tramp-message vec 5 "Setting `%s' as terminal type." tramp-terminal-type)
7e780ff1
MA
6772 (with-current-buffer (tramp-get-connection-buffer vec)
6773 (tramp-message vec 6 "\n%s" (buffer-string)))
00d6fd04 6774 (tramp-send-string vec tramp-terminal-type))
487f4fb7 6775
00d6fd04 6776(defun tramp-action-process-alive (proc vec)
20b8ac83 6777 "Check, whether a process has finished."
00d6fd04 6778 (unless (memq (process-status proc) '(run open))
19a87064
MA
6779 (throw 'tramp-action 'process-died)))
6780
00d6fd04 6781(defun tramp-action-out-of-band (proc vec)
20b8ac83 6782 "Check, whether an out-of-band copy has finished."
00d6fd04
MA
6783 (cond ((and (memq (process-status proc) '(stop exit))
6784 (zerop (process-exit-status proc)))
6785 (tramp-message vec 3 "Process has finished.")
38c65fca 6786 (throw 'tramp-action 'ok))
00d6fd04
MA
6787 ((or (and (memq (process-status proc) '(stop exit))
6788 (not (zerop (process-exit-status proc))))
6789 (memq (process-status proc) '(signal)))
01917a18
MA
6790 ;; `scp' could have copied correctly, but set modes could have failed.
6791 ;; This can be ignored.
00d6fd04
MA
6792 (with-current-buffer (process-buffer proc)
6793 (goto-char (point-min))
6794 (if (re-search-forward tramp-operation-not-permitted-regexp nil t)
6795 (progn
6796 (tramp-message vec 5 "'set mode' error ignored.")
6797 (tramp-message vec 3 "Process has finished.")
6798 (throw 'tramp-action 'ok))
6799 (tramp-message vec 3 "Process has died.")
6800 (throw 'tramp-action 'process-died))))
38c65fca
KG
6801 (t nil)))
6802
ac474af1
KG
6803;; Functions for processing the actions.
6804
00d6fd04 6805(defun tramp-process-one-action (proc vec actions)
ac474af1 6806 "Wait for output from the shell and perform one action."
00d6fd04 6807 (let (found todo item pattern action)
e6466697 6808 (while (not found)
00d6fd04
MA
6809 ;; Reread output once all actions have been performed.
6810 ;; Obviously, the output was not complete.
6811 (tramp-accept-process-output proc 1)
e6466697
MA
6812 (setq todo actions)
6813 (while todo
e6466697 6814 (setq item (pop todo))
95d610cb 6815 (setq pattern (format "\\(%s\\)\\'" (symbol-value (nth 0 item))))
e6466697 6816 (setq action (nth 1 item))
00d6fd04
MA
6817 (tramp-message
6818 vec 5 "Looking for regexp \"%s\" from remote shell" pattern)
6819 (when (tramp-check-for-regexp proc pattern)
6820 (tramp-message vec 5 "Call `%s'" (symbol-name action))
6821 (setq found (funcall action proc vec)))))
e6466697
MA
6822 found))
6823
00d6fd04 6824(defun tramp-process-actions (proc vec actions &optional timeout)
e6466697 6825 "Perform actions until success or TIMEOUT."
20b8ac83
MA
6826 ;; Preserve message for `progress-reporter'.
6827 (with-temp-message ""
6828 ;; Enable auth-source and password-cache.
6829 (tramp-set-connection-property vec "first-password-request" t)
158d5945
MA
6830 (save-restriction
6831 (let (exit)
6832 (while (not exit)
6833 (tramp-message proc 3 "Waiting for prompts from remote shell")
6834 (setq exit
6835 (catch 'tramp-action
6836 (if timeout
6837 (with-timeout (timeout)
6838 (tramp-process-one-action proc vec actions))
6839 (tramp-process-one-action proc vec actions)))))
6840 (with-current-buffer (tramp-get-connection-buffer vec)
6841 (widen)
6842 (tramp-message vec 6 "\n%s" (buffer-string)))
6843 (unless (eq exit 'ok)
6844 (tramp-clear-passwd vec)
6845 (tramp-error-with-buffer
6846 nil vec 'file-error
6847 (cond
6848 ((eq exit 'permission-denied) "Permission denied")
6849 ((eq exit 'process-died) "Process died")
6850 (t "Login failed"))))))))
fb7933a3
KG
6851
6852;; Utility functions.
6853
00d6fd04 6854(defun tramp-accept-process-output (&optional proc timeout timeout-msecs)
d2a2c17f
MA
6855 "Like `accept-process-output' for Tramp processes.
6856This is needed in order to hide `last-coding-system-used', which is set
6857for process communication also."
00d6fd04
MA
6858 (with-current-buffer (process-buffer proc)
6859 (tramp-message proc 10 "%s %s" proc (process-status proc))
6860 (let (buffer-read-only last-coding-system-used)
6861 ;; Under Windows XP, accept-process-output doesn't return
6862 ;; sometimes. So we add an additional timeout.
6863 (with-timeout ((or timeout 1))
6864 (accept-process-output proc timeout timeout-msecs)))
6865 (tramp-message proc 10 "\n%s" (buffer-string))))
6866
6867(defun tramp-check-for-regexp (proc regexp)
20b8ac83 6868 "Check, whether REGEXP is contained in process buffer of PROC.
00d6fd04
MA
6869Erase echoed commands if exists."
6870 (with-current-buffer (process-buffer proc)
6871 (goto-char (point-min))
674da028 6872
00d6fd04
MA
6873 ;; Check whether we need to remove echo output.
6874 (when (and (tramp-get-connection-property proc "check-remote-echo" nil)
6875 (re-search-forward tramp-echoed-echo-mark-regexp nil t))
6876 (let ((begin (match-beginning 0)))
6877 (when (re-search-forward tramp-echoed-echo-mark-regexp nil t)
6878 ;; Discard echo from remote output.
6879 (tramp-set-connection-property proc "check-remote-echo" nil)
6880 (tramp-message proc 5 "echo-mark found")
20b8ac83 6881 (forward-line 1)
00d6fd04
MA
6882 (delete-region begin (point))
6883 (goto-char (point-min)))))
674da028 6884
68712eb6
MA
6885 (when (or (not (tramp-get-connection-property proc "check-remote-echo" nil))
6886 ;; Sometimes, the echo string is suppressed on the remote side.
6887 (not (string-equal
20b8ac83
MA
6888 (tramp-compat-funcall
6889 'substring-no-properties tramp-echo-mark-marker
68712eb6 6890 0 (min tramp-echo-mark-marker-length (1- (point-max))))
20b8ac83
MA
6891 (tramp-compat-funcall
6892 'buffer-substring-no-properties
68712eb6 6893 1 (min (1+ tramp-echo-mark-marker-length) (point-max))))))
70c11b0b 6894 ;; No echo to be handled, now we can look for the regexp.
674da028 6895 (goto-char (point-min))
00d6fd04 6896 (re-search-forward regexp nil t))))
d2a2c17f 6897
fb7933a3
KG
6898(defun tramp-wait-for-regexp (proc timeout regexp)
6899 "Wait for a REGEXP to appear from process PROC within TIMEOUT seconds.
6900Expects the output of PROC to be sent to the current buffer. Returns
6901the string that matched, or nil. Waits indefinitely if TIMEOUT is
6902nil."
00d6fd04
MA
6903 (with-current-buffer (process-buffer proc)
6904 (let ((found (tramp-check-for-regexp proc regexp))
6905 (start-time (current-time)))
6906 (cond (timeout
6907 ;; Work around a bug in XEmacs 21, where the timeout
6908 ;; expires faster than it should. This degenerates
6909 ;; to polling for buggy XEmacsen, but oh, well.
6910 (while (and (not found)
6911 (< (tramp-time-diff (current-time) start-time)
6912 timeout))
6913 (with-timeout (timeout)
6914 (while (not found)
6915 (tramp-accept-process-output proc 1)
6916 (unless (memq (process-status proc) '(run open))
6917 (tramp-error-with-buffer
6918 nil proc 'file-error "Process has died"))
6919 (setq found (tramp-check-for-regexp proc regexp))))))
6920 (t
6921 (while (not found)
6922 (tramp-accept-process-output proc 1)
6923 (unless (memq (process-status proc) '(run open))
6924 (tramp-error-with-buffer
6925 nil proc 'file-error "Process has died"))
6926 (setq found (tramp-check-for-regexp proc regexp)))))
6927 (tramp-message proc 6 "\n%s" (buffer-string))
fb7933a3 6928 (when (not found)
00d6fd04
MA
6929 (if timeout
6930 (tramp-error
6931 proc 'file-error "[[Regexp `%s' not found in %d secs]]"
6932 regexp timeout)
6933 (tramp-error proc 'file-error "[[Regexp `%s' not found]]" regexp)))
6934 found)))
fb7933a3 6935
b25a52cc
KG
6936(defun tramp-barf-if-no-shell-prompt (proc timeout &rest error-args)
6937 "Wait for shell prompt and barf if none appears.
6938Looks at process PROC to see if a shell prompt appears in TIMEOUT
6939seconds. If not, it produces an error message with the given ERROR-ARGS."
7e780ff1
MA
6940 (unless
6941 (tramp-wait-for-regexp
6942 proc timeout
6943 (format
6944 "\\(%s\\|%s\\)\\'" shell-prompt-pattern tramp-shell-prompt-pattern))
00d6fd04
MA
6945 (apply 'tramp-error-with-buffer nil proc 'file-error error-args)))
6946
7e780ff1
MA
6947;; We don't call `tramp-send-string' in order to hide the password
6948;; from the debug buffer, and because end-of-line handling of the
6949;; string.
6950(defun tramp-enter-password (proc)
00d6fd04
MA
6951 "Prompt for a password and send it to the remote end."
6952 (process-send-string
7e780ff1
MA
6953 proc (concat (tramp-read-passwd proc)
6954 (or (tramp-get-method-parameter
6955 tramp-current-method
6956 'tramp-password-end-of-line)
6957 tramp-default-password-end-of-line))))
00d6fd04
MA
6958
6959(defun tramp-open-connection-setup-interactive-shell (proc vec)
fb7933a3 6960 "Set up an interactive shell.
00d6fd04
MA
6961Mainly sets the prompt and the echo correctly. PROC is the shell
6962process to set up. VEC specifies the connection."
dab816a9 6963 (let ((tramp-end-of-output tramp-initial-end-of-output))
8950769a
MA
6964 ;; It is useful to set the prompt in the following command because
6965 ;; some people have a setting for $PS1 which /bin/sh doesn't know
6966 ;; about and thus /bin/sh will display a strange prompt. For
6967 ;; example, if $PS1 has "${CWD}" in the value, then ksh will
6968 ;; display the current working directory but /bin/sh will display
6969 ;; a dollar sign. The following command line sets $PS1 to a sane
6970 ;; value, and works under Bourne-ish shells as well as csh-like
6971 ;; shells. Daniel Pittman reports that the unusual positioning of
6972 ;; the single quotes makes it work under `rc', too. We also unset
6973 ;; the variable $ENV because that is read by some sh
6974 ;; implementations (eg, bash when called as sh) on startup; this
6975 ;; way, we avoid the startup file clobbering $PS1. $PROMP_COMMAND
6976 ;; is another way to set the prompt in /bin/bash, it must be
6977 ;; discarded as well.
20b8ac83 6978 (tramp-open-shell
a4aeb9a4 6979 vec
20b8ac83 6980 (tramp-get-method-parameter (tramp-file-name-method vec) 'tramp-remote-sh))
8950769a
MA
6981
6982 ;; Disable echo.
6983 (tramp-message vec 5 "Setting up remote shell environment")
6984 (tramp-send-command vec "stty -inlcr -echo kill '^U' erase '^H'" t)
6985 ;; Check whether the echo has really been disabled. Some
6986 ;; implementations, like busybox of embedded GNU/Linux, don't
6987 ;; support disabling.
6988 (tramp-send-command vec "echo foo" t)
6989 (with-current-buffer (process-buffer proc)
6990 (goto-char (point-min))
6991 (when (looking-at "echo foo")
6992 (tramp-set-connection-property proc "remote-echo" t)
6993 (tramp-message vec 5 "Remote echo still on. Ok.")
6994 ;; Make sure backspaces and their echo are enabled and no line
6995 ;; width magic interferes with them.
6996 (tramp-send-command vec "stty icanon erase ^H cols 32767" t))))
e42c6bbc 6997
7e780ff1 6998 (tramp-message vec 5 "Setting shell prompt")
70c11b0b
MA
6999 (tramp-send-command
7000 vec (format "PS1=%s" (shell-quote-argument tramp-end-of-output)) t)
9fa0d3aa
MA
7001 (tramp-send-command vec "PS2=''" t)
7002 (tramp-send-command vec "PS3=''" t)
7003 (tramp-send-command vec "PROMPT_COMMAND=''" t)
e42c6bbc 7004
fb7933a3
KG
7005 ;; Try to set up the coding system correctly.
7006 ;; CCC this can't be the right way to do it. Hm.
00d6fd04 7007 (tramp-message vec 5 "Determining coding system")
7e780ff1 7008 (tramp-send-command vec "echo foo ; echo bar" t)
00d6fd04 7009 (with-current-buffer (process-buffer proc)
fb7933a3
KG
7010 (goto-char (point-min))
7011 (if (featurep 'mule)
00d6fd04
MA
7012 ;; Use MULE to select the right EOL convention for communicating
7013 ;; with the process.
20b8ac83 7014 (let* ((cs (or (tramp-compat-funcall 'process-coding-system proc)
00d6fd04
MA
7015 (cons 'undecided 'undecided)))
7016 cs-decode cs-encode)
7017 (when (symbolp cs) (setq cs (cons cs cs)))
7018 (setq cs-decode (car cs))
7019 (setq cs-encode (cdr cs))
7020 (unless cs-decode (setq cs-decode 'undecided))
7021 (unless cs-encode (setq cs-encode 'undecided))
7022 (setq cs-encode (tramp-coding-system-change-eol-conversion
7023 cs-encode 'unix))
7024 (when (search-forward "\r" nil t)
7025 (setq cs-decode (tramp-coding-system-change-eol-conversion
7026 cs-decode 'dos)))
20b8ac83
MA
7027 (tramp-compat-funcall
7028 'set-buffer-process-coding-system cs-decode cs-encode)
70c11b0b
MA
7029 (tramp-message
7030 vec 5 "Setting coding system to `%s' and `%s'" cs-decode cs-encode))
fb7933a3
KG
7031 ;; Look for ^M and do something useful if found.
7032 (when (search-forward "\r" nil t)
00d6fd04
MA
7033 ;; We have found a ^M but cannot frob the process coding system
7034 ;; because we're running on a non-MULE Emacs. Let's try
7035 ;; stty, instead.
7e780ff1 7036 (tramp-send-command vec "stty -onlcr" t))))
e499c64d 7037
7e780ff1 7038 (tramp-send-command vec "set +o vi +o emacs" t)
e42c6bbc
MA
7039
7040 ;; Check whether the output of "uname -sr" has been changed. If
7041 ;; yes, this is a strong indication that we must expire all
d8ac123e
MA
7042 ;; connection properties. We start again with
7043 ;; `tramp-maybe-open-connection', it will be catched there.
e42c6bbc
MA
7044 (tramp-message vec 5 "Checking system information")
7045 (let ((old-uname (tramp-get-connection-property vec "uname" nil))
7046 (new-uname
7047 (tramp-set-connection-property
7048 vec "uname"
7049 (tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\""))))
7050 (when (and (stringp old-uname) (not (string-equal old-uname new-uname)))
d8ac123e 7051 (with-current-buffer (tramp-get-debug-buffer vec)
20b8ac83 7052 ;; Keep the debug buffer.
2296b54d
MA
7053 (rename-buffer
7054 (generate-new-buffer-name tramp-temp-buffer-name) 'unique)
20b8ac83 7055 (tramp-compat-funcall 'tramp-cleanup-connection vec)
d8ac123e
MA
7056 (if (= (point-min) (point-max))
7057 (kill-buffer nil)
7058 (rename-buffer (tramp-debug-buffer-name vec) 'unique))
7059 ;; We call `tramp-get-buffer' in order to keep the debug buffer.
7060 (tramp-get-buffer vec)
7061 (tramp-message
7062 vec 3
7063 "Connection reset, because remote host changed from `%s' to `%s'"
7064 old-uname new-uname)
7065 (throw 'uname-changed (tramp-maybe-open-connection vec)))))
e42c6bbc
MA
7066
7067 ;; Check whether the remote host suffers from buggy
7068 ;; `send-process-string'. This is known for FreeBSD (see comment in
7069 ;; `send_process', file process.c). I've tested sending 624 bytes
7070 ;; successfully, sending 625 bytes failed. Emacs makes a hack when
7071 ;; this host type is detected locally. It cannot handle remote
7072 ;; hosts, though.
00d6fd04
MA
7073 (with-connection-property proc "chunksize"
7074 (cond
7075 ((and (integerp tramp-chunksize) (> tramp-chunksize 0))
7076 tramp-chunksize)
7077 (t
7078 (tramp-message
7079 vec 5 "Checking remote host type for `send-process-string' bug")
7080 (if (string-match
e42c6bbc 7081 "^FreeBSD" (tramp-get-connection-property vec "uname" ""))
00d6fd04 7082 500 0))))
e42c6bbc 7083
00d6fd04
MA
7084 ;; Set remote PATH variable.
7085 (tramp-set-remote-path vec)
e42c6bbc 7086
fb7933a3
KG
7087 ;; Search for a good shell before searching for a command which
7088 ;; checks if a file exists. This is done because Tramp wants to use
7089 ;; "test foo; echo $?" to check if various conditions hold, and
7090 ;; there are buggy /bin/sh implementations which don't execute the
7091 ;; "echo $?" part if the "test" part has an error. In particular,
c0e17ff2
MA
7092 ;; the OpenSolaris /bin/sh is a problem. There are also other
7093 ;; problems with /bin/sh of OpenSolaris, like redirection of stderr
20b8ac83 7094 ;; in function declarations, or changing HISTFILE in place.
c0e17ff2
MA
7095 ;; Therefore, OpenSolaris' /bin/sh is replaced by bash, when
7096 ;; detected.
00d6fd04 7097 (tramp-find-shell vec)
e42c6bbc 7098
00d6fd04 7099 ;; Disable unexpected output.
7e780ff1 7100 (tramp-send-command vec "mesg n; biff n" t)
e42c6bbc 7101
20b8ac83
MA
7102 ;; IRIX64 bash expands "!" even when in single quotes. This
7103 ;; destroys our shell functions, we must disable it. See
7104 ;; <http://stackoverflow.com/questions/3291692/irix-bash-shell-expands-expression-in-single-quotes-yet-shouldnt>.
7105 (when (string-match "^IRIX64" (tramp-get-connection-property vec "uname" ""))
7106 (tramp-send-command vec "set +H" t))
7107
e499c64d
MA
7108 ;; On BSD-like systems, ?\t is expanded to spaces. Suppress this.
7109 (when (string-match "BSD\\|Darwin"
7110 (tramp-get-connection-property vec "uname" ""))
7111 (tramp-send-command vec "stty -oxtabs" t))
7112
20b8ac83
MA
7113 ;; Set `remote-tty' process property.
7114 (ignore-errors
7115 (let ((tty (tramp-send-command-and-read vec "echo \\\"`tty`\\\"")))
6efb972c
MA
7116 (unless (zerop (length tty))
7117 (tramp-compat-process-put proc 'remote-tty tty))))
20b8ac83 7118
e499c64d
MA
7119 ;; Dump stty settings in the traces.
7120 (when (>= tramp-verbose 9)
7121 (tramp-send-command vec "stty -a" t))
7122
00d6fd04
MA
7123 ;; Set the environment.
7124 (tramp-message vec 5 "Setting default environment")
661aaece 7125
00d6fd04
MA
7126 (let ((env (copy-sequence tramp-remote-process-environment))
7127 unset item)
7128 (while env
70c11b0b 7129 (setq item (tramp-compat-split-string (car env) "="))
7e5686f0
MA
7130 (setcdr item (mapconcat 'identity (cdr item) "="))
7131 (if (and (stringp (cdr item)) (not (string-equal (cdr item) "")))
00d6fd04 7132 (tramp-send-command
7e5686f0 7133 vec (format "%s=%s; export %s" (car item) (cdr item) (car item)) t)
00d6fd04
MA
7134 (push (car item) unset))
7135 (setq env (cdr env)))
7136 (when unset
fb7933a3 7137 (tramp-send-command
20b8ac83 7138 vec (format "unset %s" (mapconcat 'identity unset " ")) t))))
fb7933a3 7139
ac474af1
KG
7140;; CCC: We should either implement a Perl version of base64 encoding
7141;; and decoding. Then we just use that in the last item. The other
7142;; alternative is to use the Perl version of UU encoding. But then
7143;; we need a Lisp version of uuencode.
16674e4f
KG
7144;;
7145;; Old text from documentation of tramp-methods:
7146;; Using a uuencode/uudecode inline method is discouraged, please use one
7147;; of the base64 methods instead since base64 encoding is much more
7148;; reliable and the commands are more standardized between the different
7149;; Unix versions. But if you can't use base64 for some reason, please
7150;; note that the default uudecode command does not work well for some
7151;; Unices, in particular AIX and Irix. For AIX, you might want to use
7152;; the following command for uudecode:
7153;;
7154;; sed '/^begin/d;/^[` ]$/d;/^end/d' | iconv -f uucode -t ISO8859-1
7155;;
7156;; For Irix, no solution is known yet.
7157
00d6fd04
MA
7158(defconst tramp-local-coding-commands
7159 '((b64 base64-encode-region base64-decode-region)
7160 (uu tramp-uuencode-region uudecode-decode-region)
7161 (pack
7162 "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
7163 "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"))
7164 "List of local coding commands for inline transfer.
16674e4f
KG
7165Each item is a list that looks like this:
7166
20b8ac83 7167\(FORMAT ENCODING DECODING\)
ac474af1 7168
00d6fd04
MA
7169FORMAT is symbol describing the encoding/decoding format. It can be
7170`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
ac474af1 7171
00d6fd04
MA
7172ENCODING and DECODING can be strings, giving commands, or symbols,
7173giving functions. If they are strings, then they can contain
16674e4f
KG
7174the \"%s\" format specifier. If that specifier is present, the input
7175filename will be put into the command line at that spot. If the
7176specifier is not present, the input should be read from standard
7177input.
ac474af1 7178
16674e4f
KG
7179If they are functions, they will be called with two arguments, start
7180and end of region, and are expected to replace the region contents
7181with the encoded or decoded results, respectively.")
ac474af1 7182
00d6fd04 7183(defconst tramp-remote-coding-commands
cdf015b1
MA
7184 '((b64 "base64" "base64 -d -i")
7185 ;; "-i" is more robust with older base64 from GNU coreutils.
7186 ;; However, I don't know whether all base64 versions do supports
7187 ;; this option.
7188 (b64 "base64" "base64 -d")
3dc847a3 7189 (b64 "mimencode -b" "mimencode -u -b")
00d6fd04
MA
7190 (b64 "mmencode -b" "mmencode -u -b")
7191 (b64 "recode data..base64" "recode base64..data")
7192 (b64 tramp-perl-encode-with-module tramp-perl-decode-with-module)
7193 (b64 tramp-perl-encode tramp-perl-decode)
7194 (uu "uuencode xxx" "uudecode -o /dev/stdout")
7195 (uu "uuencode xxx" "uudecode -o -")
7196 (uu "uuencode xxx" "uudecode -p")
7197 (uu "uuencode xxx" tramp-uudecode)
7198 (pack
7199 "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
7200 "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"))
7201 "List of remote coding commands for inline transfer.
7202Each item is a list that looks like this:
7203
20b8ac83 7204\(FORMAT ENCODING DECODING\)
00d6fd04
MA
7205
7206FORMAT is symbol describing the encoding/decoding format. It can be
7207`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
7208
7209ENCODING and DECODING can be strings, giving commands, or symbols,
7210giving variables. If they are strings, then they can contain
7211the \"%s\" format specifier. If that specifier is present, the input
7212filename will be put into the command line at that spot. If the
7213specifier is not present, the input should be read from standard
7214input.
7215
7216If they are variables, this variable is a string containing a Perl
7217implementation for this functionality. This Perl program will be transferred
db9e401b 7218to the remote host, and it is available as shell function with the same name.")
00d6fd04
MA
7219
7220(defun tramp-find-inline-encoding (vec)
ac474af1 7221 "Find an inline transfer encoding that works.
00d6fd04
MA
7222Goes through the list `tramp-local-coding-commands' and
7223`tramp-remote-coding-commands'."
7224 (save-excursion
7225 (let ((local-commands tramp-local-coding-commands)
7226 (magic "xyzzy")
7227 loc-enc loc-dec rem-enc rem-dec litem ritem found)
7228 (while (and local-commands (not found))
7229 (setq litem (pop local-commands))
7230 (catch 'wont-work-local
7231 (let ((format (nth 0 litem))
7232 (remote-commands tramp-remote-coding-commands))
7233 (setq loc-enc (nth 1 litem))
7234 (setq loc-dec (nth 2 litem))
7235 ;; If the local encoder or decoder is a string, the
7236 ;; corresponding command has to work locally.
7237 (if (not (stringp loc-enc))
7238 (tramp-message
7239 vec 5 "Checking local encoding function `%s'" loc-enc)
7240 (tramp-message
7241 vec 5 "Checking local encoding command `%s' for sanity" loc-enc)
7242 (unless (zerop (tramp-call-local-coding-command
7243 loc-enc nil nil))
7244 (throw 'wont-work-local nil)))
7245 (if (not (stringp loc-dec))
7246 (tramp-message
7247 vec 5 "Checking local decoding function `%s'" loc-dec)
7248 (tramp-message
7249 vec 5 "Checking local decoding command `%s' for sanity" loc-dec)
7250 (unless (zerop (tramp-call-local-coding-command
7251 loc-dec nil nil))
7252 (throw 'wont-work-local nil)))
7253 ;; Search for remote coding commands with the same format
7254 (while (and remote-commands (not found))
7255 (setq ritem (pop remote-commands))
7256 (catch 'wont-work-remote
7257 (when (equal format (nth 0 ritem))
7258 (setq rem-enc (nth 1 ritem))
7259 (setq rem-dec (nth 2 ritem))
7260 ;; Check if remote encoding and decoding commands can be
7261 ;; called remotely with null input and output. This makes
7262 ;; sure there are no syntax errors and the command is really
7263 ;; found. Note that we do not redirect stdout to /dev/null,
7264 ;; for two reasons: when checking the decoding command, we
7265 ;; actually check the output it gives. And also, when
7266 ;; redirecting "mimencode" output to /dev/null, then as root
7267 ;; it might change the permissions of /dev/null!
7268 (when (not (stringp rem-enc))
7269 (let ((name (symbol-name rem-enc)))
7270 (while (string-match (regexp-quote "-") name)
7271 (setq name (replace-match "_" nil t name)))
7272 (tramp-maybe-send-script vec (symbol-value rem-enc) name)
7273 (setq rem-enc name)))
7274 (tramp-message
7275 vec 5
7276 "Checking remote encoding command `%s' for sanity" rem-enc)
7277 (unless (zerop (tramp-send-command-and-check
7278 vec (format "%s </dev/null" rem-enc) t))
7279 (throw 'wont-work-remote nil))
7280
7281 (when (not (stringp rem-dec))
7282 (let ((name (symbol-name rem-dec)))
7283 (while (string-match (regexp-quote "-") name)
7284 (setq name (replace-match "_" nil t name)))
7285 (tramp-maybe-send-script vec (symbol-value rem-dec) name)
7286 (setq rem-dec name)))
7287 (tramp-message
7288 vec 5
7289 "Checking remote decoding command `%s' for sanity" rem-dec)
7290 (unless (zerop (tramp-send-command-and-check
7291 vec
7292 (format "echo %s | %s | %s"
b593f105
MA
7293 magic rem-enc rem-dec)
7294 t))
00d6fd04
MA
7295 (throw 'wont-work-remote nil))
7296
7297 (with-current-buffer (tramp-get-buffer vec)
7298 (goto-char (point-min))
7299 (unless (looking-at (regexp-quote magic))
7300 (throw 'wont-work-remote nil)))
7301
7302 ;; `rem-enc' and `rem-dec' could be a string meanwhile.
7303 (setq rem-enc (nth 1 ritem))
7304 (setq rem-dec (nth 2 ritem))
7305 (setq found t)))))))
7306
1d7e9a01 7307 ;; Did we find something?
00d6fd04 7308 (unless found
7e5686f0
MA
7309 (tramp-error
7310 vec 'file-error "Couldn't find an inline transfer encoding"))
00d6fd04
MA
7311
7312 ;; Set connection properties.
7313 (tramp-message vec 5 "Using local encoding `%s'" loc-enc)
7314 (tramp-set-connection-property vec "local-encoding" loc-enc)
7315 (tramp-message vec 5 "Using local decoding `%s'" loc-dec)
7316 (tramp-set-connection-property vec "local-decoding" loc-dec)
7317 (tramp-message vec 5 "Using remote encoding `%s'" rem-enc)
7318 (tramp-set-connection-property vec "remote-encoding" rem-enc)
7319 (tramp-message vec 5 "Using remote decoding `%s'" rem-dec)
7320 (tramp-set-connection-property vec "remote-decoding" rem-dec))))
16674e4f
KG
7321
7322(defun tramp-call-local-coding-command (cmd input output)
7323 "Call the local encoding or decoding command.
7324If CMD contains \"%s\", provide input file INPUT there in command.
7325Otherwise, INPUT is passed via standard input.
7326INPUT can also be nil which means `/dev/null'.
7327OUTPUT can be a string (which specifies a filename), or t (which
7328means standard output and thus the current buffer), or nil (which
7329means discard it)."
a4aeb9a4
MA
7330 (tramp-local-call-process
7331 tramp-encoding-shell
7332 (when (and input (not (string-match "%s" cmd))) input)
7333 (if (eq output t) t nil)
7334 nil
7335 tramp-encoding-command-switch
7336 (concat
7337 (if (string-match "%s" cmd) (format cmd input) cmd)
7338 (if (stringp output) (concat "> " output) ""))))
00d6fd04 7339
20b8ac83
MA
7340(defconst tramp-inline-compress-commands
7341 '(("gzip" "gzip -d")
7342 ("bzip2" "bzip2 -d")
7343 ("compress" "compress -d"))
7344 "List of compress and decompress commands for inline transfer.
7345Each item is a list that looks like this:
7346
7347\(COMPRESS DECOMPRESS\)
7348
7349COMPRESS or DECOMPRESS are strings with the respective commands.")
7350
7351(defun tramp-find-inline-compress (vec)
7352 "Find an inline transfer compress command that works.
7353Goes through the list `tramp-inline-compress-commands'."
7354 (save-excursion
7355 (let ((commands tramp-inline-compress-commands)
7356 (magic "xyzzy")
7357 item compress decompress
7358 found)
7359 (while (and commands (not found))
7360 (catch 'next
7361 (setq item (pop commands)
7362 compress (nth 0 item)
7363 decompress (nth 1 item))
7364 (tramp-message
7365 vec 5
7366 "Checking local compress command `%s', `%s' for sanity"
7367 compress decompress)
01d70c32
MA
7368 (unless
7369 (zerop
7370 (tramp-call-local-coding-command
7371 (format
7372 ;; Windows shells need the program file name after
7373 ;; the pipe symbol be quoted if they use forward
7374 ;; slashes as directory separators.
7375 (if (memq system-type '(windows-nt))
7376 "echo %s | \"%s\" | \"%s\""
7377 "echo %s | %s | %s")
7378 magic compress decompress) nil nil))
20b8ac83
MA
7379 (throw 'next nil))
7380 (tramp-message
7381 vec 5
7382 "Checking remote compress command `%s', `%s' for sanity"
7383 compress decompress)
7384 (unless (zerop (tramp-send-command-and-check
7385 vec (format "echo %s | %s | %s"
7386 magic compress decompress) t))
7387 (throw 'next nil))
7388 (setq found t)))
7389
7390 ;; Did we find something?
7391 (if found
7392 (progn
7393 ;; Set connection properties.
7394 (tramp-message
7395 vec 5 "Using inline transfer compress command `%s'" compress)
7396 (tramp-set-connection-property vec "inline-compress" compress)
7397 (tramp-message
7398 vec 5 "Using inline transfer decompress command `%s'" decompress)
7399 (tramp-set-connection-property vec "inline-decompress" decompress))
7400
7401 (tramp-set-connection-property vec "inline-compress" nil)
7402 (tramp-set-connection-property vec "inline-decompress" nil)
7403 (tramp-message
7404 vec 2 "Couldn't find an inline transfer compress command")))))
7405
00d6fd04
MA
7406(defun tramp-compute-multi-hops (vec)
7407 "Expands VEC according to `tramp-default-proxies-alist'.
7408Gateway hops are already opened."
7409 (let ((target-alist `(,vec))
7410 (choices tramp-default-proxies-alist)
7411 item proxy)
7412
7413 ;; Look for proxy hosts to be passed.
7414 (while choices
7415 (setq item (pop choices)
70c11b0b 7416 proxy (eval (nth 2 item)))
00d6fd04
MA
7417 (when (and
7418 ;; host
70c11b0b 7419 (string-match (or (eval (nth 0 item)) "")
00d6fd04
MA
7420 (or (tramp-file-name-host (car target-alist)) ""))
7421 ;; user
70c11b0b 7422 (string-match (or (eval (nth 1 item)) "")
00d6fd04
MA
7423 (or (tramp-file-name-user (car target-alist)) "")))
7424 (if (null proxy)
7425 ;; No more hops needed.
7426 (setq choices nil)
7427 ;; Replace placeholders.
7428 (setq proxy
7429 (format-spec
7430 proxy
20b8ac83
MA
7431 (format-spec-make
7432 ?u (or (tramp-file-name-user (car target-alist)) "")
7433 ?h (or (tramp-file-name-host (car target-alist)) ""))))
00d6fd04
MA
7434 (with-parsed-tramp-file-name proxy l
7435 ;; Add the hop.
7436 (add-to-list 'target-alist l)
7437 ;; Start next search.
7438 (setq choices tramp-default-proxies-alist)))))
7439
7440 ;; Handle gateways.
8a4438b6
MA
7441 (when (and (boundp 'tramp-gw-tunnel-method)
7442 (string-match (format
7443 "^\\(%s\\|%s\\)$"
7444 (symbol-value 'tramp-gw-tunnel-method)
7445 (symbol-value 'tramp-gw-socks-method))
7446 (tramp-file-name-method (car target-alist))))
00d6fd04
MA
7447 (let ((gw (pop target-alist))
7448 (hop (pop target-alist)))
7449 ;; Is the method prepared for gateways?
7450 (unless (tramp-get-method-parameter
7451 (tramp-file-name-method hop) 'tramp-default-port)
7452 (tramp-error
7453 vec 'file-error
7454 "Method `%s' is not supported for gateway access."
7455 (tramp-file-name-method hop)))
7456 ;; Add default port if needed.
7457 (unless
7458 (string-match
7459 tramp-host-with-port-regexp (tramp-file-name-host hop))
7460 (aset hop 2
7461 (concat
7462 (tramp-file-name-host hop) tramp-prefix-port-format
7463 (number-to-string
7464 (tramp-get-method-parameter
7465 (tramp-file-name-method hop) 'tramp-default-port)))))
7466 ;; Open the gateway connection.
7467 (add-to-list
7468 'target-alist
7469 (vector
7470 (tramp-file-name-method hop) (tramp-file-name-user hop)
20b8ac83 7471 (tramp-compat-funcall 'tramp-gw-open-connection vec gw hop) nil))
00d6fd04
MA
7472 ;; For the password prompt, we need the correct values.
7473 ;; Therefore, we must remember the gateway vector. But we
7474 ;; cannot do it as connection property, because it shouldn't
7475 ;; be persistent. And we have no started process yet either.
7476 (tramp-set-file-property (car target-alist) "" "gateway" hop)))
7477
7478 ;; Foreign and out-of-band methods are not supported for multi-hops.
7479 (when (cdr target-alist)
7480 (setq choices target-alist)
7481 (while choices
7482 (setq item (pop choices))
7483 (when
7484 (or
7485 (not
7486 (tramp-get-method-parameter
7487 (tramp-file-name-method item) 'tramp-login-program))
7488 (tramp-get-method-parameter
7489 (tramp-file-name-method item) 'tramp-copy-program))
7490 (tramp-error
7491 vec 'file-error
7492 "Method `%s' is not supported for multi-hops."
7493 (tramp-file-name-method item)))))
7494
2991e49f
MA
7495 ;; In case the host name is not used for the remote shell
7496 ;; command, the user could be misguided by applying a random
7497 ;; hostname.
7498 (let* ((v (car target-alist))
7499 (method (tramp-file-name-method v))
7500 (host (tramp-file-name-host v)))
7501 (unless
7502 (or
7503 ;; There are multi-hops.
7504 (cdr target-alist)
7505 ;; The host name is used for the remote shell command.
7506 (member
7507 '("%h") (tramp-get-method-parameter method 'tramp-login-args))
7508 ;; The host is local. We cannot use `tramp-local-host-p'
7509 ;; here, because it opens a connection as well.
b96e6899 7510 (string-match tramp-local-host-regexp host))
2991e49f 7511 (tramp-error
42bc9b6d
MA
7512 v 'file-error
7513 "Host `%s' looks like a remote host, `%s' can only use the local host"
7514 host method)))
2991e49f 7515
00d6fd04
MA
7516 ;; Result.
7517 target-alist))
7518
7519(defun tramp-maybe-open-connection (vec)
7520 "Maybe open a connection VEC.
fb7933a3
KG
7521Does not do anything if a connection is already open, but re-opens the
7522connection if a previous connection has died for some reason."
d8ac123e
MA
7523 (catch 'uname-changed
7524 (let ((p (tramp-get-connection-process vec))
20b8ac83 7525 (process-name (tramp-get-connection-property vec "process-name" nil))
d8ac123e
MA
7526 (process-environment (copy-sequence process-environment)))
7527
7528 ;; If too much time has passed since last command was sent, look
7529 ;; whether process is still alive. If it isn't, kill it. When
7530 ;; using ssh, it can sometimes happen that the remote end has
7531 ;; hung up but the local ssh client doesn't recognize this until
7532 ;; it tries to send some data to the remote end. So that's why
7533 ;; we try to send a command from time to time, then look again
7534 ;; whether the process is really alive.
7535 (condition-case nil
7536 (when (and (> (tramp-time-diff
7537 (current-time)
7538 (tramp-get-connection-property
7539 p "last-cmd-time" '(0 0 0)))
7540 60)
7541 p (processp p) (memq (process-status p) '(run open)))
7542 (tramp-send-command vec "echo are you awake" t t)
7543 (unless (and (memq (process-status p) '(run open))
7544 (tramp-wait-for-output p 10))
7545 ;; The error will be catched locally.
7546 (tramp-error vec 'file-error "Awake did fail")))
7547 (file-error
7548 (tramp-flush-connection-property vec)
7549 (tramp-flush-connection-property p)
7550 (delete-process p)
7551 (setq p nil)))
7552
7553 ;; New connection must be opened.
7554 (unless (and p (processp p) (memq (process-status p) '(run open)))
7555
7556 ;; We call `tramp-get-buffer' in order to get a debug buffer for
7557 ;; messages from the beginning.
7558 (tramp-get-buffer vec)
20b8ac83
MA
7559 (with-progress-reporter
7560 vec 3
7561 (if (zerop (length (tramp-file-name-user vec)))
7562 (format "Opening connection for %s using %s"
7563 (tramp-file-name-host vec)
7564 (tramp-file-name-method vec))
7565 (format "Opening connection for %s@%s using %s"
7566 (tramp-file-name-user vec)
7567 (tramp-file-name-host vec)
7568 (tramp-file-name-method vec)))
7569
7570 ;; Start new process.
7571 (when (and p (processp p))
7572 (delete-process p))
7573 (setenv "TERM" tramp-terminal-type)
7574 (setenv "LC_ALL" "C")
7575 (setenv "PROMPT_COMMAND")
7576 (setenv "PS1" tramp-initial-end-of-output)
7577 (let* ((target-alist (tramp-compute-multi-hops vec))
7578 (process-connection-type tramp-process-connection-type)
7579 (process-adaptive-read-buffering nil)
7580 (coding-system-for-read nil)
7581 ;; This must be done in order to avoid our file name handler.
7582 (p (let ((default-directory
7583 (tramp-compat-temporary-file-directory)))
7584 (start-process
7585 (or process-name (tramp-buffer-name vec))
7586 (tramp-get-connection-buffer vec)
7587 tramp-encoding-shell))))
d8ac123e 7588
20b8ac83
MA
7589 (tramp-message
7590 vec 6 "%s" (mapconcat 'identity (process-command p) " "))
7591
7592 ;; Check whether process is alive.
7593 (tramp-set-process-query-on-exit-flag p nil)
7594 (tramp-barf-if-no-shell-prompt
7595 p 60 "Couldn't find local shell prompt %s" tramp-encoding-shell)
7596
7597 ;; Now do all the connections as specified.
7598 (while target-alist
7599 (let* ((hop (car target-alist))
7600 (l-method (tramp-file-name-method hop))
7601 (l-user (tramp-file-name-user hop))
7602 (l-host (tramp-file-name-host hop))
7603 (l-port nil)
7604 (login-program
7605 (tramp-get-method-parameter
7606 l-method 'tramp-login-program))
7607 (login-args
7608 (tramp-get-method-parameter l-method 'tramp-login-args))
7609 (async-args
7610 (tramp-get-method-parameter l-method 'tramp-async-args))
7611 (gw-args
7612 (tramp-get-method-parameter l-method 'tramp-gw-args))
7613 (gw (tramp-get-file-property hop "" "gateway" nil))
7614 (g-method (and gw (tramp-file-name-method gw)))
7615 (g-user (and gw (tramp-file-name-user gw)))
7616 (g-host (and gw (tramp-file-name-host gw)))
7617 (command login-program)
7618 ;; We don't create the temporary file. In fact,
7619 ;; it is just a prefix for the ControlPath option
7620 ;; of ssh; the real temporary file has another
7621 ;; name, and it is created and protected by ssh.
7622 ;; It is also removed by ssh, when the connection
7623 ;; is closed.
7624 (tmpfile
7625 (tramp-set-connection-property
7626 p "temp-file"
7627 (make-temp-name
7628 (expand-file-name
7629 tramp-temp-name-prefix
7630 (tramp-compat-temporary-file-directory)))))
7631 spec)
7632
7633 ;; Add arguments for asynchrononous processes.
7634 (when (and process-name async-args)
7635 (setq login-args (append async-args login-args)))
7636
7637 ;; Add gateway arguments if necessary.
7638 (when (and gw gw-args)
7639 (setq login-args (append gw-args login-args)))
7640
7641 ;; Check for port number. Until now, there's no need
7642 ;; for handling like method, user, host.
7643 (when (string-match tramp-host-with-port-regexp l-host)
d8ac123e
MA
7644 (setq l-port (match-string 2 l-host)
7645 l-host (match-string 1 l-host)))
7646
20b8ac83
MA
7647 ;; Set variables for computing the prompt for reading
7648 ;; password. They can also be derived from a gateway.
7649 (setq tramp-current-method (or g-method l-method)
7650 tramp-current-user (or g-user l-user)
7651 tramp-current-host (or g-host l-host))
7652
7653 ;; Replace login-args place holders.
7654 (setq
7655 l-host (or l-host "")
7656 l-user (or l-user "")
7657 l-port (or l-port "")
7658 spec (format-spec-make
7659 ?h l-host ?u l-user ?p l-port ?t tmpfile)
7660 command
7661 (concat
7662 ;; We do not want to see the trailing local prompt in
7663 ;; `start-file-process'.
7664 (unless (memq system-type '(windows-nt)) "exec ")
7665 command " "
7666 (mapconcat
7667 (lambda (x)
7668 (setq x (mapcar (lambda (y) (format-spec y spec)) x))
7669 (unless (member "" x) (mapconcat 'identity x " ")))
7670 login-args " ")
7671 ;; Local shell could be a Windows COMSPEC. It
7672 ;; doesn't know the ";" syntax, but we must exit
7673 ;; always for `start-file-process'. "exec" does not
7674 ;; work either.
7675 (if (memq system-type '(windows-nt)) " && exit || exit")))
7676
7677 ;; Send the command.
7678 (tramp-message vec 3 "Sending command `%s'" command)
7679 (tramp-send-command vec command t t)
7680 (tramp-process-actions p vec tramp-actions-before-shell 60)
7681 (tramp-message
7682 vec 3 "Found remote shell prompt on `%s'" l-host))
7683 ;; Next hop.
7684 (setq target-alist (cdr target-alist)))
d8ac123e 7685
20b8ac83
MA
7686 ;; Make initial shell settings.
7687 (tramp-open-connection-setup-interactive-shell p vec)))))))
00d6fd04
MA
7688
7689(defun tramp-send-command (vec command &optional neveropen nooutput)
7690 "Send the COMMAND to connection VEC.
7691Erases temporary buffer before sending the command. If optional
7692arg NEVEROPEN is non-nil, never try to open the connection. This
7693is meant to be used from `tramp-maybe-open-connection' only. The
7694function waits for output unless NOOUTPUT is set."
7695 (unless neveropen (tramp-maybe-open-connection vec))
7696 (let ((p (tramp-get-connection-process vec)))
8950769a 7697 (when (tramp-get-connection-property p "remote-echo" nil)
00d6fd04
MA
7698 ;; We mark the command string that it can be erased in the output buffer.
7699 (tramp-set-connection-property p "check-remote-echo" t)
7700 (setq command (format "%s%s%s" tramp-echo-mark command tramp-echo-mark)))
7701 (tramp-message vec 6 "%s" command)
7702 (tramp-send-string vec command)
7703 (unless nooutput (tramp-wait-for-output p))))
7704
00d6fd04 7705(defun tramp-wait-for-output (proc &optional timeout)
7e5686f0
MA
7706 "Wait for output from remote command."
7707 (unless (buffer-live-p (process-buffer proc))
7708 (delete-process proc)
7709 (tramp-error proc 'file-error "Process `%s' not available, try again" proc))
00d6fd04 7710 (with-current-buffer (process-buffer proc)
dab816a9 7711 (let* (;; Initially, `tramp-end-of-output' is "#$ ". There might
bede3e9f 7712 ;; be leading escape sequences, which must be ignored.
dab816a9 7713 (regexp (format "[^#$\n]*%s\r?$" (regexp-quote tramp-end-of-output)))
bede3e9f
MA
7714 ;; Sometimes, the commands do not return a newline but a
7715 ;; null byte before the shell prompt, for example "git
7716 ;; ls-files -c -z ...".
7717 (regexp1 (format "\\(^\\|\000\\)%s" regexp))
7718 (found (tramp-wait-for-regexp proc timeout regexp1)))
00d6fd04
MA
7719 (if found
7720 (let (buffer-read-only)
7e5686f0
MA
7721 ;; A simple-minded busybox has sent " ^H" sequences.
7722 ;; Delete them.
7723 (goto-char (point-min))
7724 (when (re-search-forward
7725 "^\\(.\b\\)+$" (tramp-compat-line-end-position) t)
7726 (forward-line 1)
7727 (delete-region (point-min) (point)))
7728 ;; Delete the prompt.
00d6fd04 7729 (goto-char (point-max))
0664ff72 7730 (re-search-backward regexp nil t)
00d6fd04
MA
7731 (delete-region (point) (point-max)))
7732 (if timeout
7733 (tramp-error
7734 proc 'file-error
7735 "[[Remote prompt `%s' not found in %d secs]]"
7736 tramp-end-of-output timeout)
7737 (tramp-error
7738 proc 'file-error
7739 "[[Remote prompt `%s' not found]]" tramp-end-of-output)))
7740 ;; Return value is whether end-of-output sentinel was found.
7741 found)))
fb7933a3 7742
b593f105
MA
7743(defun tramp-send-command-and-check
7744 (vec command &optional subshell dont-suppress-err)
fb7933a3 7745 "Run COMMAND and check its exit status.
fb7933a3
KG
7746Sends `echo $?' along with the COMMAND for checking the exit status. If
7747COMMAND is nil, just sends `echo $?'. Returns the exit status found.
7748
b593f105
MA
7749If the optional argument SUBSHELL is non-nil, the command is
7750executed in a subshell, ie surrounded by parentheses. If
7751DONT-SUPPRESS-ERR is non-nil, stderr won't be sent to /dev/null."
00d6fd04
MA
7752 (tramp-send-command
7753 vec
7754 (concat (if subshell "( " "")
7755 command
b593f105 7756 (if command (if dont-suppress-err "; " " 2>/dev/null; ") "")
00d6fd04 7757 "echo tramp_exit_status $?"
b593f105 7758 (if subshell " )" "")))
00d6fd04
MA
7759 (with-current-buffer (tramp-get-connection-buffer vec)
7760 (goto-char (point-max))
7761 (unless (re-search-backward "tramp_exit_status [0-9]+" nil t)
7762 (tramp-error
7763 vec 'file-error "Couldn't find exit status of `%s'" command))
7764 (skip-chars-forward "^ ")
7765 (prog1
7766 (read (current-buffer))
7767 (let (buffer-read-only) (delete-region (match-beginning 0) (point-max))))))
7768
7769(defun tramp-barf-unless-okay (vec command fmt &rest args)
fb7933a3
KG
7770 "Run COMMAND, check exit status, throw error if exit status not okay.
7771Similar to `tramp-send-command-and-check' but accepts two more arguments
7772FMT and ARGS which are passed to `error'."
00d6fd04
MA
7773 (unless (zerop (tramp-send-command-and-check vec command))
7774 (apply 'tramp-error vec 'file-error fmt args)))
7775
7776(defun tramp-send-command-and-read (vec command)
7777 "Run COMMAND and return the output, which must be a Lisp expression.
7778In case there is no valid Lisp expression, it raises an error"
7779 (tramp-barf-unless-okay vec command "`%s' returns with error" command)
7780 (with-current-buffer (tramp-get-connection-buffer vec)
7781 ;; Read the expression.
7782 (goto-char (point-min))
7783 (condition-case nil
7784 (prog1 (read (current-buffer))
7785 ;; Error handling.
9e6ab520 7786 (when (re-search-forward "\\S-" (tramp-compat-line-end-position) t)
9ce8462a 7787 (error nil)))
00d6fd04
MA
7788 (error (tramp-error
7789 vec 'file-error
7790 "`%s' does not return a valid Lisp expression: `%s'"
7791 command (buffer-string))))))
fb7933a3 7792
7432277c
KG
7793;; It seems that Tru64 Unix does not like it if long strings are sent
7794;; to it in one go. (This happens when sending the Perl
7795;; `file-attributes' implementation, for instance.) Therefore, we
27e813fe 7796;; have this function which sends the string in chunks.
00d6fd04
MA
7797(defun tramp-send-string (vec string)
7798 "Send the STRING via connection VEC.
7432277c
KG
7799
7800The STRING is expected to use Unix line-endings, but the lines sent to
7801the remote host use line-endings as defined in the variable
00d6fd04
MA
7802`tramp-rsh-end-of-line'. The communication buffer is erased before sending."
7803 (let* ((p (tramp-get-connection-process vec))
7804 (chunksize (tramp-get-connection-property p "chunksize" nil)))
7805 (unless p
7806 (tramp-error
7807 vec 'file-error "Can't send string to remote host -- not logged in"))
7808 (tramp-set-connection-property p "last-cmd-time" (current-time))
7809 (tramp-message vec 10 "%s" string)
7810 (with-current-buffer (tramp-get-connection-buffer vec)
7811 ;; Clean up the buffer. We cannot call `erase-buffer' because
7812 ;; narrowing might be in effect.
7813 (let (buffer-read-only) (delete-region (point-min) (point-max)))
27e813fe 7814 ;; Replace "\n" by `tramp-rsh-end-of-line'.
00d6fd04
MA
7815 (setq string
7816 (mapconcat 'identity
70c11b0b 7817 (tramp-compat-split-string string "\n")
00d6fd04
MA
7818 tramp-rsh-end-of-line))
7819 (unless (or (string= string "")
7820 (string-equal (substring string -1) tramp-rsh-end-of-line))
7821 (setq string (concat string tramp-rsh-end-of-line)))
27e813fe 7822 ;; Send the string.
00d6fd04
MA
7823 (if (and chunksize (not (zerop chunksize)))
7824 (let ((pos 0)
7825 (end (length string)))
7826 (while (< pos end)
7827 (tramp-message
7828 vec 10 "Sending chunk from %s to %s"
7829 pos (min (+ pos chunksize) end))
7830 (process-send-string
7831 p (substring string pos (min (+ pos chunksize) end)))
7832 (setq pos (+ pos chunksize))))
7833 (process-send-string p string)))))
fb7933a3
KG
7834
7835(defun tramp-mode-string-to-int (mode-string)
7836 "Converts a ten-letter `drwxrwxrwx'-style mode string into mode bits."
f3c071dd
MA
7837 (let* (case-fold-search
7838 (mode-chars (string-to-vector mode-string))
fb7933a3
KG
7839 (owner-read (aref mode-chars 1))
7840 (owner-write (aref mode-chars 2))
7841 (owner-execute-or-setid (aref mode-chars 3))
7842 (group-read (aref mode-chars 4))
7843 (group-write (aref mode-chars 5))
7844 (group-execute-or-setid (aref mode-chars 6))
7845 (other-read (aref mode-chars 7))
7846 (other-write (aref mode-chars 8))
7847 (other-execute-or-sticky (aref mode-chars 9)))
7848 (save-match-data
7849 (logior
f3c071dd
MA
7850 (cond
7851 ((char-equal owner-read ?r) (tramp-octal-to-decimal "00400"))
7852 ((char-equal owner-read ?-) 0)
7853 (t (error "Second char `%c' must be one of `r-'" owner-read)))
7854 (cond
7855 ((char-equal owner-write ?w) (tramp-octal-to-decimal "00200"))
7856 ((char-equal owner-write ?-) 0)
7857 (t (error "Third char `%c' must be one of `w-'" owner-write)))
7858 (cond
7859 ((char-equal owner-execute-or-setid ?x)
7860 (tramp-octal-to-decimal "00100"))
7861 ((char-equal owner-execute-or-setid ?S)
7862 (tramp-octal-to-decimal "04000"))
7863 ((char-equal owner-execute-or-setid ?s)
7864 (tramp-octal-to-decimal "04100"))
7865 ((char-equal owner-execute-or-setid ?-) 0)
7866 (t (error "Fourth char `%c' must be one of `xsS-'"
7867 owner-execute-or-setid)))
7868 (cond
7869 ((char-equal group-read ?r) (tramp-octal-to-decimal "00040"))
7870 ((char-equal group-read ?-) 0)
7871 (t (error "Fifth char `%c' must be one of `r-'" group-read)))
7872 (cond
7873 ((char-equal group-write ?w) (tramp-octal-to-decimal "00020"))
7874 ((char-equal group-write ?-) 0)
7875 (t (error "Sixth char `%c' must be one of `w-'" group-write)))
7876 (cond
7877 ((char-equal group-execute-or-setid ?x)
7878 (tramp-octal-to-decimal "00010"))
7879 ((char-equal group-execute-or-setid ?S)
7880 (tramp-octal-to-decimal "02000"))
7881 ((char-equal group-execute-or-setid ?s)
7882 (tramp-octal-to-decimal "02010"))
7883 ((char-equal group-execute-or-setid ?-) 0)
7884 (t (error "Seventh char `%c' must be one of `xsS-'"
7885 group-execute-or-setid)))
7886 (cond
7887 ((char-equal other-read ?r)
7888 (tramp-octal-to-decimal "00004"))
7889 ((char-equal other-read ?-) 0)
7890 (t (error "Eighth char `%c' must be one of `r-'" other-read)))
7891 (cond
7892 ((char-equal other-write ?w) (tramp-octal-to-decimal "00002"))
7893 ((char-equal other-write ?-) 0)
fb7933a3 7894 (t (error "Nineth char `%c' must be one of `w-'" other-write)))
f3c071dd
MA
7895 (cond
7896 ((char-equal other-execute-or-sticky ?x)
7897 (tramp-octal-to-decimal "00001"))
7898 ((char-equal other-execute-or-sticky ?T)
7899 (tramp-octal-to-decimal "01000"))
7900 ((char-equal other-execute-or-sticky ?t)
7901 (tramp-octal-to-decimal "01001"))
7902 ((char-equal other-execute-or-sticky ?-) 0)
7903 (t (error "Tenth char `%c' must be one of `xtT-'"
7904 other-execute-or-sticky)))))))
fb7933a3 7905
00d6fd04
MA
7906(defun tramp-convert-file-attributes (vec attr)
7907 "Convert file-attributes ATTR generated by perl script, stat or ls.
c82c5727
LH
7908Convert file mode bits to string and set virtual device number.
7909Return ATTR."
680db9ac
MA
7910 (when attr
7911 ;; Convert last access time.
7912 (unless (listp (nth 4 attr))
7913 (setcar (nthcdr 4 attr)
7914 (list (floor (nth 4 attr) 65536)
7915 (floor (mod (nth 4 attr) 65536)))))
7916 ;; Convert last modification time.
7917 (unless (listp (nth 5 attr))
7918 (setcar (nthcdr 5 attr)
7919 (list (floor (nth 5 attr) 65536)
7920 (floor (mod (nth 5 attr) 65536)))))
7921 ;; Convert last status change time.
7922 (unless (listp (nth 6 attr))
7923 (setcar (nthcdr 6 attr)
7924 (list (floor (nth 6 attr) 65536)
7925 (floor (mod (nth 6 attr) 65536)))))
7926 ;; Convert file size.
7927 (when (< (nth 7 attr) 0)
7928 (setcar (nthcdr 7 attr) -1))
7929 (when (and (floatp (nth 7 attr))
7930 (<= (nth 7 attr) (tramp-compat-most-positive-fixnum)))
7931 (setcar (nthcdr 7 attr) (round (nth 7 attr))))
7932 ;; Convert file mode bits to string.
7933 (unless (stringp (nth 8 attr))
7934 (setcar (nthcdr 8 attr) (tramp-file-mode-from-int (nth 8 attr)))
7935 (when (stringp (car attr))
7936 (aset (nth 8 attr) 0 ?l)))
7937 ;; Convert directory indication bit.
7938 (when (string-match "^d" (nth 8 attr))
7939 (setcar attr t))
7940 ;; Convert symlink from `tramp-do-file-attributes-with-stat'.
7941 (when (consp (car attr))
7942 (if (and (stringp (caar attr))
7943 (string-match ".+ -> .\\(.+\\)." (caar attr)))
7944 (setcar attr (match-string 1 (caar attr)))
7945 (setcar attr nil)))
7946 ;; Set file's gid change bit.
7947 (setcar (nthcdr 9 attr)
7948 (if (numberp (nth 3 attr))
7949 (not (= (nth 3 attr)
7950 (tramp-get-remote-gid vec 'integer)))
7951 (not (string-equal
7952 (nth 3 attr)
7953 (tramp-get-remote-gid vec 'string)))))
7954 ;; Convert inode.
7955 (unless (listp (nth 10 attr))
7956 (setcar (nthcdr 10 attr)
7957 (condition-case nil
7958 (cons (floor (nth 10 attr) 65536)
7959 (floor (mod (nth 10 attr) 65536)))
7960 ;; Inodes can be incredible huge. We must hide this.
7961 (error (tramp-get-inode vec)))))
7962 ;; Set virtual device number.
7963 (setcar (nthcdr 11 attr)
7964 (tramp-get-device vec))
7965 attr))
c82c5727 7966
293c24f9
MA
7967(defun tramp-check-cached-permissions (vec access)
7968 "Check `file-attributes' caches for VEC.
7969Return t if according to the cache access type ACCESS is known to
7970be granted."
7971 (let ((result nil)
7972 (offset (cond
7973 ((eq ?r access) 1)
7974 ((eq ?w access) 2)
7975 ((eq ?x access) 3))))
7976 (dolist (suffix '("string" "integer") result)
7977 (setq
7978 result
7979 (or
7980 result
7981 (let ((file-attr
7982 (tramp-get-file-property
7983 vec (tramp-file-name-localname vec)
7984 (concat "file-attributes-" suffix) nil))
7985 (remote-uid
7986 (tramp-get-connection-property
7987 vec (concat "uid-" suffix) nil))
7988 (remote-gid
7989 (tramp-get-connection-property
7990 vec (concat "gid-" suffix) nil)))
7991 (and
7992 file-attr
7993 (or
7994 ;; Not a symlink
7995 (eq t (car file-attr))
7996 (null (car file-attr)))
7997 (or
7998 ;; World accessible.
7999 (eq access (aref (nth 8 file-attr) (+ offset 6)))
8000 ;; User accessible and owned by user.
8001 (and
8002 (eq access (aref (nth 8 file-attr) offset))
8003 (equal remote-uid (nth 2 file-attr)))
8004 ;; Group accessible and owned by user's
8005 ;; principal group.
8006 (and
8007 (eq access (aref (nth 8 file-attr) (+ offset 3)))
8008 (equal remote-gid (nth 3 file-attr)))))))))))
8009
ce3f516f 8010(defun tramp-get-inode (vec)
00d6fd04
MA
8011 "Returns the virtual inode number.
8012If it doesn't exist, generate a new one."
ce3f516f
MA
8013 (let ((string (tramp-make-tramp-file-name
8014 (tramp-file-name-method vec)
8015 (tramp-file-name-user vec)
8016 (tramp-file-name-host vec)
8017 "")))
00d6fd04
MA
8018 (unless (assoc string tramp-inodes)
8019 (add-to-list 'tramp-inodes
8020 (list string (length tramp-inodes))))
8021 (nth 1 (assoc string tramp-inodes))))
8022
8023(defun tramp-get-device (vec)
c82c5727
LH
8024 "Returns the virtual device number.
8025If it doesn't exist, generate a new one."
00d6fd04
MA
8026 (let ((string (tramp-make-tramp-file-name
8027 (tramp-file-name-method vec)
8028 (tramp-file-name-user vec)
8029 (tramp-file-name-host vec)
8030 "")))
c82c5727
LH
8031 (unless (assoc string tramp-devices)
8032 (add-to-list 'tramp-devices
8033 (list string (length tramp-devices))))
b946a456 8034 (cons -1 (nth 1 (assoc string tramp-devices)))))
fb7933a3
KG
8035
8036(defun tramp-file-mode-from-int (mode)
8037 "Turn an integer representing a file mode into an ls(1)-like string."
8038 (let ((type (cdr (assoc (logand (lsh mode -12) 15) tramp-file-mode-type-map)))
8039 (user (logand (lsh mode -6) 7))
8040 (group (logand (lsh mode -3) 7))
8041 (other (logand (lsh mode -0) 7))
8042 (suid (> (logand (lsh mode -9) 4) 0))
8043 (sgid (> (logand (lsh mode -9) 2) 0))
8044 (sticky (> (logand (lsh mode -9) 1) 0)))
8045 (setq user (tramp-file-mode-permissions user suid "s"))
8046 (setq group (tramp-file-mode-permissions group sgid "s"))
8047 (setq other (tramp-file-mode-permissions other sticky "t"))
8048 (concat type user group other)))
8049
fb7933a3
KG
8050(defun tramp-file-mode-permissions (perm suid suid-text)
8051 "Convert a permission bitset into a string.
8052This is used internally by `tramp-file-mode-from-int'."
8053 (let ((r (> (logand perm 4) 0))
8054 (w (> (logand perm 2) 0))
8055 (x (> (logand perm 1) 0)))
8056 (concat (or (and r "r") "-")
8057 (or (and w "w") "-")
8058 (or (and suid x suid-text) ; suid, execute
8059 (and suid (upcase suid-text)) ; suid, !execute
8060 (and x "x") "-")))) ; !suid
8061
fb7933a3
KG
8062(defun tramp-decimal-to-octal (i)
8063 "Return a string consisting of the octal digits of I.
8064Not actually used. Use `(format \"%o\" i)' instead?"
8065 (cond ((< i 0) (error "Cannot convert negative number to octal"))
8066 ((not (integerp i)) (error "Cannot convert non-integer to octal"))
8067 ((zerop i) "0")
8068 (t (concat (tramp-decimal-to-octal (/ i 8))
8069 (number-to-string (% i 8))))))
8070
fb7933a3
KG
8071;; Kudos to Gerd Moellmann for this suggestion.
8072(defun tramp-octal-to-decimal (ostr)
8073 "Given a string of octal digits, return a decimal number."
8074 (let ((x (or ostr "")))
8075 ;; `save-match' is in `tramp-mode-string-to-int' which calls this.
8076 (unless (string-match "\\`[0-7]*\\'" x)
8077 (error "Non-octal junk in string `%s'" x))
8078 (string-to-number ostr 8)))
8079
8080(defun tramp-shell-case-fold (string)
8081 "Converts STRING to shell glob pattern which ignores case."
8082 (mapconcat
8083 (lambda (c)
8084 (if (equal (downcase c) (upcase c))
8085 (vector c)
8086 (format "[%c%c]" (downcase c) (upcase c))))
8087 string
8088 ""))
8089
8090
bf247b6e 8091;; ------------------------------------------------------------
a4aeb9a4 8092;; -- Tramp file names --
bf247b6e 8093;; ------------------------------------------------------------
fb7933a3
KG
8094;; Conversion functions between external representation and
8095;; internal data structure. Convenience functions for internal
8096;; data structure.
8097
00d6fd04 8098(defun tramp-file-name-p (vec)
20b8ac83 8099 "Check, whether VEC is a Tramp object."
00d6fd04
MA
8100 (and (vectorp vec) (= 4 (length vec))))
8101
8102(defun tramp-file-name-method (vec)
8103 "Return method component of VEC."
8104 (and (tramp-file-name-p vec) (aref vec 0)))
8105
8106(defun tramp-file-name-user (vec)
8107 "Return user component of VEC."
8108 (and (tramp-file-name-p vec) (aref vec 1)))
8109
8110(defun tramp-file-name-host (vec)
8111 "Return host component of VEC."
8112 (and (tramp-file-name-p vec) (aref vec 2)))
8113
8114(defun tramp-file-name-localname (vec)
8115 "Return localname component of VEC."
8116 (and (tramp-file-name-p vec) (aref vec 3)))
8117
dea31ca6 8118;; The user part of a Tramp file name vector can be of kind
b96e6899 8119;; "user%domain". Sometimes, we must extract these parts.
dea31ca6
MA
8120(defun tramp-file-name-real-user (vec)
8121 "Return the user name of VEC without domain."
a17632c1
MA
8122 (save-match-data
8123 (let ((user (tramp-file-name-user vec)))
8124 (if (and (stringp user)
8125 (string-match tramp-user-with-domain-regexp user))
8126 (match-string 1 user)
8127 user))))
dea31ca6
MA
8128
8129(defun tramp-file-name-domain (vec)
8130 "Return the domain name of VEC."
a17632c1
MA
8131 (save-match-data
8132 (let ((user (tramp-file-name-user vec)))
8133 (and (stringp user)
8134 (string-match tramp-user-with-domain-regexp user)
8135 (match-string 2 user)))))
dea31ca6 8136
00d6fd04
MA
8137;; The host part of a Tramp file name vector can be of kind
8138;; "host#port". Sometimes, we must extract these parts.
8a4438b6 8139(defun tramp-file-name-real-host (vec)
00d6fd04 8140 "Return the host name of VEC without port."
a17632c1
MA
8141 (save-match-data
8142 (let ((host (tramp-file-name-host vec)))
8143 (if (and (stringp host)
8144 (string-match tramp-host-with-port-regexp host))
8145 (match-string 1 host)
8146 host))))
00d6fd04 8147
8a4438b6 8148(defun tramp-file-name-port (vec)
00d6fd04 8149 "Return the port number of VEC."
a17632c1
MA
8150 (save-match-data
8151 (let ((host (tramp-file-name-host vec)))
8152 (and (stringp host)
8153 (string-match tramp-host-with-port-regexp host)
8154 (string-to-number (match-string 2 host))))))
fb7933a3
KG
8155
8156(defun tramp-tramp-file-p (name)
a09dc9bf 8157 "Return t if NAME is a string with Tramp file name syntax."
fb7933a3 8158 (save-match-data
a09dc9bf 8159 (and (stringp name) (string-match tramp-file-name-regexp name))))
bf247b6e 8160
8a4438b6 8161(defun tramp-find-method (method user host)
00d6fd04
MA
8162 "Return the right method string to use.
8163This is METHOD, if non-nil. Otherwise, do a lookup in
8164`tramp-default-method-alist'."
8165 (or method
8166 (let ((choices tramp-default-method-alist)
8167 lmethod item)
8168 (while choices
8169 (setq item (pop choices))
8170 (when (and (string-match (or (nth 0 item) "") (or host ""))
8171 (string-match (or (nth 1 item) "") (or user "")))
8172 (setq lmethod (nth 2 item))
8173 (setq choices nil)))
8174 lmethod)
8175 tramp-default-method))
8176
8a4438b6 8177(defun tramp-find-user (method user host)
00d6fd04
MA
8178 "Return the right user string to use.
8179This is USER, if non-nil. Otherwise, do a lookup in
8180`tramp-default-user-alist'."
8181 (or user
8182 (let ((choices tramp-default-user-alist)
8183 luser item)
8184 (while choices
8185 (setq item (pop choices))
8186 (when (and (string-match (or (nth 0 item) "") (or method ""))
8187 (string-match (or (nth 1 item) "") (or host "")))
8188 (setq luser (nth 2 item))
8189 (setq choices nil)))
8190 luser)
8191 tramp-default-user))
8192
8a4438b6 8193(defun tramp-find-host (method user host)
00d6fd04
MA
8194 "Return the right host string to use.
8195This is HOST, if non-nil. Otherwise, it is `tramp-default-host'."
8196 (or (and (> (length host) 0) host)
8197 tramp-default-host))
8198
9ce8462a 8199(defun tramp-dissect-file-name (name &optional nodefault)
00d6fd04 8200 "Return a `tramp-file-name' structure.
9ce8462a
MA
8201The structure consists of remote method, remote user, remote host
8202and localname (file name on remote host). If NODEFAULT is
8203non-nil, the file name parts are not expanded to their default
8204values."
4007ba5b 8205 (save-match-data
00d6fd04 8206 (let ((match (string-match (nth 0 tramp-file-name-structure) name)))
a4aeb9a4 8207 (unless match (error "Not a Tramp file name: %s" name))
00d6fd04
MA
8208 (let ((method (match-string (nth 1 tramp-file-name-structure) name))
8209 (user (match-string (nth 2 tramp-file-name-structure) name))
8210 (host (match-string (nth 3 tramp-file-name-structure) name))
8211 (localname (match-string (nth 4 tramp-file-name-structure) name)))
5d449a36
MA
8212 (when (member method '("multi" "multiu"))
8213 (error
8214 "`%s' method is no longer supported, see (info \"(tramp)Multi-hops\")"
8215 method))
b96e6899
MA
8216 (when host
8217 (when (string-match tramp-prefix-ipv6-regexp host)
8218 (setq host (replace-match "" nil t host)))
8219 (when (string-match tramp-postfix-ipv6-regexp host)
8220 (setq host (replace-match "" nil t host))))
9ce8462a
MA
8221 (if nodefault
8222 (vector method user host localname)
8223 (vector
8224 (tramp-find-method method user host)
8225 (tramp-find-user method user host)
8226 (tramp-find-host method user host)
8227 localname))))))
00d6fd04
MA
8228
8229(defun tramp-equal-remote (file1 file2)
20b8ac83 8230 "Check, whether the remote parts of FILE1 and FILE2 are identical.
00d6fd04
MA
8231The check depends on method, user and host name of the files. If
8232one of the components is missing, the default values are used.
8233The local file name parts of FILE1 and FILE2 are not taken into
8234account.
fb7933a3 8235
00d6fd04
MA
8236Example:
8237
8238 (tramp-equal-remote \"/ssh::/etc\" \"/<your host name>:/home\")
8239
8240would yield `t'. On the other hand, the following check results in nil:
8241
8242 (tramp-equal-remote \"/sudo::/etc\" \"/su::/etc\")"
9e6ab520
MA
8243 (and (stringp (file-remote-p file1))
8244 (stringp (file-remote-p file2))
94be87e8 8245 (string-equal (file-remote-p file1) (file-remote-p file2))))
00d6fd04
MA
8246
8247(defun tramp-make-tramp-file-name (method user host localname)
8248 "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME."
8249 (concat tramp-prefix-format
8250 (when (not (zerop (length method)))
8251 (concat method tramp-postfix-method-format))
8252 (when (not (zerop (length user)))
8253 (concat user tramp-postfix-user-format))
b96e6899
MA
8254 (when host
8255 (if (string-match tramp-ipv6-regexp host)
8256 (concat tramp-prefix-ipv6-format host tramp-postfix-ipv6-format)
8257 host))
8258 tramp-postfix-host-format
00d6fd04
MA
8259 (when localname localname)))
8260
8261(defun tramp-completion-make-tramp-file-name (method user host localname)
8262 "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME.
8263It must not be a complete Tramp file name, but as long as there are
8264necessary only. This function will be used in file name completion."
8265 (concat tramp-prefix-format
8266 (when (not (zerop (length method)))
8267 (concat method tramp-postfix-method-format))
8268 (when (not (zerop (length user)))
8269 (concat user tramp-postfix-user-format))
8270 (when (not (zerop (length host)))
b96e6899
MA
8271 (concat
8272 (if (string-match tramp-ipv6-regexp host)
8273 (concat tramp-prefix-ipv6-format host tramp-postfix-ipv6-format)
8274 host)
8275 tramp-postfix-host-format))
00d6fd04
MA
8276 (when localname localname)))
8277
8278(defun tramp-make-copy-program-file-name (vec)
8279 "Create a file name suitable to be passed to `rcp' and workalikes."
8280 (let ((user (tramp-file-name-user vec))
0f205eee 8281 (host (tramp-file-name-real-host vec))
00d6fd04
MA
8282 (localname (tramp-shell-quote-argument
8283 (tramp-file-name-localname vec))))
8284 (if (not (zerop (length user)))
8285 (format "%s@%s:%s" user host localname)
8286 (format "%s:%s" host localname))))
8287
7f49fe46 8288(defun tramp-method-out-of-band-p (vec size)
38c65fca 8289 "Return t if this is an out-of-band method, nil otherwise."
7f49fe46
MA
8290 (and
8291 ;; It shall be an out-of-band method.
8292 (tramp-get-method-parameter (tramp-file-name-method vec) 'tramp-copy-program)
8293 ;; Either the file size is large enough, or (in rare cases) there
8294 ;; does not exist a remote encoding.
20b8ac83
MA
8295 (or (null tramp-copy-size-limit)
8296 (> size tramp-copy-size-limit)
8297 (null (tramp-get-inline-coding vec "remote-encoding" size)))))
fb7933a3 8298
0f205eee
MA
8299(defun tramp-local-host-p (vec)
8300 "Return t if this points to the local host, nil otherwise."
c992abdb
MA
8301 ;; We cannot use `tramp-file-name-real-host'. A port is an
8302 ;; indication for an ssh tunnel or alike.
8303 (let ((host (tramp-file-name-host vec)))
0f205eee
MA
8304 (and
8305 (stringp host)
b96e6899 8306 (string-match tramp-local-host-regexp host)
46bcd78c
MA
8307 ;; The method shall be applied to one of the shell file name
8308 ;; handler. `tramp-local-host-p' is also called for "smb" and
8309 ;; alike, where it must fail.
8310 (tramp-get-method-parameter
8311 (tramp-file-name-method vec) 'tramp-login-program)
a0a5183a
MA
8312 ;; The local temp directory must be writable for the other user.
8313 (file-writable-p
8314 (tramp-make-tramp-file-name
8315 (tramp-file-name-method vec)
8316 (tramp-file-name-user vec)
8317 host
93c3eb7c
MA
8318 (tramp-compat-temporary-file-directory)))
8319 ;; On some systems, chown runs only for root.
8320 (or (zerop (user-uid))
8321 (zerop (tramp-get-remote-uid vec 'integer))))))
0f205eee 8322
fb7933a3
KG
8323;; Variables local to connection.
8324
f84638eb 8325(defun tramp-get-remote-path (vec)
70c11b0b
MA
8326 (with-connection-property
8327 ;; When `tramp-own-remote-path' is in `tramp-remote-path', we
8328 ;; cache the result for the session only. Otherwise, the result
8329 ;; is cached persistently.
8330 (if (memq 'tramp-own-remote-path tramp-remote-path)
8331 (tramp-get-connection-process vec)
8332 vec)
8333 "remote-path"
20b8ac83 8334 (let* ((remote-path (copy-tree tramp-remote-path))
70c11b0b
MA
8335 (elt1 (memq 'tramp-default-remote-path remote-path))
8336 (elt2 (memq 'tramp-own-remote-path remote-path))
f84638eb 8337 (default-remote-path
70c11b0b 8338 (when elt1
f84638eb 8339 (condition-case nil
70c11b0b
MA
8340 (tramp-send-command-and-read
8341 vec "echo \\\"`getconf PATH`\\\"")
f84638eb
MA
8342 ;; Default if "getconf" is not available.
8343 (error
8344 (tramp-message
8345 vec 3
8346 "`getconf PATH' not successful, using default value \"%s\"."
8347 "/bin:/usr/bin")
70c11b0b
MA
8348 "/bin:/usr/bin"))))
8349 (own-remote-path
8350 (when elt2
8351 (condition-case nil
8352 (tramp-send-command-and-read vec "echo \\\"$PATH\\\"")
8353 ;; Default if "getconf" is not available.
8354 (error
8355 (tramp-message
8356 vec 3 "$PATH not set, ignoring `tramp-own-remote-path'.")
8357 nil)))))
8358
8359 ;; Replace place holder `tramp-default-remote-path'.
8360 (when elt1
8361 (setcdr elt1
f84638eb 8362 (append
70c11b0b
MA
8363 (tramp-compat-split-string default-remote-path ":")
8364 (cdr elt1)))
f84638eb
MA
8365 (setq remote-path (delq 'tramp-default-remote-path remote-path)))
8366
70c11b0b
MA
8367 ;; Replace place holder `tramp-own-remote-path'.
8368 (when elt2
8369 (setcdr elt2
8370 (append
8371 (tramp-compat-split-string own-remote-path ":")
8372 (cdr elt2)))
8373 (setq remote-path (delq 'tramp-own-remote-path remote-path)))
8374
8375 ;; Remove double entries.
8376 (setq elt1 remote-path)
8377 (while (consp elt1)
8378 (while (and (car elt1) (setq elt2 (member (car elt1) (cdr elt1))))
8379 (setcar elt2 nil))
8380 (setq elt1 (cdr elt1)))
8381
f84638eb
MA
8382 ;; Remove non-existing directories.
8383 (delq
8384 nil
8385 (mapcar
8386 (lambda (x)
8387 (and
70c11b0b
MA
8388 (stringp x)
8389 (file-directory-p
8390 (tramp-make-tramp-file-name
8391 (tramp-file-name-method vec)
8392 (tramp-file-name-user vec)
8393 (tramp-file-name-host vec)
8394 x))
f84638eb
MA
8395 x))
8396 remote-path)))))
8397
a4aeb9a4
MA
8398(defun tramp-get-remote-tmpdir (vec)
8399 (with-connection-property vec "tmp-directory"
8400 (let ((dir (tramp-shell-quote-argument "/tmp")))
8401 (if (and (zerop
8402 (tramp-send-command-and-check
8403 vec (format "%s -d %s" (tramp-get-test-command vec) dir)))
8404 (zerop
8405 (tramp-send-command-and-check
8406 vec (format "%s -w %s" (tramp-get-test-command vec) dir))))
8407 dir
8408 (tramp-error vec 'file-error "Directory %s not accessible" dir)))))
8409
00d6fd04
MA
8410(defun tramp-get-ls-command (vec)
8411 (with-connection-property vec "ls"
946a5aeb
MA
8412 (tramp-message vec 5 "Finding a suitable `ls' command")
8413 (or
8414 (catch 'ls-found
8415 (dolist (cmd '("ls" "gnuls" "gls"))
8416 (let ((dl (tramp-get-remote-path vec))
8417 result)
8418 (while (and dl (setq result (tramp-find-executable vec cmd dl t t)))
7e5686f0
MA
8419 ;; Check parameters. On busybox, "ls" output coloring is
8420 ;; enabled by default sometimes. So we try to disable it
8421 ;; when possible. $LS_COLORING is not supported there.
20b8ac83
MA
8422 ;; Some "ls" versions are sensible wrt the order of
8423 ;; arguments, they fail when "-al" is after the
8424 ;; "--color=never" argument (for example on FreeBSD).
946a5aeb
MA
8425 (when (zerop (tramp-send-command-and-check
8426 vec (format "%s -lnd /" result)))
7e5686f0 8427 (when (zerop (tramp-send-command-and-check
20b8ac83
MA
8428 vec (format
8429 "%s --color=never -al /dev/null" result)))
7e5686f0 8430 (setq result (concat result " --color=never")))
946a5aeb
MA
8431 (throw 'ls-found result))
8432 (setq dl (cdr dl))))))
8433 (tramp-error vec 'file-error "Couldn't find a proper `ls' command"))))
00d6fd04 8434
8e754ea2
MA
8435(defun tramp-get-ls-command-with-dired (vec)
8436 (save-match-data
8437 (with-connection-property vec "ls-dired"
8438 (tramp-message vec 5 "Checking, whether `ls --dired' works")
20b8ac83
MA
8439 ;; Some "ls" versions are sensible wrt the order of arguments,
8440 ;; they fail when "-al" is after the "--dired" argument (for
8441 ;; example on FreeBSD).
8e754ea2 8442 (zerop (tramp-send-command-and-check
20b8ac83
MA
8443 vec (format "%s --dired -al /dev/null"
8444 (tramp-get-ls-command vec)))))))
8e754ea2 8445
00d6fd04
MA
8446(defun tramp-get-test-command (vec)
8447 (with-connection-property vec "test"
946a5aeb
MA
8448 (tramp-message vec 5 "Finding a suitable `test' command")
8449 (if (zerop (tramp-send-command-and-check vec "test 0"))
8450 "test"
8451 (tramp-find-executable vec "test" (tramp-get-remote-path vec)))))
00d6fd04
MA
8452
8453(defun tramp-get-test-nt-command (vec)
8454 ;; Does `test A -nt B' work? Use abominable `find' construct if it
8455 ;; doesn't. BSD/OS 4.0 wants the parentheses around the command,
8456 ;; for otherwise the shell crashes.
8457 (with-connection-property vec "test-nt"
8458 (or
8459 (progn
8460 (tramp-send-command
8461 vec (format "( %s / -nt / )" (tramp-get-test-command vec)))
8462 (with-current-buffer (tramp-get-buffer vec)
8463 (goto-char (point-min))
a0a5183a 8464 (when (looking-at (regexp-quote tramp-end-of-output))
00d6fd04
MA
8465 (format "%s %%s -nt %%s" (tramp-get-test-command vec)))))
8466 (progn
8467 (tramp-send-command
8468 vec
8469 (format
8470 "tramp_test_nt () {\n%s -n \"`find $1 -prune -newer $2 -print`\"\n}"
8471 (tramp-get-test-command vec)))
8472 "tramp_test_nt %s %s"))))
8473
8474(defun tramp-get-file-exists-command (vec)
8475 (with-connection-property vec "file-exists"
946a5aeb
MA
8476 (tramp-message vec 5 "Finding command to check if file exists")
8477 (tramp-find-file-exists-command vec)))
00d6fd04
MA
8478
8479(defun tramp-get-remote-ln (vec)
8480 (with-connection-property vec "ln"
946a5aeb
MA
8481 (tramp-message vec 5 "Finding a suitable `ln' command")
8482 (tramp-find-executable vec "ln" (tramp-get-remote-path vec))))
00d6fd04
MA
8483
8484(defun tramp-get-remote-perl (vec)
8485 (with-connection-property vec "perl"
946a5aeb 8486 (tramp-message vec 5 "Finding a suitable `perl' command")
293c24f9
MA
8487 (let ((result
8488 (or (tramp-find-executable vec "perl5" (tramp-get-remote-path vec))
8489 (tramp-find-executable
8490 vec "perl" (tramp-get-remote-path vec)))))
8491 ;; We must check also for some Perl modules.
8492 (when result
8493 (with-connection-property vec "perl-file-spec"
8494 (zerop
8495 (tramp-send-command-and-check
8496 vec (format "%s -e 'use File::Spec;'" result))))
8497 (with-connection-property vec "perl-cwd-realpath"
8498 (zerop
8499 (tramp-send-command-and-check
8500 vec (format "%s -e 'use Cwd \"realpath\";'" result)))))
8501 result)))
00d6fd04
MA
8502
8503(defun tramp-get-remote-stat (vec)
8504 (with-connection-property vec "stat"
946a5aeb
MA
8505 (tramp-message vec 5 "Finding a suitable `stat' command")
8506 (let ((result (tramp-find-executable
8507 vec "stat" (tramp-get-remote-path vec)))
8508 tmp)
8509 ;; Check whether stat(1) returns usable syntax. %s does not
8510 ;; work on older AIX systems.
8511 (when result
8512 (setq tmp
8513 ;; We don't want to display an error message.
8514 (with-temp-message (or (current-message) "")
8515 (condition-case nil
8516 (tramp-send-command-and-read
8517 vec (format "%s -c '(\"%%N\" %%s)' /" result))
8518 (error nil))))
8519 (unless (and (listp tmp) (stringp (car tmp))
8520 (string-match "^./.$" (car tmp))
8521 (integerp (cadr tmp)))
8522 (setq result nil)))
8523 result)))
fb7933a3 8524
293c24f9
MA
8525(defun tramp-get-remote-readlink (vec)
8526 (with-connection-property vec "readlink"
8527 (tramp-message vec 5 "Finding a suitable `readlink' command")
8528 (let ((result (tramp-find-executable
8529 vec "readlink" (tramp-get-remote-path vec))))
8530 (when (and result
8531 ;; We don't want to display an error message.
8532 (with-temp-message (or (current-message) "")
8533 (condition-case nil
8534 (zerop
8535 (tramp-send-command-and-check
8536 vec (format "%s --canonicalize-missing /" result)))
8537 (error nil))))
8538 result))))
8539
20b8ac83
MA
8540(defun tramp-get-remote-trash (vec)
8541 (with-connection-property vec "trash"
8542 (tramp-message vec 5 "Finding a suitable `trash' command")
8543 (tramp-find-executable vec "trash" (tramp-get-remote-path vec))))
8544
00d6fd04
MA
8545(defun tramp-get-remote-id (vec)
8546 (with-connection-property vec "id"
946a5aeb
MA
8547 (tramp-message vec 5 "Finding POSIX `id' command")
8548 (or
8549 (catch 'id-found
8550 (let ((dl (tramp-get-remote-path vec))
8551 result)
8552 (while (and dl (setq result (tramp-find-executable vec "id" dl t t)))
8553 ;; Check POSIX parameter.
8554 (when (zerop (tramp-send-command-and-check
8555 vec (format "%s -u" result)))
8556 (throw 'id-found result))
8557 (setq dl (cdr dl)))))
8558 (tramp-error vec 'file-error "Couldn't find a POSIX `id' command"))))
00d6fd04
MA
8559
8560(defun tramp-get-remote-uid (vec id-format)
8561 (with-connection-property vec (format "uid-%s" id-format)
8562 (let ((res (tramp-send-command-and-read
8563 vec
8564 (format "%s -u%s %s"
8565 (tramp-get-remote-id vec)
8566 (if (equal id-format 'integer) "" "n")
8567 (if (equal id-format 'integer)
8568 "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
8569 ;; The command might not always return a number.
8570 (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
8571
8572(defun tramp-get-remote-gid (vec id-format)
8573 (with-connection-property vec (format "gid-%s" id-format)
8574 (let ((res (tramp-send-command-and-read
8575 vec
8576 (format "%s -g%s %s"
8577 (tramp-get-remote-id vec)
8578 (if (equal id-format 'integer) "" "n")
8579 (if (equal id-format 'integer)
8580 "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
8581 ;; The command might not always return a number.
8582 (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
fb7933a3 8583
8d60099b
MA
8584(defun tramp-get-local-uid (id-format)
8585 (if (equal id-format 'integer) (user-uid) (user-login-name)))
8586
8587(defun tramp-get-local-gid (id-format)
9e6ab520 8588 (nth 3 (tramp-compat-file-attributes "~/" id-format)))
8d60099b 8589
00d6fd04 8590;; Some predefined connection properties.
20b8ac83
MA
8591(defun tramp-get-inline-compress (vec prop size)
8592 "Return the compress command related to PROP.
8593PROP is either `inline-compress' or `inline-decompress'. SIZE is
8594the length of the file to be compressed.
8595
8596If no corresponding command is found, nil is returned."
8597 (when (and (integerp tramp-inline-compress-start-size)
8598 (> size tramp-inline-compress-start-size))
8599 (with-connection-property vec prop
8600 (tramp-find-inline-compress vec)
8601 (tramp-get-connection-property vec prop nil))))
8602
8603(defun tramp-get-inline-coding (vec prop size)
8604 "Return the coding command related to PROP.
8605PROP is either `remote-encoding', `remode-decoding',
8606`local-encoding' or `local-decoding'.
8607
8608SIZE is the length of the file to be coded. Depending on SIZE,
8609compression might be applied.
8610
8611If no corresponding command is found, nil is returned.
8612Otherwise, either a string is returned which contains a `%s' mark
8613to be used for the respective input or output file; or a Lisp
8614function cell is returned to be applied on a buffer."
efd49885
MA
8615 ;; We must catch the errors, because we want to return `nil', when
8616 ;; no inline coding is found.
8617 (ignore-errors
8618 (let ((coding
8619 (with-connection-property vec prop
8620 (tramp-find-inline-encoding vec)
8621 (tramp-get-connection-property vec prop nil)))
8622 (prop1 (if (string-match "encoding" prop)
8623 "inline-compress" "inline-decompress"))
8624 compress)
8625 ;; The connection property might have been cached. So we must
8626 ;; send the script to the remote side - maybe.
8627 (when (and coding (symbolp coding) (string-match "remote" prop))
8628 (let ((name (symbol-name coding)))
8629 (while (string-match (regexp-quote "-") name)
8630 (setq name (replace-match "_" nil t name)))
8631 (tramp-maybe-send-script vec (symbol-value coding) name)
8632 (setq coding name)))
8633 (when coding
8634 ;; Check for the `compress' command.
8635 (setq compress (tramp-get-inline-compress vec prop1 size))
8636 ;; Return the value.
8637 (cond
8638 ((and compress (symbolp coding))
8639 (if (string-match "decompress" prop1)
8640 `(lambda (beg end)
8641 (,coding beg end)
8642 (let ((coding-system-for-write 'binary)
8643 (coding-system-for-read 'binary))
8644 (apply
8645 'call-process-region (point-min) (point-max)
8646 (car (split-string ,compress)) t t nil
8647 (cdr (split-string ,compress)))))
20b8ac83 8648 `(lambda (beg end)
20b8ac83
MA
8649 (let ((coding-system-for-write 'binary)
8650 (coding-system-for-read 'binary))
8651 (apply
efd49885 8652 'call-process-region beg end
20b8ac83 8653 (car (split-string ,compress)) t t nil
efd49885
MA
8654 (cdr (split-string ,compress))))
8655 (,coding (point-min) (point-max)))))
8656 ((symbolp coding)
8657 coding)
8658 ((and compress (string-match "decoding" prop))
01d70c32
MA
8659 (format
8660 ;; Windows shells need the program file name after
8661 ;; the pipe symbol be quoted if they use forward
8662 ;; slashes as directory separators.
8663 (if (and (string-match "local" prop)
8664 (memq system-type '(windows-nt)))
8665 "(%s | \"%s\" >%%s)"
8666 "(%s | %s >%%s)")
8667 coding compress))
efd49885 8668 (compress
01d70c32
MA
8669 (format
8670 ;; Windows shells need the program file name after
8671 ;; the pipe symbol be quoted if they use forward
8672 ;; slashes as directory separators.
8673 (if (and (string-match "local" prop)
8674 (memq system-type '(windows-nt)))
8675 "(%s <%%s | \"%s\")"
8676 "(%s <%%s | %s)")
8677 compress coding))
efd49885
MA
8678 ((string-match "decoding" prop)
8679 (format "%s >%%s" coding))
8680 (t
8681 (format "%s <%%s" coding)))))))
fb7933a3 8682
00d6fd04 8683(defun tramp-get-method-parameter (method param)
c951aecb 8684 "Return the method parameter PARAM.
20b8ac83 8685If the `tramp-methods' entry does not exist, return nil."
00d6fd04
MA
8686 (let ((entry (assoc param (assoc method tramp-methods))))
8687 (when entry (cadr entry))))
90f8dc03 8688
fb7933a3
KG
8689;; Auto saving to a special directory.
8690
00cec167 8691(defun tramp-exists-file-name-handler (operation &rest args)
20b8ac83 8692 "Check, whether OPERATION runs a file name handler."
00d6fd04
MA
8693 ;; The file name handler is determined on base of either an
8694 ;; argument, `buffer-file-name', or `default-directory'.
8695 (condition-case nil
8696 (let* ((buffer-file-name "/")
8697 (default-directory "/")
8698 (fnha file-name-handler-alist)
8699 (check-file-name-operation operation)
8700 (file-name-handler-alist
8701 (list
8702 (cons "/"
aa485f7c
MA
8703 (lambda (operation &rest args)
8704 "Returns OPERATION if it is the one to be checked."
8705 (if (equal check-file-name-operation operation)
8706 operation
8707 (let ((file-name-handler-alist fnha))
8708 (apply operation args))))))))
00d6fd04
MA
8709 (equal (apply operation args) operation))
8710 (error nil)))
c1105d05
MA
8711
8712(unless (tramp-exists-file-name-handler 'make-auto-save-file-name)
8713 (defadvice make-auto-save-file-name
8714 (around tramp-advice-make-auto-save-file-name () activate)
00d6fd04 8715 "Invoke `tramp-handle-make-auto-save-file-name' for Tramp files."
20b8ac83 8716 (if (tramp-tramp-file-p (buffer-file-name))
7f49fe46
MA
8717 ;; We cannot call `tramp-handle-make-auto-save-file-name'
8718 ;; directly, because this would bypass the locking mechanism.
8719 (setq ad-return-value
8720 (tramp-file-name-handler 'make-auto-save-file-name))
a69c01a0 8721 ad-do-it))
191bb792
MA
8722 (add-hook
8723 'tramp-unload-hook
8724 (lambda ()
8725 (ad-remove-advice
8726 'make-auto-save-file-name
d7ec1df7
MA
8727 'around 'tramp-advice-make-auto-save-file-name)
8728 (ad-activate 'make-auto-save-file-name))))
fb7933a3 8729
20b8ac83
MA
8730;; In XEmacs < 21.5, autosaved remote files have permission 0666 minus
8731;; umask. This is a security threat.
414da5ab
MA
8732
8733(defun tramp-set-auto-save-file-modes ()
8734 "Set permissions of autosaved remote files to the original permissions."
8735 (let ((bfn (buffer-file-name)))
20b8ac83 8736 (when (and (tramp-tramp-file-p bfn)
b50dd0d2 8737 (buffer-modified-p)
414da5ab 8738 (stringp buffer-auto-save-file-name)
340b8d4f
MA
8739 (not (equal bfn buffer-auto-save-file-name)))
8740 (unless (file-exists-p buffer-auto-save-file-name)
8741 (write-region "" nil buffer-auto-save-file-name))
8742 ;; Permissions should be set always, because there might be an old
8743 ;; auto-saved file belonging to another original file. This could
8744 ;; be a security threat.
7177e2a3 8745 (set-file-modes buffer-auto-save-file-name
11948172 8746 (or (file-modes bfn) (tramp-octal-to-decimal "0600"))))))
414da5ab 8747
20b8ac83
MA
8748(unless (and (featurep 'xemacs)
8749 (= emacs-major-version 21)
8750 (> emacs-minor-version 4))
a69c01a0
MA
8751 (add-hook 'auto-save-hook 'tramp-set-auto-save-file-modes)
8752 (add-hook 'tramp-unload-hook
aa485f7c
MA
8753 (lambda ()
8754 (remove-hook 'auto-save-hook 'tramp-set-auto-save-file-modes))))
414da5ab 8755
fb7933a3
KG
8756(defun tramp-subst-strs-in-string (alist string)
8757 "Replace all occurrences of the string FROM with TO in STRING.
8758ALIST is of the form ((FROM . TO) ...)."
8759 (save-match-data
8760 (while alist
8761 (let* ((pr (car alist))
8762 (from (car pr))
8763 (to (cdr pr)))
8764 (while (string-match (regexp-quote from) string)
8765 (setq string (replace-match to t t string)))
8766 (setq alist (cdr alist))))
8767 string))
8768
fb7933a3
KG
8769;; ------------------------------------------------------------
8770;; -- Compatibility functions section --
8771;; ------------------------------------------------------------
8772
00d6fd04 8773(defun tramp-read-passwd (proc &optional prompt)
fb7933a3 8774 "Read a password from user (compat function).
5615d63f 8775Consults the auth-source package.
5ec2cc41 8776Invokes `password-read' if available, `read-passwd' else."
00d6fd04
MA
8777 (let* ((key (tramp-make-tramp-file-name
8778 tramp-current-method tramp-current-user
8779 tramp-current-host ""))
8780 (pw-prompt
8781 (or prompt
8782 (with-current-buffer (process-buffer proc)
8783 (tramp-check-for-regexp proc tramp-password-prompt-regexp)
8784 (format "%s for %s " (capitalize (match-string 1)) key)))))
7540f029
MA
8785 (with-parsed-tramp-file-name key nil
8786 (prog1
8787 (or
8788 ;; See if auth-sources contains something useful, if it's bound.
8789 (and (boundp 'auth-sources)
8790 (tramp-get-connection-property v "first-password-request" nil)
8791 ;; Try with Tramp's current method.
20b8ac83
MA
8792 (tramp-compat-funcall
8793 'auth-source-user-or-password
8794 "password" tramp-current-host tramp-current-method))
7540f029
MA
8795 ;; Try the password cache.
8796 (when (functionp 'password-read)
8797 (unless (tramp-get-connection-property
8798 v "first-password-request" nil)
20b8ac83 8799 (tramp-compat-funcall 'password-cache-remove key))
7540f029 8800 (let ((password
20b8ac83
MA
8801 (tramp-compat-funcall 'password-read pw-prompt key)))
8802 (tramp-compat-funcall 'password-cache-add key password)
7540f029
MA
8803 password))
8804 ;; Else, get the password interactively.
8805 (read-passwd pw-prompt))
8806 (tramp-set-connection-property v "first-password-request" nil)))))
00d6fd04 8807
9c13938d
MA
8808(defun tramp-clear-passwd (vec)
8809 "Clear password cache for connection related to VEC."
20b8ac83
MA
8810 (tramp-compat-funcall
8811 'password-cache-remove
8812 (tramp-make-tramp-file-name
8813 (tramp-file-name-method vec)
8814 (tramp-file-name-user vec)
8815 (tramp-file-name-host vec)
8816 "")))
00d6fd04
MA
8817
8818;; Snarfed code from time-date.el and parse-time.el
8819
8820(defconst tramp-half-a-year '(241 17024)
8821"Evaluated by \"(days-to-time 183)\".")
8822
8823(defconst tramp-parse-time-months
8824 '(("jan" . 1) ("feb" . 2) ("mar" . 3)
8825 ("apr" . 4) ("may" . 5) ("jun" . 6)
8826 ("jul" . 7) ("aug" . 8) ("sep" . 9)
8827 ("oct" . 10) ("nov" . 11) ("dec" . 12))
8828 "Alist mapping month names to integers.")
8829
8830(defun tramp-time-less-p (t1 t2)
8831 "Say whether time value T1 is less than time value T2."
8832 (unless t1 (setq t1 '(0 0)))
8833 (unless t2 (setq t2 '(0 0)))
8834 (or (< (car t1) (car t2))
8835 (and (= (car t1) (car t2))
8836 (< (nth 1 t1) (nth 1 t2)))))
8837
8838(defun tramp-time-subtract (t1 t2)
8839 "Subtract two time values.
8840Return the difference in the format of a time value."
8841 (unless t1 (setq t1 '(0 0)))
8842 (unless t2 (setq t2 '(0 0)))
8843 (let ((borrow (< (cadr t1) (cadr t2))))
8844 (list (- (car t1) (car t2) (if borrow 1 0))
8845 (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2)))))
fb7933a3
KG
8846
8847(defun tramp-time-diff (t1 t2)
8848 "Return the difference between the two times, in seconds.
1a762140 8849T1 and T2 are time values (as returned by `current-time' for example)."
fb7933a3 8850 ;; Pacify byte-compiler with `symbol-function'.
ea9d1443
KG
8851 (cond ((and (fboundp 'subtract-time)
8852 (fboundp 'float-time))
20b8ac83
MA
8853 (tramp-compat-funcall
8854 'float-time (tramp-compat-funcall 'subtract-time t1 t2)))
ea9d1443
KG
8855 ((and (fboundp 'subtract-time)
8856 (fboundp 'time-to-seconds))
20b8ac83
MA
8857 (tramp-compat-funcall
8858 'time-to-seconds (tramp-compat-funcall 'subtract-time t1 t2)))
fb7933a3 8859 ((fboundp 'itimer-time-difference)
20b8ac83
MA
8860 (tramp-compat-funcall
8861 'itimer-time-difference
8862 (if (< (length t1) 3) (append t1 '(0)) t1)
8863 (if (< (length t2) 3) (append t2 '(0)) t2)))
fb7933a3 8864 (t
00d6fd04 8865 (let ((time (tramp-time-subtract t1 t2)))
ea9d1443
KG
8866 (+ (* (car time) 65536.0)
8867 (cadr time)
8868 (/ (or (nth 2 time) 0) 1000000.0))))))
fb7933a3
KG
8869
8870(defun tramp-coding-system-change-eol-conversion (coding-system eol-type)
8871 "Return a coding system like CODING-SYSTEM but with given EOL-TYPE.
8872EOL-TYPE can be one of `dos', `unix', or `mac'."
8873 (cond ((fboundp 'coding-system-change-eol-conversion)
20b8ac83
MA
8874 (tramp-compat-funcall
8875 'coding-system-change-eol-conversion coding-system eol-type))
fb7933a3 8876 ((fboundp 'subsidiary-coding-system)
20b8ac83
MA
8877 (tramp-compat-funcall
8878 'subsidiary-coding-system coding-system
8879 (cond ((eq eol-type 'dos) 'crlf)
8880 ((eq eol-type 'unix) 'lf)
8881 ((eq eol-type 'mac) 'cr)
8882 (t
8883 (error "Unknown EOL-TYPE `%s', must be %s"
8884 eol-type
8885 "`dos', `unix', or `mac'")))))
fb7933a3
KG
8886 (t (error "Can't change EOL conversion -- is MULE missing?"))))
8887
19a87064
MA
8888(defun tramp-set-process-query-on-exit-flag (process flag)
8889 "Specify if query is needed for process when Emacs is exited.
8890If the second argument flag is non-nil, Emacs will query the user before
8891exiting if process is running."
8892 (if (fboundp 'set-process-query-on-exit-flag)
20b8ac83
MA
8893 (tramp-compat-funcall 'set-process-query-on-exit-flag process flag)
8894 (tramp-compat-funcall 'process-kill-without-query process flag)))
19a87064 8895
19a87064 8896
bf247b6e
KS
8897;; ------------------------------------------------------------
8898;; -- Kludges section --
8899;; ------------------------------------------------------------
fb7933a3
KG
8900
8901;; Currently (as of Emacs 20.5), the function `shell-quote-argument'
8902;; does not deal well with newline characters. Newline is replaced by
8903;; backslash newline. But if, say, the string `a backslash newline b'
8904;; is passed to a shell, the shell will expand this into "ab",
8905;; completely omitting the newline. This is not what was intended.
8906;; It does not appear to be possible to make the function
8907;; `shell-quote-argument' work with newlines without making it
8908;; dependent on the shell used. But within this package, we know that
8909;; we will always use a Bourne-like shell, so we use an approach which
8910;; groks newlines.
8911;;
8912;; The approach is simple: we call `shell-quote-argument', then
8913;; massage the newline part of the result.
8914;;
8915;; This function should produce a string which is grokked by a Unix
8916;; shell, even if the Emacs is running on Windows. Since this is the
8917;; kludges section, we bind `system-type' in such a way that
8918;; `shell-quote-arguments' behaves as if on Unix.
8919;;
8920;; Thanks to Mario DeWeerd for the hint that it is sufficient for this
8921;; function to work with Bourne-like shells.
8922;;
8923;; CCC: This function should be rewritten so that
8924;; `shell-quote-argument' is not used. This way, we are safe from
8925;; changes in `shell-quote-argument'.
8926(defun tramp-shell-quote-argument (s)
8927 "Similar to `shell-quote-argument', but groks newlines.
8928Only works for Bourne-like shells."
8929 (let ((system-type 'not-windows))
8930 (save-match-data
8931 (let ((result (shell-quote-argument s))
8932 (nl (regexp-quote (format "\\%s" tramp-rsh-end-of-line))))
8933 (when (and (>= (length result) 2)
8934 (string= (substring result 0 2) "\\~"))
8935 (setq result (substring result 1)))
8936 (while (string-match nl result)
8937 (setq result (replace-match (format "'%s'" tramp-rsh-end-of-line)
8938 t t result)))
8939 result))))
8940
a69c01a0
MA
8941;; Checklist for `tramp-unload-hook'
8942;; - Unload all `tramp-*' packages
8943;; - Reset `file-name-handler-alist'
8944;; - Cleanup hooks where Tramp functions are in
8945;; - Cleanup advised functions
8946;; - Cleanup autoloads
8947;;;###autoload
8948(defun tramp-unload-tramp ()
08b1eb21 8949 "Discard Tramp from loading remote files."
a69c01a0
MA
8950 (interactive)
8951 ;; When Tramp is not loaded yet, its autoloads are still active.
8c04e197 8952 (tramp-unload-file-name-handlers)
a69c01a0 8953 ;; ange-ftp settings must be enabled.
20b8ac83 8954 (tramp-compat-funcall 'tramp-ftp-enable-ange-ftp)
00d6fd04
MA
8955 ;; Maybe its not loaded yet.
8956 (condition-case nil
8957 (unload-feature 'tramp 'force)
a69c01a0
MA
8958 (error nil)))
8959
dea31ca6
MA
8960(when (and load-in-progress
8961 (string-match "Loading tramp..." (or (current-message) "")))
ccb4a481
MA
8962 (message "Loading tramp...done"))
8963
fb7933a3
KG
8964(provide 'tramp)
8965
fb7933a3
KG
8966;;; TODO:
8967
4007ba5b 8968;; * Handle nonlocal exits such as C-g.
00d6fd04
MA
8969;; * But it would probably be better to use with-local-quit at the
8970;; place where it's actually needed: around any potentially
8971;; indefinitely blocking piece of code. In this case it would be
8972;; within Tramp around one of its calls to accept-process-output (or
8973;; around one of the loops that calls accept-process-output)
d037d501 8974;; (Stefan Monnier).
fb7933a3 8975;; * Rewrite `tramp-shell-quote-argument' to abstain from using
b1d06e75 8976;; `shell-quote-argument'.
fb7933a3
KG
8977;; * In Emacs 21, `insert-directory' shows total number of bytes used
8978;; by the files in that directory. Add this here.
8979;; * Avoid screen blanking when hitting `g' in dired. (Eli Tziperman)
8980;; * Make ffap.el grok Tramp filenames. (Eli Tziperman)
fb7933a3
KG
8981;; * Don't use globbing for directories with many files, as this is
8982;; likely to produce long command lines, and some shells choke on
8983;; long command lines.
fb7933a3 8984;; * How to deal with MULE in `insert-file-contents' and `write-region'?
fb7933a3 8985;; * abbreviate-file-name
8e754ea2 8986;; * Better error checking. At least whenever we see something
fb7933a3
KG
8987;; strange when doing zerop, we should kill the process and start
8988;; again. (Greg Stark)
fb7933a3 8989;; * Remove unneeded parameters from methods.
fb7933a3
KG
8990;; * Make it work for different encodings, and for different file name
8991;; encodings, too. (Daniel Pittman)
fb7933a3
KG
8992;; * Don't search for perl5 and perl. Instead, only search for perl and
8993;; then look if it's the right version (with `perl -v').
8994;; * When editing a remote CVS controlled file as a different user, VC
8995;; gets confused about the file locking status. Try to find out why
8996;; the workaround doesn't work.
3cdaec13 8997;; * Username and hostname completion.
6c4e47fa 8998;; ** Try to avoid usage of `last-input-event' in `tramp-completion-mode-p'.
8daea7fc 8999;; ** Unify `tramp-parse-{rhosts,shosts,sconfig,hosts,passwd,netrc}'.
16674e4f 9000;; Code is nearly identical.
cfb5c0db
MA
9001;; * Allow out-of-band methods as _last_ multi-hop. Open a connection
9002;; until the last but one hop via `start-file-process'. Apply it
9003;; also for ftp and smb.
00d6fd04
MA
9004;; * WIBNI if we had a command "trampclient"? If I was editing in
9005;; some shell with root priviledges, it would be nice if I could
9006;; just call
9007;; trampclient filename.c
9008;; as an editor, and the _current_ shell would connect to an Emacs
9009;; server and would be used in an existing non-priviledged Emacs
9010;; session for doing the editing in question.
9011;; That way, I need not tell Emacs my password again and be afraid
9012;; that it makes it into core dumps or other ugly stuff (I had Emacs
9013;; once display a just typed password in the context of a keyboard
9014;; sequence prompt for a question immediately following in a shell
9015;; script run within Emacs -- nasty).
9016;; And if I have some ssh session running to a different computer,
9017;; having the possibility of passing a local file there to a local
9018;; Emacs session (in case I can arrange for a connection back) would
9019;; be nice.
a4aeb9a4 9020;; Likely the corresponding Tramp server should not allow the
00d6fd04
MA
9021;; equivalent of the emacsclient -eval option in order to make this
9022;; reasonably unproblematic. And maybe trampclient should have some
9023;; way of passing credentials, like by using an SSL socket or
6e4f5731 9024;; something. (David Kastrup)
00d6fd04 9025;; * Reconnect directly to a compliant shell without first going
6e4f5731 9026;; through the user's default shell. (Pete Forman)
00d6fd04 9027;; * Make `tramp-default-user' obsolete.
11c71217 9028;; * How can I interrupt the remote process with a signal
6e4f5731 9029;; (interrupt-process seems not to work)? (Markus Triska)
2296b54d
MA
9030;; * Avoid the local shell entirely for starting remote processes. If
9031;; so, I think even a signal, when delivered directly to the local
9032;; SSH instance, would correctly be propagated to the remote process
9033;; automatically; possibly SSH would have to be started with
6e4f5731 9034;; "-t". (Markus Triska)
dea31ca6 9035;; * It makes me wonder if tramp couldn't fall back to ssh when scp
6e4f5731
MA
9036;; isn't on the remote host. (Mark A. Hershberger)
9037;; * Use lsh instead of ssh. (Alfred M. Szmidt)
3e2fa353
MA
9038;; * Implement a general server-local-variable mechanism, as there are
9039;; probably other variables that need different values for different
9040;; servers too. The user could then configure a variable (such as
9041;; tramp-server-local-variable-alist) to define any such variables
9042;; that they need to, which would then be let bound as appropriate
6e4f5731 9043;; in tramp functions. (Jason Rumney)
946a5aeb
MA
9044;; * Optimize out-of-band copying, when both methods are scp-like (not
9045;; rsync).
9046;; * Keep a second connection open for out-of-band methods like scp or
9047;; rsync.
7e5686f0
MA
9048;; * IMHO, it's a drawback that currently Tramp doesn't support
9049;; Unicode in Dired file names by default. Is it possible to
9050;; improve Tramp to set LC_ALL to "C" only for commands where Tramp
9051;; expects English? Or just to set LC_MESSAGES to "C" if Tramp
6e4f5731 9052;; expects only English messages? (Juri Linkov)
7e5686f0 9053;; * Make shadowfile.el grok Tramp filenames. (Bug#4526, Bug#4846)
20b8ac83 9054;; * Load Tramp subpackages only when needed. (Bug#1529, Bug#5448, Bug#5705)
7e5686f0
MA
9055;; * Try telnet+curl as new method. It might be useful for busybox,
9056;; without built-in uuencode/uudecode.
20b8ac83
MA
9057;; * Load ~/.emacs_SHELLNAME on the remote host for `shell'.
9058;; * I was wondering it it would be possible to use tramp even if I'm
9059;; actually using sshfs. But when I launch a command I would like
9060;; to get it executed on the remote machine where the files really
9061;; are. (Andrea Crotti)
9062;; * Run emerge on two remote files. Bug is described here:
9063;; <http://www.mail-archive.com/tramp-devel@nongnu.org/msg01041.html>.
9064;; (Bug#6850)
fb7933a3
KG
9065
9066;; Functions for file-name-handler-alist:
9067;; diff-latest-backup-file -- in diff.el
fb7933a3 9068
cdd44874 9069;; arch-tag: 3a21a994-182b-48fa-b0cd-c1d9fede424a
fb7933a3 9070;;; tramp.el ends here
57671b72
MA
9071
9072;; Local Variables:
9073;; mode: Emacs-Lisp
9074;; coding: utf-8
9075;; End: