* dbusbind.c (xd_retrieve_arg): Reorder declarations in order to
[bpt/emacs.git] / lisp / net / tramp.el
CommitLineData
b1a2b924 1;;; tramp.el --- Transparent Remote Access, Multiple Protocol
fb7933a3 2
5fd6d89f 3;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
b96e6899 4;; 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
fb7933a3 5
cbd12ed7
GM
6;; (copyright statements below in code to be updated with the above notice)
7
cdd44874 8;; Author: Kai Großjohann <kai.grossjohann@gmx.net>
d2a2c17f 9;; Michael Albinus <michael.albinus@gmx.de>
fb7933a3
KG
10;; Keywords: comm, processes
11
12;; This file is part of GNU Emacs.
13
874a927a 14;; GNU Emacs is free software: you can redistribute it and/or modify
fb7933a3 15;; it under the terms of the GNU General Public License as published by
874a927a
GM
16;; the Free Software Foundation, either version 3 of the License, or
17;; (at your option) any later version.
fb7933a3
KG
18
19;; GNU Emacs is distributed in the hope that it will be useful,
20;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22;; GNU General Public License for more details.
23
24;; You should have received a copy of the GNU General Public License
874a927a 25;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
fb7933a3
KG
26
27;;; Commentary:
28
29;; This package provides remote file editing, similar to ange-ftp.
30;; The difference is that ange-ftp uses FTP to transfer files between
31;; the local and the remote host, whereas tramp.el uses a combination
32;; of rsh and rcp or other work-alike programs, such as ssh/scp.
33;;
b1a2b924 34;; For more detailed instructions, please see the info file.
fb7933a3
KG
35;;
36;; Notes:
37;; -----
bf247b6e 38;;
00d6fd04
MA
39;; This package only works for Emacs 21.1 and higher, and for XEmacs 21.4
40;; and higher. For XEmacs 21, you need the package `fsf-compat' for
41;; the `with-timeout' macro.)
fb7933a3 42;;
fb7933a3
KG
43;; Also see the todo list at the bottom of this file.
44;;
b1a2b924 45;; The current version of Tramp can be retrieved from the following URL:
340b8d4f 46;; http://ftp.gnu.org/gnu/tramp/
fb7933a3
KG
47;;
48;; There's a mailing list for this, as well. Its name is:
340b8d4f
MA
49;; tramp-devel@gnu.org
50;; You can use the Web to subscribe, under the following URL:
51;; http://lists.gnu.org/mailman/listinfo/tramp-devel
fb7933a3
KG
52;;
53;; For the adventurous, the current development sources are available
54;; via CVS. You can find instructions about this at the following URL:
c62c9d08 55;; http://savannah.gnu.org/projects/tramp/
fb7933a3
KG
56;; Click on "CVS" in the navigation bar near the top.
57;;
58;; Don't forget to put on your asbestos longjohns, first!
59
60;;; Code:
61
ccb4a481
MA
62;; Since Emacs 23.1, loading messages have been disabled during
63;; autoload. However, loading Tramp takes a while, and it could
64;; happen while typing a filename in the minibuffer. Therefore, Tramp
65;; shall inform about.
66(when (and load-in-progress (null (current-message)))
67 (message "Loading tramp..."))
68
b1a2b924
KG
69;; The Tramp version number and bug report address, as prepared by configure.
70(require 'trampver)
a69c01a0 71(add-hook 'tramp-unload-hook
aa485f7c
MA
72 (lambda ()
73 (when (featurep 'trampver)
74 (unload-feature 'trampver 'force))))
a69c01a0 75
9e6ab520 76(require 'tramp-compat)
94be87e8 77(add-hook 'tramp-unload-hook
aa485f7c
MA
78 (lambda ()
79 (when (featurep 'tramp-compat)
80 (unload-feature 'tramp-compat 'force))))
fb7933a3 81
9fa0d3aa 82(require 'format-spec) ; from Gnus 5.8, also in tar ball
5ec2cc41
KG
83;; As long as password.el is not part of (X)Emacs, it shouldn't
84;; be mandatory
85(if (featurep 'xemacs)
86 (load "password" 'noerror)
fd48cd18
GM
87 (or (require 'password-cache nil 'noerror)
88 (require 'password nil 'noerror))) ; from No Gnus, also in tar ball
5ec2cc41 89
fb7933a3
KG
90(require 'shell)
91(require 'advice)
92
bcb04d98
GM
93(eval-and-compile
94 (if (featurep 'xemacs)
95 (load "auth-source" 'noerror)
96 (require 'auth-source nil 'noerror)))
5615d63f 97
00d6fd04
MA
98;; Requiring 'tramp-cache results in an endless loop.
99(autoload 'tramp-get-file-property "tramp-cache")
100(autoload 'tramp-set-file-property "tramp-cache")
101(autoload 'tramp-flush-file-property "tramp-cache")
102(autoload 'tramp-flush-directory-property "tramp-cache")
00d6fd04
MA
103(autoload 'tramp-get-connection-property "tramp-cache")
104(autoload 'tramp-set-connection-property "tramp-cache")
105(autoload 'tramp-flush-connection-property "tramp-cache")
106(autoload 'tramp-parse-connection-properties "tramp-cache")
107(add-hook 'tramp-unload-hook
aa485f7c
MA
108 (lambda ()
109 (when (featurep 'tramp-cache)
110 (unload-feature 'tramp-cache 'force))))
00d6fd04 111
16674e4f
KG
112(autoload 'tramp-uuencode-region "tramp-uu"
113 "Implementation of `uuencode' in Lisp.")
a69c01a0 114(add-hook 'tramp-unload-hook
aa485f7c
MA
115 (lambda ()
116 (when (featurep 'tramp-uu)
117 (unload-feature 'tramp-uu 'force))))
16674e4f 118
00d6fd04 119(autoload 'uudecode-decode-region "uudecode")
16674e4f 120
0664ff72
MA
121;; The following Tramp packages must be loaded after tramp.el, because
122;; they require it as well.
00d6fd04 123(eval-after-load "tramp"
9c13938d
MA
124 '(dolist
125 (feature
126 (list
127
0664ff72 128 ;; Tramp interactive commands.
9c13938d
MA
129 'tramp-cmds
130
131 ;; Load foreign FTP method.
132 (if (featurep 'xemacs) 'tramp-efs 'tramp-ftp)
133
134 ;; tramp-smb uses "smbclient" from Samba. Not available
135 ;; under Cygwin and Windows, because they don't offer
136 ;; "smbclient". And even not necessary there, because Emacs
137 ;; supports UNC file names like "//host/share/localname".
138 (unless (memq system-type '(cygwin windows-nt)) 'tramp-smb)
139
140 ;; Load foreign FISH method.
141 'tramp-fish
00d6fd04 142
70c11b0b 143 ;; tramp-gvfs needs D-Bus messages. Available since Emacs 23
8e754ea2
MA
144 ;; on some system types. We don't call `dbus-ping', because
145 ;; this would load dbus.el.
70c11b0b 146 (when (and (featurep 'dbusbind)
2ac33804
MA
147 (condition-case nil
148 (funcall 'dbus-get-unique-name :session)
149 (error nil))
70c11b0b
MA
150 (tramp-compat-process-running-p "gvfs-fuse-daemon"))
151 'tramp-gvfs)
152
9c13938d 153 ;; Load gateways. It needs `make-network-process' from Emacs 22.
03db0efc
MA
154 (when (functionp 'make-network-process) 'tramp-gw)
155
156 ;; tramp-imap needs both epa (from Emacs 23.1) and imap-hash
157 ;; (from Emacs 23.2).
158 (when (and (locate-library "epa") (locate-library "imap-hash"))
159 'tramp-imap)))
9c13938d
MA
160
161 (when feature
70c11b0b
MA
162 ;; We have used just some basic tests, whether a package shall
163 ;; be added. There might still be other errors during loading,
164 ;; which we will catch here.
165 (catch 'tramp-loading
166 (require feature)
167 (add-hook 'tramp-unload-hook
168 `(lambda ()
169 (when (featurep (quote ,feature))
170 (unload-feature (quote ,feature) 'force)))))
171 (unless (featurep feature)
172 (message "Loading %s failed, ignoring this package" feature)))))
fb7933a3
KG
173
174;;; User Customizable Internal Variables:
175
176(defgroup tramp nil
177 "Edit remote files with a combination of rsh and rcp or similar programs."
589d30dd 178 :group 'files
bf247b6e 179 :version "22.1")
fb7933a3 180
2e271195
MA
181;; Maybe we need once a real Tramp mode, with key bindings etc.
182;;;###autoload
183(defcustom tramp-mode t
184 "*Whether Tramp is enabled.
185If it is set to nil, all remote file names are used literally."
186 :group 'tramp
187 :type 'boolean)
188
00d6fd04 189(defcustom tramp-verbose 3
263c02ef 190 "*Verbosity level for Tramp messages.
00d6fd04
MA
191Any level x includes messages for all levels 1 .. x-1. The levels are
192
193 0 silent (no tramp messages at all)
194 1 errors
195 2 warnings
196 3 connection to remote hosts (default level)
197 4 activities
198 5 internal
199 6 sent and received strings
200 7 file caching
201 8 connection properties
20210 traces (huge)."
fb7933a3
KG
203 :group 'tramp
204 :type 'integer)
205
263c02ef 206;; Emacs case.
38c65fca
KG
207(eval-and-compile
208 (when (boundp 'backup-directory-alist)
209 (defcustom tramp-backup-directory-alist nil
210 "Alist of filename patterns and backup directory names.
211Each element looks like (REGEXP . DIRECTORY), with the same meaning like
212in `backup-directory-alist'. If a Tramp file is backed up, and DIRECTORY
213is a local file name, the backup directory is prepended with Tramp file
00d6fd04 214name prefix \(method, user, host\) of file.
38c65fca
KG
215
216\(setq tramp-backup-directory-alist backup-directory-alist\)
217
218gives the same backup policy for Tramp files on their hosts like the
219policy for local files."
220 :group 'tramp
221 :type '(repeat (cons (regexp :tag "Regexp matching filename")
222 (directory :tag "Backup directory name"))))))
223
224;; XEmacs case. We cannot check for `bkup-backup-directory-info', because
225;; the package "backup-dir" might not be loaded yet.
226(eval-and-compile
227 (when (featurep 'xemacs)
228 (defcustom tramp-bkup-backup-directory-info nil
229 "*Alist of (FILE-REGEXP BACKUP-DIR OPTIONS ...))
230It has the same meaning like `bkup-backup-directory-info' from package
231`backup-dir'. If a Tramp file is backed up, and BACKUP-DIR is a local
232file name, the backup directory is prepended with Tramp file name prefix
00d6fd04 233\(method, user, host\) of file.
38c65fca
KG
234
235\(setq tramp-bkup-backup-directory-info bkup-backup-directory-info\)
236
237gives the same backup policy for Tramp files on their hosts like the
238policy for local files."
bf247b6e 239 :type '(repeat
38c65fca
KG
240 (list (regexp :tag "File regexp")
241 (string :tag "Backup Dir")
242 (set :inline t
243 (const ok-create)
244 (const full-path)
245 (const prepend-name)
246 (const search-upward))))
247 :group 'tramp)))
248
fb7933a3
KG
249(defcustom tramp-auto-save-directory nil
250 "*Put auto-save files in this directory, if set.
251The idea is to use a local directory so that auto-saving is faster."
252 :group 'tramp
00d6fd04 253 :type '(choice (const nil) string))
fb7933a3 254
16674e4f
KG
255(defcustom tramp-encoding-shell
256 (if (memq system-type '(windows-nt))
257 (getenv "COMSPEC")
258 "/bin/sh")
259 "*Use this program for encoding and decoding commands on the local host.
260This shell is used to execute the encoding and decoding command on the
261local host, so if you want to use `~' in those commands, you should
262choose a shell here which groks tilde expansion. `/bin/sh' normally
263does not understand tilde expansion.
264
265For encoding and deocding, commands like the following are executed:
266
267 /bin/sh -c COMMAND < INPUT > OUTPUT
268
269This variable can be used to change the \"/bin/sh\" part. See the
00d6fd04 270variable `tramp-encoding-command-switch' for the \"-c\" part.
fb7933a3
KG
271
272Note that this variable is not used for remote commands. There are
273mechanisms in tramp.el which automatically determine the right shell to
274use for the remote host."
275 :group 'tramp
276 :type '(file :must-match t))
277
16674e4f
KG
278(defcustom tramp-encoding-command-switch
279 (if (string-match "cmd\\.exe" tramp-encoding-shell)
280 "/c"
281 "-c")
282 "*Use this switch together with `tramp-encoding-shell' for local commands.
283See the variable `tramp-encoding-shell' for more information."
284 :group 'tramp
285 :type 'string)
286
00d6fd04
MA
287(defcustom tramp-copy-size-limit 10240
288 "*The maximum file size where inline copying is preferred over an out-of-the-band copy."
16674e4f 289 :group 'tramp
00d6fd04 290 :type 'integer)
90dc758d 291
00d6fd04
MA
292(defcustom tramp-terminal-type "dumb"
293 "*Value of TERM environment variable for logging in to remote host.
294Because Tramp wants to parse the output of the remote shell, it is easily
295confused by ANSI color escape sequences and suchlike. Often, shell init
296files conditionalize this setup based on the TERM environment variable."
90dc758d 297 :group 'tramp
00d6fd04 298 :type 'string)
90dc758d 299
dab816a9
MA
300;; ksh on OpenBSD 4.5 requires, that PS1 contains a `#' character for
301;; root users. It uses the `$' character for other users. In order
302;; to guarantee a proper prompt, we use "#$" for the prompt.
303
304(defvar tramp-end-of-output
305 (format
306 "///%s#$"
307 (md5 (concat (prin1-to-string process-environment) (current-time-string))))
308 "String used to recognize end of output.
309The '$' character at the end is quoted; the string cannot be
310detected as prompt when being sent on echoing hosts, therefore.")
311
312(defconst tramp-initial-end-of-output "#$ "
313 "Prompt when establishing a connection.")
314
00d6fd04
MA
315(defvar tramp-methods
316 `(("rcp" (tramp-login-program "rsh")
317 (tramp-login-args (("%h") ("-l" "%u")))
318 (tramp-remote-sh "/bin/sh")
319 (tramp-copy-program "rcp")
263c02ef 320 (tramp-copy-args (("-p" "%k") ("-r")))
00d6fd04 321 (tramp-copy-keep-date t)
263c02ef 322 (tramp-copy-recursive t)
00d6fd04
MA
323 (tramp-password-end-of-line nil))
324 ("scp" (tramp-login-program "ssh")
2296b54d 325 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
326 ("-e" "none")))
327 (tramp-remote-sh "/bin/sh")
328 (tramp-copy-program "scp")
263c02ef
MA
329 (tramp-copy-args (("-P" "%p") ("-p" "%k")
330 ("-q") ("-r")))
00d6fd04 331 (tramp-copy-keep-date t)
263c02ef 332 (tramp-copy-recursive t)
00d6fd04
MA
333 (tramp-password-end-of-line nil)
334 (tramp-gw-args (("-o"
335 "GlobalKnownHostsFile=/dev/null")
336 ("-o" "UserKnownHostsFile=/dev/null")
337 ("-o" "StrictHostKeyChecking=no")))
338 (tramp-default-port 22))
339 ("scp1" (tramp-login-program "ssh")
2296b54d 340 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
341 ("-1" "-e" "none")))
342 (tramp-remote-sh "/bin/sh")
343 (tramp-copy-program "scp")
344 (tramp-copy-args (("-1") ("-P" "%p") ("-p" "%k")
263c02ef 345 ("-q") ("-r")))
00d6fd04 346 (tramp-copy-keep-date t)
263c02ef 347 (tramp-copy-recursive t)
00d6fd04
MA
348 (tramp-password-end-of-line nil)
349 (tramp-gw-args (("-o"
350 "GlobalKnownHostsFile=/dev/null")
351 ("-o" "UserKnownHostsFile=/dev/null")
352 ("-o" "StrictHostKeyChecking=no")))
353 (tramp-default-port 22))
354 ("scp2" (tramp-login-program "ssh")
2296b54d 355 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
356 ("-2" "-e" "none")))
357 (tramp-remote-sh "/bin/sh")
358 (tramp-copy-program "scp")
359 (tramp-copy-args (("-2") ("-P" "%p") ("-p" "%k")
263c02ef 360 ("-q") ("-r")))
00d6fd04 361 (tramp-copy-keep-date t)
263c02ef 362 (tramp-copy-recursive t)
00d6fd04
MA
363 (tramp-password-end-of-line nil)
364 (tramp-gw-args (("-o"
365 "GlobalKnownHostsFile=/dev/null")
366 ("-o" "UserKnownHostsFile=/dev/null")
367 ("-o" "StrictHostKeyChecking=no")))
368 (tramp-default-port 22))
369 ("scp1_old"
370 (tramp-login-program "ssh1")
371 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
372 ("-e" "none")))
373 (tramp-remote-sh "/bin/sh")
374 (tramp-copy-program "scp1")
263c02ef 375 (tramp-copy-args (("-p" "%k") ("-r")))
00d6fd04 376 (tramp-copy-keep-date t)
263c02ef 377 (tramp-copy-recursive t)
00d6fd04
MA
378 (tramp-password-end-of-line nil))
379 ("scp2_old"
380 (tramp-login-program "ssh2")
381 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
382 ("-e" "none")))
383 (tramp-remote-sh "/bin/sh")
384 (tramp-copy-program "scp2")
263c02ef 385 (tramp-copy-args (("-p" "%k") ("-r")))
00d6fd04 386 (tramp-copy-keep-date t)
263c02ef 387 (tramp-copy-recursive t)
00d6fd04
MA
388 (tramp-password-end-of-line nil))
389 ("sftp" (tramp-login-program "ssh")
390 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
391 ("-e" "none")))
392 (tramp-remote-sh "/bin/sh")
393 (tramp-copy-program "sftp")
394 (tramp-copy-args nil)
395 (tramp-copy-keep-date nil)
396 (tramp-password-end-of-line nil))
397 ("rsync" (tramp-login-program "ssh")
398 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
399 ("-e" "none")))
400 (tramp-remote-sh "/bin/sh")
401 (tramp-copy-program "rsync")
263c02ef 402 (tramp-copy-args (("-e" "ssh") ("-t" "%k") ("-r")))
00d6fd04 403 (tramp-copy-keep-date t)
b88f2d0a 404 (tramp-copy-keep-tmpfile t)
263c02ef 405 (tramp-copy-recursive t)
00d6fd04 406 (tramp-password-end-of-line nil))
263c02ef
MA
407 ("rsyncc"
408 (tramp-login-program "ssh")
946a5aeb
MA
409 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
410 ("-o" "ControlPath=%t.%%r@%%h:%%p")
411 ("-o" "ControlMaster=yes")
412 ("-e" "none")))
413 (tramp-remote-sh "/bin/sh")
414 (tramp-copy-program "rsync")
263c02ef 415 (tramp-copy-args (("-t" "%k") ("-r")))
946a5aeb
MA
416 (tramp-copy-env (("RSYNC_RSH")
417 (,(concat
418 "ssh"
419 " -o ControlPath=%t.%%r@%%h:%%p"
420 " -o ControlMaster=auto"))))
421 (tramp-copy-keep-date t)
b88f2d0a 422 (tramp-copy-keep-tmpfile t)
263c02ef 423 (tramp-copy-recursive t)
946a5aeb 424 (tramp-password-end-of-line nil))
00d6fd04
MA
425 ("remcp" (tramp-login-program "remsh")
426 (tramp-login-args (("%h") ("-l" "%u")))
427 (tramp-remote-sh "/bin/sh")
428 (tramp-copy-program "rcp")
429 (tramp-copy-args (("-p" "%k")))
430 (tramp-copy-keep-date t)
431 (tramp-password-end-of-line nil))
432 ("rsh" (tramp-login-program "rsh")
433 (tramp-login-args (("%h") ("-l" "%u")))
434 (tramp-remote-sh "/bin/sh")
435 (tramp-copy-program nil)
436 (tramp-copy-args nil)
437 (tramp-copy-keep-date nil)
438 (tramp-password-end-of-line nil))
439 ("ssh" (tramp-login-program "ssh")
2296b54d 440 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
441 ("-e" "none")))
442 (tramp-remote-sh "/bin/sh")
443 (tramp-copy-program nil)
444 (tramp-copy-args nil)
445 (tramp-copy-keep-date nil)
446 (tramp-password-end-of-line nil)
447 (tramp-gw-args (("-o"
448 "GlobalKnownHostsFile=/dev/null")
449 ("-o" "UserKnownHostsFile=/dev/null")
450 ("-o" "StrictHostKeyChecking=no")))
451 (tramp-default-port 22))
452 ("ssh1" (tramp-login-program "ssh")
2296b54d 453 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
454 ("-1" "-e" "none")))
455 (tramp-remote-sh "/bin/sh")
456 (tramp-copy-program nil)
457 (tramp-copy-args nil)
458 (tramp-copy-keep-date nil)
459 (tramp-password-end-of-line nil)
460 (tramp-gw-args (("-o"
461 "GlobalKnownHostsFile=/dev/null")
462 ("-o" "UserKnownHostsFile=/dev/null")
463 ("-o" "StrictHostKeyChecking=no")))
464 (tramp-default-port 22))
465 ("ssh2" (tramp-login-program "ssh")
2296b54d 466 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
467 ("-2" "-e" "none")))
468 (tramp-remote-sh "/bin/sh")
469 (tramp-copy-program nil)
470 (tramp-copy-args nil)
471 (tramp-copy-keep-date nil)
472 (tramp-password-end-of-line nil)
473 (tramp-gw-args (("-o"
474 "GlobalKnownHostsFile=/dev/null")
475 ("-o" "UserKnownHostsFile=/dev/null")
476 ("-o" "StrictHostKeyChecking=no")))
477 (tramp-default-port 22))
478 ("ssh1_old"
479 (tramp-login-program "ssh1")
480 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
481 ("-e" "none")))
482 (tramp-remote-sh "/bin/sh")
483 (tramp-copy-program nil)
484 (tramp-copy-args nil)
485 (tramp-copy-keep-date nil)
486 (tramp-password-end-of-line nil))
487 ("ssh2_old"
488 (tramp-login-program "ssh2")
489 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
490 ("-e" "none")))
491 (tramp-remote-sh "/bin/sh")
492 (tramp-copy-program nil)
493 (tramp-copy-args nil)
494 (tramp-copy-keep-date nil)
495 (tramp-password-end-of-line nil))
496 ("remsh" (tramp-login-program "remsh")
497 (tramp-login-args (("%h") ("-l" "%u")))
498 (tramp-remote-sh "/bin/sh")
499 (tramp-copy-program nil)
500 (tramp-copy-args nil)
501 (tramp-copy-keep-date nil)
502 (tramp-password-end-of-line nil))
503 ("telnet"
504 (tramp-login-program "telnet")
505 (tramp-login-args (("%h") ("%p")))
506 (tramp-remote-sh "/bin/sh")
507 (tramp-copy-program nil)
508 (tramp-copy-args nil)
509 (tramp-copy-keep-date nil)
510 (tramp-password-end-of-line nil)
511 (tramp-default-port 23))
512 ("su" (tramp-login-program "su")
513 (tramp-login-args (("-") ("%u")))
514 (tramp-remote-sh "/bin/sh")
515 (tramp-copy-program nil)
516 (tramp-copy-args nil)
517 (tramp-copy-keep-date nil)
518 (tramp-password-end-of-line nil))
519 ("sudo" (tramp-login-program "sudo")
520 (tramp-login-args (("-u" "%u")
42bc9b6d 521 ("-s") ("-H") ("-p" "Password:")))
00d6fd04
MA
522 (tramp-remote-sh "/bin/sh")
523 (tramp-copy-program nil)
524 (tramp-copy-args nil)
525 (tramp-copy-keep-date nil)
526 (tramp-password-end-of-line nil))
527 ("scpc" (tramp-login-program "ssh")
2296b54d 528 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
529 ("-o" "ControlPath=%t.%%r@%%h:%%p")
530 ("-o" "ControlMaster=yes")
531 ("-e" "none")))
532 (tramp-remote-sh "/bin/sh")
533 (tramp-copy-program "scp")
534 (tramp-copy-args (("-P" "%p") ("-p" "%k") ("-q")
535 ("-o" "ControlPath=%t.%%r@%%h:%%p")
536 ("-o" "ControlMaster=auto")))
537 (tramp-copy-keep-date t)
538 (tramp-password-end-of-line nil)
539 (tramp-gw-args (("-o"
540 "GlobalKnownHostsFile=/dev/null")
541 ("-o" "UserKnownHostsFile=/dev/null")
542 ("-o" "StrictHostKeyChecking=no")))
543 (tramp-default-port 22))
544 ("scpx" (tramp-login-program "ssh")
2296b54d 545 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
546 ("-e" "none" "-t" "-t" "/bin/sh")))
547 (tramp-remote-sh "/bin/sh")
548 (tramp-copy-program "scp")
549 (tramp-copy-args (("-p" "%k")))
550 (tramp-copy-keep-date t)
551 (tramp-password-end-of-line nil)
552 (tramp-gw-args (("-o"
553 "GlobalKnownHostsFile=/dev/null")
554 ("-o" "UserKnownHostsFile=/dev/null")
555 ("-o" "StrictHostKeyChecking=no")))
556 (tramp-default-port 22))
557 ("sshx" (tramp-login-program "ssh")
2296b54d 558 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
559 ("-e" "none" "-t" "-t" "/bin/sh")))
560 (tramp-remote-sh "/bin/sh")
561 (tramp-copy-program nil)
562 (tramp-copy-args nil)
563 (tramp-copy-keep-date nil)
564 (tramp-password-end-of-line nil)
565 (tramp-gw-args (("-o"
566 "GlobalKnownHostsFile=/dev/null")
567 ("-o" "UserKnownHostsFile=/dev/null")
568 ("-o" "StrictHostKeyChecking=no")))
569 (tramp-default-port 22))
570 ("krlogin"
571 (tramp-login-program "krlogin")
572 (tramp-login-args (("%h") ("-l" "%u") ("-x")))
573 (tramp-remote-sh "/bin/sh")
574 (tramp-copy-program nil)
575 (tramp-copy-args nil)
576 (tramp-copy-keep-date nil)
577 (tramp-password-end-of-line nil))
578 ("plink" (tramp-login-program "plink")
579 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
580 ("-ssh")))
581 (tramp-remote-sh "/bin/sh")
582 (tramp-copy-program nil)
583 (tramp-copy-args nil)
584 (tramp-copy-keep-date nil)
585 (tramp-password-end-of-line "xy") ;see docstring for "xy"
586 (tramp-default-port 22))
587 ("plink1"
588 (tramp-login-program "plink")
589 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
590 ("-1" "-ssh")))
591 (tramp-remote-sh "/bin/sh")
592 (tramp-copy-program nil)
593 (tramp-copy-args nil)
594 (tramp-copy-keep-date nil)
595 (tramp-password-end-of-line "xy") ;see docstring for "xy"
596 (tramp-default-port 22))
597 ("plinkx"
598 (tramp-login-program "plink")
42bc9b6d
MA
599 ;; ("%h") must be a single element, see
600 ;; `tramp-compute-multi-hops'.
601 (tramp-login-args (("-load") ("%h") ("-t")
ce3f516f 602 (,(format
dab816a9
MA
603 "env 'TERM=%s' 'PROMPT_COMMAND=' 'PS1=%s'"
604 tramp-terminal-type
605 tramp-initial-end-of-output))
00d6fd04
MA
606 ("/bin/sh")))
607 (tramp-remote-sh "/bin/sh")
608 (tramp-copy-program nil)
609 (tramp-copy-args nil)
610 (tramp-copy-keep-date nil)
611 (tramp-password-end-of-line nil))
612 ("pscp" (tramp-login-program "plink")
613 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
614 ("-ssh")))
615 (tramp-remote-sh "/bin/sh")
616 (tramp-copy-program "pscp")
60f2c210 617 (tramp-copy-args (("-P" "%p") ("-scp") ("-p" "%k")))
00d6fd04
MA
618 (tramp-copy-keep-date t)
619 (tramp-password-end-of-line "xy") ;see docstring for "xy"
620 (tramp-default-port 22))
621 ("psftp" (tramp-login-program "plink")
622 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
623 ("-ssh")))
624 (tramp-remote-sh "/bin/sh")
625 (tramp-copy-program "pscp")
60f2c210 626 (tramp-copy-args (("-P" "%p") ("-sftp") ("-p" "%k")))
00d6fd04
MA
627 (tramp-copy-keep-date t)
628 (tramp-password-end-of-line "xy")) ;see docstring for "xy"
629 ("fcp" (tramp-login-program "fsh")
630 (tramp-login-args (("%h") ("-l" "%u") ("sh" "-i")))
631 (tramp-remote-sh "/bin/sh -i")
632 (tramp-copy-program "fcp")
633 (tramp-copy-args (("-p" "%k")))
634 (tramp-copy-keep-date t)
635 (tramp-password-end-of-line nil)))
fb7933a3
KG
636 "*Alist of methods for remote files.
637This is a list of entries of the form (NAME PARAM1 PARAM2 ...).
638Each NAME stands for a remote access method. Each PARAM is a
639pair of the form (KEY VALUE). The following KEYs are defined:
fb7933a3
KG
640 * `tramp-remote-sh'
641 This specifies the Bourne shell to use on the remote host. This
642 MUST be a Bourne-like shell. It is normally not necessary to set
a4aeb9a4 643 this to any value other than \"/bin/sh\": Tramp wants to use a shell
fb7933a3
KG
644 which groks tilde expansion, but it can search for it. Also note
645 that \"/bin/sh\" exists on all Unixen, this might not be true for
646 the value that you decide to use. You Have Been Warned.
b25a52cc
KG
647 * `tramp-login-program'
648 This specifies the name of the program to use for logging in to the
00d6fd04
MA
649 remote host. This may be the name of rsh or a workalike program,
650 or the name of telnet or a workalike, or the name of su or a workalike.
b25a52cc 651 * `tramp-login-args'
fb7933a3 652 This specifies the list of arguments to pass to the above
00d6fd04 653 mentioned program. Please note that this is a list of list of arguments,
fb7933a3 654 that is, normally you don't want to put \"-a -b\" or \"-f foo\"
00d6fd04
MA
655 here. Instead, you want a list (\"-a\" \"-b\"), or (\"-f\" \"foo\").
656 There are some patterns: \"%h\" in this list is replaced by the host
657 name, \"%u\" is replaced by the user name, \"%p\" is replaced by the
658 port number, and \"%%\" can be used to obtain a literal percent character.
659 If a list containing \"%h\", \"%u\" or \"%p\" is unchanged during
660 expansion (i.e. no host or no user specified), this list is not used as
661 argument. By this, arguments like (\"-l\" \"%u\") are optional.
662 \"%t\" is replaced by the temporary file name produced with
663 `tramp-make-tramp-temp-file'. \"%k\" indicates the keep-date
664 parameter of a program, if exists.
b25a52cc
KG
665 * `tramp-copy-program'
666 This specifies the name of the program to use for remotely copying
667 the file; this might be the absolute filename of rcp or the name of
668 a workalike program.
669 * `tramp-copy-args'
fb7933a3 670 This specifies the list of parameters to pass to the above mentioned
b25a52cc 671 program, the hints for `tramp-login-args' also apply here.
00d6fd04
MA
672 * `tramp-copy-keep-date'
673 This specifies whether the copying program when the preserves the
674 timestamp of the original file.
b88f2d0a
MA
675 * `tramp-copy-keep-tmpfile'
676 This specifies whether a temporary local file shall be kept
677 for optimization reasons (useful for \"rsync\" methods).
678 * `tramp-copy-recursive'
679 Whether the operation copies directories recursively.
00d6fd04
MA
680 * `tramp-default-port'
681 The default port of a method is needed in case of gateway connections.
682 Additionally, it is used as indication which method is prepared for
683 passing gateways.
684 * `tramp-gw-args'
685 As the attribute name says, additional arguments are specified here
686 when a method is applied via a gateway.
90f8dc03
KG
687 * `tramp-password-end-of-line'
688 This specifies the string to use for terminating the line after
689 submitting the password. If this method parameter is nil, then the
690 value of the normal variable `tramp-default-password-end-of-line'
691 is used. This parameter is necessary because the \"plink\" program
692 requires any two characters after sending the password. These do
693 not have to be newline or carriage return characters. Other login
694 programs are happy with just one character, the newline character.
695 We use \"xy\" as the value for methods using \"plink\".
b25a52cc
KG
696
697What does all this mean? Well, you should specify `tramp-login-program'
698for all methods; this program is used to log in to the remote site. Then,
699there are two ways to actually transfer the files between the local and the
700remote side. One way is using an additional rcp-like program. If you want
701to do this, set `tramp-copy-program' in the method.
fb7933a3
KG
702
703Another possibility for file transfer is inline transfer, i.e. the
b25a52cc 704file is passed through the same buffer used by `tramp-login-program'. In
fb7933a3 705this case, the file contents need to be protected since the
b25a52cc 706`tramp-login-program' might use escape codes or the connection might not
fb7933a3 707be eight-bit clean. Therefore, file contents are encoded for transit.
00d6fd04
MA
708See the variables `tramp-local-coding-commands' and
709`tramp-remote-coding-commands' for details.
fb7933a3 710
16674e4f 711So, to summarize: if the method is an out-of-band method, then you
b25a52cc 712must specify `tramp-copy-program' and `tramp-copy-args'. If it is an
00d6fd04
MA
713inline method, then these two parameters should be nil. Methods which
714are fit for gateways must have `tramp-default-port' at least.
fb7933a3
KG
715
716Notes:
717
00d6fd04
MA
718When using `su' or `sudo' the phrase `open connection to a remote
719host' sounds strange, but it is used nevertheless, for consistency.
720No connection is opened to a remote host, but `su' or `sudo' is
721started on the local host. You should specify a remote host
722`localhost' or the name of the local host. Another host name is
723useful only in combination with `tramp-default-proxies-alist'.")
fb7933a3 724
b25a52cc 725(defcustom tramp-default-method
83e20b5c
MA
726 ;; An external copy method seems to be preferred, because it is much
727 ;; more performant for large files, and it hasn't too serious delays
728 ;; for small files. But it must be ensured that there aren't
729 ;; permanent password queries. Either a password agent like
263c02ef
MA
730 ;; "ssh-agent" or "Pageant" shall run, or the optional
731 ;; password-cache.el or auth-sources.el packages shall be active for
732 ;; password caching. "scpc" would be another good choice because of
733 ;; the "ControlMaster" option, but this is a more modern alternative
734 ;; in OpenSSH 4, which cannot be taken as default.
00d6fd04
MA
735 (cond
736 ;; PuTTY is installed.
737 ((executable-find "pscp")
738 (if (or (fboundp 'password-read)
263c02ef 739 (fboundp 'auth-source-user-or-password)
00d6fd04 740 ;; Pageant is running.
70c11b0b 741 (tramp-compat-process-running-p "Pageant"))
00d6fd04
MA
742 "pscp"
743 "plink"))
744 ;; There is an ssh installation.
745 ((executable-find "scp")
746 (if (or (fboundp 'password-read)
263c02ef 747 (fboundp 'auth-source-user-or-password)
00d6fd04
MA
748 ;; ssh-agent is running.
749 (getenv "SSH_AUTH_SOCK")
750 (getenv "SSH_AGENT_PID"))
751 "scp"
752 "ssh"))
753 ;; Fallback.
754 (t "ftp"))
fb7933a3 755 "*Default method to use for transferring files.
c62c9d08 756See `tramp-methods' for possibilities.
4007ba5b 757Also see `tramp-default-method-alist'."
c62c9d08
KG
758 :group 'tramp
759 :type 'string)
760
505edaeb 761(defcustom tramp-default-method-alist
4007ba5b 762 '(("\\`localhost\\'" "\\`root\\'" "su"))
00d6fd04 763 "*Default method to use for specific host/user pairs.
c62c9d08
KG
764This is an alist of items (HOST USER METHOD). The first matching item
765specifies the method to use for a file name which does not specify a
766method. HOST and USER are regular expressions or nil, which is
767interpreted as a regular expression which always matches. If no entry
768matches, the variable `tramp-default-method' takes effect.
769
770If the file name does not specify the user, lookup is done using the
771empty string for the user name.
772
773See `tramp-methods' for a list of possibilities for METHOD."
774 :group 'tramp
775 :type '(repeat (list (regexp :tag "Host regexp")
776 (regexp :tag "User regexp")
777 (string :tag "Method"))))
778
00d6fd04
MA
779(defcustom tramp-default-user
780 nil
781 "*Default user to use for transferring files.
782It is nil by default; otherwise settings in configuration files like
783\"~/.ssh/config\" would be overwritten. Also see `tramp-default-user-alist'.
784
785This variable is regarded as obsolete, and will be removed soon."
786 :group 'tramp
787 :type '(choice (const nil) string))
788
789(defcustom tramp-default-user-alist
790 `(("\\`su\\(do\\)?\\'" nil "root")
791 ("\\`r\\(em\\)?\\(cp\\|sh\\)\\|telnet\\|plink1?\\'"
792 nil ,(user-login-name)))
793 "*Default user to use for specific method/host pairs.
794This is an alist of items (METHOD HOST USER). The first matching item
795specifies the user to use for a file name which does not specify a
796user. METHOD and USER are regular expressions or nil, which is
797interpreted as a regular expression which always matches. If no entry
798matches, the variable `tramp-default-user' takes effect.
799
800If the file name does not specify the method, lookup is done using the
801empty string for the method name."
802 :group 'tramp
803 :type '(repeat (list (regexp :tag "Method regexp")
804 (regexp :tag "Host regexp")
805 (string :tag "User"))))
806
807(defcustom tramp-default-host
808 (system-name)
809 "*Default host to use for transferring files.
810Useful for su and sudo methods mostly."
811 :group 'tramp
812 :type 'string)
813
814(defcustom tramp-default-proxies-alist nil
815 "*Route to be followed for specific host/user pairs.
816This is an alist of items (HOST USER PROXY). The first matching
817item specifies the proxy to be passed for a file name located on
818a remote target matching USER@HOST. HOST and USER are regular
70c11b0b
MA
819expressions. PROXY must be a Tramp filename without a localname
820part. Method and user name on PROXY are optional, which is
821interpreted with the default values. PROXY can contain the
822patterns %h and %u, which are replaced by the strings matching
823HOST or USER, respectively.
824
825HOST, USER or PROXY could also be Lisp forms, which will be
826evaluated. The result must be a string or nil, which is
827interpreted as a regular expression which always matches."
00d6fd04 828 :group 'tramp
70c11b0b
MA
829 :type '(repeat (list (choice :tag "Host regexp" regexp sexp)
830 (choice :tag "User regexp" regexp sexp)
831 (choice :tag "Proxy remote name" string (const nil)))))
00d6fd04 832
b96e6899
MA
833(defconst tramp-local-host-regexp
834 (concat
835 "^" (regexp-opt (list "localhost" (system-name) "127\.0\.0\.1" "::1") t) "$")
836 "*Host names which are regarded as local host.")
837
16674e4f 838(defconst tramp-completion-function-alist-rsh
00d6fd04
MA
839 '((tramp-parse-rhosts "/etc/hosts.equiv")
840 (tramp-parse-rhosts "~/.rhosts"))
b25a52cc 841 "Default list of (FUNCTION FILE) pairs to be examined for rsh methods.")
16674e4f 842
16674e4f 843(defconst tramp-completion-function-alist-ssh
00d6fd04
MA
844 '((tramp-parse-rhosts "/etc/hosts.equiv")
845 (tramp-parse-rhosts "/etc/shosts.equiv")
846 (tramp-parse-shosts "/etc/ssh_known_hosts")
847 (tramp-parse-sconfig "/etc/ssh_config")
848 (tramp-parse-shostkeys "/etc/ssh2/hostkeys")
849 (tramp-parse-sknownhosts "/etc/ssh2/knownhosts")
850 (tramp-parse-rhosts "~/.rhosts")
851 (tramp-parse-rhosts "~/.shosts")
852 (tramp-parse-shosts "~/.ssh/known_hosts")
853 (tramp-parse-sconfig "~/.ssh/config")
854 (tramp-parse-shostkeys "~/.ssh2/hostkeys")
855 (tramp-parse-sknownhosts "~/.ssh2/knownhosts"))
b25a52cc 856 "Default list of (FUNCTION FILE) pairs to be examined for ssh methods.")
16674e4f 857
16674e4f 858(defconst tramp-completion-function-alist-telnet
00d6fd04 859 '((tramp-parse-hosts "/etc/hosts"))
b25a52cc 860 "Default list of (FUNCTION FILE) pairs to be examined for telnet methods.")
16674e4f 861
16674e4f 862(defconst tramp-completion-function-alist-su
00d6fd04 863 '((tramp-parse-passwd "/etc/passwd"))
b25a52cc 864 "Default list of (FUNCTION FILE) pairs to be examined for su methods.")
292ffc15 865
00d6fd04
MA
866(defconst tramp-completion-function-alist-putty
867 '((tramp-parse-putty
868 "HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions"))
869 "Default list of (FUNCTION REGISTRY) pairs to be examined for putty methods.")
870
5ec2cc41 871(defvar tramp-completion-function-alist nil
16674e4f
KG
872 "*Alist of methods for remote files.
873This is a list of entries of the form (NAME PAIR1 PAIR2 ...).
874Each NAME stands for a remote access method. Each PAIR is of the form
875\(FUNCTION FILE). FUNCTION is responsible to extract user names and host
876names from FILE for completion. The following predefined FUNCTIONs exists:
877
5ec2cc41
KG
878 * `tramp-parse-rhosts' for \"~/.rhosts\" like files,
879 * `tramp-parse-shosts' for \"~/.ssh/known_hosts\" like files,
880 * `tramp-parse-sconfig' for \"~/.ssh/config\" like files,
881 * `tramp-parse-shostkeys' for \"~/.ssh2/hostkeys/*\" like files,
882 * `tramp-parse-sknownhosts' for \"~/.ssh2/knownhosts/*\" like files,
883 * `tramp-parse-hosts' for \"/etc/hosts\" like files,
884 * `tramp-parse-passwd' for \"/etc/passwd\" like files.
885 * `tramp-parse-netrc' for \"~/.netrc\" like files.
00d6fd04 886 * `tramp-parse-putty' for PuTTY registry keys.
5ec2cc41
KG
887
888FUNCTION can also be a customer defined function. For more details see
889the info pages.")
890
891(eval-after-load "tramp"
892 '(progn
893 (tramp-set-completion-function
894 "rcp" tramp-completion-function-alist-rsh)
895 (tramp-set-completion-function
896 "scp" tramp-completion-function-alist-ssh)
897 (tramp-set-completion-function
898 "scp1" tramp-completion-function-alist-ssh)
899 (tramp-set-completion-function
900 "scp2" tramp-completion-function-alist-ssh)
901 (tramp-set-completion-function
902 "scp1_old" tramp-completion-function-alist-ssh)
903 (tramp-set-completion-function
904 "scp2_old" tramp-completion-function-alist-ssh)
905 (tramp-set-completion-function
70c11b0b 906 "rsync" tramp-completion-function-alist-ssh)
946a5aeb
MA
907 (tramp-set-completion-function
908 "rsyncc" tramp-completion-function-alist-ssh)
5ec2cc41
KG
909 (tramp-set-completion-function
910 "remcp" tramp-completion-function-alist-rsh)
911 (tramp-set-completion-function
912 "rsh" tramp-completion-function-alist-rsh)
913 (tramp-set-completion-function
914 "ssh" tramp-completion-function-alist-ssh)
915 (tramp-set-completion-function
916 "ssh1" tramp-completion-function-alist-ssh)
917 (tramp-set-completion-function
918 "ssh2" tramp-completion-function-alist-ssh)
919 (tramp-set-completion-function
920 "ssh1_old" tramp-completion-function-alist-ssh)
921 (tramp-set-completion-function
922 "ssh2_old" tramp-completion-function-alist-ssh)
923 (tramp-set-completion-function
924 "remsh" tramp-completion-function-alist-rsh)
925 (tramp-set-completion-function
926 "telnet" tramp-completion-function-alist-telnet)
927 (tramp-set-completion-function
928 "su" tramp-completion-function-alist-su)
929 (tramp-set-completion-function
930 "sudo" tramp-completion-function-alist-su)
bf247b6e 931 (tramp-set-completion-function
5ec2cc41
KG
932 "scpx" tramp-completion-function-alist-ssh)
933 (tramp-set-completion-function
934 "sshx" tramp-completion-function-alist-ssh)
935 (tramp-set-completion-function
936 "krlogin" tramp-completion-function-alist-rsh)
937 (tramp-set-completion-function
938 "plink" tramp-completion-function-alist-ssh)
939 (tramp-set-completion-function
940 "plink1" tramp-completion-function-alist-ssh)
00d6fd04
MA
941 (tramp-set-completion-function
942 "plinkx" tramp-completion-function-alist-putty)
5ec2cc41
KG
943 (tramp-set-completion-function
944 "pscp" tramp-completion-function-alist-ssh)
945 (tramp-set-completion-function
946 "fcp" tramp-completion-function-alist-ssh)))
16674e4f 947
674da028
MA
948(defconst tramp-echo-mark-marker "_echo"
949 "String marker to surround echoed commands.")
950
00d6fd04
MA
951(defconst tramp-echo-mark "_echo\b\b\b\b\b"
952 "String mark to be transmitted around shell commands.
953Used to separate their echo from the output they produce. This
954will only be used if we cannot disable remote echo via stty.
955This string must have no effect on the remote shell except for
956producing some echo which can later be detected by
674da028
MA
957`tramp-echoed-echo-mark-regexp'. Using `tramp-echo-mark-marker',
958followed by an equal number of backspaces to erase them will
959usually suffice.")
00d6fd04
MA
960
961(defconst tramp-echoed-echo-mark-regexp "_echo\\(\b\\( \b\\)?\\)\\{5\\}"
962 "Regexp which matches `tramp-echo-mark' as it gets echoed by
963the remote shell.")
964
fb7933a3
KG
965(defcustom tramp-rsh-end-of-line "\n"
966 "*String used for end of line in rsh connections.
967I don't think this ever needs to be changed, so please tell me about it
16674e4f 968if you need to change this.
90f8dc03
KG
969Also see the method parameter `tramp-password-end-of-line' and the normal
970variable `tramp-default-password-end-of-line'."
16674e4f
KG
971 :group 'tramp
972 :type 'string)
973
90f8dc03
KG
974(defcustom tramp-default-password-end-of-line
975 tramp-rsh-end-of-line
16674e4f 976 "*String used for end of line after sending a password.
90f8dc03
KG
977This variable provides the default value for the method parameter
978`tramp-password-end-of-line', see `tramp-methods' for more details.
979
16674e4f
KG
980It seems that people using plink under Windows need to send
981\"\\r\\n\" (carriage-return, then newline) after a password, but just
982\"\\n\" after all other lines. This variable can be used for the
983password, see `tramp-rsh-end-of-line' for the other cases.
984
985The default value is to use the same value as `tramp-rsh-end-of-line'."
fb7933a3
KG
986 :group 'tramp
987 :type 'string)
988
00d6fd04
MA
989;; "getconf PATH" yields:
990;; HP-UX: /usr/bin:/usr/ccs/bin:/opt/ansic/bin:/opt/langtools/bin:/opt/fortran/bin
991;; Solaris: /usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin
0664ff72 992;; GNU/Linux (Debian, Suse): /bin:/usr/bin
00d6fd04 993;; FreeBSD: /usr/bin:/bin:/usr/sbin:/sbin: - beware trailing ":"!
fb7933a3 994(defcustom tramp-remote-path
00d6fd04
MA
995 '(tramp-default-remote-path "/usr/sbin" "/usr/local/bin"
996 "/local/bin" "/local/freeware/bin" "/local/gnu/bin"
fb7933a3
KG
997 "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin")
998 "*List of directories to search for executables on remote host.
00d6fd04
MA
999For every remote host, this variable will be set buffer local,
1000keeping the list of existing directories on that host.
fb7933a3
KG
1001
1002You can use `~' in this list, but when searching for a shell which groks
00d6fd04
MA
1003tilde expansion, all directory names starting with `~' will be ignored.
1004
1005`Default Directories' represent the list of directories given by
1006the command \"getconf PATH\". It is recommended to use this
1007entry on top of this list, because these are the default
70c11b0b
MA
1008directories for POSIX compatible commands.
1009
1010`Private Directories' are the settings of the $PATH environment,
1011as given in your `~/.profile'."
00d6fd04
MA
1012 :group 'tramp
1013 :type '(repeat (choice
1014 (const :tag "Default Directories" tramp-default-remote-path)
70c11b0b 1015 (const :tag "Private Directories" tramp-own-remote-path)
00d6fd04
MA
1016 (string :tag "Directory"))))
1017
00d6fd04 1018(defcustom tramp-remote-process-environment
a0a5183a 1019 `("HISTFILE=$HOME/.tramp_history" "HISTSIZE=1" "LC_ALL=C"
00d6fd04 1020 ,(concat "TERM=" tramp-terminal-type)
97c696d5
MA
1021 "EMACS=t" ;; Deprecated.
1022 ,(format "INSIDE_EMACS=%s,tramp:%s" emacs-version tramp-version)
00d6fd04
MA
1023 "CDPATH=" "HISTORY=" "MAIL=" "MAILCHECK=" "MAILPATH="
1024 "autocorrect=" "correct=")
1025
1026 "*List of environment variables to be set on the remote host.
1027
1028Each element should be a string of the form ENVVARNAME=VALUE. An
1029entry ENVVARNAME= diables the corresponding environment variable,
1030which might have been set in the init files like ~/.profile.
1031
1032Special handling is applied to the PATH environment, which should
1033not be set here. Instead of, it should be set via `tramp-remote-path'."
fb7933a3
KG
1034 :group 'tramp
1035 :type '(repeat string))
1036
1037(defcustom tramp-login-prompt-regexp
bc103d00 1038 ".*ogin\\( .*\\)?: *"
fb7933a3 1039 "*Regexp matching login-like prompts.
bc103d00
MA
1040The regexp should match at end of buffer.
1041
1042Sometimes the prompt is reported to look like \"login as:\"."
fb7933a3
KG
1043 :group 'tramp
1044 :type 'regexp)
1045
821e6e36 1046(defcustom tramp-shell-prompt-pattern
aa485f7c
MA
1047 ;; Allow a prompt to start right after a ^M since it indeed would be
1048 ;; displayed at the beginning of the line (and Zsh uses it).
dab816a9 1049 "\\(?:^\\|\r\\)[^#$%>\n]*#?[#$%>] *\\(\e\\[[0-9;]*[a-zA-Z] *\\)*"
821e6e36
KG
1050 "Regexp to match prompts from remote shell.
1051Normally, Tramp expects you to configure `shell-prompt-pattern'
1052correctly, but sometimes it happens that you are connecting to a
1053remote host which sends a different kind of shell prompt. Therefore,
1054Tramp recognizes things matched by `shell-prompt-pattern' as prompt,
1055and also things matched by this variable. The default value of this
b25a52cc 1056variable is similar to the default value of `shell-prompt-pattern',
dab816a9
MA
1057which should work well in many cases.
1058
1059This regexp must match both `tramp-initial-end-of-output' and
1060`tramp-end-of-output'."
821e6e36
KG
1061 :group 'tramp
1062 :type 'regexp)
1063
fb7933a3 1064(defcustom tramp-password-prompt-regexp
00d6fd04 1065 "^.*\\([pP]assword\\|[pP]assphrase\\).*:\^@? *"
fb7933a3 1066 "*Regexp matching password-like prompts.
ac474af1 1067The regexp should match at end of buffer.
fb7933a3
KG
1068
1069The `sudo' program appears to insert a `^@' character into the prompt."
1070 :group 'tramp
1071 :type 'regexp)
1072
1073(defcustom tramp-wrong-passwd-regexp
b1d06e75
KG
1074 (concat "^.*"
1075 ;; These strings should be on the last line
a4aeb9a4 1076 (regexp-opt '("Permission denied"
b1d06e75
KG
1077 "Login incorrect"
1078 "Login Incorrect"
1079 "Connection refused"
27e813fe 1080 "Connection closed"
b1d06e75
KG
1081 "Sorry, try again."
1082 "Name or service not known"
00d6fd04 1083 "Host key verification failed."
70c11b0b 1084 "No supported authentication methods left to try!") t)
b1d06e75
KG
1085 ".*"
1086 "\\|"
1087 "^.*\\("
1088 ;; Here comes a list of regexes, separated by \\|
1089 "Received signal [0-9]+"
1090 "\\).*")
fb7933a3 1091 "*Regexp matching a `login failed' message.
ac474af1
KG
1092The regexp should match at end of buffer."
1093 :group 'tramp
1094 :type 'regexp)
1095
1096(defcustom tramp-yesno-prompt-regexp
3cdaec13
KG
1097 (concat
1098 (regexp-opt '("Are you sure you want to continue connecting (yes/no)?") t)
1099 "\\s-*")
1100 "Regular expression matching all yes/no queries which need to be confirmed.
ac474af1 1101The confirmation should be done with yes or no.
3cdaec13
KG
1102The regexp should match at end of buffer.
1103See also `tramp-yn-prompt-regexp'."
fb7933a3
KG
1104 :group 'tramp
1105 :type 'regexp)
1106
3cdaec13 1107(defcustom tramp-yn-prompt-regexp
658052a2
MA
1108 (concat
1109 (regexp-opt '("Store key in cache? (y/n)"
1110 "Update cached key? (y/n, Return cancels connection)") t)
1111 "\\s-*")
3cdaec13
KG
1112 "Regular expression matching all y/n queries which need to be confirmed.
1113The confirmation should be done with y or n.
1114The regexp should match at end of buffer.
1115See also `tramp-yesno-prompt-regexp'."
1116 :group 'tramp
1117 :type 'regexp)
487f4fb7
KG
1118
1119(defcustom tramp-terminal-prompt-regexp
1120 (concat "\\("
1121 "TERM = (.*)"
1122 "\\|"
1123 "Terminal type\\? \\[.*\\]"
1124 "\\)\\s-*")
1125 "Regular expression matching all terminal setting prompts.
1126The regexp should match at end of buffer.
1127The answer will be provided by `tramp-action-terminal', which see."
1128 :group 'tramp
1129 :type 'regexp)
3cdaec13 1130
01917a18
MA
1131(defcustom tramp-operation-not-permitted-regexp
1132 (concat "\\(" "preserving times.*" "\\|" "set mode" "\\)" ":\\s-*"
1133 (regexp-opt '("Operation not permitted") t))
1134 "Regular expression matching keep-date problems in (s)cp operations.
1135Copying has been performed successfully already, so this message can
1136be ignored safely."
1137 :group 'tramp
1138 :type 'regexp)
1139
6b2633cc
LH
1140(defcustom tramp-copy-failed-regexp
1141 (concat "\\(.+: "
1142 (regexp-opt '("Permission denied"
1143 "not a regular file"
1144 "is a directory"
1145 "No such file or directory") t)
1146 "\\)\\s-*")
1147 "Regular expression matching copy problems in (s)cp operations."
1148 :group 'tramp
1149 :type 'regexp)
1150
19a87064 1151(defcustom tramp-process-alive-regexp
38c65fca 1152 ""
19a87064 1153 "Regular expression indicating a process has finished.
38c65fca
KG
1154In fact this expression is empty by intention, it will be used only to
1155check regularly the status of the associated process.
07dfe738 1156The answer will be provided by `tramp-action-process-alive',
00d6fd04 1157`tramp-action-out-of-band', which see."
38c65fca
KG
1158 :group 'tramp
1159 :type 'regexp)
1160
fb7933a3
KG
1161(defcustom tramp-temp-name-prefix "tramp."
1162 "*Prefix to use for temporary files.
1163If this is a relative file name (such as \"tramp.\"), it is considered
1164relative to the directory name returned by the function
9e6ab520 1165`tramp-compat-temporary-file-directory' (which see). It may also be an
fb7933a3
KG
1166absolute file name; don't forget to include a prefix for the filename
1167part, though."
1168 :group 'tramp
1169 :type 'string)
1170
2296b54d
MA
1171(defconst tramp-temp-buffer-name " *tramp temp*"
1172 "Buffer name for a temporary buffer.
1173It shall be used in combination with `generate-new-buffer-name'.")
1174
b88f2d0a
MA
1175(defvar tramp-temp-buffer-file-name nil
1176 "File name of a persistent local temporary file.
1177Useful for \"rsync\" like methods.")
1178(make-variable-buffer-local 'tramp-temp-buffer-file-name)
1179
4007ba5b 1180(defcustom tramp-sh-extra-args '(("/bash\\'" . "-norc -noprofile"))
c62c9d08
KG
1181 "*Alist specifying extra arguments to pass to the remote shell.
1182Entries are (REGEXP . ARGS) where REGEXP is a regular expression
1183matching the shell file name and ARGS is a string specifying the
1184arguments.
1185
1186This variable is only used when Tramp needs to start up another shell
1187for tilde expansion. The extra arguments should typically prevent the
1188shell from reading its init file."
1189 :group 'tramp
90f8dc03
KG
1190 ;; This might be the wrong way to test whether the widget type
1191 ;; `alist' is available. Who knows the right way to test it?
1192 :type (if (get 'alist 'widget-type)
1193 '(alist :key-type string :value-type string)
1194 '(repeat (cons string string))))
c62c9d08 1195
00d6fd04
MA
1196;; XEmacs is distributed with few Lisp packages. Further packages are
1197;; installed using EFS. If we use a unified filename format, then
1198;; Tramp is required in addition to EFS. (But why can't Tramp just
1199;; disable EFS when Tramp is loaded? Then XEmacs can ship with EFS
1200;; just like before.) Another reason for using a separate filename
1201;; syntax on XEmacs is that EFS hooks into XEmacs in many places, but
1202;; Tramp only knows how to deal with `file-name-handler-alist', not
1203;; the other places.
1204
1205;; Currently, we have the choice between 'ftp, 'sep, and 'url.
1206;;;###autoload
1207(defcustom tramp-syntax
1208 (if (featurep 'xemacs) 'sep 'ftp)
1209 "Tramp filename syntax to be used.
1210
1211It can have the following values:
1212
1213 'ftp -- Ange-FTP respective EFS like syntax (GNU Emacs default)
1214 'sep -- Syntax as defined for XEmacs (not available yet for GNU Emacs)
1215 'url -- URL-like syntax."
16674e4f 1216 :group 'tramp
00d6fd04
MA
1217 :type (if (featurep 'xemacs)
1218 '(choice (const :tag "EFS" ftp)
1219 (const :tag "XEmacs" sep)
1220 (const :tag "URL" url))
1221 '(choice (const :tag "Ange-FTP" ftp)
1222 (const :tag "URL" url))))
1223
1224(defconst tramp-prefix-format
1225 (cond ((equal tramp-syntax 'ftp) "/")
1226 ((equal tramp-syntax 'sep) "/[")
1227 ((equal tramp-syntax 'url) "/")
1228 (t (error "Wrong `tramp-syntax' defined")))
a4aeb9a4 1229 "*String matching the very beginning of Tramp file names.
00d6fd04 1230Used in `tramp-make-tramp-file-name'.")
16674e4f 1231
00d6fd04 1232(defconst tramp-prefix-regexp
16674e4f 1233 (concat "^" (regexp-quote tramp-prefix-format))
a4aeb9a4 1234 "*Regexp matching the very beginning of Tramp file names.
00d6fd04 1235Should always start with \"^\". Derived from `tramp-prefix-format'.")
16674e4f 1236
00d6fd04 1237(defconst tramp-method-regexp
16674e4f 1238 "[a-zA-Z_0-9-]+"
00d6fd04 1239 "*Regexp matching methods identifiers.")
16674e4f 1240
00d6fd04
MA
1241(defconst tramp-postfix-method-format
1242 (cond ((equal tramp-syntax 'ftp) ":")
1243 ((equal tramp-syntax 'sep) "/")
1244 ((equal tramp-syntax 'url) "://")
1245 (t (error "Wrong `tramp-syntax' defined")))
16674e4f 1246 "*String matching delimeter between method and user or host names.
00d6fd04 1247Used in `tramp-make-tramp-file-name'.")
16674e4f 1248
00d6fd04
MA
1249(defconst tramp-postfix-method-regexp
1250 (regexp-quote tramp-postfix-method-format)
16674e4f 1251 "*Regexp matching delimeter between method and user or host names.
00d6fd04 1252Derived from `tramp-postfix-method-format'.")
16674e4f 1253
00d6fd04
MA
1254(defconst tramp-user-regexp
1255 "[^:/ \t]+"
1256 "*Regexp matching user names.")
16674e4f 1257
b96e6899
MA
1258(defconst tramp-prefix-domain-format "%"
1259 "*String matching delimeter between user and domain names.")
1260
1261(defconst tramp-prefix-domain-regexp
1262 (regexp-quote tramp-prefix-domain-format)
1263 "*Regexp matching delimeter between user and domain names.
1264Derived from `tramp-prefix-domain-format'.")
1265
1266(defconst tramp-domain-regexp
70c11b0b 1267 "[-a-zA-Z0-9_.]+"
b96e6899
MA
1268 "*Regexp matching domain names.")
1269
1270(defconst tramp-user-with-domain-regexp
1271 (concat "\\(" tramp-user-regexp "\\)"
1272 tramp-prefix-domain-regexp
1273 "\\(" tramp-domain-regexp "\\)")
1274 "*Regexp matching user names with domain names.")
1275
00d6fd04 1276(defconst tramp-postfix-user-format
16674e4f
KG
1277 "@"
1278 "*String matching delimeter between user and host names.
00d6fd04 1279Used in `tramp-make-tramp-file-name'.")
16674e4f 1280
00d6fd04 1281(defconst tramp-postfix-user-regexp
16674e4f
KG
1282 (regexp-quote tramp-postfix-user-format)
1283 "*Regexp matching delimeter between user and host names.
00d6fd04
MA
1284Derived from `tramp-postfix-user-format'.")
1285
1286(defconst tramp-host-regexp
1287 "[a-zA-Z0-9_.-]+"
1288 "*Regexp matching host names.")
1289
b96e6899
MA
1290(defconst tramp-prefix-ipv6-format
1291 (cond ((equal tramp-syntax 'ftp) "[")
1292 ((equal tramp-syntax 'sep) "")
1293 ((equal tramp-syntax 'url) "[")
1294 (t (error "Wrong `tramp-syntax' defined")))
1295 "*String matching left hand side of IPv6 addresses.
1296Used in `tramp-make-tramp-file-name'.")
1297
1298(defconst tramp-prefix-ipv6-regexp
1299 (regexp-quote tramp-prefix-ipv6-format)
1300 "*Regexp matching left hand side of IPv6 addresses.
1301Derived from `tramp-prefix-ipv6-format'.")
1302
e0b6e3b9
MA
1303;; The following regexp is a bit sloppy. But it shall serve our
1304;; purposes. It covers also IPv4 mapped IPv6 addresses, like in
1305;; "::ffff:192.168.0.1".
b96e6899 1306(defconst tramp-ipv6-regexp
e0b6e3b9 1307 "\\(?:\\(?:[a-zA-Z0-9]+\\)?:\\)+[a-zA-Z0-9.]+"
b96e6899
MA
1308 "*Regexp matching IPv6 addresses.")
1309
1310(defconst tramp-postfix-ipv6-format
1311 (cond ((equal tramp-syntax 'ftp) "]")
1312 ((equal tramp-syntax 'sep) "")
1313 ((equal tramp-syntax 'url) "]")
1314 (t (error "Wrong `tramp-syntax' defined")))
1315 "*String matching right hand side of IPv6 addresses.
1316Used in `tramp-make-tramp-file-name'.")
1317
1318(defconst tramp-postfix-ipv6-regexp
1319 (regexp-quote tramp-postfix-ipv6-format)
1320 "*Regexp matching right hand side of IPv6 addresses.
1321Derived from `tramp-postfix-ipv6-format'.")
1322
00d6fd04
MA
1323(defconst tramp-prefix-port-format
1324 (cond ((equal tramp-syntax 'ftp) "#")
1325 ((equal tramp-syntax 'sep) "#")
1326 ((equal tramp-syntax 'url) ":")
1327 (t (error "Wrong `tramp-syntax' defined")))
1328 "*String matching delimeter between host names and port numbers.")
1329
1330(defconst tramp-prefix-port-regexp
1331 (regexp-quote tramp-prefix-port-format)
1332 "*Regexp matching delimeter between host names and port numbers.
1333Derived from `tramp-prefix-port-format'.")
1334
1335(defconst tramp-port-regexp
1336 "[0-9]+"
1337 "*Regexp matching port numbers.")
1338
1339(defconst tramp-host-with-port-regexp
1340 (concat "\\(" tramp-host-regexp "\\)"
1341 tramp-prefix-port-regexp
1342 "\\(" tramp-port-regexp "\\)")
1343 "*Regexp matching host names with port numbers.")
1344
1345(defconst tramp-postfix-host-format
1346 (cond ((equal tramp-syntax 'ftp) ":")
1347 ((equal tramp-syntax 'sep) "]")
1348 ((equal tramp-syntax 'url) "")
1349 (t (error "Wrong `tramp-syntax' defined")))
7432277c 1350 "*String matching delimeter between host names and localnames.
00d6fd04 1351Used in `tramp-make-tramp-file-name'.")
16674e4f 1352
00d6fd04 1353(defconst tramp-postfix-host-regexp
16674e4f 1354 (regexp-quote tramp-postfix-host-format)
7432277c 1355 "*Regexp matching delimeter between host names and localnames.
00d6fd04 1356Derived from `tramp-postfix-host-format'.")
16674e4f 1357
00d6fd04 1358(defconst tramp-localname-regexp
16674e4f 1359 ".*$"
00d6fd04 1360 "*Regexp matching localnames.")
16674e4f
KG
1361
1362;; File name format.
505edaeb 1363
00d6fd04 1364(defconst tramp-file-name-structure
16674e4f
KG
1365 (list
1366 (concat
1367 tramp-prefix-regexp
00d6fd04
MA
1368 "\\(" "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp "\\)?"
1369 "\\(" "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp "\\)?"
b96e6899
MA
1370 "\\(" "\\(" tramp-host-regexp
1371 "\\|"
1372 tramp-prefix-ipv6-regexp tramp-ipv6-regexp
1373 tramp-postfix-ipv6-regexp "\\)"
1374 "\\(" tramp-prefix-port-regexp tramp-port-regexp "\\)?" "\\)?"
00d6fd04
MA
1375 tramp-postfix-host-regexp
1376 "\\(" tramp-localname-regexp "\\)")
b96e6899 1377 2 4 5 8)
16674e4f 1378
fb7933a3 1379 "*List of five elements (REGEXP METHOD USER HOST FILE), detailing \
a4aeb9a4 1380the Tramp file name structure.
fb7933a3 1381
a4aeb9a4 1382The first element REGEXP is a regular expression matching a Tramp file
fb7933a3
KG
1383name. The regex should contain parentheses around the method name,
1384the user name, the host name, and the file name parts.
1385
1386The second element METHOD is a number, saying which pair of
1387parentheses matches the method name. The third element USER is
1388similar, but for the user name. The fourth element HOST is similar,
1389but for the host name. The fifth element FILE is for the file name.
1390These numbers are passed directly to `match-string', which see. That
1391means the opening parentheses are counted to identify the pair.
1392
00d6fd04 1393See also `tramp-file-name-regexp'.")
fb7933a3
KG
1394
1395;;;###autoload
505edaeb 1396(defconst tramp-file-name-regexp-unified
b96e6899 1397 "\\`/\\([^[/:]+\\|[^/]+]\\):"
505edaeb
KG
1398 "Value for `tramp-file-name-regexp' for unified remoting.
1399Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and
00d6fd04 1400Tramp. See `tramp-file-name-structure' for more explanations.")
505edaeb
KG
1401
1402;;;###autoload
1403(defconst tramp-file-name-regexp-separate
1404 "\\`/\\[.*\\]"
1405 "Value for `tramp-file-name-regexp' for separate remoting.
1406XEmacs uses a separate filename syntax for Tramp and EFS.
00d6fd04 1407See `tramp-file-name-structure' for more explanations.")
505edaeb
KG
1408
1409;;;###autoload
00d6fd04
MA
1410(defconst tramp-file-name-regexp-url
1411 "\\`/[^/:]+://"
1412 "Value for `tramp-file-name-regexp' for URL-like remoting.
1413See `tramp-file-name-structure' for more explanations.")
1414
1415;;;###autoload
1416(defconst tramp-file-name-regexp
1417 (cond ((equal tramp-syntax 'ftp) tramp-file-name-regexp-unified)
1418 ((equal tramp-syntax 'sep) tramp-file-name-regexp-separate)
1419 ((equal tramp-syntax 'url) tramp-file-name-regexp-url)
1420 (t (error "Wrong `tramp-syntax' defined")))
94be87e8 1421 "*Regular expression matching file names handled by Tramp.
a4aeb9a4 1422This regexp should match Tramp file names but no other file names.
fb7933a3
KG
1423\(When tramp.el is loaded, this regular expression is prepended to
1424`file-name-handler-alist', and that is searched sequentially. Thus,
a4aeb9a4
MA
1425if the Tramp entry appears rather early in the `file-name-handler-alist'
1426and is a bit too general, then some files might be considered Tramp
00d6fd04 1427files which are not really Tramp files.
fb7933a3
KG
1428
1429Please note that the entry in `file-name-handler-alist' is made when
1430this file (tramp.el) is loaded. This means that this variable must be set
1431before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1432updated after changing this variable.
1433
00d6fd04 1434Also see `tramp-file-name-structure'.")
fb7933a3 1435
16674e4f 1436;;;###autoload
8a798e41 1437(defconst tramp-root-regexp
00d6fd04 1438 (if (memq system-type '(cygwin windows-nt))
aa485f7c
MA
1439 "\\`\\([a-zA-Z]:\\)?/"
1440 "\\`/")
8a798e41 1441 "Beginning of an incomplete Tramp file name.
aa485f7c 1442Usually, it is just \"\\\\`/\". On W32 systems, there might be a
57671b72 1443volume letter, which will be removed by `tramp-drop-volume-letter'.")
8a798e41
MA
1444
1445;;;###autoload
1446(defconst tramp-completion-file-name-regexp-unified
aa485f7c 1447 (concat tramp-root-regexp "[^/]*\\'")
16674e4f 1448 "Value for `tramp-completion-file-name-regexp' for unified remoting.
8a798e41
MA
1449GNU Emacs uses a unified filename syntax for Tramp and Ange-FTP.
1450See `tramp-file-name-structure' for more explanations.")
fb7933a3 1451
16674e4f
KG
1452;;;###autoload
1453(defconst tramp-completion-file-name-regexp-separate
aa485f7c 1454 (concat tramp-root-regexp "\\([[][^]]*\\)?\\'")
16674e4f
KG
1455 "Value for `tramp-completion-file-name-regexp' for separate remoting.
1456XEmacs uses a separate filename syntax for Tramp and EFS.
00d6fd04 1457See `tramp-file-name-structure' for more explanations.")
fb7933a3 1458
16674e4f 1459;;;###autoload
00d6fd04 1460(defconst tramp-completion-file-name-regexp-url
aa485f7c 1461 (concat tramp-root-regexp "[^/:]+\\(:\\(/\\(/[^/]*\\)?\\)?\\)?\\'")
00d6fd04
MA
1462 "Value for `tramp-completion-file-name-regexp' for URL-like remoting.
1463See `tramp-file-name-structure' for more explanations.")
1464
1465;;;###autoload
1466(defconst tramp-completion-file-name-regexp
1467 (cond ((equal tramp-syntax 'ftp) tramp-completion-file-name-regexp-unified)
1468 ((equal tramp-syntax 'sep) tramp-completion-file-name-regexp-separate)
1469 ((equal tramp-syntax 'url) tramp-completion-file-name-regexp-url)
1470 (t (error "Wrong `tramp-syntax' defined")))
a4aeb9a4
MA
1471 "*Regular expression matching file names handled by Tramp completion.
1472This regexp should match partial Tramp file names only.
16674e4f
KG
1473
1474Please note that the entry in `file-name-handler-alist' is made when
1475this file (tramp.el) is loaded. This means that this variable must be set
1476before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1477updated after changing this variable.
1478
00d6fd04 1479Also see `tramp-file-name-structure'.")
fb7933a3 1480
00d6fd04
MA
1481(defconst tramp-actions-before-shell
1482 '((tramp-login-prompt-regexp tramp-action-login)
1483 (tramp-password-prompt-regexp tramp-action-password)
1484 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
ac474af1 1485 (shell-prompt-pattern tramp-action-succeed)
821e6e36 1486 (tramp-shell-prompt-pattern tramp-action-succeed)
3cdaec13 1487 (tramp-yesno-prompt-regexp tramp-action-yesno)
487f4fb7 1488 (tramp-yn-prompt-regexp tramp-action-yn)
19a87064
MA
1489 (tramp-terminal-prompt-regexp tramp-action-terminal)
1490 (tramp-process-alive-regexp tramp-action-process-alive))
ac474af1
KG
1491 "List of pattern/action pairs.
1492Whenever a pattern matches, the corresponding action is performed.
1493Each item looks like (PATTERN ACTION).
1494
1495The PATTERN should be a symbol, a variable. The value of this
1496variable gives the regular expression to search for. Note that the
1497regexp must match at the end of the buffer, \"\\'\" is implicitly
1498appended to it.
1499
1500The ACTION should also be a symbol, but a function. When the
00d6fd04 1501corresponding PATTERN matches, the ACTION function is called.")
ac474af1 1502
00d6fd04 1503(defconst tramp-actions-copy-out-of-band
38c65fca
KG
1504 '((tramp-password-prompt-regexp tramp-action-password)
1505 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
00d6fd04 1506 (tramp-copy-failed-regexp tramp-action-permission-denied)
19a87064 1507 (tramp-process-alive-regexp tramp-action-out-of-band))
38c65fca
KG
1508 "List of pattern/action pairs.
1509This list is used for copying/renaming with out-of-band methods.
90f8dc03 1510
00d6fd04
MA
1511See `tramp-actions-before-shell' for more info.")
1512
1513;; Chunked sending kludge. We set this to 500 for black-listed constellations
7432277c 1514;; known to have a bug in `process-send-string'; some ssh connections appear
7177e2a3
MA
1515;; to drop bytes when data is sent too quickly. There is also a connection
1516;; buffer local variable, which is computed depending on remote host properties
1517;; when `tramp-chunksize' is zero or nil.
7432277c
KG
1518(defcustom tramp-chunksize
1519 (when (and (not (featurep 'xemacs))
1520 (memq system-type '(hpux)))
1521 500)
55880756
MA
1522;; Parentheses in docstring starting at beginning of line are escaped.
1523;; Fontification is messed up when
1524;; `open-paren-in-column-0-is-defun-start' set to t.
7432277c
KG
1525 "*If non-nil, chunksize for sending input to local process.
1526It is necessary only on systems which have a buggy `process-send-string'
1527implementation. The necessity, whether this variable must be set, can be
1528checked via the following code:
1529
1530 (with-temp-buffer
11948172
MA
1531 (let* ((user \"xxx\") (host \"yyy\")
1532 (init 0) (step 50)
1533 (sent init) (received init))
1534 (while (= sent received)
1535 (setq sent (+ sent step))
1536 (erase-buffer)
1537 (let ((proc (start-process (buffer-name) (current-buffer)
1538 \"ssh\" \"-l\" user host \"wc\" \"-c\")))
1539 (when (memq (process-status proc) '(run open))
1540 (process-send-string proc (make-string sent ?\\ ))
1541 (process-send-eof proc)
1542 (process-send-eof proc))
1543 (while (not (progn (goto-char (point-min))
1544 (re-search-forward \"\\\\w+\" (point-max) t)))
1545 (accept-process-output proc 1))
1546 (when (memq (process-status proc) '(run open))
1547 (setq received (string-to-number (match-string 0)))
1548 (delete-process proc)
1549 (message \"Bytes sent: %s\\tBytes received: %s\" sent received)
1550 (sit-for 0))))
1551 (if (> sent (+ init step))
1552 (message \"You should set `tramp-chunksize' to a maximum of %s\"
1553 (- sent step))
1554 (message \"Test does not work\")
1555 (display-buffer (current-buffer))
1556 (sit-for 30))))
1557
1558In the Emacs normally running Tramp, evaluate the above code
55880756 1559\(replace \"xxx\" and \"yyy\" by the remote user and host name,
11948172
MA
1560respectively). You can do this, for example, by pasting it into
1561the `*scratch*' buffer and then hitting C-j with the cursor after the
1562last closing parenthesis. Note that it works only if you have configured
1563\"ssh\" to run without password query, see ssh-agent(1).
1564
1565You will see the number of bytes sent successfully to the remote host.
1566If that number exceeds 1000, you can stop the execution by hitting
1567C-g, because your Emacs is likely clean.
1568
11948172
MA
1569When it is necessary to set `tramp-chunksize', you might consider to
1570use an out-of-the-band method (like \"scp\") instead of an internal one
55880756 1571\(like \"ssh\"), because setting `tramp-chunksize' to non-nil decreases
11948172 1572performance.
c951aecb 1573
00d6fd04
MA
1574If your Emacs is buggy, the code stops and gives you an indication
1575about the value `tramp-chunksize' should be set. Maybe you could just
1576experiment a bit, e.g. changing the values of `init' and `step'
1577in the third line of the code.
1578
7432277c
KG
1579Please raise a bug report via \"M-x tramp-bug\" if your system needs
1580this variable to be set as well."
1581 :group 'tramp
b1a2b924 1582 :type '(choice (const nil) integer))
7432277c 1583
5ec2cc41
KG
1584;; Logging in to a remote host normally requires obtaining a pty. But
1585;; Emacs on MacOS X has process-connection-type set to nil by default,
1586;; so on those systems Tramp doesn't obtain a pty. Here, we allow
1587;; for an override of the system default.
1588(defcustom tramp-process-connection-type t
1589 "Overrides `process-connection-type' for connections from Tramp.
1590Tramp binds process-connection-type to the value given here before
1591opening a connection to a remote host."
1592 :group 'tramp
1593 :type '(choice (const nil) (const t) (const pty)))
1594
b50dd0d2
MA
1595(defcustom tramp-completion-reread-directory-timeout 10
1596 "Defines seconds since last remote command before rereading a directory.
1597A remote directory might have changed its contents. In order to
1598make it visible during file name completion in the minibuffer,
1599Tramp flushes its cache and rereads the directory contents when
1600more than `tramp-completion-reread-directory-timeout' seconds
1601have been gone since last remote command execution. A value of 0
1602would require an immediate reread during filename completion, nil
1603means to use always cached values for the directory contents."
1604 :group 'tramp
1605 :type '(choice (const nil) integer))
1606
fb7933a3
KG
1607;;; Internal Variables:
1608
fb7933a3 1609(defvar tramp-current-method nil
00d6fd04 1610 "Connection method for this *tramp* buffer.")
fb7933a3
KG
1611
1612(defvar tramp-current-user nil
00d6fd04 1613 "Remote login name for this *tramp* buffer.")
fb7933a3
KG
1614
1615(defvar tramp-current-host nil
00d6fd04
MA
1616 "Remote host for this *tramp* buffer.")
1617
1618(defconst tramp-uudecode
1619 "(echo begin 600 /tmp/tramp.$$; tail +2) | uudecode
fabf2143 1620cat /tmp/tramp.$$
00d6fd04 1621rm -f /tmp/tramp.$$"
fabf2143 1622 "Shell function to implement `uudecode' to standard output.
c08e6004
MA
1623Many systems support `uudecode -o /dev/stdout' or `uudecode -o -'
1624for this or `uudecode -p', but some systems don't, and for them
1625we have this shell function.")
fabf2143 1626
293c24f9
MA
1627(defconst tramp-perl-file-truename
1628 "%s -e '
1629use File::Spec;
1630use Cwd \"realpath\";
1631
1632sub recursive {
1633 my ($volume, @dirs) = @_;
1634 my $real = realpath(File::Spec->catpath(
1635 $volume, File::Spec->catdir(@dirs), \"\"));
1636 if ($real) {
1637 my ($vol, $dir) = File::Spec->splitpath($real, 1);
1638 return ($vol, File::Spec->splitdir($dir));
1639 }
1640 else {
1641 my $last = pop(@dirs);
1642 ($volume, @dirs) = recursive($volume, @dirs);
1643 push(@dirs, $last);
1644 return ($volume, @dirs);
1645 }
1646}
1647
1648$result = realpath($ARGV[0]);
1649if (!$result) {
1650 my ($vol, $dir) = File::Spec->splitpath($ARGV[0], 1);
1651 ($vol, @dirs) = recursive($vol, File::Spec->splitdir($dir));
1652
1653 $result = File::Spec->catpath($vol, File::Spec->catdir(@dirs), \"\");
1654}
1655
1656if ($ARGV[0] =~ /\\/$/) {
1657 $result = $result . \"/\";
1658}
1659
1660print \"\\\"$result\\\"\\n\";
1661' \"$1\" 2>/dev/null"
1662 "Perl script to produce output suitable for use with `file-truename'
1663on the remote file system.
1664Escape sequence %s is replaced with name of Perl binary.
1665This string is passed to `format', so percent characters need to be doubled.")
1666
1667(defconst tramp-perl-file-name-all-completions
1668 "%s -e 'sub case {
1669 my $str = shift;
1670 if ($ARGV[2]) {
1671 return lc($str);
1672 }
1673 else {
1674 return $str;
1675 }
1676}
1677opendir(d, $ARGV[0]) || die(\"$ARGV[0]: $!\\nfail\\n\");
1678@files = readdir(d); closedir(d);
1679foreach $f (@files) {
1680 if (case(substr($f, 0, length($ARGV[1]))) eq case($ARGV[1])) {
1681 if (-d \"$ARGV[0]/$f\") {
1682 print \"$f/\\n\";
1683 }
1684 else {
1685 print \"$f\\n\";
1686 }
1687 }
1688}
1689print \"ok\\n\"
1690' \"$1\" \"$2\" \"$3\" 2>/dev/null"
1691 "Perl script to produce output suitable for use with
1692`file-name-all-completions' on the remote file system. Escape
1693sequence %s is replaced with name of Perl binary. This string is
1694passed to `format', so percent characters need to be doubled.")
1695
fabf2143
KG
1696;; Perl script to implement `file-attributes' in a Lisp `read'able
1697;; output. If you are hacking on this, note that you get *no* output
1698;; unless this spits out a complete line, including the '\n' at the
1699;; end.
8daea7fc 1700;; The device number is returned as "-1", because there will be a virtual
b946a456 1701;; device number set in `tramp-handle-file-attributes'.
00d6fd04
MA
1702(defconst tramp-perl-file-attributes
1703 "%s -e '
c82c5727 1704@stat = lstat($ARGV[0]);
680db9ac
MA
1705if (!@stat) {
1706 print \"nil\\n\";
1707 exit 0;
1708}
c82c5727
LH
1709if (($stat[2] & 0170000) == 0120000)
1710{
1711 $type = readlink($ARGV[0]);
1712 $type = \"\\\"$type\\\"\";
1713}
1714elsif (($stat[2] & 0170000) == 040000)
1715{
1716 $type = \"t\";
1717}
1718else
1719{
1720 $type = \"nil\"
1721};
1722$uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
1723$gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
1724printf(
d4443a0d 1725 \"(%%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) -1)\\n\",
c82c5727
LH
1726 $type,
1727 $stat[3],
1728 $uid,
1729 $gid,
1730 $stat[8] >> 16 & 0xffff,
1731 $stat[8] & 0xffff,
1732 $stat[9] >> 16 & 0xffff,
1733 $stat[9] & 0xffff,
1734 $stat[10] >> 16 & 0xffff,
1735 $stat[10] & 0xffff,
1736 $stat[7],
1737 $stat[2],
1738 $stat[1] >> 16 & 0xffff,
1739 $stat[1] & 0xffff
00d6fd04 1740);' \"$1\" \"$2\" \"$3\" 2>/dev/null"
fb7933a3 1741 "Perl script to produce output suitable for use with `file-attributes'
00d6fd04
MA
1742on the remote file system.
1743Escape sequence %s is replaced with name of Perl binary.
1744This string is passed to `format', so percent characters need to be doubled.")
fb7933a3 1745
00d6fd04
MA
1746(defconst tramp-perl-directory-files-and-attributes
1747 "%s -e '
8cb0a559
LH
1748chdir($ARGV[0]) or printf(\"\\\"Cannot change to $ARGV[0]: $''!''\\\"\\n\"), exit();
1749opendir(DIR,\".\") or printf(\"\\\"Cannot open directory $ARGV[0]: $''!''\\\"\\n\"), exit();
c82c5727
LH
1750@list = readdir(DIR);
1751closedir(DIR);
1752$n = scalar(@list);
1753printf(\"(\\n\");
1754for($i = 0; $i < $n; $i++)
1755{
1756 $filename = $list[$i];
1757 @stat = lstat($filename);
1758 if (($stat[2] & 0170000) == 0120000)
1759 {
1760 $type = readlink($filename);
1761 $type = \"\\\"$type\\\"\";
1762 }
1763 elsif (($stat[2] & 0170000) == 040000)
1764 {
1765 $type = \"t\";
1766 }
1767 else
1768 {
1769 $type = \"nil\"
1770 };
1771 $uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
1772 $gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
1773 printf(
b946a456 1774 \"(\\\"%%s\\\" %%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) (%%u . %%u))\\n\",
c82c5727
LH
1775 $filename,
1776 $type,
1777 $stat[3],
1778 $uid,
1779 $gid,
1780 $stat[8] >> 16 & 0xffff,
1781 $stat[8] & 0xffff,
1782 $stat[9] >> 16 & 0xffff,
1783 $stat[9] & 0xffff,
1784 $stat[10] >> 16 & 0xffff,
1785 $stat[10] & 0xffff,
1786 $stat[7],
1787 $stat[2],
1788 $stat[1] >> 16 & 0xffff,
1789 $stat[1] & 0xffff,
1790 $stat[0] >> 16 & 0xffff,
1791 $stat[0] & 0xffff);
1792}
00d6fd04 1793printf(\")\\n\");' \"$1\" \"$2\" \"$3\" 2>/dev/null"
c82c5727 1794 "Perl script implementing `directory-files-attributes' as Lisp `read'able
00d6fd04
MA
1795output.
1796Escape sequence %s is replaced with name of Perl binary.
1797This string is passed to `format', so percent characters need to be doubled.")
c82c5727 1798
ac474af1
KG
1799;; ;; These two use uu encoding.
1800;; (defvar tramp-perl-encode "%s -e'\
1801;; print qq(begin 644 xxx\n);
1802;; my $s = q();
1803;; my $res = q();
1804;; while (read(STDIN, $s, 45)) {
1805;; print pack(q(u), $s);
1806;; }
1807;; print qq(`\n);
1808;; print qq(end\n);
1809;; '"
1810;; "Perl program to use for encoding a file.
1811;; Escape sequence %s is replaced with name of Perl binary.")
1812
1813;; (defvar tramp-perl-decode "%s -ne '
1814;; print unpack q(u), $_;
1815;; '"
1816;; "Perl program to use for decoding a file.
1817;; Escape sequence %s is replaced with name of Perl binary.")
1818
1819;; These two use base64 encoding.
00d6fd04
MA
1820(defconst tramp-perl-encode-with-module
1821 "%s -MMIME::Base64 -0777 -ne 'print encode_base64($_)' 2>/dev/null"
ac474af1 1822 "Perl program to use for encoding a file.
b1d06e75 1823Escape sequence %s is replaced with name of Perl binary.
89509ea0 1824This string is passed to `format', so percent characters need to be doubled.
b1d06e75
KG
1825This implementation requires the MIME::Base64 Perl module to be installed
1826on the remote host.")
1827
00d6fd04
MA
1828(defconst tramp-perl-decode-with-module
1829 "%s -MMIME::Base64 -0777 -ne 'print decode_base64($_)' 2>/dev/null"
b1d06e75
KG
1830 "Perl program to use for decoding a file.
1831Escape sequence %s is replaced with name of Perl binary.
89509ea0 1832This string is passed to `format', so percent characters need to be doubled.
b1d06e75
KG
1833This implementation requires the MIME::Base64 Perl module to be installed
1834on the remote host.")
1835
00d6fd04 1836(defconst tramp-perl-encode
b1d06e75
KG
1837 "%s -e '
1838# This script contributed by Juanma Barranquero <lektu@terra.es>.
46932a8d 1839# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
cbd12ed7 1840# Free Software Foundation, Inc.
b1d06e75
KG
1841use strict;
1842
fa32e96a 1843my %%trans = do {
b1d06e75
KG
1844 my $i = 0;
1845 map {(substr(unpack(q(B8), chr $i++), 2, 6), $_)}
1846 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/);
1847};
1848
36541701 1849binmode(\\*STDIN);
b1d06e75
KG
1850
1851# We read in chunks of 54 bytes, to generate output lines
1852# of 72 chars (plus end of line)
36541701 1853$/ = \\54;
b1d06e75
KG
1854
1855while (my $data = <STDIN>) {
1856 my $pad = q();
1857
1858 # Only for the last chunk, and only if did not fill the last three-byte packet
1859 if (eof) {
fa32e96a 1860 my $mod = length($data) %% 3;
b1d06e75
KG
1861 $pad = q(=) x (3 - $mod) if $mod;
1862 }
1863
1864 # Not the fastest method, but it is simple: unpack to binary string, split
1865 # by groups of 6 bits and convert back from binary to byte; then map into
1866 # the translation table
1867 print
1868 join q(),
1869 map($trans{$_},
1870 (substr(unpack(q(B*), $data) . q(00000), 0, 432) =~ /....../g)),
1871 $pad,
36541701 1872 qq(\\n);
00d6fd04 1873}' 2>/dev/null"
b1d06e75 1874 "Perl program to use for encoding a file.
fa32e96a 1875Escape sequence %s is replaced with name of Perl binary.
ccf29586 1876This string is passed to `format', so percent characters need to be doubled.")
ac474af1 1877
00d6fd04 1878(defconst tramp-perl-decode
b1d06e75
KG
1879 "%s -e '
1880# This script contributed by Juanma Barranquero <lektu@terra.es>.
46932a8d 1881# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
cbd12ed7 1882# Free Software Foundation, Inc.
b1d06e75
KG
1883use strict;
1884
fa32e96a 1885my %%trans = do {
b1d06e75 1886 my $i = 0;
16674e4f 1887 map {($_, substr(unpack(q(B8), chr $i++), 2, 6))}
b1d06e75
KG
1888 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/)
1889};
1890
fa32e96a 1891my %%bytes = map {(unpack(q(B8), chr $_), chr $_)} 0 .. 255;
b1d06e75 1892
36541701 1893binmode(\\*STDOUT);
b1d06e75
KG
1894
1895# We are going to accumulate into $pending to accept any line length
1896# (we do not check they are <= 76 chars as the RFC says)
1897my $pending = q();
1898
1899while (my $data = <STDIN>) {
1900 chomp $data;
1901
1902 # If we find one or two =, we have reached the end and
1903 # any following data is to be discarded
1904 my $finished = $data =~ s/(==?).*/$1/;
1905 $pending .= $data;
1906
1907 my $len = length($pending);
16674e4f 1908 my $chunk = substr($pending, 0, $len & ~3);
414da5ab 1909 $pending = substr($pending, $len & ~3 + 1);
b1d06e75
KG
1910
1911 # Easy method: translate from chars to (pregenerated) six-bit packets, join,
1912 # split in 8-bit chunks and convert back to char.
1913 print join q(),
1914 map $bytes{$_},
1915 ((join q(), map {$trans{$_} || q()} split //, $chunk) =~ /......../g);
1916
1917 last if $finished;
00d6fd04 1918}' 2>/dev/null"
ac474af1 1919 "Perl program to use for decoding a file.
fa32e96a 1920Escape sequence %s is replaced with name of Perl binary.
ccf29586 1921This string is passed to `format', so percent characters need to be doubled.")
fb7933a3 1922
946a5aeb
MA
1923(defconst tramp-vc-registered-read-file-names
1924 "echo \"(\"
1925for file in \"$@\"; do
1926 if %s $file; then
1927 echo \"(\\\"$file\\\" \\\"file-exists-p\\\" t)\"
1928 else
1929 echo \"(\\\"$file\\\" \\\"file-exists-p\\\" nil)\"
1930 fi
1931 if %s $file; then
1932 echo \"(\\\"$file\\\" \\\"file-readable-p\\\" t)\"
1933 else
1934 echo \"(\\\"$file\\\" \\\"file-readable-p\\\" nil)\"
1935 fi
1936done
1937echo \")\""
1938 "Script to check existence of VC related files.
1939It must be send formatted with two strings; the tests for file
1940existence, and file readability.")
1941
9ce8462a
MA
1942(defconst tramp-file-mode-type-map
1943 '((0 . "-") ; Normal file (SVID-v2 and XPG2)
1944 (1 . "p") ; fifo
1945 (2 . "c") ; character device
1946 (3 . "m") ; multiplexed character device (v7)
1947 (4 . "d") ; directory
1948 (5 . "?") ; Named special file (XENIX)
1949 (6 . "b") ; block device
1950 (7 . "?") ; multiplexed block device (v7)
1951 (8 . "-") ; regular file
1952 (9 . "n") ; network special file (HP-UX)
1953 (10 . "l") ; symlink
1954 (11 . "?") ; ACL shadow inode (Solaris, not userspace)
1955 (12 . "s") ; socket
1956 (13 . "D") ; door special (Solaris)
1957 (14 . "w")) ; whiteout (BSD)
fb7933a3
KG
1958 "A list of file types returned from the `stat' system call.
1959This is used to map a mode number to a permission string.")
1960
fb7933a3 1961;; New handlers should be added here. The following operations can be
c0fc6170
MA
1962;; handled using the normal primitives: file-name-sans-versions,
1963;; get-file-buffer.
fb7933a3 1964(defconst tramp-file-name-handler-alist
00d6fd04 1965 '((load . tramp-handle-load)
fb7933a3 1966 (make-symbolic-link . tramp-handle-make-symbolic-link)
c0fc6170 1967 (file-name-as-directory . tramp-handle-file-name-as-directory)
fb7933a3
KG
1968 (file-name-directory . tramp-handle-file-name-directory)
1969 (file-name-nondirectory . tramp-handle-file-name-nondirectory)
1970 (file-truename . tramp-handle-file-truename)
1971 (file-exists-p . tramp-handle-file-exists-p)
1972 (file-directory-p . tramp-handle-file-directory-p)
1973 (file-executable-p . tramp-handle-file-executable-p)
fb7933a3
KG
1974 (file-readable-p . tramp-handle-file-readable-p)
1975 (file-regular-p . tramp-handle-file-regular-p)
1976 (file-symlink-p . tramp-handle-file-symlink-p)
1977 (file-writable-p . tramp-handle-file-writable-p)
1978 (file-ownership-preserved-p . tramp-handle-file-ownership-preserved-p)
1979 (file-newer-than-file-p . tramp-handle-file-newer-than-file-p)
1980 (file-attributes . tramp-handle-file-attributes)
1981 (file-modes . tramp-handle-file-modes)
fb7933a3 1982 (directory-files . tramp-handle-directory-files)
c82c5727 1983 (directory-files-and-attributes . tramp-handle-directory-files-and-attributes)
fb7933a3
KG
1984 (file-name-all-completions . tramp-handle-file-name-all-completions)
1985 (file-name-completion . tramp-handle-file-name-completion)
1986 (add-name-to-file . tramp-handle-add-name-to-file)
1987 (copy-file . tramp-handle-copy-file)
263c02ef 1988 (copy-directory . tramp-handle-copy-directory)
fb7933a3
KG
1989 (rename-file . tramp-handle-rename-file)
1990 (set-file-modes . tramp-handle-set-file-modes)
ce3f516f 1991 (set-file-times . tramp-handle-set-file-times)
fb7933a3
KG
1992 (make-directory . tramp-handle-make-directory)
1993 (delete-directory . tramp-handle-delete-directory)
1994 (delete-file . tramp-handle-delete-file)
1995 (directory-file-name . tramp-handle-directory-file-name)
00d6fd04
MA
1996 ;; `executable-find' is not official yet.
1997 (executable-find . tramp-handle-executable-find)
1998 (start-file-process . tramp-handle-start-file-process)
0457dd55 1999 (process-file . tramp-handle-process-file)
00d6fd04 2000 (shell-command . tramp-handle-shell-command)
fb7933a3
KG
2001 (insert-directory . tramp-handle-insert-directory)
2002 (expand-file-name . tramp-handle-expand-file-name)
00d6fd04 2003 (substitute-in-file-name . tramp-handle-substitute-in-file-name)
fb7933a3 2004 (file-local-copy . tramp-handle-file-local-copy)
19a87064 2005 (file-remote-p . tramp-handle-file-remote-p)
fb7933a3 2006 (insert-file-contents . tramp-handle-insert-file-contents)
94be87e8
MA
2007 (insert-file-contents-literally
2008 . tramp-handle-insert-file-contents-literally)
fb7933a3 2009 (write-region . tramp-handle-write-region)
38c65fca 2010 (find-backup-file-name . tramp-handle-find-backup-file-name)
c1105d05 2011 (make-auto-save-file-name . tramp-handle-make-auto-save-file-name)
fb7933a3 2012 (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
5ec2cc41 2013 (dired-compress-file . tramp-handle-dired-compress-file)
fb7933a3
KG
2014 (dired-recursive-delete-directory
2015 . tramp-handle-dired-recursive-delete-directory)
70c11b0b 2016 (dired-uncache . tramp-handle-dired-uncache)
fb7933a3 2017 (set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
49096407
MA
2018 (verify-visited-file-modtime . tramp-handle-verify-visited-file-modtime)
2019 (vc-registered . tramp-handle-vc-registered))
c1105d05 2020 "Alist of handler functions.
fb7933a3
KG
2021Operations not mentioned here will be handled by the normal Emacs functions.")
2022
a4aeb9a4 2023;; Handlers for partial Tramp file names. For Emacs just
41c8e348 2024;; `file-name-all-completions' is needed.
a01b1e22 2025;;;###autoload
16674e4f 2026(defconst tramp-completion-file-name-handler-alist
a01b1e22 2027 '((file-name-all-completions . tramp-completion-handle-file-name-all-completions)
41c8e348 2028 (file-name-completion . tramp-completion-handle-file-name-completion))
16674e4f
KG
2029 "Alist of completion handler functions.
2030Used for file names matching `tramp-file-name-regexp'. Operations not
2031mentioned here will be handled by `tramp-file-name-handler-alist' or the
2032normal Emacs functions.")
2033
4007ba5b 2034;; Handlers for foreign methods, like FTP or SMB, shall be plugged here.
ea9d1443
KG
2035(defvar tramp-foreign-file-name-handler-alist
2036 ;; (identity . tramp-sh-file-name-handler) should always be the last
b88f2d0a 2037 ;; entry, because `identity' always matches.
ea9d1443 2038 '((identity . tramp-sh-file-name-handler))
4007ba5b
KG
2039 "Alist of elements (FUNCTION . HANDLER) for foreign methods handled specially.
2040If (FUNCTION FILENAME) returns non-nil, then all I/O on that file is done by
2041calling HANDLER.")
2042
0664ff72 2043;;; Internal functions which must come first:
fb7933a3 2044
00d6fd04
MA
2045(defsubst tramp-debug-message (vec fmt-string &rest args)
2046 "Append message to debug buffer.
2047Message is formatted with FMT-STRING as control string and the remaining
2048ARGS to actually emit the message (if applicable)."
2049 (when (get-buffer (tramp-buffer-name vec))
2050 (with-current-buffer (tramp-get-debug-buffer vec)
2051 (goto-char (point-max))
70c11b0b
MA
2052 ;; Headline.
2053 (when (bobp)
2054 (insert
2055 (format
2056 ";; %sEmacs: %s Tramp: %s -*- mode: outline; -*-"
2057 (if (featurep 'sxemacs) "SX" (if (featurep 'xemacs) "X" "GNU "))
2058 emacs-version tramp-version)))
00d6fd04
MA
2059 (unless (bolp)
2060 (insert "\n"))
70c11b0b 2061 ;; Timestamp.
736ac90f
MA
2062 (let ((now (current-time)))
2063 (insert (format-time-string "%T." now))
2064 (insert (format "%06d " (nth 2 now))))
70c11b0b 2065 ;; Calling function.
00d6fd04
MA
2066 (let ((btn 1) btf fn)
2067 (while (not fn)
2068 (setq btf (nth 1 (backtrace-frame btn)))
2069 (if (not btf)
2070 (setq fn "")
2071 (when (symbolp btf)
2072 (setq fn (symbol-name btf))
2073 (unless (and (string-match "^tramp" fn)
2074 (not (string-match
2075 "^tramp\\(-debug\\)?\\(-message\\|-error\\)$"
2076 fn)))
2077 (setq fn nil)))
2078 (setq btn (1+ btn))))
2079 ;; The following code inserts filename and line number.
2080 ;; Should be deactivated by default, because it is time
2081 ;; consuming.
2082; (let ((ffn (find-function-noselect (intern fn))))
2083; (insert
2084; (format
2085; "%s:%d: "
2086; (file-name-nondirectory (buffer-file-name (car ffn)))
2087; (with-current-buffer (car ffn)
2088; (1+ (count-lines (point-min) (cdr ffn)))))))
2089 (insert (format "%s " fn)))
70c11b0b 2090 ;; The message.
00d6fd04
MA
2091 (insert (apply 'format fmt-string args)))))
2092
946a5aeb
MA
2093(defvar tramp-message-show-message t
2094 "Show Tramp message in the minibuffer.
2095This variable is used to disable messages from `tramp-error'.
2096The messages are visible anyway, because an error is raised.")
2097
00d6fd04 2098(defsubst tramp-message (vec-or-proc level fmt-string &rest args)
fb7933a3 2099 "Emit a message depending on verbosity level.
a4aeb9a4 2100VEC-OR-PROC identifies the Tramp buffer to use. It can be either a
00d6fd04
MA
2101vector or a process. LEVEL says to be quiet if `tramp-verbose' is
2102less than LEVEL. The message is emitted only if `tramp-verbose' is
2103greater than or equal to LEVEL.
2104
2105The message is also logged into the debug buffer when `tramp-verbose'
2106is greater than or equal 4.
2107
2108Calls functions `message' and `tramp-debug-message' with FMT-STRING as
2109control string and the remaining ARGS to actually emit the message (if
2110applicable)."
2111 (condition-case nil
2112 (when (<= level tramp-verbose)
2113 ;; Match data must be preserved!
2114 (save-match-data
2115 ;; Display only when there is a minimum level.
946a5aeb 2116 (when (and tramp-message-show-message (<= level 3))
00d6fd04
MA
2117 (apply 'message
2118 (concat
2119 (cond
2120 ((= level 0) "")
2121 ((= level 1) "")
2122 ((= level 2) "Warning: ")
2123 (t "Tramp: "))
2124 fmt-string)
2125 args))
2126 ;; Log only when there is a minimum level.
2127 (when (>= tramp-verbose 4)
2128 (when (and vec-or-proc
2129 (processp vec-or-proc)
2130 (buffer-name (process-buffer vec-or-proc)))
2131 (with-current-buffer (process-buffer vec-or-proc)
2132 ;; Translate proc to vec.
2133 (setq vec-or-proc (tramp-dissect-file-name default-directory))))
2134 (when (and vec-or-proc (vectorp vec-or-proc))
2135 (apply 'tramp-debug-message
2136 vec-or-proc
2137 (concat (format "(%d) # " level) fmt-string)
2138 args)))))
2139 ;; Suppress all errors.
2140 (error nil)))
2141
2142(defsubst tramp-error (vec-or-proc signal fmt-string &rest args)
2143 "Emit an error.
2144VEC-OR-PROC identifies the connection to use, SIGNAL is the
2145signal identifier to be raised, remaining args passed to
2146`tramp-message'. Finally, signal SIGNAL is raised."
946a5aeb
MA
2147 (let (tramp-message-show-message)
2148 (tramp-message
2149 vec-or-proc 1 "%s"
2150 (error-message-string
2151 (list signal
2152 (get signal 'error-message)
2153 (apply 'format fmt-string args))))
2154 (signal signal (list (apply 'format fmt-string args)))))
00d6fd04
MA
2155
2156(defsubst tramp-error-with-buffer
2157 (buffer vec-or-proc signal fmt-string &rest args)
2158 "Emit an error, and show BUFFER.
2159If BUFFER is nil, show the connection buffer. Wait for 30\", or until
2160an input event arrives. The other arguments are passed to `tramp-error'."
2161 (save-window-excursion
2162 (unwind-protect
2163 (apply 'tramp-error vec-or-proc signal fmt-string args)
2164 (when (and vec-or-proc (not (zerop tramp-verbose)))
2165 (let ((enable-recursive-minibuffers t))
2166 (pop-to-buffer
2167 (or (and (bufferp buffer) buffer)
2168 (and (processp vec-or-proc) (process-buffer vec-or-proc))
2169 (tramp-get-buffer vec-or-proc)))
2170 (sit-for 30))))))
fb7933a3 2171
c62c9d08
KG
2172(defmacro with-parsed-tramp-file-name (filename var &rest body)
2173 "Parse a Tramp filename and make components available in the body.
2174
2175First arg FILENAME is evaluated and dissected into its components.
2176Second arg VAR is a symbol. It is used as a variable name to hold
2177the filename structure. It is also used as a prefix for the variables
2178holding the components. For example, if VAR is the symbol `foo', then
00d6fd04
MA
2179`foo' will be bound to the whole structure, `foo-method' will be bound to
2180the method component, and so on for `foo-user', `foo-host', `foo-localname'.
c62c9d08
KG
2181
2182Remaining args are Lisp expressions to be evaluated (inside an implicit
2183`progn').
2184
00d6fd04
MA
2185If VAR is nil, then we bind `v' to the structure and `method', `user',
2186`host', `localname' to the components."
c62c9d08 2187 `(let* ((,(or var 'v) (tramp-dissect-file-name ,filename))
c62c9d08
KG
2188 (,(if var (intern (concat (symbol-name var) "-method")) 'method)
2189 (tramp-file-name-method ,(or var 'v)))
2190 (,(if var (intern (concat (symbol-name var) "-user")) 'user)
2191 (tramp-file-name-user ,(or var 'v)))
2192 (,(if var (intern (concat (symbol-name var) "-host")) 'host)
2193 (tramp-file-name-host ,(or var 'v)))
7432277c
KG
2194 (,(if var (intern (concat (symbol-name var) "-localname")) 'localname)
2195 (tramp-file-name-localname ,(or var 'v))))
c62c9d08
KG
2196 ,@body))
2197
2198(put 'with-parsed-tramp-file-name 'lisp-indent-function 2)
00d6fd04 2199(put 'with-parsed-tramp-file-name 'edebug-form-spec '(form symbolp body))
9e6ab520 2200(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-parsed-tramp-file-name\\>"))
c62c9d08 2201
00d6fd04
MA
2202(defmacro with-file-property (vec file property &rest body)
2203 "Check in Tramp cache for PROPERTY, otherwise execute BODY and set cache.
2204FILE must be a local file name on a connection identified via VEC."
2205 `(if (file-name-absolute-p ,file)
2206 (let ((value (tramp-get-file-property ,vec ,file ,property 'undef)))
2207 (when (eq value 'undef)
2208 ;; We cannot pass @body as parameter to
2209 ;; `tramp-set-file-property' because it mangles our
2210 ;; debug messages.
2211 (setq value (progn ,@body))
2212 (tramp-set-file-property ,vec ,file ,property value))
2213 value)
2214 ,@body))
9ce8462a 2215
00d6fd04
MA
2216(put 'with-file-property 'lisp-indent-function 3)
2217(put 'with-file-property 'edebug-form-spec t)
9e6ab520 2218(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-file-property\\>"))
00d6fd04
MA
2219
2220(defmacro with-connection-property (key property &rest body)
2221 "Checks in Tramp for property PROPERTY, otherwise executes BODY and set."
2222 `(let ((value (tramp-get-connection-property ,key ,property 'undef)))
2223 (when (eq value 'undef)
2224 ;; We cannot pass ,@body as parameter to
2225 ;; `tramp-set-connection-property' because it mangles our debug
2226 ;; messages.
2227 (setq value (progn ,@body))
2228 (tramp-set-connection-property ,key ,property value))
2229 value))
9ce8462a 2230
00d6fd04
MA
2231(put 'with-connection-property 'lisp-indent-function 2)
2232(put 'with-connection-property 'edebug-form-spec t)
9e6ab520 2233(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-connection-property\\>"))
00d6fd04 2234
628c97b2
GM
2235(eval-and-compile ; silence compiler
2236 (if (memq system-type '(cygwin windows-nt))
2237 (defun tramp-drop-volume-letter (name)
2238 "Cut off unnecessary drive letter from file NAME.
2239The function `tramp-handle-expand-file-name' calls `expand-file-name'
2240locally on a remote file name. When the local system is a W32 system
2241but the remote system is Unix, this introduces a superfluous drive
2242letter into the file name. This function removes it."
2243 (save-match-data
2244 (if (string-match tramp-root-regexp name)
2245 (replace-match "/" nil t name)
2246 name)))
2247
2248 (defalias 'tramp-drop-volume-letter 'identity)))
2249
9c13938d 2250(defsubst tramp-make-tramp-temp-file (vec)
a6e96327 2251 "Create a temporary file on the remote host identified by VEC.
9c13938d
MA
2252Return the local name of the temporary file."
2253 (let ((prefix
2254 (tramp-make-tramp-file-name
2255 (tramp-file-name-method vec)
2256 (tramp-file-name-user vec)
2257 (tramp-file-name-host vec)
113e2a84
MA
2258 (tramp-drop-volume-letter
2259 (expand-file-name
2260 tramp-temp-name-prefix (tramp-get-remote-tmpdir vec)))))
9c13938d
MA
2261 result)
2262 (while (not result)
2263 ;; `make-temp-file' would be the natural choice for
2264 ;; implementation. But it calls `write-region' internally,
2265 ;; which also needs a temporary file - we would end in an
2266 ;; infinite loop.
2267 (setq result (make-temp-name prefix))
2268 (if (file-exists-p result)
2269 (setq result nil)
2270 ;; This creates the file by side effect.
2271 (set-file-times result)
2272 (set-file-modes result (tramp-octal-to-decimal "0700"))))
2273
2274 ;; Return the local part.
2275 (with-parsed-tramp-file-name result nil localname)))
8a4438b6
MA
2276
2277
16674e4f
KG
2278;;; Config Manipulation Functions:
2279
2280(defun tramp-set-completion-function (method function-list)
2281 "Sets the list of completion functions for METHOD.
2282FUNCTION-LIST is a list of entries of the form (FUNCTION FILE).
2283The FUNCTION is intended to parse FILE according its syntax.
2284It might be a predefined FUNCTION, or a user defined FUNCTION.
2285Predefined FUNCTIONs are `tramp-parse-rhosts', `tramp-parse-shosts',
8fc29035 2286`tramp-parse-sconfig', `tramp-parse-hosts', `tramp-parse-passwd',
8daea7fc
KG
2287and `tramp-parse-netrc'.
2288
16674e4f
KG
2289Example:
2290
2291 (tramp-set-completion-function
2292 \"ssh\"
8daea7fc
KG
2293 '((tramp-parse-sconfig \"/etc/ssh_config\")
2294 (tramp-parse-sconfig \"~/.ssh/config\")))"
16674e4f 2295
5ec2cc41
KG
2296 (let ((r function-list)
2297 (v function-list))
2298 (setq tramp-completion-function-alist
2299 (delete (assoc method tramp-completion-function-alist)
2300 tramp-completion-function-alist))
2301
2302 (while v
00d6fd04 2303 ;; Remove double entries.
5ec2cc41
KG
2304 (when (member (car v) (cdr v))
2305 (setcdr v (delete (car v) (cdr v))))
00d6fd04 2306 ;; Check for function and file or registry key.
5ec2cc41 2307 (unless (and (functionp (nth 0 (car v)))
00d6fd04
MA
2308 (if (string-match "^HKEY_CURRENT_USER" (nth 1 (car v)))
2309 ;; Windows registry.
2310 (and (memq system-type '(cygwin windows-nt))
a4aeb9a4
MA
2311 (zerop
2312 (tramp-local-call-process
2313 "reg" nil nil nil "query" (nth 1 (car v)))))
00d6fd04
MA
2314 ;; Configuration file.
2315 (file-exists-p (nth 1 (car v)))))
5ec2cc41
KG
2316 (setq r (delete (car v) r)))
2317 (setq v (cdr v)))
2318
2319 (when r
4007ba5b 2320 (add-to-list 'tramp-completion-function-alist
5ec2cc41 2321 (cons method r)))))
16674e4f
KG
2322
2323(defun tramp-get-completion-function (method)
00d6fd04 2324 "Returns a list of completion functions for METHOD.
16674e4f 2325For definition of that list see `tramp-set-completion-function'."
00d6fd04
MA
2326 (cons
2327 ;; Hosts visited once shall be remembered.
2328 `(tramp-parse-connection-properties ,method)
2329 ;; The method related defaults.
2330 (cdr (assoc method tramp-completion-function-alist))))
16674e4f 2331
d037d501 2332
0664ff72 2333;;; Fontification of `read-file-name':
d037d501 2334
0664ff72 2335;; rfn-eshadow.el is part of Emacs 22. It is autoloaded.
d037d501
MA
2336(defvar tramp-rfn-eshadow-overlay)
2337(make-variable-buffer-local 'tramp-rfn-eshadow-overlay)
2338
2339(defun tramp-rfn-eshadow-setup-minibuffer ()
2340 "Set up a minibuffer for `file-name-shadow-mode'.
2341Adds another overlay hiding filename parts according to Tramp's
2342special handling of `substitute-in-file-name'."
9ce8462a 2343 (when (symbol-value 'minibuffer-completing-file-name)
d037d501 2344 (setq tramp-rfn-eshadow-overlay
9e6ab520
MA
2345 (funcall (symbol-function 'make-overlay)
2346 (funcall (symbol-function 'minibuffer-prompt-end))
2347 (funcall (symbol-function 'minibuffer-prompt-end))))
d037d501 2348 ;; Copy rfn-eshadow-overlay properties.
9e6ab520
MA
2349 (let ((props (funcall (symbol-function 'overlay-properties)
2350 (symbol-value 'rfn-eshadow-overlay))))
d037d501 2351 (while props
9e6ab520
MA
2352 (funcall (symbol-function 'overlay-put)
2353 tramp-rfn-eshadow-overlay (pop props) (pop props))))))
d037d501
MA
2354
2355(when (boundp 'rfn-eshadow-setup-minibuffer-hook)
2356 (add-hook 'rfn-eshadow-setup-minibuffer-hook
48846dc5
MA
2357 'tramp-rfn-eshadow-setup-minibuffer)
2358 (add-hook 'tramp-unload-hook
aa485f7c
MA
2359 (lambda ()
2360 (remove-hook 'rfn-eshadow-setup-minibuffer-hook
2361 'tramp-rfn-eshadow-setup-minibuffer))))
d037d501 2362
adcbca53
MA
2363(defconst tramp-rfn-eshadow-update-overlay-regexp
2364 (format "[^%s/~]*\\(/\\|~\\)" tramp-postfix-host-format))
2365
d037d501
MA
2366(defun tramp-rfn-eshadow-update-overlay ()
2367 "Update `rfn-eshadow-overlay' to cover shadowed part of minibuffer input.
2368This is intended to be used as a minibuffer `post-command-hook' for
2369`file-name-shadow-mode'; the minibuffer should have already
2370been set up by `rfn-eshadow-setup-minibuffer'."
2371 ;; In remote files name, there is a shadowing just for the local part.
9e6ab520
MA
2372 (let ((end (or (funcall (symbol-function 'overlay-end)
2373 (symbol-value 'rfn-eshadow-overlay))
2374 (funcall (symbol-function 'minibuffer-prompt-end)))))
2375 (when (file-remote-p (buffer-substring-no-properties end (point-max)))
bd316474
KY
2376 (save-excursion
2377 (save-restriction
2378 (narrow-to-region
adcbca53
MA
2379 (1+ (or (string-match
2380 tramp-rfn-eshadow-update-overlay-regexp (buffer-string) end)
2381 end))
2382 (point-max))
bd316474
KY
2383 (let ((rfn-eshadow-overlay tramp-rfn-eshadow-overlay)
2384 (rfn-eshadow-update-overlay-hook nil))
dea31ca6 2385 (move-overlay rfn-eshadow-overlay (point-max) (point-max))
bd316474 2386 (funcall (symbol-function 'rfn-eshadow-update-overlay))))))))
d037d501
MA
2387
2388(when (boundp 'rfn-eshadow-update-overlay-hook)
2389 (add-hook 'rfn-eshadow-update-overlay-hook
b88f2d0a
MA
2390 'tramp-rfn-eshadow-update-overlay)
2391 (add-hook 'tramp-unload-hook
2392 (lambda ()
2393 (remove-hook 'rfn-eshadow-update-overlay-hook
2394 'tramp-rfn-eshadow-update-overlay))))
d037d501
MA
2395
2396
605a20a9
MA
2397;;; Integration of eshell.el:
2398
2399(eval-when-compile
2400 (defvar eshell-path-env))
2401
2402;; eshell.el keeps the path in `eshell-path-env'. We must change it
2403;; when `default-directory' points to another host.
2404(defun tramp-eshell-directory-change ()
2405 "Set `eshell-path-env' to $PATH of the host related to `default-directory'."
2406 (setq eshell-path-env
2407 (if (file-remote-p default-directory)
2408 (with-parsed-tramp-file-name default-directory nil
2409 (mapconcat
2410 'identity
2411 (tramp-get-remote-path v)
2412 ":"))
2413 (getenv "PATH"))))
2414
2415(eval-after-load "esh-util"
2416 '(progn
2417 (tramp-eshell-directory-change)
2418 (add-hook 'eshell-directory-change-hook
2419 'tramp-eshell-directory-change)
2420 (add-hook 'tramp-unload-hook
2421 (lambda ()
2422 (remove-hook 'eshell-directory-change-hook
2423 'tramp-eshell-directory-change)))))
2424
2425
fb7933a3
KG
2426;;; File Name Handler Functions:
2427
fb7933a3
KG
2428(defun tramp-handle-make-symbolic-link
2429 (filename linkname &optional ok-if-already-exists)
00d6fd04 2430 "Like `make-symbolic-link' for Tramp files.
cebb4ec6 2431If LINKNAME is a non-Tramp file, it is used verbatim as the target of
7432277c 2432the symlink. If LINKNAME is a Tramp file, only the localname component is
cebb4ec6
KG
2433used as the target of the symlink.
2434
7432277c
KG
2435If LINKNAME is a Tramp file and the localname component is relative, then
2436it is expanded first, before the localname component is taken. Note that
cebb4ec6
KG
2437this can give surprising results if the user/host for the source and
2438target of the symlink differ."
c62c9d08 2439 (with-parsed-tramp-file-name linkname l
00d6fd04 2440 (let ((ln (tramp-get-remote-ln l))
87bdd2c7
MA
2441 (cwd (tramp-run-real-handler
2442 'file-name-directory (list l-localname))))
c62c9d08 2443 (unless ln
00d6fd04
MA
2444 (tramp-error
2445 l 'file-error
2446 "Making a symbolic link. ln(1) does not exist on the remote host."))
c62c9d08
KG
2447
2448 ;; Do the 'confirm if exists' thing.
cebb4ec6 2449 (when (file-exists-p linkname)
c62c9d08
KG
2450 ;; What to do?
2451 (if (or (null ok-if-already-exists) ; not allowed to exist
2452 (and (numberp ok-if-already-exists)
2453 (not (yes-or-no-p
2454 (format
2455 "File %s already exists; make it a link anyway? "
7432277c 2456 l-localname)))))
00d6fd04
MA
2457 (tramp-error
2458 l 'file-already-exists "File %s already exists" l-localname)
cebb4ec6
KG
2459 (delete-file linkname)))
2460
7432277c 2461 ;; If FILENAME is a Tramp name, use just the localname component.
cebb4ec6 2462 (when (tramp-tramp-file-p filename)
1834b39f
MA
2463 (setq filename
2464 (tramp-file-name-localname
2465 (tramp-dissect-file-name (expand-file-name filename)))))
bf247b6e 2466
c62c9d08
KG
2467 ;; Right, they are on the same host, regardless of user, method, etc.
2468 ;; We now make the link on the remote machine. This will occur as the user
2469 ;; that FILENAME belongs to.
2470 (zerop
2471 (tramp-send-command-and-check
b593f105
MA
2472 l
2473 (format
2474 "cd %s && %s -sf %s %s"
2475 (tramp-shell-quote-argument cwd)
2476 ln
2477 (tramp-shell-quote-argument filename)
2478 (tramp-shell-quote-argument l-localname))
2479 t)))))
fb7933a3 2480
fb7933a3 2481(defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix)
00d6fd04
MA
2482 "Like `load' for Tramp files."
2483 (with-parsed-tramp-file-name (expand-file-name file) nil
c62c9d08
KG
2484 (unless nosuffix
2485 (cond ((file-exists-p (concat file ".elc"))
2486 (setq file (concat file ".elc")))
2487 ((file-exists-p (concat file ".el"))
2488 (setq file (concat file ".el")))))
2489 (when must-suffix
2490 ;; The first condition is always true for absolute file names.
2491 ;; Included for safety's sake.
2492 (unless (or (file-name-directory file)
2493 (string-match "\\.elc?\\'" file))
00d6fd04
MA
2494 (tramp-error
2495 v 'file-error
2496 "File `%s' does not include a `.el' or `.elc' suffix" file)))
c62c9d08
KG
2497 (unless noerror
2498 (when (not (file-exists-p file))
00d6fd04 2499 (tramp-error v 'file-error "Cannot load nonexistent file `%s'" file)))
c62c9d08
KG
2500 (if (not (file-exists-p file))
2501 nil
00d6fd04 2502 (unless nomessage (tramp-message v 0 "Loading %s..." file))
c62c9d08
KG
2503 (let ((local-copy (file-local-copy file)))
2504 ;; MUST-SUFFIX doesn't exist on XEmacs, so let it default to nil.
ce2cc728
MA
2505 (unwind-protect
2506 (load local-copy noerror t t)
2507 (delete-file local-copy)))
00d6fd04 2508 (unless nomessage (tramp-message v 0 "Loading %s...done" file))
c62c9d08 2509 t)))
fb7933a3 2510
a4aeb9a4 2511;; Localname manipulation functions that grok Tramp localnames...
c0fc6170
MA
2512(defun tramp-handle-file-name-as-directory (file)
2513 "Like `file-name-as-directory' but aware of Tramp files."
2514 ;; `file-name-as-directory' would be sufficient except localname is
2515 ;; the empty string.
2516 (let ((v (tramp-dissect-file-name file t)))
2517 ;; Run the command on the localname portion only.
2518 (tramp-make-tramp-file-name
2519 (tramp-file-name-method v)
2520 (tramp-file-name-user v)
2521 (tramp-file-name-host v)
2522 (tramp-run-real-handler
2523 'file-name-as-directory (list (or (tramp-file-name-localname v) ""))))))
2524
fb7933a3 2525(defun tramp-handle-file-name-directory (file)
00d6fd04 2526 "Like `file-name-directory' but aware of Tramp files."
9ce8462a
MA
2527 ;; Everything except the last filename thing is the directory. We
2528 ;; cannot apply `with-parsed-tramp-file-name', because this expands
2529 ;; the remote file name parts. This is a problem when we are in
2530 ;; file name completion.
2531 (let ((v (tramp-dissect-file-name file t)))
a01b1e22
MA
2532 ;; Run the command on the localname portion only.
2533 (tramp-make-tramp-file-name
9ce8462a
MA
2534 (tramp-file-name-method v)
2535 (tramp-file-name-user v)
2536 (tramp-file-name-host v)
87bdd2c7
MA
2537 (tramp-run-real-handler
2538 'file-name-directory (list (or (tramp-file-name-localname v) ""))))))
fb7933a3
KG
2539
2540(defun tramp-handle-file-name-nondirectory (file)
00d6fd04 2541 "Like `file-name-nondirectory' but aware of Tramp files."
c62c9d08 2542 (with-parsed-tramp-file-name file nil
87bdd2c7 2543 (tramp-run-real-handler 'file-name-nondirectory (list localname))))
fb7933a3
KG
2544
2545(defun tramp-handle-file-truename (filename &optional counter prev-dirs)
00d6fd04 2546 "Like `file-truename' for Tramp files."
48ddd622 2547 (with-parsed-tramp-file-name (expand-file-name filename) nil
00d6fd04 2548 (with-file-property v localname "file-truename"
293c24f9 2549 (let ((result nil)) ; result steps in reverse order
00d6fd04 2550 (tramp-message v 4 "Finding true name for `%s'" filename)
293c24f9
MA
2551 (cond
2552 ;; Use GNU readlink --canonicalize-missing where available.
2553 ((tramp-get-remote-readlink v)
2554 (setq result
2555 (tramp-send-command-and-read
2556 v
2557 (format "echo \"\\\"`%s --canonicalize-missing %s`\\\"\""
2558 (tramp-get-remote-readlink v)
2559 (tramp-shell-quote-argument localname)))))
2560
2561 ;; Use Perl implementation.
2562 ((and (tramp-get-remote-perl v)
2563 (tramp-get-connection-property v "perl-file-spec" nil)
2564 (tramp-get-connection-property v "perl-cwd-realpath" nil))
2565 (tramp-maybe-send-script
2566 v tramp-perl-file-truename "tramp_perl_file_truename")
2567 (setq result
2568 (tramp-send-command-and-read
2569 v
2570 (format "tramp_perl_file_truename %s"
2571 (tramp-shell-quote-argument localname)))))
2572
2573 ;; Do it yourself. We bind `directory-sep-char' here for
2574 ;; XEmacs on Windows, which would otherwise use backslash.
2575 (t (let* ((directory-sep-char ?/)
2576 (steps (tramp-compat-split-string localname "/"))
2577 (localnamedir (tramp-run-real-handler
2578 'file-name-as-directory (list localname)))
2579 (is-dir (string= localname localnamedir))
2580 (thisstep nil)
2581 (numchase 0)
2582 ;; Don't make the following value larger than
2583 ;; necessary. People expect an error message in a
2584 ;; timely fashion when something is wrong;
2585 ;; otherwise they might think that Emacs is hung.
2586 ;; Of course, correctness has to come first.
2587 (numchase-limit 20)
2588 symlink-target)
2589 (while (and steps (< numchase numchase-limit))
2590 (setq thisstep (pop steps))
2591 (tramp-message
2592 v 5 "Check %s"
2593 (mapconcat 'identity
2594 (append '("") (reverse result) (list thisstep))
2595 "/"))
2596 (setq symlink-target
2597 (nth 0 (file-attributes
2598 (tramp-make-tramp-file-name
2599 method user host
2600 (mapconcat 'identity
2601 (append '("")
2602 (reverse result)
2603 (list thisstep))
2604 "/")))))
2605 (cond ((string= "." thisstep)
2606 (tramp-message v 5 "Ignoring step `.'"))
2607 ((string= ".." thisstep)
2608 (tramp-message v 5 "Processing step `..'")
2609 (pop result))
2610 ((stringp symlink-target)
2611 ;; It's a symlink, follow it.
2612 (tramp-message v 5 "Follow symlink to %s" symlink-target)
2613 (setq numchase (1+ numchase))
2614 (when (file-name-absolute-p symlink-target)
2615 (setq result nil))
2616 ;; If the symlink was absolute, we'll get a string like
2617 ;; "/user@host:/some/target"; extract the
2618 ;; "/some/target" part from it.
2619 (when (tramp-tramp-file-p symlink-target)
2620 (unless (tramp-equal-remote filename symlink-target)
2621 (tramp-error
2622 v 'file-error
2623 "Symlink target `%s' on wrong host" symlink-target))
2624 (setq symlink-target localname))
2625 (setq steps
2626 (append (tramp-compat-split-string
2627 symlink-target "/")
2628 steps)))
2629 (t
2630 ;; It's a file.
2631 (setq result (cons thisstep result)))))
2632 (when (>= numchase numchase-limit)
2633 (tramp-error
2634 v 'file-error
2635 "Maximum number (%d) of symlinks exceeded" numchase-limit))
2636 (setq result (reverse result))
2637 ;; Combine list to form string.
2638 (setq result
2639 (if result
2640 (mapconcat 'identity (cons "" result) "/")
00d6fd04 2641 "/"))
293c24f9
MA
2642 (when (and is-dir (or (string= "" result)
2643 (not (string= (substring result -1) "/"))))
2644 (setq result (concat result "/"))))))
2645
2646 (tramp-message v 4 "True name of `%s' is `%s'" filename result)
2647 (tramp-make-tramp-file-name method user host result)))))
fb7933a3
KG
2648
2649;; Basic functions.
2650
2651(defun tramp-handle-file-exists-p (filename)
00d6fd04 2652 "Like `file-exists-p' for Tramp files."
c62c9d08 2653 (with-parsed-tramp-file-name filename nil
00d6fd04 2654 (with-file-property v localname "file-exists-p"
293c24f9
MA
2655 (or (not (null (tramp-get-file-property
2656 v localname "file-attributes-integer" nil)))
2657 (not (null (tramp-get-file-property
2658 v localname "file-attributes-string" nil)))
2659 (zerop (tramp-send-command-and-check
2660 v
2661 (format
2662 "%s %s"
2663 (tramp-get-file-exists-command v)
2664 (tramp-shell-quote-argument localname))))))))
fb7933a3 2665
00d6fd04
MA
2666;; Inodes don't exist for some file systems. Therefore we must
2667;; generate virtual ones. Used in `find-buffer-visiting'. The method
2668;; applied might be not so efficient (Ange-FTP uses hashes). But
2669;; performance isn't the major issue given that file transfer will
2670;; take time.
2671(defvar tramp-inodes nil
2672 "Keeps virtual inodes numbers.")
2673
8daea7fc
KG
2674;; Devices must distinguish physical file systems. The device numbers
2675;; provided by "lstat" aren't unique, because we operate on different hosts.
2676;; So we use virtual device numbers, generated by Tramp. Both Ange-FTP and
2677;; EFS use device number "-1". In order to be different, we use device number
b946a456 2678;; (-1 . x), whereby "x" is unique for a given (method user host).
8daea7fc
KG
2679(defvar tramp-devices nil
2680 "Keeps virtual device numbers.")
2681
fb7933a3
KG
2682;; CCC: This should check for an error condition and signal failure
2683;; when something goes wrong.
2684;; Daniel Pittman <daniel@danann.net>
c951aecb 2685(defun tramp-handle-file-attributes (filename &optional id-format)
00d6fd04
MA
2686 "Like `file-attributes' for Tramp files."
2687 (unless id-format (setq id-format 'integer))
aa485f7c
MA
2688 ;; Don't modify `last-coding-system-used' by accident.
2689 (let ((last-coding-system-used last-coding-system-used))
2690 (with-parsed-tramp-file-name (expand-file-name filename) nil
2691 (with-file-property v localname (format "file-attributes-%s" id-format)
7f49fe46
MA
2692 (save-excursion
2693 (tramp-convert-file-attributes
2694 v
2695 (cond
2696 ((tramp-get-remote-stat v)
2697 (tramp-do-file-attributes-with-stat v localname id-format))
2698 ((tramp-get-remote-perl v)
2699 (tramp-do-file-attributes-with-perl v localname id-format))
2700 (t
2701 (tramp-do-file-attributes-with-ls v localname id-format)))))))))
2702
2703(defun tramp-do-file-attributes-with-ls (vec localname &optional id-format)
00d6fd04 2704 "Implement `file-attributes' for Tramp files using the ls(1) command."
fb7933a3
KG
2705 (let (symlinkp dirp
2706 res-inode res-filemodes res-numlinks
2707 res-uid res-gid res-size res-symlink-target)
00d6fd04 2708 (tramp-message vec 5 "file attributes with ls: %s" localname)
fb7933a3 2709 (tramp-send-command
00d6fd04 2710 vec
680db9ac
MA
2711 (format "(%s %s || %s -h %s) && %s %s %s"
2712 (tramp-get-file-exists-command vec)
2713 (tramp-shell-quote-argument localname)
2714 (tramp-get-test-command vec)
2715 (tramp-shell-quote-argument localname)
00d6fd04 2716 (tramp-get-ls-command vec)
c82c5727 2717 (if (eq id-format 'integer) "-ildn" "-ild")
7432277c 2718 (tramp-shell-quote-argument localname)))
fb7933a3 2719 ;; parse `ls -l' output ...
00d6fd04 2720 (with-current-buffer (tramp-get-buffer vec)
680db9ac
MA
2721 (when (> (buffer-size) 0)
2722 (goto-char (point-min))
2723 ;; ... inode
2724 (setq res-inode
2725 (condition-case err
2726 (read (current-buffer))
2727 (invalid-read-syntax
2728 (when (and (equal (cadr err)
2729 "Integer constant overflow in reader")
2730 (string-match
2731 "^[0-9]+\\([0-9][0-9][0-9][0-9][0-9]\\)\\'"
2732 (car (cddr err))))
2733 (let* ((big (read (substring (car (cddr err)) 0
2734 (match-beginning 1))))
2735 (small (read (match-string 1 (car (cddr err)))))
2736 (twiddle (/ small 65536)))
2737 (cons (+ big twiddle)
2738 (- small (* twiddle 65536))))))))
2739 ;; ... file mode flags
2740 (setq res-filemodes (symbol-name (read (current-buffer))))
2741 ;; ... number links
2742 (setq res-numlinks (read (current-buffer)))
2743 ;; ... uid and gid
2744 (setq res-uid (read (current-buffer)))
2745 (setq res-gid (read (current-buffer)))
2746 (if (eq id-format 'integer)
2747 (progn
2748 (unless (numberp res-uid) (setq res-uid -1))
2749 (unless (numberp res-gid) (setq res-gid -1)))
2750 (progn
2751 (unless (stringp res-uid) (setq res-uid (symbol-name res-uid)))
2752 (unless (stringp res-gid) (setq res-gid (symbol-name res-gid)))))
2753 ;; ... size
2754 (setq res-size (read (current-buffer)))
2755 ;; From the file modes, figure out other stuff.
2756 (setq symlinkp (eq ?l (aref res-filemodes 0)))
2757 (setq dirp (eq ?d (aref res-filemodes 0)))
2758 ;; if symlink, find out file name pointed to
2759 (when symlinkp
2760 (search-forward "-> ")
2761 (setq res-symlink-target
2762 (buffer-substring (point) (tramp-compat-line-end-position))))
2763 ;; return data gathered
2764 (list
2765 ;; 0. t for directory, string (name linked to) for symbolic
2766 ;; link, or nil.
2767 (or dirp res-symlink-target)
2768 ;; 1. Number of links to file.
2769 res-numlinks
2770 ;; 2. File uid.
2771 res-uid
2772 ;; 3. File gid.
2773 res-gid
2774 ;; 4. Last access time, as a list of two integers. First
2775 ;; integer has high-order 16 bits of time, second has low 16
2776 ;; bits.
2777 ;; 5. Last modification time, likewise.
2778 ;; 6. Last status change time, likewise.
2779 '(0 0) '(0 0) '(0 0) ;CCC how to find out?
2780 ;; 7. Size in bytes (-1, if number is out of range).
2781 res-size
2782 ;; 8. File modes, as a string of ten letters or dashes as in ls -l.
2783 res-filemodes
2784 ;; 9. t if file's gid would change if file were deleted and
2785 ;; recreated. Will be set in `tramp-convert-file-attributes'
2786 t
2787 ;; 10. inode number.
2788 res-inode
2789 ;; 11. Device number. Will be replaced by a virtual device number.
2790 -1
2791 )))))
fb7933a3 2792
7f49fe46 2793(defun tramp-do-file-attributes-with-perl
00d6fd04
MA
2794 (vec localname &optional id-format)
2795 "Implement `file-attributes' for Tramp files using a Perl script."
2796 (tramp-message vec 5 "file attributes with perl: %s" localname)
2797 (tramp-maybe-send-script
2798 vec tramp-perl-file-attributes "tramp_perl_file_attributes")
2799 (tramp-send-command-and-read
2800 vec
2801 (format "tramp_perl_file_attributes %s %s"
2802 (tramp-shell-quote-argument localname) id-format)))
2803
7f49fe46 2804(defun tramp-do-file-attributes-with-stat
00d6fd04
MA
2805 (vec localname &optional id-format)
2806 "Implement `file-attributes' for Tramp files using stat(1) command."
2807 (tramp-message vec 5 "file attributes with stat: %s" localname)
2808 (tramp-send-command-and-read
2809 vec
2810 (format
680db9ac
MA
2811 "((%s %s || %s -h %s) && %s -c '((\"%%N\") %%h %s %s %%X.0 %%Y.0 %%Z.0 %%s.0 \"%%A\" t %%i.0 -1)' %s || echo nil)"
2812 (tramp-get-file-exists-command vec)
2813 (tramp-shell-quote-argument localname)
2814 (tramp-get-test-command vec)
2815 (tramp-shell-quote-argument localname)
00d6fd04
MA
2816 (tramp-get-remote-stat vec)
2817 (if (eq id-format 'integer) "%u" "\"%U\"")
2818 (if (eq id-format 'integer) "%g" "\"%G\"")
2819 (tramp-shell-quote-argument localname))))
8daea7fc 2820
fb7933a3 2821(defun tramp-handle-set-visited-file-modtime (&optional time-list)
00d6fd04 2822 "Like `set-visited-file-modtime' for Tramp files."
fb7933a3
KG
2823 (unless (buffer-file-name)
2824 (error "Can't set-visited-file-modtime: buffer `%s' not visiting a file"
2825 (buffer-name)))
48ddd622
MA
2826 (if time-list
2827 (tramp-run-real-handler 'set-visited-file-modtime (list time-list))
11948172
MA
2828 (let ((f (buffer-file-name))
2829 coding-system-used)
48ddd622
MA
2830 (with-parsed-tramp-file-name f nil
2831 (let* ((attr (file-attributes f))
2832 ;; '(-1 65535) means file doesn't exists yet.
2833 (modtime (or (nth 5 attr) '(-1 65535))))
11948172
MA
2834 (when (boundp 'last-coding-system-used)
2835 (setq coding-system-used (symbol-value 'last-coding-system-used)))
48ddd622 2836 ;; We use '(0 0) as a don't-know value. See also
7f49fe46 2837 ;; `tramp-do-file-attributes-with-ls'.
48ddd622
MA
2838 (if (not (equal modtime '(0 0)))
2839 (tramp-run-real-handler 'set-visited-file-modtime (list modtime))
00d6fd04 2840 (progn
48ddd622 2841 (tramp-send-command
00d6fd04 2842 v
48ddd622 2843 (format "%s -ild %s"
00d6fd04 2844 (tramp-get-ls-command v)
48ddd622 2845 (tramp-shell-quote-argument localname)))
48ddd622
MA
2846 (setq attr (buffer-substring (point)
2847 (progn (end-of-line) (point)))))
00d6fd04
MA
2848 (tramp-set-file-property
2849 v localname "visited-file-modtime-ild" attr))
11948172
MA
2850 (when (boundp 'last-coding-system-used)
2851 (set 'last-coding-system-used coding-system-used))
d2a2c17f 2852 nil)))))
fb7933a3 2853
c62c9d08
KG
2854;; This function makes the same assumption as
2855;; `tramp-handle-set-visited-file-modtime'.
2856(defun tramp-handle-verify-visited-file-modtime (buf)
00d6fd04 2857 "Like `verify-visited-file-modtime' for Tramp files.
c08e6004
MA
2858At the time `verify-visited-file-modtime' calls this function, we
2859already know that the buffer is visiting a file and that
2860`visited-file-modtime' does not return 0. Do not call this
2861function directly, unless those two cases are already taken care
2862of."
c62c9d08 2863 (with-current-buffer buf
b15d0c4c
MA
2864 ;; There is no file visiting the buffer, or the buffer has no
2865 ;; recorded last modification time.
2866 (if (or (not (buffer-file-name))
2867 (eq (visited-file-modtime) 0))
d2a2c17f 2868 t
b15d0c4c
MA
2869 (let ((f (buffer-file-name)))
2870 (with-parsed-tramp-file-name f nil
bce04fee 2871 (tramp-flush-file-property v localname)
b15d0c4c
MA
2872 (let* ((attr (file-attributes f))
2873 (modtime (nth 5 attr))
2874 (mt (visited-file-modtime)))
bf247b6e 2875
70c11b0b
MA
2876 (cond
2877 ;; File exists, and has a known modtime.
b15d0c4c
MA
2878 ((and attr (not (equal modtime '(0 0))))
2879 (< (abs (tramp-time-diff
2880 modtime
2881 ;; For compatibility, deal with both the old
70c11b0b
MA
2882 ;; (HIGH . LOW) and the new (HIGH LOW) return
2883 ;; values of `visited-file-modtime'.
b15d0c4c
MA
2884 (if (atom (cdr mt))
2885 (list (car mt) (cdr mt))
2886 mt)))
2887 2))
70c11b0b 2888 ;; Modtime has the don't know value.
b15d0c4c 2889 (attr
00d6fd04
MA
2890 (tramp-send-command
2891 v
2892 (format "%s -ild %s"
2893 (tramp-get-ls-command v)
2894 (tramp-shell-quote-argument localname)))
2895 (with-current-buffer (tramp-get-buffer v)
b15d0c4c
MA
2896 (setq attr (buffer-substring
2897 (point) (progn (end-of-line) (point)))))
00d6fd04
MA
2898 (equal
2899 attr
2900 (tramp-get-file-property
2901 v localname "visited-file-modtime-ild" "")))
70c11b0b
MA
2902 ;; If file does not exist, say it is not modified if and
2903 ;; only if that agrees with the buffer's record.
b15d0c4c 2904 (t (equal mt '(-1 65535))))))))))
c62c9d08 2905
fb7933a3 2906(defun tramp-handle-set-file-modes (filename mode)
00d6fd04 2907 "Like `set-file-modes' for Tramp files."
c62c9d08 2908 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2909 (tramp-flush-file-property v localname)
2910 (unless (zerop (tramp-send-command-and-check
2911 v
2912 (format "chmod %s %s"
2913 (tramp-decimal-to-octal mode)
2914 (tramp-shell-quote-argument localname))))
2915 ;; FIXME: extract the proper text from chmod's stderr.
2916 (tramp-error
2917 v 'file-error "Error while changing file's mode %s" filename))))
fb7933a3 2918
ce3f516f
MA
2919(defun tramp-handle-set-file-times (filename &optional time)
2920 "Like `set-file-times' for Tramp files."
2921 (zerop
9e6ab520 2922 (if (file-remote-p filename)
ce3f516f 2923 (with-parsed-tramp-file-name filename nil
8d60099b 2924 (tramp-flush-file-property v localname)
ce3f516f
MA
2925 (let ((time (if (or (null time) (equal time '(0 0)))
2926 (current-time)
2927 time))
2928 (utc
2929 ;; With GNU Emacs, `format-time-string' has an
2930 ;; optional parameter UNIVERSAL. This is preferred,
2931 ;; because we could handle the case when the remote
2932 ;; host is located in a different time zone as the
2933 ;; local host.
2934 (and (functionp 'subr-arity)
2935 (subrp (symbol-function 'format-time-string))
2936 (= 3 (cdr (funcall (symbol-function 'subr-arity)
2937 (symbol-function
2938 'format-time-string)))))))
2939 (tramp-send-command-and-check
2940 v (format "%s touch -t %s %s"
2941 (if utc "TZ=UTC; export TZ;" "")
2942 (if utc
2943 (format-time-string "%Y%m%d%H%M.%S" time t)
2944 (format-time-string "%Y%m%d%H%M.%S" time))
2945 (tramp-shell-quote-argument localname)))))
8d60099b 2946
ce3f516f
MA
2947 ;; We handle also the local part, because in older Emacsen,
2948 ;; without `set-file-times', this function is an alias for this.
2949 ;; We are local, so we don't need the UTC settings.
a4aeb9a4 2950 (tramp-local-call-process
ce3f516f
MA
2951 "touch" nil nil nil "-t"
2952 (format-time-string "%Y%m%d%H%M.%S" time)
2953 (tramp-shell-quote-argument filename)))))
2954
8d60099b
MA
2955(defun tramp-set-file-uid-gid (filename &optional uid gid)
2956 "Set the ownership for FILENAME.
2957If UID and GID are provided, these values are used; otherwise uid
2958and gid of the corresponding user is taken. Both parameters must be integers."
70c11b0b
MA
2959 ;; Modern Unices allow chown only for root. So we might need
2960 ;; another implementation, see `dired-do-chown'. OTOH, it is mostly
2961 ;; working with su(do)? when it is needed, so it shall succeed in
2962 ;; the majority of cases.
aa485f7c
MA
2963 ;; Don't modify `last-coding-system-used' by accident.
2964 (let ((last-coding-system-used last-coding-system-used))
2965 (if (file-remote-p filename)
2966 (with-parsed-tramp-file-name filename nil
2967 (if (and (zerop (user-uid)) (tramp-local-host-p v))
2968 ;; If we are root on the local host, we can do it directly.
2969 (tramp-set-file-uid-gid localname uid gid)
2970 (let ((uid (or (and (integerp uid) uid)
2971 (tramp-get-remote-uid v 'integer)))
2972 (gid (or (and (integerp gid) gid)
2973 (tramp-get-remote-gid v 'integer))))
2974 (tramp-send-command
2975 v (format
2976 "chown %d:%d %s" uid gid
2977 (tramp-shell-quote-argument localname))))))
2978
2979 ;; We handle also the local part, because there doesn't exist
2980 ;; `set-file-uid-gid'. On W32 "chown" might not work.
2981 (let ((uid (or (and (integerp uid) uid) (tramp-get-local-uid 'integer)))
2982 (gid (or (and (integerp gid) gid) (tramp-get-local-gid 'integer))))
2983 (tramp-local-call-process
2984 "chown" nil nil nil
2985 (format "%d:%d" uid gid) (tramp-shell-quote-argument filename))))))
8d60099b 2986
fb7933a3
KG
2987;; Simple functions using the `test' command.
2988
2989(defun tramp-handle-file-executable-p (filename)
00d6fd04 2990 "Like `file-executable-p' for Tramp files."
c62c9d08 2991 (with-parsed-tramp-file-name filename nil
00d6fd04 2992 (with-file-property v localname "file-executable-p"
293c24f9
MA
2993 ;; Examine `file-attributes' cache to see if request can be
2994 ;; satisfied without remote operation.
2995 (or (tramp-check-cached-permissions v ?x)
2996 (zerop (tramp-run-test "-x" filename))))))
fb7933a3
KG
2997
2998(defun tramp-handle-file-readable-p (filename)
00d6fd04 2999 "Like `file-readable-p' for Tramp files."
c62c9d08 3000 (with-parsed-tramp-file-name filename nil
00d6fd04 3001 (with-file-property v localname "file-readable-p"
293c24f9
MA
3002 ;; Examine `file-attributes' cache to see if request can be
3003 ;; satisfied without remote operation.
3004 (or (tramp-check-cached-permissions v ?r)
3005 (zerop (tramp-run-test "-r" filename))))))
fb7933a3
KG
3006
3007;; When the remote shell is started, it looks for a shell which groks
3008;; tilde expansion. Here, we assume that all shells which grok tilde
3009;; expansion will also provide a `test' command which groks `-nt' (for
3010;; newer than). If this breaks, tell me about it and I'll try to do
3011;; something smarter about it.
3012(defun tramp-handle-file-newer-than-file-p (file1 file2)
00d6fd04 3013 "Like `file-newer-than-file-p' for Tramp files."
fb7933a3
KG
3014 (cond ((not (file-exists-p file1))
3015 nil)
3016 ((not (file-exists-p file2))
3017 t)
91879624 3018 ;; We are sure both files exist at this point.
fb7933a3
KG
3019 (t
3020 (save-excursion
91879624
KG
3021 ;; We try to get the mtime of both files. If they are not
3022 ;; equal to the "dont-know" value, then we subtract the times
3023 ;; and obtain the result.
3024 (let ((fa1 (file-attributes file1))
3025 (fa2 (file-attributes file2)))
3026 (if (and (not (equal (nth 5 fa1) '(0 0)))
3027 (not (equal (nth 5 fa2) '(0 0))))
01917a18 3028 (> 0 (tramp-time-diff (nth 5 fa2) (nth 5 fa1)))
91879624
KG
3029 ;; If one of them is the dont-know value, then we can
3030 ;; still try to run a shell command on the remote host.
3031 ;; However, this only works if both files are Tramp
3032 ;; files and both have the same method, same user, same
3033 ;; host.
00d6fd04
MA
3034 (unless (tramp-equal-remote file1 file2)
3035 (with-parsed-tramp-file-name
3036 (if (tramp-tramp-file-p file1) file1 file2) nil
3037 (tramp-error
3038 v 'file-error
3039 "Files %s and %s must have same method, user, host"
3040 file1 file2)))
3041 (with-parsed-tramp-file-name file1 nil
3042 (zerop (tramp-run-test2
3043 (tramp-get-test-nt-command v) file1 file2)))))))))
fb7933a3
KG
3044
3045;; Functions implemented using the basic functions above.
3046
3047(defun tramp-handle-file-modes (filename)
00d6fd04 3048 "Like `file-modes' for Tramp files."
5da24108
MA
3049 (let ((truename (or (file-truename filename) filename)))
3050 (when (file-exists-p truename)
3051 (tramp-mode-string-to-int (nth 8 (file-attributes truename))))))
fb7933a3 3052
b86c1cd8
MA
3053(defun tramp-default-file-modes (filename)
3054 "Return file modes of FILENAME as integer.
3055If the file modes of FILENAME cannot be determined, return the
974647ac
MA
3056value of `default-file-modes', without execute permissions."
3057 (or (file-modes filename)
3058 (logand (default-file-modes) (tramp-octal-to-decimal "0666"))))
b86c1cd8 3059
fb7933a3 3060(defun tramp-handle-file-directory-p (filename)
00d6fd04 3061 "Like `file-directory-p' for Tramp files."
fb7933a3
KG
3062 ;; Care must be taken that this function returns `t' for symlinks
3063 ;; pointing to directories. Surely the most obvious implementation
3064 ;; would be `test -d', but that returns false for such symlinks.
3065 ;; CCC: Stefan Monnier says that `test -d' follows symlinks. And
3066 ;; I now think he's right. So we could be using `test -d', couldn't
3067 ;; we?
3068 ;;
3069 ;; Alternatives: `cd %s', `test -d %s'
c62c9d08 3070 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3071 (with-file-property v localname "file-directory-p"
3072 (zerop (tramp-run-test "-d" filename)))))
fb7933a3
KG
3073
3074(defun tramp-handle-file-regular-p (filename)
00d6fd04
MA
3075 "Like `file-regular-p' for Tramp files."
3076 (and (file-exists-p filename)
3077 (eq ?- (aref (nth 8 (file-attributes filename)) 0))))
fb7933a3
KG
3078
3079(defun tramp-handle-file-symlink-p (filename)
00d6fd04 3080 "Like `file-symlink-p' for Tramp files."
c62c9d08 3081 (with-parsed-tramp-file-name filename nil
c951aecb 3082 (let ((x (car (file-attributes filename))))
b25a52cc
KG
3083 (when (stringp x)
3084 ;; When Tramp is running on VMS, then `file-name-absolute-p'
3085 ;; might do weird things.
3086 (if (file-name-absolute-p x)
00d6fd04 3087 (tramp-make-tramp-file-name method user host x)
b25a52cc 3088 x)))))
fb7933a3
KG
3089
3090(defun tramp-handle-file-writable-p (filename)
00d6fd04 3091 "Like `file-writable-p' for Tramp files."
c62c9d08 3092 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3093 (with-file-property v localname "file-writable-p"
3094 (if (file-exists-p filename)
293c24f9
MA
3095 ;; Examine `file-attributes' cache to see if request can be
3096 ;; satisfied without remote operation.
3097 (or (tramp-check-cached-permissions v ?w)
3098 (zerop (tramp-run-test "-w" filename)))
00d6fd04
MA
3099 ;; If file doesn't exist, check if directory is writable.
3100 (and (zerop (tramp-run-test
3101 "-d" (file-name-directory filename)))
3102 (zerop (tramp-run-test
3103 "-w" (file-name-directory filename))))))))
fb7933a3
KG
3104
3105(defun tramp-handle-file-ownership-preserved-p (filename)
00d6fd04 3106 "Like `file-ownership-preserved-p' for Tramp files."
c62c9d08 3107 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3108 (with-file-property v localname "file-ownership-preserved-p"
3109 (let ((attributes (file-attributes filename)))
3110 ;; Return t if the file doesn't exist, since it's true that no
3111 ;; information would be lost by an (attempted) delete and create.
3112 (or (null attributes)
3113 (= (nth 2 attributes) (tramp-get-remote-uid v 'integer)))))))
fb7933a3
KG
3114
3115;; Other file name ops.
3116
fb7933a3 3117(defun tramp-handle-directory-file-name (directory)
00d6fd04 3118 "Like `directory-file-name' for Tramp files."
7432277c
KG
3119 ;; If localname component of filename is "/", leave it unchanged.
3120 ;; Otherwise, remove any trailing slash from localname component.
8daea7fc
KG
3121 ;; Method, host, etc, are unchanged. Does it make sense to try
3122 ;; to avoid parsing the filename?
c62c9d08 3123 (with-parsed-tramp-file-name directory nil
7432277c
KG
3124 (if (and (not (zerop (length localname)))
3125 (eq (aref localname (1- (length localname))) ?/)
3126 (not (string= localname "/")))
8daea7fc
KG
3127 (substring directory 0 -1)
3128 directory)))
fb7933a3
KG
3129
3130;; Directory listings.
3131
00d6fd04
MA
3132(defun tramp-handle-directory-files
3133 (directory &optional full match nosort files-only)
3134 "Like `directory-files' for Tramp files."
3135 ;; FILES-ONLY is valid for XEmacs only.
3136 (when (file-directory-p directory)
3137 (setq directory (expand-file-name directory))
3138 (let ((temp (nreverse (file-name-all-completions "" directory)))
3139 result item)
3140
3141 (while temp
3142 (setq item (directory-file-name (pop temp)))
3143 (when (and (or (null match) (string-match match item))
3144 (or (null files-only)
3145 ;; files only
3146 (and (equal files-only t) (file-regular-p item))
3147 ;; directories only
3148 (file-directory-p item)))
3149 (push (if full (expand-file-name item directory) item)
3150 result)))
c62c9d08
KG
3151 result)))
3152
c82c5727
LH
3153(defun tramp-handle-directory-files-and-attributes
3154 (directory &optional full match nosort id-format)
00d6fd04
MA
3155 "Like `directory-files-and-attributes' for Tramp files."
3156 (unless id-format (setq id-format 'integer))
3157 (when (file-directory-p directory)
3158 (setq directory (expand-file-name directory))
3159 (let* ((temp
9e6ab520 3160 (tramp-compat-copy-tree
00d6fd04
MA
3161 (with-parsed-tramp-file-name directory nil
3162 (with-file-property
3163 v localname
3164 (format "directory-files-and-attributes-%s" id-format)
3165 (save-excursion
3166 (mapcar
aa485f7c
MA
3167 (lambda (x)
3168 (cons (car x)
3169 (tramp-convert-file-attributes v (cdr x))))
7f49fe46
MA
3170 (cond
3171 ((tramp-get-remote-stat v)
3172 (tramp-do-directory-files-and-attributes-with-stat
3173 v localname id-format))
3174 ((tramp-get-remote-perl v)
3175 (tramp-do-directory-files-and-attributes-with-perl
3176 v localname id-format)))))))))
00d6fd04
MA
3177 result item)
3178
3179 (while temp
3180 (setq item (pop temp))
3181 (when (or (null match) (string-match match (car item)))
3182 (when full
3183 (setcar item (expand-file-name (car item) directory)))
3184 (push item result)))
3185
3186 (if nosort
3187 result
3188 (sort result (lambda (x y) (string< (car x) (car y))))))))
3189
7f49fe46 3190(defun tramp-do-directory-files-and-attributes-with-perl
00d6fd04
MA
3191 (vec localname &optional id-format)
3192 "Implement `directory-files-and-attributes' for Tramp files using a Perl script."
3193 (tramp-message vec 5 "directory-files-and-attributes with perl: %s" localname)
3194 (tramp-maybe-send-script
3195 vec tramp-perl-directory-files-and-attributes
3196 "tramp_perl_directory_files_and_attributes")
3197 (let ((object
3198 (tramp-send-command-and-read
3199 vec
3200 (format "tramp_perl_directory_files_and_attributes %s %s"
3201 (tramp-shell-quote-argument localname) id-format))))
3202 (when (stringp object) (tramp-error vec 'file-error object))
3203 object))
3204
7f49fe46 3205(defun tramp-do-directory-files-and-attributes-with-stat
00d6fd04
MA
3206 (vec localname &optional id-format)
3207 "Implement `directory-files-and-attributes' for Tramp files using stat(1) command."
3208 (tramp-message vec 5 "directory-files-and-attributes with stat: %s" localname)
3209 (tramp-send-command-and-read
3210 vec
3211 (format
3212 (concat
70c11b0b
MA
3213 ;; We must care about filenames with spaces, or starting with
3214 ;; "-"; this would confuse xargs. "ls -aQ" might be a solution,
3215 ;; but it does not work on all remote systems. Therefore, we
3216 ;; quote the filenames via sed.
3217 "cd %s; echo \"(\"; (%s -a | sed -e s/\\$/\\\"/g -e s/^/\\\"/g | xargs "
d4443a0d 3218 "%s -c '(\"%%n\" (\"%%N\") %%h %s %s %%X.0 %%Y.0 %%Z.0 %%s.0 \"%%A\" t %%i.0 -1)'); "
00d6fd04
MA
3219 "echo \")\"")
3220 (tramp-shell-quote-argument localname)
3221 (tramp-get-ls-command vec)
3222 (tramp-get-remote-stat vec)
3223 (if (eq id-format 'integer) "%u" "\"%U\"")
3224 (if (eq id-format 'integer) "%g" "\"%G\""))))
c82c5727 3225
c62c9d08 3226;; This function should return "foo/" for directories and "bar" for
00d6fd04 3227;; files.
c62c9d08 3228(defun tramp-handle-file-name-all-completions (filename directory)
00d6fd04
MA
3229 "Like `file-name-all-completions' for Tramp files."
3230 (unless (save-match-data (string-match "/" filename))
9c13938d 3231 (with-parsed-tramp-file-name (expand-file-name directory) nil
b50dd0d2 3232
00d6fd04
MA
3233 (all-completions
3234 filename
3235 (mapcar
3236 'list
293c24f9
MA
3237 (or
3238 ;; Try cache first
3239 (and
3240 ;; Ignore if expired
3241 (or (not (integerp tramp-completion-reread-directory-timeout))
3242 (<= (tramp-time-diff
3243 (current-time)
3244 (tramp-get-file-property
3245 v localname "last-completion" '(0 0 0)))
3246 tramp-completion-reread-directory-timeout))
3247
3248 ;; Try cache entries for filename, filename with last
3249 ;; character removed, filename with last two characters
3250 ;; removed, ..., and finally the empty string - all
3251 ;; concatenated to the local directory name
3252
3253 ;; This is inefficient for very long filenames, pity
3254 ;; `reduce' is not available...
3255 (car
3256 (apply
3257 'append
3258 (mapcar
3259 (lambda (x)
3260 (let ((cache-hit
3261 (tramp-get-file-property
3262 v
3263 (concat localname (substring filename 0 x))
3264 "file-name-all-completions"
3265 nil)))
3266 (when cache-hit (list cache-hit))))
3267 (tramp-compat-number-sequence (length filename) 0 -1)))))
3268
3269 ;; Cache expired or no matching cache entry found so we need
3270 ;; to perform a remote operation
3271 (let (result)
3272 ;; Get a list of directories and files, including reliably
3273 ;; tagging the directories with a trailing '/'. Because I
3274 ;; rock. --daniel@danann.net
3275
3276 ;; Changed to perform `cd' in the same remote op and only
3277 ;; get entries starting with `filename'. Capture any `cd'
3278 ;; error messages. Ensure any `cd' and `echo' aliases are
3279 ;; ignored.
3280 (tramp-send-command
3281 v
3282 (if (tramp-get-remote-perl v)
3283 (progn
3284 (tramp-maybe-send-script
3285 v tramp-perl-file-name-all-completions
3286 "tramp_perl_file_name_all_completions")
3287 (format "tramp_perl_file_name_all_completions %s %s %d"
3288 (tramp-shell-quote-argument localname)
3289 (tramp-shell-quote-argument filename)
3290 (if (symbol-value
3291 'read-file-name-completion-ignore-case)
3292 1 0)))
3293
3294 (format (concat
3295 "(\\cd %s 2>&1 && (%s %s -a 2>/dev/null"
3296 ;; `ls' with wildcard might fail with `Argument
3297 ;; list too long' error in some corner cases; if
3298 ;; `ls' fails after `cd' succeeded, chances are
3299 ;; that's the case, so let's retry without
3300 ;; wildcard. This will return "too many" entries
3301 ;; but that isn't harmful.
3302 " || %s -a 2>/dev/null)"
3303 " | while read f; do"
3304 " if %s -d \"$f\" 2>/dev/null;"
3305 " then \\echo \"$f/\"; else \\echo \"$f\"; fi; done"
3306 " && \\echo ok) || \\echo fail")
3307 (tramp-shell-quote-argument localname)
3308 (tramp-get-ls-command v)
3309 ;; When `filename' is empty, just `ls' without
3310 ;; filename argument is more efficient than `ls *'
3311 ;; for very large directories and might avoid the
3312 ;; `Argument list too long' error.
3313 ;;
3314 ;; With and only with wildcard, we need to add
3315 ;; `-d' to prevent `ls' from descending into
3316 ;; sub-directories.
3317 (if (zerop (length filename))
3318 "."
3319 (concat (tramp-shell-quote-argument filename) "* -d"))
3320 (tramp-get-ls-command v)
3321 (tramp-get-test-command v))))
3322
3323 ;; Now grab the output.
3324 (with-current-buffer (tramp-get-buffer v)
3325 (goto-char (point-max))
3326
3327 ;; Check result code, found in last line of output
3328 (forward-line -1)
3329 (if (looking-at "^fail$")
3330 (progn
3331 ;; Grab error message from line before last line
3332 ;; (it was put there by `cd 2>&1')
3333 (forward-line -1)
3334 (tramp-error
3335 v 'file-error
3336 "tramp-handle-file-name-all-completions: %s"
3337 (buffer-substring
3338 (point) (tramp-compat-line-end-position))))
3339 ;; For peace of mind, if buffer doesn't end in `fail'
3340 ;; then it should end in `ok'. If neither are in the
3341 ;; buffer something went seriously wrong on the remote
3342 ;; side.
3343 (unless (looking-at "^ok$")
3344 (tramp-error
3345 v 'file-error
3346 "\
3347tramp-handle-file-name-all-completions: internal error accessing `%s': `%s'"
3348 (tramp-shell-quote-argument localname) (buffer-string))))
3349
3350 (while (zerop (forward-line -1))
3351 (push (buffer-substring
3352 (point) (tramp-compat-line-end-position))
3353 result)))
3354
3355 ;; Because the remote op went through OK we know the
3356 ;; directory we `cd'-ed to exists
3357 (tramp-set-file-property
3358 v localname "file-exists-p" t)
3359
3360 ;; Because the remote op went through OK we know every
3361 ;; file listed by `ls' exists.
3362 (mapc (lambda (entry)
3363 (tramp-set-file-property
3364 v (concat localname entry) "file-exists-p" t))
3365 result)
3366
3367 (tramp-set-file-property
3368 v localname "last-completion" (current-time))
3369
3370 ;; Store result in the cache
3371 (tramp-set-file-property
3372 v (concat localname filename)
3373 "file-name-all-completions"
3374 result))))))))
fb7933a3
KG
3375
3376;; The following isn't needed for Emacs 20 but for 19.34?
e1e17cae
MA
3377(defun tramp-handle-file-name-completion
3378 (filename directory &optional predicate)
00d6fd04 3379 "Like `file-name-completion' for Tramp files."
fb7933a3
KG
3380 (unless (tramp-tramp-file-p directory)
3381 (error
3382 "tramp-handle-file-name-completion invoked on non-tramp directory `%s'"
3383 directory))
83e20b5c
MA
3384 (try-completion
3385 filename
3386 (mapcar 'list (file-name-all-completions filename directory))
3387 (when predicate
3388 (lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
fb7933a3
KG
3389
3390;; cp, mv and ln
3391
3392(defun tramp-handle-add-name-to-file
3393 (filename newname &optional ok-if-already-exists)
00d6fd04
MA
3394 "Like `add-name-to-file' for Tramp files."
3395 (unless (tramp-equal-remote filename newname)
3396 (with-parsed-tramp-file-name
3397 (if (tramp-tramp-file-p filename) filename newname) nil
3398 (tramp-error
3399 v 'file-error
3400 "add-name-to-file: %s"
3401 "only implemented for same method, same user, same host")))
c62c9d08
KG
3402 (with-parsed-tramp-file-name filename v1
3403 (with-parsed-tramp-file-name newname v2
00d6fd04 3404 (let ((ln (when v1 (tramp-get-remote-ln v1))))
c62c9d08
KG
3405 (when (and (not ok-if-already-exists)
3406 (file-exists-p newname)
3407 (not (numberp ok-if-already-exists))
3408 (y-or-n-p
3409 (format
3410 "File %s already exists; make it a new name anyway? "
3411 newname)))
00d6fd04
MA
3412 (tramp-error
3413 v2 'file-error
3414 "add-name-to-file: file %s already exists" newname))
3415 (tramp-flush-file-property v2 v2-localname)
c62c9d08 3416 (tramp-barf-unless-okay
00d6fd04 3417 v1
7432277c
KG
3418 (format "%s %s %s" ln (tramp-shell-quote-argument v1-localname)
3419 (tramp-shell-quote-argument v2-localname))
c62c9d08
KG
3420 "error with add-name-to-file, see buffer `%s' for details"
3421 (buffer-name))))))
fb7933a3
KG
3422
3423(defun tramp-handle-copy-file
8d60099b 3424 (filename newname &optional ok-if-already-exists keep-date preserve-uid-gid)
00d6fd04 3425 "Like `copy-file' for Tramp files."
fb7933a3 3426 ;; Check if both files are local -- invoke normal copy-file.
9e6ab520 3427 ;; Otherwise, use Tramp from local system.
fb7933a3
KG
3428 (setq filename (expand-file-name filename))
3429 (setq newname (expand-file-name newname))
9e6ab520 3430 (cond
a4aeb9a4 3431 ;; At least one file a Tramp file?
9e6ab520
MA
3432 ((or (tramp-tramp-file-p filename)
3433 (tramp-tramp-file-p newname))
3434 (tramp-do-copy-or-rename-file
3435 'copy filename newname ok-if-already-exists keep-date preserve-uid-gid))
3436 ;; Compat section.
3437 (preserve-uid-gid
fb7933a3 3438 (tramp-run-real-handler
8d60099b 3439 'copy-file
9e6ab520
MA
3440 (list filename newname ok-if-already-exists keep-date preserve-uid-gid)))
3441 (t
3442 (tramp-run-real-handler
3443 'copy-file (list filename newname ok-if-already-exists keep-date)))))
fb7933a3 3444
263c02ef
MA
3445(defun tramp-handle-copy-directory (dirname newname &optional keep-date parents)
3446 "Like `copy-directory' for Tramp files."
3447 (let ((t1 (tramp-tramp-file-p dirname))
3448 (t2 (tramp-tramp-file-p newname)))
3449 (with-parsed-tramp-file-name (if t1 dirname newname) nil
3450 (if (and (tramp-get-method-parameter method 'tramp-copy-recursive)
3451 ;; When DIRNAME and NEWNAME are remote, they must have
3452 ;; the same method.
3453 (or (null t1) (null t2)
b000a6e2
MA
3454 (string-equal
3455 (tramp-file-name-method (tramp-dissect-file-name dirname))
3456 (tramp-file-name-method (tramp-dissect-file-name newname)))))
263c02ef
MA
3457 ;; scp or rsync DTRT.
3458 (progn
3459 (setq dirname (directory-file-name (expand-file-name dirname))
3460 newname (directory-file-name (expand-file-name newname)))
3461 (if (and (file-directory-p newname)
3462 (not (string-equal (file-name-nondirectory dirname)
3463 (file-name-nondirectory newname))))
3464 (setq newname
3465 (expand-file-name
3466 (file-name-nondirectory dirname) newname)))
3467 (if (not (file-directory-p (file-name-directory newname)))
3468 (make-directory (file-name-directory newname) parents))
3469 (tramp-do-copy-or-rename-file-out-of-band
3470 'copy dirname newname keep-date))
3471 ;; We must do it file-wise.
3472 (tramp-run-real-handler
3473 'copy-directory (list dirname newname keep-date parents))))))
3474
fb7933a3
KG
3475(defun tramp-handle-rename-file
3476 (filename newname &optional ok-if-already-exists)
00d6fd04 3477 "Like `rename-file' for Tramp files."
fb7933a3 3478 ;; Check if both files are local -- invoke normal rename-file.
a4aeb9a4 3479 ;; Otherwise, use Tramp from local system.
fb7933a3
KG
3480 (setq filename (expand-file-name filename))
3481 (setq newname (expand-file-name newname))
a4aeb9a4 3482 ;; At least one file a Tramp file?
fb7933a3
KG
3483 (if (or (tramp-tramp-file-p filename)
3484 (tramp-tramp-file-p newname))
3485 (tramp-do-copy-or-rename-file
8d60099b 3486 'rename filename newname ok-if-already-exists t t)
00d6fd04
MA
3487 (tramp-run-real-handler
3488 'rename-file (list filename newname ok-if-already-exists))))
fb7933a3
KG
3489
3490(defun tramp-do-copy-or-rename-file
8d60099b 3491 (op filename newname &optional ok-if-already-exists keep-date preserve-uid-gid)
fb7933a3
KG
3492 "Copy or rename a remote file.
3493OP must be `copy' or `rename' and indicates the operation to perform.
3494FILENAME specifies the file to copy or rename, NEWNAME is the name of
3495the new file (for copy) or the new name of the file (for rename).
3496OK-IF-ALREADY-EXISTS means don't barf if NEWNAME exists already.
3497KEEP-DATE means to make sure that NEWNAME has the same timestamp
8d60099b
MA
3498as FILENAME. PRESERVE-UID-GID, when non-nil, instructs to keep
3499the uid and gid if both files are on the same host.
fb7933a3
KG
3500
3501This function is invoked by `tramp-handle-copy-file' and
3502`tramp-handle-rename-file'. It is an error if OP is neither of `copy'
3503and `rename'. FILENAME and NEWNAME must be absolute file names."
3504 (unless (memq op '(copy rename))
3505 (error "Unknown operation `%s', must be `copy' or `rename'" op))
90dc758d 3506 (let ((t1 (tramp-tramp-file-p filename))
00d6fd04 3507 (t2 (tramp-tramp-file-p newname)))
5ec2cc41 3508
da1975d7
MA
3509 (when (and (not ok-if-already-exists) (file-exists-p newname))
3510 (with-parsed-tramp-file-name (if t1 filename newname) nil
3511 (tramp-error
3512 v 'file-already-exists "File %s already exists" newname)))
5ec2cc41 3513
905fb90e
MA
3514 (with-parsed-tramp-file-name (if t1 filename newname) nil
3515 (tramp-message v 0 "Transferring %s to %s..." filename newname))
3516
00d6fd04
MA
3517 (prog1
3518 (cond
3519 ;; Both are Tramp files.
3520 ((and t1 t2)
3521 (with-parsed-tramp-file-name filename v1
3522 (with-parsed-tramp-file-name newname v2
3523 (cond
3524 ;; Shortcut: if method, host, user are the same for both
3525 ;; files, we invoke `cp' or `mv' on the remote host
3526 ;; directly.
3527 ((tramp-equal-remote filename newname)
3528 (tramp-do-copy-or-rename-file-directly
8d60099b
MA
3529 op filename newname
3530 ok-if-already-exists keep-date preserve-uid-gid))
3531
905fb90e 3532 ;; Try out-of-band operation.
7f49fe46
MA
3533 ((tramp-method-out-of-band-p
3534 v1 (nth 7 (file-attributes filename)))
00d6fd04
MA
3535 (tramp-do-copy-or-rename-file-out-of-band
3536 op filename newname keep-date))
8d60099b 3537
00d6fd04
MA
3538 ;; No shortcut was possible. So we copy the
3539 ;; file first. If the operation was `rename', we go
3540 ;; back and delete the original file (if the copy was
3541 ;; successful). The approach is simple-minded: we
3542 ;; create a new buffer, insert the contents of the
3543 ;; source file into it, then write out the buffer to
3544 ;; the target file. The advantage is that it doesn't
3545 ;; matter which filename handlers are used for the
3546 ;; source and target file.
3547 (t
3548 (tramp-do-copy-or-rename-file-via-buffer
3549 op filename newname keep-date))))))
3550
3551 ;; One file is a Tramp file, the other one is local.
3552 ((or t1 t2)
3553 (with-parsed-tramp-file-name (if t1 filename newname) nil
8d60099b
MA
3554 (cond
3555 ;; Fast track on local machine.
3556 ((tramp-local-host-p v)
3557 (tramp-do-copy-or-rename-file-directly
3558 op filename newname
3559 ok-if-already-exists keep-date preserve-uid-gid))
3560
3561 ;; If the Tramp file has an out-of-band method, the corresponding
3562 ;; copy-program can be invoked.
7f49fe46 3563 ((tramp-method-out-of-band-p v (nth 7 (file-attributes filename)))
8d60099b
MA
3564 (tramp-do-copy-or-rename-file-out-of-band
3565 op filename newname keep-date))
3566
3567 ;; Use the inline method via a Tramp buffer.
3568 (t (tramp-do-copy-or-rename-file-via-buffer
3569 op filename newname keep-date)))))
00d6fd04
MA
3570
3571 (t
3572 ;; One of them must be a Tramp file.
3573 (error "Tramp implementation says this cannot happen")))
8d60099b 3574
484ea0b6
MA
3575 ;; In case of `rename', we must flush the cache of the source file.
3576 (when (and t1 (eq op 'rename))
3577 (with-parsed-tramp-file-name filename nil
3578 (tramp-flush-file-property v localname)))
3579
00d6fd04
MA
3580 ;; When newname did exist, we have wrong cached values.
3581 (when t2
3582 (with-parsed-tramp-file-name newname nil
905fb90e
MA
3583 (tramp-flush-file-property v localname)))
3584
3585 (with-parsed-tramp-file-name (if t1 filename newname) nil
3586 (tramp-message v 0 "Transferring %s to %s...done" filename newname)))))
7432277c 3587
38c65fca 3588(defun tramp-do-copy-or-rename-file-via-buffer (op filename newname keep-date)
90dc758d
KG
3589 "Use an Emacs buffer to copy or rename a file.
3590First arg OP is either `copy' or `rename' and indicates the operation.
3591FILENAME is the source file, NEWNAME the target file.
3592KEEP-DATE is non-nil if NEWNAME should have the same timestamp as FILENAME."
8a798e41
MA
3593 (with-temp-buffer
3594 ;; We must disable multibyte, because binary data shall not be
3595 ;; converted.
3596 (set-buffer-multibyte nil)
3597 (let ((coding-system-for-read 'binary)
3598 (jka-compr-inhibit t))
3599 (insert-file-contents-literally filename))
3600 ;; We don't want the target file to be compressed, so we let-bind
3601 ;; `jka-compr-inhibit' to t.
3602 (let ((coding-system-for-write 'binary)
3603 (jka-compr-inhibit t))
3604 (write-region (point-min) (point-max) newname)))
3605 ;; KEEP-DATE handling.
3606 (when keep-date (set-file-times newname (nth 5 (file-attributes filename))))
3607 ;; Set the mode.
b86c1cd8 3608 (set-file-modes newname (tramp-default-file-modes filename))
8a798e41
MA
3609 ;; If the operation was `rename', delete the original file.
3610 (unless (eq op 'copy) (delete-file filename)))
fb7933a3
KG
3611
3612(defun tramp-do-copy-or-rename-file-directly
8d60099b 3613 (op filename newname ok-if-already-exists keep-date preserve-uid-gid)
fb7933a3
KG
3614 "Invokes `cp' or `mv' on the remote system.
3615OP must be one of `copy' or `rename', indicating `cp' or `mv',
8d60099b
MA
3616respectively. FILENAME specifies the file to copy or rename,
3617NEWNAME is the name of the new file (for copy) or the new name of
3618the file (for rename). Both files must reside on the same host.
3619KEEP-DATE means to make sure that NEWNAME has the same timestamp
3620as FILENAME. PRESERVE-UID-GID, when non-nil, instructs to keep
3621the uid and gid from FILENAME."
8a4438b6 3622 (let ((t1 (tramp-tramp-file-p filename))
4f4126e6
MA
3623 (t2 (tramp-tramp-file-p newname))
3624 (file-times (nth 5 (file-attributes filename)))
3625 (file-modes (tramp-default-file-modes filename)))
8a4438b6
MA
3626 (with-parsed-tramp-file-name (if t1 filename newname) nil
3627 (let* ((cmd (cond ((and (eq op 'copy) preserve-uid-gid) "cp -f -p")
3628 ((eq op 'copy) "cp -f")
3629 ((eq op 'rename) "mv -f")
3630 (t (tramp-error
3631 v 'file-error
3632 "Unknown operation `%s', must be `copy' or `rename'"
3633 op))))
3634 (localname1
3635 (if t1 (tramp-handle-file-remote-p filename 'localname) filename))
3636 (localname2
3637 (if t2 (tramp-handle-file-remote-p newname 'localname) newname))
293c24f9
MA
3638 (prefix (file-remote-p (if t1 filename newname)))
3639 cmd-result)
8d60099b 3640
8d60099b 3641 (cond
8a4438b6
MA
3642 ;; Both files are on a remote host, with same user.
3643 ((and t1 t2)
293c24f9
MA
3644 (setq cmd-result
3645 (tramp-send-command-and-check
3646 v
3647 (format "%s %s %s" cmd
3648 (tramp-shell-quote-argument localname1)
3649 (tramp-shell-quote-argument localname2))))
8a4438b6
MA
3650 (with-current-buffer (tramp-get-buffer v)
3651 (goto-char (point-min))
3652 (unless
3653 (or
3654 (and keep-date
3655 ;; Mask cp -f error.
3656 (re-search-forward
3657 tramp-operation-not-permitted-regexp nil t))
293c24f9 3658 (zerop cmd-result))
8a4438b6
MA
3659 (tramp-error-with-buffer
3660 nil v 'file-error
3661 "Copying directly failed, see buffer `%s' for details."
3662 (buffer-name)))))
3663
3664 ;; We are on the local host.
3665 ((or t1 t2)
8d60099b 3666 (cond
8a4438b6 3667 ;; We can do it directly.
87bdd2c7
MA
3668 ((let (file-name-handler-alist)
3669 (and (file-readable-p localname1)
3670 (file-writable-p (file-name-directory localname2))
3671 (or (file-directory-p localname2)
3672 (file-writable-p localname2))))
8d60099b 3673 (if (eq op 'copy)
9e6ab520
MA
3674 (tramp-compat-copy-file
3675 localname1 localname2 ok-if-already-exists
3676 keep-date preserve-uid-gid)
87bdd2c7
MA
3677 (tramp-run-real-handler
3678 'rename-file (list localname1 localname2 ok-if-already-exists))))
8a4438b6
MA
3679
3680 ;; We can do it directly with `tramp-send-command'
946a5aeb
MA
3681 ((and (file-readable-p (concat prefix localname1))
3682 (file-writable-p
3683 (file-name-directory (concat prefix localname2)))
3684 (or (file-directory-p (concat prefix localname2))
3685 (file-writable-p (concat prefix localname2))))
8a4438b6
MA
3686 (tramp-do-copy-or-rename-file-directly
3687 op (concat prefix localname1) (concat prefix localname2)
3688 ok-if-already-exists keep-date t)
3689 ;; We must change the ownership to the local user.
8d60099b 3690 (tramp-set-file-uid-gid
8a4438b6
MA
3691 (concat prefix localname2)
3692 (tramp-get-local-uid 'integer)
3693 (tramp-get-local-gid 'integer)))
8d60099b 3694
8a4438b6
MA
3695 ;; We need a temporary file in between.
3696 (t
2c418c5b
MA
3697 ;; Create the temporary file.
3698 (let ((tmpfile (tramp-compat-make-temp-file localname1)))
917b89a6 3699 (unwind-protect
2c418c5b
MA
3700 (progn
3701 (cond
3702 (t1
917b89a6
MA
3703 (or
3704 (zerop
3705 (tramp-send-command-and-check
3706 v (format
3707 "%s %s %s" cmd
3708 (tramp-shell-quote-argument localname1)
3709 (tramp-shell-quote-argument tmpfile))))
3710 (tramp-error-with-buffer
3711 nil v 'file-error
3712 "Copying directly failed, see buffer `%s' for details."
3713 (tramp-get-buffer v)))
2c418c5b 3714 ;; We must change the ownership as remote user.
917b89a6
MA
3715 ;; Since this does not work reliable, we also
3716 ;; give read permissions.
3717 (set-file-modes
3718 (concat prefix tmpfile) (tramp-octal-to-decimal "0777"))
2c418c5b
MA
3719 (tramp-set-file-uid-gid
3720 (concat prefix tmpfile)
3721 (tramp-get-local-uid 'integer)
3722 (tramp-get-local-gid 'integer)))
3723 (t2
3724 (if (eq op 'copy)
3725 (tramp-compat-copy-file
5ab38c3c 3726 localname1 tmpfile t
2c418c5b
MA
3727 keep-date preserve-uid-gid)
3728 (tramp-run-real-handler
3729 'rename-file
5ab38c3c 3730 (list localname1 tmpfile t)))
2c418c5b 3731 ;; We must change the ownership as local user.
917b89a6
MA
3732 ;; Since this does not work reliable, we also
3733 ;; give read permissions.
3734 (set-file-modes tmpfile (tramp-octal-to-decimal "0777"))
2c418c5b
MA
3735 (tramp-set-file-uid-gid
3736 tmpfile
3737 (tramp-get-remote-uid v 'integer)
3738 (tramp-get-remote-gid v 'integer))))
3739
3740 ;; Move the temporary file to its destination.
3741 (cond
3742 (t2
917b89a6
MA
3743 (or
3744 (zerop
3745 (tramp-send-command-and-check
3746 v (format
3747 "cp -f -p %s %s"
3748 (tramp-shell-quote-argument tmpfile)
3749 (tramp-shell-quote-argument localname2))))
3750 (tramp-error-with-buffer
3751 nil v 'file-error
3752 "Copying directly failed, see buffer `%s' for details."
3753 (tramp-get-buffer v))))
2c418c5b 3754 (t1
ce2cc728
MA
3755 (tramp-run-real-handler
3756 'rename-file
2c418c5b
MA
3757 (list tmpfile localname2 ok-if-already-exists)))))
3758
917b89a6
MA
3759 ;; Save exit.
3760 (condition-case nil
3761 (delete-file tmpfile)
3762 (error)))))))))
8d60099b
MA
3763
3764 ;; Set the time and mode. Mask possible errors.
8d60099b 3765 (condition-case nil
1f107aed 3766 (when keep-date
4f4126e6
MA
3767 (set-file-times newname file-times)
3768 (set-file-modes newname file-modes))
8d60099b
MA
3769 (error)))))
3770
5ec2cc41 3771(defun tramp-do-copy-or-rename-file-out-of-band (op filename newname keep-date)
7432277c 3772 "Invoke rcp program to copy.
905fb90e 3773The method used must be an out-of-band method."
38c65fca 3774 (let ((t1 (tramp-tramp-file-p filename))
5ec2cc41 3775 (t2 (tramp-tramp-file-p newname))
946a5aeb 3776 copy-program copy-args copy-env copy-keep-date port spec
00d6fd04
MA
3777 source target)
3778
3779 (with-parsed-tramp-file-name (if t1 filename newname) nil
905fb90e 3780 (if (and t1 t2)
00d6fd04 3781
905fb90e
MA
3782 ;; Both are Tramp files. We shall optimize it, when the
3783 ;; methods for filename and newname are the same.
3784 (let ((tmpfile (tramp-compat-make-temp-file localname)))
3785 (unwind-protect
3786 (progn
3787 (tramp-do-copy-or-rename-file-out-of-band
3788 op filename tmpfile keep-date)
3789 (tramp-do-copy-or-rename-file-out-of-band
3790 'rename tmpfile newname keep-date))
3791 ;; Save exit.
3792 (condition-case nil
3793 (delete-file tmpfile)
3794 (error))))
3795
3796 ;; Expand hops. Might be necessary for gateway methods.
3797 (setq v (car (tramp-compute-multi-hops v)))
3798 (aset v 3 localname)
3799
3800 ;; Check which ones of source and target are Tramp files.
3801 (setq source (if t1 (tramp-make-copy-program-file-name v) filename)
263c02ef
MA
3802 target (funcall
3803 (if (and (file-directory-p filename)
3804 (string-equal
3805 (file-name-nondirectory filename)
3806 (file-name-nondirectory newname)))
3807 'file-name-directory
3808 'identity)
3809 (if t2 (tramp-make-copy-program-file-name v) newname)))
905fb90e
MA
3810
3811 ;; Check for port number. Until now, there's no need for handling
3812 ;; like method, user, host.
3813 (setq host (tramp-file-name-real-host v)
3814 port (tramp-file-name-port v)
3815 port (or (and port (number-to-string port)) ""))
3816
3817 ;; Compose copy command.
3818 (setq spec `((?h . ,host) (?u . ,user) (?p . ,port)
3819 (?t . ,(tramp-get-connection-property
3820 (tramp-get-connection-process v) "temp-file" ""))
3821 (?k . ,(if keep-date " " "")))
3822 copy-program (tramp-get-method-parameter
3823 method 'tramp-copy-program)
3824 copy-keep-date (tramp-get-method-parameter
3825 method 'tramp-copy-keep-date)
3826 copy-args
3827 (delq
3828 nil
3829 (mapcar
aa485f7c
MA
3830 (lambda (x)
3831 (setq
3832 x
3833 ;; " " is indication for keep-date argument.
3834 (delete " " (mapcar (lambda (y) (format-spec y spec)) x)))
3835 (unless (member "" x) (mapconcat 'identity x " ")))
946a5aeb
MA
3836 (tramp-get-method-parameter method 'tramp-copy-args)))
3837 copy-env
3838 (delq
3839 nil
3840 (mapcar
aa485f7c
MA
3841 (lambda (x)
3842 (setq x (mapcar (lambda (y) (format-spec y spec)) x))
3843 (unless (member "" x) (mapconcat 'identity x " ")))
946a5aeb 3844 (tramp-get-method-parameter method 'tramp-copy-env))))
905fb90e
MA
3845
3846 ;; Check for program.
3847 (when (and (fboundp 'executable-find)
3848 (not (let ((default-directory
3849 (tramp-compat-temporary-file-directory)))
3850 (executable-find copy-program))))
3851 (tramp-error
3852 v 'file-error "Cannot find copy program: %s" copy-program))
00d6fd04 3853
4265deab
MA
3854 ;; Set variables for computing the prompt for reading
3855 ;; password.
3856 (setq tramp-current-method (tramp-file-name-method v)
3857 tramp-current-user (tramp-file-name-user v)
3858 tramp-current-host (tramp-file-name-host v))
3859
905fb90e
MA
3860 (unwind-protect
3861 (with-temp-buffer
3862 ;; The default directory must be remote.
3863 (let ((default-directory
946a5aeb
MA
3864 (file-name-directory (if t1 filename newname)))
3865 (process-environment (copy-sequence process-environment)))
905fb90e
MA
3866 ;; Set the transfer process properties.
3867 (tramp-set-connection-property
3868 v "process-name" (buffer-name (current-buffer)))
3869 (tramp-set-connection-property
3870 v "process-buffer" (current-buffer))
946a5aeb
MA
3871 (while copy-env
3872 (tramp-message v 5 "%s=\"%s\"" (car copy-env) (cadr copy-env))
3873 (setenv (pop copy-env) (pop copy-env)))
905fb90e
MA
3874
3875 ;; Use an asynchronous process. By this, password can
3876 ;; be handled. The default directory must be local, in
3877 ;; order to apply the correct `copy-program'. We don't
3878 ;; set a timeout, because the copying of large files can
3879 ;; last longer than 60 secs.
3880 (let ((p (let ((default-directory
3881 (tramp-compat-temporary-file-directory)))
3882 (apply 'start-process
3883 (tramp-get-connection-property
3884 v "process-name" nil)
3885 (tramp-get-connection-property
3886 v "process-buffer" nil)
3887 copy-program
3888 (append copy-args (list source target))))))
3889 (tramp-message
3890 v 6 "%s" (mapconcat 'identity (process-command p) " "))
3891 (tramp-set-process-query-on-exit-flag p nil)
3892 (tramp-process-actions p v tramp-actions-copy-out-of-band))))
00d6fd04 3893
905fb90e
MA
3894 ;; Reset the transfer process properties.
3895 (tramp-set-connection-property v "process-name" nil)
3896 (tramp-set-connection-property v "process-buffer" nil))
00d6fd04 3897
905fb90e
MA
3898 ;; Handle KEEP-DATE argument.
3899 (when (and keep-date (not copy-keep-date))
3900 (set-file-times newname (nth 5 (file-attributes filename))))
01917a18 3901
905fb90e
MA
3902 ;; Set the mode.
3903 (unless (and keep-date copy-keep-date)
3904 (set-file-modes newname (tramp-default-file-modes filename))))
5ec2cc41 3905
905fb90e
MA
3906 ;; If the operation was `rename', delete the original file.
3907 (unless (eq op 'copy)
3908 (delete-file filename)))))
7432277c 3909
fb7933a3 3910(defun tramp-handle-make-directory (dir &optional parents)
00d6fd04 3911 "Like `make-directory' for Tramp files."
ac474af1 3912 (setq dir (expand-file-name dir))
c62c9d08 3913 (with-parsed-tramp-file-name dir nil
c15cdf02 3914 (tramp-flush-directory-property v (file-name-directory localname))
b1d06e75
KG
3915 (save-excursion
3916 (tramp-barf-unless-okay
00d6fd04 3917 v
9c13938d 3918 (format "%s %s"
b1d06e75 3919 (if parents "mkdir -p" "mkdir")
7432277c 3920 (tramp-shell-quote-argument localname))
b1d06e75 3921 "Couldn't make directory %s" dir))))
fb7933a3 3922
c15cdf02 3923(defun tramp-handle-delete-directory (directory &optional recursive)
00d6fd04 3924 "Like `delete-directory' for Tramp files."
ac474af1 3925 (setq directory (expand-file-name directory))
c62c9d08 3926 (with-parsed-tramp-file-name directory nil
00d6fd04
MA
3927 (tramp-flush-directory-property v localname)
3928 (unless (zerop (tramp-send-command-and-check
3929 v
c15cdf02
MA
3930 (format
3931 "%s %s"
3932 (if recursive "rm -rf" "rmdir")
3933 (tramp-shell-quote-argument localname))))
00d6fd04 3934 (tramp-error v 'file-error "Couldn't delete %s" directory))))
fb7933a3
KG
3935
3936(defun tramp-handle-delete-file (filename)
00d6fd04 3937 "Like `delete-file' for Tramp files."
ac474af1 3938 (setq filename (expand-file-name filename))
c62c9d08 3939 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3940 (tramp-flush-file-property v localname)
3941 (unless (zerop (tramp-send-command-and-check
3942 v
3943 (format "rm -f %s"
3944 (tramp-shell-quote-argument localname))))
3945 (tramp-error v 'file-error "Couldn't delete %s" filename))))
fb7933a3
KG
3946
3947;; Dired.
3948
3949;; CCC: This does not seem to be enough. Something dies when
a4aeb9a4 3950;; we try and delete two directories under Tramp :/
fb7933a3
KG
3951(defun tramp-handle-dired-recursive-delete-directory (filename)
3952 "Recursively delete the directory given.
00d6fd04 3953This is like `dired-recursive-delete-directory' for Tramp files."
c62c9d08 3954 (with-parsed-tramp-file-name filename nil
00d6fd04 3955 ;; Run a shell command 'rm -r <localname>'
260821d3 3956 ;; Code shamelessly stolen from the dired implementation and, um, hacked :)
00d6fd04
MA
3957 (unless (file-exists-p filename)
3958 (tramp-error v 'file-error "No such directory: %s" filename))
fb7933a3 3959 ;; Which is better, -r or -R? (-r works for me <daniel@danann.net>)
00d6fd04
MA
3960 (tramp-send-command
3961 v
9c13938d 3962 (format "rm -rf %s" (tramp-shell-quote-argument localname))
00d6fd04
MA
3963 ;; Don't read the output, do it explicitely.
3964 nil t)
fb7933a3
KG
3965 ;; Wait for the remote system to return to us...
3966 ;; This might take a while, allow it plenty of time.
00d6fd04 3967 (tramp-wait-for-output (tramp-get-connection-process v) 120)
fb7933a3 3968 ;; Make sure that it worked...
c15cdf02 3969 (tramp-flush-directory-property v localname)
07dfe738 3970 (and (file-exists-p filename)
00d6fd04
MA
3971 (tramp-error
3972 v 'file-error "Failed to recursively delete %s" filename))))
bf247b6e 3973
5ec2cc41 3974(defun tramp-handle-dired-compress-file (file &rest ok-flag)
00d6fd04 3975 "Like `dired-compress-file' for Tramp files."
5ec2cc41
KG
3976 ;; OK-FLAG is valid for XEmacs only, but not implemented.
3977 ;; Code stolen mainly from dired-aux.el.
3978 (with-parsed-tramp-file-name file nil
00d6fd04 3979 (tramp-flush-file-property v localname)
5ec2cc41
KG
3980 (save-excursion
3981 (let ((suffixes
3982 (if (not (featurep 'xemacs))
3983 ;; Emacs case
3984 (symbol-value 'dired-compress-file-suffixes)
3985 ;; XEmacs has `dired-compression-method-alist', which is
3986 ;; transformed into `dired-compress-file-suffixes' structure.
3987 (mapcar
aa485f7c
MA
3988 (lambda (x)
3989 (list (concat (regexp-quote (nth 1 x)) "\\'")
3990 nil
3991 (mapconcat 'identity (nth 3 x) " ")))
5ec2cc41
KG
3992 (symbol-value 'dired-compression-method-alist))))
3993 suffix)
3994 ;; See if any suffix rule matches this file name.
3995 (while suffixes
3996 (let (case-fold-search)
3997 (if (string-match (car (car suffixes)) localname)
3998 (setq suffix (car suffixes) suffixes nil))
3999 (setq suffixes (cdr suffixes))))
4000
4001 (cond ((file-symlink-p file)
4002 nil)
4003 ((and suffix (nth 2 suffix))
4004 ;; We found an uncompression rule.
00d6fd04 4005 (tramp-message v 0 "Uncompressing %s..." file)
5ec2cc41 4006 (when (zerop (tramp-send-command-and-check
b593f105
MA
4007 v (concat (nth 2 suffix) " "
4008 (tramp-shell-quote-argument localname))))
00d6fd04 4009 (tramp-message v 0 "Uncompressing %s...done" file)
38c65fca
KG
4010 ;; `dired-remove-file' is not defined in XEmacs
4011 (funcall (symbol-function 'dired-remove-file) file)
5ec2cc41
KG
4012 (string-match (car suffix) file)
4013 (concat (substring file 0 (match-beginning 0)))))
4014 (t
4015 ;; We don't recognize the file as compressed, so compress it.
4016 ;; Try gzip.
00d6fd04 4017 (tramp-message v 0 "Compressing %s..." file)
5ec2cc41 4018 (when (zerop (tramp-send-command-and-check
b593f105
MA
4019 v (concat "gzip -f "
4020 (tramp-shell-quote-argument localname))))
00d6fd04 4021 (tramp-message v 0 "Compressing %s...done" file)
38c65fca
KG
4022 ;; `dired-remove-file' is not defined in XEmacs
4023 (funcall (symbol-function 'dired-remove-file) file)
5ec2cc41
KG
4024 (cond ((file-exists-p (concat file ".gz"))
4025 (concat file ".gz"))
4026 ((file-exists-p (concat file ".z"))
4027 (concat file ".z"))
4028 (t nil)))))))))
fb7933a3 4029
70c11b0b
MA
4030(defun tramp-handle-dired-uncache (dir)
4031 "Like `dired-uncache' for Tramp files."
4032 (with-parsed-tramp-file-name dir nil
4033 (tramp-flush-file-property v localname)))
4034
fb7933a3
KG
4035;; Pacify byte-compiler. The function is needed on XEmacs only. I'm
4036;; not sure at all that this is the right way to do it, but let's hope
4037;; it works for now, and wait for a guru to point out the Right Way to
4038;; achieve this.
4039;;(eval-when-compile
4040;; (unless (fboundp 'dired-insert-set-properties)
4041;; (fset 'dired-insert-set-properties 'ignore)))
4042;; Gerd suggests this:
4043(eval-when-compile (require 'dired))
4044;; Note that dired is required at run-time, too, when it is needed.
4045;; It is only needed on XEmacs for the function
4046;; `dired-insert-set-properties'.
4047
4048(defun tramp-handle-insert-directory
4049 (filename switches &optional wildcard full-directory-p)
00d6fd04
MA
4050 "Like `insert-directory' for Tramp files."
4051 (setq filename (expand-file-name filename))
4052 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
4053 (if (and (featurep 'ls-lisp)
4054 (not (symbol-value 'ls-lisp-use-insert-directory-program)))
4055 (tramp-run-real-handler
4056 'insert-directory (list filename switches wildcard full-directory-p))
8e754ea2
MA
4057 (when (and (string-match "^--dired\\s-+" switches)
4058 (not (tramp-get-ls-command-with-dired v)))
00d6fd04
MA
4059 (setq switches (replace-match "" nil t switches)))
4060 (tramp-message
4061 v 4 "Inserting directory `ls %s %s', wildcard %s, fulldir %s"
c82c5727
LH
4062 switches filename (if wildcard "yes" "no")
4063 (if full-directory-p "yes" "no"))
4064 (when wildcard
87bdd2c7
MA
4065 (setq wildcard (tramp-run-real-handler
4066 'file-name-nondirectory (list localname)))
4067 (setq localname (tramp-run-real-handler
4068 'file-name-directory (list localname))))
c82c5727
LH
4069 (when (listp switches)
4070 (setq switches (mapconcat 'identity switches " ")))
4071 (unless full-directory-p
4072 (setq switches (concat "-d " switches)))
4073 (when wildcard
4074 (setq switches (concat switches " " wildcard)))
00d6fd04
MA
4075 ;; If `full-directory-p', we just say `ls -l FILENAME'.
4076 ;; Else we chdir to the parent directory, then say `ls -ld BASENAME'.
4077 (if full-directory-p
4078 (tramp-send-command
4079 v
fe5facd3 4080 (format "%s %s %s 2>/dev/null"
00d6fd04
MA
4081 (tramp-get-ls-command v)
4082 switches
4083 (if wildcard
4084 localname
4085 (tramp-shell-quote-argument (concat localname ".")))))
4086 (tramp-barf-unless-okay
4087 v
4088 (format "cd %s" (tramp-shell-quote-argument
87bdd2c7
MA
4089 (tramp-run-real-handler
4090 'file-name-directory (list localname))))
00d6fd04 4091 "Couldn't `cd %s'"
87bdd2c7
MA
4092 (tramp-shell-quote-argument
4093 (tramp-run-real-handler 'file-name-directory (list localname))))
00d6fd04
MA
4094 (tramp-send-command
4095 v
4096 (format "%s %s %s"
4097 (tramp-get-ls-command v)
4098 switches
4099 (if (or wildcard
87bdd2c7
MA
4100 (zerop (length
4101 (tramp-run-real-handler
4102 'file-name-nondirectory (list localname)))))
00d6fd04
MA
4103 ""
4104 (tramp-shell-quote-argument
87bdd2c7
MA
4105 (tramp-run-real-handler
4106 'file-name-nondirectory (list localname)))))))
8e754ea2
MA
4107 (let ((beg (point)))
4108 ;; We cannot use `insert-buffer-substring' because the Tramp
4109 ;; buffer changes its contents before insertion due to calling
4110 ;; `expand-file' and alike.
4111 (insert
4112 (with-current-buffer (tramp-get-buffer v)
4113 (buffer-string)))
4114
4115 ;; Check for "--dired" output.
8e754ea2
MA
4116 (forward-line -2)
4117 (when (looking-at "//DIRED//")
7ba1d9c2 4118 (let ((end (tramp-compat-line-end-position))
8e754ea2
MA
4119 (linebeg (point)))
4120 ;; Now read the numeric positions of file names.
4121 (goto-char linebeg)
4122 (forward-word 1)
4123 (forward-char 3)
4124 (while (< (point) end)
4125 (let ((start (+ beg (read (current-buffer))))
4126 (end (+ beg (read (current-buffer)))))
7f49fe46 4127 (if (memq (char-after end) '(?\n ?\ ))
8e754ea2 4128 ;; End is followed by \n or by " -> ".
fe5facd3
MA
4129 (put-text-property start end 'dired-filename t))))))
4130 ;; Remove trailing lines.
4131 (goto-char (tramp-compat-line-beginning-position))
4132 (while (looking-at "//")
4133 (forward-line 1)
4134 (delete-region (match-beginning 0) (point)))
4135 (goto-char (point-max))))))
fb7933a3 4136
fb7933a3 4137(defun tramp-handle-unhandled-file-name-directory (filename)
00d6fd04 4138 "Like `unhandled-file-name-directory' for Tramp files."
8a798e41
MA
4139 ;; With Emacs 23, we could simply return `nil'. But we must keep it
4140 ;; for backward compatibility.
ce3f516f 4141 (expand-file-name "~/"))
fb7933a3
KG
4142
4143;; Canonicalization of file names.
4144
fb7933a3 4145(defun tramp-handle-expand-file-name (name &optional dir)
00d6fd04 4146 "Like `expand-file-name' for Tramp files.
7432277c
KG
4147If the localname part of the given filename starts with \"/../\" then
4148the result will be a local, non-Tramp, filename."
fb7933a3
KG
4149 ;; If DIR is not given, use DEFAULT-DIRECTORY or "/".
4150 (setq dir (or dir default-directory "/"))
4151 ;; Unless NAME is absolute, concat DIR and NAME.
4152 (unless (file-name-absolute-p name)
4153 (setq name (concat (file-name-as-directory dir) name)))
00d6fd04 4154 ;; If NAME is not a Tramp file, run the real handler.
fb7933a3 4155 (if (not (tramp-tramp-file-p name))
00d6fd04 4156 (tramp-run-real-handler 'expand-file-name (list name nil))
fb7933a3 4157 ;; Dissect NAME.
c62c9d08 4158 (with-parsed-tramp-file-name name nil
87bdd2c7 4159 (unless (tramp-run-real-handler 'file-name-absolute-p (list localname))
7432277c 4160 (setq localname (concat "~/" localname)))
00d6fd04
MA
4161 ;; Tilde expansion if necessary. This needs a shell which
4162 ;; groks tilde expansion! The function `tramp-find-shell' is
4163 ;; supposed to find such a shell on the remote host. Please
4164 ;; tell me about it when this doesn't work on your system.
4165 (when (string-match "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname)
4166 (let ((uname (match-string 1 localname))
4167 (fname (match-string 2 localname)))
4168 ;; We cannot simply apply "~/", because under sudo "~/" is
4169 ;; expanded to the local user home directory but to the
4170 ;; root home directory. On the other hand, using always
4171 ;; the default user name for tilde expansion is not
4172 ;; appropriate either, because ssh and companions might
4173 ;; use a user name from the config file.
4174 (when (and (string-equal uname "~")
4175 (string-match "\\`su\\(do\\)?\\'" method))
4176 (setq uname (concat uname user)))
4177 (setq uname
b593f105
MA
4178 (with-connection-property v uname
4179 (tramp-send-command
4180 v (format "cd %s; pwd" (tramp-shell-quote-argument uname)))
4181 (with-current-buffer (tramp-get-buffer v)
4182 (goto-char (point-min))
4183 (buffer-substring
4184 (point) (tramp-compat-line-end-position)))))
00d6fd04
MA
4185 (setq localname (concat uname fname))))
4186 ;; There might be a double slash, for example when "~/"
cb85dcd0 4187 ;; expands to "/". Remove this.
00d6fd04
MA
4188 (while (string-match "//" localname)
4189 (setq localname (replace-match "/" t t localname)))
4190 ;; No tilde characters in file name, do normal
a17632c1
MA
4191 ;; `expand-file-name' (this does "/./" and "/../"). We bind
4192 ;; `directory-sep-char' here for XEmacs on Windows, which would
4193 ;; otherwise use backslash. `default-directory' is bound,
4194 ;; because on Windows there would be problems with UNC shares or
4195 ;; Cygwin mounts.
aff67808
MA
4196 (let ((directory-sep-char ?/)
4197 (default-directory (tramp-compat-temporary-file-directory)))
4198 (tramp-make-tramp-file-name
4199 method user host
4200 (tramp-drop-volume-letter
87bdd2c7
MA
4201 (tramp-run-real-handler
4202 'expand-file-name (list localname))))))))
00d6fd04 4203
c23c3394
MA
4204(defun tramp-replace-environment-variables (filename)
4205 "Replace environment variables in FILENAME.
4206Return the string with the replaced variables."
2e271195 4207 (save-match-data
ec5145d6 4208 (let ((idx (string-match "$\\(\\w+\\)" filename)))
2e271195 4209 ;; `$' is coded as `$$'.
ec5145d6
MA
4210 (when (and idx
4211 (or (zerop idx) (not (eq ?$ (aref filename (1- idx)))))
4212 (getenv (match-string 1 filename)))
2e271195
MA
4213 (setq filename
4214 (replace-match
4215 (substitute-in-file-name (match-string 0 filename))
4216 t nil filename)))
4217 filename)))
c23c3394 4218
00d6fd04
MA
4219(defun tramp-handle-substitute-in-file-name (filename)
4220 "Like `substitute-in-file-name' for Tramp files.
4221\"//\" and \"/~\" substitute only in the local filename part.
4222If the URL Tramp syntax is chosen, \"//\" as method delimeter and \"/~\" at
4223beginning of local filename are not substituted."
c23c3394
MA
4224 ;; First, we must replace environment variables.
4225 (setq filename (tramp-replace-environment-variables filename))
00d6fd04
MA
4226 (with-parsed-tramp-file-name filename nil
4227 (if (equal tramp-syntax 'url)
4228 ;; We need to check localname only. The other parts cannot contain
4229 ;; "//" or "/~".
4230 (if (and (> (length localname) 1)
4231 (or (string-match "//" localname)
4232 (string-match "/~" localname 1)))
4233 (tramp-run-real-handler 'substitute-in-file-name (list filename))
4234 (tramp-make-tramp-file-name
4235 (when method (substitute-in-file-name method))
4236 (when user (substitute-in-file-name user))
4237 (when host (substitute-in-file-name host))
87bdd2c7
MA
4238 (when localname
4239 (tramp-run-real-handler
4240 'substitute-in-file-name (list localname)))))
00d6fd04
MA
4241 ;; Ignore in LOCALNAME everything before "//" or "/~".
4242 (when (and (stringp localname) (string-match ".+?/\\(/\\|~\\)" localname))
4243 (setq filename
b08104a0
MA
4244 (concat (file-remote-p filename)
4245 (replace-match "\\1" nil nil localname)))
00d6fd04
MA
4246 ;; "/m:h:~" does not work for completion. We use "/m:h:~/".
4247 (when (string-match "~$" filename)
4248 (setq filename (concat filename "/"))))
4249 (tramp-run-real-handler 'substitute-in-file-name (list filename)))))
4250
4251;; In XEmacs, electricity is implemented via a key map for ?/ and ?~,
4252;; which calls corresponding functions (see minibuf.el).
4253(when (fboundp 'minibuffer-electric-separator)
9e6ab520 4254 (mapc
aa485f7c
MA
4255 (lambda (x)
4256 (eval
4257 `(defadvice ,x
4258 (around ,(intern (format "tramp-advice-%s" x)) activate)
4259 "Invoke `substitute-in-file-name' for Tramp files."
4260 (if (and (symbol-value 'minibuffer-electric-file-name-behavior)
4261 (tramp-tramp-file-p (buffer-substring)))
4262 ;; We don't need to handle `last-input-event', because
4263 ;; due to the key map we know it must be ?/ or ?~.
4264 (let ((s (concat (buffer-substring (point-min) (point))
4265 (string last-command-char))))
4266 (delete-region (point-min) (point))
4267 (insert (substitute-in-file-name s))
4268 (setq ad-return-value last-command-char))
d7ec1df7
MA
4269 ad-do-it)))
4270 (eval
4271 `(add-hook
4272 'tramp-unload-hook
4273 (lambda ()
4274 (ad-remove-advice ',x 'around ',(intern (format "tramp-advice-%s" x)))
4275 (ad-activate ',x)))))
00d6fd04
MA
4276
4277 '(minibuffer-electric-separator
4278 minibuffer-electric-tilde)))
4279
4280
0664ff72 4281;;; Remote commands:
fb7933a3 4282
00d6fd04
MA
4283(defun tramp-handle-executable-find (command)
4284 "Like `executable-find' for Tramp files."
4285 (with-parsed-tramp-file-name default-directory nil
f84638eb 4286 (tramp-find-executable v command (tramp-get-remote-path v) t)))
00d6fd04
MA
4287
4288;; We use BUFFER also as connection buffer during setup. Because of
4289;; this, its original contents must be saved, and restored once
4290;; connection has been setup.
4291(defun tramp-handle-start-file-process (name buffer program &rest args)
4292 "Like `start-file-process' for Tramp files."
4293 (with-parsed-tramp-file-name default-directory nil
9fb2cdc5
GM
4294 (unless (stringp program)
4295 (tramp-error
4296 v 'file-error "pty association is not supported for `%s'" name))
00d6fd04 4297 (unwind-protect
263c02ef
MA
4298 (let ((command (format "cd %s; exec %s"
4299 (tramp-shell-quote-argument localname)
4300 (mapconcat 'tramp-shell-quote-argument
4301 (cons program args) " ")))
4302 (name1 name)
38d63e6a 4303 (i 0))
2296b54d 4304 (unless buffer
6ce63faf 4305 ;; BUFFER can be nil. We use a temporary buffer.
2296b54d 4306 (setq buffer (generate-new-buffer tramp-temp-buffer-name)))
38d63e6a
MA
4307 (while (get-process name1)
4308 ;; NAME must be unique as process name.
4309 (setq i (1+ i)
4310 name1 (format "%s<%d>" name i)))
4311 (setq name name1)
00d6fd04
MA
4312 ;; Set the new process properties.
4313 (tramp-set-connection-property v "process-name" name)
2296b54d 4314 (tramp-set-connection-property v "process-buffer" buffer)
00d6fd04 4315 ;; Activate narrowing in order to save BUFFER contents.
11c71217
MA
4316 ;; Clear also the modification time; otherwise we might be
4317 ;; interrupted by `verify-visited-file-modtime'.
00d6fd04 4318 (with-current-buffer (tramp-get-connection-buffer v)
11c71217 4319 (clear-visited-file-modtime)
00d6fd04 4320 (narrow-to-region (point-max) (point-max)))
263c02ef 4321 ;; Send the command. `tramp-send-command' opens a new
00d6fd04 4322 ;; connection.
263c02ef 4323 (tramp-send-command v command nil t) ; nooutput
6ce63faf
MA
4324 ;; Set query flag for this process.
4325 (tramp-set-process-query-on-exit-flag
4326 (tramp-get-connection-process v) t)
00d6fd04
MA
4327 ;; Return process.
4328 (tramp-get-connection-process v))
4329 ;; Save exit.
ce3f516f 4330 (with-current-buffer (tramp-get-connection-buffer v)
6ce63faf
MA
4331 (if (string-match tramp-temp-buffer-name (buffer-name))
4332 (progn
4333 (set-process-buffer (tramp-get-connection-process v) nil)
4334 (kill-buffer (current-buffer)))
4335 (widen)
4336 (goto-char (point-max))))
00d6fd04
MA
4337 (tramp-set-connection-property v "process-name" nil)
4338 (tramp-set-connection-property v "process-buffer" nil))))
4339
4340(defun tramp-handle-process-file
4341 (program &optional infile destination display &rest args)
4342 "Like `process-file' for Tramp files."
4343 ;; The implementation is not complete yet.
4344 (when (and (numberp destination) (zerop destination))
4345 (error "Implementation does not handle immediate return"))
4346
4347 (with-parsed-tramp-file-name default-directory nil
a6e96327 4348 (let (command input tmpinput stderr tmpstderr outbuf ret)
00d6fd04
MA
4349 ;; Compute command.
4350 (setq command (mapconcat 'tramp-shell-quote-argument
4351 (cons program args) " "))
4352 ;; Determine input.
4353 (if (null infile)
4354 (setq input "/dev/null")
4355 (setq infile (expand-file-name infile))
4356 (if (tramp-equal-remote default-directory infile)
4357 ;; INFILE is on the same remote host.
4358 (setq input (with-parsed-tramp-file-name infile nil localname))
4359 ;; INFILE must be copied to remote host.
a6e96327
MA
4360 (setq input (tramp-make-tramp-temp-file v)
4361 tmpinput (tramp-make-tramp-file-name method user host input))
4362 (copy-file infile tmpinput t)))
00d6fd04
MA
4363 (when input (setq command (format "%s <%s" command input)))
4364
4365 ;; Determine output.
4366 (cond
bede3e9f 4367 ;; Just a buffer.
00d6fd04
MA
4368 ((bufferp destination)
4369 (setq outbuf destination))
bede3e9f 4370 ;; A buffer name.
00d6fd04
MA
4371 ((stringp destination)
4372 (setq outbuf (get-buffer-create destination)))
4373 ;; (REAL-DESTINATION ERROR-DESTINATION)
4374 ((consp destination)
bede3e9f 4375 ;; output.
00d6fd04
MA
4376 (cond
4377 ((bufferp (car destination))
4378 (setq outbuf (car destination)))
4379 ((stringp (car destination))
0664ff72
MA
4380 (setq outbuf (get-buffer-create (car destination))))
4381 ((car destination)
4382 (setq outbuf (current-buffer))))
bede3e9f 4383 ;; stderr.
00d6fd04
MA
4384 (cond
4385 ((stringp (cadr destination))
4386 (setcar (cdr destination) (expand-file-name (cadr destination)))
4387 (if (tramp-equal-remote default-directory (cadr destination))
4388 ;; stderr is on the same remote host.
4389 (setq stderr (with-parsed-tramp-file-name
4390 (cadr destination) nil localname))
4391 ;; stderr must be copied to remote host. The temporary
4392 ;; file must be deleted after execution.
a6e96327
MA
4393 (setq stderr (tramp-make-tramp-temp-file v)
4394 tmpstderr (tramp-make-tramp-file-name
4395 method user host stderr))))
bede3e9f 4396 ;; stderr to be discarded.
00d6fd04
MA
4397 ((null (cadr destination))
4398 (setq stderr "/dev/null"))))
4399 ;; 't
4400 (destination
4401 (setq outbuf (current-buffer))))
4402 (when stderr (setq command (format "%s 2>%s" command stderr)))
4403
00d6fd04
MA
4404 ;; Send the command. It might not return in time, so we protect it.
4405 (condition-case nil
4406 (unwind-protect
293c24f9
MA
4407 (setq ret
4408 (tramp-send-command-and-check
4409 v (format "\\cd %s; %s"
4410 (tramp-shell-quote-argument localname)
b593f105
MA
4411 command)
4412 nil t))
00d6fd04
MA
4413 ;; We should show the output anyway.
4414 (when outbuf
293c24f9
MA
4415 (with-current-buffer outbuf
4416 (insert
4417 (with-current-buffer (tramp-get-connection-buffer v)
4418 (buffer-string))))
00d6fd04 4419 (when display (display-buffer outbuf))))
260821d3
MA
4420 ;; When the user did interrupt, we should do it also. We use
4421 ;; return code -1 as marker.
4422 (quit
4423 (kill-buffer (tramp-get-connection-buffer v))
4424 (setq ret -1))
4425 ;; Handle errors.
00d6fd04
MA
4426 (error
4427 (kill-buffer (tramp-get-connection-buffer v))
4428 (setq ret 1)))
a6e96327 4429
a6e96327
MA
4430 ;; Provide error file.
4431 (when tmpstderr (rename-file tmpstderr (cadr destination) t))
263c02ef 4432
260821d3
MA
4433 ;; Cleanup. We remove all file cache values for the connection,
4434 ;; because the remote process could have changed them.
a6e96327 4435 (when tmpinput (delete-file tmpinput))
946a5aeb
MA
4436
4437 ;; `process-file-side-effects' has been introduced with GNU
4438 ;; Emacs 23.2. If set to `nil', no remote file will be changed
4439 ;; by `program'. If it doesn't exist, we assume its default
4440 ;; value 't'.
4441 (unless (and (boundp 'process-file-side-effects)
4442 (not (symbol-value 'process-file-side-effects)))
4443 (tramp-flush-directory-property v ""))
4444
00d6fd04 4445 ;; Return exit status.
260821d3
MA
4446 (if (equal ret -1)
4447 (keyboard-quit)
4448 ret))))
00d6fd04 4449
a4aeb9a4
MA
4450(defun tramp-local-call-process
4451 (program &optional infile destination display &rest args)
4452 "Calls `call-process' on the local host.
4453This is needed because for some Emacs flavors Tramp has
4454defadviced `call-process' to behave like `process-file'. The
4455Lisp error raised when PROGRAM is nil is trapped also, returning 1."
4456 (let ((default-directory
4457 (if (file-remote-p default-directory)
4458 (tramp-compat-temporary-file-directory)
4459 default-directory)))
4460 (if (executable-find program)
4461 (apply 'call-process program infile destination display args)
4462 1)))
4463
00d6fd04
MA
4464(defun tramp-handle-call-process-region
4465 (start end program &optional delete buffer display &rest args)
4466 "Like `call-process-region' for Tramp files."
258800f8 4467 (let ((tmpfile (tramp-compat-make-temp-file "")))
00d6fd04
MA
4468 (write-region start end tmpfile)
4469 (when delete (delete-region start end))
4470 (unwind-protect
4471 (apply 'call-process program tmpfile buffer display args)
4472 (delete-file tmpfile))))
4473
4474(defun tramp-handle-shell-command
4475 (command &optional output-buffer error-buffer)
4476 "Like `shell-command' for Tramp files."
ce3f516f 4477 (let* ((asynchronous (string-match "[ \t]*&[ \t]*\\'" command))
b8bfcf96
MA
4478 ;; We cannot use `shell-file-name' and `shell-command-switch',
4479 ;; they are variables of the local host.
4480 (args (list "/bin/sh" "-c" (substring command 0 asynchronous)))
5d2ebd96 4481 current-buffer-p
ce3f516f 4482 (output-buffer
27e813fe
MA
4483 (cond
4484 ((bufferp output-buffer) output-buffer)
4485 ((stringp output-buffer) (get-buffer-create output-buffer))
5d2ebd96
AS
4486 (output-buffer
4487 (setq current-buffer-p t)
4488 (current-buffer))
42bc9b6d 4489 (t (get-buffer-create
27e813fe
MA
4490 (if asynchronous
4491 "*Async Shell Command*"
4492 "*Shell Command Output*")))))
4493 (error-buffer
4494 (cond
4495 ((bufferp error-buffer) error-buffer)
4496 ((stringp error-buffer) (get-buffer-create error-buffer))))
ce3f516f 4497 (buffer
27e813fe 4498 (if (and (not asynchronous) error-buffer)
ce3f516f
MA
4499 (with-parsed-tramp-file-name default-directory nil
4500 (list output-buffer (tramp-make-tramp-temp-file v)))
42bc9b6d 4501 output-buffer))
cfb5c0db 4502 (p (get-buffer-process output-buffer)))
42bc9b6d
MA
4503
4504 ;; Check whether there is another process running. Tramp does not
4505 ;; support 2 (asynchronous) processes in parallel.
cfb5c0db 4506 (when p
42bc9b6d 4507 (if (yes-or-no-p "A command is running. Kill it? ")
699a11fb
GM
4508 (condition-case nil
4509 (kill-process p)
4510 (error nil))
42bc9b6d
MA
4511 (error "Shell command in progress")))
4512
f34db316
AS
4513 (if current-buffer-p
4514 (progn
4515 (barf-if-buffer-read-only)
4516 (push-mark nil t))
5d2ebd96
AS
4517 (with-current-buffer output-buffer
4518 (setq buffer-read-only nil)
4519 (erase-buffer)))
42bc9b6d 4520
5d2ebd96 4521 (if (and (not current-buffer-p) (integerp asynchronous))
42bc9b6d
MA
4522 (prog1
4523 ;; Run the process.
3412f35d 4524 (apply 'start-file-process "*Async Shell*" buffer args)
42bc9b6d 4525 ;; Display output.
cfb5c0db
MA
4526 (pop-to-buffer output-buffer)
4527 (setq mode-line-process '(":%s"))
4528 (require 'shell) (shell-mode))
42bc9b6d
MA
4529
4530 (prog1
4531 ;; Run the process.
4532 (apply 'process-file (car args) nil buffer nil (cdr args))
4533 ;; Insert error messages if they were separated.
4534 (when (listp buffer)
4535 (with-current-buffer error-buffer
4536 (insert-file-contents (cadr buffer)))
4537 (delete-file (cadr buffer)))
f34db316
AS
4538 (if current-buffer-p
4539 ;; This is like exchange-point-and-mark, but doesn't
4540 ;; activate the mark. It is cleaner to avoid activation,
4541 ;; even though the command loop would deactivate the mark
4542 ;; because we inserted text.
4543 (goto-char (prog1 (mark t)
4544 (set-marker (mark-marker) (point)
4545 (current-buffer))))
4546 ;; There's some output, display it.
4547 (when (with-current-buffer output-buffer (> (point-max) (point-min)))
4548 (if (functionp 'display-message-or-buffer)
4549 (funcall (symbol-function 'display-message-or-buffer)
4550 output-buffer)
4551 (pop-to-buffer output-buffer))))))))
00d6fd04
MA
4552
4553;; File Editing.
4554
4555(defvar tramp-handle-file-local-copy-hook nil
4556 "Normal hook to be run at the end of `tramp-handle-file-local-copy'.")
4557
fb7933a3 4558(defun tramp-handle-file-local-copy (filename)
00d6fd04 4559 "Like `file-local-copy' for Tramp files."
0f205eee 4560
c62c9d08 4561 (with-parsed-tramp-file-name filename nil
2988341a
MA
4562 (unless (file-exists-p filename)
4563 (tramp-error
4564 v 'file-error
4565 "Cannot make local copy of non-existing file `%s'" filename))
4566
0f205eee 4567 (let ((rem-enc (tramp-get-remote-coding v "remote-encoding"))
00d6fd04 4568 (loc-dec (tramp-get-local-coding v "local-decoding"))
258800f8 4569 (tmpfile (tramp-compat-make-temp-file filename)))
5ec2cc41 4570
2988341a
MA
4571 (condition-case err
4572 (cond
4573 ;; `copy-file' handles direct copy and out-of-band methods.
4574 ((or (tramp-local-host-p v)
7f49fe46
MA
4575 (tramp-method-out-of-band-p
4576 v (nth 7 (file-attributes filename))))
2988341a
MA
4577 (copy-file filename tmpfile t t))
4578
4579 ;; Use inline encoding for file transfer.
4580 (rem-enc
4581 (save-excursion
4582 (tramp-message v 5 "Encoding remote file %s..." filename)
4583 (tramp-barf-unless-okay
4584 v
4585 (format "%s < %s" rem-enc (tramp-shell-quote-argument localname))
4586 "Encoding remote file failed")
4587 (tramp-message v 5 "Encoding remote file %s...done" filename)
4588
4589 (if (and (symbolp loc-dec) (fboundp loc-dec))
4590 ;; If local decoding is a function, we call it. We
4591 ;; must disable multibyte, because
4592 ;; `uudecode-decode-region' doesn't handle it
4593 ;; correctly.
0f205eee
MA
4594 (with-temp-buffer
4595 (set-buffer-multibyte nil)
4596 (insert-buffer-substring (tramp-get-buffer v))
4597 (tramp-message
4598 v 5 "Decoding remote file %s with function %s..."
4599 filename loc-dec)
4600 (funcall loc-dec (point-min) (point-max))
aa485f7c
MA
4601 ;; Unset `file-name-handler-alist'. Otherwise,
4602 ;; epa-file gets confused.
4603 (let (file-name-handler-alist
4604 (coding-system-for-write 'binary))
2988341a
MA
4605 (write-region (point-min) (point-max) tmpfile)))
4606
4607 ;; If tramp-decoding-function is not defined for this
4608 ;; method, we invoke tramp-decoding-command instead.
4609 (let ((tmpfile2 (tramp-compat-make-temp-file filename)))
aa485f7c
MA
4610 ;; Unset `file-name-handler-alist'. Otherwise,
4611 ;; epa-file gets confused.
4612 (let (file-name-handler-alist
4613 (coding-system-for-write 'binary))
2988341a
MA
4614 (write-region (point-min) (point-max) tmpfile2))
4615 (tramp-message
4616 v 5 "Decoding remote file %s with command %s..."
4617 filename loc-dec)
4618 (unwind-protect
4619 (tramp-call-local-coding-command loc-dec tmpfile2 tmpfile)
4620 (delete-file tmpfile2))))
4621
4622 (tramp-message v 5 "Decoding remote file %s...done" filename)
4623 ;; Set proper permissions.
b86c1cd8 4624 (set-file-modes tmpfile (tramp-default-file-modes filename))
2988341a
MA
4625 ;; Set local user ownership.
4626 (tramp-set-file-uid-gid tmpfile)))
4627
4628 ;; Oops, I don't know what to do.
4629 (t (tramp-error
4630 v 'file-error "Wrong method specification for `%s'" method)))
4631
4632 ;; Error handling.
4633 ((error quit)
4634 (delete-file tmpfile)
4635 (signal (car err) (cdr err))))
0f205eee 4636
00d6fd04 4637 (run-hooks 'tramp-handle-file-local-copy-hook)
94be87e8 4638 tmpfile)))
fb7933a3 4639
bce04fee 4640(defun tramp-handle-file-remote-p (filename &optional identification connected)
00d6fd04 4641 "Like `file-remote-p' for Tramp files."
15cc764c 4642 (when (tramp-tramp-file-p filename)
a09dc9bf 4643 (with-parsed-tramp-file-name (expand-file-name filename) nil
00d6fd04
MA
4644 (and (or (not connected)
4645 (let ((p (tramp-get-connection-process v)))
4646 (and p (processp p) (memq (process-status p) '(run open)))))
ce3f516f
MA
4647 (cond
4648 ((eq identification 'method) method)
4649 ((eq identification 'user) user)
4650 ((eq identification 'host) host)
8d60099b 4651 ((eq identification 'localname) localname)
ce3f516f 4652 (t (tramp-make-tramp-file-name method user host "")))))))
fb7933a3 4653
eb562962
MA
4654(defun tramp-find-file-name-coding-system-alist (filename tmpname)
4655 "Like `find-operation-coding-system' for Tramp filenames.
4656Tramp's `insert-file-contents' and `write-region' work over
4657temporary file names. If `file-coding-system-alist' contains an
4658expression, which matches more than the file name suffix, the
4659coding system might not be determined. This function repairs it."
4660 (let (result)
4661 (dolist (elt file-coding-system-alist result)
4662 (when (and (consp elt) (string-match (car elt) filename))
4663 ;; We found a matching entry in `file-coding-system-alist'.
4664 ;; So we add a similar entry, but with the temporary file name
4665 ;; as regexp.
4666 (add-to-list
4667 'result (cons (regexp-quote tmpname) (cdr elt)) 'append)))))
4668
fb7933a3
KG
4669(defun tramp-handle-insert-file-contents
4670 (filename &optional visit beg end replace)
00d6fd04 4671 "Like `insert-file-contents' for Tramp files."
fb7933a3
KG
4672 (barf-if-buffer-read-only)
4673 (setq filename (expand-file-name filename))
736ac90f 4674 (let (coding-system-used result local-copy remote-copy)
2ac33804
MA
4675 (with-parsed-tramp-file-name filename nil
4676 (unwind-protect
70c11b0b
MA
4677 (if (not (file-exists-p filename))
4678 ;; We don't raise a Tramp error, because it might be
4679 ;; suppressed, like in `find-file-noselect-1'.
4680 (signal 'file-error
4681 (list "File not found on remote host" filename))
4682
4683 (if (and (tramp-local-host-p v)
4684 (let (file-name-handler-alist)
4685 (file-readable-p localname)))
4686 ;; Short track: if we are on the local host, we can
4687 ;; run directly.
4688 (setq result
4689 (tramp-run-real-handler
4690 'insert-file-contents
4691 (list localname visit beg end replace)))
4692
736ac90f
MA
4693 ;; When we shall insert only a part of the file, we copy
4694 ;; this part.
4695 (when (or beg end)
4696 (setq remote-copy (tramp-make-tramp-temp-file v))
4697 (tramp-send-command
4698 v
4699 (cond
4700 ((and beg end)
4701 (format "tail -c +%d %s | head -c +%d >%s"
4702 (1+ beg) (tramp-shell-quote-argument localname)
4703 (- end beg) remote-copy))
4704 (beg
4705 (format "tail -c +%d %s >%s"
4706 (1+ beg) (tramp-shell-quote-argument localname)
4707 remote-copy))
4708 (end
4709 (format "head -c +%d %s >%s"
4710 (1+ end) (tramp-shell-quote-argument localname)
4711 remote-copy)))))
4712
70c11b0b
MA
4713 ;; `insert-file-contents-literally' takes care to avoid
4714 ;; calling jka-compr. By let-binding
4715 ;; `inhibit-file-name-operation', we propagate that care
4716 ;; to the `file-local-copy' operation.
4717 (setq local-copy
4718 (let ((inhibit-file-name-operation
4719 (when (eq inhibit-file-name-operation
4720 'insert-file-contents)
4721 'file-local-copy)))
b88f2d0a
MA
4722 (cond
4723 ((stringp remote-copy)
4724 (file-local-copy
4725 (tramp-make-tramp-file-name
4726 method user host remote-copy)))
4727 ((stringp tramp-temp-buffer-file-name)
4728 (copy-file filename tramp-temp-buffer-file-name 'ok)
4729 tramp-temp-buffer-file-name)
4730 (t (file-local-copy filename)))))
4731
4732 (when (and (null remote-copy)
4733 (tramp-get-method-parameter
4734 method 'tramp-copy-keep-tmpfile))
4735 ;; We keep the local file for performance reasons,
4736 ;; useful for "rsync".
4737 (set-file-modes local-copy (tramp-octal-to-decimal "0600"))
4738 (setq tramp-temp-buffer-file-name local-copy)
4739 (put 'tramp-temp-buffer-file-name 'permanent-local t))
4740
70c11b0b
MA
4741 (tramp-message
4742 v 4 "Inserting local temp file `%s'..." local-copy)
4743
4744 ;; We must ensure that `file-coding-system-alist'
4745 ;; matches `local-copy'.
4746 (let ((file-coding-system-alist
4747 (tramp-find-file-name-coding-system-alist
4748 filename local-copy)))
4749 (setq result
4750 (insert-file-contents
736ac90f 4751 local-copy nil nil nil replace))
70c11b0b
MA
4752 ;; Now `last-coding-system-used' has right value.
4753 ;; Remember it.
4754 (when (boundp 'last-coding-system-used)
4755 (setq coding-system-used
4756 (symbol-value 'last-coding-system-used))))
8d60099b 4757
70c11b0b
MA
4758 (tramp-message
4759 v 4 "Inserting local temp file `%s'...done" local-copy)
4760 (when (boundp 'last-coding-system-used)
2ac33804 4761 (set 'last-coding-system-used coding-system-used))))
70c11b0b 4762
2ac33804
MA
4763 ;; Save exit.
4764 (progn
4765 (when visit
4766 (setq buffer-file-name filename)
4767 (setq buffer-read-only (not (file-writable-p filename)))
4768 (set-visited-file-modtime)
4769 (set-buffer-modified-p nil))
b88f2d0a
MA
4770 (when (and (stringp local-copy)
4771 (or remote-copy (null tramp-temp-buffer-file-name)))
2ac33804
MA
4772 (delete-file local-copy))
4773 (when (stringp remote-copy)
4774 (delete-file
4775 (tramp-make-tramp-file-name method user host remote-copy))))))
70c11b0b
MA
4776
4777 ;; Result.
4778 (list (expand-file-name filename)
4779 (cadr result))))
fb7933a3 4780
94be87e8
MA
4781;; This is needed for XEmacs only. Code stolen from files.el.
4782(defun tramp-handle-insert-file-contents-literally
4783 (filename &optional visit beg end replace)
4784 "Like `insert-file-contents-literally' for Tramp files."
4785 (let ((format-alist nil)
4786 (after-insert-file-functions nil)
4787 (coding-system-for-read 'no-conversion)
4788 (coding-system-for-write 'no-conversion)
4789 (find-buffer-file-type-function
4790 (if (fboundp 'find-buffer-file-type)
4791 (symbol-function 'find-buffer-file-type)
4792 nil))
4793 (inhibit-file-name-handlers '(jka-compr-handler image-file-handler))
4794 (inhibit-file-name-operation 'insert-file-contents))
4795 (unwind-protect
4796 (progn
4797 (fset 'find-buffer-file-type (lambda (filename) t))
4798 (insert-file-contents filename visit beg end replace))
70c11b0b 4799 ;; Save exit.
94be87e8
MA
4800 (if find-buffer-file-type-function
4801 (fset 'find-buffer-file-type find-buffer-file-type-function)
4802 (fmakunbound 'find-buffer-file-type)))))
4803
38c65fca 4804(defun tramp-handle-find-backup-file-name (filename)
00d6fd04 4805 "Like `find-backup-file-name' for Tramp files."
07dfe738
KG
4806 (with-parsed-tramp-file-name filename nil
4807 ;; We set both variables. It doesn't matter whether it is
4808 ;; Emacs or XEmacs
4809 (let ((backup-directory-alist
4810 ;; Emacs case
4811 (when (boundp 'backup-directory-alist)
b86c1cd8 4812 (if (symbol-value 'tramp-backup-directory-alist)
07dfe738 4813 (mapcar
aa485f7c
MA
4814 (lambda (x)
4815 (cons
4816 (car x)
4817 (if (and (stringp (cdr x))
4818 (file-name-absolute-p (cdr x))
4819 (not (tramp-file-name-p (cdr x))))
4820 (tramp-make-tramp-file-name method user host (cdr x))
4821 (cdr x))))
07dfe738
KG
4822 (symbol-value 'tramp-backup-directory-alist))
4823 (symbol-value 'backup-directory-alist))))
4824
4825 (bkup-backup-directory-info
4826 ;; XEmacs case
4827 (when (boundp 'bkup-backup-directory-info)
b86c1cd8 4828 (if (symbol-value 'tramp-bkup-backup-directory-info)
07dfe738 4829 (mapcar
aa485f7c
MA
4830 (lambda (x)
4831 (nconc
4832 (list (car x))
4833 (list
4834 (if (and (stringp (car (cdr x)))
4835 (file-name-absolute-p (car (cdr x)))
4836 (not (tramp-file-name-p (car (cdr x)))))
4837 (tramp-make-tramp-file-name
4838 method user host (car (cdr x)))
4839 (car (cdr x))))
4840 (cdr (cdr x))))
07dfe738
KG
4841 (symbol-value 'tramp-bkup-backup-directory-info))
4842 (symbol-value 'bkup-backup-directory-info)))))
4843
4844 (tramp-run-real-handler 'find-backup-file-name (list filename)))))
38c65fca 4845
c1105d05 4846(defun tramp-handle-make-auto-save-file-name ()
00d6fd04 4847 "Like `make-auto-save-file-name' for Tramp files.
c1105d05 4848Returns a file name in `tramp-auto-save-directory' for autosaving this file."
00d6fd04
MA
4849 (let ((tramp-auto-save-directory tramp-auto-save-directory)
4850 (buffer-file-name
4851 (tramp-subst-strs-in-string
4852 '(("_" . "|")
4853 ("/" . "_a")
4854 (":" . "_b")
4855 ("|" . "__")
4856 ("[" . "_l")
4857 ("]" . "_r"))
4858 (buffer-file-name))))
1a762140
MA
4859 ;; File name must be unique. This is ensured with Emacs 22 (see
4860 ;; UNIQUIFY element of `auto-save-file-name-transforms'); but for
4861 ;; all other cases we must do it ourselves.
4862 (when (boundp 'auto-save-file-name-transforms)
9e6ab520 4863 (mapc
aa485f7c
MA
4864 (lambda (x)
4865 (when (and (string-match (car x) buffer-file-name)
4866 (not (car (cddr x))))
4867 (setq tramp-auto-save-directory
4868 (or tramp-auto-save-directory
4869 (tramp-compat-temporary-file-directory)))))
1a762140
MA
4870 (symbol-value 'auto-save-file-name-transforms)))
4871 ;; Create directory.
4872 (when tramp-auto-save-directory
00d6fd04
MA
4873 (setq buffer-file-name
4874 (expand-file-name buffer-file-name tramp-auto-save-directory))
1a762140
MA
4875 (unless (file-exists-p tramp-auto-save-directory)
4876 (make-directory tramp-auto-save-directory t)))
00d6fd04
MA
4877 ;; Run plain `make-auto-save-file-name'. There might be an advice when
4878 ;; it is not a magic file name operation (since Emacs 22).
4879 ;; We must deactivate it temporarily.
4880 (if (not (ad-is-active 'make-auto-save-file-name))
4881 (tramp-run-real-handler 'make-auto-save-file-name nil)
4882 ;; else
4883 (ad-deactivate 'make-auto-save-file-name)
4884 (prog1
4885 (tramp-run-real-handler 'make-auto-save-file-name nil)
4886 (ad-activate 'make-auto-save-file-name)))))
4887
4888(defvar tramp-handle-write-region-hook nil
4889 "Normal hook to be run at the end of `tramp-handle-write-region'.")
4890
b88f2d0a 4891;; CCC grok LOCKNAME
fb7933a3
KG
4892(defun tramp-handle-write-region
4893 (start end filename &optional append visit lockname confirm)
00d6fd04 4894 "Like `write-region' for Tramp files."
fb7933a3 4895 (setq filename (expand-file-name filename))
c62c9d08 4896 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
4897 ;; Following part commented out because we don't know what to do about
4898 ;; file locking, and it does not appear to be a problem to ignore it.
4899 ;; Ange-ftp ignores it, too.
4900 ;; (when (and lockname (stringp lockname))
4901 ;; (setq lockname (expand-file-name lockname)))
4902 ;; (unless (or (eq lockname nil)
4903 ;; (string= lockname filename))
4904 ;; (error
4905 ;; "tramp-handle-write-region: LOCKNAME must be nil or equal FILENAME"))
8d60099b 4906
94be87e8 4907 ;; XEmacs takes a coding system as the seventh argument, not `confirm'.
00d6fd04
MA
4908 (when (and (not (featurep 'xemacs)) confirm (file-exists-p filename))
4909 (unless (y-or-n-p (format "File %s exists; overwrite anyway? " filename))
4910 (tramp-error v 'file-error "File not overwritten")))
8d60099b 4911
a4aeb9a4 4912 (let ((uid (or (nth 2 (tramp-compat-file-attributes filename 'integer))
9c13938d 4913 (tramp-get-remote-uid v 'integer)))
a4aeb9a4 4914 (gid (or (nth 3 (tramp-compat-file-attributes filename 'integer))
9c13938d
MA
4915 (tramp-get-remote-gid v 'integer))))
4916
4917 (if (and (tramp-local-host-p v)
93c3eb7c 4918 ;; `file-writable-p' calls `file-expand-file-name'. We
87bdd2c7
MA
4919 ;; cannot use `tramp-run-real-handler' therefore.
4920 (let (file-name-handler-alist)
82f3844e
MA
4921 (and
4922 (file-writable-p (file-name-directory localname))
4923 (or (file-directory-p localname)
4924 (file-writable-p localname)))))
9c13938d 4925 ;; Short track: if we are on the local host, we can run directly.
93c3eb7c
MA
4926 (progn
4927 (tramp-run-real-handler
4928 'write-region
4929 (list start end localname append 'no-message lockname confirm))
3e2fa353 4930 (tramp-flush-file-property v localname))
9c13938d
MA
4931
4932 (let ((rem-dec (tramp-get-remote-coding v "remote-decoding"))
4933 (loc-enc (tramp-get-local-coding v "local-encoding"))
b86c1cd8 4934 (modes (save-excursion (tramp-default-file-modes filename)))
9c13938d
MA
4935 ;; We use this to save the value of
4936 ;; `last-coding-system-used' after writing the tmp file.
4937 ;; At the end of the function, we set
4938 ;; `last-coding-system-used' to this saved value. This
4939 ;; way, any intermediary coding systems used while
4940 ;; talking to the remote shell or suchlike won't hose
4941 ;; this variable. This approach was snarfed from
4942 ;; ange-ftp.el.
4943 coding-system-used
4944 ;; Write region into a tmp file. This isn't really
4945 ;; needed if we use an encoding function, but currently
4946 ;; we use it always because this makes the logic
293c24f9
MA
4947 ;; simpler.
4948 (tmpfile (or tramp-temp-buffer-file-name
4949 (tramp-compat-make-temp-file filename))))
4950
4951 ;; If `append' is non-nil, we copy the file locally, and let
4952 ;; the native `write-region' implementation do the job.
4953 (when append (copy-file filename tmpfile 'ok))
9c13938d
MA
4954
4955 ;; We say `no-message' here because we don't want the
4956 ;; visited file modtime data to be clobbered from the temp
4957 ;; file. We call `set-visited-file-modtime' ourselves later
eb562962
MA
4958 ;; on. We must ensure that `file-coding-system-alist'
4959 ;; matches `tmpfile'.
4960 (let ((file-coding-system-alist
4961 (tramp-find-file-name-coding-system-alist filename tmpfile)))
ce2cc728
MA
4962 (condition-case err
4963 (tramp-run-real-handler
4964 'write-region
4965 (list start end tmpfile append 'no-message lockname confirm))
2988341a 4966 ((error quit)
b88f2d0a 4967 (setq tramp-temp-buffer-file-name nil)
2988341a
MA
4968 (delete-file tmpfile)
4969 (signal (car err) (cdr err))))
ce2cc728 4970
eb562962
MA
4971 ;; Now, `last-coding-system-used' has the right value. Remember it.
4972 (when (boundp 'last-coding-system-used)
4973 (setq coding-system-used
4974 (symbol-value 'last-coding-system-used))))
4975
9c13938d
MA
4976 ;; The permissions of the temporary file should be set. If
4977 ;; filename does not exist (eq modes nil) it has been
4978 ;; renamed to the backup file. This case `save-buffer'
4979 ;; handles permissions.
4980 (when modes (set-file-modes tmpfile modes))
4981
4982 ;; This is a bit lengthy due to the different methods
4983 ;; possible for file transfer. First, we check whether the
4984 ;; method uses an rcp program. If so, we call it.
4985 ;; Otherwise, both encoding and decoding command must be
4986 ;; specified. However, if the method _also_ specifies an
4987 ;; encoding function, then that is used for encoding the
4988 ;; contents of the tmp file.
4989 (cond
4990 ;; `rename-file' handles direct copy and out-of-band methods.
4991 ((or (tramp-local-host-p v)
7f49fe46
MA
4992 (tramp-method-out-of-band-p
4993 v (- (or end (point-max)) (or start (point-min)))))
191bb792
MA
4994 (if (and (= (or end (point-max)) (point-max))
4995 (= (or start (point-min)) (point-min))
4996 (tramp-get-method-parameter
4997 method 'tramp-copy-keep-tmpfile))
4998 (progn
4999 (setq tramp-temp-buffer-file-name tmpfile)
5000 (condition-case err
b88f2d0a
MA
5001 ;; We keep the local file for performance
5002 ;; reasons, useful for "rsync".
191bb792
MA
5003 (copy-file tmpfile filename t)
5004 ((error quit)
5005 (setq tramp-temp-buffer-file-name nil)
5006 (delete-file tmpfile)
5007 (signal (car err) (cdr err)))))
5008 (setq tramp-temp-buffer-file-name nil)
5009 ;; Don't rename, in order to keep context in SELinux.
5010 (unwind-protect
5011 (copy-file tmpfile filename t)
5012 (delete-file tmpfile))))
9c13938d 5013
1d7e9a01 5014 ;; Use inline file transfer.
9c13938d 5015 (rem-dec
1d7e9a01 5016 ;; Encode tmpfile.
9c13938d
MA
5017 (tramp-message v 5 "Encoding region...")
5018 (unwind-protect
5019 (with-temp-buffer
5020 ;; Use encoding function or command.
5021 (if (and (symbolp loc-enc) (fboundp loc-enc))
5022 (progn
5023 (tramp-message
5024 v 5 "Encoding region using function `%s'..."
5025 (symbol-name loc-enc))
5026 (let ((coding-system-for-read 'binary))
5027 (insert-file-contents-literally tmpfile))
70c11b0b
MA
5028 ;; The following `let' is a workaround for the
5029 ;; base64.el that comes with pgnus-0.84. If
5030 ;; both of the following conditions are
5031 ;; satisfied, it tries to write to a local
5032 ;; file in default-directory, but at this
5033 ;; point, default-directory is remote.
5034 ;; (`call-process-region' can't write to
5035 ;; remote files, it seems.) The file in
5036 ;; question is a tmp file anyway.
9c13938d
MA
5037 (let ((default-directory
5038 (tramp-compat-temporary-file-directory)))
5039 (funcall loc-enc (point-min) (point-max))))
8d60099b 5040
9c13938d
MA
5041 (tramp-message
5042 v 5 "Encoding region using command `%s'..." loc-enc)
5043 (unless (equal 0 (tramp-call-local-coding-command
5044 loc-enc tmpfile t))
5045 (tramp-error
5046 v 'file-error
5047 "Cannot write to `%s', local encoding command `%s' failed"
5048 filename loc-enc)))
5049
5050 ;; Send buffer into remote decoding command which
5051 ;; writes to remote file. Because this happens on
5052 ;; the remote host, we cannot use the function.
5053 (goto-char (point-max))
5054 (unless (bolp) (newline))
8d60099b 5055 (tramp-message
9c13938d
MA
5056 v 5 "Decoding region into remote file %s..." filename)
5057 (tramp-send-command
5058 v
5059 (format
5060 "%s >%s <<'EOF'\n%sEOF"
5061 rem-dec
5062 (tramp-shell-quote-argument localname)
5063 (buffer-string)))
5064 (tramp-barf-unless-okay
5065 v nil
5066 "Couldn't write region to `%s', decode using `%s' failed"
5067 filename rem-dec)
5068 ;; When `file-precious-flag' is set, the region is
5069 ;; written to a temporary file. Check that the
5070 ;; checksum is equal to that from the local tmpfile.
5071 (when file-precious-flag
5072 (erase-buffer)
5073 (and
a4aeb9a4
MA
5074 ;; cksum runs locally, if possible.
5075 (zerop (tramp-local-call-process "cksum" tmpfile t))
5076 ;; cksum runs remotely.
9c13938d
MA
5077 (zerop
5078 (tramp-send-command-and-check
5079 v
5080 (format
5081 "cksum <%s" (tramp-shell-quote-argument localname))))
a4aeb9a4 5082 ;; ... they are different.
9c13938d
MA
5083 (not
5084 (string-equal
5085 (buffer-string)
5086 (with-current-buffer (tramp-get-buffer v)
5087 (buffer-string))))
5088 (tramp-error
5089 v 'file-error
5090 (concat "Couldn't write region to `%s',"
5091 " decode using `%s' failed")
5092 filename rem-dec)))
5093 (tramp-message
5094 v 5 "Decoding region into remote file %s...done" filename)
5095 (tramp-flush-file-property v localname))
8d60099b 5096
9c13938d
MA
5097 ;; Save exit.
5098 (delete-file tmpfile)))
8d60099b 5099
9c13938d
MA
5100 ;; That's not expected.
5101 (t
5102 (tramp-error
5103 v 'file-error
5104 (concat "Method `%s' should specify both encoding and "
5105 "decoding command or an rcp program")
5106 method)))
258800f8 5107
9c13938d
MA
5108 ;; Make `last-coding-system-used' have the right value.
5109 (when coding-system-used
5110 (set 'last-coding-system-used coding-system-used))))
0f205eee 5111
57671b72
MA
5112 ;; We must protect `last-coding-system-used', now we have set it
5113 ;; to its correct value.
293c24f9 5114 (let (last-coding-system-used (need-chown t))
57671b72
MA
5115 ;; Set file modification time.
5116 (when (or (eq visit t) (stringp visit))
293c24f9
MA
5117 (let ((file-attr (file-attributes filename)))
5118 (set-visited-file-modtime
5119 ;; We must pass modtime explicitely, because filename can
5120 ;; be different from (buffer-file-name), f.e. if
5121 ;; `file-precious-flag' is set.
5122 (nth 5 file-attr))
5123 (when (and (eq (nth 2 file-attr) uid)
5124 (eq (nth 3 file-attr) gid))
5125 (setq need-chown nil))))
57671b72
MA
5126
5127 ;; Set the ownership.
293c24f9
MA
5128 (when need-chown
5129 (tramp-set-file-uid-gid filename uid gid))
57671b72
MA
5130 (when (or (eq visit t) (null visit) (stringp visit))
5131 (tramp-message v 0 "Wrote %s" filename))
5132 (run-hooks 'tramp-handle-write-region-hook)))))
fb7933a3 5133
946a5aeb
MA
5134(defvar tramp-vc-registered-file-names nil
5135 "List used to collect file names, which are checked during `vc-registered'.")
5136
5137;; VC backends check for the existence of various different special
5138;; files. This is very time consuming, because every single check
5139;; requires a remote command (the file cache must be invalidated).
5140;; Therefore, we apply a kind of optimization. We install the file
5141;; name handler `tramp-vc-file-name-handler', which does nothing but
5142;; remembers all file names for which `file-exists-p' or
5143;; `file-readable-p' has been applied. A first run of `vc-registered'
5144;; is performed. Afterwards, a script is applied for all collected
5145;; file names, using just one remote command. The result of this
5146;; script is used to fill the file cache with actual values. Now we
5147;; can reset the file name handlers, and we make a second run of
5148;; `vc-registered', which returns the expected result without sending
5149;; any other remote command.
49096407
MA
5150(defun tramp-handle-vc-registered (file)
5151 "Like `vc-registered' for Tramp files."
946a5aeb 5152 (with-parsed-tramp-file-name file nil
7f49fe46
MA
5153
5154 ;; There could be new files, created by the vc backend. We cannot
5155 ;; reuse the old cache entries, therefore.
946a5aeb
MA
5156 (let (tramp-vc-registered-file-names
5157 (tramp-cache-inhibit-cache (current-time))
5158 (file-name-handler-alist
5159 `((,tramp-file-name-regexp . tramp-vc-file-name-handler))))
5160
5161 ;; Here we collect only file names, which need an operation.
5162 (tramp-run-real-handler 'vc-registered (list file))
5163 (tramp-message v 10 "\n%s" tramp-vc-registered-file-names)
5164
5165 ;; Send just one command, in order to fill the cache.
7f49fe46
MA
5166 (when tramp-vc-registered-file-names
5167 (tramp-maybe-send-script
5168 v
5169 (format tramp-vc-registered-read-file-names
5170 (tramp-get-file-exists-command v)
5171 (format "%s -r" (tramp-get-test-command v)))
5172 "tramp_vc_registered_read_file_names")
5173
5174 (dolist
5175 (elt
5176 (tramp-send-command-and-read
5177 v
5178 (format
5179 "tramp_vc_registered_read_file_names %s"
5180 (mapconcat 'tramp-shell-quote-argument
5181 tramp-vc-registered-file-names
5182 " "))))
946a5aeb 5183
7f49fe46 5184 (tramp-set-file-property v (car elt) (cadr elt) (cadr (cdr elt))))))
946a5aeb 5185
7f49fe46
MA
5186 ;; Second run. Now all `file-exists-p' or `file-readable-p' calls
5187 ;; shall be answered from the file cache.
5188 ;; We unset `process-file-side-effects' in order to keep the cache
5189 ;; when `process-file' calls appear.
946a5aeb
MA
5190 (let (process-file-side-effects)
5191 (tramp-run-real-handler 'vc-registered (list file)))))
49096407 5192
a01b1e22
MA
5193;;;###autoload
5194(progn (defun tramp-run-real-handler (operation args)
fb7933a3 5195 "Invoke normal file name handler for OPERATION.
c62c9d08
KG
5196First arg specifies the OPERATION, second arg is a list of arguments to
5197pass to the OPERATION."
4007ba5b
KG
5198 (let* ((inhibit-file-name-handlers
5199 `(tramp-file-name-handler
946a5aeb 5200 tramp-vc-file-name-handler
4007ba5b
KG
5201 tramp-completion-file-name-handler
5202 cygwin-mount-name-hook-function
5203 cygwin-mount-map-drive-hook-function
5204 .
5205 ,(and (eq inhibit-file-name-operation operation)
5206 inhibit-file-name-handlers)))
5207 (inhibit-file-name-operation operation))
a01b1e22 5208 (apply operation args))))
16674e4f 5209
a01b1e22
MA
5210;;;###autoload
5211(progn (defun tramp-completion-run-real-handler (operation args)
16674e4f
KG
5212 "Invoke `tramp-file-name-handler' for OPERATION.
5213First arg specifies the OPERATION, second arg is a list of arguments to
5214pass to the OPERATION."
4007ba5b
KG
5215 (let* ((inhibit-file-name-handlers
5216 `(tramp-completion-file-name-handler
5217 cygwin-mount-name-hook-function
5218 cygwin-mount-map-drive-hook-function
5219 .
5220 ,(and (eq inhibit-file-name-operation operation)
5221 inhibit-file-name-handlers)))
5222 (inhibit-file-name-operation operation))
a01b1e22 5223 (apply operation args))))
fb7933a3 5224
4007ba5b
KG
5225;; We handle here all file primitives. Most of them have the file
5226;; name as first parameter; nevertheless we check for them explicitly
04bf5b65 5227;; in order to be signaled if a new primitive appears. This
4007ba5b
KG
5228;; scenario is needed because there isn't a way to decide by
5229;; syntactical means whether a foreign method must be called. It would
19a87064 5230;; ease the life if `file-name-handler-alist' would support a decision
4007ba5b
KG
5231;; function as well but regexp only.
5232(defun tramp-file-name-for-operation (operation &rest args)
5233 "Return file name related to OPERATION file primitive.
5234ARGS are the arguments OPERATION has been called with."
5235 (cond
5236 ; FILE resp DIRECTORY
5237 ((member operation
5238 (list 'access-file 'byte-compiler-base-file-name 'delete-directory
5239 'delete-file 'diff-latest-backup-file 'directory-file-name
5240 'directory-files 'directory-files-and-attributes
5241 'dired-compress-file 'dired-uncache
5242 'file-accessible-directory-p 'file-attributes
5243 'file-directory-p 'file-executable-p 'file-exists-p
19a87064
MA
5244 'file-local-copy 'file-remote-p 'file-modes
5245 'file-name-as-directory 'file-name-directory
5246 'file-name-nondirectory 'file-name-sans-versions
5247 'file-ownership-preserved-p 'file-readable-p
5248 'file-regular-p 'file-symlink-p 'file-truename
5249 'file-writable-p 'find-backup-file-name 'find-file-noselect
5250 'get-file-buffer 'insert-directory 'insert-file-contents
5251 'load 'make-directory 'make-directory-internal
5252 'set-file-modes 'substitute-in-file-name
5253 'unhandled-file-name-directory 'vc-registered
ce3f516f
MA
5254 ; Emacs 22 only
5255 'set-file-times
4007ba5b
KG
5256 ; XEmacs only
5257 'abbreviate-file-name 'create-file-buffer
5258 'dired-file-modtime 'dired-make-compressed-filename
5259 'dired-recursive-delete-directory 'dired-set-file-modtime
5260 'dired-shell-unhandle-file-name 'dired-uucode-file
5615d63f 5261 'insert-file-contents-literally 'make-temp-name 'recover-file
4007ba5b 5262 'vm-imap-check-mail 'vm-pop-check-mail 'vm-spool-check-mail))
8daea7fc
KG
5263 (if (file-name-absolute-p (nth 0 args))
5264 (nth 0 args)
5265 (expand-file-name (nth 0 args))))
4007ba5b
KG
5266 ; FILE DIRECTORY resp FILE1 FILE2
5267 ((member operation
5268 (list 'add-name-to-file 'copy-file 'expand-file-name
5269 'file-name-all-completions 'file-name-completion
5270 'file-newer-than-file-p 'make-symbolic-link 'rename-file
263c02ef
MA
5271 ; Emacs 23 only
5272 'copy-directory
4007ba5b
KG
5273 ; XEmacs only
5274 'dired-make-relative-symlink
5275 'vm-imap-move-mail 'vm-pop-move-mail 'vm-spool-move-mail))
5276 (save-match-data
5277 (cond
5278 ((string-match tramp-file-name-regexp (nth 0 args)) (nth 0 args))
5279 ((string-match tramp-file-name-regexp (nth 1 args)) (nth 1 args))
5280 (t (buffer-file-name (current-buffer))))))
5281 ; START END FILE
5282 ((eq operation 'write-region)
5283 (nth 2 args))
5284 ; BUF
5285 ((member operation
00d6fd04 5286 (list 'set-visited-file-modtime 'verify-visited-file-modtime
b50dd0d2 5287 ; since Emacs 22 only
00d6fd04
MA
5288 'make-auto-save-file-name
5289 ; XEmacs only
4007ba5b
KG
5290 'backup-buffer))
5291 (buffer-file-name
5292 (if (bufferp (nth 0 args)) (nth 0 args) (current-buffer))))
5293 ; COMMAND
5294 ((member operation
00d6fd04
MA
5295 (list ; not in Emacs 23
5296 'dired-call-process
01917a18 5297 ; Emacs only
b71c9e75 5298 'shell-command
00d6fd04 5299 ; since Emacs 22 only
0457dd55 5300 'process-file
00d6fd04
MA
5301 ; since Emacs 23 only
5302 'start-file-process
4007ba5b 5303 ; XEmacs only
00d6fd04
MA
5304 'dired-print-file 'dired-shell-call-process
5305 ; nowhere yet
5306 'executable-find 'start-process 'call-process))
4007ba5b
KG
5307 default-directory)
5308 ; unknown file primitive
5309 (t (error "unknown file I/O primitive: %s" operation))))
5310
5311(defun tramp-find-foreign-file-name-handler (filename)
5312 "Return foreign file name handler if exists."
9ce8462a
MA
5313 (when (and (stringp filename) (tramp-tramp-file-p filename))
5314 (let ((v (tramp-dissect-file-name filename t))
5315 (handler tramp-foreign-file-name-handler-alist)
5316 elt res)
5317 ;; When we are not fully sure that filename completion is safe,
5318 ;; we should not return a handler.
5319 (when (or (tramp-file-name-method v) (tramp-file-name-user v)
1834b39f
MA
5320 (and (tramp-file-name-host v)
5321 (not (member (tramp-file-name-host v)
5322 (mapcar 'car tramp-methods))))
9ce8462a
MA
5323 (not (tramp-completion-mode-p)))
5324 (while handler
5325 (setq elt (car handler)
5326 handler (cdr handler))
5327 (when (funcall (car elt) filename)
5328 (setq handler nil
5329 res (cdr elt))))
5330 res))))
4007ba5b 5331
fb7933a3
KG
5332;; Main function.
5333;;;###autoload
5334(defun tramp-file-name-handler (operation &rest args)
ea9d1443 5335 "Invoke Tramp file name handler.
a4aeb9a4 5336Falls back to normal file name handler if no Tramp file name handler exists."
2e271195
MA
5337 (if tramp-mode
5338 (save-match-data
5339 (let* ((filename
5340 (tramp-replace-environment-variables
5341 (apply 'tramp-file-name-for-operation operation args)))
5342 (completion (tramp-completion-mode-p))
5343 (foreign (tramp-find-foreign-file-name-handler filename)))
5344 (with-parsed-tramp-file-name filename nil
5345 (cond
5346 ;; When we are in completion mode, some operations
5347 ;; shouldn't be handled by backend.
5348 ((and completion (zerop (length localname))
5349 (memq operation '(file-exists-p file-directory-p)))
5350 t)
5351 ((and completion (zerop (length localname))
5352 (memq operation '(file-name-as-directory)))
5353 filename)
5354 ;; Call the backend function.
5355 (foreign (apply foreign operation args))
5356 ;; Nothing to do for us.
5357 (t (tramp-run-real-handler operation args))))))
5358 ;; When `tramp-mode' is not enabled, we don't do anything.
5359 (tramp-run-real-handler operation args)))
fb7933a3 5360
07dfe738
KG
5361;; In Emacs, there is some concurrency due to timers. If a timer
5362;; interrupts Tramp and wishes to use the same connection buffer as
5363;; the "main" Emacs, then garbage might occur in the connection
5364;; buffer. Therefore, we need to make sure that a timer does not use
5365;; the same connection buffer as the "main" Emacs. We implement a
5366;; cheap global lock, instead of locking each connection buffer
5367;; separately. The global lock is based on two variables,
5368;; `tramp-locked' and `tramp-locker'. `tramp-locked' is set to true
5369;; (with setq) to indicate a lock. But Tramp also calls itself during
5370;; processing of a single file operation, so we need to allow
5371;; recursive calls. That's where the `tramp-locker' variable comes in
5372;; -- it is let-bound to t during the execution of the current
5373;; handler. So if `tramp-locked' is t and `tramp-locker' is also t,
5374;; then we should just proceed because we have been called
5375;; recursively. But if `tramp-locker' is nil, then we are a timer
5376;; interrupting the "main" Emacs, and then we signal an error.
5377
5378(defvar tramp-locked nil
5379 "If non-nil, then Tramp is currently busy.
5380Together with `tramp-locker', this implements a locking mechanism
5381preventing reentrant calls of Tramp.")
5382
5383(defvar tramp-locker nil
5384 "If non-nil, then a caller has locked Tramp.
5385Together with `tramp-locked', this implements a locking mechanism
5386preventing reentrant calls of Tramp.")
5387
ea9d1443
KG
5388(defun tramp-sh-file-name-handler (operation &rest args)
5389 "Invoke remote-shell Tramp file name handler.
5390Fall back to normal file name handler if no Tramp handler exists."
07dfe738 5391 (when (and tramp-locked (not tramp-locker))
11c71217 5392 (setq tramp-locked nil)
00d6fd04 5393 (signal 'file-error (list "Forbidden reentrant call of Tramp")))
07dfe738
KG
5394 (let ((tl tramp-locked))
5395 (unwind-protect
5396 (progn
5397 (setq tramp-locked t)
5398 (let ((tramp-locker t))
5399 (save-match-data
5400 (let ((fn (assoc operation tramp-file-name-handler-alist)))
5401 (if fn
5402 (apply (cdr fn) args)
5403 (tramp-run-real-handler operation args))))))
5404 (setq tramp-locked tl))))
ea9d1443 5405
946a5aeb
MA
5406(defun tramp-vc-file-name-handler (operation &rest args)
5407 "Invoke special file name handler, which collects files to be handled."
5408 (save-match-data
5409 (let ((filename
5410 (tramp-replace-environment-variables
5411 (apply 'tramp-file-name-for-operation operation args)))
5412 (fn (assoc operation tramp-file-name-handler-alist)))
5413 (with-parsed-tramp-file-name filename nil
5414 (cond
5415 ;; That's what we want: file names, for which checks are
5416 ;; applied. We assume, that VC uses only `file-exists-p' and
5417 ;; `file-readable-p' checks; otherwise we must extend the
5418 ;; list. We do not perform any action, but return nil, in
5419 ;; order to keep `vc-registered' running.
5420 ((and fn (memq operation '(file-exists-p file-readable-p)))
5421 (add-to-list 'tramp-vc-registered-file-names localname 'append)
5422 nil)
5423 ;; Tramp file name handlers like `expand-file-name'. They
5424 ;; must still work.
5425 (fn
5426 (save-match-data (apply (cdr fn) args)))
5427 ;; Default file name handlers, we don't care.
5428 (t (tramp-run-real-handler operation args)))))))
5429
16674e4f 5430;;;###autoload
1ecc6145 5431(progn (defun tramp-completion-file-name-handler (operation &rest args)
a4aeb9a4
MA
5432 "Invoke Tramp file name completion handler.
5433Falls back to normal file name handler if no Tramp file name handler exists."
57671b72
MA
5434 ;; We bind `directory-sep-char' here for XEmacs on Windows, which
5435 ;; would otherwise use backslash.
aff67808
MA
5436 (let ((directory-sep-char ?/)
5437 (fn (assoc operation tramp-completion-file-name-handler-alist)))
aa485f7c
MA
5438 (if (and
5439 ;; When `tramp-mode' is not enabled, we don't do anything.
5440 fn tramp-mode
5441 ;; For other syntaxes than `sep', the regexp matches many common
5442 ;; situations where the user doesn't actually want to use Tramp.
5443 ;; So to avoid autoloading Tramp after typing just "/s", we
5444 ;; disable this part of the completion, unless the user implicitly
5445 ;; indicated his interest in using a fancier completion system.
5446 (or (eq tramp-syntax 'sep)
5447 (featurep 'tramp) ; If it's loaded, we may as well use it.
5448 (and (boundp 'partial-completion-mode) partial-completion-mode)
5449 ;; FIXME: These may have been loaded even if the user never
5450 ;; intended to use them.
5451 (featurep 'ido)
5452 (featurep 'icicles)))
aff67808
MA
5453 (save-match-data (apply (cdr fn) args))
5454 (tramp-completion-run-real-handler operation args)))))
a01b1e22 5455
b25a52cc 5456;;;###autoload
aa485f7c
MA
5457(progn (defun tramp-register-file-name-handlers ()
5458 "Add Tramp file name handlers to `file-name-handler-alist'."
5459 ;; Remove autoloaded handlers from file name handler alist. Useful,
00d6fd04
MA
5460 ;; if `tramp-syntax' has been changed.
5461 (let ((a1 (rassq 'tramp-file-name-handler file-name-handler-alist)))
aa485f7c
MA
5462 (setq file-name-handler-alist (delq a1 file-name-handler-alist)))
5463 (let ((a1 (rassq
5464 'tramp-completion-file-name-handler file-name-handler-alist)))
5465 (setq file-name-handler-alist (delq a1 file-name-handler-alist)))
5466 ;; Add the handlers.
a01b1e22
MA
5467 (add-to-list 'file-name-handler-alist
5468 (cons tramp-file-name-regexp 'tramp-file-name-handler))
aa485f7c
MA
5469 (add-to-list 'file-name-handler-alist
5470 (cons tramp-completion-file-name-regexp
5471 'tramp-completion-file-name-handler))
5472 (put 'tramp-completion-file-name-handler 'safe-magic t)
5473 ;; If jka-compr or epa-file are already loaded, move them to the
5474 ;; front of `file-name-handler-alist'.
5475 (dolist (fnh '(epa-file-handler jka-compr-handler))
5476 (let ((entry (rassoc fnh file-name-handler-alist)))
5477 (when entry
5478 (setq file-name-handler-alist
5479 (cons entry (delete entry file-name-handler-alist))))))))
69cee873 5480
00d6fd04
MA
5481;; `tramp-file-name-handler' must be registered before evaluation of
5482;; site-start and init files, because there might exist remote files
5483;; already, f.e. files kept via recentf-mode.
aa485f7c
MA
5484;;;###autoload(tramp-register-file-name-handlers)
5485(tramp-register-file-name-handlers)
b25a52cc 5486
fb7933a3 5487;;;###autoload
8c04e197 5488(defun tramp-unload-file-name-handlers ()
a69c01a0
MA
5489 (setq file-name-handler-alist
5490 (delete (rassoc 'tramp-file-name-handler
5491 file-name-handler-alist)
5492 (delete (rassoc 'tramp-completion-file-name-handler
5493 file-name-handler-alist)
5494 file-name-handler-alist))))
5495
8c04e197 5496(add-hook 'tramp-unload-hook 'tramp-unload-file-name-handlers)
a69c01a0 5497
0664ff72 5498;;; File name handler functions for completion mode:
a6e96327
MA
5499
5500(defvar tramp-completion-mode nil
5501 "If non-nil, external packages signal that they are in file name completion.
5502
5503This is necessary, because Tramp uses a heuristic depending on last
5504input event. This fails when external packages use other characters
5505but <TAB>, <SPACE> or ?\\? for file name completion. This variable
5506should never be set globally, the intention is to let-bind it.")
16674e4f
KG
5507
5508;; Necessary because `tramp-file-name-regexp-unified' and
00d6fd04
MA
5509;; `tramp-completion-file-name-regexp-unified' aren't different. If
5510;; nil, `tramp-completion-run-real-handler' is called (i.e. forwarding
5511;; to `tramp-file-name-handler'). Otherwise, it takes
5512;; `tramp-run-real-handler'. Using `last-input-event' is a little bit
5513;; risky, because completing a file might require loading other files,
5514;; like "~/.netrc", and for them it shouldn't be decided based on that
5515;; variable. On the other hand, those files shouldn't have partial
a4aeb9a4
MA
5516;; Tramp file name syntax. Maybe another variable should be introduced
5517;; overwriting this check in such cases. Or we change Tramp file name
00d6fd04 5518;; syntax in order to avoid ambiguities, like in XEmacs ...
6c4e47fa 5519(defun tramp-completion-mode-p ()
16674e4f 5520 "Checks whether method / user name / host name completion is active."
6c4e47fa 5521 (or
a6e96327
MA
5522 ;; Signal from outside.
5523 tramp-completion-mode
5524 ;; Emacs.
94be87e8 5525 (equal last-input-event 'tab)
6c4e47fa 5526 (and (natnump last-input-event)
94be87e8 5527 (or
a6e96327 5528 ;; ?\t has event-modifier 'control.
800a97b8 5529 (equal last-input-event ?\t)
94be87e8 5530 (and (not (event-modifiers last-input-event))
800a97b8
SM
5531 (or (equal last-input-event ?\?)
5532 (equal last-input-event ?\ )))))
a6e96327 5533 ;; XEmacs.
6c4e47fa
MA
5534 (and (featurep 'xemacs)
5535 ;; `last-input-event' might be nil.
5536 (not (null last-input-event))
5537 ;; `last-input-event' may have no character approximation.
5538 (funcall (symbol-function 'event-to-character) last-input-event)
94be87e8 5539 (or
a6e96327 5540 ;; ?\t has event-modifier 'control.
800a97b8 5541 (equal
94be87e8
MA
5542 (funcall (symbol-function 'event-to-character)
5543 last-input-event) ?\t)
5544 (and (not (event-modifiers last-input-event))
800a97b8 5545 (or (equal
94be87e8
MA
5546 (funcall (symbol-function 'event-to-character)
5547 last-input-event) ?\?)
800a97b8 5548 (equal
94be87e8
MA
5549 (funcall (symbol-function 'event-to-character)
5550 last-input-event) ?\ )))))))
16674e4f 5551
16674e4f
KG
5552;; Method, host name and user name completion.
5553;; `tramp-completion-dissect-file-name' returns a list of
5554;; tramp-file-name structures. For all of them we return possible completions.
a01b1e22 5555;;;###autoload
16674e4f 5556(defun tramp-completion-handle-file-name-all-completions (filename directory)
00d6fd04 5557 "Like `file-name-all-completions' for partial Tramp files."
16674e4f 5558
00d6fd04
MA
5559 (let* ((fullname (tramp-drop-volume-letter
5560 (expand-file-name filename directory)))
5561 ;; Possible completion structures.
5562 (v (tramp-completion-dissect-file-name fullname))
5563 result result1)
5564
5565 (while v
5566 (let* ((car (car v))
5567 (method (tramp-file-name-method car))
5568 (user (tramp-file-name-user car))
5569 (host (tramp-file-name-host car))
5570 (localname (tramp-file-name-localname car))
5571 (m (tramp-find-method method user host))
5572 (tramp-current-user user) ; see `tramp-parse-passwd'
5573 all-user-hosts)
5574
5575 (unless localname ;; Nothing to complete.
5576
5577 (if (or user host)
5578
5579 ;; Method dependent user / host combinations.
5580 (progn
9e6ab520 5581 (mapc
00d6fd04
MA
5582 (lambda (x)
5583 (setq all-user-hosts
5584 (append all-user-hosts
5585 (funcall (nth 0 x) (nth 1 x)))))
5586 (tramp-get-completion-function m))
5587
9e6ab520
MA
5588 (setq result
5589 (append result
5590 (mapcar
5591 (lambda (x)
5592 (tramp-get-completion-user-host
5593 method user host (nth 0 x) (nth 1 x)))
5594 (delq nil all-user-hosts)))))
00d6fd04
MA
5595
5596 ;; Possible methods.
5597 (setq result
5598 (append result (tramp-get-completion-methods m)))))
5599
5600 (setq v (cdr v))))
5601
5602 ;; Unify list, remove nil elements.
5603 (while result
5604 (let ((car (car result)))
5605 (when car
5606 (add-to-list
5607 'result1
5608 (substring car (length (tramp-drop-volume-letter directory)))))
5609 (setq result (cdr result))))
5610
5611 ;; Complete local parts.
5612 (append
5613 result1
5614 (condition-case nil
5615 (tramp-completion-run-real-handler
5616 'file-name-all-completions (list filename directory))
5617 (error nil)))))
16674e4f
KG
5618
5619;; Method, host name and user name completion for a file.
a01b1e22 5620;;;###autoload
e1e17cae
MA
5621(defun tramp-completion-handle-file-name-completion
5622 (filename directory &optional predicate)
00d6fd04 5623 "Like `file-name-completion' for Tramp files."
e1e17cae
MA
5624 (try-completion
5625 filename
5626 (mapcar 'list (file-name-all-completions filename directory))
83e20b5c
MA
5627 (when predicate
5628 (lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
16674e4f
KG
5629
5630;; I misuse a little bit the tramp-file-name structure in order to handle
5631;; completion possibilities for partial methods / user names / host names.
5632;; Return value is a list of tramp-file-name structures according to possible
00d6fd04 5633;; completions. If "localname" is non-nil it means there
16674e4f
KG
5634;; shouldn't be a completion anymore.
5635
5636;; Expected results:
5637
00d6fd04
MA
5638;; "/x" "/[x" "/x@" "/[x@" "/x@y" "/[x@y"
5639;; [nil nil "x" nil] [nil "x" nil nil] [nil "x" "y" nil]
5640;; [nil "x" nil nil]
5641;; ["x" nil nil nil]
5642
5643;; "/x:" "/x:y" "/x:y:"
5644;; [nil nil "x" ""] [nil nil "x" "y"] ["x" nil "y" ""]
5645;; "/[x/" "/[x/y"
5646;; ["x" nil "" nil] ["x" nil "y" nil]
5647;; ["x" "" nil nil] ["x" "y" nil nil]
5648
5649;; "/x:y@" "/x:y@z" "/x:y@z:"
5650;; [nil nil "x" "y@"] [nil nil "x" "y@z"] ["x" "y" "z" ""]
5651;; "/[x/y@" "/[x/y@z"
5652;; ["x" nil "y" nil] ["x" "y" "z" nil]
16674e4f
KG
5653(defun tramp-completion-dissect-file-name (name)
5654 "Returns a list of `tramp-file-name' structures.
5655They are collected by `tramp-completion-dissect-file-name1'."
5656
5657 (let* ((result)
4007ba5b 5658 (x-nil "\\|\\(\\)")
b96e6899
MA
5659 (tramp-completion-ipv6-regexp
5660 (format
5661 "[^%s]*"
5662 (if (zerop (length tramp-postfix-ipv6-format))
5663 tramp-postfix-host-format
5664 tramp-postfix-ipv6-format)))
4007ba5b
KG
5665 ;; "/method" "/[method"
5666 (tramp-completion-file-name-structure1
5667 (list (concat tramp-prefix-regexp "\\(" tramp-method-regexp x-nil "\\)$")
5668 1 nil nil nil))
5669 ;; "/user" "/[user"
5670 (tramp-completion-file-name-structure2
5671 (list (concat tramp-prefix-regexp "\\(" tramp-user-regexp x-nil "\\)$")
5672 nil 1 nil nil))
5673 ;; "/host" "/[host"
5674 (tramp-completion-file-name-structure3
5675 (list (concat tramp-prefix-regexp "\\(" tramp-host-regexp x-nil "\\)$")
5676 nil nil 1 nil))
b96e6899 5677 ;; "/[ipv6" "/[ipv6"
4007ba5b 5678 (tramp-completion-file-name-structure4
b96e6899
MA
5679 (list (concat tramp-prefix-regexp
5680 tramp-prefix-ipv6-regexp
5681 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5682 nil nil 1 nil))
5683 ;; "/user@host" "/[user@host"
5684 (tramp-completion-file-name-structure5
4007ba5b
KG
5685 (list (concat tramp-prefix-regexp
5686 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5687 "\\(" tramp-host-regexp x-nil "\\)$")
5688 nil 1 2 nil))
b96e6899
MA
5689 ;; "/user@[ipv6" "/[user@ipv6"
5690 (tramp-completion-file-name-structure6
5691 (list (concat tramp-prefix-regexp
5692 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5693 tramp-prefix-ipv6-regexp
5694 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5695 nil 1 2 nil))
00d6fd04 5696 ;; "/method:user" "/[method/user" "/method://user"
b96e6899 5697 (tramp-completion-file-name-structure7
4007ba5b 5698 (list (concat tramp-prefix-regexp
00d6fd04 5699 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5700 "\\(" tramp-user-regexp x-nil "\\)$")
5701 1 2 nil nil))
00d6fd04 5702 ;; "/method:host" "/[method/host" "/method://host"
b96e6899 5703 (tramp-completion-file-name-structure8
4007ba5b 5704 (list (concat tramp-prefix-regexp
00d6fd04 5705 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5706 "\\(" tramp-host-regexp x-nil "\\)$")
5707 1 nil 2 nil))
b96e6899
MA
5708 ;; "/method:[ipv6" "/[method/ipv6" "/method://[ipv6"
5709 (tramp-completion-file-name-structure9
5710 (list (concat tramp-prefix-regexp
5711 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
5712 tramp-prefix-ipv6-regexp
5713 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5714 1 nil 2 nil))
00d6fd04 5715 ;; "/method:user@host" "/[method/user@host" "/method://user@host"
b96e6899 5716 (tramp-completion-file-name-structure10
4007ba5b 5717 (list (concat tramp-prefix-regexp
00d6fd04 5718 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5719 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5720 "\\(" tramp-host-regexp x-nil "\\)$")
00d6fd04 5721 1 2 3 nil))
b96e6899
MA
5722 ;; "/method:user@[ipv6" "/[method/user@ipv6" "/method://user@[ipv6"
5723 (tramp-completion-file-name-structure11
5724 (list (concat tramp-prefix-regexp
5725 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
5726 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5727 tramp-prefix-ipv6-regexp
5728 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5729 1 2 3 nil))
00d6fd04 5730 ;; "/method: "/method:/"
b96e6899 5731 (tramp-completion-file-name-structure12
00d6fd04
MA
5732 (list
5733 (if (equal tramp-syntax 'url)
5734 (concat tramp-prefix-regexp
5735 "\\(" tramp-method-regexp "\\)"
5736 "\\(" (substring tramp-postfix-method-regexp 0 1)
5737 "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)"
5738 "\\(" "\\)$")
5739 ;; Should not match if not URL syntax.
5740 (concat tramp-prefix-regexp "/$"))
5741 1 3 nil nil))
5742 ;; "/method: "/method:/"
b96e6899 5743 (tramp-completion-file-name-structure13
00d6fd04
MA
5744 (list
5745 (if (equal tramp-syntax 'url)
5746 (concat tramp-prefix-regexp
5747 "\\(" tramp-method-regexp "\\)"
5748 "\\(" (substring tramp-postfix-method-regexp 0 1)
5749 "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)"
5750 "\\(" "\\)$")
5751 ;; Should not match if not URL syntax.
5752 (concat tramp-prefix-regexp "/$"))
5753 1 nil 3 nil)))
4007ba5b 5754
9e6ab520 5755 (mapc (lambda (regexp)
16674e4f
KG
5756 (add-to-list 'result
5757 (tramp-completion-dissect-file-name1 regexp name)))
5758 (list
5759 tramp-completion-file-name-structure1
5760 tramp-completion-file-name-structure2
5761 tramp-completion-file-name-structure3
5762 tramp-completion-file-name-structure4
5763 tramp-completion-file-name-structure5
5764 tramp-completion-file-name-structure6
5765 tramp-completion-file-name-structure7
00d6fd04
MA
5766 tramp-completion-file-name-structure8
5767 tramp-completion-file-name-structure9
b96e6899
MA
5768 tramp-completion-file-name-structure10
5769 tramp-completion-file-name-structure11
5770 tramp-completion-file-name-structure12
5771 tramp-completion-file-name-structure13
16674e4f
KG
5772 tramp-file-name-structure))
5773
5774 (delq nil result)))
5775
5776(defun tramp-completion-dissect-file-name1 (structure name)
5777 "Returns a `tramp-file-name' structure matching STRUCTURE.
00d6fd04 5778The structure consists of remote method, remote user,
7432277c 5779remote host and localname (filename on remote host)."
fb7933a3 5780
00d6fd04
MA
5781 (save-match-data
5782 (when (string-match (nth 0 structure) name)
5783 (let ((method (and (nth 1 structure)
5784 (match-string (nth 1 structure) name)))
5785 (user (and (nth 2 structure)
5786 (match-string (nth 2 structure) name)))
5787 (host (and (nth 3 structure)
5788 (match-string (nth 3 structure) name)))
5789 (localname (and (nth 4 structure)
5790 (match-string (nth 4 structure) name))))
5791 (vector method user host localname)))))
16674e4f
KG
5792
5793;; This function returns all possible method completions, adding the
5794;; trailing method delimeter.
16674e4f
KG
5795(defun tramp-get-completion-methods (partial-method)
5796 "Returns all method completions for PARTIAL-METHOD."
4007ba5b
KG
5797 (mapcar
5798 (lambda (method)
5799 (and method
5800 (string-match (concat "^" (regexp-quote partial-method)) method)
00d6fd04
MA
5801 (tramp-completion-make-tramp-file-name method nil nil nil)))
5802 (mapcar 'car tramp-methods)))
16674e4f
KG
5803
5804;; Compares partial user and host names with possible completions.
5805(defun tramp-get-completion-user-host (method partial-user partial-host user host)
5806 "Returns the most expanded string for user and host name completion.
5807PARTIAL-USER must match USER, PARTIAL-HOST must match HOST."
5808 (cond
5809
5810 ((and partial-user partial-host)
5811 (if (and host
5812 (string-match (concat "^" (regexp-quote partial-host)) host)
5813 (string-equal partial-user (or user partial-user)))
5814 (setq user partial-user)
5815 (setq user nil
5816 host nil)))
5817
5818 (partial-user
5819 (setq host nil)
5820 (unless
5821 (and user (string-match (concat "^" (regexp-quote partial-user)) user))
5822 (setq user nil)))
5823
5824 (partial-host
5825 (setq user nil)
5826 (unless
5827 (and host (string-match (concat "^" (regexp-quote partial-host)) host))
5828 (setq host nil)))
5829
5830 (t (setq user nil
5831 host nil)))
5832
292ffc15 5833 (unless (zerop (+ (length user) (length host)))
00d6fd04 5834 (tramp-completion-make-tramp-file-name method user host nil)))
16674e4f
KG
5835
5836(defun tramp-parse-rhosts (filename)
5837 "Return a list of (user host) tuples allowed to access.
292ffc15 5838Either user or host may be nil."
00d6fd04
MA
5839 ;; On Windows, there are problems in completion when
5840 ;; `default-directory' is remote.
9e6ab520 5841 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5842 res)
8daea7fc 5843 (when (file-readable-p filename)
16674e4f
KG
5844 (with-temp-buffer
5845 (insert-file-contents filename)
5846 (goto-char (point-min))
5847 (while (not (eobp))
292ffc15 5848 (push (tramp-parse-rhosts-group) res))))
16674e4f
KG
5849 res))
5850
16674e4f
KG
5851(defun tramp-parse-rhosts-group ()
5852 "Return a (user host) tuple allowed to access.
292ffc15 5853Either user or host may be nil."
16674e4f
KG
5854 (let ((result)
5855 (regexp
5856 (concat
5857 "^\\(" tramp-host-regexp "\\)"
5858 "\\([ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
9e6ab520 5859 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
5860 (when (re-search-forward regexp nil t)
5861 (setq result (append (list (match-string 3) (match-string 1)))))
5862 (widen)
5863 (forward-line 1)
5864 result))
5865
5866(defun tramp-parse-shosts (filename)
5867 "Return a list of (user host) tuples allowed to access.
5868User is always nil."
00d6fd04
MA
5869 ;; On Windows, there are problems in completion when
5870 ;; `default-directory' is remote.
9e6ab520 5871 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5872 res)
8daea7fc 5873 (when (file-readable-p filename)
16674e4f
KG
5874 (with-temp-buffer
5875 (insert-file-contents filename)
5876 (goto-char (point-min))
5877 (while (not (eobp))
292ffc15 5878 (push (tramp-parse-shosts-group) res))))
16674e4f
KG
5879 res))
5880
5881(defun tramp-parse-shosts-group ()
5882 "Return a (user host) tuple allowed to access.
5883User is always nil."
16674e4f
KG
5884 (let ((result)
5885 (regexp (concat "^\\(" tramp-host-regexp "\\)")))
9e6ab520 5886 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
5887 (when (re-search-forward regexp nil t)
5888 (setq result (list nil (match-string 1))))
5889 (widen)
5890 (or
5891 (> (skip-chars-forward ",") 0)
5892 (forward-line 1))
5893 result))
5894
8daea7fc
KG
5895(defun tramp-parse-sconfig (filename)
5896 "Return a list of (user host) tuples allowed to access.
5897User is always nil."
00d6fd04
MA
5898 ;; On Windows, there are problems in completion when
5899 ;; `default-directory' is remote.
9e6ab520 5900 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5901 res)
8daea7fc
KG
5902 (when (file-readable-p filename)
5903 (with-temp-buffer
5904 (insert-file-contents filename)
5905 (goto-char (point-min))
5906 (while (not (eobp))
5907 (push (tramp-parse-sconfig-group) res))))
5908 res))
5909
5910(defun tramp-parse-sconfig-group ()
5911 "Return a (user host) tuple allowed to access.
5912User is always nil."
8daea7fc
KG
5913 (let ((result)
5914 (regexp (concat "^[ \t]*Host[ \t]+" "\\(" tramp-host-regexp "\\)")))
9e6ab520 5915 (narrow-to-region (point) (tramp-compat-line-end-position))
8daea7fc
KG
5916 (when (re-search-forward regexp nil t)
5917 (setq result (list nil (match-string 1))))
5918 (widen)
5919 (or
5920 (> (skip-chars-forward ",") 0)
5921 (forward-line 1))
5922 result))
5923
5ec2cc41
KG
5924(defun tramp-parse-shostkeys (dirname)
5925 "Return a list of (user host) tuples allowed to access.
5926User is always nil."
00d6fd04
MA
5927 ;; On Windows, there are problems in completion when
5928 ;; `default-directory' is remote.
9e6ab520 5929 (let* ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
5930 (regexp (concat "^key_[0-9]+_\\(" tramp-host-regexp "\\)\\.pub$"))
5931 (files (when (file-directory-p dirname) (directory-files dirname)))
5932 result)
5ec2cc41
KG
5933 (while files
5934 (when (string-match regexp (car files))
5935 (push (list nil (match-string 1 (car files))) result))
5936 (setq files (cdr files)))
5937 result))
5938
5939(defun tramp-parse-sknownhosts (dirname)
5940 "Return a list of (user host) tuples allowed to access.
5941User is always nil."
00d6fd04
MA
5942 ;; On Windows, there are problems in completion when
5943 ;; `default-directory' is remote.
9e6ab520 5944 (let* ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
5945 (regexp (concat "^\\(" tramp-host-regexp
5946 "\\)\\.ssh-\\(dss\\|rsa\\)\\.pub$"))
5947 (files (when (file-directory-p dirname) (directory-files dirname)))
5948 result)
5ec2cc41
KG
5949 (while files
5950 (when (string-match regexp (car files))
5951 (push (list nil (match-string 1 (car files))) result))
5952 (setq files (cdr files)))
5953 result))
5954
16674e4f
KG
5955(defun tramp-parse-hosts (filename)
5956 "Return a list of (user host) tuples allowed to access.
5957User is always nil."
00d6fd04
MA
5958 ;; On Windows, there are problems in completion when
5959 ;; `default-directory' is remote.
9e6ab520 5960 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5961 res)
8daea7fc 5962 (when (file-readable-p filename)
16674e4f
KG
5963 (with-temp-buffer
5964 (insert-file-contents filename)
5965 (goto-char (point-min))
5966 (while (not (eobp))
292ffc15 5967 (push (tramp-parse-hosts-group) res))))
16674e4f
KG
5968 res))
5969
5970(defun tramp-parse-hosts-group ()
5971 "Return a (user host) tuple allowed to access.
5972User is always nil."
16674e4f 5973 (let ((result)
b96e6899
MA
5974 (regexp
5975 (concat "^\\(" tramp-ipv6-regexp "\\|" tramp-host-regexp "\\)")))
9e6ab520 5976 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f 5977 (when (re-search-forward regexp nil t)
b96e6899 5978 (setq result (list nil (match-string 1))))
16674e4f
KG
5979 (widen)
5980 (or
5981 (> (skip-chars-forward " \t") 0)
5982 (forward-line 1))
5983 result))
5984
8daea7fc
KG
5985;; For su-alike methods it would be desirable to return "root@localhost"
5986;; as default. Unfortunately, we have no information whether any user name
00d6fd04 5987;; has been typed already. So we use `tramp-current-user' as indication,
8daea7fc 5988;; assuming it is set in `tramp-completion-handle-file-name-all-completions'.
16674e4f
KG
5989(defun tramp-parse-passwd (filename)
5990 "Return a list of (user host) tuples allowed to access.
5991Host is always \"localhost\"."
00d6fd04
MA
5992 ;; On Windows, there are problems in completion when
5993 ;; `default-directory' is remote.
9e6ab520 5994 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5995 res)
8daea7fc 5996 (if (zerop (length tramp-current-user))
16674e4f 5997 '(("root" nil))
8daea7fc 5998 (when (file-readable-p filename)
16674e4f
KG
5999 (with-temp-buffer
6000 (insert-file-contents filename)
6001 (goto-char (point-min))
6002 (while (not (eobp))
292ffc15 6003 (push (tramp-parse-passwd-group) res))))
16674e4f
KG
6004 res)))
6005
6006(defun tramp-parse-passwd-group ()
6007 "Return a (user host) tuple allowed to access.
292ffc15 6008Host is always \"localhost\"."
16674e4f
KG
6009 (let ((result)
6010 (regexp (concat "^\\(" tramp-user-regexp "\\):")))
9e6ab520 6011 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
6012 (when (re-search-forward regexp nil t)
6013 (setq result (list (match-string 1) "localhost")))
6014 (widen)
6015 (forward-line 1)
6016 result))
6017
292ffc15
KG
6018(defun tramp-parse-netrc (filename)
6019 "Return a list of (user host) tuples allowed to access.
6020User may be nil."
00d6fd04
MA
6021 ;; On Windows, there are problems in completion when
6022 ;; `default-directory' is remote.
9e6ab520 6023 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 6024 res)
8daea7fc 6025 (when (file-readable-p filename)
292ffc15
KG
6026 (with-temp-buffer
6027 (insert-file-contents filename)
6028 (goto-char (point-min))
6029 (while (not (eobp))
6030 (push (tramp-parse-netrc-group) res))))
6031 res))
6032
6033(defun tramp-parse-netrc-group ()
6034 "Return a (user host) tuple allowed to access.
6035User may be nil."
292ffc15
KG
6036 (let ((result)
6037 (regexp
6038 (concat
6039 "^[ \t]*machine[ \t]+" "\\(" tramp-host-regexp "\\)"
6040 "\\([ \t]+login[ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
9e6ab520 6041 (narrow-to-region (point) (tramp-compat-line-end-position))
292ffc15
KG
6042 (when (re-search-forward regexp nil t)
6043 (setq result (list (match-string 3) (match-string 1))))
6044 (widen)
6045 (forward-line 1)
6046 result))
6047
00d6fd04
MA
6048(defun tramp-parse-putty (registry)
6049 "Return a list of (user host) tuples allowed to access.
6050User is always nil."
6051 ;; On Windows, there are problems in completion when
6052 ;; `default-directory' is remote.
9e6ab520 6053 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
6054 res)
6055 (with-temp-buffer
a4aeb9a4 6056 (when (zerop (tramp-local-call-process "reg" nil t nil "query" registry))
00d6fd04
MA
6057 (goto-char (point-min))
6058 (while (not (eobp))
6059 (push (tramp-parse-putty-group registry) res))))
6060 res))
6061
6062(defun tramp-parse-putty-group (registry)
6063 "Return a (user host) tuple allowed to access.
6064User is always nil."
6065 (let ((result)
6066 (regexp (concat (regexp-quote registry) "\\\\\\(.+\\)")))
9e6ab520 6067 (narrow-to-region (point) (tramp-compat-line-end-position))
00d6fd04
MA
6068 (when (re-search-forward regexp nil t)
6069 (setq result (list nil (match-string 1))))
6070 (widen)
6071 (forward-line 1)
6072 result))
6073
fb7933a3
KG
6074;;; Internal Functions:
6075
00d6fd04
MA
6076(defun tramp-maybe-send-script (vec script name)
6077 "Define in remote shell function NAME implemented as SCRIPT.
6078Only send the definition if it has not already been done."
6079 (let* ((p (tramp-get-connection-process vec))
6080 (scripts (tramp-get-connection-property p "scripts" nil)))
1834b39f 6081 (unless (member name scripts)
00d6fd04
MA
6082 (tramp-message vec 5 "Sending script `%s'..." name)
6083 ;; The script could contain a call of Perl. This is masked with `%s'.
6084 (tramp-send-command-and-check
6085 vec
6086 (format "%s () {\n%s\n}" name
6087 (format script (tramp-get-remote-perl vec))))
6088 (tramp-set-connection-property p "scripts" (cons name scripts))
6089 (tramp-message vec 5 "Sending script `%s'...done." name))))
c82c5727 6090
fb7933a3 6091(defun tramp-set-auto-save ()
00d6fd04 6092 (when (and ;; ange-ftp has its own auto-save mechanism
7177e2a3
MA
6093 (eq (tramp-find-foreign-file-name-handler (buffer-file-name))
6094 'tramp-sh-file-name-handler)
fb7933a3
KG
6095 auto-save-default)
6096 (auto-save-mode 1)))
6097(add-hook 'find-file-hooks 'tramp-set-auto-save t)
a69c01a0 6098(add-hook 'tramp-unload-hook
aa485f7c
MA
6099 (lambda ()
6100 (remove-hook 'find-file-hooks 'tramp-set-auto-save)))
fb7933a3
KG
6101
6102(defun tramp-run-test (switch filename)
6103 "Run `test' on the remote system, given a SWITCH and a FILENAME.
6104Returns the exit code of the `test' program."
00d6fd04
MA
6105 (with-parsed-tramp-file-name filename nil
6106 (tramp-send-command-and-check
6107 v
6108 (format
6109 "%s %s %s"
6110 (tramp-get-test-command v)
6111 switch
6112 (tramp-shell-quote-argument localname)))))
6113
6114(defun tramp-run-test2 (format-string file1 file2)
6115 "Run `test'-like program on the remote system, given FILE1, FILE2.
6116FORMAT-STRING contains the program name, switches, and place holders.
6117Returns the exit code of the `test' program. Barfs if the methods,
fb7933a3 6118hosts, or files, disagree."
00d6fd04
MA
6119 (unless (tramp-equal-remote file1 file2)
6120 (with-parsed-tramp-file-name (if (tramp-tramp-file-p file1) file1 file2) nil
6121 (tramp-error
6122 v 'file-error
6123 "tramp-run-test2 only implemented for same method, user, host")))
6124 (with-parsed-tramp-file-name file1 v1
6125 (with-parsed-tramp-file-name file1 v2
fb7933a3 6126 (tramp-send-command-and-check
00d6fd04
MA
6127 v1
6128 (format format-string
6129 (tramp-shell-quote-argument v1-localname)
6130 (tramp-shell-quote-argument v2-localname))))))
fb7933a3 6131
00d6fd04
MA
6132(defun tramp-buffer-name (vec)
6133 "A name for the connection buffer VEC."
6134 ;; We must use `tramp-file-name-real-host', because for gateway
6135 ;; methods the default port will be expanded later on, which would
6136 ;; tamper the name.
6137 (let ((method (tramp-file-name-method vec))
6138 (user (tramp-file-name-user vec))
6139 (host (tramp-file-name-real-host vec)))
6140 (if (not (zerop (length user)))
6141 (format "*tramp/%s %s@%s*" method user host)
6142 (format "*tramp/%s %s*" method host))))
6143
b88f2d0a
MA
6144(defun tramp-delete-temp-file-function ()
6145 "Remove temporary files related to current buffer."
6146 (when (stringp tramp-temp-buffer-file-name)
6147 (condition-case nil
6148 (delete-file tramp-temp-buffer-file-name)
6149 (error nil))))
6150
6151(add-hook 'kill-buffer-hook 'tramp-delete-temp-file-function)
6152(add-hook 'tramp-cache-unload-hook
6153 (lambda ()
6154 (remove-hook 'kill-buffer-hook
6155 'tramp-delete-temp-file-function)))
6156
00d6fd04
MA
6157(defun tramp-get-buffer (vec)
6158 "Get the connection buffer to be used for VEC."
6159 (or (get-buffer (tramp-buffer-name vec))
6160 (with-current-buffer (get-buffer-create (tramp-buffer-name vec))
6161 (setq buffer-undo-list t)
6162 (setq default-directory
6163 (tramp-make-tramp-file-name
6164 (tramp-file-name-method vec)
6165 (tramp-file-name-user vec)
6166 (tramp-file-name-host vec)
6167 "/"))
6168 (current-buffer))))
6169
6170(defun tramp-get-connection-buffer (vec)
6171 "Get the connection buffer to be used for VEC.
6172In case a second asynchronous communication has been started, it is different
6173from `tramp-get-buffer'."
6174 (or (tramp-get-connection-property vec "process-buffer" nil)
6175 (tramp-get-buffer vec)))
6176
6177(defun tramp-get-connection-process (vec)
6178 "Get the connection process to be used for VEC.
6179In case a second asynchronous communication has been started, it is different
6180from the default one."
6181 (get-process
6182 (or (tramp-get-connection-property vec "process-name" nil)
6183 (tramp-buffer-name vec))))
6184
6185(defun tramp-debug-buffer-name (vec)
6186 "A name for the debug buffer for VEC."
6187 ;; We must use `tramp-file-name-real-host', because for gateway
6188 ;; methods the default port will be expanded later on, which would
6189 ;; tamper the name.
6190 (let ((method (tramp-file-name-method vec))
6191 (user (tramp-file-name-user vec))
6192 (host (tramp-file-name-real-host vec)))
6193 (if (not (zerop (length user)))
6194 (format "*debug tramp/%s %s@%s*" method user host)
6195 (format "*debug tramp/%s %s*" method host))))
6196
6197(defun tramp-get-debug-buffer (vec)
6198 "Get the debug buffer for VEC."
01917a18 6199 (with-current-buffer
00d6fd04
MA
6200 (get-buffer-create (tramp-debug-buffer-name vec))
6201 (when (bobp)
6202 (setq buffer-undo-list t)
9ce8462a
MA
6203 ;; Activate outline-mode. This runs `text-mode-hook' and
6204 ;; `outline-mode-hook'. We must prevent that local processes
6205 ;; die. Yes: I've seen `flyspell-mode', which starts "ispell"
6206 ;; ...
9e6ab520 6207 (let ((default-directory (tramp-compat-temporary-file-directory)))
00d6fd04 6208 (outline-mode))
9ce8462a 6209 (set (make-local-variable 'outline-regexp)
736ac90f 6210 "[0-9]+:[0-9]+:[0-9]+\\.[0-9]+ [a-z0-9-]+ (\\([0-9]+\\)) #")
9ce8462a
MA
6211; (set (make-local-variable 'outline-regexp)
6212; "[a-z.-]+:[0-9]+: [a-z0-9-]+ (\\([0-9]+\\)) #")
6213 (set (make-local-variable 'outline-level) 'tramp-outline-level))
01917a18 6214 (current-buffer)))
fb7933a3 6215
00d6fd04
MA
6216(defun tramp-outline-level ()
6217 "Return the depth to which a statement is nested in the outline.
6218Point must be at the beginning of a header line.
6219
6220The outline level is equal to the verbosity of the Tramp message."
6221 (1+ (string-to-number (match-string 1))))
fb7933a3 6222
00d6fd04
MA
6223(defun tramp-find-executable
6224 (vec progname dirlist &optional ignore-tilde ignore-path)
6225 "Searches for PROGNAME in $PATH and all directories mentioned in DIRLIST.
6226First arg VEC specifies the connection, PROGNAME is the program
6227to search for, and DIRLIST gives the list of directories to
6228search. If IGNORE-TILDE is non-nil, directory names starting
6229with `~' will be ignored. If IGNORE-PATH is non-nil, searches
6230only in DIRLIST.
fb7933a3 6231
7432277c 6232Returns the absolute file name of PROGNAME, if found, and nil otherwise.
fb7933a3
KG
6233
6234This function expects to be in the right *tramp* buffer."
00d6fd04
MA
6235 (with-current-buffer (tramp-get-buffer vec)
6236 (let (result)
6237 ;; Check whether the executable is in $PATH. "which(1)" does not
6238 ;; report always a correct error code; therefore we check the
6239 ;; number of words it returns.
6240 (unless ignore-path
6241 (tramp-send-command vec (format "which \\%s | wc -w" progname))
6242 (goto-char (point-min))
6243 (if (looking-at "^1$")
6244 (setq result (concat "\\" progname))))
6245 (unless result
6246 (when ignore-tilde
6247 ;; Remove all ~/foo directories from dirlist. In Emacs 20,
6248 ;; `remove' is in CL, and we want to avoid CL dependencies.
6249 (let (newdl d)
6250 (while dirlist
6251 (setq d (car dirlist))
6252 (setq dirlist (cdr dirlist))
6253 (unless (char-equal ?~ (aref d 0))
6254 (setq newdl (cons d newdl))))
6255 (setq dirlist (nreverse newdl))))
6256 (tramp-send-command
6257 vec
6258 (format (concat "while read d; "
6259 "do if test -x $d/%s -a -f $d/%s; "
6260 "then echo tramp_executable $d/%s; "
6261 "break; fi; done <<'EOF'\n"
6262 "%s\nEOF")
6263 progname progname progname (mapconcat 'identity dirlist "\n")))
6264 (goto-char (point-max))
6265 (when (search-backward "tramp_executable " nil t)
6266 (skip-chars-forward "^ ")
6267 (skip-chars-forward " ")
9e6ab520
MA
6268 (setq result (buffer-substring
6269 (point) (tramp-compat-line-end-position)))))
00d6fd04
MA
6270 result)))
6271
6272(defun tramp-set-remote-path (vec)
6273 "Sets the remote environment PATH to existing directories.
6274I.e., for each directory in `tramp-remote-path', it is tested
6275whether it exists and if so, it is added to the environment
6276variable PATH."
6277 (tramp-message vec 5 (format "Setting $PATH environment variable"))
f84638eb
MA
6278 (tramp-send-command
6279 vec (format "PATH=%s; export PATH"
6280 (mapconcat 'identity (tramp-get-remote-path vec) ":"))))
fb7933a3 6281
cfb5c0db
MA
6282;; ------------------------------------------------------------
6283;; -- Communication with external shell --
6284;; ------------------------------------------------------------
fb7933a3 6285
00d6fd04 6286(defun tramp-find-file-exists-command (vec)
fb7933a3
KG
6287 "Find a command on the remote host for checking if a file exists.
6288Here, we are looking for a command which has zero exit status if the
6289file exists and nonzero exit status otherwise."
00d6fd04 6290 (let ((existing "/")
fb7933a3 6291 (nonexisting
00d6fd04
MA
6292 (tramp-shell-quote-argument "/ this file does not exist "))
6293 result)
fb7933a3
KG
6294 ;; The algorithm is as follows: we try a list of several commands.
6295 ;; For each command, we first run `$cmd /' -- this should return
6296 ;; true, as the root directory always exists. And then we run
00d6fd04 6297 ;; `$cmd /this\ file\ does\ not\ exist ', hoping that the file indeed
fb7933a3
KG
6298 ;; does not exist. This should return false. We use the first
6299 ;; command we find that seems to work.
6300 ;; The list of commands to try is as follows:
00d6fd04
MA
6301 ;; `ls -d' This works on most systems, but NetBSD 1.4
6302 ;; has a bug: `ls' always returns zero exit
6303 ;; status, even for files which don't exist.
6304 ;; `test -e' Some Bourne shells have a `test' builtin
6305 ;; which does not know the `-e' option.
6306 ;; `/bin/test -e' For those, the `test' binary on disk normally
6307 ;; provides the option. Alas, the binary
6308 ;; is sometimes `/bin/test' and sometimes it's
6309 ;; `/usr/bin/test'.
6310 ;; `/usr/bin/test -e' In case `/bin/test' does not exist.
fb7933a3 6311 (unless (or
00d6fd04
MA
6312 (and (setq result (format "%s -e" (tramp-get-test-command vec)))
6313 (zerop (tramp-send-command-and-check
6314 vec (format "%s %s" result existing)))
6315 (not (zerop (tramp-send-command-and-check
6316 vec (format "%s %s" result nonexisting)))))
6317 (and (setq result "/bin/test -e")
6318 (zerop (tramp-send-command-and-check
6319 vec (format "%s %s" result existing)))
6320 (not (zerop (tramp-send-command-and-check
6321 vec (format "%s %s" result nonexisting)))))
6322 (and (setq result "/usr/bin/test -e")
6323 (zerop (tramp-send-command-and-check
6324 vec (format "%s %s" result existing)))
6325 (not (zerop (tramp-send-command-and-check
6326 vec (format "%s %s" result nonexisting)))))
6327 (and (setq result (format "%s -d" (tramp-get-ls-command vec)))
6328 (zerop (tramp-send-command-and-check
6329 vec (format "%s %s" result existing)))
6330 (not (zerop (tramp-send-command-and-check
6331 vec (format "%s %s" result nonexisting))))))
6332 (tramp-error
6333 vec 'file-error "Couldn't find command to check if file exists"))
6334 result))
bf247b6e 6335
fb7933a3 6336;; CCC test ksh or bash found for tilde expansion?
00d6fd04
MA
6337(defun tramp-find-shell (vec)
6338 "Opens a shell on the remote host which groks tilde expansion."
6339 (unless (tramp-get-connection-property vec "remote-shell" nil)
6340 (let (shell)
6341 (with-current-buffer (tramp-get-buffer vec)
7e780ff1 6342 (tramp-send-command vec "echo ~root" t)
00d6fd04
MA
6343 (cond
6344 ((string-match "^~root$" (buffer-string))
6345 (setq shell
f84638eb
MA
6346 (or (tramp-find-executable
6347 vec "bash" (tramp-get-remote-path vec) t)
6348 (tramp-find-executable
6349 vec "ksh" (tramp-get-remote-path vec) t)))
00d6fd04
MA
6350 (unless shell
6351 (tramp-error
6352 vec 'file-error
6353 "Couldn't find a shell which groks tilde expansion"))
6354 ;; Find arguments for this shell.
6355 (let ((alist tramp-sh-extra-args)
6356 item extra-args)
6357 (while (and alist (null extra-args))
6358 (setq item (pop alist))
6359 (when (string-match (car item) shell)
6360 (setq extra-args (cdr item))))
6361 (when extra-args (setq shell (concat shell " " extra-args))))
6362 (tramp-message
6363 vec 5 "Starting remote shell `%s' for tilde expansion..." shell)
dab816a9 6364 (let ((tramp-end-of-output tramp-initial-end-of-output))
a4aeb9a4 6365 (tramp-send-command
b08104a0 6366 vec
70c11b0b
MA
6367 (format "PROMPT_COMMAND='' PS1=%s PS2='' PS3='' exec %s"
6368 (shell-quote-argument tramp-end-of-output) shell)
b08104a0 6369 t))
a0a5183a 6370 ;; Setting prompts.
00d6fd04 6371 (tramp-message vec 5 "Setting remote shell prompt...")
70c11b0b
MA
6372 (tramp-send-command
6373 vec (format "PS1=%s" (shell-quote-argument tramp-end-of-output)) t)
9fa0d3aa
MA
6374 (tramp-send-command vec "PS2=''" t)
6375 (tramp-send-command vec "PS3=''" t)
6376 (tramp-send-command vec "PROMPT_COMMAND=''" t)
00d6fd04 6377 (tramp-message vec 5 "Setting remote shell prompt...done"))
a0a5183a 6378
00d6fd04
MA
6379 (t (tramp-message
6380 vec 5 "Remote `%s' groks tilde expansion, good"
6381 (tramp-get-method-parameter
6382 (tramp-file-name-method vec) 'tramp-remote-sh))
6383 (tramp-set-connection-property
6384 vec "remote-shell"
6385 (tramp-get-method-parameter
6386 (tramp-file-name-method vec) 'tramp-remote-sh))))))))
fb7933a3 6387
bf247b6e
KS
6388;; ------------------------------------------------------------
6389;; -- Functions for establishing connection --
6390;; ------------------------------------------------------------
fb7933a3 6391
ac474af1
KG
6392;; The following functions are actions to be taken when seeing certain
6393;; prompts from the remote host. See the variable
6394;; `tramp-actions-before-shell' for usage of these functions.
6395
00d6fd04 6396(defun tramp-action-login (proc vec)
ac474af1 6397 "Send the login name."
00d6fd04
MA
6398 (when (not (stringp tramp-current-user))
6399 (save-window-excursion
6400 (let ((enable-recursive-minibuffers t))
6401 (pop-to-buffer (tramp-get-connection-buffer vec))
6402 (setq tramp-current-user (read-string (match-string 0))))))
6403 (tramp-message vec 3 "Sending login name `%s'" tramp-current-user)
6404 (with-current-buffer (tramp-get-connection-buffer vec)
6405 (tramp-message vec 6 "\n%s" (buffer-string)))
6406 (tramp-send-string vec tramp-current-user))
6407
6408(defun tramp-action-password (proc vec)
ac474af1 6409 "Query the user for a password."
70c11b0b
MA
6410 (with-current-buffer (process-buffer proc)
6411 (tramp-check-for-regexp proc tramp-password-prompt-regexp)
6412 (tramp-message vec 3 "Sending %s" (match-string 1)))
00d6fd04
MA
6413 (tramp-enter-password proc))
6414
6415(defun tramp-action-succeed (proc vec)
ac474af1 6416 "Signal success in finding shell prompt."
ac474af1
KG
6417 (throw 'tramp-action 'ok))
6418
00d6fd04 6419(defun tramp-action-permission-denied (proc vec)
ac474af1 6420 "Signal permission denied."
00d6fd04 6421 (kill-process proc)
ac474af1
KG
6422 (throw 'tramp-action 'permission-denied))
6423
00d6fd04 6424(defun tramp-action-yesno (proc vec)
3cdaec13
KG
6425 "Ask the user for confirmation using `yes-or-no-p'.
6426Send \"yes\" to remote process on confirmation, abort otherwise.
6427See also `tramp-action-yn'."
ac474af1 6428 (save-window-excursion
00d6fd04
MA
6429 (let ((enable-recursive-minibuffers t))
6430 (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec)))
6431 (unless (yes-or-no-p (match-string 0))
6432 (kill-process proc)
6433 (throw 'tramp-action 'permission-denied))
6434 (with-current-buffer (tramp-get-connection-buffer vec)
6435 (tramp-message vec 6 "\n%s" (buffer-string)))
6436 (tramp-send-string vec "yes"))))
6437
6438(defun tramp-action-yn (proc vec)
3cdaec13
KG
6439 "Ask the user for confirmation using `y-or-n-p'.
6440Send \"y\" to remote process on confirmation, abort otherwise.
6441See also `tramp-action-yesno'."
6442 (save-window-excursion
00d6fd04
MA
6443 (let ((enable-recursive-minibuffers t))
6444 (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec)))
6445 (unless (y-or-n-p (match-string 0))
6446 (kill-process proc)
6447 (throw 'tramp-action 'permission-denied))
6448 (with-current-buffer (tramp-get-connection-buffer vec)
6449 (tramp-message vec 6 "\n%s" (buffer-string)))
6450 (tramp-send-string vec "y"))))
6451
6452(defun tramp-action-terminal (proc vec)
487f4fb7
KG
6453 "Tell the remote host which terminal type to use.
6454The terminal type can be configured with `tramp-terminal-type'."
00d6fd04 6455 (tramp-message vec 5 "Setting `%s' as terminal type." tramp-terminal-type)
7e780ff1
MA
6456 (with-current-buffer (tramp-get-connection-buffer vec)
6457 (tramp-message vec 6 "\n%s" (buffer-string)))
00d6fd04 6458 (tramp-send-string vec tramp-terminal-type))
487f4fb7 6459
00d6fd04 6460(defun tramp-action-process-alive (proc vec)
19a87064 6461 "Check whether a process has finished."
00d6fd04 6462 (unless (memq (process-status proc) '(run open))
19a87064
MA
6463 (throw 'tramp-action 'process-died)))
6464
00d6fd04 6465(defun tramp-action-out-of-band (proc vec)
38c65fca 6466 "Check whether an out-of-band copy has finished."
00d6fd04
MA
6467 (cond ((and (memq (process-status proc) '(stop exit))
6468 (zerop (process-exit-status proc)))
6469 (tramp-message vec 3 "Process has finished.")
38c65fca 6470 (throw 'tramp-action 'ok))
00d6fd04
MA
6471 ((or (and (memq (process-status proc) '(stop exit))
6472 (not (zerop (process-exit-status proc))))
6473 (memq (process-status proc) '(signal)))
01917a18
MA
6474 ;; `scp' could have copied correctly, but set modes could have failed.
6475 ;; This can be ignored.
00d6fd04
MA
6476 (with-current-buffer (process-buffer proc)
6477 (goto-char (point-min))
6478 (if (re-search-forward tramp-operation-not-permitted-regexp nil t)
6479 (progn
6480 (tramp-message vec 5 "'set mode' error ignored.")
6481 (tramp-message vec 3 "Process has finished.")
6482 (throw 'tramp-action 'ok))
6483 (tramp-message vec 3 "Process has died.")
6484 (throw 'tramp-action 'process-died))))
38c65fca
KG
6485 (t nil)))
6486
ac474af1
KG
6487;; Functions for processing the actions.
6488
00d6fd04 6489(defun tramp-process-one-action (proc vec actions)
ac474af1 6490 "Wait for output from the shell and perform one action."
00d6fd04 6491 (let (found todo item pattern action)
e6466697 6492 (while (not found)
00d6fd04
MA
6493 ;; Reread output once all actions have been performed.
6494 ;; Obviously, the output was not complete.
6495 (tramp-accept-process-output proc 1)
e6466697
MA
6496 (setq todo actions)
6497 (while todo
e6466697 6498 (setq item (pop todo))
95d610cb 6499 (setq pattern (format "\\(%s\\)\\'" (symbol-value (nth 0 item))))
e6466697 6500 (setq action (nth 1 item))
00d6fd04
MA
6501 (tramp-message
6502 vec 5 "Looking for regexp \"%s\" from remote shell" pattern)
6503 (when (tramp-check-for-regexp proc pattern)
6504 (tramp-message vec 5 "Call `%s'" (symbol-name action))
6505 (setq found (funcall action proc vec)))))
e6466697
MA
6506 found))
6507
00d6fd04 6508(defun tramp-process-actions (proc vec actions &optional timeout)
e6466697 6509 "Perform actions until success or TIMEOUT."
263c02ef 6510 ;; Enable auth-source and password-cache.
5c7043a2 6511 (tramp-set-connection-property proc "first-password-request" t)
ac474af1
KG
6512 (let (exit)
6513 (while (not exit)
00d6fd04 6514 (tramp-message proc 3 "Waiting for prompts from remote shell")
ac474af1
KG
6515 (setq exit
6516 (catch 'tramp-action
e6466697
MA
6517 (if timeout
6518 (with-timeout (timeout)
00d6fd04
MA
6519 (tramp-process-one-action proc vec actions))
6520 (tramp-process-one-action proc vec actions)))))
6521 (with-current-buffer (tramp-get-connection-buffer vec)
6522 (tramp-message vec 6 "\n%s" (buffer-string)))
ac474af1 6523 (unless (eq exit 'ok)
9c13938d 6524 (tramp-clear-passwd vec)
00d6fd04
MA
6525 (tramp-error-with-buffer
6526 nil vec 'file-error
6527 (cond
6528 ((eq exit 'permission-denied) "Permission denied")
6529 ((eq exit 'process-died) "Process died")
6530 (t "Login failed"))))))
fb7933a3
KG
6531
6532;; Utility functions.
6533
00d6fd04 6534(defun tramp-accept-process-output (&optional proc timeout timeout-msecs)
d2a2c17f
MA
6535 "Like `accept-process-output' for Tramp processes.
6536This is needed in order to hide `last-coding-system-used', which is set
6537for process communication also."
00d6fd04
MA
6538 (with-current-buffer (process-buffer proc)
6539 (tramp-message proc 10 "%s %s" proc (process-status proc))
6540 (let (buffer-read-only last-coding-system-used)
6541 ;; Under Windows XP, accept-process-output doesn't return
6542 ;; sometimes. So we add an additional timeout.
6543 (with-timeout ((or timeout 1))
6544 (accept-process-output proc timeout timeout-msecs)))
6545 (tramp-message proc 10 "\n%s" (buffer-string))))
6546
6547(defun tramp-check-for-regexp (proc regexp)
6548 "Check whether REGEXP is contained in process buffer of PROC.
6549Erase echoed commands if exists."
6550 (with-current-buffer (process-buffer proc)
6551 (goto-char (point-min))
674da028 6552
00d6fd04
MA
6553 ;; Check whether we need to remove echo output.
6554 (when (and (tramp-get-connection-property proc "check-remote-echo" nil)
6555 (re-search-forward tramp-echoed-echo-mark-regexp nil t))
6556 (let ((begin (match-beginning 0)))
6557 (when (re-search-forward tramp-echoed-echo-mark-regexp nil t)
6558 ;; Discard echo from remote output.
6559 (tramp-set-connection-property proc "check-remote-echo" nil)
6560 (tramp-message proc 5 "echo-mark found")
6561 (forward-line)
6562 (delete-region begin (point))
6563 (goto-char (point-min)))))
674da028 6564
70c11b0b
MA
6565 (when (not (tramp-get-connection-property proc "check-remote-echo" nil))
6566 ;; No echo to be handled, now we can look for the regexp.
674da028 6567 (goto-char (point-min))
00d6fd04 6568 (re-search-forward regexp nil t))))
d2a2c17f 6569
fb7933a3
KG
6570(defun tramp-wait-for-regexp (proc timeout regexp)
6571 "Wait for a REGEXP to appear from process PROC within TIMEOUT seconds.
6572Expects the output of PROC to be sent to the current buffer. Returns
6573the string that matched, or nil. Waits indefinitely if TIMEOUT is
6574nil."
00d6fd04
MA
6575 (with-current-buffer (process-buffer proc)
6576 (let ((found (tramp-check-for-regexp proc regexp))
6577 (start-time (current-time)))
6578 (cond (timeout
6579 ;; Work around a bug in XEmacs 21, where the timeout
6580 ;; expires faster than it should. This degenerates
6581 ;; to polling for buggy XEmacsen, but oh, well.
6582 (while (and (not found)
6583 (< (tramp-time-diff (current-time) start-time)
6584 timeout))
6585 (with-timeout (timeout)
6586 (while (not found)
6587 (tramp-accept-process-output proc 1)
6588 (unless (memq (process-status proc) '(run open))
6589 (tramp-error-with-buffer
6590 nil proc 'file-error "Process has died"))
6591 (setq found (tramp-check-for-regexp proc regexp))))))
6592 (t
6593 (while (not found)
6594 (tramp-accept-process-output proc 1)
6595 (unless (memq (process-status proc) '(run open))
6596 (tramp-error-with-buffer
6597 nil proc 'file-error "Process has died"))
6598 (setq found (tramp-check-for-regexp proc regexp)))))
6599 (tramp-message proc 6 "\n%s" (buffer-string))
fb7933a3 6600 (when (not found)
00d6fd04
MA
6601 (if timeout
6602 (tramp-error
6603 proc 'file-error "[[Regexp `%s' not found in %d secs]]"
6604 regexp timeout)
6605 (tramp-error proc 'file-error "[[Regexp `%s' not found]]" regexp)))
6606 found)))
fb7933a3 6607
b25a52cc
KG
6608(defun tramp-barf-if-no-shell-prompt (proc timeout &rest error-args)
6609 "Wait for shell prompt and barf if none appears.
6610Looks at process PROC to see if a shell prompt appears in TIMEOUT
6611seconds. If not, it produces an error message with the given ERROR-ARGS."
7e780ff1
MA
6612 (unless
6613 (tramp-wait-for-regexp
6614 proc timeout
6615 (format
6616 "\\(%s\\|%s\\)\\'" shell-prompt-pattern tramp-shell-prompt-pattern))
00d6fd04
MA
6617 (apply 'tramp-error-with-buffer nil proc 'file-error error-args)))
6618
7e780ff1
MA
6619;; We don't call `tramp-send-string' in order to hide the password
6620;; from the debug buffer, and because end-of-line handling of the
6621;; string.
6622(defun tramp-enter-password (proc)
00d6fd04
MA
6623 "Prompt for a password and send it to the remote end."
6624 (process-send-string
7e780ff1
MA
6625 proc (concat (tramp-read-passwd proc)
6626 (or (tramp-get-method-parameter
6627 tramp-current-method
6628 'tramp-password-end-of-line)
6629 tramp-default-password-end-of-line))))
00d6fd04
MA
6630
6631(defun tramp-open-connection-setup-interactive-shell (proc vec)
fb7933a3 6632 "Set up an interactive shell.
00d6fd04
MA
6633Mainly sets the prompt and the echo correctly. PROC is the shell
6634process to set up. VEC specifies the connection."
dab816a9 6635 (let ((tramp-end-of-output tramp-initial-end-of-output))
8950769a
MA
6636 ;; It is useful to set the prompt in the following command because
6637 ;; some people have a setting for $PS1 which /bin/sh doesn't know
6638 ;; about and thus /bin/sh will display a strange prompt. For
6639 ;; example, if $PS1 has "${CWD}" in the value, then ksh will
6640 ;; display the current working directory but /bin/sh will display
6641 ;; a dollar sign. The following command line sets $PS1 to a sane
6642 ;; value, and works under Bourne-ish shells as well as csh-like
6643 ;; shells. Daniel Pittman reports that the unusual positioning of
6644 ;; the single quotes makes it work under `rc', too. We also unset
6645 ;; the variable $ENV because that is read by some sh
6646 ;; implementations (eg, bash when called as sh) on startup; this
6647 ;; way, we avoid the startup file clobbering $PS1. $PROMP_COMMAND
6648 ;; is another way to set the prompt in /bin/bash, it must be
6649 ;; discarded as well.
a4aeb9a4
MA
6650 (tramp-send-command
6651 vec
6652 (format
70c11b0b
MA
6653 "exec env ENV='' PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s"
6654 (shell-quote-argument tramp-end-of-output)
a4aeb9a4
MA
6655 (tramp-get-method-parameter
6656 (tramp-file-name-method vec) 'tramp-remote-sh))
8950769a
MA
6657 t)
6658
6659 ;; Disable echo.
6660 (tramp-message vec 5 "Setting up remote shell environment")
6661 (tramp-send-command vec "stty -inlcr -echo kill '^U' erase '^H'" t)
6662 ;; Check whether the echo has really been disabled. Some
6663 ;; implementations, like busybox of embedded GNU/Linux, don't
6664 ;; support disabling.
6665 (tramp-send-command vec "echo foo" t)
6666 (with-current-buffer (process-buffer proc)
6667 (goto-char (point-min))
6668 (when (looking-at "echo foo")
6669 (tramp-set-connection-property proc "remote-echo" t)
6670 (tramp-message vec 5 "Remote echo still on. Ok.")
6671 ;; Make sure backspaces and their echo are enabled and no line
6672 ;; width magic interferes with them.
6673 (tramp-send-command vec "stty icanon erase ^H cols 32767" t))))
e42c6bbc 6674
7e780ff1 6675 (tramp-message vec 5 "Setting shell prompt")
70c11b0b
MA
6676 (tramp-send-command
6677 vec (format "PS1=%s" (shell-quote-argument tramp-end-of-output)) t)
9fa0d3aa
MA
6678 (tramp-send-command vec "PS2=''" t)
6679 (tramp-send-command vec "PS3=''" t)
6680 (tramp-send-command vec "PROMPT_COMMAND=''" t)
e42c6bbc 6681
fb7933a3
KG
6682 ;; Try to set up the coding system correctly.
6683 ;; CCC this can't be the right way to do it. Hm.
00d6fd04 6684 (tramp-message vec 5 "Determining coding system")
7e780ff1 6685 (tramp-send-command vec "echo foo ; echo bar" t)
00d6fd04 6686 (with-current-buffer (process-buffer proc)
fb7933a3
KG
6687 (goto-char (point-min))
6688 (if (featurep 'mule)
00d6fd04
MA
6689 ;; Use MULE to select the right EOL convention for communicating
6690 ;; with the process.
311dd93f 6691 (let* ((cs (or (funcall (symbol-function 'process-coding-system) proc)
00d6fd04
MA
6692 (cons 'undecided 'undecided)))
6693 cs-decode cs-encode)
6694 (when (symbolp cs) (setq cs (cons cs cs)))
6695 (setq cs-decode (car cs))
6696 (setq cs-encode (cdr cs))
6697 (unless cs-decode (setq cs-decode 'undecided))
6698 (unless cs-encode (setq cs-encode 'undecided))
6699 (setq cs-encode (tramp-coding-system-change-eol-conversion
6700 cs-encode 'unix))
6701 (when (search-forward "\r" nil t)
6702 (setq cs-decode (tramp-coding-system-change-eol-conversion
6703 cs-decode 'dos)))
311dd93f 6704 (funcall (symbol-function 'set-buffer-process-coding-system)
70c11b0b
MA
6705 cs-decode cs-encode)
6706 (tramp-message
6707 vec 5 "Setting coding system to `%s' and `%s'" cs-decode cs-encode))
fb7933a3
KG
6708 ;; Look for ^M and do something useful if found.
6709 (when (search-forward "\r" nil t)
00d6fd04
MA
6710 ;; We have found a ^M but cannot frob the process coding system
6711 ;; because we're running on a non-MULE Emacs. Let's try
6712 ;; stty, instead.
7e780ff1
MA
6713 (tramp-send-command vec "stty -onlcr" t))))
6714 (tramp-send-command vec "set +o vi +o emacs" t)
e42c6bbc
MA
6715
6716 ;; Check whether the output of "uname -sr" has been changed. If
6717 ;; yes, this is a strong indication that we must expire all
d8ac123e
MA
6718 ;; connection properties. We start again with
6719 ;; `tramp-maybe-open-connection', it will be catched there.
e42c6bbc
MA
6720 (tramp-message vec 5 "Checking system information")
6721 (let ((old-uname (tramp-get-connection-property vec "uname" nil))
6722 (new-uname
6723 (tramp-set-connection-property
6724 vec "uname"
6725 (tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\""))))
6726 (when (and (stringp old-uname) (not (string-equal old-uname new-uname)))
d8ac123e
MA
6727 (with-current-buffer (tramp-get-debug-buffer vec)
6728 ;; Keep the debug buffer
2296b54d
MA
6729 (rename-buffer
6730 (generate-new-buffer-name tramp-temp-buffer-name) 'unique)
d8ac123e
MA
6731 (funcall (symbol-function 'tramp-cleanup-connection) vec)
6732 (if (= (point-min) (point-max))
6733 (kill-buffer nil)
6734 (rename-buffer (tramp-debug-buffer-name vec) 'unique))
6735 ;; We call `tramp-get-buffer' in order to keep the debug buffer.
6736 (tramp-get-buffer vec)
6737 (tramp-message
6738 vec 3
6739 "Connection reset, because remote host changed from `%s' to `%s'"
6740 old-uname new-uname)
6741 (throw 'uname-changed (tramp-maybe-open-connection vec)))))
e42c6bbc
MA
6742
6743 ;; Check whether the remote host suffers from buggy
6744 ;; `send-process-string'. This is known for FreeBSD (see comment in
6745 ;; `send_process', file process.c). I've tested sending 624 bytes
6746 ;; successfully, sending 625 bytes failed. Emacs makes a hack when
6747 ;; this host type is detected locally. It cannot handle remote
6748 ;; hosts, though.
00d6fd04
MA
6749 (with-connection-property proc "chunksize"
6750 (cond
6751 ((and (integerp tramp-chunksize) (> tramp-chunksize 0))
6752 tramp-chunksize)
6753 (t
6754 (tramp-message
6755 vec 5 "Checking remote host type for `send-process-string' bug")
6756 (if (string-match
e42c6bbc 6757 "^FreeBSD" (tramp-get-connection-property vec "uname" ""))
00d6fd04 6758 500 0))))
e42c6bbc 6759
00d6fd04
MA
6760 ;; Set remote PATH variable.
6761 (tramp-set-remote-path vec)
e42c6bbc 6762
fb7933a3
KG
6763 ;; Search for a good shell before searching for a command which
6764 ;; checks if a file exists. This is done because Tramp wants to use
6765 ;; "test foo; echo $?" to check if various conditions hold, and
6766 ;; there are buggy /bin/sh implementations which don't execute the
6767 ;; "echo $?" part if the "test" part has an error. In particular,
6768 ;; the Solaris /bin/sh is a problem. I'm betting that all systems
6769 ;; with buggy /bin/sh implementations will have a working bash or
6770 ;; ksh. Whee...
00d6fd04 6771 (tramp-find-shell vec)
e42c6bbc 6772
00d6fd04 6773 ;; Disable unexpected output.
7e780ff1 6774 (tramp-send-command vec "mesg n; biff n" t)
e42c6bbc 6775
00d6fd04
MA
6776 ;; Set the environment.
6777 (tramp-message vec 5 "Setting default environment")
661aaece
MA
6778
6779 ;; On OpenSolaris, there is a bug when HISTFILE is changed in place
6780 ;; <http://bugs.opensolaris.org/view_bug.do?bug_id=6834184>. We
6781 ;; apply the workaround.
6782 (if (string-equal (tramp-get-connection-property vec "uname" "") "SunOS 5.11")
6783 (tramp-send-command vec "unset HISTFILE"))
6784
00d6fd04
MA
6785 (let ((env (copy-sequence tramp-remote-process-environment))
6786 unset item)
6787 (while env
70c11b0b 6788 (setq item (tramp-compat-split-string (car env) "="))
00d6fd04
MA
6789 (if (and (stringp (cadr item)) (not (string-equal (cadr item) "")))
6790 (tramp-send-command
7e780ff1 6791 vec (format "%s=%s; export %s" (car item) (cadr item) (car item)) t)
00d6fd04
MA
6792 (push (car item) unset))
6793 (setq env (cdr env)))
6794 (when unset
fb7933a3 6795 (tramp-send-command
7e780ff1 6796 vec (format "unset %s" (mapconcat 'identity unset " "))))) t)
fb7933a3 6797
ac474af1
KG
6798;; CCC: We should either implement a Perl version of base64 encoding
6799;; and decoding. Then we just use that in the last item. The other
6800;; alternative is to use the Perl version of UU encoding. But then
6801;; we need a Lisp version of uuencode.
16674e4f
KG
6802;;
6803;; Old text from documentation of tramp-methods:
6804;; Using a uuencode/uudecode inline method is discouraged, please use one
6805;; of the base64 methods instead since base64 encoding is much more
6806;; reliable and the commands are more standardized between the different
6807;; Unix versions. But if you can't use base64 for some reason, please
6808;; note that the default uudecode command does not work well for some
6809;; Unices, in particular AIX and Irix. For AIX, you might want to use
6810;; the following command for uudecode:
6811;;
6812;; sed '/^begin/d;/^[` ]$/d;/^end/d' | iconv -f uucode -t ISO8859-1
6813;;
6814;; For Irix, no solution is known yet.
6815
00d6fd04
MA
6816(defconst tramp-local-coding-commands
6817 '((b64 base64-encode-region base64-decode-region)
6818 (uu tramp-uuencode-region uudecode-decode-region)
6819 (pack
6820 "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
6821 "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"))
6822 "List of local coding commands for inline transfer.
16674e4f
KG
6823Each item is a list that looks like this:
6824
00d6fd04 6825\(FORMAT ENCODING DECODING)
ac474af1 6826
00d6fd04
MA
6827FORMAT is symbol describing the encoding/decoding format. It can be
6828`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
ac474af1 6829
00d6fd04
MA
6830ENCODING and DECODING can be strings, giving commands, or symbols,
6831giving functions. If they are strings, then they can contain
16674e4f
KG
6832the \"%s\" format specifier. If that specifier is present, the input
6833filename will be put into the command line at that spot. If the
6834specifier is not present, the input should be read from standard
6835input.
ac474af1 6836
16674e4f
KG
6837If they are functions, they will be called with two arguments, start
6838and end of region, and are expected to replace the region contents
6839with the encoded or decoded results, respectively.")
ac474af1 6840
00d6fd04 6841(defconst tramp-remote-coding-commands
3dc847a3
MA
6842 '((b64 "base64" "base64 -d")
6843 (b64 "mimencode -b" "mimencode -u -b")
00d6fd04
MA
6844 (b64 "mmencode -b" "mmencode -u -b")
6845 (b64 "recode data..base64" "recode base64..data")
6846 (b64 tramp-perl-encode-with-module tramp-perl-decode-with-module)
6847 (b64 tramp-perl-encode tramp-perl-decode)
6848 (uu "uuencode xxx" "uudecode -o /dev/stdout")
6849 (uu "uuencode xxx" "uudecode -o -")
6850 (uu "uuencode xxx" "uudecode -p")
6851 (uu "uuencode xxx" tramp-uudecode)
6852 (pack
6853 "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
6854 "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"))
6855 "List of remote coding commands for inline transfer.
6856Each item is a list that looks like this:
6857
6858\(FORMAT ENCODING DECODING)
6859
6860FORMAT is symbol describing the encoding/decoding format. It can be
6861`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
6862
6863ENCODING and DECODING can be strings, giving commands, or symbols,
6864giving variables. If they are strings, then they can contain
6865the \"%s\" format specifier. If that specifier is present, the input
6866filename will be put into the command line at that spot. If the
6867specifier is not present, the input should be read from standard
6868input.
6869
6870If they are variables, this variable is a string containing a Perl
6871implementation for this functionality. This Perl program will be transferred
6872to the remote host, and it is avalible as shell function with the same name.")
6873
6874(defun tramp-find-inline-encoding (vec)
ac474af1 6875 "Find an inline transfer encoding that works.
00d6fd04
MA
6876Goes through the list `tramp-local-coding-commands' and
6877`tramp-remote-coding-commands'."
6878 (save-excursion
6879 (let ((local-commands tramp-local-coding-commands)
6880 (magic "xyzzy")
6881 loc-enc loc-dec rem-enc rem-dec litem ritem found)
6882 (while (and local-commands (not found))
6883 (setq litem (pop local-commands))
6884 (catch 'wont-work-local
6885 (let ((format (nth 0 litem))
6886 (remote-commands tramp-remote-coding-commands))
6887 (setq loc-enc (nth 1 litem))
6888 (setq loc-dec (nth 2 litem))
6889 ;; If the local encoder or decoder is a string, the
6890 ;; corresponding command has to work locally.
6891 (if (not (stringp loc-enc))
6892 (tramp-message
6893 vec 5 "Checking local encoding function `%s'" loc-enc)
6894 (tramp-message
6895 vec 5 "Checking local encoding command `%s' for sanity" loc-enc)
6896 (unless (zerop (tramp-call-local-coding-command
6897 loc-enc nil nil))
6898 (throw 'wont-work-local nil)))
6899 (if (not (stringp loc-dec))
6900 (tramp-message
6901 vec 5 "Checking local decoding function `%s'" loc-dec)
6902 (tramp-message
6903 vec 5 "Checking local decoding command `%s' for sanity" loc-dec)
6904 (unless (zerop (tramp-call-local-coding-command
6905 loc-dec nil nil))
6906 (throw 'wont-work-local nil)))
6907 ;; Search for remote coding commands with the same format
6908 (while (and remote-commands (not found))
6909 (setq ritem (pop remote-commands))
6910 (catch 'wont-work-remote
6911 (when (equal format (nth 0 ritem))
6912 (setq rem-enc (nth 1 ritem))
6913 (setq rem-dec (nth 2 ritem))
6914 ;; Check if remote encoding and decoding commands can be
6915 ;; called remotely with null input and output. This makes
6916 ;; sure there are no syntax errors and the command is really
6917 ;; found. Note that we do not redirect stdout to /dev/null,
6918 ;; for two reasons: when checking the decoding command, we
6919 ;; actually check the output it gives. And also, when
6920 ;; redirecting "mimencode" output to /dev/null, then as root
6921 ;; it might change the permissions of /dev/null!
6922 (when (not (stringp rem-enc))
6923 (let ((name (symbol-name rem-enc)))
6924 (while (string-match (regexp-quote "-") name)
6925 (setq name (replace-match "_" nil t name)))
6926 (tramp-maybe-send-script vec (symbol-value rem-enc) name)
6927 (setq rem-enc name)))
6928 (tramp-message
6929 vec 5
6930 "Checking remote encoding command `%s' for sanity" rem-enc)
6931 (unless (zerop (tramp-send-command-and-check
6932 vec (format "%s </dev/null" rem-enc) t))
6933 (throw 'wont-work-remote nil))
6934
6935 (when (not (stringp rem-dec))
6936 (let ((name (symbol-name rem-dec)))
6937 (while (string-match (regexp-quote "-") name)
6938 (setq name (replace-match "_" nil t name)))
6939 (tramp-maybe-send-script vec (symbol-value rem-dec) name)
6940 (setq rem-dec name)))
6941 (tramp-message
6942 vec 5
6943 "Checking remote decoding command `%s' for sanity" rem-dec)
6944 (unless (zerop (tramp-send-command-and-check
6945 vec
6946 (format "echo %s | %s | %s"
b593f105
MA
6947 magic rem-enc rem-dec)
6948 t))
00d6fd04
MA
6949 (throw 'wont-work-remote nil))
6950
6951 (with-current-buffer (tramp-get-buffer vec)
6952 (goto-char (point-min))
6953 (unless (looking-at (regexp-quote magic))
6954 (throw 'wont-work-remote nil)))
6955
6956 ;; `rem-enc' and `rem-dec' could be a string meanwhile.
6957 (setq rem-enc (nth 1 ritem))
6958 (setq rem-dec (nth 2 ritem))
6959 (setq found t)))))))
6960
1d7e9a01 6961 ;; Did we find something?
00d6fd04 6962 (unless found
1d7e9a01 6963 (tramp-message vec 2 "Couldn't find an inline transfer encoding"))
00d6fd04
MA
6964
6965 ;; Set connection properties.
6966 (tramp-message vec 5 "Using local encoding `%s'" loc-enc)
6967 (tramp-set-connection-property vec "local-encoding" loc-enc)
6968 (tramp-message vec 5 "Using local decoding `%s'" loc-dec)
6969 (tramp-set-connection-property vec "local-decoding" loc-dec)
6970 (tramp-message vec 5 "Using remote encoding `%s'" rem-enc)
6971 (tramp-set-connection-property vec "remote-encoding" rem-enc)
6972 (tramp-message vec 5 "Using remote decoding `%s'" rem-dec)
6973 (tramp-set-connection-property vec "remote-decoding" rem-dec))))
16674e4f
KG
6974
6975(defun tramp-call-local-coding-command (cmd input output)
6976 "Call the local encoding or decoding command.
6977If CMD contains \"%s\", provide input file INPUT there in command.
6978Otherwise, INPUT is passed via standard input.
6979INPUT can also be nil which means `/dev/null'.
6980OUTPUT can be a string (which specifies a filename), or t (which
6981means standard output and thus the current buffer), or nil (which
6982means discard it)."
a4aeb9a4
MA
6983 (tramp-local-call-process
6984 tramp-encoding-shell
6985 (when (and input (not (string-match "%s" cmd))) input)
6986 (if (eq output t) t nil)
6987 nil
6988 tramp-encoding-command-switch
6989 (concat
6990 (if (string-match "%s" cmd) (format cmd input) cmd)
6991 (if (stringp output) (concat "> " output) ""))))
00d6fd04
MA
6992
6993(defun tramp-compute-multi-hops (vec)
6994 "Expands VEC according to `tramp-default-proxies-alist'.
6995Gateway hops are already opened."
6996 (let ((target-alist `(,vec))
6997 (choices tramp-default-proxies-alist)
6998 item proxy)
6999
7000 ;; Look for proxy hosts to be passed.
7001 (while choices
7002 (setq item (pop choices)
70c11b0b 7003 proxy (eval (nth 2 item)))
00d6fd04
MA
7004 (when (and
7005 ;; host
70c11b0b 7006 (string-match (or (eval (nth 0 item)) "")
00d6fd04
MA
7007 (or (tramp-file-name-host (car target-alist)) ""))
7008 ;; user
70c11b0b 7009 (string-match (or (eval (nth 1 item)) "")
00d6fd04
MA
7010 (or (tramp-file-name-user (car target-alist)) "")))
7011 (if (null proxy)
7012 ;; No more hops needed.
7013 (setq choices nil)
7014 ;; Replace placeholders.
7015 (setq proxy
7016 (format-spec
7017 proxy
7018 `((?u . ,(or (tramp-file-name-user (car target-alist)) ""))
7019 (?h . ,(or (tramp-file-name-host (car target-alist)) "")))))
7020 (with-parsed-tramp-file-name proxy l
7021 ;; Add the hop.
7022 (add-to-list 'target-alist l)
7023 ;; Start next search.
7024 (setq choices tramp-default-proxies-alist)))))
7025
7026 ;; Handle gateways.
8a4438b6
MA
7027 (when (and (boundp 'tramp-gw-tunnel-method)
7028 (string-match (format
7029 "^\\(%s\\|%s\\)$"
7030 (symbol-value 'tramp-gw-tunnel-method)
7031 (symbol-value 'tramp-gw-socks-method))
7032 (tramp-file-name-method (car target-alist))))
00d6fd04
MA
7033 (let ((gw (pop target-alist))
7034 (hop (pop target-alist)))
7035 ;; Is the method prepared for gateways?
7036 (unless (tramp-get-method-parameter
7037 (tramp-file-name-method hop) 'tramp-default-port)
7038 (tramp-error
7039 vec 'file-error
7040 "Method `%s' is not supported for gateway access."
7041 (tramp-file-name-method hop)))
7042 ;; Add default port if needed.
7043 (unless
7044 (string-match
7045 tramp-host-with-port-regexp (tramp-file-name-host hop))
7046 (aset hop 2
7047 (concat
7048 (tramp-file-name-host hop) tramp-prefix-port-format
7049 (number-to-string
7050 (tramp-get-method-parameter
7051 (tramp-file-name-method hop) 'tramp-default-port)))))
7052 ;; Open the gateway connection.
7053 (add-to-list
7054 'target-alist
7055 (vector
7056 (tramp-file-name-method hop) (tramp-file-name-user hop)
9e6ab520 7057 (funcall (symbol-function 'tramp-gw-open-connection) vec gw hop) nil))
00d6fd04
MA
7058 ;; For the password prompt, we need the correct values.
7059 ;; Therefore, we must remember the gateway vector. But we
7060 ;; cannot do it as connection property, because it shouldn't
7061 ;; be persistent. And we have no started process yet either.
7062 (tramp-set-file-property (car target-alist) "" "gateway" hop)))
7063
7064 ;; Foreign and out-of-band methods are not supported for multi-hops.
7065 (when (cdr target-alist)
7066 (setq choices target-alist)
7067 (while choices
7068 (setq item (pop choices))
7069 (when
7070 (or
7071 (not
7072 (tramp-get-method-parameter
7073 (tramp-file-name-method item) 'tramp-login-program))
7074 (tramp-get-method-parameter
7075 (tramp-file-name-method item) 'tramp-copy-program))
7076 (tramp-error
7077 vec 'file-error
7078 "Method `%s' is not supported for multi-hops."
7079 (tramp-file-name-method item)))))
7080
2991e49f
MA
7081 ;; In case the host name is not used for the remote shell
7082 ;; command, the user could be misguided by applying a random
7083 ;; hostname.
7084 (let* ((v (car target-alist))
7085 (method (tramp-file-name-method v))
7086 (host (tramp-file-name-host v)))
7087 (unless
7088 (or
7089 ;; There are multi-hops.
7090 (cdr target-alist)
7091 ;; The host name is used for the remote shell command.
7092 (member
7093 '("%h") (tramp-get-method-parameter method 'tramp-login-args))
7094 ;; The host is local. We cannot use `tramp-local-host-p'
7095 ;; here, because it opens a connection as well.
b96e6899 7096 (string-match tramp-local-host-regexp host))
2991e49f 7097 (tramp-error
42bc9b6d
MA
7098 v 'file-error
7099 "Host `%s' looks like a remote host, `%s' can only use the local host"
7100 host method)))
2991e49f 7101
00d6fd04
MA
7102 ;; Result.
7103 target-alist))
7104
7105(defun tramp-maybe-open-connection (vec)
7106 "Maybe open a connection VEC.
fb7933a3
KG
7107Does not do anything if a connection is already open, but re-opens the
7108connection if a previous connection has died for some reason."
d8ac123e
MA
7109 (catch 'uname-changed
7110 (let ((p (tramp-get-connection-process vec))
7111 (process-environment (copy-sequence process-environment)))
7112
7113 ;; If too much time has passed since last command was sent, look
7114 ;; whether process is still alive. If it isn't, kill it. When
7115 ;; using ssh, it can sometimes happen that the remote end has
7116 ;; hung up but the local ssh client doesn't recognize this until
7117 ;; it tries to send some data to the remote end. So that's why
7118 ;; we try to send a command from time to time, then look again
7119 ;; whether the process is really alive.
7120 (condition-case nil
7121 (when (and (> (tramp-time-diff
7122 (current-time)
7123 (tramp-get-connection-property
7124 p "last-cmd-time" '(0 0 0)))
7125 60)
7126 p (processp p) (memq (process-status p) '(run open)))
7127 (tramp-send-command vec "echo are you awake" t t)
7128 (unless (and (memq (process-status p) '(run open))
7129 (tramp-wait-for-output p 10))
7130 ;; The error will be catched locally.
7131 (tramp-error vec 'file-error "Awake did fail")))
7132 (file-error
7133 (tramp-flush-connection-property vec)
7134 (tramp-flush-connection-property p)
7135 (delete-process p)
7136 (setq p nil)))
7137
7138 ;; New connection must be opened.
7139 (unless (and p (processp p) (memq (process-status p) '(run open)))
7140
7141 ;; We call `tramp-get-buffer' in order to get a debug buffer for
7142 ;; messages from the beginning.
7143 (tramp-get-buffer vec)
7144 (if (zerop (length (tramp-file-name-user vec)))
7145 (tramp-message
7146 vec 3 "Opening connection for %s using %s..."
7147 (tramp-file-name-host vec)
7148 (tramp-file-name-method vec))
00d6fd04 7149 (tramp-message
d8ac123e
MA
7150 vec 3 "Opening connection for %s@%s using %s..."
7151 (tramp-file-name-user vec)
00d6fd04 7152 (tramp-file-name-host vec)
d8ac123e
MA
7153 (tramp-file-name-method vec)))
7154
7155 ;; Start new process.
7156 (when (and p (processp p))
7157 (delete-process p))
7158 (setenv "TERM" tramp-terminal-type)
7159 (setenv "LC_ALL" "C")
7160 (setenv "PROMPT_COMMAND")
dab816a9 7161 (setenv "PS1" tramp-initial-end-of-output)
d8ac123e
MA
7162 (let* ((target-alist (tramp-compute-multi-hops vec))
7163 (process-connection-type tramp-process-connection-type)
7164 (process-adaptive-read-buffering nil)
7165 (coding-system-for-read nil)
7166 ;; This must be done in order to avoid our file name handler.
7167 (p (let ((default-directory
7168 (tramp-compat-temporary-file-directory)))
7169 (start-process
7170 (or (tramp-get-connection-property vec "process-name" nil)
7171 (tramp-buffer-name vec))
7172 (tramp-get-connection-buffer vec)
70c11b0b 7173 tramp-encoding-shell))))
00d6fd04 7174
d8ac123e
MA
7175 (tramp-message
7176 vec 6 "%s" (mapconcat 'identity (process-command p) " "))
7177
7178 ;; Check whether process is alive.
d8ac123e
MA
7179 (tramp-set-process-query-on-exit-flag p nil)
7180 (tramp-message vec 3 "Waiting 60s for local shell to come up...")
7181 (tramp-barf-if-no-shell-prompt
7182 p 60 "Couldn't find local shell prompt %s" tramp-encoding-shell)
7183
7184 ;; Now do all the connections as specified.
7185 (while target-alist
7186 (let* ((hop (car target-alist))
7187 (l-method (tramp-file-name-method hop))
7188 (l-user (tramp-file-name-user hop))
7189 (l-host (tramp-file-name-host hop))
7190 (l-port nil)
7191 (login-program
7192 (tramp-get-method-parameter l-method 'tramp-login-program))
7193 (login-args
7194 (tramp-get-method-parameter l-method 'tramp-login-args))
7195 (gw-args
7196 (tramp-get-method-parameter l-method 'tramp-gw-args))
7197 (gw (tramp-get-file-property hop "" "gateway" nil))
7198 (g-method (and gw (tramp-file-name-method gw)))
7199 (g-user (and gw (tramp-file-name-user gw)))
7200 (g-host (and gw (tramp-file-name-host gw)))
7201 (command login-program)
7202 ;; We don't create the temporary file. In fact, it
7203 ;; is just a prefix for the ControlPath option of
7204 ;; ssh; the real temporary file has another name, and
7205 ;; it is created and protected by ssh. It is also
7206 ;; removed by ssh, when the connection is closed.
7207 (tmpfile
7208 (tramp-set-connection-property
7209 p "temp-file"
7210 (make-temp-name
7211 (expand-file-name
7212 tramp-temp-name-prefix
7213 (tramp-compat-temporary-file-directory)))))
7214 spec)
7215
7216 ;; Add gateway arguments if necessary.
7217 (when (and gw gw-args)
7218 (setq login-args (append login-args gw-args)))
7219
7220 ;; Check for port number. Until now, there's no need
7221 ;; for handling like method, user, host.
7222 (when (string-match tramp-host-with-port-regexp l-host)
7223 (setq l-port (match-string 2 l-host)
7224 l-host (match-string 1 l-host)))
7225
7226 ;; Set variables for computing the prompt for reading
2296b54d 7227 ;; password. They can also be derived from a gateway.
d8ac123e
MA
7228 (setq tramp-current-method (or g-method l-method)
7229 tramp-current-user (or g-user l-user)
7230 tramp-current-host (or g-host l-host))
7231
7232 ;; Replace login-args place holders.
7233 (setq
7234 l-host (or l-host "")
7235 l-user (or l-user "")
7236 l-port (or l-port "")
7237 spec `((?h . ,l-host) (?u . ,l-user) (?p . ,l-port)
7238 (?t . ,tmpfile))
7239 command
7240 (concat
e2a421af
MA
7241 ;; We do not want to see the trailing local prompt in
7242 ;; `start-file-process'.
7243 (unless (memq system-type '(windows-nt)) "exec ")
d8ac123e
MA
7244 command " "
7245 (mapconcat
aa485f7c
MA
7246 (lambda (x)
7247 (setq x (mapcar (lambda (y) (format-spec y spec)) x))
7248 (unless (member "" x) (mapconcat 'identity x " ")))
d8ac123e 7249 login-args " ")
d8ac123e
MA
7250 ;; Local shell could be a Windows COMSPEC. It doesn't
7251 ;; know the ";" syntax, but we must exit always for
70c11b0b 7252 ;; `start-file-process'. "exec" does not work either.
e2a421af 7253 (if (memq system-type '(windows-nt)) " && exit || exit")))
d8ac123e
MA
7254
7255 ;; Send the command.
7256 (tramp-message vec 3 "Sending command `%s'" command)
7257 (tramp-send-command vec command t t)
7258 (tramp-process-actions p vec tramp-actions-before-shell 60)
7259 (tramp-message vec 3 "Found remote shell prompt on `%s'" l-host))
7260 ;; Next hop.
7261 (setq target-alist (cdr target-alist)))
7262
7263 ;; Make initial shell settings.
7264 (tramp-open-connection-setup-interactive-shell p vec))))))
00d6fd04
MA
7265
7266(defun tramp-send-command (vec command &optional neveropen nooutput)
7267 "Send the COMMAND to connection VEC.
7268Erases temporary buffer before sending the command. If optional
7269arg NEVEROPEN is non-nil, never try to open the connection. This
7270is meant to be used from `tramp-maybe-open-connection' only. The
7271function waits for output unless NOOUTPUT is set."
7272 (unless neveropen (tramp-maybe-open-connection vec))
7273 (let ((p (tramp-get-connection-process vec)))
8950769a 7274 (when (tramp-get-connection-property p "remote-echo" nil)
00d6fd04
MA
7275 ;; We mark the command string that it can be erased in the output buffer.
7276 (tramp-set-connection-property p "check-remote-echo" t)
7277 (setq command (format "%s%s%s" tramp-echo-mark command tramp-echo-mark)))
7278 (tramp-message vec 6 "%s" command)
7279 (tramp-send-string vec command)
7280 (unless nooutput (tramp-wait-for-output p))))
7281
00d6fd04 7282(defun tramp-wait-for-output (proc &optional timeout)
fb7933a3 7283 "Wait for output from remote rsh command."
00d6fd04 7284 (with-current-buffer (process-buffer proc)
dab816a9 7285 (let* (;; Initially, `tramp-end-of-output' is "#$ ". There might
bede3e9f 7286 ;; be leading escape sequences, which must be ignored.
dab816a9 7287 (regexp (format "[^#$\n]*%s\r?$" (regexp-quote tramp-end-of-output)))
bede3e9f
MA
7288 ;; Sometimes, the commands do not return a newline but a
7289 ;; null byte before the shell prompt, for example "git
7290 ;; ls-files -c -z ...".
7291 (regexp1 (format "\\(^\\|\000\\)%s" regexp))
7292 (found (tramp-wait-for-regexp proc timeout regexp1)))
00d6fd04
MA
7293 (if found
7294 (let (buffer-read-only)
7295 (goto-char (point-max))
0664ff72 7296 (re-search-backward regexp nil t)
00d6fd04
MA
7297 (delete-region (point) (point-max)))
7298 (if timeout
7299 (tramp-error
7300 proc 'file-error
7301 "[[Remote prompt `%s' not found in %d secs]]"
7302 tramp-end-of-output timeout)
7303 (tramp-error
7304 proc 'file-error
7305 "[[Remote prompt `%s' not found]]" tramp-end-of-output)))
7306 ;; Return value is whether end-of-output sentinel was found.
7307 found)))
fb7933a3 7308
b593f105
MA
7309(defun tramp-send-command-and-check
7310 (vec command &optional subshell dont-suppress-err)
fb7933a3 7311 "Run COMMAND and check its exit status.
fb7933a3
KG
7312Sends `echo $?' along with the COMMAND for checking the exit status. If
7313COMMAND is nil, just sends `echo $?'. Returns the exit status found.
7314
b593f105
MA
7315If the optional argument SUBSHELL is non-nil, the command is
7316executed in a subshell, ie surrounded by parentheses. If
7317DONT-SUPPRESS-ERR is non-nil, stderr won't be sent to /dev/null."
00d6fd04
MA
7318 (tramp-send-command
7319 vec
7320 (concat (if subshell "( " "")
7321 command
b593f105 7322 (if command (if dont-suppress-err "; " " 2>/dev/null; ") "")
00d6fd04 7323 "echo tramp_exit_status $?"
b593f105 7324 (if subshell " )" "")))
00d6fd04
MA
7325 (with-current-buffer (tramp-get-connection-buffer vec)
7326 (goto-char (point-max))
7327 (unless (re-search-backward "tramp_exit_status [0-9]+" nil t)
7328 (tramp-error
7329 vec 'file-error "Couldn't find exit status of `%s'" command))
7330 (skip-chars-forward "^ ")
7331 (prog1
7332 (read (current-buffer))
7333 (let (buffer-read-only) (delete-region (match-beginning 0) (point-max))))))
7334
7335(defun tramp-barf-unless-okay (vec command fmt &rest args)
fb7933a3
KG
7336 "Run COMMAND, check exit status, throw error if exit status not okay.
7337Similar to `tramp-send-command-and-check' but accepts two more arguments
7338FMT and ARGS which are passed to `error'."
00d6fd04
MA
7339 (unless (zerop (tramp-send-command-and-check vec command))
7340 (apply 'tramp-error vec 'file-error fmt args)))
7341
7342(defun tramp-send-command-and-read (vec command)
7343 "Run COMMAND and return the output, which must be a Lisp expression.
7344In case there is no valid Lisp expression, it raises an error"
7345 (tramp-barf-unless-okay vec command "`%s' returns with error" command)
7346 (with-current-buffer (tramp-get-connection-buffer vec)
7347 ;; Read the expression.
7348 (goto-char (point-min))
7349 (condition-case nil
7350 (prog1 (read (current-buffer))
7351 ;; Error handling.
9e6ab520 7352 (when (re-search-forward "\\S-" (tramp-compat-line-end-position) t)
9ce8462a 7353 (error nil)))
00d6fd04
MA
7354 (error (tramp-error
7355 vec 'file-error
7356 "`%s' does not return a valid Lisp expression: `%s'"
7357 command (buffer-string))))))
fb7933a3 7358
7432277c
KG
7359;; It seems that Tru64 Unix does not like it if long strings are sent
7360;; to it in one go. (This happens when sending the Perl
7361;; `file-attributes' implementation, for instance.) Therefore, we
27e813fe 7362;; have this function which sends the string in chunks.
00d6fd04
MA
7363(defun tramp-send-string (vec string)
7364 "Send the STRING via connection VEC.
7432277c
KG
7365
7366The STRING is expected to use Unix line-endings, but the lines sent to
7367the remote host use line-endings as defined in the variable
00d6fd04
MA
7368`tramp-rsh-end-of-line'. The communication buffer is erased before sending."
7369 (let* ((p (tramp-get-connection-process vec))
7370 (chunksize (tramp-get-connection-property p "chunksize" nil)))
7371 (unless p
7372 (tramp-error
7373 vec 'file-error "Can't send string to remote host -- not logged in"))
7374 (tramp-set-connection-property p "last-cmd-time" (current-time))
7375 (tramp-message vec 10 "%s" string)
7376 (with-current-buffer (tramp-get-connection-buffer vec)
7377 ;; Clean up the buffer. We cannot call `erase-buffer' because
7378 ;; narrowing might be in effect.
7379 (let (buffer-read-only) (delete-region (point-min) (point-max)))
27e813fe 7380 ;; Replace "\n" by `tramp-rsh-end-of-line'.
00d6fd04
MA
7381 (setq string
7382 (mapconcat 'identity
70c11b0b 7383 (tramp-compat-split-string string "\n")
00d6fd04
MA
7384 tramp-rsh-end-of-line))
7385 (unless (or (string= string "")
7386 (string-equal (substring string -1) tramp-rsh-end-of-line))
7387 (setq string (concat string tramp-rsh-end-of-line)))
27e813fe 7388 ;; Send the string.
00d6fd04
MA
7389 (if (and chunksize (not (zerop chunksize)))
7390 (let ((pos 0)
7391 (end (length string)))
7392 (while (< pos end)
7393 (tramp-message
7394 vec 10 "Sending chunk from %s to %s"
7395 pos (min (+ pos chunksize) end))
7396 (process-send-string
7397 p (substring string pos (min (+ pos chunksize) end)))
7398 (setq pos (+ pos chunksize))))
7399 (process-send-string p string)))))
fb7933a3
KG
7400
7401(defun tramp-mode-string-to-int (mode-string)
7402 "Converts a ten-letter `drwxrwxrwx'-style mode string into mode bits."
f3c071dd
MA
7403 (let* (case-fold-search
7404 (mode-chars (string-to-vector mode-string))
fb7933a3
KG
7405 (owner-read (aref mode-chars 1))
7406 (owner-write (aref mode-chars 2))
7407 (owner-execute-or-setid (aref mode-chars 3))
7408 (group-read (aref mode-chars 4))
7409 (group-write (aref mode-chars 5))
7410 (group-execute-or-setid (aref mode-chars 6))
7411 (other-read (aref mode-chars 7))
7412 (other-write (aref mode-chars 8))
7413 (other-execute-or-sticky (aref mode-chars 9)))
7414 (save-match-data
7415 (logior
f3c071dd
MA
7416 (cond
7417 ((char-equal owner-read ?r) (tramp-octal-to-decimal "00400"))
7418 ((char-equal owner-read ?-) 0)
7419 (t (error "Second char `%c' must be one of `r-'" owner-read)))
7420 (cond
7421 ((char-equal owner-write ?w) (tramp-octal-to-decimal "00200"))
7422 ((char-equal owner-write ?-) 0)
7423 (t (error "Third char `%c' must be one of `w-'" owner-write)))
7424 (cond
7425 ((char-equal owner-execute-or-setid ?x)
7426 (tramp-octal-to-decimal "00100"))
7427 ((char-equal owner-execute-or-setid ?S)
7428 (tramp-octal-to-decimal "04000"))
7429 ((char-equal owner-execute-or-setid ?s)
7430 (tramp-octal-to-decimal "04100"))
7431 ((char-equal owner-execute-or-setid ?-) 0)
7432 (t (error "Fourth char `%c' must be one of `xsS-'"
7433 owner-execute-or-setid)))
7434 (cond
7435 ((char-equal group-read ?r) (tramp-octal-to-decimal "00040"))
7436 ((char-equal group-read ?-) 0)
7437 (t (error "Fifth char `%c' must be one of `r-'" group-read)))
7438 (cond
7439 ((char-equal group-write ?w) (tramp-octal-to-decimal "00020"))
7440 ((char-equal group-write ?-) 0)
7441 (t (error "Sixth char `%c' must be one of `w-'" group-write)))
7442 (cond
7443 ((char-equal group-execute-or-setid ?x)
7444 (tramp-octal-to-decimal "00010"))
7445 ((char-equal group-execute-or-setid ?S)
7446 (tramp-octal-to-decimal "02000"))
7447 ((char-equal group-execute-or-setid ?s)
7448 (tramp-octal-to-decimal "02010"))
7449 ((char-equal group-execute-or-setid ?-) 0)
7450 (t (error "Seventh char `%c' must be one of `xsS-'"
7451 group-execute-or-setid)))
7452 (cond
7453 ((char-equal other-read ?r)
7454 (tramp-octal-to-decimal "00004"))
7455 ((char-equal other-read ?-) 0)
7456 (t (error "Eighth char `%c' must be one of `r-'" other-read)))
7457 (cond
7458 ((char-equal other-write ?w) (tramp-octal-to-decimal "00002"))
7459 ((char-equal other-write ?-) 0)
fb7933a3 7460 (t (error "Nineth char `%c' must be one of `w-'" other-write)))
f3c071dd
MA
7461 (cond
7462 ((char-equal other-execute-or-sticky ?x)
7463 (tramp-octal-to-decimal "00001"))
7464 ((char-equal other-execute-or-sticky ?T)
7465 (tramp-octal-to-decimal "01000"))
7466 ((char-equal other-execute-or-sticky ?t)
7467 (tramp-octal-to-decimal "01001"))
7468 ((char-equal other-execute-or-sticky ?-) 0)
7469 (t (error "Tenth char `%c' must be one of `xtT-'"
7470 other-execute-or-sticky)))))))
fb7933a3 7471
00d6fd04
MA
7472(defun tramp-convert-file-attributes (vec attr)
7473 "Convert file-attributes ATTR generated by perl script, stat or ls.
c82c5727
LH
7474Convert file mode bits to string and set virtual device number.
7475Return ATTR."
680db9ac
MA
7476 (when attr
7477 ;; Convert last access time.
7478 (unless (listp (nth 4 attr))
7479 (setcar (nthcdr 4 attr)
7480 (list (floor (nth 4 attr) 65536)
7481 (floor (mod (nth 4 attr) 65536)))))
7482 ;; Convert last modification time.
7483 (unless (listp (nth 5 attr))
7484 (setcar (nthcdr 5 attr)
7485 (list (floor (nth 5 attr) 65536)
7486 (floor (mod (nth 5 attr) 65536)))))
7487 ;; Convert last status change time.
7488 (unless (listp (nth 6 attr))
7489 (setcar (nthcdr 6 attr)
7490 (list (floor (nth 6 attr) 65536)
7491 (floor (mod (nth 6 attr) 65536)))))
7492 ;; Convert file size.
7493 (when (< (nth 7 attr) 0)
7494 (setcar (nthcdr 7 attr) -1))
7495 (when (and (floatp (nth 7 attr))
7496 (<= (nth 7 attr) (tramp-compat-most-positive-fixnum)))
7497 (setcar (nthcdr 7 attr) (round (nth 7 attr))))
7498 ;; Convert file mode bits to string.
7499 (unless (stringp (nth 8 attr))
7500 (setcar (nthcdr 8 attr) (tramp-file-mode-from-int (nth 8 attr)))
7501 (when (stringp (car attr))
7502 (aset (nth 8 attr) 0 ?l)))
7503 ;; Convert directory indication bit.
7504 (when (string-match "^d" (nth 8 attr))
7505 (setcar attr t))
7506 ;; Convert symlink from `tramp-do-file-attributes-with-stat'.
7507 (when (consp (car attr))
7508 (if (and (stringp (caar attr))
7509 (string-match ".+ -> .\\(.+\\)." (caar attr)))
7510 (setcar attr (match-string 1 (caar attr)))
7511 (setcar attr nil)))
7512 ;; Set file's gid change bit.
7513 (setcar (nthcdr 9 attr)
7514 (if (numberp (nth 3 attr))
7515 (not (= (nth 3 attr)
7516 (tramp-get-remote-gid vec 'integer)))
7517 (not (string-equal
7518 (nth 3 attr)
7519 (tramp-get-remote-gid vec 'string)))))
7520 ;; Convert inode.
7521 (unless (listp (nth 10 attr))
7522 (setcar (nthcdr 10 attr)
7523 (condition-case nil
7524 (cons (floor (nth 10 attr) 65536)
7525 (floor (mod (nth 10 attr) 65536)))
7526 ;; Inodes can be incredible huge. We must hide this.
7527 (error (tramp-get-inode vec)))))
7528 ;; Set virtual device number.
7529 (setcar (nthcdr 11 attr)
7530 (tramp-get-device vec))
7531 attr))
c82c5727 7532
293c24f9
MA
7533(defun tramp-check-cached-permissions (vec access)
7534 "Check `file-attributes' caches for VEC.
7535Return t if according to the cache access type ACCESS is known to
7536be granted."
7537 (let ((result nil)
7538 (offset (cond
7539 ((eq ?r access) 1)
7540 ((eq ?w access) 2)
7541 ((eq ?x access) 3))))
7542 (dolist (suffix '("string" "integer") result)
7543 (setq
7544 result
7545 (or
7546 result
7547 (let ((file-attr
7548 (tramp-get-file-property
7549 vec (tramp-file-name-localname vec)
7550 (concat "file-attributes-" suffix) nil))
7551 (remote-uid
7552 (tramp-get-connection-property
7553 vec (concat "uid-" suffix) nil))
7554 (remote-gid
7555 (tramp-get-connection-property
7556 vec (concat "gid-" suffix) nil)))
7557 (and
7558 file-attr
7559 (or
7560 ;; Not a symlink
7561 (eq t (car file-attr))
7562 (null (car file-attr)))
7563 (or
7564 ;; World accessible.
7565 (eq access (aref (nth 8 file-attr) (+ offset 6)))
7566 ;; User accessible and owned by user.
7567 (and
7568 (eq access (aref (nth 8 file-attr) offset))
7569 (equal remote-uid (nth 2 file-attr)))
7570 ;; Group accessible and owned by user's
7571 ;; principal group.
7572 (and
7573 (eq access (aref (nth 8 file-attr) (+ offset 3)))
7574 (equal remote-gid (nth 3 file-attr)))))))))))
7575
ce3f516f 7576(defun tramp-get-inode (vec)
00d6fd04
MA
7577 "Returns the virtual inode number.
7578If it doesn't exist, generate a new one."
ce3f516f
MA
7579 (let ((string (tramp-make-tramp-file-name
7580 (tramp-file-name-method vec)
7581 (tramp-file-name-user vec)
7582 (tramp-file-name-host vec)
7583 "")))
00d6fd04
MA
7584 (unless (assoc string tramp-inodes)
7585 (add-to-list 'tramp-inodes
7586 (list string (length tramp-inodes))))
7587 (nth 1 (assoc string tramp-inodes))))
7588
7589(defun tramp-get-device (vec)
c82c5727
LH
7590 "Returns the virtual device number.
7591If it doesn't exist, generate a new one."
00d6fd04
MA
7592 (let ((string (tramp-make-tramp-file-name
7593 (tramp-file-name-method vec)
7594 (tramp-file-name-user vec)
7595 (tramp-file-name-host vec)
7596 "")))
c82c5727
LH
7597 (unless (assoc string tramp-devices)
7598 (add-to-list 'tramp-devices
7599 (list string (length tramp-devices))))
b946a456 7600 (cons -1 (nth 1 (assoc string tramp-devices)))))
fb7933a3
KG
7601
7602(defun tramp-file-mode-from-int (mode)
7603 "Turn an integer representing a file mode into an ls(1)-like string."
7604 (let ((type (cdr (assoc (logand (lsh mode -12) 15) tramp-file-mode-type-map)))
7605 (user (logand (lsh mode -6) 7))
7606 (group (logand (lsh mode -3) 7))
7607 (other (logand (lsh mode -0) 7))
7608 (suid (> (logand (lsh mode -9) 4) 0))
7609 (sgid (> (logand (lsh mode -9) 2) 0))
7610 (sticky (> (logand (lsh mode -9) 1) 0)))
7611 (setq user (tramp-file-mode-permissions user suid "s"))
7612 (setq group (tramp-file-mode-permissions group sgid "s"))
7613 (setq other (tramp-file-mode-permissions other sticky "t"))
7614 (concat type user group other)))
7615
fb7933a3
KG
7616(defun tramp-file-mode-permissions (perm suid suid-text)
7617 "Convert a permission bitset into a string.
7618This is used internally by `tramp-file-mode-from-int'."
7619 (let ((r (> (logand perm 4) 0))
7620 (w (> (logand perm 2) 0))
7621 (x (> (logand perm 1) 0)))
7622 (concat (or (and r "r") "-")
7623 (or (and w "w") "-")
7624 (or (and suid x suid-text) ; suid, execute
7625 (and suid (upcase suid-text)) ; suid, !execute
7626 (and x "x") "-")))) ; !suid
7627
fb7933a3
KG
7628(defun tramp-decimal-to-octal (i)
7629 "Return a string consisting of the octal digits of I.
7630Not actually used. Use `(format \"%o\" i)' instead?"
7631 (cond ((< i 0) (error "Cannot convert negative number to octal"))
7632 ((not (integerp i)) (error "Cannot convert non-integer to octal"))
7633 ((zerop i) "0")
7634 (t (concat (tramp-decimal-to-octal (/ i 8))
7635 (number-to-string (% i 8))))))
7636
fb7933a3
KG
7637;; Kudos to Gerd Moellmann for this suggestion.
7638(defun tramp-octal-to-decimal (ostr)
7639 "Given a string of octal digits, return a decimal number."
7640 (let ((x (or ostr "")))
7641 ;; `save-match' is in `tramp-mode-string-to-int' which calls this.
7642 (unless (string-match "\\`[0-7]*\\'" x)
7643 (error "Non-octal junk in string `%s'" x))
7644 (string-to-number ostr 8)))
7645
7646(defun tramp-shell-case-fold (string)
7647 "Converts STRING to shell glob pattern which ignores case."
7648 (mapconcat
7649 (lambda (c)
7650 (if (equal (downcase c) (upcase c))
7651 (vector c)
7652 (format "[%c%c]" (downcase c) (upcase c))))
7653 string
7654 ""))
7655
7656
bf247b6e 7657;; ------------------------------------------------------------
a4aeb9a4 7658;; -- Tramp file names --
bf247b6e 7659;; ------------------------------------------------------------
fb7933a3
KG
7660;; Conversion functions between external representation and
7661;; internal data structure. Convenience functions for internal
7662;; data structure.
7663
00d6fd04
MA
7664(defun tramp-file-name-p (vec)
7665 "Check whether VEC is a Tramp object."
7666 (and (vectorp vec) (= 4 (length vec))))
7667
7668(defun tramp-file-name-method (vec)
7669 "Return method component of VEC."
7670 (and (tramp-file-name-p vec) (aref vec 0)))
7671
7672(defun tramp-file-name-user (vec)
7673 "Return user component of VEC."
7674 (and (tramp-file-name-p vec) (aref vec 1)))
7675
7676(defun tramp-file-name-host (vec)
7677 "Return host component of VEC."
7678 (and (tramp-file-name-p vec) (aref vec 2)))
7679
7680(defun tramp-file-name-localname (vec)
7681 "Return localname component of VEC."
7682 (and (tramp-file-name-p vec) (aref vec 3)))
7683
dea31ca6 7684;; The user part of a Tramp file name vector can be of kind
b96e6899 7685;; "user%domain". Sometimes, we must extract these parts.
dea31ca6
MA
7686(defun tramp-file-name-real-user (vec)
7687 "Return the user name of VEC without domain."
a17632c1
MA
7688 (save-match-data
7689 (let ((user (tramp-file-name-user vec)))
7690 (if (and (stringp user)
7691 (string-match tramp-user-with-domain-regexp user))
7692 (match-string 1 user)
7693 user))))
dea31ca6
MA
7694
7695(defun tramp-file-name-domain (vec)
7696 "Return the domain name of VEC."
a17632c1
MA
7697 (save-match-data
7698 (let ((user (tramp-file-name-user vec)))
7699 (and (stringp user)
7700 (string-match tramp-user-with-domain-regexp user)
7701 (match-string 2 user)))))
dea31ca6 7702
00d6fd04
MA
7703;; The host part of a Tramp file name vector can be of kind
7704;; "host#port". Sometimes, we must extract these parts.
8a4438b6 7705(defun tramp-file-name-real-host (vec)
00d6fd04 7706 "Return the host name of VEC without port."
a17632c1
MA
7707 (save-match-data
7708 (let ((host (tramp-file-name-host vec)))
7709 (if (and (stringp host)
7710 (string-match tramp-host-with-port-regexp host))
7711 (match-string 1 host)
7712 host))))
00d6fd04 7713
8a4438b6 7714(defun tramp-file-name-port (vec)
00d6fd04 7715 "Return the port number of VEC."
a17632c1
MA
7716 (save-match-data
7717 (let ((host (tramp-file-name-host vec)))
7718 (and (stringp host)
7719 (string-match tramp-host-with-port-regexp host)
7720 (string-to-number (match-string 2 host))))))
fb7933a3
KG
7721
7722(defun tramp-tramp-file-p (name)
a09dc9bf 7723 "Return t if NAME is a string with Tramp file name syntax."
fb7933a3 7724 (save-match-data
a09dc9bf 7725 (and (stringp name) (string-match tramp-file-name-regexp name))))
bf247b6e 7726
8a4438b6 7727(defun tramp-find-method (method user host)
00d6fd04
MA
7728 "Return the right method string to use.
7729This is METHOD, if non-nil. Otherwise, do a lookup in
7730`tramp-default-method-alist'."
7731 (or method
7732 (let ((choices tramp-default-method-alist)
7733 lmethod item)
7734 (while choices
7735 (setq item (pop choices))
7736 (when (and (string-match (or (nth 0 item) "") (or host ""))
7737 (string-match (or (nth 1 item) "") (or user "")))
7738 (setq lmethod (nth 2 item))
7739 (setq choices nil)))
7740 lmethod)
7741 tramp-default-method))
7742
8a4438b6 7743(defun tramp-find-user (method user host)
00d6fd04
MA
7744 "Return the right user string to use.
7745This is USER, if non-nil. Otherwise, do a lookup in
7746`tramp-default-user-alist'."
7747 (or user
7748 (let ((choices tramp-default-user-alist)
7749 luser item)
7750 (while choices
7751 (setq item (pop choices))
7752 (when (and (string-match (or (nth 0 item) "") (or method ""))
7753 (string-match (or (nth 1 item) "") (or host "")))
7754 (setq luser (nth 2 item))
7755 (setq choices nil)))
7756 luser)
7757 tramp-default-user))
7758
8a4438b6 7759(defun tramp-find-host (method user host)
00d6fd04
MA
7760 "Return the right host string to use.
7761This is HOST, if non-nil. Otherwise, it is `tramp-default-host'."
7762 (or (and (> (length host) 0) host)
7763 tramp-default-host))
7764
9ce8462a 7765(defun tramp-dissect-file-name (name &optional nodefault)
00d6fd04 7766 "Return a `tramp-file-name' structure.
9ce8462a
MA
7767The structure consists of remote method, remote user, remote host
7768and localname (file name on remote host). If NODEFAULT is
7769non-nil, the file name parts are not expanded to their default
7770values."
4007ba5b 7771 (save-match-data
00d6fd04 7772 (let ((match (string-match (nth 0 tramp-file-name-structure) name)))
a4aeb9a4 7773 (unless match (error "Not a Tramp file name: %s" name))
00d6fd04
MA
7774 (let ((method (match-string (nth 1 tramp-file-name-structure) name))
7775 (user (match-string (nth 2 tramp-file-name-structure) name))
7776 (host (match-string (nth 3 tramp-file-name-structure) name))
7777 (localname (match-string (nth 4 tramp-file-name-structure) name)))
5d449a36
MA
7778 (when (member method '("multi" "multiu"))
7779 (error
7780 "`%s' method is no longer supported, see (info \"(tramp)Multi-hops\")"
7781 method))
b96e6899
MA
7782 (when host
7783 (when (string-match tramp-prefix-ipv6-regexp host)
7784 (setq host (replace-match "" nil t host)))
7785 (when (string-match tramp-postfix-ipv6-regexp host)
7786 (setq host (replace-match "" nil t host))))
9ce8462a
MA
7787 (if nodefault
7788 (vector method user host localname)
7789 (vector
7790 (tramp-find-method method user host)
7791 (tramp-find-user method user host)
7792 (tramp-find-host method user host)
7793 localname))))))
00d6fd04
MA
7794
7795(defun tramp-equal-remote (file1 file2)
7796 "Checks, whether the remote parts of FILE1 and FILE2 are identical.
7797The check depends on method, user and host name of the files. If
7798one of the components is missing, the default values are used.
7799The local file name parts of FILE1 and FILE2 are not taken into
7800account.
fb7933a3 7801
00d6fd04
MA
7802Example:
7803
7804 (tramp-equal-remote \"/ssh::/etc\" \"/<your host name>:/home\")
7805
7806would yield `t'. On the other hand, the following check results in nil:
7807
7808 (tramp-equal-remote \"/sudo::/etc\" \"/su::/etc\")"
9e6ab520
MA
7809 (and (stringp (file-remote-p file1))
7810 (stringp (file-remote-p file2))
94be87e8 7811 (string-equal (file-remote-p file1) (file-remote-p file2))))
00d6fd04
MA
7812
7813(defun tramp-make-tramp-file-name (method user host localname)
7814 "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME."
7815 (concat tramp-prefix-format
7816 (when (not (zerop (length method)))
7817 (concat method tramp-postfix-method-format))
7818 (when (not (zerop (length user)))
7819 (concat user tramp-postfix-user-format))
b96e6899
MA
7820 (when host
7821 (if (string-match tramp-ipv6-regexp host)
7822 (concat tramp-prefix-ipv6-format host tramp-postfix-ipv6-format)
7823 host))
7824 tramp-postfix-host-format
00d6fd04
MA
7825 (when localname localname)))
7826
7827(defun tramp-completion-make-tramp-file-name (method user host localname)
7828 "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME.
7829It must not be a complete Tramp file name, but as long as there are
7830necessary only. This function will be used in file name completion."
7831 (concat tramp-prefix-format
7832 (when (not (zerop (length method)))
7833 (concat method tramp-postfix-method-format))
7834 (when (not (zerop (length user)))
7835 (concat user tramp-postfix-user-format))
7836 (when (not (zerop (length host)))
b96e6899
MA
7837 (concat
7838 (if (string-match tramp-ipv6-regexp host)
7839 (concat tramp-prefix-ipv6-format host tramp-postfix-ipv6-format)
7840 host)
7841 tramp-postfix-host-format))
00d6fd04
MA
7842 (when localname localname)))
7843
7844(defun tramp-make-copy-program-file-name (vec)
7845 "Create a file name suitable to be passed to `rcp' and workalikes."
7846 (let ((user (tramp-file-name-user vec))
0f205eee 7847 (host (tramp-file-name-real-host vec))
00d6fd04
MA
7848 (localname (tramp-shell-quote-argument
7849 (tramp-file-name-localname vec))))
7850 (if (not (zerop (length user)))
7851 (format "%s@%s:%s" user host localname)
7852 (format "%s:%s" host localname))))
7853
7f49fe46 7854(defun tramp-method-out-of-band-p (vec size)
38c65fca 7855 "Return t if this is an out-of-band method, nil otherwise."
7f49fe46
MA
7856 (and
7857 ;; It shall be an out-of-band method.
7858 (tramp-get-method-parameter (tramp-file-name-method vec) 'tramp-copy-program)
7859 ;; Either the file size is large enough, or (in rare cases) there
7860 ;; does not exist a remote encoding.
7861 (or (> size tramp-copy-size-limit)
7862 (null (tramp-get-remote-coding vec "remote-encoding")))))
fb7933a3 7863
0f205eee
MA
7864(defun tramp-local-host-p (vec)
7865 "Return t if this points to the local host, nil otherwise."
c992abdb
MA
7866 ;; We cannot use `tramp-file-name-real-host'. A port is an
7867 ;; indication for an ssh tunnel or alike.
7868 (let ((host (tramp-file-name-host vec)))
0f205eee
MA
7869 (and
7870 (stringp host)
b96e6899 7871 (string-match tramp-local-host-regexp host)
46bcd78c
MA
7872 ;; The method shall be applied to one of the shell file name
7873 ;; handler. `tramp-local-host-p' is also called for "smb" and
7874 ;; alike, where it must fail.
7875 (tramp-get-method-parameter
7876 (tramp-file-name-method vec) 'tramp-login-program)
a0a5183a
MA
7877 ;; The local temp directory must be writable for the other user.
7878 (file-writable-p
7879 (tramp-make-tramp-file-name
7880 (tramp-file-name-method vec)
7881 (tramp-file-name-user vec)
7882 host
93c3eb7c
MA
7883 (tramp-compat-temporary-file-directory)))
7884 ;; On some systems, chown runs only for root.
7885 (or (zerop (user-uid))
7886 (zerop (tramp-get-remote-uid vec 'integer))))))
0f205eee 7887
fb7933a3
KG
7888;; Variables local to connection.
7889
f84638eb 7890(defun tramp-get-remote-path (vec)
70c11b0b
MA
7891 (with-connection-property
7892 ;; When `tramp-own-remote-path' is in `tramp-remote-path', we
7893 ;; cache the result for the session only. Otherwise, the result
7894 ;; is cached persistently.
7895 (if (memq 'tramp-own-remote-path tramp-remote-path)
7896 (tramp-get-connection-process vec)
7897 vec)
7898 "remote-path"
9e6ab520 7899 (let* ((remote-path (tramp-compat-copy-tree tramp-remote-path))
70c11b0b
MA
7900 (elt1 (memq 'tramp-default-remote-path remote-path))
7901 (elt2 (memq 'tramp-own-remote-path remote-path))
f84638eb 7902 (default-remote-path
70c11b0b 7903 (when elt1
f84638eb 7904 (condition-case nil
70c11b0b
MA
7905 (tramp-send-command-and-read
7906 vec "echo \\\"`getconf PATH`\\\"")
f84638eb
MA
7907 ;; Default if "getconf" is not available.
7908 (error
7909 (tramp-message
7910 vec 3
7911 "`getconf PATH' not successful, using default value \"%s\"."
7912 "/bin:/usr/bin")
70c11b0b
MA
7913 "/bin:/usr/bin"))))
7914 (own-remote-path
7915 (when elt2
7916 (condition-case nil
7917 (tramp-send-command-and-read vec "echo \\\"$PATH\\\"")
7918 ;; Default if "getconf" is not available.
7919 (error
7920 (tramp-message
7921 vec 3 "$PATH not set, ignoring `tramp-own-remote-path'.")
7922 nil)))))
7923
7924 ;; Replace place holder `tramp-default-remote-path'.
7925 (when elt1
7926 (setcdr elt1
f84638eb 7927 (append
70c11b0b
MA
7928 (tramp-compat-split-string default-remote-path ":")
7929 (cdr elt1)))
f84638eb
MA
7930 (setq remote-path (delq 'tramp-default-remote-path remote-path)))
7931
70c11b0b
MA
7932 ;; Replace place holder `tramp-own-remote-path'.
7933 (when elt2
7934 (setcdr elt2
7935 (append
7936 (tramp-compat-split-string own-remote-path ":")
7937 (cdr elt2)))
7938 (setq remote-path (delq 'tramp-own-remote-path remote-path)))
7939
7940 ;; Remove double entries.
7941 (setq elt1 remote-path)
7942 (while (consp elt1)
7943 (while (and (car elt1) (setq elt2 (member (car elt1) (cdr elt1))))
7944 (setcar elt2 nil))
7945 (setq elt1 (cdr elt1)))
7946
f84638eb
MA
7947 ;; Remove non-existing directories.
7948 (delq
7949 nil
7950 (mapcar
7951 (lambda (x)
7952 (and
70c11b0b
MA
7953 (stringp x)
7954 (file-directory-p
7955 (tramp-make-tramp-file-name
7956 (tramp-file-name-method vec)
7957 (tramp-file-name-user vec)
7958 (tramp-file-name-host vec)
7959 x))
f84638eb
MA
7960 x))
7961 remote-path)))))
7962
a4aeb9a4
MA
7963(defun tramp-get-remote-tmpdir (vec)
7964 (with-connection-property vec "tmp-directory"
7965 (let ((dir (tramp-shell-quote-argument "/tmp")))
7966 (if (and (zerop
7967 (tramp-send-command-and-check
7968 vec (format "%s -d %s" (tramp-get-test-command vec) dir)))
7969 (zerop
7970 (tramp-send-command-and-check
7971 vec (format "%s -w %s" (tramp-get-test-command vec) dir))))
7972 dir
7973 (tramp-error vec 'file-error "Directory %s not accessible" dir)))))
7974
00d6fd04
MA
7975(defun tramp-get-ls-command (vec)
7976 (with-connection-property vec "ls"
946a5aeb
MA
7977 (tramp-message vec 5 "Finding a suitable `ls' command")
7978 (or
7979 (catch 'ls-found
7980 (dolist (cmd '("ls" "gnuls" "gls"))
7981 (let ((dl (tramp-get-remote-path vec))
7982 result)
7983 (while (and dl (setq result (tramp-find-executable vec cmd dl t t)))
7984 ;; Check parameter.
7985 (when (zerop (tramp-send-command-and-check
7986 vec (format "%s -lnd /" result)))
7987 (throw 'ls-found result))
7988 (setq dl (cdr dl))))))
7989 (tramp-error vec 'file-error "Couldn't find a proper `ls' command"))))
00d6fd04 7990
8e754ea2
MA
7991(defun tramp-get-ls-command-with-dired (vec)
7992 (save-match-data
7993 (with-connection-property vec "ls-dired"
7994 (tramp-message vec 5 "Checking, whether `ls --dired' works")
7995 (zerop (tramp-send-command-and-check
7f49fe46 7996 vec (format "%s --dired /" (tramp-get-ls-command vec)))))))
8e754ea2 7997
00d6fd04
MA
7998(defun tramp-get-test-command (vec)
7999 (with-connection-property vec "test"
946a5aeb
MA
8000 (tramp-message vec 5 "Finding a suitable `test' command")
8001 (if (zerop (tramp-send-command-and-check vec "test 0"))
8002 "test"
8003 (tramp-find-executable vec "test" (tramp-get-remote-path vec)))))
00d6fd04
MA
8004
8005(defun tramp-get-test-nt-command (vec)
8006 ;; Does `test A -nt B' work? Use abominable `find' construct if it
8007 ;; doesn't. BSD/OS 4.0 wants the parentheses around the command,
8008 ;; for otherwise the shell crashes.
8009 (with-connection-property vec "test-nt"
8010 (or
8011 (progn
8012 (tramp-send-command
8013 vec (format "( %s / -nt / )" (tramp-get-test-command vec)))
8014 (with-current-buffer (tramp-get-buffer vec)
8015 (goto-char (point-min))
a0a5183a 8016 (when (looking-at (regexp-quote tramp-end-of-output))
00d6fd04
MA
8017 (format "%s %%s -nt %%s" (tramp-get-test-command vec)))))
8018 (progn
8019 (tramp-send-command
8020 vec
8021 (format
8022 "tramp_test_nt () {\n%s -n \"`find $1 -prune -newer $2 -print`\"\n}"
8023 (tramp-get-test-command vec)))
8024 "tramp_test_nt %s %s"))))
8025
8026(defun tramp-get-file-exists-command (vec)
8027 (with-connection-property vec "file-exists"
946a5aeb
MA
8028 (tramp-message vec 5 "Finding command to check if file exists")
8029 (tramp-find-file-exists-command vec)))
00d6fd04
MA
8030
8031(defun tramp-get-remote-ln (vec)
8032 (with-connection-property vec "ln"
946a5aeb
MA
8033 (tramp-message vec 5 "Finding a suitable `ln' command")
8034 (tramp-find-executable vec "ln" (tramp-get-remote-path vec))))
00d6fd04
MA
8035
8036(defun tramp-get-remote-perl (vec)
8037 (with-connection-property vec "perl"
946a5aeb 8038 (tramp-message vec 5 "Finding a suitable `perl' command")
293c24f9
MA
8039 (let ((result
8040 (or (tramp-find-executable vec "perl5" (tramp-get-remote-path vec))
8041 (tramp-find-executable
8042 vec "perl" (tramp-get-remote-path vec)))))
8043 ;; We must check also for some Perl modules.
8044 (when result
8045 (with-connection-property vec "perl-file-spec"
8046 (zerop
8047 (tramp-send-command-and-check
8048 vec (format "%s -e 'use File::Spec;'" result))))
8049 (with-connection-property vec "perl-cwd-realpath"
8050 (zerop
8051 (tramp-send-command-and-check
8052 vec (format "%s -e 'use Cwd \"realpath\";'" result)))))
8053 result)))
00d6fd04
MA
8054
8055(defun tramp-get-remote-stat (vec)
8056 (with-connection-property vec "stat"
946a5aeb
MA
8057 (tramp-message vec 5 "Finding a suitable `stat' command")
8058 (let ((result (tramp-find-executable
8059 vec "stat" (tramp-get-remote-path vec)))
8060 tmp)
8061 ;; Check whether stat(1) returns usable syntax. %s does not
8062 ;; work on older AIX systems.
8063 (when result
8064 (setq tmp
8065 ;; We don't want to display an error message.
8066 (with-temp-message (or (current-message) "")
8067 (condition-case nil
8068 (tramp-send-command-and-read
8069 vec (format "%s -c '(\"%%N\" %%s)' /" result))
8070 (error nil))))
8071 (unless (and (listp tmp) (stringp (car tmp))
8072 (string-match "^./.$" (car tmp))
8073 (integerp (cadr tmp)))
8074 (setq result nil)))
8075 result)))
fb7933a3 8076
293c24f9
MA
8077(defun tramp-get-remote-readlink (vec)
8078 (with-connection-property vec "readlink"
8079 (tramp-message vec 5 "Finding a suitable `readlink' command")
8080 (let ((result (tramp-find-executable
8081 vec "readlink" (tramp-get-remote-path vec))))
8082 (when (and result
8083 ;; We don't want to display an error message.
8084 (with-temp-message (or (current-message) "")
8085 (condition-case nil
8086 (zerop
8087 (tramp-send-command-and-check
8088 vec (format "%s --canonicalize-missing /" result)))
8089 (error nil))))
8090 result))))
8091
00d6fd04
MA
8092(defun tramp-get-remote-id (vec)
8093 (with-connection-property vec "id"
946a5aeb
MA
8094 (tramp-message vec 5 "Finding POSIX `id' command")
8095 (or
8096 (catch 'id-found
8097 (let ((dl (tramp-get-remote-path vec))
8098 result)
8099 (while (and dl (setq result (tramp-find-executable vec "id" dl t t)))
8100 ;; Check POSIX parameter.
8101 (when (zerop (tramp-send-command-and-check
8102 vec (format "%s -u" result)))
8103 (throw 'id-found result))
8104 (setq dl (cdr dl)))))
8105 (tramp-error vec 'file-error "Couldn't find a POSIX `id' command"))))
00d6fd04
MA
8106
8107(defun tramp-get-remote-uid (vec id-format)
8108 (with-connection-property vec (format "uid-%s" id-format)
8109 (let ((res (tramp-send-command-and-read
8110 vec
8111 (format "%s -u%s %s"
8112 (tramp-get-remote-id vec)
8113 (if (equal id-format 'integer) "" "n")
8114 (if (equal id-format 'integer)
8115 "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
8116 ;; The command might not always return a number.
8117 (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
8118
8119(defun tramp-get-remote-gid (vec id-format)
8120 (with-connection-property vec (format "gid-%s" id-format)
8121 (let ((res (tramp-send-command-and-read
8122 vec
8123 (format "%s -g%s %s"
8124 (tramp-get-remote-id vec)
8125 (if (equal id-format 'integer) "" "n")
8126 (if (equal id-format 'integer)
8127 "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
8128 ;; The command might not always return a number.
8129 (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
fb7933a3 8130
8d60099b
MA
8131(defun tramp-get-local-uid (id-format)
8132 (if (equal id-format 'integer) (user-uid) (user-login-name)))
8133
8134(defun tramp-get-local-gid (id-format)
9e6ab520 8135 (nth 3 (tramp-compat-file-attributes "~/" id-format)))
8d60099b 8136
00d6fd04
MA
8137;; Some predefined connection properties.
8138(defun tramp-get-remote-coding (vec prop)
8139 ;; Local coding handles properties like remote coding. So we could
8140 ;; call it without pain.
8141 (let ((ret (tramp-get-local-coding vec prop)))
8142 ;; The connection property might have been cached. So we must send
8143 ;; the script - maybe.
1d7e9a01 8144 (when (and ret (symbolp ret))
00d6fd04
MA
8145 (let ((name (symbol-name ret)))
8146 (while (string-match (regexp-quote "-") name)
8147 (setq name (replace-match "_" nil t name)))
8148 (tramp-maybe-send-script vec (symbol-value ret) name)
8149 (setq ret name)))
8150 ;; Return the value.
8151 ret))
8152
8153(defun tramp-get-local-coding (vec prop)
bf0503cb 8154 (or
00d6fd04
MA
8155 (tramp-get-connection-property vec prop nil)
8156 (progn
8157 (tramp-find-inline-encoding vec)
8158 (tramp-get-connection-property vec prop nil))))
fb7933a3 8159
00d6fd04 8160(defun tramp-get-method-parameter (method param)
c951aecb 8161 "Return the method parameter PARAM.
00d6fd04
MA
8162If the `tramp-methods' entry does not exist, return NIL."
8163 (let ((entry (assoc param (assoc method tramp-methods))))
8164 (when entry (cadr entry))))
90f8dc03 8165
fb7933a3
KG
8166;; Auto saving to a special directory.
8167
00cec167 8168(defun tramp-exists-file-name-handler (operation &rest args)
00d6fd04
MA
8169 "Checks whether OPERATION runs a file name handler."
8170 ;; The file name handler is determined on base of either an
8171 ;; argument, `buffer-file-name', or `default-directory'.
8172 (condition-case nil
8173 (let* ((buffer-file-name "/")
8174 (default-directory "/")
8175 (fnha file-name-handler-alist)
8176 (check-file-name-operation operation)
8177 (file-name-handler-alist
8178 (list
8179 (cons "/"
aa485f7c
MA
8180 (lambda (operation &rest args)
8181 "Returns OPERATION if it is the one to be checked."
8182 (if (equal check-file-name-operation operation)
8183 operation
8184 (let ((file-name-handler-alist fnha))
8185 (apply operation args))))))))
00d6fd04
MA
8186 (equal (apply operation args) operation))
8187 (error nil)))
c1105d05
MA
8188
8189(unless (tramp-exists-file-name-handler 'make-auto-save-file-name)
8190 (defadvice make-auto-save-file-name
8191 (around tramp-advice-make-auto-save-file-name () activate)
00d6fd04 8192 "Invoke `tramp-handle-make-auto-save-file-name' for Tramp files."
c1105d05 8193 (if (and (buffer-file-name) (tramp-tramp-file-p (buffer-file-name)))
7f49fe46
MA
8194 ;; We cannot call `tramp-handle-make-auto-save-file-name'
8195 ;; directly, because this would bypass the locking mechanism.
8196 (setq ad-return-value
8197 (tramp-file-name-handler 'make-auto-save-file-name))
a69c01a0 8198 ad-do-it))
191bb792
MA
8199 (add-hook
8200 'tramp-unload-hook
8201 (lambda ()
8202 (ad-remove-advice
8203 'make-auto-save-file-name
d7ec1df7
MA
8204 'around 'tramp-advice-make-auto-save-file-name)
8205 (ad-activate 'make-auto-save-file-name))))
fb7933a3 8206
340b8d4f
MA
8207;; In Emacs < 22 and XEmacs < 21.5 autosaved remote files have
8208;; permission 0666 minus umask. This is a security threat.
414da5ab
MA
8209
8210(defun tramp-set-auto-save-file-modes ()
8211 "Set permissions of autosaved remote files to the original permissions."
8212 (let ((bfn (buffer-file-name)))
8213 (when (and (stringp bfn)
8214 (tramp-tramp-file-p bfn)
b50dd0d2 8215 (buffer-modified-p)
414da5ab 8216 (stringp buffer-auto-save-file-name)
340b8d4f
MA
8217 (not (equal bfn buffer-auto-save-file-name)))
8218 (unless (file-exists-p buffer-auto-save-file-name)
8219 (write-region "" nil buffer-auto-save-file-name))
8220 ;; Permissions should be set always, because there might be an old
8221 ;; auto-saved file belonging to another original file. This could
8222 ;; be a security threat.
7177e2a3 8223 (set-file-modes buffer-auto-save-file-name
11948172 8224 (or (file-modes bfn) (tramp-octal-to-decimal "0600"))))))
414da5ab
MA
8225
8226(unless (or (> emacs-major-version 21)
8227 (and (featurep 'xemacs)
8228 (= emacs-major-version 21)
340b8d4f 8229 (> emacs-minor-version 4)))
a69c01a0
MA
8230 (add-hook 'auto-save-hook 'tramp-set-auto-save-file-modes)
8231 (add-hook 'tramp-unload-hook
aa485f7c
MA
8232 (lambda ()
8233 (remove-hook 'auto-save-hook 'tramp-set-auto-save-file-modes))))
414da5ab 8234
fb7933a3
KG
8235(defun tramp-subst-strs-in-string (alist string)
8236 "Replace all occurrences of the string FROM with TO in STRING.
8237ALIST is of the form ((FROM . TO) ...)."
8238 (save-match-data
8239 (while alist
8240 (let* ((pr (car alist))
8241 (from (car pr))
8242 (to (cdr pr)))
8243 (while (string-match (regexp-quote from) string)
8244 (setq string (replace-match to t t string)))
8245 (setq alist (cdr alist))))
8246 string))
8247
fb7933a3
KG
8248;; ------------------------------------------------------------
8249;; -- Compatibility functions section --
8250;; ------------------------------------------------------------
8251
00d6fd04 8252(defun tramp-read-passwd (proc &optional prompt)
fb7933a3 8253 "Read a password from user (compat function).
5615d63f 8254Consults the auth-source package.
5ec2cc41 8255Invokes `password-read' if available, `read-passwd' else."
00d6fd04
MA
8256 (let* ((key (tramp-make-tramp-file-name
8257 tramp-current-method tramp-current-user
8258 tramp-current-host ""))
8259 (pw-prompt
8260 (or prompt
8261 (with-current-buffer (process-buffer proc)
8262 (tramp-check-for-regexp proc tramp-password-prompt-regexp)
8263 (format "%s for %s " (capitalize (match-string 1)) key)))))
5c7043a2
MA
8264 (prog1
8265 (or
8266 ;; See if auth-sources contains something useful, if it's bound.
8267 (and (boundp 'auth-sources)
8268 (tramp-get-connection-property proc "first-password-request" nil)
8269 ;; Try with Tramp's current method.
8270 (funcall (symbol-function 'auth-source-user-or-password)
8271 "password" tramp-current-host tramp-current-method))
8272 ;; Try the password cache.
cb85dcd0
MA
8273 (when (functionp 'password-read)
8274 (unless (tramp-get-connection-property
8275 proc "first-password-request" nil)
8276 (funcall (symbol-function 'password-cache-remove) key))
8277 (let ((password
8278 (funcall (symbol-function 'password-read) pw-prompt key)))
8279 (funcall (symbol-function 'password-cache-add) key password)
8280 password))
5c7043a2
MA
8281 ;; Else, get the password interactively.
8282 (read-passwd pw-prompt))
8283 (tramp-set-connection-property proc "first-password-request" nil))))
00d6fd04 8284
9c13938d
MA
8285(defun tramp-clear-passwd (vec)
8286 "Clear password cache for connection related to VEC."
00d6fd04 8287 (when (functionp 'password-cache-remove)
9c13938d
MA
8288 (funcall
8289 (symbol-function 'password-cache-remove)
8290 (tramp-make-tramp-file-name
8291 (tramp-file-name-method vec)
8292 (tramp-file-name-user vec)
8293 (tramp-file-name-host vec)
8294 ""))))
00d6fd04
MA
8295
8296;; Snarfed code from time-date.el and parse-time.el
8297
8298(defconst tramp-half-a-year '(241 17024)
8299"Evaluated by \"(days-to-time 183)\".")
8300
8301(defconst tramp-parse-time-months
8302 '(("jan" . 1) ("feb" . 2) ("mar" . 3)
8303 ("apr" . 4) ("may" . 5) ("jun" . 6)
8304 ("jul" . 7) ("aug" . 8) ("sep" . 9)
8305 ("oct" . 10) ("nov" . 11) ("dec" . 12))
8306 "Alist mapping month names to integers.")
8307
8308(defun tramp-time-less-p (t1 t2)
8309 "Say whether time value T1 is less than time value T2."
8310 (unless t1 (setq t1 '(0 0)))
8311 (unless t2 (setq t2 '(0 0)))
8312 (or (< (car t1) (car t2))
8313 (and (= (car t1) (car t2))
8314 (< (nth 1 t1) (nth 1 t2)))))
8315
8316(defun tramp-time-subtract (t1 t2)
8317 "Subtract two time values.
8318Return the difference in the format of a time value."
8319 (unless t1 (setq t1 '(0 0)))
8320 (unless t2 (setq t2 '(0 0)))
8321 (let ((borrow (< (cadr t1) (cadr t2))))
8322 (list (- (car t1) (car t2) (if borrow 1 0))
8323 (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2)))))
fb7933a3
KG
8324
8325(defun tramp-time-diff (t1 t2)
8326 "Return the difference between the two times, in seconds.
1a762140 8327T1 and T2 are time values (as returned by `current-time' for example)."
fb7933a3 8328 ;; Pacify byte-compiler with `symbol-function'.
ea9d1443
KG
8329 (cond ((and (fboundp 'subtract-time)
8330 (fboundp 'float-time))
8331 (funcall (symbol-function 'float-time)
8332 (funcall (symbol-function 'subtract-time) t1 t2)))
8333 ((and (fboundp 'subtract-time)
8334 (fboundp 'time-to-seconds))
8335 (funcall (symbol-function 'time-to-seconds)
8336 (funcall (symbol-function 'subtract-time) t1 t2)))
fb7933a3 8337 ((fboundp 'itimer-time-difference)
1a762140
MA
8338 (funcall (symbol-function 'itimer-time-difference)
8339 (if (< (length t1) 3) (append t1 '(0)) t1)
8340 (if (< (length t2) 3) (append t2 '(0)) t2)))
fb7933a3 8341 (t
00d6fd04 8342 (let ((time (tramp-time-subtract t1 t2)))
ea9d1443
KG
8343 (+ (* (car time) 65536.0)
8344 (cadr time)
8345 (/ (or (nth 2 time) 0) 1000000.0))))))
fb7933a3
KG
8346
8347(defun tramp-coding-system-change-eol-conversion (coding-system eol-type)
8348 "Return a coding system like CODING-SYSTEM but with given EOL-TYPE.
8349EOL-TYPE can be one of `dos', `unix', or `mac'."
8350 (cond ((fboundp 'coding-system-change-eol-conversion)
9e6ab520
MA
8351 (funcall (symbol-function 'coding-system-change-eol-conversion)
8352 coding-system eol-type))
fb7933a3 8353 ((fboundp 'subsidiary-coding-system)
9e6ab520
MA
8354 (funcall (symbol-function 'subsidiary-coding-system)
8355 coding-system
8356 (cond ((eq eol-type 'dos) 'crlf)
8357 ((eq eol-type 'unix) 'lf)
8358 ((eq eol-type 'mac) 'cr)
8359 (t
8360 (error "Unknown EOL-TYPE `%s', must be %s"
8361 eol-type
8362 "`dos', `unix', or `mac'")))))
fb7933a3
KG
8363 (t (error "Can't change EOL conversion -- is MULE missing?"))))
8364
19a87064
MA
8365(defun tramp-set-process-query-on-exit-flag (process flag)
8366 "Specify if query is needed for process when Emacs is exited.
8367If the second argument flag is non-nil, Emacs will query the user before
8368exiting if process is running."
8369 (if (fboundp 'set-process-query-on-exit-flag)
00d6fd04
MA
8370 (funcall (symbol-function 'set-process-query-on-exit-flag) process flag)
8371 (funcall (symbol-function 'process-kill-without-query) process flag)))
19a87064 8372
19a87064 8373
bf247b6e
KS
8374;; ------------------------------------------------------------
8375;; -- Kludges section --
8376;; ------------------------------------------------------------
fb7933a3
KG
8377
8378;; Currently (as of Emacs 20.5), the function `shell-quote-argument'
8379;; does not deal well with newline characters. Newline is replaced by
8380;; backslash newline. But if, say, the string `a backslash newline b'
8381;; is passed to a shell, the shell will expand this into "ab",
8382;; completely omitting the newline. This is not what was intended.
8383;; It does not appear to be possible to make the function
8384;; `shell-quote-argument' work with newlines without making it
8385;; dependent on the shell used. But within this package, we know that
8386;; we will always use a Bourne-like shell, so we use an approach which
8387;; groks newlines.
8388;;
8389;; The approach is simple: we call `shell-quote-argument', then
8390;; massage the newline part of the result.
8391;;
8392;; This function should produce a string which is grokked by a Unix
8393;; shell, even if the Emacs is running on Windows. Since this is the
8394;; kludges section, we bind `system-type' in such a way that
8395;; `shell-quote-arguments' behaves as if on Unix.
8396;;
8397;; Thanks to Mario DeWeerd for the hint that it is sufficient for this
8398;; function to work with Bourne-like shells.
8399;;
8400;; CCC: This function should be rewritten so that
8401;; `shell-quote-argument' is not used. This way, we are safe from
8402;; changes in `shell-quote-argument'.
8403(defun tramp-shell-quote-argument (s)
8404 "Similar to `shell-quote-argument', but groks newlines.
8405Only works for Bourne-like shells."
8406 (let ((system-type 'not-windows))
8407 (save-match-data
8408 (let ((result (shell-quote-argument s))
8409 (nl (regexp-quote (format "\\%s" tramp-rsh-end-of-line))))
8410 (when (and (>= (length result) 2)
8411 (string= (substring result 0 2) "\\~"))
8412 (setq result (substring result 1)))
8413 (while (string-match nl result)
8414 (setq result (replace-match (format "'%s'" tramp-rsh-end-of-line)
8415 t t result)))
8416 result))))
8417
16674e4f
KG
8418;; We currently (sometimes) use "[" and "]" in the filename format.
8419;; This means that Emacs wants to expand wildcards if
fb7933a3
KG
8420;; `find-file-wildcards' is non-nil, and then barfs because no
8421;; expansion could be found. We detect this situation and do
8422;; something really awful: we have `file-expand-wildcards' return the
8423;; original filename if it can't expand anything. Let's just hope
8424;; that this doesn't break anything else.
16674e4f
KG
8425;; CCC: This check is now also really awful; we should search all
8426;; of the filename format, not just the prefix.
8427(when (string-match "\\[" tramp-prefix-format)
1834b39f
MA
8428 (defadvice file-expand-wildcards
8429 (around tramp-advice-file-expand-wildcards activate)
d2a2c17f 8430 (let ((name (ad-get-arg 0)))
e268e987
MA
8431 ;; If it's a Tramp file, dissect it and look if wildcards need
8432 ;; to be expanded at all.
8433 (if (and
8434 (tramp-tramp-file-p name)
8435 (not (string-match
8436 "[[*?]"
8437 (tramp-file-name-localname (tramp-dissect-file-name name)))))
8438 (setq ad-return-value (list name))
8439 ;; Otherwise, just run the original function.
8440 ad-do-it)))
191bb792
MA
8441 (add-hook
8442 'tramp-unload-hook
8443 (lambda ()
8444 (ad-remove-advice
d7ec1df7
MA
8445 'file-expand-wildcards 'around 'tramp-advice-file-expand-wildcards)
8446 (ad-activate 'file-expand-wildcards))))
fb7933a3 8447
a69c01a0
MA
8448;; Checklist for `tramp-unload-hook'
8449;; - Unload all `tramp-*' packages
8450;; - Reset `file-name-handler-alist'
8451;; - Cleanup hooks where Tramp functions are in
8452;; - Cleanup advised functions
8453;; - Cleanup autoloads
8454;;;###autoload
8455(defun tramp-unload-tramp ()
08b1eb21 8456 "Discard Tramp from loading remote files."
a69c01a0
MA
8457 (interactive)
8458 ;; When Tramp is not loaded yet, its autoloads are still active.
8c04e197 8459 (tramp-unload-file-name-handlers)
a69c01a0
MA
8460 ;; ange-ftp settings must be enabled.
8461 (when (functionp 'tramp-ftp-enable-ange-ftp)
8462 (funcall (symbol-function 'tramp-ftp-enable-ange-ftp)))
00d6fd04
MA
8463 ;; Maybe its not loaded yet.
8464 (condition-case nil
8465 (unload-feature 'tramp 'force)
a69c01a0
MA
8466 (error nil)))
8467
dea31ca6
MA
8468(when (and load-in-progress
8469 (string-match "Loading tramp..." (or (current-message) "")))
ccb4a481
MA
8470 (message "Loading tramp...done"))
8471
fb7933a3
KG
8472(provide 'tramp)
8473
fb7933a3
KG
8474;;; TODO:
8475
4007ba5b 8476;; * Handle nonlocal exits such as C-g.
00d6fd04
MA
8477;; * But it would probably be better to use with-local-quit at the
8478;; place where it's actually needed: around any potentially
8479;; indefinitely blocking piece of code. In this case it would be
8480;; within Tramp around one of its calls to accept-process-output (or
8481;; around one of the loops that calls accept-process-output)
d037d501 8482;; (Stefan Monnier).
fb7933a3 8483;; * Rewrite `tramp-shell-quote-argument' to abstain from using
b1d06e75 8484;; `shell-quote-argument'.
fb7933a3
KG
8485;; * In Emacs 21, `insert-directory' shows total number of bytes used
8486;; by the files in that directory. Add this here.
8487;; * Avoid screen blanking when hitting `g' in dired. (Eli Tziperman)
8488;; * Make ffap.el grok Tramp filenames. (Eli Tziperman)
fb7933a3 8489;; * Case-insensitive filename completion. (Norbert Goevert.)
fb7933a3
KG
8490;; * Don't use globbing for directories with many files, as this is
8491;; likely to produce long command lines, and some shells choke on
8492;; long command lines.
fb7933a3
KG
8493;; * `vc-directory' does not work. It never displays any files, even
8494;; if it does show files when run locally.
fb7933a3 8495;; * How to deal with MULE in `insert-file-contents' and `write-region'?
fb7933a3
KG
8496;; * Test remote ksh or bash for tilde expansion in `tramp-find-shell'?
8497;; * abbreviate-file-name
8e754ea2 8498;; * Better error checking. At least whenever we see something
fb7933a3
KG
8499;; strange when doing zerop, we should kill the process and start
8500;; again. (Greg Stark)
fb7933a3 8501;; * Remove unneeded parameters from methods.
fb7933a3
KG
8502;; * Make it work for different encodings, and for different file name
8503;; encodings, too. (Daniel Pittman)
fb7933a3 8504;; * Progress reports while copying files. (Michael Kifer)
fb7933a3
KG
8505;; * Don't search for perl5 and perl. Instead, only search for perl and
8506;; then look if it's the right version (with `perl -v').
8507;; * When editing a remote CVS controlled file as a different user, VC
8508;; gets confused about the file locking status. Try to find out why
8509;; the workaround doesn't work.
3cdaec13 8510;; * Username and hostname completion.
6c4e47fa 8511;; ** Try to avoid usage of `last-input-event' in `tramp-completion-mode-p'.
8daea7fc 8512;; ** Unify `tramp-parse-{rhosts,shosts,sconfig,hosts,passwd,netrc}'.
16674e4f 8513;; Code is nearly identical.
cfb5c0db
MA
8514;; * Allow out-of-band methods as _last_ multi-hop. Open a connection
8515;; until the last but one hop via `start-file-process'. Apply it
8516;; also for ftp and smb.
00d6fd04
MA
8517;; * WIBNI if we had a command "trampclient"? If I was editing in
8518;; some shell with root priviledges, it would be nice if I could
8519;; just call
8520;; trampclient filename.c
8521;; as an editor, and the _current_ shell would connect to an Emacs
8522;; server and would be used in an existing non-priviledged Emacs
8523;; session for doing the editing in question.
8524;; That way, I need not tell Emacs my password again and be afraid
8525;; that it makes it into core dumps or other ugly stuff (I had Emacs
8526;; once display a just typed password in the context of a keyboard
8527;; sequence prompt for a question immediately following in a shell
8528;; script run within Emacs -- nasty).
8529;; And if I have some ssh session running to a different computer,
8530;; having the possibility of passing a local file there to a local
8531;; Emacs session (in case I can arrange for a connection back) would
8532;; be nice.
a4aeb9a4 8533;; Likely the corresponding Tramp server should not allow the
00d6fd04
MA
8534;; equivalent of the emacsclient -eval option in order to make this
8535;; reasonably unproblematic. And maybe trampclient should have some
8536;; way of passing credentials, like by using an SSL socket or
8537;; something. (David Kastrup)
00d6fd04
MA
8538;; * Reconnect directly to a compliant shell without first going
8539;; through the user's default shell. (Pete Forman)
00d6fd04 8540;; * Make `tramp-default-user' obsolete.
adb67129
MA
8541;; * Tramp shall reconnect automatically to its ssh connection when it
8542;; detects that the process "has died". (David Reitter)
11c71217
MA
8543;; * How can I interrupt the remote process with a signal
8544;; (interrupt-process seems not to work)? (Markus Triska)
2296b54d
MA
8545;; * Avoid the local shell entirely for starting remote processes. If
8546;; so, I think even a signal, when delivered directly to the local
8547;; SSH instance, would correctly be propagated to the remote process
8548;; automatically; possibly SSH would have to be started with
8549;; "-t". (Markus Triska)
dea31ca6
MA
8550;; * It makes me wonder if tramp couldn't fall back to ssh when scp
8551;; isn't on the remote host. (Mark A. Hershberger)
3e2fa353
MA
8552;; * Use lsh instead of ssh. (Alfred M. Szmidt)
8553;; * Implement a general server-local-variable mechanism, as there are
8554;; probably other variables that need different values for different
8555;; servers too. The user could then configure a variable (such as
8556;; tramp-server-local-variable-alist) to define any such variables
8557;; that they need to, which would then be let bound as appropriate
8558;; in tramp functions. (Jason Rumney)
946a5aeb
MA
8559;; * Optimize out-of-band copying, when both methods are scp-like (not
8560;; rsync).
8561;; * Keep a second connection open for out-of-band methods like scp or
8562;; rsync.
263c02ef 8563;; * Support ptys in `tramp-handle-start-file-process'.
fb7933a3
KG
8564
8565;; Functions for file-name-handler-alist:
8566;; diff-latest-backup-file -- in diff.el
fb7933a3 8567
cdd44874 8568;; arch-tag: 3a21a994-182b-48fa-b0cd-c1d9fede424a
fb7933a3 8569;;; tramp.el ends here
57671b72
MA
8570
8571;; Local Variables:
8572;; mode: Emacs-Lisp
8573;; coding: utf-8
8574;; End: