xfns.c (Fx_show_tip): Subtract last glyph's width only when it is for padding.
[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,
114f9c96 4;; 2005, 2006, 2007, 2008, 2009, 2010 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
7f4d4a97 41;; the `with-timeout' macro.
fb7933a3 42;;
fb7933a3
KG
43;; Also see the todo list at the bottom of this file.
44;;
b1a2b924 45;; The current version of Tramp can be retrieved from the following URL:
340b8d4f 46;; http://ftp.gnu.org/gnu/tramp/
fb7933a3
KG
47;;
48;; There's a mailing list for this, as well. Its name is:
340b8d4f
MA
49;; tramp-devel@gnu.org
50;; You can use the Web to subscribe, under the following URL:
51;; http://lists.gnu.org/mailman/listinfo/tramp-devel
fb7933a3
KG
52;;
53;; For the adventurous, the current development sources are available
54;; via CVS. You can find instructions about this at the following URL:
c62c9d08 55;; http://savannah.gnu.org/projects/tramp/
fb7933a3
KG
56;; Click on "CVS" in the navigation bar near the top.
57;;
58;; Don't forget to put on your asbestos longjohns, first!
59
60;;; Code:
61
ccb4a481
MA
62;; Since Emacs 23.1, loading messages have been disabled during
63;; autoload. However, loading Tramp takes a while, and it could
64;; happen while typing a filename in the minibuffer. Therefore, Tramp
65;; shall inform about.
66(when (and load-in-progress (null (current-message)))
67 (message "Loading tramp..."))
68
b1a2b924
KG
69;; The Tramp version number and bug report address, as prepared by configure.
70(require 'trampver)
a69c01a0 71(add-hook 'tramp-unload-hook
aa485f7c
MA
72 (lambda ()
73 (when (featurep 'trampver)
74 (unload-feature 'trampver 'force))))
a69c01a0 75
9e6ab520 76(require 'tramp-compat)
94be87e8 77(add-hook 'tramp-unload-hook
aa485f7c
MA
78 (lambda ()
79 (when (featurep 'tramp-compat)
80 (unload-feature 'tramp-compat 'force))))
fb7933a3 81
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
26f4b8ab 179 :group 'comm
bf247b6e 180 :version "22.1")
fb7933a3 181
2e271195
MA
182;; Maybe we need once a real Tramp mode, with key bindings etc.
183;;;###autoload
184(defcustom tramp-mode t
185 "*Whether Tramp is enabled.
186If it is set to nil, all remote file names are used literally."
187 :group 'tramp
188 :type 'boolean)
189
00d6fd04 190(defcustom tramp-verbose 3
263c02ef 191 "*Verbosity level for Tramp messages.
00d6fd04
MA
192Any level x includes messages for all levels 1 .. x-1. The levels are
193
194 0 silent (no tramp messages at all)
195 1 errors
196 2 warnings
197 3 connection to remote hosts (default level)
198 4 activities
199 5 internal
200 6 sent and received strings
201 7 file caching
202 8 connection properties
20310 traces (huge)."
fb7933a3
KG
204 :group 'tramp
205 :type 'integer)
206
263c02ef 207;; Emacs case.
38c65fca
KG
208(eval-and-compile
209 (when (boundp 'backup-directory-alist)
210 (defcustom tramp-backup-directory-alist nil
211 "Alist of filename patterns and backup directory names.
212Each element looks like (REGEXP . DIRECTORY), with the same meaning like
213in `backup-directory-alist'. If a Tramp file is backed up, and DIRECTORY
214is a local file name, the backup directory is prepended with Tramp file
00d6fd04 215name prefix \(method, user, host\) of file.
38c65fca
KG
216
217\(setq tramp-backup-directory-alist backup-directory-alist\)
218
219gives the same backup policy for Tramp files on their hosts like the
220policy for local files."
221 :group 'tramp
222 :type '(repeat (cons (regexp :tag "Regexp matching filename")
223 (directory :tag "Backup directory name"))))))
224
225;; XEmacs case. We cannot check for `bkup-backup-directory-info', because
226;; the package "backup-dir" might not be loaded yet.
227(eval-and-compile
228 (when (featurep 'xemacs)
229 (defcustom tramp-bkup-backup-directory-info nil
230 "*Alist of (FILE-REGEXP BACKUP-DIR OPTIONS ...))
231It has the same meaning like `bkup-backup-directory-info' from package
232`backup-dir'. If a Tramp file is backed up, and BACKUP-DIR is a local
233file name, the backup directory is prepended with Tramp file name prefix
00d6fd04 234\(method, user, host\) of file.
38c65fca
KG
235
236\(setq tramp-bkup-backup-directory-info bkup-backup-directory-info\)
237
238gives the same backup policy for Tramp files on their hosts like the
239policy for local files."
bf247b6e 240 :type '(repeat
38c65fca
KG
241 (list (regexp :tag "File regexp")
242 (string :tag "Backup Dir")
243 (set :inline t
244 (const ok-create)
245 (const full-path)
246 (const prepend-name)
247 (const search-upward))))
248 :group 'tramp)))
249
fb7933a3
KG
250(defcustom tramp-auto-save-directory nil
251 "*Put auto-save files in this directory, if set.
252The idea is to use a local directory so that auto-saving is faster."
253 :group 'tramp
00d6fd04 254 :type '(choice (const nil) string))
fb7933a3 255
16674e4f
KG
256(defcustom tramp-encoding-shell
257 (if (memq system-type '(windows-nt))
258 (getenv "COMSPEC")
259 "/bin/sh")
260 "*Use this program for encoding and decoding commands on the local host.
261This shell is used to execute the encoding and decoding command on the
262local host, so if you want to use `~' in those commands, you should
263choose a shell here which groks tilde expansion. `/bin/sh' normally
264does not understand tilde expansion.
265
266For encoding and deocding, commands like the following are executed:
267
268 /bin/sh -c COMMAND < INPUT > OUTPUT
269
270This variable can be used to change the \"/bin/sh\" part. See the
00d6fd04 271variable `tramp-encoding-command-switch' for the \"-c\" part.
fb7933a3
KG
272
273Note that this variable is not used for remote commands. There are
274mechanisms in tramp.el which automatically determine the right shell to
275use for the remote host."
276 :group 'tramp
277 :type '(file :must-match t))
278
16674e4f
KG
279(defcustom tramp-encoding-command-switch
280 (if (string-match "cmd\\.exe" tramp-encoding-shell)
281 "/c"
282 "-c")
283 "*Use this switch together with `tramp-encoding-shell' for local commands.
284See the variable `tramp-encoding-shell' for more information."
285 :group 'tramp
286 :type 'string)
287
00d6fd04
MA
288(defcustom tramp-copy-size-limit 10240
289 "*The maximum file size where inline copying is preferred over an out-of-the-band copy."
16674e4f 290 :group 'tramp
00d6fd04 291 :type 'integer)
90dc758d 292
00d6fd04
MA
293(defcustom tramp-terminal-type "dumb"
294 "*Value of TERM environment variable for logging in to remote host.
295Because Tramp wants to parse the output of the remote shell, it is easily
296confused by ANSI color escape sequences and suchlike. Often, shell init
297files conditionalize this setup based on the TERM environment variable."
90dc758d 298 :group 'tramp
00d6fd04 299 :type 'string)
90dc758d 300
dab816a9
MA
301;; ksh on OpenBSD 4.5 requires, that PS1 contains a `#' character for
302;; root users. It uses the `$' character for other users. In order
303;; to guarantee a proper prompt, we use "#$" for the prompt.
304
305(defvar tramp-end-of-output
306 (format
307 "///%s#$"
308 (md5 (concat (prin1-to-string process-environment) (current-time-string))))
309 "String used to recognize end of output.
310The '$' character at the end is quoted; the string cannot be
311detected as prompt when being sent on echoing hosts, therefore.")
312
313(defconst tramp-initial-end-of-output "#$ "
314 "Prompt when establishing a connection.")
315
00d6fd04
MA
316(defvar tramp-methods
317 `(("rcp" (tramp-login-program "rsh")
318 (tramp-login-args (("%h") ("-l" "%u")))
319 (tramp-remote-sh "/bin/sh")
320 (tramp-copy-program "rcp")
263c02ef 321 (tramp-copy-args (("-p" "%k") ("-r")))
00d6fd04 322 (tramp-copy-keep-date t)
263c02ef 323 (tramp-copy-recursive t)
00d6fd04
MA
324 (tramp-password-end-of-line nil))
325 ("scp" (tramp-login-program "ssh")
2296b54d 326 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
327 ("-e" "none")))
328 (tramp-remote-sh "/bin/sh")
329 (tramp-copy-program "scp")
263c02ef
MA
330 (tramp-copy-args (("-P" "%p") ("-p" "%k")
331 ("-q") ("-r")))
00d6fd04 332 (tramp-copy-keep-date t)
263c02ef 333 (tramp-copy-recursive t)
00d6fd04
MA
334 (tramp-password-end-of-line nil)
335 (tramp-gw-args (("-o"
336 "GlobalKnownHostsFile=/dev/null")
337 ("-o" "UserKnownHostsFile=/dev/null")
338 ("-o" "StrictHostKeyChecking=no")))
339 (tramp-default-port 22))
340 ("scp1" (tramp-login-program "ssh")
2296b54d 341 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
342 ("-1" "-e" "none")))
343 (tramp-remote-sh "/bin/sh")
344 (tramp-copy-program "scp")
345 (tramp-copy-args (("-1") ("-P" "%p") ("-p" "%k")
263c02ef 346 ("-q") ("-r")))
00d6fd04 347 (tramp-copy-keep-date t)
263c02ef 348 (tramp-copy-recursive t)
00d6fd04
MA
349 (tramp-password-end-of-line nil)
350 (tramp-gw-args (("-o"
351 "GlobalKnownHostsFile=/dev/null")
352 ("-o" "UserKnownHostsFile=/dev/null")
353 ("-o" "StrictHostKeyChecking=no")))
354 (tramp-default-port 22))
355 ("scp2" (tramp-login-program "ssh")
2296b54d 356 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
357 ("-2" "-e" "none")))
358 (tramp-remote-sh "/bin/sh")
359 (tramp-copy-program "scp")
360 (tramp-copy-args (("-2") ("-P" "%p") ("-p" "%k")
263c02ef 361 ("-q") ("-r")))
00d6fd04 362 (tramp-copy-keep-date t)
263c02ef 363 (tramp-copy-recursive t)
00d6fd04
MA
364 (tramp-password-end-of-line nil)
365 (tramp-gw-args (("-o"
366 "GlobalKnownHostsFile=/dev/null")
367 ("-o" "UserKnownHostsFile=/dev/null")
368 ("-o" "StrictHostKeyChecking=no")))
369 (tramp-default-port 22))
370 ("scp1_old"
371 (tramp-login-program "ssh1")
372 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
373 ("-e" "none")))
374 (tramp-remote-sh "/bin/sh")
375 (tramp-copy-program "scp1")
263c02ef 376 (tramp-copy-args (("-p" "%k") ("-r")))
00d6fd04 377 (tramp-copy-keep-date t)
263c02ef 378 (tramp-copy-recursive t)
00d6fd04
MA
379 (tramp-password-end-of-line nil))
380 ("scp2_old"
381 (tramp-login-program "ssh2")
382 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
383 ("-e" "none")))
384 (tramp-remote-sh "/bin/sh")
385 (tramp-copy-program "scp2")
263c02ef 386 (tramp-copy-args (("-p" "%k") ("-r")))
00d6fd04 387 (tramp-copy-keep-date t)
263c02ef 388 (tramp-copy-recursive t)
00d6fd04
MA
389 (tramp-password-end-of-line nil))
390 ("sftp" (tramp-login-program "ssh")
391 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
392 ("-e" "none")))
393 (tramp-remote-sh "/bin/sh")
394 (tramp-copy-program "sftp")
395 (tramp-copy-args nil)
396 (tramp-copy-keep-date nil)
397 (tramp-password-end-of-line nil))
398 ("rsync" (tramp-login-program "ssh")
399 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
400 ("-e" "none")))
401 (tramp-remote-sh "/bin/sh")
402 (tramp-copy-program "rsync")
263c02ef 403 (tramp-copy-args (("-e" "ssh") ("-t" "%k") ("-r")))
00d6fd04 404 (tramp-copy-keep-date t)
b88f2d0a 405 (tramp-copy-keep-tmpfile t)
263c02ef 406 (tramp-copy-recursive t)
00d6fd04 407 (tramp-password-end-of-line nil))
263c02ef
MA
408 ("rsyncc"
409 (tramp-login-program "ssh")
946a5aeb
MA
410 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
411 ("-o" "ControlPath=%t.%%r@%%h:%%p")
412 ("-o" "ControlMaster=yes")
413 ("-e" "none")))
414 (tramp-remote-sh "/bin/sh")
415 (tramp-copy-program "rsync")
263c02ef 416 (tramp-copy-args (("-t" "%k") ("-r")))
946a5aeb
MA
417 (tramp-copy-env (("RSYNC_RSH")
418 (,(concat
419 "ssh"
420 " -o ControlPath=%t.%%r@%%h:%%p"
421 " -o ControlMaster=auto"))))
422 (tramp-copy-keep-date t)
b88f2d0a 423 (tramp-copy-keep-tmpfile t)
263c02ef 424 (tramp-copy-recursive t)
946a5aeb 425 (tramp-password-end-of-line nil))
00d6fd04
MA
426 ("remcp" (tramp-login-program "remsh")
427 (tramp-login-args (("%h") ("-l" "%u")))
428 (tramp-remote-sh "/bin/sh")
429 (tramp-copy-program "rcp")
430 (tramp-copy-args (("-p" "%k")))
431 (tramp-copy-keep-date t)
432 (tramp-password-end-of-line nil))
433 ("rsh" (tramp-login-program "rsh")
434 (tramp-login-args (("%h") ("-l" "%u")))
435 (tramp-remote-sh "/bin/sh")
436 (tramp-copy-program nil)
437 (tramp-copy-args nil)
438 (tramp-copy-keep-date nil)
439 (tramp-password-end-of-line nil))
440 ("ssh" (tramp-login-program "ssh")
2296b54d 441 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
442 ("-e" "none")))
443 (tramp-remote-sh "/bin/sh")
444 (tramp-copy-program nil)
445 (tramp-copy-args nil)
446 (tramp-copy-keep-date nil)
447 (tramp-password-end-of-line nil)
448 (tramp-gw-args (("-o"
449 "GlobalKnownHostsFile=/dev/null")
450 ("-o" "UserKnownHostsFile=/dev/null")
451 ("-o" "StrictHostKeyChecking=no")))
452 (tramp-default-port 22))
453 ("ssh1" (tramp-login-program "ssh")
2296b54d 454 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
455 ("-1" "-e" "none")))
456 (tramp-remote-sh "/bin/sh")
457 (tramp-copy-program nil)
458 (tramp-copy-args nil)
459 (tramp-copy-keep-date nil)
460 (tramp-password-end-of-line nil)
461 (tramp-gw-args (("-o"
462 "GlobalKnownHostsFile=/dev/null")
463 ("-o" "UserKnownHostsFile=/dev/null")
464 ("-o" "StrictHostKeyChecking=no")))
465 (tramp-default-port 22))
466 ("ssh2" (tramp-login-program "ssh")
2296b54d 467 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
468 ("-2" "-e" "none")))
469 (tramp-remote-sh "/bin/sh")
470 (tramp-copy-program nil)
471 (tramp-copy-args nil)
472 (tramp-copy-keep-date nil)
473 (tramp-password-end-of-line nil)
474 (tramp-gw-args (("-o"
475 "GlobalKnownHostsFile=/dev/null")
476 ("-o" "UserKnownHostsFile=/dev/null")
477 ("-o" "StrictHostKeyChecking=no")))
478 (tramp-default-port 22))
479 ("ssh1_old"
480 (tramp-login-program "ssh1")
481 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
482 ("-e" "none")))
483 (tramp-remote-sh "/bin/sh")
484 (tramp-copy-program nil)
485 (tramp-copy-args nil)
486 (tramp-copy-keep-date nil)
487 (tramp-password-end-of-line nil))
488 ("ssh2_old"
489 (tramp-login-program "ssh2")
490 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
491 ("-e" "none")))
492 (tramp-remote-sh "/bin/sh")
493 (tramp-copy-program nil)
494 (tramp-copy-args nil)
495 (tramp-copy-keep-date nil)
496 (tramp-password-end-of-line nil))
497 ("remsh" (tramp-login-program "remsh")
498 (tramp-login-args (("%h") ("-l" "%u")))
499 (tramp-remote-sh "/bin/sh")
500 (tramp-copy-program nil)
501 (tramp-copy-args nil)
502 (tramp-copy-keep-date nil)
503 (tramp-password-end-of-line nil))
504 ("telnet"
505 (tramp-login-program "telnet")
506 (tramp-login-args (("%h") ("%p")))
507 (tramp-remote-sh "/bin/sh")
508 (tramp-copy-program nil)
509 (tramp-copy-args nil)
510 (tramp-copy-keep-date nil)
511 (tramp-password-end-of-line nil)
512 (tramp-default-port 23))
513 ("su" (tramp-login-program "su")
514 (tramp-login-args (("-") ("%u")))
515 (tramp-remote-sh "/bin/sh")
516 (tramp-copy-program nil)
517 (tramp-copy-args nil)
518 (tramp-copy-keep-date nil)
519 (tramp-password-end-of-line nil))
520 ("sudo" (tramp-login-program "sudo")
521 (tramp-login-args (("-u" "%u")
42bc9b6d 522 ("-s") ("-H") ("-p" "Password:")))
00d6fd04
MA
523 (tramp-remote-sh "/bin/sh")
524 (tramp-copy-program nil)
525 (tramp-copy-args nil)
526 (tramp-copy-keep-date nil)
527 (tramp-password-end-of-line nil))
528 ("scpc" (tramp-login-program "ssh")
2296b54d 529 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
530 ("-o" "ControlPath=%t.%%r@%%h:%%p")
531 ("-o" "ControlMaster=yes")
532 ("-e" "none")))
533 (tramp-remote-sh "/bin/sh")
534 (tramp-copy-program "scp")
535 (tramp-copy-args (("-P" "%p") ("-p" "%k") ("-q")
536 ("-o" "ControlPath=%t.%%r@%%h:%%p")
537 ("-o" "ControlMaster=auto")))
538 (tramp-copy-keep-date t)
539 (tramp-password-end-of-line nil)
540 (tramp-gw-args (("-o"
541 "GlobalKnownHostsFile=/dev/null")
542 ("-o" "UserKnownHostsFile=/dev/null")
543 ("-o" "StrictHostKeyChecking=no")))
544 (tramp-default-port 22))
545 ("scpx" (tramp-login-program "ssh")
2296b54d 546 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
547 ("-e" "none" "-t" "-t" "/bin/sh")))
548 (tramp-remote-sh "/bin/sh")
549 (tramp-copy-program "scp")
550 (tramp-copy-args (("-p" "%k")))
551 (tramp-copy-keep-date t)
552 (tramp-password-end-of-line nil)
553 (tramp-gw-args (("-o"
554 "GlobalKnownHostsFile=/dev/null")
555 ("-o" "UserKnownHostsFile=/dev/null")
556 ("-o" "StrictHostKeyChecking=no")))
557 (tramp-default-port 22))
558 ("sshx" (tramp-login-program "ssh")
2296b54d 559 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
560 ("-e" "none" "-t" "-t" "/bin/sh")))
561 (tramp-remote-sh "/bin/sh")
562 (tramp-copy-program nil)
563 (tramp-copy-args nil)
564 (tramp-copy-keep-date nil)
565 (tramp-password-end-of-line nil)
566 (tramp-gw-args (("-o"
567 "GlobalKnownHostsFile=/dev/null")
568 ("-o" "UserKnownHostsFile=/dev/null")
569 ("-o" "StrictHostKeyChecking=no")))
570 (tramp-default-port 22))
571 ("krlogin"
572 (tramp-login-program "krlogin")
573 (tramp-login-args (("%h") ("-l" "%u") ("-x")))
574 (tramp-remote-sh "/bin/sh")
575 (tramp-copy-program nil)
576 (tramp-copy-args nil)
577 (tramp-copy-keep-date nil)
578 (tramp-password-end-of-line nil))
579 ("plink" (tramp-login-program "plink")
580 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
581 ("-ssh")))
582 (tramp-remote-sh "/bin/sh")
583 (tramp-copy-program nil)
584 (tramp-copy-args nil)
585 (tramp-copy-keep-date nil)
586 (tramp-password-end-of-line "xy") ;see docstring for "xy"
587 (tramp-default-port 22))
588 ("plink1"
589 (tramp-login-program "plink")
590 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
591 ("-1" "-ssh")))
592 (tramp-remote-sh "/bin/sh")
593 (tramp-copy-program nil)
594 (tramp-copy-args nil)
595 (tramp-copy-keep-date nil)
596 (tramp-password-end-of-line "xy") ;see docstring for "xy"
597 (tramp-default-port 22))
598 ("plinkx"
599 (tramp-login-program "plink")
42bc9b6d
MA
600 ;; ("%h") must be a single element, see
601 ;; `tramp-compute-multi-hops'.
602 (tramp-login-args (("-load") ("%h") ("-t")
ce3f516f 603 (,(format
dab816a9
MA
604 "env 'TERM=%s' 'PROMPT_COMMAND=' 'PS1=%s'"
605 tramp-terminal-type
606 tramp-initial-end-of-output))
00d6fd04
MA
607 ("/bin/sh")))
608 (tramp-remote-sh "/bin/sh")
609 (tramp-copy-program nil)
610 (tramp-copy-args nil)
611 (tramp-copy-keep-date nil)
612 (tramp-password-end-of-line nil))
613 ("pscp" (tramp-login-program "plink")
614 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
615 ("-ssh")))
616 (tramp-remote-sh "/bin/sh")
617 (tramp-copy-program "pscp")
60f2c210 618 (tramp-copy-args (("-P" "%p") ("-scp") ("-p" "%k")))
00d6fd04
MA
619 (tramp-copy-keep-date t)
620 (tramp-password-end-of-line "xy") ;see docstring for "xy"
621 (tramp-default-port 22))
622 ("psftp" (tramp-login-program "plink")
623 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
624 ("-ssh")))
625 (tramp-remote-sh "/bin/sh")
626 (tramp-copy-program "pscp")
60f2c210 627 (tramp-copy-args (("-P" "%p") ("-sftp") ("-p" "%k")))
00d6fd04
MA
628 (tramp-copy-keep-date t)
629 (tramp-password-end-of-line "xy")) ;see docstring for "xy"
630 ("fcp" (tramp-login-program "fsh")
631 (tramp-login-args (("%h") ("-l" "%u") ("sh" "-i")))
632 (tramp-remote-sh "/bin/sh -i")
633 (tramp-copy-program "fcp")
634 (tramp-copy-args (("-p" "%k")))
635 (tramp-copy-keep-date t)
636 (tramp-password-end-of-line nil)))
fb7933a3
KG
637 "*Alist of methods for remote files.
638This is a list of entries of the form (NAME PARAM1 PARAM2 ...).
639Each NAME stands for a remote access method. Each PARAM is a
640pair of the form (KEY VALUE). The following KEYs are defined:
fb7933a3
KG
641 * `tramp-remote-sh'
642 This specifies the Bourne shell to use on the remote host. This
643 MUST be a Bourne-like shell. It is normally not necessary to set
a4aeb9a4 644 this to any value other than \"/bin/sh\": Tramp wants to use a shell
fb7933a3
KG
645 which groks tilde expansion, but it can search for it. Also note
646 that \"/bin/sh\" exists on all Unixen, this might not be true for
647 the value that you decide to use. You Have Been Warned.
b25a52cc
KG
648 * `tramp-login-program'
649 This specifies the name of the program to use for logging in to the
00d6fd04
MA
650 remote host. This may be the name of rsh or a workalike program,
651 or the name of telnet or a workalike, or the name of su or a workalike.
b25a52cc 652 * `tramp-login-args'
fb7933a3 653 This specifies the list of arguments to pass to the above
00d6fd04 654 mentioned program. Please note that this is a list of list of arguments,
fb7933a3 655 that is, normally you don't want to put \"-a -b\" or \"-f foo\"
00d6fd04
MA
656 here. Instead, you want a list (\"-a\" \"-b\"), or (\"-f\" \"foo\").
657 There are some patterns: \"%h\" in this list is replaced by the host
658 name, \"%u\" is replaced by the user name, \"%p\" is replaced by the
659 port number, and \"%%\" can be used to obtain a literal percent character.
660 If a list containing \"%h\", \"%u\" or \"%p\" is unchanged during
661 expansion (i.e. no host or no user specified), this list is not used as
662 argument. By this, arguments like (\"-l\" \"%u\") are optional.
663 \"%t\" is replaced by the temporary file name produced with
664 `tramp-make-tramp-temp-file'. \"%k\" indicates the keep-date
665 parameter of a program, if exists.
b25a52cc
KG
666 * `tramp-copy-program'
667 This specifies the name of the program to use for remotely copying
668 the file; this might be the absolute filename of rcp or the name of
669 a workalike program.
670 * `tramp-copy-args'
fb7933a3 671 This specifies the list of parameters to pass to the above mentioned
b25a52cc 672 program, the hints for `tramp-login-args' also apply here.
00d6fd04
MA
673 * `tramp-copy-keep-date'
674 This specifies whether the copying program when the preserves the
675 timestamp of the original file.
b88f2d0a
MA
676 * `tramp-copy-keep-tmpfile'
677 This specifies whether a temporary local file shall be kept
678 for optimization reasons (useful for \"rsync\" methods).
679 * `tramp-copy-recursive'
680 Whether the operation copies directories recursively.
00d6fd04
MA
681 * `tramp-default-port'
682 The default port of a method is needed in case of gateway connections.
683 Additionally, it is used as indication which method is prepared for
684 passing gateways.
685 * `tramp-gw-args'
686 As the attribute name says, additional arguments are specified here
687 when a method is applied via a gateway.
90f8dc03
KG
688 * `tramp-password-end-of-line'
689 This specifies the string to use for terminating the line after
690 submitting the password. If this method parameter is nil, then the
691 value of the normal variable `tramp-default-password-end-of-line'
692 is used. This parameter is necessary because the \"plink\" program
693 requires any two characters after sending the password. These do
694 not have to be newline or carriage return characters. Other login
695 programs are happy with just one character, the newline character.
696 We use \"xy\" as the value for methods using \"plink\".
b25a52cc
KG
697
698What does all this mean? Well, you should specify `tramp-login-program'
699for all methods; this program is used to log in to the remote site. Then,
700there are two ways to actually transfer the files between the local and the
701remote side. One way is using an additional rcp-like program. If you want
702to do this, set `tramp-copy-program' in the method.
fb7933a3
KG
703
704Another possibility for file transfer is inline transfer, i.e. the
b25a52cc 705file is passed through the same buffer used by `tramp-login-program'. In
fb7933a3 706this case, the file contents need to be protected since the
b25a52cc 707`tramp-login-program' might use escape codes or the connection might not
fb7933a3 708be eight-bit clean. Therefore, file contents are encoded for transit.
00d6fd04
MA
709See the variables `tramp-local-coding-commands' and
710`tramp-remote-coding-commands' for details.
fb7933a3 711
16674e4f 712So, to summarize: if the method is an out-of-band method, then you
b25a52cc 713must specify `tramp-copy-program' and `tramp-copy-args'. If it is an
00d6fd04
MA
714inline method, then these two parameters should be nil. Methods which
715are fit for gateways must have `tramp-default-port' at least.
fb7933a3
KG
716
717Notes:
718
00d6fd04
MA
719When using `su' or `sudo' the phrase `open connection to a remote
720host' sounds strange, but it is used nevertheless, for consistency.
721No connection is opened to a remote host, but `su' or `sudo' is
722started on the local host. You should specify a remote host
723`localhost' or the name of the local host. Another host name is
724useful only in combination with `tramp-default-proxies-alist'.")
fb7933a3 725
b25a52cc 726(defcustom tramp-default-method
83e20b5c
MA
727 ;; An external copy method seems to be preferred, because it is much
728 ;; more performant for large files, and it hasn't too serious delays
729 ;; for small files. But it must be ensured that there aren't
730 ;; permanent password queries. Either a password agent like
263c02ef
MA
731 ;; "ssh-agent" or "Pageant" shall run, or the optional
732 ;; password-cache.el or auth-sources.el packages shall be active for
733 ;; password caching. "scpc" would be another good choice because of
734 ;; the "ControlMaster" option, but this is a more modern alternative
735 ;; in OpenSSH 4, which cannot be taken as default.
00d6fd04
MA
736 (cond
737 ;; PuTTY is installed.
738 ((executable-find "pscp")
739 (if (or (fboundp 'password-read)
263c02ef 740 (fboundp 'auth-source-user-or-password)
00d6fd04 741 ;; Pageant is running.
70c11b0b 742 (tramp-compat-process-running-p "Pageant"))
00d6fd04
MA
743 "pscp"
744 "plink"))
745 ;; There is an ssh installation.
746 ((executable-find "scp")
747 (if (or (fboundp 'password-read)
263c02ef 748 (fboundp 'auth-source-user-or-password)
00d6fd04
MA
749 ;; ssh-agent is running.
750 (getenv "SSH_AUTH_SOCK")
751 (getenv "SSH_AGENT_PID"))
752 "scp"
753 "ssh"))
754 ;; Fallback.
755 (t "ftp"))
fb7933a3 756 "*Default method to use for transferring files.
c62c9d08 757See `tramp-methods' for possibilities.
4007ba5b 758Also see `tramp-default-method-alist'."
c62c9d08
KG
759 :group 'tramp
760 :type 'string)
761
505edaeb 762(defcustom tramp-default-method-alist
4007ba5b 763 '(("\\`localhost\\'" "\\`root\\'" "su"))
00d6fd04 764 "*Default method to use for specific host/user pairs.
c62c9d08
KG
765This is an alist of items (HOST USER METHOD). The first matching item
766specifies the method to use for a file name which does not specify a
767method. HOST and USER are regular expressions or nil, which is
768interpreted as a regular expression which always matches. If no entry
769matches, the variable `tramp-default-method' takes effect.
770
771If the file name does not specify the user, lookup is done using the
772empty string for the user name.
773
774See `tramp-methods' for a list of possibilities for METHOD."
775 :group 'tramp
776 :type '(repeat (list (regexp :tag "Host regexp")
777 (regexp :tag "User regexp")
778 (string :tag "Method"))))
779
00d6fd04
MA
780(defcustom tramp-default-user
781 nil
782 "*Default user to use for transferring files.
783It is nil by default; otherwise settings in configuration files like
784\"~/.ssh/config\" would be overwritten. Also see `tramp-default-user-alist'.
785
786This variable is regarded as obsolete, and will be removed soon."
787 :group 'tramp
788 :type '(choice (const nil) string))
789
790(defcustom tramp-default-user-alist
791 `(("\\`su\\(do\\)?\\'" nil "root")
792 ("\\`r\\(em\\)?\\(cp\\|sh\\)\\|telnet\\|plink1?\\'"
793 nil ,(user-login-name)))
794 "*Default user to use for specific method/host pairs.
795This is an alist of items (METHOD HOST USER). The first matching item
796specifies the user to use for a file name which does not specify a
797user. METHOD and USER are regular expressions or nil, which is
798interpreted as a regular expression which always matches. If no entry
799matches, the variable `tramp-default-user' takes effect.
800
801If the file name does not specify the method, lookup is done using the
802empty string for the method name."
803 :group 'tramp
804 :type '(repeat (list (regexp :tag "Method regexp")
805 (regexp :tag "Host regexp")
806 (string :tag "User"))))
807
808(defcustom tramp-default-host
809 (system-name)
810 "*Default host to use for transferring files.
811Useful for su and sudo methods mostly."
812 :group 'tramp
813 :type 'string)
814
815(defcustom tramp-default-proxies-alist nil
816 "*Route to be followed for specific host/user pairs.
817This is an alist of items (HOST USER PROXY). The first matching
818item specifies the proxy to be passed for a file name located on
819a remote target matching USER@HOST. HOST and USER are regular
70c11b0b
MA
820expressions. PROXY must be a Tramp filename without a localname
821part. Method and user name on PROXY are optional, which is
822interpreted with the default values. PROXY can contain the
823patterns %h and %u, which are replaced by the strings matching
824HOST or USER, respectively.
825
826HOST, USER or PROXY could also be Lisp forms, which will be
827evaluated. The result must be a string or nil, which is
828interpreted as a regular expression which always matches."
00d6fd04 829 :group 'tramp
70c11b0b
MA
830 :type '(repeat (list (choice :tag "Host regexp" regexp sexp)
831 (choice :tag "User regexp" regexp sexp)
832 (choice :tag "Proxy remote name" string (const nil)))))
00d6fd04 833
b96e6899
MA
834(defconst tramp-local-host-regexp
835 (concat
836 "^" (regexp-opt (list "localhost" (system-name) "127\.0\.0\.1" "::1") t) "$")
837 "*Host names which are regarded as local host.")
838
16674e4f 839(defconst tramp-completion-function-alist-rsh
00d6fd04
MA
840 '((tramp-parse-rhosts "/etc/hosts.equiv")
841 (tramp-parse-rhosts "~/.rhosts"))
b25a52cc 842 "Default list of (FUNCTION FILE) pairs to be examined for rsh methods.")
16674e4f 843
16674e4f 844(defconst tramp-completion-function-alist-ssh
00d6fd04
MA
845 '((tramp-parse-rhosts "/etc/hosts.equiv")
846 (tramp-parse-rhosts "/etc/shosts.equiv")
847 (tramp-parse-shosts "/etc/ssh_known_hosts")
848 (tramp-parse-sconfig "/etc/ssh_config")
849 (tramp-parse-shostkeys "/etc/ssh2/hostkeys")
850 (tramp-parse-sknownhosts "/etc/ssh2/knownhosts")
851 (tramp-parse-rhosts "~/.rhosts")
852 (tramp-parse-rhosts "~/.shosts")
853 (tramp-parse-shosts "~/.ssh/known_hosts")
854 (tramp-parse-sconfig "~/.ssh/config")
855 (tramp-parse-shostkeys "~/.ssh2/hostkeys")
856 (tramp-parse-sknownhosts "~/.ssh2/knownhosts"))
b25a52cc 857 "Default list of (FUNCTION FILE) pairs to be examined for ssh methods.")
16674e4f 858
16674e4f 859(defconst tramp-completion-function-alist-telnet
00d6fd04 860 '((tramp-parse-hosts "/etc/hosts"))
b25a52cc 861 "Default list of (FUNCTION FILE) pairs to be examined for telnet methods.")
16674e4f 862
16674e4f 863(defconst tramp-completion-function-alist-su
00d6fd04 864 '((tramp-parse-passwd "/etc/passwd"))
b25a52cc 865 "Default list of (FUNCTION FILE) pairs to be examined for su methods.")
292ffc15 866
00d6fd04
MA
867(defconst tramp-completion-function-alist-putty
868 '((tramp-parse-putty
869 "HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions"))
870 "Default list of (FUNCTION REGISTRY) pairs to be examined for putty methods.")
871
5ec2cc41 872(defvar tramp-completion-function-alist nil
16674e4f
KG
873 "*Alist of methods for remote files.
874This is a list of entries of the form (NAME PAIR1 PAIR2 ...).
875Each NAME stands for a remote access method. Each PAIR is of the form
876\(FUNCTION FILE). FUNCTION is responsible to extract user names and host
877names from FILE for completion. The following predefined FUNCTIONs exists:
878
5ec2cc41
KG
879 * `tramp-parse-rhosts' for \"~/.rhosts\" like files,
880 * `tramp-parse-shosts' for \"~/.ssh/known_hosts\" like files,
881 * `tramp-parse-sconfig' for \"~/.ssh/config\" like files,
882 * `tramp-parse-shostkeys' for \"~/.ssh2/hostkeys/*\" like files,
883 * `tramp-parse-sknownhosts' for \"~/.ssh2/knownhosts/*\" like files,
884 * `tramp-parse-hosts' for \"/etc/hosts\" like files,
885 * `tramp-parse-passwd' for \"/etc/passwd\" like files.
886 * `tramp-parse-netrc' for \"~/.netrc\" like files.
00d6fd04 887 * `tramp-parse-putty' for PuTTY registry keys.
5ec2cc41
KG
888
889FUNCTION can also be a customer defined function. For more details see
890the info pages.")
891
892(eval-after-load "tramp"
893 '(progn
894 (tramp-set-completion-function
895 "rcp" tramp-completion-function-alist-rsh)
896 (tramp-set-completion-function
897 "scp" tramp-completion-function-alist-ssh)
898 (tramp-set-completion-function
899 "scp1" tramp-completion-function-alist-ssh)
900 (tramp-set-completion-function
901 "scp2" tramp-completion-function-alist-ssh)
902 (tramp-set-completion-function
903 "scp1_old" tramp-completion-function-alist-ssh)
904 (tramp-set-completion-function
905 "scp2_old" tramp-completion-function-alist-ssh)
906 (tramp-set-completion-function
70c11b0b 907 "rsync" tramp-completion-function-alist-ssh)
946a5aeb
MA
908 (tramp-set-completion-function
909 "rsyncc" tramp-completion-function-alist-ssh)
5ec2cc41
KG
910 (tramp-set-completion-function
911 "remcp" tramp-completion-function-alist-rsh)
912 (tramp-set-completion-function
913 "rsh" tramp-completion-function-alist-rsh)
914 (tramp-set-completion-function
915 "ssh" tramp-completion-function-alist-ssh)
916 (tramp-set-completion-function
917 "ssh1" tramp-completion-function-alist-ssh)
918 (tramp-set-completion-function
919 "ssh2" tramp-completion-function-alist-ssh)
920 (tramp-set-completion-function
921 "ssh1_old" tramp-completion-function-alist-ssh)
922 (tramp-set-completion-function
923 "ssh2_old" tramp-completion-function-alist-ssh)
924 (tramp-set-completion-function
925 "remsh" tramp-completion-function-alist-rsh)
926 (tramp-set-completion-function
927 "telnet" tramp-completion-function-alist-telnet)
928 (tramp-set-completion-function
929 "su" tramp-completion-function-alist-su)
930 (tramp-set-completion-function
931 "sudo" tramp-completion-function-alist-su)
bf247b6e 932 (tramp-set-completion-function
5ec2cc41
KG
933 "scpx" tramp-completion-function-alist-ssh)
934 (tramp-set-completion-function
935 "sshx" tramp-completion-function-alist-ssh)
936 (tramp-set-completion-function
937 "krlogin" tramp-completion-function-alist-rsh)
938 (tramp-set-completion-function
939 "plink" tramp-completion-function-alist-ssh)
940 (tramp-set-completion-function
941 "plink1" tramp-completion-function-alist-ssh)
00d6fd04
MA
942 (tramp-set-completion-function
943 "plinkx" tramp-completion-function-alist-putty)
5ec2cc41
KG
944 (tramp-set-completion-function
945 "pscp" tramp-completion-function-alist-ssh)
946 (tramp-set-completion-function
947 "fcp" tramp-completion-function-alist-ssh)))
16674e4f 948
674da028
MA
949(defconst tramp-echo-mark-marker "_echo"
950 "String marker to surround echoed commands.")
951
68712eb6
MA
952(defconst tramp-echo-mark-marker-length (length tramp-echo-mark-marker)
953 "String length of `tramp-echo-mark-marker'.")
954
955(defconst tramp-echo-mark
956 (concat tramp-echo-mark-marker
957 (make-string tramp-echo-mark-marker-length ?\b))
00d6fd04
MA
958 "String mark to be transmitted around shell commands.
959Used to separate their echo from the output they produce. This
960will only be used if we cannot disable remote echo via stty.
961This string must have no effect on the remote shell except for
962producing some echo which can later be detected by
674da028
MA
963`tramp-echoed-echo-mark-regexp'. Using `tramp-echo-mark-marker',
964followed by an equal number of backspaces to erase them will
965usually suffice.")
00d6fd04 966
68712eb6
MA
967(defconst tramp-echoed-echo-mark-regexp
968 (format "%s\\(\b\\( \b\\)?\\)\\{%d\\}"
969 tramp-echo-mark-marker tramp-echo-mark-marker-length)
00d6fd04
MA
970 "Regexp which matches `tramp-echo-mark' as it gets echoed by
971the remote shell.")
972
fb7933a3
KG
973(defcustom tramp-rsh-end-of-line "\n"
974 "*String used for end of line in rsh connections.
975I don't think this ever needs to be changed, so please tell me about it
16674e4f 976if you need to change this.
90f8dc03
KG
977Also see the method parameter `tramp-password-end-of-line' and the normal
978variable `tramp-default-password-end-of-line'."
16674e4f
KG
979 :group 'tramp
980 :type 'string)
981
90f8dc03
KG
982(defcustom tramp-default-password-end-of-line
983 tramp-rsh-end-of-line
16674e4f 984 "*String used for end of line after sending a password.
90f8dc03
KG
985This variable provides the default value for the method parameter
986`tramp-password-end-of-line', see `tramp-methods' for more details.
987
16674e4f
KG
988It seems that people using plink under Windows need to send
989\"\\r\\n\" (carriage-return, then newline) after a password, but just
990\"\\n\" after all other lines. This variable can be used for the
991password, see `tramp-rsh-end-of-line' for the other cases.
992
993The default value is to use the same value as `tramp-rsh-end-of-line'."
fb7933a3
KG
994 :group 'tramp
995 :type 'string)
996
00d6fd04
MA
997;; "getconf PATH" yields:
998;; HP-UX: /usr/bin:/usr/ccs/bin:/opt/ansic/bin:/opt/langtools/bin:/opt/fortran/bin
999;; Solaris: /usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin
0664ff72 1000;; GNU/Linux (Debian, Suse): /bin:/usr/bin
00d6fd04 1001;; FreeBSD: /usr/bin:/bin:/usr/sbin:/sbin: - beware trailing ":"!
fb7933a3 1002(defcustom tramp-remote-path
00d6fd04
MA
1003 '(tramp-default-remote-path "/usr/sbin" "/usr/local/bin"
1004 "/local/bin" "/local/freeware/bin" "/local/gnu/bin"
fb7933a3
KG
1005 "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin")
1006 "*List of directories to search for executables on remote host.
00d6fd04
MA
1007For every remote host, this variable will be set buffer local,
1008keeping the list of existing directories on that host.
fb7933a3
KG
1009
1010You can use `~' in this list, but when searching for a shell which groks
00d6fd04
MA
1011tilde expansion, all directory names starting with `~' will be ignored.
1012
1013`Default Directories' represent the list of directories given by
1014the command \"getconf PATH\". It is recommended to use this
1015entry on top of this list, because these are the default
70c11b0b
MA
1016directories for POSIX compatible commands.
1017
1018`Private Directories' are the settings of the $PATH environment,
1019as given in your `~/.profile'."
00d6fd04
MA
1020 :group 'tramp
1021 :type '(repeat (choice
1022 (const :tag "Default Directories" tramp-default-remote-path)
70c11b0b 1023 (const :tag "Private Directories" tramp-own-remote-path)
00d6fd04
MA
1024 (string :tag "Directory"))))
1025
00d6fd04 1026(defcustom tramp-remote-process-environment
a0a5183a 1027 `("HISTFILE=$HOME/.tramp_history" "HISTSIZE=1" "LC_ALL=C"
00d6fd04 1028 ,(concat "TERM=" tramp-terminal-type)
97c696d5
MA
1029 "EMACS=t" ;; Deprecated.
1030 ,(format "INSIDE_EMACS=%s,tramp:%s" emacs-version tramp-version)
00d6fd04
MA
1031 "CDPATH=" "HISTORY=" "MAIL=" "MAILCHECK=" "MAILPATH="
1032 "autocorrect=" "correct=")
1033
1034 "*List of environment variables to be set on the remote host.
1035
1036Each element should be a string of the form ENVVARNAME=VALUE. An
1037entry ENVVARNAME= diables the corresponding environment variable,
1038which might have been set in the init files like ~/.profile.
1039
1040Special handling is applied to the PATH environment, which should
1041not be set here. Instead of, it should be set via `tramp-remote-path'."
fb7933a3
KG
1042 :group 'tramp
1043 :type '(repeat string))
1044
1045(defcustom tramp-login-prompt-regexp
bc103d00 1046 ".*ogin\\( .*\\)?: *"
fb7933a3 1047 "*Regexp matching login-like prompts.
bc103d00
MA
1048The regexp should match at end of buffer.
1049
1050Sometimes the prompt is reported to look like \"login as:\"."
fb7933a3
KG
1051 :group 'tramp
1052 :type 'regexp)
1053
821e6e36 1054(defcustom tramp-shell-prompt-pattern
aa485f7c
MA
1055 ;; Allow a prompt to start right after a ^M since it indeed would be
1056 ;; displayed at the beginning of the line (and Zsh uses it).
dab816a9 1057 "\\(?:^\\|\r\\)[^#$%>\n]*#?[#$%>] *\\(\e\\[[0-9;]*[a-zA-Z] *\\)*"
821e6e36
KG
1058 "Regexp to match prompts from remote shell.
1059Normally, Tramp expects you to configure `shell-prompt-pattern'
1060correctly, but sometimes it happens that you are connecting to a
1061remote host which sends a different kind of shell prompt. Therefore,
1062Tramp recognizes things matched by `shell-prompt-pattern' as prompt,
1063and also things matched by this variable. The default value of this
b25a52cc 1064variable is similar to the default value of `shell-prompt-pattern',
dab816a9
MA
1065which should work well in many cases.
1066
1067This regexp must match both `tramp-initial-end-of-output' and
1068`tramp-end-of-output'."
821e6e36
KG
1069 :group 'tramp
1070 :type 'regexp)
1071
fb7933a3 1072(defcustom tramp-password-prompt-regexp
00d6fd04 1073 "^.*\\([pP]assword\\|[pP]assphrase\\).*:\^@? *"
fb7933a3 1074 "*Regexp matching password-like prompts.
ac474af1 1075The regexp should match at end of buffer.
fb7933a3
KG
1076
1077The `sudo' program appears to insert a `^@' character into the prompt."
1078 :group 'tramp
1079 :type 'regexp)
1080
1081(defcustom tramp-wrong-passwd-regexp
b1d06e75
KG
1082 (concat "^.*"
1083 ;; These strings should be on the last line
a4aeb9a4 1084 (regexp-opt '("Permission denied"
b1d06e75
KG
1085 "Login incorrect"
1086 "Login Incorrect"
1087 "Connection refused"
27e813fe 1088 "Connection closed"
7e5686f0 1089 "Timeout, server not responding."
b1d06e75
KG
1090 "Sorry, try again."
1091 "Name or service not known"
00d6fd04 1092 "Host key verification failed."
70c11b0b 1093 "No supported authentication methods left to try!") t)
b1d06e75
KG
1094 ".*"
1095 "\\|"
1096 "^.*\\("
1097 ;; Here comes a list of regexes, separated by \\|
1098 "Received signal [0-9]+"
1099 "\\).*")
fb7933a3 1100 "*Regexp matching a `login failed' message.
ac474af1
KG
1101The regexp should match at end of buffer."
1102 :group 'tramp
1103 :type 'regexp)
1104
1105(defcustom tramp-yesno-prompt-regexp
3cdaec13
KG
1106 (concat
1107 (regexp-opt '("Are you sure you want to continue connecting (yes/no)?") t)
1108 "\\s-*")
1109 "Regular expression matching all yes/no queries which need to be confirmed.
ac474af1 1110The confirmation should be done with yes or no.
3cdaec13
KG
1111The regexp should match at end of buffer.
1112See also `tramp-yn-prompt-regexp'."
fb7933a3
KG
1113 :group 'tramp
1114 :type 'regexp)
1115
3cdaec13 1116(defcustom tramp-yn-prompt-regexp
658052a2
MA
1117 (concat
1118 (regexp-opt '("Store key in cache? (y/n)"
1119 "Update cached key? (y/n, Return cancels connection)") t)
1120 "\\s-*")
3cdaec13
KG
1121 "Regular expression matching all y/n queries which need to be confirmed.
1122The confirmation should be done with y or n.
1123The regexp should match at end of buffer.
1124See also `tramp-yesno-prompt-regexp'."
1125 :group 'tramp
1126 :type 'regexp)
487f4fb7
KG
1127
1128(defcustom tramp-terminal-prompt-regexp
1129 (concat "\\("
1130 "TERM = (.*)"
1131 "\\|"
1132 "Terminal type\\? \\[.*\\]"
1133 "\\)\\s-*")
1134 "Regular expression matching all terminal setting prompts.
1135The regexp should match at end of buffer.
1136The answer will be provided by `tramp-action-terminal', which see."
1137 :group 'tramp
1138 :type 'regexp)
3cdaec13 1139
01917a18
MA
1140(defcustom tramp-operation-not-permitted-regexp
1141 (concat "\\(" "preserving times.*" "\\|" "set mode" "\\)" ":\\s-*"
1142 (regexp-opt '("Operation not permitted") t))
1143 "Regular expression matching keep-date problems in (s)cp operations.
1144Copying has been performed successfully already, so this message can
1145be ignored safely."
1146 :group 'tramp
1147 :type 'regexp)
1148
6b2633cc
LH
1149(defcustom tramp-copy-failed-regexp
1150 (concat "\\(.+: "
1151 (regexp-opt '("Permission denied"
1152 "not a regular file"
1153 "is a directory"
1154 "No such file or directory") t)
1155 "\\)\\s-*")
1156 "Regular expression matching copy problems in (s)cp operations."
1157 :group 'tramp
1158 :type 'regexp)
1159
19a87064 1160(defcustom tramp-process-alive-regexp
38c65fca 1161 ""
19a87064 1162 "Regular expression indicating a process has finished.
38c65fca
KG
1163In fact this expression is empty by intention, it will be used only to
1164check regularly the status of the associated process.
07dfe738 1165The answer will be provided by `tramp-action-process-alive',
00d6fd04 1166`tramp-action-out-of-band', which see."
38c65fca
KG
1167 :group 'tramp
1168 :type 'regexp)
1169
fb7933a3
KG
1170(defcustom tramp-temp-name-prefix "tramp."
1171 "*Prefix to use for temporary files.
1172If this is a relative file name (such as \"tramp.\"), it is considered
1173relative to the directory name returned by the function
9e6ab520 1174`tramp-compat-temporary-file-directory' (which see). It may also be an
fb7933a3
KG
1175absolute file name; don't forget to include a prefix for the filename
1176part, though."
1177 :group 'tramp
1178 :type 'string)
1179
2296b54d
MA
1180(defconst tramp-temp-buffer-name " *tramp temp*"
1181 "Buffer name for a temporary buffer.
1182It shall be used in combination with `generate-new-buffer-name'.")
1183
b88f2d0a
MA
1184(defvar tramp-temp-buffer-file-name nil
1185 "File name of a persistent local temporary file.
1186Useful for \"rsync\" like methods.")
1187(make-variable-buffer-local 'tramp-temp-buffer-file-name)
1188
4007ba5b 1189(defcustom tramp-sh-extra-args '(("/bash\\'" . "-norc -noprofile"))
c62c9d08
KG
1190 "*Alist specifying extra arguments to pass to the remote shell.
1191Entries are (REGEXP . ARGS) where REGEXP is a regular expression
1192matching the shell file name and ARGS is a string specifying the
1193arguments.
1194
1195This variable is only used when Tramp needs to start up another shell
1196for tilde expansion. The extra arguments should typically prevent the
1197shell from reading its init file."
1198 :group 'tramp
90f8dc03
KG
1199 ;; This might be the wrong way to test whether the widget type
1200 ;; `alist' is available. Who knows the right way to test it?
1201 :type (if (get 'alist 'widget-type)
1202 '(alist :key-type string :value-type string)
1203 '(repeat (cons string string))))
c62c9d08 1204
00d6fd04
MA
1205;; XEmacs is distributed with few Lisp packages. Further packages are
1206;; installed using EFS. If we use a unified filename format, then
1207;; Tramp is required in addition to EFS. (But why can't Tramp just
1208;; disable EFS when Tramp is loaded? Then XEmacs can ship with EFS
1209;; just like before.) Another reason for using a separate filename
1210;; syntax on XEmacs is that EFS hooks into XEmacs in many places, but
1211;; Tramp only knows how to deal with `file-name-handler-alist', not
1212;; the other places.
1213
1214;; Currently, we have the choice between 'ftp, 'sep, and 'url.
1215;;;###autoload
1216(defcustom tramp-syntax
1217 (if (featurep 'xemacs) 'sep 'ftp)
1218 "Tramp filename syntax to be used.
1219
1220It can have the following values:
1221
1222 'ftp -- Ange-FTP respective EFS like syntax (GNU Emacs default)
1223 'sep -- Syntax as defined for XEmacs (not available yet for GNU Emacs)
1224 'url -- URL-like syntax."
16674e4f 1225 :group 'tramp
00d6fd04
MA
1226 :type (if (featurep 'xemacs)
1227 '(choice (const :tag "EFS" ftp)
1228 (const :tag "XEmacs" sep)
1229 (const :tag "URL" url))
1230 '(choice (const :tag "Ange-FTP" ftp)
1231 (const :tag "URL" url))))
1232
1233(defconst tramp-prefix-format
1234 (cond ((equal tramp-syntax 'ftp) "/")
1235 ((equal tramp-syntax 'sep) "/[")
1236 ((equal tramp-syntax 'url) "/")
1237 (t (error "Wrong `tramp-syntax' defined")))
a4aeb9a4 1238 "*String matching the very beginning of Tramp file names.
00d6fd04 1239Used in `tramp-make-tramp-file-name'.")
16674e4f 1240
00d6fd04 1241(defconst tramp-prefix-regexp
16674e4f 1242 (concat "^" (regexp-quote tramp-prefix-format))
a4aeb9a4 1243 "*Regexp matching the very beginning of Tramp file names.
00d6fd04 1244Should always start with \"^\". Derived from `tramp-prefix-format'.")
16674e4f 1245
00d6fd04 1246(defconst tramp-method-regexp
16674e4f 1247 "[a-zA-Z_0-9-]+"
00d6fd04 1248 "*Regexp matching methods identifiers.")
16674e4f 1249
00d6fd04
MA
1250(defconst tramp-postfix-method-format
1251 (cond ((equal tramp-syntax 'ftp) ":")
1252 ((equal tramp-syntax 'sep) "/")
1253 ((equal tramp-syntax 'url) "://")
1254 (t (error "Wrong `tramp-syntax' defined")))
16674e4f 1255 "*String matching delimeter between method and user or host names.
00d6fd04 1256Used in `tramp-make-tramp-file-name'.")
16674e4f 1257
00d6fd04
MA
1258(defconst tramp-postfix-method-regexp
1259 (regexp-quote tramp-postfix-method-format)
16674e4f 1260 "*Regexp matching delimeter between method and user or host names.
00d6fd04 1261Derived from `tramp-postfix-method-format'.")
16674e4f 1262
00d6fd04
MA
1263(defconst tramp-user-regexp
1264 "[^:/ \t]+"
1265 "*Regexp matching user names.")
16674e4f 1266
b96e6899
MA
1267(defconst tramp-prefix-domain-format "%"
1268 "*String matching delimeter between user and domain names.")
1269
1270(defconst tramp-prefix-domain-regexp
1271 (regexp-quote tramp-prefix-domain-format)
1272 "*Regexp matching delimeter between user and domain names.
1273Derived from `tramp-prefix-domain-format'.")
1274
1275(defconst tramp-domain-regexp
70c11b0b 1276 "[-a-zA-Z0-9_.]+"
b96e6899
MA
1277 "*Regexp matching domain names.")
1278
1279(defconst tramp-user-with-domain-regexp
1280 (concat "\\(" tramp-user-regexp "\\)"
1281 tramp-prefix-domain-regexp
1282 "\\(" tramp-domain-regexp "\\)")
1283 "*Regexp matching user names with domain names.")
1284
00d6fd04 1285(defconst tramp-postfix-user-format
16674e4f
KG
1286 "@"
1287 "*String matching delimeter between user and host names.
00d6fd04 1288Used in `tramp-make-tramp-file-name'.")
16674e4f 1289
00d6fd04 1290(defconst tramp-postfix-user-regexp
16674e4f
KG
1291 (regexp-quote tramp-postfix-user-format)
1292 "*Regexp matching delimeter between user and host names.
00d6fd04
MA
1293Derived from `tramp-postfix-user-format'.")
1294
1295(defconst tramp-host-regexp
1296 "[a-zA-Z0-9_.-]+"
1297 "*Regexp matching host names.")
1298
b96e6899
MA
1299(defconst tramp-prefix-ipv6-format
1300 (cond ((equal tramp-syntax 'ftp) "[")
1301 ((equal tramp-syntax 'sep) "")
1302 ((equal tramp-syntax 'url) "[")
1303 (t (error "Wrong `tramp-syntax' defined")))
1304 "*String matching left hand side of IPv6 addresses.
1305Used in `tramp-make-tramp-file-name'.")
1306
1307(defconst tramp-prefix-ipv6-regexp
1308 (regexp-quote tramp-prefix-ipv6-format)
1309 "*Regexp matching left hand side of IPv6 addresses.
1310Derived from `tramp-prefix-ipv6-format'.")
1311
e0b6e3b9
MA
1312;; The following regexp is a bit sloppy. But it shall serve our
1313;; purposes. It covers also IPv4 mapped IPv6 addresses, like in
1314;; "::ffff:192.168.0.1".
b96e6899 1315(defconst tramp-ipv6-regexp
e0b6e3b9 1316 "\\(?:\\(?:[a-zA-Z0-9]+\\)?:\\)+[a-zA-Z0-9.]+"
b96e6899
MA
1317 "*Regexp matching IPv6 addresses.")
1318
1319(defconst tramp-postfix-ipv6-format
1320 (cond ((equal tramp-syntax 'ftp) "]")
1321 ((equal tramp-syntax 'sep) "")
1322 ((equal tramp-syntax 'url) "]")
1323 (t (error "Wrong `tramp-syntax' defined")))
1324 "*String matching right hand side of IPv6 addresses.
1325Used in `tramp-make-tramp-file-name'.")
1326
1327(defconst tramp-postfix-ipv6-regexp
1328 (regexp-quote tramp-postfix-ipv6-format)
1329 "*Regexp matching right hand side of IPv6 addresses.
1330Derived from `tramp-postfix-ipv6-format'.")
1331
00d6fd04
MA
1332(defconst tramp-prefix-port-format
1333 (cond ((equal tramp-syntax 'ftp) "#")
1334 ((equal tramp-syntax 'sep) "#")
1335 ((equal tramp-syntax 'url) ":")
1336 (t (error "Wrong `tramp-syntax' defined")))
1337 "*String matching delimeter between host names and port numbers.")
1338
1339(defconst tramp-prefix-port-regexp
1340 (regexp-quote tramp-prefix-port-format)
1341 "*Regexp matching delimeter between host names and port numbers.
1342Derived from `tramp-prefix-port-format'.")
1343
1344(defconst tramp-port-regexp
1345 "[0-9]+"
1346 "*Regexp matching port numbers.")
1347
1348(defconst tramp-host-with-port-regexp
1349 (concat "\\(" tramp-host-regexp "\\)"
1350 tramp-prefix-port-regexp
1351 "\\(" tramp-port-regexp "\\)")
1352 "*Regexp matching host names with port numbers.")
1353
1354(defconst tramp-postfix-host-format
1355 (cond ((equal tramp-syntax 'ftp) ":")
1356 ((equal tramp-syntax 'sep) "]")
1357 ((equal tramp-syntax 'url) "")
1358 (t (error "Wrong `tramp-syntax' defined")))
7432277c 1359 "*String matching delimeter between host names and localnames.
00d6fd04 1360Used in `tramp-make-tramp-file-name'.")
16674e4f 1361
00d6fd04 1362(defconst tramp-postfix-host-regexp
16674e4f 1363 (regexp-quote tramp-postfix-host-format)
7432277c 1364 "*Regexp matching delimeter between host names and localnames.
00d6fd04 1365Derived from `tramp-postfix-host-format'.")
16674e4f 1366
00d6fd04 1367(defconst tramp-localname-regexp
16674e4f 1368 ".*$"
00d6fd04 1369 "*Regexp matching localnames.")
16674e4f
KG
1370
1371;; File name format.
505edaeb 1372
00d6fd04 1373(defconst tramp-file-name-structure
16674e4f
KG
1374 (list
1375 (concat
1376 tramp-prefix-regexp
00d6fd04
MA
1377 "\\(" "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp "\\)?"
1378 "\\(" "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp "\\)?"
b96e6899
MA
1379 "\\(" "\\(" tramp-host-regexp
1380 "\\|"
1381 tramp-prefix-ipv6-regexp tramp-ipv6-regexp
1382 tramp-postfix-ipv6-regexp "\\)"
1383 "\\(" tramp-prefix-port-regexp tramp-port-regexp "\\)?" "\\)?"
00d6fd04
MA
1384 tramp-postfix-host-regexp
1385 "\\(" tramp-localname-regexp "\\)")
b96e6899 1386 2 4 5 8)
16674e4f 1387
fb7933a3 1388 "*List of five elements (REGEXP METHOD USER HOST FILE), detailing \
a4aeb9a4 1389the Tramp file name structure.
fb7933a3 1390
a4aeb9a4 1391The first element REGEXP is a regular expression matching a Tramp file
fb7933a3
KG
1392name. The regex should contain parentheses around the method name,
1393the user name, the host name, and the file name parts.
1394
1395The second element METHOD is a number, saying which pair of
1396parentheses matches the method name. The third element USER is
1397similar, but for the user name. The fourth element HOST is similar,
1398but for the host name. The fifth element FILE is for the file name.
1399These numbers are passed directly to `match-string', which see. That
1400means the opening parentheses are counted to identify the pair.
1401
00d6fd04 1402See also `tramp-file-name-regexp'.")
fb7933a3
KG
1403
1404;;;###autoload
505edaeb 1405(defconst tramp-file-name-regexp-unified
b96e6899 1406 "\\`/\\([^[/:]+\\|[^/]+]\\):"
505edaeb
KG
1407 "Value for `tramp-file-name-regexp' for unified remoting.
1408Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and
00d6fd04 1409Tramp. See `tramp-file-name-structure' for more explanations.")
505edaeb
KG
1410
1411;;;###autoload
1412(defconst tramp-file-name-regexp-separate
1413 "\\`/\\[.*\\]"
1414 "Value for `tramp-file-name-regexp' for separate remoting.
1415XEmacs uses a separate filename syntax for Tramp and EFS.
00d6fd04 1416See `tramp-file-name-structure' for more explanations.")
505edaeb
KG
1417
1418;;;###autoload
00d6fd04
MA
1419(defconst tramp-file-name-regexp-url
1420 "\\`/[^/:]+://"
1421 "Value for `tramp-file-name-regexp' for URL-like remoting.
1422See `tramp-file-name-structure' for more explanations.")
1423
1424;;;###autoload
1425(defconst tramp-file-name-regexp
1426 (cond ((equal tramp-syntax 'ftp) tramp-file-name-regexp-unified)
1427 ((equal tramp-syntax 'sep) tramp-file-name-regexp-separate)
1428 ((equal tramp-syntax 'url) tramp-file-name-regexp-url)
1429 (t (error "Wrong `tramp-syntax' defined")))
94be87e8 1430 "*Regular expression matching file names handled by Tramp.
a4aeb9a4 1431This regexp should match Tramp file names but no other file names.
fb7933a3
KG
1432\(When tramp.el is loaded, this regular expression is prepended to
1433`file-name-handler-alist', and that is searched sequentially. Thus,
a4aeb9a4
MA
1434if the Tramp entry appears rather early in the `file-name-handler-alist'
1435and is a bit too general, then some files might be considered Tramp
00d6fd04 1436files which are not really Tramp files.
fb7933a3
KG
1437
1438Please note that the entry in `file-name-handler-alist' is made when
1439this file (tramp.el) is loaded. This means that this variable must be set
1440before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1441updated after changing this variable.
1442
00d6fd04 1443Also see `tramp-file-name-structure'.")
fb7933a3 1444
16674e4f 1445;;;###autoload
8a798e41 1446(defconst tramp-root-regexp
00d6fd04 1447 (if (memq system-type '(cygwin windows-nt))
aa485f7c
MA
1448 "\\`\\([a-zA-Z]:\\)?/"
1449 "\\`/")
8a798e41 1450 "Beginning of an incomplete Tramp file name.
aa485f7c 1451Usually, it is just \"\\\\`/\". On W32 systems, there might be a
57671b72 1452volume letter, which will be removed by `tramp-drop-volume-letter'.")
8a798e41
MA
1453
1454;;;###autoload
1455(defconst tramp-completion-file-name-regexp-unified
aa485f7c 1456 (concat tramp-root-regexp "[^/]*\\'")
16674e4f 1457 "Value for `tramp-completion-file-name-regexp' for unified remoting.
8a798e41
MA
1458GNU Emacs uses a unified filename syntax for Tramp and Ange-FTP.
1459See `tramp-file-name-structure' for more explanations.")
fb7933a3 1460
16674e4f
KG
1461;;;###autoload
1462(defconst tramp-completion-file-name-regexp-separate
aa485f7c 1463 (concat tramp-root-regexp "\\([[][^]]*\\)?\\'")
16674e4f
KG
1464 "Value for `tramp-completion-file-name-regexp' for separate remoting.
1465XEmacs uses a separate filename syntax for Tramp and EFS.
00d6fd04 1466See `tramp-file-name-structure' for more explanations.")
fb7933a3 1467
16674e4f 1468;;;###autoload
00d6fd04 1469(defconst tramp-completion-file-name-regexp-url
aa485f7c 1470 (concat tramp-root-regexp "[^/:]+\\(:\\(/\\(/[^/]*\\)?\\)?\\)?\\'")
00d6fd04
MA
1471 "Value for `tramp-completion-file-name-regexp' for URL-like remoting.
1472See `tramp-file-name-structure' for more explanations.")
1473
1474;;;###autoload
1475(defconst tramp-completion-file-name-regexp
1476 (cond ((equal tramp-syntax 'ftp) tramp-completion-file-name-regexp-unified)
1477 ((equal tramp-syntax 'sep) tramp-completion-file-name-regexp-separate)
1478 ((equal tramp-syntax 'url) tramp-completion-file-name-regexp-url)
1479 (t (error "Wrong `tramp-syntax' defined")))
a4aeb9a4
MA
1480 "*Regular expression matching file names handled by Tramp completion.
1481This regexp should match partial Tramp file names only.
16674e4f
KG
1482
1483Please note that the entry in `file-name-handler-alist' is made when
1484this file (tramp.el) is loaded. This means that this variable must be set
1485before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1486updated after changing this variable.
1487
00d6fd04 1488Also see `tramp-file-name-structure'.")
fb7933a3 1489
00d6fd04
MA
1490(defconst tramp-actions-before-shell
1491 '((tramp-login-prompt-regexp tramp-action-login)
1492 (tramp-password-prompt-regexp tramp-action-password)
1493 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
ac474af1 1494 (shell-prompt-pattern tramp-action-succeed)
821e6e36 1495 (tramp-shell-prompt-pattern tramp-action-succeed)
3cdaec13 1496 (tramp-yesno-prompt-regexp tramp-action-yesno)
487f4fb7 1497 (tramp-yn-prompt-regexp tramp-action-yn)
19a87064
MA
1498 (tramp-terminal-prompt-regexp tramp-action-terminal)
1499 (tramp-process-alive-regexp tramp-action-process-alive))
ac474af1
KG
1500 "List of pattern/action pairs.
1501Whenever a pattern matches, the corresponding action is performed.
1502Each item looks like (PATTERN ACTION).
1503
1504The PATTERN should be a symbol, a variable. The value of this
1505variable gives the regular expression to search for. Note that the
1506regexp must match at the end of the buffer, \"\\'\" is implicitly
1507appended to it.
1508
1509The ACTION should also be a symbol, but a function. When the
00d6fd04 1510corresponding PATTERN matches, the ACTION function is called.")
ac474af1 1511
00d6fd04 1512(defconst tramp-actions-copy-out-of-band
38c65fca
KG
1513 '((tramp-password-prompt-regexp tramp-action-password)
1514 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
00d6fd04 1515 (tramp-copy-failed-regexp tramp-action-permission-denied)
19a87064 1516 (tramp-process-alive-regexp tramp-action-out-of-band))
38c65fca
KG
1517 "List of pattern/action pairs.
1518This list is used for copying/renaming with out-of-band methods.
90f8dc03 1519
00d6fd04
MA
1520See `tramp-actions-before-shell' for more info.")
1521
1522;; Chunked sending kludge. We set this to 500 for black-listed constellations
7432277c 1523;; known to have a bug in `process-send-string'; some ssh connections appear
7177e2a3
MA
1524;; to drop bytes when data is sent too quickly. There is also a connection
1525;; buffer local variable, which is computed depending on remote host properties
1526;; when `tramp-chunksize' is zero or nil.
7432277c
KG
1527(defcustom tramp-chunksize
1528 (when (and (not (featurep 'xemacs))
1529 (memq system-type '(hpux)))
1530 500)
55880756
MA
1531;; Parentheses in docstring starting at beginning of line are escaped.
1532;; Fontification is messed up when
1533;; `open-paren-in-column-0-is-defun-start' set to t.
7432277c
KG
1534 "*If non-nil, chunksize for sending input to local process.
1535It is necessary only on systems which have a buggy `process-send-string'
1536implementation. The necessity, whether this variable must be set, can be
1537checked via the following code:
1538
1539 (with-temp-buffer
11948172
MA
1540 (let* ((user \"xxx\") (host \"yyy\")
1541 (init 0) (step 50)
1542 (sent init) (received init))
1543 (while (= sent received)
1544 (setq sent (+ sent step))
1545 (erase-buffer)
1546 (let ((proc (start-process (buffer-name) (current-buffer)
1547 \"ssh\" \"-l\" user host \"wc\" \"-c\")))
1548 (when (memq (process-status proc) '(run open))
1549 (process-send-string proc (make-string sent ?\\ ))
1550 (process-send-eof proc)
1551 (process-send-eof proc))
1552 (while (not (progn (goto-char (point-min))
1553 (re-search-forward \"\\\\w+\" (point-max) t)))
1554 (accept-process-output proc 1))
1555 (when (memq (process-status proc) '(run open))
1556 (setq received (string-to-number (match-string 0)))
1557 (delete-process proc)
1558 (message \"Bytes sent: %s\\tBytes received: %s\" sent received)
1559 (sit-for 0))))
1560 (if (> sent (+ init step))
1561 (message \"You should set `tramp-chunksize' to a maximum of %s\"
1562 (- sent step))
1563 (message \"Test does not work\")
1564 (display-buffer (current-buffer))
1565 (sit-for 30))))
1566
1567In the Emacs normally running Tramp, evaluate the above code
55880756 1568\(replace \"xxx\" and \"yyy\" by the remote user and host name,
11948172
MA
1569respectively). You can do this, for example, by pasting it into
1570the `*scratch*' buffer and then hitting C-j with the cursor after the
1571last closing parenthesis. Note that it works only if you have configured
1572\"ssh\" to run without password query, see ssh-agent(1).
1573
1574You will see the number of bytes sent successfully to the remote host.
1575If that number exceeds 1000, you can stop the execution by hitting
1576C-g, because your Emacs is likely clean.
1577
11948172
MA
1578When it is necessary to set `tramp-chunksize', you might consider to
1579use an out-of-the-band method (like \"scp\") instead of an internal one
55880756 1580\(like \"ssh\"), because setting `tramp-chunksize' to non-nil decreases
11948172 1581performance.
c951aecb 1582
00d6fd04
MA
1583If your Emacs is buggy, the code stops and gives you an indication
1584about the value `tramp-chunksize' should be set. Maybe you could just
1585experiment a bit, e.g. changing the values of `init' and `step'
1586in the third line of the code.
1587
7432277c
KG
1588Please raise a bug report via \"M-x tramp-bug\" if your system needs
1589this variable to be set as well."
1590 :group 'tramp
b1a2b924 1591 :type '(choice (const nil) integer))
7432277c 1592
5ec2cc41
KG
1593;; Logging in to a remote host normally requires obtaining a pty. But
1594;; Emacs on MacOS X has process-connection-type set to nil by default,
1595;; so on those systems Tramp doesn't obtain a pty. Here, we allow
1596;; for an override of the system default.
1597(defcustom tramp-process-connection-type t
1598 "Overrides `process-connection-type' for connections from Tramp.
1599Tramp binds process-connection-type to the value given here before
1600opening a connection to a remote host."
1601 :group 'tramp
1602 :type '(choice (const nil) (const t) (const pty)))
1603
b50dd0d2
MA
1604(defcustom tramp-completion-reread-directory-timeout 10
1605 "Defines seconds since last remote command before rereading a directory.
1606A remote directory might have changed its contents. In order to
1607make it visible during file name completion in the minibuffer,
1608Tramp flushes its cache and rereads the directory contents when
1609more than `tramp-completion-reread-directory-timeout' seconds
1610have been gone since last remote command execution. A value of 0
1611would require an immediate reread during filename completion, nil
1612means to use always cached values for the directory contents."
1613 :group 'tramp
1614 :type '(choice (const nil) integer))
1615
fb7933a3
KG
1616;;; Internal Variables:
1617
fb7933a3 1618(defvar tramp-current-method nil
00d6fd04 1619 "Connection method for this *tramp* buffer.")
fb7933a3
KG
1620
1621(defvar tramp-current-user nil
00d6fd04 1622 "Remote login name for this *tramp* buffer.")
fb7933a3
KG
1623
1624(defvar tramp-current-host nil
00d6fd04
MA
1625 "Remote host for this *tramp* buffer.")
1626
1627(defconst tramp-uudecode
1628 "(echo begin 600 /tmp/tramp.$$; tail +2) | uudecode
fabf2143 1629cat /tmp/tramp.$$
00d6fd04 1630rm -f /tmp/tramp.$$"
fabf2143 1631 "Shell function to implement `uudecode' to standard output.
c08e6004
MA
1632Many systems support `uudecode -o /dev/stdout' or `uudecode -o -'
1633for this or `uudecode -p', but some systems don't, and for them
1634we have this shell function.")
fabf2143 1635
293c24f9
MA
1636(defconst tramp-perl-file-truename
1637 "%s -e '
1638use File::Spec;
1639use Cwd \"realpath\";
1640
1641sub recursive {
1642 my ($volume, @dirs) = @_;
1643 my $real = realpath(File::Spec->catpath(
1644 $volume, File::Spec->catdir(@dirs), \"\"));
1645 if ($real) {
1646 my ($vol, $dir) = File::Spec->splitpath($real, 1);
1647 return ($vol, File::Spec->splitdir($dir));
1648 }
1649 else {
1650 my $last = pop(@dirs);
1651 ($volume, @dirs) = recursive($volume, @dirs);
1652 push(@dirs, $last);
1653 return ($volume, @dirs);
1654 }
1655}
1656
1657$result = realpath($ARGV[0]);
1658if (!$result) {
1659 my ($vol, $dir) = File::Spec->splitpath($ARGV[0], 1);
1660 ($vol, @dirs) = recursive($vol, File::Spec->splitdir($dir));
1661
1662 $result = File::Spec->catpath($vol, File::Spec->catdir(@dirs), \"\");
1663}
1664
1665if ($ARGV[0] =~ /\\/$/) {
1666 $result = $result . \"/\";
1667}
1668
1669print \"\\\"$result\\\"\\n\";
1670' \"$1\" 2>/dev/null"
1671 "Perl script to produce output suitable for use with `file-truename'
1672on the remote file system.
1673Escape sequence %s is replaced with name of Perl binary.
1674This string is passed to `format', so percent characters need to be doubled.")
1675
1676(defconst tramp-perl-file-name-all-completions
1677 "%s -e 'sub case {
1678 my $str = shift;
1679 if ($ARGV[2]) {
1680 return lc($str);
1681 }
1682 else {
1683 return $str;
1684 }
1685}
1686opendir(d, $ARGV[0]) || die(\"$ARGV[0]: $!\\nfail\\n\");
1687@files = readdir(d); closedir(d);
1688foreach $f (@files) {
1689 if (case(substr($f, 0, length($ARGV[1]))) eq case($ARGV[1])) {
1690 if (-d \"$ARGV[0]/$f\") {
1691 print \"$f/\\n\";
1692 }
1693 else {
1694 print \"$f\\n\";
1695 }
1696 }
1697}
1698print \"ok\\n\"
1699' \"$1\" \"$2\" \"$3\" 2>/dev/null"
1700 "Perl script to produce output suitable for use with
1701`file-name-all-completions' on the remote file system. Escape
1702sequence %s is replaced with name of Perl binary. This string is
1703passed to `format', so percent characters need to be doubled.")
1704
fabf2143
KG
1705;; Perl script to implement `file-attributes' in a Lisp `read'able
1706;; output. If you are hacking on this, note that you get *no* output
1707;; unless this spits out a complete line, including the '\n' at the
1708;; end.
8daea7fc 1709;; The device number is returned as "-1", because there will be a virtual
b946a456 1710;; device number set in `tramp-handle-file-attributes'.
00d6fd04
MA
1711(defconst tramp-perl-file-attributes
1712 "%s -e '
c82c5727 1713@stat = lstat($ARGV[0]);
680db9ac
MA
1714if (!@stat) {
1715 print \"nil\\n\";
1716 exit 0;
1717}
c82c5727
LH
1718if (($stat[2] & 0170000) == 0120000)
1719{
1720 $type = readlink($ARGV[0]);
1721 $type = \"\\\"$type\\\"\";
1722}
1723elsif (($stat[2] & 0170000) == 040000)
1724{
1725 $type = \"t\";
1726}
1727else
1728{
1729 $type = \"nil\"
1730};
1731$uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
1732$gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
1733printf(
d4443a0d 1734 \"(%%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) -1)\\n\",
c82c5727
LH
1735 $type,
1736 $stat[3],
1737 $uid,
1738 $gid,
1739 $stat[8] >> 16 & 0xffff,
1740 $stat[8] & 0xffff,
1741 $stat[9] >> 16 & 0xffff,
1742 $stat[9] & 0xffff,
1743 $stat[10] >> 16 & 0xffff,
1744 $stat[10] & 0xffff,
1745 $stat[7],
1746 $stat[2],
1747 $stat[1] >> 16 & 0xffff,
1748 $stat[1] & 0xffff
00d6fd04 1749);' \"$1\" \"$2\" \"$3\" 2>/dev/null"
fb7933a3 1750 "Perl script to produce output suitable for use with `file-attributes'
00d6fd04
MA
1751on the remote file system.
1752Escape sequence %s is replaced with name of Perl binary.
1753This string is passed to `format', so percent characters need to be doubled.")
fb7933a3 1754
00d6fd04
MA
1755(defconst tramp-perl-directory-files-and-attributes
1756 "%s -e '
8cb0a559
LH
1757chdir($ARGV[0]) or printf(\"\\\"Cannot change to $ARGV[0]: $''!''\\\"\\n\"), exit();
1758opendir(DIR,\".\") or printf(\"\\\"Cannot open directory $ARGV[0]: $''!''\\\"\\n\"), exit();
c82c5727
LH
1759@list = readdir(DIR);
1760closedir(DIR);
1761$n = scalar(@list);
1762printf(\"(\\n\");
1763for($i = 0; $i < $n; $i++)
1764{
1765 $filename = $list[$i];
1766 @stat = lstat($filename);
1767 if (($stat[2] & 0170000) == 0120000)
1768 {
1769 $type = readlink($filename);
1770 $type = \"\\\"$type\\\"\";
1771 }
1772 elsif (($stat[2] & 0170000) == 040000)
1773 {
1774 $type = \"t\";
1775 }
1776 else
1777 {
1778 $type = \"nil\"
1779 };
1780 $uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
1781 $gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
1782 printf(
b946a456 1783 \"(\\\"%%s\\\" %%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) (%%u . %%u))\\n\",
c82c5727
LH
1784 $filename,
1785 $type,
1786 $stat[3],
1787 $uid,
1788 $gid,
1789 $stat[8] >> 16 & 0xffff,
1790 $stat[8] & 0xffff,
1791 $stat[9] >> 16 & 0xffff,
1792 $stat[9] & 0xffff,
1793 $stat[10] >> 16 & 0xffff,
1794 $stat[10] & 0xffff,
1795 $stat[7],
1796 $stat[2],
1797 $stat[1] >> 16 & 0xffff,
1798 $stat[1] & 0xffff,
1799 $stat[0] >> 16 & 0xffff,
1800 $stat[0] & 0xffff);
1801}
00d6fd04 1802printf(\")\\n\");' \"$1\" \"$2\" \"$3\" 2>/dev/null"
c82c5727 1803 "Perl script implementing `directory-files-attributes' as Lisp `read'able
00d6fd04
MA
1804output.
1805Escape sequence %s is replaced with name of Perl binary.
1806This string is passed to `format', so percent characters need to be doubled.")
c82c5727 1807
ac474af1
KG
1808;; ;; These two use uu encoding.
1809;; (defvar tramp-perl-encode "%s -e'\
1810;; print qq(begin 644 xxx\n);
1811;; my $s = q();
1812;; my $res = q();
1813;; while (read(STDIN, $s, 45)) {
1814;; print pack(q(u), $s);
1815;; }
1816;; print qq(`\n);
1817;; print qq(end\n);
1818;; '"
1819;; "Perl program to use for encoding a file.
1820;; Escape sequence %s is replaced with name of Perl binary.")
1821
1822;; (defvar tramp-perl-decode "%s -ne '
1823;; print unpack q(u), $_;
1824;; '"
1825;; "Perl program to use for decoding a file.
1826;; Escape sequence %s is replaced with name of Perl binary.")
1827
1828;; These two use base64 encoding.
00d6fd04
MA
1829(defconst tramp-perl-encode-with-module
1830 "%s -MMIME::Base64 -0777 -ne 'print encode_base64($_)' 2>/dev/null"
ac474af1 1831 "Perl program to use for encoding a file.
b1d06e75 1832Escape sequence %s is replaced with name of Perl binary.
89509ea0 1833This string is passed to `format', so percent characters need to be doubled.
b1d06e75
KG
1834This implementation requires the MIME::Base64 Perl module to be installed
1835on the remote host.")
1836
00d6fd04
MA
1837(defconst tramp-perl-decode-with-module
1838 "%s -MMIME::Base64 -0777 -ne 'print decode_base64($_)' 2>/dev/null"
b1d06e75
KG
1839 "Perl program to use for decoding a file.
1840Escape sequence %s is replaced with name of Perl binary.
89509ea0 1841This string is passed to `format', so percent characters need to be doubled.
b1d06e75
KG
1842This implementation requires the MIME::Base64 Perl module to be installed
1843on the remote host.")
1844
00d6fd04 1845(defconst tramp-perl-encode
b1d06e75
KG
1846 "%s -e '
1847# This script contributed by Juanma Barranquero <lektu@terra.es>.
114f9c96 1848# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
cbd12ed7 1849# Free Software Foundation, Inc.
b1d06e75
KG
1850use strict;
1851
fa32e96a 1852my %%trans = do {
b1d06e75
KG
1853 my $i = 0;
1854 map {(substr(unpack(q(B8), chr $i++), 2, 6), $_)}
1855 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/);
1856};
1857
36541701 1858binmode(\\*STDIN);
b1d06e75
KG
1859
1860# We read in chunks of 54 bytes, to generate output lines
1861# of 72 chars (plus end of line)
36541701 1862$/ = \\54;
b1d06e75
KG
1863
1864while (my $data = <STDIN>) {
1865 my $pad = q();
1866
1867 # Only for the last chunk, and only if did not fill the last three-byte packet
1868 if (eof) {
fa32e96a 1869 my $mod = length($data) %% 3;
b1d06e75
KG
1870 $pad = q(=) x (3 - $mod) if $mod;
1871 }
1872
1873 # Not the fastest method, but it is simple: unpack to binary string, split
1874 # by groups of 6 bits and convert back from binary to byte; then map into
1875 # the translation table
1876 print
1877 join q(),
1878 map($trans{$_},
1879 (substr(unpack(q(B*), $data) . q(00000), 0, 432) =~ /....../g)),
1880 $pad,
36541701 1881 qq(\\n);
00d6fd04 1882}' 2>/dev/null"
b1d06e75 1883 "Perl program to use for encoding a file.
fa32e96a 1884Escape sequence %s is replaced with name of Perl binary.
ccf29586 1885This string is passed to `format', so percent characters need to be doubled.")
ac474af1 1886
00d6fd04 1887(defconst tramp-perl-decode
b1d06e75
KG
1888 "%s -e '
1889# This script contributed by Juanma Barranquero <lektu@terra.es>.
114f9c96 1890# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
cbd12ed7 1891# Free Software Foundation, Inc.
b1d06e75
KG
1892use strict;
1893
fa32e96a 1894my %%trans = do {
b1d06e75 1895 my $i = 0;
16674e4f 1896 map {($_, substr(unpack(q(B8), chr $i++), 2, 6))}
b1d06e75
KG
1897 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/)
1898};
1899
fa32e96a 1900my %%bytes = map {(unpack(q(B8), chr $_), chr $_)} 0 .. 255;
b1d06e75 1901
36541701 1902binmode(\\*STDOUT);
b1d06e75
KG
1903
1904# We are going to accumulate into $pending to accept any line length
1905# (we do not check they are <= 76 chars as the RFC says)
1906my $pending = q();
1907
1908while (my $data = <STDIN>) {
1909 chomp $data;
1910
1911 # If we find one or two =, we have reached the end and
1912 # any following data is to be discarded
1913 my $finished = $data =~ s/(==?).*/$1/;
1914 $pending .= $data;
1915
1916 my $len = length($pending);
16674e4f 1917 my $chunk = substr($pending, 0, $len & ~3);
414da5ab 1918 $pending = substr($pending, $len & ~3 + 1);
b1d06e75
KG
1919
1920 # Easy method: translate from chars to (pregenerated) six-bit packets, join,
1921 # split in 8-bit chunks and convert back to char.
1922 print join q(),
1923 map $bytes{$_},
1924 ((join q(), map {$trans{$_} || q()} split //, $chunk) =~ /......../g);
1925
1926 last if $finished;
00d6fd04 1927}' 2>/dev/null"
ac474af1 1928 "Perl program to use for decoding a file.
fa32e96a 1929Escape sequence %s is replaced with name of Perl binary.
ccf29586 1930This string is passed to `format', so percent characters need to be doubled.")
fb7933a3 1931
946a5aeb
MA
1932(defconst tramp-vc-registered-read-file-names
1933 "echo \"(\"
1934for file in \"$@\"; do
1935 if %s $file; then
1936 echo \"(\\\"$file\\\" \\\"file-exists-p\\\" t)\"
1937 else
1938 echo \"(\\\"$file\\\" \\\"file-exists-p\\\" nil)\"
1939 fi
1940 if %s $file; then
1941 echo \"(\\\"$file\\\" \\\"file-readable-p\\\" t)\"
1942 else
1943 echo \"(\\\"$file\\\" \\\"file-readable-p\\\" nil)\"
1944 fi
1945done
1946echo \")\""
1947 "Script to check existence of VC related files.
1948It must be send formatted with two strings; the tests for file
1949existence, and file readability.")
1950
9ce8462a
MA
1951(defconst tramp-file-mode-type-map
1952 '((0 . "-") ; Normal file (SVID-v2 and XPG2)
1953 (1 . "p") ; fifo
1954 (2 . "c") ; character device
1955 (3 . "m") ; multiplexed character device (v7)
1956 (4 . "d") ; directory
1957 (5 . "?") ; Named special file (XENIX)
1958 (6 . "b") ; block device
1959 (7 . "?") ; multiplexed block device (v7)
1960 (8 . "-") ; regular file
1961 (9 . "n") ; network special file (HP-UX)
1962 (10 . "l") ; symlink
1963 (11 . "?") ; ACL shadow inode (Solaris, not userspace)
1964 (12 . "s") ; socket
1965 (13 . "D") ; door special (Solaris)
1966 (14 . "w")) ; whiteout (BSD)
fb7933a3
KG
1967 "A list of file types returned from the `stat' system call.
1968This is used to map a mode number to a permission string.")
1969
fb7933a3 1970;; New handlers should be added here. The following operations can be
c0fc6170
MA
1971;; handled using the normal primitives: file-name-sans-versions,
1972;; get-file-buffer.
fb7933a3 1973(defconst tramp-file-name-handler-alist
00d6fd04 1974 '((load . tramp-handle-load)
fb7933a3 1975 (make-symbolic-link . tramp-handle-make-symbolic-link)
c0fc6170 1976 (file-name-as-directory . tramp-handle-file-name-as-directory)
fb7933a3
KG
1977 (file-name-directory . tramp-handle-file-name-directory)
1978 (file-name-nondirectory . tramp-handle-file-name-nondirectory)
1979 (file-truename . tramp-handle-file-truename)
1980 (file-exists-p . tramp-handle-file-exists-p)
1981 (file-directory-p . tramp-handle-file-directory-p)
1982 (file-executable-p . tramp-handle-file-executable-p)
fb7933a3
KG
1983 (file-readable-p . tramp-handle-file-readable-p)
1984 (file-regular-p . tramp-handle-file-regular-p)
1985 (file-symlink-p . tramp-handle-file-symlink-p)
1986 (file-writable-p . tramp-handle-file-writable-p)
1987 (file-ownership-preserved-p . tramp-handle-file-ownership-preserved-p)
1988 (file-newer-than-file-p . tramp-handle-file-newer-than-file-p)
1989 (file-attributes . tramp-handle-file-attributes)
1990 (file-modes . tramp-handle-file-modes)
fb7933a3 1991 (directory-files . tramp-handle-directory-files)
c82c5727 1992 (directory-files-and-attributes . tramp-handle-directory-files-and-attributes)
fb7933a3
KG
1993 (file-name-all-completions . tramp-handle-file-name-all-completions)
1994 (file-name-completion . tramp-handle-file-name-completion)
1995 (add-name-to-file . tramp-handle-add-name-to-file)
1996 (copy-file . tramp-handle-copy-file)
263c02ef 1997 (copy-directory . tramp-handle-copy-directory)
fb7933a3
KG
1998 (rename-file . tramp-handle-rename-file)
1999 (set-file-modes . tramp-handle-set-file-modes)
ce3f516f 2000 (set-file-times . tramp-handle-set-file-times)
fb7933a3
KG
2001 (make-directory . tramp-handle-make-directory)
2002 (delete-directory . tramp-handle-delete-directory)
2003 (delete-file . tramp-handle-delete-file)
2004 (directory-file-name . tramp-handle-directory-file-name)
00d6fd04
MA
2005 ;; `executable-find' is not official yet.
2006 (executable-find . tramp-handle-executable-find)
2007 (start-file-process . tramp-handle-start-file-process)
0457dd55 2008 (process-file . tramp-handle-process-file)
00d6fd04 2009 (shell-command . tramp-handle-shell-command)
fb7933a3
KG
2010 (insert-directory . tramp-handle-insert-directory)
2011 (expand-file-name . tramp-handle-expand-file-name)
00d6fd04 2012 (substitute-in-file-name . tramp-handle-substitute-in-file-name)
fb7933a3 2013 (file-local-copy . tramp-handle-file-local-copy)
19a87064 2014 (file-remote-p . tramp-handle-file-remote-p)
fb7933a3 2015 (insert-file-contents . tramp-handle-insert-file-contents)
94be87e8
MA
2016 (insert-file-contents-literally
2017 . tramp-handle-insert-file-contents-literally)
fb7933a3 2018 (write-region . tramp-handle-write-region)
38c65fca 2019 (find-backup-file-name . tramp-handle-find-backup-file-name)
c1105d05 2020 (make-auto-save-file-name . tramp-handle-make-auto-save-file-name)
fb7933a3 2021 (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
5ec2cc41 2022 (dired-compress-file . tramp-handle-dired-compress-file)
fb7933a3
KG
2023 (dired-recursive-delete-directory
2024 . tramp-handle-dired-recursive-delete-directory)
70c11b0b 2025 (dired-uncache . tramp-handle-dired-uncache)
fb7933a3 2026 (set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
49096407
MA
2027 (verify-visited-file-modtime . tramp-handle-verify-visited-file-modtime)
2028 (vc-registered . tramp-handle-vc-registered))
c1105d05 2029 "Alist of handler functions.
fb7933a3
KG
2030Operations not mentioned here will be handled by the normal Emacs functions.")
2031
a4aeb9a4 2032;; Handlers for partial Tramp file names. For Emacs just
41c8e348 2033;; `file-name-all-completions' is needed.
a01b1e22 2034;;;###autoload
16674e4f 2035(defconst tramp-completion-file-name-handler-alist
a01b1e22 2036 '((file-name-all-completions . tramp-completion-handle-file-name-all-completions)
41c8e348 2037 (file-name-completion . tramp-completion-handle-file-name-completion))
16674e4f
KG
2038 "Alist of completion handler functions.
2039Used for file names matching `tramp-file-name-regexp'. Operations not
2040mentioned here will be handled by `tramp-file-name-handler-alist' or the
2041normal Emacs functions.")
2042
4007ba5b 2043;; Handlers for foreign methods, like FTP or SMB, shall be plugged here.
ea9d1443
KG
2044(defvar tramp-foreign-file-name-handler-alist
2045 ;; (identity . tramp-sh-file-name-handler) should always be the last
b88f2d0a 2046 ;; entry, because `identity' always matches.
ea9d1443 2047 '((identity . tramp-sh-file-name-handler))
4007ba5b
KG
2048 "Alist of elements (FUNCTION . HANDLER) for foreign methods handled specially.
2049If (FUNCTION FILENAME) returns non-nil, then all I/O on that file is done by
2050calling HANDLER.")
2051
0664ff72 2052;;; Internal functions which must come first:
fb7933a3 2053
00d6fd04
MA
2054(defsubst tramp-debug-message (vec fmt-string &rest args)
2055 "Append message to debug buffer.
2056Message is formatted with FMT-STRING as control string and the remaining
2057ARGS to actually emit the message (if applicable)."
2058 (when (get-buffer (tramp-buffer-name vec))
2059 (with-current-buffer (tramp-get-debug-buffer vec)
2060 (goto-char (point-max))
70c11b0b
MA
2061 ;; Headline.
2062 (when (bobp)
2063 (insert
2064 (format
2065 ";; %sEmacs: %s Tramp: %s -*- mode: outline; -*-"
2066 (if (featurep 'sxemacs) "SX" (if (featurep 'xemacs) "X" "GNU "))
2067 emacs-version tramp-version)))
00d6fd04
MA
2068 (unless (bolp)
2069 (insert "\n"))
70c11b0b 2070 ;; Timestamp.
736ac90f
MA
2071 (let ((now (current-time)))
2072 (insert (format-time-string "%T." now))
2073 (insert (format "%06d " (nth 2 now))))
70c11b0b 2074 ;; Calling function.
00d6fd04
MA
2075 (let ((btn 1) btf fn)
2076 (while (not fn)
2077 (setq btf (nth 1 (backtrace-frame btn)))
2078 (if (not btf)
2079 (setq fn "")
2080 (when (symbolp btf)
2081 (setq fn (symbol-name btf))
2082 (unless (and (string-match "^tramp" fn)
2083 (not (string-match
2084 "^tramp\\(-debug\\)?\\(-message\\|-error\\)$"
2085 fn)))
2086 (setq fn nil)))
2087 (setq btn (1+ btn))))
2088 ;; The following code inserts filename and line number.
2089 ;; Should be deactivated by default, because it is time
2090 ;; consuming.
2091; (let ((ffn (find-function-noselect (intern fn))))
2092; (insert
2093; (format
2094; "%s:%d: "
2095; (file-name-nondirectory (buffer-file-name (car ffn)))
2096; (with-current-buffer (car ffn)
2097; (1+ (count-lines (point-min) (cdr ffn)))))))
2098 (insert (format "%s " fn)))
70c11b0b 2099 ;; The message.
00d6fd04
MA
2100 (insert (apply 'format fmt-string args)))))
2101
946a5aeb
MA
2102(defvar tramp-message-show-message t
2103 "Show Tramp message in the minibuffer.
2104This variable is used to disable messages from `tramp-error'.
2105The messages are visible anyway, because an error is raised.")
2106
00d6fd04 2107(defsubst tramp-message (vec-or-proc level fmt-string &rest args)
fb7933a3 2108 "Emit a message depending on verbosity level.
a4aeb9a4 2109VEC-OR-PROC identifies the Tramp buffer to use. It can be either a
00d6fd04
MA
2110vector or a process. LEVEL says to be quiet if `tramp-verbose' is
2111less than LEVEL. The message is emitted only if `tramp-verbose' is
2112greater than or equal to LEVEL.
2113
2114The message is also logged into the debug buffer when `tramp-verbose'
2115is greater than or equal 4.
2116
2117Calls functions `message' and `tramp-debug-message' with FMT-STRING as
2118control string and the remaining ARGS to actually emit the message (if
2119applicable)."
2120 (condition-case nil
2121 (when (<= level tramp-verbose)
2122 ;; Match data must be preserved!
2123 (save-match-data
2124 ;; Display only when there is a minimum level.
946a5aeb 2125 (when (and tramp-message-show-message (<= level 3))
00d6fd04
MA
2126 (apply 'message
2127 (concat
2128 (cond
2129 ((= level 0) "")
2130 ((= level 1) "")
2131 ((= level 2) "Warning: ")
2132 (t "Tramp: "))
2133 fmt-string)
2134 args))
2135 ;; Log only when there is a minimum level.
2136 (when (>= tramp-verbose 4)
2137 (when (and vec-or-proc
2138 (processp vec-or-proc)
2139 (buffer-name (process-buffer vec-or-proc)))
2140 (with-current-buffer (process-buffer vec-or-proc)
2141 ;; Translate proc to vec.
2142 (setq vec-or-proc (tramp-dissect-file-name default-directory))))
2143 (when (and vec-or-proc (vectorp vec-or-proc))
2144 (apply 'tramp-debug-message
2145 vec-or-proc
2146 (concat (format "(%d) # " level) fmt-string)
2147 args)))))
2148 ;; Suppress all errors.
2149 (error nil)))
2150
2151(defsubst tramp-error (vec-or-proc signal fmt-string &rest args)
2152 "Emit an error.
2153VEC-OR-PROC identifies the connection to use, SIGNAL is the
2154signal identifier to be raised, remaining args passed to
2155`tramp-message'. Finally, signal SIGNAL is raised."
946a5aeb
MA
2156 (let (tramp-message-show-message)
2157 (tramp-message
2158 vec-or-proc 1 "%s"
2159 (error-message-string
2160 (list signal
2161 (get signal 'error-message)
2162 (apply 'format fmt-string args))))
2163 (signal signal (list (apply 'format fmt-string args)))))
00d6fd04
MA
2164
2165(defsubst tramp-error-with-buffer
2166 (buffer vec-or-proc signal fmt-string &rest args)
2167 "Emit an error, and show BUFFER.
2168If BUFFER is nil, show the connection buffer. Wait for 30\", or until
2169an input event arrives. The other arguments are passed to `tramp-error'."
2170 (save-window-excursion
2171 (unwind-protect
2172 (apply 'tramp-error vec-or-proc signal fmt-string args)
2173 (when (and vec-or-proc (not (zerop tramp-verbose)))
2174 (let ((enable-recursive-minibuffers t))
2175 (pop-to-buffer
2176 (or (and (bufferp buffer) buffer)
2177 (and (processp vec-or-proc) (process-buffer vec-or-proc))
2178 (tramp-get-buffer vec-or-proc)))
2179 (sit-for 30))))))
fb7933a3 2180
c62c9d08
KG
2181(defmacro with-parsed-tramp-file-name (filename var &rest body)
2182 "Parse a Tramp filename and make components available in the body.
2183
2184First arg FILENAME is evaluated and dissected into its components.
2185Second arg VAR is a symbol. It is used as a variable name to hold
2186the filename structure. It is also used as a prefix for the variables
2187holding the components. For example, if VAR is the symbol `foo', then
00d6fd04
MA
2188`foo' will be bound to the whole structure, `foo-method' will be bound to
2189the method component, and so on for `foo-user', `foo-host', `foo-localname'.
c62c9d08
KG
2190
2191Remaining args are Lisp expressions to be evaluated (inside an implicit
2192`progn').
2193
00d6fd04
MA
2194If VAR is nil, then we bind `v' to the structure and `method', `user',
2195`host', `localname' to the components."
c62c9d08 2196 `(let* ((,(or var 'v) (tramp-dissect-file-name ,filename))
c62c9d08
KG
2197 (,(if var (intern (concat (symbol-name var) "-method")) 'method)
2198 (tramp-file-name-method ,(or var 'v)))
2199 (,(if var (intern (concat (symbol-name var) "-user")) 'user)
2200 (tramp-file-name-user ,(or var 'v)))
2201 (,(if var (intern (concat (symbol-name var) "-host")) 'host)
2202 (tramp-file-name-host ,(or var 'v)))
7432277c
KG
2203 (,(if var (intern (concat (symbol-name var) "-localname")) 'localname)
2204 (tramp-file-name-localname ,(or var 'v))))
c62c9d08
KG
2205 ,@body))
2206
2207(put 'with-parsed-tramp-file-name 'lisp-indent-function 2)
00d6fd04 2208(put 'with-parsed-tramp-file-name 'edebug-form-spec '(form symbolp body))
9e6ab520 2209(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-parsed-tramp-file-name\\>"))
c62c9d08 2210
00d6fd04
MA
2211(defmacro with-file-property (vec file property &rest body)
2212 "Check in Tramp cache for PROPERTY, otherwise execute BODY and set cache.
2213FILE must be a local file name on a connection identified via VEC."
2214 `(if (file-name-absolute-p ,file)
2215 (let ((value (tramp-get-file-property ,vec ,file ,property 'undef)))
2216 (when (eq value 'undef)
2217 ;; We cannot pass @body as parameter to
2218 ;; `tramp-set-file-property' because it mangles our
2219 ;; debug messages.
2220 (setq value (progn ,@body))
2221 (tramp-set-file-property ,vec ,file ,property value))
2222 value)
2223 ,@body))
9ce8462a 2224
00d6fd04
MA
2225(put 'with-file-property 'lisp-indent-function 3)
2226(put 'with-file-property 'edebug-form-spec t)
9e6ab520 2227(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-file-property\\>"))
00d6fd04
MA
2228
2229(defmacro with-connection-property (key property &rest body)
2230 "Checks in Tramp for property PROPERTY, otherwise executes BODY and set."
2231 `(let ((value (tramp-get-connection-property ,key ,property 'undef)))
2232 (when (eq value 'undef)
2233 ;; We cannot pass ,@body as parameter to
2234 ;; `tramp-set-connection-property' because it mangles our debug
2235 ;; messages.
2236 (setq value (progn ,@body))
2237 (tramp-set-connection-property ,key ,property value))
2238 value))
9ce8462a 2239
00d6fd04
MA
2240(put 'with-connection-property 'lisp-indent-function 2)
2241(put 'with-connection-property 'edebug-form-spec t)
9e6ab520 2242(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-connection-property\\>"))
00d6fd04 2243
628c97b2
GM
2244(eval-and-compile ; silence compiler
2245 (if (memq system-type '(cygwin windows-nt))
2246 (defun tramp-drop-volume-letter (name)
2247 "Cut off unnecessary drive letter from file NAME.
2248The function `tramp-handle-expand-file-name' calls `expand-file-name'
2249locally on a remote file name. When the local system is a W32 system
2250but the remote system is Unix, this introduces a superfluous drive
2251letter into the file name. This function removes it."
2252 (save-match-data
2253 (if (string-match tramp-root-regexp name)
2254 (replace-match "/" nil t name)
2255 name)))
2256
2257 (defalias 'tramp-drop-volume-letter 'identity)))
2258
9c13938d 2259(defsubst tramp-make-tramp-temp-file (vec)
a6e96327 2260 "Create a temporary file on the remote host identified by VEC.
9c13938d
MA
2261Return the local name of the temporary file."
2262 (let ((prefix
2263 (tramp-make-tramp-file-name
2264 (tramp-file-name-method vec)
2265 (tramp-file-name-user vec)
2266 (tramp-file-name-host vec)
113e2a84
MA
2267 (tramp-drop-volume-letter
2268 (expand-file-name
2269 tramp-temp-name-prefix (tramp-get-remote-tmpdir vec)))))
9c13938d
MA
2270 result)
2271 (while (not result)
2272 ;; `make-temp-file' would be the natural choice for
2273 ;; implementation. But it calls `write-region' internally,
2274 ;; which also needs a temporary file - we would end in an
2275 ;; infinite loop.
2276 (setq result (make-temp-name prefix))
2277 (if (file-exists-p result)
2278 (setq result nil)
2279 ;; This creates the file by side effect.
2280 (set-file-times result)
2281 (set-file-modes result (tramp-octal-to-decimal "0700"))))
2282
2283 ;; Return the local part.
2284 (with-parsed-tramp-file-name result nil localname)))
8a4438b6
MA
2285
2286
16674e4f
KG
2287;;; Config Manipulation Functions:
2288
2289(defun tramp-set-completion-function (method function-list)
2290 "Sets the list of completion functions for METHOD.
2291FUNCTION-LIST is a list of entries of the form (FUNCTION FILE).
2292The FUNCTION is intended to parse FILE according its syntax.
2293It might be a predefined FUNCTION, or a user defined FUNCTION.
2294Predefined FUNCTIONs are `tramp-parse-rhosts', `tramp-parse-shosts',
8fc29035 2295`tramp-parse-sconfig', `tramp-parse-hosts', `tramp-parse-passwd',
8daea7fc
KG
2296and `tramp-parse-netrc'.
2297
16674e4f
KG
2298Example:
2299
2300 (tramp-set-completion-function
2301 \"ssh\"
8daea7fc
KG
2302 '((tramp-parse-sconfig \"/etc/ssh_config\")
2303 (tramp-parse-sconfig \"~/.ssh/config\")))"
16674e4f 2304
5ec2cc41
KG
2305 (let ((r function-list)
2306 (v function-list))
2307 (setq tramp-completion-function-alist
2308 (delete (assoc method tramp-completion-function-alist)
2309 tramp-completion-function-alist))
2310
2311 (while v
00d6fd04 2312 ;; Remove double entries.
5ec2cc41
KG
2313 (when (member (car v) (cdr v))
2314 (setcdr v (delete (car v) (cdr v))))
00d6fd04 2315 ;; Check for function and file or registry key.
5ec2cc41 2316 (unless (and (functionp (nth 0 (car v)))
00d6fd04
MA
2317 (if (string-match "^HKEY_CURRENT_USER" (nth 1 (car v)))
2318 ;; Windows registry.
2319 (and (memq system-type '(cygwin windows-nt))
a4aeb9a4
MA
2320 (zerop
2321 (tramp-local-call-process
2322 "reg" nil nil nil "query" (nth 1 (car v)))))
00d6fd04
MA
2323 ;; Configuration file.
2324 (file-exists-p (nth 1 (car v)))))
5ec2cc41
KG
2325 (setq r (delete (car v) r)))
2326 (setq v (cdr v)))
2327
2328 (when r
4007ba5b 2329 (add-to-list 'tramp-completion-function-alist
5ec2cc41 2330 (cons method r)))))
16674e4f
KG
2331
2332(defun tramp-get-completion-function (method)
00d6fd04 2333 "Returns a list of completion functions for METHOD.
16674e4f 2334For definition of that list see `tramp-set-completion-function'."
00d6fd04
MA
2335 (cons
2336 ;; Hosts visited once shall be remembered.
2337 `(tramp-parse-connection-properties ,method)
2338 ;; The method related defaults.
2339 (cdr (assoc method tramp-completion-function-alist))))
16674e4f 2340
d037d501 2341
0664ff72 2342;;; Fontification of `read-file-name':
d037d501 2343
0664ff72 2344;; rfn-eshadow.el is part of Emacs 22. It is autoloaded.
d037d501
MA
2345(defvar tramp-rfn-eshadow-overlay)
2346(make-variable-buffer-local 'tramp-rfn-eshadow-overlay)
2347
2348(defun tramp-rfn-eshadow-setup-minibuffer ()
2349 "Set up a minibuffer for `file-name-shadow-mode'.
2350Adds another overlay hiding filename parts according to Tramp's
2351special handling of `substitute-in-file-name'."
9ce8462a 2352 (when (symbol-value 'minibuffer-completing-file-name)
d037d501 2353 (setq tramp-rfn-eshadow-overlay
9e6ab520
MA
2354 (funcall (symbol-function 'make-overlay)
2355 (funcall (symbol-function 'minibuffer-prompt-end))
2356 (funcall (symbol-function 'minibuffer-prompt-end))))
d037d501 2357 ;; Copy rfn-eshadow-overlay properties.
9e6ab520
MA
2358 (let ((props (funcall (symbol-function 'overlay-properties)
2359 (symbol-value 'rfn-eshadow-overlay))))
d037d501 2360 (while props
9e6ab520
MA
2361 (funcall (symbol-function 'overlay-put)
2362 tramp-rfn-eshadow-overlay (pop props) (pop props))))))
d037d501
MA
2363
2364(when (boundp 'rfn-eshadow-setup-minibuffer-hook)
2365 (add-hook 'rfn-eshadow-setup-minibuffer-hook
48846dc5
MA
2366 'tramp-rfn-eshadow-setup-minibuffer)
2367 (add-hook 'tramp-unload-hook
aa485f7c
MA
2368 (lambda ()
2369 (remove-hook 'rfn-eshadow-setup-minibuffer-hook
2370 'tramp-rfn-eshadow-setup-minibuffer))))
d037d501 2371
adcbca53
MA
2372(defconst tramp-rfn-eshadow-update-overlay-regexp
2373 (format "[^%s/~]*\\(/\\|~\\)" tramp-postfix-host-format))
2374
d037d501
MA
2375(defun tramp-rfn-eshadow-update-overlay ()
2376 "Update `rfn-eshadow-overlay' to cover shadowed part of minibuffer input.
2377This is intended to be used as a minibuffer `post-command-hook' for
2378`file-name-shadow-mode'; the minibuffer should have already
2379been set up by `rfn-eshadow-setup-minibuffer'."
2380 ;; In remote files name, there is a shadowing just for the local part.
9e6ab520
MA
2381 (let ((end (or (funcall (symbol-function 'overlay-end)
2382 (symbol-value 'rfn-eshadow-overlay))
2383 (funcall (symbol-function 'minibuffer-prompt-end)))))
2384 (when (file-remote-p (buffer-substring-no-properties end (point-max)))
bd316474
KY
2385 (save-excursion
2386 (save-restriction
2387 (narrow-to-region
adcbca53
MA
2388 (1+ (or (string-match
2389 tramp-rfn-eshadow-update-overlay-regexp (buffer-string) end)
2390 end))
2391 (point-max))
bd316474
KY
2392 (let ((rfn-eshadow-overlay tramp-rfn-eshadow-overlay)
2393 (rfn-eshadow-update-overlay-hook nil))
dea31ca6 2394 (move-overlay rfn-eshadow-overlay (point-max) (point-max))
bd316474 2395 (funcall (symbol-function 'rfn-eshadow-update-overlay))))))))
d037d501
MA
2396
2397(when (boundp 'rfn-eshadow-update-overlay-hook)
2398 (add-hook 'rfn-eshadow-update-overlay-hook
b88f2d0a
MA
2399 'tramp-rfn-eshadow-update-overlay)
2400 (add-hook 'tramp-unload-hook
2401 (lambda ()
2402 (remove-hook 'rfn-eshadow-update-overlay-hook
2403 'tramp-rfn-eshadow-update-overlay))))
d037d501
MA
2404
2405
605a20a9
MA
2406;;; Integration of eshell.el:
2407
2408(eval-when-compile
2409 (defvar eshell-path-env))
2410
2411;; eshell.el keeps the path in `eshell-path-env'. We must change it
2412;; when `default-directory' points to another host.
2413(defun tramp-eshell-directory-change ()
2414 "Set `eshell-path-env' to $PATH of the host related to `default-directory'."
2415 (setq eshell-path-env
2416 (if (file-remote-p default-directory)
2417 (with-parsed-tramp-file-name default-directory nil
2418 (mapconcat
2419 'identity
2420 (tramp-get-remote-path v)
2421 ":"))
2422 (getenv "PATH"))))
2423
2424(eval-after-load "esh-util"
2425 '(progn
2426 (tramp-eshell-directory-change)
2427 (add-hook 'eshell-directory-change-hook
2428 'tramp-eshell-directory-change)
2429 (add-hook 'tramp-unload-hook
2430 (lambda ()
2431 (remove-hook 'eshell-directory-change-hook
2432 'tramp-eshell-directory-change)))))
2433
2434
fb7933a3
KG
2435;;; File Name Handler Functions:
2436
fb7933a3
KG
2437(defun tramp-handle-make-symbolic-link
2438 (filename linkname &optional ok-if-already-exists)
00d6fd04 2439 "Like `make-symbolic-link' for Tramp files.
cebb4ec6 2440If LINKNAME is a non-Tramp file, it is used verbatim as the target of
7432277c 2441the symlink. If LINKNAME is a Tramp file, only the localname component is
cebb4ec6
KG
2442used as the target of the symlink.
2443
7432277c
KG
2444If LINKNAME is a Tramp file and the localname component is relative, then
2445it is expanded first, before the localname component is taken. Note that
cebb4ec6
KG
2446this can give surprising results if the user/host for the source and
2447target of the symlink differ."
c62c9d08 2448 (with-parsed-tramp-file-name linkname l
00d6fd04 2449 (let ((ln (tramp-get-remote-ln l))
87bdd2c7
MA
2450 (cwd (tramp-run-real-handler
2451 'file-name-directory (list l-localname))))
c62c9d08 2452 (unless ln
00d6fd04
MA
2453 (tramp-error
2454 l 'file-error
2455 "Making a symbolic link. ln(1) does not exist on the remote host."))
c62c9d08
KG
2456
2457 ;; Do the 'confirm if exists' thing.
cebb4ec6 2458 (when (file-exists-p linkname)
c62c9d08
KG
2459 ;; What to do?
2460 (if (or (null ok-if-already-exists) ; not allowed to exist
2461 (and (numberp ok-if-already-exists)
2462 (not (yes-or-no-p
2463 (format
2464 "File %s already exists; make it a link anyway? "
7432277c 2465 l-localname)))))
00d6fd04
MA
2466 (tramp-error
2467 l 'file-already-exists "File %s already exists" l-localname)
cebb4ec6
KG
2468 (delete-file linkname)))
2469
7432277c 2470 ;; If FILENAME is a Tramp name, use just the localname component.
cebb4ec6 2471 (when (tramp-tramp-file-p filename)
1834b39f
MA
2472 (setq filename
2473 (tramp-file-name-localname
2474 (tramp-dissect-file-name (expand-file-name filename)))))
bf247b6e 2475
c62c9d08
KG
2476 ;; Right, they are on the same host, regardless of user, method, etc.
2477 ;; We now make the link on the remote machine. This will occur as the user
2478 ;; that FILENAME belongs to.
2479 (zerop
2480 (tramp-send-command-and-check
b593f105
MA
2481 l
2482 (format
2483 "cd %s && %s -sf %s %s"
2484 (tramp-shell-quote-argument cwd)
2485 ln
2486 (tramp-shell-quote-argument filename)
2487 (tramp-shell-quote-argument l-localname))
2488 t)))))
fb7933a3 2489
fb7933a3 2490(defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix)
00d6fd04
MA
2491 "Like `load' for Tramp files."
2492 (with-parsed-tramp-file-name (expand-file-name file) nil
c62c9d08
KG
2493 (unless nosuffix
2494 (cond ((file-exists-p (concat file ".elc"))
2495 (setq file (concat file ".elc")))
2496 ((file-exists-p (concat file ".el"))
2497 (setq file (concat file ".el")))))
2498 (when must-suffix
2499 ;; The first condition is always true for absolute file names.
2500 ;; Included for safety's sake.
2501 (unless (or (file-name-directory file)
2502 (string-match "\\.elc?\\'" file))
00d6fd04
MA
2503 (tramp-error
2504 v 'file-error
2505 "File `%s' does not include a `.el' or `.elc' suffix" file)))
c62c9d08
KG
2506 (unless noerror
2507 (when (not (file-exists-p file))
00d6fd04 2508 (tramp-error v 'file-error "Cannot load nonexistent file `%s'" file)))
c62c9d08
KG
2509 (if (not (file-exists-p file))
2510 nil
00d6fd04 2511 (unless nomessage (tramp-message v 0 "Loading %s..." file))
c62c9d08
KG
2512 (let ((local-copy (file-local-copy file)))
2513 ;; MUST-SUFFIX doesn't exist on XEmacs, so let it default to nil.
ce2cc728
MA
2514 (unwind-protect
2515 (load local-copy noerror t t)
2516 (delete-file local-copy)))
00d6fd04 2517 (unless nomessage (tramp-message v 0 "Loading %s...done" file))
c62c9d08 2518 t)))
fb7933a3 2519
a4aeb9a4 2520;; Localname manipulation functions that grok Tramp localnames...
c0fc6170
MA
2521(defun tramp-handle-file-name-as-directory (file)
2522 "Like `file-name-as-directory' but aware of Tramp files."
2523 ;; `file-name-as-directory' would be sufficient except localname is
2524 ;; the empty string.
2525 (let ((v (tramp-dissect-file-name file t)))
2526 ;; Run the command on the localname portion only.
2527 (tramp-make-tramp-file-name
2528 (tramp-file-name-method v)
2529 (tramp-file-name-user v)
2530 (tramp-file-name-host v)
2531 (tramp-run-real-handler
2532 'file-name-as-directory (list (or (tramp-file-name-localname v) ""))))))
2533
fb7933a3 2534(defun tramp-handle-file-name-directory (file)
00d6fd04 2535 "Like `file-name-directory' but aware of Tramp files."
9ce8462a
MA
2536 ;; Everything except the last filename thing is the directory. We
2537 ;; cannot apply `with-parsed-tramp-file-name', because this expands
2538 ;; the remote file name parts. This is a problem when we are in
2539 ;; file name completion.
2540 (let ((v (tramp-dissect-file-name file t)))
a01b1e22
MA
2541 ;; Run the command on the localname portion only.
2542 (tramp-make-tramp-file-name
9ce8462a
MA
2543 (tramp-file-name-method v)
2544 (tramp-file-name-user v)
2545 (tramp-file-name-host v)
87bdd2c7
MA
2546 (tramp-run-real-handler
2547 'file-name-directory (list (or (tramp-file-name-localname v) ""))))))
fb7933a3
KG
2548
2549(defun tramp-handle-file-name-nondirectory (file)
00d6fd04 2550 "Like `file-name-nondirectory' but aware of Tramp files."
c62c9d08 2551 (with-parsed-tramp-file-name file nil
87bdd2c7 2552 (tramp-run-real-handler 'file-name-nondirectory (list localname))))
fb7933a3
KG
2553
2554(defun tramp-handle-file-truename (filename &optional counter prev-dirs)
00d6fd04 2555 "Like `file-truename' for Tramp files."
48ddd622 2556 (with-parsed-tramp-file-name (expand-file-name filename) nil
00d6fd04 2557 (with-file-property v localname "file-truename"
293c24f9 2558 (let ((result nil)) ; result steps in reverse order
00d6fd04 2559 (tramp-message v 4 "Finding true name for `%s'" filename)
293c24f9
MA
2560 (cond
2561 ;; Use GNU readlink --canonicalize-missing where available.
2562 ((tramp-get-remote-readlink v)
2563 (setq result
2564 (tramp-send-command-and-read
2565 v
2566 (format "echo \"\\\"`%s --canonicalize-missing %s`\\\"\""
2567 (tramp-get-remote-readlink v)
2568 (tramp-shell-quote-argument localname)))))
2569
2570 ;; Use Perl implementation.
2571 ((and (tramp-get-remote-perl v)
2572 (tramp-get-connection-property v "perl-file-spec" nil)
2573 (tramp-get-connection-property v "perl-cwd-realpath" nil))
2574 (tramp-maybe-send-script
2575 v tramp-perl-file-truename "tramp_perl_file_truename")
2576 (setq result
2577 (tramp-send-command-and-read
2578 v
2579 (format "tramp_perl_file_truename %s"
2580 (tramp-shell-quote-argument localname)))))
2581
2582 ;; Do it yourself. We bind `directory-sep-char' here for
2583 ;; XEmacs on Windows, which would otherwise use backslash.
2584 (t (let* ((directory-sep-char ?/)
2585 (steps (tramp-compat-split-string localname "/"))
2586 (localnamedir (tramp-run-real-handler
2587 'file-name-as-directory (list localname)))
2588 (is-dir (string= localname localnamedir))
2589 (thisstep nil)
2590 (numchase 0)
2591 ;; Don't make the following value larger than
2592 ;; necessary. People expect an error message in a
2593 ;; timely fashion when something is wrong;
2594 ;; otherwise they might think that Emacs is hung.
2595 ;; Of course, correctness has to come first.
2596 (numchase-limit 20)
2597 symlink-target)
2598 (while (and steps (< numchase numchase-limit))
2599 (setq thisstep (pop steps))
2600 (tramp-message
2601 v 5 "Check %s"
2602 (mapconcat 'identity
2603 (append '("") (reverse result) (list thisstep))
2604 "/"))
2605 (setq symlink-target
2606 (nth 0 (file-attributes
2607 (tramp-make-tramp-file-name
2608 method user host
2609 (mapconcat 'identity
2610 (append '("")
2611 (reverse result)
2612 (list thisstep))
2613 "/")))))
2614 (cond ((string= "." thisstep)
2615 (tramp-message v 5 "Ignoring step `.'"))
2616 ((string= ".." thisstep)
2617 (tramp-message v 5 "Processing step `..'")
2618 (pop result))
2619 ((stringp symlink-target)
2620 ;; It's a symlink, follow it.
2621 (tramp-message v 5 "Follow symlink to %s" symlink-target)
2622 (setq numchase (1+ numchase))
2623 (when (file-name-absolute-p symlink-target)
2624 (setq result nil))
2625 ;; If the symlink was absolute, we'll get a string like
2626 ;; "/user@host:/some/target"; extract the
2627 ;; "/some/target" part from it.
2628 (when (tramp-tramp-file-p symlink-target)
2629 (unless (tramp-equal-remote filename symlink-target)
2630 (tramp-error
2631 v 'file-error
2632 "Symlink target `%s' on wrong host" symlink-target))
2633 (setq symlink-target localname))
2634 (setq steps
2635 (append (tramp-compat-split-string
2636 symlink-target "/")
2637 steps)))
2638 (t
2639 ;; It's a file.
2640 (setq result (cons thisstep result)))))
2641 (when (>= numchase numchase-limit)
2642 (tramp-error
2643 v 'file-error
2644 "Maximum number (%d) of symlinks exceeded" numchase-limit))
2645 (setq result (reverse result))
2646 ;; Combine list to form string.
2647 (setq result
2648 (if result
2649 (mapconcat 'identity (cons "" result) "/")
00d6fd04 2650 "/"))
293c24f9
MA
2651 (when (and is-dir (or (string= "" result)
2652 (not (string= (substring result -1) "/"))))
2653 (setq result (concat result "/"))))))
2654
2655 (tramp-message v 4 "True name of `%s' is `%s'" filename result)
2656 (tramp-make-tramp-file-name method user host result)))))
fb7933a3
KG
2657
2658;; Basic functions.
2659
2660(defun tramp-handle-file-exists-p (filename)
00d6fd04 2661 "Like `file-exists-p' for Tramp files."
c62c9d08 2662 (with-parsed-tramp-file-name filename nil
00d6fd04 2663 (with-file-property v localname "file-exists-p"
293c24f9
MA
2664 (or (not (null (tramp-get-file-property
2665 v localname "file-attributes-integer" nil)))
2666 (not (null (tramp-get-file-property
2667 v localname "file-attributes-string" nil)))
2668 (zerop (tramp-send-command-and-check
2669 v
2670 (format
2671 "%s %s"
2672 (tramp-get-file-exists-command v)
2673 (tramp-shell-quote-argument localname))))))))
fb7933a3 2674
00d6fd04
MA
2675;; Inodes don't exist for some file systems. Therefore we must
2676;; generate virtual ones. Used in `find-buffer-visiting'. The method
2677;; applied might be not so efficient (Ange-FTP uses hashes). But
2678;; performance isn't the major issue given that file transfer will
2679;; take time.
2680(defvar tramp-inodes nil
2681 "Keeps virtual inodes numbers.")
2682
8daea7fc
KG
2683;; Devices must distinguish physical file systems. The device numbers
2684;; provided by "lstat" aren't unique, because we operate on different hosts.
2685;; So we use virtual device numbers, generated by Tramp. Both Ange-FTP and
2686;; EFS use device number "-1". In order to be different, we use device number
b946a456 2687;; (-1 . x), whereby "x" is unique for a given (method user host).
8daea7fc
KG
2688(defvar tramp-devices nil
2689 "Keeps virtual device numbers.")
2690
fb7933a3
KG
2691;; CCC: This should check for an error condition and signal failure
2692;; when something goes wrong.
2693;; Daniel Pittman <daniel@danann.net>
c951aecb 2694(defun tramp-handle-file-attributes (filename &optional id-format)
00d6fd04
MA
2695 "Like `file-attributes' for Tramp files."
2696 (unless id-format (setq id-format 'integer))
aa485f7c
MA
2697 ;; Don't modify `last-coding-system-used' by accident.
2698 (let ((last-coding-system-used last-coding-system-used))
2699 (with-parsed-tramp-file-name (expand-file-name filename) nil
2700 (with-file-property v localname (format "file-attributes-%s" id-format)
7f49fe46
MA
2701 (save-excursion
2702 (tramp-convert-file-attributes
2703 v
2704 (cond
2705 ((tramp-get-remote-stat v)
2706 (tramp-do-file-attributes-with-stat v localname id-format))
2707 ((tramp-get-remote-perl v)
2708 (tramp-do-file-attributes-with-perl v localname id-format))
2709 (t
2710 (tramp-do-file-attributes-with-ls v localname id-format)))))))))
2711
2712(defun tramp-do-file-attributes-with-ls (vec localname &optional id-format)
00d6fd04 2713 "Implement `file-attributes' for Tramp files using the ls(1) command."
fb7933a3
KG
2714 (let (symlinkp dirp
2715 res-inode res-filemodes res-numlinks
2716 res-uid res-gid res-size res-symlink-target)
00d6fd04 2717 (tramp-message vec 5 "file attributes with ls: %s" localname)
fb7933a3 2718 (tramp-send-command
00d6fd04 2719 vec
680db9ac
MA
2720 (format "(%s %s || %s -h %s) && %s %s %s"
2721 (tramp-get-file-exists-command vec)
2722 (tramp-shell-quote-argument localname)
2723 (tramp-get-test-command vec)
2724 (tramp-shell-quote-argument localname)
00d6fd04 2725 (tramp-get-ls-command vec)
c82c5727 2726 (if (eq id-format 'integer) "-ildn" "-ild")
7432277c 2727 (tramp-shell-quote-argument localname)))
fb7933a3 2728 ;; parse `ls -l' output ...
00d6fd04 2729 (with-current-buffer (tramp-get-buffer vec)
680db9ac
MA
2730 (when (> (buffer-size) 0)
2731 (goto-char (point-min))
2732 ;; ... inode
2733 (setq res-inode
2734 (condition-case err
2735 (read (current-buffer))
2736 (invalid-read-syntax
2737 (when (and (equal (cadr err)
2738 "Integer constant overflow in reader")
2739 (string-match
2740 "^[0-9]+\\([0-9][0-9][0-9][0-9][0-9]\\)\\'"
2741 (car (cddr err))))
2742 (let* ((big (read (substring (car (cddr err)) 0
2743 (match-beginning 1))))
2744 (small (read (match-string 1 (car (cddr err)))))
2745 (twiddle (/ small 65536)))
2746 (cons (+ big twiddle)
2747 (- small (* twiddle 65536))))))))
2748 ;; ... file mode flags
2749 (setq res-filemodes (symbol-name (read (current-buffer))))
2750 ;; ... number links
2751 (setq res-numlinks (read (current-buffer)))
2752 ;; ... uid and gid
2753 (setq res-uid (read (current-buffer)))
2754 (setq res-gid (read (current-buffer)))
2755 (if (eq id-format 'integer)
2756 (progn
2757 (unless (numberp res-uid) (setq res-uid -1))
2758 (unless (numberp res-gid) (setq res-gid -1)))
2759 (progn
2760 (unless (stringp res-uid) (setq res-uid (symbol-name res-uid)))
2761 (unless (stringp res-gid) (setq res-gid (symbol-name res-gid)))))
2762 ;; ... size
2763 (setq res-size (read (current-buffer)))
2764 ;; From the file modes, figure out other stuff.
2765 (setq symlinkp (eq ?l (aref res-filemodes 0)))
2766 (setq dirp (eq ?d (aref res-filemodes 0)))
2767 ;; if symlink, find out file name pointed to
2768 (when symlinkp
2769 (search-forward "-> ")
2770 (setq res-symlink-target
2771 (buffer-substring (point) (tramp-compat-line-end-position))))
2772 ;; return data gathered
2773 (list
2774 ;; 0. t for directory, string (name linked to) for symbolic
2775 ;; link, or nil.
2776 (or dirp res-symlink-target)
2777 ;; 1. Number of links to file.
2778 res-numlinks
2779 ;; 2. File uid.
2780 res-uid
2781 ;; 3. File gid.
2782 res-gid
2783 ;; 4. Last access time, as a list of two integers. First
2784 ;; integer has high-order 16 bits of time, second has low 16
2785 ;; bits.
2786 ;; 5. Last modification time, likewise.
2787 ;; 6. Last status change time, likewise.
2788 '(0 0) '(0 0) '(0 0) ;CCC how to find out?
2789 ;; 7. Size in bytes (-1, if number is out of range).
2790 res-size
2791 ;; 8. File modes, as a string of ten letters or dashes as in ls -l.
2792 res-filemodes
2793 ;; 9. t if file's gid would change if file were deleted and
2794 ;; recreated. Will be set in `tramp-convert-file-attributes'
2795 t
2796 ;; 10. inode number.
2797 res-inode
2798 ;; 11. Device number. Will be replaced by a virtual device number.
2799 -1
2800 )))))
fb7933a3 2801
7f49fe46 2802(defun tramp-do-file-attributes-with-perl
00d6fd04
MA
2803 (vec localname &optional id-format)
2804 "Implement `file-attributes' for Tramp files using a Perl script."
2805 (tramp-message vec 5 "file attributes with perl: %s" localname)
2806 (tramp-maybe-send-script
2807 vec tramp-perl-file-attributes "tramp_perl_file_attributes")
2808 (tramp-send-command-and-read
2809 vec
2810 (format "tramp_perl_file_attributes %s %s"
2811 (tramp-shell-quote-argument localname) id-format)))
2812
7f49fe46 2813(defun tramp-do-file-attributes-with-stat
00d6fd04
MA
2814 (vec localname &optional id-format)
2815 "Implement `file-attributes' for Tramp files using stat(1) command."
2816 (tramp-message vec 5 "file attributes with stat: %s" localname)
2817 (tramp-send-command-and-read
2818 vec
2819 (format
680db9ac
MA
2820 "((%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)"
2821 (tramp-get-file-exists-command vec)
2822 (tramp-shell-quote-argument localname)
2823 (tramp-get-test-command vec)
2824 (tramp-shell-quote-argument localname)
00d6fd04
MA
2825 (tramp-get-remote-stat vec)
2826 (if (eq id-format 'integer) "%u" "\"%U\"")
2827 (if (eq id-format 'integer) "%g" "\"%G\"")
2828 (tramp-shell-quote-argument localname))))
8daea7fc 2829
fb7933a3 2830(defun tramp-handle-set-visited-file-modtime (&optional time-list)
00d6fd04 2831 "Like `set-visited-file-modtime' for Tramp files."
fb7933a3
KG
2832 (unless (buffer-file-name)
2833 (error "Can't set-visited-file-modtime: buffer `%s' not visiting a file"
2834 (buffer-name)))
48ddd622
MA
2835 (if time-list
2836 (tramp-run-real-handler 'set-visited-file-modtime (list time-list))
11948172
MA
2837 (let ((f (buffer-file-name))
2838 coding-system-used)
48ddd622
MA
2839 (with-parsed-tramp-file-name f nil
2840 (let* ((attr (file-attributes f))
2841 ;; '(-1 65535) means file doesn't exists yet.
2842 (modtime (or (nth 5 attr) '(-1 65535))))
11948172
MA
2843 (when (boundp 'last-coding-system-used)
2844 (setq coding-system-used (symbol-value 'last-coding-system-used)))
48ddd622 2845 ;; We use '(0 0) as a don't-know value. See also
7f49fe46 2846 ;; `tramp-do-file-attributes-with-ls'.
48ddd622
MA
2847 (if (not (equal modtime '(0 0)))
2848 (tramp-run-real-handler 'set-visited-file-modtime (list modtime))
00d6fd04 2849 (progn
48ddd622 2850 (tramp-send-command
00d6fd04 2851 v
48ddd622 2852 (format "%s -ild %s"
00d6fd04 2853 (tramp-get-ls-command v)
48ddd622 2854 (tramp-shell-quote-argument localname)))
48ddd622
MA
2855 (setq attr (buffer-substring (point)
2856 (progn (end-of-line) (point)))))
00d6fd04
MA
2857 (tramp-set-file-property
2858 v localname "visited-file-modtime-ild" attr))
11948172
MA
2859 (when (boundp 'last-coding-system-used)
2860 (set 'last-coding-system-used coding-system-used))
d2a2c17f 2861 nil)))))
fb7933a3 2862
c62c9d08
KG
2863;; This function makes the same assumption as
2864;; `tramp-handle-set-visited-file-modtime'.
2865(defun tramp-handle-verify-visited-file-modtime (buf)
00d6fd04 2866 "Like `verify-visited-file-modtime' for Tramp files.
c08e6004
MA
2867At the time `verify-visited-file-modtime' calls this function, we
2868already know that the buffer is visiting a file and that
2869`visited-file-modtime' does not return 0. Do not call this
2870function directly, unless those two cases are already taken care
2871of."
c62c9d08 2872 (with-current-buffer buf
b15d0c4c
MA
2873 ;; There is no file visiting the buffer, or the buffer has no
2874 ;; recorded last modification time.
2875 (if (or (not (buffer-file-name))
2876 (eq (visited-file-modtime) 0))
d2a2c17f 2877 t
b15d0c4c
MA
2878 (let ((f (buffer-file-name)))
2879 (with-parsed-tramp-file-name f nil
bce04fee 2880 (tramp-flush-file-property v localname)
b15d0c4c
MA
2881 (let* ((attr (file-attributes f))
2882 (modtime (nth 5 attr))
2883 (mt (visited-file-modtime)))
bf247b6e 2884
70c11b0b
MA
2885 (cond
2886 ;; File exists, and has a known modtime.
b15d0c4c
MA
2887 ((and attr (not (equal modtime '(0 0))))
2888 (< (abs (tramp-time-diff
2889 modtime
2890 ;; For compatibility, deal with both the old
70c11b0b
MA
2891 ;; (HIGH . LOW) and the new (HIGH LOW) return
2892 ;; values of `visited-file-modtime'.
b15d0c4c
MA
2893 (if (atom (cdr mt))
2894 (list (car mt) (cdr mt))
2895 mt)))
2896 2))
70c11b0b 2897 ;; Modtime has the don't know value.
b15d0c4c 2898 (attr
00d6fd04
MA
2899 (tramp-send-command
2900 v
2901 (format "%s -ild %s"
2902 (tramp-get-ls-command v)
2903 (tramp-shell-quote-argument localname)))
2904 (with-current-buffer (tramp-get-buffer v)
b15d0c4c
MA
2905 (setq attr (buffer-substring
2906 (point) (progn (end-of-line) (point)))))
00d6fd04
MA
2907 (equal
2908 attr
2909 (tramp-get-file-property
2910 v localname "visited-file-modtime-ild" "")))
70c11b0b
MA
2911 ;; If file does not exist, say it is not modified if and
2912 ;; only if that agrees with the buffer's record.
b15d0c4c 2913 (t (equal mt '(-1 65535))))))))))
c62c9d08 2914
fb7933a3 2915(defun tramp-handle-set-file-modes (filename mode)
00d6fd04 2916 "Like `set-file-modes' for Tramp files."
c62c9d08 2917 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2918 (tramp-flush-file-property v localname)
2919 (unless (zerop (tramp-send-command-and-check
2920 v
2921 (format "chmod %s %s"
2922 (tramp-decimal-to-octal mode)
2923 (tramp-shell-quote-argument localname))))
2924 ;; FIXME: extract the proper text from chmod's stderr.
2925 (tramp-error
2926 v 'file-error "Error while changing file's mode %s" filename))))
fb7933a3 2927
ce3f516f
MA
2928(defun tramp-handle-set-file-times (filename &optional time)
2929 "Like `set-file-times' for Tramp files."
2930 (zerop
9e6ab520 2931 (if (file-remote-p filename)
ce3f516f 2932 (with-parsed-tramp-file-name filename nil
8d60099b 2933 (tramp-flush-file-property v localname)
ce3f516f
MA
2934 (let ((time (if (or (null time) (equal time '(0 0)))
2935 (current-time)
2936 time))
2937 (utc
2938 ;; With GNU Emacs, `format-time-string' has an
2939 ;; optional parameter UNIVERSAL. This is preferred,
2940 ;; because we could handle the case when the remote
2941 ;; host is located in a different time zone as the
2942 ;; local host.
2943 (and (functionp 'subr-arity)
2944 (subrp (symbol-function 'format-time-string))
2945 (= 3 (cdr (funcall (symbol-function 'subr-arity)
2946 (symbol-function
2947 'format-time-string)))))))
2948 (tramp-send-command-and-check
2949 v (format "%s touch -t %s %s"
2950 (if utc "TZ=UTC; export TZ;" "")
2951 (if utc
2952 (format-time-string "%Y%m%d%H%M.%S" time t)
2953 (format-time-string "%Y%m%d%H%M.%S" time))
2954 (tramp-shell-quote-argument localname)))))
8d60099b 2955
ce3f516f
MA
2956 ;; We handle also the local part, because in older Emacsen,
2957 ;; without `set-file-times', this function is an alias for this.
2958 ;; We are local, so we don't need the UTC settings.
a4aeb9a4 2959 (tramp-local-call-process
ce3f516f
MA
2960 "touch" nil nil nil "-t"
2961 (format-time-string "%Y%m%d%H%M.%S" time)
2962 (tramp-shell-quote-argument filename)))))
2963
8d60099b
MA
2964(defun tramp-set-file-uid-gid (filename &optional uid gid)
2965 "Set the ownership for FILENAME.
2966If UID and GID are provided, these values are used; otherwise uid
2967and gid of the corresponding user is taken. Both parameters must be integers."
70c11b0b
MA
2968 ;; Modern Unices allow chown only for root. So we might need
2969 ;; another implementation, see `dired-do-chown'. OTOH, it is mostly
2970 ;; working with su(do)? when it is needed, so it shall succeed in
2971 ;; the majority of cases.
aa485f7c
MA
2972 ;; Don't modify `last-coding-system-used' by accident.
2973 (let ((last-coding-system-used last-coding-system-used))
2974 (if (file-remote-p filename)
2975 (with-parsed-tramp-file-name filename nil
2976 (if (and (zerop (user-uid)) (tramp-local-host-p v))
2977 ;; If we are root on the local host, we can do it directly.
2978 (tramp-set-file-uid-gid localname uid gid)
2979 (let ((uid (or (and (integerp uid) uid)
2980 (tramp-get-remote-uid v 'integer)))
2981 (gid (or (and (integerp gid) gid)
2982 (tramp-get-remote-gid v 'integer))))
2983 (tramp-send-command
2984 v (format
2985 "chown %d:%d %s" uid gid
2986 (tramp-shell-quote-argument localname))))))
2987
2988 ;; We handle also the local part, because there doesn't exist
2989 ;; `set-file-uid-gid'. On W32 "chown" might not work.
2990 (let ((uid (or (and (integerp uid) uid) (tramp-get-local-uid 'integer)))
2991 (gid (or (and (integerp gid) gid) (tramp-get-local-gid 'integer))))
2992 (tramp-local-call-process
2993 "chown" nil nil nil
2994 (format "%d:%d" uid gid) (tramp-shell-quote-argument filename))))))
8d60099b 2995
fb7933a3
KG
2996;; Simple functions using the `test' command.
2997
2998(defun tramp-handle-file-executable-p (filename)
00d6fd04 2999 "Like `file-executable-p' for Tramp files."
c62c9d08 3000 (with-parsed-tramp-file-name filename nil
00d6fd04 3001 (with-file-property v localname "file-executable-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 ?x)
3005 (zerop (tramp-run-test "-x" filename))))))
fb7933a3
KG
3006
3007(defun tramp-handle-file-readable-p (filename)
00d6fd04 3008 "Like `file-readable-p' for Tramp files."
c62c9d08 3009 (with-parsed-tramp-file-name filename nil
00d6fd04 3010 (with-file-property v localname "file-readable-p"
293c24f9
MA
3011 ;; Examine `file-attributes' cache to see if request can be
3012 ;; satisfied without remote operation.
3013 (or (tramp-check-cached-permissions v ?r)
3014 (zerop (tramp-run-test "-r" filename))))))
fb7933a3
KG
3015
3016;; When the remote shell is started, it looks for a shell which groks
3017;; tilde expansion. Here, we assume that all shells which grok tilde
3018;; expansion will also provide a `test' command which groks `-nt' (for
3019;; newer than). If this breaks, tell me about it and I'll try to do
3020;; something smarter about it.
3021(defun tramp-handle-file-newer-than-file-p (file1 file2)
00d6fd04 3022 "Like `file-newer-than-file-p' for Tramp files."
fb7933a3
KG
3023 (cond ((not (file-exists-p file1))
3024 nil)
3025 ((not (file-exists-p file2))
3026 t)
91879624 3027 ;; We are sure both files exist at this point.
fb7933a3
KG
3028 (t
3029 (save-excursion
91879624
KG
3030 ;; We try to get the mtime of both files. If they are not
3031 ;; equal to the "dont-know" value, then we subtract the times
3032 ;; and obtain the result.
3033 (let ((fa1 (file-attributes file1))
3034 (fa2 (file-attributes file2)))
3035 (if (and (not (equal (nth 5 fa1) '(0 0)))
3036 (not (equal (nth 5 fa2) '(0 0))))
01917a18 3037 (> 0 (tramp-time-diff (nth 5 fa2) (nth 5 fa1)))
91879624
KG
3038 ;; If one of them is the dont-know value, then we can
3039 ;; still try to run a shell command on the remote host.
3040 ;; However, this only works if both files are Tramp
3041 ;; files and both have the same method, same user, same
3042 ;; host.
00d6fd04
MA
3043 (unless (tramp-equal-remote file1 file2)
3044 (with-parsed-tramp-file-name
3045 (if (tramp-tramp-file-p file1) file1 file2) nil
3046 (tramp-error
3047 v 'file-error
3048 "Files %s and %s must have same method, user, host"
3049 file1 file2)))
3050 (with-parsed-tramp-file-name file1 nil
3051 (zerop (tramp-run-test2
3052 (tramp-get-test-nt-command v) file1 file2)))))))))
fb7933a3
KG
3053
3054;; Functions implemented using the basic functions above.
3055
3056(defun tramp-handle-file-modes (filename)
00d6fd04 3057 "Like `file-modes' for Tramp files."
5da24108
MA
3058 (let ((truename (or (file-truename filename) filename)))
3059 (when (file-exists-p truename)
3060 (tramp-mode-string-to-int (nth 8 (file-attributes truename))))))
fb7933a3 3061
b86c1cd8
MA
3062(defun tramp-default-file-modes (filename)
3063 "Return file modes of FILENAME as integer.
3064If the file modes of FILENAME cannot be determined, return the
974647ac
MA
3065value of `default-file-modes', without execute permissions."
3066 (or (file-modes filename)
3067 (logand (default-file-modes) (tramp-octal-to-decimal "0666"))))
b86c1cd8 3068
fb7933a3 3069(defun tramp-handle-file-directory-p (filename)
00d6fd04 3070 "Like `file-directory-p' for Tramp files."
fb7933a3
KG
3071 ;; Care must be taken that this function returns `t' for symlinks
3072 ;; pointing to directories. Surely the most obvious implementation
3073 ;; would be `test -d', but that returns false for such symlinks.
3074 ;; CCC: Stefan Monnier says that `test -d' follows symlinks. And
3075 ;; I now think he's right. So we could be using `test -d', couldn't
3076 ;; we?
3077 ;;
3078 ;; Alternatives: `cd %s', `test -d %s'
c62c9d08 3079 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3080 (with-file-property v localname "file-directory-p"
3081 (zerop (tramp-run-test "-d" filename)))))
fb7933a3
KG
3082
3083(defun tramp-handle-file-regular-p (filename)
00d6fd04
MA
3084 "Like `file-regular-p' for Tramp files."
3085 (and (file-exists-p filename)
3086 (eq ?- (aref (nth 8 (file-attributes filename)) 0))))
fb7933a3
KG
3087
3088(defun tramp-handle-file-symlink-p (filename)
00d6fd04 3089 "Like `file-symlink-p' for Tramp files."
c62c9d08 3090 (with-parsed-tramp-file-name filename nil
c951aecb 3091 (let ((x (car (file-attributes filename))))
b25a52cc
KG
3092 (when (stringp x)
3093 ;; When Tramp is running on VMS, then `file-name-absolute-p'
3094 ;; might do weird things.
3095 (if (file-name-absolute-p x)
00d6fd04 3096 (tramp-make-tramp-file-name method user host x)
b25a52cc 3097 x)))))
fb7933a3
KG
3098
3099(defun tramp-handle-file-writable-p (filename)
00d6fd04 3100 "Like `file-writable-p' for Tramp files."
c62c9d08 3101 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3102 (with-file-property v localname "file-writable-p"
3103 (if (file-exists-p filename)
293c24f9
MA
3104 ;; Examine `file-attributes' cache to see if request can be
3105 ;; satisfied without remote operation.
3106 (or (tramp-check-cached-permissions v ?w)
3107 (zerop (tramp-run-test "-w" filename)))
00d6fd04
MA
3108 ;; If file doesn't exist, check if directory is writable.
3109 (and (zerop (tramp-run-test
3110 "-d" (file-name-directory filename)))
3111 (zerop (tramp-run-test
3112 "-w" (file-name-directory filename))))))))
fb7933a3
KG
3113
3114(defun tramp-handle-file-ownership-preserved-p (filename)
00d6fd04 3115 "Like `file-ownership-preserved-p' for Tramp files."
c62c9d08 3116 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3117 (with-file-property v localname "file-ownership-preserved-p"
3118 (let ((attributes (file-attributes filename)))
3119 ;; Return t if the file doesn't exist, since it's true that no
3120 ;; information would be lost by an (attempted) delete and create.
3121 (or (null attributes)
3122 (= (nth 2 attributes) (tramp-get-remote-uid v 'integer)))))))
fb7933a3
KG
3123
3124;; Other file name ops.
3125
fb7933a3 3126(defun tramp-handle-directory-file-name (directory)
00d6fd04 3127 "Like `directory-file-name' for Tramp files."
7432277c
KG
3128 ;; If localname component of filename is "/", leave it unchanged.
3129 ;; Otherwise, remove any trailing slash from localname component.
8daea7fc
KG
3130 ;; Method, host, etc, are unchanged. Does it make sense to try
3131 ;; to avoid parsing the filename?
c62c9d08 3132 (with-parsed-tramp-file-name directory nil
7432277c
KG
3133 (if (and (not (zerop (length localname)))
3134 (eq (aref localname (1- (length localname))) ?/)
3135 (not (string= localname "/")))
8daea7fc
KG
3136 (substring directory 0 -1)
3137 directory)))
fb7933a3
KG
3138
3139;; Directory listings.
3140
00d6fd04
MA
3141(defun tramp-handle-directory-files
3142 (directory &optional full match nosort files-only)
3143 "Like `directory-files' for Tramp files."
3144 ;; FILES-ONLY is valid for XEmacs only.
3145 (when (file-directory-p directory)
73a37a69 3146 (setq directory (file-name-as-directory (expand-file-name directory)))
00d6fd04
MA
3147 (let ((temp (nreverse (file-name-all-completions "" directory)))
3148 result item)
3149
3150 (while temp
3151 (setq item (directory-file-name (pop temp)))
3152 (when (and (or (null match) (string-match match item))
3153 (or (null files-only)
73a37a69 3154 ;; Files only.
00d6fd04 3155 (and (equal files-only t) (file-regular-p item))
73a37a69 3156 ;; Directories only.
00d6fd04 3157 (file-directory-p item)))
73a37a69 3158 (push (if full (concat directory item) item)
00d6fd04 3159 result)))
73a37a69 3160 (if nosort result (sort result 'string<)))))
c62c9d08 3161
c82c5727
LH
3162(defun tramp-handle-directory-files-and-attributes
3163 (directory &optional full match nosort id-format)
00d6fd04
MA
3164 "Like `directory-files-and-attributes' for Tramp files."
3165 (unless id-format (setq id-format 'integer))
3166 (when (file-directory-p directory)
3167 (setq directory (expand-file-name directory))
3168 (let* ((temp
9e6ab520 3169 (tramp-compat-copy-tree
00d6fd04
MA
3170 (with-parsed-tramp-file-name directory nil
3171 (with-file-property
3172 v localname
3173 (format "directory-files-and-attributes-%s" id-format)
3174 (save-excursion
3175 (mapcar
aa485f7c
MA
3176 (lambda (x)
3177 (cons (car x)
3178 (tramp-convert-file-attributes v (cdr x))))
7f49fe46
MA
3179 (cond
3180 ((tramp-get-remote-stat v)
3181 (tramp-do-directory-files-and-attributes-with-stat
3182 v localname id-format))
3183 ((tramp-get-remote-perl v)
3184 (tramp-do-directory-files-and-attributes-with-perl
3185 v localname id-format)))))))))
00d6fd04
MA
3186 result item)
3187
3188 (while temp
3189 (setq item (pop temp))
3190 (when (or (null match) (string-match match (car item)))
3191 (when full
3192 (setcar item (expand-file-name (car item) directory)))
3193 (push item result)))
3194
3195 (if nosort
3196 result
3197 (sort result (lambda (x y) (string< (car x) (car y))))))))
3198
7f49fe46 3199(defun tramp-do-directory-files-and-attributes-with-perl
00d6fd04
MA
3200 (vec localname &optional id-format)
3201 "Implement `directory-files-and-attributes' for Tramp files using a Perl script."
3202 (tramp-message vec 5 "directory-files-and-attributes with perl: %s" localname)
3203 (tramp-maybe-send-script
3204 vec tramp-perl-directory-files-and-attributes
3205 "tramp_perl_directory_files_and_attributes")
3206 (let ((object
3207 (tramp-send-command-and-read
3208 vec
3209 (format "tramp_perl_directory_files_and_attributes %s %s"
3210 (tramp-shell-quote-argument localname) id-format))))
3211 (when (stringp object) (tramp-error vec 'file-error object))
3212 object))
3213
7f49fe46 3214(defun tramp-do-directory-files-and-attributes-with-stat
00d6fd04
MA
3215 (vec localname &optional id-format)
3216 "Implement `directory-files-and-attributes' for Tramp files using stat(1) command."
3217 (tramp-message vec 5 "directory-files-and-attributes with stat: %s" localname)
3218 (tramp-send-command-and-read
3219 vec
3220 (format
3221 (concat
70c11b0b
MA
3222 ;; We must care about filenames with spaces, or starting with
3223 ;; "-"; this would confuse xargs. "ls -aQ" might be a solution,
3224 ;; but it does not work on all remote systems. Therefore, we
3225 ;; quote the filenames via sed.
3226 "cd %s; echo \"(\"; (%s -a | sed -e s/\\$/\\\"/g -e s/^/\\\"/g | xargs "
d4443a0d 3227 "%s -c '(\"%%n\" (\"%%N\") %%h %s %s %%X.0 %%Y.0 %%Z.0 %%s.0 \"%%A\" t %%i.0 -1)'); "
00d6fd04
MA
3228 "echo \")\"")
3229 (tramp-shell-quote-argument localname)
3230 (tramp-get-ls-command vec)
3231 (tramp-get-remote-stat vec)
3232 (if (eq id-format 'integer) "%u" "\"%U\"")
3233 (if (eq id-format 'integer) "%g" "\"%G\""))))
c82c5727 3234
c62c9d08 3235;; This function should return "foo/" for directories and "bar" for
00d6fd04 3236;; files.
c62c9d08 3237(defun tramp-handle-file-name-all-completions (filename directory)
00d6fd04
MA
3238 "Like `file-name-all-completions' for Tramp files."
3239 (unless (save-match-data (string-match "/" filename))
9c13938d 3240 (with-parsed-tramp-file-name (expand-file-name directory) nil
b50dd0d2 3241
00d6fd04
MA
3242 (all-completions
3243 filename
3244 (mapcar
3245 'list
293c24f9
MA
3246 (or
3247 ;; Try cache first
3248 (and
3249 ;; Ignore if expired
3250 (or (not (integerp tramp-completion-reread-directory-timeout))
3251 (<= (tramp-time-diff
3252 (current-time)
3253 (tramp-get-file-property
3254 v localname "last-completion" '(0 0 0)))
3255 tramp-completion-reread-directory-timeout))
3256
3257 ;; Try cache entries for filename, filename with last
3258 ;; character removed, filename with last two characters
3259 ;; removed, ..., and finally the empty string - all
3260 ;; concatenated to the local directory name
3261
3262 ;; This is inefficient for very long filenames, pity
3263 ;; `reduce' is not available...
3264 (car
3265 (apply
3266 'append
3267 (mapcar
3268 (lambda (x)
3269 (let ((cache-hit
3270 (tramp-get-file-property
3271 v
3272 (concat localname (substring filename 0 x))
3273 "file-name-all-completions"
3274 nil)))
3275 (when cache-hit (list cache-hit))))
3276 (tramp-compat-number-sequence (length filename) 0 -1)))))
3277
3278 ;; Cache expired or no matching cache entry found so we need
3279 ;; to perform a remote operation
3280 (let (result)
3281 ;; Get a list of directories and files, including reliably
3282 ;; tagging the directories with a trailing '/'. Because I
3283 ;; rock. --daniel@danann.net
3284
3285 ;; Changed to perform `cd' in the same remote op and only
3286 ;; get entries starting with `filename'. Capture any `cd'
3287 ;; error messages. Ensure any `cd' and `echo' aliases are
3288 ;; ignored.
3289 (tramp-send-command
3290 v
3291 (if (tramp-get-remote-perl v)
3292 (progn
3293 (tramp-maybe-send-script
3294 v tramp-perl-file-name-all-completions
3295 "tramp_perl_file_name_all_completions")
3296 (format "tramp_perl_file_name_all_completions %s %s %d"
3297 (tramp-shell-quote-argument localname)
3298 (tramp-shell-quote-argument filename)
3299 (if (symbol-value
3300 'read-file-name-completion-ignore-case)
3301 1 0)))
3302
3303 (format (concat
3304 "(\\cd %s 2>&1 && (%s %s -a 2>/dev/null"
3305 ;; `ls' with wildcard might fail with `Argument
3306 ;; list too long' error in some corner cases; if
3307 ;; `ls' fails after `cd' succeeded, chances are
3308 ;; that's the case, so let's retry without
3309 ;; wildcard. This will return "too many" entries
3310 ;; but that isn't harmful.
3311 " || %s -a 2>/dev/null)"
3312 " | while read f; do"
3313 " if %s -d \"$f\" 2>/dev/null;"
3314 " then \\echo \"$f/\"; else \\echo \"$f\"; fi; done"
3315 " && \\echo ok) || \\echo fail")
3316 (tramp-shell-quote-argument localname)
3317 (tramp-get-ls-command v)
3318 ;; When `filename' is empty, just `ls' without
3319 ;; filename argument is more efficient than `ls *'
3320 ;; for very large directories and might avoid the
3321 ;; `Argument list too long' error.
3322 ;;
3323 ;; With and only with wildcard, we need to add
3324 ;; `-d' to prevent `ls' from descending into
3325 ;; sub-directories.
3326 (if (zerop (length filename))
3327 "."
3328 (concat (tramp-shell-quote-argument filename) "* -d"))
3329 (tramp-get-ls-command v)
3330 (tramp-get-test-command v))))
3331
3332 ;; Now grab the output.
3333 (with-current-buffer (tramp-get-buffer v)
3334 (goto-char (point-max))
3335
3336 ;; Check result code, found in last line of output
3337 (forward-line -1)
3338 (if (looking-at "^fail$")
3339 (progn
3340 ;; Grab error message from line before last line
3341 ;; (it was put there by `cd 2>&1')
3342 (forward-line -1)
3343 (tramp-error
3344 v 'file-error
3345 "tramp-handle-file-name-all-completions: %s"
3346 (buffer-substring
3347 (point) (tramp-compat-line-end-position))))
3348 ;; For peace of mind, if buffer doesn't end in `fail'
3349 ;; then it should end in `ok'. If neither are in the
3350 ;; buffer something went seriously wrong on the remote
3351 ;; side.
3352 (unless (looking-at "^ok$")
3353 (tramp-error
3354 v 'file-error
3355 "\
3356tramp-handle-file-name-all-completions: internal error accessing `%s': `%s'"
3357 (tramp-shell-quote-argument localname) (buffer-string))))
3358
3359 (while (zerop (forward-line -1))
3360 (push (buffer-substring
3361 (point) (tramp-compat-line-end-position))
3362 result)))
3363
3364 ;; Because the remote op went through OK we know the
3365 ;; directory we `cd'-ed to exists
3366 (tramp-set-file-property
3367 v localname "file-exists-p" t)
3368
3369 ;; Because the remote op went through OK we know every
3370 ;; file listed by `ls' exists.
3371 (mapc (lambda (entry)
3372 (tramp-set-file-property
3373 v (concat localname entry) "file-exists-p" t))
3374 result)
3375
3376 (tramp-set-file-property
3377 v localname "last-completion" (current-time))
3378
3379 ;; Store result in the cache
3380 (tramp-set-file-property
3381 v (concat localname filename)
3382 "file-name-all-completions"
3383 result))))))))
fb7933a3
KG
3384
3385;; The following isn't needed for Emacs 20 but for 19.34?
e1e17cae
MA
3386(defun tramp-handle-file-name-completion
3387 (filename directory &optional predicate)
00d6fd04 3388 "Like `file-name-completion' for Tramp files."
fb7933a3
KG
3389 (unless (tramp-tramp-file-p directory)
3390 (error
3391 "tramp-handle-file-name-completion invoked on non-tramp directory `%s'"
3392 directory))
83e20b5c
MA
3393 (try-completion
3394 filename
3395 (mapcar 'list (file-name-all-completions filename directory))
3396 (when predicate
3397 (lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
fb7933a3
KG
3398
3399;; cp, mv and ln
3400
3401(defun tramp-handle-add-name-to-file
3402 (filename newname &optional ok-if-already-exists)
00d6fd04
MA
3403 "Like `add-name-to-file' for Tramp files."
3404 (unless (tramp-equal-remote filename newname)
3405 (with-parsed-tramp-file-name
3406 (if (tramp-tramp-file-p filename) filename newname) nil
3407 (tramp-error
3408 v 'file-error
3409 "add-name-to-file: %s"
3410 "only implemented for same method, same user, same host")))
c62c9d08
KG
3411 (with-parsed-tramp-file-name filename v1
3412 (with-parsed-tramp-file-name newname v2
00d6fd04 3413 (let ((ln (when v1 (tramp-get-remote-ln v1))))
c62c9d08
KG
3414 (when (and (not ok-if-already-exists)
3415 (file-exists-p newname)
3416 (not (numberp ok-if-already-exists))
3417 (y-or-n-p
3418 (format
3419 "File %s already exists; make it a new name anyway? "
3420 newname)))
00d6fd04
MA
3421 (tramp-error
3422 v2 'file-error
3423 "add-name-to-file: file %s already exists" newname))
aac0b0f2 3424 (tramp-flush-file-property v2 (file-name-directory v2-localname))
00d6fd04 3425 (tramp-flush-file-property v2 v2-localname)
c62c9d08 3426 (tramp-barf-unless-okay
00d6fd04 3427 v1
7432277c
KG
3428 (format "%s %s %s" ln (tramp-shell-quote-argument v1-localname)
3429 (tramp-shell-quote-argument v2-localname))
c62c9d08
KG
3430 "error with add-name-to-file, see buffer `%s' for details"
3431 (buffer-name))))))
fb7933a3
KG
3432
3433(defun tramp-handle-copy-file
8d60099b 3434 (filename newname &optional ok-if-already-exists keep-date preserve-uid-gid)
00d6fd04 3435 "Like `copy-file' for Tramp files."
fb7933a3 3436 ;; Check if both files are local -- invoke normal copy-file.
9e6ab520 3437 ;; Otherwise, use Tramp from local system.
fb7933a3
KG
3438 (setq filename (expand-file-name filename))
3439 (setq newname (expand-file-name newname))
9e6ab520 3440 (cond
a4aeb9a4 3441 ;; At least one file a Tramp file?
9e6ab520
MA
3442 ((or (tramp-tramp-file-p filename)
3443 (tramp-tramp-file-p newname))
3444 (tramp-do-copy-or-rename-file
3445 'copy filename newname ok-if-already-exists keep-date preserve-uid-gid))
3446 ;; Compat section.
3447 (preserve-uid-gid
fb7933a3 3448 (tramp-run-real-handler
8d60099b 3449 'copy-file
9e6ab520
MA
3450 (list filename newname ok-if-already-exists keep-date preserve-uid-gid)))
3451 (t
3452 (tramp-run-real-handler
3453 'copy-file (list filename newname ok-if-already-exists keep-date)))))
fb7933a3 3454
263c02ef
MA
3455(defun tramp-handle-copy-directory (dirname newname &optional keep-date parents)
3456 "Like `copy-directory' for Tramp files."
3457 (let ((t1 (tramp-tramp-file-p dirname))
3458 (t2 (tramp-tramp-file-p newname)))
3459 (with-parsed-tramp-file-name (if t1 dirname newname) nil
3460 (if (and (tramp-get-method-parameter method 'tramp-copy-recursive)
3461 ;; When DIRNAME and NEWNAME are remote, they must have
3462 ;; the same method.
3463 (or (null t1) (null t2)
b000a6e2
MA
3464 (string-equal
3465 (tramp-file-name-method (tramp-dissect-file-name dirname))
3466 (tramp-file-name-method (tramp-dissect-file-name newname)))))
263c02ef
MA
3467 ;; scp or rsync DTRT.
3468 (progn
3469 (setq dirname (directory-file-name (expand-file-name dirname))
3470 newname (directory-file-name (expand-file-name newname)))
3471 (if (and (file-directory-p newname)
3472 (not (string-equal (file-name-nondirectory dirname)
3473 (file-name-nondirectory newname))))
3474 (setq newname
3475 (expand-file-name
3476 (file-name-nondirectory dirname) newname)))
3477 (if (not (file-directory-p (file-name-directory newname)))
3478 (make-directory (file-name-directory newname) parents))
3479 (tramp-do-copy-or-rename-file-out-of-band
3480 'copy dirname newname keep-date))
3481 ;; We must do it file-wise.
3482 (tramp-run-real-handler
aac0b0f2
MA
3483 'copy-directory (list dirname newname keep-date parents)))
3484
3485 ;; When newname did exist, we have wrong cached values.
3486 (when t2
3487 (with-parsed-tramp-file-name newname nil
3488 (tramp-flush-file-property v (file-name-directory localname))
3489 (tramp-flush-file-property v localname))))))
263c02ef 3490
fb7933a3
KG
3491(defun tramp-handle-rename-file
3492 (filename newname &optional ok-if-already-exists)
00d6fd04 3493 "Like `rename-file' for Tramp files."
fb7933a3 3494 ;; Check if both files are local -- invoke normal rename-file.
a4aeb9a4 3495 ;; Otherwise, use Tramp from local system.
fb7933a3
KG
3496 (setq filename (expand-file-name filename))
3497 (setq newname (expand-file-name newname))
a4aeb9a4 3498 ;; At least one file a Tramp file?
fb7933a3
KG
3499 (if (or (tramp-tramp-file-p filename)
3500 (tramp-tramp-file-p newname))
3501 (tramp-do-copy-or-rename-file
8d60099b 3502 'rename filename newname ok-if-already-exists t t)
00d6fd04
MA
3503 (tramp-run-real-handler
3504 'rename-file (list filename newname ok-if-already-exists))))
fb7933a3
KG
3505
3506(defun tramp-do-copy-or-rename-file
8d60099b 3507 (op filename newname &optional ok-if-already-exists keep-date preserve-uid-gid)
fb7933a3
KG
3508 "Copy or rename a remote file.
3509OP must be `copy' or `rename' and indicates the operation to perform.
3510FILENAME specifies the file to copy or rename, NEWNAME is the name of
3511the new file (for copy) or the new name of the file (for rename).
3512OK-IF-ALREADY-EXISTS means don't barf if NEWNAME exists already.
3513KEEP-DATE means to make sure that NEWNAME has the same timestamp
8d60099b
MA
3514as FILENAME. PRESERVE-UID-GID, when non-nil, instructs to keep
3515the uid and gid if both files are on the same host.
fb7933a3
KG
3516
3517This function is invoked by `tramp-handle-copy-file' and
3518`tramp-handle-rename-file'. It is an error if OP is neither of `copy'
3519and `rename'. FILENAME and NEWNAME must be absolute file names."
3520 (unless (memq op '(copy rename))
3521 (error "Unknown operation `%s', must be `copy' or `rename'" op))
90dc758d 3522 (let ((t1 (tramp-tramp-file-p filename))
00d6fd04 3523 (t2 (tramp-tramp-file-p newname)))
5ec2cc41 3524
da1975d7
MA
3525 (when (and (not ok-if-already-exists) (file-exists-p newname))
3526 (with-parsed-tramp-file-name (if t1 filename newname) nil
3527 (tramp-error
3528 v 'file-already-exists "File %s already exists" newname)))
5ec2cc41 3529
905fb90e
MA
3530 (with-parsed-tramp-file-name (if t1 filename newname) nil
3531 (tramp-message v 0 "Transferring %s to %s..." filename newname))
3532
00d6fd04
MA
3533 (prog1
3534 (cond
3535 ;; Both are Tramp files.
3536 ((and t1 t2)
3537 (with-parsed-tramp-file-name filename v1
3538 (with-parsed-tramp-file-name newname v2
3539 (cond
3540 ;; Shortcut: if method, host, user are the same for both
3541 ;; files, we invoke `cp' or `mv' on the remote host
3542 ;; directly.
3543 ((tramp-equal-remote filename newname)
3544 (tramp-do-copy-or-rename-file-directly
8d60099b
MA
3545 op filename newname
3546 ok-if-already-exists keep-date preserve-uid-gid))
3547
905fb90e 3548 ;; Try out-of-band operation.
7f49fe46
MA
3549 ((tramp-method-out-of-band-p
3550 v1 (nth 7 (file-attributes filename)))
00d6fd04
MA
3551 (tramp-do-copy-or-rename-file-out-of-band
3552 op filename newname keep-date))
8d60099b 3553
00d6fd04
MA
3554 ;; No shortcut was possible. So we copy the
3555 ;; file first. If the operation was `rename', we go
3556 ;; back and delete the original file (if the copy was
3557 ;; successful). The approach is simple-minded: we
3558 ;; create a new buffer, insert the contents of the
3559 ;; source file into it, then write out the buffer to
3560 ;; the target file. The advantage is that it doesn't
3561 ;; matter which filename handlers are used for the
3562 ;; source and target file.
3563 (t
3564 (tramp-do-copy-or-rename-file-via-buffer
3565 op filename newname keep-date))))))
3566
3567 ;; One file is a Tramp file, the other one is local.
3568 ((or t1 t2)
3569 (with-parsed-tramp-file-name (if t1 filename newname) nil
8d60099b
MA
3570 (cond
3571 ;; Fast track on local machine.
3572 ((tramp-local-host-p v)
3573 (tramp-do-copy-or-rename-file-directly
3574 op filename newname
3575 ok-if-already-exists keep-date preserve-uid-gid))
3576
3577 ;; If the Tramp file has an out-of-band method, the corresponding
3578 ;; copy-program can be invoked.
7f49fe46 3579 ((tramp-method-out-of-band-p v (nth 7 (file-attributes filename)))
8d60099b
MA
3580 (tramp-do-copy-or-rename-file-out-of-band
3581 op filename newname keep-date))
3582
3583 ;; Use the inline method via a Tramp buffer.
3584 (t (tramp-do-copy-or-rename-file-via-buffer
3585 op filename newname keep-date)))))
00d6fd04
MA
3586
3587 (t
3588 ;; One of them must be a Tramp file.
3589 (error "Tramp implementation says this cannot happen")))
8d60099b 3590
484ea0b6
MA
3591 ;; In case of `rename', we must flush the cache of the source file.
3592 (when (and t1 (eq op 'rename))
3593 (with-parsed-tramp-file-name filename nil
aac0b0f2 3594 (tramp-flush-file-property v (file-name-directory localname))
484ea0b6
MA
3595 (tramp-flush-file-property v localname)))
3596
00d6fd04
MA
3597 ;; When newname did exist, we have wrong cached values.
3598 (when t2
3599 (with-parsed-tramp-file-name newname nil
aac0b0f2 3600 (tramp-flush-file-property v (file-name-directory localname))
905fb90e
MA
3601 (tramp-flush-file-property v localname)))
3602
3603 (with-parsed-tramp-file-name (if t1 filename newname) nil
3604 (tramp-message v 0 "Transferring %s to %s...done" filename newname)))))
7432277c 3605
38c65fca 3606(defun tramp-do-copy-or-rename-file-via-buffer (op filename newname keep-date)
90dc758d
KG
3607 "Use an Emacs buffer to copy or rename a file.
3608First arg OP is either `copy' or `rename' and indicates the operation.
3609FILENAME is the source file, NEWNAME the target file.
3610KEEP-DATE is non-nil if NEWNAME should have the same timestamp as FILENAME."
8a798e41
MA
3611 (with-temp-buffer
3612 ;; We must disable multibyte, because binary data shall not be
3613 ;; converted.
3614 (set-buffer-multibyte nil)
3615 (let ((coding-system-for-read 'binary)
3616 (jka-compr-inhibit t))
3617 (insert-file-contents-literally filename))
3618 ;; We don't want the target file to be compressed, so we let-bind
3619 ;; `jka-compr-inhibit' to t.
3620 (let ((coding-system-for-write 'binary)
3621 (jka-compr-inhibit t))
3622 (write-region (point-min) (point-max) newname)))
3623 ;; KEEP-DATE handling.
3624 (when keep-date (set-file-times newname (nth 5 (file-attributes filename))))
3625 ;; Set the mode.
b86c1cd8 3626 (set-file-modes newname (tramp-default-file-modes filename))
8a798e41
MA
3627 ;; If the operation was `rename', delete the original file.
3628 (unless (eq op 'copy) (delete-file filename)))
fb7933a3
KG
3629
3630(defun tramp-do-copy-or-rename-file-directly
8d60099b 3631 (op filename newname ok-if-already-exists keep-date preserve-uid-gid)
fb7933a3
KG
3632 "Invokes `cp' or `mv' on the remote system.
3633OP must be one of `copy' or `rename', indicating `cp' or `mv',
8d60099b
MA
3634respectively. FILENAME specifies the file to copy or rename,
3635NEWNAME is the name of the new file (for copy) or the new name of
3636the file (for rename). Both files must reside on the same host.
3637KEEP-DATE means to make sure that NEWNAME has the same timestamp
3638as FILENAME. PRESERVE-UID-GID, when non-nil, instructs to keep
3639the uid and gid from FILENAME."
8a4438b6 3640 (let ((t1 (tramp-tramp-file-p filename))
4f4126e6
MA
3641 (t2 (tramp-tramp-file-p newname))
3642 (file-times (nth 5 (file-attributes filename)))
3643 (file-modes (tramp-default-file-modes filename)))
8a4438b6
MA
3644 (with-parsed-tramp-file-name (if t1 filename newname) nil
3645 (let* ((cmd (cond ((and (eq op 'copy) preserve-uid-gid) "cp -f -p")
3646 ((eq op 'copy) "cp -f")
3647 ((eq op 'rename) "mv -f")
3648 (t (tramp-error
3649 v 'file-error
3650 "Unknown operation `%s', must be `copy' or `rename'"
3651 op))))
3652 (localname1
3653 (if t1 (tramp-handle-file-remote-p filename 'localname) filename))
3654 (localname2
3655 (if t2 (tramp-handle-file-remote-p newname 'localname) newname))
293c24f9
MA
3656 (prefix (file-remote-p (if t1 filename newname)))
3657 cmd-result)
8d60099b 3658
8d60099b 3659 (cond
8a4438b6
MA
3660 ;; Both files are on a remote host, with same user.
3661 ((and t1 t2)
293c24f9
MA
3662 (setq cmd-result
3663 (tramp-send-command-and-check
3664 v
3665 (format "%s %s %s" cmd
3666 (tramp-shell-quote-argument localname1)
3667 (tramp-shell-quote-argument localname2))))
8a4438b6
MA
3668 (with-current-buffer (tramp-get-buffer v)
3669 (goto-char (point-min))
3670 (unless
3671 (or
3672 (and keep-date
3673 ;; Mask cp -f error.
3674 (re-search-forward
3675 tramp-operation-not-permitted-regexp nil t))
293c24f9 3676 (zerop cmd-result))
8a4438b6
MA
3677 (tramp-error-with-buffer
3678 nil v 'file-error
3679 "Copying directly failed, see buffer `%s' for details."
3680 (buffer-name)))))
3681
3682 ;; We are on the local host.
3683 ((or t1 t2)
8d60099b 3684 (cond
8a4438b6 3685 ;; We can do it directly.
87bdd2c7
MA
3686 ((let (file-name-handler-alist)
3687 (and (file-readable-p localname1)
3688 (file-writable-p (file-name-directory localname2))
3689 (or (file-directory-p localname2)
3690 (file-writable-p localname2))))
8d60099b 3691 (if (eq op 'copy)
9e6ab520
MA
3692 (tramp-compat-copy-file
3693 localname1 localname2 ok-if-already-exists
3694 keep-date preserve-uid-gid)
87bdd2c7
MA
3695 (tramp-run-real-handler
3696 'rename-file (list localname1 localname2 ok-if-already-exists))))
8a4438b6
MA
3697
3698 ;; We can do it directly with `tramp-send-command'
946a5aeb
MA
3699 ((and (file-readable-p (concat prefix localname1))
3700 (file-writable-p
3701 (file-name-directory (concat prefix localname2)))
3702 (or (file-directory-p (concat prefix localname2))
3703 (file-writable-p (concat prefix localname2))))
8a4438b6
MA
3704 (tramp-do-copy-or-rename-file-directly
3705 op (concat prefix localname1) (concat prefix localname2)
3706 ok-if-already-exists keep-date t)
3707 ;; We must change the ownership to the local user.
8d60099b 3708 (tramp-set-file-uid-gid
8a4438b6
MA
3709 (concat prefix localname2)
3710 (tramp-get-local-uid 'integer)
3711 (tramp-get-local-gid 'integer)))
8d60099b 3712
8a4438b6
MA
3713 ;; We need a temporary file in between.
3714 (t
2c418c5b
MA
3715 ;; Create the temporary file.
3716 (let ((tmpfile (tramp-compat-make-temp-file localname1)))
917b89a6 3717 (unwind-protect
2c418c5b
MA
3718 (progn
3719 (cond
3720 (t1
917b89a6
MA
3721 (or
3722 (zerop
3723 (tramp-send-command-and-check
3724 v (format
3725 "%s %s %s" cmd
3726 (tramp-shell-quote-argument localname1)
3727 (tramp-shell-quote-argument tmpfile))))
3728 (tramp-error-with-buffer
3729 nil v 'file-error
3730 "Copying directly failed, see buffer `%s' for details."
3731 (tramp-get-buffer v)))
2c418c5b 3732 ;; We must change the ownership as remote user.
917b89a6
MA
3733 ;; Since this does not work reliable, we also
3734 ;; give read permissions.
3735 (set-file-modes
3736 (concat prefix tmpfile) (tramp-octal-to-decimal "0777"))
2c418c5b
MA
3737 (tramp-set-file-uid-gid
3738 (concat prefix tmpfile)
3739 (tramp-get-local-uid 'integer)
3740 (tramp-get-local-gid 'integer)))
3741 (t2
3742 (if (eq op 'copy)
3743 (tramp-compat-copy-file
5ab38c3c 3744 localname1 tmpfile t
2c418c5b
MA
3745 keep-date preserve-uid-gid)
3746 (tramp-run-real-handler
3747 'rename-file
5ab38c3c 3748 (list localname1 tmpfile t)))
2c418c5b 3749 ;; We must change the ownership as local user.
917b89a6
MA
3750 ;; Since this does not work reliable, we also
3751 ;; give read permissions.
3752 (set-file-modes tmpfile (tramp-octal-to-decimal "0777"))
2c418c5b
MA
3753 (tramp-set-file-uid-gid
3754 tmpfile
3755 (tramp-get-remote-uid v 'integer)
3756 (tramp-get-remote-gid v 'integer))))
3757
3758 ;; Move the temporary file to its destination.
3759 (cond
3760 (t2
917b89a6
MA
3761 (or
3762 (zerop
3763 (tramp-send-command-and-check
3764 v (format
3765 "cp -f -p %s %s"
3766 (tramp-shell-quote-argument tmpfile)
3767 (tramp-shell-quote-argument localname2))))
3768 (tramp-error-with-buffer
3769 nil v 'file-error
3770 "Copying directly failed, see buffer `%s' for details."
3771 (tramp-get-buffer v))))
2c418c5b 3772 (t1
ce2cc728
MA
3773 (tramp-run-real-handler
3774 'rename-file
2c418c5b
MA
3775 (list tmpfile localname2 ok-if-already-exists)))))
3776
917b89a6
MA
3777 ;; Save exit.
3778 (condition-case nil
3779 (delete-file tmpfile)
3780 (error)))))))))
8d60099b
MA
3781
3782 ;; Set the time and mode. Mask possible errors.
8d60099b 3783 (condition-case nil
1f107aed 3784 (when keep-date
4f4126e6
MA
3785 (set-file-times newname file-times)
3786 (set-file-modes newname file-modes))
8d60099b
MA
3787 (error)))))
3788
5ec2cc41 3789(defun tramp-do-copy-or-rename-file-out-of-band (op filename newname keep-date)
7432277c 3790 "Invoke rcp program to copy.
905fb90e 3791The method used must be an out-of-band method."
38c65fca 3792 (let ((t1 (tramp-tramp-file-p filename))
5ec2cc41 3793 (t2 (tramp-tramp-file-p newname))
946a5aeb 3794 copy-program copy-args copy-env copy-keep-date port spec
00d6fd04
MA
3795 source target)
3796
3797 (with-parsed-tramp-file-name (if t1 filename newname) nil
905fb90e 3798 (if (and t1 t2)
00d6fd04 3799
905fb90e
MA
3800 ;; Both are Tramp files. We shall optimize it, when the
3801 ;; methods for filename and newname are the same.
9cf3544e
MA
3802 (let* ((dir-flag (file-directory-p filename))
3803 (tmpfile (tramp-compat-make-temp-file localname dir-flag)))
3804 (if dir-flag
3805 (setq tmpfile
3806 (expand-file-name
3807 (file-name-nondirectory newname) tmpfile)))
905fb90e
MA
3808 (unwind-protect
3809 (progn
3810 (tramp-do-copy-or-rename-file-out-of-band
3811 op filename tmpfile keep-date)
3812 (tramp-do-copy-or-rename-file-out-of-band
3813 'rename tmpfile newname keep-date))
3814 ;; Save exit.
3815 (condition-case nil
9cf3544e
MA
3816 (if dir-flag
3817 (delete-directory
3818 (expand-file-name ".." tmpfile) 'recursive)
3819 (delete-file tmpfile))
905fb90e
MA
3820 (error))))
3821
3822 ;; Expand hops. Might be necessary for gateway methods.
3823 (setq v (car (tramp-compute-multi-hops v)))
3824 (aset v 3 localname)
3825
3826 ;; Check which ones of source and target are Tramp files.
3827 (setq source (if t1 (tramp-make-copy-program-file-name v) filename)
263c02ef
MA
3828 target (funcall
3829 (if (and (file-directory-p filename)
3830 (string-equal
3831 (file-name-nondirectory filename)
3832 (file-name-nondirectory newname)))
3833 'file-name-directory
3834 'identity)
3835 (if t2 (tramp-make-copy-program-file-name v) newname)))
905fb90e
MA
3836
3837 ;; Check for port number. Until now, there's no need for handling
3838 ;; like method, user, host.
3839 (setq host (tramp-file-name-real-host v)
3840 port (tramp-file-name-port v)
3841 port (or (and port (number-to-string port)) ""))
3842
3843 ;; Compose copy command.
3844 (setq spec `((?h . ,host) (?u . ,user) (?p . ,port)
3845 (?t . ,(tramp-get-connection-property
3846 (tramp-get-connection-process v) "temp-file" ""))
3847 (?k . ,(if keep-date " " "")))
3848 copy-program (tramp-get-method-parameter
3849 method 'tramp-copy-program)
3850 copy-keep-date (tramp-get-method-parameter
3851 method 'tramp-copy-keep-date)
3852 copy-args
3853 (delq
3854 nil
3855 (mapcar
aa485f7c
MA
3856 (lambda (x)
3857 (setq
3858 x
3859 ;; " " is indication for keep-date argument.
3860 (delete " " (mapcar (lambda (y) (format-spec y spec)) x)))
3861 (unless (member "" x) (mapconcat 'identity x " ")))
946a5aeb
MA
3862 (tramp-get-method-parameter method 'tramp-copy-args)))
3863 copy-env
3864 (delq
3865 nil
3866 (mapcar
aa485f7c
MA
3867 (lambda (x)
3868 (setq x (mapcar (lambda (y) (format-spec y spec)) x))
3869 (unless (member "" x) (mapconcat 'identity x " ")))
946a5aeb 3870 (tramp-get-method-parameter method 'tramp-copy-env))))
905fb90e
MA
3871
3872 ;; Check for program.
3873 (when (and (fboundp 'executable-find)
3874 (not (let ((default-directory
3875 (tramp-compat-temporary-file-directory)))
3876 (executable-find copy-program))))
3877 (tramp-error
3878 v 'file-error "Cannot find copy program: %s" copy-program))
00d6fd04 3879
4265deab
MA
3880 ;; Set variables for computing the prompt for reading
3881 ;; password.
3882 (setq tramp-current-method (tramp-file-name-method v)
3883 tramp-current-user (tramp-file-name-user v)
3884 tramp-current-host (tramp-file-name-host v))
3885
905fb90e
MA
3886 (unwind-protect
3887 (with-temp-buffer
3888 ;; The default directory must be remote.
3889 (let ((default-directory
946a5aeb
MA
3890 (file-name-directory (if t1 filename newname)))
3891 (process-environment (copy-sequence process-environment)))
905fb90e
MA
3892 ;; Set the transfer process properties.
3893 (tramp-set-connection-property
3894 v "process-name" (buffer-name (current-buffer)))
3895 (tramp-set-connection-property
3896 v "process-buffer" (current-buffer))
946a5aeb
MA
3897 (while copy-env
3898 (tramp-message v 5 "%s=\"%s\"" (car copy-env) (cadr copy-env))
3899 (setenv (pop copy-env) (pop copy-env)))
905fb90e
MA
3900
3901 ;; Use an asynchronous process. By this, password can
3902 ;; be handled. The default directory must be local, in
3903 ;; order to apply the correct `copy-program'. We don't
3904 ;; set a timeout, because the copying of large files can
3905 ;; last longer than 60 secs.
3906 (let ((p (let ((default-directory
3907 (tramp-compat-temporary-file-directory)))
3908 (apply 'start-process
3909 (tramp-get-connection-property
3910 v "process-name" nil)
3911 (tramp-get-connection-property
3912 v "process-buffer" nil)
3913 copy-program
3914 (append copy-args (list source target))))))
3915 (tramp-message
3916 v 6 "%s" (mapconcat 'identity (process-command p) " "))
3917 (tramp-set-process-query-on-exit-flag p nil)
3918 (tramp-process-actions p v tramp-actions-copy-out-of-band))))
00d6fd04 3919
905fb90e
MA
3920 ;; Reset the transfer process properties.
3921 (tramp-set-connection-property v "process-name" nil)
3922 (tramp-set-connection-property v "process-buffer" nil))
00d6fd04 3923
905fb90e
MA
3924 ;; Handle KEEP-DATE argument.
3925 (when (and keep-date (not copy-keep-date))
3926 (set-file-times newname (nth 5 (file-attributes filename))))
01917a18 3927
905fb90e
MA
3928 ;; Set the mode.
3929 (unless (and keep-date copy-keep-date)
459a5f4b
MA
3930 (ignore-errors
3931 (set-file-modes newname (tramp-default-file-modes filename)))))
5ec2cc41 3932
905fb90e
MA
3933 ;; If the operation was `rename', delete the original file.
3934 (unless (eq op 'copy)
aac0b0f2
MA
3935 (if (file-regular-p filename)
3936 (delete-file filename)
3937 (delete-directory filename 'recursive))))))
7432277c 3938
fb7933a3 3939(defun tramp-handle-make-directory (dir &optional parents)
00d6fd04 3940 "Like `make-directory' for Tramp files."
ac474af1 3941 (setq dir (expand-file-name dir))
c62c9d08 3942 (with-parsed-tramp-file-name dir nil
c15cdf02 3943 (tramp-flush-directory-property v (file-name-directory localname))
b1d06e75
KG
3944 (save-excursion
3945 (tramp-barf-unless-okay
00d6fd04 3946 v
9c13938d 3947 (format "%s %s"
b1d06e75 3948 (if parents "mkdir -p" "mkdir")
7432277c 3949 (tramp-shell-quote-argument localname))
b1d06e75 3950 "Couldn't make directory %s" dir))))
fb7933a3 3951
c15cdf02 3952(defun tramp-handle-delete-directory (directory &optional recursive)
00d6fd04 3953 "Like `delete-directory' for Tramp files."
ac474af1 3954 (setq directory (expand-file-name directory))
c62c9d08 3955 (with-parsed-tramp-file-name directory nil
aac0b0f2 3956 (tramp-flush-file-property v (file-name-directory localname))
00d6fd04
MA
3957 (tramp-flush-directory-property v localname)
3958 (unless (zerop (tramp-send-command-and-check
3959 v
c15cdf02
MA
3960 (format
3961 "%s %s"
3962 (if recursive "rm -rf" "rmdir")
3963 (tramp-shell-quote-argument localname))))
00d6fd04 3964 (tramp-error v 'file-error "Couldn't delete %s" directory))))
fb7933a3
KG
3965
3966(defun tramp-handle-delete-file (filename)
00d6fd04 3967 "Like `delete-file' for Tramp files."
ac474af1 3968 (setq filename (expand-file-name filename))
c62c9d08 3969 (with-parsed-tramp-file-name filename nil
aac0b0f2 3970 (tramp-flush-file-property v (file-name-directory localname))
00d6fd04
MA
3971 (tramp-flush-file-property v localname)
3972 (unless (zerop (tramp-send-command-and-check
3973 v
3974 (format "rm -f %s"
3975 (tramp-shell-quote-argument localname))))
3976 (tramp-error v 'file-error "Couldn't delete %s" filename))))
fb7933a3
KG
3977
3978;; Dired.
3979
3980;; CCC: This does not seem to be enough. Something dies when
a4aeb9a4 3981;; we try and delete two directories under Tramp :/
fb7933a3
KG
3982(defun tramp-handle-dired-recursive-delete-directory (filename)
3983 "Recursively delete the directory given.
00d6fd04 3984This is like `dired-recursive-delete-directory' for Tramp files."
c62c9d08 3985 (with-parsed-tramp-file-name filename nil
00d6fd04 3986 ;; Run a shell command 'rm -r <localname>'
260821d3 3987 ;; Code shamelessly stolen from the dired implementation and, um, hacked :)
00d6fd04
MA
3988 (unless (file-exists-p filename)
3989 (tramp-error v 'file-error "No such directory: %s" filename))
fb7933a3 3990 ;; Which is better, -r or -R? (-r works for me <daniel@danann.net>)
00d6fd04
MA
3991 (tramp-send-command
3992 v
9c13938d 3993 (format "rm -rf %s" (tramp-shell-quote-argument localname))
00d6fd04
MA
3994 ;; Don't read the output, do it explicitely.
3995 nil t)
fb7933a3
KG
3996 ;; Wait for the remote system to return to us...
3997 ;; This might take a while, allow it plenty of time.
00d6fd04 3998 (tramp-wait-for-output (tramp-get-connection-process v) 120)
fb7933a3 3999 ;; Make sure that it worked...
aac0b0f2 4000 (tramp-flush-file-property v (file-name-directory localname))
c15cdf02 4001 (tramp-flush-directory-property v localname)
07dfe738 4002 (and (file-exists-p filename)
00d6fd04
MA
4003 (tramp-error
4004 v 'file-error "Failed to recursively delete %s" filename))))
bf247b6e 4005
5ec2cc41 4006(defun tramp-handle-dired-compress-file (file &rest ok-flag)
00d6fd04 4007 "Like `dired-compress-file' for Tramp files."
5ec2cc41
KG
4008 ;; OK-FLAG is valid for XEmacs only, but not implemented.
4009 ;; Code stolen mainly from dired-aux.el.
4010 (with-parsed-tramp-file-name file nil
00d6fd04 4011 (tramp-flush-file-property v localname)
5ec2cc41
KG
4012 (save-excursion
4013 (let ((suffixes
4014 (if (not (featurep 'xemacs))
4015 ;; Emacs case
4016 (symbol-value 'dired-compress-file-suffixes)
4017 ;; XEmacs has `dired-compression-method-alist', which is
4018 ;; transformed into `dired-compress-file-suffixes' structure.
4019 (mapcar
aa485f7c
MA
4020 (lambda (x)
4021 (list (concat (regexp-quote (nth 1 x)) "\\'")
4022 nil
4023 (mapconcat 'identity (nth 3 x) " ")))
5ec2cc41
KG
4024 (symbol-value 'dired-compression-method-alist))))
4025 suffix)
4026 ;; See if any suffix rule matches this file name.
4027 (while suffixes
4028 (let (case-fold-search)
4029 (if (string-match (car (car suffixes)) localname)
4030 (setq suffix (car suffixes) suffixes nil))
4031 (setq suffixes (cdr suffixes))))
4032
4033 (cond ((file-symlink-p file)
4034 nil)
4035 ((and suffix (nth 2 suffix))
4036 ;; We found an uncompression rule.
00d6fd04 4037 (tramp-message v 0 "Uncompressing %s..." file)
5ec2cc41 4038 (when (zerop (tramp-send-command-and-check
b593f105
MA
4039 v (concat (nth 2 suffix) " "
4040 (tramp-shell-quote-argument localname))))
00d6fd04 4041 (tramp-message v 0 "Uncompressing %s...done" file)
38c65fca
KG
4042 ;; `dired-remove-file' is not defined in XEmacs
4043 (funcall (symbol-function 'dired-remove-file) file)
5ec2cc41
KG
4044 (string-match (car suffix) file)
4045 (concat (substring file 0 (match-beginning 0)))))
4046 (t
4047 ;; We don't recognize the file as compressed, so compress it.
4048 ;; Try gzip.
00d6fd04 4049 (tramp-message v 0 "Compressing %s..." file)
5ec2cc41 4050 (when (zerop (tramp-send-command-and-check
b593f105
MA
4051 v (concat "gzip -f "
4052 (tramp-shell-quote-argument localname))))
00d6fd04 4053 (tramp-message v 0 "Compressing %s...done" file)
38c65fca
KG
4054 ;; `dired-remove-file' is not defined in XEmacs
4055 (funcall (symbol-function 'dired-remove-file) file)
5ec2cc41
KG
4056 (cond ((file-exists-p (concat file ".gz"))
4057 (concat file ".gz"))
4058 ((file-exists-p (concat file ".z"))
4059 (concat file ".z"))
4060 (t nil)))))))))
fb7933a3 4061
d5b3979c 4062(defun tramp-handle-dired-uncache (dir &optional dir-p)
70c11b0b 4063 "Like `dired-uncache' for Tramp files."
d5b3979c
MA
4064 ;; DIR-P is valid for XEmacs only.
4065 (with-parsed-tramp-file-name
4066 (if (or dir-p (file-directory-p dir)) dir (file-name-directory dir)) nil
70c11b0b
MA
4067 (tramp-flush-file-property v localname)))
4068
fb7933a3
KG
4069;; Pacify byte-compiler. The function is needed on XEmacs only. I'm
4070;; not sure at all that this is the right way to do it, but let's hope
4071;; it works for now, and wait for a guru to point out the Right Way to
4072;; achieve this.
4073;;(eval-when-compile
4074;; (unless (fboundp 'dired-insert-set-properties)
4075;; (fset 'dired-insert-set-properties 'ignore)))
4076;; Gerd suggests this:
4077(eval-when-compile (require 'dired))
4078;; Note that dired is required at run-time, too, when it is needed.
4079;; It is only needed on XEmacs for the function
4080;; `dired-insert-set-properties'.
4081
4082(defun tramp-handle-insert-directory
4083 (filename switches &optional wildcard full-directory-p)
00d6fd04
MA
4084 "Like `insert-directory' for Tramp files."
4085 (setq filename (expand-file-name filename))
4086 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
4087 (if (and (featurep 'ls-lisp)
4088 (not (symbol-value 'ls-lisp-use-insert-directory-program)))
4089 (tramp-run-real-handler
4090 'insert-directory (list filename switches wildcard full-directory-p))
0c0b61f1
MA
4091 (when (stringp switches)
4092 (setq switches (split-string switches)))
4093 (when (and (member "--dired" switches)
8e754ea2 4094 (not (tramp-get-ls-command-with-dired v)))
0c0b61f1 4095 (setq switches (delete "--dired" switches)))
c82c5727 4096 (when wildcard
87bdd2c7
MA
4097 (setq wildcard (tramp-run-real-handler
4098 'file-name-nondirectory (list localname)))
4099 (setq localname (tramp-run-real-handler
4100 'file-name-directory (list localname))))
c82c5727 4101 (unless full-directory-p
0c0b61f1
MA
4102 (setq switches (add-to-list 'switches "-d" 'append)))
4103 (setq switches (mapconcat 'tramp-shell-quote-argument switches " "))
c82c5727 4104 (when wildcard
0c0b61f1
MA
4105 (setq switches (concat switches " " wildcard)))
4106 (tramp-message
4107 v 4 "Inserting directory `ls %s %s', wildcard %s, fulldir %s"
4108 switches filename (if wildcard "yes" "no")
4109 (if full-directory-p "yes" "no"))
00d6fd04
MA
4110 ;; If `full-directory-p', we just say `ls -l FILENAME'.
4111 ;; Else we chdir to the parent directory, then say `ls -ld BASENAME'.
4112 (if full-directory-p
4113 (tramp-send-command
4114 v
fe5facd3 4115 (format "%s %s %s 2>/dev/null"
00d6fd04
MA
4116 (tramp-get-ls-command v)
4117 switches
4118 (if wildcard
4119 localname
4120 (tramp-shell-quote-argument (concat localname ".")))))
4121 (tramp-barf-unless-okay
4122 v
4123 (format "cd %s" (tramp-shell-quote-argument
87bdd2c7
MA
4124 (tramp-run-real-handler
4125 'file-name-directory (list localname))))
00d6fd04 4126 "Couldn't `cd %s'"
87bdd2c7
MA
4127 (tramp-shell-quote-argument
4128 (tramp-run-real-handler 'file-name-directory (list localname))))
00d6fd04
MA
4129 (tramp-send-command
4130 v
4131 (format "%s %s %s"
4132 (tramp-get-ls-command v)
4133 switches
4134 (if (or wildcard
87bdd2c7
MA
4135 (zerop (length
4136 (tramp-run-real-handler
4137 'file-name-nondirectory (list localname)))))
00d6fd04
MA
4138 ""
4139 (tramp-shell-quote-argument
87bdd2c7
MA
4140 (tramp-run-real-handler
4141 'file-name-nondirectory (list localname)))))))
8e754ea2
MA
4142 (let ((beg (point)))
4143 ;; We cannot use `insert-buffer-substring' because the Tramp
4144 ;; buffer changes its contents before insertion due to calling
4145 ;; `expand-file' and alike.
4146 (insert
4147 (with-current-buffer (tramp-get-buffer v)
4148 (buffer-string)))
4149
4150 ;; Check for "--dired" output.
8e754ea2 4151 (forward-line -2)
7f4d4a97
MA
4152 (when (looking-at "//SUBDIRED//")
4153 (forward-line -1))
8e754ea2 4154 (when (looking-at "//DIRED//")
7ba1d9c2 4155 (let ((end (tramp-compat-line-end-position))
8e754ea2
MA
4156 (linebeg (point)))
4157 ;; Now read the numeric positions of file names.
4158 (goto-char linebeg)
4159 (forward-word 1)
4160 (forward-char 3)
4161 (while (< (point) end)
4162 (let ((start (+ beg (read (current-buffer))))
4163 (end (+ beg (read (current-buffer)))))
7f49fe46 4164 (if (memq (char-after end) '(?\n ?\ ))
8e754ea2 4165 ;; End is followed by \n or by " -> ".
fe5facd3
MA
4166 (put-text-property start end 'dired-filename t))))))
4167 ;; Remove trailing lines.
4168 (goto-char (tramp-compat-line-beginning-position))
4169 (while (looking-at "//")
4170 (forward-line 1)
4171 (delete-region (match-beginning 0) (point)))
0c0b61f1
MA
4172
4173 ;; The inserted file could be from somewhere else.
4174 (when (and (not wildcard) (not full-directory-p))
4175 (goto-char (point-max))
e5c70c41
MA
4176 (when (file-symlink-p filename)
4177 (goto-char (search-backward "->" beg 'noerror)))
0c0b61f1
MA
4178 (search-backward
4179 (if (zerop (length (file-name-nondirectory filename)))
4180 "."
4181 (file-name-nondirectory filename))
4182 beg 'noerror)
4183 (replace-match (file-relative-name filename) t))
4184
fe5facd3 4185 (goto-char (point-max))))))
fb7933a3 4186
fb7933a3 4187(defun tramp-handle-unhandled-file-name-directory (filename)
00d6fd04 4188 "Like `unhandled-file-name-directory' for Tramp files."
8a798e41
MA
4189 ;; With Emacs 23, we could simply return `nil'. But we must keep it
4190 ;; for backward compatibility.
ce3f516f 4191 (expand-file-name "~/"))
fb7933a3
KG
4192
4193;; Canonicalization of file names.
4194
fb7933a3 4195(defun tramp-handle-expand-file-name (name &optional dir)
00d6fd04 4196 "Like `expand-file-name' for Tramp files.
7432277c
KG
4197If the localname part of the given filename starts with \"/../\" then
4198the result will be a local, non-Tramp, filename."
fb7933a3
KG
4199 ;; If DIR is not given, use DEFAULT-DIRECTORY or "/".
4200 (setq dir (or dir default-directory "/"))
4201 ;; Unless NAME is absolute, concat DIR and NAME.
4202 (unless (file-name-absolute-p name)
4203 (setq name (concat (file-name-as-directory dir) name)))
00d6fd04 4204 ;; If NAME is not a Tramp file, run the real handler.
fb7933a3 4205 (if (not (tramp-tramp-file-p name))
00d6fd04 4206 (tramp-run-real-handler 'expand-file-name (list name nil))
fb7933a3 4207 ;; Dissect NAME.
c62c9d08 4208 (with-parsed-tramp-file-name name nil
87bdd2c7 4209 (unless (tramp-run-real-handler 'file-name-absolute-p (list localname))
7432277c 4210 (setq localname (concat "~/" localname)))
00d6fd04
MA
4211 ;; Tilde expansion if necessary. This needs a shell which
4212 ;; groks tilde expansion! The function `tramp-find-shell' is
4213 ;; supposed to find such a shell on the remote host. Please
4214 ;; tell me about it when this doesn't work on your system.
4215 (when (string-match "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname)
4216 (let ((uname (match-string 1 localname))
4217 (fname (match-string 2 localname)))
4218 ;; We cannot simply apply "~/", because under sudo "~/" is
4219 ;; expanded to the local user home directory but to the
4220 ;; root home directory. On the other hand, using always
4221 ;; the default user name for tilde expansion is not
4222 ;; appropriate either, because ssh and companions might
4223 ;; use a user name from the config file.
4224 (when (and (string-equal uname "~")
4225 (string-match "\\`su\\(do\\)?\\'" method))
4226 (setq uname (concat uname user)))
4227 (setq uname
b593f105
MA
4228 (with-connection-property v uname
4229 (tramp-send-command
4230 v (format "cd %s; pwd" (tramp-shell-quote-argument uname)))
4231 (with-current-buffer (tramp-get-buffer v)
4232 (goto-char (point-min))
4233 (buffer-substring
4234 (point) (tramp-compat-line-end-position)))))
00d6fd04
MA
4235 (setq localname (concat uname fname))))
4236 ;; There might be a double slash, for example when "~/"
cb85dcd0 4237 ;; expands to "/". Remove this.
00d6fd04
MA
4238 (while (string-match "//" localname)
4239 (setq localname (replace-match "/" t t localname)))
4240 ;; No tilde characters in file name, do normal
a17632c1
MA
4241 ;; `expand-file-name' (this does "/./" and "/../"). We bind
4242 ;; `directory-sep-char' here for XEmacs on Windows, which would
4243 ;; otherwise use backslash. `default-directory' is bound,
4244 ;; because on Windows there would be problems with UNC shares or
4245 ;; Cygwin mounts.
aff67808
MA
4246 (let ((directory-sep-char ?/)
4247 (default-directory (tramp-compat-temporary-file-directory)))
4248 (tramp-make-tramp-file-name
4249 method user host
4250 (tramp-drop-volume-letter
87bdd2c7
MA
4251 (tramp-run-real-handler
4252 'expand-file-name (list localname))))))))
00d6fd04 4253
c23c3394
MA
4254(defun tramp-replace-environment-variables (filename)
4255 "Replace environment variables in FILENAME.
4256Return the string with the replaced variables."
2e271195 4257 (save-match-data
ec5145d6 4258 (let ((idx (string-match "$\\(\\w+\\)" filename)))
2e271195 4259 ;; `$' is coded as `$$'.
ec5145d6
MA
4260 (when (and idx
4261 (or (zerop idx) (not (eq ?$ (aref filename (1- idx)))))
4262 (getenv (match-string 1 filename)))
2e271195
MA
4263 (setq filename
4264 (replace-match
4265 (substitute-in-file-name (match-string 0 filename))
4266 t nil filename)))
4267 filename)))
c23c3394 4268
00d6fd04
MA
4269(defun tramp-handle-substitute-in-file-name (filename)
4270 "Like `substitute-in-file-name' for Tramp files.
4271\"//\" and \"/~\" substitute only in the local filename part.
4272If the URL Tramp syntax is chosen, \"//\" as method delimeter and \"/~\" at
4273beginning of local filename are not substituted."
c23c3394
MA
4274 ;; First, we must replace environment variables.
4275 (setq filename (tramp-replace-environment-variables filename))
00d6fd04
MA
4276 (with-parsed-tramp-file-name filename nil
4277 (if (equal tramp-syntax 'url)
4278 ;; We need to check localname only. The other parts cannot contain
4279 ;; "//" or "/~".
4280 (if (and (> (length localname) 1)
4281 (or (string-match "//" localname)
4282 (string-match "/~" localname 1)))
4283 (tramp-run-real-handler 'substitute-in-file-name (list filename))
4284 (tramp-make-tramp-file-name
4285 (when method (substitute-in-file-name method))
4286 (when user (substitute-in-file-name user))
4287 (when host (substitute-in-file-name host))
87bdd2c7
MA
4288 (when localname
4289 (tramp-run-real-handler
4290 'substitute-in-file-name (list localname)))))
00d6fd04
MA
4291 ;; Ignore in LOCALNAME everything before "//" or "/~".
4292 (when (and (stringp localname) (string-match ".+?/\\(/\\|~\\)" localname))
4293 (setq filename
b08104a0
MA
4294 (concat (file-remote-p filename)
4295 (replace-match "\\1" nil nil localname)))
00d6fd04
MA
4296 ;; "/m:h:~" does not work for completion. We use "/m:h:~/".
4297 (when (string-match "~$" filename)
4298 (setq filename (concat filename "/"))))
4299 (tramp-run-real-handler 'substitute-in-file-name (list filename)))))
4300
4301;; In XEmacs, electricity is implemented via a key map for ?/ and ?~,
4302;; which calls corresponding functions (see minibuf.el).
4303(when (fboundp 'minibuffer-electric-separator)
9e6ab520 4304 (mapc
aa485f7c
MA
4305 (lambda (x)
4306 (eval
4307 `(defadvice ,x
4308 (around ,(intern (format "tramp-advice-%s" x)) activate)
4309 "Invoke `substitute-in-file-name' for Tramp files."
4310 (if (and (symbol-value 'minibuffer-electric-file-name-behavior)
4311 (tramp-tramp-file-p (buffer-substring)))
4312 ;; We don't need to handle `last-input-event', because
4313 ;; due to the key map we know it must be ?/ or ?~.
4314 (let ((s (concat (buffer-substring (point-min) (point))
4315 (string last-command-char))))
4316 (delete-region (point-min) (point))
4317 (insert (substitute-in-file-name s))
4318 (setq ad-return-value last-command-char))
d7ec1df7
MA
4319 ad-do-it)))
4320 (eval
4321 `(add-hook
4322 'tramp-unload-hook
4323 (lambda ()
4324 (ad-remove-advice ',x 'around ',(intern (format "tramp-advice-%s" x)))
4325 (ad-activate ',x)))))
00d6fd04
MA
4326
4327 '(minibuffer-electric-separator
4328 minibuffer-electric-tilde)))
4329
4330
0664ff72 4331;;; Remote commands:
fb7933a3 4332
00d6fd04
MA
4333(defun tramp-handle-executable-find (command)
4334 "Like `executable-find' for Tramp files."
4335 (with-parsed-tramp-file-name default-directory nil
f84638eb 4336 (tramp-find-executable v command (tramp-get-remote-path v) t)))
00d6fd04
MA
4337
4338;; We use BUFFER also as connection buffer during setup. Because of
4339;; this, its original contents must be saved, and restored once
4340;; connection has been setup.
4341(defun tramp-handle-start-file-process (name buffer program &rest args)
4342 "Like `start-file-process' for Tramp files."
4343 (with-parsed-tramp-file-name default-directory nil
9fb2cdc5
GM
4344 (unless (stringp program)
4345 (tramp-error
4346 v 'file-error "pty association is not supported for `%s'" name))
00d6fd04 4347 (unwind-protect
263c02ef
MA
4348 (let ((command (format "cd %s; exec %s"
4349 (tramp-shell-quote-argument localname)
4350 (mapconcat 'tramp-shell-quote-argument
4351 (cons program args) " ")))
4352 (name1 name)
38d63e6a 4353 (i 0))
2296b54d 4354 (unless buffer
6ce63faf 4355 ;; BUFFER can be nil. We use a temporary buffer.
2296b54d 4356 (setq buffer (generate-new-buffer tramp-temp-buffer-name)))
38d63e6a
MA
4357 (while (get-process name1)
4358 ;; NAME must be unique as process name.
4359 (setq i (1+ i)
4360 name1 (format "%s<%d>" name i)))
4361 (setq name name1)
00d6fd04
MA
4362 ;; Set the new process properties.
4363 (tramp-set-connection-property v "process-name" name)
2296b54d 4364 (tramp-set-connection-property v "process-buffer" buffer)
00d6fd04 4365 ;; Activate narrowing in order to save BUFFER contents.
11c71217
MA
4366 ;; Clear also the modification time; otherwise we might be
4367 ;; interrupted by `verify-visited-file-modtime'.
00d6fd04 4368 (with-current-buffer (tramp-get-connection-buffer v)
11c71217 4369 (clear-visited-file-modtime)
00d6fd04 4370 (narrow-to-region (point-max) (point-max)))
263c02ef 4371 ;; Send the command. `tramp-send-command' opens a new
00d6fd04 4372 ;; connection.
263c02ef 4373 (tramp-send-command v command nil t) ; nooutput
6ce63faf
MA
4374 ;; Set query flag for this process.
4375 (tramp-set-process-query-on-exit-flag
4376 (tramp-get-connection-process v) t)
00d6fd04
MA
4377 ;; Return process.
4378 (tramp-get-connection-process v))
4379 ;; Save exit.
ce3f516f 4380 (with-current-buffer (tramp-get-connection-buffer v)
6ce63faf
MA
4381 (if (string-match tramp-temp-buffer-name (buffer-name))
4382 (progn
4383 (set-process-buffer (tramp-get-connection-process v) nil)
4384 (kill-buffer (current-buffer)))
4385 (widen)
4386 (goto-char (point-max))))
00d6fd04
MA
4387 (tramp-set-connection-property v "process-name" nil)
4388 (tramp-set-connection-property v "process-buffer" nil))))
4389
4390(defun tramp-handle-process-file
4391 (program &optional infile destination display &rest args)
4392 "Like `process-file' for Tramp files."
4393 ;; The implementation is not complete yet.
4394 (when (and (numberp destination) (zerop destination))
4395 (error "Implementation does not handle immediate return"))
4396
4397 (with-parsed-tramp-file-name default-directory nil
a6e96327 4398 (let (command input tmpinput stderr tmpstderr outbuf ret)
00d6fd04
MA
4399 ;; Compute command.
4400 (setq command (mapconcat 'tramp-shell-quote-argument
4401 (cons program args) " "))
4402 ;; Determine input.
4403 (if (null infile)
4404 (setq input "/dev/null")
4405 (setq infile (expand-file-name infile))
4406 (if (tramp-equal-remote default-directory infile)
4407 ;; INFILE is on the same remote host.
4408 (setq input (with-parsed-tramp-file-name infile nil localname))
4409 ;; INFILE must be copied to remote host.
a6e96327
MA
4410 (setq input (tramp-make-tramp-temp-file v)
4411 tmpinput (tramp-make-tramp-file-name method user host input))
4412 (copy-file infile tmpinput t)))
00d6fd04
MA
4413 (when input (setq command (format "%s <%s" command input)))
4414
4415 ;; Determine output.
4416 (cond
bede3e9f 4417 ;; Just a buffer.
00d6fd04
MA
4418 ((bufferp destination)
4419 (setq outbuf destination))
bede3e9f 4420 ;; A buffer name.
00d6fd04
MA
4421 ((stringp destination)
4422 (setq outbuf (get-buffer-create destination)))
4423 ;; (REAL-DESTINATION ERROR-DESTINATION)
4424 ((consp destination)
bede3e9f 4425 ;; output.
00d6fd04
MA
4426 (cond
4427 ((bufferp (car destination))
4428 (setq outbuf (car destination)))
4429 ((stringp (car destination))
0664ff72
MA
4430 (setq outbuf (get-buffer-create (car destination))))
4431 ((car destination)
4432 (setq outbuf (current-buffer))))
bede3e9f 4433 ;; stderr.
00d6fd04
MA
4434 (cond
4435 ((stringp (cadr destination))
4436 (setcar (cdr destination) (expand-file-name (cadr destination)))
4437 (if (tramp-equal-remote default-directory (cadr destination))
4438 ;; stderr is on the same remote host.
4439 (setq stderr (with-parsed-tramp-file-name
4440 (cadr destination) nil localname))
4441 ;; stderr must be copied to remote host. The temporary
4442 ;; file must be deleted after execution.
a6e96327
MA
4443 (setq stderr (tramp-make-tramp-temp-file v)
4444 tmpstderr (tramp-make-tramp-file-name
4445 method user host stderr))))
bede3e9f 4446 ;; stderr to be discarded.
00d6fd04
MA
4447 ((null (cadr destination))
4448 (setq stderr "/dev/null"))))
4449 ;; 't
4450 (destination
4451 (setq outbuf (current-buffer))))
4452 (when stderr (setq command (format "%s 2>%s" command stderr)))
4453
00d6fd04
MA
4454 ;; Send the command. It might not return in time, so we protect it.
4455 (condition-case nil
4456 (unwind-protect
293c24f9
MA
4457 (setq ret
4458 (tramp-send-command-and-check
4459 v (format "\\cd %s; %s"
4460 (tramp-shell-quote-argument localname)
b593f105
MA
4461 command)
4462 nil t))
00d6fd04
MA
4463 ;; We should show the output anyway.
4464 (when outbuf
293c24f9
MA
4465 (with-current-buffer outbuf
4466 (insert
4467 (with-current-buffer (tramp-get-connection-buffer v)
4468 (buffer-string))))
00d6fd04 4469 (when display (display-buffer outbuf))))
260821d3
MA
4470 ;; When the user did interrupt, we should do it also. We use
4471 ;; return code -1 as marker.
4472 (quit
4473 (kill-buffer (tramp-get-connection-buffer v))
4474 (setq ret -1))
4475 ;; Handle errors.
00d6fd04
MA
4476 (error
4477 (kill-buffer (tramp-get-connection-buffer v))
4478 (setq ret 1)))
a6e96327 4479
a6e96327
MA
4480 ;; Provide error file.
4481 (when tmpstderr (rename-file tmpstderr (cadr destination) t))
263c02ef 4482
260821d3
MA
4483 ;; Cleanup. We remove all file cache values for the connection,
4484 ;; because the remote process could have changed them.
a6e96327 4485 (when tmpinput (delete-file tmpinput))
946a5aeb
MA
4486
4487 ;; `process-file-side-effects' has been introduced with GNU
4488 ;; Emacs 23.2. If set to `nil', no remote file will be changed
4489 ;; by `program'. If it doesn't exist, we assume its default
4490 ;; value 't'.
4491 (unless (and (boundp 'process-file-side-effects)
4492 (not (symbol-value 'process-file-side-effects)))
4493 (tramp-flush-directory-property v ""))
4494
00d6fd04 4495 ;; Return exit status.
260821d3
MA
4496 (if (equal ret -1)
4497 (keyboard-quit)
4498 ret))))
00d6fd04 4499
a4aeb9a4
MA
4500(defun tramp-local-call-process
4501 (program &optional infile destination display &rest args)
4502 "Calls `call-process' on the local host.
4503This is needed because for some Emacs flavors Tramp has
4504defadviced `call-process' to behave like `process-file'. The
4505Lisp error raised when PROGRAM is nil is trapped also, returning 1."
4506 (let ((default-directory
4507 (if (file-remote-p default-directory)
4508 (tramp-compat-temporary-file-directory)
4509 default-directory)))
4510 (if (executable-find program)
4511 (apply 'call-process program infile destination display args)
4512 1)))
4513
00d6fd04
MA
4514(defun tramp-handle-call-process-region
4515 (start end program &optional delete buffer display &rest args)
4516 "Like `call-process-region' for Tramp files."
258800f8 4517 (let ((tmpfile (tramp-compat-make-temp-file "")))
00d6fd04
MA
4518 (write-region start end tmpfile)
4519 (when delete (delete-region start end))
4520 (unwind-protect
4521 (apply 'call-process program tmpfile buffer display args)
4522 (delete-file tmpfile))))
4523
4524(defun tramp-handle-shell-command
4525 (command &optional output-buffer error-buffer)
4526 "Like `shell-command' for Tramp files."
ce3f516f 4527 (let* ((asynchronous (string-match "[ \t]*&[ \t]*\\'" command))
b8bfcf96
MA
4528 ;; We cannot use `shell-file-name' and `shell-command-switch',
4529 ;; they are variables of the local host.
4530 (args (list "/bin/sh" "-c" (substring command 0 asynchronous)))
5d2ebd96 4531 current-buffer-p
ce3f516f 4532 (output-buffer
27e813fe
MA
4533 (cond
4534 ((bufferp output-buffer) output-buffer)
4535 ((stringp output-buffer) (get-buffer-create output-buffer))
5d2ebd96
AS
4536 (output-buffer
4537 (setq current-buffer-p t)
4538 (current-buffer))
42bc9b6d 4539 (t (get-buffer-create
27e813fe
MA
4540 (if asynchronous
4541 "*Async Shell Command*"
4542 "*Shell Command Output*")))))
4543 (error-buffer
4544 (cond
4545 ((bufferp error-buffer) error-buffer)
4546 ((stringp error-buffer) (get-buffer-create error-buffer))))
ce3f516f 4547 (buffer
27e813fe 4548 (if (and (not asynchronous) error-buffer)
ce3f516f
MA
4549 (with-parsed-tramp-file-name default-directory nil
4550 (list output-buffer (tramp-make-tramp-temp-file v)))
42bc9b6d 4551 output-buffer))
cfb5c0db 4552 (p (get-buffer-process output-buffer)))
42bc9b6d
MA
4553
4554 ;; Check whether there is another process running. Tramp does not
4555 ;; support 2 (asynchronous) processes in parallel.
cfb5c0db 4556 (when p
42bc9b6d 4557 (if (yes-or-no-p "A command is running. Kill it? ")
699a11fb
GM
4558 (condition-case nil
4559 (kill-process p)
4560 (error nil))
42bc9b6d
MA
4561 (error "Shell command in progress")))
4562
f34db316
AS
4563 (if current-buffer-p
4564 (progn
4565 (barf-if-buffer-read-only)
4566 (push-mark nil t))
5d2ebd96
AS
4567 (with-current-buffer output-buffer
4568 (setq buffer-read-only nil)
4569 (erase-buffer)))
42bc9b6d 4570
5d2ebd96 4571 (if (and (not current-buffer-p) (integerp asynchronous))
42bc9b6d
MA
4572 (prog1
4573 ;; Run the process.
3412f35d 4574 (apply 'start-file-process "*Async Shell*" buffer args)
42bc9b6d 4575 ;; Display output.
cfb5c0db
MA
4576 (pop-to-buffer output-buffer)
4577 (setq mode-line-process '(":%s"))
4578 (require 'shell) (shell-mode))
42bc9b6d
MA
4579
4580 (prog1
4581 ;; Run the process.
4582 (apply 'process-file (car args) nil buffer nil (cdr args))
4583 ;; Insert error messages if they were separated.
4584 (when (listp buffer)
4585 (with-current-buffer error-buffer
4586 (insert-file-contents (cadr buffer)))
4587 (delete-file (cadr buffer)))
f34db316
AS
4588 (if current-buffer-p
4589 ;; This is like exchange-point-and-mark, but doesn't
4590 ;; activate the mark. It is cleaner to avoid activation,
4591 ;; even though the command loop would deactivate the mark
4592 ;; because we inserted text.
4593 (goto-char (prog1 (mark t)
4594 (set-marker (mark-marker) (point)
4595 (current-buffer))))
4596 ;; There's some output, display it.
4597 (when (with-current-buffer output-buffer (> (point-max) (point-min)))
4598 (if (functionp 'display-message-or-buffer)
4599 (funcall (symbol-function 'display-message-or-buffer)
4600 output-buffer)
4601 (pop-to-buffer output-buffer))))))))
00d6fd04
MA
4602
4603;; File Editing.
4604
4605(defvar tramp-handle-file-local-copy-hook nil
4606 "Normal hook to be run at the end of `tramp-handle-file-local-copy'.")
4607
fb7933a3 4608(defun tramp-handle-file-local-copy (filename)
00d6fd04 4609 "Like `file-local-copy' for Tramp files."
0f205eee 4610
c62c9d08 4611 (with-parsed-tramp-file-name filename nil
2988341a
MA
4612 (unless (file-exists-p filename)
4613 (tramp-error
4614 v 'file-error
4615 "Cannot make local copy of non-existing file `%s'" filename))
4616
0f205eee 4617 (let ((rem-enc (tramp-get-remote-coding v "remote-encoding"))
00d6fd04 4618 (loc-dec (tramp-get-local-coding v "local-decoding"))
258800f8 4619 (tmpfile (tramp-compat-make-temp-file filename)))
5ec2cc41 4620
2988341a
MA
4621 (condition-case err
4622 (cond
4623 ;; `copy-file' handles direct copy and out-of-band methods.
4624 ((or (tramp-local-host-p v)
7f49fe46
MA
4625 (tramp-method-out-of-band-p
4626 v (nth 7 (file-attributes filename))))
2988341a
MA
4627 (copy-file filename tmpfile t t))
4628
4629 ;; Use inline encoding for file transfer.
4630 (rem-enc
4631 (save-excursion
4632 (tramp-message v 5 "Encoding remote file %s..." filename)
4633 (tramp-barf-unless-okay
4634 v
4635 (format "%s < %s" rem-enc (tramp-shell-quote-argument localname))
4636 "Encoding remote file failed")
4637 (tramp-message v 5 "Encoding remote file %s...done" filename)
4638
4639 (if (and (symbolp loc-dec) (fboundp loc-dec))
4640 ;; If local decoding is a function, we call it. We
4641 ;; must disable multibyte, because
4642 ;; `uudecode-decode-region' doesn't handle it
4643 ;; correctly.
0f205eee
MA
4644 (with-temp-buffer
4645 (set-buffer-multibyte nil)
4646 (insert-buffer-substring (tramp-get-buffer v))
4647 (tramp-message
4648 v 5 "Decoding remote file %s with function %s..."
4649 filename loc-dec)
4650 (funcall loc-dec (point-min) (point-max))
aa485f7c
MA
4651 ;; Unset `file-name-handler-alist'. Otherwise,
4652 ;; epa-file gets confused.
4653 (let (file-name-handler-alist
4654 (coding-system-for-write 'binary))
2988341a
MA
4655 (write-region (point-min) (point-max) tmpfile)))
4656
4657 ;; If tramp-decoding-function is not defined for this
4658 ;; method, we invoke tramp-decoding-command instead.
4659 (let ((tmpfile2 (tramp-compat-make-temp-file filename)))
aa485f7c
MA
4660 ;; Unset `file-name-handler-alist'. Otherwise,
4661 ;; epa-file gets confused.
4662 (let (file-name-handler-alist
4663 (coding-system-for-write 'binary))
2988341a
MA
4664 (write-region (point-min) (point-max) tmpfile2))
4665 (tramp-message
4666 v 5 "Decoding remote file %s with command %s..."
4667 filename loc-dec)
4668 (unwind-protect
4669 (tramp-call-local-coding-command loc-dec tmpfile2 tmpfile)
4670 (delete-file tmpfile2))))
4671
4672 (tramp-message v 5 "Decoding remote file %s...done" filename)
4673 ;; Set proper permissions.
b86c1cd8 4674 (set-file-modes tmpfile (tramp-default-file-modes filename))
2988341a
MA
4675 ;; Set local user ownership.
4676 (tramp-set-file-uid-gid tmpfile)))
4677
4678 ;; Oops, I don't know what to do.
4679 (t (tramp-error
4680 v 'file-error "Wrong method specification for `%s'" method)))
4681
4682 ;; Error handling.
4683 ((error quit)
4684 (delete-file tmpfile)
4685 (signal (car err) (cdr err))))
0f205eee 4686
00d6fd04 4687 (run-hooks 'tramp-handle-file-local-copy-hook)
94be87e8 4688 tmpfile)))
fb7933a3 4689
bce04fee 4690(defun tramp-handle-file-remote-p (filename &optional identification connected)
00d6fd04 4691 "Like `file-remote-p' for Tramp files."
d5b3979c
MA
4692 (let ((tramp-verbose 3))
4693 (when (tramp-tramp-file-p filename)
4694 (let* ((v (tramp-dissect-file-name filename))
4695 (p (tramp-get-connection-process v))
4696 (c (and p (processp p) (memq (process-status p) '(run open)))))
4697 ;; We expand the file name only, if there is already a connection.
4698 (with-parsed-tramp-file-name
4699 (if c (expand-file-name filename) filename) nil
4700 (and (or (not connected) c)
4701 (cond
4702 ((eq identification 'method) method)
4703 ((eq identification 'user) user)
4704 ((eq identification 'host) host)
4705 ((eq identification 'localname) localname)
4706 (t (tramp-make-tramp-file-name method user host "")))))))))
fb7933a3 4707
eb562962
MA
4708(defun tramp-find-file-name-coding-system-alist (filename tmpname)
4709 "Like `find-operation-coding-system' for Tramp filenames.
4710Tramp's `insert-file-contents' and `write-region' work over
4711temporary file names. If `file-coding-system-alist' contains an
4712expression, which matches more than the file name suffix, the
4713coding system might not be determined. This function repairs it."
4714 (let (result)
4715 (dolist (elt file-coding-system-alist result)
4716 (when (and (consp elt) (string-match (car elt) filename))
4717 ;; We found a matching entry in `file-coding-system-alist'.
4718 ;; So we add a similar entry, but with the temporary file name
4719 ;; as regexp.
4720 (add-to-list
4721 'result (cons (regexp-quote tmpname) (cdr elt)) 'append)))))
4722
fb7933a3
KG
4723(defun tramp-handle-insert-file-contents
4724 (filename &optional visit beg end replace)
00d6fd04 4725 "Like `insert-file-contents' for Tramp files."
fb7933a3
KG
4726 (barf-if-buffer-read-only)
4727 (setq filename (expand-file-name filename))
736ac90f 4728 (let (coding-system-used result local-copy remote-copy)
2ac33804
MA
4729 (with-parsed-tramp-file-name filename nil
4730 (unwind-protect
70c11b0b
MA
4731 (if (not (file-exists-p filename))
4732 ;; We don't raise a Tramp error, because it might be
4733 ;; suppressed, like in `find-file-noselect-1'.
4734 (signal 'file-error
4735 (list "File not found on remote host" filename))
4736
4737 (if (and (tramp-local-host-p v)
4738 (let (file-name-handler-alist)
4739 (file-readable-p localname)))
4740 ;; Short track: if we are on the local host, we can
4741 ;; run directly.
4742 (setq result
4743 (tramp-run-real-handler
4744 'insert-file-contents
4745 (list localname visit beg end replace)))
4746
736ac90f
MA
4747 ;; When we shall insert only a part of the file, we copy
4748 ;; this part.
4749 (when (or beg end)
4750 (setq remote-copy (tramp-make-tramp-temp-file v))
4751 (tramp-send-command
4752 v
4753 (cond
4754 ((and beg end)
4755 (format "tail -c +%d %s | head -c +%d >%s"
4756 (1+ beg) (tramp-shell-quote-argument localname)
4757 (- end beg) remote-copy))
4758 (beg
4759 (format "tail -c +%d %s >%s"
4760 (1+ beg) (tramp-shell-quote-argument localname)
4761 remote-copy))
4762 (end
4763 (format "head -c +%d %s >%s"
4764 (1+ end) (tramp-shell-quote-argument localname)
4765 remote-copy)))))
4766
70c11b0b
MA
4767 ;; `insert-file-contents-literally' takes care to avoid
4768 ;; calling jka-compr. By let-binding
4769 ;; `inhibit-file-name-operation', we propagate that care
4770 ;; to the `file-local-copy' operation.
4771 (setq local-copy
4772 (let ((inhibit-file-name-operation
4773 (when (eq inhibit-file-name-operation
4774 'insert-file-contents)
4775 'file-local-copy)))
b88f2d0a
MA
4776 (cond
4777 ((stringp remote-copy)
4778 (file-local-copy
4779 (tramp-make-tramp-file-name
4780 method user host remote-copy)))
4781 ((stringp tramp-temp-buffer-file-name)
4782 (copy-file filename tramp-temp-buffer-file-name 'ok)
4783 tramp-temp-buffer-file-name)
4784 (t (file-local-copy filename)))))
4785
6e4f5731
MA
4786 ;; When the file is not readable for the owner, it
4787 ;; cannot be inserted, even it is redable for the group
4788 ;; or for everybody.
4789 (set-file-modes local-copy (tramp-octal-to-decimal "0600"))
4790
b88f2d0a
MA
4791 (when (and (null remote-copy)
4792 (tramp-get-method-parameter
4793 method 'tramp-copy-keep-tmpfile))
4794 ;; We keep the local file for performance reasons,
4795 ;; useful for "rsync".
b88f2d0a
MA
4796 (setq tramp-temp-buffer-file-name local-copy)
4797 (put 'tramp-temp-buffer-file-name 'permanent-local t))
4798
70c11b0b
MA
4799 (tramp-message
4800 v 4 "Inserting local temp file `%s'..." local-copy)
4801
4802 ;; We must ensure that `file-coding-system-alist'
4803 ;; matches `local-copy'.
4804 (let ((file-coding-system-alist
4805 (tramp-find-file-name-coding-system-alist
4806 filename local-copy)))
4807 (setq result
4808 (insert-file-contents
736ac90f 4809 local-copy nil nil nil replace))
70c11b0b
MA
4810 ;; Now `last-coding-system-used' has right value.
4811 ;; Remember it.
4812 (when (boundp 'last-coding-system-used)
4813 (setq coding-system-used
4814 (symbol-value 'last-coding-system-used))))
8d60099b 4815
70c11b0b
MA
4816 (tramp-message
4817 v 4 "Inserting local temp file `%s'...done" local-copy)
4818 (when (boundp 'last-coding-system-used)
2ac33804 4819 (set 'last-coding-system-used coding-system-used))))
70c11b0b 4820
2ac33804
MA
4821 ;; Save exit.
4822 (progn
4823 (when visit
4824 (setq buffer-file-name filename)
4825 (setq buffer-read-only (not (file-writable-p filename)))
4826 (set-visited-file-modtime)
4827 (set-buffer-modified-p nil))
b88f2d0a
MA
4828 (when (and (stringp local-copy)
4829 (or remote-copy (null tramp-temp-buffer-file-name)))
2ac33804
MA
4830 (delete-file local-copy))
4831 (when (stringp remote-copy)
4832 (delete-file
4833 (tramp-make-tramp-file-name method user host remote-copy))))))
70c11b0b
MA
4834
4835 ;; Result.
4836 (list (expand-file-name filename)
4837 (cadr result))))
fb7933a3 4838
94be87e8
MA
4839;; This is needed for XEmacs only. Code stolen from files.el.
4840(defun tramp-handle-insert-file-contents-literally
4841 (filename &optional visit beg end replace)
4842 "Like `insert-file-contents-literally' for Tramp files."
4843 (let ((format-alist nil)
4844 (after-insert-file-functions nil)
4845 (coding-system-for-read 'no-conversion)
4846 (coding-system-for-write 'no-conversion)
4847 (find-buffer-file-type-function
4848 (if (fboundp 'find-buffer-file-type)
4849 (symbol-function 'find-buffer-file-type)
4850 nil))
4851 (inhibit-file-name-handlers '(jka-compr-handler image-file-handler))
4852 (inhibit-file-name-operation 'insert-file-contents))
4853 (unwind-protect
4854 (progn
4855 (fset 'find-buffer-file-type (lambda (filename) t))
4856 (insert-file-contents filename visit beg end replace))
70c11b0b 4857 ;; Save exit.
94be87e8
MA
4858 (if find-buffer-file-type-function
4859 (fset 'find-buffer-file-type find-buffer-file-type-function)
4860 (fmakunbound 'find-buffer-file-type)))))
4861
38c65fca 4862(defun tramp-handle-find-backup-file-name (filename)
00d6fd04 4863 "Like `find-backup-file-name' for Tramp files."
07dfe738
KG
4864 (with-parsed-tramp-file-name filename nil
4865 ;; We set both variables. It doesn't matter whether it is
4866 ;; Emacs or XEmacs
4867 (let ((backup-directory-alist
4868 ;; Emacs case
4869 (when (boundp 'backup-directory-alist)
b86c1cd8 4870 (if (symbol-value 'tramp-backup-directory-alist)
07dfe738 4871 (mapcar
aa485f7c
MA
4872 (lambda (x)
4873 (cons
4874 (car x)
4875 (if (and (stringp (cdr x))
4876 (file-name-absolute-p (cdr x))
4877 (not (tramp-file-name-p (cdr x))))
4878 (tramp-make-tramp-file-name method user host (cdr x))
4879 (cdr x))))
07dfe738
KG
4880 (symbol-value 'tramp-backup-directory-alist))
4881 (symbol-value 'backup-directory-alist))))
4882
4883 (bkup-backup-directory-info
4884 ;; XEmacs case
4885 (when (boundp 'bkup-backup-directory-info)
b86c1cd8 4886 (if (symbol-value 'tramp-bkup-backup-directory-info)
07dfe738 4887 (mapcar
aa485f7c
MA
4888 (lambda (x)
4889 (nconc
4890 (list (car x))
4891 (list
4892 (if (and (stringp (car (cdr x)))
4893 (file-name-absolute-p (car (cdr x)))
4894 (not (tramp-file-name-p (car (cdr x)))))
4895 (tramp-make-tramp-file-name
4896 method user host (car (cdr x)))
4897 (car (cdr x))))
4898 (cdr (cdr x))))
07dfe738
KG
4899 (symbol-value 'tramp-bkup-backup-directory-info))
4900 (symbol-value 'bkup-backup-directory-info)))))
4901
4902 (tramp-run-real-handler 'find-backup-file-name (list filename)))))
38c65fca 4903
c1105d05 4904(defun tramp-handle-make-auto-save-file-name ()
00d6fd04 4905 "Like `make-auto-save-file-name' for Tramp files.
c1105d05 4906Returns a file name in `tramp-auto-save-directory' for autosaving this file."
00d6fd04
MA
4907 (let ((tramp-auto-save-directory tramp-auto-save-directory)
4908 (buffer-file-name
4909 (tramp-subst-strs-in-string
4910 '(("_" . "|")
4911 ("/" . "_a")
4912 (":" . "_b")
4913 ("|" . "__")
4914 ("[" . "_l")
4915 ("]" . "_r"))
4916 (buffer-file-name))))
1a762140
MA
4917 ;; File name must be unique. This is ensured with Emacs 22 (see
4918 ;; UNIQUIFY element of `auto-save-file-name-transforms'); but for
4919 ;; all other cases we must do it ourselves.
4920 (when (boundp 'auto-save-file-name-transforms)
9e6ab520 4921 (mapc
aa485f7c
MA
4922 (lambda (x)
4923 (when (and (string-match (car x) buffer-file-name)
4924 (not (car (cddr x))))
4925 (setq tramp-auto-save-directory
4926 (or tramp-auto-save-directory
4927 (tramp-compat-temporary-file-directory)))))
1a762140
MA
4928 (symbol-value 'auto-save-file-name-transforms)))
4929 ;; Create directory.
4930 (when tramp-auto-save-directory
00d6fd04
MA
4931 (setq buffer-file-name
4932 (expand-file-name buffer-file-name tramp-auto-save-directory))
1a762140
MA
4933 (unless (file-exists-p tramp-auto-save-directory)
4934 (make-directory tramp-auto-save-directory t)))
00d6fd04
MA
4935 ;; Run plain `make-auto-save-file-name'. There might be an advice when
4936 ;; it is not a magic file name operation (since Emacs 22).
4937 ;; We must deactivate it temporarily.
4938 (if (not (ad-is-active 'make-auto-save-file-name))
4939 (tramp-run-real-handler 'make-auto-save-file-name nil)
4940 ;; else
4941 (ad-deactivate 'make-auto-save-file-name)
4942 (prog1
4943 (tramp-run-real-handler 'make-auto-save-file-name nil)
4944 (ad-activate 'make-auto-save-file-name)))))
4945
4946(defvar tramp-handle-write-region-hook nil
4947 "Normal hook to be run at the end of `tramp-handle-write-region'.")
4948
b88f2d0a 4949;; CCC grok LOCKNAME
fb7933a3
KG
4950(defun tramp-handle-write-region
4951 (start end filename &optional append visit lockname confirm)
00d6fd04 4952 "Like `write-region' for Tramp files."
fb7933a3 4953 (setq filename (expand-file-name filename))
c62c9d08 4954 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
4955 ;; Following part commented out because we don't know what to do about
4956 ;; file locking, and it does not appear to be a problem to ignore it.
4957 ;; Ange-ftp ignores it, too.
4958 ;; (when (and lockname (stringp lockname))
4959 ;; (setq lockname (expand-file-name lockname)))
4960 ;; (unless (or (eq lockname nil)
4961 ;; (string= lockname filename))
4962 ;; (error
4963 ;; "tramp-handle-write-region: LOCKNAME must be nil or equal FILENAME"))
8d60099b 4964
94be87e8 4965 ;; XEmacs takes a coding system as the seventh argument, not `confirm'.
00d6fd04
MA
4966 (when (and (not (featurep 'xemacs)) confirm (file-exists-p filename))
4967 (unless (y-or-n-p (format "File %s exists; overwrite anyway? " filename))
4968 (tramp-error v 'file-error "File not overwritten")))
8d60099b 4969
a4aeb9a4 4970 (let ((uid (or (nth 2 (tramp-compat-file-attributes filename 'integer))
9c13938d 4971 (tramp-get-remote-uid v 'integer)))
a4aeb9a4 4972 (gid (or (nth 3 (tramp-compat-file-attributes filename 'integer))
9c13938d
MA
4973 (tramp-get-remote-gid v 'integer))))
4974
4975 (if (and (tramp-local-host-p v)
93c3eb7c 4976 ;; `file-writable-p' calls `file-expand-file-name'. We
87bdd2c7
MA
4977 ;; cannot use `tramp-run-real-handler' therefore.
4978 (let (file-name-handler-alist)
82f3844e
MA
4979 (and
4980 (file-writable-p (file-name-directory localname))
4981 (or (file-directory-p localname)
4982 (file-writable-p localname)))))
9c13938d 4983 ;; Short track: if we are on the local host, we can run directly.
aac0b0f2
MA
4984 (tramp-run-real-handler
4985 'write-region
4986 (list start end localname append 'no-message lockname confirm))
9c13938d
MA
4987
4988 (let ((rem-dec (tramp-get-remote-coding v "remote-decoding"))
4989 (loc-enc (tramp-get-local-coding v "local-encoding"))
b86c1cd8 4990 (modes (save-excursion (tramp-default-file-modes filename)))
9c13938d
MA
4991 ;; We use this to save the value of
4992 ;; `last-coding-system-used' after writing the tmp file.
4993 ;; At the end of the function, we set
4994 ;; `last-coding-system-used' to this saved value. This
4995 ;; way, any intermediary coding systems used while
4996 ;; talking to the remote shell or suchlike won't hose
4997 ;; this variable. This approach was snarfed from
4998 ;; ange-ftp.el.
4999 coding-system-used
5000 ;; Write region into a tmp file. This isn't really
5001 ;; needed if we use an encoding function, but currently
5002 ;; we use it always because this makes the logic
293c24f9
MA
5003 ;; simpler.
5004 (tmpfile (or tramp-temp-buffer-file-name
5005 (tramp-compat-make-temp-file filename))))
5006
5007 ;; If `append' is non-nil, we copy the file locally, and let
5008 ;; the native `write-region' implementation do the job.
5009 (when append (copy-file filename tmpfile 'ok))
9c13938d
MA
5010
5011 ;; We say `no-message' here because we don't want the
5012 ;; visited file modtime data to be clobbered from the temp
5013 ;; file. We call `set-visited-file-modtime' ourselves later
eb562962
MA
5014 ;; on. We must ensure that `file-coding-system-alist'
5015 ;; matches `tmpfile'.
5016 (let ((file-coding-system-alist
5017 (tramp-find-file-name-coding-system-alist filename tmpfile)))
ce2cc728
MA
5018 (condition-case err
5019 (tramp-run-real-handler
5020 'write-region
5021 (list start end tmpfile append 'no-message lockname confirm))
2988341a 5022 ((error quit)
b88f2d0a 5023 (setq tramp-temp-buffer-file-name nil)
2988341a
MA
5024 (delete-file tmpfile)
5025 (signal (car err) (cdr err))))
ce2cc728 5026
eb562962
MA
5027 ;; Now, `last-coding-system-used' has the right value. Remember it.
5028 (when (boundp 'last-coding-system-used)
5029 (setq coding-system-used
5030 (symbol-value 'last-coding-system-used))))
5031
9c13938d
MA
5032 ;; The permissions of the temporary file should be set. If
5033 ;; filename does not exist (eq modes nil) it has been
5034 ;; renamed to the backup file. This case `save-buffer'
5035 ;; handles permissions.
459a5f4b
MA
5036 ;; Ensure, that it is still readable.
5037 (when modes
5038 (set-file-modes
5039 tmpfile (logior (or modes 0) (tramp-octal-to-decimal "0400"))))
9c13938d
MA
5040
5041 ;; This is a bit lengthy due to the different methods
5042 ;; possible for file transfer. First, we check whether the
5043 ;; method uses an rcp program. If so, we call it.
5044 ;; Otherwise, both encoding and decoding command must be
5045 ;; specified. However, if the method _also_ specifies an
5046 ;; encoding function, then that is used for encoding the
5047 ;; contents of the tmp file.
5048 (cond
00cffdeb 5049 ;; `copy-file' handles direct copy and out-of-band methods.
9c13938d 5050 ((or (tramp-local-host-p v)
7f49fe46 5051 (tramp-method-out-of-band-p
00cffdeb
MA
5052 v (nth 7 (file-attributes tmpfile))))
5053 (if (and (not (stringp start))
5054 (= (or end (point-max)) (point-max))
191bb792
MA
5055 (= (or start (point-min)) (point-min))
5056 (tramp-get-method-parameter
5057 method 'tramp-copy-keep-tmpfile))
5058 (progn
5059 (setq tramp-temp-buffer-file-name tmpfile)
5060 (condition-case err
b88f2d0a
MA
5061 ;; We keep the local file for performance
5062 ;; reasons, useful for "rsync".
191bb792
MA
5063 (copy-file tmpfile filename t)
5064 ((error quit)
5065 (setq tramp-temp-buffer-file-name nil)
5066 (delete-file tmpfile)
5067 (signal (car err) (cdr err)))))
5068 (setq tramp-temp-buffer-file-name nil)
5069 ;; Don't rename, in order to keep context in SELinux.
5070 (unwind-protect
5071 (copy-file tmpfile filename t)
5072 (delete-file tmpfile))))
9c13938d 5073
1d7e9a01 5074 ;; Use inline file transfer.
9c13938d 5075 (rem-dec
1d7e9a01 5076 ;; Encode tmpfile.
9c13938d
MA
5077 (tramp-message v 5 "Encoding region...")
5078 (unwind-protect
5079 (with-temp-buffer
5080 ;; Use encoding function or command.
5081 (if (and (symbolp loc-enc) (fboundp loc-enc))
5082 (progn
5083 (tramp-message
5084 v 5 "Encoding region using function `%s'..."
5085 (symbol-name loc-enc))
5086 (let ((coding-system-for-read 'binary))
5087 (insert-file-contents-literally tmpfile))
70c11b0b
MA
5088 ;; The following `let' is a workaround for the
5089 ;; base64.el that comes with pgnus-0.84. If
5090 ;; both of the following conditions are
5091 ;; satisfied, it tries to write to a local
5092 ;; file in default-directory, but at this
5093 ;; point, default-directory is remote.
5094 ;; (`call-process-region' can't write to
5095 ;; remote files, it seems.) The file in
5096 ;; question is a tmp file anyway.
9c13938d
MA
5097 (let ((default-directory
5098 (tramp-compat-temporary-file-directory)))
5099 (funcall loc-enc (point-min) (point-max))))
8d60099b 5100
9c13938d
MA
5101 (tramp-message
5102 v 5 "Encoding region using command `%s'..." loc-enc)
5103 (unless (equal 0 (tramp-call-local-coding-command
5104 loc-enc tmpfile t))
5105 (tramp-error
5106 v 'file-error
5107 "Cannot write to `%s', local encoding command `%s' failed"
5108 filename loc-enc)))
5109
5110 ;; Send buffer into remote decoding command which
5111 ;; writes to remote file. Because this happens on
5112 ;; the remote host, we cannot use the function.
5113 (goto-char (point-max))
5114 (unless (bolp) (newline))
8d60099b 5115 (tramp-message
9c13938d
MA
5116 v 5 "Decoding region into remote file %s..." filename)
5117 (tramp-send-command
5118 v
5119 (format
5120 "%s >%s <<'EOF'\n%sEOF"
5121 rem-dec
5122 (tramp-shell-quote-argument localname)
5123 (buffer-string)))
5124 (tramp-barf-unless-okay
5125 v nil
5126 "Couldn't write region to `%s', decode using `%s' failed"
5127 filename rem-dec)
5128 ;; When `file-precious-flag' is set, the region is
5129 ;; written to a temporary file. Check that the
5130 ;; checksum is equal to that from the local tmpfile.
5131 (when file-precious-flag
5132 (erase-buffer)
5133 (and
a4aeb9a4
MA
5134 ;; cksum runs locally, if possible.
5135 (zerop (tramp-local-call-process "cksum" tmpfile t))
5136 ;; cksum runs remotely.
9c13938d
MA
5137 (zerop
5138 (tramp-send-command-and-check
5139 v
5140 (format
5141 "cksum <%s" (tramp-shell-quote-argument localname))))
a4aeb9a4 5142 ;; ... they are different.
9c13938d
MA
5143 (not
5144 (string-equal
5145 (buffer-string)
5146 (with-current-buffer (tramp-get-buffer v)
5147 (buffer-string))))
5148 (tramp-error
5149 v 'file-error
5150 (concat "Couldn't write region to `%s',"
5151 " decode using `%s' failed")
5152 filename rem-dec)))
5153 (tramp-message
aac0b0f2 5154 v 5 "Decoding region into remote file %s...done" filename))
8d60099b 5155
9c13938d
MA
5156 ;; Save exit.
5157 (delete-file tmpfile)))
8d60099b 5158
9c13938d
MA
5159 ;; That's not expected.
5160 (t
5161 (tramp-error
5162 v 'file-error
5163 (concat "Method `%s' should specify both encoding and "
5164 "decoding command or an rcp program")
5165 method)))
258800f8 5166
9c13938d
MA
5167 ;; Make `last-coding-system-used' have the right value.
5168 (when coding-system-used
5169 (set 'last-coding-system-used coding-system-used))))
0f205eee 5170
aac0b0f2
MA
5171 (tramp-flush-file-property v (file-name-directory localname))
5172 (tramp-flush-file-property v localname)
5173
57671b72
MA
5174 ;; We must protect `last-coding-system-used', now we have set it
5175 ;; to its correct value.
293c24f9 5176 (let (last-coding-system-used (need-chown t))
57671b72
MA
5177 ;; Set file modification time.
5178 (when (or (eq visit t) (stringp visit))
293c24f9
MA
5179 (let ((file-attr (file-attributes filename)))
5180 (set-visited-file-modtime
5181 ;; We must pass modtime explicitely, because filename can
5182 ;; be different from (buffer-file-name), f.e. if
5183 ;; `file-precious-flag' is set.
5184 (nth 5 file-attr))
5185 (when (and (eq (nth 2 file-attr) uid)
5186 (eq (nth 3 file-attr) gid))
5187 (setq need-chown nil))))
57671b72
MA
5188
5189 ;; Set the ownership.
293c24f9
MA
5190 (when need-chown
5191 (tramp-set-file-uid-gid filename uid gid))
57671b72
MA
5192 (when (or (eq visit t) (null visit) (stringp visit))
5193 (tramp-message v 0 "Wrote %s" filename))
5194 (run-hooks 'tramp-handle-write-region-hook)))))
fb7933a3 5195
946a5aeb
MA
5196(defvar tramp-vc-registered-file-names nil
5197 "List used to collect file names, which are checked during `vc-registered'.")
5198
5199;; VC backends check for the existence of various different special
5200;; files. This is very time consuming, because every single check
5201;; requires a remote command (the file cache must be invalidated).
5202;; Therefore, we apply a kind of optimization. We install the file
5203;; name handler `tramp-vc-file-name-handler', which does nothing but
5204;; remembers all file names for which `file-exists-p' or
5205;; `file-readable-p' has been applied. A first run of `vc-registered'
5206;; is performed. Afterwards, a script is applied for all collected
5207;; file names, using just one remote command. The result of this
5208;; script is used to fill the file cache with actual values. Now we
5209;; can reset the file name handlers, and we make a second run of
5210;; `vc-registered', which returns the expected result without sending
5211;; any other remote command.
49096407
MA
5212(defun tramp-handle-vc-registered (file)
5213 "Like `vc-registered' for Tramp files."
946a5aeb 5214 (with-parsed-tramp-file-name file nil
7f49fe46
MA
5215
5216 ;; There could be new files, created by the vc backend. We cannot
5217 ;; reuse the old cache entries, therefore.
946a5aeb
MA
5218 (let (tramp-vc-registered-file-names
5219 (tramp-cache-inhibit-cache (current-time))
5220 (file-name-handler-alist
5221 `((,tramp-file-name-regexp . tramp-vc-file-name-handler))))
5222
5223 ;; Here we collect only file names, which need an operation.
5224 (tramp-run-real-handler 'vc-registered (list file))
5225 (tramp-message v 10 "\n%s" tramp-vc-registered-file-names)
5226
5227 ;; Send just one command, in order to fill the cache.
7f49fe46
MA
5228 (when tramp-vc-registered-file-names
5229 (tramp-maybe-send-script
5230 v
5231 (format tramp-vc-registered-read-file-names
5232 (tramp-get-file-exists-command v)
5233 (format "%s -r" (tramp-get-test-command v)))
5234 "tramp_vc_registered_read_file_names")
5235
5236 (dolist
5237 (elt
5238 (tramp-send-command-and-read
5239 v
5240 (format
5241 "tramp_vc_registered_read_file_names %s"
5242 (mapconcat 'tramp-shell-quote-argument
5243 tramp-vc-registered-file-names
5244 " "))))
946a5aeb 5245
7f49fe46 5246 (tramp-set-file-property v (car elt) (cadr elt) (cadr (cdr elt))))))
946a5aeb 5247
7f49fe46
MA
5248 ;; Second run. Now all `file-exists-p' or `file-readable-p' calls
5249 ;; shall be answered from the file cache.
5250 ;; We unset `process-file-side-effects' in order to keep the cache
5251 ;; when `process-file' calls appear.
946a5aeb
MA
5252 (let (process-file-side-effects)
5253 (tramp-run-real-handler 'vc-registered (list file)))))
49096407 5254
a01b1e22
MA
5255;;;###autoload
5256(progn (defun tramp-run-real-handler (operation args)
fb7933a3 5257 "Invoke normal file name handler for OPERATION.
c62c9d08
KG
5258First arg specifies the OPERATION, second arg is a list of arguments to
5259pass to the OPERATION."
4007ba5b
KG
5260 (let* ((inhibit-file-name-handlers
5261 `(tramp-file-name-handler
946a5aeb 5262 tramp-vc-file-name-handler
4007ba5b
KG
5263 tramp-completion-file-name-handler
5264 cygwin-mount-name-hook-function
5265 cygwin-mount-map-drive-hook-function
5266 .
5267 ,(and (eq inhibit-file-name-operation operation)
5268 inhibit-file-name-handlers)))
5269 (inhibit-file-name-operation operation))
a01b1e22 5270 (apply operation args))))
16674e4f 5271
a01b1e22
MA
5272;;;###autoload
5273(progn (defun tramp-completion-run-real-handler (operation args)
16674e4f
KG
5274 "Invoke `tramp-file-name-handler' for OPERATION.
5275First arg specifies the OPERATION, second arg is a list of arguments to
5276pass to the OPERATION."
4007ba5b
KG
5277 (let* ((inhibit-file-name-handlers
5278 `(tramp-completion-file-name-handler
5279 cygwin-mount-name-hook-function
5280 cygwin-mount-map-drive-hook-function
5281 .
5282 ,(and (eq inhibit-file-name-operation operation)
5283 inhibit-file-name-handlers)))
5284 (inhibit-file-name-operation operation))
a01b1e22 5285 (apply operation args))))
fb7933a3 5286
4007ba5b
KG
5287;; We handle here all file primitives. Most of them have the file
5288;; name as first parameter; nevertheless we check for them explicitly
04bf5b65 5289;; in order to be signaled if a new primitive appears. This
4007ba5b
KG
5290;; scenario is needed because there isn't a way to decide by
5291;; syntactical means whether a foreign method must be called. It would
19a87064 5292;; ease the life if `file-name-handler-alist' would support a decision
4007ba5b
KG
5293;; function as well but regexp only.
5294(defun tramp-file-name-for-operation (operation &rest args)
5295 "Return file name related to OPERATION file primitive.
5296ARGS are the arguments OPERATION has been called with."
5297 (cond
5298 ; FILE resp DIRECTORY
5299 ((member operation
5300 (list 'access-file 'byte-compiler-base-file-name 'delete-directory
5301 'delete-file 'diff-latest-backup-file 'directory-file-name
5302 'directory-files 'directory-files-and-attributes
5303 'dired-compress-file 'dired-uncache
5304 'file-accessible-directory-p 'file-attributes
5305 'file-directory-p 'file-executable-p 'file-exists-p
19a87064
MA
5306 'file-local-copy 'file-remote-p 'file-modes
5307 'file-name-as-directory 'file-name-directory
5308 'file-name-nondirectory 'file-name-sans-versions
5309 'file-ownership-preserved-p 'file-readable-p
5310 'file-regular-p 'file-symlink-p 'file-truename
5311 'file-writable-p 'find-backup-file-name 'find-file-noselect
5312 'get-file-buffer 'insert-directory 'insert-file-contents
5313 'load 'make-directory 'make-directory-internal
5314 'set-file-modes 'substitute-in-file-name
5315 'unhandled-file-name-directory 'vc-registered
ce3f516f
MA
5316 ; Emacs 22 only
5317 'set-file-times
4007ba5b
KG
5318 ; XEmacs only
5319 'abbreviate-file-name 'create-file-buffer
5320 'dired-file-modtime 'dired-make-compressed-filename
5321 'dired-recursive-delete-directory 'dired-set-file-modtime
5322 'dired-shell-unhandle-file-name 'dired-uucode-file
5615d63f 5323 'insert-file-contents-literally 'make-temp-name 'recover-file
4007ba5b 5324 'vm-imap-check-mail 'vm-pop-check-mail 'vm-spool-check-mail))
8daea7fc
KG
5325 (if (file-name-absolute-p (nth 0 args))
5326 (nth 0 args)
5327 (expand-file-name (nth 0 args))))
4007ba5b
KG
5328 ; FILE DIRECTORY resp FILE1 FILE2
5329 ((member operation
5330 (list 'add-name-to-file 'copy-file 'expand-file-name
5331 'file-name-all-completions 'file-name-completion
5332 'file-newer-than-file-p 'make-symbolic-link 'rename-file
263c02ef
MA
5333 ; Emacs 23 only
5334 'copy-directory
4007ba5b
KG
5335 ; XEmacs only
5336 'dired-make-relative-symlink
5337 'vm-imap-move-mail 'vm-pop-move-mail 'vm-spool-move-mail))
5338 (save-match-data
5339 (cond
5340 ((string-match tramp-file-name-regexp (nth 0 args)) (nth 0 args))
5341 ((string-match tramp-file-name-regexp (nth 1 args)) (nth 1 args))
5342 (t (buffer-file-name (current-buffer))))))
5343 ; START END FILE
5344 ((eq operation 'write-region)
5345 (nth 2 args))
5346 ; BUF
5347 ((member operation
00d6fd04 5348 (list 'set-visited-file-modtime 'verify-visited-file-modtime
b50dd0d2 5349 ; since Emacs 22 only
00d6fd04
MA
5350 'make-auto-save-file-name
5351 ; XEmacs only
4007ba5b
KG
5352 'backup-buffer))
5353 (buffer-file-name
5354 (if (bufferp (nth 0 args)) (nth 0 args) (current-buffer))))
5355 ; COMMAND
5356 ((member operation
00d6fd04
MA
5357 (list ; not in Emacs 23
5358 'dired-call-process
01917a18 5359 ; Emacs only
b71c9e75 5360 'shell-command
00d6fd04 5361 ; since Emacs 22 only
0457dd55 5362 'process-file
00d6fd04
MA
5363 ; since Emacs 23 only
5364 'start-file-process
4007ba5b 5365 ; XEmacs only
00d6fd04
MA
5366 'dired-print-file 'dired-shell-call-process
5367 ; nowhere yet
5368 'executable-find 'start-process 'call-process))
4007ba5b
KG
5369 default-directory)
5370 ; unknown file primitive
5371 (t (error "unknown file I/O primitive: %s" operation))))
5372
5373(defun tramp-find-foreign-file-name-handler (filename)
5374 "Return foreign file name handler if exists."
9ce8462a
MA
5375 (when (and (stringp filename) (tramp-tramp-file-p filename))
5376 (let ((v (tramp-dissect-file-name filename t))
5377 (handler tramp-foreign-file-name-handler-alist)
5378 elt res)
5379 ;; When we are not fully sure that filename completion is safe,
5380 ;; we should not return a handler.
5381 (when (or (tramp-file-name-method v) (tramp-file-name-user v)
1834b39f
MA
5382 (and (tramp-file-name-host v)
5383 (not (member (tramp-file-name-host v)
5384 (mapcar 'car tramp-methods))))
9ce8462a
MA
5385 (not (tramp-completion-mode-p)))
5386 (while handler
5387 (setq elt (car handler)
5388 handler (cdr handler))
5389 (when (funcall (car elt) filename)
5390 (setq handler nil
5391 res (cdr elt))))
5392 res))))
4007ba5b 5393
fb7933a3
KG
5394;; Main function.
5395;;;###autoload
5396(defun tramp-file-name-handler (operation &rest args)
ea9d1443 5397 "Invoke Tramp file name handler.
a4aeb9a4 5398Falls back to normal file name handler if no Tramp file name handler exists."
2e271195
MA
5399 (if tramp-mode
5400 (save-match-data
5401 (let* ((filename
5402 (tramp-replace-environment-variables
5403 (apply 'tramp-file-name-for-operation operation args)))
5404 (completion (tramp-completion-mode-p))
5405 (foreign (tramp-find-foreign-file-name-handler filename)))
5406 (with-parsed-tramp-file-name filename nil
5407 (cond
5408 ;; When we are in completion mode, some operations
5409 ;; shouldn't be handled by backend.
5410 ((and completion (zerop (length localname))
5411 (memq operation '(file-exists-p file-directory-p)))
5412 t)
5413 ((and completion (zerop (length localname))
5414 (memq operation '(file-name-as-directory)))
5415 filename)
5416 ;; Call the backend function.
5417 (foreign (apply foreign operation args))
5418 ;; Nothing to do for us.
5419 (t (tramp-run-real-handler operation args))))))
5420 ;; When `tramp-mode' is not enabled, we don't do anything.
5421 (tramp-run-real-handler operation args)))
fb7933a3 5422
07dfe738
KG
5423;; In Emacs, there is some concurrency due to timers. If a timer
5424;; interrupts Tramp and wishes to use the same connection buffer as
5425;; the "main" Emacs, then garbage might occur in the connection
5426;; buffer. Therefore, we need to make sure that a timer does not use
5427;; the same connection buffer as the "main" Emacs. We implement a
5428;; cheap global lock, instead of locking each connection buffer
5429;; separately. The global lock is based on two variables,
5430;; `tramp-locked' and `tramp-locker'. `tramp-locked' is set to true
5431;; (with setq) to indicate a lock. But Tramp also calls itself during
5432;; processing of a single file operation, so we need to allow
5433;; recursive calls. That's where the `tramp-locker' variable comes in
5434;; -- it is let-bound to t during the execution of the current
5435;; handler. So if `tramp-locked' is t and `tramp-locker' is also t,
5436;; then we should just proceed because we have been called
5437;; recursively. But if `tramp-locker' is nil, then we are a timer
5438;; interrupting the "main" Emacs, and then we signal an error.
5439
5440(defvar tramp-locked nil
5441 "If non-nil, then Tramp is currently busy.
5442Together with `tramp-locker', this implements a locking mechanism
5443preventing reentrant calls of Tramp.")
5444
5445(defvar tramp-locker nil
5446 "If non-nil, then a caller has locked Tramp.
5447Together with `tramp-locked', this implements a locking mechanism
5448preventing reentrant calls of Tramp.")
5449
ea9d1443
KG
5450(defun tramp-sh-file-name-handler (operation &rest args)
5451 "Invoke remote-shell Tramp file name handler.
5452Fall back to normal file name handler if no Tramp handler exists."
07dfe738 5453 (when (and tramp-locked (not tramp-locker))
11c71217 5454 (setq tramp-locked nil)
00d6fd04 5455 (signal 'file-error (list "Forbidden reentrant call of Tramp")))
07dfe738
KG
5456 (let ((tl tramp-locked))
5457 (unwind-protect
5458 (progn
5459 (setq tramp-locked t)
5460 (let ((tramp-locker t))
5461 (save-match-data
5462 (let ((fn (assoc operation tramp-file-name-handler-alist)))
5463 (if fn
5464 (apply (cdr fn) args)
5465 (tramp-run-real-handler operation args))))))
5466 (setq tramp-locked tl))))
ea9d1443 5467
946a5aeb
MA
5468(defun tramp-vc-file-name-handler (operation &rest args)
5469 "Invoke special file name handler, which collects files to be handled."
5470 (save-match-data
5471 (let ((filename
5472 (tramp-replace-environment-variables
5473 (apply 'tramp-file-name-for-operation operation args)))
5474 (fn (assoc operation tramp-file-name-handler-alist)))
5475 (with-parsed-tramp-file-name filename nil
5476 (cond
5477 ;; That's what we want: file names, for which checks are
5478 ;; applied. We assume, that VC uses only `file-exists-p' and
5479 ;; `file-readable-p' checks; otherwise we must extend the
5480 ;; list. We do not perform any action, but return nil, in
5481 ;; order to keep `vc-registered' running.
5482 ((and fn (memq operation '(file-exists-p file-readable-p)))
5483 (add-to-list 'tramp-vc-registered-file-names localname 'append)
5484 nil)
5485 ;; Tramp file name handlers like `expand-file-name'. They
5486 ;; must still work.
5487 (fn
5488 (save-match-data (apply (cdr fn) args)))
5489 ;; Default file name handlers, we don't care.
5490 (t (tramp-run-real-handler operation args)))))))
5491
16674e4f 5492;;;###autoload
1ecc6145 5493(progn (defun tramp-completion-file-name-handler (operation &rest args)
a4aeb9a4
MA
5494 "Invoke Tramp file name completion handler.
5495Falls back to normal file name handler if no Tramp file name handler exists."
57671b72
MA
5496 ;; We bind `directory-sep-char' here for XEmacs on Windows, which
5497 ;; would otherwise use backslash.
aff67808
MA
5498 (let ((directory-sep-char ?/)
5499 (fn (assoc operation tramp-completion-file-name-handler-alist)))
aa485f7c
MA
5500 (if (and
5501 ;; When `tramp-mode' is not enabled, we don't do anything.
5502 fn tramp-mode
5503 ;; For other syntaxes than `sep', the regexp matches many common
5504 ;; situations where the user doesn't actually want to use Tramp.
5505 ;; So to avoid autoloading Tramp after typing just "/s", we
5506 ;; disable this part of the completion, unless the user implicitly
5507 ;; indicated his interest in using a fancier completion system.
5508 (or (eq tramp-syntax 'sep)
5509 (featurep 'tramp) ; If it's loaded, we may as well use it.
5510 (and (boundp 'partial-completion-mode) partial-completion-mode)
5511 ;; FIXME: These may have been loaded even if the user never
5512 ;; intended to use them.
5513 (featurep 'ido)
5514 (featurep 'icicles)))
aff67808
MA
5515 (save-match-data (apply (cdr fn) args))
5516 (tramp-completion-run-real-handler operation args)))))
a01b1e22 5517
b25a52cc 5518;;;###autoload
aa485f7c
MA
5519(progn (defun tramp-register-file-name-handlers ()
5520 "Add Tramp file name handlers to `file-name-handler-alist'."
5521 ;; Remove autoloaded handlers from file name handler alist. Useful,
00d6fd04
MA
5522 ;; if `tramp-syntax' has been changed.
5523 (let ((a1 (rassq 'tramp-file-name-handler file-name-handler-alist)))
aa485f7c
MA
5524 (setq file-name-handler-alist (delq a1 file-name-handler-alist)))
5525 (let ((a1 (rassq
5526 'tramp-completion-file-name-handler file-name-handler-alist)))
5527 (setq file-name-handler-alist (delq a1 file-name-handler-alist)))
5528 ;; Add the handlers.
a01b1e22
MA
5529 (add-to-list 'file-name-handler-alist
5530 (cons tramp-file-name-regexp 'tramp-file-name-handler))
0c0b61f1 5531 (put 'tramp-file-name-handler 'safe-magic t)
aa485f7c
MA
5532 (add-to-list 'file-name-handler-alist
5533 (cons tramp-completion-file-name-regexp
5534 'tramp-completion-file-name-handler))
5535 (put 'tramp-completion-file-name-handler 'safe-magic t)
5536 ;; If jka-compr or epa-file are already loaded, move them to the
5537 ;; front of `file-name-handler-alist'.
5538 (dolist (fnh '(epa-file-handler jka-compr-handler))
5539 (let ((entry (rassoc fnh file-name-handler-alist)))
5540 (when entry
5541 (setq file-name-handler-alist
5542 (cons entry (delete entry file-name-handler-alist))))))))
69cee873 5543
00d6fd04
MA
5544;; `tramp-file-name-handler' must be registered before evaluation of
5545;; site-start and init files, because there might exist remote files
5546;; already, f.e. files kept via recentf-mode.
aa485f7c
MA
5547;;;###autoload(tramp-register-file-name-handlers)
5548(tramp-register-file-name-handlers)
b25a52cc 5549
fb7933a3 5550;;;###autoload
8c04e197 5551(defun tramp-unload-file-name-handlers ()
a69c01a0
MA
5552 (setq file-name-handler-alist
5553 (delete (rassoc 'tramp-file-name-handler
5554 file-name-handler-alist)
5555 (delete (rassoc 'tramp-completion-file-name-handler
5556 file-name-handler-alist)
5557 file-name-handler-alist))))
5558
8c04e197 5559(add-hook 'tramp-unload-hook 'tramp-unload-file-name-handlers)
a69c01a0 5560
0664ff72 5561;;; File name handler functions for completion mode:
a6e96327
MA
5562
5563(defvar tramp-completion-mode nil
5564 "If non-nil, external packages signal that they are in file name completion.
5565
5566This is necessary, because Tramp uses a heuristic depending on last
5567input event. This fails when external packages use other characters
5568but <TAB>, <SPACE> or ?\\? for file name completion. This variable
5569should never be set globally, the intention is to let-bind it.")
16674e4f
KG
5570
5571;; Necessary because `tramp-file-name-regexp-unified' and
00d6fd04
MA
5572;; `tramp-completion-file-name-regexp-unified' aren't different. If
5573;; nil, `tramp-completion-run-real-handler' is called (i.e. forwarding
5574;; to `tramp-file-name-handler'). Otherwise, it takes
5575;; `tramp-run-real-handler'. Using `last-input-event' is a little bit
5576;; risky, because completing a file might require loading other files,
5577;; like "~/.netrc", and for them it shouldn't be decided based on that
5578;; variable. On the other hand, those files shouldn't have partial
a4aeb9a4
MA
5579;; Tramp file name syntax. Maybe another variable should be introduced
5580;; overwriting this check in such cases. Or we change Tramp file name
00d6fd04 5581;; syntax in order to avoid ambiguities, like in XEmacs ...
6c4e47fa 5582(defun tramp-completion-mode-p ()
16674e4f 5583 "Checks whether method / user name / host name completion is active."
6c4e47fa 5584 (or
a6e96327
MA
5585 ;; Signal from outside.
5586 tramp-completion-mode
5587 ;; Emacs.
94be87e8 5588 (equal last-input-event 'tab)
6c4e47fa 5589 (and (natnump last-input-event)
94be87e8 5590 (or
a6e96327 5591 ;; ?\t has event-modifier 'control.
800a97b8 5592 (equal last-input-event ?\t)
94be87e8 5593 (and (not (event-modifiers last-input-event))
800a97b8
SM
5594 (or (equal last-input-event ?\?)
5595 (equal last-input-event ?\ )))))
a6e96327 5596 ;; XEmacs.
6c4e47fa
MA
5597 (and (featurep 'xemacs)
5598 ;; `last-input-event' might be nil.
5599 (not (null last-input-event))
5600 ;; `last-input-event' may have no character approximation.
5601 (funcall (symbol-function 'event-to-character) last-input-event)
94be87e8 5602 (or
a6e96327 5603 ;; ?\t has event-modifier 'control.
800a97b8 5604 (equal
94be87e8
MA
5605 (funcall (symbol-function 'event-to-character)
5606 last-input-event) ?\t)
5607 (and (not (event-modifiers last-input-event))
800a97b8 5608 (or (equal
94be87e8
MA
5609 (funcall (symbol-function 'event-to-character)
5610 last-input-event) ?\?)
800a97b8 5611 (equal
94be87e8
MA
5612 (funcall (symbol-function 'event-to-character)
5613 last-input-event) ?\ )))))))
16674e4f 5614
16674e4f
KG
5615;; Method, host name and user name completion.
5616;; `tramp-completion-dissect-file-name' returns a list of
5617;; tramp-file-name structures. For all of them we return possible completions.
a01b1e22 5618;;;###autoload
16674e4f 5619(defun tramp-completion-handle-file-name-all-completions (filename directory)
00d6fd04 5620 "Like `file-name-all-completions' for partial Tramp files."
16674e4f 5621
00d6fd04
MA
5622 (let* ((fullname (tramp-drop-volume-letter
5623 (expand-file-name filename directory)))
5624 ;; Possible completion structures.
5625 (v (tramp-completion-dissect-file-name fullname))
5626 result result1)
5627
5628 (while v
5629 (let* ((car (car v))
5630 (method (tramp-file-name-method car))
5631 (user (tramp-file-name-user car))
5632 (host (tramp-file-name-host car))
5633 (localname (tramp-file-name-localname car))
5634 (m (tramp-find-method method user host))
5635 (tramp-current-user user) ; see `tramp-parse-passwd'
5636 all-user-hosts)
5637
5638 (unless localname ;; Nothing to complete.
5639
5640 (if (or user host)
5641
5642 ;; Method dependent user / host combinations.
5643 (progn
9e6ab520 5644 (mapc
00d6fd04
MA
5645 (lambda (x)
5646 (setq all-user-hosts
5647 (append all-user-hosts
5648 (funcall (nth 0 x) (nth 1 x)))))
5649 (tramp-get-completion-function m))
5650
9e6ab520
MA
5651 (setq result
5652 (append result
5653 (mapcar
5654 (lambda (x)
5655 (tramp-get-completion-user-host
5656 method user host (nth 0 x) (nth 1 x)))
5657 (delq nil all-user-hosts)))))
00d6fd04
MA
5658
5659 ;; Possible methods.
5660 (setq result
5661 (append result (tramp-get-completion-methods m)))))
5662
5663 (setq v (cdr v))))
5664
5665 ;; Unify list, remove nil elements.
5666 (while result
5667 (let ((car (car result)))
5668 (when car
5669 (add-to-list
5670 'result1
5671 (substring car (length (tramp-drop-volume-letter directory)))))
5672 (setq result (cdr result))))
5673
5674 ;; Complete local parts.
5675 (append
5676 result1
5677 (condition-case nil
5678 (tramp-completion-run-real-handler
5679 'file-name-all-completions (list filename directory))
5680 (error nil)))))
16674e4f
KG
5681
5682;; Method, host name and user name completion for a file.
a01b1e22 5683;;;###autoload
e1e17cae
MA
5684(defun tramp-completion-handle-file-name-completion
5685 (filename directory &optional predicate)
00d6fd04 5686 "Like `file-name-completion' for Tramp files."
e1e17cae
MA
5687 (try-completion
5688 filename
5689 (mapcar 'list (file-name-all-completions filename directory))
83e20b5c
MA
5690 (when predicate
5691 (lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
16674e4f
KG
5692
5693;; I misuse a little bit the tramp-file-name structure in order to handle
5694;; completion possibilities for partial methods / user names / host names.
5695;; Return value is a list of tramp-file-name structures according to possible
00d6fd04 5696;; completions. If "localname" is non-nil it means there
16674e4f
KG
5697;; shouldn't be a completion anymore.
5698
5699;; Expected results:
5700
00d6fd04
MA
5701;; "/x" "/[x" "/x@" "/[x@" "/x@y" "/[x@y"
5702;; [nil nil "x" nil] [nil "x" nil nil] [nil "x" "y" nil]
5703;; [nil "x" nil nil]
5704;; ["x" nil nil nil]
5705
5706;; "/x:" "/x:y" "/x:y:"
5707;; [nil nil "x" ""] [nil nil "x" "y"] ["x" nil "y" ""]
5708;; "/[x/" "/[x/y"
5709;; ["x" nil "" nil] ["x" nil "y" nil]
5710;; ["x" "" nil nil] ["x" "y" nil nil]
5711
5712;; "/x:y@" "/x:y@z" "/x:y@z:"
5713;; [nil nil "x" "y@"] [nil nil "x" "y@z"] ["x" "y" "z" ""]
5714;; "/[x/y@" "/[x/y@z"
5715;; ["x" nil "y" nil] ["x" "y" "z" nil]
16674e4f
KG
5716(defun tramp-completion-dissect-file-name (name)
5717 "Returns a list of `tramp-file-name' structures.
5718They are collected by `tramp-completion-dissect-file-name1'."
5719
5720 (let* ((result)
4007ba5b 5721 (x-nil "\\|\\(\\)")
b96e6899
MA
5722 (tramp-completion-ipv6-regexp
5723 (format
5724 "[^%s]*"
5725 (if (zerop (length tramp-postfix-ipv6-format))
5726 tramp-postfix-host-format
5727 tramp-postfix-ipv6-format)))
4007ba5b
KG
5728 ;; "/method" "/[method"
5729 (tramp-completion-file-name-structure1
5730 (list (concat tramp-prefix-regexp "\\(" tramp-method-regexp x-nil "\\)$")
5731 1 nil nil nil))
5732 ;; "/user" "/[user"
5733 (tramp-completion-file-name-structure2
5734 (list (concat tramp-prefix-regexp "\\(" tramp-user-regexp x-nil "\\)$")
5735 nil 1 nil nil))
5736 ;; "/host" "/[host"
5737 (tramp-completion-file-name-structure3
5738 (list (concat tramp-prefix-regexp "\\(" tramp-host-regexp x-nil "\\)$")
5739 nil nil 1 nil))
b96e6899 5740 ;; "/[ipv6" "/[ipv6"
4007ba5b 5741 (tramp-completion-file-name-structure4
b96e6899
MA
5742 (list (concat tramp-prefix-regexp
5743 tramp-prefix-ipv6-regexp
5744 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5745 nil nil 1 nil))
5746 ;; "/user@host" "/[user@host"
5747 (tramp-completion-file-name-structure5
4007ba5b
KG
5748 (list (concat tramp-prefix-regexp
5749 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5750 "\\(" tramp-host-regexp x-nil "\\)$")
5751 nil 1 2 nil))
b96e6899
MA
5752 ;; "/user@[ipv6" "/[user@ipv6"
5753 (tramp-completion-file-name-structure6
5754 (list (concat tramp-prefix-regexp
5755 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5756 tramp-prefix-ipv6-regexp
5757 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5758 nil 1 2 nil))
00d6fd04 5759 ;; "/method:user" "/[method/user" "/method://user"
b96e6899 5760 (tramp-completion-file-name-structure7
4007ba5b 5761 (list (concat tramp-prefix-regexp
00d6fd04 5762 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5763 "\\(" tramp-user-regexp x-nil "\\)$")
5764 1 2 nil nil))
00d6fd04 5765 ;; "/method:host" "/[method/host" "/method://host"
b96e6899 5766 (tramp-completion-file-name-structure8
4007ba5b 5767 (list (concat tramp-prefix-regexp
00d6fd04 5768 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5769 "\\(" tramp-host-regexp x-nil "\\)$")
5770 1 nil 2 nil))
b96e6899
MA
5771 ;; "/method:[ipv6" "/[method/ipv6" "/method://[ipv6"
5772 (tramp-completion-file-name-structure9
5773 (list (concat tramp-prefix-regexp
5774 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
5775 tramp-prefix-ipv6-regexp
5776 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5777 1 nil 2 nil))
00d6fd04 5778 ;; "/method:user@host" "/[method/user@host" "/method://user@host"
b96e6899 5779 (tramp-completion-file-name-structure10
4007ba5b 5780 (list (concat tramp-prefix-regexp
00d6fd04 5781 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5782 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5783 "\\(" tramp-host-regexp x-nil "\\)$")
00d6fd04 5784 1 2 3 nil))
b96e6899
MA
5785 ;; "/method:user@[ipv6" "/[method/user@ipv6" "/method://user@[ipv6"
5786 (tramp-completion-file-name-structure11
5787 (list (concat tramp-prefix-regexp
5788 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
5789 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5790 tramp-prefix-ipv6-regexp
5791 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5792 1 2 3 nil))
00d6fd04 5793 ;; "/method: "/method:/"
b96e6899 5794 (tramp-completion-file-name-structure12
00d6fd04
MA
5795 (list
5796 (if (equal tramp-syntax 'url)
5797 (concat tramp-prefix-regexp
5798 "\\(" tramp-method-regexp "\\)"
5799 "\\(" (substring tramp-postfix-method-regexp 0 1)
5800 "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)"
5801 "\\(" "\\)$")
5802 ;; Should not match if not URL syntax.
5803 (concat tramp-prefix-regexp "/$"))
5804 1 3 nil nil))
5805 ;; "/method: "/method:/"
b96e6899 5806 (tramp-completion-file-name-structure13
00d6fd04
MA
5807 (list
5808 (if (equal tramp-syntax 'url)
5809 (concat tramp-prefix-regexp
5810 "\\(" tramp-method-regexp "\\)"
5811 "\\(" (substring tramp-postfix-method-regexp 0 1)
5812 "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)"
5813 "\\(" "\\)$")
5814 ;; Should not match if not URL syntax.
5815 (concat tramp-prefix-regexp "/$"))
5816 1 nil 3 nil)))
4007ba5b 5817
9e6ab520 5818 (mapc (lambda (regexp)
16674e4f
KG
5819 (add-to-list 'result
5820 (tramp-completion-dissect-file-name1 regexp name)))
5821 (list
5822 tramp-completion-file-name-structure1
5823 tramp-completion-file-name-structure2
5824 tramp-completion-file-name-structure3
5825 tramp-completion-file-name-structure4
5826 tramp-completion-file-name-structure5
5827 tramp-completion-file-name-structure6
5828 tramp-completion-file-name-structure7
00d6fd04
MA
5829 tramp-completion-file-name-structure8
5830 tramp-completion-file-name-structure9
b96e6899
MA
5831 tramp-completion-file-name-structure10
5832 tramp-completion-file-name-structure11
5833 tramp-completion-file-name-structure12
5834 tramp-completion-file-name-structure13
16674e4f
KG
5835 tramp-file-name-structure))
5836
5837 (delq nil result)))
5838
5839(defun tramp-completion-dissect-file-name1 (structure name)
5840 "Returns a `tramp-file-name' structure matching STRUCTURE.
00d6fd04 5841The structure consists of remote method, remote user,
7432277c 5842remote host and localname (filename on remote host)."
fb7933a3 5843
00d6fd04
MA
5844 (save-match-data
5845 (when (string-match (nth 0 structure) name)
5846 (let ((method (and (nth 1 structure)
5847 (match-string (nth 1 structure) name)))
5848 (user (and (nth 2 structure)
5849 (match-string (nth 2 structure) name)))
5850 (host (and (nth 3 structure)
5851 (match-string (nth 3 structure) name)))
5852 (localname (and (nth 4 structure)
5853 (match-string (nth 4 structure) name))))
5854 (vector method user host localname)))))
16674e4f
KG
5855
5856;; This function returns all possible method completions, adding the
5857;; trailing method delimeter.
16674e4f
KG
5858(defun tramp-get-completion-methods (partial-method)
5859 "Returns all method completions for PARTIAL-METHOD."
4007ba5b
KG
5860 (mapcar
5861 (lambda (method)
5862 (and method
5863 (string-match (concat "^" (regexp-quote partial-method)) method)
00d6fd04
MA
5864 (tramp-completion-make-tramp-file-name method nil nil nil)))
5865 (mapcar 'car tramp-methods)))
16674e4f
KG
5866
5867;; Compares partial user and host names with possible completions.
5868(defun tramp-get-completion-user-host (method partial-user partial-host user host)
5869 "Returns the most expanded string for user and host name completion.
5870PARTIAL-USER must match USER, PARTIAL-HOST must match HOST."
5871 (cond
5872
5873 ((and partial-user partial-host)
5874 (if (and host
5875 (string-match (concat "^" (regexp-quote partial-host)) host)
5876 (string-equal partial-user (or user partial-user)))
5877 (setq user partial-user)
5878 (setq user nil
5879 host nil)))
5880
5881 (partial-user
5882 (setq host nil)
5883 (unless
5884 (and user (string-match (concat "^" (regexp-quote partial-user)) user))
5885 (setq user nil)))
5886
5887 (partial-host
5888 (setq user nil)
5889 (unless
5890 (and host (string-match (concat "^" (regexp-quote partial-host)) host))
5891 (setq host nil)))
5892
5893 (t (setq user nil
5894 host nil)))
5895
292ffc15 5896 (unless (zerop (+ (length user) (length host)))
00d6fd04 5897 (tramp-completion-make-tramp-file-name method user host nil)))
16674e4f
KG
5898
5899(defun tramp-parse-rhosts (filename)
5900 "Return a list of (user host) tuples allowed to access.
292ffc15 5901Either user or host may be nil."
00d6fd04
MA
5902 ;; On Windows, there are problems in completion when
5903 ;; `default-directory' is remote.
9e6ab520 5904 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5905 res)
8daea7fc 5906 (when (file-readable-p filename)
16674e4f
KG
5907 (with-temp-buffer
5908 (insert-file-contents filename)
5909 (goto-char (point-min))
5910 (while (not (eobp))
292ffc15 5911 (push (tramp-parse-rhosts-group) res))))
16674e4f
KG
5912 res))
5913
16674e4f
KG
5914(defun tramp-parse-rhosts-group ()
5915 "Return a (user host) tuple allowed to access.
292ffc15 5916Either user or host may be nil."
16674e4f
KG
5917 (let ((result)
5918 (regexp
5919 (concat
5920 "^\\(" tramp-host-regexp "\\)"
5921 "\\([ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
9e6ab520 5922 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
5923 (when (re-search-forward regexp nil t)
5924 (setq result (append (list (match-string 3) (match-string 1)))))
5925 (widen)
5926 (forward-line 1)
5927 result))
5928
5929(defun tramp-parse-shosts (filename)
5930 "Return a list of (user host) tuples allowed to access.
5931User is always nil."
00d6fd04
MA
5932 ;; On Windows, there are problems in completion when
5933 ;; `default-directory' is remote.
9e6ab520 5934 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5935 res)
8daea7fc 5936 (when (file-readable-p filename)
16674e4f
KG
5937 (with-temp-buffer
5938 (insert-file-contents filename)
5939 (goto-char (point-min))
5940 (while (not (eobp))
292ffc15 5941 (push (tramp-parse-shosts-group) res))))
16674e4f
KG
5942 res))
5943
5944(defun tramp-parse-shosts-group ()
5945 "Return a (user host) tuple allowed to access.
5946User is always nil."
16674e4f
KG
5947 (let ((result)
5948 (regexp (concat "^\\(" tramp-host-regexp "\\)")))
9e6ab520 5949 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
5950 (when (re-search-forward regexp nil t)
5951 (setq result (list nil (match-string 1))))
5952 (widen)
5953 (or
5954 (> (skip-chars-forward ",") 0)
5955 (forward-line 1))
5956 result))
5957
8daea7fc
KG
5958(defun tramp-parse-sconfig (filename)
5959 "Return a list of (user host) tuples allowed to access.
5960User is always nil."
00d6fd04
MA
5961 ;; On Windows, there are problems in completion when
5962 ;; `default-directory' is remote.
9e6ab520 5963 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5964 res)
8daea7fc
KG
5965 (when (file-readable-p filename)
5966 (with-temp-buffer
5967 (insert-file-contents filename)
5968 (goto-char (point-min))
5969 (while (not (eobp))
5970 (push (tramp-parse-sconfig-group) res))))
5971 res))
5972
5973(defun tramp-parse-sconfig-group ()
5974 "Return a (user host) tuple allowed to access.
5975User is always nil."
8daea7fc
KG
5976 (let ((result)
5977 (regexp (concat "^[ \t]*Host[ \t]+" "\\(" tramp-host-regexp "\\)")))
9e6ab520 5978 (narrow-to-region (point) (tramp-compat-line-end-position))
8daea7fc
KG
5979 (when (re-search-forward regexp nil t)
5980 (setq result (list nil (match-string 1))))
5981 (widen)
5982 (or
5983 (> (skip-chars-forward ",") 0)
5984 (forward-line 1))
5985 result))
5986
5ec2cc41
KG
5987(defun tramp-parse-shostkeys (dirname)
5988 "Return a list of (user host) tuples allowed to access.
5989User is always nil."
00d6fd04
MA
5990 ;; On Windows, there are problems in completion when
5991 ;; `default-directory' is remote.
9e6ab520 5992 (let* ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
5993 (regexp (concat "^key_[0-9]+_\\(" tramp-host-regexp "\\)\\.pub$"))
5994 (files (when (file-directory-p dirname) (directory-files dirname)))
5995 result)
5ec2cc41
KG
5996 (while files
5997 (when (string-match regexp (car files))
5998 (push (list nil (match-string 1 (car files))) result))
5999 (setq files (cdr files)))
6000 result))
6001
6002(defun tramp-parse-sknownhosts (dirname)
6003 "Return a list of (user host) tuples allowed to access.
6004User is always nil."
00d6fd04
MA
6005 ;; On Windows, there are problems in completion when
6006 ;; `default-directory' is remote.
9e6ab520 6007 (let* ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
6008 (regexp (concat "^\\(" tramp-host-regexp
6009 "\\)\\.ssh-\\(dss\\|rsa\\)\\.pub$"))
6010 (files (when (file-directory-p dirname) (directory-files dirname)))
6011 result)
5ec2cc41
KG
6012 (while files
6013 (when (string-match regexp (car files))
6014 (push (list nil (match-string 1 (car files))) result))
6015 (setq files (cdr files)))
6016 result))
6017
16674e4f
KG
6018(defun tramp-parse-hosts (filename)
6019 "Return a list of (user host) tuples allowed to access.
6020User is always 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)
16674e4f
KG
6026 (with-temp-buffer
6027 (insert-file-contents filename)
6028 (goto-char (point-min))
6029 (while (not (eobp))
292ffc15 6030 (push (tramp-parse-hosts-group) res))))
16674e4f
KG
6031 res))
6032
6033(defun tramp-parse-hosts-group ()
6034 "Return a (user host) tuple allowed to access.
6035User is always nil."
16674e4f 6036 (let ((result)
b96e6899
MA
6037 (regexp
6038 (concat "^\\(" tramp-ipv6-regexp "\\|" tramp-host-regexp "\\)")))
9e6ab520 6039 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f 6040 (when (re-search-forward regexp nil t)
b96e6899 6041 (setq result (list nil (match-string 1))))
16674e4f
KG
6042 (widen)
6043 (or
6044 (> (skip-chars-forward " \t") 0)
6045 (forward-line 1))
6046 result))
6047
8daea7fc
KG
6048;; For su-alike methods it would be desirable to return "root@localhost"
6049;; as default. Unfortunately, we have no information whether any user name
00d6fd04 6050;; has been typed already. So we use `tramp-current-user' as indication,
8daea7fc 6051;; assuming it is set in `tramp-completion-handle-file-name-all-completions'.
16674e4f
KG
6052(defun tramp-parse-passwd (filename)
6053 "Return a list of (user host) tuples allowed to access.
6054Host is always \"localhost\"."
00d6fd04
MA
6055 ;; On Windows, there are problems in completion when
6056 ;; `default-directory' is remote.
9e6ab520 6057 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 6058 res)
8daea7fc 6059 (if (zerop (length tramp-current-user))
16674e4f 6060 '(("root" nil))
8daea7fc 6061 (when (file-readable-p filename)
16674e4f
KG
6062 (with-temp-buffer
6063 (insert-file-contents filename)
6064 (goto-char (point-min))
6065 (while (not (eobp))
292ffc15 6066 (push (tramp-parse-passwd-group) res))))
16674e4f
KG
6067 res)))
6068
6069(defun tramp-parse-passwd-group ()
6070 "Return a (user host) tuple allowed to access.
292ffc15 6071Host is always \"localhost\"."
16674e4f
KG
6072 (let ((result)
6073 (regexp (concat "^\\(" tramp-user-regexp "\\):")))
9e6ab520 6074 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
6075 (when (re-search-forward regexp nil t)
6076 (setq result (list (match-string 1) "localhost")))
6077 (widen)
6078 (forward-line 1)
6079 result))
6080
292ffc15
KG
6081(defun tramp-parse-netrc (filename)
6082 "Return a list of (user host) tuples allowed to access.
6083User may be nil."
00d6fd04
MA
6084 ;; On Windows, there are problems in completion when
6085 ;; `default-directory' is remote.
9e6ab520 6086 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 6087 res)
8daea7fc 6088 (when (file-readable-p filename)
292ffc15
KG
6089 (with-temp-buffer
6090 (insert-file-contents filename)
6091 (goto-char (point-min))
6092 (while (not (eobp))
6093 (push (tramp-parse-netrc-group) res))))
6094 res))
6095
6096(defun tramp-parse-netrc-group ()
6097 "Return a (user host) tuple allowed to access.
6098User may be nil."
292ffc15
KG
6099 (let ((result)
6100 (regexp
6101 (concat
6102 "^[ \t]*machine[ \t]+" "\\(" tramp-host-regexp "\\)"
6103 "\\([ \t]+login[ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
9e6ab520 6104 (narrow-to-region (point) (tramp-compat-line-end-position))
292ffc15
KG
6105 (when (re-search-forward regexp nil t)
6106 (setq result (list (match-string 3) (match-string 1))))
6107 (widen)
6108 (forward-line 1)
6109 result))
6110
00d6fd04
MA
6111(defun tramp-parse-putty (registry)
6112 "Return a list of (user host) tuples allowed to access.
6113User is always nil."
6114 ;; On Windows, there are problems in completion when
6115 ;; `default-directory' is remote.
9e6ab520 6116 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
6117 res)
6118 (with-temp-buffer
a4aeb9a4 6119 (when (zerop (tramp-local-call-process "reg" nil t nil "query" registry))
00d6fd04
MA
6120 (goto-char (point-min))
6121 (while (not (eobp))
6122 (push (tramp-parse-putty-group registry) res))))
6123 res))
6124
6125(defun tramp-parse-putty-group (registry)
6126 "Return a (user host) tuple allowed to access.
6127User is always nil."
6128 (let ((result)
6129 (regexp (concat (regexp-quote registry) "\\\\\\(.+\\)")))
9e6ab520 6130 (narrow-to-region (point) (tramp-compat-line-end-position))
00d6fd04
MA
6131 (when (re-search-forward regexp nil t)
6132 (setq result (list nil (match-string 1))))
6133 (widen)
6134 (forward-line 1)
6135 result))
6136
fb7933a3
KG
6137;;; Internal Functions:
6138
00d6fd04
MA
6139(defun tramp-maybe-send-script (vec script name)
6140 "Define in remote shell function NAME implemented as SCRIPT.
6141Only send the definition if it has not already been done."
6142 (let* ((p (tramp-get-connection-process vec))
6143 (scripts (tramp-get-connection-property p "scripts" nil)))
1834b39f 6144 (unless (member name scripts)
00d6fd04
MA
6145 (tramp-message vec 5 "Sending script `%s'..." name)
6146 ;; The script could contain a call of Perl. This is masked with `%s'.
6147 (tramp-send-command-and-check
6148 vec
6149 (format "%s () {\n%s\n}" name
6150 (format script (tramp-get-remote-perl vec))))
6151 (tramp-set-connection-property p "scripts" (cons name scripts))
6152 (tramp-message vec 5 "Sending script `%s'...done." name))))
c82c5727 6153
fb7933a3 6154(defun tramp-set-auto-save ()
00d6fd04 6155 (when (and ;; ange-ftp has its own auto-save mechanism
7177e2a3
MA
6156 (eq (tramp-find-foreign-file-name-handler (buffer-file-name))
6157 'tramp-sh-file-name-handler)
fb7933a3
KG
6158 auto-save-default)
6159 (auto-save-mode 1)))
6160(add-hook 'find-file-hooks 'tramp-set-auto-save t)
a69c01a0 6161(add-hook 'tramp-unload-hook
aa485f7c
MA
6162 (lambda ()
6163 (remove-hook 'find-file-hooks 'tramp-set-auto-save)))
fb7933a3
KG
6164
6165(defun tramp-run-test (switch filename)
6166 "Run `test' on the remote system, given a SWITCH and a FILENAME.
6167Returns the exit code of the `test' program."
00d6fd04
MA
6168 (with-parsed-tramp-file-name filename nil
6169 (tramp-send-command-and-check
6170 v
6171 (format
6172 "%s %s %s"
6173 (tramp-get-test-command v)
6174 switch
6175 (tramp-shell-quote-argument localname)))))
6176
6177(defun tramp-run-test2 (format-string file1 file2)
6178 "Run `test'-like program on the remote system, given FILE1, FILE2.
6179FORMAT-STRING contains the program name, switches, and place holders.
6180Returns the exit code of the `test' program. Barfs if the methods,
fb7933a3 6181hosts, or files, disagree."
00d6fd04
MA
6182 (unless (tramp-equal-remote file1 file2)
6183 (with-parsed-tramp-file-name (if (tramp-tramp-file-p file1) file1 file2) nil
6184 (tramp-error
6185 v 'file-error
6186 "tramp-run-test2 only implemented for same method, user, host")))
6187 (with-parsed-tramp-file-name file1 v1
6188 (with-parsed-tramp-file-name file1 v2
fb7933a3 6189 (tramp-send-command-and-check
00d6fd04
MA
6190 v1
6191 (format format-string
6192 (tramp-shell-quote-argument v1-localname)
6193 (tramp-shell-quote-argument v2-localname))))))
fb7933a3 6194
00d6fd04
MA
6195(defun tramp-buffer-name (vec)
6196 "A name for the connection buffer VEC."
6197 ;; We must use `tramp-file-name-real-host', because for gateway
6198 ;; methods the default port will be expanded later on, which would
6199 ;; tamper the name.
6200 (let ((method (tramp-file-name-method vec))
6201 (user (tramp-file-name-user vec))
6202 (host (tramp-file-name-real-host vec)))
6203 (if (not (zerop (length user)))
6204 (format "*tramp/%s %s@%s*" method user host)
6205 (format "*tramp/%s %s*" method host))))
6206
b88f2d0a
MA
6207(defun tramp-delete-temp-file-function ()
6208 "Remove temporary files related to current buffer."
6209 (when (stringp tramp-temp-buffer-file-name)
6210 (condition-case nil
6211 (delete-file tramp-temp-buffer-file-name)
6212 (error nil))))
6213
6214(add-hook 'kill-buffer-hook 'tramp-delete-temp-file-function)
6215(add-hook 'tramp-cache-unload-hook
6216 (lambda ()
6217 (remove-hook 'kill-buffer-hook
6218 'tramp-delete-temp-file-function)))
6219
00d6fd04
MA
6220(defun tramp-get-buffer (vec)
6221 "Get the connection buffer to be used for VEC."
6222 (or (get-buffer (tramp-buffer-name vec))
6223 (with-current-buffer (get-buffer-create (tramp-buffer-name vec))
6224 (setq buffer-undo-list t)
6225 (setq default-directory
6226 (tramp-make-tramp-file-name
6227 (tramp-file-name-method vec)
6228 (tramp-file-name-user vec)
6229 (tramp-file-name-host vec)
6230 "/"))
6231 (current-buffer))))
6232
6233(defun tramp-get-connection-buffer (vec)
6234 "Get the connection buffer to be used for VEC.
6235In case a second asynchronous communication has been started, it is different
6236from `tramp-get-buffer'."
6237 (or (tramp-get-connection-property vec "process-buffer" nil)
6238 (tramp-get-buffer vec)))
6239
6240(defun tramp-get-connection-process (vec)
6241 "Get the connection process to be used for VEC.
6242In case a second asynchronous communication has been started, it is different
6243from the default one."
6244 (get-process
6245 (or (tramp-get-connection-property vec "process-name" nil)
6246 (tramp-buffer-name vec))))
6247
6248(defun tramp-debug-buffer-name (vec)
6249 "A name for the debug buffer for VEC."
6250 ;; We must use `tramp-file-name-real-host', because for gateway
6251 ;; methods the default port will be expanded later on, which would
6252 ;; tamper the name.
6253 (let ((method (tramp-file-name-method vec))
6254 (user (tramp-file-name-user vec))
6255 (host (tramp-file-name-real-host vec)))
6256 (if (not (zerop (length user)))
6257 (format "*debug tramp/%s %s@%s*" method user host)
6258 (format "*debug tramp/%s %s*" method host))))
6259
6260(defun tramp-get-debug-buffer (vec)
6261 "Get the debug buffer for VEC."
01917a18 6262 (with-current-buffer
00d6fd04
MA
6263 (get-buffer-create (tramp-debug-buffer-name vec))
6264 (when (bobp)
6265 (setq buffer-undo-list t)
9ce8462a
MA
6266 ;; Activate outline-mode. This runs `text-mode-hook' and
6267 ;; `outline-mode-hook'. We must prevent that local processes
6268 ;; die. Yes: I've seen `flyspell-mode', which starts "ispell"
6269 ;; ...
9e6ab520 6270 (let ((default-directory (tramp-compat-temporary-file-directory)))
00d6fd04 6271 (outline-mode))
9ce8462a 6272 (set (make-local-variable 'outline-regexp)
736ac90f 6273 "[0-9]+:[0-9]+:[0-9]+\\.[0-9]+ [a-z0-9-]+ (\\([0-9]+\\)) #")
9ce8462a
MA
6274; (set (make-local-variable 'outline-regexp)
6275; "[a-z.-]+:[0-9]+: [a-z0-9-]+ (\\([0-9]+\\)) #")
6276 (set (make-local-variable 'outline-level) 'tramp-outline-level))
01917a18 6277 (current-buffer)))
fb7933a3 6278
00d6fd04
MA
6279(defun tramp-outline-level ()
6280 "Return the depth to which a statement is nested in the outline.
6281Point must be at the beginning of a header line.
6282
6283The outline level is equal to the verbosity of the Tramp message."
6284 (1+ (string-to-number (match-string 1))))
fb7933a3 6285
00d6fd04
MA
6286(defun tramp-find-executable
6287 (vec progname dirlist &optional ignore-tilde ignore-path)
6288 "Searches for PROGNAME in $PATH and all directories mentioned in DIRLIST.
6289First arg VEC specifies the connection, PROGNAME is the program
6290to search for, and DIRLIST gives the list of directories to
6291search. If IGNORE-TILDE is non-nil, directory names starting
6292with `~' will be ignored. If IGNORE-PATH is non-nil, searches
6293only in DIRLIST.
fb7933a3 6294
7432277c 6295Returns the absolute file name of PROGNAME, if found, and nil otherwise.
fb7933a3
KG
6296
6297This function expects to be in the right *tramp* buffer."
c0e17ff2 6298 (with-current-buffer (tramp-get-connection-buffer vec)
00d6fd04
MA
6299 (let (result)
6300 ;; Check whether the executable is in $PATH. "which(1)" does not
6301 ;; report always a correct error code; therefore we check the
6302 ;; number of words it returns.
6303 (unless ignore-path
6304 (tramp-send-command vec (format "which \\%s | wc -w" progname))
6305 (goto-char (point-min))
c0e17ff2 6306 (if (looking-at "^\\s-*1$")
00d6fd04
MA
6307 (setq result (concat "\\" progname))))
6308 (unless result
6309 (when ignore-tilde
6310 ;; Remove all ~/foo directories from dirlist. In Emacs 20,
6311 ;; `remove' is in CL, and we want to avoid CL dependencies.
6312 (let (newdl d)
6313 (while dirlist
6314 (setq d (car dirlist))
6315 (setq dirlist (cdr dirlist))
6316 (unless (char-equal ?~ (aref d 0))
6317 (setq newdl (cons d newdl))))
6318 (setq dirlist (nreverse newdl))))
6319 (tramp-send-command
6320 vec
6321 (format (concat "while read d; "
6322 "do if test -x $d/%s -a -f $d/%s; "
6323 "then echo tramp_executable $d/%s; "
6324 "break; fi; done <<'EOF'\n"
6325 "%s\nEOF")
6326 progname progname progname (mapconcat 'identity dirlist "\n")))
6327 (goto-char (point-max))
6328 (when (search-backward "tramp_executable " nil t)
6329 (skip-chars-forward "^ ")
6330 (skip-chars-forward " ")
9e6ab520
MA
6331 (setq result (buffer-substring
6332 (point) (tramp-compat-line-end-position)))))
00d6fd04
MA
6333 result)))
6334
6335(defun tramp-set-remote-path (vec)
6336 "Sets the remote environment PATH to existing directories.
6337I.e., for each directory in `tramp-remote-path', it is tested
6338whether it exists and if so, it is added to the environment
6339variable PATH."
6340 (tramp-message vec 5 (format "Setting $PATH environment variable"))
f84638eb
MA
6341 (tramp-send-command
6342 vec (format "PATH=%s; export PATH"
6343 (mapconcat 'identity (tramp-get-remote-path vec) ":"))))
fb7933a3 6344
cfb5c0db
MA
6345;; ------------------------------------------------------------
6346;; -- Communication with external shell --
6347;; ------------------------------------------------------------
fb7933a3 6348
00d6fd04 6349(defun tramp-find-file-exists-command (vec)
fb7933a3
KG
6350 "Find a command on the remote host for checking if a file exists.
6351Here, we are looking for a command which has zero exit status if the
6352file exists and nonzero exit status otherwise."
00d6fd04 6353 (let ((existing "/")
fb7933a3 6354 (nonexisting
00d6fd04
MA
6355 (tramp-shell-quote-argument "/ this file does not exist "))
6356 result)
fb7933a3
KG
6357 ;; The algorithm is as follows: we try a list of several commands.
6358 ;; For each command, we first run `$cmd /' -- this should return
6359 ;; true, as the root directory always exists. And then we run
00d6fd04 6360 ;; `$cmd /this\ file\ does\ not\ exist ', hoping that the file indeed
fb7933a3
KG
6361 ;; does not exist. This should return false. We use the first
6362 ;; command we find that seems to work.
6363 ;; The list of commands to try is as follows:
00d6fd04
MA
6364 ;; `ls -d' This works on most systems, but NetBSD 1.4
6365 ;; has a bug: `ls' always returns zero exit
6366 ;; status, even for files which don't exist.
6367 ;; `test -e' Some Bourne shells have a `test' builtin
6368 ;; which does not know the `-e' option.
6369 ;; `/bin/test -e' For those, the `test' binary on disk normally
6370 ;; provides the option. Alas, the binary
6371 ;; is sometimes `/bin/test' and sometimes it's
6372 ;; `/usr/bin/test'.
6373 ;; `/usr/bin/test -e' In case `/bin/test' does not exist.
fb7933a3 6374 (unless (or
00d6fd04
MA
6375 (and (setq result (format "%s -e" (tramp-get-test-command vec)))
6376 (zerop (tramp-send-command-and-check
6377 vec (format "%s %s" result existing)))
6378 (not (zerop (tramp-send-command-and-check
6379 vec (format "%s %s" result nonexisting)))))
6380 (and (setq result "/bin/test -e")
6381 (zerop (tramp-send-command-and-check
6382 vec (format "%s %s" result existing)))
6383 (not (zerop (tramp-send-command-and-check
6384 vec (format "%s %s" result nonexisting)))))
6385 (and (setq result "/usr/bin/test -e")
6386 (zerop (tramp-send-command-and-check
6387 vec (format "%s %s" result existing)))
6388 (not (zerop (tramp-send-command-and-check
6389 vec (format "%s %s" result nonexisting)))))
6390 (and (setq result (format "%s -d" (tramp-get-ls-command vec)))
6391 (zerop (tramp-send-command-and-check
6392 vec (format "%s %s" result existing)))
6393 (not (zerop (tramp-send-command-and-check
6394 vec (format "%s %s" result nonexisting))))))
6395 (tramp-error
6396 vec 'file-error "Couldn't find command to check if file exists"))
6397 result))
bf247b6e 6398
fb7933a3 6399;; CCC test ksh or bash found for tilde expansion?
00d6fd04
MA
6400(defun tramp-find-shell (vec)
6401 "Opens a shell on the remote host which groks tilde expansion."
6402 (unless (tramp-get-connection-property vec "remote-shell" nil)
6403 (let (shell)
6404 (with-current-buffer (tramp-get-buffer vec)
7e780ff1 6405 (tramp-send-command vec "echo ~root" t)
00d6fd04 6406 (cond
c0e17ff2
MA
6407 ((or (string-match "^~root$" (buffer-string))
6408 ;; The default shell (ksh93) of OpenSolaris is buggy.
6409 (string-equal (tramp-get-connection-property vec "uname" "")
6410 "SunOS 5.11"))
00d6fd04 6411 (setq shell
f84638eb 6412 (or (tramp-find-executable
c0e17ff2 6413 vec "bash" (tramp-get-remote-path vec) t t)
f84638eb 6414 (tramp-find-executable
c0e17ff2 6415 vec "ksh" (tramp-get-remote-path vec) t t)))
00d6fd04
MA
6416 (unless shell
6417 (tramp-error
6418 vec 'file-error
6419 "Couldn't find a shell which groks tilde expansion"))
6420 ;; Find arguments for this shell.
6421 (let ((alist tramp-sh-extra-args)
6422 item extra-args)
6423 (while (and alist (null extra-args))
6424 (setq item (pop alist))
6425 (when (string-match (car item) shell)
6426 (setq extra-args (cdr item))))
6427 (when extra-args (setq shell (concat shell " " extra-args))))
6428 (tramp-message
6429 vec 5 "Starting remote shell `%s' for tilde expansion..." shell)
dab816a9 6430 (let ((tramp-end-of-output tramp-initial-end-of-output))
a4aeb9a4 6431 (tramp-send-command
b08104a0 6432 vec
70c11b0b
MA
6433 (format "PROMPT_COMMAND='' PS1=%s PS2='' PS3='' exec %s"
6434 (shell-quote-argument tramp-end-of-output) shell)
b08104a0 6435 t))
a0a5183a 6436 ;; Setting prompts.
00d6fd04 6437 (tramp-message vec 5 "Setting remote shell prompt...")
70c11b0b
MA
6438 (tramp-send-command
6439 vec (format "PS1=%s" (shell-quote-argument tramp-end-of-output)) t)
9fa0d3aa
MA
6440 (tramp-send-command vec "PS2=''" t)
6441 (tramp-send-command vec "PS3=''" t)
6442 (tramp-send-command vec "PROMPT_COMMAND=''" t)
00d6fd04 6443 (tramp-message vec 5 "Setting remote shell prompt...done"))
a0a5183a 6444
00d6fd04
MA
6445 (t (tramp-message
6446 vec 5 "Remote `%s' groks tilde expansion, good"
6447 (tramp-get-method-parameter
6448 (tramp-file-name-method vec) 'tramp-remote-sh))
6449 (tramp-set-connection-property
6450 vec "remote-shell"
6451 (tramp-get-method-parameter
6452 (tramp-file-name-method vec) 'tramp-remote-sh))))))))
fb7933a3 6453
bf247b6e
KS
6454;; ------------------------------------------------------------
6455;; -- Functions for establishing connection --
6456;; ------------------------------------------------------------
fb7933a3 6457
ac474af1
KG
6458;; The following functions are actions to be taken when seeing certain
6459;; prompts from the remote host. See the variable
6460;; `tramp-actions-before-shell' for usage of these functions.
6461
00d6fd04 6462(defun tramp-action-login (proc vec)
ac474af1 6463 "Send the login name."
00d6fd04
MA
6464 (when (not (stringp tramp-current-user))
6465 (save-window-excursion
6466 (let ((enable-recursive-minibuffers t))
6467 (pop-to-buffer (tramp-get-connection-buffer vec))
6468 (setq tramp-current-user (read-string (match-string 0))))))
6469 (tramp-message vec 3 "Sending login name `%s'" tramp-current-user)
6470 (with-current-buffer (tramp-get-connection-buffer vec)
6471 (tramp-message vec 6 "\n%s" (buffer-string)))
6472 (tramp-send-string vec tramp-current-user))
6473
6474(defun tramp-action-password (proc vec)
ac474af1 6475 "Query the user for a password."
70c11b0b
MA
6476 (with-current-buffer (process-buffer proc)
6477 (tramp-check-for-regexp proc tramp-password-prompt-regexp)
6478 (tramp-message vec 3 "Sending %s" (match-string 1)))
00d6fd04
MA
6479 (tramp-enter-password proc))
6480
6481(defun tramp-action-succeed (proc vec)
ac474af1 6482 "Signal success in finding shell prompt."
ac474af1
KG
6483 (throw 'tramp-action 'ok))
6484
00d6fd04 6485(defun tramp-action-permission-denied (proc vec)
ac474af1 6486 "Signal permission denied."
00d6fd04 6487 (kill-process proc)
ac474af1
KG
6488 (throw 'tramp-action 'permission-denied))
6489
00d6fd04 6490(defun tramp-action-yesno (proc vec)
3cdaec13
KG
6491 "Ask the user for confirmation using `yes-or-no-p'.
6492Send \"yes\" to remote process on confirmation, abort otherwise.
6493See also `tramp-action-yn'."
ac474af1 6494 (save-window-excursion
00d6fd04
MA
6495 (let ((enable-recursive-minibuffers t))
6496 (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec)))
6497 (unless (yes-or-no-p (match-string 0))
6498 (kill-process proc)
6499 (throw 'tramp-action 'permission-denied))
6500 (with-current-buffer (tramp-get-connection-buffer vec)
6501 (tramp-message vec 6 "\n%s" (buffer-string)))
6502 (tramp-send-string vec "yes"))))
6503
6504(defun tramp-action-yn (proc vec)
3cdaec13
KG
6505 "Ask the user for confirmation using `y-or-n-p'.
6506Send \"y\" to remote process on confirmation, abort otherwise.
6507See also `tramp-action-yesno'."
6508 (save-window-excursion
00d6fd04
MA
6509 (let ((enable-recursive-minibuffers t))
6510 (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec)))
6511 (unless (y-or-n-p (match-string 0))
6512 (kill-process proc)
6513 (throw 'tramp-action 'permission-denied))
6514 (with-current-buffer (tramp-get-connection-buffer vec)
6515 (tramp-message vec 6 "\n%s" (buffer-string)))
6516 (tramp-send-string vec "y"))))
6517
6518(defun tramp-action-terminal (proc vec)
487f4fb7
KG
6519 "Tell the remote host which terminal type to use.
6520The terminal type can be configured with `tramp-terminal-type'."
00d6fd04 6521 (tramp-message vec 5 "Setting `%s' as terminal type." tramp-terminal-type)
7e780ff1
MA
6522 (with-current-buffer (tramp-get-connection-buffer vec)
6523 (tramp-message vec 6 "\n%s" (buffer-string)))
00d6fd04 6524 (tramp-send-string vec tramp-terminal-type))
487f4fb7 6525
00d6fd04 6526(defun tramp-action-process-alive (proc vec)
19a87064 6527 "Check whether a process has finished."
00d6fd04 6528 (unless (memq (process-status proc) '(run open))
19a87064
MA
6529 (throw 'tramp-action 'process-died)))
6530
00d6fd04 6531(defun tramp-action-out-of-band (proc vec)
38c65fca 6532 "Check whether an out-of-band copy has finished."
00d6fd04
MA
6533 (cond ((and (memq (process-status proc) '(stop exit))
6534 (zerop (process-exit-status proc)))
6535 (tramp-message vec 3 "Process has finished.")
38c65fca 6536 (throw 'tramp-action 'ok))
00d6fd04
MA
6537 ((or (and (memq (process-status proc) '(stop exit))
6538 (not (zerop (process-exit-status proc))))
6539 (memq (process-status proc) '(signal)))
01917a18
MA
6540 ;; `scp' could have copied correctly, but set modes could have failed.
6541 ;; This can be ignored.
00d6fd04
MA
6542 (with-current-buffer (process-buffer proc)
6543 (goto-char (point-min))
6544 (if (re-search-forward tramp-operation-not-permitted-regexp nil t)
6545 (progn
6546 (tramp-message vec 5 "'set mode' error ignored.")
6547 (tramp-message vec 3 "Process has finished.")
6548 (throw 'tramp-action 'ok))
6549 (tramp-message vec 3 "Process has died.")
6550 (throw 'tramp-action 'process-died))))
38c65fca
KG
6551 (t nil)))
6552
ac474af1
KG
6553;; Functions for processing the actions.
6554
00d6fd04 6555(defun tramp-process-one-action (proc vec actions)
ac474af1 6556 "Wait for output from the shell and perform one action."
00d6fd04 6557 (let (found todo item pattern action)
e6466697 6558 (while (not found)
00d6fd04
MA
6559 ;; Reread output once all actions have been performed.
6560 ;; Obviously, the output was not complete.
6561 (tramp-accept-process-output proc 1)
e6466697
MA
6562 (setq todo actions)
6563 (while todo
e6466697 6564 (setq item (pop todo))
95d610cb 6565 (setq pattern (format "\\(%s\\)\\'" (symbol-value (nth 0 item))))
e6466697 6566 (setq action (nth 1 item))
00d6fd04
MA
6567 (tramp-message
6568 vec 5 "Looking for regexp \"%s\" from remote shell" pattern)
6569 (when (tramp-check-for-regexp proc pattern)
6570 (tramp-message vec 5 "Call `%s'" (symbol-name action))
6571 (setq found (funcall action proc vec)))))
e6466697
MA
6572 found))
6573
00d6fd04 6574(defun tramp-process-actions (proc vec actions &optional timeout)
e6466697 6575 "Perform actions until success or TIMEOUT."
263c02ef 6576 ;; Enable auth-source and password-cache.
7540f029 6577 (tramp-set-connection-property vec "first-password-request" t)
ac474af1
KG
6578 (let (exit)
6579 (while (not exit)
00d6fd04 6580 (tramp-message proc 3 "Waiting for prompts from remote shell")
ac474af1
KG
6581 (setq exit
6582 (catch 'tramp-action
e6466697
MA
6583 (if timeout
6584 (with-timeout (timeout)
00d6fd04
MA
6585 (tramp-process-one-action proc vec actions))
6586 (tramp-process-one-action proc vec actions)))))
6587 (with-current-buffer (tramp-get-connection-buffer vec)
6588 (tramp-message vec 6 "\n%s" (buffer-string)))
ac474af1 6589 (unless (eq exit 'ok)
9c13938d 6590 (tramp-clear-passwd vec)
00d6fd04
MA
6591 (tramp-error-with-buffer
6592 nil vec 'file-error
6593 (cond
6594 ((eq exit 'permission-denied) "Permission denied")
6595 ((eq exit 'process-died) "Process died")
6596 (t "Login failed"))))))
fb7933a3
KG
6597
6598;; Utility functions.
6599
00d6fd04 6600(defun tramp-accept-process-output (&optional proc timeout timeout-msecs)
d2a2c17f
MA
6601 "Like `accept-process-output' for Tramp processes.
6602This is needed in order to hide `last-coding-system-used', which is set
6603for process communication also."
00d6fd04
MA
6604 (with-current-buffer (process-buffer proc)
6605 (tramp-message proc 10 "%s %s" proc (process-status proc))
6606 (let (buffer-read-only last-coding-system-used)
6607 ;; Under Windows XP, accept-process-output doesn't return
6608 ;; sometimes. So we add an additional timeout.
6609 (with-timeout ((or timeout 1))
6610 (accept-process-output proc timeout timeout-msecs)))
6611 (tramp-message proc 10 "\n%s" (buffer-string))))
6612
6613(defun tramp-check-for-regexp (proc regexp)
6614 "Check whether REGEXP is contained in process buffer of PROC.
6615Erase echoed commands if exists."
6616 (with-current-buffer (process-buffer proc)
6617 (goto-char (point-min))
674da028 6618
00d6fd04
MA
6619 ;; Check whether we need to remove echo output.
6620 (when (and (tramp-get-connection-property proc "check-remote-echo" nil)
6621 (re-search-forward tramp-echoed-echo-mark-regexp nil t))
6622 (let ((begin (match-beginning 0)))
6623 (when (re-search-forward tramp-echoed-echo-mark-regexp nil t)
6624 ;; Discard echo from remote output.
6625 (tramp-set-connection-property proc "check-remote-echo" nil)
6626 (tramp-message proc 5 "echo-mark found")
6627 (forward-line)
6628 (delete-region begin (point))
6629 (goto-char (point-min)))))
674da028 6630
68712eb6
MA
6631 (when (or (not (tramp-get-connection-property proc "check-remote-echo" nil))
6632 ;; Sometimes, the echo string is suppressed on the remote side.
6633 (not (string-equal
6634 (substring-no-properties
6635 tramp-echo-mark-marker
6636 0 (min tramp-echo-mark-marker-length (1- (point-max))))
6637 (buffer-substring-no-properties
6638 1 (min (1+ tramp-echo-mark-marker-length) (point-max))))))
70c11b0b 6639 ;; No echo to be handled, now we can look for the regexp.
674da028 6640 (goto-char (point-min))
00d6fd04 6641 (re-search-forward regexp nil t))))
d2a2c17f 6642
fb7933a3
KG
6643(defun tramp-wait-for-regexp (proc timeout regexp)
6644 "Wait for a REGEXP to appear from process PROC within TIMEOUT seconds.
6645Expects the output of PROC to be sent to the current buffer. Returns
6646the string that matched, or nil. Waits indefinitely if TIMEOUT is
6647nil."
00d6fd04
MA
6648 (with-current-buffer (process-buffer proc)
6649 (let ((found (tramp-check-for-regexp proc regexp))
6650 (start-time (current-time)))
6651 (cond (timeout
6652 ;; Work around a bug in XEmacs 21, where the timeout
6653 ;; expires faster than it should. This degenerates
6654 ;; to polling for buggy XEmacsen, but oh, well.
6655 (while (and (not found)
6656 (< (tramp-time-diff (current-time) start-time)
6657 timeout))
6658 (with-timeout (timeout)
6659 (while (not found)
6660 (tramp-accept-process-output proc 1)
6661 (unless (memq (process-status proc) '(run open))
6662 (tramp-error-with-buffer
6663 nil proc 'file-error "Process has died"))
6664 (setq found (tramp-check-for-regexp proc regexp))))))
6665 (t
6666 (while (not found)
6667 (tramp-accept-process-output proc 1)
6668 (unless (memq (process-status proc) '(run open))
6669 (tramp-error-with-buffer
6670 nil proc 'file-error "Process has died"))
6671 (setq found (tramp-check-for-regexp proc regexp)))))
6672 (tramp-message proc 6 "\n%s" (buffer-string))
fb7933a3 6673 (when (not found)
00d6fd04
MA
6674 (if timeout
6675 (tramp-error
6676 proc 'file-error "[[Regexp `%s' not found in %d secs]]"
6677 regexp timeout)
6678 (tramp-error proc 'file-error "[[Regexp `%s' not found]]" regexp)))
6679 found)))
fb7933a3 6680
b25a52cc
KG
6681(defun tramp-barf-if-no-shell-prompt (proc timeout &rest error-args)
6682 "Wait for shell prompt and barf if none appears.
6683Looks at process PROC to see if a shell prompt appears in TIMEOUT
6684seconds. If not, it produces an error message with the given ERROR-ARGS."
7e780ff1
MA
6685 (unless
6686 (tramp-wait-for-regexp
6687 proc timeout
6688 (format
6689 "\\(%s\\|%s\\)\\'" shell-prompt-pattern tramp-shell-prompt-pattern))
00d6fd04
MA
6690 (apply 'tramp-error-with-buffer nil proc 'file-error error-args)))
6691
7e780ff1
MA
6692;; We don't call `tramp-send-string' in order to hide the password
6693;; from the debug buffer, and because end-of-line handling of the
6694;; string.
6695(defun tramp-enter-password (proc)
00d6fd04
MA
6696 "Prompt for a password and send it to the remote end."
6697 (process-send-string
7e780ff1
MA
6698 proc (concat (tramp-read-passwd proc)
6699 (or (tramp-get-method-parameter
6700 tramp-current-method
6701 'tramp-password-end-of-line)
6702 tramp-default-password-end-of-line))))
00d6fd04
MA
6703
6704(defun tramp-open-connection-setup-interactive-shell (proc vec)
fb7933a3 6705 "Set up an interactive shell.
00d6fd04
MA
6706Mainly sets the prompt and the echo correctly. PROC is the shell
6707process to set up. VEC specifies the connection."
dab816a9 6708 (let ((tramp-end-of-output tramp-initial-end-of-output))
8950769a
MA
6709 ;; It is useful to set the prompt in the following command because
6710 ;; some people have a setting for $PS1 which /bin/sh doesn't know
6711 ;; about and thus /bin/sh will display a strange prompt. For
6712 ;; example, if $PS1 has "${CWD}" in the value, then ksh will
6713 ;; display the current working directory but /bin/sh will display
6714 ;; a dollar sign. The following command line sets $PS1 to a sane
6715 ;; value, and works under Bourne-ish shells as well as csh-like
6716 ;; shells. Daniel Pittman reports that the unusual positioning of
6717 ;; the single quotes makes it work under `rc', too. We also unset
6718 ;; the variable $ENV because that is read by some sh
6719 ;; implementations (eg, bash when called as sh) on startup; this
6720 ;; way, we avoid the startup file clobbering $PS1. $PROMP_COMMAND
6721 ;; is another way to set the prompt in /bin/bash, it must be
6722 ;; discarded as well.
a4aeb9a4
MA
6723 (tramp-send-command
6724 vec
6725 (format
70c11b0b
MA
6726 "exec env ENV='' PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s"
6727 (shell-quote-argument tramp-end-of-output)
a4aeb9a4
MA
6728 (tramp-get-method-parameter
6729 (tramp-file-name-method vec) 'tramp-remote-sh))
8950769a
MA
6730 t)
6731
6732 ;; Disable echo.
6733 (tramp-message vec 5 "Setting up remote shell environment")
6734 (tramp-send-command vec "stty -inlcr -echo kill '^U' erase '^H'" t)
6735 ;; Check whether the echo has really been disabled. Some
6736 ;; implementations, like busybox of embedded GNU/Linux, don't
6737 ;; support disabling.
6738 (tramp-send-command vec "echo foo" t)
6739 (with-current-buffer (process-buffer proc)
6740 (goto-char (point-min))
6741 (when (looking-at "echo foo")
6742 (tramp-set-connection-property proc "remote-echo" t)
6743 (tramp-message vec 5 "Remote echo still on. Ok.")
6744 ;; Make sure backspaces and their echo are enabled and no line
6745 ;; width magic interferes with them.
6746 (tramp-send-command vec "stty icanon erase ^H cols 32767" t))))
e42c6bbc 6747
7e780ff1 6748 (tramp-message vec 5 "Setting shell prompt")
70c11b0b
MA
6749 (tramp-send-command
6750 vec (format "PS1=%s" (shell-quote-argument tramp-end-of-output)) t)
9fa0d3aa
MA
6751 (tramp-send-command vec "PS2=''" t)
6752 (tramp-send-command vec "PS3=''" t)
6753 (tramp-send-command vec "PROMPT_COMMAND=''" t)
e42c6bbc 6754
fb7933a3
KG
6755 ;; Try to set up the coding system correctly.
6756 ;; CCC this can't be the right way to do it. Hm.
00d6fd04 6757 (tramp-message vec 5 "Determining coding system")
7e780ff1 6758 (tramp-send-command vec "echo foo ; echo bar" t)
00d6fd04 6759 (with-current-buffer (process-buffer proc)
fb7933a3
KG
6760 (goto-char (point-min))
6761 (if (featurep 'mule)
00d6fd04
MA
6762 ;; Use MULE to select the right EOL convention for communicating
6763 ;; with the process.
311dd93f 6764 (let* ((cs (or (funcall (symbol-function 'process-coding-system) proc)
00d6fd04
MA
6765 (cons 'undecided 'undecided)))
6766 cs-decode cs-encode)
6767 (when (symbolp cs) (setq cs (cons cs cs)))
6768 (setq cs-decode (car cs))
6769 (setq cs-encode (cdr cs))
6770 (unless cs-decode (setq cs-decode 'undecided))
6771 (unless cs-encode (setq cs-encode 'undecided))
6772 (setq cs-encode (tramp-coding-system-change-eol-conversion
6773 cs-encode 'unix))
6774 (when (search-forward "\r" nil t)
6775 (setq cs-decode (tramp-coding-system-change-eol-conversion
6776 cs-decode 'dos)))
311dd93f 6777 (funcall (symbol-function 'set-buffer-process-coding-system)
70c11b0b
MA
6778 cs-decode cs-encode)
6779 (tramp-message
6780 vec 5 "Setting coding system to `%s' and `%s'" cs-decode cs-encode))
fb7933a3
KG
6781 ;; Look for ^M and do something useful if found.
6782 (when (search-forward "\r" nil t)
00d6fd04
MA
6783 ;; We have found a ^M but cannot frob the process coding system
6784 ;; because we're running on a non-MULE Emacs. Let's try
6785 ;; stty, instead.
7e780ff1 6786 (tramp-send-command vec "stty -onlcr" t))))
7e5686f0
MA
6787 ;; Dump stty settings in the traces.
6788 (when (>= tramp-verbose 10)
6789 (tramp-send-command vec "stty -a" t))
7e780ff1 6790 (tramp-send-command vec "set +o vi +o emacs" t)
e42c6bbc
MA
6791
6792 ;; Check whether the output of "uname -sr" has been changed. If
6793 ;; yes, this is a strong indication that we must expire all
d8ac123e
MA
6794 ;; connection properties. We start again with
6795 ;; `tramp-maybe-open-connection', it will be catched there.
e42c6bbc
MA
6796 (tramp-message vec 5 "Checking system information")
6797 (let ((old-uname (tramp-get-connection-property vec "uname" nil))
6798 (new-uname
6799 (tramp-set-connection-property
6800 vec "uname"
6801 (tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\""))))
6802 (when (and (stringp old-uname) (not (string-equal old-uname new-uname)))
d8ac123e
MA
6803 (with-current-buffer (tramp-get-debug-buffer vec)
6804 ;; Keep the debug buffer
2296b54d
MA
6805 (rename-buffer
6806 (generate-new-buffer-name tramp-temp-buffer-name) 'unique)
d8ac123e
MA
6807 (funcall (symbol-function 'tramp-cleanup-connection) vec)
6808 (if (= (point-min) (point-max))
6809 (kill-buffer nil)
6810 (rename-buffer (tramp-debug-buffer-name vec) 'unique))
6811 ;; We call `tramp-get-buffer' in order to keep the debug buffer.
6812 (tramp-get-buffer vec)
6813 (tramp-message
6814 vec 3
6815 "Connection reset, because remote host changed from `%s' to `%s'"
6816 old-uname new-uname)
6817 (throw 'uname-changed (tramp-maybe-open-connection vec)))))
e42c6bbc
MA
6818
6819 ;; Check whether the remote host suffers from buggy
6820 ;; `send-process-string'. This is known for FreeBSD (see comment in
6821 ;; `send_process', file process.c). I've tested sending 624 bytes
6822 ;; successfully, sending 625 bytes failed. Emacs makes a hack when
6823 ;; this host type is detected locally. It cannot handle remote
6824 ;; hosts, though.
00d6fd04
MA
6825 (with-connection-property proc "chunksize"
6826 (cond
6827 ((and (integerp tramp-chunksize) (> tramp-chunksize 0))
6828 tramp-chunksize)
6829 (t
6830 (tramp-message
6831 vec 5 "Checking remote host type for `send-process-string' bug")
6832 (if (string-match
e42c6bbc 6833 "^FreeBSD" (tramp-get-connection-property vec "uname" ""))
00d6fd04 6834 500 0))))
e42c6bbc 6835
00d6fd04
MA
6836 ;; Set remote PATH variable.
6837 (tramp-set-remote-path vec)
e42c6bbc 6838
fb7933a3
KG
6839 ;; Search for a good shell before searching for a command which
6840 ;; checks if a file exists. This is done because Tramp wants to use
6841 ;; "test foo; echo $?" to check if various conditions hold, and
6842 ;; there are buggy /bin/sh implementations which don't execute the
6843 ;; "echo $?" part if the "test" part has an error. In particular,
c0e17ff2
MA
6844 ;; the OpenSolaris /bin/sh is a problem. There are also other
6845 ;; problems with /bin/sh of OpenSolaris, like redirection of stderr
6846 ;; in in function declarations, or changing HISTFILE in place.
6847 ;; Therefore, OpenSolaris' /bin/sh is replaced by bash, when
6848 ;; detected.
00d6fd04 6849 (tramp-find-shell vec)
e42c6bbc 6850
00d6fd04 6851 ;; Disable unexpected output.
7e780ff1 6852 (tramp-send-command vec "mesg n; biff n" t)
e42c6bbc 6853
00d6fd04
MA
6854 ;; Set the environment.
6855 (tramp-message vec 5 "Setting default environment")
661aaece 6856
00d6fd04
MA
6857 (let ((env (copy-sequence tramp-remote-process-environment))
6858 unset item)
6859 (while env
70c11b0b 6860 (setq item (tramp-compat-split-string (car env) "="))
7e5686f0
MA
6861 (setcdr item (mapconcat 'identity (cdr item) "="))
6862 (if (and (stringp (cdr item)) (not (string-equal (cdr item) "")))
00d6fd04 6863 (tramp-send-command
7e5686f0 6864 vec (format "%s=%s; export %s" (car item) (cdr item) (car item)) t)
00d6fd04
MA
6865 (push (car item) unset))
6866 (setq env (cdr env)))
6867 (when unset
fb7933a3 6868 (tramp-send-command
7e780ff1 6869 vec (format "unset %s" (mapconcat 'identity unset " "))))) t)
fb7933a3 6870
ac474af1
KG
6871;; CCC: We should either implement a Perl version of base64 encoding
6872;; and decoding. Then we just use that in the last item. The other
6873;; alternative is to use the Perl version of UU encoding. But then
6874;; we need a Lisp version of uuencode.
16674e4f
KG
6875;;
6876;; Old text from documentation of tramp-methods:
6877;; Using a uuencode/uudecode inline method is discouraged, please use one
6878;; of the base64 methods instead since base64 encoding is much more
6879;; reliable and the commands are more standardized between the different
6880;; Unix versions. But if you can't use base64 for some reason, please
6881;; note that the default uudecode command does not work well for some
6882;; Unices, in particular AIX and Irix. For AIX, you might want to use
6883;; the following command for uudecode:
6884;;
6885;; sed '/^begin/d;/^[` ]$/d;/^end/d' | iconv -f uucode -t ISO8859-1
6886;;
6887;; For Irix, no solution is known yet.
6888
00d6fd04
MA
6889(defconst tramp-local-coding-commands
6890 '((b64 base64-encode-region base64-decode-region)
6891 (uu tramp-uuencode-region uudecode-decode-region)
6892 (pack
6893 "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
6894 "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"))
6895 "List of local coding commands for inline transfer.
16674e4f
KG
6896Each item is a list that looks like this:
6897
00d6fd04 6898\(FORMAT ENCODING DECODING)
ac474af1 6899
00d6fd04
MA
6900FORMAT is symbol describing the encoding/decoding format. It can be
6901`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
ac474af1 6902
00d6fd04
MA
6903ENCODING and DECODING can be strings, giving commands, or symbols,
6904giving functions. If they are strings, then they can contain
16674e4f
KG
6905the \"%s\" format specifier. If that specifier is present, the input
6906filename will be put into the command line at that spot. If the
6907specifier is not present, the input should be read from standard
6908input.
ac474af1 6909
16674e4f
KG
6910If they are functions, they will be called with two arguments, start
6911and end of region, and are expected to replace the region contents
6912with the encoded or decoded results, respectively.")
ac474af1 6913
00d6fd04 6914(defconst tramp-remote-coding-commands
3dc847a3
MA
6915 '((b64 "base64" "base64 -d")
6916 (b64 "mimencode -b" "mimencode -u -b")
00d6fd04
MA
6917 (b64 "mmencode -b" "mmencode -u -b")
6918 (b64 "recode data..base64" "recode base64..data")
6919 (b64 tramp-perl-encode-with-module tramp-perl-decode-with-module)
6920 (b64 tramp-perl-encode tramp-perl-decode)
6921 (uu "uuencode xxx" "uudecode -o /dev/stdout")
6922 (uu "uuencode xxx" "uudecode -o -")
6923 (uu "uuencode xxx" "uudecode -p")
6924 (uu "uuencode xxx" tramp-uudecode)
6925 (pack
6926 "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
6927 "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"))
6928 "List of remote coding commands for inline transfer.
6929Each item is a list that looks like this:
6930
6931\(FORMAT ENCODING DECODING)
6932
6933FORMAT is symbol describing the encoding/decoding format. It can be
6934`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
6935
6936ENCODING and DECODING can be strings, giving commands, or symbols,
6937giving variables. If they are strings, then they can contain
6938the \"%s\" format specifier. If that specifier is present, the input
6939filename will be put into the command line at that spot. If the
6940specifier is not present, the input should be read from standard
6941input.
6942
6943If they are variables, this variable is a string containing a Perl
6944implementation for this functionality. This Perl program will be transferred
db9e401b 6945to the remote host, and it is available as shell function with the same name.")
00d6fd04
MA
6946
6947(defun tramp-find-inline-encoding (vec)
ac474af1 6948 "Find an inline transfer encoding that works.
00d6fd04
MA
6949Goes through the list `tramp-local-coding-commands' and
6950`tramp-remote-coding-commands'."
6951 (save-excursion
6952 (let ((local-commands tramp-local-coding-commands)
6953 (magic "xyzzy")
6954 loc-enc loc-dec rem-enc rem-dec litem ritem found)
6955 (while (and local-commands (not found))
6956 (setq litem (pop local-commands))
6957 (catch 'wont-work-local
6958 (let ((format (nth 0 litem))
6959 (remote-commands tramp-remote-coding-commands))
6960 (setq loc-enc (nth 1 litem))
6961 (setq loc-dec (nth 2 litem))
6962 ;; If the local encoder or decoder is a string, the
6963 ;; corresponding command has to work locally.
6964 (if (not (stringp loc-enc))
6965 (tramp-message
6966 vec 5 "Checking local encoding function `%s'" loc-enc)
6967 (tramp-message
6968 vec 5 "Checking local encoding command `%s' for sanity" loc-enc)
6969 (unless (zerop (tramp-call-local-coding-command
6970 loc-enc nil nil))
6971 (throw 'wont-work-local nil)))
6972 (if (not (stringp loc-dec))
6973 (tramp-message
6974 vec 5 "Checking local decoding function `%s'" loc-dec)
6975 (tramp-message
6976 vec 5 "Checking local decoding command `%s' for sanity" loc-dec)
6977 (unless (zerop (tramp-call-local-coding-command
6978 loc-dec nil nil))
6979 (throw 'wont-work-local nil)))
6980 ;; Search for remote coding commands with the same format
6981 (while (and remote-commands (not found))
6982 (setq ritem (pop remote-commands))
6983 (catch 'wont-work-remote
6984 (when (equal format (nth 0 ritem))
6985 (setq rem-enc (nth 1 ritem))
6986 (setq rem-dec (nth 2 ritem))
6987 ;; Check if remote encoding and decoding commands can be
6988 ;; called remotely with null input and output. This makes
6989 ;; sure there are no syntax errors and the command is really
6990 ;; found. Note that we do not redirect stdout to /dev/null,
6991 ;; for two reasons: when checking the decoding command, we
6992 ;; actually check the output it gives. And also, when
6993 ;; redirecting "mimencode" output to /dev/null, then as root
6994 ;; it might change the permissions of /dev/null!
6995 (when (not (stringp rem-enc))
6996 (let ((name (symbol-name rem-enc)))
6997 (while (string-match (regexp-quote "-") name)
6998 (setq name (replace-match "_" nil t name)))
6999 (tramp-maybe-send-script vec (symbol-value rem-enc) name)
7000 (setq rem-enc name)))
7001 (tramp-message
7002 vec 5
7003 "Checking remote encoding command `%s' for sanity" rem-enc)
7004 (unless (zerop (tramp-send-command-and-check
7005 vec (format "%s </dev/null" rem-enc) t))
7006 (throw 'wont-work-remote nil))
7007
7008 (when (not (stringp rem-dec))
7009 (let ((name (symbol-name rem-dec)))
7010 (while (string-match (regexp-quote "-") name)
7011 (setq name (replace-match "_" nil t name)))
7012 (tramp-maybe-send-script vec (symbol-value rem-dec) name)
7013 (setq rem-dec name)))
7014 (tramp-message
7015 vec 5
7016 "Checking remote decoding command `%s' for sanity" rem-dec)
7017 (unless (zerop (tramp-send-command-and-check
7018 vec
7019 (format "echo %s | %s | %s"
b593f105
MA
7020 magic rem-enc rem-dec)
7021 t))
00d6fd04
MA
7022 (throw 'wont-work-remote nil))
7023
7024 (with-current-buffer (tramp-get-buffer vec)
7025 (goto-char (point-min))
7026 (unless (looking-at (regexp-quote magic))
7027 (throw 'wont-work-remote nil)))
7028
7029 ;; `rem-enc' and `rem-dec' could be a string meanwhile.
7030 (setq rem-enc (nth 1 ritem))
7031 (setq rem-dec (nth 2 ritem))
7032 (setq found t)))))))
7033
1d7e9a01 7034 ;; Did we find something?
00d6fd04 7035 (unless found
7e5686f0
MA
7036 (tramp-error
7037 vec 'file-error "Couldn't find an inline transfer encoding"))
00d6fd04
MA
7038
7039 ;; Set connection properties.
7040 (tramp-message vec 5 "Using local encoding `%s'" loc-enc)
7041 (tramp-set-connection-property vec "local-encoding" loc-enc)
7042 (tramp-message vec 5 "Using local decoding `%s'" loc-dec)
7043 (tramp-set-connection-property vec "local-decoding" loc-dec)
7044 (tramp-message vec 5 "Using remote encoding `%s'" rem-enc)
7045 (tramp-set-connection-property vec "remote-encoding" rem-enc)
7046 (tramp-message vec 5 "Using remote decoding `%s'" rem-dec)
7047 (tramp-set-connection-property vec "remote-decoding" rem-dec))))
16674e4f
KG
7048
7049(defun tramp-call-local-coding-command (cmd input output)
7050 "Call the local encoding or decoding command.
7051If CMD contains \"%s\", provide input file INPUT there in command.
7052Otherwise, INPUT is passed via standard input.
7053INPUT can also be nil which means `/dev/null'.
7054OUTPUT can be a string (which specifies a filename), or t (which
7055means standard output and thus the current buffer), or nil (which
7056means discard it)."
a4aeb9a4
MA
7057 (tramp-local-call-process
7058 tramp-encoding-shell
7059 (when (and input (not (string-match "%s" cmd))) input)
7060 (if (eq output t) t nil)
7061 nil
7062 tramp-encoding-command-switch
7063 (concat
7064 (if (string-match "%s" cmd) (format cmd input) cmd)
7065 (if (stringp output) (concat "> " output) ""))))
00d6fd04
MA
7066
7067(defun tramp-compute-multi-hops (vec)
7068 "Expands VEC according to `tramp-default-proxies-alist'.
7069Gateway hops are already opened."
7070 (let ((target-alist `(,vec))
7071 (choices tramp-default-proxies-alist)
7072 item proxy)
7073
7074 ;; Look for proxy hosts to be passed.
7075 (while choices
7076 (setq item (pop choices)
70c11b0b 7077 proxy (eval (nth 2 item)))
00d6fd04
MA
7078 (when (and
7079 ;; host
70c11b0b 7080 (string-match (or (eval (nth 0 item)) "")
00d6fd04
MA
7081 (or (tramp-file-name-host (car target-alist)) ""))
7082 ;; user
70c11b0b 7083 (string-match (or (eval (nth 1 item)) "")
00d6fd04
MA
7084 (or (tramp-file-name-user (car target-alist)) "")))
7085 (if (null proxy)
7086 ;; No more hops needed.
7087 (setq choices nil)
7088 ;; Replace placeholders.
7089 (setq proxy
7090 (format-spec
7091 proxy
7092 `((?u . ,(or (tramp-file-name-user (car target-alist)) ""))
7093 (?h . ,(or (tramp-file-name-host (car target-alist)) "")))))
7094 (with-parsed-tramp-file-name proxy l
7095 ;; Add the hop.
7096 (add-to-list 'target-alist l)
7097 ;; Start next search.
7098 (setq choices tramp-default-proxies-alist)))))
7099
7100 ;; Handle gateways.
8a4438b6
MA
7101 (when (and (boundp 'tramp-gw-tunnel-method)
7102 (string-match (format
7103 "^\\(%s\\|%s\\)$"
7104 (symbol-value 'tramp-gw-tunnel-method)
7105 (symbol-value 'tramp-gw-socks-method))
7106 (tramp-file-name-method (car target-alist))))
00d6fd04
MA
7107 (let ((gw (pop target-alist))
7108 (hop (pop target-alist)))
7109 ;; Is the method prepared for gateways?
7110 (unless (tramp-get-method-parameter
7111 (tramp-file-name-method hop) 'tramp-default-port)
7112 (tramp-error
7113 vec 'file-error
7114 "Method `%s' is not supported for gateway access."
7115 (tramp-file-name-method hop)))
7116 ;; Add default port if needed.
7117 (unless
7118 (string-match
7119 tramp-host-with-port-regexp (tramp-file-name-host hop))
7120 (aset hop 2
7121 (concat
7122 (tramp-file-name-host hop) tramp-prefix-port-format
7123 (number-to-string
7124 (tramp-get-method-parameter
7125 (tramp-file-name-method hop) 'tramp-default-port)))))
7126 ;; Open the gateway connection.
7127 (add-to-list
7128 'target-alist
7129 (vector
7130 (tramp-file-name-method hop) (tramp-file-name-user hop)
9e6ab520 7131 (funcall (symbol-function 'tramp-gw-open-connection) vec gw hop) nil))
00d6fd04
MA
7132 ;; For the password prompt, we need the correct values.
7133 ;; Therefore, we must remember the gateway vector. But we
7134 ;; cannot do it as connection property, because it shouldn't
7135 ;; be persistent. And we have no started process yet either.
7136 (tramp-set-file-property (car target-alist) "" "gateway" hop)))
7137
7138 ;; Foreign and out-of-band methods are not supported for multi-hops.
7139 (when (cdr target-alist)
7140 (setq choices target-alist)
7141 (while choices
7142 (setq item (pop choices))
7143 (when
7144 (or
7145 (not
7146 (tramp-get-method-parameter
7147 (tramp-file-name-method item) 'tramp-login-program))
7148 (tramp-get-method-parameter
7149 (tramp-file-name-method item) 'tramp-copy-program))
7150 (tramp-error
7151 vec 'file-error
7152 "Method `%s' is not supported for multi-hops."
7153 (tramp-file-name-method item)))))
7154
2991e49f
MA
7155 ;; In case the host name is not used for the remote shell
7156 ;; command, the user could be misguided by applying a random
7157 ;; hostname.
7158 (let* ((v (car target-alist))
7159 (method (tramp-file-name-method v))
7160 (host (tramp-file-name-host v)))
7161 (unless
7162 (or
7163 ;; There are multi-hops.
7164 (cdr target-alist)
7165 ;; The host name is used for the remote shell command.
7166 (member
7167 '("%h") (tramp-get-method-parameter method 'tramp-login-args))
7168 ;; The host is local. We cannot use `tramp-local-host-p'
7169 ;; here, because it opens a connection as well.
b96e6899 7170 (string-match tramp-local-host-regexp host))
2991e49f 7171 (tramp-error
42bc9b6d
MA
7172 v 'file-error
7173 "Host `%s' looks like a remote host, `%s' can only use the local host"
7174 host method)))
2991e49f 7175
00d6fd04
MA
7176 ;; Result.
7177 target-alist))
7178
7179(defun tramp-maybe-open-connection (vec)
7180 "Maybe open a connection VEC.
fb7933a3
KG
7181Does not do anything if a connection is already open, but re-opens the
7182connection if a previous connection has died for some reason."
d8ac123e
MA
7183 (catch 'uname-changed
7184 (let ((p (tramp-get-connection-process vec))
7185 (process-environment (copy-sequence process-environment)))
7186
7187 ;; If too much time has passed since last command was sent, look
7188 ;; whether process is still alive. If it isn't, kill it. When
7189 ;; using ssh, it can sometimes happen that the remote end has
7190 ;; hung up but the local ssh client doesn't recognize this until
7191 ;; it tries to send some data to the remote end. So that's why
7192 ;; we try to send a command from time to time, then look again
7193 ;; whether the process is really alive.
7194 (condition-case nil
7195 (when (and (> (tramp-time-diff
7196 (current-time)
7197 (tramp-get-connection-property
7198 p "last-cmd-time" '(0 0 0)))
7199 60)
7200 p (processp p) (memq (process-status p) '(run open)))
7201 (tramp-send-command vec "echo are you awake" t t)
7202 (unless (and (memq (process-status p) '(run open))
7203 (tramp-wait-for-output p 10))
7204 ;; The error will be catched locally.
7205 (tramp-error vec 'file-error "Awake did fail")))
7206 (file-error
7207 (tramp-flush-connection-property vec)
7208 (tramp-flush-connection-property p)
7209 (delete-process p)
7210 (setq p nil)))
7211
7212 ;; New connection must be opened.
7213 (unless (and p (processp p) (memq (process-status p) '(run open)))
7214
7215 ;; We call `tramp-get-buffer' in order to get a debug buffer for
7216 ;; messages from the beginning.
7217 (tramp-get-buffer vec)
7218 (if (zerop (length (tramp-file-name-user vec)))
7219 (tramp-message
7220 vec 3 "Opening connection for %s using %s..."
7221 (tramp-file-name-host vec)
7222 (tramp-file-name-method vec))
00d6fd04 7223 (tramp-message
d8ac123e
MA
7224 vec 3 "Opening connection for %s@%s using %s..."
7225 (tramp-file-name-user vec)
00d6fd04 7226 (tramp-file-name-host vec)
d8ac123e
MA
7227 (tramp-file-name-method vec)))
7228
7229 ;; Start new process.
7230 (when (and p (processp p))
7231 (delete-process p))
7232 (setenv "TERM" tramp-terminal-type)
7233 (setenv "LC_ALL" "C")
7234 (setenv "PROMPT_COMMAND")
dab816a9 7235 (setenv "PS1" tramp-initial-end-of-output)
d8ac123e
MA
7236 (let* ((target-alist (tramp-compute-multi-hops vec))
7237 (process-connection-type tramp-process-connection-type)
7238 (process-adaptive-read-buffering nil)
7239 (coding-system-for-read nil)
7240 ;; This must be done in order to avoid our file name handler.
7241 (p (let ((default-directory
7242 (tramp-compat-temporary-file-directory)))
7243 (start-process
7244 (or (tramp-get-connection-property vec "process-name" nil)
7245 (tramp-buffer-name vec))
7246 (tramp-get-connection-buffer vec)
70c11b0b 7247 tramp-encoding-shell))))
00d6fd04 7248
d8ac123e
MA
7249 (tramp-message
7250 vec 6 "%s" (mapconcat 'identity (process-command p) " "))
7251
7252 ;; Check whether process is alive.
d8ac123e
MA
7253 (tramp-set-process-query-on-exit-flag p nil)
7254 (tramp-message vec 3 "Waiting 60s for local shell to come up...")
7255 (tramp-barf-if-no-shell-prompt
7256 p 60 "Couldn't find local shell prompt %s" tramp-encoding-shell)
7257
7258 ;; Now do all the connections as specified.
7259 (while target-alist
7260 (let* ((hop (car target-alist))
7261 (l-method (tramp-file-name-method hop))
7262 (l-user (tramp-file-name-user hop))
7263 (l-host (tramp-file-name-host hop))
7264 (l-port nil)
7265 (login-program
7266 (tramp-get-method-parameter l-method 'tramp-login-program))
7267 (login-args
7268 (tramp-get-method-parameter l-method 'tramp-login-args))
7269 (gw-args
7270 (tramp-get-method-parameter l-method 'tramp-gw-args))
7271 (gw (tramp-get-file-property hop "" "gateway" nil))
7272 (g-method (and gw (tramp-file-name-method gw)))
7273 (g-user (and gw (tramp-file-name-user gw)))
7274 (g-host (and gw (tramp-file-name-host gw)))
7275 (command login-program)
7276 ;; We don't create the temporary file. In fact, it
7277 ;; is just a prefix for the ControlPath option of
7278 ;; ssh; the real temporary file has another name, and
7279 ;; it is created and protected by ssh. It is also
7280 ;; removed by ssh, when the connection is closed.
7281 (tmpfile
7282 (tramp-set-connection-property
7283 p "temp-file"
7284 (make-temp-name
7285 (expand-file-name
7286 tramp-temp-name-prefix
7287 (tramp-compat-temporary-file-directory)))))
7288 spec)
7289
7290 ;; Add gateway arguments if necessary.
7291 (when (and gw gw-args)
7292 (setq login-args (append login-args gw-args)))
7293
7294 ;; Check for port number. Until now, there's no need
7295 ;; for handling like method, user, host.
7296 (when (string-match tramp-host-with-port-regexp l-host)
7297 (setq l-port (match-string 2 l-host)
7298 l-host (match-string 1 l-host)))
7299
7300 ;; Set variables for computing the prompt for reading
2296b54d 7301 ;; password. They can also be derived from a gateway.
d8ac123e
MA
7302 (setq tramp-current-method (or g-method l-method)
7303 tramp-current-user (or g-user l-user)
7304 tramp-current-host (or g-host l-host))
7305
7306 ;; Replace login-args place holders.
7307 (setq
7308 l-host (or l-host "")
7309 l-user (or l-user "")
7310 l-port (or l-port "")
7311 spec `((?h . ,l-host) (?u . ,l-user) (?p . ,l-port)
7312 (?t . ,tmpfile))
7313 command
7314 (concat
e2a421af
MA
7315 ;; We do not want to see the trailing local prompt in
7316 ;; `start-file-process'.
7317 (unless (memq system-type '(windows-nt)) "exec ")
d8ac123e
MA
7318 command " "
7319 (mapconcat
aa485f7c
MA
7320 (lambda (x)
7321 (setq x (mapcar (lambda (y) (format-spec y spec)) x))
7322 (unless (member "" x) (mapconcat 'identity x " ")))
d8ac123e 7323 login-args " ")
d8ac123e
MA
7324 ;; Local shell could be a Windows COMSPEC. It doesn't
7325 ;; know the ";" syntax, but we must exit always for
70c11b0b 7326 ;; `start-file-process'. "exec" does not work either.
e2a421af 7327 (if (memq system-type '(windows-nt)) " && exit || exit")))
d8ac123e
MA
7328
7329 ;; Send the command.
7330 (tramp-message vec 3 "Sending command `%s'" command)
7331 (tramp-send-command vec command t t)
7332 (tramp-process-actions p vec tramp-actions-before-shell 60)
7333 (tramp-message vec 3 "Found remote shell prompt on `%s'" l-host))
7334 ;; Next hop.
7335 (setq target-alist (cdr target-alist)))
7336
7337 ;; Make initial shell settings.
7338 (tramp-open-connection-setup-interactive-shell p vec))))))
00d6fd04
MA
7339
7340(defun tramp-send-command (vec command &optional neveropen nooutput)
7341 "Send the COMMAND to connection VEC.
7342Erases temporary buffer before sending the command. If optional
7343arg NEVEROPEN is non-nil, never try to open the connection. This
7344is meant to be used from `tramp-maybe-open-connection' only. The
7345function waits for output unless NOOUTPUT is set."
7346 (unless neveropen (tramp-maybe-open-connection vec))
7347 (let ((p (tramp-get-connection-process vec)))
8950769a 7348 (when (tramp-get-connection-property p "remote-echo" nil)
00d6fd04
MA
7349 ;; We mark the command string that it can be erased in the output buffer.
7350 (tramp-set-connection-property p "check-remote-echo" t)
7351 (setq command (format "%s%s%s" tramp-echo-mark command tramp-echo-mark)))
7352 (tramp-message vec 6 "%s" command)
7353 (tramp-send-string vec command)
7354 (unless nooutput (tramp-wait-for-output p))))
7355
00d6fd04 7356(defun tramp-wait-for-output (proc &optional timeout)
7e5686f0
MA
7357 "Wait for output from remote command."
7358 (unless (buffer-live-p (process-buffer proc))
7359 (delete-process proc)
7360 (tramp-error proc 'file-error "Process `%s' not available, try again" proc))
00d6fd04 7361 (with-current-buffer (process-buffer proc)
dab816a9 7362 (let* (;; Initially, `tramp-end-of-output' is "#$ ". There might
bede3e9f 7363 ;; be leading escape sequences, which must be ignored.
dab816a9 7364 (regexp (format "[^#$\n]*%s\r?$" (regexp-quote tramp-end-of-output)))
bede3e9f
MA
7365 ;; Sometimes, the commands do not return a newline but a
7366 ;; null byte before the shell prompt, for example "git
7367 ;; ls-files -c -z ...".
7368 (regexp1 (format "\\(^\\|\000\\)%s" regexp))
7369 (found (tramp-wait-for-regexp proc timeout regexp1)))
00d6fd04
MA
7370 (if found
7371 (let (buffer-read-only)
7e5686f0
MA
7372 ;; A simple-minded busybox has sent " ^H" sequences.
7373 ;; Delete them.
7374 (goto-char (point-min))
7375 (when (re-search-forward
7376 "^\\(.\b\\)+$" (tramp-compat-line-end-position) t)
7377 (forward-line 1)
7378 (delete-region (point-min) (point)))
7379 ;; Delete the prompt.
00d6fd04 7380 (goto-char (point-max))
0664ff72 7381 (re-search-backward regexp nil t)
00d6fd04
MA
7382 (delete-region (point) (point-max)))
7383 (if timeout
7384 (tramp-error
7385 proc 'file-error
7386 "[[Remote prompt `%s' not found in %d secs]]"
7387 tramp-end-of-output timeout)
7388 (tramp-error
7389 proc 'file-error
7390 "[[Remote prompt `%s' not found]]" tramp-end-of-output)))
7391 ;; Return value is whether end-of-output sentinel was found.
7392 found)))
fb7933a3 7393
b593f105
MA
7394(defun tramp-send-command-and-check
7395 (vec command &optional subshell dont-suppress-err)
fb7933a3 7396 "Run COMMAND and check its exit status.
fb7933a3
KG
7397Sends `echo $?' along with the COMMAND for checking the exit status. If
7398COMMAND is nil, just sends `echo $?'. Returns the exit status found.
7399
b593f105
MA
7400If the optional argument SUBSHELL is non-nil, the command is
7401executed in a subshell, ie surrounded by parentheses. If
7402DONT-SUPPRESS-ERR is non-nil, stderr won't be sent to /dev/null."
00d6fd04
MA
7403 (tramp-send-command
7404 vec
7405 (concat (if subshell "( " "")
7406 command
b593f105 7407 (if command (if dont-suppress-err "; " " 2>/dev/null; ") "")
00d6fd04 7408 "echo tramp_exit_status $?"
b593f105 7409 (if subshell " )" "")))
00d6fd04
MA
7410 (with-current-buffer (tramp-get-connection-buffer vec)
7411 (goto-char (point-max))
7412 (unless (re-search-backward "tramp_exit_status [0-9]+" nil t)
7413 (tramp-error
7414 vec 'file-error "Couldn't find exit status of `%s'" command))
7415 (skip-chars-forward "^ ")
7416 (prog1
7417 (read (current-buffer))
7418 (let (buffer-read-only) (delete-region (match-beginning 0) (point-max))))))
7419
7420(defun tramp-barf-unless-okay (vec command fmt &rest args)
fb7933a3
KG
7421 "Run COMMAND, check exit status, throw error if exit status not okay.
7422Similar to `tramp-send-command-and-check' but accepts two more arguments
7423FMT and ARGS which are passed to `error'."
00d6fd04
MA
7424 (unless (zerop (tramp-send-command-and-check vec command))
7425 (apply 'tramp-error vec 'file-error fmt args)))
7426
7427(defun tramp-send-command-and-read (vec command)
7428 "Run COMMAND and return the output, which must be a Lisp expression.
7429In case there is no valid Lisp expression, it raises an error"
7430 (tramp-barf-unless-okay vec command "`%s' returns with error" command)
7431 (with-current-buffer (tramp-get-connection-buffer vec)
7432 ;; Read the expression.
7433 (goto-char (point-min))
7434 (condition-case nil
7435 (prog1 (read (current-buffer))
7436 ;; Error handling.
9e6ab520 7437 (when (re-search-forward "\\S-" (tramp-compat-line-end-position) t)
9ce8462a 7438 (error nil)))
00d6fd04
MA
7439 (error (tramp-error
7440 vec 'file-error
7441 "`%s' does not return a valid Lisp expression: `%s'"
7442 command (buffer-string))))))
fb7933a3 7443
7432277c
KG
7444;; It seems that Tru64 Unix does not like it if long strings are sent
7445;; to it in one go. (This happens when sending the Perl
7446;; `file-attributes' implementation, for instance.) Therefore, we
27e813fe 7447;; have this function which sends the string in chunks.
00d6fd04
MA
7448(defun tramp-send-string (vec string)
7449 "Send the STRING via connection VEC.
7432277c
KG
7450
7451The STRING is expected to use Unix line-endings, but the lines sent to
7452the remote host use line-endings as defined in the variable
00d6fd04
MA
7453`tramp-rsh-end-of-line'. The communication buffer is erased before sending."
7454 (let* ((p (tramp-get-connection-process vec))
7455 (chunksize (tramp-get-connection-property p "chunksize" nil)))
7456 (unless p
7457 (tramp-error
7458 vec 'file-error "Can't send string to remote host -- not logged in"))
7459 (tramp-set-connection-property p "last-cmd-time" (current-time))
7460 (tramp-message vec 10 "%s" string)
7461 (with-current-buffer (tramp-get-connection-buffer vec)
7462 ;; Clean up the buffer. We cannot call `erase-buffer' because
7463 ;; narrowing might be in effect.
7464 (let (buffer-read-only) (delete-region (point-min) (point-max)))
27e813fe 7465 ;; Replace "\n" by `tramp-rsh-end-of-line'.
00d6fd04
MA
7466 (setq string
7467 (mapconcat 'identity
70c11b0b 7468 (tramp-compat-split-string string "\n")
00d6fd04
MA
7469 tramp-rsh-end-of-line))
7470 (unless (or (string= string "")
7471 (string-equal (substring string -1) tramp-rsh-end-of-line))
7472 (setq string (concat string tramp-rsh-end-of-line)))
27e813fe 7473 ;; Send the string.
00d6fd04
MA
7474 (if (and chunksize (not (zerop chunksize)))
7475 (let ((pos 0)
7476 (end (length string)))
7477 (while (< pos end)
7478 (tramp-message
7479 vec 10 "Sending chunk from %s to %s"
7480 pos (min (+ pos chunksize) end))
7481 (process-send-string
7482 p (substring string pos (min (+ pos chunksize) end)))
7483 (setq pos (+ pos chunksize))))
7484 (process-send-string p string)))))
fb7933a3
KG
7485
7486(defun tramp-mode-string-to-int (mode-string)
7487 "Converts a ten-letter `drwxrwxrwx'-style mode string into mode bits."
f3c071dd
MA
7488 (let* (case-fold-search
7489 (mode-chars (string-to-vector mode-string))
fb7933a3
KG
7490 (owner-read (aref mode-chars 1))
7491 (owner-write (aref mode-chars 2))
7492 (owner-execute-or-setid (aref mode-chars 3))
7493 (group-read (aref mode-chars 4))
7494 (group-write (aref mode-chars 5))
7495 (group-execute-or-setid (aref mode-chars 6))
7496 (other-read (aref mode-chars 7))
7497 (other-write (aref mode-chars 8))
7498 (other-execute-or-sticky (aref mode-chars 9)))
7499 (save-match-data
7500 (logior
f3c071dd
MA
7501 (cond
7502 ((char-equal owner-read ?r) (tramp-octal-to-decimal "00400"))
7503 ((char-equal owner-read ?-) 0)
7504 (t (error "Second char `%c' must be one of `r-'" owner-read)))
7505 (cond
7506 ((char-equal owner-write ?w) (tramp-octal-to-decimal "00200"))
7507 ((char-equal owner-write ?-) 0)
7508 (t (error "Third char `%c' must be one of `w-'" owner-write)))
7509 (cond
7510 ((char-equal owner-execute-or-setid ?x)
7511 (tramp-octal-to-decimal "00100"))
7512 ((char-equal owner-execute-or-setid ?S)
7513 (tramp-octal-to-decimal "04000"))
7514 ((char-equal owner-execute-or-setid ?s)
7515 (tramp-octal-to-decimal "04100"))
7516 ((char-equal owner-execute-or-setid ?-) 0)
7517 (t (error "Fourth char `%c' must be one of `xsS-'"
7518 owner-execute-or-setid)))
7519 (cond
7520 ((char-equal group-read ?r) (tramp-octal-to-decimal "00040"))
7521 ((char-equal group-read ?-) 0)
7522 (t (error "Fifth char `%c' must be one of `r-'" group-read)))
7523 (cond
7524 ((char-equal group-write ?w) (tramp-octal-to-decimal "00020"))
7525 ((char-equal group-write ?-) 0)
7526 (t (error "Sixth char `%c' must be one of `w-'" group-write)))
7527 (cond
7528 ((char-equal group-execute-or-setid ?x)
7529 (tramp-octal-to-decimal "00010"))
7530 ((char-equal group-execute-or-setid ?S)
7531 (tramp-octal-to-decimal "02000"))
7532 ((char-equal group-execute-or-setid ?s)
7533 (tramp-octal-to-decimal "02010"))
7534 ((char-equal group-execute-or-setid ?-) 0)
7535 (t (error "Seventh char `%c' must be one of `xsS-'"
7536 group-execute-or-setid)))
7537 (cond
7538 ((char-equal other-read ?r)
7539 (tramp-octal-to-decimal "00004"))
7540 ((char-equal other-read ?-) 0)
7541 (t (error "Eighth char `%c' must be one of `r-'" other-read)))
7542 (cond
7543 ((char-equal other-write ?w) (tramp-octal-to-decimal "00002"))
7544 ((char-equal other-write ?-) 0)
fb7933a3 7545 (t (error "Nineth char `%c' must be one of `w-'" other-write)))
f3c071dd
MA
7546 (cond
7547 ((char-equal other-execute-or-sticky ?x)
7548 (tramp-octal-to-decimal "00001"))
7549 ((char-equal other-execute-or-sticky ?T)
7550 (tramp-octal-to-decimal "01000"))
7551 ((char-equal other-execute-or-sticky ?t)
7552 (tramp-octal-to-decimal "01001"))
7553 ((char-equal other-execute-or-sticky ?-) 0)
7554 (t (error "Tenth char `%c' must be one of `xtT-'"
7555 other-execute-or-sticky)))))))
fb7933a3 7556
00d6fd04
MA
7557(defun tramp-convert-file-attributes (vec attr)
7558 "Convert file-attributes ATTR generated by perl script, stat or ls.
c82c5727
LH
7559Convert file mode bits to string and set virtual device number.
7560Return ATTR."
680db9ac
MA
7561 (when attr
7562 ;; Convert last access time.
7563 (unless (listp (nth 4 attr))
7564 (setcar (nthcdr 4 attr)
7565 (list (floor (nth 4 attr) 65536)
7566 (floor (mod (nth 4 attr) 65536)))))
7567 ;; Convert last modification time.
7568 (unless (listp (nth 5 attr))
7569 (setcar (nthcdr 5 attr)
7570 (list (floor (nth 5 attr) 65536)
7571 (floor (mod (nth 5 attr) 65536)))))
7572 ;; Convert last status change time.
7573 (unless (listp (nth 6 attr))
7574 (setcar (nthcdr 6 attr)
7575 (list (floor (nth 6 attr) 65536)
7576 (floor (mod (nth 6 attr) 65536)))))
7577 ;; Convert file size.
7578 (when (< (nth 7 attr) 0)
7579 (setcar (nthcdr 7 attr) -1))
7580 (when (and (floatp (nth 7 attr))
7581 (<= (nth 7 attr) (tramp-compat-most-positive-fixnum)))
7582 (setcar (nthcdr 7 attr) (round (nth 7 attr))))
7583 ;; Convert file mode bits to string.
7584 (unless (stringp (nth 8 attr))
7585 (setcar (nthcdr 8 attr) (tramp-file-mode-from-int (nth 8 attr)))
7586 (when (stringp (car attr))
7587 (aset (nth 8 attr) 0 ?l)))
7588 ;; Convert directory indication bit.
7589 (when (string-match "^d" (nth 8 attr))
7590 (setcar attr t))
7591 ;; Convert symlink from `tramp-do-file-attributes-with-stat'.
7592 (when (consp (car attr))
7593 (if (and (stringp (caar attr))
7594 (string-match ".+ -> .\\(.+\\)." (caar attr)))
7595 (setcar attr (match-string 1 (caar attr)))
7596 (setcar attr nil)))
7597 ;; Set file's gid change bit.
7598 (setcar (nthcdr 9 attr)
7599 (if (numberp (nth 3 attr))
7600 (not (= (nth 3 attr)
7601 (tramp-get-remote-gid vec 'integer)))
7602 (not (string-equal
7603 (nth 3 attr)
7604 (tramp-get-remote-gid vec 'string)))))
7605 ;; Convert inode.
7606 (unless (listp (nth 10 attr))
7607 (setcar (nthcdr 10 attr)
7608 (condition-case nil
7609 (cons (floor (nth 10 attr) 65536)
7610 (floor (mod (nth 10 attr) 65536)))
7611 ;; Inodes can be incredible huge. We must hide this.
7612 (error (tramp-get-inode vec)))))
7613 ;; Set virtual device number.
7614 (setcar (nthcdr 11 attr)
7615 (tramp-get-device vec))
7616 attr))
c82c5727 7617
293c24f9
MA
7618(defun tramp-check-cached-permissions (vec access)
7619 "Check `file-attributes' caches for VEC.
7620Return t if according to the cache access type ACCESS is known to
7621be granted."
7622 (let ((result nil)
7623 (offset (cond
7624 ((eq ?r access) 1)
7625 ((eq ?w access) 2)
7626 ((eq ?x access) 3))))
7627 (dolist (suffix '("string" "integer") result)
7628 (setq
7629 result
7630 (or
7631 result
7632 (let ((file-attr
7633 (tramp-get-file-property
7634 vec (tramp-file-name-localname vec)
7635 (concat "file-attributes-" suffix) nil))
7636 (remote-uid
7637 (tramp-get-connection-property
7638 vec (concat "uid-" suffix) nil))
7639 (remote-gid
7640 (tramp-get-connection-property
7641 vec (concat "gid-" suffix) nil)))
7642 (and
7643 file-attr
7644 (or
7645 ;; Not a symlink
7646 (eq t (car file-attr))
7647 (null (car file-attr)))
7648 (or
7649 ;; World accessible.
7650 (eq access (aref (nth 8 file-attr) (+ offset 6)))
7651 ;; User accessible and owned by user.
7652 (and
7653 (eq access (aref (nth 8 file-attr) offset))
7654 (equal remote-uid (nth 2 file-attr)))
7655 ;; Group accessible and owned by user's
7656 ;; principal group.
7657 (and
7658 (eq access (aref (nth 8 file-attr) (+ offset 3)))
7659 (equal remote-gid (nth 3 file-attr)))))))))))
7660
ce3f516f 7661(defun tramp-get-inode (vec)
00d6fd04
MA
7662 "Returns the virtual inode number.
7663If it doesn't exist, generate a new one."
ce3f516f
MA
7664 (let ((string (tramp-make-tramp-file-name
7665 (tramp-file-name-method vec)
7666 (tramp-file-name-user vec)
7667 (tramp-file-name-host vec)
7668 "")))
00d6fd04
MA
7669 (unless (assoc string tramp-inodes)
7670 (add-to-list 'tramp-inodes
7671 (list string (length tramp-inodes))))
7672 (nth 1 (assoc string tramp-inodes))))
7673
7674(defun tramp-get-device (vec)
c82c5727
LH
7675 "Returns the virtual device number.
7676If it doesn't exist, generate a new one."
00d6fd04
MA
7677 (let ((string (tramp-make-tramp-file-name
7678 (tramp-file-name-method vec)
7679 (tramp-file-name-user vec)
7680 (tramp-file-name-host vec)
7681 "")))
c82c5727
LH
7682 (unless (assoc string tramp-devices)
7683 (add-to-list 'tramp-devices
7684 (list string (length tramp-devices))))
b946a456 7685 (cons -1 (nth 1 (assoc string tramp-devices)))))
fb7933a3
KG
7686
7687(defun tramp-file-mode-from-int (mode)
7688 "Turn an integer representing a file mode into an ls(1)-like string."
7689 (let ((type (cdr (assoc (logand (lsh mode -12) 15) tramp-file-mode-type-map)))
7690 (user (logand (lsh mode -6) 7))
7691 (group (logand (lsh mode -3) 7))
7692 (other (logand (lsh mode -0) 7))
7693 (suid (> (logand (lsh mode -9) 4) 0))
7694 (sgid (> (logand (lsh mode -9) 2) 0))
7695 (sticky (> (logand (lsh mode -9) 1) 0)))
7696 (setq user (tramp-file-mode-permissions user suid "s"))
7697 (setq group (tramp-file-mode-permissions group sgid "s"))
7698 (setq other (tramp-file-mode-permissions other sticky "t"))
7699 (concat type user group other)))
7700
fb7933a3
KG
7701(defun tramp-file-mode-permissions (perm suid suid-text)
7702 "Convert a permission bitset into a string.
7703This is used internally by `tramp-file-mode-from-int'."
7704 (let ((r (> (logand perm 4) 0))
7705 (w (> (logand perm 2) 0))
7706 (x (> (logand perm 1) 0)))
7707 (concat (or (and r "r") "-")
7708 (or (and w "w") "-")
7709 (or (and suid x suid-text) ; suid, execute
7710 (and suid (upcase suid-text)) ; suid, !execute
7711 (and x "x") "-")))) ; !suid
7712
fb7933a3
KG
7713(defun tramp-decimal-to-octal (i)
7714 "Return a string consisting of the octal digits of I.
7715Not actually used. Use `(format \"%o\" i)' instead?"
7716 (cond ((< i 0) (error "Cannot convert negative number to octal"))
7717 ((not (integerp i)) (error "Cannot convert non-integer to octal"))
7718 ((zerop i) "0")
7719 (t (concat (tramp-decimal-to-octal (/ i 8))
7720 (number-to-string (% i 8))))))
7721
fb7933a3
KG
7722;; Kudos to Gerd Moellmann for this suggestion.
7723(defun tramp-octal-to-decimal (ostr)
7724 "Given a string of octal digits, return a decimal number."
7725 (let ((x (or ostr "")))
7726 ;; `save-match' is in `tramp-mode-string-to-int' which calls this.
7727 (unless (string-match "\\`[0-7]*\\'" x)
7728 (error "Non-octal junk in string `%s'" x))
7729 (string-to-number ostr 8)))
7730
7731(defun tramp-shell-case-fold (string)
7732 "Converts STRING to shell glob pattern which ignores case."
7733 (mapconcat
7734 (lambda (c)
7735 (if (equal (downcase c) (upcase c))
7736 (vector c)
7737 (format "[%c%c]" (downcase c) (upcase c))))
7738 string
7739 ""))
7740
7741
bf247b6e 7742;; ------------------------------------------------------------
a4aeb9a4 7743;; -- Tramp file names --
bf247b6e 7744;; ------------------------------------------------------------
fb7933a3
KG
7745;; Conversion functions between external representation and
7746;; internal data structure. Convenience functions for internal
7747;; data structure.
7748
00d6fd04
MA
7749(defun tramp-file-name-p (vec)
7750 "Check whether VEC is a Tramp object."
7751 (and (vectorp vec) (= 4 (length vec))))
7752
7753(defun tramp-file-name-method (vec)
7754 "Return method component of VEC."
7755 (and (tramp-file-name-p vec) (aref vec 0)))
7756
7757(defun tramp-file-name-user (vec)
7758 "Return user component of VEC."
7759 (and (tramp-file-name-p vec) (aref vec 1)))
7760
7761(defun tramp-file-name-host (vec)
7762 "Return host component of VEC."
7763 (and (tramp-file-name-p vec) (aref vec 2)))
7764
7765(defun tramp-file-name-localname (vec)
7766 "Return localname component of VEC."
7767 (and (tramp-file-name-p vec) (aref vec 3)))
7768
dea31ca6 7769;; The user part of a Tramp file name vector can be of kind
b96e6899 7770;; "user%domain". Sometimes, we must extract these parts.
dea31ca6
MA
7771(defun tramp-file-name-real-user (vec)
7772 "Return the user name of VEC without domain."
a17632c1
MA
7773 (save-match-data
7774 (let ((user (tramp-file-name-user vec)))
7775 (if (and (stringp user)
7776 (string-match tramp-user-with-domain-regexp user))
7777 (match-string 1 user)
7778 user))))
dea31ca6
MA
7779
7780(defun tramp-file-name-domain (vec)
7781 "Return the domain name of VEC."
a17632c1
MA
7782 (save-match-data
7783 (let ((user (tramp-file-name-user vec)))
7784 (and (stringp user)
7785 (string-match tramp-user-with-domain-regexp user)
7786 (match-string 2 user)))))
dea31ca6 7787
00d6fd04
MA
7788;; The host part of a Tramp file name vector can be of kind
7789;; "host#port". Sometimes, we must extract these parts.
8a4438b6 7790(defun tramp-file-name-real-host (vec)
00d6fd04 7791 "Return the host name of VEC without port."
a17632c1
MA
7792 (save-match-data
7793 (let ((host (tramp-file-name-host vec)))
7794 (if (and (stringp host)
7795 (string-match tramp-host-with-port-regexp host))
7796 (match-string 1 host)
7797 host))))
00d6fd04 7798
8a4438b6 7799(defun tramp-file-name-port (vec)
00d6fd04 7800 "Return the port number of VEC."
a17632c1
MA
7801 (save-match-data
7802 (let ((host (tramp-file-name-host vec)))
7803 (and (stringp host)
7804 (string-match tramp-host-with-port-regexp host)
7805 (string-to-number (match-string 2 host))))))
fb7933a3
KG
7806
7807(defun tramp-tramp-file-p (name)
a09dc9bf 7808 "Return t if NAME is a string with Tramp file name syntax."
fb7933a3 7809 (save-match-data
a09dc9bf 7810 (and (stringp name) (string-match tramp-file-name-regexp name))))
bf247b6e 7811
8a4438b6 7812(defun tramp-find-method (method user host)
00d6fd04
MA
7813 "Return the right method string to use.
7814This is METHOD, if non-nil. Otherwise, do a lookup in
7815`tramp-default-method-alist'."
7816 (or method
7817 (let ((choices tramp-default-method-alist)
7818 lmethod item)
7819 (while choices
7820 (setq item (pop choices))
7821 (when (and (string-match (or (nth 0 item) "") (or host ""))
7822 (string-match (or (nth 1 item) "") (or user "")))
7823 (setq lmethod (nth 2 item))
7824 (setq choices nil)))
7825 lmethod)
7826 tramp-default-method))
7827
8a4438b6 7828(defun tramp-find-user (method user host)
00d6fd04
MA
7829 "Return the right user string to use.
7830This is USER, if non-nil. Otherwise, do a lookup in
7831`tramp-default-user-alist'."
7832 (or user
7833 (let ((choices tramp-default-user-alist)
7834 luser item)
7835 (while choices
7836 (setq item (pop choices))
7837 (when (and (string-match (or (nth 0 item) "") (or method ""))
7838 (string-match (or (nth 1 item) "") (or host "")))
7839 (setq luser (nth 2 item))
7840 (setq choices nil)))
7841 luser)
7842 tramp-default-user))
7843
8a4438b6 7844(defun tramp-find-host (method user host)
00d6fd04
MA
7845 "Return the right host string to use.
7846This is HOST, if non-nil. Otherwise, it is `tramp-default-host'."
7847 (or (and (> (length host) 0) host)
7848 tramp-default-host))
7849
9ce8462a 7850(defun tramp-dissect-file-name (name &optional nodefault)
00d6fd04 7851 "Return a `tramp-file-name' structure.
9ce8462a
MA
7852The structure consists of remote method, remote user, remote host
7853and localname (file name on remote host). If NODEFAULT is
7854non-nil, the file name parts are not expanded to their default
7855values."
4007ba5b 7856 (save-match-data
00d6fd04 7857 (let ((match (string-match (nth 0 tramp-file-name-structure) name)))
a4aeb9a4 7858 (unless match (error "Not a Tramp file name: %s" name))
00d6fd04
MA
7859 (let ((method (match-string (nth 1 tramp-file-name-structure) name))
7860 (user (match-string (nth 2 tramp-file-name-structure) name))
7861 (host (match-string (nth 3 tramp-file-name-structure) name))
7862 (localname (match-string (nth 4 tramp-file-name-structure) name)))
5d449a36
MA
7863 (when (member method '("multi" "multiu"))
7864 (error
7865 "`%s' method is no longer supported, see (info \"(tramp)Multi-hops\")"
7866 method))
b96e6899
MA
7867 (when host
7868 (when (string-match tramp-prefix-ipv6-regexp host)
7869 (setq host (replace-match "" nil t host)))
7870 (when (string-match tramp-postfix-ipv6-regexp host)
7871 (setq host (replace-match "" nil t host))))
9ce8462a
MA
7872 (if nodefault
7873 (vector method user host localname)
7874 (vector
7875 (tramp-find-method method user host)
7876 (tramp-find-user method user host)
7877 (tramp-find-host method user host)
7878 localname))))))
00d6fd04
MA
7879
7880(defun tramp-equal-remote (file1 file2)
7881 "Checks, whether the remote parts of FILE1 and FILE2 are identical.
7882The check depends on method, user and host name of the files. If
7883one of the components is missing, the default values are used.
7884The local file name parts of FILE1 and FILE2 are not taken into
7885account.
fb7933a3 7886
00d6fd04
MA
7887Example:
7888
7889 (tramp-equal-remote \"/ssh::/etc\" \"/<your host name>:/home\")
7890
7891would yield `t'. On the other hand, the following check results in nil:
7892
7893 (tramp-equal-remote \"/sudo::/etc\" \"/su::/etc\")"
9e6ab520
MA
7894 (and (stringp (file-remote-p file1))
7895 (stringp (file-remote-p file2))
94be87e8 7896 (string-equal (file-remote-p file1) (file-remote-p file2))))
00d6fd04
MA
7897
7898(defun tramp-make-tramp-file-name (method user host localname)
7899 "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME."
7900 (concat tramp-prefix-format
7901 (when (not (zerop (length method)))
7902 (concat method tramp-postfix-method-format))
7903 (when (not (zerop (length user)))
7904 (concat user tramp-postfix-user-format))
b96e6899
MA
7905 (when host
7906 (if (string-match tramp-ipv6-regexp host)
7907 (concat tramp-prefix-ipv6-format host tramp-postfix-ipv6-format)
7908 host))
7909 tramp-postfix-host-format
00d6fd04
MA
7910 (when localname localname)))
7911
7912(defun tramp-completion-make-tramp-file-name (method user host localname)
7913 "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME.
7914It must not be a complete Tramp file name, but as long as there are
7915necessary only. This function will be used in file name completion."
7916 (concat tramp-prefix-format
7917 (when (not (zerop (length method)))
7918 (concat method tramp-postfix-method-format))
7919 (when (not (zerop (length user)))
7920 (concat user tramp-postfix-user-format))
7921 (when (not (zerop (length host)))
b96e6899
MA
7922 (concat
7923 (if (string-match tramp-ipv6-regexp host)
7924 (concat tramp-prefix-ipv6-format host tramp-postfix-ipv6-format)
7925 host)
7926 tramp-postfix-host-format))
00d6fd04
MA
7927 (when localname localname)))
7928
7929(defun tramp-make-copy-program-file-name (vec)
7930 "Create a file name suitable to be passed to `rcp' and workalikes."
7931 (let ((user (tramp-file-name-user vec))
0f205eee 7932 (host (tramp-file-name-real-host vec))
00d6fd04
MA
7933 (localname (tramp-shell-quote-argument
7934 (tramp-file-name-localname vec))))
7935 (if (not (zerop (length user)))
7936 (format "%s@%s:%s" user host localname)
7937 (format "%s:%s" host localname))))
7938
7f49fe46 7939(defun tramp-method-out-of-band-p (vec size)
38c65fca 7940 "Return t if this is an out-of-band method, nil otherwise."
7f49fe46
MA
7941 (and
7942 ;; It shall be an out-of-band method.
7943 (tramp-get-method-parameter (tramp-file-name-method vec) 'tramp-copy-program)
7944 ;; Either the file size is large enough, or (in rare cases) there
7945 ;; does not exist a remote encoding.
7946 (or (> size tramp-copy-size-limit)
7947 (null (tramp-get-remote-coding vec "remote-encoding")))))
fb7933a3 7948
0f205eee
MA
7949(defun tramp-local-host-p (vec)
7950 "Return t if this points to the local host, nil otherwise."
c992abdb
MA
7951 ;; We cannot use `tramp-file-name-real-host'. A port is an
7952 ;; indication for an ssh tunnel or alike.
7953 (let ((host (tramp-file-name-host vec)))
0f205eee
MA
7954 (and
7955 (stringp host)
b96e6899 7956 (string-match tramp-local-host-regexp host)
46bcd78c
MA
7957 ;; The method shall be applied to one of the shell file name
7958 ;; handler. `tramp-local-host-p' is also called for "smb" and
7959 ;; alike, where it must fail.
7960 (tramp-get-method-parameter
7961 (tramp-file-name-method vec) 'tramp-login-program)
a0a5183a
MA
7962 ;; The local temp directory must be writable for the other user.
7963 (file-writable-p
7964 (tramp-make-tramp-file-name
7965 (tramp-file-name-method vec)
7966 (tramp-file-name-user vec)
7967 host
93c3eb7c
MA
7968 (tramp-compat-temporary-file-directory)))
7969 ;; On some systems, chown runs only for root.
7970 (or (zerop (user-uid))
7971 (zerop (tramp-get-remote-uid vec 'integer))))))
0f205eee 7972
fb7933a3
KG
7973;; Variables local to connection.
7974
f84638eb 7975(defun tramp-get-remote-path (vec)
70c11b0b
MA
7976 (with-connection-property
7977 ;; When `tramp-own-remote-path' is in `tramp-remote-path', we
7978 ;; cache the result for the session only. Otherwise, the result
7979 ;; is cached persistently.
7980 (if (memq 'tramp-own-remote-path tramp-remote-path)
7981 (tramp-get-connection-process vec)
7982 vec)
7983 "remote-path"
9e6ab520 7984 (let* ((remote-path (tramp-compat-copy-tree tramp-remote-path))
70c11b0b
MA
7985 (elt1 (memq 'tramp-default-remote-path remote-path))
7986 (elt2 (memq 'tramp-own-remote-path remote-path))
f84638eb 7987 (default-remote-path
70c11b0b 7988 (when elt1
f84638eb 7989 (condition-case nil
70c11b0b
MA
7990 (tramp-send-command-and-read
7991 vec "echo \\\"`getconf PATH`\\\"")
f84638eb
MA
7992 ;; Default if "getconf" is not available.
7993 (error
7994 (tramp-message
7995 vec 3
7996 "`getconf PATH' not successful, using default value \"%s\"."
7997 "/bin:/usr/bin")
70c11b0b
MA
7998 "/bin:/usr/bin"))))
7999 (own-remote-path
8000 (when elt2
8001 (condition-case nil
8002 (tramp-send-command-and-read vec "echo \\\"$PATH\\\"")
8003 ;; Default if "getconf" is not available.
8004 (error
8005 (tramp-message
8006 vec 3 "$PATH not set, ignoring `tramp-own-remote-path'.")
8007 nil)))))
8008
8009 ;; Replace place holder `tramp-default-remote-path'.
8010 (when elt1
8011 (setcdr elt1
f84638eb 8012 (append
70c11b0b
MA
8013 (tramp-compat-split-string default-remote-path ":")
8014 (cdr elt1)))
f84638eb
MA
8015 (setq remote-path (delq 'tramp-default-remote-path remote-path)))
8016
70c11b0b
MA
8017 ;; Replace place holder `tramp-own-remote-path'.
8018 (when elt2
8019 (setcdr elt2
8020 (append
8021 (tramp-compat-split-string own-remote-path ":")
8022 (cdr elt2)))
8023 (setq remote-path (delq 'tramp-own-remote-path remote-path)))
8024
8025 ;; Remove double entries.
8026 (setq elt1 remote-path)
8027 (while (consp elt1)
8028 (while (and (car elt1) (setq elt2 (member (car elt1) (cdr elt1))))
8029 (setcar elt2 nil))
8030 (setq elt1 (cdr elt1)))
8031
f84638eb
MA
8032 ;; Remove non-existing directories.
8033 (delq
8034 nil
8035 (mapcar
8036 (lambda (x)
8037 (and
70c11b0b
MA
8038 (stringp x)
8039 (file-directory-p
8040 (tramp-make-tramp-file-name
8041 (tramp-file-name-method vec)
8042 (tramp-file-name-user vec)
8043 (tramp-file-name-host vec)
8044 x))
f84638eb
MA
8045 x))
8046 remote-path)))))
8047
a4aeb9a4
MA
8048(defun tramp-get-remote-tmpdir (vec)
8049 (with-connection-property vec "tmp-directory"
8050 (let ((dir (tramp-shell-quote-argument "/tmp")))
8051 (if (and (zerop
8052 (tramp-send-command-and-check
8053 vec (format "%s -d %s" (tramp-get-test-command vec) dir)))
8054 (zerop
8055 (tramp-send-command-and-check
8056 vec (format "%s -w %s" (tramp-get-test-command vec) dir))))
8057 dir
8058 (tramp-error vec 'file-error "Directory %s not accessible" dir)))))
8059
00d6fd04
MA
8060(defun tramp-get-ls-command (vec)
8061 (with-connection-property vec "ls"
946a5aeb
MA
8062 (tramp-message vec 5 "Finding a suitable `ls' command")
8063 (or
8064 (catch 'ls-found
8065 (dolist (cmd '("ls" "gnuls" "gls"))
8066 (let ((dl (tramp-get-remote-path vec))
8067 result)
8068 (while (and dl (setq result (tramp-find-executable vec cmd dl t t)))
7e5686f0
MA
8069 ;; Check parameters. On busybox, "ls" output coloring is
8070 ;; enabled by default sometimes. So we try to disable it
8071 ;; when possible. $LS_COLORING is not supported there.
946a5aeb
MA
8072 (when (zerop (tramp-send-command-and-check
8073 vec (format "%s -lnd /" result)))
7e5686f0
MA
8074 (when (zerop (tramp-send-command-and-check
8075 vec (format "%s --color=never /" result)))
8076 (setq result (concat result " --color=never")))
946a5aeb
MA
8077 (throw 'ls-found result))
8078 (setq dl (cdr dl))))))
8079 (tramp-error vec 'file-error "Couldn't find a proper `ls' command"))))
00d6fd04 8080
8e754ea2
MA
8081(defun tramp-get-ls-command-with-dired (vec)
8082 (save-match-data
8083 (with-connection-property vec "ls-dired"
8084 (tramp-message vec 5 "Checking, whether `ls --dired' works")
8085 (zerop (tramp-send-command-and-check
7f49fe46 8086 vec (format "%s --dired /" (tramp-get-ls-command vec)))))))
8e754ea2 8087
00d6fd04
MA
8088(defun tramp-get-test-command (vec)
8089 (with-connection-property vec "test"
946a5aeb
MA
8090 (tramp-message vec 5 "Finding a suitable `test' command")
8091 (if (zerop (tramp-send-command-and-check vec "test 0"))
8092 "test"
8093 (tramp-find-executable vec "test" (tramp-get-remote-path vec)))))
00d6fd04
MA
8094
8095(defun tramp-get-test-nt-command (vec)
8096 ;; Does `test A -nt B' work? Use abominable `find' construct if it
8097 ;; doesn't. BSD/OS 4.0 wants the parentheses around the command,
8098 ;; for otherwise the shell crashes.
8099 (with-connection-property vec "test-nt"
8100 (or
8101 (progn
8102 (tramp-send-command
8103 vec (format "( %s / -nt / )" (tramp-get-test-command vec)))
8104 (with-current-buffer (tramp-get-buffer vec)
8105 (goto-char (point-min))
a0a5183a 8106 (when (looking-at (regexp-quote tramp-end-of-output))
00d6fd04
MA
8107 (format "%s %%s -nt %%s" (tramp-get-test-command vec)))))
8108 (progn
8109 (tramp-send-command
8110 vec
8111 (format
8112 "tramp_test_nt () {\n%s -n \"`find $1 -prune -newer $2 -print`\"\n}"
8113 (tramp-get-test-command vec)))
8114 "tramp_test_nt %s %s"))))
8115
8116(defun tramp-get-file-exists-command (vec)
8117 (with-connection-property vec "file-exists"
946a5aeb
MA
8118 (tramp-message vec 5 "Finding command to check if file exists")
8119 (tramp-find-file-exists-command vec)))
00d6fd04
MA
8120
8121(defun tramp-get-remote-ln (vec)
8122 (with-connection-property vec "ln"
946a5aeb
MA
8123 (tramp-message vec 5 "Finding a suitable `ln' command")
8124 (tramp-find-executable vec "ln" (tramp-get-remote-path vec))))
00d6fd04
MA
8125
8126(defun tramp-get-remote-perl (vec)
8127 (with-connection-property vec "perl"
946a5aeb 8128 (tramp-message vec 5 "Finding a suitable `perl' command")
293c24f9
MA
8129 (let ((result
8130 (or (tramp-find-executable vec "perl5" (tramp-get-remote-path vec))
8131 (tramp-find-executable
8132 vec "perl" (tramp-get-remote-path vec)))))
8133 ;; We must check also for some Perl modules.
8134 (when result
8135 (with-connection-property vec "perl-file-spec"
8136 (zerop
8137 (tramp-send-command-and-check
8138 vec (format "%s -e 'use File::Spec;'" result))))
8139 (with-connection-property vec "perl-cwd-realpath"
8140 (zerop
8141 (tramp-send-command-and-check
8142 vec (format "%s -e 'use Cwd \"realpath\";'" result)))))
8143 result)))
00d6fd04
MA
8144
8145(defun tramp-get-remote-stat (vec)
8146 (with-connection-property vec "stat"
946a5aeb
MA
8147 (tramp-message vec 5 "Finding a suitable `stat' command")
8148 (let ((result (tramp-find-executable
8149 vec "stat" (tramp-get-remote-path vec)))
8150 tmp)
8151 ;; Check whether stat(1) returns usable syntax. %s does not
8152 ;; work on older AIX systems.
8153 (when result
8154 (setq tmp
8155 ;; We don't want to display an error message.
8156 (with-temp-message (or (current-message) "")
8157 (condition-case nil
8158 (tramp-send-command-and-read
8159 vec (format "%s -c '(\"%%N\" %%s)' /" result))
8160 (error nil))))
8161 (unless (and (listp tmp) (stringp (car tmp))
8162 (string-match "^./.$" (car tmp))
8163 (integerp (cadr tmp)))
8164 (setq result nil)))
8165 result)))
fb7933a3 8166
293c24f9
MA
8167(defun tramp-get-remote-readlink (vec)
8168 (with-connection-property vec "readlink"
8169 (tramp-message vec 5 "Finding a suitable `readlink' command")
8170 (let ((result (tramp-find-executable
8171 vec "readlink" (tramp-get-remote-path vec))))
8172 (when (and result
8173 ;; We don't want to display an error message.
8174 (with-temp-message (or (current-message) "")
8175 (condition-case nil
8176 (zerop
8177 (tramp-send-command-and-check
8178 vec (format "%s --canonicalize-missing /" result)))
8179 (error nil))))
8180 result))))
8181
00d6fd04
MA
8182(defun tramp-get-remote-id (vec)
8183 (with-connection-property vec "id"
946a5aeb
MA
8184 (tramp-message vec 5 "Finding POSIX `id' command")
8185 (or
8186 (catch 'id-found
8187 (let ((dl (tramp-get-remote-path vec))
8188 result)
8189 (while (and dl (setq result (tramp-find-executable vec "id" dl t t)))
8190 ;; Check POSIX parameter.
8191 (when (zerop (tramp-send-command-and-check
8192 vec (format "%s -u" result)))
8193 (throw 'id-found result))
8194 (setq dl (cdr dl)))))
8195 (tramp-error vec 'file-error "Couldn't find a POSIX `id' command"))))
00d6fd04
MA
8196
8197(defun tramp-get-remote-uid (vec id-format)
8198 (with-connection-property vec (format "uid-%s" id-format)
8199 (let ((res (tramp-send-command-and-read
8200 vec
8201 (format "%s -u%s %s"
8202 (tramp-get-remote-id vec)
8203 (if (equal id-format 'integer) "" "n")
8204 (if (equal id-format 'integer)
8205 "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
8206 ;; The command might not always return a number.
8207 (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
8208
8209(defun tramp-get-remote-gid (vec id-format)
8210 (with-connection-property vec (format "gid-%s" id-format)
8211 (let ((res (tramp-send-command-and-read
8212 vec
8213 (format "%s -g%s %s"
8214 (tramp-get-remote-id vec)
8215 (if (equal id-format 'integer) "" "n")
8216 (if (equal id-format 'integer)
8217 "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
8218 ;; The command might not always return a number.
8219 (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
fb7933a3 8220
8d60099b
MA
8221(defun tramp-get-local-uid (id-format)
8222 (if (equal id-format 'integer) (user-uid) (user-login-name)))
8223
8224(defun tramp-get-local-gid (id-format)
9e6ab520 8225 (nth 3 (tramp-compat-file-attributes "~/" id-format)))
8d60099b 8226
00d6fd04
MA
8227;; Some predefined connection properties.
8228(defun tramp-get-remote-coding (vec prop)
8229 ;; Local coding handles properties like remote coding. So we could
8230 ;; call it without pain.
8231 (let ((ret (tramp-get-local-coding vec prop)))
8232 ;; The connection property might have been cached. So we must send
8233 ;; the script - maybe.
1d7e9a01 8234 (when (and ret (symbolp ret))
00d6fd04
MA
8235 (let ((name (symbol-name ret)))
8236 (while (string-match (regexp-quote "-") name)
8237 (setq name (replace-match "_" nil t name)))
8238 (tramp-maybe-send-script vec (symbol-value ret) name)
8239 (setq ret name)))
8240 ;; Return the value.
8241 ret))
8242
8243(defun tramp-get-local-coding (vec prop)
bf0503cb 8244 (or
00d6fd04
MA
8245 (tramp-get-connection-property vec prop nil)
8246 (progn
8247 (tramp-find-inline-encoding vec)
8248 (tramp-get-connection-property vec prop nil))))
fb7933a3 8249
00d6fd04 8250(defun tramp-get-method-parameter (method param)
c951aecb 8251 "Return the method parameter PARAM.
00d6fd04
MA
8252If the `tramp-methods' entry does not exist, return NIL."
8253 (let ((entry (assoc param (assoc method tramp-methods))))
8254 (when entry (cadr entry))))
90f8dc03 8255
fb7933a3
KG
8256;; Auto saving to a special directory.
8257
00cec167 8258(defun tramp-exists-file-name-handler (operation &rest args)
00d6fd04
MA
8259 "Checks whether OPERATION runs a file name handler."
8260 ;; The file name handler is determined on base of either an
8261 ;; argument, `buffer-file-name', or `default-directory'.
8262 (condition-case nil
8263 (let* ((buffer-file-name "/")
8264 (default-directory "/")
8265 (fnha file-name-handler-alist)
8266 (check-file-name-operation operation)
8267 (file-name-handler-alist
8268 (list
8269 (cons "/"
aa485f7c
MA
8270 (lambda (operation &rest args)
8271 "Returns OPERATION if it is the one to be checked."
8272 (if (equal check-file-name-operation operation)
8273 operation
8274 (let ((file-name-handler-alist fnha))
8275 (apply operation args))))))))
00d6fd04
MA
8276 (equal (apply operation args) operation))
8277 (error nil)))
c1105d05
MA
8278
8279(unless (tramp-exists-file-name-handler 'make-auto-save-file-name)
8280 (defadvice make-auto-save-file-name
8281 (around tramp-advice-make-auto-save-file-name () activate)
00d6fd04 8282 "Invoke `tramp-handle-make-auto-save-file-name' for Tramp files."
c1105d05 8283 (if (and (buffer-file-name) (tramp-tramp-file-p (buffer-file-name)))
7f49fe46
MA
8284 ;; We cannot call `tramp-handle-make-auto-save-file-name'
8285 ;; directly, because this would bypass the locking mechanism.
8286 (setq ad-return-value
8287 (tramp-file-name-handler 'make-auto-save-file-name))
a69c01a0 8288 ad-do-it))
191bb792
MA
8289 (add-hook
8290 'tramp-unload-hook
8291 (lambda ()
8292 (ad-remove-advice
8293 'make-auto-save-file-name
d7ec1df7
MA
8294 'around 'tramp-advice-make-auto-save-file-name)
8295 (ad-activate 'make-auto-save-file-name))))
fb7933a3 8296
340b8d4f
MA
8297;; In Emacs < 22 and XEmacs < 21.5 autosaved remote files have
8298;; permission 0666 minus umask. This is a security threat.
414da5ab
MA
8299
8300(defun tramp-set-auto-save-file-modes ()
8301 "Set permissions of autosaved remote files to the original permissions."
8302 (let ((bfn (buffer-file-name)))
8303 (when (and (stringp bfn)
8304 (tramp-tramp-file-p bfn)
b50dd0d2 8305 (buffer-modified-p)
414da5ab 8306 (stringp buffer-auto-save-file-name)
340b8d4f
MA
8307 (not (equal bfn buffer-auto-save-file-name)))
8308 (unless (file-exists-p buffer-auto-save-file-name)
8309 (write-region "" nil buffer-auto-save-file-name))
8310 ;; Permissions should be set always, because there might be an old
8311 ;; auto-saved file belonging to another original file. This could
8312 ;; be a security threat.
7177e2a3 8313 (set-file-modes buffer-auto-save-file-name
11948172 8314 (or (file-modes bfn) (tramp-octal-to-decimal "0600"))))))
414da5ab
MA
8315
8316(unless (or (> emacs-major-version 21)
8317 (and (featurep 'xemacs)
8318 (= emacs-major-version 21)
340b8d4f 8319 (> emacs-minor-version 4)))
a69c01a0
MA
8320 (add-hook 'auto-save-hook 'tramp-set-auto-save-file-modes)
8321 (add-hook 'tramp-unload-hook
aa485f7c
MA
8322 (lambda ()
8323 (remove-hook 'auto-save-hook 'tramp-set-auto-save-file-modes))))
414da5ab 8324
fb7933a3
KG
8325(defun tramp-subst-strs-in-string (alist string)
8326 "Replace all occurrences of the string FROM with TO in STRING.
8327ALIST is of the form ((FROM . TO) ...)."
8328 (save-match-data
8329 (while alist
8330 (let* ((pr (car alist))
8331 (from (car pr))
8332 (to (cdr pr)))
8333 (while (string-match (regexp-quote from) string)
8334 (setq string (replace-match to t t string)))
8335 (setq alist (cdr alist))))
8336 string))
8337
fb7933a3
KG
8338;; ------------------------------------------------------------
8339;; -- Compatibility functions section --
8340;; ------------------------------------------------------------
8341
00d6fd04 8342(defun tramp-read-passwd (proc &optional prompt)
fb7933a3 8343 "Read a password from user (compat function).
5615d63f 8344Consults the auth-source package.
5ec2cc41 8345Invokes `password-read' if available, `read-passwd' else."
00d6fd04
MA
8346 (let* ((key (tramp-make-tramp-file-name
8347 tramp-current-method tramp-current-user
8348 tramp-current-host ""))
8349 (pw-prompt
8350 (or prompt
8351 (with-current-buffer (process-buffer proc)
8352 (tramp-check-for-regexp proc tramp-password-prompt-regexp)
8353 (format "%s for %s " (capitalize (match-string 1)) key)))))
7540f029
MA
8354 (with-parsed-tramp-file-name key nil
8355 (prog1
8356 (or
8357 ;; See if auth-sources contains something useful, if it's bound.
8358 (and (boundp 'auth-sources)
8359 (tramp-get-connection-property v "first-password-request" nil)
8360 ;; Try with Tramp's current method.
8361 (funcall (symbol-function 'auth-source-user-or-password)
8362 "password" tramp-current-host tramp-current-method))
8363 ;; Try the password cache.
8364 (when (functionp 'password-read)
8365 (unless (tramp-get-connection-property
8366 v "first-password-request" nil)
8367 (funcall (symbol-function 'password-cache-remove) key))
8368 (let ((password
8369 (funcall (symbol-function 'password-read) pw-prompt key)))
8370 (funcall (symbol-function 'password-cache-add) key password)
8371 password))
8372 ;; Else, get the password interactively.
8373 (read-passwd pw-prompt))
8374 (tramp-set-connection-property v "first-password-request" nil)))))
00d6fd04 8375
9c13938d
MA
8376(defun tramp-clear-passwd (vec)
8377 "Clear password cache for connection related to VEC."
00d6fd04 8378 (when (functionp 'password-cache-remove)
9c13938d
MA
8379 (funcall
8380 (symbol-function 'password-cache-remove)
8381 (tramp-make-tramp-file-name
8382 (tramp-file-name-method vec)
8383 (tramp-file-name-user vec)
8384 (tramp-file-name-host vec)
8385 ""))))
00d6fd04
MA
8386
8387;; Snarfed code from time-date.el and parse-time.el
8388
8389(defconst tramp-half-a-year '(241 17024)
8390"Evaluated by \"(days-to-time 183)\".")
8391
8392(defconst tramp-parse-time-months
8393 '(("jan" . 1) ("feb" . 2) ("mar" . 3)
8394 ("apr" . 4) ("may" . 5) ("jun" . 6)
8395 ("jul" . 7) ("aug" . 8) ("sep" . 9)
8396 ("oct" . 10) ("nov" . 11) ("dec" . 12))
8397 "Alist mapping month names to integers.")
8398
8399(defun tramp-time-less-p (t1 t2)
8400 "Say whether time value T1 is less than time value T2."
8401 (unless t1 (setq t1 '(0 0)))
8402 (unless t2 (setq t2 '(0 0)))
8403 (or (< (car t1) (car t2))
8404 (and (= (car t1) (car t2))
8405 (< (nth 1 t1) (nth 1 t2)))))
8406
8407(defun tramp-time-subtract (t1 t2)
8408 "Subtract two time values.
8409Return the difference in the format of a time value."
8410 (unless t1 (setq t1 '(0 0)))
8411 (unless t2 (setq t2 '(0 0)))
8412 (let ((borrow (< (cadr t1) (cadr t2))))
8413 (list (- (car t1) (car t2) (if borrow 1 0))
8414 (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2)))))
fb7933a3
KG
8415
8416(defun tramp-time-diff (t1 t2)
8417 "Return the difference between the two times, in seconds.
1a762140 8418T1 and T2 are time values (as returned by `current-time' for example)."
fb7933a3 8419 ;; Pacify byte-compiler with `symbol-function'.
ea9d1443
KG
8420 (cond ((and (fboundp 'subtract-time)
8421 (fboundp 'float-time))
8422 (funcall (symbol-function 'float-time)
8423 (funcall (symbol-function 'subtract-time) t1 t2)))
8424 ((and (fboundp 'subtract-time)
8425 (fboundp 'time-to-seconds))
8426 (funcall (symbol-function 'time-to-seconds)
8427 (funcall (symbol-function 'subtract-time) t1 t2)))
fb7933a3 8428 ((fboundp 'itimer-time-difference)
1a762140
MA
8429 (funcall (symbol-function 'itimer-time-difference)
8430 (if (< (length t1) 3) (append t1 '(0)) t1)
8431 (if (< (length t2) 3) (append t2 '(0)) t2)))
fb7933a3 8432 (t
00d6fd04 8433 (let ((time (tramp-time-subtract t1 t2)))
ea9d1443
KG
8434 (+ (* (car time) 65536.0)
8435 (cadr time)
8436 (/ (or (nth 2 time) 0) 1000000.0))))))
fb7933a3
KG
8437
8438(defun tramp-coding-system-change-eol-conversion (coding-system eol-type)
8439 "Return a coding system like CODING-SYSTEM but with given EOL-TYPE.
8440EOL-TYPE can be one of `dos', `unix', or `mac'."
8441 (cond ((fboundp 'coding-system-change-eol-conversion)
9e6ab520
MA
8442 (funcall (symbol-function 'coding-system-change-eol-conversion)
8443 coding-system eol-type))
fb7933a3 8444 ((fboundp 'subsidiary-coding-system)
9e6ab520
MA
8445 (funcall (symbol-function 'subsidiary-coding-system)
8446 coding-system
8447 (cond ((eq eol-type 'dos) 'crlf)
8448 ((eq eol-type 'unix) 'lf)
8449 ((eq eol-type 'mac) 'cr)
8450 (t
8451 (error "Unknown EOL-TYPE `%s', must be %s"
8452 eol-type
8453 "`dos', `unix', or `mac'")))))
fb7933a3
KG
8454 (t (error "Can't change EOL conversion -- is MULE missing?"))))
8455
19a87064
MA
8456(defun tramp-set-process-query-on-exit-flag (process flag)
8457 "Specify if query is needed for process when Emacs is exited.
8458If the second argument flag is non-nil, Emacs will query the user before
8459exiting if process is running."
8460 (if (fboundp 'set-process-query-on-exit-flag)
00d6fd04
MA
8461 (funcall (symbol-function 'set-process-query-on-exit-flag) process flag)
8462 (funcall (symbol-function 'process-kill-without-query) process flag)))
19a87064 8463
19a87064 8464
bf247b6e
KS
8465;; ------------------------------------------------------------
8466;; -- Kludges section --
8467;; ------------------------------------------------------------
fb7933a3
KG
8468
8469;; Currently (as of Emacs 20.5), the function `shell-quote-argument'
8470;; does not deal well with newline characters. Newline is replaced by
8471;; backslash newline. But if, say, the string `a backslash newline b'
8472;; is passed to a shell, the shell will expand this into "ab",
8473;; completely omitting the newline. This is not what was intended.
8474;; It does not appear to be possible to make the function
8475;; `shell-quote-argument' work with newlines without making it
8476;; dependent on the shell used. But within this package, we know that
8477;; we will always use a Bourne-like shell, so we use an approach which
8478;; groks newlines.
8479;;
8480;; The approach is simple: we call `shell-quote-argument', then
8481;; massage the newline part of the result.
8482;;
8483;; This function should produce a string which is grokked by a Unix
8484;; shell, even if the Emacs is running on Windows. Since this is the
8485;; kludges section, we bind `system-type' in such a way that
8486;; `shell-quote-arguments' behaves as if on Unix.
8487;;
8488;; Thanks to Mario DeWeerd for the hint that it is sufficient for this
8489;; function to work with Bourne-like shells.
8490;;
8491;; CCC: This function should be rewritten so that
8492;; `shell-quote-argument' is not used. This way, we are safe from
8493;; changes in `shell-quote-argument'.
8494(defun tramp-shell-quote-argument (s)
8495 "Similar to `shell-quote-argument', but groks newlines.
8496Only works for Bourne-like shells."
8497 (let ((system-type 'not-windows))
8498 (save-match-data
8499 (let ((result (shell-quote-argument s))
8500 (nl (regexp-quote (format "\\%s" tramp-rsh-end-of-line))))
8501 (when (and (>= (length result) 2)
8502 (string= (substring result 0 2) "\\~"))
8503 (setq result (substring result 1)))
8504 (while (string-match nl result)
8505 (setq result (replace-match (format "'%s'" tramp-rsh-end-of-line)
8506 t t result)))
8507 result))))
8508
a69c01a0
MA
8509;; Checklist for `tramp-unload-hook'
8510;; - Unload all `tramp-*' packages
8511;; - Reset `file-name-handler-alist'
8512;; - Cleanup hooks where Tramp functions are in
8513;; - Cleanup advised functions
8514;; - Cleanup autoloads
8515;;;###autoload
8516(defun tramp-unload-tramp ()
08b1eb21 8517 "Discard Tramp from loading remote files."
a69c01a0
MA
8518 (interactive)
8519 ;; When Tramp is not loaded yet, its autoloads are still active.
8c04e197 8520 (tramp-unload-file-name-handlers)
a69c01a0
MA
8521 ;; ange-ftp settings must be enabled.
8522 (when (functionp 'tramp-ftp-enable-ange-ftp)
8523 (funcall (symbol-function 'tramp-ftp-enable-ange-ftp)))
00d6fd04
MA
8524 ;; Maybe its not loaded yet.
8525 (condition-case nil
8526 (unload-feature 'tramp 'force)
a69c01a0
MA
8527 (error nil)))
8528
dea31ca6
MA
8529(when (and load-in-progress
8530 (string-match "Loading tramp..." (or (current-message) "")))
ccb4a481
MA
8531 (message "Loading tramp...done"))
8532
fb7933a3
KG
8533(provide 'tramp)
8534
fb7933a3
KG
8535;;; TODO:
8536
4007ba5b 8537;; * Handle nonlocal exits such as C-g.
00d6fd04
MA
8538;; * But it would probably be better to use with-local-quit at the
8539;; place where it's actually needed: around any potentially
8540;; indefinitely blocking piece of code. In this case it would be
8541;; within Tramp around one of its calls to accept-process-output (or
8542;; around one of the loops that calls accept-process-output)
d037d501 8543;; (Stefan Monnier).
fb7933a3 8544;; * Rewrite `tramp-shell-quote-argument' to abstain from using
b1d06e75 8545;; `shell-quote-argument'.
fb7933a3
KG
8546;; * In Emacs 21, `insert-directory' shows total number of bytes used
8547;; by the files in that directory. Add this here.
8548;; * Avoid screen blanking when hitting `g' in dired. (Eli Tziperman)
8549;; * Make ffap.el grok Tramp filenames. (Eli Tziperman)
fb7933a3 8550;; * Case-insensitive filename completion. (Norbert Goevert.)
fb7933a3
KG
8551;; * Don't use globbing for directories with many files, as this is
8552;; likely to produce long command lines, and some shells choke on
8553;; long command lines.
fb7933a3 8554;; * How to deal with MULE in `insert-file-contents' and `write-region'?
fb7933a3
KG
8555;; * Test remote ksh or bash for tilde expansion in `tramp-find-shell'?
8556;; * abbreviate-file-name
8e754ea2 8557;; * Better error checking. At least whenever we see something
fb7933a3
KG
8558;; strange when doing zerop, we should kill the process and start
8559;; again. (Greg Stark)
fb7933a3 8560;; * Remove unneeded parameters from methods.
fb7933a3
KG
8561;; * Make it work for different encodings, and for different file name
8562;; encodings, too. (Daniel Pittman)
fb7933a3 8563;; * Progress reports while copying files. (Michael Kifer)
fb7933a3
KG
8564;; * Don't search for perl5 and perl. Instead, only search for perl and
8565;; then look if it's the right version (with `perl -v').
8566;; * When editing a remote CVS controlled file as a different user, VC
8567;; gets confused about the file locking status. Try to find out why
8568;; the workaround doesn't work.
3cdaec13 8569;; * Username and hostname completion.
6c4e47fa 8570;; ** Try to avoid usage of `last-input-event' in `tramp-completion-mode-p'.
8daea7fc 8571;; ** Unify `tramp-parse-{rhosts,shosts,sconfig,hosts,passwd,netrc}'.
16674e4f 8572;; Code is nearly identical.
cfb5c0db
MA
8573;; * Allow out-of-band methods as _last_ multi-hop. Open a connection
8574;; until the last but one hop via `start-file-process'. Apply it
8575;; also for ftp and smb.
00d6fd04
MA
8576;; * WIBNI if we had a command "trampclient"? If I was editing in
8577;; some shell with root priviledges, it would be nice if I could
8578;; just call
8579;; trampclient filename.c
8580;; as an editor, and the _current_ shell would connect to an Emacs
8581;; server and would be used in an existing non-priviledged Emacs
8582;; session for doing the editing in question.
8583;; That way, I need not tell Emacs my password again and be afraid
8584;; that it makes it into core dumps or other ugly stuff (I had Emacs
8585;; once display a just typed password in the context of a keyboard
8586;; sequence prompt for a question immediately following in a shell
8587;; script run within Emacs -- nasty).
8588;; And if I have some ssh session running to a different computer,
8589;; having the possibility of passing a local file there to a local
8590;; Emacs session (in case I can arrange for a connection back) would
8591;; be nice.
a4aeb9a4 8592;; Likely the corresponding Tramp server should not allow the
00d6fd04
MA
8593;; equivalent of the emacsclient -eval option in order to make this
8594;; reasonably unproblematic. And maybe trampclient should have some
8595;; way of passing credentials, like by using an SSL socket or
6e4f5731 8596;; something. (David Kastrup)
00d6fd04 8597;; * Reconnect directly to a compliant shell without first going
6e4f5731 8598;; through the user's default shell. (Pete Forman)
00d6fd04 8599;; * Make `tramp-default-user' obsolete.
11c71217 8600;; * How can I interrupt the remote process with a signal
6e4f5731 8601;; (interrupt-process seems not to work)? (Markus Triska)
2296b54d
MA
8602;; * Avoid the local shell entirely for starting remote processes. If
8603;; so, I think even a signal, when delivered directly to the local
8604;; SSH instance, would correctly be propagated to the remote process
8605;; automatically; possibly SSH would have to be started with
6e4f5731 8606;; "-t". (Markus Triska)
dea31ca6 8607;; * It makes me wonder if tramp couldn't fall back to ssh when scp
6e4f5731
MA
8608;; isn't on the remote host. (Mark A. Hershberger)
8609;; * Use lsh instead of ssh. (Alfred M. Szmidt)
3e2fa353
MA
8610;; * Implement a general server-local-variable mechanism, as there are
8611;; probably other variables that need different values for different
8612;; servers too. The user could then configure a variable (such as
8613;; tramp-server-local-variable-alist) to define any such variables
8614;; that they need to, which would then be let bound as appropriate
6e4f5731 8615;; in tramp functions. (Jason Rumney)
946a5aeb
MA
8616;; * Optimize out-of-band copying, when both methods are scp-like (not
8617;; rsync).
8618;; * Keep a second connection open for out-of-band methods like scp or
8619;; rsync.
7540f029 8620;; * Support ptys in `tramp-handle-start-file-process'. (Bug#4604)
7e5686f0
MA
8621;; * IMHO, it's a drawback that currently Tramp doesn't support
8622;; Unicode in Dired file names by default. Is it possible to
8623;; improve Tramp to set LC_ALL to "C" only for commands where Tramp
8624;; expects English? Or just to set LC_MESSAGES to "C" if Tramp
6e4f5731 8625;; expects only English messages? (Juri Linkov)
7e5686f0
MA
8626;; * Make shadowfile.el grok Tramp filenames. (Bug#4526, Bug#4846)
8627;; * Do not handle files with drive letter as remote. (Bug#5447)
8628;; * Load Tramp subpackages only when needed. (Bug#1529, Bug#5448)
8629;; * Try telnet+curl as new method. It might be useful for busybox,
8630;; without built-in uuencode/uudecode.
7540f029
MA
8631;; * Let `shell-dynamic-complete-*' and `comint-dynamic-complete' work
8632;; on remote hosts.
8633;; * Use secrets.el for password handling.
fb7933a3
KG
8634
8635;; Functions for file-name-handler-alist:
8636;; diff-latest-backup-file -- in diff.el
fb7933a3 8637
cdd44874 8638;; arch-tag: 3a21a994-182b-48fa-b0cd-c1d9fede424a
fb7933a3 8639;;; tramp.el ends here
57671b72
MA
8640
8641;; Local Variables:
8642;; mode: Emacs-Lisp
8643;; coding: utf-8
8644;; End: