* mh-acros.el: Comment fixes.
[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
bf247b6e 179 :version "22.1")
fb7933a3 180
2e271195
MA
181;; Maybe we need once a real Tramp mode, with key bindings etc.
182;;;###autoload
183(defcustom tramp-mode t
184 "*Whether Tramp is enabled.
185If it is set to nil, all remote file names are used literally."
186 :group 'tramp
187 :type 'boolean)
188
00d6fd04 189(defcustom tramp-verbose 3
263c02ef 190 "*Verbosity level for Tramp messages.
00d6fd04
MA
191Any level x includes messages for all levels 1 .. x-1. The levels are
192
193 0 silent (no tramp messages at all)
194 1 errors
195 2 warnings
196 3 connection to remote hosts (default level)
197 4 activities
198 5 internal
199 6 sent and received strings
200 7 file caching
201 8 connection properties
20210 traces (huge)."
fb7933a3
KG
203 :group 'tramp
204 :type 'integer)
205
263c02ef 206;; Emacs case.
38c65fca
KG
207(eval-and-compile
208 (when (boundp 'backup-directory-alist)
209 (defcustom tramp-backup-directory-alist nil
210 "Alist of filename patterns and backup directory names.
211Each element looks like (REGEXP . DIRECTORY), with the same meaning like
212in `backup-directory-alist'. If a Tramp file is backed up, and DIRECTORY
213is a local file name, the backup directory is prepended with Tramp file
00d6fd04 214name prefix \(method, user, host\) of file.
38c65fca
KG
215
216\(setq tramp-backup-directory-alist backup-directory-alist\)
217
218gives the same backup policy for Tramp files on their hosts like the
219policy for local files."
220 :group 'tramp
221 :type '(repeat (cons (regexp :tag "Regexp matching filename")
222 (directory :tag "Backup directory name"))))))
223
224;; XEmacs case. We cannot check for `bkup-backup-directory-info', because
225;; the package "backup-dir" might not be loaded yet.
226(eval-and-compile
227 (when (featurep 'xemacs)
228 (defcustom tramp-bkup-backup-directory-info nil
229 "*Alist of (FILE-REGEXP BACKUP-DIR OPTIONS ...))
230It has the same meaning like `bkup-backup-directory-info' from package
231`backup-dir'. If a Tramp file is backed up, and BACKUP-DIR is a local
232file name, the backup directory is prepended with Tramp file name prefix
00d6fd04 233\(method, user, host\) of file.
38c65fca
KG
234
235\(setq tramp-bkup-backup-directory-info bkup-backup-directory-info\)
236
237gives the same backup policy for Tramp files on their hosts like the
238policy for local files."
bf247b6e 239 :type '(repeat
38c65fca
KG
240 (list (regexp :tag "File regexp")
241 (string :tag "Backup Dir")
242 (set :inline t
243 (const ok-create)
244 (const full-path)
245 (const prepend-name)
246 (const search-upward))))
247 :group 'tramp)))
248
fb7933a3
KG
249(defcustom tramp-auto-save-directory nil
250 "*Put auto-save files in this directory, if set.
251The idea is to use a local directory so that auto-saving is faster."
252 :group 'tramp
00d6fd04 253 :type '(choice (const nil) string))
fb7933a3 254
16674e4f
KG
255(defcustom tramp-encoding-shell
256 (if (memq system-type '(windows-nt))
257 (getenv "COMSPEC")
258 "/bin/sh")
259 "*Use this program for encoding and decoding commands on the local host.
260This shell is used to execute the encoding and decoding command on the
261local host, so if you want to use `~' in those commands, you should
262choose a shell here which groks tilde expansion. `/bin/sh' normally
263does not understand tilde expansion.
264
265For encoding and deocding, commands like the following are executed:
266
267 /bin/sh -c COMMAND < INPUT > OUTPUT
268
269This variable can be used to change the \"/bin/sh\" part. See the
00d6fd04 270variable `tramp-encoding-command-switch' for the \"-c\" part.
fb7933a3
KG
271
272Note that this variable is not used for remote commands. There are
273mechanisms in tramp.el which automatically determine the right shell to
274use for the remote host."
275 :group 'tramp
276 :type '(file :must-match t))
277
16674e4f
KG
278(defcustom tramp-encoding-command-switch
279 (if (string-match "cmd\\.exe" tramp-encoding-shell)
280 "/c"
281 "-c")
282 "*Use this switch together with `tramp-encoding-shell' for local commands.
283See the variable `tramp-encoding-shell' for more information."
284 :group 'tramp
285 :type 'string)
286
00d6fd04
MA
287(defcustom tramp-copy-size-limit 10240
288 "*The maximum file size where inline copying is preferred over an out-of-the-band copy."
16674e4f 289 :group 'tramp
00d6fd04 290 :type 'integer)
90dc758d 291
00d6fd04
MA
292(defcustom tramp-terminal-type "dumb"
293 "*Value of TERM environment variable for logging in to remote host.
294Because Tramp wants to parse the output of the remote shell, it is easily
295confused by ANSI color escape sequences and suchlike. Often, shell init
296files conditionalize this setup based on the TERM environment variable."
90dc758d 297 :group 'tramp
00d6fd04 298 :type 'string)
90dc758d 299
dab816a9
MA
300;; ksh on OpenBSD 4.5 requires, that PS1 contains a `#' character for
301;; root users. It uses the `$' character for other users. In order
302;; to guarantee a proper prompt, we use "#$" for the prompt.
303
304(defvar tramp-end-of-output
305 (format
306 "///%s#$"
307 (md5 (concat (prin1-to-string process-environment) (current-time-string))))
308 "String used to recognize end of output.
309The '$' character at the end is quoted; the string cannot be
310detected as prompt when being sent on echoing hosts, therefore.")
311
312(defconst tramp-initial-end-of-output "#$ "
313 "Prompt when establishing a connection.")
314
00d6fd04
MA
315(defvar tramp-methods
316 `(("rcp" (tramp-login-program "rsh")
317 (tramp-login-args (("%h") ("-l" "%u")))
318 (tramp-remote-sh "/bin/sh")
319 (tramp-copy-program "rcp")
263c02ef 320 (tramp-copy-args (("-p" "%k") ("-r")))
00d6fd04 321 (tramp-copy-keep-date t)
263c02ef 322 (tramp-copy-recursive t)
00d6fd04
MA
323 (tramp-password-end-of-line nil))
324 ("scp" (tramp-login-program "ssh")
2296b54d 325 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
326 ("-e" "none")))
327 (tramp-remote-sh "/bin/sh")
328 (tramp-copy-program "scp")
263c02ef
MA
329 (tramp-copy-args (("-P" "%p") ("-p" "%k")
330 ("-q") ("-r")))
00d6fd04 331 (tramp-copy-keep-date t)
263c02ef 332 (tramp-copy-recursive t)
00d6fd04
MA
333 (tramp-password-end-of-line nil)
334 (tramp-gw-args (("-o"
335 "GlobalKnownHostsFile=/dev/null")
336 ("-o" "UserKnownHostsFile=/dev/null")
337 ("-o" "StrictHostKeyChecking=no")))
338 (tramp-default-port 22))
339 ("scp1" (tramp-login-program "ssh")
2296b54d 340 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
341 ("-1" "-e" "none")))
342 (tramp-remote-sh "/bin/sh")
343 (tramp-copy-program "scp")
344 (tramp-copy-args (("-1") ("-P" "%p") ("-p" "%k")
263c02ef 345 ("-q") ("-r")))
00d6fd04 346 (tramp-copy-keep-date t)
263c02ef 347 (tramp-copy-recursive t)
00d6fd04
MA
348 (tramp-password-end-of-line nil)
349 (tramp-gw-args (("-o"
350 "GlobalKnownHostsFile=/dev/null")
351 ("-o" "UserKnownHostsFile=/dev/null")
352 ("-o" "StrictHostKeyChecking=no")))
353 (tramp-default-port 22))
354 ("scp2" (tramp-login-program "ssh")
2296b54d 355 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
356 ("-2" "-e" "none")))
357 (tramp-remote-sh "/bin/sh")
358 (tramp-copy-program "scp")
359 (tramp-copy-args (("-2") ("-P" "%p") ("-p" "%k")
263c02ef 360 ("-q") ("-r")))
00d6fd04 361 (tramp-copy-keep-date t)
263c02ef 362 (tramp-copy-recursive t)
00d6fd04
MA
363 (tramp-password-end-of-line nil)
364 (tramp-gw-args (("-o"
365 "GlobalKnownHostsFile=/dev/null")
366 ("-o" "UserKnownHostsFile=/dev/null")
367 ("-o" "StrictHostKeyChecking=no")))
368 (tramp-default-port 22))
369 ("scp1_old"
370 (tramp-login-program "ssh1")
371 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
372 ("-e" "none")))
373 (tramp-remote-sh "/bin/sh")
374 (tramp-copy-program "scp1")
263c02ef 375 (tramp-copy-args (("-p" "%k") ("-r")))
00d6fd04 376 (tramp-copy-keep-date t)
263c02ef 377 (tramp-copy-recursive t)
00d6fd04
MA
378 (tramp-password-end-of-line nil))
379 ("scp2_old"
380 (tramp-login-program "ssh2")
381 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
382 ("-e" "none")))
383 (tramp-remote-sh "/bin/sh")
384 (tramp-copy-program "scp2")
263c02ef 385 (tramp-copy-args (("-p" "%k") ("-r")))
00d6fd04 386 (tramp-copy-keep-date t)
263c02ef 387 (tramp-copy-recursive t)
00d6fd04
MA
388 (tramp-password-end-of-line nil))
389 ("sftp" (tramp-login-program "ssh")
390 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
391 ("-e" "none")))
392 (tramp-remote-sh "/bin/sh")
393 (tramp-copy-program "sftp")
394 (tramp-copy-args nil)
395 (tramp-copy-keep-date nil)
396 (tramp-password-end-of-line nil))
397 ("rsync" (tramp-login-program "ssh")
398 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
399 ("-e" "none")))
400 (tramp-remote-sh "/bin/sh")
401 (tramp-copy-program "rsync")
263c02ef 402 (tramp-copy-args (("-e" "ssh") ("-t" "%k") ("-r")))
00d6fd04 403 (tramp-copy-keep-date t)
b88f2d0a 404 (tramp-copy-keep-tmpfile t)
263c02ef 405 (tramp-copy-recursive t)
00d6fd04 406 (tramp-password-end-of-line nil))
263c02ef
MA
407 ("rsyncc"
408 (tramp-login-program "ssh")
946a5aeb
MA
409 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
410 ("-o" "ControlPath=%t.%%r@%%h:%%p")
411 ("-o" "ControlMaster=yes")
412 ("-e" "none")))
413 (tramp-remote-sh "/bin/sh")
414 (tramp-copy-program "rsync")
263c02ef 415 (tramp-copy-args (("-t" "%k") ("-r")))
946a5aeb
MA
416 (tramp-copy-env (("RSYNC_RSH")
417 (,(concat
418 "ssh"
419 " -o ControlPath=%t.%%r@%%h:%%p"
420 " -o ControlMaster=auto"))))
421 (tramp-copy-keep-date t)
b88f2d0a 422 (tramp-copy-keep-tmpfile t)
263c02ef 423 (tramp-copy-recursive t)
946a5aeb 424 (tramp-password-end-of-line nil))
00d6fd04
MA
425 ("remcp" (tramp-login-program "remsh")
426 (tramp-login-args (("%h") ("-l" "%u")))
427 (tramp-remote-sh "/bin/sh")
428 (tramp-copy-program "rcp")
429 (tramp-copy-args (("-p" "%k")))
430 (tramp-copy-keep-date t)
431 (tramp-password-end-of-line nil))
432 ("rsh" (tramp-login-program "rsh")
433 (tramp-login-args (("%h") ("-l" "%u")))
434 (tramp-remote-sh "/bin/sh")
435 (tramp-copy-program nil)
436 (tramp-copy-args nil)
437 (tramp-copy-keep-date nil)
438 (tramp-password-end-of-line nil))
439 ("ssh" (tramp-login-program "ssh")
2296b54d 440 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
441 ("-e" "none")))
442 (tramp-remote-sh "/bin/sh")
443 (tramp-copy-program nil)
444 (tramp-copy-args nil)
445 (tramp-copy-keep-date nil)
446 (tramp-password-end-of-line nil)
447 (tramp-gw-args (("-o"
448 "GlobalKnownHostsFile=/dev/null")
449 ("-o" "UserKnownHostsFile=/dev/null")
450 ("-o" "StrictHostKeyChecking=no")))
451 (tramp-default-port 22))
452 ("ssh1" (tramp-login-program "ssh")
2296b54d 453 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
454 ("-1" "-e" "none")))
455 (tramp-remote-sh "/bin/sh")
456 (tramp-copy-program nil)
457 (tramp-copy-args nil)
458 (tramp-copy-keep-date nil)
459 (tramp-password-end-of-line nil)
460 (tramp-gw-args (("-o"
461 "GlobalKnownHostsFile=/dev/null")
462 ("-o" "UserKnownHostsFile=/dev/null")
463 ("-o" "StrictHostKeyChecking=no")))
464 (tramp-default-port 22))
465 ("ssh2" (tramp-login-program "ssh")
2296b54d 466 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
467 ("-2" "-e" "none")))
468 (tramp-remote-sh "/bin/sh")
469 (tramp-copy-program nil)
470 (tramp-copy-args nil)
471 (tramp-copy-keep-date nil)
472 (tramp-password-end-of-line nil)
473 (tramp-gw-args (("-o"
474 "GlobalKnownHostsFile=/dev/null")
475 ("-o" "UserKnownHostsFile=/dev/null")
476 ("-o" "StrictHostKeyChecking=no")))
477 (tramp-default-port 22))
478 ("ssh1_old"
479 (tramp-login-program "ssh1")
480 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
481 ("-e" "none")))
482 (tramp-remote-sh "/bin/sh")
483 (tramp-copy-program nil)
484 (tramp-copy-args nil)
485 (tramp-copy-keep-date nil)
486 (tramp-password-end-of-line nil))
487 ("ssh2_old"
488 (tramp-login-program "ssh2")
489 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
490 ("-e" "none")))
491 (tramp-remote-sh "/bin/sh")
492 (tramp-copy-program nil)
493 (tramp-copy-args nil)
494 (tramp-copy-keep-date nil)
495 (tramp-password-end-of-line nil))
496 ("remsh" (tramp-login-program "remsh")
497 (tramp-login-args (("%h") ("-l" "%u")))
498 (tramp-remote-sh "/bin/sh")
499 (tramp-copy-program nil)
500 (tramp-copy-args nil)
501 (tramp-copy-keep-date nil)
502 (tramp-password-end-of-line nil))
503 ("telnet"
504 (tramp-login-program "telnet")
505 (tramp-login-args (("%h") ("%p")))
506 (tramp-remote-sh "/bin/sh")
507 (tramp-copy-program nil)
508 (tramp-copy-args nil)
509 (tramp-copy-keep-date nil)
510 (tramp-password-end-of-line nil)
511 (tramp-default-port 23))
512 ("su" (tramp-login-program "su")
513 (tramp-login-args (("-") ("%u")))
514 (tramp-remote-sh "/bin/sh")
515 (tramp-copy-program nil)
516 (tramp-copy-args nil)
517 (tramp-copy-keep-date nil)
518 (tramp-password-end-of-line nil))
519 ("sudo" (tramp-login-program "sudo")
520 (tramp-login-args (("-u" "%u")
42bc9b6d 521 ("-s") ("-H") ("-p" "Password:")))
00d6fd04
MA
522 (tramp-remote-sh "/bin/sh")
523 (tramp-copy-program nil)
524 (tramp-copy-args nil)
525 (tramp-copy-keep-date nil)
526 (tramp-password-end-of-line nil))
527 ("scpc" (tramp-login-program "ssh")
2296b54d 528 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
529 ("-o" "ControlPath=%t.%%r@%%h:%%p")
530 ("-o" "ControlMaster=yes")
531 ("-e" "none")))
532 (tramp-remote-sh "/bin/sh")
533 (tramp-copy-program "scp")
534 (tramp-copy-args (("-P" "%p") ("-p" "%k") ("-q")
535 ("-o" "ControlPath=%t.%%r@%%h:%%p")
536 ("-o" "ControlMaster=auto")))
537 (tramp-copy-keep-date t)
538 (tramp-password-end-of-line nil)
539 (tramp-gw-args (("-o"
540 "GlobalKnownHostsFile=/dev/null")
541 ("-o" "UserKnownHostsFile=/dev/null")
542 ("-o" "StrictHostKeyChecking=no")))
543 (tramp-default-port 22))
544 ("scpx" (tramp-login-program "ssh")
2296b54d 545 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
546 ("-e" "none" "-t" "-t" "/bin/sh")))
547 (tramp-remote-sh "/bin/sh")
548 (tramp-copy-program "scp")
549 (tramp-copy-args (("-p" "%k")))
550 (tramp-copy-keep-date t)
551 (tramp-password-end-of-line nil)
552 (tramp-gw-args (("-o"
553 "GlobalKnownHostsFile=/dev/null")
554 ("-o" "UserKnownHostsFile=/dev/null")
555 ("-o" "StrictHostKeyChecking=no")))
556 (tramp-default-port 22))
557 ("sshx" (tramp-login-program "ssh")
2296b54d 558 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") ("-q")
00d6fd04
MA
559 ("-e" "none" "-t" "-t" "/bin/sh")))
560 (tramp-remote-sh "/bin/sh")
561 (tramp-copy-program nil)
562 (tramp-copy-args nil)
563 (tramp-copy-keep-date nil)
564 (tramp-password-end-of-line nil)
565 (tramp-gw-args (("-o"
566 "GlobalKnownHostsFile=/dev/null")
567 ("-o" "UserKnownHostsFile=/dev/null")
568 ("-o" "StrictHostKeyChecking=no")))
569 (tramp-default-port 22))
570 ("krlogin"
571 (tramp-login-program "krlogin")
572 (tramp-login-args (("%h") ("-l" "%u") ("-x")))
573 (tramp-remote-sh "/bin/sh")
574 (tramp-copy-program nil)
575 (tramp-copy-args nil)
576 (tramp-copy-keep-date nil)
577 (tramp-password-end-of-line nil))
578 ("plink" (tramp-login-program "plink")
579 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
580 ("-ssh")))
581 (tramp-remote-sh "/bin/sh")
582 (tramp-copy-program nil)
583 (tramp-copy-args nil)
584 (tramp-copy-keep-date nil)
585 (tramp-password-end-of-line "xy") ;see docstring for "xy"
586 (tramp-default-port 22))
587 ("plink1"
588 (tramp-login-program "plink")
589 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
590 ("-1" "-ssh")))
591 (tramp-remote-sh "/bin/sh")
592 (tramp-copy-program nil)
593 (tramp-copy-args nil)
594 (tramp-copy-keep-date nil)
595 (tramp-password-end-of-line "xy") ;see docstring for "xy"
596 (tramp-default-port 22))
597 ("plinkx"
598 (tramp-login-program "plink")
42bc9b6d
MA
599 ;; ("%h") must be a single element, see
600 ;; `tramp-compute-multi-hops'.
601 (tramp-login-args (("-load") ("%h") ("-t")
ce3f516f 602 (,(format
dab816a9
MA
603 "env 'TERM=%s' 'PROMPT_COMMAND=' 'PS1=%s'"
604 tramp-terminal-type
605 tramp-initial-end-of-output))
00d6fd04
MA
606 ("/bin/sh")))
607 (tramp-remote-sh "/bin/sh")
608 (tramp-copy-program nil)
609 (tramp-copy-args nil)
610 (tramp-copy-keep-date nil)
611 (tramp-password-end-of-line nil))
612 ("pscp" (tramp-login-program "plink")
613 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
614 ("-ssh")))
615 (tramp-remote-sh "/bin/sh")
616 (tramp-copy-program "pscp")
60f2c210 617 (tramp-copy-args (("-P" "%p") ("-scp") ("-p" "%k")))
00d6fd04
MA
618 (tramp-copy-keep-date t)
619 (tramp-password-end-of-line "xy") ;see docstring for "xy"
620 (tramp-default-port 22))
621 ("psftp" (tramp-login-program "plink")
622 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
623 ("-ssh")))
624 (tramp-remote-sh "/bin/sh")
625 (tramp-copy-program "pscp")
60f2c210 626 (tramp-copy-args (("-P" "%p") ("-sftp") ("-p" "%k")))
00d6fd04
MA
627 (tramp-copy-keep-date t)
628 (tramp-password-end-of-line "xy")) ;see docstring for "xy"
629 ("fcp" (tramp-login-program "fsh")
630 (tramp-login-args (("%h") ("-l" "%u") ("sh" "-i")))
631 (tramp-remote-sh "/bin/sh -i")
632 (tramp-copy-program "fcp")
633 (tramp-copy-args (("-p" "%k")))
634 (tramp-copy-keep-date t)
635 (tramp-password-end-of-line nil)))
fb7933a3
KG
636 "*Alist of methods for remote files.
637This is a list of entries of the form (NAME PARAM1 PARAM2 ...).
638Each NAME stands for a remote access method. Each PARAM is a
639pair of the form (KEY VALUE). The following KEYs are defined:
fb7933a3
KG
640 * `tramp-remote-sh'
641 This specifies the Bourne shell to use on the remote host. This
642 MUST be a Bourne-like shell. It is normally not necessary to set
a4aeb9a4 643 this to any value other than \"/bin/sh\": Tramp wants to use a shell
fb7933a3
KG
644 which groks tilde expansion, but it can search for it. Also note
645 that \"/bin/sh\" exists on all Unixen, this might not be true for
646 the value that you decide to use. You Have Been Warned.
b25a52cc
KG
647 * `tramp-login-program'
648 This specifies the name of the program to use for logging in to the
00d6fd04
MA
649 remote host. This may be the name of rsh or a workalike program,
650 or the name of telnet or a workalike, or the name of su or a workalike.
b25a52cc 651 * `tramp-login-args'
fb7933a3 652 This specifies the list of arguments to pass to the above
00d6fd04 653 mentioned program. Please note that this is a list of list of arguments,
fb7933a3 654 that is, normally you don't want to put \"-a -b\" or \"-f foo\"
00d6fd04
MA
655 here. Instead, you want a list (\"-a\" \"-b\"), or (\"-f\" \"foo\").
656 There are some patterns: \"%h\" in this list is replaced by the host
657 name, \"%u\" is replaced by the user name, \"%p\" is replaced by the
658 port number, and \"%%\" can be used to obtain a literal percent character.
659 If a list containing \"%h\", \"%u\" or \"%p\" is unchanged during
660 expansion (i.e. no host or no user specified), this list is not used as
661 argument. By this, arguments like (\"-l\" \"%u\") are optional.
662 \"%t\" is replaced by the temporary file name produced with
663 `tramp-make-tramp-temp-file'. \"%k\" indicates the keep-date
664 parameter of a program, if exists.
b25a52cc
KG
665 * `tramp-copy-program'
666 This specifies the name of the program to use for remotely copying
667 the file; this might be the absolute filename of rcp or the name of
668 a workalike program.
669 * `tramp-copy-args'
fb7933a3 670 This specifies the list of parameters to pass to the above mentioned
b25a52cc 671 program, the hints for `tramp-login-args' also apply here.
00d6fd04
MA
672 * `tramp-copy-keep-date'
673 This specifies whether the copying program when the preserves the
674 timestamp of the original file.
b88f2d0a
MA
675 * `tramp-copy-keep-tmpfile'
676 This specifies whether a temporary local file shall be kept
677 for optimization reasons (useful for \"rsync\" methods).
678 * `tramp-copy-recursive'
679 Whether the operation copies directories recursively.
00d6fd04
MA
680 * `tramp-default-port'
681 The default port of a method is needed in case of gateway connections.
682 Additionally, it is used as indication which method is prepared for
683 passing gateways.
684 * `tramp-gw-args'
685 As the attribute name says, additional arguments are specified here
686 when a method is applied via a gateway.
90f8dc03
KG
687 * `tramp-password-end-of-line'
688 This specifies the string to use for terminating the line after
689 submitting the password. If this method parameter is nil, then the
690 value of the normal variable `tramp-default-password-end-of-line'
691 is used. This parameter is necessary because the \"plink\" program
692 requires any two characters after sending the password. These do
693 not have to be newline or carriage return characters. Other login
694 programs are happy with just one character, the newline character.
695 We use \"xy\" as the value for methods using \"plink\".
b25a52cc
KG
696
697What does all this mean? Well, you should specify `tramp-login-program'
698for all methods; this program is used to log in to the remote site. Then,
699there are two ways to actually transfer the files between the local and the
700remote side. One way is using an additional rcp-like program. If you want
701to do this, set `tramp-copy-program' in the method.
fb7933a3
KG
702
703Another possibility for file transfer is inline transfer, i.e. the
b25a52cc 704file is passed through the same buffer used by `tramp-login-program'. In
fb7933a3 705this case, the file contents need to be protected since the
b25a52cc 706`tramp-login-program' might use escape codes or the connection might not
fb7933a3 707be eight-bit clean. Therefore, file contents are encoded for transit.
00d6fd04
MA
708See the variables `tramp-local-coding-commands' and
709`tramp-remote-coding-commands' for details.
fb7933a3 710
16674e4f 711So, to summarize: if the method is an out-of-band method, then you
b25a52cc 712must specify `tramp-copy-program' and `tramp-copy-args'. If it is an
00d6fd04
MA
713inline method, then these two parameters should be nil. Methods which
714are fit for gateways must have `tramp-default-port' at least.
fb7933a3
KG
715
716Notes:
717
00d6fd04
MA
718When using `su' or `sudo' the phrase `open connection to a remote
719host' sounds strange, but it is used nevertheless, for consistency.
720No connection is opened to a remote host, but `su' or `sudo' is
721started on the local host. You should specify a remote host
722`localhost' or the name of the local host. Another host name is
723useful only in combination with `tramp-default-proxies-alist'.")
fb7933a3 724
b25a52cc 725(defcustom tramp-default-method
83e20b5c
MA
726 ;; An external copy method seems to be preferred, because it is much
727 ;; more performant for large files, and it hasn't too serious delays
728 ;; for small files. But it must be ensured that there aren't
729 ;; permanent password queries. Either a password agent like
263c02ef
MA
730 ;; "ssh-agent" or "Pageant" shall run, or the optional
731 ;; password-cache.el or auth-sources.el packages shall be active for
732 ;; password caching. "scpc" would be another good choice because of
733 ;; the "ControlMaster" option, but this is a more modern alternative
734 ;; in OpenSSH 4, which cannot be taken as default.
00d6fd04
MA
735 (cond
736 ;; PuTTY is installed.
737 ((executable-find "pscp")
738 (if (or (fboundp 'password-read)
263c02ef 739 (fboundp 'auth-source-user-or-password)
00d6fd04 740 ;; Pageant is running.
70c11b0b 741 (tramp-compat-process-running-p "Pageant"))
00d6fd04
MA
742 "pscp"
743 "plink"))
744 ;; There is an ssh installation.
745 ((executable-find "scp")
746 (if (or (fboundp 'password-read)
263c02ef 747 (fboundp 'auth-source-user-or-password)
00d6fd04
MA
748 ;; ssh-agent is running.
749 (getenv "SSH_AUTH_SOCK")
750 (getenv "SSH_AGENT_PID"))
751 "scp"
752 "ssh"))
753 ;; Fallback.
754 (t "ftp"))
fb7933a3 755 "*Default method to use for transferring files.
c62c9d08 756See `tramp-methods' for possibilities.
4007ba5b 757Also see `tramp-default-method-alist'."
c62c9d08
KG
758 :group 'tramp
759 :type 'string)
760
505edaeb 761(defcustom tramp-default-method-alist
4007ba5b 762 '(("\\`localhost\\'" "\\`root\\'" "su"))
00d6fd04 763 "*Default method to use for specific host/user pairs.
c62c9d08
KG
764This is an alist of items (HOST USER METHOD). The first matching item
765specifies the method to use for a file name which does not specify a
766method. HOST and USER are regular expressions or nil, which is
767interpreted as a regular expression which always matches. If no entry
768matches, the variable `tramp-default-method' takes effect.
769
770If the file name does not specify the user, lookup is done using the
771empty string for the user name.
772
773See `tramp-methods' for a list of possibilities for METHOD."
774 :group 'tramp
775 :type '(repeat (list (regexp :tag "Host regexp")
776 (regexp :tag "User regexp")
777 (string :tag "Method"))))
778
00d6fd04
MA
779(defcustom tramp-default-user
780 nil
781 "*Default user to use for transferring files.
782It is nil by default; otherwise settings in configuration files like
783\"~/.ssh/config\" would be overwritten. Also see `tramp-default-user-alist'.
784
785This variable is regarded as obsolete, and will be removed soon."
786 :group 'tramp
787 :type '(choice (const nil) string))
788
789(defcustom tramp-default-user-alist
790 `(("\\`su\\(do\\)?\\'" nil "root")
791 ("\\`r\\(em\\)?\\(cp\\|sh\\)\\|telnet\\|plink1?\\'"
792 nil ,(user-login-name)))
793 "*Default user to use for specific method/host pairs.
794This is an alist of items (METHOD HOST USER). The first matching item
795specifies the user to use for a file name which does not specify a
796user. METHOD and USER are regular expressions or nil, which is
797interpreted as a regular expression which always matches. If no entry
798matches, the variable `tramp-default-user' takes effect.
799
800If the file name does not specify the method, lookup is done using the
801empty string for the method name."
802 :group 'tramp
803 :type '(repeat (list (regexp :tag "Method regexp")
804 (regexp :tag "Host regexp")
805 (string :tag "User"))))
806
807(defcustom tramp-default-host
808 (system-name)
809 "*Default host to use for transferring files.
810Useful for su and sudo methods mostly."
811 :group 'tramp
812 :type 'string)
813
814(defcustom tramp-default-proxies-alist nil
815 "*Route to be followed for specific host/user pairs.
816This is an alist of items (HOST USER PROXY). The first matching
817item specifies the proxy to be passed for a file name located on
818a remote target matching USER@HOST. HOST and USER are regular
70c11b0b
MA
819expressions. PROXY must be a Tramp filename without a localname
820part. Method and user name on PROXY are optional, which is
821interpreted with the default values. PROXY can contain the
822patterns %h and %u, which are replaced by the strings matching
823HOST or USER, respectively.
824
825HOST, USER or PROXY could also be Lisp forms, which will be
826evaluated. The result must be a string or nil, which is
827interpreted as a regular expression which always matches."
00d6fd04 828 :group 'tramp
70c11b0b
MA
829 :type '(repeat (list (choice :tag "Host regexp" regexp sexp)
830 (choice :tag "User regexp" regexp sexp)
831 (choice :tag "Proxy remote name" string (const nil)))))
00d6fd04 832
b96e6899
MA
833(defconst tramp-local-host-regexp
834 (concat
835 "^" (regexp-opt (list "localhost" (system-name) "127\.0\.0\.1" "::1") t) "$")
836 "*Host names which are regarded as local host.")
837
16674e4f 838(defconst tramp-completion-function-alist-rsh
00d6fd04
MA
839 '((tramp-parse-rhosts "/etc/hosts.equiv")
840 (tramp-parse-rhosts "~/.rhosts"))
b25a52cc 841 "Default list of (FUNCTION FILE) pairs to be examined for rsh methods.")
16674e4f 842
16674e4f 843(defconst tramp-completion-function-alist-ssh
00d6fd04
MA
844 '((tramp-parse-rhosts "/etc/hosts.equiv")
845 (tramp-parse-rhosts "/etc/shosts.equiv")
846 (tramp-parse-shosts "/etc/ssh_known_hosts")
847 (tramp-parse-sconfig "/etc/ssh_config")
848 (tramp-parse-shostkeys "/etc/ssh2/hostkeys")
849 (tramp-parse-sknownhosts "/etc/ssh2/knownhosts")
850 (tramp-parse-rhosts "~/.rhosts")
851 (tramp-parse-rhosts "~/.shosts")
852 (tramp-parse-shosts "~/.ssh/known_hosts")
853 (tramp-parse-sconfig "~/.ssh/config")
854 (tramp-parse-shostkeys "~/.ssh2/hostkeys")
855 (tramp-parse-sknownhosts "~/.ssh2/knownhosts"))
b25a52cc 856 "Default list of (FUNCTION FILE) pairs to be examined for ssh methods.")
16674e4f 857
16674e4f 858(defconst tramp-completion-function-alist-telnet
00d6fd04 859 '((tramp-parse-hosts "/etc/hosts"))
b25a52cc 860 "Default list of (FUNCTION FILE) pairs to be examined for telnet methods.")
16674e4f 861
16674e4f 862(defconst tramp-completion-function-alist-su
00d6fd04 863 '((tramp-parse-passwd "/etc/passwd"))
b25a52cc 864 "Default list of (FUNCTION FILE) pairs to be examined for su methods.")
292ffc15 865
00d6fd04
MA
866(defconst tramp-completion-function-alist-putty
867 '((tramp-parse-putty
868 "HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions"))
869 "Default list of (FUNCTION REGISTRY) pairs to be examined for putty methods.")
870
5ec2cc41 871(defvar tramp-completion-function-alist nil
16674e4f
KG
872 "*Alist of methods for remote files.
873This is a list of entries of the form (NAME PAIR1 PAIR2 ...).
874Each NAME stands for a remote access method. Each PAIR is of the form
875\(FUNCTION FILE). FUNCTION is responsible to extract user names and host
876names from FILE for completion. The following predefined FUNCTIONs exists:
877
5ec2cc41
KG
878 * `tramp-parse-rhosts' for \"~/.rhosts\" like files,
879 * `tramp-parse-shosts' for \"~/.ssh/known_hosts\" like files,
880 * `tramp-parse-sconfig' for \"~/.ssh/config\" like files,
881 * `tramp-parse-shostkeys' for \"~/.ssh2/hostkeys/*\" like files,
882 * `tramp-parse-sknownhosts' for \"~/.ssh2/knownhosts/*\" like files,
883 * `tramp-parse-hosts' for \"/etc/hosts\" like files,
884 * `tramp-parse-passwd' for \"/etc/passwd\" like files.
885 * `tramp-parse-netrc' for \"~/.netrc\" like files.
00d6fd04 886 * `tramp-parse-putty' for PuTTY registry keys.
5ec2cc41
KG
887
888FUNCTION can also be a customer defined function. For more details see
889the info pages.")
890
891(eval-after-load "tramp"
892 '(progn
893 (tramp-set-completion-function
894 "rcp" tramp-completion-function-alist-rsh)
895 (tramp-set-completion-function
896 "scp" tramp-completion-function-alist-ssh)
897 (tramp-set-completion-function
898 "scp1" tramp-completion-function-alist-ssh)
899 (tramp-set-completion-function
900 "scp2" tramp-completion-function-alist-ssh)
901 (tramp-set-completion-function
902 "scp1_old" tramp-completion-function-alist-ssh)
903 (tramp-set-completion-function
904 "scp2_old" tramp-completion-function-alist-ssh)
905 (tramp-set-completion-function
70c11b0b 906 "rsync" tramp-completion-function-alist-ssh)
946a5aeb
MA
907 (tramp-set-completion-function
908 "rsyncc" tramp-completion-function-alist-ssh)
5ec2cc41
KG
909 (tramp-set-completion-function
910 "remcp" tramp-completion-function-alist-rsh)
911 (tramp-set-completion-function
912 "rsh" tramp-completion-function-alist-rsh)
913 (tramp-set-completion-function
914 "ssh" tramp-completion-function-alist-ssh)
915 (tramp-set-completion-function
916 "ssh1" tramp-completion-function-alist-ssh)
917 (tramp-set-completion-function
918 "ssh2" tramp-completion-function-alist-ssh)
919 (tramp-set-completion-function
920 "ssh1_old" tramp-completion-function-alist-ssh)
921 (tramp-set-completion-function
922 "ssh2_old" tramp-completion-function-alist-ssh)
923 (tramp-set-completion-function
924 "remsh" tramp-completion-function-alist-rsh)
925 (tramp-set-completion-function
926 "telnet" tramp-completion-function-alist-telnet)
927 (tramp-set-completion-function
928 "su" tramp-completion-function-alist-su)
929 (tramp-set-completion-function
930 "sudo" tramp-completion-function-alist-su)
bf247b6e 931 (tramp-set-completion-function
5ec2cc41
KG
932 "scpx" tramp-completion-function-alist-ssh)
933 (tramp-set-completion-function
934 "sshx" tramp-completion-function-alist-ssh)
935 (tramp-set-completion-function
936 "krlogin" tramp-completion-function-alist-rsh)
937 (tramp-set-completion-function
938 "plink" tramp-completion-function-alist-ssh)
939 (tramp-set-completion-function
940 "plink1" tramp-completion-function-alist-ssh)
00d6fd04
MA
941 (tramp-set-completion-function
942 "plinkx" tramp-completion-function-alist-putty)
5ec2cc41
KG
943 (tramp-set-completion-function
944 "pscp" tramp-completion-function-alist-ssh)
945 (tramp-set-completion-function
946 "fcp" tramp-completion-function-alist-ssh)))
16674e4f 947
674da028
MA
948(defconst tramp-echo-mark-marker "_echo"
949 "String marker to surround echoed commands.")
950
68712eb6
MA
951(defconst tramp-echo-mark-marker-length (length tramp-echo-mark-marker)
952 "String length of `tramp-echo-mark-marker'.")
953
954(defconst tramp-echo-mark
955 (concat tramp-echo-mark-marker
956 (make-string tramp-echo-mark-marker-length ?\b))
00d6fd04
MA
957 "String mark to be transmitted around shell commands.
958Used to separate their echo from the output they produce. This
959will only be used if we cannot disable remote echo via stty.
960This string must have no effect on the remote shell except for
961producing some echo which can later be detected by
674da028
MA
962`tramp-echoed-echo-mark-regexp'. Using `tramp-echo-mark-marker',
963followed by an equal number of backspaces to erase them will
964usually suffice.")
00d6fd04 965
68712eb6
MA
966(defconst tramp-echoed-echo-mark-regexp
967 (format "%s\\(\b\\( \b\\)?\\)\\{%d\\}"
968 tramp-echo-mark-marker tramp-echo-mark-marker-length)
00d6fd04
MA
969 "Regexp which matches `tramp-echo-mark' as it gets echoed by
970the remote shell.")
971
fb7933a3
KG
972(defcustom tramp-rsh-end-of-line "\n"
973 "*String used for end of line in rsh connections.
974I don't think this ever needs to be changed, so please tell me about it
16674e4f 975if you need to change this.
90f8dc03
KG
976Also see the method parameter `tramp-password-end-of-line' and the normal
977variable `tramp-default-password-end-of-line'."
16674e4f
KG
978 :group 'tramp
979 :type 'string)
980
90f8dc03
KG
981(defcustom tramp-default-password-end-of-line
982 tramp-rsh-end-of-line
16674e4f 983 "*String used for end of line after sending a password.
90f8dc03
KG
984This variable provides the default value for the method parameter
985`tramp-password-end-of-line', see `tramp-methods' for more details.
986
16674e4f
KG
987It seems that people using plink under Windows need to send
988\"\\r\\n\" (carriage-return, then newline) after a password, but just
989\"\\n\" after all other lines. This variable can be used for the
990password, see `tramp-rsh-end-of-line' for the other cases.
991
992The default value is to use the same value as `tramp-rsh-end-of-line'."
fb7933a3
KG
993 :group 'tramp
994 :type 'string)
995
00d6fd04
MA
996;; "getconf PATH" yields:
997;; HP-UX: /usr/bin:/usr/ccs/bin:/opt/ansic/bin:/opt/langtools/bin:/opt/fortran/bin
998;; Solaris: /usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin
0664ff72 999;; GNU/Linux (Debian, Suse): /bin:/usr/bin
00d6fd04 1000;; FreeBSD: /usr/bin:/bin:/usr/sbin:/sbin: - beware trailing ":"!
fb7933a3 1001(defcustom tramp-remote-path
00d6fd04
MA
1002 '(tramp-default-remote-path "/usr/sbin" "/usr/local/bin"
1003 "/local/bin" "/local/freeware/bin" "/local/gnu/bin"
fb7933a3
KG
1004 "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin")
1005 "*List of directories to search for executables on remote host.
00d6fd04
MA
1006For every remote host, this variable will be set buffer local,
1007keeping the list of existing directories on that host.
fb7933a3
KG
1008
1009You can use `~' in this list, but when searching for a shell which groks
00d6fd04
MA
1010tilde expansion, all directory names starting with `~' will be ignored.
1011
1012`Default Directories' represent the list of directories given by
1013the command \"getconf PATH\". It is recommended to use this
1014entry on top of this list, because these are the default
70c11b0b
MA
1015directories for POSIX compatible commands.
1016
1017`Private Directories' are the settings of the $PATH environment,
1018as given in your `~/.profile'."
00d6fd04
MA
1019 :group 'tramp
1020 :type '(repeat (choice
1021 (const :tag "Default Directories" tramp-default-remote-path)
70c11b0b 1022 (const :tag "Private Directories" tramp-own-remote-path)
00d6fd04
MA
1023 (string :tag "Directory"))))
1024
00d6fd04 1025(defcustom tramp-remote-process-environment
a0a5183a 1026 `("HISTFILE=$HOME/.tramp_history" "HISTSIZE=1" "LC_ALL=C"
00d6fd04 1027 ,(concat "TERM=" tramp-terminal-type)
97c696d5
MA
1028 "EMACS=t" ;; Deprecated.
1029 ,(format "INSIDE_EMACS=%s,tramp:%s" emacs-version tramp-version)
00d6fd04
MA
1030 "CDPATH=" "HISTORY=" "MAIL=" "MAILCHECK=" "MAILPATH="
1031 "autocorrect=" "correct=")
1032
1033 "*List of environment variables to be set on the remote host.
1034
1035Each element should be a string of the form ENVVARNAME=VALUE. An
1036entry ENVVARNAME= diables the corresponding environment variable,
1037which might have been set in the init files like ~/.profile.
1038
1039Special handling is applied to the PATH environment, which should
1040not be set here. Instead of, it should be set via `tramp-remote-path'."
fb7933a3
KG
1041 :group 'tramp
1042 :type '(repeat string))
1043
1044(defcustom tramp-login-prompt-regexp
bc103d00 1045 ".*ogin\\( .*\\)?: *"
fb7933a3 1046 "*Regexp matching login-like prompts.
bc103d00
MA
1047The regexp should match at end of buffer.
1048
1049Sometimes the prompt is reported to look like \"login as:\"."
fb7933a3
KG
1050 :group 'tramp
1051 :type 'regexp)
1052
821e6e36 1053(defcustom tramp-shell-prompt-pattern
aa485f7c
MA
1054 ;; Allow a prompt to start right after a ^M since it indeed would be
1055 ;; displayed at the beginning of the line (and Zsh uses it).
dab816a9 1056 "\\(?:^\\|\r\\)[^#$%>\n]*#?[#$%>] *\\(\e\\[[0-9;]*[a-zA-Z] *\\)*"
821e6e36
KG
1057 "Regexp to match prompts from remote shell.
1058Normally, Tramp expects you to configure `shell-prompt-pattern'
1059correctly, but sometimes it happens that you are connecting to a
1060remote host which sends a different kind of shell prompt. Therefore,
1061Tramp recognizes things matched by `shell-prompt-pattern' as prompt,
1062and also things matched by this variable. The default value of this
b25a52cc 1063variable is similar to the default value of `shell-prompt-pattern',
dab816a9
MA
1064which should work well in many cases.
1065
1066This regexp must match both `tramp-initial-end-of-output' and
1067`tramp-end-of-output'."
821e6e36
KG
1068 :group 'tramp
1069 :type 'regexp)
1070
fb7933a3 1071(defcustom tramp-password-prompt-regexp
00d6fd04 1072 "^.*\\([pP]assword\\|[pP]assphrase\\).*:\^@? *"
fb7933a3 1073 "*Regexp matching password-like prompts.
ac474af1 1074The regexp should match at end of buffer.
fb7933a3
KG
1075
1076The `sudo' program appears to insert a `^@' character into the prompt."
1077 :group 'tramp
1078 :type 'regexp)
1079
1080(defcustom tramp-wrong-passwd-regexp
b1d06e75
KG
1081 (concat "^.*"
1082 ;; These strings should be on the last line
a4aeb9a4 1083 (regexp-opt '("Permission denied"
b1d06e75
KG
1084 "Login incorrect"
1085 "Login Incorrect"
1086 "Connection refused"
27e813fe 1087 "Connection closed"
7e5686f0 1088 "Timeout, server not responding."
b1d06e75
KG
1089 "Sorry, try again."
1090 "Name or service not known"
00d6fd04 1091 "Host key verification failed."
70c11b0b 1092 "No supported authentication methods left to try!") t)
b1d06e75
KG
1093 ".*"
1094 "\\|"
1095 "^.*\\("
1096 ;; Here comes a list of regexes, separated by \\|
1097 "Received signal [0-9]+"
1098 "\\).*")
fb7933a3 1099 "*Regexp matching a `login failed' message.
ac474af1
KG
1100The regexp should match at end of buffer."
1101 :group 'tramp
1102 :type 'regexp)
1103
1104(defcustom tramp-yesno-prompt-regexp
3cdaec13
KG
1105 (concat
1106 (regexp-opt '("Are you sure you want to continue connecting (yes/no)?") t)
1107 "\\s-*")
1108 "Regular expression matching all yes/no queries which need to be confirmed.
ac474af1 1109The confirmation should be done with yes or no.
3cdaec13
KG
1110The regexp should match at end of buffer.
1111See also `tramp-yn-prompt-regexp'."
fb7933a3
KG
1112 :group 'tramp
1113 :type 'regexp)
1114
3cdaec13 1115(defcustom tramp-yn-prompt-regexp
658052a2
MA
1116 (concat
1117 (regexp-opt '("Store key in cache? (y/n)"
1118 "Update cached key? (y/n, Return cancels connection)") t)
1119 "\\s-*")
3cdaec13
KG
1120 "Regular expression matching all y/n queries which need to be confirmed.
1121The confirmation should be done with y or n.
1122The regexp should match at end of buffer.
1123See also `tramp-yesno-prompt-regexp'."
1124 :group 'tramp
1125 :type 'regexp)
487f4fb7
KG
1126
1127(defcustom tramp-terminal-prompt-regexp
1128 (concat "\\("
1129 "TERM = (.*)"
1130 "\\|"
1131 "Terminal type\\? \\[.*\\]"
1132 "\\)\\s-*")
1133 "Regular expression matching all terminal setting prompts.
1134The regexp should match at end of buffer.
1135The answer will be provided by `tramp-action-terminal', which see."
1136 :group 'tramp
1137 :type 'regexp)
3cdaec13 1138
01917a18
MA
1139(defcustom tramp-operation-not-permitted-regexp
1140 (concat "\\(" "preserving times.*" "\\|" "set mode" "\\)" ":\\s-*"
1141 (regexp-opt '("Operation not permitted") t))
1142 "Regular expression matching keep-date problems in (s)cp operations.
1143Copying has been performed successfully already, so this message can
1144be ignored safely."
1145 :group 'tramp
1146 :type 'regexp)
1147
6b2633cc
LH
1148(defcustom tramp-copy-failed-regexp
1149 (concat "\\(.+: "
1150 (regexp-opt '("Permission denied"
1151 "not a regular file"
1152 "is a directory"
1153 "No such file or directory") t)
1154 "\\)\\s-*")
1155 "Regular expression matching copy problems in (s)cp operations."
1156 :group 'tramp
1157 :type 'regexp)
1158
19a87064 1159(defcustom tramp-process-alive-regexp
38c65fca 1160 ""
19a87064 1161 "Regular expression indicating a process has finished.
38c65fca
KG
1162In fact this expression is empty by intention, it will be used only to
1163check regularly the status of the associated process.
07dfe738 1164The answer will be provided by `tramp-action-process-alive',
00d6fd04 1165`tramp-action-out-of-band', which see."
38c65fca
KG
1166 :group 'tramp
1167 :type 'regexp)
1168
fb7933a3
KG
1169(defcustom tramp-temp-name-prefix "tramp."
1170 "*Prefix to use for temporary files.
1171If this is a relative file name (such as \"tramp.\"), it is considered
1172relative to the directory name returned by the function
9e6ab520 1173`tramp-compat-temporary-file-directory' (which see). It may also be an
fb7933a3
KG
1174absolute file name; don't forget to include a prefix for the filename
1175part, though."
1176 :group 'tramp
1177 :type 'string)
1178
2296b54d
MA
1179(defconst tramp-temp-buffer-name " *tramp temp*"
1180 "Buffer name for a temporary buffer.
1181It shall be used in combination with `generate-new-buffer-name'.")
1182
b88f2d0a
MA
1183(defvar tramp-temp-buffer-file-name nil
1184 "File name of a persistent local temporary file.
1185Useful for \"rsync\" like methods.")
1186(make-variable-buffer-local 'tramp-temp-buffer-file-name)
1187
4007ba5b 1188(defcustom tramp-sh-extra-args '(("/bash\\'" . "-norc -noprofile"))
c62c9d08
KG
1189 "*Alist specifying extra arguments to pass to the remote shell.
1190Entries are (REGEXP . ARGS) where REGEXP is a regular expression
1191matching the shell file name and ARGS is a string specifying the
1192arguments.
1193
1194This variable is only used when Tramp needs to start up another shell
1195for tilde expansion. The extra arguments should typically prevent the
1196shell from reading its init file."
1197 :group 'tramp
90f8dc03
KG
1198 ;; This might be the wrong way to test whether the widget type
1199 ;; `alist' is available. Who knows the right way to test it?
1200 :type (if (get 'alist 'widget-type)
1201 '(alist :key-type string :value-type string)
1202 '(repeat (cons string string))))
c62c9d08 1203
00d6fd04
MA
1204;; XEmacs is distributed with few Lisp packages. Further packages are
1205;; installed using EFS. If we use a unified filename format, then
1206;; Tramp is required in addition to EFS. (But why can't Tramp just
1207;; disable EFS when Tramp is loaded? Then XEmacs can ship with EFS
1208;; just like before.) Another reason for using a separate filename
1209;; syntax on XEmacs is that EFS hooks into XEmacs in many places, but
1210;; Tramp only knows how to deal with `file-name-handler-alist', not
1211;; the other places.
1212
1213;; Currently, we have the choice between 'ftp, 'sep, and 'url.
1214;;;###autoload
1215(defcustom tramp-syntax
1216 (if (featurep 'xemacs) 'sep 'ftp)
1217 "Tramp filename syntax to be used.
1218
1219It can have the following values:
1220
1221 'ftp -- Ange-FTP respective EFS like syntax (GNU Emacs default)
1222 'sep -- Syntax as defined for XEmacs (not available yet for GNU Emacs)
1223 'url -- URL-like syntax."
16674e4f 1224 :group 'tramp
00d6fd04
MA
1225 :type (if (featurep 'xemacs)
1226 '(choice (const :tag "EFS" ftp)
1227 (const :tag "XEmacs" sep)
1228 (const :tag "URL" url))
1229 '(choice (const :tag "Ange-FTP" ftp)
1230 (const :tag "URL" url))))
1231
1232(defconst tramp-prefix-format
1233 (cond ((equal tramp-syntax 'ftp) "/")
1234 ((equal tramp-syntax 'sep) "/[")
1235 ((equal tramp-syntax 'url) "/")
1236 (t (error "Wrong `tramp-syntax' defined")))
a4aeb9a4 1237 "*String matching the very beginning of Tramp file names.
00d6fd04 1238Used in `tramp-make-tramp-file-name'.")
16674e4f 1239
00d6fd04 1240(defconst tramp-prefix-regexp
16674e4f 1241 (concat "^" (regexp-quote tramp-prefix-format))
a4aeb9a4 1242 "*Regexp matching the very beginning of Tramp file names.
00d6fd04 1243Should always start with \"^\". Derived from `tramp-prefix-format'.")
16674e4f 1244
00d6fd04 1245(defconst tramp-method-regexp
16674e4f 1246 "[a-zA-Z_0-9-]+"
00d6fd04 1247 "*Regexp matching methods identifiers.")
16674e4f 1248
00d6fd04
MA
1249(defconst tramp-postfix-method-format
1250 (cond ((equal tramp-syntax 'ftp) ":")
1251 ((equal tramp-syntax 'sep) "/")
1252 ((equal tramp-syntax 'url) "://")
1253 (t (error "Wrong `tramp-syntax' defined")))
16674e4f 1254 "*String matching delimeter between method and user or host names.
00d6fd04 1255Used in `tramp-make-tramp-file-name'.")
16674e4f 1256
00d6fd04
MA
1257(defconst tramp-postfix-method-regexp
1258 (regexp-quote tramp-postfix-method-format)
16674e4f 1259 "*Regexp matching delimeter between method and user or host names.
00d6fd04 1260Derived from `tramp-postfix-method-format'.")
16674e4f 1261
00d6fd04
MA
1262(defconst tramp-user-regexp
1263 "[^:/ \t]+"
1264 "*Regexp matching user names.")
16674e4f 1265
b96e6899
MA
1266(defconst tramp-prefix-domain-format "%"
1267 "*String matching delimeter between user and domain names.")
1268
1269(defconst tramp-prefix-domain-regexp
1270 (regexp-quote tramp-prefix-domain-format)
1271 "*Regexp matching delimeter between user and domain names.
1272Derived from `tramp-prefix-domain-format'.")
1273
1274(defconst tramp-domain-regexp
70c11b0b 1275 "[-a-zA-Z0-9_.]+"
b96e6899
MA
1276 "*Regexp matching domain names.")
1277
1278(defconst tramp-user-with-domain-regexp
1279 (concat "\\(" tramp-user-regexp "\\)"
1280 tramp-prefix-domain-regexp
1281 "\\(" tramp-domain-regexp "\\)")
1282 "*Regexp matching user names with domain names.")
1283
00d6fd04 1284(defconst tramp-postfix-user-format
16674e4f
KG
1285 "@"
1286 "*String matching delimeter between user and host names.
00d6fd04 1287Used in `tramp-make-tramp-file-name'.")
16674e4f 1288
00d6fd04 1289(defconst tramp-postfix-user-regexp
16674e4f
KG
1290 (regexp-quote tramp-postfix-user-format)
1291 "*Regexp matching delimeter between user and host names.
00d6fd04
MA
1292Derived from `tramp-postfix-user-format'.")
1293
1294(defconst tramp-host-regexp
1295 "[a-zA-Z0-9_.-]+"
1296 "*Regexp matching host names.")
1297
b96e6899
MA
1298(defconst tramp-prefix-ipv6-format
1299 (cond ((equal tramp-syntax 'ftp) "[")
1300 ((equal tramp-syntax 'sep) "")
1301 ((equal tramp-syntax 'url) "[")
1302 (t (error "Wrong `tramp-syntax' defined")))
1303 "*String matching left hand side of IPv6 addresses.
1304Used in `tramp-make-tramp-file-name'.")
1305
1306(defconst tramp-prefix-ipv6-regexp
1307 (regexp-quote tramp-prefix-ipv6-format)
1308 "*Regexp matching left hand side of IPv6 addresses.
1309Derived from `tramp-prefix-ipv6-format'.")
1310
e0b6e3b9
MA
1311;; The following regexp is a bit sloppy. But it shall serve our
1312;; purposes. It covers also IPv4 mapped IPv6 addresses, like in
1313;; "::ffff:192.168.0.1".
b96e6899 1314(defconst tramp-ipv6-regexp
e0b6e3b9 1315 "\\(?:\\(?:[a-zA-Z0-9]+\\)?:\\)+[a-zA-Z0-9.]+"
b96e6899
MA
1316 "*Regexp matching IPv6 addresses.")
1317
1318(defconst tramp-postfix-ipv6-format
1319 (cond ((equal tramp-syntax 'ftp) "]")
1320 ((equal tramp-syntax 'sep) "")
1321 ((equal tramp-syntax 'url) "]")
1322 (t (error "Wrong `tramp-syntax' defined")))
1323 "*String matching right hand side of IPv6 addresses.
1324Used in `tramp-make-tramp-file-name'.")
1325
1326(defconst tramp-postfix-ipv6-regexp
1327 (regexp-quote tramp-postfix-ipv6-format)
1328 "*Regexp matching right hand side of IPv6 addresses.
1329Derived from `tramp-postfix-ipv6-format'.")
1330
00d6fd04
MA
1331(defconst tramp-prefix-port-format
1332 (cond ((equal tramp-syntax 'ftp) "#")
1333 ((equal tramp-syntax 'sep) "#")
1334 ((equal tramp-syntax 'url) ":")
1335 (t (error "Wrong `tramp-syntax' defined")))
1336 "*String matching delimeter between host names and port numbers.")
1337
1338(defconst tramp-prefix-port-regexp
1339 (regexp-quote tramp-prefix-port-format)
1340 "*Regexp matching delimeter between host names and port numbers.
1341Derived from `tramp-prefix-port-format'.")
1342
1343(defconst tramp-port-regexp
1344 "[0-9]+"
1345 "*Regexp matching port numbers.")
1346
1347(defconst tramp-host-with-port-regexp
1348 (concat "\\(" tramp-host-regexp "\\)"
1349 tramp-prefix-port-regexp
1350 "\\(" tramp-port-regexp "\\)")
1351 "*Regexp matching host names with port numbers.")
1352
1353(defconst tramp-postfix-host-format
1354 (cond ((equal tramp-syntax 'ftp) ":")
1355 ((equal tramp-syntax 'sep) "]")
1356 ((equal tramp-syntax 'url) "")
1357 (t (error "Wrong `tramp-syntax' defined")))
7432277c 1358 "*String matching delimeter between host names and localnames.
00d6fd04 1359Used in `tramp-make-tramp-file-name'.")
16674e4f 1360
00d6fd04 1361(defconst tramp-postfix-host-regexp
16674e4f 1362 (regexp-quote tramp-postfix-host-format)
7432277c 1363 "*Regexp matching delimeter between host names and localnames.
00d6fd04 1364Derived from `tramp-postfix-host-format'.")
16674e4f 1365
00d6fd04 1366(defconst tramp-localname-regexp
16674e4f 1367 ".*$"
00d6fd04 1368 "*Regexp matching localnames.")
16674e4f
KG
1369
1370;; File name format.
505edaeb 1371
00d6fd04 1372(defconst tramp-file-name-structure
16674e4f
KG
1373 (list
1374 (concat
1375 tramp-prefix-regexp
00d6fd04
MA
1376 "\\(" "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp "\\)?"
1377 "\\(" "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp "\\)?"
b96e6899
MA
1378 "\\(" "\\(" tramp-host-regexp
1379 "\\|"
1380 tramp-prefix-ipv6-regexp tramp-ipv6-regexp
1381 tramp-postfix-ipv6-regexp "\\)"
1382 "\\(" tramp-prefix-port-regexp tramp-port-regexp "\\)?" "\\)?"
00d6fd04
MA
1383 tramp-postfix-host-regexp
1384 "\\(" tramp-localname-regexp "\\)")
b96e6899 1385 2 4 5 8)
16674e4f 1386
fb7933a3 1387 "*List of five elements (REGEXP METHOD USER HOST FILE), detailing \
a4aeb9a4 1388the Tramp file name structure.
fb7933a3 1389
a4aeb9a4 1390The first element REGEXP is a regular expression matching a Tramp file
fb7933a3
KG
1391name. The regex should contain parentheses around the method name,
1392the user name, the host name, and the file name parts.
1393
1394The second element METHOD is a number, saying which pair of
1395parentheses matches the method name. The third element USER is
1396similar, but for the user name. The fourth element HOST is similar,
1397but for the host name. The fifth element FILE is for the file name.
1398These numbers are passed directly to `match-string', which see. That
1399means the opening parentheses are counted to identify the pair.
1400
00d6fd04 1401See also `tramp-file-name-regexp'.")
fb7933a3
KG
1402
1403;;;###autoload
505edaeb 1404(defconst tramp-file-name-regexp-unified
b96e6899 1405 "\\`/\\([^[/:]+\\|[^/]+]\\):"
505edaeb
KG
1406 "Value for `tramp-file-name-regexp' for unified remoting.
1407Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and
00d6fd04 1408Tramp. See `tramp-file-name-structure' for more explanations.")
505edaeb
KG
1409
1410;;;###autoload
1411(defconst tramp-file-name-regexp-separate
1412 "\\`/\\[.*\\]"
1413 "Value for `tramp-file-name-regexp' for separate remoting.
1414XEmacs uses a separate filename syntax for Tramp and EFS.
00d6fd04 1415See `tramp-file-name-structure' for more explanations.")
505edaeb
KG
1416
1417;;;###autoload
00d6fd04
MA
1418(defconst tramp-file-name-regexp-url
1419 "\\`/[^/:]+://"
1420 "Value for `tramp-file-name-regexp' for URL-like remoting.
1421See `tramp-file-name-structure' for more explanations.")
1422
1423;;;###autoload
1424(defconst tramp-file-name-regexp
1425 (cond ((equal tramp-syntax 'ftp) tramp-file-name-regexp-unified)
1426 ((equal tramp-syntax 'sep) tramp-file-name-regexp-separate)
1427 ((equal tramp-syntax 'url) tramp-file-name-regexp-url)
1428 (t (error "Wrong `tramp-syntax' defined")))
94be87e8 1429 "*Regular expression matching file names handled by Tramp.
a4aeb9a4 1430This regexp should match Tramp file names but no other file names.
fb7933a3
KG
1431\(When tramp.el is loaded, this regular expression is prepended to
1432`file-name-handler-alist', and that is searched sequentially. Thus,
a4aeb9a4
MA
1433if the Tramp entry appears rather early in the `file-name-handler-alist'
1434and is a bit too general, then some files might be considered Tramp
00d6fd04 1435files which are not really Tramp files.
fb7933a3
KG
1436
1437Please note that the entry in `file-name-handler-alist' is made when
1438this file (tramp.el) is loaded. This means that this variable must be set
1439before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1440updated after changing this variable.
1441
00d6fd04 1442Also see `tramp-file-name-structure'.")
fb7933a3 1443
16674e4f 1444;;;###autoload
8a798e41 1445(defconst tramp-root-regexp
00d6fd04 1446 (if (memq system-type '(cygwin windows-nt))
aa485f7c
MA
1447 "\\`\\([a-zA-Z]:\\)?/"
1448 "\\`/")
8a798e41 1449 "Beginning of an incomplete Tramp file name.
aa485f7c 1450Usually, it is just \"\\\\`/\". On W32 systems, there might be a
57671b72 1451volume letter, which will be removed by `tramp-drop-volume-letter'.")
8a798e41
MA
1452
1453;;;###autoload
1454(defconst tramp-completion-file-name-regexp-unified
aa485f7c 1455 (concat tramp-root-regexp "[^/]*\\'")
16674e4f 1456 "Value for `tramp-completion-file-name-regexp' for unified remoting.
8a798e41
MA
1457GNU Emacs uses a unified filename syntax for Tramp and Ange-FTP.
1458See `tramp-file-name-structure' for more explanations.")
fb7933a3 1459
16674e4f
KG
1460;;;###autoload
1461(defconst tramp-completion-file-name-regexp-separate
aa485f7c 1462 (concat tramp-root-regexp "\\([[][^]]*\\)?\\'")
16674e4f
KG
1463 "Value for `tramp-completion-file-name-regexp' for separate remoting.
1464XEmacs uses a separate filename syntax for Tramp and EFS.
00d6fd04 1465See `tramp-file-name-structure' for more explanations.")
fb7933a3 1466
16674e4f 1467;;;###autoload
00d6fd04 1468(defconst tramp-completion-file-name-regexp-url
aa485f7c 1469 (concat tramp-root-regexp "[^/:]+\\(:\\(/\\(/[^/]*\\)?\\)?\\)?\\'")
00d6fd04
MA
1470 "Value for `tramp-completion-file-name-regexp' for URL-like remoting.
1471See `tramp-file-name-structure' for more explanations.")
1472
1473;;;###autoload
1474(defconst tramp-completion-file-name-regexp
1475 (cond ((equal tramp-syntax 'ftp) tramp-completion-file-name-regexp-unified)
1476 ((equal tramp-syntax 'sep) tramp-completion-file-name-regexp-separate)
1477 ((equal tramp-syntax 'url) tramp-completion-file-name-regexp-url)
1478 (t (error "Wrong `tramp-syntax' defined")))
a4aeb9a4
MA
1479 "*Regular expression matching file names handled by Tramp completion.
1480This regexp should match partial Tramp file names only.
16674e4f
KG
1481
1482Please note that the entry in `file-name-handler-alist' is made when
1483this file (tramp.el) is loaded. This means that this variable must be set
1484before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1485updated after changing this variable.
1486
00d6fd04 1487Also see `tramp-file-name-structure'.")
fb7933a3 1488
00d6fd04
MA
1489(defconst tramp-actions-before-shell
1490 '((tramp-login-prompt-regexp tramp-action-login)
1491 (tramp-password-prompt-regexp tramp-action-password)
1492 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
ac474af1 1493 (shell-prompt-pattern tramp-action-succeed)
821e6e36 1494 (tramp-shell-prompt-pattern tramp-action-succeed)
3cdaec13 1495 (tramp-yesno-prompt-regexp tramp-action-yesno)
487f4fb7 1496 (tramp-yn-prompt-regexp tramp-action-yn)
19a87064
MA
1497 (tramp-terminal-prompt-regexp tramp-action-terminal)
1498 (tramp-process-alive-regexp tramp-action-process-alive))
ac474af1
KG
1499 "List of pattern/action pairs.
1500Whenever a pattern matches, the corresponding action is performed.
1501Each item looks like (PATTERN ACTION).
1502
1503The PATTERN should be a symbol, a variable. The value of this
1504variable gives the regular expression to search for. Note that the
1505regexp must match at the end of the buffer, \"\\'\" is implicitly
1506appended to it.
1507
1508The ACTION should also be a symbol, but a function. When the
00d6fd04 1509corresponding PATTERN matches, the ACTION function is called.")
ac474af1 1510
00d6fd04 1511(defconst tramp-actions-copy-out-of-band
38c65fca
KG
1512 '((tramp-password-prompt-regexp tramp-action-password)
1513 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
00d6fd04 1514 (tramp-copy-failed-regexp tramp-action-permission-denied)
19a87064 1515 (tramp-process-alive-regexp tramp-action-out-of-band))
38c65fca
KG
1516 "List of pattern/action pairs.
1517This list is used for copying/renaming with out-of-band methods.
90f8dc03 1518
00d6fd04
MA
1519See `tramp-actions-before-shell' for more info.")
1520
1521;; Chunked sending kludge. We set this to 500 for black-listed constellations
7432277c 1522;; known to have a bug in `process-send-string'; some ssh connections appear
7177e2a3
MA
1523;; to drop bytes when data is sent too quickly. There is also a connection
1524;; buffer local variable, which is computed depending on remote host properties
1525;; when `tramp-chunksize' is zero or nil.
7432277c
KG
1526(defcustom tramp-chunksize
1527 (when (and (not (featurep 'xemacs))
1528 (memq system-type '(hpux)))
1529 500)
55880756
MA
1530;; Parentheses in docstring starting at beginning of line are escaped.
1531;; Fontification is messed up when
1532;; `open-paren-in-column-0-is-defun-start' set to t.
7432277c
KG
1533 "*If non-nil, chunksize for sending input to local process.
1534It is necessary only on systems which have a buggy `process-send-string'
1535implementation. The necessity, whether this variable must be set, can be
1536checked via the following code:
1537
1538 (with-temp-buffer
11948172
MA
1539 (let* ((user \"xxx\") (host \"yyy\")
1540 (init 0) (step 50)
1541 (sent init) (received init))
1542 (while (= sent received)
1543 (setq sent (+ sent step))
1544 (erase-buffer)
1545 (let ((proc (start-process (buffer-name) (current-buffer)
1546 \"ssh\" \"-l\" user host \"wc\" \"-c\")))
1547 (when (memq (process-status proc) '(run open))
1548 (process-send-string proc (make-string sent ?\\ ))
1549 (process-send-eof proc)
1550 (process-send-eof proc))
1551 (while (not (progn (goto-char (point-min))
1552 (re-search-forward \"\\\\w+\" (point-max) t)))
1553 (accept-process-output proc 1))
1554 (when (memq (process-status proc) '(run open))
1555 (setq received (string-to-number (match-string 0)))
1556 (delete-process proc)
1557 (message \"Bytes sent: %s\\tBytes received: %s\" sent received)
1558 (sit-for 0))))
1559 (if (> sent (+ init step))
1560 (message \"You should set `tramp-chunksize' to a maximum of %s\"
1561 (- sent step))
1562 (message \"Test does not work\")
1563 (display-buffer (current-buffer))
1564 (sit-for 30))))
1565
1566In the Emacs normally running Tramp, evaluate the above code
55880756 1567\(replace \"xxx\" and \"yyy\" by the remote user and host name,
11948172
MA
1568respectively). You can do this, for example, by pasting it into
1569the `*scratch*' buffer and then hitting C-j with the cursor after the
1570last closing parenthesis. Note that it works only if you have configured
1571\"ssh\" to run without password query, see ssh-agent(1).
1572
1573You will see the number of bytes sent successfully to the remote host.
1574If that number exceeds 1000, you can stop the execution by hitting
1575C-g, because your Emacs is likely clean.
1576
11948172
MA
1577When it is necessary to set `tramp-chunksize', you might consider to
1578use an out-of-the-band method (like \"scp\") instead of an internal one
55880756 1579\(like \"ssh\"), because setting `tramp-chunksize' to non-nil decreases
11948172 1580performance.
c951aecb 1581
00d6fd04
MA
1582If your Emacs is buggy, the code stops and gives you an indication
1583about the value `tramp-chunksize' should be set. Maybe you could just
1584experiment a bit, e.g. changing the values of `init' and `step'
1585in the third line of the code.
1586
7432277c
KG
1587Please raise a bug report via \"M-x tramp-bug\" if your system needs
1588this variable to be set as well."
1589 :group 'tramp
b1a2b924 1590 :type '(choice (const nil) integer))
7432277c 1591
5ec2cc41
KG
1592;; Logging in to a remote host normally requires obtaining a pty. But
1593;; Emacs on MacOS X has process-connection-type set to nil by default,
1594;; so on those systems Tramp doesn't obtain a pty. Here, we allow
1595;; for an override of the system default.
1596(defcustom tramp-process-connection-type t
1597 "Overrides `process-connection-type' for connections from Tramp.
1598Tramp binds process-connection-type to the value given here before
1599opening a connection to a remote host."
1600 :group 'tramp
1601 :type '(choice (const nil) (const t) (const pty)))
1602
b50dd0d2
MA
1603(defcustom tramp-completion-reread-directory-timeout 10
1604 "Defines seconds since last remote command before rereading a directory.
1605A remote directory might have changed its contents. In order to
1606make it visible during file name completion in the minibuffer,
1607Tramp flushes its cache and rereads the directory contents when
1608more than `tramp-completion-reread-directory-timeout' seconds
1609have been gone since last remote command execution. A value of 0
1610would require an immediate reread during filename completion, nil
1611means to use always cached values for the directory contents."
1612 :group 'tramp
1613 :type '(choice (const nil) integer))
1614
fb7933a3
KG
1615;;; Internal Variables:
1616
fb7933a3 1617(defvar tramp-current-method nil
00d6fd04 1618 "Connection method for this *tramp* buffer.")
fb7933a3
KG
1619
1620(defvar tramp-current-user nil
00d6fd04 1621 "Remote login name for this *tramp* buffer.")
fb7933a3
KG
1622
1623(defvar tramp-current-host nil
00d6fd04
MA
1624 "Remote host for this *tramp* buffer.")
1625
1626(defconst tramp-uudecode
1627 "(echo begin 600 /tmp/tramp.$$; tail +2) | uudecode
fabf2143 1628cat /tmp/tramp.$$
00d6fd04 1629rm -f /tmp/tramp.$$"
fabf2143 1630 "Shell function to implement `uudecode' to standard output.
c08e6004
MA
1631Many systems support `uudecode -o /dev/stdout' or `uudecode -o -'
1632for this or `uudecode -p', but some systems don't, and for them
1633we have this shell function.")
fabf2143 1634
293c24f9
MA
1635(defconst tramp-perl-file-truename
1636 "%s -e '
1637use File::Spec;
1638use Cwd \"realpath\";
1639
1640sub recursive {
1641 my ($volume, @dirs) = @_;
1642 my $real = realpath(File::Spec->catpath(
1643 $volume, File::Spec->catdir(@dirs), \"\"));
1644 if ($real) {
1645 my ($vol, $dir) = File::Spec->splitpath($real, 1);
1646 return ($vol, File::Spec->splitdir($dir));
1647 }
1648 else {
1649 my $last = pop(@dirs);
1650 ($volume, @dirs) = recursive($volume, @dirs);
1651 push(@dirs, $last);
1652 return ($volume, @dirs);
1653 }
1654}
1655
1656$result = realpath($ARGV[0]);
1657if (!$result) {
1658 my ($vol, $dir) = File::Spec->splitpath($ARGV[0], 1);
1659 ($vol, @dirs) = recursive($vol, File::Spec->splitdir($dir));
1660
1661 $result = File::Spec->catpath($vol, File::Spec->catdir(@dirs), \"\");
1662}
1663
1664if ($ARGV[0] =~ /\\/$/) {
1665 $result = $result . \"/\";
1666}
1667
1668print \"\\\"$result\\\"\\n\";
1669' \"$1\" 2>/dev/null"
1670 "Perl script to produce output suitable for use with `file-truename'
1671on the remote file system.
1672Escape sequence %s is replaced with name of Perl binary.
1673This string is passed to `format', so percent characters need to be doubled.")
1674
1675(defconst tramp-perl-file-name-all-completions
1676 "%s -e 'sub case {
1677 my $str = shift;
1678 if ($ARGV[2]) {
1679 return lc($str);
1680 }
1681 else {
1682 return $str;
1683 }
1684}
1685opendir(d, $ARGV[0]) || die(\"$ARGV[0]: $!\\nfail\\n\");
1686@files = readdir(d); closedir(d);
1687foreach $f (@files) {
1688 if (case(substr($f, 0, length($ARGV[1]))) eq case($ARGV[1])) {
1689 if (-d \"$ARGV[0]/$f\") {
1690 print \"$f/\\n\";
1691 }
1692 else {
1693 print \"$f\\n\";
1694 }
1695 }
1696}
1697print \"ok\\n\"
1698' \"$1\" \"$2\" \"$3\" 2>/dev/null"
1699 "Perl script to produce output suitable for use with
1700`file-name-all-completions' on the remote file system. Escape
1701sequence %s is replaced with name of Perl binary. This string is
1702passed to `format', so percent characters need to be doubled.")
1703
fabf2143
KG
1704;; Perl script to implement `file-attributes' in a Lisp `read'able
1705;; output. If you are hacking on this, note that you get *no* output
1706;; unless this spits out a complete line, including the '\n' at the
1707;; end.
8daea7fc 1708;; The device number is returned as "-1", because there will be a virtual
b946a456 1709;; device number set in `tramp-handle-file-attributes'.
00d6fd04
MA
1710(defconst tramp-perl-file-attributes
1711 "%s -e '
c82c5727 1712@stat = lstat($ARGV[0]);
680db9ac
MA
1713if (!@stat) {
1714 print \"nil\\n\";
1715 exit 0;
1716}
c82c5727
LH
1717if (($stat[2] & 0170000) == 0120000)
1718{
1719 $type = readlink($ARGV[0]);
1720 $type = \"\\\"$type\\\"\";
1721}
1722elsif (($stat[2] & 0170000) == 040000)
1723{
1724 $type = \"t\";
1725}
1726else
1727{
1728 $type = \"nil\"
1729};
1730$uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
1731$gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
1732printf(
d4443a0d 1733 \"(%%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) -1)\\n\",
c82c5727
LH
1734 $type,
1735 $stat[3],
1736 $uid,
1737 $gid,
1738 $stat[8] >> 16 & 0xffff,
1739 $stat[8] & 0xffff,
1740 $stat[9] >> 16 & 0xffff,
1741 $stat[9] & 0xffff,
1742 $stat[10] >> 16 & 0xffff,
1743 $stat[10] & 0xffff,
1744 $stat[7],
1745 $stat[2],
1746 $stat[1] >> 16 & 0xffff,
1747 $stat[1] & 0xffff
00d6fd04 1748);' \"$1\" \"$2\" \"$3\" 2>/dev/null"
fb7933a3 1749 "Perl script to produce output suitable for use with `file-attributes'
00d6fd04
MA
1750on the remote file system.
1751Escape sequence %s is replaced with name of Perl binary.
1752This string is passed to `format', so percent characters need to be doubled.")
fb7933a3 1753
00d6fd04
MA
1754(defconst tramp-perl-directory-files-and-attributes
1755 "%s -e '
8cb0a559
LH
1756chdir($ARGV[0]) or printf(\"\\\"Cannot change to $ARGV[0]: $''!''\\\"\\n\"), exit();
1757opendir(DIR,\".\") or printf(\"\\\"Cannot open directory $ARGV[0]: $''!''\\\"\\n\"), exit();
c82c5727
LH
1758@list = readdir(DIR);
1759closedir(DIR);
1760$n = scalar(@list);
1761printf(\"(\\n\");
1762for($i = 0; $i < $n; $i++)
1763{
1764 $filename = $list[$i];
1765 @stat = lstat($filename);
1766 if (($stat[2] & 0170000) == 0120000)
1767 {
1768 $type = readlink($filename);
1769 $type = \"\\\"$type\\\"\";
1770 }
1771 elsif (($stat[2] & 0170000) == 040000)
1772 {
1773 $type = \"t\";
1774 }
1775 else
1776 {
1777 $type = \"nil\"
1778 };
1779 $uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
1780 $gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
1781 printf(
b946a456 1782 \"(\\\"%%s\\\" %%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) (%%u . %%u))\\n\",
c82c5727
LH
1783 $filename,
1784 $type,
1785 $stat[3],
1786 $uid,
1787 $gid,
1788 $stat[8] >> 16 & 0xffff,
1789 $stat[8] & 0xffff,
1790 $stat[9] >> 16 & 0xffff,
1791 $stat[9] & 0xffff,
1792 $stat[10] >> 16 & 0xffff,
1793 $stat[10] & 0xffff,
1794 $stat[7],
1795 $stat[2],
1796 $stat[1] >> 16 & 0xffff,
1797 $stat[1] & 0xffff,
1798 $stat[0] >> 16 & 0xffff,
1799 $stat[0] & 0xffff);
1800}
00d6fd04 1801printf(\")\\n\");' \"$1\" \"$2\" \"$3\" 2>/dev/null"
c82c5727 1802 "Perl script implementing `directory-files-attributes' as Lisp `read'able
00d6fd04
MA
1803output.
1804Escape sequence %s is replaced with name of Perl binary.
1805This string is passed to `format', so percent characters need to be doubled.")
c82c5727 1806
ac474af1
KG
1807;; ;; These two use uu encoding.
1808;; (defvar tramp-perl-encode "%s -e'\
1809;; print qq(begin 644 xxx\n);
1810;; my $s = q();
1811;; my $res = q();
1812;; while (read(STDIN, $s, 45)) {
1813;; print pack(q(u), $s);
1814;; }
1815;; print qq(`\n);
1816;; print qq(end\n);
1817;; '"
1818;; "Perl program to use for encoding a file.
1819;; Escape sequence %s is replaced with name of Perl binary.")
1820
1821;; (defvar tramp-perl-decode "%s -ne '
1822;; print unpack q(u), $_;
1823;; '"
1824;; "Perl program to use for decoding a file.
1825;; Escape sequence %s is replaced with name of Perl binary.")
1826
1827;; These two use base64 encoding.
00d6fd04
MA
1828(defconst tramp-perl-encode-with-module
1829 "%s -MMIME::Base64 -0777 -ne 'print encode_base64($_)' 2>/dev/null"
ac474af1 1830 "Perl program to use for encoding a file.
b1d06e75 1831Escape sequence %s is replaced with name of Perl binary.
89509ea0 1832This string is passed to `format', so percent characters need to be doubled.
b1d06e75
KG
1833This implementation requires the MIME::Base64 Perl module to be installed
1834on the remote host.")
1835
00d6fd04
MA
1836(defconst tramp-perl-decode-with-module
1837 "%s -MMIME::Base64 -0777 -ne 'print decode_base64($_)' 2>/dev/null"
b1d06e75
KG
1838 "Perl program to use for decoding a file.
1839Escape sequence %s is replaced with name of Perl binary.
89509ea0 1840This string is passed to `format', so percent characters need to be doubled.
b1d06e75
KG
1841This implementation requires the MIME::Base64 Perl module to be installed
1842on the remote host.")
1843
00d6fd04 1844(defconst tramp-perl-encode
b1d06e75
KG
1845 "%s -e '
1846# This script contributed by Juanma Barranquero <lektu@terra.es>.
114f9c96 1847# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
cbd12ed7 1848# Free Software Foundation, Inc.
b1d06e75
KG
1849use strict;
1850
fa32e96a 1851my %%trans = do {
b1d06e75
KG
1852 my $i = 0;
1853 map {(substr(unpack(q(B8), chr $i++), 2, 6), $_)}
1854 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/);
1855};
1856
36541701 1857binmode(\\*STDIN);
b1d06e75
KG
1858
1859# We read in chunks of 54 bytes, to generate output lines
1860# of 72 chars (plus end of line)
36541701 1861$/ = \\54;
b1d06e75
KG
1862
1863while (my $data = <STDIN>) {
1864 my $pad = q();
1865
1866 # Only for the last chunk, and only if did not fill the last three-byte packet
1867 if (eof) {
fa32e96a 1868 my $mod = length($data) %% 3;
b1d06e75
KG
1869 $pad = q(=) x (3 - $mod) if $mod;
1870 }
1871
1872 # Not the fastest method, but it is simple: unpack to binary string, split
1873 # by groups of 6 bits and convert back from binary to byte; then map into
1874 # the translation table
1875 print
1876 join q(),
1877 map($trans{$_},
1878 (substr(unpack(q(B*), $data) . q(00000), 0, 432) =~ /....../g)),
1879 $pad,
36541701 1880 qq(\\n);
00d6fd04 1881}' 2>/dev/null"
b1d06e75 1882 "Perl program to use for encoding a file.
fa32e96a 1883Escape sequence %s is replaced with name of Perl binary.
ccf29586 1884This string is passed to `format', so percent characters need to be doubled.")
ac474af1 1885
00d6fd04 1886(defconst tramp-perl-decode
b1d06e75
KG
1887 "%s -e '
1888# This script contributed by Juanma Barranquero <lektu@terra.es>.
114f9c96 1889# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
cbd12ed7 1890# Free Software Foundation, Inc.
b1d06e75
KG
1891use strict;
1892
fa32e96a 1893my %%trans = do {
b1d06e75 1894 my $i = 0;
16674e4f 1895 map {($_, substr(unpack(q(B8), chr $i++), 2, 6))}
b1d06e75
KG
1896 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/)
1897};
1898
fa32e96a 1899my %%bytes = map {(unpack(q(B8), chr $_), chr $_)} 0 .. 255;
b1d06e75 1900
36541701 1901binmode(\\*STDOUT);
b1d06e75
KG
1902
1903# We are going to accumulate into $pending to accept any line length
1904# (we do not check they are <= 76 chars as the RFC says)
1905my $pending = q();
1906
1907while (my $data = <STDIN>) {
1908 chomp $data;
1909
1910 # If we find one or two =, we have reached the end and
1911 # any following data is to be discarded
1912 my $finished = $data =~ s/(==?).*/$1/;
1913 $pending .= $data;
1914
1915 my $len = length($pending);
16674e4f 1916 my $chunk = substr($pending, 0, $len & ~3);
414da5ab 1917 $pending = substr($pending, $len & ~3 + 1);
b1d06e75
KG
1918
1919 # Easy method: translate from chars to (pregenerated) six-bit packets, join,
1920 # split in 8-bit chunks and convert back to char.
1921 print join q(),
1922 map $bytes{$_},
1923 ((join q(), map {$trans{$_} || q()} split //, $chunk) =~ /......../g);
1924
1925 last if $finished;
00d6fd04 1926}' 2>/dev/null"
ac474af1 1927 "Perl program to use for decoding a file.
fa32e96a 1928Escape sequence %s is replaced with name of Perl binary.
ccf29586 1929This string is passed to `format', so percent characters need to be doubled.")
fb7933a3 1930
946a5aeb
MA
1931(defconst tramp-vc-registered-read-file-names
1932 "echo \"(\"
1933for file in \"$@\"; do
1934 if %s $file; then
1935 echo \"(\\\"$file\\\" \\\"file-exists-p\\\" t)\"
1936 else
1937 echo \"(\\\"$file\\\" \\\"file-exists-p\\\" nil)\"
1938 fi
1939 if %s $file; then
1940 echo \"(\\\"$file\\\" \\\"file-readable-p\\\" t)\"
1941 else
1942 echo \"(\\\"$file\\\" \\\"file-readable-p\\\" nil)\"
1943 fi
1944done
1945echo \")\""
1946 "Script to check existence of VC related files.
1947It must be send formatted with two strings; the tests for file
1948existence, and file readability.")
1949
9ce8462a
MA
1950(defconst tramp-file-mode-type-map
1951 '((0 . "-") ; Normal file (SVID-v2 and XPG2)
1952 (1 . "p") ; fifo
1953 (2 . "c") ; character device
1954 (3 . "m") ; multiplexed character device (v7)
1955 (4 . "d") ; directory
1956 (5 . "?") ; Named special file (XENIX)
1957 (6 . "b") ; block device
1958 (7 . "?") ; multiplexed block device (v7)
1959 (8 . "-") ; regular file
1960 (9 . "n") ; network special file (HP-UX)
1961 (10 . "l") ; symlink
1962 (11 . "?") ; ACL shadow inode (Solaris, not userspace)
1963 (12 . "s") ; socket
1964 (13 . "D") ; door special (Solaris)
1965 (14 . "w")) ; whiteout (BSD)
fb7933a3
KG
1966 "A list of file types returned from the `stat' system call.
1967This is used to map a mode number to a permission string.")
1968
fb7933a3 1969;; New handlers should be added here. The following operations can be
c0fc6170
MA
1970;; handled using the normal primitives: file-name-sans-versions,
1971;; get-file-buffer.
fb7933a3 1972(defconst tramp-file-name-handler-alist
00d6fd04 1973 '((load . tramp-handle-load)
fb7933a3 1974 (make-symbolic-link . tramp-handle-make-symbolic-link)
c0fc6170 1975 (file-name-as-directory . tramp-handle-file-name-as-directory)
fb7933a3
KG
1976 (file-name-directory . tramp-handle-file-name-directory)
1977 (file-name-nondirectory . tramp-handle-file-name-nondirectory)
1978 (file-truename . tramp-handle-file-truename)
1979 (file-exists-p . tramp-handle-file-exists-p)
1980 (file-directory-p . tramp-handle-file-directory-p)
1981 (file-executable-p . tramp-handle-file-executable-p)
fb7933a3
KG
1982 (file-readable-p . tramp-handle-file-readable-p)
1983 (file-regular-p . tramp-handle-file-regular-p)
1984 (file-symlink-p . tramp-handle-file-symlink-p)
1985 (file-writable-p . tramp-handle-file-writable-p)
1986 (file-ownership-preserved-p . tramp-handle-file-ownership-preserved-p)
1987 (file-newer-than-file-p . tramp-handle-file-newer-than-file-p)
1988 (file-attributes . tramp-handle-file-attributes)
1989 (file-modes . tramp-handle-file-modes)
fb7933a3 1990 (directory-files . tramp-handle-directory-files)
c82c5727 1991 (directory-files-and-attributes . tramp-handle-directory-files-and-attributes)
fb7933a3
KG
1992 (file-name-all-completions . tramp-handle-file-name-all-completions)
1993 (file-name-completion . tramp-handle-file-name-completion)
1994 (add-name-to-file . tramp-handle-add-name-to-file)
1995 (copy-file . tramp-handle-copy-file)
263c02ef 1996 (copy-directory . tramp-handle-copy-directory)
fb7933a3
KG
1997 (rename-file . tramp-handle-rename-file)
1998 (set-file-modes . tramp-handle-set-file-modes)
ce3f516f 1999 (set-file-times . tramp-handle-set-file-times)
fb7933a3
KG
2000 (make-directory . tramp-handle-make-directory)
2001 (delete-directory . tramp-handle-delete-directory)
2002 (delete-file . tramp-handle-delete-file)
2003 (directory-file-name . tramp-handle-directory-file-name)
00d6fd04
MA
2004 ;; `executable-find' is not official yet.
2005 (executable-find . tramp-handle-executable-find)
2006 (start-file-process . tramp-handle-start-file-process)
0457dd55 2007 (process-file . tramp-handle-process-file)
00d6fd04 2008 (shell-command . tramp-handle-shell-command)
fb7933a3
KG
2009 (insert-directory . tramp-handle-insert-directory)
2010 (expand-file-name . tramp-handle-expand-file-name)
00d6fd04 2011 (substitute-in-file-name . tramp-handle-substitute-in-file-name)
fb7933a3 2012 (file-local-copy . tramp-handle-file-local-copy)
19a87064 2013 (file-remote-p . tramp-handle-file-remote-p)
fb7933a3 2014 (insert-file-contents . tramp-handle-insert-file-contents)
94be87e8
MA
2015 (insert-file-contents-literally
2016 . tramp-handle-insert-file-contents-literally)
fb7933a3 2017 (write-region . tramp-handle-write-region)
38c65fca 2018 (find-backup-file-name . tramp-handle-find-backup-file-name)
c1105d05 2019 (make-auto-save-file-name . tramp-handle-make-auto-save-file-name)
fb7933a3 2020 (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
5ec2cc41 2021 (dired-compress-file . tramp-handle-dired-compress-file)
fb7933a3
KG
2022 (dired-recursive-delete-directory
2023 . tramp-handle-dired-recursive-delete-directory)
70c11b0b 2024 (dired-uncache . tramp-handle-dired-uncache)
fb7933a3 2025 (set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
49096407
MA
2026 (verify-visited-file-modtime . tramp-handle-verify-visited-file-modtime)
2027 (vc-registered . tramp-handle-vc-registered))
c1105d05 2028 "Alist of handler functions.
fb7933a3
KG
2029Operations not mentioned here will be handled by the normal Emacs functions.")
2030
a4aeb9a4 2031;; Handlers for partial Tramp file names. For Emacs just
41c8e348 2032;; `file-name-all-completions' is needed.
a01b1e22 2033;;;###autoload
16674e4f 2034(defconst tramp-completion-file-name-handler-alist
a01b1e22 2035 '((file-name-all-completions . tramp-completion-handle-file-name-all-completions)
41c8e348 2036 (file-name-completion . tramp-completion-handle-file-name-completion))
16674e4f
KG
2037 "Alist of completion handler functions.
2038Used for file names matching `tramp-file-name-regexp'. Operations not
2039mentioned here will be handled by `tramp-file-name-handler-alist' or the
2040normal Emacs functions.")
2041
4007ba5b 2042;; Handlers for foreign methods, like FTP or SMB, shall be plugged here.
ea9d1443
KG
2043(defvar tramp-foreign-file-name-handler-alist
2044 ;; (identity . tramp-sh-file-name-handler) should always be the last
b88f2d0a 2045 ;; entry, because `identity' always matches.
ea9d1443 2046 '((identity . tramp-sh-file-name-handler))
4007ba5b
KG
2047 "Alist of elements (FUNCTION . HANDLER) for foreign methods handled specially.
2048If (FUNCTION FILENAME) returns non-nil, then all I/O on that file is done by
2049calling HANDLER.")
2050
0664ff72 2051;;; Internal functions which must come first:
fb7933a3 2052
00d6fd04
MA
2053(defsubst tramp-debug-message (vec fmt-string &rest args)
2054 "Append message to debug buffer.
2055Message is formatted with FMT-STRING as control string and the remaining
2056ARGS to actually emit the message (if applicable)."
2057 (when (get-buffer (tramp-buffer-name vec))
2058 (with-current-buffer (tramp-get-debug-buffer vec)
2059 (goto-char (point-max))
70c11b0b
MA
2060 ;; Headline.
2061 (when (bobp)
2062 (insert
2063 (format
2064 ";; %sEmacs: %s Tramp: %s -*- mode: outline; -*-"
2065 (if (featurep 'sxemacs) "SX" (if (featurep 'xemacs) "X" "GNU "))
2066 emacs-version tramp-version)))
00d6fd04
MA
2067 (unless (bolp)
2068 (insert "\n"))
70c11b0b 2069 ;; Timestamp.
736ac90f
MA
2070 (let ((now (current-time)))
2071 (insert (format-time-string "%T." now))
2072 (insert (format "%06d " (nth 2 now))))
70c11b0b 2073 ;; Calling function.
00d6fd04
MA
2074 (let ((btn 1) btf fn)
2075 (while (not fn)
2076 (setq btf (nth 1 (backtrace-frame btn)))
2077 (if (not btf)
2078 (setq fn "")
2079 (when (symbolp btf)
2080 (setq fn (symbol-name btf))
2081 (unless (and (string-match "^tramp" fn)
2082 (not (string-match
2083 "^tramp\\(-debug\\)?\\(-message\\|-error\\)$"
2084 fn)))
2085 (setq fn nil)))
2086 (setq btn (1+ btn))))
2087 ;; The following code inserts filename and line number.
2088 ;; Should be deactivated by default, because it is time
2089 ;; consuming.
2090; (let ((ffn (find-function-noselect (intern fn))))
2091; (insert
2092; (format
2093; "%s:%d: "
2094; (file-name-nondirectory (buffer-file-name (car ffn)))
2095; (with-current-buffer (car ffn)
2096; (1+ (count-lines (point-min) (cdr ffn)))))))
2097 (insert (format "%s " fn)))
70c11b0b 2098 ;; The message.
00d6fd04
MA
2099 (insert (apply 'format fmt-string args)))))
2100
946a5aeb
MA
2101(defvar tramp-message-show-message t
2102 "Show Tramp message in the minibuffer.
2103This variable is used to disable messages from `tramp-error'.
2104The messages are visible anyway, because an error is raised.")
2105
00d6fd04 2106(defsubst tramp-message (vec-or-proc level fmt-string &rest args)
fb7933a3 2107 "Emit a message depending on verbosity level.
a4aeb9a4 2108VEC-OR-PROC identifies the Tramp buffer to use. It can be either a
00d6fd04
MA
2109vector or a process. LEVEL says to be quiet if `tramp-verbose' is
2110less than LEVEL. The message is emitted only if `tramp-verbose' is
2111greater than or equal to LEVEL.
2112
2113The message is also logged into the debug buffer when `tramp-verbose'
2114is greater than or equal 4.
2115
2116Calls functions `message' and `tramp-debug-message' with FMT-STRING as
2117control string and the remaining ARGS to actually emit the message (if
2118applicable)."
2119 (condition-case nil
2120 (when (<= level tramp-verbose)
2121 ;; Match data must be preserved!
2122 (save-match-data
2123 ;; Display only when there is a minimum level.
946a5aeb 2124 (when (and tramp-message-show-message (<= level 3))
00d6fd04
MA
2125 (apply 'message
2126 (concat
2127 (cond
2128 ((= level 0) "")
2129 ((= level 1) "")
2130 ((= level 2) "Warning: ")
2131 (t "Tramp: "))
2132 fmt-string)
2133 args))
2134 ;; Log only when there is a minimum level.
2135 (when (>= tramp-verbose 4)
2136 (when (and vec-or-proc
2137 (processp vec-or-proc)
2138 (buffer-name (process-buffer vec-or-proc)))
2139 (with-current-buffer (process-buffer vec-or-proc)
2140 ;; Translate proc to vec.
2141 (setq vec-or-proc (tramp-dissect-file-name default-directory))))
2142 (when (and vec-or-proc (vectorp vec-or-proc))
2143 (apply 'tramp-debug-message
2144 vec-or-proc
2145 (concat (format "(%d) # " level) fmt-string)
2146 args)))))
2147 ;; Suppress all errors.
2148 (error nil)))
2149
2150(defsubst tramp-error (vec-or-proc signal fmt-string &rest args)
2151 "Emit an error.
2152VEC-OR-PROC identifies the connection to use, SIGNAL is the
2153signal identifier to be raised, remaining args passed to
2154`tramp-message'. Finally, signal SIGNAL is raised."
946a5aeb
MA
2155 (let (tramp-message-show-message)
2156 (tramp-message
2157 vec-or-proc 1 "%s"
2158 (error-message-string
2159 (list signal
2160 (get signal 'error-message)
2161 (apply 'format fmt-string args))))
2162 (signal signal (list (apply 'format fmt-string args)))))
00d6fd04
MA
2163
2164(defsubst tramp-error-with-buffer
2165 (buffer vec-or-proc signal fmt-string &rest args)
2166 "Emit an error, and show BUFFER.
2167If BUFFER is nil, show the connection buffer. Wait for 30\", or until
2168an input event arrives. The other arguments are passed to `tramp-error'."
2169 (save-window-excursion
2170 (unwind-protect
2171 (apply 'tramp-error vec-or-proc signal fmt-string args)
2172 (when (and vec-or-proc (not (zerop tramp-verbose)))
2173 (let ((enable-recursive-minibuffers t))
2174 (pop-to-buffer
2175 (or (and (bufferp buffer) buffer)
2176 (and (processp vec-or-proc) (process-buffer vec-or-proc))
2177 (tramp-get-buffer vec-or-proc)))
2178 (sit-for 30))))))
fb7933a3 2179
c62c9d08
KG
2180(defmacro with-parsed-tramp-file-name (filename var &rest body)
2181 "Parse a Tramp filename and make components available in the body.
2182
2183First arg FILENAME is evaluated and dissected into its components.
2184Second arg VAR is a symbol. It is used as a variable name to hold
2185the filename structure. It is also used as a prefix for the variables
2186holding the components. For example, if VAR is the symbol `foo', then
00d6fd04
MA
2187`foo' will be bound to the whole structure, `foo-method' will be bound to
2188the method component, and so on for `foo-user', `foo-host', `foo-localname'.
c62c9d08
KG
2189
2190Remaining args are Lisp expressions to be evaluated (inside an implicit
2191`progn').
2192
00d6fd04
MA
2193If VAR is nil, then we bind `v' to the structure and `method', `user',
2194`host', `localname' to the components."
c62c9d08 2195 `(let* ((,(or var 'v) (tramp-dissect-file-name ,filename))
c62c9d08
KG
2196 (,(if var (intern (concat (symbol-name var) "-method")) 'method)
2197 (tramp-file-name-method ,(or var 'v)))
2198 (,(if var (intern (concat (symbol-name var) "-user")) 'user)
2199 (tramp-file-name-user ,(or var 'v)))
2200 (,(if var (intern (concat (symbol-name var) "-host")) 'host)
2201 (tramp-file-name-host ,(or var 'v)))
7432277c
KG
2202 (,(if var (intern (concat (symbol-name var) "-localname")) 'localname)
2203 (tramp-file-name-localname ,(or var 'v))))
c62c9d08
KG
2204 ,@body))
2205
2206(put 'with-parsed-tramp-file-name 'lisp-indent-function 2)
00d6fd04 2207(put 'with-parsed-tramp-file-name 'edebug-form-spec '(form symbolp body))
9e6ab520 2208(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-parsed-tramp-file-name\\>"))
c62c9d08 2209
00d6fd04
MA
2210(defmacro with-file-property (vec file property &rest body)
2211 "Check in Tramp cache for PROPERTY, otherwise execute BODY and set cache.
2212FILE must be a local file name on a connection identified via VEC."
2213 `(if (file-name-absolute-p ,file)
2214 (let ((value (tramp-get-file-property ,vec ,file ,property 'undef)))
2215 (when (eq value 'undef)
2216 ;; We cannot pass @body as parameter to
2217 ;; `tramp-set-file-property' because it mangles our
2218 ;; debug messages.
2219 (setq value (progn ,@body))
2220 (tramp-set-file-property ,vec ,file ,property value))
2221 value)
2222 ,@body))
9ce8462a 2223
00d6fd04
MA
2224(put 'with-file-property 'lisp-indent-function 3)
2225(put 'with-file-property 'edebug-form-spec t)
9e6ab520 2226(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-file-property\\>"))
00d6fd04
MA
2227
2228(defmacro with-connection-property (key property &rest body)
2229 "Checks in Tramp for property PROPERTY, otherwise executes BODY and set."
2230 `(let ((value (tramp-get-connection-property ,key ,property 'undef)))
2231 (when (eq value 'undef)
2232 ;; We cannot pass ,@body as parameter to
2233 ;; `tramp-set-connection-property' because it mangles our debug
2234 ;; messages.
2235 (setq value (progn ,@body))
2236 (tramp-set-connection-property ,key ,property value))
2237 value))
9ce8462a 2238
00d6fd04
MA
2239(put 'with-connection-property 'lisp-indent-function 2)
2240(put 'with-connection-property 'edebug-form-spec t)
9e6ab520 2241(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-connection-property\\>"))
00d6fd04 2242
628c97b2
GM
2243(eval-and-compile ; silence compiler
2244 (if (memq system-type '(cygwin windows-nt))
2245 (defun tramp-drop-volume-letter (name)
2246 "Cut off unnecessary drive letter from file NAME.
2247The function `tramp-handle-expand-file-name' calls `expand-file-name'
2248locally on a remote file name. When the local system is a W32 system
2249but the remote system is Unix, this introduces a superfluous drive
2250letter into the file name. This function removes it."
2251 (save-match-data
2252 (if (string-match tramp-root-regexp name)
2253 (replace-match "/" nil t name)
2254 name)))
2255
2256 (defalias 'tramp-drop-volume-letter 'identity)))
2257
9c13938d 2258(defsubst tramp-make-tramp-temp-file (vec)
a6e96327 2259 "Create a temporary file on the remote host identified by VEC.
9c13938d
MA
2260Return the local name of the temporary file."
2261 (let ((prefix
2262 (tramp-make-tramp-file-name
2263 (tramp-file-name-method vec)
2264 (tramp-file-name-user vec)
2265 (tramp-file-name-host vec)
113e2a84
MA
2266 (tramp-drop-volume-letter
2267 (expand-file-name
2268 tramp-temp-name-prefix (tramp-get-remote-tmpdir vec)))))
9c13938d
MA
2269 result)
2270 (while (not result)
2271 ;; `make-temp-file' would be the natural choice for
2272 ;; implementation. But it calls `write-region' internally,
2273 ;; which also needs a temporary file - we would end in an
2274 ;; infinite loop.
2275 (setq result (make-temp-name prefix))
2276 (if (file-exists-p result)
2277 (setq result nil)
2278 ;; This creates the file by side effect.
2279 (set-file-times result)
2280 (set-file-modes result (tramp-octal-to-decimal "0700"))))
2281
2282 ;; Return the local part.
2283 (with-parsed-tramp-file-name result nil localname)))
8a4438b6
MA
2284
2285
16674e4f
KG
2286;;; Config Manipulation Functions:
2287
2288(defun tramp-set-completion-function (method function-list)
2289 "Sets the list of completion functions for METHOD.
2290FUNCTION-LIST is a list of entries of the form (FUNCTION FILE).
2291The FUNCTION is intended to parse FILE according its syntax.
2292It might be a predefined FUNCTION, or a user defined FUNCTION.
2293Predefined FUNCTIONs are `tramp-parse-rhosts', `tramp-parse-shosts',
8fc29035 2294`tramp-parse-sconfig', `tramp-parse-hosts', `tramp-parse-passwd',
8daea7fc
KG
2295and `tramp-parse-netrc'.
2296
16674e4f
KG
2297Example:
2298
2299 (tramp-set-completion-function
2300 \"ssh\"
8daea7fc
KG
2301 '((tramp-parse-sconfig \"/etc/ssh_config\")
2302 (tramp-parse-sconfig \"~/.ssh/config\")))"
16674e4f 2303
5ec2cc41
KG
2304 (let ((r function-list)
2305 (v function-list))
2306 (setq tramp-completion-function-alist
2307 (delete (assoc method tramp-completion-function-alist)
2308 tramp-completion-function-alist))
2309
2310 (while v
00d6fd04 2311 ;; Remove double entries.
5ec2cc41
KG
2312 (when (member (car v) (cdr v))
2313 (setcdr v (delete (car v) (cdr v))))
00d6fd04 2314 ;; Check for function and file or registry key.
5ec2cc41 2315 (unless (and (functionp (nth 0 (car v)))
00d6fd04
MA
2316 (if (string-match "^HKEY_CURRENT_USER" (nth 1 (car v)))
2317 ;; Windows registry.
2318 (and (memq system-type '(cygwin windows-nt))
a4aeb9a4
MA
2319 (zerop
2320 (tramp-local-call-process
2321 "reg" nil nil nil "query" (nth 1 (car v)))))
00d6fd04
MA
2322 ;; Configuration file.
2323 (file-exists-p (nth 1 (car v)))))
5ec2cc41
KG
2324 (setq r (delete (car v) r)))
2325 (setq v (cdr v)))
2326
2327 (when r
4007ba5b 2328 (add-to-list 'tramp-completion-function-alist
5ec2cc41 2329 (cons method r)))))
16674e4f
KG
2330
2331(defun tramp-get-completion-function (method)
00d6fd04 2332 "Returns a list of completion functions for METHOD.
16674e4f 2333For definition of that list see `tramp-set-completion-function'."
00d6fd04
MA
2334 (cons
2335 ;; Hosts visited once shall be remembered.
2336 `(tramp-parse-connection-properties ,method)
2337 ;; The method related defaults.
2338 (cdr (assoc method tramp-completion-function-alist))))
16674e4f 2339
d037d501 2340
0664ff72 2341;;; Fontification of `read-file-name':
d037d501 2342
0664ff72 2343;; rfn-eshadow.el is part of Emacs 22. It is autoloaded.
d037d501
MA
2344(defvar tramp-rfn-eshadow-overlay)
2345(make-variable-buffer-local 'tramp-rfn-eshadow-overlay)
2346
2347(defun tramp-rfn-eshadow-setup-minibuffer ()
2348 "Set up a minibuffer for `file-name-shadow-mode'.
2349Adds another overlay hiding filename parts according to Tramp's
2350special handling of `substitute-in-file-name'."
9ce8462a 2351 (when (symbol-value 'minibuffer-completing-file-name)
d037d501 2352 (setq tramp-rfn-eshadow-overlay
9e6ab520
MA
2353 (funcall (symbol-function 'make-overlay)
2354 (funcall (symbol-function 'minibuffer-prompt-end))
2355 (funcall (symbol-function 'minibuffer-prompt-end))))
d037d501 2356 ;; Copy rfn-eshadow-overlay properties.
9e6ab520
MA
2357 (let ((props (funcall (symbol-function 'overlay-properties)
2358 (symbol-value 'rfn-eshadow-overlay))))
d037d501 2359 (while props
9e6ab520
MA
2360 (funcall (symbol-function 'overlay-put)
2361 tramp-rfn-eshadow-overlay (pop props) (pop props))))))
d037d501
MA
2362
2363(when (boundp 'rfn-eshadow-setup-minibuffer-hook)
2364 (add-hook 'rfn-eshadow-setup-minibuffer-hook
48846dc5
MA
2365 'tramp-rfn-eshadow-setup-minibuffer)
2366 (add-hook 'tramp-unload-hook
aa485f7c
MA
2367 (lambda ()
2368 (remove-hook 'rfn-eshadow-setup-minibuffer-hook
2369 'tramp-rfn-eshadow-setup-minibuffer))))
d037d501 2370
adcbca53
MA
2371(defconst tramp-rfn-eshadow-update-overlay-regexp
2372 (format "[^%s/~]*\\(/\\|~\\)" tramp-postfix-host-format))
2373
d037d501
MA
2374(defun tramp-rfn-eshadow-update-overlay ()
2375 "Update `rfn-eshadow-overlay' to cover shadowed part of minibuffer input.
2376This is intended to be used as a minibuffer `post-command-hook' for
2377`file-name-shadow-mode'; the minibuffer should have already
2378been set up by `rfn-eshadow-setup-minibuffer'."
2379 ;; In remote files name, there is a shadowing just for the local part.
9e6ab520
MA
2380 (let ((end (or (funcall (symbol-function 'overlay-end)
2381 (symbol-value 'rfn-eshadow-overlay))
2382 (funcall (symbol-function 'minibuffer-prompt-end)))))
2383 (when (file-remote-p (buffer-substring-no-properties end (point-max)))
bd316474
KY
2384 (save-excursion
2385 (save-restriction
2386 (narrow-to-region
adcbca53
MA
2387 (1+ (or (string-match
2388 tramp-rfn-eshadow-update-overlay-regexp (buffer-string) end)
2389 end))
2390 (point-max))
bd316474
KY
2391 (let ((rfn-eshadow-overlay tramp-rfn-eshadow-overlay)
2392 (rfn-eshadow-update-overlay-hook nil))
dea31ca6 2393 (move-overlay rfn-eshadow-overlay (point-max) (point-max))
bd316474 2394 (funcall (symbol-function 'rfn-eshadow-update-overlay))))))))
d037d501
MA
2395
2396(when (boundp 'rfn-eshadow-update-overlay-hook)
2397 (add-hook 'rfn-eshadow-update-overlay-hook
b88f2d0a
MA
2398 'tramp-rfn-eshadow-update-overlay)
2399 (add-hook 'tramp-unload-hook
2400 (lambda ()
2401 (remove-hook 'rfn-eshadow-update-overlay-hook
2402 'tramp-rfn-eshadow-update-overlay))))
d037d501
MA
2403
2404
605a20a9
MA
2405;;; Integration of eshell.el:
2406
2407(eval-when-compile
2408 (defvar eshell-path-env))
2409
2410;; eshell.el keeps the path in `eshell-path-env'. We must change it
2411;; when `default-directory' points to another host.
2412(defun tramp-eshell-directory-change ()
2413 "Set `eshell-path-env' to $PATH of the host related to `default-directory'."
2414 (setq eshell-path-env
2415 (if (file-remote-p default-directory)
2416 (with-parsed-tramp-file-name default-directory nil
2417 (mapconcat
2418 'identity
2419 (tramp-get-remote-path v)
2420 ":"))
2421 (getenv "PATH"))))
2422
2423(eval-after-load "esh-util"
2424 '(progn
2425 (tramp-eshell-directory-change)
2426 (add-hook 'eshell-directory-change-hook
2427 'tramp-eshell-directory-change)
2428 (add-hook 'tramp-unload-hook
2429 (lambda ()
2430 (remove-hook 'eshell-directory-change-hook
2431 'tramp-eshell-directory-change)))))
2432
2433
fb7933a3
KG
2434;;; File Name Handler Functions:
2435
fb7933a3
KG
2436(defun tramp-handle-make-symbolic-link
2437 (filename linkname &optional ok-if-already-exists)
00d6fd04 2438 "Like `make-symbolic-link' for Tramp files.
cebb4ec6 2439If LINKNAME is a non-Tramp file, it is used verbatim as the target of
7432277c 2440the symlink. If LINKNAME is a Tramp file, only the localname component is
cebb4ec6
KG
2441used as the target of the symlink.
2442
7432277c
KG
2443If LINKNAME is a Tramp file and the localname component is relative, then
2444it is expanded first, before the localname component is taken. Note that
cebb4ec6
KG
2445this can give surprising results if the user/host for the source and
2446target of the symlink differ."
c62c9d08 2447 (with-parsed-tramp-file-name linkname l
00d6fd04 2448 (let ((ln (tramp-get-remote-ln l))
87bdd2c7
MA
2449 (cwd (tramp-run-real-handler
2450 'file-name-directory (list l-localname))))
c62c9d08 2451 (unless ln
00d6fd04
MA
2452 (tramp-error
2453 l 'file-error
2454 "Making a symbolic link. ln(1) does not exist on the remote host."))
c62c9d08
KG
2455
2456 ;; Do the 'confirm if exists' thing.
cebb4ec6 2457 (when (file-exists-p linkname)
c62c9d08
KG
2458 ;; What to do?
2459 (if (or (null ok-if-already-exists) ; not allowed to exist
2460 (and (numberp ok-if-already-exists)
2461 (not (yes-or-no-p
2462 (format
2463 "File %s already exists; make it a link anyway? "
7432277c 2464 l-localname)))))
00d6fd04
MA
2465 (tramp-error
2466 l 'file-already-exists "File %s already exists" l-localname)
cebb4ec6
KG
2467 (delete-file linkname)))
2468
7432277c 2469 ;; If FILENAME is a Tramp name, use just the localname component.
cebb4ec6 2470 (when (tramp-tramp-file-p filename)
1834b39f
MA
2471 (setq filename
2472 (tramp-file-name-localname
2473 (tramp-dissect-file-name (expand-file-name filename)))))
bf247b6e 2474
c62c9d08
KG
2475 ;; Right, they are on the same host, regardless of user, method, etc.
2476 ;; We now make the link on the remote machine. This will occur as the user
2477 ;; that FILENAME belongs to.
2478 (zerop
2479 (tramp-send-command-and-check
b593f105
MA
2480 l
2481 (format
2482 "cd %s && %s -sf %s %s"
2483 (tramp-shell-quote-argument cwd)
2484 ln
2485 (tramp-shell-quote-argument filename)
2486 (tramp-shell-quote-argument l-localname))
2487 t)))))
fb7933a3 2488
fb7933a3 2489(defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix)
00d6fd04
MA
2490 "Like `load' for Tramp files."
2491 (with-parsed-tramp-file-name (expand-file-name file) nil
c62c9d08
KG
2492 (unless nosuffix
2493 (cond ((file-exists-p (concat file ".elc"))
2494 (setq file (concat file ".elc")))
2495 ((file-exists-p (concat file ".el"))
2496 (setq file (concat file ".el")))))
2497 (when must-suffix
2498 ;; The first condition is always true for absolute file names.
2499 ;; Included for safety's sake.
2500 (unless (or (file-name-directory file)
2501 (string-match "\\.elc?\\'" file))
00d6fd04
MA
2502 (tramp-error
2503 v 'file-error
2504 "File `%s' does not include a `.el' or `.elc' suffix" file)))
c62c9d08
KG
2505 (unless noerror
2506 (when (not (file-exists-p file))
00d6fd04 2507 (tramp-error v 'file-error "Cannot load nonexistent file `%s'" file)))
c62c9d08
KG
2508 (if (not (file-exists-p file))
2509 nil
00d6fd04 2510 (unless nomessage (tramp-message v 0 "Loading %s..." file))
c62c9d08
KG
2511 (let ((local-copy (file-local-copy file)))
2512 ;; MUST-SUFFIX doesn't exist on XEmacs, so let it default to nil.
ce2cc728
MA
2513 (unwind-protect
2514 (load local-copy noerror t t)
2515 (delete-file local-copy)))
00d6fd04 2516 (unless nomessage (tramp-message v 0 "Loading %s...done" file))
c62c9d08 2517 t)))
fb7933a3 2518
a4aeb9a4 2519;; Localname manipulation functions that grok Tramp localnames...
c0fc6170
MA
2520(defun tramp-handle-file-name-as-directory (file)
2521 "Like `file-name-as-directory' but aware of Tramp files."
2522 ;; `file-name-as-directory' would be sufficient except localname is
2523 ;; the empty string.
2524 (let ((v (tramp-dissect-file-name file t)))
2525 ;; Run the command on the localname portion only.
2526 (tramp-make-tramp-file-name
2527 (tramp-file-name-method v)
2528 (tramp-file-name-user v)
2529 (tramp-file-name-host v)
2530 (tramp-run-real-handler
2531 'file-name-as-directory (list (or (tramp-file-name-localname v) ""))))))
2532
fb7933a3 2533(defun tramp-handle-file-name-directory (file)
00d6fd04 2534 "Like `file-name-directory' but aware of Tramp files."
9ce8462a
MA
2535 ;; Everything except the last filename thing is the directory. We
2536 ;; cannot apply `with-parsed-tramp-file-name', because this expands
2537 ;; the remote file name parts. This is a problem when we are in
2538 ;; file name completion.
2539 (let ((v (tramp-dissect-file-name file t)))
a01b1e22
MA
2540 ;; Run the command on the localname portion only.
2541 (tramp-make-tramp-file-name
9ce8462a
MA
2542 (tramp-file-name-method v)
2543 (tramp-file-name-user v)
2544 (tramp-file-name-host v)
87bdd2c7
MA
2545 (tramp-run-real-handler
2546 'file-name-directory (list (or (tramp-file-name-localname v) ""))))))
fb7933a3
KG
2547
2548(defun tramp-handle-file-name-nondirectory (file)
00d6fd04 2549 "Like `file-name-nondirectory' but aware of Tramp files."
c62c9d08 2550 (with-parsed-tramp-file-name file nil
87bdd2c7 2551 (tramp-run-real-handler 'file-name-nondirectory (list localname))))
fb7933a3
KG
2552
2553(defun tramp-handle-file-truename (filename &optional counter prev-dirs)
00d6fd04 2554 "Like `file-truename' for Tramp files."
48ddd622 2555 (with-parsed-tramp-file-name (expand-file-name filename) nil
00d6fd04 2556 (with-file-property v localname "file-truename"
293c24f9 2557 (let ((result nil)) ; result steps in reverse order
00d6fd04 2558 (tramp-message v 4 "Finding true name for `%s'" filename)
293c24f9
MA
2559 (cond
2560 ;; Use GNU readlink --canonicalize-missing where available.
2561 ((tramp-get-remote-readlink v)
2562 (setq result
2563 (tramp-send-command-and-read
2564 v
2565 (format "echo \"\\\"`%s --canonicalize-missing %s`\\\"\""
2566 (tramp-get-remote-readlink v)
2567 (tramp-shell-quote-argument localname)))))
2568
2569 ;; Use Perl implementation.
2570 ((and (tramp-get-remote-perl v)
2571 (tramp-get-connection-property v "perl-file-spec" nil)
2572 (tramp-get-connection-property v "perl-cwd-realpath" nil))
2573 (tramp-maybe-send-script
2574 v tramp-perl-file-truename "tramp_perl_file_truename")
2575 (setq result
2576 (tramp-send-command-and-read
2577 v
2578 (format "tramp_perl_file_truename %s"
2579 (tramp-shell-quote-argument localname)))))
2580
2581 ;; Do it yourself. We bind `directory-sep-char' here for
2582 ;; XEmacs on Windows, which would otherwise use backslash.
2583 (t (let* ((directory-sep-char ?/)
2584 (steps (tramp-compat-split-string localname "/"))
2585 (localnamedir (tramp-run-real-handler
2586 'file-name-as-directory (list localname)))
2587 (is-dir (string= localname localnamedir))
2588 (thisstep nil)
2589 (numchase 0)
2590 ;; Don't make the following value larger than
2591 ;; necessary. People expect an error message in a
2592 ;; timely fashion when something is wrong;
2593 ;; otherwise they might think that Emacs is hung.
2594 ;; Of course, correctness has to come first.
2595 (numchase-limit 20)
2596 symlink-target)
2597 (while (and steps (< numchase numchase-limit))
2598 (setq thisstep (pop steps))
2599 (tramp-message
2600 v 5 "Check %s"
2601 (mapconcat 'identity
2602 (append '("") (reverse result) (list thisstep))
2603 "/"))
2604 (setq symlink-target
2605 (nth 0 (file-attributes
2606 (tramp-make-tramp-file-name
2607 method user host
2608 (mapconcat 'identity
2609 (append '("")
2610 (reverse result)
2611 (list thisstep))
2612 "/")))))
2613 (cond ((string= "." thisstep)
2614 (tramp-message v 5 "Ignoring step `.'"))
2615 ((string= ".." thisstep)
2616 (tramp-message v 5 "Processing step `..'")
2617 (pop result))
2618 ((stringp symlink-target)
2619 ;; It's a symlink, follow it.
2620 (tramp-message v 5 "Follow symlink to %s" symlink-target)
2621 (setq numchase (1+ numchase))
2622 (when (file-name-absolute-p symlink-target)
2623 (setq result nil))
2624 ;; If the symlink was absolute, we'll get a string like
2625 ;; "/user@host:/some/target"; extract the
2626 ;; "/some/target" part from it.
2627 (when (tramp-tramp-file-p symlink-target)
2628 (unless (tramp-equal-remote filename symlink-target)
2629 (tramp-error
2630 v 'file-error
2631 "Symlink target `%s' on wrong host" symlink-target))
2632 (setq symlink-target localname))
2633 (setq steps
2634 (append (tramp-compat-split-string
2635 symlink-target "/")
2636 steps)))
2637 (t
2638 ;; It's a file.
2639 (setq result (cons thisstep result)))))
2640 (when (>= numchase numchase-limit)
2641 (tramp-error
2642 v 'file-error
2643 "Maximum number (%d) of symlinks exceeded" numchase-limit))
2644 (setq result (reverse result))
2645 ;; Combine list to form string.
2646 (setq result
2647 (if result
2648 (mapconcat 'identity (cons "" result) "/")
00d6fd04 2649 "/"))
293c24f9
MA
2650 (when (and is-dir (or (string= "" result)
2651 (not (string= (substring result -1) "/"))))
2652 (setq result (concat result "/"))))))
2653
2654 (tramp-message v 4 "True name of `%s' is `%s'" filename result)
2655 (tramp-make-tramp-file-name method user host result)))))
fb7933a3
KG
2656
2657;; Basic functions.
2658
2659(defun tramp-handle-file-exists-p (filename)
00d6fd04 2660 "Like `file-exists-p' for Tramp files."
c62c9d08 2661 (with-parsed-tramp-file-name filename nil
00d6fd04 2662 (with-file-property v localname "file-exists-p"
293c24f9
MA
2663 (or (not (null (tramp-get-file-property
2664 v localname "file-attributes-integer" nil)))
2665 (not (null (tramp-get-file-property
2666 v localname "file-attributes-string" nil)))
2667 (zerop (tramp-send-command-and-check
2668 v
2669 (format
2670 "%s %s"
2671 (tramp-get-file-exists-command v)
2672 (tramp-shell-quote-argument localname))))))))
fb7933a3 2673
00d6fd04
MA
2674;; Inodes don't exist for some file systems. Therefore we must
2675;; generate virtual ones. Used in `find-buffer-visiting'. The method
2676;; applied might be not so efficient (Ange-FTP uses hashes). But
2677;; performance isn't the major issue given that file transfer will
2678;; take time.
2679(defvar tramp-inodes nil
2680 "Keeps virtual inodes numbers.")
2681
8daea7fc
KG
2682;; Devices must distinguish physical file systems. The device numbers
2683;; provided by "lstat" aren't unique, because we operate on different hosts.
2684;; So we use virtual device numbers, generated by Tramp. Both Ange-FTP and
2685;; EFS use device number "-1". In order to be different, we use device number
b946a456 2686;; (-1 . x), whereby "x" is unique for a given (method user host).
8daea7fc
KG
2687(defvar tramp-devices nil
2688 "Keeps virtual device numbers.")
2689
fb7933a3
KG
2690;; CCC: This should check for an error condition and signal failure
2691;; when something goes wrong.
2692;; Daniel Pittman <daniel@danann.net>
c951aecb 2693(defun tramp-handle-file-attributes (filename &optional id-format)
00d6fd04
MA
2694 "Like `file-attributes' for Tramp files."
2695 (unless id-format (setq id-format 'integer))
aa485f7c
MA
2696 ;; Don't modify `last-coding-system-used' by accident.
2697 (let ((last-coding-system-used last-coding-system-used))
2698 (with-parsed-tramp-file-name (expand-file-name filename) nil
2699 (with-file-property v localname (format "file-attributes-%s" id-format)
7f49fe46
MA
2700 (save-excursion
2701 (tramp-convert-file-attributes
2702 v
2703 (cond
2704 ((tramp-get-remote-stat v)
2705 (tramp-do-file-attributes-with-stat v localname id-format))
2706 ((tramp-get-remote-perl v)
2707 (tramp-do-file-attributes-with-perl v localname id-format))
2708 (t
2709 (tramp-do-file-attributes-with-ls v localname id-format)))))))))
2710
2711(defun tramp-do-file-attributes-with-ls (vec localname &optional id-format)
00d6fd04 2712 "Implement `file-attributes' for Tramp files using the ls(1) command."
fb7933a3
KG
2713 (let (symlinkp dirp
2714 res-inode res-filemodes res-numlinks
2715 res-uid res-gid res-size res-symlink-target)
00d6fd04 2716 (tramp-message vec 5 "file attributes with ls: %s" localname)
fb7933a3 2717 (tramp-send-command
00d6fd04 2718 vec
680db9ac
MA
2719 (format "(%s %s || %s -h %s) && %s %s %s"
2720 (tramp-get-file-exists-command vec)
2721 (tramp-shell-quote-argument localname)
2722 (tramp-get-test-command vec)
2723 (tramp-shell-quote-argument localname)
00d6fd04 2724 (tramp-get-ls-command vec)
c82c5727 2725 (if (eq id-format 'integer) "-ildn" "-ild")
7432277c 2726 (tramp-shell-quote-argument localname)))
fb7933a3 2727 ;; parse `ls -l' output ...
00d6fd04 2728 (with-current-buffer (tramp-get-buffer vec)
680db9ac
MA
2729 (when (> (buffer-size) 0)
2730 (goto-char (point-min))
2731 ;; ... inode
2732 (setq res-inode
2733 (condition-case err
2734 (read (current-buffer))
2735 (invalid-read-syntax
2736 (when (and (equal (cadr err)
2737 "Integer constant overflow in reader")
2738 (string-match
2739 "^[0-9]+\\([0-9][0-9][0-9][0-9][0-9]\\)\\'"
2740 (car (cddr err))))
2741 (let* ((big (read (substring (car (cddr err)) 0
2742 (match-beginning 1))))
2743 (small (read (match-string 1 (car (cddr err)))))
2744 (twiddle (/ small 65536)))
2745 (cons (+ big twiddle)
2746 (- small (* twiddle 65536))))))))
2747 ;; ... file mode flags
2748 (setq res-filemodes (symbol-name (read (current-buffer))))
2749 ;; ... number links
2750 (setq res-numlinks (read (current-buffer)))
2751 ;; ... uid and gid
2752 (setq res-uid (read (current-buffer)))
2753 (setq res-gid (read (current-buffer)))
2754 (if (eq id-format 'integer)
2755 (progn
2756 (unless (numberp res-uid) (setq res-uid -1))
2757 (unless (numberp res-gid) (setq res-gid -1)))
2758 (progn
2759 (unless (stringp res-uid) (setq res-uid (symbol-name res-uid)))
2760 (unless (stringp res-gid) (setq res-gid (symbol-name res-gid)))))
2761 ;; ... size
2762 (setq res-size (read (current-buffer)))
2763 ;; From the file modes, figure out other stuff.
2764 (setq symlinkp (eq ?l (aref res-filemodes 0)))
2765 (setq dirp (eq ?d (aref res-filemodes 0)))
2766 ;; if symlink, find out file name pointed to
2767 (when symlinkp
2768 (search-forward "-> ")
2769 (setq res-symlink-target
2770 (buffer-substring (point) (tramp-compat-line-end-position))))
2771 ;; return data gathered
2772 (list
2773 ;; 0. t for directory, string (name linked to) for symbolic
2774 ;; link, or nil.
2775 (or dirp res-symlink-target)
2776 ;; 1. Number of links to file.
2777 res-numlinks
2778 ;; 2. File uid.
2779 res-uid
2780 ;; 3. File gid.
2781 res-gid
2782 ;; 4. Last access time, as a list of two integers. First
2783 ;; integer has high-order 16 bits of time, second has low 16
2784 ;; bits.
2785 ;; 5. Last modification time, likewise.
2786 ;; 6. Last status change time, likewise.
2787 '(0 0) '(0 0) '(0 0) ;CCC how to find out?
2788 ;; 7. Size in bytes (-1, if number is out of range).
2789 res-size
2790 ;; 8. File modes, as a string of ten letters or dashes as in ls -l.
2791 res-filemodes
2792 ;; 9. t if file's gid would change if file were deleted and
2793 ;; recreated. Will be set in `tramp-convert-file-attributes'
2794 t
2795 ;; 10. inode number.
2796 res-inode
2797 ;; 11. Device number. Will be replaced by a virtual device number.
2798 -1
2799 )))))
fb7933a3 2800
7f49fe46 2801(defun tramp-do-file-attributes-with-perl
00d6fd04
MA
2802 (vec localname &optional id-format)
2803 "Implement `file-attributes' for Tramp files using a Perl script."
2804 (tramp-message vec 5 "file attributes with perl: %s" localname)
2805 (tramp-maybe-send-script
2806 vec tramp-perl-file-attributes "tramp_perl_file_attributes")
2807 (tramp-send-command-and-read
2808 vec
2809 (format "tramp_perl_file_attributes %s %s"
2810 (tramp-shell-quote-argument localname) id-format)))
2811
7f49fe46 2812(defun tramp-do-file-attributes-with-stat
00d6fd04
MA
2813 (vec localname &optional id-format)
2814 "Implement `file-attributes' for Tramp files using stat(1) command."
2815 (tramp-message vec 5 "file attributes with stat: %s" localname)
2816 (tramp-send-command-and-read
2817 vec
2818 (format
680db9ac
MA
2819 "((%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)"
2820 (tramp-get-file-exists-command vec)
2821 (tramp-shell-quote-argument localname)
2822 (tramp-get-test-command vec)
2823 (tramp-shell-quote-argument localname)
00d6fd04
MA
2824 (tramp-get-remote-stat vec)
2825 (if (eq id-format 'integer) "%u" "\"%U\"")
2826 (if (eq id-format 'integer) "%g" "\"%G\"")
2827 (tramp-shell-quote-argument localname))))
8daea7fc 2828
fb7933a3 2829(defun tramp-handle-set-visited-file-modtime (&optional time-list)
00d6fd04 2830 "Like `set-visited-file-modtime' for Tramp files."
fb7933a3
KG
2831 (unless (buffer-file-name)
2832 (error "Can't set-visited-file-modtime: buffer `%s' not visiting a file"
2833 (buffer-name)))
48ddd622
MA
2834 (if time-list
2835 (tramp-run-real-handler 'set-visited-file-modtime (list time-list))
11948172
MA
2836 (let ((f (buffer-file-name))
2837 coding-system-used)
48ddd622
MA
2838 (with-parsed-tramp-file-name f nil
2839 (let* ((attr (file-attributes f))
2840 ;; '(-1 65535) means file doesn't exists yet.
2841 (modtime (or (nth 5 attr) '(-1 65535))))
11948172
MA
2842 (when (boundp 'last-coding-system-used)
2843 (setq coding-system-used (symbol-value 'last-coding-system-used)))
48ddd622 2844 ;; We use '(0 0) as a don't-know value. See also
7f49fe46 2845 ;; `tramp-do-file-attributes-with-ls'.
48ddd622
MA
2846 (if (not (equal modtime '(0 0)))
2847 (tramp-run-real-handler 'set-visited-file-modtime (list modtime))
00d6fd04 2848 (progn
48ddd622 2849 (tramp-send-command
00d6fd04 2850 v
48ddd622 2851 (format "%s -ild %s"
00d6fd04 2852 (tramp-get-ls-command v)
48ddd622 2853 (tramp-shell-quote-argument localname)))
48ddd622
MA
2854 (setq attr (buffer-substring (point)
2855 (progn (end-of-line) (point)))))
00d6fd04
MA
2856 (tramp-set-file-property
2857 v localname "visited-file-modtime-ild" attr))
11948172
MA
2858 (when (boundp 'last-coding-system-used)
2859 (set 'last-coding-system-used coding-system-used))
d2a2c17f 2860 nil)))))
fb7933a3 2861
c62c9d08
KG
2862;; This function makes the same assumption as
2863;; `tramp-handle-set-visited-file-modtime'.
2864(defun tramp-handle-verify-visited-file-modtime (buf)
00d6fd04 2865 "Like `verify-visited-file-modtime' for Tramp files.
c08e6004
MA
2866At the time `verify-visited-file-modtime' calls this function, we
2867already know that the buffer is visiting a file and that
2868`visited-file-modtime' does not return 0. Do not call this
2869function directly, unless those two cases are already taken care
2870of."
c62c9d08 2871 (with-current-buffer buf
b15d0c4c
MA
2872 ;; There is no file visiting the buffer, or the buffer has no
2873 ;; recorded last modification time.
2874 (if (or (not (buffer-file-name))
2875 (eq (visited-file-modtime) 0))
d2a2c17f 2876 t
b15d0c4c
MA
2877 (let ((f (buffer-file-name)))
2878 (with-parsed-tramp-file-name f nil
bce04fee 2879 (tramp-flush-file-property v localname)
b15d0c4c
MA
2880 (let* ((attr (file-attributes f))
2881 (modtime (nth 5 attr))
2882 (mt (visited-file-modtime)))
bf247b6e 2883
70c11b0b
MA
2884 (cond
2885 ;; File exists, and has a known modtime.
b15d0c4c
MA
2886 ((and attr (not (equal modtime '(0 0))))
2887 (< (abs (tramp-time-diff
2888 modtime
2889 ;; For compatibility, deal with both the old
70c11b0b
MA
2890 ;; (HIGH . LOW) and the new (HIGH LOW) return
2891 ;; values of `visited-file-modtime'.
b15d0c4c
MA
2892 (if (atom (cdr mt))
2893 (list (car mt) (cdr mt))
2894 mt)))
2895 2))
70c11b0b 2896 ;; Modtime has the don't know value.
b15d0c4c 2897 (attr
00d6fd04
MA
2898 (tramp-send-command
2899 v
2900 (format "%s -ild %s"
2901 (tramp-get-ls-command v)
2902 (tramp-shell-quote-argument localname)))
2903 (with-current-buffer (tramp-get-buffer v)
b15d0c4c
MA
2904 (setq attr (buffer-substring
2905 (point) (progn (end-of-line) (point)))))
00d6fd04
MA
2906 (equal
2907 attr
2908 (tramp-get-file-property
2909 v localname "visited-file-modtime-ild" "")))
70c11b0b
MA
2910 ;; If file does not exist, say it is not modified if and
2911 ;; only if that agrees with the buffer's record.
b15d0c4c 2912 (t (equal mt '(-1 65535))))))))))
c62c9d08 2913
fb7933a3 2914(defun tramp-handle-set-file-modes (filename mode)
00d6fd04 2915 "Like `set-file-modes' for Tramp files."
c62c9d08 2916 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2917 (tramp-flush-file-property v localname)
2918 (unless (zerop (tramp-send-command-and-check
2919 v
2920 (format "chmod %s %s"
2921 (tramp-decimal-to-octal mode)
2922 (tramp-shell-quote-argument localname))))
2923 ;; FIXME: extract the proper text from chmod's stderr.
2924 (tramp-error
2925 v 'file-error "Error while changing file's mode %s" filename))))
fb7933a3 2926
ce3f516f
MA
2927(defun tramp-handle-set-file-times (filename &optional time)
2928 "Like `set-file-times' for Tramp files."
2929 (zerop
9e6ab520 2930 (if (file-remote-p filename)
ce3f516f 2931 (with-parsed-tramp-file-name filename nil
8d60099b 2932 (tramp-flush-file-property v localname)
ce3f516f
MA
2933 (let ((time (if (or (null time) (equal time '(0 0)))
2934 (current-time)
2935 time))
2936 (utc
2937 ;; With GNU Emacs, `format-time-string' has an
2938 ;; optional parameter UNIVERSAL. This is preferred,
2939 ;; because we could handle the case when the remote
2940 ;; host is located in a different time zone as the
2941 ;; local host.
2942 (and (functionp 'subr-arity)
2943 (subrp (symbol-function 'format-time-string))
2944 (= 3 (cdr (funcall (symbol-function 'subr-arity)
2945 (symbol-function
2946 'format-time-string)))))))
2947 (tramp-send-command-and-check
2948 v (format "%s touch -t %s %s"
2949 (if utc "TZ=UTC; export TZ;" "")
2950 (if utc
2951 (format-time-string "%Y%m%d%H%M.%S" time t)
2952 (format-time-string "%Y%m%d%H%M.%S" time))
2953 (tramp-shell-quote-argument localname)))))
8d60099b 2954
ce3f516f
MA
2955 ;; We handle also the local part, because in older Emacsen,
2956 ;; without `set-file-times', this function is an alias for this.
2957 ;; We are local, so we don't need the UTC settings.
a4aeb9a4 2958 (tramp-local-call-process
ce3f516f
MA
2959 "touch" nil nil nil "-t"
2960 (format-time-string "%Y%m%d%H%M.%S" time)
2961 (tramp-shell-quote-argument filename)))))
2962
8d60099b
MA
2963(defun tramp-set-file-uid-gid (filename &optional uid gid)
2964 "Set the ownership for FILENAME.
2965If UID and GID are provided, these values are used; otherwise uid
2966and gid of the corresponding user is taken. Both parameters must be integers."
70c11b0b
MA
2967 ;; Modern Unices allow chown only for root. So we might need
2968 ;; another implementation, see `dired-do-chown'. OTOH, it is mostly
2969 ;; working with su(do)? when it is needed, so it shall succeed in
2970 ;; the majority of cases.
aa485f7c
MA
2971 ;; Don't modify `last-coding-system-used' by accident.
2972 (let ((last-coding-system-used last-coding-system-used))
2973 (if (file-remote-p filename)
2974 (with-parsed-tramp-file-name filename nil
2975 (if (and (zerop (user-uid)) (tramp-local-host-p v))
2976 ;; If we are root on the local host, we can do it directly.
2977 (tramp-set-file-uid-gid localname uid gid)
2978 (let ((uid (or (and (integerp uid) uid)
2979 (tramp-get-remote-uid v 'integer)))
2980 (gid (or (and (integerp gid) gid)
2981 (tramp-get-remote-gid v 'integer))))
2982 (tramp-send-command
2983 v (format
2984 "chown %d:%d %s" uid gid
2985 (tramp-shell-quote-argument localname))))))
2986
2987 ;; We handle also the local part, because there doesn't exist
2988 ;; `set-file-uid-gid'. On W32 "chown" might not work.
2989 (let ((uid (or (and (integerp uid) uid) (tramp-get-local-uid 'integer)))
2990 (gid (or (and (integerp gid) gid) (tramp-get-local-gid 'integer))))
2991 (tramp-local-call-process
2992 "chown" nil nil nil
2993 (format "%d:%d" uid gid) (tramp-shell-quote-argument filename))))))
8d60099b 2994
fb7933a3
KG
2995;; Simple functions using the `test' command.
2996
2997(defun tramp-handle-file-executable-p (filename)
00d6fd04 2998 "Like `file-executable-p' for Tramp files."
c62c9d08 2999 (with-parsed-tramp-file-name filename nil
00d6fd04 3000 (with-file-property v localname "file-executable-p"
293c24f9
MA
3001 ;; Examine `file-attributes' cache to see if request can be
3002 ;; satisfied without remote operation.
3003 (or (tramp-check-cached-permissions v ?x)
3004 (zerop (tramp-run-test "-x" filename))))))
fb7933a3
KG
3005
3006(defun tramp-handle-file-readable-p (filename)
00d6fd04 3007 "Like `file-readable-p' for Tramp files."
c62c9d08 3008 (with-parsed-tramp-file-name filename nil
00d6fd04 3009 (with-file-property v localname "file-readable-p"
293c24f9
MA
3010 ;; Examine `file-attributes' cache to see if request can be
3011 ;; satisfied without remote operation.
3012 (or (tramp-check-cached-permissions v ?r)
3013 (zerop (tramp-run-test "-r" filename))))))
fb7933a3
KG
3014
3015;; When the remote shell is started, it looks for a shell which groks
3016;; tilde expansion. Here, we assume that all shells which grok tilde
3017;; expansion will also provide a `test' command which groks `-nt' (for
3018;; newer than). If this breaks, tell me about it and I'll try to do
3019;; something smarter about it.
3020(defun tramp-handle-file-newer-than-file-p (file1 file2)
00d6fd04 3021 "Like `file-newer-than-file-p' for Tramp files."
fb7933a3
KG
3022 (cond ((not (file-exists-p file1))
3023 nil)
3024 ((not (file-exists-p file2))
3025 t)
91879624 3026 ;; We are sure both files exist at this point.
fb7933a3
KG
3027 (t
3028 (save-excursion
91879624
KG
3029 ;; We try to get the mtime of both files. If they are not
3030 ;; equal to the "dont-know" value, then we subtract the times
3031 ;; and obtain the result.
3032 (let ((fa1 (file-attributes file1))
3033 (fa2 (file-attributes file2)))
3034 (if (and (not (equal (nth 5 fa1) '(0 0)))
3035 (not (equal (nth 5 fa2) '(0 0))))
01917a18 3036 (> 0 (tramp-time-diff (nth 5 fa2) (nth 5 fa1)))
91879624
KG
3037 ;; If one of them is the dont-know value, then we can
3038 ;; still try to run a shell command on the remote host.
3039 ;; However, this only works if both files are Tramp
3040 ;; files and both have the same method, same user, same
3041 ;; host.
00d6fd04
MA
3042 (unless (tramp-equal-remote file1 file2)
3043 (with-parsed-tramp-file-name
3044 (if (tramp-tramp-file-p file1) file1 file2) nil
3045 (tramp-error
3046 v 'file-error
3047 "Files %s and %s must have same method, user, host"
3048 file1 file2)))
3049 (with-parsed-tramp-file-name file1 nil
3050 (zerop (tramp-run-test2
3051 (tramp-get-test-nt-command v) file1 file2)))))))))
fb7933a3
KG
3052
3053;; Functions implemented using the basic functions above.
3054
3055(defun tramp-handle-file-modes (filename)
00d6fd04 3056 "Like `file-modes' for Tramp files."
5da24108
MA
3057 (let ((truename (or (file-truename filename) filename)))
3058 (when (file-exists-p truename)
3059 (tramp-mode-string-to-int (nth 8 (file-attributes truename))))))
fb7933a3 3060
b86c1cd8
MA
3061(defun tramp-default-file-modes (filename)
3062 "Return file modes of FILENAME as integer.
3063If the file modes of FILENAME cannot be determined, return the
974647ac
MA
3064value of `default-file-modes', without execute permissions."
3065 (or (file-modes filename)
3066 (logand (default-file-modes) (tramp-octal-to-decimal "0666"))))
b86c1cd8 3067
fb7933a3 3068(defun tramp-handle-file-directory-p (filename)
00d6fd04 3069 "Like `file-directory-p' for Tramp files."
fb7933a3
KG
3070 ;; Care must be taken that this function returns `t' for symlinks
3071 ;; pointing to directories. Surely the most obvious implementation
3072 ;; would be `test -d', but that returns false for such symlinks.
3073 ;; CCC: Stefan Monnier says that `test -d' follows symlinks. And
3074 ;; I now think he's right. So we could be using `test -d', couldn't
3075 ;; we?
3076 ;;
3077 ;; Alternatives: `cd %s', `test -d %s'
c62c9d08 3078 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3079 (with-file-property v localname "file-directory-p"
3080 (zerop (tramp-run-test "-d" filename)))))
fb7933a3
KG
3081
3082(defun tramp-handle-file-regular-p (filename)
00d6fd04
MA
3083 "Like `file-regular-p' for Tramp files."
3084 (and (file-exists-p filename)
3085 (eq ?- (aref (nth 8 (file-attributes filename)) 0))))
fb7933a3
KG
3086
3087(defun tramp-handle-file-symlink-p (filename)
00d6fd04 3088 "Like `file-symlink-p' for Tramp files."
c62c9d08 3089 (with-parsed-tramp-file-name filename nil
c951aecb 3090 (let ((x (car (file-attributes filename))))
b25a52cc
KG
3091 (when (stringp x)
3092 ;; When Tramp is running on VMS, then `file-name-absolute-p'
3093 ;; might do weird things.
3094 (if (file-name-absolute-p x)
00d6fd04 3095 (tramp-make-tramp-file-name method user host x)
b25a52cc 3096 x)))))
fb7933a3
KG
3097
3098(defun tramp-handle-file-writable-p (filename)
00d6fd04 3099 "Like `file-writable-p' for Tramp files."
c62c9d08 3100 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3101 (with-file-property v localname "file-writable-p"
3102 (if (file-exists-p filename)
293c24f9
MA
3103 ;; Examine `file-attributes' cache to see if request can be
3104 ;; satisfied without remote operation.
3105 (or (tramp-check-cached-permissions v ?w)
3106 (zerop (tramp-run-test "-w" filename)))
00d6fd04
MA
3107 ;; If file doesn't exist, check if directory is writable.
3108 (and (zerop (tramp-run-test
3109 "-d" (file-name-directory filename)))
3110 (zerop (tramp-run-test
3111 "-w" (file-name-directory filename))))))))
fb7933a3
KG
3112
3113(defun tramp-handle-file-ownership-preserved-p (filename)
00d6fd04 3114 "Like `file-ownership-preserved-p' for Tramp files."
c62c9d08 3115 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3116 (with-file-property v localname "file-ownership-preserved-p"
3117 (let ((attributes (file-attributes filename)))
3118 ;; Return t if the file doesn't exist, since it's true that no
3119 ;; information would be lost by an (attempted) delete and create.
3120 (or (null attributes)
3121 (= (nth 2 attributes) (tramp-get-remote-uid v 'integer)))))))
fb7933a3
KG
3122
3123;; Other file name ops.
3124
fb7933a3 3125(defun tramp-handle-directory-file-name (directory)
00d6fd04 3126 "Like `directory-file-name' for Tramp files."
7432277c
KG
3127 ;; If localname component of filename is "/", leave it unchanged.
3128 ;; Otherwise, remove any trailing slash from localname component.
8daea7fc
KG
3129 ;; Method, host, etc, are unchanged. Does it make sense to try
3130 ;; to avoid parsing the filename?
c62c9d08 3131 (with-parsed-tramp-file-name directory nil
7432277c
KG
3132 (if (and (not (zerop (length localname)))
3133 (eq (aref localname (1- (length localname))) ?/)
3134 (not (string= localname "/")))
8daea7fc
KG
3135 (substring directory 0 -1)
3136 directory)))
fb7933a3
KG
3137
3138;; Directory listings.
3139
00d6fd04
MA
3140(defun tramp-handle-directory-files
3141 (directory &optional full match nosort files-only)
3142 "Like `directory-files' for Tramp files."
3143 ;; FILES-ONLY is valid for XEmacs only.
3144 (when (file-directory-p directory)
3145 (setq directory (expand-file-name directory))
3146 (let ((temp (nreverse (file-name-all-completions "" directory)))
3147 result item)
3148
3149 (while temp
3150 (setq item (directory-file-name (pop temp)))
3151 (when (and (or (null match) (string-match match item))
3152 (or (null files-only)
3153 ;; files only
3154 (and (equal files-only t) (file-regular-p item))
3155 ;; directories only
3156 (file-directory-p item)))
3157 (push (if full (expand-file-name item directory) item)
3158 result)))
c62c9d08
KG
3159 result)))
3160
c82c5727
LH
3161(defun tramp-handle-directory-files-and-attributes
3162 (directory &optional full match nosort id-format)
00d6fd04
MA
3163 "Like `directory-files-and-attributes' for Tramp files."
3164 (unless id-format (setq id-format 'integer))
3165 (when (file-directory-p directory)
3166 (setq directory (expand-file-name directory))
3167 (let* ((temp
9e6ab520 3168 (tramp-compat-copy-tree
00d6fd04
MA
3169 (with-parsed-tramp-file-name directory nil
3170 (with-file-property
3171 v localname
3172 (format "directory-files-and-attributes-%s" id-format)
3173 (save-excursion
3174 (mapcar
aa485f7c
MA
3175 (lambda (x)
3176 (cons (car x)
3177 (tramp-convert-file-attributes v (cdr x))))
7f49fe46
MA
3178 (cond
3179 ((tramp-get-remote-stat v)
3180 (tramp-do-directory-files-and-attributes-with-stat
3181 v localname id-format))
3182 ((tramp-get-remote-perl v)
3183 (tramp-do-directory-files-and-attributes-with-perl
3184 v localname id-format)))))))))
00d6fd04
MA
3185 result item)
3186
3187 (while temp
3188 (setq item (pop temp))
3189 (when (or (null match) (string-match match (car item)))
3190 (when full
3191 (setcar item (expand-file-name (car item) directory)))
3192 (push item result)))
3193
3194 (if nosort
3195 result
3196 (sort result (lambda (x y) (string< (car x) (car y))))))))
3197
7f49fe46 3198(defun tramp-do-directory-files-and-attributes-with-perl
00d6fd04
MA
3199 (vec localname &optional id-format)
3200 "Implement `directory-files-and-attributes' for Tramp files using a Perl script."
3201 (tramp-message vec 5 "directory-files-and-attributes with perl: %s" localname)
3202 (tramp-maybe-send-script
3203 vec tramp-perl-directory-files-and-attributes
3204 "tramp_perl_directory_files_and_attributes")
3205 (let ((object
3206 (tramp-send-command-and-read
3207 vec
3208 (format "tramp_perl_directory_files_and_attributes %s %s"
3209 (tramp-shell-quote-argument localname) id-format))))
3210 (when (stringp object) (tramp-error vec 'file-error object))
3211 object))
3212
7f49fe46 3213(defun tramp-do-directory-files-and-attributes-with-stat
00d6fd04
MA
3214 (vec localname &optional id-format)
3215 "Implement `directory-files-and-attributes' for Tramp files using stat(1) command."
3216 (tramp-message vec 5 "directory-files-and-attributes with stat: %s" localname)
3217 (tramp-send-command-and-read
3218 vec
3219 (format
3220 (concat
70c11b0b
MA
3221 ;; We must care about filenames with spaces, or starting with
3222 ;; "-"; this would confuse xargs. "ls -aQ" might be a solution,
3223 ;; but it does not work on all remote systems. Therefore, we
3224 ;; quote the filenames via sed.
3225 "cd %s; echo \"(\"; (%s -a | sed -e s/\\$/\\\"/g -e s/^/\\\"/g | xargs "
d4443a0d 3226 "%s -c '(\"%%n\" (\"%%N\") %%h %s %s %%X.0 %%Y.0 %%Z.0 %%s.0 \"%%A\" t %%i.0 -1)'); "
00d6fd04
MA
3227 "echo \")\"")
3228 (tramp-shell-quote-argument localname)
3229 (tramp-get-ls-command vec)
3230 (tramp-get-remote-stat vec)
3231 (if (eq id-format 'integer) "%u" "\"%U\"")
3232 (if (eq id-format 'integer) "%g" "\"%G\""))))
c82c5727 3233
c62c9d08 3234;; This function should return "foo/" for directories and "bar" for
00d6fd04 3235;; files.
c62c9d08 3236(defun tramp-handle-file-name-all-completions (filename directory)
00d6fd04
MA
3237 "Like `file-name-all-completions' for Tramp files."
3238 (unless (save-match-data (string-match "/" filename))
9c13938d 3239 (with-parsed-tramp-file-name (expand-file-name directory) nil
b50dd0d2 3240
00d6fd04
MA
3241 (all-completions
3242 filename
3243 (mapcar
3244 'list
293c24f9
MA
3245 (or
3246 ;; Try cache first
3247 (and
3248 ;; Ignore if expired
3249 (or (not (integerp tramp-completion-reread-directory-timeout))
3250 (<= (tramp-time-diff
3251 (current-time)
3252 (tramp-get-file-property
3253 v localname "last-completion" '(0 0 0)))
3254 tramp-completion-reread-directory-timeout))
3255
3256 ;; Try cache entries for filename, filename with last
3257 ;; character removed, filename with last two characters
3258 ;; removed, ..., and finally the empty string - all
3259 ;; concatenated to the local directory name
3260
3261 ;; This is inefficient for very long filenames, pity
3262 ;; `reduce' is not available...
3263 (car
3264 (apply
3265 'append
3266 (mapcar
3267 (lambda (x)
3268 (let ((cache-hit
3269 (tramp-get-file-property
3270 v
3271 (concat localname (substring filename 0 x))
3272 "file-name-all-completions"
3273 nil)))
3274 (when cache-hit (list cache-hit))))
3275 (tramp-compat-number-sequence (length filename) 0 -1)))))
3276
3277 ;; Cache expired or no matching cache entry found so we need
3278 ;; to perform a remote operation
3279 (let (result)
3280 ;; Get a list of directories and files, including reliably
3281 ;; tagging the directories with a trailing '/'. Because I
3282 ;; rock. --daniel@danann.net
3283
3284 ;; Changed to perform `cd' in the same remote op and only
3285 ;; get entries starting with `filename'. Capture any `cd'
3286 ;; error messages. Ensure any `cd' and `echo' aliases are
3287 ;; ignored.
3288 (tramp-send-command
3289 v
3290 (if (tramp-get-remote-perl v)
3291 (progn
3292 (tramp-maybe-send-script
3293 v tramp-perl-file-name-all-completions
3294 "tramp_perl_file_name_all_completions")
3295 (format "tramp_perl_file_name_all_completions %s %s %d"
3296 (tramp-shell-quote-argument localname)
3297 (tramp-shell-quote-argument filename)
3298 (if (symbol-value
3299 'read-file-name-completion-ignore-case)
3300 1 0)))
3301
3302 (format (concat
3303 "(\\cd %s 2>&1 && (%s %s -a 2>/dev/null"
3304 ;; `ls' with wildcard might fail with `Argument
3305 ;; list too long' error in some corner cases; if
3306 ;; `ls' fails after `cd' succeeded, chances are
3307 ;; that's the case, so let's retry without
3308 ;; wildcard. This will return "too many" entries
3309 ;; but that isn't harmful.
3310 " || %s -a 2>/dev/null)"
3311 " | while read f; do"
3312 " if %s -d \"$f\" 2>/dev/null;"
3313 " then \\echo \"$f/\"; else \\echo \"$f\"; fi; done"
3314 " && \\echo ok) || \\echo fail")
3315 (tramp-shell-quote-argument localname)
3316 (tramp-get-ls-command v)
3317 ;; When `filename' is empty, just `ls' without
3318 ;; filename argument is more efficient than `ls *'
3319 ;; for very large directories and might avoid the
3320 ;; `Argument list too long' error.
3321 ;;
3322 ;; With and only with wildcard, we need to add
3323 ;; `-d' to prevent `ls' from descending into
3324 ;; sub-directories.
3325 (if (zerop (length filename))
3326 "."
3327 (concat (tramp-shell-quote-argument filename) "* -d"))
3328 (tramp-get-ls-command v)
3329 (tramp-get-test-command v))))
3330
3331 ;; Now grab the output.
3332 (with-current-buffer (tramp-get-buffer v)
3333 (goto-char (point-max))
3334
3335 ;; Check result code, found in last line of output
3336 (forward-line -1)
3337 (if (looking-at "^fail$")
3338 (progn
3339 ;; Grab error message from line before last line
3340 ;; (it was put there by `cd 2>&1')
3341 (forward-line -1)
3342 (tramp-error
3343 v 'file-error
3344 "tramp-handle-file-name-all-completions: %s"
3345 (buffer-substring
3346 (point) (tramp-compat-line-end-position))))
3347 ;; For peace of mind, if buffer doesn't end in `fail'
3348 ;; then it should end in `ok'. If neither are in the
3349 ;; buffer something went seriously wrong on the remote
3350 ;; side.
3351 (unless (looking-at "^ok$")
3352 (tramp-error
3353 v 'file-error
3354 "\
3355tramp-handle-file-name-all-completions: internal error accessing `%s': `%s'"
3356 (tramp-shell-quote-argument localname) (buffer-string))))
3357
3358 (while (zerop (forward-line -1))
3359 (push (buffer-substring
3360 (point) (tramp-compat-line-end-position))
3361 result)))
3362
3363 ;; Because the remote op went through OK we know the
3364 ;; directory we `cd'-ed to exists
3365 (tramp-set-file-property
3366 v localname "file-exists-p" t)
3367
3368 ;; Because the remote op went through OK we know every
3369 ;; file listed by `ls' exists.
3370 (mapc (lambda (entry)
3371 (tramp-set-file-property
3372 v (concat localname entry) "file-exists-p" t))
3373 result)
3374
3375 (tramp-set-file-property
3376 v localname "last-completion" (current-time))
3377
3378 ;; Store result in the cache
3379 (tramp-set-file-property
3380 v (concat localname filename)
3381 "file-name-all-completions"
3382 result))))))))
fb7933a3
KG
3383
3384;; The following isn't needed for Emacs 20 but for 19.34?
e1e17cae
MA
3385(defun tramp-handle-file-name-completion
3386 (filename directory &optional predicate)
00d6fd04 3387 "Like `file-name-completion' for Tramp files."
fb7933a3
KG
3388 (unless (tramp-tramp-file-p directory)
3389 (error
3390 "tramp-handle-file-name-completion invoked on non-tramp directory `%s'"
3391 directory))
83e20b5c
MA
3392 (try-completion
3393 filename
3394 (mapcar 'list (file-name-all-completions filename directory))
3395 (when predicate
3396 (lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
fb7933a3
KG
3397
3398;; cp, mv and ln
3399
3400(defun tramp-handle-add-name-to-file
3401 (filename newname &optional ok-if-already-exists)
00d6fd04
MA
3402 "Like `add-name-to-file' for Tramp files."
3403 (unless (tramp-equal-remote filename newname)
3404 (with-parsed-tramp-file-name
3405 (if (tramp-tramp-file-p filename) filename newname) nil
3406 (tramp-error
3407 v 'file-error
3408 "add-name-to-file: %s"
3409 "only implemented for same method, same user, same host")))
c62c9d08
KG
3410 (with-parsed-tramp-file-name filename v1
3411 (with-parsed-tramp-file-name newname v2
00d6fd04 3412 (let ((ln (when v1 (tramp-get-remote-ln v1))))
c62c9d08
KG
3413 (when (and (not ok-if-already-exists)
3414 (file-exists-p newname)
3415 (not (numberp ok-if-already-exists))
3416 (y-or-n-p
3417 (format
3418 "File %s already exists; make it a new name anyway? "
3419 newname)))
00d6fd04
MA
3420 (tramp-error
3421 v2 'file-error
3422 "add-name-to-file: file %s already exists" newname))
aac0b0f2 3423 (tramp-flush-file-property v2 (file-name-directory v2-localname))
00d6fd04 3424 (tramp-flush-file-property v2 v2-localname)
c62c9d08 3425 (tramp-barf-unless-okay
00d6fd04 3426 v1
7432277c
KG
3427 (format "%s %s %s" ln (tramp-shell-quote-argument v1-localname)
3428 (tramp-shell-quote-argument v2-localname))
c62c9d08
KG
3429 "error with add-name-to-file, see buffer `%s' for details"
3430 (buffer-name))))))
fb7933a3
KG
3431
3432(defun tramp-handle-copy-file
8d60099b 3433 (filename newname &optional ok-if-already-exists keep-date preserve-uid-gid)
00d6fd04 3434 "Like `copy-file' for Tramp files."
fb7933a3 3435 ;; Check if both files are local -- invoke normal copy-file.
9e6ab520 3436 ;; Otherwise, use Tramp from local system.
fb7933a3
KG
3437 (setq filename (expand-file-name filename))
3438 (setq newname (expand-file-name newname))
9e6ab520 3439 (cond
a4aeb9a4 3440 ;; At least one file a Tramp file?
9e6ab520
MA
3441 ((or (tramp-tramp-file-p filename)
3442 (tramp-tramp-file-p newname))
3443 (tramp-do-copy-or-rename-file
3444 'copy filename newname ok-if-already-exists keep-date preserve-uid-gid))
3445 ;; Compat section.
3446 (preserve-uid-gid
fb7933a3 3447 (tramp-run-real-handler
8d60099b 3448 'copy-file
9e6ab520
MA
3449 (list filename newname ok-if-already-exists keep-date preserve-uid-gid)))
3450 (t
3451 (tramp-run-real-handler
3452 'copy-file (list filename newname ok-if-already-exists keep-date)))))
fb7933a3 3453
263c02ef
MA
3454(defun tramp-handle-copy-directory (dirname newname &optional keep-date parents)
3455 "Like `copy-directory' for Tramp files."
3456 (let ((t1 (tramp-tramp-file-p dirname))
3457 (t2 (tramp-tramp-file-p newname)))
3458 (with-parsed-tramp-file-name (if t1 dirname newname) nil
3459 (if (and (tramp-get-method-parameter method 'tramp-copy-recursive)
3460 ;; When DIRNAME and NEWNAME are remote, they must have
3461 ;; the same method.
3462 (or (null t1) (null t2)
b000a6e2
MA
3463 (string-equal
3464 (tramp-file-name-method (tramp-dissect-file-name dirname))
3465 (tramp-file-name-method (tramp-dissect-file-name newname)))))
263c02ef
MA
3466 ;; scp or rsync DTRT.
3467 (progn
3468 (setq dirname (directory-file-name (expand-file-name dirname))
3469 newname (directory-file-name (expand-file-name newname)))
3470 (if (and (file-directory-p newname)
3471 (not (string-equal (file-name-nondirectory dirname)
3472 (file-name-nondirectory newname))))
3473 (setq newname
3474 (expand-file-name
3475 (file-name-nondirectory dirname) newname)))
3476 (if (not (file-directory-p (file-name-directory newname)))
3477 (make-directory (file-name-directory newname) parents))
3478 (tramp-do-copy-or-rename-file-out-of-band
3479 'copy dirname newname keep-date))
3480 ;; We must do it file-wise.
3481 (tramp-run-real-handler
aac0b0f2
MA
3482 'copy-directory (list dirname newname keep-date parents)))
3483
3484 ;; When newname did exist, we have wrong cached values.
3485 (when t2
3486 (with-parsed-tramp-file-name newname nil
3487 (tramp-flush-file-property v (file-name-directory localname))
3488 (tramp-flush-file-property v localname))))))
263c02ef 3489
fb7933a3
KG
3490(defun tramp-handle-rename-file
3491 (filename newname &optional ok-if-already-exists)
00d6fd04 3492 "Like `rename-file' for Tramp files."
fb7933a3 3493 ;; Check if both files are local -- invoke normal rename-file.
a4aeb9a4 3494 ;; Otherwise, use Tramp from local system.
fb7933a3
KG
3495 (setq filename (expand-file-name filename))
3496 (setq newname (expand-file-name newname))
a4aeb9a4 3497 ;; At least one file a Tramp file?
fb7933a3
KG
3498 (if (or (tramp-tramp-file-p filename)
3499 (tramp-tramp-file-p newname))
3500 (tramp-do-copy-or-rename-file
8d60099b 3501 'rename filename newname ok-if-already-exists t t)
00d6fd04
MA
3502 (tramp-run-real-handler
3503 'rename-file (list filename newname ok-if-already-exists))))
fb7933a3
KG
3504
3505(defun tramp-do-copy-or-rename-file
8d60099b 3506 (op filename newname &optional ok-if-already-exists keep-date preserve-uid-gid)
fb7933a3
KG
3507 "Copy or rename a remote file.
3508OP must be `copy' or `rename' and indicates the operation to perform.
3509FILENAME specifies the file to copy or rename, NEWNAME is the name of
3510the new file (for copy) or the new name of the file (for rename).
3511OK-IF-ALREADY-EXISTS means don't barf if NEWNAME exists already.
3512KEEP-DATE means to make sure that NEWNAME has the same timestamp
8d60099b
MA
3513as FILENAME. PRESERVE-UID-GID, when non-nil, instructs to keep
3514the uid and gid if both files are on the same host.
fb7933a3
KG
3515
3516This function is invoked by `tramp-handle-copy-file' and
3517`tramp-handle-rename-file'. It is an error if OP is neither of `copy'
3518and `rename'. FILENAME and NEWNAME must be absolute file names."
3519 (unless (memq op '(copy rename))
3520 (error "Unknown operation `%s', must be `copy' or `rename'" op))
90dc758d 3521 (let ((t1 (tramp-tramp-file-p filename))
00d6fd04 3522 (t2 (tramp-tramp-file-p newname)))
5ec2cc41 3523
da1975d7
MA
3524 (when (and (not ok-if-already-exists) (file-exists-p newname))
3525 (with-parsed-tramp-file-name (if t1 filename newname) nil
3526 (tramp-error
3527 v 'file-already-exists "File %s already exists" newname)))
5ec2cc41 3528
905fb90e
MA
3529 (with-parsed-tramp-file-name (if t1 filename newname) nil
3530 (tramp-message v 0 "Transferring %s to %s..." filename newname))
3531
00d6fd04
MA
3532 (prog1
3533 (cond
3534 ;; Both are Tramp files.
3535 ((and t1 t2)
3536 (with-parsed-tramp-file-name filename v1
3537 (with-parsed-tramp-file-name newname v2
3538 (cond
3539 ;; Shortcut: if method, host, user are the same for both
3540 ;; files, we invoke `cp' or `mv' on the remote host
3541 ;; directly.
3542 ((tramp-equal-remote filename newname)
3543 (tramp-do-copy-or-rename-file-directly
8d60099b
MA
3544 op filename newname
3545 ok-if-already-exists keep-date preserve-uid-gid))
3546
905fb90e 3547 ;; Try out-of-band operation.
7f49fe46
MA
3548 ((tramp-method-out-of-band-p
3549 v1 (nth 7 (file-attributes filename)))
00d6fd04
MA
3550 (tramp-do-copy-or-rename-file-out-of-band
3551 op filename newname keep-date))
8d60099b 3552
00d6fd04
MA
3553 ;; No shortcut was possible. So we copy the
3554 ;; file first. If the operation was `rename', we go
3555 ;; back and delete the original file (if the copy was
3556 ;; successful). The approach is simple-minded: we
3557 ;; create a new buffer, insert the contents of the
3558 ;; source file into it, then write out the buffer to
3559 ;; the target file. The advantage is that it doesn't
3560 ;; matter which filename handlers are used for the
3561 ;; source and target file.
3562 (t
3563 (tramp-do-copy-or-rename-file-via-buffer
3564 op filename newname keep-date))))))
3565
3566 ;; One file is a Tramp file, the other one is local.
3567 ((or t1 t2)
3568 (with-parsed-tramp-file-name (if t1 filename newname) nil
8d60099b
MA
3569 (cond
3570 ;; Fast track on local machine.
3571 ((tramp-local-host-p v)
3572 (tramp-do-copy-or-rename-file-directly
3573 op filename newname
3574 ok-if-already-exists keep-date preserve-uid-gid))
3575
3576 ;; If the Tramp file has an out-of-band method, the corresponding
3577 ;; copy-program can be invoked.
7f49fe46 3578 ((tramp-method-out-of-band-p v (nth 7 (file-attributes filename)))
8d60099b
MA
3579 (tramp-do-copy-or-rename-file-out-of-band
3580 op filename newname keep-date))
3581
3582 ;; Use the inline method via a Tramp buffer.
3583 (t (tramp-do-copy-or-rename-file-via-buffer
3584 op filename newname keep-date)))))
00d6fd04
MA
3585
3586 (t
3587 ;; One of them must be a Tramp file.
3588 (error "Tramp implementation says this cannot happen")))
8d60099b 3589
484ea0b6
MA
3590 ;; In case of `rename', we must flush the cache of the source file.
3591 (when (and t1 (eq op 'rename))
3592 (with-parsed-tramp-file-name filename nil
aac0b0f2 3593 (tramp-flush-file-property v (file-name-directory localname))
484ea0b6
MA
3594 (tramp-flush-file-property v localname)))
3595
00d6fd04
MA
3596 ;; When newname did exist, we have wrong cached values.
3597 (when t2
3598 (with-parsed-tramp-file-name newname nil
aac0b0f2 3599 (tramp-flush-file-property v (file-name-directory localname))
905fb90e
MA
3600 (tramp-flush-file-property v localname)))
3601
3602 (with-parsed-tramp-file-name (if t1 filename newname) nil
3603 (tramp-message v 0 "Transferring %s to %s...done" filename newname)))))
7432277c 3604
38c65fca 3605(defun tramp-do-copy-or-rename-file-via-buffer (op filename newname keep-date)
90dc758d
KG
3606 "Use an Emacs buffer to copy or rename a file.
3607First arg OP is either `copy' or `rename' and indicates the operation.
3608FILENAME is the source file, NEWNAME the target file.
3609KEEP-DATE is non-nil if NEWNAME should have the same timestamp as FILENAME."
8a798e41
MA
3610 (with-temp-buffer
3611 ;; We must disable multibyte, because binary data shall not be
3612 ;; converted.
3613 (set-buffer-multibyte nil)
3614 (let ((coding-system-for-read 'binary)
3615 (jka-compr-inhibit t))
3616 (insert-file-contents-literally filename))
3617 ;; We don't want the target file to be compressed, so we let-bind
3618 ;; `jka-compr-inhibit' to t.
3619 (let ((coding-system-for-write 'binary)
3620 (jka-compr-inhibit t))
3621 (write-region (point-min) (point-max) newname)))
3622 ;; KEEP-DATE handling.
3623 (when keep-date (set-file-times newname (nth 5 (file-attributes filename))))
3624 ;; Set the mode.
b86c1cd8 3625 (set-file-modes newname (tramp-default-file-modes filename))
8a798e41
MA
3626 ;; If the operation was `rename', delete the original file.
3627 (unless (eq op 'copy) (delete-file filename)))
fb7933a3
KG
3628
3629(defun tramp-do-copy-or-rename-file-directly
8d60099b 3630 (op filename newname ok-if-already-exists keep-date preserve-uid-gid)
fb7933a3
KG
3631 "Invokes `cp' or `mv' on the remote system.
3632OP must be one of `copy' or `rename', indicating `cp' or `mv',
8d60099b
MA
3633respectively. FILENAME specifies the file to copy or rename,
3634NEWNAME is the name of the new file (for copy) or the new name of
3635the file (for rename). Both files must reside on the same host.
3636KEEP-DATE means to make sure that NEWNAME has the same timestamp
3637as FILENAME. PRESERVE-UID-GID, when non-nil, instructs to keep
3638the uid and gid from FILENAME."
8a4438b6 3639 (let ((t1 (tramp-tramp-file-p filename))
4f4126e6
MA
3640 (t2 (tramp-tramp-file-p newname))
3641 (file-times (nth 5 (file-attributes filename)))
3642 (file-modes (tramp-default-file-modes filename)))
8a4438b6
MA
3643 (with-parsed-tramp-file-name (if t1 filename newname) nil
3644 (let* ((cmd (cond ((and (eq op 'copy) preserve-uid-gid) "cp -f -p")
3645 ((eq op 'copy) "cp -f")
3646 ((eq op 'rename) "mv -f")
3647 (t (tramp-error
3648 v 'file-error
3649 "Unknown operation `%s', must be `copy' or `rename'"
3650 op))))
3651 (localname1
3652 (if t1 (tramp-handle-file-remote-p filename 'localname) filename))
3653 (localname2
3654 (if t2 (tramp-handle-file-remote-p newname 'localname) newname))
293c24f9
MA
3655 (prefix (file-remote-p (if t1 filename newname)))
3656 cmd-result)
8d60099b 3657
8d60099b 3658 (cond
8a4438b6
MA
3659 ;; Both files are on a remote host, with same user.
3660 ((and t1 t2)
293c24f9
MA
3661 (setq cmd-result
3662 (tramp-send-command-and-check
3663 v
3664 (format "%s %s %s" cmd
3665 (tramp-shell-quote-argument localname1)
3666 (tramp-shell-quote-argument localname2))))
8a4438b6
MA
3667 (with-current-buffer (tramp-get-buffer v)
3668 (goto-char (point-min))
3669 (unless
3670 (or
3671 (and keep-date
3672 ;; Mask cp -f error.
3673 (re-search-forward
3674 tramp-operation-not-permitted-regexp nil t))
293c24f9 3675 (zerop cmd-result))
8a4438b6
MA
3676 (tramp-error-with-buffer
3677 nil v 'file-error
3678 "Copying directly failed, see buffer `%s' for details."
3679 (buffer-name)))))
3680
3681 ;; We are on the local host.
3682 ((or t1 t2)
8d60099b 3683 (cond
8a4438b6 3684 ;; We can do it directly.
87bdd2c7
MA
3685 ((let (file-name-handler-alist)
3686 (and (file-readable-p localname1)
3687 (file-writable-p (file-name-directory localname2))
3688 (or (file-directory-p localname2)
3689 (file-writable-p localname2))))
8d60099b 3690 (if (eq op 'copy)
9e6ab520
MA
3691 (tramp-compat-copy-file
3692 localname1 localname2 ok-if-already-exists
3693 keep-date preserve-uid-gid)
87bdd2c7
MA
3694 (tramp-run-real-handler
3695 'rename-file (list localname1 localname2 ok-if-already-exists))))
8a4438b6
MA
3696
3697 ;; We can do it directly with `tramp-send-command'
946a5aeb
MA
3698 ((and (file-readable-p (concat prefix localname1))
3699 (file-writable-p
3700 (file-name-directory (concat prefix localname2)))
3701 (or (file-directory-p (concat prefix localname2))
3702 (file-writable-p (concat prefix localname2))))
8a4438b6
MA
3703 (tramp-do-copy-or-rename-file-directly
3704 op (concat prefix localname1) (concat prefix localname2)
3705 ok-if-already-exists keep-date t)
3706 ;; We must change the ownership to the local user.
8d60099b 3707 (tramp-set-file-uid-gid
8a4438b6
MA
3708 (concat prefix localname2)
3709 (tramp-get-local-uid 'integer)
3710 (tramp-get-local-gid 'integer)))
8d60099b 3711
8a4438b6
MA
3712 ;; We need a temporary file in between.
3713 (t
2c418c5b
MA
3714 ;; Create the temporary file.
3715 (let ((tmpfile (tramp-compat-make-temp-file localname1)))
917b89a6 3716 (unwind-protect
2c418c5b
MA
3717 (progn
3718 (cond
3719 (t1
917b89a6
MA
3720 (or
3721 (zerop
3722 (tramp-send-command-and-check
3723 v (format
3724 "%s %s %s" cmd
3725 (tramp-shell-quote-argument localname1)
3726 (tramp-shell-quote-argument tmpfile))))
3727 (tramp-error-with-buffer
3728 nil v 'file-error
3729 "Copying directly failed, see buffer `%s' for details."
3730 (tramp-get-buffer v)))
2c418c5b 3731 ;; We must change the ownership as remote user.
917b89a6
MA
3732 ;; Since this does not work reliable, we also
3733 ;; give read permissions.
3734 (set-file-modes
3735 (concat prefix tmpfile) (tramp-octal-to-decimal "0777"))
2c418c5b
MA
3736 (tramp-set-file-uid-gid
3737 (concat prefix tmpfile)
3738 (tramp-get-local-uid 'integer)
3739 (tramp-get-local-gid 'integer)))
3740 (t2
3741 (if (eq op 'copy)
3742 (tramp-compat-copy-file
5ab38c3c 3743 localname1 tmpfile t
2c418c5b
MA
3744 keep-date preserve-uid-gid)
3745 (tramp-run-real-handler
3746 'rename-file
5ab38c3c 3747 (list localname1 tmpfile t)))
2c418c5b 3748 ;; We must change the ownership as local user.
917b89a6
MA
3749 ;; Since this does not work reliable, we also
3750 ;; give read permissions.
3751 (set-file-modes tmpfile (tramp-octal-to-decimal "0777"))
2c418c5b
MA
3752 (tramp-set-file-uid-gid
3753 tmpfile
3754 (tramp-get-remote-uid v 'integer)
3755 (tramp-get-remote-gid v 'integer))))
3756
3757 ;; Move the temporary file to its destination.
3758 (cond
3759 (t2
917b89a6
MA
3760 (or
3761 (zerop
3762 (tramp-send-command-and-check
3763 v (format
3764 "cp -f -p %s %s"
3765 (tramp-shell-quote-argument tmpfile)
3766 (tramp-shell-quote-argument localname2))))
3767 (tramp-error-with-buffer
3768 nil v 'file-error
3769 "Copying directly failed, see buffer `%s' for details."
3770 (tramp-get-buffer v))))
2c418c5b 3771 (t1
ce2cc728
MA
3772 (tramp-run-real-handler
3773 'rename-file
2c418c5b
MA
3774 (list tmpfile localname2 ok-if-already-exists)))))
3775
917b89a6
MA
3776 ;; Save exit.
3777 (condition-case nil
3778 (delete-file tmpfile)
3779 (error)))))))))
8d60099b
MA
3780
3781 ;; Set the time and mode. Mask possible errors.
8d60099b 3782 (condition-case nil
1f107aed 3783 (when keep-date
4f4126e6
MA
3784 (set-file-times newname file-times)
3785 (set-file-modes newname file-modes))
8d60099b
MA
3786 (error)))))
3787
5ec2cc41 3788(defun tramp-do-copy-or-rename-file-out-of-band (op filename newname keep-date)
7432277c 3789 "Invoke rcp program to copy.
905fb90e 3790The method used must be an out-of-band method."
38c65fca 3791 (let ((t1 (tramp-tramp-file-p filename))
5ec2cc41 3792 (t2 (tramp-tramp-file-p newname))
946a5aeb 3793 copy-program copy-args copy-env copy-keep-date port spec
00d6fd04
MA
3794 source target)
3795
3796 (with-parsed-tramp-file-name (if t1 filename newname) nil
905fb90e 3797 (if (and t1 t2)
00d6fd04 3798
905fb90e
MA
3799 ;; Both are Tramp files. We shall optimize it, when the
3800 ;; methods for filename and newname are the same.
aac0b0f2
MA
3801 (let ((tmpfile
3802 (if (file-regular-p filename)
3803 (tramp-compat-make-temp-file localname)
3804 (make-temp-name
3805 (expand-file-name
3806 tramp-temp-name-prefix
3807 (tramp-compat-temporary-file-directory))))))
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
aac0b0f2
MA
3816 (if (file-regular-p tmpfile)
3817 (delete-file tmpfile)
3818 (delete-directory tmpfile 'recursive))
905fb90e
MA
3819 (error))))
3820
3821 ;; Expand hops. Might be necessary for gateway methods.
3822 (setq v (car (tramp-compute-multi-hops v)))
3823 (aset v 3 localname)
3824
3825 ;; Check which ones of source and target are Tramp files.
3826 (setq source (if t1 (tramp-make-copy-program-file-name v) filename)
263c02ef
MA
3827 target (funcall
3828 (if (and (file-directory-p filename)
3829 (string-equal
3830 (file-name-nondirectory filename)
3831 (file-name-nondirectory newname)))
3832 'file-name-directory
3833 'identity)
3834 (if t2 (tramp-make-copy-program-file-name v) newname)))
905fb90e
MA
3835
3836 ;; Check for port number. Until now, there's no need for handling
3837 ;; like method, user, host.
3838 (setq host (tramp-file-name-real-host v)
3839 port (tramp-file-name-port v)
3840 port (or (and port (number-to-string port)) ""))
3841
3842 ;; Compose copy command.
3843 (setq spec `((?h . ,host) (?u . ,user) (?p . ,port)
3844 (?t . ,(tramp-get-connection-property
3845 (tramp-get-connection-process v) "temp-file" ""))
3846 (?k . ,(if keep-date " " "")))
3847 copy-program (tramp-get-method-parameter
3848 method 'tramp-copy-program)
3849 copy-keep-date (tramp-get-method-parameter
3850 method 'tramp-copy-keep-date)
3851 copy-args
3852 (delq
3853 nil
3854 (mapcar
aa485f7c
MA
3855 (lambda (x)
3856 (setq
3857 x
3858 ;; " " is indication for keep-date argument.
3859 (delete " " (mapcar (lambda (y) (format-spec y spec)) x)))
3860 (unless (member "" x) (mapconcat 'identity x " ")))
946a5aeb
MA
3861 (tramp-get-method-parameter method 'tramp-copy-args)))
3862 copy-env
3863 (delq
3864 nil
3865 (mapcar
aa485f7c
MA
3866 (lambda (x)
3867 (setq x (mapcar (lambda (y) (format-spec y spec)) x))
3868 (unless (member "" x) (mapconcat 'identity x " ")))
946a5aeb 3869 (tramp-get-method-parameter method 'tramp-copy-env))))
905fb90e
MA
3870
3871 ;; Check for program.
3872 (when (and (fboundp 'executable-find)
3873 (not (let ((default-directory
3874 (tramp-compat-temporary-file-directory)))
3875 (executable-find copy-program))))
3876 (tramp-error
3877 v 'file-error "Cannot find copy program: %s" copy-program))
00d6fd04 3878
4265deab
MA
3879 ;; Set variables for computing the prompt for reading
3880 ;; password.
3881 (setq tramp-current-method (tramp-file-name-method v)
3882 tramp-current-user (tramp-file-name-user v)
3883 tramp-current-host (tramp-file-name-host v))
3884
905fb90e
MA
3885 (unwind-protect
3886 (with-temp-buffer
3887 ;; The default directory must be remote.
3888 (let ((default-directory
946a5aeb
MA
3889 (file-name-directory (if t1 filename newname)))
3890 (process-environment (copy-sequence process-environment)))
905fb90e
MA
3891 ;; Set the transfer process properties.
3892 (tramp-set-connection-property
3893 v "process-name" (buffer-name (current-buffer)))
3894 (tramp-set-connection-property
3895 v "process-buffer" (current-buffer))
946a5aeb
MA
3896 (while copy-env
3897 (tramp-message v 5 "%s=\"%s\"" (car copy-env) (cadr copy-env))
3898 (setenv (pop copy-env) (pop copy-env)))
905fb90e
MA
3899
3900 ;; Use an asynchronous process. By this, password can
3901 ;; be handled. The default directory must be local, in
3902 ;; order to apply the correct `copy-program'. We don't
3903 ;; set a timeout, because the copying of large files can
3904 ;; last longer than 60 secs.
3905 (let ((p (let ((default-directory
3906 (tramp-compat-temporary-file-directory)))
3907 (apply 'start-process
3908 (tramp-get-connection-property
3909 v "process-name" nil)
3910 (tramp-get-connection-property
3911 v "process-buffer" nil)
3912 copy-program
3913 (append copy-args (list source target))))))
3914 (tramp-message
3915 v 6 "%s" (mapconcat 'identity (process-command p) " "))
3916 (tramp-set-process-query-on-exit-flag p nil)
3917 (tramp-process-actions p v tramp-actions-copy-out-of-band))))
00d6fd04 3918
905fb90e
MA
3919 ;; Reset the transfer process properties.
3920 (tramp-set-connection-property v "process-name" nil)
3921 (tramp-set-connection-property v "process-buffer" nil))
00d6fd04 3922
905fb90e
MA
3923 ;; Handle KEEP-DATE argument.
3924 (when (and keep-date (not copy-keep-date))
3925 (set-file-times newname (nth 5 (file-attributes filename))))
01917a18 3926
905fb90e
MA
3927 ;; Set the mode.
3928 (unless (and keep-date copy-keep-date)
3929 (set-file-modes newname (tramp-default-file-modes filename))))
5ec2cc41 3930
905fb90e
MA
3931 ;; If the operation was `rename', delete the original file.
3932 (unless (eq op 'copy)
aac0b0f2
MA
3933 (if (file-regular-p filename)
3934 (delete-file filename)
3935 (delete-directory filename 'recursive))))))
7432277c 3936
fb7933a3 3937(defun tramp-handle-make-directory (dir &optional parents)
00d6fd04 3938 "Like `make-directory' for Tramp files."
ac474af1 3939 (setq dir (expand-file-name dir))
c62c9d08 3940 (with-parsed-tramp-file-name dir nil
c15cdf02 3941 (tramp-flush-directory-property v (file-name-directory localname))
b1d06e75
KG
3942 (save-excursion
3943 (tramp-barf-unless-okay
00d6fd04 3944 v
9c13938d 3945 (format "%s %s"
b1d06e75 3946 (if parents "mkdir -p" "mkdir")
7432277c 3947 (tramp-shell-quote-argument localname))
b1d06e75 3948 "Couldn't make directory %s" dir))))
fb7933a3 3949
c15cdf02 3950(defun tramp-handle-delete-directory (directory &optional recursive)
00d6fd04 3951 "Like `delete-directory' for Tramp files."
ac474af1 3952 (setq directory (expand-file-name directory))
c62c9d08 3953 (with-parsed-tramp-file-name directory nil
aac0b0f2 3954 (tramp-flush-file-property v (file-name-directory localname))
00d6fd04
MA
3955 (tramp-flush-directory-property v localname)
3956 (unless (zerop (tramp-send-command-and-check
3957 v
c15cdf02
MA
3958 (format
3959 "%s %s"
3960 (if recursive "rm -rf" "rmdir")
3961 (tramp-shell-quote-argument localname))))
00d6fd04 3962 (tramp-error v 'file-error "Couldn't delete %s" directory))))
fb7933a3
KG
3963
3964(defun tramp-handle-delete-file (filename)
00d6fd04 3965 "Like `delete-file' for Tramp files."
ac474af1 3966 (setq filename (expand-file-name filename))
c62c9d08 3967 (with-parsed-tramp-file-name filename nil
aac0b0f2 3968 (tramp-flush-file-property v (file-name-directory localname))
00d6fd04
MA
3969 (tramp-flush-file-property v localname)
3970 (unless (zerop (tramp-send-command-and-check
3971 v
3972 (format "rm -f %s"
3973 (tramp-shell-quote-argument localname))))
3974 (tramp-error v 'file-error "Couldn't delete %s" filename))))
fb7933a3
KG
3975
3976;; Dired.
3977
3978;; CCC: This does not seem to be enough. Something dies when
a4aeb9a4 3979;; we try and delete two directories under Tramp :/
fb7933a3
KG
3980(defun tramp-handle-dired-recursive-delete-directory (filename)
3981 "Recursively delete the directory given.
00d6fd04 3982This is like `dired-recursive-delete-directory' for Tramp files."
c62c9d08 3983 (with-parsed-tramp-file-name filename nil
00d6fd04 3984 ;; Run a shell command 'rm -r <localname>'
260821d3 3985 ;; Code shamelessly stolen from the dired implementation and, um, hacked :)
00d6fd04
MA
3986 (unless (file-exists-p filename)
3987 (tramp-error v 'file-error "No such directory: %s" filename))
fb7933a3 3988 ;; Which is better, -r or -R? (-r works for me <daniel@danann.net>)
00d6fd04
MA
3989 (tramp-send-command
3990 v
9c13938d 3991 (format "rm -rf %s" (tramp-shell-quote-argument localname))
00d6fd04
MA
3992 ;; Don't read the output, do it explicitely.
3993 nil t)
fb7933a3
KG
3994 ;; Wait for the remote system to return to us...
3995 ;; This might take a while, allow it plenty of time.
00d6fd04 3996 (tramp-wait-for-output (tramp-get-connection-process v) 120)
fb7933a3 3997 ;; Make sure that it worked...
aac0b0f2 3998 (tramp-flush-file-property v (file-name-directory localname))
c15cdf02 3999 (tramp-flush-directory-property v localname)
07dfe738 4000 (and (file-exists-p filename)
00d6fd04
MA
4001 (tramp-error
4002 v 'file-error "Failed to recursively delete %s" filename))))
bf247b6e 4003
5ec2cc41 4004(defun tramp-handle-dired-compress-file (file &rest ok-flag)
00d6fd04 4005 "Like `dired-compress-file' for Tramp files."
5ec2cc41
KG
4006 ;; OK-FLAG is valid for XEmacs only, but not implemented.
4007 ;; Code stolen mainly from dired-aux.el.
4008 (with-parsed-tramp-file-name file nil
00d6fd04 4009 (tramp-flush-file-property v localname)
5ec2cc41
KG
4010 (save-excursion
4011 (let ((suffixes
4012 (if (not (featurep 'xemacs))
4013 ;; Emacs case
4014 (symbol-value 'dired-compress-file-suffixes)
4015 ;; XEmacs has `dired-compression-method-alist', which is
4016 ;; transformed into `dired-compress-file-suffixes' structure.
4017 (mapcar
aa485f7c
MA
4018 (lambda (x)
4019 (list (concat (regexp-quote (nth 1 x)) "\\'")
4020 nil
4021 (mapconcat 'identity (nth 3 x) " ")))
5ec2cc41
KG
4022 (symbol-value 'dired-compression-method-alist))))
4023 suffix)
4024 ;; See if any suffix rule matches this file name.
4025 (while suffixes
4026 (let (case-fold-search)
4027 (if (string-match (car (car suffixes)) localname)
4028 (setq suffix (car suffixes) suffixes nil))
4029 (setq suffixes (cdr suffixes))))
4030
4031 (cond ((file-symlink-p file)
4032 nil)
4033 ((and suffix (nth 2 suffix))
4034 ;; We found an uncompression rule.
00d6fd04 4035 (tramp-message v 0 "Uncompressing %s..." file)
5ec2cc41 4036 (when (zerop (tramp-send-command-and-check
b593f105
MA
4037 v (concat (nth 2 suffix) " "
4038 (tramp-shell-quote-argument localname))))
00d6fd04 4039 (tramp-message v 0 "Uncompressing %s...done" file)
38c65fca
KG
4040 ;; `dired-remove-file' is not defined in XEmacs
4041 (funcall (symbol-function 'dired-remove-file) file)
5ec2cc41
KG
4042 (string-match (car suffix) file)
4043 (concat (substring file 0 (match-beginning 0)))))
4044 (t
4045 ;; We don't recognize the file as compressed, so compress it.
4046 ;; Try gzip.
00d6fd04 4047 (tramp-message v 0 "Compressing %s..." file)
5ec2cc41 4048 (when (zerop (tramp-send-command-and-check
b593f105
MA
4049 v (concat "gzip -f "
4050 (tramp-shell-quote-argument localname))))
00d6fd04 4051 (tramp-message v 0 "Compressing %s...done" file)
38c65fca
KG
4052 ;; `dired-remove-file' is not defined in XEmacs
4053 (funcall (symbol-function 'dired-remove-file) file)
5ec2cc41
KG
4054 (cond ((file-exists-p (concat file ".gz"))
4055 (concat file ".gz"))
4056 ((file-exists-p (concat file ".z"))
4057 (concat file ".z"))
4058 (t nil)))))))))
fb7933a3 4059
d5b3979c 4060(defun tramp-handle-dired-uncache (dir &optional dir-p)
70c11b0b 4061 "Like `dired-uncache' for Tramp files."
d5b3979c
MA
4062 ;; DIR-P is valid for XEmacs only.
4063 (with-parsed-tramp-file-name
4064 (if (or dir-p (file-directory-p dir)) dir (file-name-directory dir)) nil
70c11b0b
MA
4065 (tramp-flush-file-property v localname)))
4066
fb7933a3
KG
4067;; Pacify byte-compiler. The function is needed on XEmacs only. I'm
4068;; not sure at all that this is the right way to do it, but let's hope
4069;; it works for now, and wait for a guru to point out the Right Way to
4070;; achieve this.
4071;;(eval-when-compile
4072;; (unless (fboundp 'dired-insert-set-properties)
4073;; (fset 'dired-insert-set-properties 'ignore)))
4074;; Gerd suggests this:
4075(eval-when-compile (require 'dired))
4076;; Note that dired is required at run-time, too, when it is needed.
4077;; It is only needed on XEmacs for the function
4078;; `dired-insert-set-properties'.
4079
4080(defun tramp-handle-insert-directory
4081 (filename switches &optional wildcard full-directory-p)
00d6fd04
MA
4082 "Like `insert-directory' for Tramp files."
4083 (setq filename (expand-file-name filename))
4084 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
4085 (if (and (featurep 'ls-lisp)
4086 (not (symbol-value 'ls-lisp-use-insert-directory-program)))
4087 (tramp-run-real-handler
4088 'insert-directory (list filename switches wildcard full-directory-p))
0c0b61f1
MA
4089 (when (stringp switches)
4090 (setq switches (split-string switches)))
4091 (when (and (member "--dired" switches)
8e754ea2 4092 (not (tramp-get-ls-command-with-dired v)))
0c0b61f1 4093 (setq switches (delete "--dired" switches)))
c82c5727 4094 (when wildcard
87bdd2c7
MA
4095 (setq wildcard (tramp-run-real-handler
4096 'file-name-nondirectory (list localname)))
4097 (setq localname (tramp-run-real-handler
4098 'file-name-directory (list localname))))
c82c5727 4099 (unless full-directory-p
0c0b61f1
MA
4100 (setq switches (add-to-list 'switches "-d" 'append)))
4101 (setq switches (mapconcat 'tramp-shell-quote-argument switches " "))
c82c5727 4102 (when wildcard
0c0b61f1
MA
4103 (setq switches (concat switches " " wildcard)))
4104 (tramp-message
4105 v 4 "Inserting directory `ls %s %s', wildcard %s, fulldir %s"
4106 switches filename (if wildcard "yes" "no")
4107 (if full-directory-p "yes" "no"))
00d6fd04
MA
4108 ;; If `full-directory-p', we just say `ls -l FILENAME'.
4109 ;; Else we chdir to the parent directory, then say `ls -ld BASENAME'.
4110 (if full-directory-p
4111 (tramp-send-command
4112 v
fe5facd3 4113 (format "%s %s %s 2>/dev/null"
00d6fd04
MA
4114 (tramp-get-ls-command v)
4115 switches
4116 (if wildcard
4117 localname
4118 (tramp-shell-quote-argument (concat localname ".")))))
4119 (tramp-barf-unless-okay
4120 v
4121 (format "cd %s" (tramp-shell-quote-argument
87bdd2c7
MA
4122 (tramp-run-real-handler
4123 'file-name-directory (list localname))))
00d6fd04 4124 "Couldn't `cd %s'"
87bdd2c7
MA
4125 (tramp-shell-quote-argument
4126 (tramp-run-real-handler 'file-name-directory (list localname))))
00d6fd04
MA
4127 (tramp-send-command
4128 v
4129 (format "%s %s %s"
4130 (tramp-get-ls-command v)
4131 switches
4132 (if (or wildcard
87bdd2c7
MA
4133 (zerop (length
4134 (tramp-run-real-handler
4135 'file-name-nondirectory (list localname)))))
00d6fd04
MA
4136 ""
4137 (tramp-shell-quote-argument
87bdd2c7
MA
4138 (tramp-run-real-handler
4139 'file-name-nondirectory (list localname)))))))
8e754ea2
MA
4140 (let ((beg (point)))
4141 ;; We cannot use `insert-buffer-substring' because the Tramp
4142 ;; buffer changes its contents before insertion due to calling
4143 ;; `expand-file' and alike.
4144 (insert
4145 (with-current-buffer (tramp-get-buffer v)
4146 (buffer-string)))
4147
4148 ;; Check for "--dired" output.
8e754ea2 4149 (forward-line -2)
7f4d4a97
MA
4150 (when (looking-at "//SUBDIRED//")
4151 (forward-line -1))
8e754ea2 4152 (when (looking-at "//DIRED//")
7ba1d9c2 4153 (let ((end (tramp-compat-line-end-position))
8e754ea2
MA
4154 (linebeg (point)))
4155 ;; Now read the numeric positions of file names.
4156 (goto-char linebeg)
4157 (forward-word 1)
4158 (forward-char 3)
4159 (while (< (point) end)
4160 (let ((start (+ beg (read (current-buffer))))
4161 (end (+ beg (read (current-buffer)))))
7f49fe46 4162 (if (memq (char-after end) '(?\n ?\ ))
8e754ea2 4163 ;; End is followed by \n or by " -> ".
fe5facd3
MA
4164 (put-text-property start end 'dired-filename t))))))
4165 ;; Remove trailing lines.
4166 (goto-char (tramp-compat-line-beginning-position))
4167 (while (looking-at "//")
4168 (forward-line 1)
4169 (delete-region (match-beginning 0) (point)))
0c0b61f1
MA
4170
4171 ;; The inserted file could be from somewhere else.
4172 (when (and (not wildcard) (not full-directory-p))
4173 (goto-char (point-max))
e5c70c41
MA
4174 (when (file-symlink-p filename)
4175 (goto-char (search-backward "->" beg 'noerror)))
0c0b61f1
MA
4176 (search-backward
4177 (if (zerop (length (file-name-nondirectory filename)))
4178 "."
4179 (file-name-nondirectory filename))
4180 beg 'noerror)
4181 (replace-match (file-relative-name filename) t))
4182
fe5facd3 4183 (goto-char (point-max))))))
fb7933a3 4184
fb7933a3 4185(defun tramp-handle-unhandled-file-name-directory (filename)
00d6fd04 4186 "Like `unhandled-file-name-directory' for Tramp files."
8a798e41
MA
4187 ;; With Emacs 23, we could simply return `nil'. But we must keep it
4188 ;; for backward compatibility.
ce3f516f 4189 (expand-file-name "~/"))
fb7933a3
KG
4190
4191;; Canonicalization of file names.
4192
fb7933a3 4193(defun tramp-handle-expand-file-name (name &optional dir)
00d6fd04 4194 "Like `expand-file-name' for Tramp files.
7432277c
KG
4195If the localname part of the given filename starts with \"/../\" then
4196the result will be a local, non-Tramp, filename."
fb7933a3
KG
4197 ;; If DIR is not given, use DEFAULT-DIRECTORY or "/".
4198 (setq dir (or dir default-directory "/"))
4199 ;; Unless NAME is absolute, concat DIR and NAME.
4200 (unless (file-name-absolute-p name)
4201 (setq name (concat (file-name-as-directory dir) name)))
00d6fd04 4202 ;; If NAME is not a Tramp file, run the real handler.
fb7933a3 4203 (if (not (tramp-tramp-file-p name))
00d6fd04 4204 (tramp-run-real-handler 'expand-file-name (list name nil))
fb7933a3 4205 ;; Dissect NAME.
c62c9d08 4206 (with-parsed-tramp-file-name name nil
87bdd2c7 4207 (unless (tramp-run-real-handler 'file-name-absolute-p (list localname))
7432277c 4208 (setq localname (concat "~/" localname)))
00d6fd04
MA
4209 ;; Tilde expansion if necessary. This needs a shell which
4210 ;; groks tilde expansion! The function `tramp-find-shell' is
4211 ;; supposed to find such a shell on the remote host. Please
4212 ;; tell me about it when this doesn't work on your system.
4213 (when (string-match "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname)
4214 (let ((uname (match-string 1 localname))
4215 (fname (match-string 2 localname)))
4216 ;; We cannot simply apply "~/", because under sudo "~/" is
4217 ;; expanded to the local user home directory but to the
4218 ;; root home directory. On the other hand, using always
4219 ;; the default user name for tilde expansion is not
4220 ;; appropriate either, because ssh and companions might
4221 ;; use a user name from the config file.
4222 (when (and (string-equal uname "~")
4223 (string-match "\\`su\\(do\\)?\\'" method))
4224 (setq uname (concat uname user)))
4225 (setq uname
b593f105
MA
4226 (with-connection-property v uname
4227 (tramp-send-command
4228 v (format "cd %s; pwd" (tramp-shell-quote-argument uname)))
4229 (with-current-buffer (tramp-get-buffer v)
4230 (goto-char (point-min))
4231 (buffer-substring
4232 (point) (tramp-compat-line-end-position)))))
00d6fd04
MA
4233 (setq localname (concat uname fname))))
4234 ;; There might be a double slash, for example when "~/"
cb85dcd0 4235 ;; expands to "/". Remove this.
00d6fd04
MA
4236 (while (string-match "//" localname)
4237 (setq localname (replace-match "/" t t localname)))
4238 ;; No tilde characters in file name, do normal
a17632c1
MA
4239 ;; `expand-file-name' (this does "/./" and "/../"). We bind
4240 ;; `directory-sep-char' here for XEmacs on Windows, which would
4241 ;; otherwise use backslash. `default-directory' is bound,
4242 ;; because on Windows there would be problems with UNC shares or
4243 ;; Cygwin mounts.
aff67808
MA
4244 (let ((directory-sep-char ?/)
4245 (default-directory (tramp-compat-temporary-file-directory)))
4246 (tramp-make-tramp-file-name
4247 method user host
4248 (tramp-drop-volume-letter
87bdd2c7
MA
4249 (tramp-run-real-handler
4250 'expand-file-name (list localname))))))))
00d6fd04 4251
c23c3394
MA
4252(defun tramp-replace-environment-variables (filename)
4253 "Replace environment variables in FILENAME.
4254Return the string with the replaced variables."
2e271195 4255 (save-match-data
ec5145d6 4256 (let ((idx (string-match "$\\(\\w+\\)" filename)))
2e271195 4257 ;; `$' is coded as `$$'.
ec5145d6
MA
4258 (when (and idx
4259 (or (zerop idx) (not (eq ?$ (aref filename (1- idx)))))
4260 (getenv (match-string 1 filename)))
2e271195
MA
4261 (setq filename
4262 (replace-match
4263 (substitute-in-file-name (match-string 0 filename))
4264 t nil filename)))
4265 filename)))
c23c3394 4266
00d6fd04
MA
4267(defun tramp-handle-substitute-in-file-name (filename)
4268 "Like `substitute-in-file-name' for Tramp files.
4269\"//\" and \"/~\" substitute only in the local filename part.
4270If the URL Tramp syntax is chosen, \"//\" as method delimeter and \"/~\" at
4271beginning of local filename are not substituted."
c23c3394
MA
4272 ;; First, we must replace environment variables.
4273 (setq filename (tramp-replace-environment-variables filename))
00d6fd04
MA
4274 (with-parsed-tramp-file-name filename nil
4275 (if (equal tramp-syntax 'url)
4276 ;; We need to check localname only. The other parts cannot contain
4277 ;; "//" or "/~".
4278 (if (and (> (length localname) 1)
4279 (or (string-match "//" localname)
4280 (string-match "/~" localname 1)))
4281 (tramp-run-real-handler 'substitute-in-file-name (list filename))
4282 (tramp-make-tramp-file-name
4283 (when method (substitute-in-file-name method))
4284 (when user (substitute-in-file-name user))
4285 (when host (substitute-in-file-name host))
87bdd2c7
MA
4286 (when localname
4287 (tramp-run-real-handler
4288 'substitute-in-file-name (list localname)))))
00d6fd04
MA
4289 ;; Ignore in LOCALNAME everything before "//" or "/~".
4290 (when (and (stringp localname) (string-match ".+?/\\(/\\|~\\)" localname))
4291 (setq filename
b08104a0
MA
4292 (concat (file-remote-p filename)
4293 (replace-match "\\1" nil nil localname)))
00d6fd04
MA
4294 ;; "/m:h:~" does not work for completion. We use "/m:h:~/".
4295 (when (string-match "~$" filename)
4296 (setq filename (concat filename "/"))))
4297 (tramp-run-real-handler 'substitute-in-file-name (list filename)))))
4298
4299;; In XEmacs, electricity is implemented via a key map for ?/ and ?~,
4300;; which calls corresponding functions (see minibuf.el).
4301(when (fboundp 'minibuffer-electric-separator)
9e6ab520 4302 (mapc
aa485f7c
MA
4303 (lambda (x)
4304 (eval
4305 `(defadvice ,x
4306 (around ,(intern (format "tramp-advice-%s" x)) activate)
4307 "Invoke `substitute-in-file-name' for Tramp files."
4308 (if (and (symbol-value 'minibuffer-electric-file-name-behavior)
4309 (tramp-tramp-file-p (buffer-substring)))
4310 ;; We don't need to handle `last-input-event', because
4311 ;; due to the key map we know it must be ?/ or ?~.
4312 (let ((s (concat (buffer-substring (point-min) (point))
4313 (string last-command-char))))
4314 (delete-region (point-min) (point))
4315 (insert (substitute-in-file-name s))
4316 (setq ad-return-value last-command-char))
d7ec1df7
MA
4317 ad-do-it)))
4318 (eval
4319 `(add-hook
4320 'tramp-unload-hook
4321 (lambda ()
4322 (ad-remove-advice ',x 'around ',(intern (format "tramp-advice-%s" x)))
4323 (ad-activate ',x)))))
00d6fd04
MA
4324
4325 '(minibuffer-electric-separator
4326 minibuffer-electric-tilde)))
4327
4328
0664ff72 4329;;; Remote commands:
fb7933a3 4330
00d6fd04
MA
4331(defun tramp-handle-executable-find (command)
4332 "Like `executable-find' for Tramp files."
4333 (with-parsed-tramp-file-name default-directory nil
f84638eb 4334 (tramp-find-executable v command (tramp-get-remote-path v) t)))
00d6fd04
MA
4335
4336;; We use BUFFER also as connection buffer during setup. Because of
4337;; this, its original contents must be saved, and restored once
4338;; connection has been setup.
4339(defun tramp-handle-start-file-process (name buffer program &rest args)
4340 "Like `start-file-process' for Tramp files."
4341 (with-parsed-tramp-file-name default-directory nil
9fb2cdc5
GM
4342 (unless (stringp program)
4343 (tramp-error
4344 v 'file-error "pty association is not supported for `%s'" name))
00d6fd04 4345 (unwind-protect
263c02ef
MA
4346 (let ((command (format "cd %s; exec %s"
4347 (tramp-shell-quote-argument localname)
4348 (mapconcat 'tramp-shell-quote-argument
4349 (cons program args) " ")))
4350 (name1 name)
38d63e6a 4351 (i 0))
2296b54d 4352 (unless buffer
6ce63faf 4353 ;; BUFFER can be nil. We use a temporary buffer.
2296b54d 4354 (setq buffer (generate-new-buffer tramp-temp-buffer-name)))
38d63e6a
MA
4355 (while (get-process name1)
4356 ;; NAME must be unique as process name.
4357 (setq i (1+ i)
4358 name1 (format "%s<%d>" name i)))
4359 (setq name name1)
00d6fd04
MA
4360 ;; Set the new process properties.
4361 (tramp-set-connection-property v "process-name" name)
2296b54d 4362 (tramp-set-connection-property v "process-buffer" buffer)
00d6fd04 4363 ;; Activate narrowing in order to save BUFFER contents.
11c71217
MA
4364 ;; Clear also the modification time; otherwise we might be
4365 ;; interrupted by `verify-visited-file-modtime'.
00d6fd04 4366 (with-current-buffer (tramp-get-connection-buffer v)
11c71217 4367 (clear-visited-file-modtime)
00d6fd04 4368 (narrow-to-region (point-max) (point-max)))
263c02ef 4369 ;; Send the command. `tramp-send-command' opens a new
00d6fd04 4370 ;; connection.
263c02ef 4371 (tramp-send-command v command nil t) ; nooutput
6ce63faf
MA
4372 ;; Set query flag for this process.
4373 (tramp-set-process-query-on-exit-flag
4374 (tramp-get-connection-process v) t)
00d6fd04
MA
4375 ;; Return process.
4376 (tramp-get-connection-process v))
4377 ;; Save exit.
ce3f516f 4378 (with-current-buffer (tramp-get-connection-buffer v)
6ce63faf
MA
4379 (if (string-match tramp-temp-buffer-name (buffer-name))
4380 (progn
4381 (set-process-buffer (tramp-get-connection-process v) nil)
4382 (kill-buffer (current-buffer)))
4383 (widen)
4384 (goto-char (point-max))))
00d6fd04
MA
4385 (tramp-set-connection-property v "process-name" nil)
4386 (tramp-set-connection-property v "process-buffer" nil))))
4387
4388(defun tramp-handle-process-file
4389 (program &optional infile destination display &rest args)
4390 "Like `process-file' for Tramp files."
4391 ;; The implementation is not complete yet.
4392 (when (and (numberp destination) (zerop destination))
4393 (error "Implementation does not handle immediate return"))
4394
4395 (with-parsed-tramp-file-name default-directory nil
a6e96327 4396 (let (command input tmpinput stderr tmpstderr outbuf ret)
00d6fd04
MA
4397 ;; Compute command.
4398 (setq command (mapconcat 'tramp-shell-quote-argument
4399 (cons program args) " "))
4400 ;; Determine input.
4401 (if (null infile)
4402 (setq input "/dev/null")
4403 (setq infile (expand-file-name infile))
4404 (if (tramp-equal-remote default-directory infile)
4405 ;; INFILE is on the same remote host.
4406 (setq input (with-parsed-tramp-file-name infile nil localname))
4407 ;; INFILE must be copied to remote host.
a6e96327
MA
4408 (setq input (tramp-make-tramp-temp-file v)
4409 tmpinput (tramp-make-tramp-file-name method user host input))
4410 (copy-file infile tmpinput t)))
00d6fd04
MA
4411 (when input (setq command (format "%s <%s" command input)))
4412
4413 ;; Determine output.
4414 (cond
bede3e9f 4415 ;; Just a buffer.
00d6fd04
MA
4416 ((bufferp destination)
4417 (setq outbuf destination))
bede3e9f 4418 ;; A buffer name.
00d6fd04
MA
4419 ((stringp destination)
4420 (setq outbuf (get-buffer-create destination)))
4421 ;; (REAL-DESTINATION ERROR-DESTINATION)
4422 ((consp destination)
bede3e9f 4423 ;; output.
00d6fd04
MA
4424 (cond
4425 ((bufferp (car destination))
4426 (setq outbuf (car destination)))
4427 ((stringp (car destination))
0664ff72
MA
4428 (setq outbuf (get-buffer-create (car destination))))
4429 ((car destination)
4430 (setq outbuf (current-buffer))))
bede3e9f 4431 ;; stderr.
00d6fd04
MA
4432 (cond
4433 ((stringp (cadr destination))
4434 (setcar (cdr destination) (expand-file-name (cadr destination)))
4435 (if (tramp-equal-remote default-directory (cadr destination))
4436 ;; stderr is on the same remote host.
4437 (setq stderr (with-parsed-tramp-file-name
4438 (cadr destination) nil localname))
4439 ;; stderr must be copied to remote host. The temporary
4440 ;; file must be deleted after execution.
a6e96327
MA
4441 (setq stderr (tramp-make-tramp-temp-file v)
4442 tmpstderr (tramp-make-tramp-file-name
4443 method user host stderr))))
bede3e9f 4444 ;; stderr to be discarded.
00d6fd04
MA
4445 ((null (cadr destination))
4446 (setq stderr "/dev/null"))))
4447 ;; 't
4448 (destination
4449 (setq outbuf (current-buffer))))
4450 (when stderr (setq command (format "%s 2>%s" command stderr)))
4451
00d6fd04
MA
4452 ;; Send the command. It might not return in time, so we protect it.
4453 (condition-case nil
4454 (unwind-protect
293c24f9
MA
4455 (setq ret
4456 (tramp-send-command-and-check
4457 v (format "\\cd %s; %s"
4458 (tramp-shell-quote-argument localname)
b593f105
MA
4459 command)
4460 nil t))
00d6fd04
MA
4461 ;; We should show the output anyway.
4462 (when outbuf
293c24f9
MA
4463 (with-current-buffer outbuf
4464 (insert
4465 (with-current-buffer (tramp-get-connection-buffer v)
4466 (buffer-string))))
00d6fd04 4467 (when display (display-buffer outbuf))))
260821d3
MA
4468 ;; When the user did interrupt, we should do it also. We use
4469 ;; return code -1 as marker.
4470 (quit
4471 (kill-buffer (tramp-get-connection-buffer v))
4472 (setq ret -1))
4473 ;; Handle errors.
00d6fd04
MA
4474 (error
4475 (kill-buffer (tramp-get-connection-buffer v))
4476 (setq ret 1)))
a6e96327 4477
a6e96327
MA
4478 ;; Provide error file.
4479 (when tmpstderr (rename-file tmpstderr (cadr destination) t))
263c02ef 4480
260821d3
MA
4481 ;; Cleanup. We remove all file cache values for the connection,
4482 ;; because the remote process could have changed them.
a6e96327 4483 (when tmpinput (delete-file tmpinput))
946a5aeb
MA
4484
4485 ;; `process-file-side-effects' has been introduced with GNU
4486 ;; Emacs 23.2. If set to `nil', no remote file will be changed
4487 ;; by `program'. If it doesn't exist, we assume its default
4488 ;; value 't'.
4489 (unless (and (boundp 'process-file-side-effects)
4490 (not (symbol-value 'process-file-side-effects)))
4491 (tramp-flush-directory-property v ""))
4492
00d6fd04 4493 ;; Return exit status.
260821d3
MA
4494 (if (equal ret -1)
4495 (keyboard-quit)
4496 ret))))
00d6fd04 4497
a4aeb9a4
MA
4498(defun tramp-local-call-process
4499 (program &optional infile destination display &rest args)
4500 "Calls `call-process' on the local host.
4501This is needed because for some Emacs flavors Tramp has
4502defadviced `call-process' to behave like `process-file'. The
4503Lisp error raised when PROGRAM is nil is trapped also, returning 1."
4504 (let ((default-directory
4505 (if (file-remote-p default-directory)
4506 (tramp-compat-temporary-file-directory)
4507 default-directory)))
4508 (if (executable-find program)
4509 (apply 'call-process program infile destination display args)
4510 1)))
4511
00d6fd04
MA
4512(defun tramp-handle-call-process-region
4513 (start end program &optional delete buffer display &rest args)
4514 "Like `call-process-region' for Tramp files."
258800f8 4515 (let ((tmpfile (tramp-compat-make-temp-file "")))
00d6fd04
MA
4516 (write-region start end tmpfile)
4517 (when delete (delete-region start end))
4518 (unwind-protect
4519 (apply 'call-process program tmpfile buffer display args)
4520 (delete-file tmpfile))))
4521
4522(defun tramp-handle-shell-command
4523 (command &optional output-buffer error-buffer)
4524 "Like `shell-command' for Tramp files."
ce3f516f 4525 (let* ((asynchronous (string-match "[ \t]*&[ \t]*\\'" command))
b8bfcf96
MA
4526 ;; We cannot use `shell-file-name' and `shell-command-switch',
4527 ;; they are variables of the local host.
4528 (args (list "/bin/sh" "-c" (substring command 0 asynchronous)))
5d2ebd96 4529 current-buffer-p
ce3f516f 4530 (output-buffer
27e813fe
MA
4531 (cond
4532 ((bufferp output-buffer) output-buffer)
4533 ((stringp output-buffer) (get-buffer-create output-buffer))
5d2ebd96
AS
4534 (output-buffer
4535 (setq current-buffer-p t)
4536 (current-buffer))
42bc9b6d 4537 (t (get-buffer-create
27e813fe
MA
4538 (if asynchronous
4539 "*Async Shell Command*"
4540 "*Shell Command Output*")))))
4541 (error-buffer
4542 (cond
4543 ((bufferp error-buffer) error-buffer)
4544 ((stringp error-buffer) (get-buffer-create error-buffer))))
ce3f516f 4545 (buffer
27e813fe 4546 (if (and (not asynchronous) error-buffer)
ce3f516f
MA
4547 (with-parsed-tramp-file-name default-directory nil
4548 (list output-buffer (tramp-make-tramp-temp-file v)))
42bc9b6d 4549 output-buffer))
cfb5c0db 4550 (p (get-buffer-process output-buffer)))
42bc9b6d
MA
4551
4552 ;; Check whether there is another process running. Tramp does not
4553 ;; support 2 (asynchronous) processes in parallel.
cfb5c0db 4554 (when p
42bc9b6d 4555 (if (yes-or-no-p "A command is running. Kill it? ")
699a11fb
GM
4556 (condition-case nil
4557 (kill-process p)
4558 (error nil))
42bc9b6d
MA
4559 (error "Shell command in progress")))
4560
f34db316
AS
4561 (if current-buffer-p
4562 (progn
4563 (barf-if-buffer-read-only)
4564 (push-mark nil t))
5d2ebd96
AS
4565 (with-current-buffer output-buffer
4566 (setq buffer-read-only nil)
4567 (erase-buffer)))
42bc9b6d 4568
5d2ebd96 4569 (if (and (not current-buffer-p) (integerp asynchronous))
42bc9b6d
MA
4570 (prog1
4571 ;; Run the process.
3412f35d 4572 (apply 'start-file-process "*Async Shell*" buffer args)
42bc9b6d 4573 ;; Display output.
cfb5c0db
MA
4574 (pop-to-buffer output-buffer)
4575 (setq mode-line-process '(":%s"))
4576 (require 'shell) (shell-mode))
42bc9b6d
MA
4577
4578 (prog1
4579 ;; Run the process.
4580 (apply 'process-file (car args) nil buffer nil (cdr args))
4581 ;; Insert error messages if they were separated.
4582 (when (listp buffer)
4583 (with-current-buffer error-buffer
4584 (insert-file-contents (cadr buffer)))
4585 (delete-file (cadr buffer)))
f34db316
AS
4586 (if current-buffer-p
4587 ;; This is like exchange-point-and-mark, but doesn't
4588 ;; activate the mark. It is cleaner to avoid activation,
4589 ;; even though the command loop would deactivate the mark
4590 ;; because we inserted text.
4591 (goto-char (prog1 (mark t)
4592 (set-marker (mark-marker) (point)
4593 (current-buffer))))
4594 ;; There's some output, display it.
4595 (when (with-current-buffer output-buffer (> (point-max) (point-min)))
4596 (if (functionp 'display-message-or-buffer)
4597 (funcall (symbol-function 'display-message-or-buffer)
4598 output-buffer)
4599 (pop-to-buffer output-buffer))))))))
00d6fd04
MA
4600
4601;; File Editing.
4602
4603(defvar tramp-handle-file-local-copy-hook nil
4604 "Normal hook to be run at the end of `tramp-handle-file-local-copy'.")
4605
fb7933a3 4606(defun tramp-handle-file-local-copy (filename)
00d6fd04 4607 "Like `file-local-copy' for Tramp files."
0f205eee 4608
c62c9d08 4609 (with-parsed-tramp-file-name filename nil
2988341a
MA
4610 (unless (file-exists-p filename)
4611 (tramp-error
4612 v 'file-error
4613 "Cannot make local copy of non-existing file `%s'" filename))
4614
0f205eee 4615 (let ((rem-enc (tramp-get-remote-coding v "remote-encoding"))
00d6fd04 4616 (loc-dec (tramp-get-local-coding v "local-decoding"))
258800f8 4617 (tmpfile (tramp-compat-make-temp-file filename)))
5ec2cc41 4618
2988341a
MA
4619 (condition-case err
4620 (cond
4621 ;; `copy-file' handles direct copy and out-of-band methods.
4622 ((or (tramp-local-host-p v)
7f49fe46
MA
4623 (tramp-method-out-of-band-p
4624 v (nth 7 (file-attributes filename))))
2988341a
MA
4625 (copy-file filename tmpfile t t))
4626
4627 ;; Use inline encoding for file transfer.
4628 (rem-enc
4629 (save-excursion
4630 (tramp-message v 5 "Encoding remote file %s..." filename)
4631 (tramp-barf-unless-okay
4632 v
4633 (format "%s < %s" rem-enc (tramp-shell-quote-argument localname))
4634 "Encoding remote file failed")
4635 (tramp-message v 5 "Encoding remote file %s...done" filename)
4636
4637 (if (and (symbolp loc-dec) (fboundp loc-dec))
4638 ;; If local decoding is a function, we call it. We
4639 ;; must disable multibyte, because
4640 ;; `uudecode-decode-region' doesn't handle it
4641 ;; correctly.
0f205eee
MA
4642 (with-temp-buffer
4643 (set-buffer-multibyte nil)
4644 (insert-buffer-substring (tramp-get-buffer v))
4645 (tramp-message
4646 v 5 "Decoding remote file %s with function %s..."
4647 filename loc-dec)
4648 (funcall loc-dec (point-min) (point-max))
aa485f7c
MA
4649 ;; Unset `file-name-handler-alist'. Otherwise,
4650 ;; epa-file gets confused.
4651 (let (file-name-handler-alist
4652 (coding-system-for-write 'binary))
2988341a
MA
4653 (write-region (point-min) (point-max) tmpfile)))
4654
4655 ;; If tramp-decoding-function is not defined for this
4656 ;; method, we invoke tramp-decoding-command instead.
4657 (let ((tmpfile2 (tramp-compat-make-temp-file filename)))
aa485f7c
MA
4658 ;; Unset `file-name-handler-alist'. Otherwise,
4659 ;; epa-file gets confused.
4660 (let (file-name-handler-alist
4661 (coding-system-for-write 'binary))
2988341a
MA
4662 (write-region (point-min) (point-max) tmpfile2))
4663 (tramp-message
4664 v 5 "Decoding remote file %s with command %s..."
4665 filename loc-dec)
4666 (unwind-protect
4667 (tramp-call-local-coding-command loc-dec tmpfile2 tmpfile)
4668 (delete-file tmpfile2))))
4669
4670 (tramp-message v 5 "Decoding remote file %s...done" filename)
4671 ;; Set proper permissions.
b86c1cd8 4672 (set-file-modes tmpfile (tramp-default-file-modes filename))
2988341a
MA
4673 ;; Set local user ownership.
4674 (tramp-set-file-uid-gid tmpfile)))
4675
4676 ;; Oops, I don't know what to do.
4677 (t (tramp-error
4678 v 'file-error "Wrong method specification for `%s'" method)))
4679
4680 ;; Error handling.
4681 ((error quit)
4682 (delete-file tmpfile)
4683 (signal (car err) (cdr err))))
0f205eee 4684
00d6fd04 4685 (run-hooks 'tramp-handle-file-local-copy-hook)
94be87e8 4686 tmpfile)))
fb7933a3 4687
bce04fee 4688(defun tramp-handle-file-remote-p (filename &optional identification connected)
00d6fd04 4689 "Like `file-remote-p' for Tramp files."
d5b3979c
MA
4690 (let ((tramp-verbose 3))
4691 (when (tramp-tramp-file-p filename)
4692 (let* ((v (tramp-dissect-file-name filename))
4693 (p (tramp-get-connection-process v))
4694 (c (and p (processp p) (memq (process-status p) '(run open)))))
4695 ;; We expand the file name only, if there is already a connection.
4696 (with-parsed-tramp-file-name
4697 (if c (expand-file-name filename) filename) nil
4698 (and (or (not connected) c)
4699 (cond
4700 ((eq identification 'method) method)
4701 ((eq identification 'user) user)
4702 ((eq identification 'host) host)
4703 ((eq identification 'localname) localname)
4704 (t (tramp-make-tramp-file-name method user host "")))))))))
fb7933a3 4705
eb562962
MA
4706(defun tramp-find-file-name-coding-system-alist (filename tmpname)
4707 "Like `find-operation-coding-system' for Tramp filenames.
4708Tramp's `insert-file-contents' and `write-region' work over
4709temporary file names. If `file-coding-system-alist' contains an
4710expression, which matches more than the file name suffix, the
4711coding system might not be determined. This function repairs it."
4712 (let (result)
4713 (dolist (elt file-coding-system-alist result)
4714 (when (and (consp elt) (string-match (car elt) filename))
4715 ;; We found a matching entry in `file-coding-system-alist'.
4716 ;; So we add a similar entry, but with the temporary file name
4717 ;; as regexp.
4718 (add-to-list
4719 'result (cons (regexp-quote tmpname) (cdr elt)) 'append)))))
4720
fb7933a3
KG
4721(defun tramp-handle-insert-file-contents
4722 (filename &optional visit beg end replace)
00d6fd04 4723 "Like `insert-file-contents' for Tramp files."
fb7933a3
KG
4724 (barf-if-buffer-read-only)
4725 (setq filename (expand-file-name filename))
736ac90f 4726 (let (coding-system-used result local-copy remote-copy)
2ac33804
MA
4727 (with-parsed-tramp-file-name filename nil
4728 (unwind-protect
70c11b0b
MA
4729 (if (not (file-exists-p filename))
4730 ;; We don't raise a Tramp error, because it might be
4731 ;; suppressed, like in `find-file-noselect-1'.
4732 (signal 'file-error
4733 (list "File not found on remote host" filename))
4734
4735 (if (and (tramp-local-host-p v)
4736 (let (file-name-handler-alist)
4737 (file-readable-p localname)))
4738 ;; Short track: if we are on the local host, we can
4739 ;; run directly.
4740 (setq result
4741 (tramp-run-real-handler
4742 'insert-file-contents
4743 (list localname visit beg end replace)))
4744
736ac90f
MA
4745 ;; When we shall insert only a part of the file, we copy
4746 ;; this part.
4747 (when (or beg end)
4748 (setq remote-copy (tramp-make-tramp-temp-file v))
4749 (tramp-send-command
4750 v
4751 (cond
4752 ((and beg end)
4753 (format "tail -c +%d %s | head -c +%d >%s"
4754 (1+ beg) (tramp-shell-quote-argument localname)
4755 (- end beg) remote-copy))
4756 (beg
4757 (format "tail -c +%d %s >%s"
4758 (1+ beg) (tramp-shell-quote-argument localname)
4759 remote-copy))
4760 (end
4761 (format "head -c +%d %s >%s"
4762 (1+ end) (tramp-shell-quote-argument localname)
4763 remote-copy)))))
4764
70c11b0b
MA
4765 ;; `insert-file-contents-literally' takes care to avoid
4766 ;; calling jka-compr. By let-binding
4767 ;; `inhibit-file-name-operation', we propagate that care
4768 ;; to the `file-local-copy' operation.
4769 (setq local-copy
4770 (let ((inhibit-file-name-operation
4771 (when (eq inhibit-file-name-operation
4772 'insert-file-contents)
4773 'file-local-copy)))
b88f2d0a
MA
4774 (cond
4775 ((stringp remote-copy)
4776 (file-local-copy
4777 (tramp-make-tramp-file-name
4778 method user host remote-copy)))
4779 ((stringp tramp-temp-buffer-file-name)
4780 (copy-file filename tramp-temp-buffer-file-name 'ok)
4781 tramp-temp-buffer-file-name)
4782 (t (file-local-copy filename)))))
4783
4784 (when (and (null remote-copy)
4785 (tramp-get-method-parameter
4786 method 'tramp-copy-keep-tmpfile))
4787 ;; We keep the local file for performance reasons,
4788 ;; useful for "rsync".
4789 (set-file-modes local-copy (tramp-octal-to-decimal "0600"))
4790 (setq tramp-temp-buffer-file-name local-copy)
4791 (put 'tramp-temp-buffer-file-name 'permanent-local t))
4792
70c11b0b
MA
4793 (tramp-message
4794 v 4 "Inserting local temp file `%s'..." local-copy)
4795
4796 ;; We must ensure that `file-coding-system-alist'
4797 ;; matches `local-copy'.
4798 (let ((file-coding-system-alist
4799 (tramp-find-file-name-coding-system-alist
4800 filename local-copy)))
4801 (setq result
4802 (insert-file-contents
736ac90f 4803 local-copy nil nil nil replace))
70c11b0b
MA
4804 ;; Now `last-coding-system-used' has right value.
4805 ;; Remember it.
4806 (when (boundp 'last-coding-system-used)
4807 (setq coding-system-used
4808 (symbol-value 'last-coding-system-used))))
8d60099b 4809
70c11b0b
MA
4810 (tramp-message
4811 v 4 "Inserting local temp file `%s'...done" local-copy)
4812 (when (boundp 'last-coding-system-used)
2ac33804 4813 (set 'last-coding-system-used coding-system-used))))
70c11b0b 4814
2ac33804
MA
4815 ;; Save exit.
4816 (progn
4817 (when visit
4818 (setq buffer-file-name filename)
4819 (setq buffer-read-only (not (file-writable-p filename)))
4820 (set-visited-file-modtime)
4821 (set-buffer-modified-p nil))
b88f2d0a
MA
4822 (when (and (stringp local-copy)
4823 (or remote-copy (null tramp-temp-buffer-file-name)))
2ac33804
MA
4824 (delete-file local-copy))
4825 (when (stringp remote-copy)
4826 (delete-file
4827 (tramp-make-tramp-file-name method user host remote-copy))))))
70c11b0b
MA
4828
4829 ;; Result.
4830 (list (expand-file-name filename)
4831 (cadr result))))
fb7933a3 4832
94be87e8
MA
4833;; This is needed for XEmacs only. Code stolen from files.el.
4834(defun tramp-handle-insert-file-contents-literally
4835 (filename &optional visit beg end replace)
4836 "Like `insert-file-contents-literally' for Tramp files."
4837 (let ((format-alist nil)
4838 (after-insert-file-functions nil)
4839 (coding-system-for-read 'no-conversion)
4840 (coding-system-for-write 'no-conversion)
4841 (find-buffer-file-type-function
4842 (if (fboundp 'find-buffer-file-type)
4843 (symbol-function 'find-buffer-file-type)
4844 nil))
4845 (inhibit-file-name-handlers '(jka-compr-handler image-file-handler))
4846 (inhibit-file-name-operation 'insert-file-contents))
4847 (unwind-protect
4848 (progn
4849 (fset 'find-buffer-file-type (lambda (filename) t))
4850 (insert-file-contents filename visit beg end replace))
70c11b0b 4851 ;; Save exit.
94be87e8
MA
4852 (if find-buffer-file-type-function
4853 (fset 'find-buffer-file-type find-buffer-file-type-function)
4854 (fmakunbound 'find-buffer-file-type)))))
4855
38c65fca 4856(defun tramp-handle-find-backup-file-name (filename)
00d6fd04 4857 "Like `find-backup-file-name' for Tramp files."
07dfe738
KG
4858 (with-parsed-tramp-file-name filename nil
4859 ;; We set both variables. It doesn't matter whether it is
4860 ;; Emacs or XEmacs
4861 (let ((backup-directory-alist
4862 ;; Emacs case
4863 (when (boundp 'backup-directory-alist)
b86c1cd8 4864 (if (symbol-value 'tramp-backup-directory-alist)
07dfe738 4865 (mapcar
aa485f7c
MA
4866 (lambda (x)
4867 (cons
4868 (car x)
4869 (if (and (stringp (cdr x))
4870 (file-name-absolute-p (cdr x))
4871 (not (tramp-file-name-p (cdr x))))
4872 (tramp-make-tramp-file-name method user host (cdr x))
4873 (cdr x))))
07dfe738
KG
4874 (symbol-value 'tramp-backup-directory-alist))
4875 (symbol-value 'backup-directory-alist))))
4876
4877 (bkup-backup-directory-info
4878 ;; XEmacs case
4879 (when (boundp 'bkup-backup-directory-info)
b86c1cd8 4880 (if (symbol-value 'tramp-bkup-backup-directory-info)
07dfe738 4881 (mapcar
aa485f7c
MA
4882 (lambda (x)
4883 (nconc
4884 (list (car x))
4885 (list
4886 (if (and (stringp (car (cdr x)))
4887 (file-name-absolute-p (car (cdr x)))
4888 (not (tramp-file-name-p (car (cdr x)))))
4889 (tramp-make-tramp-file-name
4890 method user host (car (cdr x)))
4891 (car (cdr x))))
4892 (cdr (cdr x))))
07dfe738
KG
4893 (symbol-value 'tramp-bkup-backup-directory-info))
4894 (symbol-value 'bkup-backup-directory-info)))))
4895
4896 (tramp-run-real-handler 'find-backup-file-name (list filename)))))
38c65fca 4897
c1105d05 4898(defun tramp-handle-make-auto-save-file-name ()
00d6fd04 4899 "Like `make-auto-save-file-name' for Tramp files.
c1105d05 4900Returns a file name in `tramp-auto-save-directory' for autosaving this file."
00d6fd04
MA
4901 (let ((tramp-auto-save-directory tramp-auto-save-directory)
4902 (buffer-file-name
4903 (tramp-subst-strs-in-string
4904 '(("_" . "|")
4905 ("/" . "_a")
4906 (":" . "_b")
4907 ("|" . "__")
4908 ("[" . "_l")
4909 ("]" . "_r"))
4910 (buffer-file-name))))
1a762140
MA
4911 ;; File name must be unique. This is ensured with Emacs 22 (see
4912 ;; UNIQUIFY element of `auto-save-file-name-transforms'); but for
4913 ;; all other cases we must do it ourselves.
4914 (when (boundp 'auto-save-file-name-transforms)
9e6ab520 4915 (mapc
aa485f7c
MA
4916 (lambda (x)
4917 (when (and (string-match (car x) buffer-file-name)
4918 (not (car (cddr x))))
4919 (setq tramp-auto-save-directory
4920 (or tramp-auto-save-directory
4921 (tramp-compat-temporary-file-directory)))))
1a762140
MA
4922 (symbol-value 'auto-save-file-name-transforms)))
4923 ;; Create directory.
4924 (when tramp-auto-save-directory
00d6fd04
MA
4925 (setq buffer-file-name
4926 (expand-file-name buffer-file-name tramp-auto-save-directory))
1a762140
MA
4927 (unless (file-exists-p tramp-auto-save-directory)
4928 (make-directory tramp-auto-save-directory t)))
00d6fd04
MA
4929 ;; Run plain `make-auto-save-file-name'. There might be an advice when
4930 ;; it is not a magic file name operation (since Emacs 22).
4931 ;; We must deactivate it temporarily.
4932 (if (not (ad-is-active 'make-auto-save-file-name))
4933 (tramp-run-real-handler 'make-auto-save-file-name nil)
4934 ;; else
4935 (ad-deactivate 'make-auto-save-file-name)
4936 (prog1
4937 (tramp-run-real-handler 'make-auto-save-file-name nil)
4938 (ad-activate 'make-auto-save-file-name)))))
4939
4940(defvar tramp-handle-write-region-hook nil
4941 "Normal hook to be run at the end of `tramp-handle-write-region'.")
4942
b88f2d0a 4943;; CCC grok LOCKNAME
fb7933a3
KG
4944(defun tramp-handle-write-region
4945 (start end filename &optional append visit lockname confirm)
00d6fd04 4946 "Like `write-region' for Tramp files."
fb7933a3 4947 (setq filename (expand-file-name filename))
c62c9d08 4948 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
4949 ;; Following part commented out because we don't know what to do about
4950 ;; file locking, and it does not appear to be a problem to ignore it.
4951 ;; Ange-ftp ignores it, too.
4952 ;; (when (and lockname (stringp lockname))
4953 ;; (setq lockname (expand-file-name lockname)))
4954 ;; (unless (or (eq lockname nil)
4955 ;; (string= lockname filename))
4956 ;; (error
4957 ;; "tramp-handle-write-region: LOCKNAME must be nil or equal FILENAME"))
8d60099b 4958
94be87e8 4959 ;; XEmacs takes a coding system as the seventh argument, not `confirm'.
00d6fd04
MA
4960 (when (and (not (featurep 'xemacs)) confirm (file-exists-p filename))
4961 (unless (y-or-n-p (format "File %s exists; overwrite anyway? " filename))
4962 (tramp-error v 'file-error "File not overwritten")))
8d60099b 4963
a4aeb9a4 4964 (let ((uid (or (nth 2 (tramp-compat-file-attributes filename 'integer))
9c13938d 4965 (tramp-get-remote-uid v 'integer)))
a4aeb9a4 4966 (gid (or (nth 3 (tramp-compat-file-attributes filename 'integer))
9c13938d
MA
4967 (tramp-get-remote-gid v 'integer))))
4968
4969 (if (and (tramp-local-host-p v)
93c3eb7c 4970 ;; `file-writable-p' calls `file-expand-file-name'. We
87bdd2c7
MA
4971 ;; cannot use `tramp-run-real-handler' therefore.
4972 (let (file-name-handler-alist)
82f3844e
MA
4973 (and
4974 (file-writable-p (file-name-directory localname))
4975 (or (file-directory-p localname)
4976 (file-writable-p localname)))))
9c13938d 4977 ;; Short track: if we are on the local host, we can run directly.
aac0b0f2
MA
4978 (tramp-run-real-handler
4979 'write-region
4980 (list start end localname append 'no-message lockname confirm))
9c13938d
MA
4981
4982 (let ((rem-dec (tramp-get-remote-coding v "remote-decoding"))
4983 (loc-enc (tramp-get-local-coding v "local-encoding"))
b86c1cd8 4984 (modes (save-excursion (tramp-default-file-modes filename)))
9c13938d
MA
4985 ;; We use this to save the value of
4986 ;; `last-coding-system-used' after writing the tmp file.
4987 ;; At the end of the function, we set
4988 ;; `last-coding-system-used' to this saved value. This
4989 ;; way, any intermediary coding systems used while
4990 ;; talking to the remote shell or suchlike won't hose
4991 ;; this variable. This approach was snarfed from
4992 ;; ange-ftp.el.
4993 coding-system-used
4994 ;; Write region into a tmp file. This isn't really
4995 ;; needed if we use an encoding function, but currently
4996 ;; we use it always because this makes the logic
293c24f9
MA
4997 ;; simpler.
4998 (tmpfile (or tramp-temp-buffer-file-name
4999 (tramp-compat-make-temp-file filename))))
5000
5001 ;; If `append' is non-nil, we copy the file locally, and let
5002 ;; the native `write-region' implementation do the job.
5003 (when append (copy-file filename tmpfile 'ok))
9c13938d
MA
5004
5005 ;; We say `no-message' here because we don't want the
5006 ;; visited file modtime data to be clobbered from the temp
5007 ;; file. We call `set-visited-file-modtime' ourselves later
eb562962
MA
5008 ;; on. We must ensure that `file-coding-system-alist'
5009 ;; matches `tmpfile'.
5010 (let ((file-coding-system-alist
5011 (tramp-find-file-name-coding-system-alist filename tmpfile)))
ce2cc728
MA
5012 (condition-case err
5013 (tramp-run-real-handler
5014 'write-region
5015 (list start end tmpfile append 'no-message lockname confirm))
2988341a 5016 ((error quit)
b88f2d0a 5017 (setq tramp-temp-buffer-file-name nil)
2988341a
MA
5018 (delete-file tmpfile)
5019 (signal (car err) (cdr err))))
ce2cc728 5020
eb562962
MA
5021 ;; Now, `last-coding-system-used' has the right value. Remember it.
5022 (when (boundp 'last-coding-system-used)
5023 (setq coding-system-used
5024 (symbol-value 'last-coding-system-used))))
5025
9c13938d
MA
5026 ;; The permissions of the temporary file should be set. If
5027 ;; filename does not exist (eq modes nil) it has been
5028 ;; renamed to the backup file. This case `save-buffer'
5029 ;; handles permissions.
5030 (when modes (set-file-modes tmpfile modes))
5031
5032 ;; This is a bit lengthy due to the different methods
5033 ;; possible for file transfer. First, we check whether the
5034 ;; method uses an rcp program. If so, we call it.
5035 ;; Otherwise, both encoding and decoding command must be
5036 ;; specified. However, if the method _also_ specifies an
5037 ;; encoding function, then that is used for encoding the
5038 ;; contents of the tmp file.
5039 (cond
5040 ;; `rename-file' handles direct copy and out-of-band methods.
5041 ((or (tramp-local-host-p v)
7f49fe46
MA
5042 (tramp-method-out-of-band-p
5043 v (- (or end (point-max)) (or start (point-min)))))
191bb792
MA
5044 (if (and (= (or end (point-max)) (point-max))
5045 (= (or start (point-min)) (point-min))
5046 (tramp-get-method-parameter
5047 method 'tramp-copy-keep-tmpfile))
5048 (progn
5049 (setq tramp-temp-buffer-file-name tmpfile)
5050 (condition-case err
b88f2d0a
MA
5051 ;; We keep the local file for performance
5052 ;; reasons, useful for "rsync".
191bb792
MA
5053 (copy-file tmpfile filename t)
5054 ((error quit)
5055 (setq tramp-temp-buffer-file-name nil)
5056 (delete-file tmpfile)
5057 (signal (car err) (cdr err)))))
5058 (setq tramp-temp-buffer-file-name nil)
5059 ;; Don't rename, in order to keep context in SELinux.
5060 (unwind-protect
5061 (copy-file tmpfile filename t)
5062 (delete-file tmpfile))))
9c13938d 5063
1d7e9a01 5064 ;; Use inline file transfer.
9c13938d 5065 (rem-dec
1d7e9a01 5066 ;; Encode tmpfile.
9c13938d
MA
5067 (tramp-message v 5 "Encoding region...")
5068 (unwind-protect
5069 (with-temp-buffer
5070 ;; Use encoding function or command.
5071 (if (and (symbolp loc-enc) (fboundp loc-enc))
5072 (progn
5073 (tramp-message
5074 v 5 "Encoding region using function `%s'..."
5075 (symbol-name loc-enc))
5076 (let ((coding-system-for-read 'binary))
5077 (insert-file-contents-literally tmpfile))
70c11b0b
MA
5078 ;; The following `let' is a workaround for the
5079 ;; base64.el that comes with pgnus-0.84. If
5080 ;; both of the following conditions are
5081 ;; satisfied, it tries to write to a local
5082 ;; file in default-directory, but at this
5083 ;; point, default-directory is remote.
5084 ;; (`call-process-region' can't write to
5085 ;; remote files, it seems.) The file in
5086 ;; question is a tmp file anyway.
9c13938d
MA
5087 (let ((default-directory
5088 (tramp-compat-temporary-file-directory)))
5089 (funcall loc-enc (point-min) (point-max))))
8d60099b 5090
9c13938d
MA
5091 (tramp-message
5092 v 5 "Encoding region using command `%s'..." loc-enc)
5093 (unless (equal 0 (tramp-call-local-coding-command
5094 loc-enc tmpfile t))
5095 (tramp-error
5096 v 'file-error
5097 "Cannot write to `%s', local encoding command `%s' failed"
5098 filename loc-enc)))
5099
5100 ;; Send buffer into remote decoding command which
5101 ;; writes to remote file. Because this happens on
5102 ;; the remote host, we cannot use the function.
5103 (goto-char (point-max))
5104 (unless (bolp) (newline))
8d60099b 5105 (tramp-message
9c13938d
MA
5106 v 5 "Decoding region into remote file %s..." filename)
5107 (tramp-send-command
5108 v
5109 (format
5110 "%s >%s <<'EOF'\n%sEOF"
5111 rem-dec
5112 (tramp-shell-quote-argument localname)
5113 (buffer-string)))
5114 (tramp-barf-unless-okay
5115 v nil
5116 "Couldn't write region to `%s', decode using `%s' failed"
5117 filename rem-dec)
5118 ;; When `file-precious-flag' is set, the region is
5119 ;; written to a temporary file. Check that the
5120 ;; checksum is equal to that from the local tmpfile.
5121 (when file-precious-flag
5122 (erase-buffer)
5123 (and
a4aeb9a4
MA
5124 ;; cksum runs locally, if possible.
5125 (zerop (tramp-local-call-process "cksum" tmpfile t))
5126 ;; cksum runs remotely.
9c13938d
MA
5127 (zerop
5128 (tramp-send-command-and-check
5129 v
5130 (format
5131 "cksum <%s" (tramp-shell-quote-argument localname))))
a4aeb9a4 5132 ;; ... they are different.
9c13938d
MA
5133 (not
5134 (string-equal
5135 (buffer-string)
5136 (with-current-buffer (tramp-get-buffer v)
5137 (buffer-string))))
5138 (tramp-error
5139 v 'file-error
5140 (concat "Couldn't write region to `%s',"
5141 " decode using `%s' failed")
5142 filename rem-dec)))
5143 (tramp-message
aac0b0f2 5144 v 5 "Decoding region into remote file %s...done" filename))
8d60099b 5145
9c13938d
MA
5146 ;; Save exit.
5147 (delete-file tmpfile)))
8d60099b 5148
9c13938d
MA
5149 ;; That's not expected.
5150 (t
5151 (tramp-error
5152 v 'file-error
5153 (concat "Method `%s' should specify both encoding and "
5154 "decoding command or an rcp program")
5155 method)))
258800f8 5156
9c13938d
MA
5157 ;; Make `last-coding-system-used' have the right value.
5158 (when coding-system-used
5159 (set 'last-coding-system-used coding-system-used))))
0f205eee 5160
aac0b0f2
MA
5161 (tramp-flush-file-property v (file-name-directory localname))
5162 (tramp-flush-file-property v localname)
5163
57671b72
MA
5164 ;; We must protect `last-coding-system-used', now we have set it
5165 ;; to its correct value.
293c24f9 5166 (let (last-coding-system-used (need-chown t))
57671b72
MA
5167 ;; Set file modification time.
5168 (when (or (eq visit t) (stringp visit))
293c24f9
MA
5169 (let ((file-attr (file-attributes filename)))
5170 (set-visited-file-modtime
5171 ;; We must pass modtime explicitely, because filename can
5172 ;; be different from (buffer-file-name), f.e. if
5173 ;; `file-precious-flag' is set.
5174 (nth 5 file-attr))
5175 (when (and (eq (nth 2 file-attr) uid)
5176 (eq (nth 3 file-attr) gid))
5177 (setq need-chown nil))))
57671b72
MA
5178
5179 ;; Set the ownership.
293c24f9
MA
5180 (when need-chown
5181 (tramp-set-file-uid-gid filename uid gid))
57671b72
MA
5182 (when (or (eq visit t) (null visit) (stringp visit))
5183 (tramp-message v 0 "Wrote %s" filename))
5184 (run-hooks 'tramp-handle-write-region-hook)))))
fb7933a3 5185
946a5aeb
MA
5186(defvar tramp-vc-registered-file-names nil
5187 "List used to collect file names, which are checked during `vc-registered'.")
5188
5189;; VC backends check for the existence of various different special
5190;; files. This is very time consuming, because every single check
5191;; requires a remote command (the file cache must be invalidated).
5192;; Therefore, we apply a kind of optimization. We install the file
5193;; name handler `tramp-vc-file-name-handler', which does nothing but
5194;; remembers all file names for which `file-exists-p' or
5195;; `file-readable-p' has been applied. A first run of `vc-registered'
5196;; is performed. Afterwards, a script is applied for all collected
5197;; file names, using just one remote command. The result of this
5198;; script is used to fill the file cache with actual values. Now we
5199;; can reset the file name handlers, and we make a second run of
5200;; `vc-registered', which returns the expected result without sending
5201;; any other remote command.
49096407
MA
5202(defun tramp-handle-vc-registered (file)
5203 "Like `vc-registered' for Tramp files."
946a5aeb 5204 (with-parsed-tramp-file-name file nil
7f49fe46
MA
5205
5206 ;; There could be new files, created by the vc backend. We cannot
5207 ;; reuse the old cache entries, therefore.
946a5aeb
MA
5208 (let (tramp-vc-registered-file-names
5209 (tramp-cache-inhibit-cache (current-time))
5210 (file-name-handler-alist
5211 `((,tramp-file-name-regexp . tramp-vc-file-name-handler))))
5212
5213 ;; Here we collect only file names, which need an operation.
5214 (tramp-run-real-handler 'vc-registered (list file))
5215 (tramp-message v 10 "\n%s" tramp-vc-registered-file-names)
5216
5217 ;; Send just one command, in order to fill the cache.
7f49fe46
MA
5218 (when tramp-vc-registered-file-names
5219 (tramp-maybe-send-script
5220 v
5221 (format tramp-vc-registered-read-file-names
5222 (tramp-get-file-exists-command v)
5223 (format "%s -r" (tramp-get-test-command v)))
5224 "tramp_vc_registered_read_file_names")
5225
5226 (dolist
5227 (elt
5228 (tramp-send-command-and-read
5229 v
5230 (format
5231 "tramp_vc_registered_read_file_names %s"
5232 (mapconcat 'tramp-shell-quote-argument
5233 tramp-vc-registered-file-names
5234 " "))))
946a5aeb 5235
7f49fe46 5236 (tramp-set-file-property v (car elt) (cadr elt) (cadr (cdr elt))))))
946a5aeb 5237
7f49fe46
MA
5238 ;; Second run. Now all `file-exists-p' or `file-readable-p' calls
5239 ;; shall be answered from the file cache.
5240 ;; We unset `process-file-side-effects' in order to keep the cache
5241 ;; when `process-file' calls appear.
946a5aeb
MA
5242 (let (process-file-side-effects)
5243 (tramp-run-real-handler 'vc-registered (list file)))))
49096407 5244
a01b1e22
MA
5245;;;###autoload
5246(progn (defun tramp-run-real-handler (operation args)
fb7933a3 5247 "Invoke normal file name handler for OPERATION.
c62c9d08
KG
5248First arg specifies the OPERATION, second arg is a list of arguments to
5249pass to the OPERATION."
4007ba5b
KG
5250 (let* ((inhibit-file-name-handlers
5251 `(tramp-file-name-handler
946a5aeb 5252 tramp-vc-file-name-handler
4007ba5b
KG
5253 tramp-completion-file-name-handler
5254 cygwin-mount-name-hook-function
5255 cygwin-mount-map-drive-hook-function
5256 .
5257 ,(and (eq inhibit-file-name-operation operation)
5258 inhibit-file-name-handlers)))
5259 (inhibit-file-name-operation operation))
a01b1e22 5260 (apply operation args))))
16674e4f 5261
a01b1e22
MA
5262;;;###autoload
5263(progn (defun tramp-completion-run-real-handler (operation args)
16674e4f
KG
5264 "Invoke `tramp-file-name-handler' for OPERATION.
5265First arg specifies the OPERATION, second arg is a list of arguments to
5266pass to the OPERATION."
4007ba5b
KG
5267 (let* ((inhibit-file-name-handlers
5268 `(tramp-completion-file-name-handler
5269 cygwin-mount-name-hook-function
5270 cygwin-mount-map-drive-hook-function
5271 .
5272 ,(and (eq inhibit-file-name-operation operation)
5273 inhibit-file-name-handlers)))
5274 (inhibit-file-name-operation operation))
a01b1e22 5275 (apply operation args))))
fb7933a3 5276
4007ba5b
KG
5277;; We handle here all file primitives. Most of them have the file
5278;; name as first parameter; nevertheless we check for them explicitly
04bf5b65 5279;; in order to be signaled if a new primitive appears. This
4007ba5b
KG
5280;; scenario is needed because there isn't a way to decide by
5281;; syntactical means whether a foreign method must be called. It would
19a87064 5282;; ease the life if `file-name-handler-alist' would support a decision
4007ba5b
KG
5283;; function as well but regexp only.
5284(defun tramp-file-name-for-operation (operation &rest args)
5285 "Return file name related to OPERATION file primitive.
5286ARGS are the arguments OPERATION has been called with."
5287 (cond
5288 ; FILE resp DIRECTORY
5289 ((member operation
5290 (list 'access-file 'byte-compiler-base-file-name 'delete-directory
5291 'delete-file 'diff-latest-backup-file 'directory-file-name
5292 'directory-files 'directory-files-and-attributes
5293 'dired-compress-file 'dired-uncache
5294 'file-accessible-directory-p 'file-attributes
5295 'file-directory-p 'file-executable-p 'file-exists-p
19a87064
MA
5296 'file-local-copy 'file-remote-p 'file-modes
5297 'file-name-as-directory 'file-name-directory
5298 'file-name-nondirectory 'file-name-sans-versions
5299 'file-ownership-preserved-p 'file-readable-p
5300 'file-regular-p 'file-symlink-p 'file-truename
5301 'file-writable-p 'find-backup-file-name 'find-file-noselect
5302 'get-file-buffer 'insert-directory 'insert-file-contents
5303 'load 'make-directory 'make-directory-internal
5304 'set-file-modes 'substitute-in-file-name
5305 'unhandled-file-name-directory 'vc-registered
ce3f516f
MA
5306 ; Emacs 22 only
5307 'set-file-times
4007ba5b
KG
5308 ; XEmacs only
5309 'abbreviate-file-name 'create-file-buffer
5310 'dired-file-modtime 'dired-make-compressed-filename
5311 'dired-recursive-delete-directory 'dired-set-file-modtime
5312 'dired-shell-unhandle-file-name 'dired-uucode-file
5615d63f 5313 'insert-file-contents-literally 'make-temp-name 'recover-file
4007ba5b 5314 'vm-imap-check-mail 'vm-pop-check-mail 'vm-spool-check-mail))
8daea7fc
KG
5315 (if (file-name-absolute-p (nth 0 args))
5316 (nth 0 args)
5317 (expand-file-name (nth 0 args))))
4007ba5b
KG
5318 ; FILE DIRECTORY resp FILE1 FILE2
5319 ((member operation
5320 (list 'add-name-to-file 'copy-file 'expand-file-name
5321 'file-name-all-completions 'file-name-completion
5322 'file-newer-than-file-p 'make-symbolic-link 'rename-file
263c02ef
MA
5323 ; Emacs 23 only
5324 'copy-directory
4007ba5b
KG
5325 ; XEmacs only
5326 'dired-make-relative-symlink
5327 'vm-imap-move-mail 'vm-pop-move-mail 'vm-spool-move-mail))
5328 (save-match-data
5329 (cond
5330 ((string-match tramp-file-name-regexp (nth 0 args)) (nth 0 args))
5331 ((string-match tramp-file-name-regexp (nth 1 args)) (nth 1 args))
5332 (t (buffer-file-name (current-buffer))))))
5333 ; START END FILE
5334 ((eq operation 'write-region)
5335 (nth 2 args))
5336 ; BUF
5337 ((member operation
00d6fd04 5338 (list 'set-visited-file-modtime 'verify-visited-file-modtime
b50dd0d2 5339 ; since Emacs 22 only
00d6fd04
MA
5340 'make-auto-save-file-name
5341 ; XEmacs only
4007ba5b
KG
5342 'backup-buffer))
5343 (buffer-file-name
5344 (if (bufferp (nth 0 args)) (nth 0 args) (current-buffer))))
5345 ; COMMAND
5346 ((member operation
00d6fd04
MA
5347 (list ; not in Emacs 23
5348 'dired-call-process
01917a18 5349 ; Emacs only
b71c9e75 5350 'shell-command
00d6fd04 5351 ; since Emacs 22 only
0457dd55 5352 'process-file
00d6fd04
MA
5353 ; since Emacs 23 only
5354 'start-file-process
4007ba5b 5355 ; XEmacs only
00d6fd04
MA
5356 'dired-print-file 'dired-shell-call-process
5357 ; nowhere yet
5358 'executable-find 'start-process 'call-process))
4007ba5b
KG
5359 default-directory)
5360 ; unknown file primitive
5361 (t (error "unknown file I/O primitive: %s" operation))))
5362
5363(defun tramp-find-foreign-file-name-handler (filename)
5364 "Return foreign file name handler if exists."
9ce8462a
MA
5365 (when (and (stringp filename) (tramp-tramp-file-p filename))
5366 (let ((v (tramp-dissect-file-name filename t))
5367 (handler tramp-foreign-file-name-handler-alist)
5368 elt res)
5369 ;; When we are not fully sure that filename completion is safe,
5370 ;; we should not return a handler.
5371 (when (or (tramp-file-name-method v) (tramp-file-name-user v)
1834b39f
MA
5372 (and (tramp-file-name-host v)
5373 (not (member (tramp-file-name-host v)
5374 (mapcar 'car tramp-methods))))
9ce8462a
MA
5375 (not (tramp-completion-mode-p)))
5376 (while handler
5377 (setq elt (car handler)
5378 handler (cdr handler))
5379 (when (funcall (car elt) filename)
5380 (setq handler nil
5381 res (cdr elt))))
5382 res))))
4007ba5b 5383
fb7933a3
KG
5384;; Main function.
5385;;;###autoload
5386(defun tramp-file-name-handler (operation &rest args)
ea9d1443 5387 "Invoke Tramp file name handler.
a4aeb9a4 5388Falls back to normal file name handler if no Tramp file name handler exists."
2e271195
MA
5389 (if tramp-mode
5390 (save-match-data
5391 (let* ((filename
5392 (tramp-replace-environment-variables
5393 (apply 'tramp-file-name-for-operation operation args)))
5394 (completion (tramp-completion-mode-p))
5395 (foreign (tramp-find-foreign-file-name-handler filename)))
5396 (with-parsed-tramp-file-name filename nil
5397 (cond
5398 ;; When we are in completion mode, some operations
5399 ;; shouldn't be handled by backend.
5400 ((and completion (zerop (length localname))
5401 (memq operation '(file-exists-p file-directory-p)))
5402 t)
5403 ((and completion (zerop (length localname))
5404 (memq operation '(file-name-as-directory)))
5405 filename)
5406 ;; Call the backend function.
5407 (foreign (apply foreign operation args))
5408 ;; Nothing to do for us.
5409 (t (tramp-run-real-handler operation args))))))
5410 ;; When `tramp-mode' is not enabled, we don't do anything.
5411 (tramp-run-real-handler operation args)))
fb7933a3 5412
07dfe738
KG
5413;; In Emacs, there is some concurrency due to timers. If a timer
5414;; interrupts Tramp and wishes to use the same connection buffer as
5415;; the "main" Emacs, then garbage might occur in the connection
5416;; buffer. Therefore, we need to make sure that a timer does not use
5417;; the same connection buffer as the "main" Emacs. We implement a
5418;; cheap global lock, instead of locking each connection buffer
5419;; separately. The global lock is based on two variables,
5420;; `tramp-locked' and `tramp-locker'. `tramp-locked' is set to true
5421;; (with setq) to indicate a lock. But Tramp also calls itself during
5422;; processing of a single file operation, so we need to allow
5423;; recursive calls. That's where the `tramp-locker' variable comes in
5424;; -- it is let-bound to t during the execution of the current
5425;; handler. So if `tramp-locked' is t and `tramp-locker' is also t,
5426;; then we should just proceed because we have been called
5427;; recursively. But if `tramp-locker' is nil, then we are a timer
5428;; interrupting the "main" Emacs, and then we signal an error.
5429
5430(defvar tramp-locked nil
5431 "If non-nil, then Tramp is currently busy.
5432Together with `tramp-locker', this implements a locking mechanism
5433preventing reentrant calls of Tramp.")
5434
5435(defvar tramp-locker nil
5436 "If non-nil, then a caller has locked Tramp.
5437Together with `tramp-locked', this implements a locking mechanism
5438preventing reentrant calls of Tramp.")
5439
ea9d1443
KG
5440(defun tramp-sh-file-name-handler (operation &rest args)
5441 "Invoke remote-shell Tramp file name handler.
5442Fall back to normal file name handler if no Tramp handler exists."
07dfe738 5443 (when (and tramp-locked (not tramp-locker))
11c71217 5444 (setq tramp-locked nil)
00d6fd04 5445 (signal 'file-error (list "Forbidden reentrant call of Tramp")))
07dfe738
KG
5446 (let ((tl tramp-locked))
5447 (unwind-protect
5448 (progn
5449 (setq tramp-locked t)
5450 (let ((tramp-locker t))
5451 (save-match-data
5452 (let ((fn (assoc operation tramp-file-name-handler-alist)))
5453 (if fn
5454 (apply (cdr fn) args)
5455 (tramp-run-real-handler operation args))))))
5456 (setq tramp-locked tl))))
ea9d1443 5457
946a5aeb
MA
5458(defun tramp-vc-file-name-handler (operation &rest args)
5459 "Invoke special file name handler, which collects files to be handled."
5460 (save-match-data
5461 (let ((filename
5462 (tramp-replace-environment-variables
5463 (apply 'tramp-file-name-for-operation operation args)))
5464 (fn (assoc operation tramp-file-name-handler-alist)))
5465 (with-parsed-tramp-file-name filename nil
5466 (cond
5467 ;; That's what we want: file names, for which checks are
5468 ;; applied. We assume, that VC uses only `file-exists-p' and
5469 ;; `file-readable-p' checks; otherwise we must extend the
5470 ;; list. We do not perform any action, but return nil, in
5471 ;; order to keep `vc-registered' running.
5472 ((and fn (memq operation '(file-exists-p file-readable-p)))
5473 (add-to-list 'tramp-vc-registered-file-names localname 'append)
5474 nil)
5475 ;; Tramp file name handlers like `expand-file-name'. They
5476 ;; must still work.
5477 (fn
5478 (save-match-data (apply (cdr fn) args)))
5479 ;; Default file name handlers, we don't care.
5480 (t (tramp-run-real-handler operation args)))))))
5481
16674e4f 5482;;;###autoload
1ecc6145 5483(progn (defun tramp-completion-file-name-handler (operation &rest args)
a4aeb9a4
MA
5484 "Invoke Tramp file name completion handler.
5485Falls back to normal file name handler if no Tramp file name handler exists."
57671b72
MA
5486 ;; We bind `directory-sep-char' here for XEmacs on Windows, which
5487 ;; would otherwise use backslash.
aff67808
MA
5488 (let ((directory-sep-char ?/)
5489 (fn (assoc operation tramp-completion-file-name-handler-alist)))
aa485f7c
MA
5490 (if (and
5491 ;; When `tramp-mode' is not enabled, we don't do anything.
5492 fn tramp-mode
5493 ;; For other syntaxes than `sep', the regexp matches many common
5494 ;; situations where the user doesn't actually want to use Tramp.
5495 ;; So to avoid autoloading Tramp after typing just "/s", we
5496 ;; disable this part of the completion, unless the user implicitly
5497 ;; indicated his interest in using a fancier completion system.
5498 (or (eq tramp-syntax 'sep)
5499 (featurep 'tramp) ; If it's loaded, we may as well use it.
5500 (and (boundp 'partial-completion-mode) partial-completion-mode)
5501 ;; FIXME: These may have been loaded even if the user never
5502 ;; intended to use them.
5503 (featurep 'ido)
5504 (featurep 'icicles)))
aff67808
MA
5505 (save-match-data (apply (cdr fn) args))
5506 (tramp-completion-run-real-handler operation args)))))
a01b1e22 5507
b25a52cc 5508;;;###autoload
aa485f7c
MA
5509(progn (defun tramp-register-file-name-handlers ()
5510 "Add Tramp file name handlers to `file-name-handler-alist'."
5511 ;; Remove autoloaded handlers from file name handler alist. Useful,
00d6fd04
MA
5512 ;; if `tramp-syntax' has been changed.
5513 (let ((a1 (rassq 'tramp-file-name-handler file-name-handler-alist)))
aa485f7c
MA
5514 (setq file-name-handler-alist (delq a1 file-name-handler-alist)))
5515 (let ((a1 (rassq
5516 'tramp-completion-file-name-handler file-name-handler-alist)))
5517 (setq file-name-handler-alist (delq a1 file-name-handler-alist)))
5518 ;; Add the handlers.
a01b1e22
MA
5519 (add-to-list 'file-name-handler-alist
5520 (cons tramp-file-name-regexp 'tramp-file-name-handler))
0c0b61f1 5521 (put 'tramp-file-name-handler 'safe-magic t)
aa485f7c
MA
5522 (add-to-list 'file-name-handler-alist
5523 (cons tramp-completion-file-name-regexp
5524 'tramp-completion-file-name-handler))
5525 (put 'tramp-completion-file-name-handler 'safe-magic t)
5526 ;; If jka-compr or epa-file are already loaded, move them to the
5527 ;; front of `file-name-handler-alist'.
5528 (dolist (fnh '(epa-file-handler jka-compr-handler))
5529 (let ((entry (rassoc fnh file-name-handler-alist)))
5530 (when entry
5531 (setq file-name-handler-alist
5532 (cons entry (delete entry file-name-handler-alist))))))))
69cee873 5533
00d6fd04
MA
5534;; `tramp-file-name-handler' must be registered before evaluation of
5535;; site-start and init files, because there might exist remote files
5536;; already, f.e. files kept via recentf-mode.
aa485f7c
MA
5537;;;###autoload(tramp-register-file-name-handlers)
5538(tramp-register-file-name-handlers)
b25a52cc 5539
fb7933a3 5540;;;###autoload
8c04e197 5541(defun tramp-unload-file-name-handlers ()
a69c01a0
MA
5542 (setq file-name-handler-alist
5543 (delete (rassoc 'tramp-file-name-handler
5544 file-name-handler-alist)
5545 (delete (rassoc 'tramp-completion-file-name-handler
5546 file-name-handler-alist)
5547 file-name-handler-alist))))
5548
8c04e197 5549(add-hook 'tramp-unload-hook 'tramp-unload-file-name-handlers)
a69c01a0 5550
0664ff72 5551;;; File name handler functions for completion mode:
a6e96327
MA
5552
5553(defvar tramp-completion-mode nil
5554 "If non-nil, external packages signal that they are in file name completion.
5555
5556This is necessary, because Tramp uses a heuristic depending on last
5557input event. This fails when external packages use other characters
5558but <TAB>, <SPACE> or ?\\? for file name completion. This variable
5559should never be set globally, the intention is to let-bind it.")
16674e4f
KG
5560
5561;; Necessary because `tramp-file-name-regexp-unified' and
00d6fd04
MA
5562;; `tramp-completion-file-name-regexp-unified' aren't different. If
5563;; nil, `tramp-completion-run-real-handler' is called (i.e. forwarding
5564;; to `tramp-file-name-handler'). Otherwise, it takes
5565;; `tramp-run-real-handler'. Using `last-input-event' is a little bit
5566;; risky, because completing a file might require loading other files,
5567;; like "~/.netrc", and for them it shouldn't be decided based on that
5568;; variable. On the other hand, those files shouldn't have partial
a4aeb9a4
MA
5569;; Tramp file name syntax. Maybe another variable should be introduced
5570;; overwriting this check in such cases. Or we change Tramp file name
00d6fd04 5571;; syntax in order to avoid ambiguities, like in XEmacs ...
6c4e47fa 5572(defun tramp-completion-mode-p ()
16674e4f 5573 "Checks whether method / user name / host name completion is active."
6c4e47fa 5574 (or
a6e96327
MA
5575 ;; Signal from outside.
5576 tramp-completion-mode
5577 ;; Emacs.
94be87e8 5578 (equal last-input-event 'tab)
6c4e47fa 5579 (and (natnump last-input-event)
94be87e8 5580 (or
a6e96327 5581 ;; ?\t has event-modifier 'control.
800a97b8 5582 (equal last-input-event ?\t)
94be87e8 5583 (and (not (event-modifiers last-input-event))
800a97b8
SM
5584 (or (equal last-input-event ?\?)
5585 (equal last-input-event ?\ )))))
a6e96327 5586 ;; XEmacs.
6c4e47fa
MA
5587 (and (featurep 'xemacs)
5588 ;; `last-input-event' might be nil.
5589 (not (null last-input-event))
5590 ;; `last-input-event' may have no character approximation.
5591 (funcall (symbol-function 'event-to-character) last-input-event)
94be87e8 5592 (or
a6e96327 5593 ;; ?\t has event-modifier 'control.
800a97b8 5594 (equal
94be87e8
MA
5595 (funcall (symbol-function 'event-to-character)
5596 last-input-event) ?\t)
5597 (and (not (event-modifiers last-input-event))
800a97b8 5598 (or (equal
94be87e8
MA
5599 (funcall (symbol-function 'event-to-character)
5600 last-input-event) ?\?)
800a97b8 5601 (equal
94be87e8
MA
5602 (funcall (symbol-function 'event-to-character)
5603 last-input-event) ?\ )))))))
16674e4f 5604
16674e4f
KG
5605;; Method, host name and user name completion.
5606;; `tramp-completion-dissect-file-name' returns a list of
5607;; tramp-file-name structures. For all of them we return possible completions.
a01b1e22 5608;;;###autoload
16674e4f 5609(defun tramp-completion-handle-file-name-all-completions (filename directory)
00d6fd04 5610 "Like `file-name-all-completions' for partial Tramp files."
16674e4f 5611
00d6fd04
MA
5612 (let* ((fullname (tramp-drop-volume-letter
5613 (expand-file-name filename directory)))
5614 ;; Possible completion structures.
5615 (v (tramp-completion-dissect-file-name fullname))
5616 result result1)
5617
5618 (while v
5619 (let* ((car (car v))
5620 (method (tramp-file-name-method car))
5621 (user (tramp-file-name-user car))
5622 (host (tramp-file-name-host car))
5623 (localname (tramp-file-name-localname car))
5624 (m (tramp-find-method method user host))
5625 (tramp-current-user user) ; see `tramp-parse-passwd'
5626 all-user-hosts)
5627
5628 (unless localname ;; Nothing to complete.
5629
5630 (if (or user host)
5631
5632 ;; Method dependent user / host combinations.
5633 (progn
9e6ab520 5634 (mapc
00d6fd04
MA
5635 (lambda (x)
5636 (setq all-user-hosts
5637 (append all-user-hosts
5638 (funcall (nth 0 x) (nth 1 x)))))
5639 (tramp-get-completion-function m))
5640
9e6ab520
MA
5641 (setq result
5642 (append result
5643 (mapcar
5644 (lambda (x)
5645 (tramp-get-completion-user-host
5646 method user host (nth 0 x) (nth 1 x)))
5647 (delq nil all-user-hosts)))))
00d6fd04
MA
5648
5649 ;; Possible methods.
5650 (setq result
5651 (append result (tramp-get-completion-methods m)))))
5652
5653 (setq v (cdr v))))
5654
5655 ;; Unify list, remove nil elements.
5656 (while result
5657 (let ((car (car result)))
5658 (when car
5659 (add-to-list
5660 'result1
5661 (substring car (length (tramp-drop-volume-letter directory)))))
5662 (setq result (cdr result))))
5663
5664 ;; Complete local parts.
5665 (append
5666 result1
5667 (condition-case nil
5668 (tramp-completion-run-real-handler
5669 'file-name-all-completions (list filename directory))
5670 (error nil)))))
16674e4f
KG
5671
5672;; Method, host name and user name completion for a file.
a01b1e22 5673;;;###autoload
e1e17cae
MA
5674(defun tramp-completion-handle-file-name-completion
5675 (filename directory &optional predicate)
00d6fd04 5676 "Like `file-name-completion' for Tramp files."
e1e17cae
MA
5677 (try-completion
5678 filename
5679 (mapcar 'list (file-name-all-completions filename directory))
83e20b5c
MA
5680 (when predicate
5681 (lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
16674e4f
KG
5682
5683;; I misuse a little bit the tramp-file-name structure in order to handle
5684;; completion possibilities for partial methods / user names / host names.
5685;; Return value is a list of tramp-file-name structures according to possible
00d6fd04 5686;; completions. If "localname" is non-nil it means there
16674e4f
KG
5687;; shouldn't be a completion anymore.
5688
5689;; Expected results:
5690
00d6fd04
MA
5691;; "/x" "/[x" "/x@" "/[x@" "/x@y" "/[x@y"
5692;; [nil nil "x" nil] [nil "x" nil nil] [nil "x" "y" nil]
5693;; [nil "x" nil nil]
5694;; ["x" nil nil nil]
5695
5696;; "/x:" "/x:y" "/x:y:"
5697;; [nil nil "x" ""] [nil nil "x" "y"] ["x" nil "y" ""]
5698;; "/[x/" "/[x/y"
5699;; ["x" nil "" nil] ["x" nil "y" nil]
5700;; ["x" "" nil nil] ["x" "y" nil nil]
5701
5702;; "/x:y@" "/x:y@z" "/x:y@z:"
5703;; [nil nil "x" "y@"] [nil nil "x" "y@z"] ["x" "y" "z" ""]
5704;; "/[x/y@" "/[x/y@z"
5705;; ["x" nil "y" nil] ["x" "y" "z" nil]
16674e4f
KG
5706(defun tramp-completion-dissect-file-name (name)
5707 "Returns a list of `tramp-file-name' structures.
5708They are collected by `tramp-completion-dissect-file-name1'."
5709
5710 (let* ((result)
4007ba5b 5711 (x-nil "\\|\\(\\)")
b96e6899
MA
5712 (tramp-completion-ipv6-regexp
5713 (format
5714 "[^%s]*"
5715 (if (zerop (length tramp-postfix-ipv6-format))
5716 tramp-postfix-host-format
5717 tramp-postfix-ipv6-format)))
4007ba5b
KG
5718 ;; "/method" "/[method"
5719 (tramp-completion-file-name-structure1
5720 (list (concat tramp-prefix-regexp "\\(" tramp-method-regexp x-nil "\\)$")
5721 1 nil nil nil))
5722 ;; "/user" "/[user"
5723 (tramp-completion-file-name-structure2
5724 (list (concat tramp-prefix-regexp "\\(" tramp-user-regexp x-nil "\\)$")
5725 nil 1 nil nil))
5726 ;; "/host" "/[host"
5727 (tramp-completion-file-name-structure3
5728 (list (concat tramp-prefix-regexp "\\(" tramp-host-regexp x-nil "\\)$")
5729 nil nil 1 nil))
b96e6899 5730 ;; "/[ipv6" "/[ipv6"
4007ba5b 5731 (tramp-completion-file-name-structure4
b96e6899
MA
5732 (list (concat tramp-prefix-regexp
5733 tramp-prefix-ipv6-regexp
5734 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5735 nil nil 1 nil))
5736 ;; "/user@host" "/[user@host"
5737 (tramp-completion-file-name-structure5
4007ba5b
KG
5738 (list (concat tramp-prefix-regexp
5739 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5740 "\\(" tramp-host-regexp x-nil "\\)$")
5741 nil 1 2 nil))
b96e6899
MA
5742 ;; "/user@[ipv6" "/[user@ipv6"
5743 (tramp-completion-file-name-structure6
5744 (list (concat tramp-prefix-regexp
5745 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5746 tramp-prefix-ipv6-regexp
5747 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5748 nil 1 2 nil))
00d6fd04 5749 ;; "/method:user" "/[method/user" "/method://user"
b96e6899 5750 (tramp-completion-file-name-structure7
4007ba5b 5751 (list (concat tramp-prefix-regexp
00d6fd04 5752 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5753 "\\(" tramp-user-regexp x-nil "\\)$")
5754 1 2 nil nil))
00d6fd04 5755 ;; "/method:host" "/[method/host" "/method://host"
b96e6899 5756 (tramp-completion-file-name-structure8
4007ba5b 5757 (list (concat tramp-prefix-regexp
00d6fd04 5758 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5759 "\\(" tramp-host-regexp x-nil "\\)$")
5760 1 nil 2 nil))
b96e6899
MA
5761 ;; "/method:[ipv6" "/[method/ipv6" "/method://[ipv6"
5762 (tramp-completion-file-name-structure9
5763 (list (concat tramp-prefix-regexp
5764 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
5765 tramp-prefix-ipv6-regexp
5766 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5767 1 nil 2 nil))
00d6fd04 5768 ;; "/method:user@host" "/[method/user@host" "/method://user@host"
b96e6899 5769 (tramp-completion-file-name-structure10
4007ba5b 5770 (list (concat tramp-prefix-regexp
00d6fd04 5771 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
5772 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5773 "\\(" tramp-host-regexp x-nil "\\)$")
00d6fd04 5774 1 2 3 nil))
b96e6899
MA
5775 ;; "/method:user@[ipv6" "/[method/user@ipv6" "/method://user@[ipv6"
5776 (tramp-completion-file-name-structure11
5777 (list (concat tramp-prefix-regexp
5778 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
5779 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
5780 tramp-prefix-ipv6-regexp
5781 "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
5782 1 2 3 nil))
00d6fd04 5783 ;; "/method: "/method:/"
b96e6899 5784 (tramp-completion-file-name-structure12
00d6fd04
MA
5785 (list
5786 (if (equal tramp-syntax 'url)
5787 (concat tramp-prefix-regexp
5788 "\\(" tramp-method-regexp "\\)"
5789 "\\(" (substring tramp-postfix-method-regexp 0 1)
5790 "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)"
5791 "\\(" "\\)$")
5792 ;; Should not match if not URL syntax.
5793 (concat tramp-prefix-regexp "/$"))
5794 1 3 nil nil))
5795 ;; "/method: "/method:/"
b96e6899 5796 (tramp-completion-file-name-structure13
00d6fd04
MA
5797 (list
5798 (if (equal tramp-syntax 'url)
5799 (concat tramp-prefix-regexp
5800 "\\(" tramp-method-regexp "\\)"
5801 "\\(" (substring tramp-postfix-method-regexp 0 1)
5802 "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)"
5803 "\\(" "\\)$")
5804 ;; Should not match if not URL syntax.
5805 (concat tramp-prefix-regexp "/$"))
5806 1 nil 3 nil)))
4007ba5b 5807
9e6ab520 5808 (mapc (lambda (regexp)
16674e4f
KG
5809 (add-to-list 'result
5810 (tramp-completion-dissect-file-name1 regexp name)))
5811 (list
5812 tramp-completion-file-name-structure1
5813 tramp-completion-file-name-structure2
5814 tramp-completion-file-name-structure3
5815 tramp-completion-file-name-structure4
5816 tramp-completion-file-name-structure5
5817 tramp-completion-file-name-structure6
5818 tramp-completion-file-name-structure7
00d6fd04
MA
5819 tramp-completion-file-name-structure8
5820 tramp-completion-file-name-structure9
b96e6899
MA
5821 tramp-completion-file-name-structure10
5822 tramp-completion-file-name-structure11
5823 tramp-completion-file-name-structure12
5824 tramp-completion-file-name-structure13
16674e4f
KG
5825 tramp-file-name-structure))
5826
5827 (delq nil result)))
5828
5829(defun tramp-completion-dissect-file-name1 (structure name)
5830 "Returns a `tramp-file-name' structure matching STRUCTURE.
00d6fd04 5831The structure consists of remote method, remote user,
7432277c 5832remote host and localname (filename on remote host)."
fb7933a3 5833
00d6fd04
MA
5834 (save-match-data
5835 (when (string-match (nth 0 structure) name)
5836 (let ((method (and (nth 1 structure)
5837 (match-string (nth 1 structure) name)))
5838 (user (and (nth 2 structure)
5839 (match-string (nth 2 structure) name)))
5840 (host (and (nth 3 structure)
5841 (match-string (nth 3 structure) name)))
5842 (localname (and (nth 4 structure)
5843 (match-string (nth 4 structure) name))))
5844 (vector method user host localname)))))
16674e4f
KG
5845
5846;; This function returns all possible method completions, adding the
5847;; trailing method delimeter.
16674e4f
KG
5848(defun tramp-get-completion-methods (partial-method)
5849 "Returns all method completions for PARTIAL-METHOD."
4007ba5b
KG
5850 (mapcar
5851 (lambda (method)
5852 (and method
5853 (string-match (concat "^" (regexp-quote partial-method)) method)
00d6fd04
MA
5854 (tramp-completion-make-tramp-file-name method nil nil nil)))
5855 (mapcar 'car tramp-methods)))
16674e4f
KG
5856
5857;; Compares partial user and host names with possible completions.
5858(defun tramp-get-completion-user-host (method partial-user partial-host user host)
5859 "Returns the most expanded string for user and host name completion.
5860PARTIAL-USER must match USER, PARTIAL-HOST must match HOST."
5861 (cond
5862
5863 ((and partial-user partial-host)
5864 (if (and host
5865 (string-match (concat "^" (regexp-quote partial-host)) host)
5866 (string-equal partial-user (or user partial-user)))
5867 (setq user partial-user)
5868 (setq user nil
5869 host nil)))
5870
5871 (partial-user
5872 (setq host nil)
5873 (unless
5874 (and user (string-match (concat "^" (regexp-quote partial-user)) user))
5875 (setq user nil)))
5876
5877 (partial-host
5878 (setq user nil)
5879 (unless
5880 (and host (string-match (concat "^" (regexp-quote partial-host)) host))
5881 (setq host nil)))
5882
5883 (t (setq user nil
5884 host nil)))
5885
292ffc15 5886 (unless (zerop (+ (length user) (length host)))
00d6fd04 5887 (tramp-completion-make-tramp-file-name method user host nil)))
16674e4f
KG
5888
5889(defun tramp-parse-rhosts (filename)
5890 "Return a list of (user host) tuples allowed to access.
292ffc15 5891Either user or host may be nil."
00d6fd04
MA
5892 ;; On Windows, there are problems in completion when
5893 ;; `default-directory' is remote.
9e6ab520 5894 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5895 res)
8daea7fc 5896 (when (file-readable-p filename)
16674e4f
KG
5897 (with-temp-buffer
5898 (insert-file-contents filename)
5899 (goto-char (point-min))
5900 (while (not (eobp))
292ffc15 5901 (push (tramp-parse-rhosts-group) res))))
16674e4f
KG
5902 res))
5903
16674e4f
KG
5904(defun tramp-parse-rhosts-group ()
5905 "Return a (user host) tuple allowed to access.
292ffc15 5906Either user or host may be nil."
16674e4f
KG
5907 (let ((result)
5908 (regexp
5909 (concat
5910 "^\\(" tramp-host-regexp "\\)"
5911 "\\([ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
9e6ab520 5912 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
5913 (when (re-search-forward regexp nil t)
5914 (setq result (append (list (match-string 3) (match-string 1)))))
5915 (widen)
5916 (forward-line 1)
5917 result))
5918
5919(defun tramp-parse-shosts (filename)
5920 "Return a list of (user host) tuples allowed to access.
5921User is always nil."
00d6fd04
MA
5922 ;; On Windows, there are problems in completion when
5923 ;; `default-directory' is remote.
9e6ab520 5924 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5925 res)
8daea7fc 5926 (when (file-readable-p filename)
16674e4f
KG
5927 (with-temp-buffer
5928 (insert-file-contents filename)
5929 (goto-char (point-min))
5930 (while (not (eobp))
292ffc15 5931 (push (tramp-parse-shosts-group) res))))
16674e4f
KG
5932 res))
5933
5934(defun tramp-parse-shosts-group ()
5935 "Return a (user host) tuple allowed to access.
5936User is always nil."
16674e4f
KG
5937 (let ((result)
5938 (regexp (concat "^\\(" tramp-host-regexp "\\)")))
9e6ab520 5939 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
5940 (when (re-search-forward regexp nil t)
5941 (setq result (list nil (match-string 1))))
5942 (widen)
5943 (or
5944 (> (skip-chars-forward ",") 0)
5945 (forward-line 1))
5946 result))
5947
8daea7fc
KG
5948(defun tramp-parse-sconfig (filename)
5949 "Return a list of (user host) tuples allowed to access.
5950User is always nil."
00d6fd04
MA
5951 ;; On Windows, there are problems in completion when
5952 ;; `default-directory' is remote.
9e6ab520 5953 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5954 res)
8daea7fc
KG
5955 (when (file-readable-p filename)
5956 (with-temp-buffer
5957 (insert-file-contents filename)
5958 (goto-char (point-min))
5959 (while (not (eobp))
5960 (push (tramp-parse-sconfig-group) res))))
5961 res))
5962
5963(defun tramp-parse-sconfig-group ()
5964 "Return a (user host) tuple allowed to access.
5965User is always nil."
8daea7fc
KG
5966 (let ((result)
5967 (regexp (concat "^[ \t]*Host[ \t]+" "\\(" tramp-host-regexp "\\)")))
9e6ab520 5968 (narrow-to-region (point) (tramp-compat-line-end-position))
8daea7fc
KG
5969 (when (re-search-forward regexp nil t)
5970 (setq result (list nil (match-string 1))))
5971 (widen)
5972 (or
5973 (> (skip-chars-forward ",") 0)
5974 (forward-line 1))
5975 result))
5976
5ec2cc41
KG
5977(defun tramp-parse-shostkeys (dirname)
5978 "Return a list of (user host) tuples allowed to access.
5979User is always nil."
00d6fd04
MA
5980 ;; On Windows, there are problems in completion when
5981 ;; `default-directory' is remote.
9e6ab520 5982 (let* ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
5983 (regexp (concat "^key_[0-9]+_\\(" tramp-host-regexp "\\)\\.pub$"))
5984 (files (when (file-directory-p dirname) (directory-files dirname)))
5985 result)
5ec2cc41
KG
5986 (while files
5987 (when (string-match regexp (car files))
5988 (push (list nil (match-string 1 (car files))) result))
5989 (setq files (cdr files)))
5990 result))
5991
5992(defun tramp-parse-sknownhosts (dirname)
5993 "Return a list of (user host) tuples allowed to access.
5994User is always nil."
00d6fd04
MA
5995 ;; On Windows, there are problems in completion when
5996 ;; `default-directory' is remote.
9e6ab520 5997 (let* ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
5998 (regexp (concat "^\\(" tramp-host-regexp
5999 "\\)\\.ssh-\\(dss\\|rsa\\)\\.pub$"))
6000 (files (when (file-directory-p dirname) (directory-files dirname)))
6001 result)
5ec2cc41
KG
6002 (while files
6003 (when (string-match regexp (car files))
6004 (push (list nil (match-string 1 (car files))) result))
6005 (setq files (cdr files)))
6006 result))
6007
16674e4f
KG
6008(defun tramp-parse-hosts (filename)
6009 "Return a list of (user host) tuples allowed to access.
6010User is always nil."
00d6fd04
MA
6011 ;; On Windows, there are problems in completion when
6012 ;; `default-directory' is remote.
9e6ab520 6013 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 6014 res)
8daea7fc 6015 (when (file-readable-p filename)
16674e4f
KG
6016 (with-temp-buffer
6017 (insert-file-contents filename)
6018 (goto-char (point-min))
6019 (while (not (eobp))
292ffc15 6020 (push (tramp-parse-hosts-group) res))))
16674e4f
KG
6021 res))
6022
6023(defun tramp-parse-hosts-group ()
6024 "Return a (user host) tuple allowed to access.
6025User is always nil."
16674e4f 6026 (let ((result)
b96e6899
MA
6027 (regexp
6028 (concat "^\\(" tramp-ipv6-regexp "\\|" tramp-host-regexp "\\)")))
9e6ab520 6029 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f 6030 (when (re-search-forward regexp nil t)
b96e6899 6031 (setq result (list nil (match-string 1))))
16674e4f
KG
6032 (widen)
6033 (or
6034 (> (skip-chars-forward " \t") 0)
6035 (forward-line 1))
6036 result))
6037
8daea7fc
KG
6038;; For su-alike methods it would be desirable to return "root@localhost"
6039;; as default. Unfortunately, we have no information whether any user name
00d6fd04 6040;; has been typed already. So we use `tramp-current-user' as indication,
8daea7fc 6041;; assuming it is set in `tramp-completion-handle-file-name-all-completions'.
16674e4f
KG
6042(defun tramp-parse-passwd (filename)
6043 "Return a list of (user host) tuples allowed to access.
6044Host is always \"localhost\"."
00d6fd04
MA
6045 ;; On Windows, there are problems in completion when
6046 ;; `default-directory' is remote.
9e6ab520 6047 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 6048 res)
8daea7fc 6049 (if (zerop (length tramp-current-user))
16674e4f 6050 '(("root" nil))
8daea7fc 6051 (when (file-readable-p filename)
16674e4f
KG
6052 (with-temp-buffer
6053 (insert-file-contents filename)
6054 (goto-char (point-min))
6055 (while (not (eobp))
292ffc15 6056 (push (tramp-parse-passwd-group) res))))
16674e4f
KG
6057 res)))
6058
6059(defun tramp-parse-passwd-group ()
6060 "Return a (user host) tuple allowed to access.
292ffc15 6061Host is always \"localhost\"."
16674e4f
KG
6062 (let ((result)
6063 (regexp (concat "^\\(" tramp-user-regexp "\\):")))
9e6ab520 6064 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
6065 (when (re-search-forward regexp nil t)
6066 (setq result (list (match-string 1) "localhost")))
6067 (widen)
6068 (forward-line 1)
6069 result))
6070
292ffc15
KG
6071(defun tramp-parse-netrc (filename)
6072 "Return a list of (user host) tuples allowed to access.
6073User may be nil."
00d6fd04
MA
6074 ;; On Windows, there are problems in completion when
6075 ;; `default-directory' is remote.
9e6ab520 6076 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 6077 res)
8daea7fc 6078 (when (file-readable-p filename)
292ffc15
KG
6079 (with-temp-buffer
6080 (insert-file-contents filename)
6081 (goto-char (point-min))
6082 (while (not (eobp))
6083 (push (tramp-parse-netrc-group) res))))
6084 res))
6085
6086(defun tramp-parse-netrc-group ()
6087 "Return a (user host) tuple allowed to access.
6088User may be nil."
292ffc15
KG
6089 (let ((result)
6090 (regexp
6091 (concat
6092 "^[ \t]*machine[ \t]+" "\\(" tramp-host-regexp "\\)"
6093 "\\([ \t]+login[ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
9e6ab520 6094 (narrow-to-region (point) (tramp-compat-line-end-position))
292ffc15
KG
6095 (when (re-search-forward regexp nil t)
6096 (setq result (list (match-string 3) (match-string 1))))
6097 (widen)
6098 (forward-line 1)
6099 result))
6100
00d6fd04
MA
6101(defun tramp-parse-putty (registry)
6102 "Return a list of (user host) tuples allowed to access.
6103User is always nil."
6104 ;; On Windows, there are problems in completion when
6105 ;; `default-directory' is remote.
9e6ab520 6106 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
6107 res)
6108 (with-temp-buffer
a4aeb9a4 6109 (when (zerop (tramp-local-call-process "reg" nil t nil "query" registry))
00d6fd04
MA
6110 (goto-char (point-min))
6111 (while (not (eobp))
6112 (push (tramp-parse-putty-group registry) res))))
6113 res))
6114
6115(defun tramp-parse-putty-group (registry)
6116 "Return a (user host) tuple allowed to access.
6117User is always nil."
6118 (let ((result)
6119 (regexp (concat (regexp-quote registry) "\\\\\\(.+\\)")))
9e6ab520 6120 (narrow-to-region (point) (tramp-compat-line-end-position))
00d6fd04
MA
6121 (when (re-search-forward regexp nil t)
6122 (setq result (list nil (match-string 1))))
6123 (widen)
6124 (forward-line 1)
6125 result))
6126
fb7933a3
KG
6127;;; Internal Functions:
6128
00d6fd04
MA
6129(defun tramp-maybe-send-script (vec script name)
6130 "Define in remote shell function NAME implemented as SCRIPT.
6131Only send the definition if it has not already been done."
6132 (let* ((p (tramp-get-connection-process vec))
6133 (scripts (tramp-get-connection-property p "scripts" nil)))
1834b39f 6134 (unless (member name scripts)
00d6fd04
MA
6135 (tramp-message vec 5 "Sending script `%s'..." name)
6136 ;; The script could contain a call of Perl. This is masked with `%s'.
6137 (tramp-send-command-and-check
6138 vec
6139 (format "%s () {\n%s\n}" name
6140 (format script (tramp-get-remote-perl vec))))
6141 (tramp-set-connection-property p "scripts" (cons name scripts))
6142 (tramp-message vec 5 "Sending script `%s'...done." name))))
c82c5727 6143
fb7933a3 6144(defun tramp-set-auto-save ()
00d6fd04 6145 (when (and ;; ange-ftp has its own auto-save mechanism
7177e2a3
MA
6146 (eq (tramp-find-foreign-file-name-handler (buffer-file-name))
6147 'tramp-sh-file-name-handler)
fb7933a3
KG
6148 auto-save-default)
6149 (auto-save-mode 1)))
6150(add-hook 'find-file-hooks 'tramp-set-auto-save t)
a69c01a0 6151(add-hook 'tramp-unload-hook
aa485f7c
MA
6152 (lambda ()
6153 (remove-hook 'find-file-hooks 'tramp-set-auto-save)))
fb7933a3
KG
6154
6155(defun tramp-run-test (switch filename)
6156 "Run `test' on the remote system, given a SWITCH and a FILENAME.
6157Returns the exit code of the `test' program."
00d6fd04
MA
6158 (with-parsed-tramp-file-name filename nil
6159 (tramp-send-command-and-check
6160 v
6161 (format
6162 "%s %s %s"
6163 (tramp-get-test-command v)
6164 switch
6165 (tramp-shell-quote-argument localname)))))
6166
6167(defun tramp-run-test2 (format-string file1 file2)
6168 "Run `test'-like program on the remote system, given FILE1, FILE2.
6169FORMAT-STRING contains the program name, switches, and place holders.
6170Returns the exit code of the `test' program. Barfs if the methods,
fb7933a3 6171hosts, or files, disagree."
00d6fd04
MA
6172 (unless (tramp-equal-remote file1 file2)
6173 (with-parsed-tramp-file-name (if (tramp-tramp-file-p file1) file1 file2) nil
6174 (tramp-error
6175 v 'file-error
6176 "tramp-run-test2 only implemented for same method, user, host")))
6177 (with-parsed-tramp-file-name file1 v1
6178 (with-parsed-tramp-file-name file1 v2
fb7933a3 6179 (tramp-send-command-and-check
00d6fd04
MA
6180 v1
6181 (format format-string
6182 (tramp-shell-quote-argument v1-localname)
6183 (tramp-shell-quote-argument v2-localname))))))
fb7933a3 6184
00d6fd04
MA
6185(defun tramp-buffer-name (vec)
6186 "A name for the connection buffer VEC."
6187 ;; We must use `tramp-file-name-real-host', because for gateway
6188 ;; methods the default port will be expanded later on, which would
6189 ;; tamper the name.
6190 (let ((method (tramp-file-name-method vec))
6191 (user (tramp-file-name-user vec))
6192 (host (tramp-file-name-real-host vec)))
6193 (if (not (zerop (length user)))
6194 (format "*tramp/%s %s@%s*" method user host)
6195 (format "*tramp/%s %s*" method host))))
6196
b88f2d0a
MA
6197(defun tramp-delete-temp-file-function ()
6198 "Remove temporary files related to current buffer."
6199 (when (stringp tramp-temp-buffer-file-name)
6200 (condition-case nil
6201 (delete-file tramp-temp-buffer-file-name)
6202 (error nil))))
6203
6204(add-hook 'kill-buffer-hook 'tramp-delete-temp-file-function)
6205(add-hook 'tramp-cache-unload-hook
6206 (lambda ()
6207 (remove-hook 'kill-buffer-hook
6208 'tramp-delete-temp-file-function)))
6209
00d6fd04
MA
6210(defun tramp-get-buffer (vec)
6211 "Get the connection buffer to be used for VEC."
6212 (or (get-buffer (tramp-buffer-name vec))
6213 (with-current-buffer (get-buffer-create (tramp-buffer-name vec))
6214 (setq buffer-undo-list t)
6215 (setq default-directory
6216 (tramp-make-tramp-file-name
6217 (tramp-file-name-method vec)
6218 (tramp-file-name-user vec)
6219 (tramp-file-name-host vec)
6220 "/"))
6221 (current-buffer))))
6222
6223(defun tramp-get-connection-buffer (vec)
6224 "Get the connection buffer to be used for VEC.
6225In case a second asynchronous communication has been started, it is different
6226from `tramp-get-buffer'."
6227 (or (tramp-get-connection-property vec "process-buffer" nil)
6228 (tramp-get-buffer vec)))
6229
6230(defun tramp-get-connection-process (vec)
6231 "Get the connection process to be used for VEC.
6232In case a second asynchronous communication has been started, it is different
6233from the default one."
6234 (get-process
6235 (or (tramp-get-connection-property vec "process-name" nil)
6236 (tramp-buffer-name vec))))
6237
6238(defun tramp-debug-buffer-name (vec)
6239 "A name for the debug buffer for VEC."
6240 ;; We must use `tramp-file-name-real-host', because for gateway
6241 ;; methods the default port will be expanded later on, which would
6242 ;; tamper the name.
6243 (let ((method (tramp-file-name-method vec))
6244 (user (tramp-file-name-user vec))
6245 (host (tramp-file-name-real-host vec)))
6246 (if (not (zerop (length user)))
6247 (format "*debug tramp/%s %s@%s*" method user host)
6248 (format "*debug tramp/%s %s*" method host))))
6249
6250(defun tramp-get-debug-buffer (vec)
6251 "Get the debug buffer for VEC."
01917a18 6252 (with-current-buffer
00d6fd04
MA
6253 (get-buffer-create (tramp-debug-buffer-name vec))
6254 (when (bobp)
6255 (setq buffer-undo-list t)
9ce8462a
MA
6256 ;; Activate outline-mode. This runs `text-mode-hook' and
6257 ;; `outline-mode-hook'. We must prevent that local processes
6258 ;; die. Yes: I've seen `flyspell-mode', which starts "ispell"
6259 ;; ...
9e6ab520 6260 (let ((default-directory (tramp-compat-temporary-file-directory)))
00d6fd04 6261 (outline-mode))
9ce8462a 6262 (set (make-local-variable 'outline-regexp)
736ac90f 6263 "[0-9]+:[0-9]+:[0-9]+\\.[0-9]+ [a-z0-9-]+ (\\([0-9]+\\)) #")
9ce8462a
MA
6264; (set (make-local-variable 'outline-regexp)
6265; "[a-z.-]+:[0-9]+: [a-z0-9-]+ (\\([0-9]+\\)) #")
6266 (set (make-local-variable 'outline-level) 'tramp-outline-level))
01917a18 6267 (current-buffer)))
fb7933a3 6268
00d6fd04
MA
6269(defun tramp-outline-level ()
6270 "Return the depth to which a statement is nested in the outline.
6271Point must be at the beginning of a header line.
6272
6273The outline level is equal to the verbosity of the Tramp message."
6274 (1+ (string-to-number (match-string 1))))
fb7933a3 6275
00d6fd04
MA
6276(defun tramp-find-executable
6277 (vec progname dirlist &optional ignore-tilde ignore-path)
6278 "Searches for PROGNAME in $PATH and all directories mentioned in DIRLIST.
6279First arg VEC specifies the connection, PROGNAME is the program
6280to search for, and DIRLIST gives the list of directories to
6281search. If IGNORE-TILDE is non-nil, directory names starting
6282with `~' will be ignored. If IGNORE-PATH is non-nil, searches
6283only in DIRLIST.
fb7933a3 6284
7432277c 6285Returns the absolute file name of PROGNAME, if found, and nil otherwise.
fb7933a3
KG
6286
6287This function expects to be in the right *tramp* buffer."
00d6fd04
MA
6288 (with-current-buffer (tramp-get-buffer vec)
6289 (let (result)
6290 ;; Check whether the executable is in $PATH. "which(1)" does not
6291 ;; report always a correct error code; therefore we check the
6292 ;; number of words it returns.
6293 (unless ignore-path
6294 (tramp-send-command vec (format "which \\%s | wc -w" progname))
6295 (goto-char (point-min))
6296 (if (looking-at "^1$")
6297 (setq result (concat "\\" progname))))
6298 (unless result
6299 (when ignore-tilde
6300 ;; Remove all ~/foo directories from dirlist. In Emacs 20,
6301 ;; `remove' is in CL, and we want to avoid CL dependencies.
6302 (let (newdl d)
6303 (while dirlist
6304 (setq d (car dirlist))
6305 (setq dirlist (cdr dirlist))
6306 (unless (char-equal ?~ (aref d 0))
6307 (setq newdl (cons d newdl))))
6308 (setq dirlist (nreverse newdl))))
6309 (tramp-send-command
6310 vec
6311 (format (concat "while read d; "
6312 "do if test -x $d/%s -a -f $d/%s; "
6313 "then echo tramp_executable $d/%s; "
6314 "break; fi; done <<'EOF'\n"
6315 "%s\nEOF")
6316 progname progname progname (mapconcat 'identity dirlist "\n")))
6317 (goto-char (point-max))
6318 (when (search-backward "tramp_executable " nil t)
6319 (skip-chars-forward "^ ")
6320 (skip-chars-forward " ")
9e6ab520
MA
6321 (setq result (buffer-substring
6322 (point) (tramp-compat-line-end-position)))))
00d6fd04
MA
6323 result)))
6324
6325(defun tramp-set-remote-path (vec)
6326 "Sets the remote environment PATH to existing directories.
6327I.e., for each directory in `tramp-remote-path', it is tested
6328whether it exists and if so, it is added to the environment
6329variable PATH."
6330 (tramp-message vec 5 (format "Setting $PATH environment variable"))
f84638eb
MA
6331 (tramp-send-command
6332 vec (format "PATH=%s; export PATH"
6333 (mapconcat 'identity (tramp-get-remote-path vec) ":"))))
fb7933a3 6334
cfb5c0db
MA
6335;; ------------------------------------------------------------
6336;; -- Communication with external shell --
6337;; ------------------------------------------------------------
fb7933a3 6338
00d6fd04 6339(defun tramp-find-file-exists-command (vec)
fb7933a3
KG
6340 "Find a command on the remote host for checking if a file exists.
6341Here, we are looking for a command which has zero exit status if the
6342file exists and nonzero exit status otherwise."
00d6fd04 6343 (let ((existing "/")
fb7933a3 6344 (nonexisting
00d6fd04
MA
6345 (tramp-shell-quote-argument "/ this file does not exist "))
6346 result)
fb7933a3
KG
6347 ;; The algorithm is as follows: we try a list of several commands.
6348 ;; For each command, we first run `$cmd /' -- this should return
6349 ;; true, as the root directory always exists. And then we run
00d6fd04 6350 ;; `$cmd /this\ file\ does\ not\ exist ', hoping that the file indeed
fb7933a3
KG
6351 ;; does not exist. This should return false. We use the first
6352 ;; command we find that seems to work.
6353 ;; The list of commands to try is as follows:
00d6fd04
MA
6354 ;; `ls -d' This works on most systems, but NetBSD 1.4
6355 ;; has a bug: `ls' always returns zero exit
6356 ;; status, even for files which don't exist.
6357 ;; `test -e' Some Bourne shells have a `test' builtin
6358 ;; which does not know the `-e' option.
6359 ;; `/bin/test -e' For those, the `test' binary on disk normally
6360 ;; provides the option. Alas, the binary
6361 ;; is sometimes `/bin/test' and sometimes it's
6362 ;; `/usr/bin/test'.
6363 ;; `/usr/bin/test -e' In case `/bin/test' does not exist.
fb7933a3 6364 (unless (or
00d6fd04
MA
6365 (and (setq result (format "%s -e" (tramp-get-test-command vec)))
6366 (zerop (tramp-send-command-and-check
6367 vec (format "%s %s" result existing)))
6368 (not (zerop (tramp-send-command-and-check
6369 vec (format "%s %s" result nonexisting)))))
6370 (and (setq result "/bin/test -e")
6371 (zerop (tramp-send-command-and-check
6372 vec (format "%s %s" result existing)))
6373 (not (zerop (tramp-send-command-and-check
6374 vec (format "%s %s" result nonexisting)))))
6375 (and (setq result "/usr/bin/test -e")
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 (format "%s -d" (tramp-get-ls-command vec)))
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 (tramp-error
6386 vec 'file-error "Couldn't find command to check if file exists"))
6387 result))
bf247b6e 6388
fb7933a3 6389;; CCC test ksh or bash found for tilde expansion?
00d6fd04
MA
6390(defun tramp-find-shell (vec)
6391 "Opens a shell on the remote host which groks tilde expansion."
6392 (unless (tramp-get-connection-property vec "remote-shell" nil)
6393 (let (shell)
6394 (with-current-buffer (tramp-get-buffer vec)
7e780ff1 6395 (tramp-send-command vec "echo ~root" t)
00d6fd04
MA
6396 (cond
6397 ((string-match "^~root$" (buffer-string))
6398 (setq shell
f84638eb
MA
6399 (or (tramp-find-executable
6400 vec "bash" (tramp-get-remote-path vec) t)
6401 (tramp-find-executable
6402 vec "ksh" (tramp-get-remote-path vec) t)))
00d6fd04
MA
6403 (unless shell
6404 (tramp-error
6405 vec 'file-error
6406 "Couldn't find a shell which groks tilde expansion"))
6407 ;; Find arguments for this shell.
6408 (let ((alist tramp-sh-extra-args)
6409 item extra-args)
6410 (while (and alist (null extra-args))
6411 (setq item (pop alist))
6412 (when (string-match (car item) shell)
6413 (setq extra-args (cdr item))))
6414 (when extra-args (setq shell (concat shell " " extra-args))))
6415 (tramp-message
6416 vec 5 "Starting remote shell `%s' for tilde expansion..." shell)
dab816a9 6417 (let ((tramp-end-of-output tramp-initial-end-of-output))
a4aeb9a4 6418 (tramp-send-command
b08104a0 6419 vec
70c11b0b
MA
6420 (format "PROMPT_COMMAND='' PS1=%s PS2='' PS3='' exec %s"
6421 (shell-quote-argument tramp-end-of-output) shell)
b08104a0 6422 t))
a0a5183a 6423 ;; Setting prompts.
00d6fd04 6424 (tramp-message vec 5 "Setting remote shell prompt...")
70c11b0b
MA
6425 (tramp-send-command
6426 vec (format "PS1=%s" (shell-quote-argument tramp-end-of-output)) t)
9fa0d3aa
MA
6427 (tramp-send-command vec "PS2=''" t)
6428 (tramp-send-command vec "PS3=''" t)
6429 (tramp-send-command vec "PROMPT_COMMAND=''" t)
00d6fd04 6430 (tramp-message vec 5 "Setting remote shell prompt...done"))
a0a5183a 6431
00d6fd04
MA
6432 (t (tramp-message
6433 vec 5 "Remote `%s' groks tilde expansion, good"
6434 (tramp-get-method-parameter
6435 (tramp-file-name-method vec) 'tramp-remote-sh))
6436 (tramp-set-connection-property
6437 vec "remote-shell"
6438 (tramp-get-method-parameter
6439 (tramp-file-name-method vec) 'tramp-remote-sh))))))))
fb7933a3 6440
bf247b6e
KS
6441;; ------------------------------------------------------------
6442;; -- Functions for establishing connection --
6443;; ------------------------------------------------------------
fb7933a3 6444
ac474af1
KG
6445;; The following functions are actions to be taken when seeing certain
6446;; prompts from the remote host. See the variable
6447;; `tramp-actions-before-shell' for usage of these functions.
6448
00d6fd04 6449(defun tramp-action-login (proc vec)
ac474af1 6450 "Send the login name."
00d6fd04
MA
6451 (when (not (stringp tramp-current-user))
6452 (save-window-excursion
6453 (let ((enable-recursive-minibuffers t))
6454 (pop-to-buffer (tramp-get-connection-buffer vec))
6455 (setq tramp-current-user (read-string (match-string 0))))))
6456 (tramp-message vec 3 "Sending login name `%s'" tramp-current-user)
6457 (with-current-buffer (tramp-get-connection-buffer vec)
6458 (tramp-message vec 6 "\n%s" (buffer-string)))
6459 (tramp-send-string vec tramp-current-user))
6460
6461(defun tramp-action-password (proc vec)
ac474af1 6462 "Query the user for a password."
70c11b0b
MA
6463 (with-current-buffer (process-buffer proc)
6464 (tramp-check-for-regexp proc tramp-password-prompt-regexp)
6465 (tramp-message vec 3 "Sending %s" (match-string 1)))
00d6fd04
MA
6466 (tramp-enter-password proc))
6467
6468(defun tramp-action-succeed (proc vec)
ac474af1 6469 "Signal success in finding shell prompt."
ac474af1
KG
6470 (throw 'tramp-action 'ok))
6471
00d6fd04 6472(defun tramp-action-permission-denied (proc vec)
ac474af1 6473 "Signal permission denied."
00d6fd04 6474 (kill-process proc)
ac474af1
KG
6475 (throw 'tramp-action 'permission-denied))
6476
00d6fd04 6477(defun tramp-action-yesno (proc vec)
3cdaec13
KG
6478 "Ask the user for confirmation using `yes-or-no-p'.
6479Send \"yes\" to remote process on confirmation, abort otherwise.
6480See also `tramp-action-yn'."
ac474af1 6481 (save-window-excursion
00d6fd04
MA
6482 (let ((enable-recursive-minibuffers t))
6483 (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec)))
6484 (unless (yes-or-no-p (match-string 0))
6485 (kill-process proc)
6486 (throw 'tramp-action 'permission-denied))
6487 (with-current-buffer (tramp-get-connection-buffer vec)
6488 (tramp-message vec 6 "\n%s" (buffer-string)))
6489 (tramp-send-string vec "yes"))))
6490
6491(defun tramp-action-yn (proc vec)
3cdaec13
KG
6492 "Ask the user for confirmation using `y-or-n-p'.
6493Send \"y\" to remote process on confirmation, abort otherwise.
6494See also `tramp-action-yesno'."
6495 (save-window-excursion
00d6fd04
MA
6496 (let ((enable-recursive-minibuffers t))
6497 (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec)))
6498 (unless (y-or-n-p (match-string 0))
6499 (kill-process proc)
6500 (throw 'tramp-action 'permission-denied))
6501 (with-current-buffer (tramp-get-connection-buffer vec)
6502 (tramp-message vec 6 "\n%s" (buffer-string)))
6503 (tramp-send-string vec "y"))))
6504
6505(defun tramp-action-terminal (proc vec)
487f4fb7
KG
6506 "Tell the remote host which terminal type to use.
6507The terminal type can be configured with `tramp-terminal-type'."
00d6fd04 6508 (tramp-message vec 5 "Setting `%s' as terminal type." tramp-terminal-type)
7e780ff1
MA
6509 (with-current-buffer (tramp-get-connection-buffer vec)
6510 (tramp-message vec 6 "\n%s" (buffer-string)))
00d6fd04 6511 (tramp-send-string vec tramp-terminal-type))
487f4fb7 6512
00d6fd04 6513(defun tramp-action-process-alive (proc vec)
19a87064 6514 "Check whether a process has finished."
00d6fd04 6515 (unless (memq (process-status proc) '(run open))
19a87064
MA
6516 (throw 'tramp-action 'process-died)))
6517
00d6fd04 6518(defun tramp-action-out-of-band (proc vec)
38c65fca 6519 "Check whether an out-of-band copy has finished."
00d6fd04
MA
6520 (cond ((and (memq (process-status proc) '(stop exit))
6521 (zerop (process-exit-status proc)))
6522 (tramp-message vec 3 "Process has finished.")
38c65fca 6523 (throw 'tramp-action 'ok))
00d6fd04
MA
6524 ((or (and (memq (process-status proc) '(stop exit))
6525 (not (zerop (process-exit-status proc))))
6526 (memq (process-status proc) '(signal)))
01917a18
MA
6527 ;; `scp' could have copied correctly, but set modes could have failed.
6528 ;; This can be ignored.
00d6fd04
MA
6529 (with-current-buffer (process-buffer proc)
6530 (goto-char (point-min))
6531 (if (re-search-forward tramp-operation-not-permitted-regexp nil t)
6532 (progn
6533 (tramp-message vec 5 "'set mode' error ignored.")
6534 (tramp-message vec 3 "Process has finished.")
6535 (throw 'tramp-action 'ok))
6536 (tramp-message vec 3 "Process has died.")
6537 (throw 'tramp-action 'process-died))))
38c65fca
KG
6538 (t nil)))
6539
ac474af1
KG
6540;; Functions for processing the actions.
6541
00d6fd04 6542(defun tramp-process-one-action (proc vec actions)
ac474af1 6543 "Wait for output from the shell and perform one action."
00d6fd04 6544 (let (found todo item pattern action)
e6466697 6545 (while (not found)
00d6fd04
MA
6546 ;; Reread output once all actions have been performed.
6547 ;; Obviously, the output was not complete.
6548 (tramp-accept-process-output proc 1)
e6466697
MA
6549 (setq todo actions)
6550 (while todo
e6466697 6551 (setq item (pop todo))
95d610cb 6552 (setq pattern (format "\\(%s\\)\\'" (symbol-value (nth 0 item))))
e6466697 6553 (setq action (nth 1 item))
00d6fd04
MA
6554 (tramp-message
6555 vec 5 "Looking for regexp \"%s\" from remote shell" pattern)
6556 (when (tramp-check-for-regexp proc pattern)
6557 (tramp-message vec 5 "Call `%s'" (symbol-name action))
6558 (setq found (funcall action proc vec)))))
e6466697
MA
6559 found))
6560
00d6fd04 6561(defun tramp-process-actions (proc vec actions &optional timeout)
e6466697 6562 "Perform actions until success or TIMEOUT."
263c02ef 6563 ;; Enable auth-source and password-cache.
7540f029 6564 (tramp-set-connection-property vec "first-password-request" t)
ac474af1
KG
6565 (let (exit)
6566 (while (not exit)
00d6fd04 6567 (tramp-message proc 3 "Waiting for prompts from remote shell")
ac474af1
KG
6568 (setq exit
6569 (catch 'tramp-action
e6466697
MA
6570 (if timeout
6571 (with-timeout (timeout)
00d6fd04
MA
6572 (tramp-process-one-action proc vec actions))
6573 (tramp-process-one-action proc vec actions)))))
6574 (with-current-buffer (tramp-get-connection-buffer vec)
6575 (tramp-message vec 6 "\n%s" (buffer-string)))
ac474af1 6576 (unless (eq exit 'ok)
9c13938d 6577 (tramp-clear-passwd vec)
00d6fd04
MA
6578 (tramp-error-with-buffer
6579 nil vec 'file-error
6580 (cond
6581 ((eq exit 'permission-denied) "Permission denied")
6582 ((eq exit 'process-died) "Process died")
6583 (t "Login failed"))))))
fb7933a3
KG
6584
6585;; Utility functions.
6586
00d6fd04 6587(defun tramp-accept-process-output (&optional proc timeout timeout-msecs)
d2a2c17f
MA
6588 "Like `accept-process-output' for Tramp processes.
6589This is needed in order to hide `last-coding-system-used', which is set
6590for process communication also."
00d6fd04
MA
6591 (with-current-buffer (process-buffer proc)
6592 (tramp-message proc 10 "%s %s" proc (process-status proc))
6593 (let (buffer-read-only last-coding-system-used)
6594 ;; Under Windows XP, accept-process-output doesn't return
6595 ;; sometimes. So we add an additional timeout.
6596 (with-timeout ((or timeout 1))
6597 (accept-process-output proc timeout timeout-msecs)))
6598 (tramp-message proc 10 "\n%s" (buffer-string))))
6599
6600(defun tramp-check-for-regexp (proc regexp)
6601 "Check whether REGEXP is contained in process buffer of PROC.
6602Erase echoed commands if exists."
6603 (with-current-buffer (process-buffer proc)
6604 (goto-char (point-min))
674da028 6605
00d6fd04
MA
6606 ;; Check whether we need to remove echo output.
6607 (when (and (tramp-get-connection-property proc "check-remote-echo" nil)
6608 (re-search-forward tramp-echoed-echo-mark-regexp nil t))
6609 (let ((begin (match-beginning 0)))
6610 (when (re-search-forward tramp-echoed-echo-mark-regexp nil t)
6611 ;; Discard echo from remote output.
6612 (tramp-set-connection-property proc "check-remote-echo" nil)
6613 (tramp-message proc 5 "echo-mark found")
6614 (forward-line)
6615 (delete-region begin (point))
6616 (goto-char (point-min)))))
674da028 6617
68712eb6
MA
6618 (when (or (not (tramp-get-connection-property proc "check-remote-echo" nil))
6619 ;; Sometimes, the echo string is suppressed on the remote side.
6620 (not (string-equal
6621 (substring-no-properties
6622 tramp-echo-mark-marker
6623 0 (min tramp-echo-mark-marker-length (1- (point-max))))
6624 (buffer-substring-no-properties
6625 1 (min (1+ tramp-echo-mark-marker-length) (point-max))))))
70c11b0b 6626 ;; No echo to be handled, now we can look for the regexp.
674da028 6627 (goto-char (point-min))
00d6fd04 6628 (re-search-forward regexp nil t))))
d2a2c17f 6629
fb7933a3
KG
6630(defun tramp-wait-for-regexp (proc timeout regexp)
6631 "Wait for a REGEXP to appear from process PROC within TIMEOUT seconds.
6632Expects the output of PROC to be sent to the current buffer. Returns
6633the string that matched, or nil. Waits indefinitely if TIMEOUT is
6634nil."
00d6fd04
MA
6635 (with-current-buffer (process-buffer proc)
6636 (let ((found (tramp-check-for-regexp proc regexp))
6637 (start-time (current-time)))
6638 (cond (timeout
6639 ;; Work around a bug in XEmacs 21, where the timeout
6640 ;; expires faster than it should. This degenerates
6641 ;; to polling for buggy XEmacsen, but oh, well.
6642 (while (and (not found)
6643 (< (tramp-time-diff (current-time) start-time)
6644 timeout))
6645 (with-timeout (timeout)
6646 (while (not found)
6647 (tramp-accept-process-output proc 1)
6648 (unless (memq (process-status proc) '(run open))
6649 (tramp-error-with-buffer
6650 nil proc 'file-error "Process has died"))
6651 (setq found (tramp-check-for-regexp proc regexp))))))
6652 (t
6653 (while (not found)
6654 (tramp-accept-process-output proc 1)
6655 (unless (memq (process-status proc) '(run open))
6656 (tramp-error-with-buffer
6657 nil proc 'file-error "Process has died"))
6658 (setq found (tramp-check-for-regexp proc regexp)))))
6659 (tramp-message proc 6 "\n%s" (buffer-string))
fb7933a3 6660 (when (not found)
00d6fd04
MA
6661 (if timeout
6662 (tramp-error
6663 proc 'file-error "[[Regexp `%s' not found in %d secs]]"
6664 regexp timeout)
6665 (tramp-error proc 'file-error "[[Regexp `%s' not found]]" regexp)))
6666 found)))
fb7933a3 6667
b25a52cc
KG
6668(defun tramp-barf-if-no-shell-prompt (proc timeout &rest error-args)
6669 "Wait for shell prompt and barf if none appears.
6670Looks at process PROC to see if a shell prompt appears in TIMEOUT
6671seconds. If not, it produces an error message with the given ERROR-ARGS."
7e780ff1
MA
6672 (unless
6673 (tramp-wait-for-regexp
6674 proc timeout
6675 (format
6676 "\\(%s\\|%s\\)\\'" shell-prompt-pattern tramp-shell-prompt-pattern))
00d6fd04
MA
6677 (apply 'tramp-error-with-buffer nil proc 'file-error error-args)))
6678
7e780ff1
MA
6679;; We don't call `tramp-send-string' in order to hide the password
6680;; from the debug buffer, and because end-of-line handling of the
6681;; string.
6682(defun tramp-enter-password (proc)
00d6fd04
MA
6683 "Prompt for a password and send it to the remote end."
6684 (process-send-string
7e780ff1
MA
6685 proc (concat (tramp-read-passwd proc)
6686 (or (tramp-get-method-parameter
6687 tramp-current-method
6688 'tramp-password-end-of-line)
6689 tramp-default-password-end-of-line))))
00d6fd04
MA
6690
6691(defun tramp-open-connection-setup-interactive-shell (proc vec)
fb7933a3 6692 "Set up an interactive shell.
00d6fd04
MA
6693Mainly sets the prompt and the echo correctly. PROC is the shell
6694process to set up. VEC specifies the connection."
dab816a9 6695 (let ((tramp-end-of-output tramp-initial-end-of-output))
8950769a
MA
6696 ;; It is useful to set the prompt in the following command because
6697 ;; some people have a setting for $PS1 which /bin/sh doesn't know
6698 ;; about and thus /bin/sh will display a strange prompt. For
6699 ;; example, if $PS1 has "${CWD}" in the value, then ksh will
6700 ;; display the current working directory but /bin/sh will display
6701 ;; a dollar sign. The following command line sets $PS1 to a sane
6702 ;; value, and works under Bourne-ish shells as well as csh-like
6703 ;; shells. Daniel Pittman reports that the unusual positioning of
6704 ;; the single quotes makes it work under `rc', too. We also unset
6705 ;; the variable $ENV because that is read by some sh
6706 ;; implementations (eg, bash when called as sh) on startup; this
6707 ;; way, we avoid the startup file clobbering $PS1. $PROMP_COMMAND
6708 ;; is another way to set the prompt in /bin/bash, it must be
6709 ;; discarded as well.
a4aeb9a4
MA
6710 (tramp-send-command
6711 vec
6712 (format
70c11b0b
MA
6713 "exec env ENV='' PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s"
6714 (shell-quote-argument tramp-end-of-output)
a4aeb9a4
MA
6715 (tramp-get-method-parameter
6716 (tramp-file-name-method vec) 'tramp-remote-sh))
8950769a
MA
6717 t)
6718
6719 ;; Disable echo.
6720 (tramp-message vec 5 "Setting up remote shell environment")
6721 (tramp-send-command vec "stty -inlcr -echo kill '^U' erase '^H'" t)
6722 ;; Check whether the echo has really been disabled. Some
6723 ;; implementations, like busybox of embedded GNU/Linux, don't
6724 ;; support disabling.
6725 (tramp-send-command vec "echo foo" t)
6726 (with-current-buffer (process-buffer proc)
6727 (goto-char (point-min))
6728 (when (looking-at "echo foo")
6729 (tramp-set-connection-property proc "remote-echo" t)
6730 (tramp-message vec 5 "Remote echo still on. Ok.")
6731 ;; Make sure backspaces and their echo are enabled and no line
6732 ;; width magic interferes with them.
6733 (tramp-send-command vec "stty icanon erase ^H cols 32767" t))))
e42c6bbc 6734
7e780ff1 6735 (tramp-message vec 5 "Setting shell prompt")
70c11b0b
MA
6736 (tramp-send-command
6737 vec (format "PS1=%s" (shell-quote-argument tramp-end-of-output)) t)
9fa0d3aa
MA
6738 (tramp-send-command vec "PS2=''" t)
6739 (tramp-send-command vec "PS3=''" t)
6740 (tramp-send-command vec "PROMPT_COMMAND=''" t)
e42c6bbc 6741
fb7933a3
KG
6742 ;; Try to set up the coding system correctly.
6743 ;; CCC this can't be the right way to do it. Hm.
00d6fd04 6744 (tramp-message vec 5 "Determining coding system")
7e780ff1 6745 (tramp-send-command vec "echo foo ; echo bar" t)
00d6fd04 6746 (with-current-buffer (process-buffer proc)
fb7933a3
KG
6747 (goto-char (point-min))
6748 (if (featurep 'mule)
00d6fd04
MA
6749 ;; Use MULE to select the right EOL convention for communicating
6750 ;; with the process.
311dd93f 6751 (let* ((cs (or (funcall (symbol-function 'process-coding-system) proc)
00d6fd04
MA
6752 (cons 'undecided 'undecided)))
6753 cs-decode cs-encode)
6754 (when (symbolp cs) (setq cs (cons cs cs)))
6755 (setq cs-decode (car cs))
6756 (setq cs-encode (cdr cs))
6757 (unless cs-decode (setq cs-decode 'undecided))
6758 (unless cs-encode (setq cs-encode 'undecided))
6759 (setq cs-encode (tramp-coding-system-change-eol-conversion
6760 cs-encode 'unix))
6761 (when (search-forward "\r" nil t)
6762 (setq cs-decode (tramp-coding-system-change-eol-conversion
6763 cs-decode 'dos)))
311dd93f 6764 (funcall (symbol-function 'set-buffer-process-coding-system)
70c11b0b
MA
6765 cs-decode cs-encode)
6766 (tramp-message
6767 vec 5 "Setting coding system to `%s' and `%s'" cs-decode cs-encode))
fb7933a3
KG
6768 ;; Look for ^M and do something useful if found.
6769 (when (search-forward "\r" nil t)
00d6fd04
MA
6770 ;; We have found a ^M but cannot frob the process coding system
6771 ;; because we're running on a non-MULE Emacs. Let's try
6772 ;; stty, instead.
7e780ff1 6773 (tramp-send-command vec "stty -onlcr" t))))
7e5686f0
MA
6774 ;; Dump stty settings in the traces.
6775 (when (>= tramp-verbose 10)
6776 (tramp-send-command vec "stty -a" t))
7e780ff1 6777 (tramp-send-command vec "set +o vi +o emacs" t)
e42c6bbc
MA
6778
6779 ;; Check whether the output of "uname -sr" has been changed. If
6780 ;; yes, this is a strong indication that we must expire all
d8ac123e
MA
6781 ;; connection properties. We start again with
6782 ;; `tramp-maybe-open-connection', it will be catched there.
e42c6bbc
MA
6783 (tramp-message vec 5 "Checking system information")
6784 (let ((old-uname (tramp-get-connection-property vec "uname" nil))
6785 (new-uname
6786 (tramp-set-connection-property
6787 vec "uname"
6788 (tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\""))))
6789 (when (and (stringp old-uname) (not (string-equal old-uname new-uname)))
d8ac123e
MA
6790 (with-current-buffer (tramp-get-debug-buffer vec)
6791 ;; Keep the debug buffer
2296b54d
MA
6792 (rename-buffer
6793 (generate-new-buffer-name tramp-temp-buffer-name) 'unique)
d8ac123e
MA
6794 (funcall (symbol-function 'tramp-cleanup-connection) vec)
6795 (if (= (point-min) (point-max))
6796 (kill-buffer nil)
6797 (rename-buffer (tramp-debug-buffer-name vec) 'unique))
6798 ;; We call `tramp-get-buffer' in order to keep the debug buffer.
6799 (tramp-get-buffer vec)
6800 (tramp-message
6801 vec 3
6802 "Connection reset, because remote host changed from `%s' to `%s'"
6803 old-uname new-uname)
6804 (throw 'uname-changed (tramp-maybe-open-connection vec)))))
e42c6bbc
MA
6805
6806 ;; Check whether the remote host suffers from buggy
6807 ;; `send-process-string'. This is known for FreeBSD (see comment in
6808 ;; `send_process', file process.c). I've tested sending 624 bytes
6809 ;; successfully, sending 625 bytes failed. Emacs makes a hack when
6810 ;; this host type is detected locally. It cannot handle remote
6811 ;; hosts, though.
00d6fd04
MA
6812 (with-connection-property proc "chunksize"
6813 (cond
6814 ((and (integerp tramp-chunksize) (> tramp-chunksize 0))
6815 tramp-chunksize)
6816 (t
6817 (tramp-message
6818 vec 5 "Checking remote host type for `send-process-string' bug")
6819 (if (string-match
e42c6bbc 6820 "^FreeBSD" (tramp-get-connection-property vec "uname" ""))
00d6fd04 6821 500 0))))
e42c6bbc 6822
00d6fd04
MA
6823 ;; Set remote PATH variable.
6824 (tramp-set-remote-path vec)
e42c6bbc 6825
fb7933a3
KG
6826 ;; Search for a good shell before searching for a command which
6827 ;; checks if a file exists. This is done because Tramp wants to use
6828 ;; "test foo; echo $?" to check if various conditions hold, and
6829 ;; there are buggy /bin/sh implementations which don't execute the
6830 ;; "echo $?" part if the "test" part has an error. In particular,
6831 ;; the Solaris /bin/sh is a problem. I'm betting that all systems
6832 ;; with buggy /bin/sh implementations will have a working bash or
6833 ;; ksh. Whee...
00d6fd04 6834 (tramp-find-shell vec)
e42c6bbc 6835
00d6fd04 6836 ;; Disable unexpected output.
7e780ff1 6837 (tramp-send-command vec "mesg n; biff n" t)
e42c6bbc 6838
00d6fd04
MA
6839 ;; Set the environment.
6840 (tramp-message vec 5 "Setting default environment")
661aaece
MA
6841
6842 ;; On OpenSolaris, there is a bug when HISTFILE is changed in place
6843 ;; <http://bugs.opensolaris.org/view_bug.do?bug_id=6834184>. We
6844 ;; apply the workaround.
6845 (if (string-equal (tramp-get-connection-property vec "uname" "") "SunOS 5.11")
7e5686f0 6846 (tramp-send-command vec "unset HISTFILE" t))
661aaece 6847
00d6fd04
MA
6848 (let ((env (copy-sequence tramp-remote-process-environment))
6849 unset item)
6850 (while env
70c11b0b 6851 (setq item (tramp-compat-split-string (car env) "="))
7e5686f0
MA
6852 (setcdr item (mapconcat 'identity (cdr item) "="))
6853 (if (and (stringp (cdr item)) (not (string-equal (cdr item) "")))
00d6fd04 6854 (tramp-send-command
7e5686f0 6855 vec (format "%s=%s; export %s" (car item) (cdr item) (car item)) t)
00d6fd04
MA
6856 (push (car item) unset))
6857 (setq env (cdr env)))
6858 (when unset
fb7933a3 6859 (tramp-send-command
7e780ff1 6860 vec (format "unset %s" (mapconcat 'identity unset " "))))) t)
fb7933a3 6861
ac474af1
KG
6862;; CCC: We should either implement a Perl version of base64 encoding
6863;; and decoding. Then we just use that in the last item. The other
6864;; alternative is to use the Perl version of UU encoding. But then
6865;; we need a Lisp version of uuencode.
16674e4f
KG
6866;;
6867;; Old text from documentation of tramp-methods:
6868;; Using a uuencode/uudecode inline method is discouraged, please use one
6869;; of the base64 methods instead since base64 encoding is much more
6870;; reliable and the commands are more standardized between the different
6871;; Unix versions. But if you can't use base64 for some reason, please
6872;; note that the default uudecode command does not work well for some
6873;; Unices, in particular AIX and Irix. For AIX, you might want to use
6874;; the following command for uudecode:
6875;;
6876;; sed '/^begin/d;/^[` ]$/d;/^end/d' | iconv -f uucode -t ISO8859-1
6877;;
6878;; For Irix, no solution is known yet.
6879
00d6fd04
MA
6880(defconst tramp-local-coding-commands
6881 '((b64 base64-encode-region base64-decode-region)
6882 (uu tramp-uuencode-region uudecode-decode-region)
6883 (pack
6884 "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
6885 "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"))
6886 "List of local coding commands for inline transfer.
16674e4f
KG
6887Each item is a list that looks like this:
6888
00d6fd04 6889\(FORMAT ENCODING DECODING)
ac474af1 6890
00d6fd04
MA
6891FORMAT is symbol describing the encoding/decoding format. It can be
6892`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
ac474af1 6893
00d6fd04
MA
6894ENCODING and DECODING can be strings, giving commands, or symbols,
6895giving functions. If they are strings, then they can contain
16674e4f
KG
6896the \"%s\" format specifier. If that specifier is present, the input
6897filename will be put into the command line at that spot. If the
6898specifier is not present, the input should be read from standard
6899input.
ac474af1 6900
16674e4f
KG
6901If they are functions, they will be called with two arguments, start
6902and end of region, and are expected to replace the region contents
6903with the encoded or decoded results, respectively.")
ac474af1 6904
00d6fd04 6905(defconst tramp-remote-coding-commands
3dc847a3
MA
6906 '((b64 "base64" "base64 -d")
6907 (b64 "mimencode -b" "mimencode -u -b")
00d6fd04
MA
6908 (b64 "mmencode -b" "mmencode -u -b")
6909 (b64 "recode data..base64" "recode base64..data")
6910 (b64 tramp-perl-encode-with-module tramp-perl-decode-with-module)
6911 (b64 tramp-perl-encode tramp-perl-decode)
6912 (uu "uuencode xxx" "uudecode -o /dev/stdout")
6913 (uu "uuencode xxx" "uudecode -o -")
6914 (uu "uuencode xxx" "uudecode -p")
6915 (uu "uuencode xxx" tramp-uudecode)
6916 (pack
6917 "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
6918 "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"))
6919 "List of remote coding commands for inline transfer.
6920Each item is a list that looks like this:
6921
6922\(FORMAT ENCODING DECODING)
6923
6924FORMAT is symbol describing the encoding/decoding format. It can be
6925`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
6926
6927ENCODING and DECODING can be strings, giving commands, or symbols,
6928giving variables. If they are strings, then they can contain
6929the \"%s\" format specifier. If that specifier is present, the input
6930filename will be put into the command line at that spot. If the
6931specifier is not present, the input should be read from standard
6932input.
6933
6934If they are variables, this variable is a string containing a Perl
6935implementation for this functionality. This Perl program will be transferred
db9e401b 6936to the remote host, and it is available as shell function with the same name.")
00d6fd04
MA
6937
6938(defun tramp-find-inline-encoding (vec)
ac474af1 6939 "Find an inline transfer encoding that works.
00d6fd04
MA
6940Goes through the list `tramp-local-coding-commands' and
6941`tramp-remote-coding-commands'."
6942 (save-excursion
6943 (let ((local-commands tramp-local-coding-commands)
6944 (magic "xyzzy")
6945 loc-enc loc-dec rem-enc rem-dec litem ritem found)
6946 (while (and local-commands (not found))
6947 (setq litem (pop local-commands))
6948 (catch 'wont-work-local
6949 (let ((format (nth 0 litem))
6950 (remote-commands tramp-remote-coding-commands))
6951 (setq loc-enc (nth 1 litem))
6952 (setq loc-dec (nth 2 litem))
6953 ;; If the local encoder or decoder is a string, the
6954 ;; corresponding command has to work locally.
6955 (if (not (stringp loc-enc))
6956 (tramp-message
6957 vec 5 "Checking local encoding function `%s'" loc-enc)
6958 (tramp-message
6959 vec 5 "Checking local encoding command `%s' for sanity" loc-enc)
6960 (unless (zerop (tramp-call-local-coding-command
6961 loc-enc nil nil))
6962 (throw 'wont-work-local nil)))
6963 (if (not (stringp loc-dec))
6964 (tramp-message
6965 vec 5 "Checking local decoding function `%s'" loc-dec)
6966 (tramp-message
6967 vec 5 "Checking local decoding command `%s' for sanity" loc-dec)
6968 (unless (zerop (tramp-call-local-coding-command
6969 loc-dec nil nil))
6970 (throw 'wont-work-local nil)))
6971 ;; Search for remote coding commands with the same format
6972 (while (and remote-commands (not found))
6973 (setq ritem (pop remote-commands))
6974 (catch 'wont-work-remote
6975 (when (equal format (nth 0 ritem))
6976 (setq rem-enc (nth 1 ritem))
6977 (setq rem-dec (nth 2 ritem))
6978 ;; Check if remote encoding and decoding commands can be
6979 ;; called remotely with null input and output. This makes
6980 ;; sure there are no syntax errors and the command is really
6981 ;; found. Note that we do not redirect stdout to /dev/null,
6982 ;; for two reasons: when checking the decoding command, we
6983 ;; actually check the output it gives. And also, when
6984 ;; redirecting "mimencode" output to /dev/null, then as root
6985 ;; it might change the permissions of /dev/null!
6986 (when (not (stringp rem-enc))
6987 (let ((name (symbol-name rem-enc)))
6988 (while (string-match (regexp-quote "-") name)
6989 (setq name (replace-match "_" nil t name)))
6990 (tramp-maybe-send-script vec (symbol-value rem-enc) name)
6991 (setq rem-enc name)))
6992 (tramp-message
6993 vec 5
6994 "Checking remote encoding command `%s' for sanity" rem-enc)
6995 (unless (zerop (tramp-send-command-and-check
6996 vec (format "%s </dev/null" rem-enc) t))
6997 (throw 'wont-work-remote nil))
6998
6999 (when (not (stringp rem-dec))
7000 (let ((name (symbol-name rem-dec)))
7001 (while (string-match (regexp-quote "-") name)
7002 (setq name (replace-match "_" nil t name)))
7003 (tramp-maybe-send-script vec (symbol-value rem-dec) name)
7004 (setq rem-dec name)))
7005 (tramp-message
7006 vec 5
7007 "Checking remote decoding command `%s' for sanity" rem-dec)
7008 (unless (zerop (tramp-send-command-and-check
7009 vec
7010 (format "echo %s | %s | %s"
b593f105
MA
7011 magic rem-enc rem-dec)
7012 t))
00d6fd04
MA
7013 (throw 'wont-work-remote nil))
7014
7015 (with-current-buffer (tramp-get-buffer vec)
7016 (goto-char (point-min))
7017 (unless (looking-at (regexp-quote magic))
7018 (throw 'wont-work-remote nil)))
7019
7020 ;; `rem-enc' and `rem-dec' could be a string meanwhile.
7021 (setq rem-enc (nth 1 ritem))
7022 (setq rem-dec (nth 2 ritem))
7023 (setq found t)))))))
7024
1d7e9a01 7025 ;; Did we find something?
00d6fd04 7026 (unless found
7e5686f0
MA
7027 (tramp-error
7028 vec 'file-error "Couldn't find an inline transfer encoding"))
00d6fd04
MA
7029
7030 ;; Set connection properties.
7031 (tramp-message vec 5 "Using local encoding `%s'" loc-enc)
7032 (tramp-set-connection-property vec "local-encoding" loc-enc)
7033 (tramp-message vec 5 "Using local decoding `%s'" loc-dec)
7034 (tramp-set-connection-property vec "local-decoding" loc-dec)
7035 (tramp-message vec 5 "Using remote encoding `%s'" rem-enc)
7036 (tramp-set-connection-property vec "remote-encoding" rem-enc)
7037 (tramp-message vec 5 "Using remote decoding `%s'" rem-dec)
7038 (tramp-set-connection-property vec "remote-decoding" rem-dec))))
16674e4f
KG
7039
7040(defun tramp-call-local-coding-command (cmd input output)
7041 "Call the local encoding or decoding command.
7042If CMD contains \"%s\", provide input file INPUT there in command.
7043Otherwise, INPUT is passed via standard input.
7044INPUT can also be nil which means `/dev/null'.
7045OUTPUT can be a string (which specifies a filename), or t (which
7046means standard output and thus the current buffer), or nil (which
7047means discard it)."
a4aeb9a4
MA
7048 (tramp-local-call-process
7049 tramp-encoding-shell
7050 (when (and input (not (string-match "%s" cmd))) input)
7051 (if (eq output t) t nil)
7052 nil
7053 tramp-encoding-command-switch
7054 (concat
7055 (if (string-match "%s" cmd) (format cmd input) cmd)
7056 (if (stringp output) (concat "> " output) ""))))
00d6fd04
MA
7057
7058(defun tramp-compute-multi-hops (vec)
7059 "Expands VEC according to `tramp-default-proxies-alist'.
7060Gateway hops are already opened."
7061 (let ((target-alist `(,vec))
7062 (choices tramp-default-proxies-alist)
7063 item proxy)
7064
7065 ;; Look for proxy hosts to be passed.
7066 (while choices
7067 (setq item (pop choices)
70c11b0b 7068 proxy (eval (nth 2 item)))
00d6fd04
MA
7069 (when (and
7070 ;; host
70c11b0b 7071 (string-match (or (eval (nth 0 item)) "")
00d6fd04
MA
7072 (or (tramp-file-name-host (car target-alist)) ""))
7073 ;; user
70c11b0b 7074 (string-match (or (eval (nth 1 item)) "")
00d6fd04
MA
7075 (or (tramp-file-name-user (car target-alist)) "")))
7076 (if (null proxy)
7077 ;; No more hops needed.
7078 (setq choices nil)
7079 ;; Replace placeholders.
7080 (setq proxy
7081 (format-spec
7082 proxy
7083 `((?u . ,(or (tramp-file-name-user (car target-alist)) ""))
7084 (?h . ,(or (tramp-file-name-host (car target-alist)) "")))))
7085 (with-parsed-tramp-file-name proxy l
7086 ;; Add the hop.
7087 (add-to-list 'target-alist l)
7088 ;; Start next search.
7089 (setq choices tramp-default-proxies-alist)))))
7090
7091 ;; Handle gateways.
8a4438b6
MA
7092 (when (and (boundp 'tramp-gw-tunnel-method)
7093 (string-match (format
7094 "^\\(%s\\|%s\\)$"
7095 (symbol-value 'tramp-gw-tunnel-method)
7096 (symbol-value 'tramp-gw-socks-method))
7097 (tramp-file-name-method (car target-alist))))
00d6fd04
MA
7098 (let ((gw (pop target-alist))
7099 (hop (pop target-alist)))
7100 ;; Is the method prepared for gateways?
7101 (unless (tramp-get-method-parameter
7102 (tramp-file-name-method hop) 'tramp-default-port)
7103 (tramp-error
7104 vec 'file-error
7105 "Method `%s' is not supported for gateway access."
7106 (tramp-file-name-method hop)))
7107 ;; Add default port if needed.
7108 (unless
7109 (string-match
7110 tramp-host-with-port-regexp (tramp-file-name-host hop))
7111 (aset hop 2
7112 (concat
7113 (tramp-file-name-host hop) tramp-prefix-port-format
7114 (number-to-string
7115 (tramp-get-method-parameter
7116 (tramp-file-name-method hop) 'tramp-default-port)))))
7117 ;; Open the gateway connection.
7118 (add-to-list
7119 'target-alist
7120 (vector
7121 (tramp-file-name-method hop) (tramp-file-name-user hop)
9e6ab520 7122 (funcall (symbol-function 'tramp-gw-open-connection) vec gw hop) nil))
00d6fd04
MA
7123 ;; For the password prompt, we need the correct values.
7124 ;; Therefore, we must remember the gateway vector. But we
7125 ;; cannot do it as connection property, because it shouldn't
7126 ;; be persistent. And we have no started process yet either.
7127 (tramp-set-file-property (car target-alist) "" "gateway" hop)))
7128
7129 ;; Foreign and out-of-band methods are not supported for multi-hops.
7130 (when (cdr target-alist)
7131 (setq choices target-alist)
7132 (while choices
7133 (setq item (pop choices))
7134 (when
7135 (or
7136 (not
7137 (tramp-get-method-parameter
7138 (tramp-file-name-method item) 'tramp-login-program))
7139 (tramp-get-method-parameter
7140 (tramp-file-name-method item) 'tramp-copy-program))
7141 (tramp-error
7142 vec 'file-error
7143 "Method `%s' is not supported for multi-hops."
7144 (tramp-file-name-method item)))))
7145
2991e49f
MA
7146 ;; In case the host name is not used for the remote shell
7147 ;; command, the user could be misguided by applying a random
7148 ;; hostname.
7149 (let* ((v (car target-alist))
7150 (method (tramp-file-name-method v))
7151 (host (tramp-file-name-host v)))
7152 (unless
7153 (or
7154 ;; There are multi-hops.
7155 (cdr target-alist)
7156 ;; The host name is used for the remote shell command.
7157 (member
7158 '("%h") (tramp-get-method-parameter method 'tramp-login-args))
7159 ;; The host is local. We cannot use `tramp-local-host-p'
7160 ;; here, because it opens a connection as well.
b96e6899 7161 (string-match tramp-local-host-regexp host))
2991e49f 7162 (tramp-error
42bc9b6d
MA
7163 v 'file-error
7164 "Host `%s' looks like a remote host, `%s' can only use the local host"
7165 host method)))
2991e49f 7166
00d6fd04
MA
7167 ;; Result.
7168 target-alist))
7169
7170(defun tramp-maybe-open-connection (vec)
7171 "Maybe open a connection VEC.
fb7933a3
KG
7172Does not do anything if a connection is already open, but re-opens the
7173connection if a previous connection has died for some reason."
d8ac123e
MA
7174 (catch 'uname-changed
7175 (let ((p (tramp-get-connection-process vec))
7176 (process-environment (copy-sequence process-environment)))
7177
7178 ;; If too much time has passed since last command was sent, look
7179 ;; whether process is still alive. If it isn't, kill it. When
7180 ;; using ssh, it can sometimes happen that the remote end has
7181 ;; hung up but the local ssh client doesn't recognize this until
7182 ;; it tries to send some data to the remote end. So that's why
7183 ;; we try to send a command from time to time, then look again
7184 ;; whether the process is really alive.
7185 (condition-case nil
7186 (when (and (> (tramp-time-diff
7187 (current-time)
7188 (tramp-get-connection-property
7189 p "last-cmd-time" '(0 0 0)))
7190 60)
7191 p (processp p) (memq (process-status p) '(run open)))
7192 (tramp-send-command vec "echo are you awake" t t)
7193 (unless (and (memq (process-status p) '(run open))
7194 (tramp-wait-for-output p 10))
7195 ;; The error will be catched locally.
7196 (tramp-error vec 'file-error "Awake did fail")))
7197 (file-error
7198 (tramp-flush-connection-property vec)
7199 (tramp-flush-connection-property p)
7200 (delete-process p)
7201 (setq p nil)))
7202
7203 ;; New connection must be opened.
7204 (unless (and p (processp p) (memq (process-status p) '(run open)))
7205
7206 ;; We call `tramp-get-buffer' in order to get a debug buffer for
7207 ;; messages from the beginning.
7208 (tramp-get-buffer vec)
7209 (if (zerop (length (tramp-file-name-user vec)))
7210 (tramp-message
7211 vec 3 "Opening connection for %s using %s..."
7212 (tramp-file-name-host vec)
7213 (tramp-file-name-method vec))
00d6fd04 7214 (tramp-message
d8ac123e
MA
7215 vec 3 "Opening connection for %s@%s using %s..."
7216 (tramp-file-name-user vec)
00d6fd04 7217 (tramp-file-name-host vec)
d8ac123e
MA
7218 (tramp-file-name-method vec)))
7219
7220 ;; Start new process.
7221 (when (and p (processp p))
7222 (delete-process p))
7223 (setenv "TERM" tramp-terminal-type)
7224 (setenv "LC_ALL" "C")
7225 (setenv "PROMPT_COMMAND")
dab816a9 7226 (setenv "PS1" tramp-initial-end-of-output)
d8ac123e
MA
7227 (let* ((target-alist (tramp-compute-multi-hops vec))
7228 (process-connection-type tramp-process-connection-type)
7229 (process-adaptive-read-buffering nil)
7230 (coding-system-for-read nil)
7231 ;; This must be done in order to avoid our file name handler.
7232 (p (let ((default-directory
7233 (tramp-compat-temporary-file-directory)))
7234 (start-process
7235 (or (tramp-get-connection-property vec "process-name" nil)
7236 (tramp-buffer-name vec))
7237 (tramp-get-connection-buffer vec)
70c11b0b 7238 tramp-encoding-shell))))
00d6fd04 7239
d8ac123e
MA
7240 (tramp-message
7241 vec 6 "%s" (mapconcat 'identity (process-command p) " "))
7242
7243 ;; Check whether process is alive.
d8ac123e
MA
7244 (tramp-set-process-query-on-exit-flag p nil)
7245 (tramp-message vec 3 "Waiting 60s for local shell to come up...")
7246 (tramp-barf-if-no-shell-prompt
7247 p 60 "Couldn't find local shell prompt %s" tramp-encoding-shell)
7248
7249 ;; Now do all the connections as specified.
7250 (while target-alist
7251 (let* ((hop (car target-alist))
7252 (l-method (tramp-file-name-method hop))
7253 (l-user (tramp-file-name-user hop))
7254 (l-host (tramp-file-name-host hop))
7255 (l-port nil)
7256 (login-program
7257 (tramp-get-method-parameter l-method 'tramp-login-program))
7258 (login-args
7259 (tramp-get-method-parameter l-method 'tramp-login-args))
7260 (gw-args
7261 (tramp-get-method-parameter l-method 'tramp-gw-args))
7262 (gw (tramp-get-file-property hop "" "gateway" nil))
7263 (g-method (and gw (tramp-file-name-method gw)))
7264 (g-user (and gw (tramp-file-name-user gw)))
7265 (g-host (and gw (tramp-file-name-host gw)))
7266 (command login-program)
7267 ;; We don't create the temporary file. In fact, it
7268 ;; is just a prefix for the ControlPath option of
7269 ;; ssh; the real temporary file has another name, and
7270 ;; it is created and protected by ssh. It is also
7271 ;; removed by ssh, when the connection is closed.
7272 (tmpfile
7273 (tramp-set-connection-property
7274 p "temp-file"
7275 (make-temp-name
7276 (expand-file-name
7277 tramp-temp-name-prefix
7278 (tramp-compat-temporary-file-directory)))))
7279 spec)
7280
7281 ;; Add gateway arguments if necessary.
7282 (when (and gw gw-args)
7283 (setq login-args (append login-args gw-args)))
7284
7285 ;; Check for port number. Until now, there's no need
7286 ;; for handling like method, user, host.
7287 (when (string-match tramp-host-with-port-regexp l-host)
7288 (setq l-port (match-string 2 l-host)
7289 l-host (match-string 1 l-host)))
7290
7291 ;; Set variables for computing the prompt for reading
2296b54d 7292 ;; password. They can also be derived from a gateway.
d8ac123e
MA
7293 (setq tramp-current-method (or g-method l-method)
7294 tramp-current-user (or g-user l-user)
7295 tramp-current-host (or g-host l-host))
7296
7297 ;; Replace login-args place holders.
7298 (setq
7299 l-host (or l-host "")
7300 l-user (or l-user "")
7301 l-port (or l-port "")
7302 spec `((?h . ,l-host) (?u . ,l-user) (?p . ,l-port)
7303 (?t . ,tmpfile))
7304 command
7305 (concat
e2a421af
MA
7306 ;; We do not want to see the trailing local prompt in
7307 ;; `start-file-process'.
7308 (unless (memq system-type '(windows-nt)) "exec ")
d8ac123e
MA
7309 command " "
7310 (mapconcat
aa485f7c
MA
7311 (lambda (x)
7312 (setq x (mapcar (lambda (y) (format-spec y spec)) x))
7313 (unless (member "" x) (mapconcat 'identity x " ")))
d8ac123e 7314 login-args " ")
d8ac123e
MA
7315 ;; Local shell could be a Windows COMSPEC. It doesn't
7316 ;; know the ";" syntax, but we must exit always for
70c11b0b 7317 ;; `start-file-process'. "exec" does not work either.
e2a421af 7318 (if (memq system-type '(windows-nt)) " && exit || exit")))
d8ac123e
MA
7319
7320 ;; Send the command.
7321 (tramp-message vec 3 "Sending command `%s'" command)
7322 (tramp-send-command vec command t t)
7323 (tramp-process-actions p vec tramp-actions-before-shell 60)
7324 (tramp-message vec 3 "Found remote shell prompt on `%s'" l-host))
7325 ;; Next hop.
7326 (setq target-alist (cdr target-alist)))
7327
7328 ;; Make initial shell settings.
7329 (tramp-open-connection-setup-interactive-shell p vec))))))
00d6fd04
MA
7330
7331(defun tramp-send-command (vec command &optional neveropen nooutput)
7332 "Send the COMMAND to connection VEC.
7333Erases temporary buffer before sending the command. If optional
7334arg NEVEROPEN is non-nil, never try to open the connection. This
7335is meant to be used from `tramp-maybe-open-connection' only. The
7336function waits for output unless NOOUTPUT is set."
7337 (unless neveropen (tramp-maybe-open-connection vec))
7338 (let ((p (tramp-get-connection-process vec)))
8950769a 7339 (when (tramp-get-connection-property p "remote-echo" nil)
00d6fd04
MA
7340 ;; We mark the command string that it can be erased in the output buffer.
7341 (tramp-set-connection-property p "check-remote-echo" t)
7342 (setq command (format "%s%s%s" tramp-echo-mark command tramp-echo-mark)))
7343 (tramp-message vec 6 "%s" command)
7344 (tramp-send-string vec command)
7345 (unless nooutput (tramp-wait-for-output p))))
7346
00d6fd04 7347(defun tramp-wait-for-output (proc &optional timeout)
7e5686f0
MA
7348 "Wait for output from remote command."
7349 (unless (buffer-live-p (process-buffer proc))
7350 (delete-process proc)
7351 (tramp-error proc 'file-error "Process `%s' not available, try again" proc))
00d6fd04 7352 (with-current-buffer (process-buffer proc)
dab816a9 7353 (let* (;; Initially, `tramp-end-of-output' is "#$ ". There might
bede3e9f 7354 ;; be leading escape sequences, which must be ignored.
dab816a9 7355 (regexp (format "[^#$\n]*%s\r?$" (regexp-quote tramp-end-of-output)))
bede3e9f
MA
7356 ;; Sometimes, the commands do not return a newline but a
7357 ;; null byte before the shell prompt, for example "git
7358 ;; ls-files -c -z ...".
7359 (regexp1 (format "\\(^\\|\000\\)%s" regexp))
7360 (found (tramp-wait-for-regexp proc timeout regexp1)))
00d6fd04
MA
7361 (if found
7362 (let (buffer-read-only)
7e5686f0
MA
7363 ;; A simple-minded busybox has sent " ^H" sequences.
7364 ;; Delete them.
7365 (goto-char (point-min))
7366 (when (re-search-forward
7367 "^\\(.\b\\)+$" (tramp-compat-line-end-position) t)
7368 (forward-line 1)
7369 (delete-region (point-min) (point)))
7370 ;; Delete the prompt.
00d6fd04 7371 (goto-char (point-max))
0664ff72 7372 (re-search-backward regexp nil t)
00d6fd04
MA
7373 (delete-region (point) (point-max)))
7374 (if timeout
7375 (tramp-error
7376 proc 'file-error
7377 "[[Remote prompt `%s' not found in %d secs]]"
7378 tramp-end-of-output timeout)
7379 (tramp-error
7380 proc 'file-error
7381 "[[Remote prompt `%s' not found]]" tramp-end-of-output)))
7382 ;; Return value is whether end-of-output sentinel was found.
7383 found)))
fb7933a3 7384
b593f105
MA
7385(defun tramp-send-command-and-check
7386 (vec command &optional subshell dont-suppress-err)
fb7933a3 7387 "Run COMMAND and check its exit status.
fb7933a3
KG
7388Sends `echo $?' along with the COMMAND for checking the exit status. If
7389COMMAND is nil, just sends `echo $?'. Returns the exit status found.
7390
b593f105
MA
7391If the optional argument SUBSHELL is non-nil, the command is
7392executed in a subshell, ie surrounded by parentheses. If
7393DONT-SUPPRESS-ERR is non-nil, stderr won't be sent to /dev/null."
00d6fd04
MA
7394 (tramp-send-command
7395 vec
7396 (concat (if subshell "( " "")
7397 command
b593f105 7398 (if command (if dont-suppress-err "; " " 2>/dev/null; ") "")
00d6fd04 7399 "echo tramp_exit_status $?"
b593f105 7400 (if subshell " )" "")))
00d6fd04
MA
7401 (with-current-buffer (tramp-get-connection-buffer vec)
7402 (goto-char (point-max))
7403 (unless (re-search-backward "tramp_exit_status [0-9]+" nil t)
7404 (tramp-error
7405 vec 'file-error "Couldn't find exit status of `%s'" command))
7406 (skip-chars-forward "^ ")
7407 (prog1
7408 (read (current-buffer))
7409 (let (buffer-read-only) (delete-region (match-beginning 0) (point-max))))))
7410
7411(defun tramp-barf-unless-okay (vec command fmt &rest args)
fb7933a3
KG
7412 "Run COMMAND, check exit status, throw error if exit status not okay.
7413Similar to `tramp-send-command-and-check' but accepts two more arguments
7414FMT and ARGS which are passed to `error'."
00d6fd04
MA
7415 (unless (zerop (tramp-send-command-and-check vec command))
7416 (apply 'tramp-error vec 'file-error fmt args)))
7417
7418(defun tramp-send-command-and-read (vec command)
7419 "Run COMMAND and return the output, which must be a Lisp expression.
7420In case there is no valid Lisp expression, it raises an error"
7421 (tramp-barf-unless-okay vec command "`%s' returns with error" command)
7422 (with-current-buffer (tramp-get-connection-buffer vec)
7423 ;; Read the expression.
7424 (goto-char (point-min))
7425 (condition-case nil
7426 (prog1 (read (current-buffer))
7427 ;; Error handling.
9e6ab520 7428 (when (re-search-forward "\\S-" (tramp-compat-line-end-position) t)
9ce8462a 7429 (error nil)))
00d6fd04
MA
7430 (error (tramp-error
7431 vec 'file-error
7432 "`%s' does not return a valid Lisp expression: `%s'"
7433 command (buffer-string))))))
fb7933a3 7434
7432277c
KG
7435;; It seems that Tru64 Unix does not like it if long strings are sent
7436;; to it in one go. (This happens when sending the Perl
7437;; `file-attributes' implementation, for instance.) Therefore, we
27e813fe 7438;; have this function which sends the string in chunks.
00d6fd04
MA
7439(defun tramp-send-string (vec string)
7440 "Send the STRING via connection VEC.
7432277c
KG
7441
7442The STRING is expected to use Unix line-endings, but the lines sent to
7443the remote host use line-endings as defined in the variable
00d6fd04
MA
7444`tramp-rsh-end-of-line'. The communication buffer is erased before sending."
7445 (let* ((p (tramp-get-connection-process vec))
7446 (chunksize (tramp-get-connection-property p "chunksize" nil)))
7447 (unless p
7448 (tramp-error
7449 vec 'file-error "Can't send string to remote host -- not logged in"))
7450 (tramp-set-connection-property p "last-cmd-time" (current-time))
7451 (tramp-message vec 10 "%s" string)
7452 (with-current-buffer (tramp-get-connection-buffer vec)
7453 ;; Clean up the buffer. We cannot call `erase-buffer' because
7454 ;; narrowing might be in effect.
7455 (let (buffer-read-only) (delete-region (point-min) (point-max)))
27e813fe 7456 ;; Replace "\n" by `tramp-rsh-end-of-line'.
00d6fd04
MA
7457 (setq string
7458 (mapconcat 'identity
70c11b0b 7459 (tramp-compat-split-string string "\n")
00d6fd04
MA
7460 tramp-rsh-end-of-line))
7461 (unless (or (string= string "")
7462 (string-equal (substring string -1) tramp-rsh-end-of-line))
7463 (setq string (concat string tramp-rsh-end-of-line)))
27e813fe 7464 ;; Send the string.
00d6fd04
MA
7465 (if (and chunksize (not (zerop chunksize)))
7466 (let ((pos 0)
7467 (end (length string)))
7468 (while (< pos end)
7469 (tramp-message
7470 vec 10 "Sending chunk from %s to %s"
7471 pos (min (+ pos chunksize) end))
7472 (process-send-string
7473 p (substring string pos (min (+ pos chunksize) end)))
7474 (setq pos (+ pos chunksize))))
7475 (process-send-string p string)))))
fb7933a3
KG
7476
7477(defun tramp-mode-string-to-int (mode-string)
7478 "Converts a ten-letter `drwxrwxrwx'-style mode string into mode bits."
f3c071dd
MA
7479 (let* (case-fold-search
7480 (mode-chars (string-to-vector mode-string))
fb7933a3
KG
7481 (owner-read (aref mode-chars 1))
7482 (owner-write (aref mode-chars 2))
7483 (owner-execute-or-setid (aref mode-chars 3))
7484 (group-read (aref mode-chars 4))
7485 (group-write (aref mode-chars 5))
7486 (group-execute-or-setid (aref mode-chars 6))
7487 (other-read (aref mode-chars 7))
7488 (other-write (aref mode-chars 8))
7489 (other-execute-or-sticky (aref mode-chars 9)))
7490 (save-match-data
7491 (logior
f3c071dd
MA
7492 (cond
7493 ((char-equal owner-read ?r) (tramp-octal-to-decimal "00400"))
7494 ((char-equal owner-read ?-) 0)
7495 (t (error "Second char `%c' must be one of `r-'" owner-read)))
7496 (cond
7497 ((char-equal owner-write ?w) (tramp-octal-to-decimal "00200"))
7498 ((char-equal owner-write ?-) 0)
7499 (t (error "Third char `%c' must be one of `w-'" owner-write)))
7500 (cond
7501 ((char-equal owner-execute-or-setid ?x)
7502 (tramp-octal-to-decimal "00100"))
7503 ((char-equal owner-execute-or-setid ?S)
7504 (tramp-octal-to-decimal "04000"))
7505 ((char-equal owner-execute-or-setid ?s)
7506 (tramp-octal-to-decimal "04100"))
7507 ((char-equal owner-execute-or-setid ?-) 0)
7508 (t (error "Fourth char `%c' must be one of `xsS-'"
7509 owner-execute-or-setid)))
7510 (cond
7511 ((char-equal group-read ?r) (tramp-octal-to-decimal "00040"))
7512 ((char-equal group-read ?-) 0)
7513 (t (error "Fifth char `%c' must be one of `r-'" group-read)))
7514 (cond
7515 ((char-equal group-write ?w) (tramp-octal-to-decimal "00020"))
7516 ((char-equal group-write ?-) 0)
7517 (t (error "Sixth char `%c' must be one of `w-'" group-write)))
7518 (cond
7519 ((char-equal group-execute-or-setid ?x)
7520 (tramp-octal-to-decimal "00010"))
7521 ((char-equal group-execute-or-setid ?S)
7522 (tramp-octal-to-decimal "02000"))
7523 ((char-equal group-execute-or-setid ?s)
7524 (tramp-octal-to-decimal "02010"))
7525 ((char-equal group-execute-or-setid ?-) 0)
7526 (t (error "Seventh char `%c' must be one of `xsS-'"
7527 group-execute-or-setid)))
7528 (cond
7529 ((char-equal other-read ?r)
7530 (tramp-octal-to-decimal "00004"))
7531 ((char-equal other-read ?-) 0)
7532 (t (error "Eighth char `%c' must be one of `r-'" other-read)))
7533 (cond
7534 ((char-equal other-write ?w) (tramp-octal-to-decimal "00002"))
7535 ((char-equal other-write ?-) 0)
fb7933a3 7536 (t (error "Nineth char `%c' must be one of `w-'" other-write)))
f3c071dd
MA
7537 (cond
7538 ((char-equal other-execute-or-sticky ?x)
7539 (tramp-octal-to-decimal "00001"))
7540 ((char-equal other-execute-or-sticky ?T)
7541 (tramp-octal-to-decimal "01000"))
7542 ((char-equal other-execute-or-sticky ?t)
7543 (tramp-octal-to-decimal "01001"))
7544 ((char-equal other-execute-or-sticky ?-) 0)
7545 (t (error "Tenth char `%c' must be one of `xtT-'"
7546 other-execute-or-sticky)))))))
fb7933a3 7547
00d6fd04
MA
7548(defun tramp-convert-file-attributes (vec attr)
7549 "Convert file-attributes ATTR generated by perl script, stat or ls.
c82c5727
LH
7550Convert file mode bits to string and set virtual device number.
7551Return ATTR."
680db9ac
MA
7552 (when attr
7553 ;; Convert last access time.
7554 (unless (listp (nth 4 attr))
7555 (setcar (nthcdr 4 attr)
7556 (list (floor (nth 4 attr) 65536)
7557 (floor (mod (nth 4 attr) 65536)))))
7558 ;; Convert last modification time.
7559 (unless (listp (nth 5 attr))
7560 (setcar (nthcdr 5 attr)
7561 (list (floor (nth 5 attr) 65536)
7562 (floor (mod (nth 5 attr) 65536)))))
7563 ;; Convert last status change time.
7564 (unless (listp (nth 6 attr))
7565 (setcar (nthcdr 6 attr)
7566 (list (floor (nth 6 attr) 65536)
7567 (floor (mod (nth 6 attr) 65536)))))
7568 ;; Convert file size.
7569 (when (< (nth 7 attr) 0)
7570 (setcar (nthcdr 7 attr) -1))
7571 (when (and (floatp (nth 7 attr))
7572 (<= (nth 7 attr) (tramp-compat-most-positive-fixnum)))
7573 (setcar (nthcdr 7 attr) (round (nth 7 attr))))
7574 ;; Convert file mode bits to string.
7575 (unless (stringp (nth 8 attr))
7576 (setcar (nthcdr 8 attr) (tramp-file-mode-from-int (nth 8 attr)))
7577 (when (stringp (car attr))
7578 (aset (nth 8 attr) 0 ?l)))
7579 ;; Convert directory indication bit.
7580 (when (string-match "^d" (nth 8 attr))
7581 (setcar attr t))
7582 ;; Convert symlink from `tramp-do-file-attributes-with-stat'.
7583 (when (consp (car attr))
7584 (if (and (stringp (caar attr))
7585 (string-match ".+ -> .\\(.+\\)." (caar attr)))
7586 (setcar attr (match-string 1 (caar attr)))
7587 (setcar attr nil)))
7588 ;; Set file's gid change bit.
7589 (setcar (nthcdr 9 attr)
7590 (if (numberp (nth 3 attr))
7591 (not (= (nth 3 attr)
7592 (tramp-get-remote-gid vec 'integer)))
7593 (not (string-equal
7594 (nth 3 attr)
7595 (tramp-get-remote-gid vec 'string)))))
7596 ;; Convert inode.
7597 (unless (listp (nth 10 attr))
7598 (setcar (nthcdr 10 attr)
7599 (condition-case nil
7600 (cons (floor (nth 10 attr) 65536)
7601 (floor (mod (nth 10 attr) 65536)))
7602 ;; Inodes can be incredible huge. We must hide this.
7603 (error (tramp-get-inode vec)))))
7604 ;; Set virtual device number.
7605 (setcar (nthcdr 11 attr)
7606 (tramp-get-device vec))
7607 attr))
c82c5727 7608
293c24f9
MA
7609(defun tramp-check-cached-permissions (vec access)
7610 "Check `file-attributes' caches for VEC.
7611Return t if according to the cache access type ACCESS is known to
7612be granted."
7613 (let ((result nil)
7614 (offset (cond
7615 ((eq ?r access) 1)
7616 ((eq ?w access) 2)
7617 ((eq ?x access) 3))))
7618 (dolist (suffix '("string" "integer") result)
7619 (setq
7620 result
7621 (or
7622 result
7623 (let ((file-attr
7624 (tramp-get-file-property
7625 vec (tramp-file-name-localname vec)
7626 (concat "file-attributes-" suffix) nil))
7627 (remote-uid
7628 (tramp-get-connection-property
7629 vec (concat "uid-" suffix) nil))
7630 (remote-gid
7631 (tramp-get-connection-property
7632 vec (concat "gid-" suffix) nil)))
7633 (and
7634 file-attr
7635 (or
7636 ;; Not a symlink
7637 (eq t (car file-attr))
7638 (null (car file-attr)))
7639 (or
7640 ;; World accessible.
7641 (eq access (aref (nth 8 file-attr) (+ offset 6)))
7642 ;; User accessible and owned by user.
7643 (and
7644 (eq access (aref (nth 8 file-attr) offset))
7645 (equal remote-uid (nth 2 file-attr)))
7646 ;; Group accessible and owned by user's
7647 ;; principal group.
7648 (and
7649 (eq access (aref (nth 8 file-attr) (+ offset 3)))
7650 (equal remote-gid (nth 3 file-attr)))))))))))
7651
ce3f516f 7652(defun tramp-get-inode (vec)
00d6fd04
MA
7653 "Returns the virtual inode number.
7654If it doesn't exist, generate a new one."
ce3f516f
MA
7655 (let ((string (tramp-make-tramp-file-name
7656 (tramp-file-name-method vec)
7657 (tramp-file-name-user vec)
7658 (tramp-file-name-host vec)
7659 "")))
00d6fd04
MA
7660 (unless (assoc string tramp-inodes)
7661 (add-to-list 'tramp-inodes
7662 (list string (length tramp-inodes))))
7663 (nth 1 (assoc string tramp-inodes))))
7664
7665(defun tramp-get-device (vec)
c82c5727
LH
7666 "Returns the virtual device number.
7667If it doesn't exist, generate a new one."
00d6fd04
MA
7668 (let ((string (tramp-make-tramp-file-name
7669 (tramp-file-name-method vec)
7670 (tramp-file-name-user vec)
7671 (tramp-file-name-host vec)
7672 "")))
c82c5727
LH
7673 (unless (assoc string tramp-devices)
7674 (add-to-list 'tramp-devices
7675 (list string (length tramp-devices))))
b946a456 7676 (cons -1 (nth 1 (assoc string tramp-devices)))))
fb7933a3
KG
7677
7678(defun tramp-file-mode-from-int (mode)
7679 "Turn an integer representing a file mode into an ls(1)-like string."
7680 (let ((type (cdr (assoc (logand (lsh mode -12) 15) tramp-file-mode-type-map)))
7681 (user (logand (lsh mode -6) 7))
7682 (group (logand (lsh mode -3) 7))
7683 (other (logand (lsh mode -0) 7))
7684 (suid (> (logand (lsh mode -9) 4) 0))
7685 (sgid (> (logand (lsh mode -9) 2) 0))
7686 (sticky (> (logand (lsh mode -9) 1) 0)))
7687 (setq user (tramp-file-mode-permissions user suid "s"))
7688 (setq group (tramp-file-mode-permissions group sgid "s"))
7689 (setq other (tramp-file-mode-permissions other sticky "t"))
7690 (concat type user group other)))
7691
fb7933a3
KG
7692(defun tramp-file-mode-permissions (perm suid suid-text)
7693 "Convert a permission bitset into a string.
7694This is used internally by `tramp-file-mode-from-int'."
7695 (let ((r (> (logand perm 4) 0))
7696 (w (> (logand perm 2) 0))
7697 (x (> (logand perm 1) 0)))
7698 (concat (or (and r "r") "-")
7699 (or (and w "w") "-")
7700 (or (and suid x suid-text) ; suid, execute
7701 (and suid (upcase suid-text)) ; suid, !execute
7702 (and x "x") "-")))) ; !suid
7703
fb7933a3
KG
7704(defun tramp-decimal-to-octal (i)
7705 "Return a string consisting of the octal digits of I.
7706Not actually used. Use `(format \"%o\" i)' instead?"
7707 (cond ((< i 0) (error "Cannot convert negative number to octal"))
7708 ((not (integerp i)) (error "Cannot convert non-integer to octal"))
7709 ((zerop i) "0")
7710 (t (concat (tramp-decimal-to-octal (/ i 8))
7711 (number-to-string (% i 8))))))
7712
fb7933a3
KG
7713;; Kudos to Gerd Moellmann for this suggestion.
7714(defun tramp-octal-to-decimal (ostr)
7715 "Given a string of octal digits, return a decimal number."
7716 (let ((x (or ostr "")))
7717 ;; `save-match' is in `tramp-mode-string-to-int' which calls this.
7718 (unless (string-match "\\`[0-7]*\\'" x)
7719 (error "Non-octal junk in string `%s'" x))
7720 (string-to-number ostr 8)))
7721
7722(defun tramp-shell-case-fold (string)
7723 "Converts STRING to shell glob pattern which ignores case."
7724 (mapconcat
7725 (lambda (c)
7726 (if (equal (downcase c) (upcase c))
7727 (vector c)
7728 (format "[%c%c]" (downcase c) (upcase c))))
7729 string
7730 ""))
7731
7732
bf247b6e 7733;; ------------------------------------------------------------
a4aeb9a4 7734;; -- Tramp file names --
bf247b6e 7735;; ------------------------------------------------------------
fb7933a3
KG
7736;; Conversion functions between external representation and
7737;; internal data structure. Convenience functions for internal
7738;; data structure.
7739
00d6fd04
MA
7740(defun tramp-file-name-p (vec)
7741 "Check whether VEC is a Tramp object."
7742 (and (vectorp vec) (= 4 (length vec))))
7743
7744(defun tramp-file-name-method (vec)
7745 "Return method component of VEC."
7746 (and (tramp-file-name-p vec) (aref vec 0)))
7747
7748(defun tramp-file-name-user (vec)
7749 "Return user component of VEC."
7750 (and (tramp-file-name-p vec) (aref vec 1)))
7751
7752(defun tramp-file-name-host (vec)
7753 "Return host component of VEC."
7754 (and (tramp-file-name-p vec) (aref vec 2)))
7755
7756(defun tramp-file-name-localname (vec)
7757 "Return localname component of VEC."
7758 (and (tramp-file-name-p vec) (aref vec 3)))
7759
dea31ca6 7760;; The user part of a Tramp file name vector can be of kind
b96e6899 7761;; "user%domain". Sometimes, we must extract these parts.
dea31ca6
MA
7762(defun tramp-file-name-real-user (vec)
7763 "Return the user name of VEC without domain."
a17632c1
MA
7764 (save-match-data
7765 (let ((user (tramp-file-name-user vec)))
7766 (if (and (stringp user)
7767 (string-match tramp-user-with-domain-regexp user))
7768 (match-string 1 user)
7769 user))))
dea31ca6
MA
7770
7771(defun tramp-file-name-domain (vec)
7772 "Return the domain name of VEC."
a17632c1
MA
7773 (save-match-data
7774 (let ((user (tramp-file-name-user vec)))
7775 (and (stringp user)
7776 (string-match tramp-user-with-domain-regexp user)
7777 (match-string 2 user)))))
dea31ca6 7778
00d6fd04
MA
7779;; The host part of a Tramp file name vector can be of kind
7780;; "host#port". Sometimes, we must extract these parts.
8a4438b6 7781(defun tramp-file-name-real-host (vec)
00d6fd04 7782 "Return the host name of VEC without port."
a17632c1
MA
7783 (save-match-data
7784 (let ((host (tramp-file-name-host vec)))
7785 (if (and (stringp host)
7786 (string-match tramp-host-with-port-regexp host))
7787 (match-string 1 host)
7788 host))))
00d6fd04 7789
8a4438b6 7790(defun tramp-file-name-port (vec)
00d6fd04 7791 "Return the port number of VEC."
a17632c1
MA
7792 (save-match-data
7793 (let ((host (tramp-file-name-host vec)))
7794 (and (stringp host)
7795 (string-match tramp-host-with-port-regexp host)
7796 (string-to-number (match-string 2 host))))))
fb7933a3
KG
7797
7798(defun tramp-tramp-file-p (name)
a09dc9bf 7799 "Return t if NAME is a string with Tramp file name syntax."
fb7933a3 7800 (save-match-data
a09dc9bf 7801 (and (stringp name) (string-match tramp-file-name-regexp name))))
bf247b6e 7802
8a4438b6 7803(defun tramp-find-method (method user host)
00d6fd04
MA
7804 "Return the right method string to use.
7805This is METHOD, if non-nil. Otherwise, do a lookup in
7806`tramp-default-method-alist'."
7807 (or method
7808 (let ((choices tramp-default-method-alist)
7809 lmethod item)
7810 (while choices
7811 (setq item (pop choices))
7812 (when (and (string-match (or (nth 0 item) "") (or host ""))
7813 (string-match (or (nth 1 item) "") (or user "")))
7814 (setq lmethod (nth 2 item))
7815 (setq choices nil)))
7816 lmethod)
7817 tramp-default-method))
7818
8a4438b6 7819(defun tramp-find-user (method user host)
00d6fd04
MA
7820 "Return the right user string to use.
7821This is USER, if non-nil. Otherwise, do a lookup in
7822`tramp-default-user-alist'."
7823 (or user
7824 (let ((choices tramp-default-user-alist)
7825 luser item)
7826 (while choices
7827 (setq item (pop choices))
7828 (when (and (string-match (or (nth 0 item) "") (or method ""))
7829 (string-match (or (nth 1 item) "") (or host "")))
7830 (setq luser (nth 2 item))
7831 (setq choices nil)))
7832 luser)
7833 tramp-default-user))
7834
8a4438b6 7835(defun tramp-find-host (method user host)
00d6fd04
MA
7836 "Return the right host string to use.
7837This is HOST, if non-nil. Otherwise, it is `tramp-default-host'."
7838 (or (and (> (length host) 0) host)
7839 tramp-default-host))
7840
9ce8462a 7841(defun tramp-dissect-file-name (name &optional nodefault)
00d6fd04 7842 "Return a `tramp-file-name' structure.
9ce8462a
MA
7843The structure consists of remote method, remote user, remote host
7844and localname (file name on remote host). If NODEFAULT is
7845non-nil, the file name parts are not expanded to their default
7846values."
4007ba5b 7847 (save-match-data
00d6fd04 7848 (let ((match (string-match (nth 0 tramp-file-name-structure) name)))
a4aeb9a4 7849 (unless match (error "Not a Tramp file name: %s" name))
00d6fd04
MA
7850 (let ((method (match-string (nth 1 tramp-file-name-structure) name))
7851 (user (match-string (nth 2 tramp-file-name-structure) name))
7852 (host (match-string (nth 3 tramp-file-name-structure) name))
7853 (localname (match-string (nth 4 tramp-file-name-structure) name)))
5d449a36
MA
7854 (when (member method '("multi" "multiu"))
7855 (error
7856 "`%s' method is no longer supported, see (info \"(tramp)Multi-hops\")"
7857 method))
b96e6899
MA
7858 (when host
7859 (when (string-match tramp-prefix-ipv6-regexp host)
7860 (setq host (replace-match "" nil t host)))
7861 (when (string-match tramp-postfix-ipv6-regexp host)
7862 (setq host (replace-match "" nil t host))))
9ce8462a
MA
7863 (if nodefault
7864 (vector method user host localname)
7865 (vector
7866 (tramp-find-method method user host)
7867 (tramp-find-user method user host)
7868 (tramp-find-host method user host)
7869 localname))))))
00d6fd04
MA
7870
7871(defun tramp-equal-remote (file1 file2)
7872 "Checks, whether the remote parts of FILE1 and FILE2 are identical.
7873The check depends on method, user and host name of the files. If
7874one of the components is missing, the default values are used.
7875The local file name parts of FILE1 and FILE2 are not taken into
7876account.
fb7933a3 7877
00d6fd04
MA
7878Example:
7879
7880 (tramp-equal-remote \"/ssh::/etc\" \"/<your host name>:/home\")
7881
7882would yield `t'. On the other hand, the following check results in nil:
7883
7884 (tramp-equal-remote \"/sudo::/etc\" \"/su::/etc\")"
9e6ab520
MA
7885 (and (stringp (file-remote-p file1))
7886 (stringp (file-remote-p file2))
94be87e8 7887 (string-equal (file-remote-p file1) (file-remote-p file2))))
00d6fd04
MA
7888
7889(defun tramp-make-tramp-file-name (method user host localname)
7890 "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME."
7891 (concat tramp-prefix-format
7892 (when (not (zerop (length method)))
7893 (concat method tramp-postfix-method-format))
7894 (when (not (zerop (length user)))
7895 (concat user tramp-postfix-user-format))
b96e6899
MA
7896 (when host
7897 (if (string-match tramp-ipv6-regexp host)
7898 (concat tramp-prefix-ipv6-format host tramp-postfix-ipv6-format)
7899 host))
7900 tramp-postfix-host-format
00d6fd04
MA
7901 (when localname localname)))
7902
7903(defun tramp-completion-make-tramp-file-name (method user host localname)
7904 "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME.
7905It must not be a complete Tramp file name, but as long as there are
7906necessary only. This function will be used in file name completion."
7907 (concat tramp-prefix-format
7908 (when (not (zerop (length method)))
7909 (concat method tramp-postfix-method-format))
7910 (when (not (zerop (length user)))
7911 (concat user tramp-postfix-user-format))
7912 (when (not (zerop (length host)))
b96e6899
MA
7913 (concat
7914 (if (string-match tramp-ipv6-regexp host)
7915 (concat tramp-prefix-ipv6-format host tramp-postfix-ipv6-format)
7916 host)
7917 tramp-postfix-host-format))
00d6fd04
MA
7918 (when localname localname)))
7919
7920(defun tramp-make-copy-program-file-name (vec)
7921 "Create a file name suitable to be passed to `rcp' and workalikes."
7922 (let ((user (tramp-file-name-user vec))
0f205eee 7923 (host (tramp-file-name-real-host vec))
00d6fd04
MA
7924 (localname (tramp-shell-quote-argument
7925 (tramp-file-name-localname vec))))
7926 (if (not (zerop (length user)))
7927 (format "%s@%s:%s" user host localname)
7928 (format "%s:%s" host localname))))
7929
7f49fe46 7930(defun tramp-method-out-of-band-p (vec size)
38c65fca 7931 "Return t if this is an out-of-band method, nil otherwise."
7f49fe46
MA
7932 (and
7933 ;; It shall be an out-of-band method.
7934 (tramp-get-method-parameter (tramp-file-name-method vec) 'tramp-copy-program)
7935 ;; Either the file size is large enough, or (in rare cases) there
7936 ;; does not exist a remote encoding.
7937 (or (> size tramp-copy-size-limit)
7938 (null (tramp-get-remote-coding vec "remote-encoding")))))
fb7933a3 7939
0f205eee
MA
7940(defun tramp-local-host-p (vec)
7941 "Return t if this points to the local host, nil otherwise."
c992abdb
MA
7942 ;; We cannot use `tramp-file-name-real-host'. A port is an
7943 ;; indication for an ssh tunnel or alike.
7944 (let ((host (tramp-file-name-host vec)))
0f205eee
MA
7945 (and
7946 (stringp host)
b96e6899 7947 (string-match tramp-local-host-regexp host)
46bcd78c
MA
7948 ;; The method shall be applied to one of the shell file name
7949 ;; handler. `tramp-local-host-p' is also called for "smb" and
7950 ;; alike, where it must fail.
7951 (tramp-get-method-parameter
7952 (tramp-file-name-method vec) 'tramp-login-program)
a0a5183a
MA
7953 ;; The local temp directory must be writable for the other user.
7954 (file-writable-p
7955 (tramp-make-tramp-file-name
7956 (tramp-file-name-method vec)
7957 (tramp-file-name-user vec)
7958 host
93c3eb7c
MA
7959 (tramp-compat-temporary-file-directory)))
7960 ;; On some systems, chown runs only for root.
7961 (or (zerop (user-uid))
7962 (zerop (tramp-get-remote-uid vec 'integer))))))
0f205eee 7963
fb7933a3
KG
7964;; Variables local to connection.
7965
f84638eb 7966(defun tramp-get-remote-path (vec)
70c11b0b
MA
7967 (with-connection-property
7968 ;; When `tramp-own-remote-path' is in `tramp-remote-path', we
7969 ;; cache the result for the session only. Otherwise, the result
7970 ;; is cached persistently.
7971 (if (memq 'tramp-own-remote-path tramp-remote-path)
7972 (tramp-get-connection-process vec)
7973 vec)
7974 "remote-path"
9e6ab520 7975 (let* ((remote-path (tramp-compat-copy-tree tramp-remote-path))
70c11b0b
MA
7976 (elt1 (memq 'tramp-default-remote-path remote-path))
7977 (elt2 (memq 'tramp-own-remote-path remote-path))
f84638eb 7978 (default-remote-path
70c11b0b 7979 (when elt1
f84638eb 7980 (condition-case nil
70c11b0b
MA
7981 (tramp-send-command-and-read
7982 vec "echo \\\"`getconf PATH`\\\"")
f84638eb
MA
7983 ;; Default if "getconf" is not available.
7984 (error
7985 (tramp-message
7986 vec 3
7987 "`getconf PATH' not successful, using default value \"%s\"."
7988 "/bin:/usr/bin")
70c11b0b
MA
7989 "/bin:/usr/bin"))))
7990 (own-remote-path
7991 (when elt2
7992 (condition-case nil
7993 (tramp-send-command-and-read vec "echo \\\"$PATH\\\"")
7994 ;; Default if "getconf" is not available.
7995 (error
7996 (tramp-message
7997 vec 3 "$PATH not set, ignoring `tramp-own-remote-path'.")
7998 nil)))))
7999
8000 ;; Replace place holder `tramp-default-remote-path'.
8001 (when elt1
8002 (setcdr elt1
f84638eb 8003 (append
70c11b0b
MA
8004 (tramp-compat-split-string default-remote-path ":")
8005 (cdr elt1)))
f84638eb
MA
8006 (setq remote-path (delq 'tramp-default-remote-path remote-path)))
8007
70c11b0b
MA
8008 ;; Replace place holder `tramp-own-remote-path'.
8009 (when elt2
8010 (setcdr elt2
8011 (append
8012 (tramp-compat-split-string own-remote-path ":")
8013 (cdr elt2)))
8014 (setq remote-path (delq 'tramp-own-remote-path remote-path)))
8015
8016 ;; Remove double entries.
8017 (setq elt1 remote-path)
8018 (while (consp elt1)
8019 (while (and (car elt1) (setq elt2 (member (car elt1) (cdr elt1))))
8020 (setcar elt2 nil))
8021 (setq elt1 (cdr elt1)))
8022
f84638eb
MA
8023 ;; Remove non-existing directories.
8024 (delq
8025 nil
8026 (mapcar
8027 (lambda (x)
8028 (and
70c11b0b
MA
8029 (stringp x)
8030 (file-directory-p
8031 (tramp-make-tramp-file-name
8032 (tramp-file-name-method vec)
8033 (tramp-file-name-user vec)
8034 (tramp-file-name-host vec)
8035 x))
f84638eb
MA
8036 x))
8037 remote-path)))))
8038
a4aeb9a4
MA
8039(defun tramp-get-remote-tmpdir (vec)
8040 (with-connection-property vec "tmp-directory"
8041 (let ((dir (tramp-shell-quote-argument "/tmp")))
8042 (if (and (zerop
8043 (tramp-send-command-and-check
8044 vec (format "%s -d %s" (tramp-get-test-command vec) dir)))
8045 (zerop
8046 (tramp-send-command-and-check
8047 vec (format "%s -w %s" (tramp-get-test-command vec) dir))))
8048 dir
8049 (tramp-error vec 'file-error "Directory %s not accessible" dir)))))
8050
00d6fd04
MA
8051(defun tramp-get-ls-command (vec)
8052 (with-connection-property vec "ls"
946a5aeb
MA
8053 (tramp-message vec 5 "Finding a suitable `ls' command")
8054 (or
8055 (catch 'ls-found
8056 (dolist (cmd '("ls" "gnuls" "gls"))
8057 (let ((dl (tramp-get-remote-path vec))
8058 result)
8059 (while (and dl (setq result (tramp-find-executable vec cmd dl t t)))
7e5686f0
MA
8060 ;; Check parameters. On busybox, "ls" output coloring is
8061 ;; enabled by default sometimes. So we try to disable it
8062 ;; when possible. $LS_COLORING is not supported there.
946a5aeb
MA
8063 (when (zerop (tramp-send-command-and-check
8064 vec (format "%s -lnd /" result)))
7e5686f0
MA
8065 (when (zerop (tramp-send-command-and-check
8066 vec (format "%s --color=never /" result)))
8067 (setq result (concat result " --color=never")))
946a5aeb
MA
8068 (throw 'ls-found result))
8069 (setq dl (cdr dl))))))
8070 (tramp-error vec 'file-error "Couldn't find a proper `ls' command"))))
00d6fd04 8071
8e754ea2
MA
8072(defun tramp-get-ls-command-with-dired (vec)
8073 (save-match-data
8074 (with-connection-property vec "ls-dired"
8075 (tramp-message vec 5 "Checking, whether `ls --dired' works")
8076 (zerop (tramp-send-command-and-check
7f49fe46 8077 vec (format "%s --dired /" (tramp-get-ls-command vec)))))))
8e754ea2 8078
00d6fd04
MA
8079(defun tramp-get-test-command (vec)
8080 (with-connection-property vec "test"
946a5aeb
MA
8081 (tramp-message vec 5 "Finding a suitable `test' command")
8082 (if (zerop (tramp-send-command-and-check vec "test 0"))
8083 "test"
8084 (tramp-find-executable vec "test" (tramp-get-remote-path vec)))))
00d6fd04
MA
8085
8086(defun tramp-get-test-nt-command (vec)
8087 ;; Does `test A -nt B' work? Use abominable `find' construct if it
8088 ;; doesn't. BSD/OS 4.0 wants the parentheses around the command,
8089 ;; for otherwise the shell crashes.
8090 (with-connection-property vec "test-nt"
8091 (or
8092 (progn
8093 (tramp-send-command
8094 vec (format "( %s / -nt / )" (tramp-get-test-command vec)))
8095 (with-current-buffer (tramp-get-buffer vec)
8096 (goto-char (point-min))
a0a5183a 8097 (when (looking-at (regexp-quote tramp-end-of-output))
00d6fd04
MA
8098 (format "%s %%s -nt %%s" (tramp-get-test-command vec)))))
8099 (progn
8100 (tramp-send-command
8101 vec
8102 (format
8103 "tramp_test_nt () {\n%s -n \"`find $1 -prune -newer $2 -print`\"\n}"
8104 (tramp-get-test-command vec)))
8105 "tramp_test_nt %s %s"))))
8106
8107(defun tramp-get-file-exists-command (vec)
8108 (with-connection-property vec "file-exists"
946a5aeb
MA
8109 (tramp-message vec 5 "Finding command to check if file exists")
8110 (tramp-find-file-exists-command vec)))
00d6fd04
MA
8111
8112(defun tramp-get-remote-ln (vec)
8113 (with-connection-property vec "ln"
946a5aeb
MA
8114 (tramp-message vec 5 "Finding a suitable `ln' command")
8115 (tramp-find-executable vec "ln" (tramp-get-remote-path vec))))
00d6fd04
MA
8116
8117(defun tramp-get-remote-perl (vec)
8118 (with-connection-property vec "perl"
946a5aeb 8119 (tramp-message vec 5 "Finding a suitable `perl' command")
293c24f9
MA
8120 (let ((result
8121 (or (tramp-find-executable vec "perl5" (tramp-get-remote-path vec))
8122 (tramp-find-executable
8123 vec "perl" (tramp-get-remote-path vec)))))
8124 ;; We must check also for some Perl modules.
8125 (when result
8126 (with-connection-property vec "perl-file-spec"
8127 (zerop
8128 (tramp-send-command-and-check
8129 vec (format "%s -e 'use File::Spec;'" result))))
8130 (with-connection-property vec "perl-cwd-realpath"
8131 (zerop
8132 (tramp-send-command-and-check
8133 vec (format "%s -e 'use Cwd \"realpath\";'" result)))))
8134 result)))
00d6fd04
MA
8135
8136(defun tramp-get-remote-stat (vec)
8137 (with-connection-property vec "stat"
946a5aeb
MA
8138 (tramp-message vec 5 "Finding a suitable `stat' command")
8139 (let ((result (tramp-find-executable
8140 vec "stat" (tramp-get-remote-path vec)))
8141 tmp)
8142 ;; Check whether stat(1) returns usable syntax. %s does not
8143 ;; work on older AIX systems.
8144 (when result
8145 (setq tmp
8146 ;; We don't want to display an error message.
8147 (with-temp-message (or (current-message) "")
8148 (condition-case nil
8149 (tramp-send-command-and-read
8150 vec (format "%s -c '(\"%%N\" %%s)' /" result))
8151 (error nil))))
8152 (unless (and (listp tmp) (stringp (car tmp))
8153 (string-match "^./.$" (car tmp))
8154 (integerp (cadr tmp)))
8155 (setq result nil)))
8156 result)))
fb7933a3 8157
293c24f9
MA
8158(defun tramp-get-remote-readlink (vec)
8159 (with-connection-property vec "readlink"
8160 (tramp-message vec 5 "Finding a suitable `readlink' command")
8161 (let ((result (tramp-find-executable
8162 vec "readlink" (tramp-get-remote-path vec))))
8163 (when (and result
8164 ;; We don't want to display an error message.
8165 (with-temp-message (or (current-message) "")
8166 (condition-case nil
8167 (zerop
8168 (tramp-send-command-and-check
8169 vec (format "%s --canonicalize-missing /" result)))
8170 (error nil))))
8171 result))))
8172
00d6fd04
MA
8173(defun tramp-get-remote-id (vec)
8174 (with-connection-property vec "id"
946a5aeb
MA
8175 (tramp-message vec 5 "Finding POSIX `id' command")
8176 (or
8177 (catch 'id-found
8178 (let ((dl (tramp-get-remote-path vec))
8179 result)
8180 (while (and dl (setq result (tramp-find-executable vec "id" dl t t)))
8181 ;; Check POSIX parameter.
8182 (when (zerop (tramp-send-command-and-check
8183 vec (format "%s -u" result)))
8184 (throw 'id-found result))
8185 (setq dl (cdr dl)))))
8186 (tramp-error vec 'file-error "Couldn't find a POSIX `id' command"))))
00d6fd04
MA
8187
8188(defun tramp-get-remote-uid (vec id-format)
8189 (with-connection-property vec (format "uid-%s" id-format)
8190 (let ((res (tramp-send-command-and-read
8191 vec
8192 (format "%s -u%s %s"
8193 (tramp-get-remote-id vec)
8194 (if (equal id-format 'integer) "" "n")
8195 (if (equal id-format 'integer)
8196 "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
8197 ;; The command might not always return a number.
8198 (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
8199
8200(defun tramp-get-remote-gid (vec id-format)
8201 (with-connection-property vec (format "gid-%s" id-format)
8202 (let ((res (tramp-send-command-and-read
8203 vec
8204 (format "%s -g%s %s"
8205 (tramp-get-remote-id vec)
8206 (if (equal id-format 'integer) "" "n")
8207 (if (equal id-format 'integer)
8208 "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
8209 ;; The command might not always return a number.
8210 (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
fb7933a3 8211
8d60099b
MA
8212(defun tramp-get-local-uid (id-format)
8213 (if (equal id-format 'integer) (user-uid) (user-login-name)))
8214
8215(defun tramp-get-local-gid (id-format)
9e6ab520 8216 (nth 3 (tramp-compat-file-attributes "~/" id-format)))
8d60099b 8217
00d6fd04
MA
8218;; Some predefined connection properties.
8219(defun tramp-get-remote-coding (vec prop)
8220 ;; Local coding handles properties like remote coding. So we could
8221 ;; call it without pain.
8222 (let ((ret (tramp-get-local-coding vec prop)))
8223 ;; The connection property might have been cached. So we must send
8224 ;; the script - maybe.
1d7e9a01 8225 (when (and ret (symbolp ret))
00d6fd04
MA
8226 (let ((name (symbol-name ret)))
8227 (while (string-match (regexp-quote "-") name)
8228 (setq name (replace-match "_" nil t name)))
8229 (tramp-maybe-send-script vec (symbol-value ret) name)
8230 (setq ret name)))
8231 ;; Return the value.
8232 ret))
8233
8234(defun tramp-get-local-coding (vec prop)
bf0503cb 8235 (or
00d6fd04
MA
8236 (tramp-get-connection-property vec prop nil)
8237 (progn
8238 (tramp-find-inline-encoding vec)
8239 (tramp-get-connection-property vec prop nil))))
fb7933a3 8240
00d6fd04 8241(defun tramp-get-method-parameter (method param)
c951aecb 8242 "Return the method parameter PARAM.
00d6fd04
MA
8243If the `tramp-methods' entry does not exist, return NIL."
8244 (let ((entry (assoc param (assoc method tramp-methods))))
8245 (when entry (cadr entry))))
90f8dc03 8246
fb7933a3
KG
8247;; Auto saving to a special directory.
8248
00cec167 8249(defun tramp-exists-file-name-handler (operation &rest args)
00d6fd04
MA
8250 "Checks whether OPERATION runs a file name handler."
8251 ;; The file name handler is determined on base of either an
8252 ;; argument, `buffer-file-name', or `default-directory'.
8253 (condition-case nil
8254 (let* ((buffer-file-name "/")
8255 (default-directory "/")
8256 (fnha file-name-handler-alist)
8257 (check-file-name-operation operation)
8258 (file-name-handler-alist
8259 (list
8260 (cons "/"
aa485f7c
MA
8261 (lambda (operation &rest args)
8262 "Returns OPERATION if it is the one to be checked."
8263 (if (equal check-file-name-operation operation)
8264 operation
8265 (let ((file-name-handler-alist fnha))
8266 (apply operation args))))))))
00d6fd04
MA
8267 (equal (apply operation args) operation))
8268 (error nil)))
c1105d05
MA
8269
8270(unless (tramp-exists-file-name-handler 'make-auto-save-file-name)
8271 (defadvice make-auto-save-file-name
8272 (around tramp-advice-make-auto-save-file-name () activate)
00d6fd04 8273 "Invoke `tramp-handle-make-auto-save-file-name' for Tramp files."
c1105d05 8274 (if (and (buffer-file-name) (tramp-tramp-file-p (buffer-file-name)))
7f49fe46
MA
8275 ;; We cannot call `tramp-handle-make-auto-save-file-name'
8276 ;; directly, because this would bypass the locking mechanism.
8277 (setq ad-return-value
8278 (tramp-file-name-handler 'make-auto-save-file-name))
a69c01a0 8279 ad-do-it))
191bb792
MA
8280 (add-hook
8281 'tramp-unload-hook
8282 (lambda ()
8283 (ad-remove-advice
8284 'make-auto-save-file-name
d7ec1df7
MA
8285 'around 'tramp-advice-make-auto-save-file-name)
8286 (ad-activate 'make-auto-save-file-name))))
fb7933a3 8287
340b8d4f
MA
8288;; In Emacs < 22 and XEmacs < 21.5 autosaved remote files have
8289;; permission 0666 minus umask. This is a security threat.
414da5ab
MA
8290
8291(defun tramp-set-auto-save-file-modes ()
8292 "Set permissions of autosaved remote files to the original permissions."
8293 (let ((bfn (buffer-file-name)))
8294 (when (and (stringp bfn)
8295 (tramp-tramp-file-p bfn)
b50dd0d2 8296 (buffer-modified-p)
414da5ab 8297 (stringp buffer-auto-save-file-name)
340b8d4f
MA
8298 (not (equal bfn buffer-auto-save-file-name)))
8299 (unless (file-exists-p buffer-auto-save-file-name)
8300 (write-region "" nil buffer-auto-save-file-name))
8301 ;; Permissions should be set always, because there might be an old
8302 ;; auto-saved file belonging to another original file. This could
8303 ;; be a security threat.
7177e2a3 8304 (set-file-modes buffer-auto-save-file-name
11948172 8305 (or (file-modes bfn) (tramp-octal-to-decimal "0600"))))))
414da5ab
MA
8306
8307(unless (or (> emacs-major-version 21)
8308 (and (featurep 'xemacs)
8309 (= emacs-major-version 21)
340b8d4f 8310 (> emacs-minor-version 4)))
a69c01a0
MA
8311 (add-hook 'auto-save-hook 'tramp-set-auto-save-file-modes)
8312 (add-hook 'tramp-unload-hook
aa485f7c
MA
8313 (lambda ()
8314 (remove-hook 'auto-save-hook 'tramp-set-auto-save-file-modes))))
414da5ab 8315
fb7933a3
KG
8316(defun tramp-subst-strs-in-string (alist string)
8317 "Replace all occurrences of the string FROM with TO in STRING.
8318ALIST is of the form ((FROM . TO) ...)."
8319 (save-match-data
8320 (while alist
8321 (let* ((pr (car alist))
8322 (from (car pr))
8323 (to (cdr pr)))
8324 (while (string-match (regexp-quote from) string)
8325 (setq string (replace-match to t t string)))
8326 (setq alist (cdr alist))))
8327 string))
8328
fb7933a3
KG
8329;; ------------------------------------------------------------
8330;; -- Compatibility functions section --
8331;; ------------------------------------------------------------
8332
00d6fd04 8333(defun tramp-read-passwd (proc &optional prompt)
fb7933a3 8334 "Read a password from user (compat function).
5615d63f 8335Consults the auth-source package.
5ec2cc41 8336Invokes `password-read' if available, `read-passwd' else."
00d6fd04
MA
8337 (let* ((key (tramp-make-tramp-file-name
8338 tramp-current-method tramp-current-user
8339 tramp-current-host ""))
8340 (pw-prompt
8341 (or prompt
8342 (with-current-buffer (process-buffer proc)
8343 (tramp-check-for-regexp proc tramp-password-prompt-regexp)
8344 (format "%s for %s " (capitalize (match-string 1)) key)))))
7540f029
MA
8345 (with-parsed-tramp-file-name key nil
8346 (prog1
8347 (or
8348 ;; See if auth-sources contains something useful, if it's bound.
8349 (and (boundp 'auth-sources)
8350 (tramp-get-connection-property v "first-password-request" nil)
8351 ;; Try with Tramp's current method.
8352 (funcall (symbol-function 'auth-source-user-or-password)
8353 "password" tramp-current-host tramp-current-method))
8354 ;; Try the password cache.
8355 (when (functionp 'password-read)
8356 (unless (tramp-get-connection-property
8357 v "first-password-request" nil)
8358 (funcall (symbol-function 'password-cache-remove) key))
8359 (let ((password
8360 (funcall (symbol-function 'password-read) pw-prompt key)))
8361 (funcall (symbol-function 'password-cache-add) key password)
8362 password))
8363 ;; Else, get the password interactively.
8364 (read-passwd pw-prompt))
8365 (tramp-set-connection-property v "first-password-request" nil)))))
00d6fd04 8366
9c13938d
MA
8367(defun tramp-clear-passwd (vec)
8368 "Clear password cache for connection related to VEC."
00d6fd04 8369 (when (functionp 'password-cache-remove)
9c13938d
MA
8370 (funcall
8371 (symbol-function 'password-cache-remove)
8372 (tramp-make-tramp-file-name
8373 (tramp-file-name-method vec)
8374 (tramp-file-name-user vec)
8375 (tramp-file-name-host vec)
8376 ""))))
00d6fd04
MA
8377
8378;; Snarfed code from time-date.el and parse-time.el
8379
8380(defconst tramp-half-a-year '(241 17024)
8381"Evaluated by \"(days-to-time 183)\".")
8382
8383(defconst tramp-parse-time-months
8384 '(("jan" . 1) ("feb" . 2) ("mar" . 3)
8385 ("apr" . 4) ("may" . 5) ("jun" . 6)
8386 ("jul" . 7) ("aug" . 8) ("sep" . 9)
8387 ("oct" . 10) ("nov" . 11) ("dec" . 12))
8388 "Alist mapping month names to integers.")
8389
8390(defun tramp-time-less-p (t1 t2)
8391 "Say whether time value T1 is less than time value T2."
8392 (unless t1 (setq t1 '(0 0)))
8393 (unless t2 (setq t2 '(0 0)))
8394 (or (< (car t1) (car t2))
8395 (and (= (car t1) (car t2))
8396 (< (nth 1 t1) (nth 1 t2)))))
8397
8398(defun tramp-time-subtract (t1 t2)
8399 "Subtract two time values.
8400Return the difference in the format of a time value."
8401 (unless t1 (setq t1 '(0 0)))
8402 (unless t2 (setq t2 '(0 0)))
8403 (let ((borrow (< (cadr t1) (cadr t2))))
8404 (list (- (car t1) (car t2) (if borrow 1 0))
8405 (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2)))))
fb7933a3
KG
8406
8407(defun tramp-time-diff (t1 t2)
8408 "Return the difference between the two times, in seconds.
1a762140 8409T1 and T2 are time values (as returned by `current-time' for example)."
fb7933a3 8410 ;; Pacify byte-compiler with `symbol-function'.
ea9d1443
KG
8411 (cond ((and (fboundp 'subtract-time)
8412 (fboundp 'float-time))
8413 (funcall (symbol-function 'float-time)
8414 (funcall (symbol-function 'subtract-time) t1 t2)))
8415 ((and (fboundp 'subtract-time)
8416 (fboundp 'time-to-seconds))
8417 (funcall (symbol-function 'time-to-seconds)
8418 (funcall (symbol-function 'subtract-time) t1 t2)))
fb7933a3 8419 ((fboundp 'itimer-time-difference)
1a762140
MA
8420 (funcall (symbol-function 'itimer-time-difference)
8421 (if (< (length t1) 3) (append t1 '(0)) t1)
8422 (if (< (length t2) 3) (append t2 '(0)) t2)))
fb7933a3 8423 (t
00d6fd04 8424 (let ((time (tramp-time-subtract t1 t2)))
ea9d1443
KG
8425 (+ (* (car time) 65536.0)
8426 (cadr time)
8427 (/ (or (nth 2 time) 0) 1000000.0))))))
fb7933a3
KG
8428
8429(defun tramp-coding-system-change-eol-conversion (coding-system eol-type)
8430 "Return a coding system like CODING-SYSTEM but with given EOL-TYPE.
8431EOL-TYPE can be one of `dos', `unix', or `mac'."
8432 (cond ((fboundp 'coding-system-change-eol-conversion)
9e6ab520
MA
8433 (funcall (symbol-function 'coding-system-change-eol-conversion)
8434 coding-system eol-type))
fb7933a3 8435 ((fboundp 'subsidiary-coding-system)
9e6ab520
MA
8436 (funcall (symbol-function 'subsidiary-coding-system)
8437 coding-system
8438 (cond ((eq eol-type 'dos) 'crlf)
8439 ((eq eol-type 'unix) 'lf)
8440 ((eq eol-type 'mac) 'cr)
8441 (t
8442 (error "Unknown EOL-TYPE `%s', must be %s"
8443 eol-type
8444 "`dos', `unix', or `mac'")))))
fb7933a3
KG
8445 (t (error "Can't change EOL conversion -- is MULE missing?"))))
8446
19a87064
MA
8447(defun tramp-set-process-query-on-exit-flag (process flag)
8448 "Specify if query is needed for process when Emacs is exited.
8449If the second argument flag is non-nil, Emacs will query the user before
8450exiting if process is running."
8451 (if (fboundp 'set-process-query-on-exit-flag)
00d6fd04
MA
8452 (funcall (symbol-function 'set-process-query-on-exit-flag) process flag)
8453 (funcall (symbol-function 'process-kill-without-query) process flag)))
19a87064 8454
19a87064 8455
bf247b6e
KS
8456;; ------------------------------------------------------------
8457;; -- Kludges section --
8458;; ------------------------------------------------------------
fb7933a3
KG
8459
8460;; Currently (as of Emacs 20.5), the function `shell-quote-argument'
8461;; does not deal well with newline characters. Newline is replaced by
8462;; backslash newline. But if, say, the string `a backslash newline b'
8463;; is passed to a shell, the shell will expand this into "ab",
8464;; completely omitting the newline. This is not what was intended.
8465;; It does not appear to be possible to make the function
8466;; `shell-quote-argument' work with newlines without making it
8467;; dependent on the shell used. But within this package, we know that
8468;; we will always use a Bourne-like shell, so we use an approach which
8469;; groks newlines.
8470;;
8471;; The approach is simple: we call `shell-quote-argument', then
8472;; massage the newline part of the result.
8473;;
8474;; This function should produce a string which is grokked by a Unix
8475;; shell, even if the Emacs is running on Windows. Since this is the
8476;; kludges section, we bind `system-type' in such a way that
8477;; `shell-quote-arguments' behaves as if on Unix.
8478;;
8479;; Thanks to Mario DeWeerd for the hint that it is sufficient for this
8480;; function to work with Bourne-like shells.
8481;;
8482;; CCC: This function should be rewritten so that
8483;; `shell-quote-argument' is not used. This way, we are safe from
8484;; changes in `shell-quote-argument'.
8485(defun tramp-shell-quote-argument (s)
8486 "Similar to `shell-quote-argument', but groks newlines.
8487Only works for Bourne-like shells."
8488 (let ((system-type 'not-windows))
8489 (save-match-data
8490 (let ((result (shell-quote-argument s))
8491 (nl (regexp-quote (format "\\%s" tramp-rsh-end-of-line))))
8492 (when (and (>= (length result) 2)
8493 (string= (substring result 0 2) "\\~"))
8494 (setq result (substring result 1)))
8495 (while (string-match nl result)
8496 (setq result (replace-match (format "'%s'" tramp-rsh-end-of-line)
8497 t t result)))
8498 result))))
8499
a69c01a0
MA
8500;; Checklist for `tramp-unload-hook'
8501;; - Unload all `tramp-*' packages
8502;; - Reset `file-name-handler-alist'
8503;; - Cleanup hooks where Tramp functions are in
8504;; - Cleanup advised functions
8505;; - Cleanup autoloads
8506;;;###autoload
8507(defun tramp-unload-tramp ()
08b1eb21 8508 "Discard Tramp from loading remote files."
a69c01a0
MA
8509 (interactive)
8510 ;; When Tramp is not loaded yet, its autoloads are still active.
8c04e197 8511 (tramp-unload-file-name-handlers)
a69c01a0
MA
8512 ;; ange-ftp settings must be enabled.
8513 (when (functionp 'tramp-ftp-enable-ange-ftp)
8514 (funcall (symbol-function 'tramp-ftp-enable-ange-ftp)))
00d6fd04
MA
8515 ;; Maybe its not loaded yet.
8516 (condition-case nil
8517 (unload-feature 'tramp 'force)
a69c01a0
MA
8518 (error nil)))
8519
dea31ca6
MA
8520(when (and load-in-progress
8521 (string-match "Loading tramp..." (or (current-message) "")))
ccb4a481
MA
8522 (message "Loading tramp...done"))
8523
fb7933a3
KG
8524(provide 'tramp)
8525
fb7933a3
KG
8526;;; TODO:
8527
4007ba5b 8528;; * Handle nonlocal exits such as C-g.
00d6fd04
MA
8529;; * But it would probably be better to use with-local-quit at the
8530;; place where it's actually needed: around any potentially
8531;; indefinitely blocking piece of code. In this case it would be
8532;; within Tramp around one of its calls to accept-process-output (or
8533;; around one of the loops that calls accept-process-output)
d037d501 8534;; (Stefan Monnier).
fb7933a3 8535;; * Rewrite `tramp-shell-quote-argument' to abstain from using
b1d06e75 8536;; `shell-quote-argument'.
fb7933a3
KG
8537;; * In Emacs 21, `insert-directory' shows total number of bytes used
8538;; by the files in that directory. Add this here.
8539;; * Avoid screen blanking when hitting `g' in dired. (Eli Tziperman)
8540;; * Make ffap.el grok Tramp filenames. (Eli Tziperman)
fb7933a3 8541;; * Case-insensitive filename completion. (Norbert Goevert.)
fb7933a3
KG
8542;; * Don't use globbing for directories with many files, as this is
8543;; likely to produce long command lines, and some shells choke on
8544;; long command lines.
fb7933a3 8545;; * How to deal with MULE in `insert-file-contents' and `write-region'?
fb7933a3
KG
8546;; * Test remote ksh or bash for tilde expansion in `tramp-find-shell'?
8547;; * abbreviate-file-name
8e754ea2 8548;; * Better error checking. At least whenever we see something
fb7933a3
KG
8549;; strange when doing zerop, we should kill the process and start
8550;; again. (Greg Stark)
fb7933a3 8551;; * Remove unneeded parameters from methods.
fb7933a3
KG
8552;; * Make it work for different encodings, and for different file name
8553;; encodings, too. (Daniel Pittman)
fb7933a3 8554;; * Progress reports while copying files. (Michael Kifer)
fb7933a3
KG
8555;; * Don't search for perl5 and perl. Instead, only search for perl and
8556;; then look if it's the right version (with `perl -v').
8557;; * When editing a remote CVS controlled file as a different user, VC
8558;; gets confused about the file locking status. Try to find out why
8559;; the workaround doesn't work.
3cdaec13 8560;; * Username and hostname completion.
6c4e47fa 8561;; ** Try to avoid usage of `last-input-event' in `tramp-completion-mode-p'.
8daea7fc 8562;; ** Unify `tramp-parse-{rhosts,shosts,sconfig,hosts,passwd,netrc}'.
16674e4f 8563;; Code is nearly identical.
cfb5c0db
MA
8564;; * Allow out-of-band methods as _last_ multi-hop. Open a connection
8565;; until the last but one hop via `start-file-process'. Apply it
8566;; also for ftp and smb.
00d6fd04
MA
8567;; * WIBNI if we had a command "trampclient"? If I was editing in
8568;; some shell with root priviledges, it would be nice if I could
8569;; just call
8570;; trampclient filename.c
8571;; as an editor, and the _current_ shell would connect to an Emacs
8572;; server and would be used in an existing non-priviledged Emacs
8573;; session for doing the editing in question.
8574;; That way, I need not tell Emacs my password again and be afraid
8575;; that it makes it into core dumps or other ugly stuff (I had Emacs
8576;; once display a just typed password in the context of a keyboard
8577;; sequence prompt for a question immediately following in a shell
8578;; script run within Emacs -- nasty).
8579;; And if I have some ssh session running to a different computer,
8580;; having the possibility of passing a local file there to a local
8581;; Emacs session (in case I can arrange for a connection back) would
8582;; be nice.
a4aeb9a4 8583;; Likely the corresponding Tramp server should not allow the
00d6fd04
MA
8584;; equivalent of the emacsclient -eval option in order to make this
8585;; reasonably unproblematic. And maybe trampclient should have some
8586;; way of passing credentials, like by using an SSL socket or
8587;; something. (David Kastrup)
00d6fd04
MA
8588;; * Reconnect directly to a compliant shell without first going
8589;; through the user's default shell. (Pete Forman)
00d6fd04 8590;; * Make `tramp-default-user' obsolete.
11c71217
MA
8591;; * How can I interrupt the remote process with a signal
8592;; (interrupt-process seems not to work)? (Markus Triska)
2296b54d
MA
8593;; * Avoid the local shell entirely for starting remote processes. If
8594;; so, I think even a signal, when delivered directly to the local
8595;; SSH instance, would correctly be propagated to the remote process
8596;; automatically; possibly SSH would have to be started with
8597;; "-t". (Markus Triska)
dea31ca6
MA
8598;; * It makes me wonder if tramp couldn't fall back to ssh when scp
8599;; isn't on the remote host. (Mark A. Hershberger)
3e2fa353
MA
8600;; * Use lsh instead of ssh. (Alfred M. Szmidt)
8601;; * Implement a general server-local-variable mechanism, as there are
8602;; probably other variables that need different values for different
8603;; servers too. The user could then configure a variable (such as
8604;; tramp-server-local-variable-alist) to define any such variables
8605;; that they need to, which would then be let bound as appropriate
8606;; in tramp functions. (Jason Rumney)
946a5aeb
MA
8607;; * Optimize out-of-band copying, when both methods are scp-like (not
8608;; rsync).
8609;; * Keep a second connection open for out-of-band methods like scp or
8610;; rsync.
7540f029 8611;; * Support ptys in `tramp-handle-start-file-process'. (Bug#4604)
7e5686f0
MA
8612;; * IMHO, it's a drawback that currently Tramp doesn't support
8613;; Unicode in Dired file names by default. Is it possible to
8614;; improve Tramp to set LC_ALL to "C" only for commands where Tramp
8615;; expects English? Or just to set LC_MESSAGES to "C" if Tramp
8616;; expects only English messages? (Juri Linkov)
8617;; * Make shadowfile.el grok Tramp filenames. (Bug#4526, Bug#4846)
8618;; * Do not handle files with drive letter as remote. (Bug#5447)
8619;; * Load Tramp subpackages only when needed. (Bug#1529, Bug#5448)
8620;; * Try telnet+curl as new method. It might be useful for busybox,
8621;; without built-in uuencode/uudecode.
7540f029
MA
8622;; * Let `shell-dynamic-complete-*' and `comint-dynamic-complete' work
8623;; on remote hosts.
8624;; * Use secrets.el for password handling.
fb7933a3
KG
8625
8626;; Functions for file-name-handler-alist:
8627;; diff-latest-backup-file -- in diff.el
fb7933a3 8628
cdd44874 8629;; arch-tag: 3a21a994-182b-48fa-b0cd-c1d9fede424a
fb7933a3 8630;;; tramp.el ends here
57671b72
MA
8631
8632;; Local Variables:
8633;; mode: Emacs-Lisp
8634;; coding: utf-8
8635;; End: