* net/tramp.el (tramp-do-copy-or-rename-file): Fix check for
[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,
0664ff72 4;; 2005, 2006, 2007, 2008 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
14;; GNU Emacs is free software; you can redistribute it and/or modify
15;; it under the terms of the GNU General Public License as published by
ceaeecb0 16;; the Free Software Foundation; either version 3, or (at your option)
fb7933a3
KG
17;; any later version.
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
00d6fd04
MA
25;; along with GNU Emacs; see the file COPYING. If not, see
26;; <http://www.gnu.org/licenses/>.
fb7933a3
KG
27
28;;; Commentary:
29
30;; This package provides remote file editing, similar to ange-ftp.
31;; The difference is that ange-ftp uses FTP to transfer files between
32;; the local and the remote host, whereas tramp.el uses a combination
33;; of rsh and rcp or other work-alike programs, such as ssh/scp.
34;;
b1a2b924 35;; For more detailed instructions, please see the info file.
fb7933a3
KG
36;;
37;; Notes:
38;; -----
bf247b6e 39;;
00d6fd04
MA
40;; This package only works for Emacs 21.1 and higher, and for XEmacs 21.4
41;; and higher. For XEmacs 21, you need the package `fsf-compat' for
42;; the `with-timeout' macro.)
fb7933a3
KG
43;;
44;; This version might not work with pre-Emacs 21 VC unless VC is
45;; loaded before tramp.el. Could you please test this and tell me about
46;; the result? Thanks.
47;;
48;; Also see the todo list at the bottom of this file.
49;;
b1a2b924 50;; The current version of Tramp can be retrieved from the following URL:
340b8d4f 51;; http://ftp.gnu.org/gnu/tramp/
fb7933a3
KG
52;;
53;; There's a mailing list for this, as well. Its name is:
340b8d4f
MA
54;; tramp-devel@gnu.org
55;; You can use the Web to subscribe, under the following URL:
56;; http://lists.gnu.org/mailman/listinfo/tramp-devel
fb7933a3
KG
57;;
58;; For the adventurous, the current development sources are available
59;; via CVS. You can find instructions about this at the following URL:
c62c9d08 60;; http://savannah.gnu.org/projects/tramp/
fb7933a3
KG
61;; Click on "CVS" in the navigation bar near the top.
62;;
63;; Don't forget to put on your asbestos longjohns, first!
64
65;;; Code:
66
b1a2b924
KG
67;; The Tramp version number and bug report address, as prepared by configure.
68(require 'trampver)
a69c01a0
MA
69(add-hook 'tramp-unload-hook
70 '(lambda ()
71 (when (featurep 'trampver)
72 (unload-feature 'trampver 'force))))
73
9e6ab520 74(require 'tramp-compat)
94be87e8
MA
75(add-hook 'tramp-unload-hook
76 '(lambda ()
77 (when (featurep 'tramp-compat)
78 (unload-feature 'tramp-compat 'force))))
fb7933a3 79
9fa0d3aa 80(require 'format-spec) ; from Gnus 5.8, also in tar ball
5ec2cc41
KG
81;; As long as password.el is not part of (X)Emacs, it shouldn't
82;; be mandatory
83(if (featurep 'xemacs)
84 (load "password" 'noerror)
fd48cd18
GM
85 (or (require 'password-cache nil 'noerror)
86 (require 'password nil 'noerror))) ; from No Gnus, also in tar ball
5ec2cc41 87
fb7933a3
KG
88(require 'shell)
89(require 'advice)
90
00d6fd04
MA
91;; Requiring 'tramp-cache results in an endless loop.
92(autoload 'tramp-get-file-property "tramp-cache")
93(autoload 'tramp-set-file-property "tramp-cache")
94(autoload 'tramp-flush-file-property "tramp-cache")
95(autoload 'tramp-flush-directory-property "tramp-cache")
00d6fd04
MA
96(autoload 'tramp-get-connection-property "tramp-cache")
97(autoload 'tramp-set-connection-property "tramp-cache")
98(autoload 'tramp-flush-connection-property "tramp-cache")
99(autoload 'tramp-parse-connection-properties "tramp-cache")
100(add-hook 'tramp-unload-hook
101 '(lambda ()
102 (when (featurep 'tramp-cache)
103 (unload-feature 'tramp-cache 'force))))
104
16674e4f
KG
105(autoload 'tramp-uuencode-region "tramp-uu"
106 "Implementation of `uuencode' in Lisp.")
a69c01a0
MA
107(add-hook 'tramp-unload-hook
108 '(lambda ()
109 (when (featurep 'tramp-uu)
110 (unload-feature 'tramp-uu 'force))))
16674e4f 111
00d6fd04 112(autoload 'uudecode-decode-region "uudecode")
16674e4f 113
0664ff72
MA
114;; The following Tramp packages must be loaded after tramp.el, because
115;; they require it as well.
00d6fd04 116(eval-after-load "tramp"
9c13938d
MA
117 '(dolist
118 (feature
119 (list
120
0664ff72 121 ;; Tramp interactive commands.
9c13938d
MA
122 'tramp-cmds
123
124 ;; Load foreign FTP method.
125 (if (featurep 'xemacs) 'tramp-efs 'tramp-ftp)
126
127 ;; tramp-smb uses "smbclient" from Samba. Not available
128 ;; under Cygwin and Windows, because they don't offer
129 ;; "smbclient". And even not necessary there, because Emacs
130 ;; supports UNC file names like "//host/share/localname".
131 (unless (memq system-type '(cygwin windows-nt)) 'tramp-smb)
132
133 ;; Load foreign FISH method.
134 'tramp-fish
00d6fd04 135
9c13938d
MA
136 ;; Load gateways. It needs `make-network-process' from Emacs 22.
137 (when (functionp 'make-network-process) 'tramp-gw)))
138
139 (when feature
00d6fd04 140 (require feature)
a69c01a0 141 (add-hook 'tramp-unload-hook
00d6fd04
MA
142 `(lambda ()
143 (when (featurep ,feature)
9c13938d 144 (unload-feature ,feature 'force)))))))
fb7933a3
KG
145
146;;; User Customizable Internal Variables:
147
148(defgroup tramp nil
149 "Edit remote files with a combination of rsh and rcp or similar programs."
589d30dd 150 :group 'files
bf247b6e 151 :version "22.1")
fb7933a3 152
00d6fd04 153(defcustom tramp-verbose 3
94be87e8 154 "*Verbosity level for Tramp.
00d6fd04
MA
155Any level x includes messages for all levels 1 .. x-1. The levels are
156
157 0 silent (no tramp messages at all)
158 1 errors
159 2 warnings
160 3 connection to remote hosts (default level)
161 4 activities
162 5 internal
163 6 sent and received strings
164 7 file caching
165 8 connection properties
16610 traces (huge)."
fb7933a3
KG
167 :group 'tramp
168 :type 'integer)
169
38c65fca
KG
170;; Emacs case
171(eval-and-compile
172 (when (boundp 'backup-directory-alist)
173 (defcustom tramp-backup-directory-alist nil
174 "Alist of filename patterns and backup directory names.
175Each element looks like (REGEXP . DIRECTORY), with the same meaning like
176in `backup-directory-alist'. If a Tramp file is backed up, and DIRECTORY
177is a local file name, the backup directory is prepended with Tramp file
00d6fd04 178name prefix \(method, user, host\) of file.
38c65fca
KG
179
180\(setq tramp-backup-directory-alist backup-directory-alist\)
181
182gives the same backup policy for Tramp files on their hosts like the
183policy for local files."
184 :group 'tramp
185 :type '(repeat (cons (regexp :tag "Regexp matching filename")
186 (directory :tag "Backup directory name"))))))
187
188;; XEmacs case. We cannot check for `bkup-backup-directory-info', because
189;; the package "backup-dir" might not be loaded yet.
190(eval-and-compile
191 (when (featurep 'xemacs)
192 (defcustom tramp-bkup-backup-directory-info nil
193 "*Alist of (FILE-REGEXP BACKUP-DIR OPTIONS ...))
194It has the same meaning like `bkup-backup-directory-info' from package
195`backup-dir'. If a Tramp file is backed up, and BACKUP-DIR is a local
196file name, the backup directory is prepended with Tramp file name prefix
00d6fd04 197\(method, user, host\) of file.
38c65fca
KG
198
199\(setq tramp-bkup-backup-directory-info bkup-backup-directory-info\)
200
201gives the same backup policy for Tramp files on their hosts like the
202policy for local files."
bf247b6e 203 :type '(repeat
38c65fca
KG
204 (list (regexp :tag "File regexp")
205 (string :tag "Backup Dir")
206 (set :inline t
207 (const ok-create)
208 (const full-path)
209 (const prepend-name)
210 (const search-upward))))
211 :group 'tramp)))
212
fb7933a3
KG
213(defcustom tramp-auto-save-directory nil
214 "*Put auto-save files in this directory, if set.
215The idea is to use a local directory so that auto-saving is faster."
216 :group 'tramp
00d6fd04 217 :type '(choice (const nil) string))
fb7933a3 218
16674e4f
KG
219(defcustom tramp-encoding-shell
220 (if (memq system-type '(windows-nt))
221 (getenv "COMSPEC")
222 "/bin/sh")
223 "*Use this program for encoding and decoding commands on the local host.
224This shell is used to execute the encoding and decoding command on the
225local host, so if you want to use `~' in those commands, you should
226choose a shell here which groks tilde expansion. `/bin/sh' normally
227does not understand tilde expansion.
228
229For encoding and deocding, commands like the following are executed:
230
231 /bin/sh -c COMMAND < INPUT > OUTPUT
232
233This variable can be used to change the \"/bin/sh\" part. See the
00d6fd04 234variable `tramp-encoding-command-switch' for the \"-c\" part.
fb7933a3
KG
235
236Note that this variable is not used for remote commands. There are
237mechanisms in tramp.el which automatically determine the right shell to
238use for the remote host."
239 :group 'tramp
240 :type '(file :must-match t))
241
16674e4f
KG
242(defcustom tramp-encoding-command-switch
243 (if (string-match "cmd\\.exe" tramp-encoding-shell)
244 "/c"
245 "-c")
246 "*Use this switch together with `tramp-encoding-shell' for local commands.
247See the variable `tramp-encoding-shell' for more information."
248 :group 'tramp
249 :type 'string)
250
00d6fd04
MA
251(defcustom tramp-copy-size-limit 10240
252 "*The maximum file size where inline copying is preferred over an out-of-the-band copy."
16674e4f 253 :group 'tramp
00d6fd04 254 :type 'integer)
90dc758d 255
00d6fd04
MA
256(defcustom tramp-terminal-type "dumb"
257 "*Value of TERM environment variable for logging in to remote host.
258Because Tramp wants to parse the output of the remote shell, it is easily
259confused by ANSI color escape sequences and suchlike. Often, shell init
260files conditionalize this setup based on the TERM environment variable."
90dc758d 261 :group 'tramp
00d6fd04 262 :type 'string)
90dc758d 263
00d6fd04
MA
264(defvar tramp-methods
265 `(("rcp" (tramp-login-program "rsh")
266 (tramp-login-args (("%h") ("-l" "%u")))
267 (tramp-remote-sh "/bin/sh")
268 (tramp-copy-program "rcp")
269 (tramp-copy-args (("-p" "%k")))
270 (tramp-copy-keep-date t)
271 (tramp-password-end-of-line nil))
272 ("scp" (tramp-login-program "ssh")
273 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
274 ("-e" "none")))
275 (tramp-remote-sh "/bin/sh")
276 (tramp-copy-program "scp")
277 (tramp-copy-args (("-P" "%p") ("-p" "%k") ("-q")))
278 (tramp-copy-keep-date t)
279 (tramp-password-end-of-line nil)
280 (tramp-gw-args (("-o"
281 "GlobalKnownHostsFile=/dev/null")
282 ("-o" "UserKnownHostsFile=/dev/null")
283 ("-o" "StrictHostKeyChecking=no")))
284 (tramp-default-port 22))
285 ("scp1" (tramp-login-program "ssh")
286 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
287 ("-1" "-e" "none")))
288 (tramp-remote-sh "/bin/sh")
289 (tramp-copy-program "scp")
290 (tramp-copy-args (("-1") ("-P" "%p") ("-p" "%k")
291 ("-q")))
292 (tramp-copy-keep-date t)
293 (tramp-password-end-of-line nil)
294 (tramp-gw-args (("-o"
295 "GlobalKnownHostsFile=/dev/null")
296 ("-o" "UserKnownHostsFile=/dev/null")
297 ("-o" "StrictHostKeyChecking=no")))
298 (tramp-default-port 22))
299 ("scp2" (tramp-login-program "ssh")
300 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
301 ("-2" "-e" "none")))
302 (tramp-remote-sh "/bin/sh")
303 (tramp-copy-program "scp")
304 (tramp-copy-args (("-2") ("-P" "%p") ("-p" "%k")
305 ("-q")))
306 (tramp-copy-keep-date t)
307 (tramp-password-end-of-line nil)
308 (tramp-gw-args (("-o"
309 "GlobalKnownHostsFile=/dev/null")
310 ("-o" "UserKnownHostsFile=/dev/null")
311 ("-o" "StrictHostKeyChecking=no")))
312 (tramp-default-port 22))
313 ("scp1_old"
314 (tramp-login-program "ssh1")
315 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
316 ("-e" "none")))
317 (tramp-remote-sh "/bin/sh")
318 (tramp-copy-program "scp1")
319 (tramp-copy-args (("-p" "%k")))
320 (tramp-copy-keep-date t)
321 (tramp-password-end-of-line nil))
322 ("scp2_old"
323 (tramp-login-program "ssh2")
324 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
325 ("-e" "none")))
326 (tramp-remote-sh "/bin/sh")
327 (tramp-copy-program "scp2")
328 (tramp-copy-args (("-p" "%k")))
329 (tramp-copy-keep-date t)
330 (tramp-password-end-of-line nil))
331 ("sftp" (tramp-login-program "ssh")
332 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
333 ("-e" "none")))
334 (tramp-remote-sh "/bin/sh")
335 (tramp-copy-program "sftp")
336 (tramp-copy-args nil)
337 (tramp-copy-keep-date nil)
338 (tramp-password-end-of-line nil))
339 ("rsync" (tramp-login-program "ssh")
340 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
341 ("-e" "none")))
342 (tramp-remote-sh "/bin/sh")
343 (tramp-copy-program "rsync")
344 (tramp-copy-args (("-e" "ssh") ("-t" "%k")))
345 (tramp-copy-keep-date t)
346 (tramp-password-end-of-line nil))
347 ("remcp" (tramp-login-program "remsh")
348 (tramp-login-args (("%h") ("-l" "%u")))
349 (tramp-remote-sh "/bin/sh")
350 (tramp-copy-program "rcp")
351 (tramp-copy-args (("-p" "%k")))
352 (tramp-copy-keep-date t)
353 (tramp-password-end-of-line nil))
354 ("rsh" (tramp-login-program "rsh")
355 (tramp-login-args (("%h") ("-l" "%u")))
356 (tramp-remote-sh "/bin/sh")
357 (tramp-copy-program nil)
358 (tramp-copy-args nil)
359 (tramp-copy-keep-date nil)
360 (tramp-password-end-of-line nil))
361 ("ssh" (tramp-login-program "ssh")
362 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
363 ("-e" "none")))
364 (tramp-remote-sh "/bin/sh")
365 (tramp-copy-program nil)
366 (tramp-copy-args nil)
367 (tramp-copy-keep-date nil)
368 (tramp-password-end-of-line nil)
369 (tramp-gw-args (("-o"
370 "GlobalKnownHostsFile=/dev/null")
371 ("-o" "UserKnownHostsFile=/dev/null")
372 ("-o" "StrictHostKeyChecking=no")))
373 (tramp-default-port 22))
374 ("ssh1" (tramp-login-program "ssh")
375 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
376 ("-1" "-e" "none")))
377 (tramp-remote-sh "/bin/sh")
378 (tramp-copy-program nil)
379 (tramp-copy-args nil)
380 (tramp-copy-keep-date nil)
381 (tramp-password-end-of-line nil)
382 (tramp-gw-args (("-o"
383 "GlobalKnownHostsFile=/dev/null")
384 ("-o" "UserKnownHostsFile=/dev/null")
385 ("-o" "StrictHostKeyChecking=no")))
386 (tramp-default-port 22))
387 ("ssh2" (tramp-login-program "ssh")
388 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
389 ("-2" "-e" "none")))
390 (tramp-remote-sh "/bin/sh")
391 (tramp-copy-program nil)
392 (tramp-copy-args nil)
393 (tramp-copy-keep-date nil)
394 (tramp-password-end-of-line nil)
395 (tramp-gw-args (("-o"
396 "GlobalKnownHostsFile=/dev/null")
397 ("-o" "UserKnownHostsFile=/dev/null")
398 ("-o" "StrictHostKeyChecking=no")))
399 (tramp-default-port 22))
400 ("ssh1_old"
401 (tramp-login-program "ssh1")
402 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
403 ("-e" "none")))
404 (tramp-remote-sh "/bin/sh")
405 (tramp-copy-program nil)
406 (tramp-copy-args nil)
407 (tramp-copy-keep-date nil)
408 (tramp-password-end-of-line nil))
409 ("ssh2_old"
410 (tramp-login-program "ssh2")
411 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
412 ("-e" "none")))
413 (tramp-remote-sh "/bin/sh")
414 (tramp-copy-program nil)
415 (tramp-copy-args nil)
416 (tramp-copy-keep-date nil)
417 (tramp-password-end-of-line nil))
418 ("remsh" (tramp-login-program "remsh")
419 (tramp-login-args (("%h") ("-l" "%u")))
420 (tramp-remote-sh "/bin/sh")
421 (tramp-copy-program nil)
422 (tramp-copy-args nil)
423 (tramp-copy-keep-date nil)
424 (tramp-password-end-of-line nil))
425 ("telnet"
426 (tramp-login-program "telnet")
427 (tramp-login-args (("%h") ("%p")))
428 (tramp-remote-sh "/bin/sh")
429 (tramp-copy-program nil)
430 (tramp-copy-args nil)
431 (tramp-copy-keep-date nil)
432 (tramp-password-end-of-line nil)
433 (tramp-default-port 23))
434 ("su" (tramp-login-program "su")
435 (tramp-login-args (("-") ("%u")))
436 (tramp-remote-sh "/bin/sh")
437 (tramp-copy-program nil)
438 (tramp-copy-args nil)
439 (tramp-copy-keep-date nil)
440 (tramp-password-end-of-line nil))
441 ("sudo" (tramp-login-program "sudo")
442 (tramp-login-args (("-u" "%u")
42bc9b6d 443 ("-s") ("-H") ("-p" "Password:")))
00d6fd04
MA
444 (tramp-remote-sh "/bin/sh")
445 (tramp-copy-program nil)
446 (tramp-copy-args nil)
447 (tramp-copy-keep-date nil)
448 (tramp-password-end-of-line nil))
449 ("scpc" (tramp-login-program "ssh")
450 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
451 ("-o" "ControlPath=%t.%%r@%%h:%%p")
452 ("-o" "ControlMaster=yes")
453 ("-e" "none")))
454 (tramp-remote-sh "/bin/sh")
455 (tramp-copy-program "scp")
456 (tramp-copy-args (("-P" "%p") ("-p" "%k") ("-q")
457 ("-o" "ControlPath=%t.%%r@%%h:%%p")
458 ("-o" "ControlMaster=auto")))
459 (tramp-copy-keep-date t)
460 (tramp-password-end-of-line nil)
461 (tramp-gw-args (("-o"
462 "GlobalKnownHostsFile=/dev/null")
463 ("-o" "UserKnownHostsFile=/dev/null")
464 ("-o" "StrictHostKeyChecking=no")))
465 (tramp-default-port 22))
466 ("scpx" (tramp-login-program "ssh")
467 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
468 ("-e" "none" "-t" "-t" "/bin/sh")))
469 (tramp-remote-sh "/bin/sh")
470 (tramp-copy-program "scp")
471 (tramp-copy-args (("-p" "%k")))
472 (tramp-copy-keep-date t)
473 (tramp-password-end-of-line nil)
474 (tramp-gw-args (("-o"
475 "GlobalKnownHostsFile=/dev/null")
476 ("-o" "UserKnownHostsFile=/dev/null")
477 ("-o" "StrictHostKeyChecking=no")))
478 (tramp-default-port 22))
479 ("sshx" (tramp-login-program "ssh")
480 (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
481 ("-e" "none" "-t" "-t" "/bin/sh")))
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 (tramp-gw-args (("-o"
488 "GlobalKnownHostsFile=/dev/null")
489 ("-o" "UserKnownHostsFile=/dev/null")
490 ("-o" "StrictHostKeyChecking=no")))
491 (tramp-default-port 22))
492 ("krlogin"
493 (tramp-login-program "krlogin")
494 (tramp-login-args (("%h") ("-l" "%u") ("-x")))
495 (tramp-remote-sh "/bin/sh")
496 (tramp-copy-program nil)
497 (tramp-copy-args nil)
498 (tramp-copy-keep-date nil)
499 (tramp-password-end-of-line nil))
500 ("plink" (tramp-login-program "plink")
501 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
502 ("-ssh")))
503 (tramp-remote-sh "/bin/sh")
504 (tramp-copy-program nil)
505 (tramp-copy-args nil)
506 (tramp-copy-keep-date nil)
507 (tramp-password-end-of-line "xy") ;see docstring for "xy"
508 (tramp-default-port 22))
509 ("plink1"
510 (tramp-login-program "plink")
511 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
512 ("-1" "-ssh")))
513 (tramp-remote-sh "/bin/sh")
514 (tramp-copy-program nil)
515 (tramp-copy-args nil)
516 (tramp-copy-keep-date nil)
517 (tramp-password-end-of-line "xy") ;see docstring for "xy"
518 (tramp-default-port 22))
519 ("plinkx"
520 (tramp-login-program "plink")
42bc9b6d
MA
521 ;; ("%h") must be a single element, see
522 ;; `tramp-compute-multi-hops'.
523 (tramp-login-args (("-load") ("%h") ("-t")
ce3f516f
MA
524 (,(format
525 "env 'TERM=%s' 'PROMPT_COMMAND=' 'PS1=$ '"
526 tramp-terminal-type))
00d6fd04
MA
527 ("/bin/sh")))
528 (tramp-remote-sh "/bin/sh")
529 (tramp-copy-program nil)
530 (tramp-copy-args nil)
531 (tramp-copy-keep-date nil)
532 (tramp-password-end-of-line nil))
533 ("pscp" (tramp-login-program "plink")
534 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
535 ("-ssh")))
536 (tramp-remote-sh "/bin/sh")
537 (tramp-copy-program "pscp")
12aeeb57 538 (tramp-copy-args (("-P") ("%p") ("-scp") ("-p" "%k")))
00d6fd04
MA
539 (tramp-copy-keep-date t)
540 (tramp-password-end-of-line "xy") ;see docstring for "xy"
541 (tramp-default-port 22))
542 ("psftp" (tramp-login-program "plink")
543 (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p")
544 ("-ssh")))
545 (tramp-remote-sh "/bin/sh")
546 (tramp-copy-program "pscp")
12aeeb57 547 (tramp-copy-args (("-P") ("%p") ("-sftp") ("-p" "%k")))
00d6fd04
MA
548 (tramp-copy-keep-date t)
549 (tramp-password-end-of-line "xy")) ;see docstring for "xy"
550 ("fcp" (tramp-login-program "fsh")
551 (tramp-login-args (("%h") ("-l" "%u") ("sh" "-i")))
552 (tramp-remote-sh "/bin/sh -i")
553 (tramp-copy-program "fcp")
554 (tramp-copy-args (("-p" "%k")))
555 (tramp-copy-keep-date t)
556 (tramp-password-end-of-line nil)))
fb7933a3
KG
557 "*Alist of methods for remote files.
558This is a list of entries of the form (NAME PARAM1 PARAM2 ...).
559Each NAME stands for a remote access method. Each PARAM is a
560pair of the form (KEY VALUE). The following KEYs are defined:
fb7933a3
KG
561 * `tramp-remote-sh'
562 This specifies the Bourne shell to use on the remote host. This
563 MUST be a Bourne-like shell. It is normally not necessary to set
a4aeb9a4 564 this to any value other than \"/bin/sh\": Tramp wants to use a shell
fb7933a3
KG
565 which groks tilde expansion, but it can search for it. Also note
566 that \"/bin/sh\" exists on all Unixen, this might not be true for
567 the value that you decide to use. You Have Been Warned.
b25a52cc
KG
568 * `tramp-login-program'
569 This specifies the name of the program to use for logging in to the
00d6fd04
MA
570 remote host. This may be the name of rsh or a workalike program,
571 or the name of telnet or a workalike, or the name of su or a workalike.
b25a52cc 572 * `tramp-login-args'
fb7933a3 573 This specifies the list of arguments to pass to the above
00d6fd04 574 mentioned program. Please note that this is a list of list of arguments,
fb7933a3 575 that is, normally you don't want to put \"-a -b\" or \"-f foo\"
00d6fd04
MA
576 here. Instead, you want a list (\"-a\" \"-b\"), or (\"-f\" \"foo\").
577 There are some patterns: \"%h\" in this list is replaced by the host
578 name, \"%u\" is replaced by the user name, \"%p\" is replaced by the
579 port number, and \"%%\" can be used to obtain a literal percent character.
580 If a list containing \"%h\", \"%u\" or \"%p\" is unchanged during
581 expansion (i.e. no host or no user specified), this list is not used as
582 argument. By this, arguments like (\"-l\" \"%u\") are optional.
583 \"%t\" is replaced by the temporary file name produced with
584 `tramp-make-tramp-temp-file'. \"%k\" indicates the keep-date
585 parameter of a program, if exists.
b25a52cc
KG
586 * `tramp-copy-program'
587 This specifies the name of the program to use for remotely copying
588 the file; this might be the absolute filename of rcp or the name of
589 a workalike program.
590 * `tramp-copy-args'
fb7933a3 591 This specifies the list of parameters to pass to the above mentioned
b25a52cc 592 program, the hints for `tramp-login-args' also apply here.
00d6fd04
MA
593 * `tramp-copy-keep-date'
594 This specifies whether the copying program when the preserves the
595 timestamp of the original file.
596 * `tramp-default-port'
597 The default port of a method is needed in case of gateway connections.
598 Additionally, it is used as indication which method is prepared for
599 passing gateways.
600 * `tramp-gw-args'
601 As the attribute name says, additional arguments are specified here
602 when a method is applied via a gateway.
90f8dc03
KG
603 * `tramp-password-end-of-line'
604 This specifies the string to use for terminating the line after
605 submitting the password. If this method parameter is nil, then the
606 value of the normal variable `tramp-default-password-end-of-line'
607 is used. This parameter is necessary because the \"plink\" program
608 requires any two characters after sending the password. These do
609 not have to be newline or carriage return characters. Other login
610 programs are happy with just one character, the newline character.
611 We use \"xy\" as the value for methods using \"plink\".
b25a52cc
KG
612
613What does all this mean? Well, you should specify `tramp-login-program'
614for all methods; this program is used to log in to the remote site. Then,
615there are two ways to actually transfer the files between the local and the
616remote side. One way is using an additional rcp-like program. If you want
617to do this, set `tramp-copy-program' in the method.
fb7933a3
KG
618
619Another possibility for file transfer is inline transfer, i.e. the
b25a52cc 620file is passed through the same buffer used by `tramp-login-program'. In
fb7933a3 621this case, the file contents need to be protected since the
b25a52cc 622`tramp-login-program' might use escape codes or the connection might not
fb7933a3 623be eight-bit clean. Therefore, file contents are encoded for transit.
00d6fd04
MA
624See the variables `tramp-local-coding-commands' and
625`tramp-remote-coding-commands' for details.
fb7933a3 626
16674e4f 627So, to summarize: if the method is an out-of-band method, then you
b25a52cc 628must specify `tramp-copy-program' and `tramp-copy-args'. If it is an
00d6fd04
MA
629inline method, then these two parameters should be nil. Methods which
630are fit for gateways must have `tramp-default-port' at least.
fb7933a3
KG
631
632Notes:
633
00d6fd04
MA
634When using `su' or `sudo' the phrase `open connection to a remote
635host' sounds strange, but it is used nevertheless, for consistency.
636No connection is opened to a remote host, but `su' or `sudo' is
637started on the local host. You should specify a remote host
638`localhost' or the name of the local host. Another host name is
639useful only in combination with `tramp-default-proxies-alist'.")
fb7933a3 640
b25a52cc 641(defcustom tramp-default-method
83e20b5c
MA
642 ;; An external copy method seems to be preferred, because it is much
643 ;; more performant for large files, and it hasn't too serious delays
644 ;; for small files. But it must be ensured that there aren't
645 ;; permanent password queries. Either a password agent like
646 ;; "ssh-agent" or "Pageant" shall run, or the optional password.el
647 ;; package shall be active for password caching. "scpc" would be
648 ;; another good choice because of the "ControlMaster" option, but
649 ;; this is a more modern alternative in OpenSSH 4, which cannot be
650 ;; taken as default.
00d6fd04
MA
651 (cond
652 ;; PuTTY is installed.
653 ((executable-find "pscp")
654 (if (or (fboundp 'password-read)
655 ;; Pageant is running.
656 (and (fboundp 'w32-window-exists-p)
657 (funcall (symbol-function 'w32-window-exists-p)
658 "Pageant" "Pageant")))
659 "pscp"
660 "plink"))
661 ;; There is an ssh installation.
662 ((executable-find "scp")
663 (if (or (fboundp 'password-read)
664 ;; ssh-agent is running.
665 (getenv "SSH_AUTH_SOCK")
666 (getenv "SSH_AGENT_PID"))
667 "scp"
668 "ssh"))
669 ;; Fallback.
670 (t "ftp"))
fb7933a3 671 "*Default method to use for transferring files.
c62c9d08 672See `tramp-methods' for possibilities.
4007ba5b 673Also see `tramp-default-method-alist'."
c62c9d08
KG
674 :group 'tramp
675 :type 'string)
676
505edaeb 677(defcustom tramp-default-method-alist
4007ba5b 678 '(("\\`localhost\\'" "\\`root\\'" "su"))
00d6fd04 679 "*Default method to use for specific host/user pairs.
c62c9d08
KG
680This is an alist of items (HOST USER METHOD). The first matching item
681specifies the method to use for a file name which does not specify a
682method. HOST and USER are regular expressions or nil, which is
683interpreted as a regular expression which always matches. If no entry
684matches, the variable `tramp-default-method' takes effect.
685
686If the file name does not specify the user, lookup is done using the
687empty string for the user name.
688
689See `tramp-methods' for a list of possibilities for METHOD."
690 :group 'tramp
691 :type '(repeat (list (regexp :tag "Host regexp")
692 (regexp :tag "User regexp")
693 (string :tag "Method"))))
694
00d6fd04
MA
695(defcustom tramp-default-user
696 nil
697 "*Default user to use for transferring files.
698It is nil by default; otherwise settings in configuration files like
699\"~/.ssh/config\" would be overwritten. Also see `tramp-default-user-alist'.
700
701This variable is regarded as obsolete, and will be removed soon."
702 :group 'tramp
703 :type '(choice (const nil) string))
704
705(defcustom tramp-default-user-alist
706 `(("\\`su\\(do\\)?\\'" nil "root")
707 ("\\`r\\(em\\)?\\(cp\\|sh\\)\\|telnet\\|plink1?\\'"
708 nil ,(user-login-name)))
709 "*Default user to use for specific method/host pairs.
710This is an alist of items (METHOD HOST USER). The first matching item
711specifies the user to use for a file name which does not specify a
712user. METHOD and USER are regular expressions or nil, which is
713interpreted as a regular expression which always matches. If no entry
714matches, the variable `tramp-default-user' takes effect.
715
716If the file name does not specify the method, lookup is done using the
717empty string for the method name."
718 :group 'tramp
719 :type '(repeat (list (regexp :tag "Method regexp")
720 (regexp :tag "Host regexp")
721 (string :tag "User"))))
722
723(defcustom tramp-default-host
724 (system-name)
725 "*Default host to use for transferring files.
726Useful for su and sudo methods mostly."
727 :group 'tramp
728 :type 'string)
729
730(defcustom tramp-default-proxies-alist nil
731 "*Route to be followed for specific host/user pairs.
732This is an alist of items (HOST USER PROXY). The first matching
733item specifies the proxy to be passed for a file name located on
734a remote target matching USER@HOST. HOST and USER are regular
735expressions or nil, which is interpreted as a regular expression
736which always matches. PROXY must be a Tramp filename without a
737localname part. Method and user name on PROXY are optional,
738which is interpreted with the default values. PROXY can contain
739the patterns %h and %u, which are replaced by the strings
740matching HOST or USER, respectively."
741 :group 'tramp
742 :type '(repeat (list (regexp :tag "Host regexp")
743 (regexp :tag "User regexp")
744 (string :tag "Proxy remote name"))))
745
16674e4f 746(defconst tramp-completion-function-alist-rsh
00d6fd04
MA
747 '((tramp-parse-rhosts "/etc/hosts.equiv")
748 (tramp-parse-rhosts "~/.rhosts"))
b25a52cc 749 "Default list of (FUNCTION FILE) pairs to be examined for rsh methods.")
16674e4f 750
16674e4f 751(defconst tramp-completion-function-alist-ssh
00d6fd04
MA
752 '((tramp-parse-rhosts "/etc/hosts.equiv")
753 (tramp-parse-rhosts "/etc/shosts.equiv")
754 (tramp-parse-shosts "/etc/ssh_known_hosts")
755 (tramp-parse-sconfig "/etc/ssh_config")
756 (tramp-parse-shostkeys "/etc/ssh2/hostkeys")
757 (tramp-parse-sknownhosts "/etc/ssh2/knownhosts")
758 (tramp-parse-rhosts "~/.rhosts")
759 (tramp-parse-rhosts "~/.shosts")
760 (tramp-parse-shosts "~/.ssh/known_hosts")
761 (tramp-parse-sconfig "~/.ssh/config")
762 (tramp-parse-shostkeys "~/.ssh2/hostkeys")
763 (tramp-parse-sknownhosts "~/.ssh2/knownhosts"))
b25a52cc 764 "Default list of (FUNCTION FILE) pairs to be examined for ssh methods.")
16674e4f 765
16674e4f 766(defconst tramp-completion-function-alist-telnet
00d6fd04 767 '((tramp-parse-hosts "/etc/hosts"))
b25a52cc 768 "Default list of (FUNCTION FILE) pairs to be examined for telnet methods.")
16674e4f 769
16674e4f 770(defconst tramp-completion-function-alist-su
00d6fd04 771 '((tramp-parse-passwd "/etc/passwd"))
b25a52cc 772 "Default list of (FUNCTION FILE) pairs to be examined for su methods.")
292ffc15 773
00d6fd04
MA
774(defconst tramp-completion-function-alist-putty
775 '((tramp-parse-putty
776 "HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions"))
777 "Default list of (FUNCTION REGISTRY) pairs to be examined for putty methods.")
778
5ec2cc41 779(defvar tramp-completion-function-alist nil
16674e4f
KG
780 "*Alist of methods for remote files.
781This is a list of entries of the form (NAME PAIR1 PAIR2 ...).
782Each NAME stands for a remote access method. Each PAIR is of the form
783\(FUNCTION FILE). FUNCTION is responsible to extract user names and host
784names from FILE for completion. The following predefined FUNCTIONs exists:
785
5ec2cc41
KG
786 * `tramp-parse-rhosts' for \"~/.rhosts\" like files,
787 * `tramp-parse-shosts' for \"~/.ssh/known_hosts\" like files,
788 * `tramp-parse-sconfig' for \"~/.ssh/config\" like files,
789 * `tramp-parse-shostkeys' for \"~/.ssh2/hostkeys/*\" like files,
790 * `tramp-parse-sknownhosts' for \"~/.ssh2/knownhosts/*\" like files,
791 * `tramp-parse-hosts' for \"/etc/hosts\" like files,
792 * `tramp-parse-passwd' for \"/etc/passwd\" like files.
793 * `tramp-parse-netrc' for \"~/.netrc\" like files.
00d6fd04 794 * `tramp-parse-putty' for PuTTY registry keys.
5ec2cc41
KG
795
796FUNCTION can also be a customer defined function. For more details see
797the info pages.")
798
799(eval-after-load "tramp"
800 '(progn
801 (tramp-set-completion-function
802 "rcp" tramp-completion-function-alist-rsh)
803 (tramp-set-completion-function
804 "scp" tramp-completion-function-alist-ssh)
805 (tramp-set-completion-function
806 "scp1" tramp-completion-function-alist-ssh)
807 (tramp-set-completion-function
808 "scp2" tramp-completion-function-alist-ssh)
809 (tramp-set-completion-function
810 "scp1_old" tramp-completion-function-alist-ssh)
811 (tramp-set-completion-function
812 "scp2_old" tramp-completion-function-alist-ssh)
813 (tramp-set-completion-function
814 "rsync" tramp-completion-function-alist-rsh)
815 (tramp-set-completion-function
816 "remcp" tramp-completion-function-alist-rsh)
817 (tramp-set-completion-function
818 "rsh" tramp-completion-function-alist-rsh)
819 (tramp-set-completion-function
820 "ssh" tramp-completion-function-alist-ssh)
821 (tramp-set-completion-function
822 "ssh1" tramp-completion-function-alist-ssh)
823 (tramp-set-completion-function
824 "ssh2" tramp-completion-function-alist-ssh)
825 (tramp-set-completion-function
826 "ssh1_old" tramp-completion-function-alist-ssh)
827 (tramp-set-completion-function
828 "ssh2_old" tramp-completion-function-alist-ssh)
829 (tramp-set-completion-function
830 "remsh" tramp-completion-function-alist-rsh)
831 (tramp-set-completion-function
832 "telnet" tramp-completion-function-alist-telnet)
833 (tramp-set-completion-function
834 "su" tramp-completion-function-alist-su)
835 (tramp-set-completion-function
836 "sudo" tramp-completion-function-alist-su)
bf247b6e 837 (tramp-set-completion-function
5ec2cc41
KG
838 "scpx" tramp-completion-function-alist-ssh)
839 (tramp-set-completion-function
840 "sshx" tramp-completion-function-alist-ssh)
841 (tramp-set-completion-function
842 "krlogin" tramp-completion-function-alist-rsh)
843 (tramp-set-completion-function
844 "plink" tramp-completion-function-alist-ssh)
845 (tramp-set-completion-function
846 "plink1" tramp-completion-function-alist-ssh)
00d6fd04
MA
847 (tramp-set-completion-function
848 "plinkx" tramp-completion-function-alist-putty)
5ec2cc41
KG
849 (tramp-set-completion-function
850 "pscp" tramp-completion-function-alist-ssh)
851 (tramp-set-completion-function
852 "fcp" tramp-completion-function-alist-ssh)))
16674e4f 853
00d6fd04
MA
854(defconst tramp-echo-mark "_echo\b\b\b\b\b"
855 "String mark to be transmitted around shell commands.
856Used to separate their echo from the output they produce. This
857will only be used if we cannot disable remote echo via stty.
858This string must have no effect on the remote shell except for
859producing some echo which can later be detected by
860`tramp-echoed-echo-mark-regexp'. Using some characters followed
861by an equal number of backspaces to erase them will usually
862suffice.")
863
864(defconst tramp-echoed-echo-mark-regexp "_echo\\(\b\\( \b\\)?\\)\\{5\\}"
865 "Regexp which matches `tramp-echo-mark' as it gets echoed by
866the remote shell.")
867
fb7933a3
KG
868(defcustom tramp-rsh-end-of-line "\n"
869 "*String used for end of line in rsh connections.
870I don't think this ever needs to be changed, so please tell me about it
16674e4f 871if you need to change this.
90f8dc03
KG
872Also see the method parameter `tramp-password-end-of-line' and the normal
873variable `tramp-default-password-end-of-line'."
16674e4f
KG
874 :group 'tramp
875 :type 'string)
876
90f8dc03
KG
877(defcustom tramp-default-password-end-of-line
878 tramp-rsh-end-of-line
16674e4f 879 "*String used for end of line after sending a password.
90f8dc03
KG
880This variable provides the default value for the method parameter
881`tramp-password-end-of-line', see `tramp-methods' for more details.
882
16674e4f
KG
883It seems that people using plink under Windows need to send
884\"\\r\\n\" (carriage-return, then newline) after a password, but just
885\"\\n\" after all other lines. This variable can be used for the
886password, see `tramp-rsh-end-of-line' for the other cases.
887
888The default value is to use the same value as `tramp-rsh-end-of-line'."
fb7933a3
KG
889 :group 'tramp
890 :type 'string)
891
00d6fd04
MA
892;; "getconf PATH" yields:
893;; HP-UX: /usr/bin:/usr/ccs/bin:/opt/ansic/bin:/opt/langtools/bin:/opt/fortran/bin
894;; Solaris: /usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin
0664ff72 895;; GNU/Linux (Debian, Suse): /bin:/usr/bin
00d6fd04 896;; FreeBSD: /usr/bin:/bin:/usr/sbin:/sbin: - beware trailing ":"!
fb7933a3 897(defcustom tramp-remote-path
00d6fd04
MA
898 '(tramp-default-remote-path "/usr/sbin" "/usr/local/bin"
899 "/local/bin" "/local/freeware/bin" "/local/gnu/bin"
fb7933a3
KG
900 "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin")
901 "*List of directories to search for executables on remote host.
00d6fd04
MA
902For every remote host, this variable will be set buffer local,
903keeping the list of existing directories on that host.
fb7933a3
KG
904
905You can use `~' in this list, but when searching for a shell which groks
00d6fd04
MA
906tilde expansion, all directory names starting with `~' will be ignored.
907
908`Default Directories' represent the list of directories given by
909the command \"getconf PATH\". It is recommended to use this
910entry on top of this list, because these are the default
911directories for POSIX compatible commands."
912 :group 'tramp
913 :type '(repeat (choice
914 (const :tag "Default Directories" tramp-default-remote-path)
915 (string :tag "Directory"))))
916
00d6fd04 917(defcustom tramp-remote-process-environment
a0a5183a 918 `("HISTFILE=$HOME/.tramp_history" "HISTSIZE=1" "LC_ALL=C"
00d6fd04
MA
919 ,(concat "TERM=" tramp-terminal-type)
920 "CDPATH=" "HISTORY=" "MAIL=" "MAILCHECK=" "MAILPATH="
921 "autocorrect=" "correct=")
922
923 "*List of environment variables to be set on the remote host.
924
925Each element should be a string of the form ENVVARNAME=VALUE. An
926entry ENVVARNAME= diables the corresponding environment variable,
927which might have been set in the init files like ~/.profile.
928
929Special handling is applied to the PATH environment, which should
930not be set here. Instead of, it should be set via `tramp-remote-path'."
fb7933a3
KG
931 :group 'tramp
932 :type '(repeat string))
933
934(defcustom tramp-login-prompt-regexp
bc103d00 935 ".*ogin\\( .*\\)?: *"
fb7933a3 936 "*Regexp matching login-like prompts.
bc103d00
MA
937The regexp should match at end of buffer.
938
939Sometimes the prompt is reported to look like \"login as:\"."
fb7933a3
KG
940 :group 'tramp
941 :type 'regexp)
942
821e6e36 943(defcustom tramp-shell-prompt-pattern
ea9d1443 944 "^[^#$%>\n]*[#$%>] *\\(\e\\[[0-9;]*[a-zA-Z] *\\)*"
821e6e36
KG
945 "Regexp to match prompts from remote shell.
946Normally, Tramp expects you to configure `shell-prompt-pattern'
947correctly, but sometimes it happens that you are connecting to a
948remote host which sends a different kind of shell prompt. Therefore,
949Tramp recognizes things matched by `shell-prompt-pattern' as prompt,
950and also things matched by this variable. The default value of this
b25a52cc 951variable is similar to the default value of `shell-prompt-pattern',
821e6e36
KG
952which should work well in many cases."
953 :group 'tramp
954 :type 'regexp)
955
fb7933a3 956(defcustom tramp-password-prompt-regexp
00d6fd04 957 "^.*\\([pP]assword\\|[pP]assphrase\\).*:\^@? *"
fb7933a3 958 "*Regexp matching password-like prompts.
ac474af1 959The regexp should match at end of buffer.
fb7933a3
KG
960
961The `sudo' program appears to insert a `^@' character into the prompt."
962 :group 'tramp
963 :type 'regexp)
964
965(defcustom tramp-wrong-passwd-regexp
b1d06e75
KG
966 (concat "^.*"
967 ;; These strings should be on the last line
a4aeb9a4 968 (regexp-opt '("Permission denied"
b1d06e75
KG
969 "Login incorrect"
970 "Login Incorrect"
971 "Connection refused"
27e813fe 972 "Connection closed"
b1d06e75
KG
973 "Sorry, try again."
974 "Name or service not known"
00d6fd04
MA
975 "Host key verification failed."
976 "No supported authentication methods left to try!"
977 "Tramp connection closed") t)
b1d06e75
KG
978 ".*"
979 "\\|"
980 "^.*\\("
981 ;; Here comes a list of regexes, separated by \\|
982 "Received signal [0-9]+"
983 "\\).*")
fb7933a3 984 "*Regexp matching a `login failed' message.
ac474af1
KG
985The regexp should match at end of buffer."
986 :group 'tramp
987 :type 'regexp)
988
989(defcustom tramp-yesno-prompt-regexp
3cdaec13
KG
990 (concat
991 (regexp-opt '("Are you sure you want to continue connecting (yes/no)?") t)
992 "\\s-*")
993 "Regular expression matching all yes/no queries which need to be confirmed.
ac474af1 994The confirmation should be done with yes or no.
3cdaec13
KG
995The regexp should match at end of buffer.
996See also `tramp-yn-prompt-regexp'."
fb7933a3
KG
997 :group 'tramp
998 :type 'regexp)
999
3cdaec13 1000(defcustom tramp-yn-prompt-regexp
658052a2
MA
1001 (concat
1002 (regexp-opt '("Store key in cache? (y/n)"
1003 "Update cached key? (y/n, Return cancels connection)") t)
1004 "\\s-*")
3cdaec13
KG
1005 "Regular expression matching all y/n queries which need to be confirmed.
1006The confirmation should be done with y or n.
1007The regexp should match at end of buffer.
1008See also `tramp-yesno-prompt-regexp'."
1009 :group 'tramp
1010 :type 'regexp)
487f4fb7
KG
1011
1012(defcustom tramp-terminal-prompt-regexp
1013 (concat "\\("
1014 "TERM = (.*)"
1015 "\\|"
1016 "Terminal type\\? \\[.*\\]"
1017 "\\)\\s-*")
1018 "Regular expression matching all terminal setting prompts.
1019The regexp should match at end of buffer.
1020The answer will be provided by `tramp-action-terminal', which see."
1021 :group 'tramp
1022 :type 'regexp)
3cdaec13 1023
01917a18
MA
1024(defcustom tramp-operation-not-permitted-regexp
1025 (concat "\\(" "preserving times.*" "\\|" "set mode" "\\)" ":\\s-*"
1026 (regexp-opt '("Operation not permitted") t))
1027 "Regular expression matching keep-date problems in (s)cp operations.
1028Copying has been performed successfully already, so this message can
1029be ignored safely."
1030 :group 'tramp
1031 :type 'regexp)
1032
6b2633cc
LH
1033(defcustom tramp-copy-failed-regexp
1034 (concat "\\(.+: "
1035 (regexp-opt '("Permission denied"
1036 "not a regular file"
1037 "is a directory"
1038 "No such file or directory") t)
1039 "\\)\\s-*")
1040 "Regular expression matching copy problems in (s)cp operations."
1041 :group 'tramp
1042 :type 'regexp)
1043
19a87064 1044(defcustom tramp-process-alive-regexp
38c65fca 1045 ""
19a87064 1046 "Regular expression indicating a process has finished.
38c65fca
KG
1047In fact this expression is empty by intention, it will be used only to
1048check regularly the status of the associated process.
07dfe738 1049The answer will be provided by `tramp-action-process-alive',
00d6fd04 1050`tramp-action-out-of-band', which see."
38c65fca
KG
1051 :group 'tramp
1052 :type 'regexp)
1053
fb7933a3
KG
1054(defcustom tramp-temp-name-prefix "tramp."
1055 "*Prefix to use for temporary files.
1056If this is a relative file name (such as \"tramp.\"), it is considered
1057relative to the directory name returned by the function
9e6ab520 1058`tramp-compat-temporary-file-directory' (which see). It may also be an
fb7933a3
KG
1059absolute file name; don't forget to include a prefix for the filename
1060part, though."
1061 :group 'tramp
1062 :type 'string)
1063
4007ba5b 1064(defcustom tramp-sh-extra-args '(("/bash\\'" . "-norc -noprofile"))
c62c9d08
KG
1065 "*Alist specifying extra arguments to pass to the remote shell.
1066Entries are (REGEXP . ARGS) where REGEXP is a regular expression
1067matching the shell file name and ARGS is a string specifying the
1068arguments.
1069
1070This variable is only used when Tramp needs to start up another shell
1071for tilde expansion. The extra arguments should typically prevent the
1072shell from reading its init file."
1073 :group 'tramp
90f8dc03
KG
1074 ;; This might be the wrong way to test whether the widget type
1075 ;; `alist' is available. Who knows the right way to test it?
1076 :type (if (get 'alist 'widget-type)
1077 '(alist :key-type string :value-type string)
1078 '(repeat (cons string string))))
c62c9d08 1079
00d6fd04
MA
1080;; XEmacs is distributed with few Lisp packages. Further packages are
1081;; installed using EFS. If we use a unified filename format, then
1082;; Tramp is required in addition to EFS. (But why can't Tramp just
1083;; disable EFS when Tramp is loaded? Then XEmacs can ship with EFS
1084;; just like before.) Another reason for using a separate filename
1085;; syntax on XEmacs is that EFS hooks into XEmacs in many places, but
1086;; Tramp only knows how to deal with `file-name-handler-alist', not
1087;; the other places.
1088
1089;; Currently, we have the choice between 'ftp, 'sep, and 'url.
1090;;;###autoload
1091(defcustom tramp-syntax
1092 (if (featurep 'xemacs) 'sep 'ftp)
1093 "Tramp filename syntax to be used.
1094
1095It can have the following values:
1096
1097 'ftp -- Ange-FTP respective EFS like syntax (GNU Emacs default)
1098 'sep -- Syntax as defined for XEmacs (not available yet for GNU Emacs)
1099 'url -- URL-like syntax."
16674e4f 1100 :group 'tramp
00d6fd04
MA
1101 :type (if (featurep 'xemacs)
1102 '(choice (const :tag "EFS" ftp)
1103 (const :tag "XEmacs" sep)
1104 (const :tag "URL" url))
1105 '(choice (const :tag "Ange-FTP" ftp)
1106 (const :tag "URL" url))))
1107
1108(defconst tramp-prefix-format
1109 (cond ((equal tramp-syntax 'ftp) "/")
1110 ((equal tramp-syntax 'sep) "/[")
1111 ((equal tramp-syntax 'url) "/")
1112 (t (error "Wrong `tramp-syntax' defined")))
a4aeb9a4 1113 "*String matching the very beginning of Tramp file names.
00d6fd04 1114Used in `tramp-make-tramp-file-name'.")
16674e4f 1115
00d6fd04 1116(defconst tramp-prefix-regexp
16674e4f 1117 (concat "^" (regexp-quote tramp-prefix-format))
a4aeb9a4 1118 "*Regexp matching the very beginning of Tramp file names.
00d6fd04 1119Should always start with \"^\". Derived from `tramp-prefix-format'.")
16674e4f 1120
00d6fd04 1121(defconst tramp-method-regexp
16674e4f 1122 "[a-zA-Z_0-9-]+"
00d6fd04 1123 "*Regexp matching methods identifiers.")
16674e4f 1124
00d6fd04
MA
1125(defconst tramp-postfix-method-format
1126 (cond ((equal tramp-syntax 'ftp) ":")
1127 ((equal tramp-syntax 'sep) "/")
1128 ((equal tramp-syntax 'url) "://")
1129 (t (error "Wrong `tramp-syntax' defined")))
16674e4f 1130 "*String matching delimeter between method and user or host names.
00d6fd04 1131Used in `tramp-make-tramp-file-name'.")
16674e4f 1132
00d6fd04
MA
1133(defconst tramp-postfix-method-regexp
1134 (regexp-quote tramp-postfix-method-format)
16674e4f 1135 "*Regexp matching delimeter between method and user or host names.
00d6fd04 1136Derived from `tramp-postfix-method-format'.")
16674e4f 1137
00d6fd04
MA
1138(defconst tramp-user-regexp
1139 "[^:/ \t]+"
1140 "*Regexp matching user names.")
16674e4f 1141
00d6fd04 1142(defconst tramp-postfix-user-format
16674e4f
KG
1143 "@"
1144 "*String matching delimeter between user and host names.
00d6fd04 1145Used in `tramp-make-tramp-file-name'.")
16674e4f 1146
00d6fd04 1147(defconst tramp-postfix-user-regexp
16674e4f
KG
1148 (regexp-quote tramp-postfix-user-format)
1149 "*Regexp matching delimeter between user and host names.
00d6fd04
MA
1150Derived from `tramp-postfix-user-format'.")
1151
1152(defconst tramp-host-regexp
1153 "[a-zA-Z0-9_.-]+"
1154 "*Regexp matching host names.")
1155
1156(defconst tramp-prefix-port-format
1157 (cond ((equal tramp-syntax 'ftp) "#")
1158 ((equal tramp-syntax 'sep) "#")
1159 ((equal tramp-syntax 'url) ":")
1160 (t (error "Wrong `tramp-syntax' defined")))
1161 "*String matching delimeter between host names and port numbers.")
1162
1163(defconst tramp-prefix-port-regexp
1164 (regexp-quote tramp-prefix-port-format)
1165 "*Regexp matching delimeter between host names and port numbers.
1166Derived from `tramp-prefix-port-format'.")
1167
1168(defconst tramp-port-regexp
1169 "[0-9]+"
1170 "*Regexp matching port numbers.")
1171
1172(defconst tramp-host-with-port-regexp
1173 (concat "\\(" tramp-host-regexp "\\)"
1174 tramp-prefix-port-regexp
1175 "\\(" tramp-port-regexp "\\)")
1176 "*Regexp matching host names with port numbers.")
1177
1178(defconst tramp-postfix-host-format
1179 (cond ((equal tramp-syntax 'ftp) ":")
1180 ((equal tramp-syntax 'sep) "]")
1181 ((equal tramp-syntax 'url) "")
1182 (t (error "Wrong `tramp-syntax' defined")))
7432277c 1183 "*String matching delimeter between host names and localnames.
00d6fd04 1184Used in `tramp-make-tramp-file-name'.")
16674e4f 1185
00d6fd04 1186(defconst tramp-postfix-host-regexp
16674e4f 1187 (regexp-quote tramp-postfix-host-format)
7432277c 1188 "*Regexp matching delimeter between host names and localnames.
00d6fd04 1189Derived from `tramp-postfix-host-format'.")
16674e4f 1190
00d6fd04 1191(defconst tramp-localname-regexp
16674e4f 1192 ".*$"
00d6fd04 1193 "*Regexp matching localnames.")
16674e4f
KG
1194
1195;; File name format.
505edaeb 1196
00d6fd04 1197(defconst tramp-file-name-structure
16674e4f
KG
1198 (list
1199 (concat
1200 tramp-prefix-regexp
00d6fd04
MA
1201 "\\(" "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp "\\)?"
1202 "\\(" "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp "\\)?"
1203 "\\(" tramp-host-regexp
1204 "\\(" tramp-prefix-port-regexp tramp-port-regexp "\\)?" "\\)?"
1205 tramp-postfix-host-regexp
1206 "\\(" tramp-localname-regexp "\\)")
1207 2 4 5 7)
16674e4f 1208
fb7933a3 1209 "*List of five elements (REGEXP METHOD USER HOST FILE), detailing \
a4aeb9a4 1210the Tramp file name structure.
fb7933a3 1211
a4aeb9a4 1212The first element REGEXP is a regular expression matching a Tramp file
fb7933a3
KG
1213name. The regex should contain parentheses around the method name,
1214the user name, the host name, and the file name parts.
1215
1216The second element METHOD is a number, saying which pair of
1217parentheses matches the method name. The third element USER is
1218similar, but for the user name. The fourth element HOST is similar,
1219but for the host name. The fifth element FILE is for the file name.
1220These numbers are passed directly to `match-string', which see. That
1221means the opening parentheses are counted to identify the pair.
1222
00d6fd04 1223See also `tramp-file-name-regexp'.")
fb7933a3
KG
1224
1225;;;###autoload
505edaeb
KG
1226(defconst tramp-file-name-regexp-unified
1227 "\\`/[^/:]+:"
1228 "Value for `tramp-file-name-regexp' for unified remoting.
1229Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and
00d6fd04 1230Tramp. See `tramp-file-name-structure' for more explanations.")
505edaeb
KG
1231
1232;;;###autoload
1233(defconst tramp-file-name-regexp-separate
1234 "\\`/\\[.*\\]"
1235 "Value for `tramp-file-name-regexp' for separate remoting.
1236XEmacs uses a separate filename syntax for Tramp and EFS.
00d6fd04 1237See `tramp-file-name-structure' for more explanations.")
505edaeb
KG
1238
1239;;;###autoload
00d6fd04
MA
1240(defconst tramp-file-name-regexp-url
1241 "\\`/[^/:]+://"
1242 "Value for `tramp-file-name-regexp' for URL-like remoting.
1243See `tramp-file-name-structure' for more explanations.")
1244
1245;;;###autoload
1246(defconst tramp-file-name-regexp
1247 (cond ((equal tramp-syntax 'ftp) tramp-file-name-regexp-unified)
1248 ((equal tramp-syntax 'sep) tramp-file-name-regexp-separate)
1249 ((equal tramp-syntax 'url) tramp-file-name-regexp-url)
1250 (t (error "Wrong `tramp-syntax' defined")))
94be87e8 1251 "*Regular expression matching file names handled by Tramp.
a4aeb9a4 1252This regexp should match Tramp file names but no other file names.
fb7933a3
KG
1253\(When tramp.el is loaded, this regular expression is prepended to
1254`file-name-handler-alist', and that is searched sequentially. Thus,
a4aeb9a4
MA
1255if the Tramp entry appears rather early in the `file-name-handler-alist'
1256and is a bit too general, then some files might be considered Tramp
00d6fd04 1257files which are not really Tramp files.
fb7933a3
KG
1258
1259Please note that the entry in `file-name-handler-alist' is made when
1260this file (tramp.el) is loaded. This means that this variable must be set
1261before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1262updated after changing this variable.
1263
00d6fd04 1264Also see `tramp-file-name-structure'.")
fb7933a3 1265
16674e4f 1266;;;###autoload
8a798e41 1267(defconst tramp-root-regexp
00d6fd04 1268 (if (memq system-type '(cygwin windows-nt))
57671b72
MA
1269 "^\\([a-zA-Z]:\\)?/"
1270 "^/")
8a798e41
MA
1271 "Beginning of an incomplete Tramp file name.
1272Usually, it is just \"^/\". On W32 systems, there might be a
57671b72 1273volume letter, which will be removed by `tramp-drop-volume-letter'.")
8a798e41
MA
1274
1275;;;###autoload
1276(defconst tramp-completion-file-name-regexp-unified
1277 (concat tramp-root-regexp "[^/]*$")
16674e4f 1278 "Value for `tramp-completion-file-name-regexp' for unified remoting.
8a798e41
MA
1279GNU Emacs uses a unified filename syntax for Tramp and Ange-FTP.
1280See `tramp-file-name-structure' for more explanations.")
fb7933a3 1281
16674e4f
KG
1282;;;###autoload
1283(defconst tramp-completion-file-name-regexp-separate
57671b72 1284 (concat tramp-root-regexp "\\([[][^]]*\\)?$")
16674e4f
KG
1285 "Value for `tramp-completion-file-name-regexp' for separate remoting.
1286XEmacs uses a separate filename syntax for Tramp and EFS.
00d6fd04 1287See `tramp-file-name-structure' for more explanations.")
fb7933a3 1288
16674e4f 1289;;;###autoload
00d6fd04 1290(defconst tramp-completion-file-name-regexp-url
8a798e41 1291 (concat tramp-root-regexp "[^/:]+\\(:\\(/\\(/[^/]*\\)?\\)?\\)?$")
00d6fd04
MA
1292 "Value for `tramp-completion-file-name-regexp' for URL-like remoting.
1293See `tramp-file-name-structure' for more explanations.")
1294
1295;;;###autoload
1296(defconst tramp-completion-file-name-regexp
1297 (cond ((equal tramp-syntax 'ftp) tramp-completion-file-name-regexp-unified)
1298 ((equal tramp-syntax 'sep) tramp-completion-file-name-regexp-separate)
1299 ((equal tramp-syntax 'url) tramp-completion-file-name-regexp-url)
1300 (t (error "Wrong `tramp-syntax' defined")))
a4aeb9a4
MA
1301 "*Regular expression matching file names handled by Tramp completion.
1302This regexp should match partial Tramp file names only.
16674e4f
KG
1303
1304Please note that the entry in `file-name-handler-alist' is made when
1305this file (tramp.el) is loaded. This means that this variable must be set
1306before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1307updated after changing this variable.
1308
00d6fd04 1309Also see `tramp-file-name-structure'.")
fb7933a3 1310
00d6fd04
MA
1311(defconst tramp-actions-before-shell
1312 '((tramp-login-prompt-regexp tramp-action-login)
1313 (tramp-password-prompt-regexp tramp-action-password)
1314 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
ac474af1 1315 (shell-prompt-pattern tramp-action-succeed)
821e6e36 1316 (tramp-shell-prompt-pattern tramp-action-succeed)
3cdaec13 1317 (tramp-yesno-prompt-regexp tramp-action-yesno)
487f4fb7 1318 (tramp-yn-prompt-regexp tramp-action-yn)
19a87064
MA
1319 (tramp-terminal-prompt-regexp tramp-action-terminal)
1320 (tramp-process-alive-regexp tramp-action-process-alive))
ac474af1
KG
1321 "List of pattern/action pairs.
1322Whenever a pattern matches, the corresponding action is performed.
1323Each item looks like (PATTERN ACTION).
1324
1325The PATTERN should be a symbol, a variable. The value of this
1326variable gives the regular expression to search for. Note that the
1327regexp must match at the end of the buffer, \"\\'\" is implicitly
1328appended to it.
1329
1330The ACTION should also be a symbol, but a function. When the
00d6fd04 1331corresponding PATTERN matches, the ACTION function is called.")
ac474af1 1332
00d6fd04 1333(defconst tramp-actions-copy-out-of-band
38c65fca
KG
1334 '((tramp-password-prompt-regexp tramp-action-password)
1335 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
00d6fd04 1336 (tramp-copy-failed-regexp tramp-action-permission-denied)
19a87064 1337 (tramp-process-alive-regexp tramp-action-out-of-band))
38c65fca
KG
1338 "List of pattern/action pairs.
1339This list is used for copying/renaming with out-of-band methods.
90f8dc03 1340
00d6fd04
MA
1341See `tramp-actions-before-shell' for more info.")
1342
1343;; Chunked sending kludge. We set this to 500 for black-listed constellations
7432277c 1344;; known to have a bug in `process-send-string'; some ssh connections appear
7177e2a3
MA
1345;; to drop bytes when data is sent too quickly. There is also a connection
1346;; buffer local variable, which is computed depending on remote host properties
1347;; when `tramp-chunksize' is zero or nil.
7432277c
KG
1348(defcustom tramp-chunksize
1349 (when (and (not (featurep 'xemacs))
1350 (memq system-type '(hpux)))
1351 500)
55880756
MA
1352;; Parentheses in docstring starting at beginning of line are escaped.
1353;; Fontification is messed up when
1354;; `open-paren-in-column-0-is-defun-start' set to t.
7432277c
KG
1355 "*If non-nil, chunksize for sending input to local process.
1356It is necessary only on systems which have a buggy `process-send-string'
1357implementation. The necessity, whether this variable must be set, can be
1358checked via the following code:
1359
1360 (with-temp-buffer
11948172
MA
1361 (let* ((user \"xxx\") (host \"yyy\")
1362 (init 0) (step 50)
1363 (sent init) (received init))
1364 (while (= sent received)
1365 (setq sent (+ sent step))
1366 (erase-buffer)
1367 (let ((proc (start-process (buffer-name) (current-buffer)
1368 \"ssh\" \"-l\" user host \"wc\" \"-c\")))
1369 (when (memq (process-status proc) '(run open))
1370 (process-send-string proc (make-string sent ?\\ ))
1371 (process-send-eof proc)
1372 (process-send-eof proc))
1373 (while (not (progn (goto-char (point-min))
1374 (re-search-forward \"\\\\w+\" (point-max) t)))
1375 (accept-process-output proc 1))
1376 (when (memq (process-status proc) '(run open))
1377 (setq received (string-to-number (match-string 0)))
1378 (delete-process proc)
1379 (message \"Bytes sent: %s\\tBytes received: %s\" sent received)
1380 (sit-for 0))))
1381 (if (> sent (+ init step))
1382 (message \"You should set `tramp-chunksize' to a maximum of %s\"
1383 (- sent step))
1384 (message \"Test does not work\")
1385 (display-buffer (current-buffer))
1386 (sit-for 30))))
1387
1388In the Emacs normally running Tramp, evaluate the above code
55880756 1389\(replace \"xxx\" and \"yyy\" by the remote user and host name,
11948172
MA
1390respectively). You can do this, for example, by pasting it into
1391the `*scratch*' buffer and then hitting C-j with the cursor after the
1392last closing parenthesis. Note that it works only if you have configured
1393\"ssh\" to run without password query, see ssh-agent(1).
1394
1395You will see the number of bytes sent successfully to the remote host.
1396If that number exceeds 1000, you can stop the execution by hitting
1397C-g, because your Emacs is likely clean.
1398
11948172
MA
1399When it is necessary to set `tramp-chunksize', you might consider to
1400use an out-of-the-band method (like \"scp\") instead of an internal one
55880756 1401\(like \"ssh\"), because setting `tramp-chunksize' to non-nil decreases
11948172 1402performance.
c951aecb 1403
00d6fd04
MA
1404If your Emacs is buggy, the code stops and gives you an indication
1405about the value `tramp-chunksize' should be set. Maybe you could just
1406experiment a bit, e.g. changing the values of `init' and `step'
1407in the third line of the code.
1408
7432277c
KG
1409Please raise a bug report via \"M-x tramp-bug\" if your system needs
1410this variable to be set as well."
1411 :group 'tramp
b1a2b924 1412 :type '(choice (const nil) integer))
7432277c 1413
5ec2cc41
KG
1414;; Logging in to a remote host normally requires obtaining a pty. But
1415;; Emacs on MacOS X has process-connection-type set to nil by default,
1416;; so on those systems Tramp doesn't obtain a pty. Here, we allow
1417;; for an override of the system default.
1418(defcustom tramp-process-connection-type t
1419 "Overrides `process-connection-type' for connections from Tramp.
1420Tramp binds process-connection-type to the value given here before
1421opening a connection to a remote host."
1422 :group 'tramp
1423 :type '(choice (const nil) (const t) (const pty)))
1424
b50dd0d2
MA
1425(defcustom tramp-completion-reread-directory-timeout 10
1426 "Defines seconds since last remote command before rereading a directory.
1427A remote directory might have changed its contents. In order to
1428make it visible during file name completion in the minibuffer,
1429Tramp flushes its cache and rereads the directory contents when
1430more than `tramp-completion-reread-directory-timeout' seconds
1431have been gone since last remote command execution. A value of 0
1432would require an immediate reread during filename completion, nil
1433means to use always cached values for the directory contents."
1434 :group 'tramp
1435 :type '(choice (const nil) integer))
1436
fb7933a3
KG
1437;;; Internal Variables:
1438
4007ba5b 1439(defvar tramp-end-of-output
a0a5183a
MA
1440 (format
1441 "%s///%s%s"
1442 tramp-rsh-end-of-line
1443 (md5 (concat (prin1-to-string process-environment) (current-time-string)))
1444 tramp-rsh-end-of-line)
fb7933a3
KG
1445 "String used to recognize end of output.")
1446
fb7933a3 1447(defvar tramp-current-method nil
00d6fd04 1448 "Connection method for this *tramp* buffer.")
fb7933a3
KG
1449
1450(defvar tramp-current-user nil
00d6fd04 1451 "Remote login name for this *tramp* buffer.")
fb7933a3
KG
1452
1453(defvar tramp-current-host nil
00d6fd04
MA
1454 "Remote host for this *tramp* buffer.")
1455
1456(defconst tramp-uudecode
1457 "(echo begin 600 /tmp/tramp.$$; tail +2) | uudecode
fabf2143 1458cat /tmp/tramp.$$
00d6fd04 1459rm -f /tmp/tramp.$$"
fabf2143 1460 "Shell function to implement `uudecode' to standard output.
c08e6004
MA
1461Many systems support `uudecode -o /dev/stdout' or `uudecode -o -'
1462for this or `uudecode -p', but some systems don't, and for them
1463we have this shell function.")
fabf2143
KG
1464
1465;; Perl script to implement `file-attributes' in a Lisp `read'able
1466;; output. If you are hacking on this, note that you get *no* output
1467;; unless this spits out a complete line, including the '\n' at the
1468;; end.
8daea7fc
KG
1469;; The device number is returned as "-1", because there will be a virtual
1470;; device number set in `tramp-handle-file-attributes'
00d6fd04
MA
1471(defconst tramp-perl-file-attributes
1472 "%s -e '
c82c5727
LH
1473@stat = lstat($ARGV[0]);
1474if (($stat[2] & 0170000) == 0120000)
1475{
1476 $type = readlink($ARGV[0]);
1477 $type = \"\\\"$type\\\"\";
1478}
1479elsif (($stat[2] & 0170000) == 040000)
1480{
1481 $type = \"t\";
1482}
1483else
1484{
1485 $type = \"nil\"
1486};
1487$uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
1488$gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
1489printf(
d4443a0d 1490 \"(%%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) -1)\\n\",
c82c5727
LH
1491 $type,
1492 $stat[3],
1493 $uid,
1494 $gid,
1495 $stat[8] >> 16 & 0xffff,
1496 $stat[8] & 0xffff,
1497 $stat[9] >> 16 & 0xffff,
1498 $stat[9] & 0xffff,
1499 $stat[10] >> 16 & 0xffff,
1500 $stat[10] & 0xffff,
1501 $stat[7],
1502 $stat[2],
1503 $stat[1] >> 16 & 0xffff,
1504 $stat[1] & 0xffff
00d6fd04 1505);' \"$1\" \"$2\" \"$3\" 2>/dev/null"
fb7933a3 1506 "Perl script to produce output suitable for use with `file-attributes'
00d6fd04
MA
1507on the remote file system.
1508Escape sequence %s is replaced with name of Perl binary.
1509This string is passed to `format', so percent characters need to be doubled.")
fb7933a3 1510
00d6fd04
MA
1511(defconst tramp-perl-directory-files-and-attributes
1512 "%s -e '
8cb0a559
LH
1513chdir($ARGV[0]) or printf(\"\\\"Cannot change to $ARGV[0]: $''!''\\\"\\n\"), exit();
1514opendir(DIR,\".\") or printf(\"\\\"Cannot open directory $ARGV[0]: $''!''\\\"\\n\"), exit();
c82c5727
LH
1515@list = readdir(DIR);
1516closedir(DIR);
1517$n = scalar(@list);
1518printf(\"(\\n\");
1519for($i = 0; $i < $n; $i++)
1520{
1521 $filename = $list[$i];
1522 @stat = lstat($filename);
1523 if (($stat[2] & 0170000) == 0120000)
1524 {
1525 $type = readlink($filename);
1526 $type = \"\\\"$type\\\"\";
1527 }
1528 elsif (($stat[2] & 0170000) == 040000)
1529 {
1530 $type = \"t\";
1531 }
1532 else
1533 {
1534 $type = \"nil\"
1535 };
1536 $uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\";
1537 $gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\";
1538 printf(
d4443a0d 1539 \"(\\\"%%s\\\" %%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u.0 %%u t (%%u . %%u) (%%u %%u))\\n\",
c82c5727
LH
1540 $filename,
1541 $type,
1542 $stat[3],
1543 $uid,
1544 $gid,
1545 $stat[8] >> 16 & 0xffff,
1546 $stat[8] & 0xffff,
1547 $stat[9] >> 16 & 0xffff,
1548 $stat[9] & 0xffff,
1549 $stat[10] >> 16 & 0xffff,
1550 $stat[10] & 0xffff,
1551 $stat[7],
1552 $stat[2],
1553 $stat[1] >> 16 & 0xffff,
1554 $stat[1] & 0xffff,
1555 $stat[0] >> 16 & 0xffff,
1556 $stat[0] & 0xffff);
1557}
00d6fd04 1558printf(\")\\n\");' \"$1\" \"$2\" \"$3\" 2>/dev/null"
c82c5727 1559 "Perl script implementing `directory-files-attributes' as Lisp `read'able
00d6fd04
MA
1560output.
1561Escape sequence %s is replaced with name of Perl binary.
1562This string is passed to `format', so percent characters need to be doubled.")
c82c5727 1563
ac474af1
KG
1564;; ;; These two use uu encoding.
1565;; (defvar tramp-perl-encode "%s -e'\
1566;; print qq(begin 644 xxx\n);
1567;; my $s = q();
1568;; my $res = q();
1569;; while (read(STDIN, $s, 45)) {
1570;; print pack(q(u), $s);
1571;; }
1572;; print qq(`\n);
1573;; print qq(end\n);
1574;; '"
1575;; "Perl program to use for encoding a file.
1576;; Escape sequence %s is replaced with name of Perl binary.")
1577
1578;; (defvar tramp-perl-decode "%s -ne '
1579;; print unpack q(u), $_;
1580;; '"
1581;; "Perl program to use for decoding a file.
1582;; Escape sequence %s is replaced with name of Perl binary.")
1583
1584;; These two use base64 encoding.
00d6fd04
MA
1585(defconst tramp-perl-encode-with-module
1586 "%s -MMIME::Base64 -0777 -ne 'print encode_base64($_)' 2>/dev/null"
ac474af1 1587 "Perl program to use for encoding a file.
b1d06e75 1588Escape sequence %s is replaced with name of Perl binary.
89509ea0 1589This string is passed to `format', so percent characters need to be doubled.
b1d06e75
KG
1590This implementation requires the MIME::Base64 Perl module to be installed
1591on the remote host.")
1592
00d6fd04
MA
1593(defconst tramp-perl-decode-with-module
1594 "%s -MMIME::Base64 -0777 -ne 'print decode_base64($_)' 2>/dev/null"
b1d06e75
KG
1595 "Perl program to use for decoding a file.
1596Escape sequence %s is replaced with name of Perl binary.
89509ea0 1597This string is passed to `format', so percent characters need to be doubled.
b1d06e75
KG
1598This implementation requires the MIME::Base64 Perl module to be installed
1599on the remote host.")
1600
00d6fd04 1601(defconst tramp-perl-encode
b1d06e75
KG
1602 "%s -e '
1603# This script contributed by Juanma Barranquero <lektu@terra.es>.
0664ff72 1604# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008
cbd12ed7 1605# Free Software Foundation, Inc.
b1d06e75
KG
1606use strict;
1607
fa32e96a 1608my %%trans = do {
b1d06e75
KG
1609 my $i = 0;
1610 map {(substr(unpack(q(B8), chr $i++), 2, 6), $_)}
1611 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/);
1612};
1613
36541701 1614binmode(\\*STDIN);
b1d06e75
KG
1615
1616# We read in chunks of 54 bytes, to generate output lines
1617# of 72 chars (plus end of line)
36541701 1618$/ = \\54;
b1d06e75
KG
1619
1620while (my $data = <STDIN>) {
1621 my $pad = q();
1622
1623 # Only for the last chunk, and only if did not fill the last three-byte packet
1624 if (eof) {
fa32e96a 1625 my $mod = length($data) %% 3;
b1d06e75
KG
1626 $pad = q(=) x (3 - $mod) if $mod;
1627 }
1628
1629 # Not the fastest method, but it is simple: unpack to binary string, split
1630 # by groups of 6 bits and convert back from binary to byte; then map into
1631 # the translation table
1632 print
1633 join q(),
1634 map($trans{$_},
1635 (substr(unpack(q(B*), $data) . q(00000), 0, 432) =~ /....../g)),
1636 $pad,
36541701 1637 qq(\\n);
00d6fd04 1638}' 2>/dev/null"
b1d06e75 1639 "Perl program to use for encoding a file.
fa32e96a 1640Escape sequence %s is replaced with name of Perl binary.
ccf29586 1641This string is passed to `format', so percent characters need to be doubled.")
ac474af1 1642
00d6fd04 1643(defconst tramp-perl-decode
b1d06e75
KG
1644 "%s -e '
1645# This script contributed by Juanma Barranquero <lektu@terra.es>.
0664ff72 1646# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008
cbd12ed7 1647# Free Software Foundation, Inc.
b1d06e75
KG
1648use strict;
1649
fa32e96a 1650my %%trans = do {
b1d06e75 1651 my $i = 0;
16674e4f 1652 map {($_, substr(unpack(q(B8), chr $i++), 2, 6))}
b1d06e75
KG
1653 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/)
1654};
1655
fa32e96a 1656my %%bytes = map {(unpack(q(B8), chr $_), chr $_)} 0 .. 255;
b1d06e75 1657
36541701 1658binmode(\\*STDOUT);
b1d06e75
KG
1659
1660# We are going to accumulate into $pending to accept any line length
1661# (we do not check they are <= 76 chars as the RFC says)
1662my $pending = q();
1663
1664while (my $data = <STDIN>) {
1665 chomp $data;
1666
1667 # If we find one or two =, we have reached the end and
1668 # any following data is to be discarded
1669 my $finished = $data =~ s/(==?).*/$1/;
1670 $pending .= $data;
1671
1672 my $len = length($pending);
16674e4f 1673 my $chunk = substr($pending, 0, $len & ~3);
414da5ab 1674 $pending = substr($pending, $len & ~3 + 1);
b1d06e75
KG
1675
1676 # Easy method: translate from chars to (pregenerated) six-bit packets, join,
1677 # split in 8-bit chunks and convert back to char.
1678 print join q(),
1679 map $bytes{$_},
1680 ((join q(), map {$trans{$_} || q()} split //, $chunk) =~ /......../g);
1681
1682 last if $finished;
00d6fd04 1683}' 2>/dev/null"
ac474af1 1684 "Perl program to use for decoding a file.
fa32e96a 1685Escape sequence %s is replaced with name of Perl binary.
ccf29586 1686This string is passed to `format', so percent characters need to be doubled.")
fb7933a3 1687
9ce8462a
MA
1688(defconst tramp-file-mode-type-map
1689 '((0 . "-") ; Normal file (SVID-v2 and XPG2)
1690 (1 . "p") ; fifo
1691 (2 . "c") ; character device
1692 (3 . "m") ; multiplexed character device (v7)
1693 (4 . "d") ; directory
1694 (5 . "?") ; Named special file (XENIX)
1695 (6 . "b") ; block device
1696 (7 . "?") ; multiplexed block device (v7)
1697 (8 . "-") ; regular file
1698 (9 . "n") ; network special file (HP-UX)
1699 (10 . "l") ; symlink
1700 (11 . "?") ; ACL shadow inode (Solaris, not userspace)
1701 (12 . "s") ; socket
1702 (13 . "D") ; door special (Solaris)
1703 (14 . "w")) ; whiteout (BSD)
fb7933a3
KG
1704 "A list of file types returned from the `stat' system call.
1705This is used to map a mode number to a permission string.")
1706
fb7933a3
KG
1707;; New handlers should be added here. The following operations can be
1708;; handled using the normal primitives: file-name-as-directory,
fb7933a3
KG
1709;; file-name-sans-versions, get-file-buffer.
1710(defconst tramp-file-name-handler-alist
00d6fd04 1711 '((load . tramp-handle-load)
fb7933a3
KG
1712 (make-symbolic-link . tramp-handle-make-symbolic-link)
1713 (file-name-directory . tramp-handle-file-name-directory)
1714 (file-name-nondirectory . tramp-handle-file-name-nondirectory)
1715 (file-truename . tramp-handle-file-truename)
1716 (file-exists-p . tramp-handle-file-exists-p)
1717 (file-directory-p . tramp-handle-file-directory-p)
1718 (file-executable-p . tramp-handle-file-executable-p)
fb7933a3
KG
1719 (file-readable-p . tramp-handle-file-readable-p)
1720 (file-regular-p . tramp-handle-file-regular-p)
1721 (file-symlink-p . tramp-handle-file-symlink-p)
1722 (file-writable-p . tramp-handle-file-writable-p)
1723 (file-ownership-preserved-p . tramp-handle-file-ownership-preserved-p)
1724 (file-newer-than-file-p . tramp-handle-file-newer-than-file-p)
1725 (file-attributes . tramp-handle-file-attributes)
1726 (file-modes . tramp-handle-file-modes)
fb7933a3 1727 (directory-files . tramp-handle-directory-files)
c82c5727 1728 (directory-files-and-attributes . tramp-handle-directory-files-and-attributes)
fb7933a3
KG
1729 (file-name-all-completions . tramp-handle-file-name-all-completions)
1730 (file-name-completion . tramp-handle-file-name-completion)
1731 (add-name-to-file . tramp-handle-add-name-to-file)
1732 (copy-file . tramp-handle-copy-file)
1733 (rename-file . tramp-handle-rename-file)
1734 (set-file-modes . tramp-handle-set-file-modes)
ce3f516f 1735 (set-file-times . tramp-handle-set-file-times)
fb7933a3
KG
1736 (make-directory . tramp-handle-make-directory)
1737 (delete-directory . tramp-handle-delete-directory)
1738 (delete-file . tramp-handle-delete-file)
1739 (directory-file-name . tramp-handle-directory-file-name)
00d6fd04
MA
1740 ;; `executable-find' is not official yet.
1741 (executable-find . tramp-handle-executable-find)
1742 (start-file-process . tramp-handle-start-file-process)
0457dd55 1743 (process-file . tramp-handle-process-file)
00d6fd04 1744 (shell-command . tramp-handle-shell-command)
fb7933a3
KG
1745 (insert-directory . tramp-handle-insert-directory)
1746 (expand-file-name . tramp-handle-expand-file-name)
00d6fd04 1747 (substitute-in-file-name . tramp-handle-substitute-in-file-name)
fb7933a3 1748 (file-local-copy . tramp-handle-file-local-copy)
19a87064 1749 (file-remote-p . tramp-handle-file-remote-p)
fb7933a3 1750 (insert-file-contents . tramp-handle-insert-file-contents)
94be87e8
MA
1751 (insert-file-contents-literally
1752 . tramp-handle-insert-file-contents-literally)
fb7933a3 1753 (write-region . tramp-handle-write-region)
38c65fca 1754 (find-backup-file-name . tramp-handle-find-backup-file-name)
c1105d05 1755 (make-auto-save-file-name . tramp-handle-make-auto-save-file-name)
fb7933a3 1756 (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
5ec2cc41 1757 (dired-compress-file . tramp-handle-dired-compress-file)
fb7933a3
KG
1758 (dired-recursive-delete-directory
1759 . tramp-handle-dired-recursive-delete-directory)
1760 (set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
1761 (verify-visited-file-modtime . tramp-handle-verify-visited-file-modtime))
c1105d05 1762 "Alist of handler functions.
fb7933a3
KG
1763Operations not mentioned here will be handled by the normal Emacs functions.")
1764
a4aeb9a4 1765;; Handlers for partial Tramp file names. For Emacs just
41c8e348 1766;; `file-name-all-completions' is needed.
a01b1e22 1767;;;###autoload
16674e4f 1768(defconst tramp-completion-file-name-handler-alist
a01b1e22 1769 '((file-name-all-completions . tramp-completion-handle-file-name-all-completions)
41c8e348 1770 (file-name-completion . tramp-completion-handle-file-name-completion))
16674e4f
KG
1771 "Alist of completion handler functions.
1772Used for file names matching `tramp-file-name-regexp'. Operations not
1773mentioned here will be handled by `tramp-file-name-handler-alist' or the
1774normal Emacs functions.")
1775
4007ba5b 1776;; Handlers for foreign methods, like FTP or SMB, shall be plugged here.
ea9d1443
KG
1777(defvar tramp-foreign-file-name-handler-alist
1778 ;; (identity . tramp-sh-file-name-handler) should always be the last
1779 ;; entry, since `identity' always matches.
1780 '((identity . tramp-sh-file-name-handler))
4007ba5b
KG
1781 "Alist of elements (FUNCTION . HANDLER) for foreign methods handled specially.
1782If (FUNCTION FILENAME) returns non-nil, then all I/O on that file is done by
1783calling HANDLER.")
1784
0664ff72 1785;;; Internal functions which must come first:
fb7933a3 1786
00d6fd04
MA
1787(defsubst tramp-debug-message (vec fmt-string &rest args)
1788 "Append message to debug buffer.
1789Message is formatted with FMT-STRING as control string and the remaining
1790ARGS to actually emit the message (if applicable)."
1791 (when (get-buffer (tramp-buffer-name vec))
1792 (with-current-buffer (tramp-get-debug-buffer vec)
1793 (goto-char (point-max))
1794 (unless (bolp)
1795 (insert "\n"))
1796 ;; Timestamp
1797 (insert (format-time-string "%T "))
1798 ;; Calling function
1799 (let ((btn 1) btf fn)
1800 (while (not fn)
1801 (setq btf (nth 1 (backtrace-frame btn)))
1802 (if (not btf)
1803 (setq fn "")
1804 (when (symbolp btf)
1805 (setq fn (symbol-name btf))
1806 (unless (and (string-match "^tramp" fn)
1807 (not (string-match
1808 "^tramp\\(-debug\\)?\\(-message\\|-error\\)$"
1809 fn)))
1810 (setq fn nil)))
1811 (setq btn (1+ btn))))
1812 ;; The following code inserts filename and line number.
1813 ;; Should be deactivated by default, because it is time
1814 ;; consuming.
1815; (let ((ffn (find-function-noselect (intern fn))))
1816; (insert
1817; (format
1818; "%s:%d: "
1819; (file-name-nondirectory (buffer-file-name (car ffn)))
1820; (with-current-buffer (car ffn)
1821; (1+ (count-lines (point-min) (cdr ffn)))))))
1822 (insert (format "%s " fn)))
1823 ;; The message
1824 (insert (apply 'format fmt-string args)))))
1825
1826(defsubst tramp-message (vec-or-proc level fmt-string &rest args)
fb7933a3 1827 "Emit a message depending on verbosity level.
a4aeb9a4 1828VEC-OR-PROC identifies the Tramp buffer to use. It can be either a
00d6fd04
MA
1829vector or a process. LEVEL says to be quiet if `tramp-verbose' is
1830less than LEVEL. The message is emitted only if `tramp-verbose' is
1831greater than or equal to LEVEL.
1832
1833The message is also logged into the debug buffer when `tramp-verbose'
1834is greater than or equal 4.
1835
1836Calls functions `message' and `tramp-debug-message' with FMT-STRING as
1837control string and the remaining ARGS to actually emit the message (if
1838applicable)."
1839 (condition-case nil
1840 (when (<= level tramp-verbose)
1841 ;; Match data must be preserved!
1842 (save-match-data
1843 ;; Display only when there is a minimum level.
1844 (when (<= level 3)
1845 (apply 'message
1846 (concat
1847 (cond
1848 ((= level 0) "")
1849 ((= level 1) "")
1850 ((= level 2) "Warning: ")
1851 (t "Tramp: "))
1852 fmt-string)
1853 args))
1854 ;; Log only when there is a minimum level.
1855 (when (>= tramp-verbose 4)
1856 (when (and vec-or-proc
1857 (processp vec-or-proc)
1858 (buffer-name (process-buffer vec-or-proc)))
1859 (with-current-buffer (process-buffer vec-or-proc)
1860 ;; Translate proc to vec.
1861 (setq vec-or-proc (tramp-dissect-file-name default-directory))))
1862 (when (and vec-or-proc (vectorp vec-or-proc))
1863 (apply 'tramp-debug-message
1864 vec-or-proc
1865 (concat (format "(%d) # " level) fmt-string)
1866 args)))))
1867 ;; Suppress all errors.
1868 (error nil)))
1869
1870(defsubst tramp-error (vec-or-proc signal fmt-string &rest args)
1871 "Emit an error.
1872VEC-OR-PROC identifies the connection to use, SIGNAL is the
1873signal identifier to be raised, remaining args passed to
1874`tramp-message'. Finally, signal SIGNAL is raised."
1875 (tramp-message
1876 vec-or-proc 1 "%s"
1877 (error-message-string
1878 (list signal (get signal 'error-message) (apply 'format fmt-string args))))
1879 (signal signal (list (apply 'format fmt-string args))))
1880
1881(defsubst tramp-error-with-buffer
1882 (buffer vec-or-proc signal fmt-string &rest args)
1883 "Emit an error, and show BUFFER.
1884If BUFFER is nil, show the connection buffer. Wait for 30\", or until
1885an input event arrives. The other arguments are passed to `tramp-error'."
1886 (save-window-excursion
1887 (unwind-protect
1888 (apply 'tramp-error vec-or-proc signal fmt-string args)
1889 (when (and vec-or-proc (not (zerop tramp-verbose)))
1890 (let ((enable-recursive-minibuffers t))
1891 (pop-to-buffer
1892 (or (and (bufferp buffer) buffer)
1893 (and (processp vec-or-proc) (process-buffer vec-or-proc))
1894 (tramp-get-buffer vec-or-proc)))
1895 (sit-for 30))))))
fb7933a3 1896
c62c9d08
KG
1897(defmacro with-parsed-tramp-file-name (filename var &rest body)
1898 "Parse a Tramp filename and make components available in the body.
1899
1900First arg FILENAME is evaluated and dissected into its components.
1901Second arg VAR is a symbol. It is used as a variable name to hold
1902the filename structure. It is also used as a prefix for the variables
1903holding the components. For example, if VAR is the symbol `foo', then
00d6fd04
MA
1904`foo' will be bound to the whole structure, `foo-method' will be bound to
1905the method component, and so on for `foo-user', `foo-host', `foo-localname'.
c62c9d08
KG
1906
1907Remaining args are Lisp expressions to be evaluated (inside an implicit
1908`progn').
1909
00d6fd04
MA
1910If VAR is nil, then we bind `v' to the structure and `method', `user',
1911`host', `localname' to the components."
c62c9d08 1912 `(let* ((,(or var 'v) (tramp-dissect-file-name ,filename))
c62c9d08
KG
1913 (,(if var (intern (concat (symbol-name var) "-method")) 'method)
1914 (tramp-file-name-method ,(or var 'v)))
1915 (,(if var (intern (concat (symbol-name var) "-user")) 'user)
1916 (tramp-file-name-user ,(or var 'v)))
1917 (,(if var (intern (concat (symbol-name var) "-host")) 'host)
1918 (tramp-file-name-host ,(or var 'v)))
7432277c
KG
1919 (,(if var (intern (concat (symbol-name var) "-localname")) 'localname)
1920 (tramp-file-name-localname ,(or var 'v))))
c62c9d08
KG
1921 ,@body))
1922
1923(put 'with-parsed-tramp-file-name 'lisp-indent-function 2)
00d6fd04 1924(put 'with-parsed-tramp-file-name 'edebug-form-spec '(form symbolp body))
9e6ab520 1925(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-parsed-tramp-file-name\\>"))
c62c9d08 1926
00d6fd04
MA
1927(defmacro with-file-property (vec file property &rest body)
1928 "Check in Tramp cache for PROPERTY, otherwise execute BODY and set cache.
1929FILE must be a local file name on a connection identified via VEC."
1930 `(if (file-name-absolute-p ,file)
1931 (let ((value (tramp-get-file-property ,vec ,file ,property 'undef)))
1932 (when (eq value 'undef)
1933 ;; We cannot pass @body as parameter to
1934 ;; `tramp-set-file-property' because it mangles our
1935 ;; debug messages.
1936 (setq value (progn ,@body))
1937 (tramp-set-file-property ,vec ,file ,property value))
1938 value)
1939 ,@body))
9ce8462a 1940
00d6fd04
MA
1941(put 'with-file-property 'lisp-indent-function 3)
1942(put 'with-file-property 'edebug-form-spec t)
9e6ab520 1943(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-file-property\\>"))
00d6fd04
MA
1944
1945(defmacro with-connection-property (key property &rest body)
1946 "Checks in Tramp for property PROPERTY, otherwise executes BODY and set."
1947 `(let ((value (tramp-get-connection-property ,key ,property 'undef)))
1948 (when (eq value 'undef)
1949 ;; We cannot pass ,@body as parameter to
1950 ;; `tramp-set-connection-property' because it mangles our debug
1951 ;; messages.
1952 (setq value (progn ,@body))
1953 (tramp-set-connection-property ,key ,property value))
1954 value))
9ce8462a 1955
00d6fd04
MA
1956(put 'with-connection-property 'lisp-indent-function 2)
1957(put 'with-connection-property 'edebug-form-spec t)
9e6ab520 1958(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-connection-property\\>"))
00d6fd04 1959
9c13938d 1960(defsubst tramp-make-tramp-temp-file (vec)
a6e96327 1961 "Create a temporary file on the remote host identified by VEC.
9c13938d
MA
1962Return the local name of the temporary file."
1963 (let ((prefix
1964 (tramp-make-tramp-file-name
1965 (tramp-file-name-method vec)
1966 (tramp-file-name-user vec)
1967 (tramp-file-name-host vec)
a4aeb9a4
MA
1968 (expand-file-name
1969 tramp-temp-name-prefix (tramp-get-remote-tmpdir vec))))
9c13938d
MA
1970 result)
1971 (while (not result)
1972 ;; `make-temp-file' would be the natural choice for
1973 ;; implementation. But it calls `write-region' internally,
1974 ;; which also needs a temporary file - we would end in an
1975 ;; infinite loop.
1976 (setq result (make-temp-name prefix))
1977 (if (file-exists-p result)
1978 (setq result nil)
1979 ;; This creates the file by side effect.
1980 (set-file-times result)
1981 (set-file-modes result (tramp-octal-to-decimal "0700"))))
1982
1983 ;; Return the local part.
1984 (with-parsed-tramp-file-name result nil localname)))
8a4438b6
MA
1985
1986
16674e4f
KG
1987;;; Config Manipulation Functions:
1988
1989(defun tramp-set-completion-function (method function-list)
1990 "Sets the list of completion functions for METHOD.
1991FUNCTION-LIST is a list of entries of the form (FUNCTION FILE).
1992The FUNCTION is intended to parse FILE according its syntax.
1993It might be a predefined FUNCTION, or a user defined FUNCTION.
1994Predefined FUNCTIONs are `tramp-parse-rhosts', `tramp-parse-shosts',
8daea7fc
KG
1995`tramp-parse-sconfig',`tramp-parse-hosts', `tramp-parse-passwd',
1996and `tramp-parse-netrc'.
1997
16674e4f
KG
1998Example:
1999
2000 (tramp-set-completion-function
2001 \"ssh\"
8daea7fc
KG
2002 '((tramp-parse-sconfig \"/etc/ssh_config\")
2003 (tramp-parse-sconfig \"~/.ssh/config\")))"
16674e4f 2004
5ec2cc41
KG
2005 (let ((r function-list)
2006 (v function-list))
2007 (setq tramp-completion-function-alist
2008 (delete (assoc method tramp-completion-function-alist)
2009 tramp-completion-function-alist))
2010
2011 (while v
00d6fd04 2012 ;; Remove double entries.
5ec2cc41
KG
2013 (when (member (car v) (cdr v))
2014 (setcdr v (delete (car v) (cdr v))))
00d6fd04 2015 ;; Check for function and file or registry key.
5ec2cc41 2016 (unless (and (functionp (nth 0 (car v)))
00d6fd04
MA
2017 (if (string-match "^HKEY_CURRENT_USER" (nth 1 (car v)))
2018 ;; Windows registry.
2019 (and (memq system-type '(cygwin windows-nt))
a4aeb9a4
MA
2020 (zerop
2021 (tramp-local-call-process
2022 "reg" nil nil nil "query" (nth 1 (car v)))))
00d6fd04
MA
2023 ;; Configuration file.
2024 (file-exists-p (nth 1 (car v)))))
5ec2cc41
KG
2025 (setq r (delete (car v) r)))
2026 (setq v (cdr v)))
2027
2028 (when r
4007ba5b 2029 (add-to-list 'tramp-completion-function-alist
5ec2cc41 2030 (cons method r)))))
16674e4f
KG
2031
2032(defun tramp-get-completion-function (method)
00d6fd04 2033 "Returns a list of completion functions for METHOD.
16674e4f 2034For definition of that list see `tramp-set-completion-function'."
00d6fd04
MA
2035 (cons
2036 ;; Hosts visited once shall be remembered.
2037 `(tramp-parse-connection-properties ,method)
2038 ;; The method related defaults.
2039 (cdr (assoc method tramp-completion-function-alist))))
16674e4f 2040
d037d501 2041
0664ff72 2042;;; Fontification of `read-file-name':
d037d501 2043
0664ff72 2044;; rfn-eshadow.el is part of Emacs 22. It is autoloaded.
d037d501
MA
2045(defvar tramp-rfn-eshadow-overlay)
2046(make-variable-buffer-local 'tramp-rfn-eshadow-overlay)
2047
2048(defun tramp-rfn-eshadow-setup-minibuffer ()
2049 "Set up a minibuffer for `file-name-shadow-mode'.
2050Adds another overlay hiding filename parts according to Tramp's
2051special handling of `substitute-in-file-name'."
9ce8462a 2052 (when (symbol-value 'minibuffer-completing-file-name)
d037d501 2053 (setq tramp-rfn-eshadow-overlay
9e6ab520
MA
2054 (funcall (symbol-function 'make-overlay)
2055 (funcall (symbol-function 'minibuffer-prompt-end))
2056 (funcall (symbol-function 'minibuffer-prompt-end))))
d037d501 2057 ;; Copy rfn-eshadow-overlay properties.
9e6ab520
MA
2058 (let ((props (funcall (symbol-function 'overlay-properties)
2059 (symbol-value 'rfn-eshadow-overlay))))
d037d501 2060 (while props
9e6ab520
MA
2061 (funcall (symbol-function 'overlay-put)
2062 tramp-rfn-eshadow-overlay (pop props) (pop props))))))
d037d501
MA
2063
2064(when (boundp 'rfn-eshadow-setup-minibuffer-hook)
2065 (add-hook 'rfn-eshadow-setup-minibuffer-hook
2066 'tramp-rfn-eshadow-setup-minibuffer))
2067
2068(defun tramp-rfn-eshadow-update-overlay ()
2069 "Update `rfn-eshadow-overlay' to cover shadowed part of minibuffer input.
2070This is intended to be used as a minibuffer `post-command-hook' for
2071`file-name-shadow-mode'; the minibuffer should have already
2072been set up by `rfn-eshadow-setup-minibuffer'."
2073 ;; In remote files name, there is a shadowing just for the local part.
9e6ab520
MA
2074 (let ((end (or (funcall (symbol-function 'overlay-end)
2075 (symbol-value 'rfn-eshadow-overlay))
2076 (funcall (symbol-function 'minibuffer-prompt-end)))))
2077 (when (file-remote-p (buffer-substring-no-properties end (point-max)))
bd316474
KY
2078 (save-excursion
2079 (save-restriction
2080 (narrow-to-region
2081 (1+ (or (string-match "/" (buffer-string) end) end)) (point-max))
2082 (let ((rfn-eshadow-overlay tramp-rfn-eshadow-overlay)
2083 (rfn-eshadow-update-overlay-hook nil))
2084 (funcall (symbol-function 'rfn-eshadow-update-overlay))))))))
d037d501
MA
2085
2086(when (boundp 'rfn-eshadow-update-overlay-hook)
2087 (add-hook 'rfn-eshadow-update-overlay-hook
2088 'tramp-rfn-eshadow-update-overlay))
2089
2090
fb7933a3
KG
2091;;; File Name Handler Functions:
2092
fb7933a3
KG
2093(defun tramp-handle-make-symbolic-link
2094 (filename linkname &optional ok-if-already-exists)
00d6fd04 2095 "Like `make-symbolic-link' for Tramp files.
cebb4ec6 2096If LINKNAME is a non-Tramp file, it is used verbatim as the target of
7432277c 2097the symlink. If LINKNAME is a Tramp file, only the localname component is
cebb4ec6
KG
2098used as the target of the symlink.
2099
7432277c
KG
2100If LINKNAME is a Tramp file and the localname component is relative, then
2101it is expanded first, before the localname component is taken. Note that
cebb4ec6
KG
2102this can give surprising results if the user/host for the source and
2103target of the symlink differ."
c62c9d08 2104 (with-parsed-tramp-file-name linkname l
00d6fd04 2105 (let ((ln (tramp-get-remote-ln l))
7432277c 2106 (cwd (file-name-directory l-localname)))
c62c9d08 2107 (unless ln
00d6fd04
MA
2108 (tramp-error
2109 l 'file-error
2110 "Making a symbolic link. ln(1) does not exist on the remote host."))
c62c9d08
KG
2111
2112 ;; Do the 'confirm if exists' thing.
cebb4ec6 2113 (when (file-exists-p linkname)
c62c9d08
KG
2114 ;; What to do?
2115 (if (or (null ok-if-already-exists) ; not allowed to exist
2116 (and (numberp ok-if-already-exists)
2117 (not (yes-or-no-p
2118 (format
2119 "File %s already exists; make it a link anyway? "
7432277c 2120 l-localname)))))
00d6fd04
MA
2121 (tramp-error
2122 l 'file-already-exists "File %s already exists" l-localname)
cebb4ec6
KG
2123 (delete-file linkname)))
2124
7432277c 2125 ;; If FILENAME is a Tramp name, use just the localname component.
cebb4ec6 2126 (when (tramp-tramp-file-p filename)
1834b39f
MA
2127 (setq filename
2128 (tramp-file-name-localname
2129 (tramp-dissect-file-name (expand-file-name filename)))))
bf247b6e 2130
c62c9d08
KG
2131 ;; Right, they are on the same host, regardless of user, method, etc.
2132 ;; We now make the link on the remote machine. This will occur as the user
2133 ;; that FILENAME belongs to.
2134 (zerop
2135 (tramp-send-command-and-check
00d6fd04 2136 l (format "cd %s && %s -sf %s %s" cwd ln filename l-localname) t)))))
fb7933a3
KG
2137
2138
2139(defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix)
00d6fd04
MA
2140 "Like `load' for Tramp files."
2141 (with-parsed-tramp-file-name (expand-file-name file) nil
c62c9d08
KG
2142 (unless nosuffix
2143 (cond ((file-exists-p (concat file ".elc"))
2144 (setq file (concat file ".elc")))
2145 ((file-exists-p (concat file ".el"))
2146 (setq file (concat file ".el")))))
2147 (when must-suffix
2148 ;; The first condition is always true for absolute file names.
2149 ;; Included for safety's sake.
2150 (unless (or (file-name-directory file)
2151 (string-match "\\.elc?\\'" file))
00d6fd04
MA
2152 (tramp-error
2153 v 'file-error
2154 "File `%s' does not include a `.el' or `.elc' suffix" file)))
c62c9d08
KG
2155 (unless noerror
2156 (when (not (file-exists-p file))
00d6fd04 2157 (tramp-error v 'file-error "Cannot load nonexistent file `%s'" file)))
c62c9d08
KG
2158 (if (not (file-exists-p file))
2159 nil
00d6fd04 2160 (unless nomessage (tramp-message v 0 "Loading %s..." file))
c62c9d08
KG
2161 (let ((local-copy (file-local-copy file)))
2162 ;; MUST-SUFFIX doesn't exist on XEmacs, so let it default to nil.
2163 (load local-copy noerror t t)
2164 (delete-file local-copy))
00d6fd04 2165 (unless nomessage (tramp-message v 0 "Loading %s...done" file))
c62c9d08 2166 t)))
fb7933a3 2167
a4aeb9a4 2168;; Localname manipulation functions that grok Tramp localnames...
fb7933a3 2169(defun tramp-handle-file-name-directory (file)
00d6fd04 2170 "Like `file-name-directory' but aware of Tramp files."
9ce8462a
MA
2171 ;; Everything except the last filename thing is the directory. We
2172 ;; cannot apply `with-parsed-tramp-file-name', because this expands
2173 ;; the remote file name parts. This is a problem when we are in
2174 ;; file name completion.
2175 (let ((v (tramp-dissect-file-name file t)))
a01b1e22
MA
2176 ;; Run the command on the localname portion only.
2177 (tramp-make-tramp-file-name
9ce8462a
MA
2178 (tramp-file-name-method v)
2179 (tramp-file-name-user v)
2180 (tramp-file-name-host v)
2181 (file-name-directory (or (tramp-file-name-localname v) "")))))
fb7933a3
KG
2182
2183(defun tramp-handle-file-name-nondirectory (file)
00d6fd04 2184 "Like `file-name-nondirectory' but aware of Tramp files."
c62c9d08 2185 (with-parsed-tramp-file-name file nil
7432277c 2186 (file-name-nondirectory localname)))
fb7933a3
KG
2187
2188(defun tramp-handle-file-truename (filename &optional counter prev-dirs)
00d6fd04 2189 "Like `file-truename' for Tramp files."
48ddd622 2190 (with-parsed-tramp-file-name (expand-file-name filename) nil
00d6fd04 2191 (with-file-property v localname "file-truename"
aff67808
MA
2192 (let* ((directory-sep-char ?/) ; for XEmacs
2193 (steps (tramp-split-string localname "/"))
2194 (localnamedir (file-name-as-directory localname))
00d6fd04
MA
2195 (is-dir (string= localname localnamedir))
2196 (thisstep nil)
2197 (numchase 0)
2198 ;; Don't make the following value larger than necessary.
2199 ;; People expect an error message in a timely fashion when
2200 ;; something is wrong; otherwise they might think that Emacs
2201 ;; is hung. Of course, correctness has to come first.
2202 (numchase-limit 20)
2203 (result nil) ;result steps in reverse order
2204 symlink-target)
2205 (tramp-message v 4 "Finding true name for `%s'" filename)
2206 (while (and steps (< numchase numchase-limit))
2207 (setq thisstep (pop steps))
2208 (tramp-message
2209 v 5 "Check %s"
2210 (mapconcat 'identity
2211 (append '("") (reverse result) (list thisstep))
2212 "/"))
2213 (setq symlink-target
2214 (nth 0 (file-attributes
2215 (tramp-make-tramp-file-name
2216 method user host
2217 (mapconcat 'identity
2218 (append '("")
2219 (reverse result)
2220 (list thisstep))
2221 "/")))))
2222 (cond ((string= "." thisstep)
2223 (tramp-message v 5 "Ignoring step `.'"))
2224 ((string= ".." thisstep)
2225 (tramp-message v 5 "Processing step `..'")
2226 (pop result))
2227 ((stringp symlink-target)
2228 ;; It's a symlink, follow it.
2229 (tramp-message v 5 "Follow symlink to %s" symlink-target)
2230 (setq numchase (1+ numchase))
2231 (when (file-name-absolute-p symlink-target)
2232 (setq result nil))
2233 ;; If the symlink was absolute, we'll get a string like
2234 ;; "/user@host:/some/target"; extract the
2235 ;; "/some/target" part from it.
2236 (when (tramp-tramp-file-p symlink-target)
2237 (unless (tramp-equal-remote filename symlink-target)
2238 (tramp-error
2239 v 'file-error
2240 "Symlink target `%s' on wrong host" symlink-target))
2241 (setq symlink-target localname))
2242 (setq steps
2243 (append (tramp-split-string symlink-target "/")
2244 steps)))
2245 (t
2246 ;; It's a file.
2247 (setq result (cons thisstep result)))))
2248 (when (>= numchase numchase-limit)
2249 (tramp-error
2250 v 'file-error
2251 "Maximum number (%d) of symlinks exceeded" numchase-limit))
2252 (setq result (reverse result))
2253 ;; Combine list to form string.
2254 (setq result
2255 (if result
2256 (mapconcat 'identity (cons "" result) "/")
2257 "/"))
2258 (when (and is-dir (or (string= "" result)
2259 (not (string= (substring result -1) "/"))))
2260 (setq result (concat result "/")))
2261 (tramp-message v 4 "True name of `%s' is `%s'" filename result)
2262 (tramp-make-tramp-file-name method user host result)))))
fb7933a3
KG
2263
2264;; Basic functions.
2265
2266(defun tramp-handle-file-exists-p (filename)
00d6fd04 2267 "Like `file-exists-p' for Tramp files."
c62c9d08 2268 (with-parsed-tramp-file-name filename nil
00d6fd04 2269 (with-file-property v localname "file-exists-p"
fb7933a3 2270 (zerop (tramp-send-command-and-check
00d6fd04 2271 v
fb7933a3 2272 (format
00d6fd04
MA
2273 "%s %s"
2274 (tramp-get-file-exists-command v)
7432277c 2275 (tramp-shell-quote-argument localname)))))))
fb7933a3 2276
00d6fd04
MA
2277;; Inodes don't exist for some file systems. Therefore we must
2278;; generate virtual ones. Used in `find-buffer-visiting'. The method
2279;; applied might be not so efficient (Ange-FTP uses hashes). But
2280;; performance isn't the major issue given that file transfer will
2281;; take time.
2282(defvar tramp-inodes nil
2283 "Keeps virtual inodes numbers.")
2284
8daea7fc
KG
2285;; Devices must distinguish physical file systems. The device numbers
2286;; provided by "lstat" aren't unique, because we operate on different hosts.
2287;; So we use virtual device numbers, generated by Tramp. Both Ange-FTP and
2288;; EFS use device number "-1". In order to be different, we use device number
00d6fd04 2289;; (-1 x), whereby "x" is unique for a given (method user host).
8daea7fc
KG
2290(defvar tramp-devices nil
2291 "Keeps virtual device numbers.")
2292
fb7933a3
KG
2293;; CCC: This should check for an error condition and signal failure
2294;; when something goes wrong.
2295;; Daniel Pittman <daniel@danann.net>
c951aecb 2296(defun tramp-handle-file-attributes (filename &optional id-format)
00d6fd04
MA
2297 "Like `file-attributes' for Tramp files."
2298 (unless id-format (setq id-format 'integer))
2299 (with-parsed-tramp-file-name (expand-file-name filename) nil
2300 (with-file-property v localname (format "file-attributes-%s" id-format)
2301 (when (file-exists-p filename)
2302 ;; file exists, find out stuff
2303 (save-excursion
2304 (tramp-convert-file-attributes
2305 v
2306 (if (tramp-get-remote-stat v)
2307 (tramp-handle-file-attributes-with-stat v localname id-format)
2308 (if (tramp-get-remote-perl v)
2309 (tramp-handle-file-attributes-with-perl v localname id-format)
2310 (tramp-handle-file-attributes-with-ls
2311 v localname id-format)))))))))
2312
2313(defun tramp-handle-file-attributes-with-ls (vec localname &optional id-format)
2314 "Implement `file-attributes' for Tramp files using the ls(1) command."
fb7933a3
KG
2315 (let (symlinkp dirp
2316 res-inode res-filemodes res-numlinks
2317 res-uid res-gid res-size res-symlink-target)
00d6fd04 2318 (tramp-message vec 5 "file attributes with ls: %s" localname)
fb7933a3 2319 (tramp-send-command
00d6fd04 2320 vec
fb7933a3 2321 (format "%s %s %s"
00d6fd04 2322 (tramp-get-ls-command vec)
c82c5727 2323 (if (eq id-format 'integer) "-ildn" "-ild")
7432277c 2324 (tramp-shell-quote-argument localname)))
fb7933a3 2325 ;; parse `ls -l' output ...
00d6fd04
MA
2326 (with-current-buffer (tramp-get-buffer vec)
2327 (goto-char (point-min))
2328 ;; ... inode
2329 (setq res-inode
2330 (condition-case err
2331 (read (current-buffer))
2332 (invalid-read-syntax
2333 (when (and (equal (cadr err)
2334 "Integer constant overflow in reader")
2335 (string-match
2336 "^[0-9]+\\([0-9][0-9][0-9][0-9][0-9]\\)\\'"
2337 (car (cddr err))))
2338 (let* ((big (read (substring (car (cddr err)) 0
2339 (match-beginning 1))))
2340 (small (read (match-string 1 (car (cddr err)))))
2341 (twiddle (/ small 65536)))
2342 (cons (+ big twiddle)
2343 (- small (* twiddle 65536))))))))
2344 ;; ... file mode flags
2345 (setq res-filemodes (symbol-name (read (current-buffer))))
2346 ;; ... number links
2347 (setq res-numlinks (read (current-buffer)))
2348 ;; ... uid and gid
2349 (setq res-uid (read (current-buffer)))
2350 (setq res-gid (read (current-buffer)))
2351 (if (eq id-format 'integer)
2352 (progn
2353 (unless (numberp res-uid) (setq res-uid -1))
2354 (unless (numberp res-gid) (setq res-gid -1)))
2355 (progn
2356 (unless (stringp res-uid) (setq res-uid (symbol-name res-uid)))
2357 (unless (stringp res-gid) (setq res-gid (symbol-name res-gid)))))
2358 ;; ... size
2359 (setq res-size (read (current-buffer)))
2360 ;; From the file modes, figure out other stuff.
2361 (setq symlinkp (eq ?l (aref res-filemodes 0)))
2362 (setq dirp (eq ?d (aref res-filemodes 0)))
2363 ;; if symlink, find out file name pointed to
2364 (when symlinkp
2365 (search-forward "-> ")
2366 (setq res-symlink-target
9e6ab520 2367 (buffer-substring (point) (tramp-compat-line-end-position))))
00d6fd04
MA
2368 ;; return data gathered
2369 (list
2370 ;; 0. t for directory, string (name linked to) for symbolic
2371 ;; link, or nil.
2372 (or dirp res-symlink-target)
2373 ;; 1. Number of links to file.
2374 res-numlinks
2375 ;; 2. File uid.
2376 res-uid
2377 ;; 3. File gid.
2378 res-gid
2379 ;; 4. Last access time, as a list of two integers. First
2380 ;; integer has high-order 16 bits of time, second has low 16
2381 ;; bits.
2382 ;; 5. Last modification time, likewise.
2383 ;; 6. Last status change time, likewise.
2384 '(0 0) '(0 0) '(0 0) ;CCC how to find out?
2385 ;; 7. Size in bytes (-1, if number is out of range).
2386 res-size
2387 ;; 8. File modes, as a string of ten letters or dashes as in ls -l.
2388 res-filemodes
1437876c 2389 ;; 9. t if file's gid would change if file were deleted and
00d6fd04
MA
2390 ;; recreated. Will be set in `tramp-convert-file-attributes'
2391 t
2392 ;; 10. inode number.
2393 res-inode
2394 ;; 11. Device number. Will be replaced by a virtual device number.
2395 -1
2396 ))))
fb7933a3
KG
2397
2398(defun tramp-handle-file-attributes-with-perl
00d6fd04
MA
2399 (vec localname &optional id-format)
2400 "Implement `file-attributes' for Tramp files using a Perl script."
2401 (tramp-message vec 5 "file attributes with perl: %s" localname)
2402 (tramp-maybe-send-script
2403 vec tramp-perl-file-attributes "tramp_perl_file_attributes")
2404 (tramp-send-command-and-read
2405 vec
2406 (format "tramp_perl_file_attributes %s %s"
2407 (tramp-shell-quote-argument localname) id-format)))
2408
2409(defun tramp-handle-file-attributes-with-stat
2410 (vec localname &optional id-format)
2411 "Implement `file-attributes' for Tramp files using stat(1) command."
2412 (tramp-message vec 5 "file attributes with stat: %s" localname)
2413 (tramp-send-command-and-read
2414 vec
2415 (format
d4443a0d 2416 "%s -c '((\"%%N\") %%h %s %s %%X.0 %%Y.0 %%Z.0 %%s.0 \"%%A\" t %%i.0 -1)' %s"
00d6fd04
MA
2417 (tramp-get-remote-stat vec)
2418 (if (eq id-format 'integer) "%u" "\"%U\"")
2419 (if (eq id-format 'integer) "%g" "\"%G\"")
2420 (tramp-shell-quote-argument localname))))
8daea7fc 2421
fb7933a3 2422(defun tramp-handle-set-visited-file-modtime (&optional time-list)
00d6fd04 2423 "Like `set-visited-file-modtime' for Tramp files."
fb7933a3
KG
2424 (unless (buffer-file-name)
2425 (error "Can't set-visited-file-modtime: buffer `%s' not visiting a file"
2426 (buffer-name)))
48ddd622
MA
2427 (if time-list
2428 (tramp-run-real-handler 'set-visited-file-modtime (list time-list))
11948172
MA
2429 (let ((f (buffer-file-name))
2430 coding-system-used)
48ddd622
MA
2431 (with-parsed-tramp-file-name f nil
2432 (let* ((attr (file-attributes f))
2433 ;; '(-1 65535) means file doesn't exists yet.
2434 (modtime (or (nth 5 attr) '(-1 65535))))
11948172
MA
2435 (when (boundp 'last-coding-system-used)
2436 (setq coding-system-used (symbol-value 'last-coding-system-used)))
48ddd622
MA
2437 ;; We use '(0 0) as a don't-know value. See also
2438 ;; `tramp-handle-file-attributes-with-ls'.
48ddd622
MA
2439 (if (not (equal modtime '(0 0)))
2440 (tramp-run-real-handler 'set-visited-file-modtime (list modtime))
00d6fd04 2441 (progn
48ddd622 2442 (tramp-send-command
00d6fd04 2443 v
48ddd622 2444 (format "%s -ild %s"
00d6fd04 2445 (tramp-get-ls-command v)
48ddd622 2446 (tramp-shell-quote-argument localname)))
48ddd622
MA
2447 (setq attr (buffer-substring (point)
2448 (progn (end-of-line) (point)))))
00d6fd04
MA
2449 (tramp-set-file-property
2450 v localname "visited-file-modtime-ild" attr))
11948172
MA
2451 (when (boundp 'last-coding-system-used)
2452 (set 'last-coding-system-used coding-system-used))
d2a2c17f 2453 nil)))))
fb7933a3 2454
c62c9d08
KG
2455;; CCC continue here
2456
2457;; This function makes the same assumption as
2458;; `tramp-handle-set-visited-file-modtime'.
2459(defun tramp-handle-verify-visited-file-modtime (buf)
00d6fd04 2460 "Like `verify-visited-file-modtime' for Tramp files.
c08e6004
MA
2461At the time `verify-visited-file-modtime' calls this function, we
2462already know that the buffer is visiting a file and that
2463`visited-file-modtime' does not return 0. Do not call this
2464function directly, unless those two cases are already taken care
2465of."
c62c9d08 2466 (with-current-buffer buf
b15d0c4c
MA
2467 ;; There is no file visiting the buffer, or the buffer has no
2468 ;; recorded last modification time.
2469 (if (or (not (buffer-file-name))
2470 (eq (visited-file-modtime) 0))
d2a2c17f 2471 t
b15d0c4c
MA
2472 (let ((f (buffer-file-name)))
2473 (with-parsed-tramp-file-name f nil
bce04fee 2474 (tramp-flush-file-property v localname)
b15d0c4c
MA
2475 (let* ((attr (file-attributes f))
2476 (modtime (nth 5 attr))
2477 (mt (visited-file-modtime)))
bf247b6e 2478
b15d0c4c
MA
2479 (cond
2480 ;; file exists, and has a known modtime.
2481 ((and attr (not (equal modtime '(0 0))))
2482 (< (abs (tramp-time-diff
2483 modtime
2484 ;; For compatibility, deal with both the old
2485 ;; (HIGH . LOW) and the new (HIGH LOW)
2486 ;; return values of `visited-file-modtime'.
2487 (if (atom (cdr mt))
2488 (list (car mt) (cdr mt))
2489 mt)))
2490 2))
2491 ;; modtime has the don't know value.
2492 (attr
00d6fd04
MA
2493 (tramp-send-command
2494 v
2495 (format "%s -ild %s"
2496 (tramp-get-ls-command v)
2497 (tramp-shell-quote-argument localname)))
2498 (with-current-buffer (tramp-get-buffer v)
b15d0c4c
MA
2499 (setq attr (buffer-substring
2500 (point) (progn (end-of-line) (point)))))
00d6fd04
MA
2501 (equal
2502 attr
2503 (tramp-get-file-property
2504 v localname "visited-file-modtime-ild" "")))
b15d0c4c
MA
2505 ;; If file does not exist, say it is not modified
2506 ;; if and only if that agrees with the buffer's record.
2507 (t (equal mt '(-1 65535))))))))))
c62c9d08 2508
fb7933a3 2509(defun tramp-handle-set-file-modes (filename mode)
00d6fd04 2510 "Like `set-file-modes' for Tramp files."
c62c9d08 2511 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2512 (tramp-flush-file-property v localname)
2513 (unless (zerop (tramp-send-command-and-check
2514 v
2515 (format "chmod %s %s"
2516 (tramp-decimal-to-octal mode)
2517 (tramp-shell-quote-argument localname))))
2518 ;; FIXME: extract the proper text from chmod's stderr.
2519 (tramp-error
2520 v 'file-error "Error while changing file's mode %s" filename))))
fb7933a3 2521
ce3f516f
MA
2522(defun tramp-handle-set-file-times (filename &optional time)
2523 "Like `set-file-times' for Tramp files."
2524 (zerop
9e6ab520 2525 (if (file-remote-p filename)
ce3f516f 2526 (with-parsed-tramp-file-name filename nil
8d60099b 2527 (tramp-flush-file-property v localname)
ce3f516f
MA
2528 (let ((time (if (or (null time) (equal time '(0 0)))
2529 (current-time)
2530 time))
2531 (utc
2532 ;; With GNU Emacs, `format-time-string' has an
2533 ;; optional parameter UNIVERSAL. This is preferred,
2534 ;; because we could handle the case when the remote
2535 ;; host is located in a different time zone as the
2536 ;; local host.
2537 (and (functionp 'subr-arity)
2538 (subrp (symbol-function 'format-time-string))
2539 (= 3 (cdr (funcall (symbol-function 'subr-arity)
2540 (symbol-function
2541 'format-time-string)))))))
2542 (tramp-send-command-and-check
2543 v (format "%s touch -t %s %s"
2544 (if utc "TZ=UTC; export TZ;" "")
2545 (if utc
2546 (format-time-string "%Y%m%d%H%M.%S" time t)
2547 (format-time-string "%Y%m%d%H%M.%S" time))
2548 (tramp-shell-quote-argument localname)))))
8d60099b 2549
ce3f516f
MA
2550 ;; We handle also the local part, because in older Emacsen,
2551 ;; without `set-file-times', this function is an alias for this.
2552 ;; We are local, so we don't need the UTC settings.
a4aeb9a4 2553 (tramp-local-call-process
ce3f516f
MA
2554 "touch" nil nil nil "-t"
2555 (format-time-string "%Y%m%d%H%M.%S" time)
2556 (tramp-shell-quote-argument filename)))))
2557
8d60099b
MA
2558(defun tramp-set-file-uid-gid (filename &optional uid gid)
2559 "Set the ownership for FILENAME.
2560If UID and GID are provided, these values are used; otherwise uid
2561and gid of the corresponding user is taken. Both parameters must be integers."
2562 ;; CCC: Modern Unices allow chown only for root. So we might need
2563 ;; another implementation, see `dired-do-chown'. OTOH, it is
2564 ;; mostly working with su(do)? when it is needed, so it shall
2565 ;; succeed in the majority of cases.
9e6ab520 2566 (if (file-remote-p filename)
8d60099b
MA
2567 (with-parsed-tramp-file-name filename nil
2568 (let ((uid (or (and (integerp uid) uid)
2569 (tramp-get-remote-uid v 'integer)))
2570 (gid (or (and (integerp gid) gid)
2571 (tramp-get-remote-gid v 'integer))))
2572 (tramp-send-command
2573 v (format
2574 "chown %d:%d %s" uid gid
2575 (tramp-shell-quote-argument localname)))))
2576
2577 ;; We handle also the local part, because there doesn't exist
a4aeb9a4 2578 ;; `set-file-uid-gid'. On Win32 "chown" might not work.
8d60099b 2579 (let ((uid (or (and (integerp uid) uid) (tramp-get-local-uid 'integer)))
a4aeb9a4
MA
2580 (gid (or (and (integerp gid) gid) (tramp-get-local-gid 'integer))))
2581 (tramp-local-call-process
2582 "chown" nil nil nil
2583 (format "%d:%d" uid gid) (tramp-shell-quote-argument filename)))))
8d60099b 2584
fb7933a3
KG
2585;; Simple functions using the `test' command.
2586
2587(defun tramp-handle-file-executable-p (filename)
00d6fd04 2588 "Like `file-executable-p' for Tramp files."
c62c9d08 2589 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2590 (with-file-property v localname "file-executable-p"
2591 (zerop (tramp-run-test "-x" filename)))))
fb7933a3
KG
2592
2593(defun tramp-handle-file-readable-p (filename)
00d6fd04 2594 "Like `file-readable-p' for Tramp files."
c62c9d08 2595 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2596 (with-file-property v localname "file-readable-p"
2597 (zerop (tramp-run-test "-r" filename)))))
fb7933a3
KG
2598
2599;; When the remote shell is started, it looks for a shell which groks
2600;; tilde expansion. Here, we assume that all shells which grok tilde
2601;; expansion will also provide a `test' command which groks `-nt' (for
2602;; newer than). If this breaks, tell me about it and I'll try to do
2603;; something smarter about it.
2604(defun tramp-handle-file-newer-than-file-p (file1 file2)
00d6fd04 2605 "Like `file-newer-than-file-p' for Tramp files."
fb7933a3
KG
2606 (cond ((not (file-exists-p file1))
2607 nil)
2608 ((not (file-exists-p file2))
2609 t)
91879624 2610 ;; We are sure both files exist at this point.
fb7933a3
KG
2611 (t
2612 (save-excursion
91879624
KG
2613 ;; We try to get the mtime of both files. If they are not
2614 ;; equal to the "dont-know" value, then we subtract the times
2615 ;; and obtain the result.
2616 (let ((fa1 (file-attributes file1))
2617 (fa2 (file-attributes file2)))
2618 (if (and (not (equal (nth 5 fa1) '(0 0)))
2619 (not (equal (nth 5 fa2) '(0 0))))
01917a18 2620 (> 0 (tramp-time-diff (nth 5 fa2) (nth 5 fa1)))
91879624
KG
2621 ;; If one of them is the dont-know value, then we can
2622 ;; still try to run a shell command on the remote host.
2623 ;; However, this only works if both files are Tramp
2624 ;; files and both have the same method, same user, same
2625 ;; host.
00d6fd04
MA
2626 (unless (tramp-equal-remote file1 file2)
2627 (with-parsed-tramp-file-name
2628 (if (tramp-tramp-file-p file1) file1 file2) nil
2629 (tramp-error
2630 v 'file-error
2631 "Files %s and %s must have same method, user, host"
2632 file1 file2)))
2633 (with-parsed-tramp-file-name file1 nil
2634 (zerop (tramp-run-test2
2635 (tramp-get-test-nt-command v) file1 file2)))))))))
fb7933a3
KG
2636
2637;; Functions implemented using the basic functions above.
2638
2639(defun tramp-handle-file-modes (filename)
00d6fd04
MA
2640 "Like `file-modes' for Tramp files."
2641 (when (file-exists-p filename)
2642 (tramp-mode-string-to-int
2643 (nth 8 (file-attributes filename)))))
fb7933a3
KG
2644
2645(defun tramp-handle-file-directory-p (filename)
00d6fd04 2646 "Like `file-directory-p' for Tramp files."
fb7933a3
KG
2647 ;; Care must be taken that this function returns `t' for symlinks
2648 ;; pointing to directories. Surely the most obvious implementation
2649 ;; would be `test -d', but that returns false for such symlinks.
2650 ;; CCC: Stefan Monnier says that `test -d' follows symlinks. And
2651 ;; I now think he's right. So we could be using `test -d', couldn't
2652 ;; we?
2653 ;;
2654 ;; Alternatives: `cd %s', `test -d %s'
c62c9d08 2655 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2656 (with-file-property v localname "file-directory-p"
2657 (zerop (tramp-run-test "-d" filename)))))
fb7933a3
KG
2658
2659(defun tramp-handle-file-regular-p (filename)
00d6fd04
MA
2660 "Like `file-regular-p' for Tramp files."
2661 (and (file-exists-p filename)
2662 (eq ?- (aref (nth 8 (file-attributes filename)) 0))))
fb7933a3
KG
2663
2664(defun tramp-handle-file-symlink-p (filename)
00d6fd04 2665 "Like `file-symlink-p' for Tramp files."
c62c9d08 2666 (with-parsed-tramp-file-name filename nil
c951aecb 2667 (let ((x (car (file-attributes filename))))
b25a52cc
KG
2668 (when (stringp x)
2669 ;; When Tramp is running on VMS, then `file-name-absolute-p'
2670 ;; might do weird things.
2671 (if (file-name-absolute-p x)
00d6fd04 2672 (tramp-make-tramp-file-name method user host x)
b25a52cc 2673 x)))))
fb7933a3
KG
2674
2675(defun tramp-handle-file-writable-p (filename)
00d6fd04 2676 "Like `file-writable-p' for Tramp files."
c62c9d08 2677 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2678 (with-file-property v localname "file-writable-p"
2679 (if (file-exists-p filename)
2680 ;; Existing files must be writable.
2681 (zerop (tramp-run-test "-w" filename))
2682 ;; If file doesn't exist, check if directory is writable.
2683 (and (zerop (tramp-run-test
2684 "-d" (file-name-directory filename)))
2685 (zerop (tramp-run-test
2686 "-w" (file-name-directory filename))))))))
fb7933a3
KG
2687
2688(defun tramp-handle-file-ownership-preserved-p (filename)
00d6fd04 2689 "Like `file-ownership-preserved-p' for Tramp files."
c62c9d08 2690 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
2691 (with-file-property v localname "file-ownership-preserved-p"
2692 (let ((attributes (file-attributes filename)))
2693 ;; Return t if the file doesn't exist, since it's true that no
2694 ;; information would be lost by an (attempted) delete and create.
2695 (or (null attributes)
2696 (= (nth 2 attributes) (tramp-get-remote-uid v 'integer)))))))
fb7933a3
KG
2697
2698;; Other file name ops.
2699
fb7933a3 2700(defun tramp-handle-directory-file-name (directory)
00d6fd04 2701 "Like `directory-file-name' for Tramp files."
7432277c
KG
2702 ;; If localname component of filename is "/", leave it unchanged.
2703 ;; Otherwise, remove any trailing slash from localname component.
8daea7fc
KG
2704 ;; Method, host, etc, are unchanged. Does it make sense to try
2705 ;; to avoid parsing the filename?
c62c9d08 2706 (with-parsed-tramp-file-name directory nil
7432277c
KG
2707 (if (and (not (zerop (length localname)))
2708 (eq (aref localname (1- (length localname))) ?/)
2709 (not (string= localname "/")))
8daea7fc
KG
2710 (substring directory 0 -1)
2711 directory)))
fb7933a3
KG
2712
2713;; Directory listings.
2714
00d6fd04
MA
2715(defun tramp-handle-directory-files
2716 (directory &optional full match nosort files-only)
2717 "Like `directory-files' for Tramp files."
2718 ;; FILES-ONLY is valid for XEmacs only.
2719 (when (file-directory-p directory)
2720 (setq directory (expand-file-name directory))
2721 (let ((temp (nreverse (file-name-all-completions "" directory)))
2722 result item)
2723
2724 (while temp
2725 (setq item (directory-file-name (pop temp)))
2726 (when (and (or (null match) (string-match match item))
2727 (or (null files-only)
2728 ;; files only
2729 (and (equal files-only t) (file-regular-p item))
2730 ;; directories only
2731 (file-directory-p item)))
2732 (push (if full (expand-file-name item directory) item)
2733 result)))
c62c9d08
KG
2734 result)))
2735
c82c5727
LH
2736(defun tramp-handle-directory-files-and-attributes
2737 (directory &optional full match nosort id-format)
00d6fd04
MA
2738 "Like `directory-files-and-attributes' for Tramp files."
2739 (unless id-format (setq id-format 'integer))
2740 (when (file-directory-p directory)
2741 (setq directory (expand-file-name directory))
2742 (let* ((temp
9e6ab520 2743 (tramp-compat-copy-tree
00d6fd04
MA
2744 (with-parsed-tramp-file-name directory nil
2745 (with-file-property
2746 v localname
2747 (format "directory-files-and-attributes-%s" id-format)
2748 (save-excursion
2749 (mapcar
2750 '(lambda (x)
2751 (cons (car x)
2752 (tramp-convert-file-attributes v (cdr x))))
2753 (if (tramp-get-remote-stat v)
2754 (tramp-handle-directory-files-and-attributes-with-stat
2755 v localname id-format)
2756 (if (tramp-get-remote-perl v)
2757 (tramp-handle-directory-files-and-attributes-with-perl
2758 v localname id-format)))))))))
2759 result item)
2760
2761 (while temp
2762 (setq item (pop temp))
2763 (when (or (null match) (string-match match (car item)))
2764 (when full
2765 (setcar item (expand-file-name (car item) directory)))
2766 (push item result)))
2767
2768 (if nosort
2769 result
2770 (sort result (lambda (x y) (string< (car x) (car y))))))))
2771
2772(defun tramp-handle-directory-files-and-attributes-with-perl
2773 (vec localname &optional id-format)
2774 "Implement `directory-files-and-attributes' for Tramp files using a Perl script."
2775 (tramp-message vec 5 "directory-files-and-attributes with perl: %s" localname)
2776 (tramp-maybe-send-script
2777 vec tramp-perl-directory-files-and-attributes
2778 "tramp_perl_directory_files_and_attributes")
2779 (let ((object
2780 (tramp-send-command-and-read
2781 vec
2782 (format "tramp_perl_directory_files_and_attributes %s %s"
2783 (tramp-shell-quote-argument localname) id-format))))
2784 (when (stringp object) (tramp-error vec 'file-error object))
2785 object))
2786
2787(defun tramp-handle-directory-files-and-attributes-with-stat
2788 (vec localname &optional id-format)
2789 "Implement `directory-files-and-attributes' for Tramp files using stat(1) command."
2790 (tramp-message vec 5 "directory-files-and-attributes with stat: %s" localname)
2791 (tramp-send-command-and-read
2792 vec
2793 (format
2794 (concat
2795 "cd %s; echo \"(\"; (%s -ab | xargs "
d4443a0d 2796 "%s -c '(\"%%n\" (\"%%N\") %%h %s %s %%X.0 %%Y.0 %%Z.0 %%s.0 \"%%A\" t %%i.0 -1)'); "
00d6fd04
MA
2797 "echo \")\"")
2798 (tramp-shell-quote-argument localname)
2799 (tramp-get-ls-command vec)
2800 (tramp-get-remote-stat vec)
2801 (if (eq id-format 'integer) "%u" "\"%U\"")
2802 (if (eq id-format 'integer) "%g" "\"%G\""))))
c82c5727 2803
c62c9d08 2804;; This function should return "foo/" for directories and "bar" for
00d6fd04 2805;; files.
c62c9d08 2806(defun tramp-handle-file-name-all-completions (filename directory)
00d6fd04
MA
2807 "Like `file-name-all-completions' for Tramp files."
2808 (unless (save-match-data (string-match "/" filename))
9c13938d 2809 (with-parsed-tramp-file-name (expand-file-name directory) nil
b50dd0d2
MA
2810 ;; Flush the directory cache. There could be changed directory
2811 ;; contents.
2812 (when (and (integerp tramp-completion-reread-directory-timeout)
2813 (> (tramp-time-diff
2814 (current-time)
2815 (tramp-get-file-property
2816 v localname "last-completion" '(0 0 0)))
2817 tramp-completion-reread-directory-timeout))
2818 (tramp-flush-file-property v localname))
2819
00d6fd04
MA
2820 (all-completions
2821 filename
2822 (mapcar
2823 'list
2824 (with-file-property v localname "file-name-all-completions"
2825 (let (result)
2826 (tramp-barf-unless-okay
2827 v
2828 (format "cd %s" (tramp-shell-quote-argument localname))
2829 "tramp-handle-file-name-all-completions: Couldn't `cd %s'"
2830 (tramp-shell-quote-argument localname))
2831
2832 ;; Get a list of directories and files, including reliably
2833 ;; tagging the directories with a trailing '/'. Because I
2834 ;; rock. --daniel@danann.net
2835 (tramp-send-command
2836 v
2837 (format (concat "%s -ab 2>/dev/null | while read f; do "
2838 "if %s -d \"$f\" 2>/dev/null; "
2839 "then echo \"$f/\"; else echo \"$f\"; fi; done")
2840 (tramp-get-ls-command v)
2841 (tramp-get-test-command v)))
2842
2843 ;; Now grab the output.
2844 (with-current-buffer (tramp-get-buffer v)
2845 (goto-char (point-max))
2846 (while (zerop (forward-line -1))
9e6ab520
MA
2847 (push (buffer-substring
2848 (point) (tramp-compat-line-end-position))
00d6fd04
MA
2849 result)))
2850
b50dd0d2
MA
2851 (tramp-set-file-property
2852 v localname "last-completion" (current-time))
00d6fd04 2853 result)))))))
fb7933a3
KG
2854
2855;; The following isn't needed for Emacs 20 but for 19.34?
e1e17cae
MA
2856(defun tramp-handle-file-name-completion
2857 (filename directory &optional predicate)
00d6fd04 2858 "Like `file-name-completion' for Tramp files."
fb7933a3
KG
2859 (unless (tramp-tramp-file-p directory)
2860 (error
2861 "tramp-handle-file-name-completion invoked on non-tramp directory `%s'"
2862 directory))
83e20b5c
MA
2863 (try-completion
2864 filename
2865 (mapcar 'list (file-name-all-completions filename directory))
2866 (when predicate
2867 (lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
fb7933a3
KG
2868
2869;; cp, mv and ln
2870
2871(defun tramp-handle-add-name-to-file
2872 (filename newname &optional ok-if-already-exists)
00d6fd04
MA
2873 "Like `add-name-to-file' for Tramp files."
2874 (unless (tramp-equal-remote filename newname)
2875 (with-parsed-tramp-file-name
2876 (if (tramp-tramp-file-p filename) filename newname) nil
2877 (tramp-error
2878 v 'file-error
2879 "add-name-to-file: %s"
2880 "only implemented for same method, same user, same host")))
c62c9d08
KG
2881 (with-parsed-tramp-file-name filename v1
2882 (with-parsed-tramp-file-name newname v2
00d6fd04 2883 (let ((ln (when v1 (tramp-get-remote-ln v1))))
c62c9d08
KG
2884 (when (and (not ok-if-already-exists)
2885 (file-exists-p newname)
2886 (not (numberp ok-if-already-exists))
2887 (y-or-n-p
2888 (format
2889 "File %s already exists; make it a new name anyway? "
2890 newname)))
00d6fd04
MA
2891 (tramp-error
2892 v2 'file-error
2893 "add-name-to-file: file %s already exists" newname))
2894 (tramp-flush-file-property v2 v2-localname)
c62c9d08 2895 (tramp-barf-unless-okay
00d6fd04 2896 v1
7432277c
KG
2897 (format "%s %s %s" ln (tramp-shell-quote-argument v1-localname)
2898 (tramp-shell-quote-argument v2-localname))
c62c9d08
KG
2899 "error with add-name-to-file, see buffer `%s' for details"
2900 (buffer-name))))))
fb7933a3
KG
2901
2902(defun tramp-handle-copy-file
8d60099b 2903 (filename newname &optional ok-if-already-exists keep-date preserve-uid-gid)
00d6fd04 2904 "Like `copy-file' for Tramp files."
fb7933a3 2905 ;; Check if both files are local -- invoke normal copy-file.
9e6ab520 2906 ;; Otherwise, use Tramp from local system.
fb7933a3
KG
2907 (setq filename (expand-file-name filename))
2908 (setq newname (expand-file-name newname))
9e6ab520 2909 (cond
a4aeb9a4 2910 ;; At least one file a Tramp file?
9e6ab520
MA
2911 ((or (tramp-tramp-file-p filename)
2912 (tramp-tramp-file-p newname))
2913 (tramp-do-copy-or-rename-file
2914 'copy filename newname ok-if-already-exists keep-date preserve-uid-gid))
2915 ;; Compat section.
2916 (preserve-uid-gid
fb7933a3 2917 (tramp-run-real-handler
8d60099b 2918 'copy-file
9e6ab520
MA
2919 (list filename newname ok-if-already-exists keep-date preserve-uid-gid)))
2920 (t
2921 (tramp-run-real-handler
2922 'copy-file (list filename newname ok-if-already-exists keep-date)))))
fb7933a3
KG
2923
2924(defun tramp-handle-rename-file
2925 (filename newname &optional ok-if-already-exists)
00d6fd04 2926 "Like `rename-file' for Tramp files."
fb7933a3 2927 ;; Check if both files are local -- invoke normal rename-file.
a4aeb9a4 2928 ;; Otherwise, use Tramp from local system.
fb7933a3
KG
2929 (setq filename (expand-file-name filename))
2930 (setq newname (expand-file-name newname))
a4aeb9a4 2931 ;; At least one file a Tramp file?
fb7933a3
KG
2932 (if (or (tramp-tramp-file-p filename)
2933 (tramp-tramp-file-p newname))
2934 (tramp-do-copy-or-rename-file
8d60099b 2935 'rename filename newname ok-if-already-exists t t)
00d6fd04
MA
2936 (tramp-run-real-handler
2937 'rename-file (list filename newname ok-if-already-exists))))
fb7933a3
KG
2938
2939(defun tramp-do-copy-or-rename-file
8d60099b 2940 (op filename newname &optional ok-if-already-exists keep-date preserve-uid-gid)
fb7933a3
KG
2941 "Copy or rename a remote file.
2942OP must be `copy' or `rename' and indicates the operation to perform.
2943FILENAME specifies the file to copy or rename, NEWNAME is the name of
2944the new file (for copy) or the new name of the file (for rename).
2945OK-IF-ALREADY-EXISTS means don't barf if NEWNAME exists already.
2946KEEP-DATE means to make sure that NEWNAME has the same timestamp
8d60099b
MA
2947as FILENAME. PRESERVE-UID-GID, when non-nil, instructs to keep
2948the uid and gid if both files are on the same host.
fb7933a3
KG
2949
2950This function is invoked by `tramp-handle-copy-file' and
2951`tramp-handle-rename-file'. It is an error if OP is neither of `copy'
2952and `rename'. FILENAME and NEWNAME must be absolute file names."
2953 (unless (memq op '(copy rename))
2954 (error "Unknown operation `%s', must be `copy' or `rename'" op))
90dc758d 2955 (let ((t1 (tramp-tramp-file-p filename))
00d6fd04 2956 (t2 (tramp-tramp-file-p newname)))
5ec2cc41 2957
da1975d7
MA
2958 (when (and (not ok-if-already-exists) (file-exists-p newname))
2959 (with-parsed-tramp-file-name (if t1 filename newname) nil
2960 (tramp-error
2961 v 'file-already-exists "File %s already exists" newname)))
5ec2cc41 2962
00d6fd04
MA
2963 (prog1
2964 (cond
2965 ;; Both are Tramp files.
2966 ((and t1 t2)
2967 (with-parsed-tramp-file-name filename v1
2968 (with-parsed-tramp-file-name newname v2
2969 (cond
2970 ;; Shortcut: if method, host, user are the same for both
2971 ;; files, we invoke `cp' or `mv' on the remote host
2972 ;; directly.
2973 ((tramp-equal-remote filename newname)
2974 (tramp-do-copy-or-rename-file-directly
8d60099b
MA
2975 op filename newname
2976 ok-if-already-exists keep-date preserve-uid-gid))
2977
00d6fd04
MA
2978 ;; If both source and target are Tramp files,
2979 ;; both are using the same copy-program, then we
2980 ;; can invoke rcp directly. Note that
2981 ;; default-directory should point to a local
2982 ;; directory if we want to invoke rcp.
2983 ((and (equal v1-method v2-method)
2984 (tramp-method-out-of-band-p v1)
2985 (> (nth 7 (file-attributes filename))
2986 tramp-copy-size-limit))
2987 (tramp-do-copy-or-rename-file-out-of-band
2988 op filename newname keep-date))
8d60099b 2989
00d6fd04
MA
2990 ;; No shortcut was possible. So we copy the
2991 ;; file first. If the operation was `rename', we go
2992 ;; back and delete the original file (if the copy was
2993 ;; successful). The approach is simple-minded: we
2994 ;; create a new buffer, insert the contents of the
2995 ;; source file into it, then write out the buffer to
2996 ;; the target file. The advantage is that it doesn't
2997 ;; matter which filename handlers are used for the
2998 ;; source and target file.
2999 (t
3000 (tramp-do-copy-or-rename-file-via-buffer
3001 op filename newname keep-date))))))
3002
3003 ;; One file is a Tramp file, the other one is local.
3004 ((or t1 t2)
3005 (with-parsed-tramp-file-name (if t1 filename newname) nil
8d60099b
MA
3006 (cond
3007 ;; Fast track on local machine.
3008 ((tramp-local-host-p v)
3009 (tramp-do-copy-or-rename-file-directly
3010 op filename newname
3011 ok-if-already-exists keep-date preserve-uid-gid))
3012
3013 ;; If the Tramp file has an out-of-band method, the corresponding
3014 ;; copy-program can be invoked.
3015 ((and (tramp-method-out-of-band-p v)
3016 (> (nth 7 (file-attributes filename))
3017 tramp-copy-size-limit))
3018 (tramp-do-copy-or-rename-file-out-of-band
3019 op filename newname keep-date))
3020
3021 ;; Use the inline method via a Tramp buffer.
3022 (t (tramp-do-copy-or-rename-file-via-buffer
3023 op filename newname keep-date)))))
00d6fd04
MA
3024
3025 (t
3026 ;; One of them must be a Tramp file.
3027 (error "Tramp implementation says this cannot happen")))
8d60099b 3028
484ea0b6
MA
3029 ;; In case of `rename', we must flush the cache of the source file.
3030 (when (and t1 (eq op 'rename))
3031 (with-parsed-tramp-file-name filename nil
3032 (tramp-flush-file-property v localname)))
3033
00d6fd04
MA
3034 ;; When newname did exist, we have wrong cached values.
3035 (when t2
3036 (with-parsed-tramp-file-name newname nil
3037 (tramp-flush-file-property v localname))))))
7432277c 3038
38c65fca 3039(defun tramp-do-copy-or-rename-file-via-buffer (op filename newname keep-date)
90dc758d
KG
3040 "Use an Emacs buffer to copy or rename a file.
3041First arg OP is either `copy' or `rename' and indicates the operation.
3042FILENAME is the source file, NEWNAME the target file.
3043KEEP-DATE is non-nil if NEWNAME should have the same timestamp as FILENAME."
8a798e41
MA
3044 (with-temp-buffer
3045 ;; We must disable multibyte, because binary data shall not be
3046 ;; converted.
3047 (set-buffer-multibyte nil)
3048 (let ((coding-system-for-read 'binary)
3049 (jka-compr-inhibit t))
3050 (insert-file-contents-literally filename))
3051 ;; We don't want the target file to be compressed, so we let-bind
3052 ;; `jka-compr-inhibit' to t.
3053 (let ((coding-system-for-write 'binary)
3054 (jka-compr-inhibit t))
3055 (write-region (point-min) (point-max) newname)))
3056 ;; KEEP-DATE handling.
3057 (when keep-date (set-file-times newname (nth 5 (file-attributes filename))))
3058 ;; Set the mode.
3059 (set-file-modes newname (file-modes filename))
3060 ;; If the operation was `rename', delete the original file.
3061 (unless (eq op 'copy) (delete-file filename)))
fb7933a3
KG
3062
3063(defun tramp-do-copy-or-rename-file-directly
8d60099b 3064 (op filename newname ok-if-already-exists keep-date preserve-uid-gid)
fb7933a3
KG
3065 "Invokes `cp' or `mv' on the remote system.
3066OP must be one of `copy' or `rename', indicating `cp' or `mv',
8d60099b
MA
3067respectively. FILENAME specifies the file to copy or rename,
3068NEWNAME is the name of the new file (for copy) or the new name of
3069the file (for rename). Both files must reside on the same host.
3070KEEP-DATE means to make sure that NEWNAME has the same timestamp
3071as FILENAME. PRESERVE-UID-GID, when non-nil, instructs to keep
3072the uid and gid from FILENAME."
8a4438b6
MA
3073 (let ((t1 (tramp-tramp-file-p filename))
3074 (t2 (tramp-tramp-file-p newname)))
3075 (with-parsed-tramp-file-name (if t1 filename newname) nil
3076 (let* ((cmd (cond ((and (eq op 'copy) preserve-uid-gid) "cp -f -p")
3077 ((eq op 'copy) "cp -f")
3078 ((eq op 'rename) "mv -f")
3079 (t (tramp-error
3080 v 'file-error
3081 "Unknown operation `%s', must be `copy' or `rename'"
3082 op))))
3083 (localname1
3084 (if t1 (tramp-handle-file-remote-p filename 'localname) filename))
3085 (localname2
3086 (if t2 (tramp-handle-file-remote-p newname 'localname) newname))
258800f8 3087 (prefix (file-remote-p (if t1 filename newname))))
8d60099b 3088
8d60099b 3089 (cond
8a4438b6
MA
3090 ;; Both files are on a remote host, with same user.
3091 ((and t1 t2)
3092 (tramp-send-command
3093 v
3094 (format "%s %s %s" cmd
3095 (tramp-shell-quote-argument localname1)
3096 (tramp-shell-quote-argument localname2)))
3097 (with-current-buffer (tramp-get-buffer v)
3098 (goto-char (point-min))
3099 (unless
3100 (or
3101 (and keep-date
3102 ;; Mask cp -f error.
3103 (re-search-forward
3104 tramp-operation-not-permitted-regexp nil t))
3105 (zerop (tramp-send-command-and-check v nil)))
3106 (tramp-error-with-buffer
3107 nil v 'file-error
3108 "Copying directly failed, see buffer `%s' for details."
3109 (buffer-name)))))
3110
3111 ;; We are on the local host.
3112 ((or t1 t2)
8d60099b 3113 (cond
8a4438b6
MA
3114 ;; We can do it directly.
3115 ((and (file-readable-p localname1)
9c13938d
MA
3116 (file-writable-p (file-name-directory localname2))
3117 (or (file-directory-p localname2)
3118 (file-writable-p localname2)))
8d60099b 3119 (if (eq op 'copy)
9e6ab520
MA
3120 (tramp-compat-copy-file
3121 localname1 localname2 ok-if-already-exists
3122 keep-date preserve-uid-gid)
8a4438b6
MA
3123 (rename-file localname1 localname2 ok-if-already-exists)))
3124
3125 ;; We can do it directly with `tramp-send-command'
3126 ((and (file-readable-p (concat prefix localname1))
3127 (file-writable-p
3128 (file-name-directory (concat prefix localname2))))
3129 (tramp-do-copy-or-rename-file-directly
3130 op (concat prefix localname1) (concat prefix localname2)
3131 ok-if-already-exists keep-date t)
3132 ;; We must change the ownership to the local user.
8d60099b 3133 (tramp-set-file-uid-gid
8a4438b6
MA
3134 (concat prefix localname2)
3135 (tramp-get-local-uid 'integer)
3136 (tramp-get-local-gid 'integer)))
8d60099b 3137
8a4438b6
MA
3138 ;; We need a temporary file in between.
3139 (t
3140 ;; Create the temporary file.
258800f8
MA
3141 (let ((tmpfile (tramp-compat-make-temp-file localname1)))
3142 (cond
3143 (t1
3144 (tramp-send-command
3145 v (format
3146 "%s %s %s" cmd
3147 (tramp-shell-quote-argument localname1)
3148 (tramp-shell-quote-argument tmpfile)))
3149 ;; We must change the ownership as remote user.
3150 (tramp-set-file-uid-gid
3151 (concat prefix tmpfile)
3152 (tramp-get-local-uid 'integer)
3153 (tramp-get-local-gid 'integer)))
3154 (t2
3155 (if (eq op 'copy)
3156 (tramp-compat-copy-file
3157 localname1 tmpfile ok-if-already-exists
3158 keep-date preserve-uid-gid)
3159 (rename-file localname1 tmpfile ok-if-already-exists))
3160 ;; We must change the ownership as local user.
3161 (tramp-set-file-uid-gid
3162 tmpfile
3163 (tramp-get-remote-uid v 'integer)
3164 (tramp-get-remote-gid v 'integer))))
3165
3166 ;; Move the temporary file to its destination.
3167 (cond
3168 (t2
3169 (tramp-send-command
3170 v (format
3171 "mv -f %s %s"
3172 (tramp-shell-quote-argument tmpfile)
3173 (tramp-shell-quote-argument localname2))))
3174 (t1
3175 (rename-file tmpfile localname2 ok-if-already-exists)))))))))
8d60099b
MA
3176
3177 ;; Set the time and mode. Mask possible errors.
3178 ;; Won't be applied for 'rename.
3179 (condition-case nil
3180 (when (and keep-date (not preserve-uid-gid))
9e6ab520 3181 (set-file-times newname (nth 5 (file-attributes filename)))
8d60099b
MA
3182 (set-file-modes newname (file-modes filename)))
3183 (error)))))
3184
fb7933a3 3185
5ec2cc41 3186(defun tramp-do-copy-or-rename-file-out-of-band (op filename newname keep-date)
7432277c
KG
3187 "Invoke rcp program to copy.
3188One of FILENAME and NEWNAME must be a Tramp name, the other must
3189be a local filename. The method used must be an out-of-band method."
38c65fca 3190 (let ((t1 (tramp-tramp-file-p filename))
5ec2cc41 3191 (t2 (tramp-tramp-file-p newname))
00d6fd04
MA
3192 copy-program copy-args copy-keep-date port spec
3193 source target)
3194
3195 (with-parsed-tramp-file-name (if t1 filename newname) nil
3196
3197 ;; Expand hops. Might be necessary for gateway methods.
3198 (setq v (car (tramp-compute-multi-hops v)))
3199 (aset v 3 localname)
3200
3201 ;; Check which ones of source and target are Tramp files.
3202 (setq source (if t1 (tramp-make-copy-program-file-name v) filename)
3203 target (if t2 (tramp-make-copy-program-file-name v) newname))
3204
3205 ;; Check for port number. Until now, there's no need for handling
3206 ;; like method, user, host.
3207 (setq host (tramp-file-name-real-host v)
3208 port (tramp-file-name-port v)
3209 port (or (and port (number-to-string port)) ""))
3210
3211 ;; Compose copy command.
3212 (setq spec `((?h . ,host) (?u . ,user) (?p . ,port)
9c13938d
MA
3213 (?t . ,(tramp-get-connection-property
3214 (tramp-get-connection-process v) "temp-file" ""))
00d6fd04
MA
3215 (?k . ,(if keep-date " " "")))
3216 copy-program (tramp-get-method-parameter
3217 method 'tramp-copy-program)
3218 copy-keep-date (tramp-get-method-parameter
3219 method 'tramp-copy-keep-date)
3220 copy-args
3221 (delq
3222 nil
3223 (mapcar
3224 '(lambda (x)
3225 (setq
3226 ;; " " is indication for keep-date argument.
3227 x (delete " " (mapcar '(lambda (y) (format-spec y spec)) x)))
3228 (unless (member "" x) (mapconcat 'identity x " ")))
9c13938d 3229 (tramp-get-method-parameter method 'tramp-copy-args))))
c08e6004
MA
3230
3231 ;; Check for program.
3232 (when (and (fboundp 'executable-find)
00d6fd04 3233 (not (let ((default-directory
9e6ab520 3234 (tramp-compat-temporary-file-directory)))
00d6fd04
MA
3235 (executable-find copy-program))))
3236 (tramp-error
3237 v 'file-error "Cannot find copy program: %s" copy-program))
c08e6004 3238
00d6fd04 3239 (tramp-message v 0 "Transferring %s to %s..." filename newname)
38c65fca 3240
6b2633cc 3241 (unwind-protect
00d6fd04
MA
3242 (with-temp-buffer
3243 ;; The default directory must be remote.
3244 (let ((default-directory
3245 (file-name-directory (if t1 filename newname))))
3246 ;; Set the transfer process properties.
3247 (tramp-set-connection-property
3248 v "process-name" (buffer-name (current-buffer)))
3249 (tramp-set-connection-property
3250 v "process-buffer" (current-buffer))
3251
3252 ;; Use an asynchronous process. By this, password can
3253 ;; be handled. The default directory must be local, in
3254 ;; order to apply the correct `copy-program'. We don't
3255 ;; set a timeout, because the copying of large files can
3256 ;; last longer than 60 secs.
3257 (let ((p (let ((default-directory
9e6ab520 3258 (tramp-compat-temporary-file-directory)))
00d6fd04
MA
3259 (apply 'start-process
3260 (tramp-get-connection-property
3261 v "process-name" nil)
3262 (tramp-get-connection-property
3263 v "process-buffer" nil)
3264 copy-program
3265 (append copy-args (list source target))))))
3266 (tramp-message
3267 v 6 "%s" (mapconcat 'identity (process-command p) " "))
cfb5c0db 3268 (set-process-sentinel p 'tramp-process-sentinel)
00d6fd04
MA
3269 (tramp-set-process-query-on-exit-flag p nil)
3270 (tramp-process-actions p v tramp-actions-copy-out-of-band))))
3271
3272 ;; Reset the transfer process properties.
3273 (tramp-set-connection-property v "process-name" nil)
3274 (tramp-set-connection-property v "process-buffer" nil))
3275
3276 (tramp-message v 0 "Transferring %s to %s...done" filename newname)
3277
3278 ;; Handle KEEP-DATE argument.
9ce8462a 3279 (when (and keep-date (not copy-keep-date))
9e6ab520 3280 (set-file-times newname (nth 5 (file-attributes filename))))
01917a18
MA
3281
3282 ;; Set the mode.
00d6fd04 3283 (unless (and keep-date copy-keep-date)
01917a18 3284 (set-file-modes newname (file-modes filename))))
5ec2cc41
KG
3285
3286 ;; If the operation was `rename', delete the original file.
3287 (unless (eq op 'copy)
3288 (delete-file filename))))
7432277c 3289
fb7933a3 3290(defun tramp-handle-make-directory (dir &optional parents)
00d6fd04 3291 "Like `make-directory' for Tramp files."
ac474af1 3292 (setq dir (expand-file-name dir))
c62c9d08 3293 (with-parsed-tramp-file-name dir nil
b1d06e75
KG
3294 (save-excursion
3295 (tramp-barf-unless-okay
00d6fd04 3296 v
9c13938d 3297 (format "%s %s"
b1d06e75 3298 (if parents "mkdir -p" "mkdir")
7432277c 3299 (tramp-shell-quote-argument localname))
b1d06e75 3300 "Couldn't make directory %s" dir))))
fb7933a3 3301
fb7933a3 3302(defun tramp-handle-delete-directory (directory)
00d6fd04 3303 "Like `delete-directory' for Tramp files."
ac474af1 3304 (setq directory (expand-file-name directory))
c62c9d08 3305 (with-parsed-tramp-file-name directory nil
00d6fd04
MA
3306 (tramp-flush-directory-property v localname)
3307 (unless (zerop (tramp-send-command-and-check
3308 v
cfb5c0db 3309 (format "rmdir %s" (tramp-shell-quote-argument localname))))
00d6fd04 3310 (tramp-error v 'file-error "Couldn't delete %s" directory))))
fb7933a3
KG
3311
3312(defun tramp-handle-delete-file (filename)
00d6fd04 3313 "Like `delete-file' for Tramp files."
ac474af1 3314 (setq filename (expand-file-name filename))
c62c9d08 3315 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3316 (tramp-flush-file-property v localname)
3317 (unless (zerop (tramp-send-command-and-check
3318 v
3319 (format "rm -f %s"
3320 (tramp-shell-quote-argument localname))))
3321 (tramp-error v 'file-error "Couldn't delete %s" filename))))
fb7933a3
KG
3322
3323;; Dired.
3324
3325;; CCC: This does not seem to be enough. Something dies when
a4aeb9a4 3326;; we try and delete two directories under Tramp :/
fb7933a3
KG
3327(defun tramp-handle-dired-recursive-delete-directory (filename)
3328 "Recursively delete the directory given.
00d6fd04 3329This is like `dired-recursive-delete-directory' for Tramp files."
c62c9d08 3330 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3331 (tramp-flush-directory-property v filename)
3332 ;; Run a shell command 'rm -r <localname>'
fb7933a3 3333 ;; Code shamelessly stolen for the dired implementation and, um, hacked :)
00d6fd04
MA
3334 (unless (file-exists-p filename)
3335 (tramp-error v 'file-error "No such directory: %s" filename))
fb7933a3 3336 ;; Which is better, -r or -R? (-r works for me <daniel@danann.net>)
00d6fd04
MA
3337 (tramp-send-command
3338 v
9c13938d 3339 (format "rm -rf %s" (tramp-shell-quote-argument localname))
00d6fd04
MA
3340 ;; Don't read the output, do it explicitely.
3341 nil t)
fb7933a3
KG
3342 ;; Wait for the remote system to return to us...
3343 ;; This might take a while, allow it plenty of time.
00d6fd04 3344 (tramp-wait-for-output (tramp-get-connection-process v) 120)
fb7933a3 3345 ;; Make sure that it worked...
07dfe738 3346 (and (file-exists-p filename)
00d6fd04
MA
3347 (tramp-error
3348 v 'file-error "Failed to recursively delete %s" filename))))
bf247b6e 3349
5ec2cc41 3350(defun tramp-handle-dired-compress-file (file &rest ok-flag)
00d6fd04 3351 "Like `dired-compress-file' for Tramp files."
5ec2cc41
KG
3352 ;; OK-FLAG is valid for XEmacs only, but not implemented.
3353 ;; Code stolen mainly from dired-aux.el.
3354 (with-parsed-tramp-file-name file nil
00d6fd04 3355 (tramp-flush-file-property v localname)
5ec2cc41
KG
3356 (save-excursion
3357 (let ((suffixes
3358 (if (not (featurep 'xemacs))
3359 ;; Emacs case
3360 (symbol-value 'dired-compress-file-suffixes)
3361 ;; XEmacs has `dired-compression-method-alist', which is
3362 ;; transformed into `dired-compress-file-suffixes' structure.
3363 (mapcar
3364 '(lambda (x)
3365 (list (concat (regexp-quote (nth 1 x)) "\\'")
3366 nil
3367 (mapconcat 'identity (nth 3 x) " ")))
3368 (symbol-value 'dired-compression-method-alist))))
3369 suffix)
3370 ;; See if any suffix rule matches this file name.
3371 (while suffixes
3372 (let (case-fold-search)
3373 (if (string-match (car (car suffixes)) localname)
3374 (setq suffix (car suffixes) suffixes nil))
3375 (setq suffixes (cdr suffixes))))
3376
3377 (cond ((file-symlink-p file)
3378 nil)
3379 ((and suffix (nth 2 suffix))
3380 ;; We found an uncompression rule.
00d6fd04 3381 (tramp-message v 0 "Uncompressing %s..." file)
5ec2cc41 3382 (when (zerop (tramp-send-command-and-check
00d6fd04
MA
3383 v (concat (nth 2 suffix) " " localname)))
3384 (tramp-message v 0 "Uncompressing %s...done" file)
38c65fca
KG
3385 ;; `dired-remove-file' is not defined in XEmacs
3386 (funcall (symbol-function 'dired-remove-file) file)
5ec2cc41
KG
3387 (string-match (car suffix) file)
3388 (concat (substring file 0 (match-beginning 0)))))
3389 (t
3390 ;; We don't recognize the file as compressed, so compress it.
3391 ;; Try gzip.
00d6fd04 3392 (tramp-message v 0 "Compressing %s..." file)
5ec2cc41 3393 (when (zerop (tramp-send-command-and-check
00d6fd04
MA
3394 v (concat "gzip -f " localname)))
3395 (tramp-message v 0 "Compressing %s...done" file)
38c65fca
KG
3396 ;; `dired-remove-file' is not defined in XEmacs
3397 (funcall (symbol-function 'dired-remove-file) file)
5ec2cc41
KG
3398 (cond ((file-exists-p (concat file ".gz"))
3399 (concat file ".gz"))
3400 ((file-exists-p (concat file ".z"))
3401 (concat file ".z"))
3402 (t nil)))))))))
fb7933a3
KG
3403
3404;; Pacify byte-compiler. The function is needed on XEmacs only. I'm
3405;; not sure at all that this is the right way to do it, but let's hope
3406;; it works for now, and wait for a guru to point out the Right Way to
3407;; achieve this.
3408;;(eval-when-compile
3409;; (unless (fboundp 'dired-insert-set-properties)
3410;; (fset 'dired-insert-set-properties 'ignore)))
3411;; Gerd suggests this:
3412(eval-when-compile (require 'dired))
3413;; Note that dired is required at run-time, too, when it is needed.
3414;; It is only needed on XEmacs for the function
3415;; `dired-insert-set-properties'.
3416
3417(defun tramp-handle-insert-directory
3418 (filename switches &optional wildcard full-directory-p)
00d6fd04
MA
3419 "Like `insert-directory' for Tramp files."
3420 (setq filename (expand-file-name filename))
3421 (with-parsed-tramp-file-name filename nil
3422 (tramp-flush-file-property v localname)
3423 (if (and (featurep 'ls-lisp)
3424 (not (symbol-value 'ls-lisp-use-insert-directory-program)))
3425 (tramp-run-real-handler
3426 'insert-directory (list filename switches wildcard full-directory-p))
3427 ;; For the moment, we assume that the remote "ls" program does not
3428 ;; grok "--dired". In the future, we should detect this on
3429 ;; connection setup.
3430 (when (string-match "^--dired\\s-+" switches)
3431 (setq switches (replace-match "" nil t switches)))
3432 (tramp-message
3433 v 4 "Inserting directory `ls %s %s', wildcard %s, fulldir %s"
c82c5727
LH
3434 switches filename (if wildcard "yes" "no")
3435 (if full-directory-p "yes" "no"))
3436 (when wildcard
3437 (setq wildcard (file-name-nondirectory localname))
3438 (setq localname (file-name-directory localname)))
3439 (when (listp switches)
3440 (setq switches (mapconcat 'identity switches " ")))
3441 (unless full-directory-p
3442 (setq switches (concat "-d " switches)))
3443 (when wildcard
3444 (setq switches (concat switches " " wildcard)))
00d6fd04
MA
3445 ;; If `full-directory-p', we just say `ls -l FILENAME'.
3446 ;; Else we chdir to the parent directory, then say `ls -ld BASENAME'.
3447 (if full-directory-p
3448 (tramp-send-command
3449 v
3450 (format "%s %s %s"
3451 (tramp-get-ls-command v)
3452 switches
3453 (if wildcard
3454 localname
3455 (tramp-shell-quote-argument (concat localname ".")))))
3456 (tramp-barf-unless-okay
3457 v
3458 (format "cd %s" (tramp-shell-quote-argument
3459 (file-name-directory localname)))
3460 "Couldn't `cd %s'"
3461 (tramp-shell-quote-argument (file-name-directory localname)))
3462 (tramp-send-command
3463 v
3464 (format "%s %s %s"
3465 (tramp-get-ls-command v)
3466 switches
3467 (if (or wildcard
3468 (zerop (length (file-name-nondirectory localname))))
3469 ""
3470 (tramp-shell-quote-argument
3471 (file-name-nondirectory localname))))))
a4aeb9a4 3472 ;; We cannot use `insert-buffer-substring' because the Tramp buffer
00d6fd04
MA
3473 ;; changes its contents before insertion due to calling
3474 ;; `expand-file' and alike.
3475 (insert
3476 (with-current-buffer (tramp-get-buffer v)
3477 (buffer-string))))))
fb7933a3 3478
fb7933a3 3479(defun tramp-handle-unhandled-file-name-directory (filename)
00d6fd04 3480 "Like `unhandled-file-name-directory' for Tramp files."
8a798e41
MA
3481 ;; With Emacs 23, we could simply return `nil'. But we must keep it
3482 ;; for backward compatibility.
ce3f516f 3483 (expand-file-name "~/"))
fb7933a3
KG
3484
3485;; Canonicalization of file names.
3486
699a11fb
GM
3487(eval-and-compile ; silence compiler
3488 (if (memq system-type '(cygwin windows-nt))
3489 (defun tramp-drop-volume-letter (name)
3490 "Cut off unnecessary drive letter from file NAME.
fb7933a3
KG
3491The function `tramp-handle-expand-file-name' calls `expand-file-name'
3492locally on a remote file name. When the local system is a W32 system
3493but the remote system is Unix, this introduces a superfluous drive
57671b72 3494letter into the file name. This function removes it."
aff67808
MA
3495 (save-match-data
3496 (if (string-match tramp-root-regexp name)
3497 (replace-match "/" nil t name)
3498 name)))
fb7933a3 3499
699a11fb 3500 (defalias 'tramp-drop-volume-letter 'identity)))
fb7933a3
KG
3501
3502(defun tramp-handle-expand-file-name (name &optional dir)
00d6fd04 3503 "Like `expand-file-name' for Tramp files.
7432277c
KG
3504If the localname part of the given filename starts with \"/../\" then
3505the result will be a local, non-Tramp, filename."
fb7933a3
KG
3506 ;; If DIR is not given, use DEFAULT-DIRECTORY or "/".
3507 (setq dir (or dir default-directory "/"))
3508 ;; Unless NAME is absolute, concat DIR and NAME.
3509 (unless (file-name-absolute-p name)
3510 (setq name (concat (file-name-as-directory dir) name)))
00d6fd04 3511 ;; If NAME is not a Tramp file, run the real handler.
fb7933a3 3512 (if (not (tramp-tramp-file-p name))
00d6fd04 3513 (tramp-run-real-handler 'expand-file-name (list name nil))
fb7933a3 3514 ;; Dissect NAME.
c62c9d08 3515 (with-parsed-tramp-file-name name nil
7432277c
KG
3516 (unless (file-name-absolute-p localname)
3517 (setq localname (concat "~/" localname)))
00d6fd04
MA
3518 ;; Tilde expansion if necessary. This needs a shell which
3519 ;; groks tilde expansion! The function `tramp-find-shell' is
3520 ;; supposed to find such a shell on the remote host. Please
3521 ;; tell me about it when this doesn't work on your system.
3522 (when (string-match "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname)
3523 (let ((uname (match-string 1 localname))
3524 (fname (match-string 2 localname)))
3525 ;; We cannot simply apply "~/", because under sudo "~/" is
3526 ;; expanded to the local user home directory but to the
3527 ;; root home directory. On the other hand, using always
3528 ;; the default user name for tilde expansion is not
3529 ;; appropriate either, because ssh and companions might
3530 ;; use a user name from the config file.
3531 (when (and (string-equal uname "~")
3532 (string-match "\\`su\\(do\\)?\\'" method))
3533 (setq uname (concat uname user)))
3534 (setq uname
3535 (with-connection-property v uname
3536 (tramp-send-command v (format "cd %s; pwd" uname))
3537 (with-current-buffer (tramp-get-buffer v)
3538 (goto-char (point-min))
9e6ab520 3539 (buffer-substring (point) (tramp-compat-line-end-position)))))
00d6fd04
MA
3540 (setq localname (concat uname fname))))
3541 ;; There might be a double slash, for example when "~/"
3542 ;; expands to "/". Remove this.
3543 (while (string-match "//" localname)
3544 (setq localname (replace-match "/" t t localname)))
3545 ;; No tilde characters in file name, do normal
3546 ;; expand-file-name (this does "/./" and "/../"). We bind
3547 ;; `directory-sep-char' here for XEmacs on Windows, which
3548 ;; would otherwise use backslash. `default-directory' is
3549 ;; bound, because on Windows there would be problems with UNC
3550 ;; shares or Cygwin mounts.
aff67808
MA
3551 (let ((directory-sep-char ?/)
3552 (default-directory (tramp-compat-temporary-file-directory)))
3553 (tramp-make-tramp-file-name
3554 method user host
3555 (tramp-drop-volume-letter
3556 (tramp-run-real-handler 'expand-file-name
3557 (list localname))))))))
00d6fd04
MA
3558
3559(defun tramp-handle-substitute-in-file-name (filename)
3560 "Like `substitute-in-file-name' for Tramp files.
3561\"//\" and \"/~\" substitute only in the local filename part.
3562If the URL Tramp syntax is chosen, \"//\" as method delimeter and \"/~\" at
3563beginning of local filename are not substituted."
3564 (with-parsed-tramp-file-name filename nil
3565 (if (equal tramp-syntax 'url)
3566 ;; We need to check localname only. The other parts cannot contain
3567 ;; "//" or "/~".
3568 (if (and (> (length localname) 1)
3569 (or (string-match "//" localname)
3570 (string-match "/~" localname 1)))
3571 (tramp-run-real-handler 'substitute-in-file-name (list filename))
3572 (tramp-make-tramp-file-name
3573 (when method (substitute-in-file-name method))
3574 (when user (substitute-in-file-name user))
3575 (when host (substitute-in-file-name host))
3576 (when localname (substitute-in-file-name localname))))
3577 ;; Ignore in LOCALNAME everything before "//" or "/~".
3578 (when (and (stringp localname) (string-match ".+?/\\(/\\|~\\)" localname))
3579 (setq filename
b08104a0
MA
3580 (concat (file-remote-p filename)
3581 (replace-match "\\1" nil nil localname)))
00d6fd04
MA
3582 ;; "/m:h:~" does not work for completion. We use "/m:h:~/".
3583 (when (string-match "~$" filename)
3584 (setq filename (concat filename "/"))))
3585 (tramp-run-real-handler 'substitute-in-file-name (list filename)))))
3586
3587;; In XEmacs, electricity is implemented via a key map for ?/ and ?~,
3588;; which calls corresponding functions (see minibuf.el).
3589(when (fboundp 'minibuffer-electric-separator)
9e6ab520 3590 (mapc
00d6fd04
MA
3591 '(lambda (x)
3592 (eval
3593 `(defadvice ,x
3594 (around ,(intern (format "tramp-advice-%s" x)) activate)
3595 "Invoke `substitute-in-file-name' for Tramp files."
3596 (if (and (symbol-value 'minibuffer-electric-file-name-behavior)
3597 (tramp-tramp-file-p (buffer-substring)))
3598 ;; We don't need to handle `last-input-event', because
3599 ;; due to the key map we know it must be ?/ or ?~.
3600 (let ((s (concat (buffer-substring (point-min) (point))
3601 (string last-command-char))))
3602 (delete-region (point-min) (point))
3603 (insert (substitute-in-file-name s))
3604 (setq ad-return-value last-command-char))
3605 ad-do-it))))
3606
3607 '(minibuffer-electric-separator
3608 minibuffer-electric-tilde)))
3609
3610
0664ff72 3611;;; Remote commands:
fb7933a3 3612
00d6fd04
MA
3613(defun tramp-handle-executable-find (command)
3614 "Like `executable-find' for Tramp files."
3615 (with-parsed-tramp-file-name default-directory nil
f84638eb 3616 (tramp-find-executable v command (tramp-get-remote-path v) t)))
00d6fd04
MA
3617
3618;; We use BUFFER also as connection buffer during setup. Because of
3619;; this, its original contents must be saved, and restored once
3620;; connection has been setup.
3621(defun tramp-handle-start-file-process (name buffer program &rest args)
3622 "Like `start-file-process' for Tramp files."
3623 (with-parsed-tramp-file-name default-directory nil
3624 (unwind-protect
3625 (progn
3626 ;; Set the new process properties.
3627 (tramp-set-connection-property v "process-name" name)
3628 (tramp-set-connection-property
3629 v "process-buffer"
ce3f516f
MA
3630 ;; BUFFER can be nil.
3631 (get-buffer-create (or buffer (current-buffer))))
00d6fd04
MA
3632 ;; Activate narrowing in order to save BUFFER contents.
3633 (with-current-buffer (tramp-get-connection-buffer v)
3634 (narrow-to-region (point-max) (point-max)))
3635 ;; Goto working directory. `tramp-send-command' opens a new
3636 ;; connection.
3637 (tramp-send-command
3638 v (format "cd %s" (tramp-shell-quote-argument localname)))
3639 ;; Send the command.
3640 (tramp-send-command
3641 v
cfb5c0db 3642 (format "%s; echo %s; exit"
00d6fd04 3643 (mapconcat 'tramp-shell-quote-argument
cfb5c0db
MA
3644 (cons program args) " ")
3645 (tramp-shell-quote-argument tramp-end-of-output))
00d6fd04
MA
3646 nil t) ; nooutput
3647 ;; Return process.
3648 (tramp-get-connection-process v))
3649 ;; Save exit.
ce3f516f
MA
3650 (with-current-buffer (tramp-get-connection-buffer v)
3651 (widen)
3652 (goto-char (point-max)))
00d6fd04
MA
3653 (tramp-set-connection-property v "process-name" nil)
3654 (tramp-set-connection-property v "process-buffer" nil))))
3655
3656(defun tramp-handle-process-file
3657 (program &optional infile destination display &rest args)
3658 "Like `process-file' for Tramp files."
3659 ;; The implementation is not complete yet.
3660 (when (and (numberp destination) (zerop destination))
3661 (error "Implementation does not handle immediate return"))
3662
3663 (with-parsed-tramp-file-name default-directory nil
a6e96327 3664 (let (command input tmpinput stderr tmpstderr outbuf ret)
00d6fd04
MA
3665 ;; Compute command.
3666 (setq command (mapconcat 'tramp-shell-quote-argument
3667 (cons program args) " "))
3668 ;; Determine input.
3669 (if (null infile)
3670 (setq input "/dev/null")
3671 (setq infile (expand-file-name infile))
3672 (if (tramp-equal-remote default-directory infile)
3673 ;; INFILE is on the same remote host.
3674 (setq input (with-parsed-tramp-file-name infile nil localname))
3675 ;; INFILE must be copied to remote host.
a6e96327
MA
3676 (setq input (tramp-make-tramp-temp-file v)
3677 tmpinput (tramp-make-tramp-file-name method user host input))
3678 (copy-file infile tmpinput t)))
00d6fd04
MA
3679 (when input (setq command (format "%s <%s" command input)))
3680
3681 ;; Determine output.
3682 (cond
3683 ;; Just a buffer
3684 ((bufferp destination)
3685 (setq outbuf destination))
3686 ;; A buffer name
3687 ((stringp destination)
3688 (setq outbuf (get-buffer-create destination)))
3689 ;; (REAL-DESTINATION ERROR-DESTINATION)
3690 ((consp destination)
3691 ;; output
3692 (cond
3693 ((bufferp (car destination))
3694 (setq outbuf (car destination)))
3695 ((stringp (car destination))
0664ff72
MA
3696 (setq outbuf (get-buffer-create (car destination))))
3697 ((car destination)
3698 (setq outbuf (current-buffer))))
00d6fd04
MA
3699 ;; stderr
3700 (cond
3701 ((stringp (cadr destination))
3702 (setcar (cdr destination) (expand-file-name (cadr destination)))
3703 (if (tramp-equal-remote default-directory (cadr destination))
3704 ;; stderr is on the same remote host.
3705 (setq stderr (with-parsed-tramp-file-name
3706 (cadr destination) nil localname))
3707 ;; stderr must be copied to remote host. The temporary
3708 ;; file must be deleted after execution.
a6e96327
MA
3709 (setq stderr (tramp-make-tramp-temp-file v)
3710 tmpstderr (tramp-make-tramp-file-name
3711 method user host stderr))))
00d6fd04
MA
3712 ;; stderr to be discarded
3713 ((null (cadr destination))
3714 (setq stderr "/dev/null"))))
3715 ;; 't
3716 (destination
3717 (setq outbuf (current-buffer))))
3718 (when stderr (setq command (format "%s 2>%s" command stderr)))
3719
00d6fd04
MA
3720 ;; Goto working directory.
3721 (tramp-send-command
3722 v (format "cd %s" (tramp-shell-quote-argument localname)))
3723 ;; Send the command. It might not return in time, so we protect it.
3724 (condition-case nil
3725 (unwind-protect
3726 (tramp-send-command v command)
3727 ;; We should show the output anyway.
3728 (when outbuf
27e813fe
MA
3729 (let ((output-string
3730 (with-current-buffer (tramp-get-connection-buffer v)
3731 (buffer-substring (point-min) (point-max)))))
3732 (with-current-buffer outbuf
3733 (insert output-string)))
00d6fd04
MA
3734 (when display (display-buffer outbuf))))
3735 ;; When the user did interrupt, we should do it also.
3736 (error
3737 (kill-buffer (tramp-get-connection-buffer v))
3738 (setq ret 1)))
a6e96327
MA
3739
3740 ;; Check return code.
3741 (unless ret (setq ret (tramp-send-command-and-check v nil)))
3742 ;; Provide error file.
3743 (when tmpstderr (rename-file tmpstderr (cadr destination) t))
3744 ;; Cleanup.
3745 (when tmpinput (delete-file tmpinput))
00d6fd04
MA
3746 ;; Return exit status.
3747 ret)))
3748
a4aeb9a4
MA
3749(defun tramp-local-call-process
3750 (program &optional infile destination display &rest args)
3751 "Calls `call-process' on the local host.
3752This is needed because for some Emacs flavors Tramp has
3753defadviced `call-process' to behave like `process-file'. The
3754Lisp error raised when PROGRAM is nil is trapped also, returning 1."
3755 (let ((default-directory
3756 (if (file-remote-p default-directory)
3757 (tramp-compat-temporary-file-directory)
3758 default-directory)))
3759 (if (executable-find program)
3760 (apply 'call-process program infile destination display args)
3761 1)))
3762
00d6fd04
MA
3763(defun tramp-handle-call-process-region
3764 (start end program &optional delete buffer display &rest args)
3765 "Like `call-process-region' for Tramp files."
258800f8 3766 (let ((tmpfile (tramp-compat-make-temp-file "")))
00d6fd04
MA
3767 (write-region start end tmpfile)
3768 (when delete (delete-region start end))
3769 (unwind-protect
3770 (apply 'call-process program tmpfile buffer display args)
3771 (delete-file tmpfile))))
3772
3773(defun tramp-handle-shell-command
3774 (command &optional output-buffer error-buffer)
3775 "Like `shell-command' for Tramp files."
ce3f516f 3776 (let* ((asynchronous (string-match "[ \t]*&[ \t]*\\'" command))
b8bfcf96
MA
3777 ;; We cannot use `shell-file-name' and `shell-command-switch',
3778 ;; they are variables of the local host.
3779 (args (list "/bin/sh" "-c" (substring command 0 asynchronous)))
ce3f516f 3780 (output-buffer
27e813fe
MA
3781 (cond
3782 ((bufferp output-buffer) output-buffer)
3783 ((stringp output-buffer) (get-buffer-create output-buffer))
3784 (output-buffer (current-buffer))
42bc9b6d 3785 (t (get-buffer-create
27e813fe
MA
3786 (if asynchronous
3787 "*Async Shell Command*"
3788 "*Shell Command Output*")))))
3789 (error-buffer
3790 (cond
3791 ((bufferp error-buffer) error-buffer)
3792 ((stringp error-buffer) (get-buffer-create error-buffer))))
ce3f516f 3793 (buffer
27e813fe 3794 (if (and (not asynchronous) error-buffer)
ce3f516f
MA
3795 (with-parsed-tramp-file-name default-directory nil
3796 (list output-buffer (tramp-make-tramp-temp-file v)))
42bc9b6d 3797 output-buffer))
cfb5c0db 3798 (p (get-buffer-process output-buffer)))
42bc9b6d
MA
3799
3800 ;; Check whether there is another process running. Tramp does not
3801 ;; support 2 (asynchronous) processes in parallel.
cfb5c0db 3802 (when p
42bc9b6d 3803 (if (yes-or-no-p "A command is running. Kill it? ")
699a11fb
GM
3804 (condition-case nil
3805 (kill-process p)
3806 (error nil))
42bc9b6d
MA
3807 (error "Shell command in progress")))
3808
3809 (with-current-buffer output-buffer
3810 (setq buffer-read-only nil
3811 buffer-undo-list t)
3812 (erase-buffer))
3813
3814 (if (integerp asynchronous)
3815 (prog1
3816 ;; Run the process.
3412f35d 3817 (apply 'start-file-process "*Async Shell*" buffer args)
42bc9b6d 3818 ;; Display output.
cfb5c0db
MA
3819 (pop-to-buffer output-buffer)
3820 (setq mode-line-process '(":%s"))
3821 (require 'shell) (shell-mode))
42bc9b6d
MA
3822
3823 (prog1
3824 ;; Run the process.
3825 (apply 'process-file (car args) nil buffer nil (cdr args))
3826 ;; Insert error messages if they were separated.
3827 (when (listp buffer)
3828 (with-current-buffer error-buffer
3829 (insert-file-contents (cadr buffer)))
3830 (delete-file (cadr buffer)))
3831 ;; There's some output, display it.
3832 (when (with-current-buffer output-buffer (> (point-max) (point-min)))
3833 (if (functionp 'display-message-or-buffer)
3834 (funcall (symbol-function 'display-message-or-buffer)
3835 output-buffer)
3836 (pop-to-buffer output-buffer)))))))
00d6fd04
MA
3837
3838;; File Editing.
3839
3840(defvar tramp-handle-file-local-copy-hook nil
3841 "Normal hook to be run at the end of `tramp-handle-file-local-copy'.")
3842
fb7933a3 3843(defun tramp-handle-file-local-copy (filename)
00d6fd04 3844 "Like `file-local-copy' for Tramp files."
0f205eee 3845
c62c9d08 3846 (with-parsed-tramp-file-name filename nil
0f205eee 3847 (let ((rem-enc (tramp-get-remote-coding v "remote-encoding"))
00d6fd04 3848 (loc-dec (tramp-get-local-coding v "local-decoding"))
258800f8 3849 (tmpfile (tramp-compat-make-temp-file filename)))
c62c9d08 3850 (unless (file-exists-p filename)
00d6fd04
MA
3851 (tramp-error
3852 v 'file-error
3853 "Cannot make local copy of non-existing file `%s'" filename))
5ec2cc41 3854
0f205eee 3855 (cond
8d60099b
MA
3856 ;; `copy-file' handles direct copy and out-of-band methods.
3857 ((or (tramp-local-host-p v)
3858 (and (tramp-method-out-of-band-p v)
3859 (> (nth 7 (file-attributes filename)) tramp-copy-size-limit)))
94be87e8 3860 (copy-file filename tmpfile t t))
0f205eee
MA
3861
3862 ;; Use inline encoding for file transfer.
3863 (rem-enc
3864 (save-excursion
3865 (tramp-message v 5 "Encoding remote file %s..." filename)
3866 (tramp-barf-unless-okay
3867 v (format "%s < %s" rem-enc (tramp-shell-quote-argument localname))
3868 "Encoding remote file failed")
3869 (tramp-message v 5 "Encoding remote file %s...done" filename)
3870
3871 (tramp-message v 5 "Decoding remote file %s..." filename)
3872 (if (and (symbolp loc-dec) (fboundp loc-dec))
3873 ;; If local decoding is a function, we call it. We must
3874 ;; disable multibyte, because `uudecode-decode-region'
3875 ;; doesn't handle it correctly.
3876 (unwind-protect
3877 (with-temp-buffer
3878 (set-buffer-multibyte nil)
3879 (insert-buffer-substring (tramp-get-buffer v))
3880 (tramp-message
3881 v 5 "Decoding remote file %s with function %s..."
3882 filename loc-dec)
3883 (funcall loc-dec (point-min) (point-max))
3884 (let ((coding-system-for-write 'binary))
94be87e8 3885 (write-region (point-min) (point-max) tmpfile))))
0f205eee
MA
3886 ;; If tramp-decoding-function is not defined for this
3887 ;; method, we invoke tramp-decoding-command instead.
258800f8 3888 (let ((tmpfile2 (tramp-compat-make-temp-file filename)))
0f205eee 3889 (let ((coding-system-for-write 'binary))
94be87e8 3890 (write-region (point-min) (point-max) tmpfile2))
0f205eee
MA
3891 (tramp-message
3892 v 5 "Decoding remote file %s with command %s..."
3893 filename loc-dec)
94be87e8
MA
3894 (tramp-call-local-coding-command loc-dec tmpfile2 tmpfile)
3895 (delete-file tmpfile2)))
0f205eee
MA
3896 (tramp-message v 5 "Decoding remote file %s...done" filename)
3897 ;; Set proper permissions.
94be87e8 3898 (set-file-modes tmpfile (file-modes filename))
8d60099b 3899 ;; Set local user ownership.
94be87e8 3900 (tramp-set-file-uid-gid tmpfile)))
0f205eee
MA
3901
3902 ;; Oops, I don't know what to do.
3903 (t (tramp-error
3904 v 'file-error "Wrong method specification for `%s'" method)))
3905
00d6fd04 3906 (run-hooks 'tramp-handle-file-local-copy-hook)
94be87e8 3907 tmpfile)))
fb7933a3 3908
bce04fee 3909(defun tramp-handle-file-remote-p (filename &optional identification connected)
00d6fd04 3910 "Like `file-remote-p' for Tramp files."
15cc764c
KG
3911 (when (tramp-tramp-file-p filename)
3912 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
3913 (and (or (not connected)
3914 (let ((p (tramp-get-connection-process v)))
3915 (and p (processp p) (memq (process-status p) '(run open)))))
ce3f516f
MA
3916 (cond
3917 ((eq identification 'method) method)
3918 ((eq identification 'user) user)
3919 ((eq identification 'host) host)
8d60099b 3920 ((eq identification 'localname) localname)
ce3f516f 3921 (t (tramp-make-tramp-file-name method user host "")))))))
fb7933a3
KG
3922
3923(defun tramp-handle-insert-file-contents
3924 (filename &optional visit beg end replace)
00d6fd04 3925 "Like `insert-file-contents' for Tramp files."
fb7933a3
KG
3926 (barf-if-buffer-read-only)
3927 (setq filename (expand-file-name filename))
8d60099b
MA
3928 (let (coding-system-used result)
3929 (with-parsed-tramp-file-name filename nil
3930
3931 (if (not (file-exists-p filename))
3932 (progn
3933 (when visit
3934 (setq buffer-file-name filename)
3935 (set-visited-file-modtime)
3936 (set-buffer-modified-p nil))
9c13938d
MA
3937 ;; We don't raise a Tramp error, because it might be
3938 ;; suppressed, like in `find-file-noselect-1'.
3939 (signal 'file-error (list "File not found on remote host" filename))
8d60099b
MA
3940 (list (expand-file-name filename) 0))
3941
3942 (if (and (tramp-local-host-p v)
3943 (file-readable-p localname))
3944 ;; Short track: if we are on the local host, we can run directly.
94be87e8 3945 (setq result (insert-file-contents localname visit beg end replace))
8d60099b
MA
3946
3947 ;; `insert-file-contents-literally' takes care to avoid calling
3948 ;; jka-compr. By let-binding inhibit-file-name-operation, we
3949 ;; propagate that care to the file-local-copy operation.
3950 (let ((local-copy
3951 (let ((inhibit-file-name-operation
3952 (when (eq inhibit-file-name-operation
3953 'insert-file-contents)
3954 'file-local-copy)))
3955 (file-local-copy filename))))
3956 (tramp-message v 4 "Inserting local temp file `%s'..." local-copy)
3957 (setq result (insert-file-contents local-copy nil beg end replace))
3958 ;; Now `last-coding-system-used' has right value. Remember it.
3959 (when (boundp 'last-coding-system-used)
3960 (setq coding-system-used (symbol-value 'last-coding-system-used)))
3961 (tramp-message v 4 "Inserting local temp file `%s'...done" local-copy)
3962 (delete-file local-copy)
3963 (when (boundp 'last-coding-system-used)
3964 (set 'last-coding-system-used coding-system-used))))
3965
fb7933a3 3966 (when visit
8d60099b 3967 (setq buffer-read-only (file-writable-p filename))
fb7933a3
KG
3968 (setq buffer-file-name filename)
3969 (set-visited-file-modtime)
3970 (set-buffer-modified-p nil))
fb7933a3 3971 (list (expand-file-name filename)
f3c071dd 3972 (cadr result))))))
fb7933a3 3973
94be87e8
MA
3974;; This is needed for XEmacs only. Code stolen from files.el.
3975(defun tramp-handle-insert-file-contents-literally
3976 (filename &optional visit beg end replace)
3977 "Like `insert-file-contents-literally' for Tramp files."
3978 (let ((format-alist nil)
3979 (after-insert-file-functions nil)
3980 (coding-system-for-read 'no-conversion)
3981 (coding-system-for-write 'no-conversion)
3982 (find-buffer-file-type-function
3983 (if (fboundp 'find-buffer-file-type)
3984 (symbol-function 'find-buffer-file-type)
3985 nil))
3986 (inhibit-file-name-handlers '(jka-compr-handler image-file-handler))
3987 (inhibit-file-name-operation 'insert-file-contents))
3988 (unwind-protect
3989 (progn
3990 (fset 'find-buffer-file-type (lambda (filename) t))
3991 (insert-file-contents filename visit beg end replace))
3992 (if find-buffer-file-type-function
3993 (fset 'find-buffer-file-type find-buffer-file-type-function)
3994 (fmakunbound 'find-buffer-file-type)))))
3995
38c65fca 3996(defun tramp-handle-find-backup-file-name (filename)
00d6fd04 3997 "Like `find-backup-file-name' for Tramp files."
07dfe738
KG
3998 (with-parsed-tramp-file-name filename nil
3999 ;; We set both variables. It doesn't matter whether it is
4000 ;; Emacs or XEmacs
4001 (let ((backup-directory-alist
4002 ;; Emacs case
4003 (when (boundp 'backup-directory-alist)
4004 (if (boundp 'tramp-backup-directory-alist)
4005 (mapcar
4006 '(lambda (x)
4007 (cons
4008 (car x)
4009 (if (and (stringp (cdr x))
4010 (file-name-absolute-p (cdr x))
4011 (not (tramp-file-name-p (cdr x))))
00d6fd04 4012 (tramp-make-tramp-file-name method user host (cdr x))
07dfe738
KG
4013 (cdr x))))
4014 (symbol-value 'tramp-backup-directory-alist))
4015 (symbol-value 'backup-directory-alist))))
4016
4017 (bkup-backup-directory-info
4018 ;; XEmacs case
4019 (when (boundp 'bkup-backup-directory-info)
4020 (if (boundp 'tramp-bkup-backup-directory-info)
4021 (mapcar
4022 '(lambda (x)
4023 (nconc
4024 (list (car x))
4025 (list
4026 (if (and (stringp (car (cdr x)))
4027 (file-name-absolute-p (car (cdr x)))
4028 (not (tramp-file-name-p (car (cdr x)))))
4029 (tramp-make-tramp-file-name
00d6fd04 4030 method user host (car (cdr x)))
07dfe738
KG
4031 (car (cdr x))))
4032 (cdr (cdr x))))
4033 (symbol-value 'tramp-bkup-backup-directory-info))
4034 (symbol-value 'bkup-backup-directory-info)))))
4035
4036 (tramp-run-real-handler 'find-backup-file-name (list filename)))))
38c65fca 4037
c1105d05 4038(defun tramp-handle-make-auto-save-file-name ()
00d6fd04 4039 "Like `make-auto-save-file-name' for Tramp files.
c1105d05 4040Returns a file name in `tramp-auto-save-directory' for autosaving this file."
00d6fd04
MA
4041 (let ((tramp-auto-save-directory tramp-auto-save-directory)
4042 (buffer-file-name
4043 (tramp-subst-strs-in-string
4044 '(("_" . "|")
4045 ("/" . "_a")
4046 (":" . "_b")
4047 ("|" . "__")
4048 ("[" . "_l")
4049 ("]" . "_r"))
4050 (buffer-file-name))))
1a762140
MA
4051 ;; File name must be unique. This is ensured with Emacs 22 (see
4052 ;; UNIQUIFY element of `auto-save-file-name-transforms'); but for
4053 ;; all other cases we must do it ourselves.
4054 (when (boundp 'auto-save-file-name-transforms)
9e6ab520 4055 (mapc
1a762140
MA
4056 '(lambda (x)
4057 (when (and (string-match (car x) buffer-file-name)
4058 (not (car (cddr x))))
4059 (setq tramp-auto-save-directory
f3c071dd 4060 (or tramp-auto-save-directory
9e6ab520 4061 (tramp-compat-temporary-file-directory)))))
1a762140
MA
4062 (symbol-value 'auto-save-file-name-transforms)))
4063 ;; Create directory.
4064 (when tramp-auto-save-directory
00d6fd04
MA
4065 (setq buffer-file-name
4066 (expand-file-name buffer-file-name tramp-auto-save-directory))
1a762140
MA
4067 (unless (file-exists-p tramp-auto-save-directory)
4068 (make-directory tramp-auto-save-directory t)))
00d6fd04
MA
4069 ;; Run plain `make-auto-save-file-name'. There might be an advice when
4070 ;; it is not a magic file name operation (since Emacs 22).
4071 ;; We must deactivate it temporarily.
4072 (if (not (ad-is-active 'make-auto-save-file-name))
4073 (tramp-run-real-handler 'make-auto-save-file-name nil)
4074 ;; else
4075 (ad-deactivate 'make-auto-save-file-name)
4076 (prog1
4077 (tramp-run-real-handler 'make-auto-save-file-name nil)
4078 (ad-activate 'make-auto-save-file-name)))))
4079
4080(defvar tramp-handle-write-region-hook nil
4081 "Normal hook to be run at the end of `tramp-handle-write-region'.")
4082
4083;; CCC grok APPEND, LOCKNAME
fb7933a3
KG
4084(defun tramp-handle-write-region
4085 (start end filename &optional append visit lockname confirm)
00d6fd04 4086 "Like `write-region' for Tramp files."
fb7933a3 4087 (setq filename (expand-file-name filename))
c62c9d08 4088 (with-parsed-tramp-file-name filename nil
00d6fd04
MA
4089 (unless (null append)
4090 (tramp-error
4091 v 'file-error "Cannot append to file using Tramp (`%s')" filename))
4092 ;; Following part commented out because we don't know what to do about
4093 ;; file locking, and it does not appear to be a problem to ignore it.
4094 ;; Ange-ftp ignores it, too.
4095 ;; (when (and lockname (stringp lockname))
4096 ;; (setq lockname (expand-file-name lockname)))
4097 ;; (unless (or (eq lockname nil)
4098 ;; (string= lockname filename))
4099 ;; (error
4100 ;; "tramp-handle-write-region: LOCKNAME must be nil or equal FILENAME"))
8d60099b 4101
94be87e8 4102 ;; XEmacs takes a coding system as the seventh argument, not `confirm'.
00d6fd04
MA
4103 (when (and (not (featurep 'xemacs)) confirm (file-exists-p filename))
4104 (unless (y-or-n-p (format "File %s exists; overwrite anyway? " filename))
4105 (tramp-error v 'file-error "File not overwritten")))
8d60099b 4106
a4aeb9a4 4107 (let ((uid (or (nth 2 (tramp-compat-file-attributes filename 'integer))
9c13938d 4108 (tramp-get-remote-uid v 'integer)))
a4aeb9a4 4109 (gid (or (nth 3 (tramp-compat-file-attributes filename 'integer))
9c13938d
MA
4110 (tramp-get-remote-gid v 'integer))))
4111
4112 (if (and (tramp-local-host-p v)
4113 (file-writable-p (file-name-directory localname))
4114 (or (file-directory-p localname)
4115 (file-writable-p localname)))
4116 ;; Short track: if we are on the local host, we can run directly.
4117 (write-region start end localname append 'no-message lockname confirm)
4118
4119 (let ((rem-dec (tramp-get-remote-coding v "remote-decoding"))
4120 (loc-enc (tramp-get-local-coding v "local-encoding"))
4121 (modes (save-excursion (file-modes filename)))
4122 ;; We use this to save the value of
4123 ;; `last-coding-system-used' after writing the tmp file.
4124 ;; At the end of the function, we set
4125 ;; `last-coding-system-used' to this saved value. This
4126 ;; way, any intermediary coding systems used while
4127 ;; talking to the remote shell or suchlike won't hose
4128 ;; this variable. This approach was snarfed from
4129 ;; ange-ftp.el.
4130 coding-system-used
4131 ;; Write region into a tmp file. This isn't really
4132 ;; needed if we use an encoding function, but currently
4133 ;; we use it always because this makes the logic
4134 ;; simpler.
4135 (tmpfile (tramp-compat-make-temp-file filename)))
4136
4137 ;; We say `no-message' here because we don't want the
4138 ;; visited file modtime data to be clobbered from the temp
4139 ;; file. We call `set-visited-file-modtime' ourselves later
4140 ;; on.
4141 (tramp-run-real-handler
4142 'write-region
4143 (list start end tmpfile append 'no-message lockname confirm))
4144 ;; Now, `last-coding-system-used' has the right value. Remember it.
4145 (when (boundp 'last-coding-system-used)
4146 (setq coding-system-used (symbol-value 'last-coding-system-used)))
4147 ;; The permissions of the temporary file should be set. If
4148 ;; filename does not exist (eq modes nil) it has been
4149 ;; renamed to the backup file. This case `save-buffer'
4150 ;; handles permissions.
4151 (when modes (set-file-modes tmpfile modes))
4152
4153 ;; This is a bit lengthy due to the different methods
4154 ;; possible for file transfer. First, we check whether the
4155 ;; method uses an rcp program. If so, we call it.
4156 ;; Otherwise, both encoding and decoding command must be
4157 ;; specified. However, if the method _also_ specifies an
4158 ;; encoding function, then that is used for encoding the
4159 ;; contents of the tmp file.
4160 (cond
4161 ;; `rename-file' handles direct copy and out-of-band methods.
4162 ((or (tramp-local-host-p v)
4163 (and (tramp-method-out-of-band-p v)
4164 (integerp start)
4165 (> (- end start) tramp-copy-size-limit)))
4166 (rename-file tmpfile filename t))
4167
4168 ;; Use inline file transfer
4169 (rem-dec
4170 ;; Encode tmpfile
4171 (tramp-message v 5 "Encoding region...")
4172 (unwind-protect
4173 (with-temp-buffer
4174 ;; Use encoding function or command.
4175 (if (and (symbolp loc-enc) (fboundp loc-enc))
4176 (progn
4177 (tramp-message
4178 v 5 "Encoding region using function `%s'..."
4179 (symbol-name loc-enc))
4180 (let ((coding-system-for-read 'binary))
4181 (insert-file-contents-literally tmpfile))
4182 ;; CCC. The following `let' is a workaround
4183 ;; for the base64.el that comes with
4184 ;; pgnus-0.84. If both of the following
4185 ;; conditions are satisfied, it tries to write
4186 ;; to a local file in default-directory, but
4187 ;; at this point, default-directory is remote.
cfb5c0db 4188 ;; (`call-process-region' can't write to remote
9c13938d
MA
4189 ;; files, it seems.) The file in question is
4190 ;; a tmp file anyway.
4191 (let ((default-directory
4192 (tramp-compat-temporary-file-directory)))
4193 (funcall loc-enc (point-min) (point-max))))
8d60099b 4194
9c13938d
MA
4195 (tramp-message
4196 v 5 "Encoding region using command `%s'..." loc-enc)
4197 (unless (equal 0 (tramp-call-local-coding-command
4198 loc-enc tmpfile t))
4199 (tramp-error
4200 v 'file-error
4201 "Cannot write to `%s', local encoding command `%s' failed"
4202 filename loc-enc)))
4203
4204 ;; Send buffer into remote decoding command which
4205 ;; writes to remote file. Because this happens on
4206 ;; the remote host, we cannot use the function.
4207 (goto-char (point-max))
4208 (unless (bolp) (newline))
8d60099b 4209 (tramp-message
9c13938d
MA
4210 v 5 "Decoding region into remote file %s..." filename)
4211 (tramp-send-command
4212 v
4213 (format
4214 "%s >%s <<'EOF'\n%sEOF"
4215 rem-dec
4216 (tramp-shell-quote-argument localname)
4217 (buffer-string)))
4218 (tramp-barf-unless-okay
4219 v nil
4220 "Couldn't write region to `%s', decode using `%s' failed"
4221 filename rem-dec)
4222 ;; When `file-precious-flag' is set, the region is
4223 ;; written to a temporary file. Check that the
4224 ;; checksum is equal to that from the local tmpfile.
4225 (when file-precious-flag
4226 (erase-buffer)
4227 (and
a4aeb9a4
MA
4228 ;; cksum runs locally, if possible.
4229 (zerop (tramp-local-call-process "cksum" tmpfile t))
4230 ;; cksum runs remotely.
9c13938d
MA
4231 (zerop
4232 (tramp-send-command-and-check
4233 v
4234 (format
4235 "cksum <%s" (tramp-shell-quote-argument localname))))
a4aeb9a4 4236 ;; ... they are different.
9c13938d
MA
4237 (not
4238 (string-equal
4239 (buffer-string)
4240 (with-current-buffer (tramp-get-buffer v)
4241 (buffer-string))))
4242 (tramp-error
4243 v 'file-error
4244 (concat "Couldn't write region to `%s',"
4245 " decode using `%s' failed")
4246 filename rem-dec)))
4247 (tramp-message
4248 v 5 "Decoding region into remote file %s...done" filename)
4249 (tramp-flush-file-property v localname))
8d60099b 4250
9c13938d
MA
4251 ;; Save exit.
4252 (delete-file tmpfile)))
8d60099b 4253
9c13938d
MA
4254 ;; That's not expected.
4255 (t
4256 (tramp-error
4257 v 'file-error
4258 (concat "Method `%s' should specify both encoding and "
4259 "decoding command or an rcp program")
4260 method)))
258800f8 4261
9c13938d
MA
4262 ;; Make `last-coding-system-used' have the right value.
4263 (when coding-system-used
4264 (set 'last-coding-system-used coding-system-used))))
0f205eee 4265
57671b72
MA
4266 ;; We must protect `last-coding-system-used', now we have set it
4267 ;; to its correct value.
4268 (let (last-coding-system-used)
4269 ;; Set file modification time.
4270 (when (or (eq visit t) (stringp visit))
4271 (set-visited-file-modtime
4272 ;; We must pass modtime explicitely, because filename can
4273 ;; be different from (buffer-file-name), f.e. if
4274 ;; `file-precious-flag' is set.
4275 (nth 5 (file-attributes filename))))
4276
4277 ;; Set the ownership.
4278 (tramp-set-file-uid-gid filename uid gid)
4279 (when (or (eq visit t) (null visit) (stringp visit))
4280 (tramp-message v 0 "Wrote %s" filename))
4281 (run-hooks 'tramp-handle-write-region-hook)))))
fb7933a3 4282
a01b1e22
MA
4283;;;###autoload
4284(progn (defun tramp-run-real-handler (operation args)
fb7933a3 4285 "Invoke normal file name handler for OPERATION.
c62c9d08
KG
4286First arg specifies the OPERATION, second arg is a list of arguments to
4287pass to the OPERATION."
4007ba5b
KG
4288 (let* ((inhibit-file-name-handlers
4289 `(tramp-file-name-handler
4290 tramp-completion-file-name-handler
4291 cygwin-mount-name-hook-function
4292 cygwin-mount-map-drive-hook-function
4293 .
4294 ,(and (eq inhibit-file-name-operation operation)
4295 inhibit-file-name-handlers)))
4296 (inhibit-file-name-operation operation))
a01b1e22 4297 (apply operation args))))
16674e4f 4298
a01b1e22
MA
4299;;;###autoload
4300(progn (defun tramp-completion-run-real-handler (operation args)
16674e4f
KG
4301 "Invoke `tramp-file-name-handler' for OPERATION.
4302First arg specifies the OPERATION, second arg is a list of arguments to
4303pass to the OPERATION."
4007ba5b
KG
4304 (let* ((inhibit-file-name-handlers
4305 `(tramp-completion-file-name-handler
4306 cygwin-mount-name-hook-function
4307 cygwin-mount-map-drive-hook-function
4308 .
4309 ,(and (eq inhibit-file-name-operation operation)
4310 inhibit-file-name-handlers)))
4311 (inhibit-file-name-operation operation))
a01b1e22 4312 (apply operation args))))
fb7933a3 4313
4007ba5b
KG
4314;; We handle here all file primitives. Most of them have the file
4315;; name as first parameter; nevertheless we check for them explicitly
19a87064 4316;; in order to be signalled if a new primitive appears. This
4007ba5b
KG
4317;; scenario is needed because there isn't a way to decide by
4318;; syntactical means whether a foreign method must be called. It would
19a87064 4319;; ease the life if `file-name-handler-alist' would support a decision
4007ba5b
KG
4320;; function as well but regexp only.
4321(defun tramp-file-name-for-operation (operation &rest args)
4322 "Return file name related to OPERATION file primitive.
4323ARGS are the arguments OPERATION has been called with."
4324 (cond
4325 ; FILE resp DIRECTORY
4326 ((member operation
4327 (list 'access-file 'byte-compiler-base-file-name 'delete-directory
4328 'delete-file 'diff-latest-backup-file 'directory-file-name
4329 'directory-files 'directory-files-and-attributes
4330 'dired-compress-file 'dired-uncache
4331 'file-accessible-directory-p 'file-attributes
4332 'file-directory-p 'file-executable-p 'file-exists-p
19a87064
MA
4333 'file-local-copy 'file-remote-p 'file-modes
4334 'file-name-as-directory 'file-name-directory
4335 'file-name-nondirectory 'file-name-sans-versions
4336 'file-ownership-preserved-p 'file-readable-p
4337 'file-regular-p 'file-symlink-p 'file-truename
4338 'file-writable-p 'find-backup-file-name 'find-file-noselect
4339 'get-file-buffer 'insert-directory 'insert-file-contents
4340 'load 'make-directory 'make-directory-internal
4341 'set-file-modes 'substitute-in-file-name
4342 'unhandled-file-name-directory 'vc-registered
ce3f516f
MA
4343 ; Emacs 22 only
4344 'set-file-times
4007ba5b
KG
4345 ; XEmacs only
4346 'abbreviate-file-name 'create-file-buffer
4347 'dired-file-modtime 'dired-make-compressed-filename
4348 'dired-recursive-delete-directory 'dired-set-file-modtime
4349 'dired-shell-unhandle-file-name 'dired-uucode-file
4350 'insert-file-contents-literally 'recover-file
4351 'vm-imap-check-mail 'vm-pop-check-mail 'vm-spool-check-mail))
8daea7fc
KG
4352 (if (file-name-absolute-p (nth 0 args))
4353 (nth 0 args)
4354 (expand-file-name (nth 0 args))))
4007ba5b
KG
4355 ; FILE DIRECTORY resp FILE1 FILE2
4356 ((member operation
4357 (list 'add-name-to-file 'copy-file 'expand-file-name
4358 'file-name-all-completions 'file-name-completion
4359 'file-newer-than-file-p 'make-symbolic-link 'rename-file
4360 ; XEmacs only
4361 'dired-make-relative-symlink
4362 'vm-imap-move-mail 'vm-pop-move-mail 'vm-spool-move-mail))
4363 (save-match-data
4364 (cond
4365 ((string-match tramp-file-name-regexp (nth 0 args)) (nth 0 args))
4366 ((string-match tramp-file-name-regexp (nth 1 args)) (nth 1 args))
4367 (t (buffer-file-name (current-buffer))))))
4368 ; START END FILE
4369 ((eq operation 'write-region)
4370 (nth 2 args))
4371 ; BUF
4372 ((member operation
00d6fd04 4373 (list 'set-visited-file-modtime 'verify-visited-file-modtime
b50dd0d2 4374 ; since Emacs 22 only
00d6fd04
MA
4375 'make-auto-save-file-name
4376 ; XEmacs only
4007ba5b
KG
4377 'backup-buffer))
4378 (buffer-file-name
4379 (if (bufferp (nth 0 args)) (nth 0 args) (current-buffer))))
4380 ; COMMAND
4381 ((member operation
00d6fd04
MA
4382 (list ; not in Emacs 23
4383 'dired-call-process
01917a18 4384 ; Emacs only
b71c9e75 4385 'shell-command
00d6fd04 4386 ; since Emacs 22 only
0457dd55 4387 'process-file
00d6fd04
MA
4388 ; since Emacs 23 only
4389 'start-file-process
4007ba5b 4390 ; XEmacs only
00d6fd04
MA
4391 'dired-print-file 'dired-shell-call-process
4392 ; nowhere yet
4393 'executable-find 'start-process 'call-process))
4007ba5b
KG
4394 default-directory)
4395 ; unknown file primitive
4396 (t (error "unknown file I/O primitive: %s" operation))))
4397
4398(defun tramp-find-foreign-file-name-handler (filename)
4399 "Return foreign file name handler if exists."
9ce8462a
MA
4400 (when (and (stringp filename) (tramp-tramp-file-p filename))
4401 (let ((v (tramp-dissect-file-name filename t))
4402 (handler tramp-foreign-file-name-handler-alist)
4403 elt res)
4404 ;; When we are not fully sure that filename completion is safe,
4405 ;; we should not return a handler.
4406 (when (or (tramp-file-name-method v) (tramp-file-name-user v)
1834b39f
MA
4407 (and (tramp-file-name-host v)
4408 (not (member (tramp-file-name-host v)
4409 (mapcar 'car tramp-methods))))
9ce8462a
MA
4410 (not (tramp-completion-mode-p)))
4411 (while handler
4412 (setq elt (car handler)
4413 handler (cdr handler))
4414 (when (funcall (car elt) filename)
4415 (setq handler nil
4416 res (cdr elt))))
4417 res))))
4007ba5b 4418
fb7933a3
KG
4419;; Main function.
4420;;;###autoload
4421(defun tramp-file-name-handler (operation &rest args)
ea9d1443 4422 "Invoke Tramp file name handler.
a4aeb9a4 4423Falls back to normal file name handler if no Tramp file name handler exists."
4007ba5b 4424 (save-match-data
ea9d1443 4425 (let* ((filename (apply 'tramp-file-name-for-operation operation args))
6c4e47fa 4426 (completion (tramp-completion-mode-p))
e762677c 4427 (foreign (tramp-find-foreign-file-name-handler filename)))
a01b1e22
MA
4428 (with-parsed-tramp-file-name filename nil
4429 (cond
00d6fd04 4430 ;; When we are in completion mode, some operations shouldn't be
a01b1e22 4431 ;; handled by backend.
a01b1e22
MA
4432 ((and completion (zerop (length localname))
4433 (memq operation '(file-exists-p file-directory-p)))
4434 t)
00d6fd04
MA
4435 ((and completion (zerop (length localname))
4436 (memq operation '(file-name-as-directory)))
4437 filename)
8a4438b6 4438 ;; Call the backend function.
0f205eee 4439 (foreign (apply foreign operation args))
a01b1e22
MA
4440 ;; Nothing to do for us.
4441 (t (tramp-run-real-handler operation args)))))))
fb7933a3 4442
07dfe738
KG
4443;; In Emacs, there is some concurrency due to timers. If a timer
4444;; interrupts Tramp and wishes to use the same connection buffer as
4445;; the "main" Emacs, then garbage might occur in the connection
4446;; buffer. Therefore, we need to make sure that a timer does not use
4447;; the same connection buffer as the "main" Emacs. We implement a
4448;; cheap global lock, instead of locking each connection buffer
4449;; separately. The global lock is based on two variables,
4450;; `tramp-locked' and `tramp-locker'. `tramp-locked' is set to true
4451;; (with setq) to indicate a lock. But Tramp also calls itself during
4452;; processing of a single file operation, so we need to allow
4453;; recursive calls. That's where the `tramp-locker' variable comes in
4454;; -- it is let-bound to t during the execution of the current
4455;; handler. So if `tramp-locked' is t and `tramp-locker' is also t,
4456;; then we should just proceed because we have been called
4457;; recursively. But if `tramp-locker' is nil, then we are a timer
4458;; interrupting the "main" Emacs, and then we signal an error.
4459
4460(defvar tramp-locked nil
4461 "If non-nil, then Tramp is currently busy.
4462Together with `tramp-locker', this implements a locking mechanism
4463preventing reentrant calls of Tramp.")
4464
4465(defvar tramp-locker nil
4466 "If non-nil, then a caller has locked Tramp.
4467Together with `tramp-locked', this implements a locking mechanism
4468preventing reentrant calls of Tramp.")
4469
ea9d1443
KG
4470(defun tramp-sh-file-name-handler (operation &rest args)
4471 "Invoke remote-shell Tramp file name handler.
4472Fall back to normal file name handler if no Tramp handler exists."
07dfe738 4473 (when (and tramp-locked (not tramp-locker))
00d6fd04 4474 (signal 'file-error (list "Forbidden reentrant call of Tramp")))
07dfe738
KG
4475 (let ((tl tramp-locked))
4476 (unwind-protect
4477 (progn
4478 (setq tramp-locked t)
4479 (let ((tramp-locker t))
4480 (save-match-data
4481 (let ((fn (assoc operation tramp-file-name-handler-alist)))
4482 (if fn
4483 (apply (cdr fn) args)
4484 (tramp-run-real-handler operation args))))))
4485 (setq tramp-locked tl))))
ea9d1443 4486
16674e4f 4487;;;###autoload
1ecc6145 4488(progn (defun tramp-completion-file-name-handler (operation &rest args)
a4aeb9a4
MA
4489 "Invoke Tramp file name completion handler.
4490Falls back to normal file name handler if no Tramp file name handler exists."
57671b72
MA
4491 ;; We bind `directory-sep-char' here for XEmacs on Windows, which
4492 ;; would otherwise use backslash.
aff67808
MA
4493 (let ((directory-sep-char ?/)
4494 (fn (assoc operation tramp-completion-file-name-handler-alist)))
4495 (if fn
4496 (save-match-data (apply (cdr fn) args))
4497 (tramp-completion-run-real-handler operation args)))))
a01b1e22 4498
b25a52cc 4499;;;###autoload
69cee873 4500(defsubst tramp-register-file-name-handler ()
a4aeb9a4 4501 "Add Tramp file name handler to `file-name-handler-alist'."
00d6fd04
MA
4502 ;; Remove autoloaded handler from file name handler alist. Useful,
4503 ;; if `tramp-syntax' has been changed.
4504 (let ((a1 (rassq 'tramp-file-name-handler file-name-handler-alist)))
4505 (setq file-name-handler-alist (delete a1 file-name-handler-alist)))
4506 ;; Add the handler.
a01b1e22
MA
4507 (add-to-list 'file-name-handler-alist
4508 (cons tramp-file-name-regexp 'tramp-file-name-handler))
69cee873
MA
4509 ;; If jka-compr is already loaded, move it to the front of
4510 ;; `file-name-handler-alist'.
4511 (let ((jka (rassoc 'jka-compr-handler file-name-handler-alist)))
4512 (when jka
4513 (setq file-name-handler-alist
4514 (cons jka (delete jka file-name-handler-alist))))))
4515
00d6fd04
MA
4516;; `tramp-file-name-handler' must be registered before evaluation of
4517;; site-start and init files, because there might exist remote files
4518;; already, f.e. files kept via recentf-mode.
4519;;;###autoload(tramp-register-file-name-handler)
4520(tramp-register-file-name-handler)
4521
69cee873
MA
4522;;;###autoload
4523(defsubst tramp-register-completion-file-name-handler ()
a4aeb9a4 4524 "Add Tramp completion file name handler to `file-name-handler-alist'."
00d6fd04
MA
4525 ;; Remove autoloaded handler from file name handler alist. Useful,
4526 ;; if `tramp-syntax' has been changed.
4527 (let ((a1 (rassq
4528 'tramp-completion-file-name-handler file-name-handler-alist)))
4529 (setq file-name-handler-alist (delete a1 file-name-handler-alist)))
1a762140
MA
4530 ;; `partial-completion-mode' is unknown in XEmacs. So we should
4531 ;; load it unconditionally there. In the GNU Emacs case, method/
4532 ;; user/host name completion shall be bound to `partial-completion-mode'.
9e6ab520
MA
4533 ;; `ido-mode' and `icy-mode' are other packages which extend file
4534 ;; name completion.
1a762140
MA
4535 (when (or (not (boundp 'partial-completion-mode))
4536 (symbol-value 'partial-completion-mode)
9e6ab520
MA
4537 (featurep 'ido)
4538 (featurep 'icicles))
8c04e197
MA
4539 (add-to-list 'file-name-handler-alist
4540 (cons tramp-completion-file-name-regexp
4541 'tramp-completion-file-name-handler))
a01b1e22
MA
4542 (put 'tramp-completion-file-name-handler 'safe-magic t))
4543 ;; If jka-compr is already loaded, move it to the front of
4544 ;; `file-name-handler-alist'.
4545 (let ((jka (rassoc 'jka-compr-handler file-name-handler-alist)))
4546 (when jka
4547 (setq file-name-handler-alist
4548 (cons jka (delete jka file-name-handler-alist))))))
4549
4550;; During autoload, it shall be checked whether
69cee873
MA
4551;; `partial-completion-mode' is active. Therefore registering of
4552;; `tramp-completion-file-name-handler' will be delayed.
8c04e197 4553;;;###autoload(add-hook
1ecc6145 4554;;;###autoload 'after-init-hook
69cee873 4555;;;###autoload '(lambda () (tramp-register-completion-file-name-handler)))
69cee873 4556(tramp-register-completion-file-name-handler)
b25a52cc 4557
fb7933a3 4558;;;###autoload
8c04e197 4559(defun tramp-unload-file-name-handlers ()
a69c01a0
MA
4560 (setq file-name-handler-alist
4561 (delete (rassoc 'tramp-file-name-handler
4562 file-name-handler-alist)
4563 (delete (rassoc 'tramp-completion-file-name-handler
4564 file-name-handler-alist)
4565 file-name-handler-alist))))
4566
8c04e197 4567(add-hook 'tramp-unload-hook 'tramp-unload-file-name-handlers)
a69c01a0 4568
0664ff72 4569;;; File name handler functions for completion mode:
a6e96327
MA
4570
4571(defvar tramp-completion-mode nil
4572 "If non-nil, external packages signal that they are in file name completion.
4573
4574This is necessary, because Tramp uses a heuristic depending on last
4575input event. This fails when external packages use other characters
4576but <TAB>, <SPACE> or ?\\? for file name completion. This variable
4577should never be set globally, the intention is to let-bind it.")
16674e4f
KG
4578
4579;; Necessary because `tramp-file-name-regexp-unified' and
00d6fd04
MA
4580;; `tramp-completion-file-name-regexp-unified' aren't different. If
4581;; nil, `tramp-completion-run-real-handler' is called (i.e. forwarding
4582;; to `tramp-file-name-handler'). Otherwise, it takes
4583;; `tramp-run-real-handler'. Using `last-input-event' is a little bit
4584;; risky, because completing a file might require loading other files,
4585;; like "~/.netrc", and for them it shouldn't be decided based on that
4586;; variable. On the other hand, those files shouldn't have partial
a4aeb9a4
MA
4587;; Tramp file name syntax. Maybe another variable should be introduced
4588;; overwriting this check in such cases. Or we change Tramp file name
00d6fd04 4589;; syntax in order to avoid ambiguities, like in XEmacs ...
6c4e47fa 4590(defun tramp-completion-mode-p ()
16674e4f 4591 "Checks whether method / user name / host name completion is active."
6c4e47fa 4592 (or
a6e96327
MA
4593 ;; Signal from outside.
4594 tramp-completion-mode
4595 ;; Emacs.
94be87e8 4596 (equal last-input-event 'tab)
6c4e47fa 4597 (and (natnump last-input-event)
94be87e8 4598 (or
a6e96327 4599 ;; ?\t has event-modifier 'control.
800a97b8 4600 (equal last-input-event ?\t)
94be87e8 4601 (and (not (event-modifiers last-input-event))
800a97b8
SM
4602 (or (equal last-input-event ?\?)
4603 (equal last-input-event ?\ )))))
a6e96327 4604 ;; XEmacs.
6c4e47fa
MA
4605 (and (featurep 'xemacs)
4606 ;; `last-input-event' might be nil.
4607 (not (null last-input-event))
4608 ;; `last-input-event' may have no character approximation.
4609 (funcall (symbol-function 'event-to-character) last-input-event)
94be87e8 4610 (or
a6e96327 4611 ;; ?\t has event-modifier 'control.
800a97b8 4612 (equal
94be87e8
MA
4613 (funcall (symbol-function 'event-to-character)
4614 last-input-event) ?\t)
4615 (and (not (event-modifiers last-input-event))
800a97b8 4616 (or (equal
94be87e8
MA
4617 (funcall (symbol-function 'event-to-character)
4618 last-input-event) ?\?)
800a97b8 4619 (equal
94be87e8
MA
4620 (funcall (symbol-function 'event-to-character)
4621 last-input-event) ?\ )))))))
16674e4f 4622
16674e4f
KG
4623;; Method, host name and user name completion.
4624;; `tramp-completion-dissect-file-name' returns a list of
4625;; tramp-file-name structures. For all of them we return possible completions.
a01b1e22 4626;;;###autoload
16674e4f 4627(defun tramp-completion-handle-file-name-all-completions (filename directory)
00d6fd04 4628 "Like `file-name-all-completions' for partial Tramp files."
16674e4f 4629
00d6fd04
MA
4630 (let* ((fullname (tramp-drop-volume-letter
4631 (expand-file-name filename directory)))
4632 ;; Possible completion structures.
4633 (v (tramp-completion-dissect-file-name fullname))
4634 result result1)
4635
4636 (while v
4637 (let* ((car (car v))
4638 (method (tramp-file-name-method car))
4639 (user (tramp-file-name-user car))
4640 (host (tramp-file-name-host car))
4641 (localname (tramp-file-name-localname car))
4642 (m (tramp-find-method method user host))
4643 (tramp-current-user user) ; see `tramp-parse-passwd'
4644 all-user-hosts)
4645
4646 (unless localname ;; Nothing to complete.
4647
4648 (if (or user host)
4649
4650 ;; Method dependent user / host combinations.
4651 (progn
9e6ab520 4652 (mapc
00d6fd04
MA
4653 (lambda (x)
4654 (setq all-user-hosts
4655 (append all-user-hosts
4656 (funcall (nth 0 x) (nth 1 x)))))
4657 (tramp-get-completion-function m))
4658
9e6ab520
MA
4659 (setq result
4660 (append result
4661 (mapcar
4662 (lambda (x)
4663 (tramp-get-completion-user-host
4664 method user host (nth 0 x) (nth 1 x)))
4665 (delq nil all-user-hosts)))))
00d6fd04
MA
4666
4667 ;; Possible methods.
4668 (setq result
4669 (append result (tramp-get-completion-methods m)))))
4670
4671 (setq v (cdr v))))
4672
4673 ;; Unify list, remove nil elements.
4674 (while result
4675 (let ((car (car result)))
4676 (when car
4677 (add-to-list
4678 'result1
4679 (substring car (length (tramp-drop-volume-letter directory)))))
4680 (setq result (cdr result))))
4681
4682 ;; Complete local parts.
4683 (append
4684 result1
4685 (condition-case nil
4686 (tramp-completion-run-real-handler
4687 'file-name-all-completions (list filename directory))
4688 (error nil)))))
16674e4f
KG
4689
4690;; Method, host name and user name completion for a file.
a01b1e22 4691;;;###autoload
e1e17cae
MA
4692(defun tramp-completion-handle-file-name-completion
4693 (filename directory &optional predicate)
00d6fd04 4694 "Like `file-name-completion' for Tramp files."
e1e17cae
MA
4695 (try-completion
4696 filename
4697 (mapcar 'list (file-name-all-completions filename directory))
83e20b5c
MA
4698 (when predicate
4699 (lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
16674e4f
KG
4700
4701;; I misuse a little bit the tramp-file-name structure in order to handle
4702;; completion possibilities for partial methods / user names / host names.
4703;; Return value is a list of tramp-file-name structures according to possible
00d6fd04 4704;; completions. If "localname" is non-nil it means there
16674e4f
KG
4705;; shouldn't be a completion anymore.
4706
4707;; Expected results:
4708
00d6fd04
MA
4709;; "/x" "/[x" "/x@" "/[x@" "/x@y" "/[x@y"
4710;; [nil nil "x" nil] [nil "x" nil nil] [nil "x" "y" nil]
4711;; [nil "x" nil nil]
4712;; ["x" nil nil nil]
4713
4714;; "/x:" "/x:y" "/x:y:"
4715;; [nil nil "x" ""] [nil nil "x" "y"] ["x" nil "y" ""]
4716;; "/[x/" "/[x/y"
4717;; ["x" nil "" nil] ["x" nil "y" nil]
4718;; ["x" "" nil nil] ["x" "y" nil nil]
4719
4720;; "/x:y@" "/x:y@z" "/x:y@z:"
4721;; [nil nil "x" "y@"] [nil nil "x" "y@z"] ["x" "y" "z" ""]
4722;; "/[x/y@" "/[x/y@z"
4723;; ["x" nil "y" nil] ["x" "y" "z" nil]
16674e4f
KG
4724(defun tramp-completion-dissect-file-name (name)
4725 "Returns a list of `tramp-file-name' structures.
4726They are collected by `tramp-completion-dissect-file-name1'."
4727
4728 (let* ((result)
4007ba5b
KG
4729 (x-nil "\\|\\(\\)")
4730 ;; "/method" "/[method"
4731 (tramp-completion-file-name-structure1
4732 (list (concat tramp-prefix-regexp "\\(" tramp-method-regexp x-nil "\\)$")
4733 1 nil nil nil))
4734 ;; "/user" "/[user"
4735 (tramp-completion-file-name-structure2
4736 (list (concat tramp-prefix-regexp "\\(" tramp-user-regexp x-nil "\\)$")
4737 nil 1 nil nil))
4738 ;; "/host" "/[host"
4739 (tramp-completion-file-name-structure3
4740 (list (concat tramp-prefix-regexp "\\(" tramp-host-regexp x-nil "\\)$")
4741 nil nil 1 nil))
4742 ;; "/user@host" "/[user@host"
4743 (tramp-completion-file-name-structure4
4744 (list (concat tramp-prefix-regexp
4745 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
4746 "\\(" tramp-host-regexp x-nil "\\)$")
4747 nil 1 2 nil))
00d6fd04 4748 ;; "/method:user" "/[method/user" "/method://user"
4007ba5b
KG
4749 (tramp-completion-file-name-structure5
4750 (list (concat tramp-prefix-regexp
00d6fd04 4751 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
4752 "\\(" tramp-user-regexp x-nil "\\)$")
4753 1 2 nil nil))
00d6fd04 4754 ;; "/method:host" "/[method/host" "/method://host"
4007ba5b
KG
4755 (tramp-completion-file-name-structure6
4756 (list (concat tramp-prefix-regexp
00d6fd04 4757 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
4758 "\\(" tramp-host-regexp x-nil "\\)$")
4759 1 nil 2 nil))
00d6fd04 4760 ;; "/method:user@host" "/[method/user@host" "/method://user@host"
4007ba5b
KG
4761 (tramp-completion-file-name-structure7
4762 (list (concat tramp-prefix-regexp
00d6fd04 4763 "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
4007ba5b
KG
4764 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
4765 "\\(" tramp-host-regexp x-nil "\\)$")
00d6fd04
MA
4766 1 2 3 nil))
4767 ;; "/method: "/method:/"
4768 (tramp-completion-file-name-structure8
4769 (list
4770 (if (equal tramp-syntax 'url)
4771 (concat tramp-prefix-regexp
4772 "\\(" tramp-method-regexp "\\)"
4773 "\\(" (substring tramp-postfix-method-regexp 0 1)
4774 "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)"
4775 "\\(" "\\)$")
4776 ;; Should not match if not URL syntax.
4777 (concat tramp-prefix-regexp "/$"))
4778 1 3 nil nil))
4779 ;; "/method: "/method:/"
4780 (tramp-completion-file-name-structure9
4781 (list
4782 (if (equal tramp-syntax 'url)
4783 (concat tramp-prefix-regexp
4784 "\\(" tramp-method-regexp "\\)"
4785 "\\(" (substring tramp-postfix-method-regexp 0 1)
4786 "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)"
4787 "\\(" "\\)$")
4788 ;; Should not match if not URL syntax.
4789 (concat tramp-prefix-regexp "/$"))
4790 1 nil 3 nil)))
4007ba5b 4791
9e6ab520 4792 (mapc (lambda (regexp)
16674e4f
KG
4793 (add-to-list 'result
4794 (tramp-completion-dissect-file-name1 regexp name)))
4795 (list
4796 tramp-completion-file-name-structure1
4797 tramp-completion-file-name-structure2
4798 tramp-completion-file-name-structure3
4799 tramp-completion-file-name-structure4
4800 tramp-completion-file-name-structure5
4801 tramp-completion-file-name-structure6
4802 tramp-completion-file-name-structure7
00d6fd04
MA
4803 tramp-completion-file-name-structure8
4804 tramp-completion-file-name-structure9
16674e4f
KG
4805 tramp-file-name-structure))
4806
4807 (delq nil result)))
4808
4809(defun tramp-completion-dissect-file-name1 (structure name)
4810 "Returns a `tramp-file-name' structure matching STRUCTURE.
00d6fd04 4811The structure consists of remote method, remote user,
7432277c 4812remote host and localname (filename on remote host)."
fb7933a3 4813
00d6fd04
MA
4814 (save-match-data
4815 (when (string-match (nth 0 structure) name)
4816 (let ((method (and (nth 1 structure)
4817 (match-string (nth 1 structure) name)))
4818 (user (and (nth 2 structure)
4819 (match-string (nth 2 structure) name)))
4820 (host (and (nth 3 structure)
4821 (match-string (nth 3 structure) name)))
4822 (localname (and (nth 4 structure)
4823 (match-string (nth 4 structure) name))))
4824 (vector method user host localname)))))
16674e4f
KG
4825
4826;; This function returns all possible method completions, adding the
4827;; trailing method delimeter.
16674e4f
KG
4828(defun tramp-get-completion-methods (partial-method)
4829 "Returns all method completions for PARTIAL-METHOD."
4007ba5b
KG
4830 (mapcar
4831 (lambda (method)
4832 (and method
4833 (string-match (concat "^" (regexp-quote partial-method)) method)
00d6fd04
MA
4834 (tramp-completion-make-tramp-file-name method nil nil nil)))
4835 (mapcar 'car tramp-methods)))
16674e4f
KG
4836
4837;; Compares partial user and host names with possible completions.
4838(defun tramp-get-completion-user-host (method partial-user partial-host user host)
4839 "Returns the most expanded string for user and host name completion.
4840PARTIAL-USER must match USER, PARTIAL-HOST must match HOST."
4841 (cond
4842
4843 ((and partial-user partial-host)
4844 (if (and host
4845 (string-match (concat "^" (regexp-quote partial-host)) host)
4846 (string-equal partial-user (or user partial-user)))
4847 (setq user partial-user)
4848 (setq user nil
4849 host nil)))
4850
4851 (partial-user
4852 (setq host nil)
4853 (unless
4854 (and user (string-match (concat "^" (regexp-quote partial-user)) user))
4855 (setq user nil)))
4856
4857 (partial-host
4858 (setq user nil)
4859 (unless
4860 (and host (string-match (concat "^" (regexp-quote partial-host)) host))
4861 (setq host nil)))
4862
4863 (t (setq user nil
4864 host nil)))
4865
292ffc15 4866 (unless (zerop (+ (length user) (length host)))
00d6fd04 4867 (tramp-completion-make-tramp-file-name method user host nil)))
16674e4f
KG
4868
4869(defun tramp-parse-rhosts (filename)
4870 "Return a list of (user host) tuples allowed to access.
292ffc15 4871Either user or host may be nil."
00d6fd04
MA
4872 ;; On Windows, there are problems in completion when
4873 ;; `default-directory' is remote.
9e6ab520 4874 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 4875 res)
8daea7fc 4876 (when (file-readable-p filename)
16674e4f
KG
4877 (with-temp-buffer
4878 (insert-file-contents filename)
4879 (goto-char (point-min))
4880 (while (not (eobp))
292ffc15 4881 (push (tramp-parse-rhosts-group) res))))
16674e4f
KG
4882 res))
4883
16674e4f
KG
4884(defun tramp-parse-rhosts-group ()
4885 "Return a (user host) tuple allowed to access.
292ffc15 4886Either user or host may be nil."
16674e4f
KG
4887 (let ((result)
4888 (regexp
4889 (concat
4890 "^\\(" tramp-host-regexp "\\)"
4891 "\\([ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
9e6ab520 4892 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
4893 (when (re-search-forward regexp nil t)
4894 (setq result (append (list (match-string 3) (match-string 1)))))
4895 (widen)
4896 (forward-line 1)
4897 result))
4898
4899(defun tramp-parse-shosts (filename)
4900 "Return a list of (user host) tuples allowed to access.
4901User is always nil."
00d6fd04
MA
4902 ;; On Windows, there are problems in completion when
4903 ;; `default-directory' is remote.
9e6ab520 4904 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 4905 res)
8daea7fc 4906 (when (file-readable-p filename)
16674e4f
KG
4907 (with-temp-buffer
4908 (insert-file-contents filename)
4909 (goto-char (point-min))
4910 (while (not (eobp))
292ffc15 4911 (push (tramp-parse-shosts-group) res))))
16674e4f
KG
4912 res))
4913
4914(defun tramp-parse-shosts-group ()
4915 "Return a (user host) tuple allowed to access.
4916User is always nil."
16674e4f
KG
4917 (let ((result)
4918 (regexp (concat "^\\(" tramp-host-regexp "\\)")))
9e6ab520 4919 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
4920 (when (re-search-forward regexp nil t)
4921 (setq result (list nil (match-string 1))))
4922 (widen)
4923 (or
4924 (> (skip-chars-forward ",") 0)
4925 (forward-line 1))
4926 result))
4927
8daea7fc
KG
4928(defun tramp-parse-sconfig (filename)
4929 "Return a list of (user host) tuples allowed to access.
4930User is always nil."
00d6fd04
MA
4931 ;; On Windows, there are problems in completion when
4932 ;; `default-directory' is remote.
9e6ab520 4933 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 4934 res)
8daea7fc
KG
4935 (when (file-readable-p filename)
4936 (with-temp-buffer
4937 (insert-file-contents filename)
4938 (goto-char (point-min))
4939 (while (not (eobp))
4940 (push (tramp-parse-sconfig-group) res))))
4941 res))
4942
4943(defun tramp-parse-sconfig-group ()
4944 "Return a (user host) tuple allowed to access.
4945User is always nil."
8daea7fc
KG
4946 (let ((result)
4947 (regexp (concat "^[ \t]*Host[ \t]+" "\\(" tramp-host-regexp "\\)")))
9e6ab520 4948 (narrow-to-region (point) (tramp-compat-line-end-position))
8daea7fc
KG
4949 (when (re-search-forward regexp nil t)
4950 (setq result (list nil (match-string 1))))
4951 (widen)
4952 (or
4953 (> (skip-chars-forward ",") 0)
4954 (forward-line 1))
4955 result))
4956
5ec2cc41
KG
4957(defun tramp-parse-shostkeys (dirname)
4958 "Return a list of (user host) tuples allowed to access.
4959User is always nil."
00d6fd04
MA
4960 ;; On Windows, there are problems in completion when
4961 ;; `default-directory' is remote.
9e6ab520 4962 (let* ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
4963 (regexp (concat "^key_[0-9]+_\\(" tramp-host-regexp "\\)\\.pub$"))
4964 (files (when (file-directory-p dirname) (directory-files dirname)))
4965 result)
5ec2cc41
KG
4966 (while files
4967 (when (string-match regexp (car files))
4968 (push (list nil (match-string 1 (car files))) result))
4969 (setq files (cdr files)))
4970 result))
4971
4972(defun tramp-parse-sknownhosts (dirname)
4973 "Return a list of (user host) tuples allowed to access.
4974User is always nil."
00d6fd04
MA
4975 ;; On Windows, there are problems in completion when
4976 ;; `default-directory' is remote.
9e6ab520 4977 (let* ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
4978 (regexp (concat "^\\(" tramp-host-regexp
4979 "\\)\\.ssh-\\(dss\\|rsa\\)\\.pub$"))
4980 (files (when (file-directory-p dirname) (directory-files dirname)))
4981 result)
5ec2cc41
KG
4982 (while files
4983 (when (string-match regexp (car files))
4984 (push (list nil (match-string 1 (car files))) result))
4985 (setq files (cdr files)))
4986 result))
4987
16674e4f
KG
4988(defun tramp-parse-hosts (filename)
4989 "Return a list of (user host) tuples allowed to access.
4990User is always nil."
00d6fd04
MA
4991 ;; On Windows, there are problems in completion when
4992 ;; `default-directory' is remote.
9e6ab520 4993 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 4994 res)
8daea7fc 4995 (when (file-readable-p filename)
16674e4f
KG
4996 (with-temp-buffer
4997 (insert-file-contents filename)
4998 (goto-char (point-min))
4999 (while (not (eobp))
292ffc15 5000 (push (tramp-parse-hosts-group) res))))
16674e4f
KG
5001 res))
5002
5003(defun tramp-parse-hosts-group ()
5004 "Return a (user host) tuple allowed to access.
5005User is always nil."
16674e4f
KG
5006 (let ((result)
5007 (regexp (concat "^\\(" tramp-host-regexp "\\)")))
9e6ab520 5008 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
5009 (when (re-search-forward regexp nil t)
5010 (unless (char-equal (or (char-after) ?\n) ?:) ; no IPv6
5011 (setq result (list nil (match-string 1)))))
5012 (widen)
5013 (or
5014 (> (skip-chars-forward " \t") 0)
5015 (forward-line 1))
5016 result))
5017
8daea7fc
KG
5018;; For su-alike methods it would be desirable to return "root@localhost"
5019;; as default. Unfortunately, we have no information whether any user name
00d6fd04 5020;; has been typed already. So we use `tramp-current-user' as indication,
8daea7fc 5021;; assuming it is set in `tramp-completion-handle-file-name-all-completions'.
16674e4f
KG
5022(defun tramp-parse-passwd (filename)
5023 "Return a list of (user host) tuples allowed to access.
5024Host is always \"localhost\"."
00d6fd04
MA
5025 ;; On Windows, there are problems in completion when
5026 ;; `default-directory' is remote.
9e6ab520 5027 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5028 res)
8daea7fc 5029 (if (zerop (length tramp-current-user))
16674e4f 5030 '(("root" nil))
8daea7fc 5031 (when (file-readable-p filename)
16674e4f
KG
5032 (with-temp-buffer
5033 (insert-file-contents filename)
5034 (goto-char (point-min))
5035 (while (not (eobp))
292ffc15 5036 (push (tramp-parse-passwd-group) res))))
16674e4f
KG
5037 res)))
5038
5039(defun tramp-parse-passwd-group ()
5040 "Return a (user host) tuple allowed to access.
292ffc15 5041Host is always \"localhost\"."
16674e4f
KG
5042 (let ((result)
5043 (regexp (concat "^\\(" tramp-user-regexp "\\):")))
9e6ab520 5044 (narrow-to-region (point) (tramp-compat-line-end-position))
16674e4f
KG
5045 (when (re-search-forward regexp nil t)
5046 (setq result (list (match-string 1) "localhost")))
5047 (widen)
5048 (forward-line 1)
5049 result))
5050
292ffc15
KG
5051(defun tramp-parse-netrc (filename)
5052 "Return a list of (user host) tuples allowed to access.
5053User may be nil."
00d6fd04
MA
5054 ;; On Windows, there are problems in completion when
5055 ;; `default-directory' is remote.
9e6ab520 5056 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04 5057 res)
8daea7fc 5058 (when (file-readable-p filename)
292ffc15
KG
5059 (with-temp-buffer
5060 (insert-file-contents filename)
5061 (goto-char (point-min))
5062 (while (not (eobp))
5063 (push (tramp-parse-netrc-group) res))))
5064 res))
5065
5066(defun tramp-parse-netrc-group ()
5067 "Return a (user host) tuple allowed to access.
5068User may be nil."
292ffc15
KG
5069 (let ((result)
5070 (regexp
5071 (concat
5072 "^[ \t]*machine[ \t]+" "\\(" tramp-host-regexp "\\)"
5073 "\\([ \t]+login[ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
9e6ab520 5074 (narrow-to-region (point) (tramp-compat-line-end-position))
292ffc15
KG
5075 (when (re-search-forward regexp nil t)
5076 (setq result (list (match-string 3) (match-string 1))))
5077 (widen)
5078 (forward-line 1)
5079 result))
5080
00d6fd04
MA
5081(defun tramp-parse-putty (registry)
5082 "Return a list of (user host) tuples allowed to access.
5083User is always nil."
5084 ;; On Windows, there are problems in completion when
5085 ;; `default-directory' is remote.
9e6ab520 5086 (let ((default-directory (tramp-compat-temporary-file-directory))
00d6fd04
MA
5087 res)
5088 (with-temp-buffer
a4aeb9a4 5089 (when (zerop (tramp-local-call-process "reg" nil t nil "query" registry))
00d6fd04
MA
5090 (goto-char (point-min))
5091 (while (not (eobp))
5092 (push (tramp-parse-putty-group registry) res))))
5093 res))
5094
5095(defun tramp-parse-putty-group (registry)
5096 "Return a (user host) tuple allowed to access.
5097User is always nil."
5098 (let ((result)
5099 (regexp (concat (regexp-quote registry) "\\\\\\(.+\\)")))
9e6ab520 5100 (narrow-to-region (point) (tramp-compat-line-end-position))
00d6fd04
MA
5101 (when (re-search-forward regexp nil t)
5102 (setq result (list nil (match-string 1))))
5103 (widen)
5104 (forward-line 1)
5105 result))
5106
fb7933a3
KG
5107;;; Internal Functions:
5108
00d6fd04
MA
5109(defun tramp-maybe-send-script (vec script name)
5110 "Define in remote shell function NAME implemented as SCRIPT.
5111Only send the definition if it has not already been done."
5112 (let* ((p (tramp-get-connection-process vec))
5113 (scripts (tramp-get-connection-property p "scripts" nil)))
1834b39f 5114 (unless (member name scripts)
00d6fd04
MA
5115 (tramp-message vec 5 "Sending script `%s'..." name)
5116 ;; The script could contain a call of Perl. This is masked with `%s'.
5117 (tramp-send-command-and-check
5118 vec
5119 (format "%s () {\n%s\n}" name
5120 (format script (tramp-get-remote-perl vec))))
5121 (tramp-set-connection-property p "scripts" (cons name scripts))
5122 (tramp-message vec 5 "Sending script `%s'...done." name))))
c82c5727 5123
fb7933a3 5124(defun tramp-set-auto-save ()
00d6fd04 5125 (when (and ;; ange-ftp has its own auto-save mechanism
7177e2a3
MA
5126 (eq (tramp-find-foreign-file-name-handler (buffer-file-name))
5127 'tramp-sh-file-name-handler)
fb7933a3
KG
5128 auto-save-default)
5129 (auto-save-mode 1)))
5130(add-hook 'find-file-hooks 'tramp-set-auto-save t)
a69c01a0
MA
5131(add-hook 'tramp-unload-hook
5132 '(lambda ()
5133 (remove-hook 'find-file-hooks 'tramp-set-auto-save)))
fb7933a3
KG
5134
5135(defun tramp-run-test (switch filename)
5136 "Run `test' on the remote system, given a SWITCH and a FILENAME.
5137Returns the exit code of the `test' program."
00d6fd04
MA
5138 (with-parsed-tramp-file-name filename nil
5139 (tramp-send-command-and-check
5140 v
5141 (format
5142 "%s %s %s"
5143 (tramp-get-test-command v)
5144 switch
5145 (tramp-shell-quote-argument localname)))))
5146
5147(defun tramp-run-test2 (format-string file1 file2)
5148 "Run `test'-like program on the remote system, given FILE1, FILE2.
5149FORMAT-STRING contains the program name, switches, and place holders.
5150Returns the exit code of the `test' program. Barfs if the methods,
fb7933a3 5151hosts, or files, disagree."
00d6fd04
MA
5152 (unless (tramp-equal-remote file1 file2)
5153 (with-parsed-tramp-file-name (if (tramp-tramp-file-p file1) file1 file2) nil
5154 (tramp-error
5155 v 'file-error
5156 "tramp-run-test2 only implemented for same method, user, host")))
5157 (with-parsed-tramp-file-name file1 v1
5158 (with-parsed-tramp-file-name file1 v2
fb7933a3 5159 (tramp-send-command-and-check
00d6fd04
MA
5160 v1
5161 (format format-string
5162 (tramp-shell-quote-argument v1-localname)
5163 (tramp-shell-quote-argument v2-localname))))))
fb7933a3 5164
00d6fd04
MA
5165(defun tramp-buffer-name (vec)
5166 "A name for the connection buffer VEC."
5167 ;; We must use `tramp-file-name-real-host', because for gateway
5168 ;; methods the default port will be expanded later on, which would
5169 ;; tamper the name.
5170 (let ((method (tramp-file-name-method vec))
5171 (user (tramp-file-name-user vec))
5172 (host (tramp-file-name-real-host vec)))
5173 (if (not (zerop (length user)))
5174 (format "*tramp/%s %s@%s*" method user host)
5175 (format "*tramp/%s %s*" method host))))
5176
5177(defun tramp-get-buffer (vec)
5178 "Get the connection buffer to be used for VEC."
5179 (or (get-buffer (tramp-buffer-name vec))
5180 (with-current-buffer (get-buffer-create (tramp-buffer-name vec))
5181 (setq buffer-undo-list t)
5182 (setq default-directory
5183 (tramp-make-tramp-file-name
5184 (tramp-file-name-method vec)
5185 (tramp-file-name-user vec)
5186 (tramp-file-name-host vec)
5187 "/"))
5188 (current-buffer))))
5189
5190(defun tramp-get-connection-buffer (vec)
5191 "Get the connection buffer to be used for VEC.
5192In case a second asynchronous communication has been started, it is different
5193from `tramp-get-buffer'."
5194 (or (tramp-get-connection-property vec "process-buffer" nil)
5195 (tramp-get-buffer vec)))
5196
5197(defun tramp-get-connection-process (vec)
5198 "Get the connection process to be used for VEC.
5199In case a second asynchronous communication has been started, it is different
5200from the default one."
5201 (get-process
5202 (or (tramp-get-connection-property vec "process-name" nil)
5203 (tramp-buffer-name vec))))
5204
5205(defun tramp-debug-buffer-name (vec)
5206 "A name for the debug buffer for VEC."
5207 ;; We must use `tramp-file-name-real-host', because for gateway
5208 ;; methods the default port will be expanded later on, which would
5209 ;; tamper the name.
5210 (let ((method (tramp-file-name-method vec))
5211 (user (tramp-file-name-user vec))
5212 (host (tramp-file-name-real-host vec)))
5213 (if (not (zerop (length user)))
5214 (format "*debug tramp/%s %s@%s*" method user host)
5215 (format "*debug tramp/%s %s*" method host))))
5216
5217(defun tramp-get-debug-buffer (vec)
5218 "Get the debug buffer for VEC."
01917a18 5219 (with-current-buffer
00d6fd04
MA
5220 (get-buffer-create (tramp-debug-buffer-name vec))
5221 (when (bobp)
5222 (setq buffer-undo-list t)
9ce8462a
MA
5223 ;; Activate outline-mode. This runs `text-mode-hook' and
5224 ;; `outline-mode-hook'. We must prevent that local processes
5225 ;; die. Yes: I've seen `flyspell-mode', which starts "ispell"
5226 ;; ...
9e6ab520 5227 (let ((default-directory (tramp-compat-temporary-file-directory)))
00d6fd04 5228 (outline-mode))
9ce8462a
MA
5229 (set (make-local-variable 'outline-regexp)
5230 "[0-9]+:[0-9]+:[0-9]+ [a-z0-9-]+ (\\([0-9]+\\)) #")
5231; (set (make-local-variable 'outline-regexp)
5232; "[a-z.-]+:[0-9]+: [a-z0-9-]+ (\\([0-9]+\\)) #")
5233 (set (make-local-variable 'outline-level) 'tramp-outline-level))
01917a18 5234 (current-buffer)))
fb7933a3 5235
00d6fd04
MA
5236(defun tramp-outline-level ()
5237 "Return the depth to which a statement is nested in the outline.
5238Point must be at the beginning of a header line.
5239
5240The outline level is equal to the verbosity of the Tramp message."
5241 (1+ (string-to-number (match-string 1))))
fb7933a3 5242
00d6fd04
MA
5243(defun tramp-find-executable
5244 (vec progname dirlist &optional ignore-tilde ignore-path)
5245 "Searches for PROGNAME in $PATH and all directories mentioned in DIRLIST.
5246First arg VEC specifies the connection, PROGNAME is the program
5247to search for, and DIRLIST gives the list of directories to
5248search. If IGNORE-TILDE is non-nil, directory names starting
5249with `~' will be ignored. If IGNORE-PATH is non-nil, searches
5250only in DIRLIST.
fb7933a3 5251
7432277c 5252Returns the absolute file name of PROGNAME, if found, and nil otherwise.
fb7933a3
KG
5253
5254This function expects to be in the right *tramp* buffer."
00d6fd04
MA
5255 (with-current-buffer (tramp-get-buffer vec)
5256 (let (result)
5257 ;; Check whether the executable is in $PATH. "which(1)" does not
5258 ;; report always a correct error code; therefore we check the
5259 ;; number of words it returns.
5260 (unless ignore-path
5261 (tramp-send-command vec (format "which \\%s | wc -w" progname))
5262 (goto-char (point-min))
5263 (if (looking-at "^1$")
5264 (setq result (concat "\\" progname))))
5265 (unless result
5266 (when ignore-tilde
5267 ;; Remove all ~/foo directories from dirlist. In Emacs 20,
5268 ;; `remove' is in CL, and we want to avoid CL dependencies.
5269 (let (newdl d)
5270 (while dirlist
5271 (setq d (car dirlist))
5272 (setq dirlist (cdr dirlist))
5273 (unless (char-equal ?~ (aref d 0))
5274 (setq newdl (cons d newdl))))
5275 (setq dirlist (nreverse newdl))))
5276 (tramp-send-command
5277 vec
5278 (format (concat "while read d; "
5279 "do if test -x $d/%s -a -f $d/%s; "
5280 "then echo tramp_executable $d/%s; "
5281 "break; fi; done <<'EOF'\n"
5282 "%s\nEOF")
5283 progname progname progname (mapconcat 'identity dirlist "\n")))
5284 (goto-char (point-max))
5285 (when (search-backward "tramp_executable " nil t)
5286 (skip-chars-forward "^ ")
5287 (skip-chars-forward " ")
9e6ab520
MA
5288 (setq result (buffer-substring
5289 (point) (tramp-compat-line-end-position)))))
00d6fd04
MA
5290 result)))
5291
5292(defun tramp-set-remote-path (vec)
5293 "Sets the remote environment PATH to existing directories.
5294I.e., for each directory in `tramp-remote-path', it is tested
5295whether it exists and if so, it is added to the environment
5296variable PATH."
5297 (tramp-message vec 5 (format "Setting $PATH environment variable"))
f84638eb
MA
5298 (tramp-send-command
5299 vec (format "PATH=%s; export PATH"
5300 (mapconcat 'identity (tramp-get-remote-path vec) ":"))))
fb7933a3 5301
cfb5c0db
MA
5302;; ------------------------------------------------------------
5303;; -- Communication with external shell --
5304;; ------------------------------------------------------------
fb7933a3 5305
00d6fd04 5306(defun tramp-find-file-exists-command (vec)
fb7933a3
KG
5307 "Find a command on the remote host for checking if a file exists.
5308Here, we are looking for a command which has zero exit status if the
5309file exists and nonzero exit status otherwise."
00d6fd04 5310 (let ((existing "/")
fb7933a3 5311 (nonexisting
00d6fd04
MA
5312 (tramp-shell-quote-argument "/ this file does not exist "))
5313 result)
fb7933a3
KG
5314 ;; The algorithm is as follows: we try a list of several commands.
5315 ;; For each command, we first run `$cmd /' -- this should return
5316 ;; true, as the root directory always exists. And then we run
00d6fd04 5317 ;; `$cmd /this\ file\ does\ not\ exist ', hoping that the file indeed
fb7933a3
KG
5318 ;; does not exist. This should return false. We use the first
5319 ;; command we find that seems to work.
5320 ;; The list of commands to try is as follows:
00d6fd04
MA
5321 ;; `ls -d' This works on most systems, but NetBSD 1.4
5322 ;; has a bug: `ls' always returns zero exit
5323 ;; status, even for files which don't exist.
5324 ;; `test -e' Some Bourne shells have a `test' builtin
5325 ;; which does not know the `-e' option.
5326 ;; `/bin/test -e' For those, the `test' binary on disk normally
5327 ;; provides the option. Alas, the binary
5328 ;; is sometimes `/bin/test' and sometimes it's
5329 ;; `/usr/bin/test'.
5330 ;; `/usr/bin/test -e' In case `/bin/test' does not exist.
fb7933a3 5331 (unless (or
00d6fd04
MA
5332 (and (setq result (format "%s -e" (tramp-get-test-command vec)))
5333 (zerop (tramp-send-command-and-check
5334 vec (format "%s %s" result existing)))
5335 (not (zerop (tramp-send-command-and-check
5336 vec (format "%s %s" result nonexisting)))))
5337 (and (setq result "/bin/test -e")
5338 (zerop (tramp-send-command-and-check
5339 vec (format "%s %s" result existing)))
5340 (not (zerop (tramp-send-command-and-check
5341 vec (format "%s %s" result nonexisting)))))
5342 (and (setq result "/usr/bin/test -e")
5343 (zerop (tramp-send-command-and-check
5344 vec (format "%s %s" result existing)))
5345 (not (zerop (tramp-send-command-and-check
5346 vec (format "%s %s" result nonexisting)))))
5347 (and (setq result (format "%s -d" (tramp-get-ls-command vec)))
5348 (zerop (tramp-send-command-and-check
5349 vec (format "%s %s" result existing)))
5350 (not (zerop (tramp-send-command-and-check
5351 vec (format "%s %s" result nonexisting))))))
5352 (tramp-error
5353 vec 'file-error "Couldn't find command to check if file exists"))
5354 result))
bf247b6e 5355
fb7933a3 5356;; CCC test ksh or bash found for tilde expansion?
00d6fd04
MA
5357(defun tramp-find-shell (vec)
5358 "Opens a shell on the remote host which groks tilde expansion."
5359 (unless (tramp-get-connection-property vec "remote-shell" nil)
5360 (let (shell)
5361 (with-current-buffer (tramp-get-buffer vec)
7e780ff1 5362 (tramp-send-command vec "echo ~root" t)
00d6fd04
MA
5363 (cond
5364 ((string-match "^~root$" (buffer-string))
5365 (setq shell
f84638eb
MA
5366 (or (tramp-find-executable
5367 vec "bash" (tramp-get-remote-path vec) t)
5368 (tramp-find-executable
5369 vec "ksh" (tramp-get-remote-path vec) t)))
00d6fd04
MA
5370 (unless shell
5371 (tramp-error
5372 vec 'file-error
5373 "Couldn't find a shell which groks tilde expansion"))
5374 ;; Find arguments for this shell.
5375 (let ((alist tramp-sh-extra-args)
5376 item extra-args)
5377 (while (and alist (null extra-args))
5378 (setq item (pop alist))
5379 (when (string-match (car item) shell)
5380 (setq extra-args (cdr item))))
5381 (when extra-args (setq shell (concat shell " " extra-args))))
5382 (tramp-message
5383 vec 5 "Starting remote shell `%s' for tilde expansion..." shell)
a4aeb9a4
MA
5384 (let ((tramp-end-of-output "$ "))
5385 (tramp-send-command
b08104a0
MA
5386 vec
5387 (format "PROMPT_COMMAND='' PS1='$ ' PS2='' PS3='' exec %s" shell)
5388 t))
a0a5183a 5389 ;; Setting prompts.
00d6fd04 5390 (tramp-message vec 5 "Setting remote shell prompt...")
a0a5183a 5391 (tramp-send-command vec (format "PS1='%s'" tramp-end-of-output) t)
9fa0d3aa
MA
5392 (tramp-send-command vec "PS2=''" t)
5393 (tramp-send-command vec "PS3=''" t)
5394 (tramp-send-command vec "PROMPT_COMMAND=''" t)
00d6fd04 5395 (tramp-message vec 5 "Setting remote shell prompt...done"))
a0a5183a 5396
00d6fd04
MA
5397 (t (tramp-message
5398 vec 5 "Remote `%s' groks tilde expansion, good"
5399 (tramp-get-method-parameter
5400 (tramp-file-name-method vec) 'tramp-remote-sh))
5401 (tramp-set-connection-property
5402 vec "remote-shell"
5403 (tramp-get-method-parameter
5404 (tramp-file-name-method vec) 'tramp-remote-sh))))))))
fb7933a3 5405
bf247b6e
KS
5406;; ------------------------------------------------------------
5407;; -- Functions for establishing connection --
5408;; ------------------------------------------------------------
fb7933a3 5409
ac474af1
KG
5410;; The following functions are actions to be taken when seeing certain
5411;; prompts from the remote host. See the variable
5412;; `tramp-actions-before-shell' for usage of these functions.
5413
00d6fd04 5414(defun tramp-action-login (proc vec)
ac474af1 5415 "Send the login name."
00d6fd04
MA
5416 (when (not (stringp tramp-current-user))
5417 (save-window-excursion
5418 (let ((enable-recursive-minibuffers t))
5419 (pop-to-buffer (tramp-get-connection-buffer vec))
5420 (setq tramp-current-user (read-string (match-string 0))))))
5421 (tramp-message vec 3 "Sending login name `%s'" tramp-current-user)
5422 (with-current-buffer (tramp-get-connection-buffer vec)
5423 (tramp-message vec 6 "\n%s" (buffer-string)))
5424 (tramp-send-string vec tramp-current-user))
5425
5426(defun tramp-action-password (proc vec)
ac474af1 5427 "Query the user for a password."
00d6fd04
MA
5428 (tramp-message vec 3 "Sending password")
5429 (tramp-enter-password proc))
5430
5431(defun tramp-action-succeed (proc vec)
ac474af1 5432 "Signal success in finding shell prompt."
ac474af1
KG
5433 (throw 'tramp-action 'ok))
5434
00d6fd04 5435(defun tramp-action-permission-denied (proc vec)
ac474af1 5436 "Signal permission denied."
00d6fd04 5437 (kill-process proc)
ac474af1
KG
5438 (throw 'tramp-action 'permission-denied))
5439
00d6fd04 5440(defun tramp-action-yesno (proc vec)
3cdaec13
KG
5441 "Ask the user for confirmation using `yes-or-no-p'.
5442Send \"yes\" to remote process on confirmation, abort otherwise.
5443See also `tramp-action-yn'."
ac474af1 5444 (save-window-excursion
00d6fd04
MA
5445 (let ((enable-recursive-minibuffers t))
5446 (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec)))
5447 (unless (yes-or-no-p (match-string 0))
5448 (kill-process proc)
5449 (throw 'tramp-action 'permission-denied))
5450 (with-current-buffer (tramp-get-connection-buffer vec)
5451 (tramp-message vec 6 "\n%s" (buffer-string)))
5452 (tramp-send-string vec "yes"))))
5453
5454(defun tramp-action-yn (proc vec)
3cdaec13
KG
5455 "Ask the user for confirmation using `y-or-n-p'.
5456Send \"y\" to remote process on confirmation, abort otherwise.
5457See also `tramp-action-yesno'."
5458 (save-window-excursion
00d6fd04
MA
5459 (let ((enable-recursive-minibuffers t))
5460 (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec)))
5461 (unless (y-or-n-p (match-string 0))
5462 (kill-process proc)
5463 (throw 'tramp-action 'permission-denied))
5464 (with-current-buffer (tramp-get-connection-buffer vec)
5465 (tramp-message vec 6 "\n%s" (buffer-string)))
5466 (tramp-send-string vec "y"))))
5467
5468(defun tramp-action-terminal (proc vec)
487f4fb7
KG
5469 "Tell the remote host which terminal type to use.
5470The terminal type can be configured with `tramp-terminal-type'."
00d6fd04 5471 (tramp-message vec 5 "Setting `%s' as terminal type." tramp-terminal-type)
7e780ff1
MA
5472 (with-current-buffer (tramp-get-connection-buffer vec)
5473 (tramp-message vec 6 "\n%s" (buffer-string)))
00d6fd04 5474 (tramp-send-string vec tramp-terminal-type))
487f4fb7 5475
00d6fd04 5476(defun tramp-action-process-alive (proc vec)
19a87064 5477 "Check whether a process has finished."
00d6fd04 5478 (unless (memq (process-status proc) '(run open))
19a87064
MA
5479 (throw 'tramp-action 'process-died)))
5480
00d6fd04 5481(defun tramp-action-out-of-band (proc vec)
38c65fca 5482 "Check whether an out-of-band copy has finished."
00d6fd04
MA
5483 (cond ((and (memq (process-status proc) '(stop exit))
5484 (zerop (process-exit-status proc)))
5485 (tramp-message vec 3 "Process has finished.")
38c65fca 5486 (throw 'tramp-action 'ok))
00d6fd04
MA
5487 ((or (and (memq (process-status proc) '(stop exit))
5488 (not (zerop (process-exit-status proc))))
5489 (memq (process-status proc) '(signal)))
01917a18
MA
5490 ;; `scp' could have copied correctly, but set modes could have failed.
5491 ;; This can be ignored.
00d6fd04
MA
5492 (with-current-buffer (process-buffer proc)
5493 (goto-char (point-min))
5494 (if (re-search-forward tramp-operation-not-permitted-regexp nil t)
5495 (progn
5496 (tramp-message vec 5 "'set mode' error ignored.")
5497 (tramp-message vec 3 "Process has finished.")
5498 (throw 'tramp-action 'ok))
5499 (tramp-message vec 3 "Process has died.")
5500 (throw 'tramp-action 'process-died))))
38c65fca
KG
5501 (t nil)))
5502
ac474af1
KG
5503;; Functions for processing the actions.
5504
00d6fd04 5505(defun tramp-process-one-action (proc vec actions)
ac474af1 5506 "Wait for output from the shell and perform one action."
00d6fd04 5507 (let (found todo item pattern action)
e6466697 5508 (while (not found)
00d6fd04
MA
5509 ;; Reread output once all actions have been performed.
5510 ;; Obviously, the output was not complete.
5511 (tramp-accept-process-output proc 1)
e6466697
MA
5512 (setq todo actions)
5513 (while todo
e6466697 5514 (setq item (pop todo))
00d6fd04 5515 (setq pattern (concat (symbol-value (nth 0 item)) "\\'"))
e6466697 5516 (setq action (nth 1 item))
00d6fd04
MA
5517 (tramp-message
5518 vec 5 "Looking for regexp \"%s\" from remote shell" pattern)
5519 (when (tramp-check-for-regexp proc pattern)
5520 (tramp-message vec 5 "Call `%s'" (symbol-name action))
5521 (setq found (funcall action proc vec)))))
e6466697
MA
5522 found))
5523
00d6fd04 5524(defun tramp-process-actions (proc vec actions &optional timeout)
e6466697 5525 "Perform actions until success or TIMEOUT."
ac474af1
KG
5526 (let (exit)
5527 (while (not exit)
00d6fd04 5528 (tramp-message proc 3 "Waiting for prompts from remote shell")
ac474af1
KG
5529 (setq exit
5530 (catch 'tramp-action
e6466697
MA
5531 (if timeout
5532 (with-timeout (timeout)
00d6fd04
MA
5533 (tramp-process-one-action proc vec actions))
5534 (tramp-process-one-action proc vec actions)))))
5535 (with-current-buffer (tramp-get-connection-buffer vec)
5536 (tramp-message vec 6 "\n%s" (buffer-string)))
ac474af1 5537 (unless (eq exit 'ok)
9c13938d 5538 (tramp-clear-passwd vec)
00d6fd04
MA
5539 (tramp-error-with-buffer
5540 nil vec 'file-error
5541 (cond
5542 ((eq exit 'permission-denied) "Permission denied")
5543 ((eq exit 'process-died) "Process died")
5544 (t "Login failed"))))))
fb7933a3
KG
5545
5546;; Utility functions.
5547
00d6fd04 5548(defun tramp-accept-process-output (&optional proc timeout timeout-msecs)
d2a2c17f
MA
5549 "Like `accept-process-output' for Tramp processes.
5550This is needed in order to hide `last-coding-system-used', which is set
5551for process communication also."
00d6fd04
MA
5552 (with-current-buffer (process-buffer proc)
5553 (tramp-message proc 10 "%s %s" proc (process-status proc))
5554 (let (buffer-read-only last-coding-system-used)
5555 ;; Under Windows XP, accept-process-output doesn't return
5556 ;; sometimes. So we add an additional timeout.
5557 (with-timeout ((or timeout 1))
5558 (accept-process-output proc timeout timeout-msecs)))
5559 (tramp-message proc 10 "\n%s" (buffer-string))))
5560
5561(defun tramp-check-for-regexp (proc regexp)
5562 "Check whether REGEXP is contained in process buffer of PROC.
5563Erase echoed commands if exists."
5564 (with-current-buffer (process-buffer proc)
5565 (goto-char (point-min))
5566 ;; Check whether we need to remove echo output.
5567 (when (and (tramp-get-connection-property proc "check-remote-echo" nil)
5568 (re-search-forward tramp-echoed-echo-mark-regexp nil t))
5569 (let ((begin (match-beginning 0)))
5570 (when (re-search-forward tramp-echoed-echo-mark-regexp nil t)
5571 ;; Discard echo from remote output.
5572 (tramp-set-connection-property proc "check-remote-echo" nil)
5573 (tramp-message proc 5 "echo-mark found")
5574 (forward-line)
5575 (delete-region begin (point))
5576 (goto-char (point-min)))))
5577 ;; No echo to be handled, now we can look for the regexp.
5578 (when (not (tramp-get-connection-property proc "check-remote-echo" nil))
5579 (re-search-forward regexp nil t))))
d2a2c17f 5580
fb7933a3
KG
5581(defun tramp-wait-for-regexp (proc timeout regexp)
5582 "Wait for a REGEXP to appear from process PROC within TIMEOUT seconds.
5583Expects the output of PROC to be sent to the current buffer. Returns
5584the string that matched, or nil. Waits indefinitely if TIMEOUT is
5585nil."
00d6fd04
MA
5586 (with-current-buffer (process-buffer proc)
5587 (let ((found (tramp-check-for-regexp proc regexp))
5588 (start-time (current-time)))
5589 (cond (timeout
5590 ;; Work around a bug in XEmacs 21, where the timeout
5591 ;; expires faster than it should. This degenerates
5592 ;; to polling for buggy XEmacsen, but oh, well.
5593 (while (and (not found)
5594 (< (tramp-time-diff (current-time) start-time)
5595 timeout))
5596 (with-timeout (timeout)
5597 (while (not found)
5598 (tramp-accept-process-output proc 1)
5599 (unless (memq (process-status proc) '(run open))
5600 (tramp-error-with-buffer
5601 nil proc 'file-error "Process has died"))
5602 (setq found (tramp-check-for-regexp proc regexp))))))
5603 (t
5604 (while (not found)
5605 (tramp-accept-process-output proc 1)
5606 (unless (memq (process-status proc) '(run open))
5607 (tramp-error-with-buffer
5608 nil proc 'file-error "Process has died"))
5609 (setq found (tramp-check-for-regexp proc regexp)))))
5610 (tramp-message proc 6 "\n%s" (buffer-string))
fb7933a3 5611 (when (not found)
00d6fd04
MA
5612 (if timeout
5613 (tramp-error
5614 proc 'file-error "[[Regexp `%s' not found in %d secs]]"
5615 regexp timeout)
5616 (tramp-error proc 'file-error "[[Regexp `%s' not found]]" regexp)))
5617 found)))
fb7933a3 5618
b25a52cc
KG
5619(defun tramp-barf-if-no-shell-prompt (proc timeout &rest error-args)
5620 "Wait for shell prompt and barf if none appears.
5621Looks at process PROC to see if a shell prompt appears in TIMEOUT
5622seconds. If not, it produces an error message with the given ERROR-ARGS."
7e780ff1
MA
5623 (unless
5624 (tramp-wait-for-regexp
5625 proc timeout
5626 (format
5627 "\\(%s\\|%s\\)\\'" shell-prompt-pattern tramp-shell-prompt-pattern))
00d6fd04
MA
5628 (apply 'tramp-error-with-buffer nil proc 'file-error error-args)))
5629
7e780ff1
MA
5630;; We don't call `tramp-send-string' in order to hide the password
5631;; from the debug buffer, and because end-of-line handling of the
5632;; string.
5633(defun tramp-enter-password (proc)
00d6fd04
MA
5634 "Prompt for a password and send it to the remote end."
5635 (process-send-string
7e780ff1
MA
5636 proc (concat (tramp-read-passwd proc)
5637 (or (tramp-get-method-parameter
5638 tramp-current-method
5639 'tramp-password-end-of-line)
5640 tramp-default-password-end-of-line))))
00d6fd04 5641
cfb5c0db
MA
5642(defun tramp-process-sentinel (proc event)
5643 "Process sentinel for Tramp processes."
5644 (when (memq (process-status proc) '(stop exit signal))
5645 (tramp-flush-connection-property proc)
5646 ;; The "Connection closed" and "exit" messages disturb the output
8a798e41
MA
5647 ;; for asynchronous processes. That's why we have echoed the
5648 ;; Tramp prompt at the end. Trailing messages can be removed.
fd35d9d6
MO
5649 (let ((buf (process-buffer proc)))
5650 (when (buffer-live-p buf)
5651 (with-current-buffer buf
5652 (goto-char (point-max))
5653 (re-search-backward
5654 (mapconcat 'identity (split-string tramp-end-of-output "\n")
5655 "\r?\n")
5656 (line-beginning-position -8) t)
5657 (delete-region (point) (point-max)))))))
cfb5c0db 5658
00d6fd04 5659(defun tramp-open-connection-setup-interactive-shell (proc vec)
fb7933a3 5660 "Set up an interactive shell.
00d6fd04
MA
5661Mainly sets the prompt and the echo correctly. PROC is the shell
5662process to set up. VEC specifies the connection."
a4aeb9a4 5663 (let ((tramp-end-of-output "$ "))
8950769a
MA
5664 ;; It is useful to set the prompt in the following command because
5665 ;; some people have a setting for $PS1 which /bin/sh doesn't know
5666 ;; about and thus /bin/sh will display a strange prompt. For
5667 ;; example, if $PS1 has "${CWD}" in the value, then ksh will
5668 ;; display the current working directory but /bin/sh will display
5669 ;; a dollar sign. The following command line sets $PS1 to a sane
5670 ;; value, and works under Bourne-ish shells as well as csh-like
5671 ;; shells. Daniel Pittman reports that the unusual positioning of
5672 ;; the single quotes makes it work under `rc', too. We also unset
5673 ;; the variable $ENV because that is read by some sh
5674 ;; implementations (eg, bash when called as sh) on startup; this
5675 ;; way, we avoid the startup file clobbering $PS1. $PROMP_COMMAND
5676 ;; is another way to set the prompt in /bin/bash, it must be
5677 ;; discarded as well.
a4aeb9a4
MA
5678 (tramp-send-command
5679 vec
5680 (format
9fa0d3aa 5681 "exec env ENV='' PROMPT_COMMAND='' PS1='$ ' PS2='' PS3='' %s"
a4aeb9a4
MA
5682 (tramp-get-method-parameter
5683 (tramp-file-name-method vec) 'tramp-remote-sh))
8950769a
MA
5684 t)
5685
5686 ;; Disable echo.
5687 (tramp-message vec 5 "Setting up remote shell environment")
5688 (tramp-send-command vec "stty -inlcr -echo kill '^U' erase '^H'" t)
5689 ;; Check whether the echo has really been disabled. Some
5690 ;; implementations, like busybox of embedded GNU/Linux, don't
5691 ;; support disabling.
5692 (tramp-send-command vec "echo foo" t)
5693 (with-current-buffer (process-buffer proc)
5694 (goto-char (point-min))
5695 (when (looking-at "echo foo")
5696 (tramp-set-connection-property proc "remote-echo" t)
5697 (tramp-message vec 5 "Remote echo still on. Ok.")
5698 ;; Make sure backspaces and their echo are enabled and no line
5699 ;; width magic interferes with them.
5700 (tramp-send-command vec "stty icanon erase ^H cols 32767" t))))
e42c6bbc 5701
7e780ff1 5702 (tramp-message vec 5 "Setting shell prompt")
8950769a
MA
5703 ;; We can set $PS1 to `tramp-end-of-output' only when the echo has
5704 ;; been disabled. Otherwise, the echo of the command would be
5705 ;; regarded as prompt already.
a0a5183a 5706 (tramp-send-command vec (format "PS1='%s'" tramp-end-of-output) t)
9fa0d3aa
MA
5707 (tramp-send-command vec "PS2=''" t)
5708 (tramp-send-command vec "PS3=''" t)
5709 (tramp-send-command vec "PROMPT_COMMAND=''" t)
e42c6bbc 5710
fb7933a3
KG
5711 ;; Try to set up the coding system correctly.
5712 ;; CCC this can't be the right way to do it. Hm.
00d6fd04 5713 (tramp-message vec 5 "Determining coding system")
7e780ff1 5714 (tramp-send-command vec "echo foo ; echo bar" t)
00d6fd04 5715 (with-current-buffer (process-buffer proc)
fb7933a3
KG
5716 (goto-char (point-min))
5717 (if (featurep 'mule)
00d6fd04
MA
5718 ;; Use MULE to select the right EOL convention for communicating
5719 ;; with the process.
311dd93f 5720 (let* ((cs (or (funcall (symbol-function 'process-coding-system) proc)
00d6fd04
MA
5721 (cons 'undecided 'undecided)))
5722 cs-decode cs-encode)
5723 (when (symbolp cs) (setq cs (cons cs cs)))
5724 (setq cs-decode (car cs))
5725 (setq cs-encode (cdr cs))
5726 (unless cs-decode (setq cs-decode 'undecided))
5727 (unless cs-encode (setq cs-encode 'undecided))
5728 (setq cs-encode (tramp-coding-system-change-eol-conversion
5729 cs-encode 'unix))
5730 (when (search-forward "\r" nil t)
5731 (setq cs-decode (tramp-coding-system-change-eol-conversion
5732 cs-decode 'dos)))
311dd93f
MA
5733 (funcall (symbol-function 'set-buffer-process-coding-system)
5734 cs-decode cs-encode))
fb7933a3
KG
5735 ;; Look for ^M and do something useful if found.
5736 (when (search-forward "\r" nil t)
00d6fd04
MA
5737 ;; We have found a ^M but cannot frob the process coding system
5738 ;; because we're running on a non-MULE Emacs. Let's try
5739 ;; stty, instead.
7e780ff1
MA
5740 (tramp-send-command vec "stty -onlcr" t))))
5741 (tramp-send-command vec "set +o vi +o emacs" t)
e42c6bbc
MA
5742
5743 ;; Check whether the output of "uname -sr" has been changed. If
5744 ;; yes, this is a strong indication that we must expire all
5745 ;; connection properties.
5746 (tramp-message vec 5 "Checking system information")
5747 (let ((old-uname (tramp-get-connection-property vec "uname" nil))
5748 (new-uname
5749 (tramp-set-connection-property
5750 vec "uname"
5751 (tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\""))))
5752 (when (and (stringp old-uname) (not (string-equal old-uname new-uname)))
b50dd0d2 5753 (funcall (symbol-function 'tramp-cleanup-connection) vec)
e42c6bbc
MA
5754 (signal
5755 'quit
5756 (list (format
5757 "Connection reset, because remote host changed from `%s' to `%s'"
5758 old-uname new-uname)))))
5759
5760 ;; Check whether the remote host suffers from buggy
5761 ;; `send-process-string'. This is known for FreeBSD (see comment in
5762 ;; `send_process', file process.c). I've tested sending 624 bytes
5763 ;; successfully, sending 625 bytes failed. Emacs makes a hack when
5764 ;; this host type is detected locally. It cannot handle remote
5765 ;; hosts, though.
00d6fd04
MA
5766 (with-connection-property proc "chunksize"
5767 (cond
5768 ((and (integerp tramp-chunksize) (> tramp-chunksize 0))
5769 tramp-chunksize)
5770 (t
5771 (tramp-message
5772 vec 5 "Checking remote host type for `send-process-string' bug")
5773 (if (string-match
e42c6bbc 5774 "^FreeBSD" (tramp-get-connection-property vec "uname" ""))
00d6fd04 5775 500 0))))
e42c6bbc 5776
00d6fd04
MA
5777 ;; Set remote PATH variable.
5778 (tramp-set-remote-path vec)
e42c6bbc 5779
fb7933a3
KG
5780 ;; Search for a good shell before searching for a command which
5781 ;; checks if a file exists. This is done because Tramp wants to use
5782 ;; "test foo; echo $?" to check if various conditions hold, and
5783 ;; there are buggy /bin/sh implementations which don't execute the
5784 ;; "echo $?" part if the "test" part has an error. In particular,
5785 ;; the Solaris /bin/sh is a problem. I'm betting that all systems
5786 ;; with buggy /bin/sh implementations will have a working bash or
5787 ;; ksh. Whee...
00d6fd04 5788 (tramp-find-shell vec)
e42c6bbc 5789
00d6fd04 5790 ;; Disable unexpected output.
7e780ff1 5791 (tramp-send-command vec "mesg n; biff n" t)
e42c6bbc 5792
00d6fd04
MA
5793 ;; Set the environment.
5794 (tramp-message vec 5 "Setting default environment")
5795 (let ((env (copy-sequence tramp-remote-process-environment))
5796 unset item)
5797 (while env
5798 (setq item (split-string (car env) "="))
5799 (if (and (stringp (cadr item)) (not (string-equal (cadr item) "")))
5800 (tramp-send-command
7e780ff1 5801 vec (format "%s=%s; export %s" (car item) (cadr item) (car item)) t)
00d6fd04
MA
5802 (push (car item) unset))
5803 (setq env (cdr env)))
5804 (when unset
fb7933a3 5805 (tramp-send-command
7e780ff1 5806 vec (format "unset %s" (mapconcat 'identity unset " "))))) t)
fb7933a3 5807
ac474af1
KG
5808;; CCC: We should either implement a Perl version of base64 encoding
5809;; and decoding. Then we just use that in the last item. The other
5810;; alternative is to use the Perl version of UU encoding. But then
5811;; we need a Lisp version of uuencode.
16674e4f
KG
5812;;
5813;; Old text from documentation of tramp-methods:
5814;; Using a uuencode/uudecode inline method is discouraged, please use one
5815;; of the base64 methods instead since base64 encoding is much more
5816;; reliable and the commands are more standardized between the different
5817;; Unix versions. But if you can't use base64 for some reason, please
5818;; note that the default uudecode command does not work well for some
5819;; Unices, in particular AIX and Irix. For AIX, you might want to use
5820;; the following command for uudecode:
5821;;
5822;; sed '/^begin/d;/^[` ]$/d;/^end/d' | iconv -f uucode -t ISO8859-1
5823;;
5824;; For Irix, no solution is known yet.
5825
00d6fd04
MA
5826(defconst tramp-local-coding-commands
5827 '((b64 base64-encode-region base64-decode-region)
5828 (uu tramp-uuencode-region uudecode-decode-region)
5829 (pack
5830 "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
5831 "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"))
5832 "List of local coding commands for inline transfer.
16674e4f
KG
5833Each item is a list that looks like this:
5834
00d6fd04 5835\(FORMAT ENCODING DECODING)
ac474af1 5836
00d6fd04
MA
5837FORMAT is symbol describing the encoding/decoding format. It can be
5838`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
ac474af1 5839
00d6fd04
MA
5840ENCODING and DECODING can be strings, giving commands, or symbols,
5841giving functions. If they are strings, then they can contain
16674e4f
KG
5842the \"%s\" format specifier. If that specifier is present, the input
5843filename will be put into the command line at that spot. If the
5844specifier is not present, the input should be read from standard
5845input.
ac474af1 5846
16674e4f
KG
5847If they are functions, they will be called with two arguments, start
5848and end of region, and are expected to replace the region contents
5849with the encoded or decoded results, respectively.")
ac474af1 5850
00d6fd04
MA
5851(defconst tramp-remote-coding-commands
5852 '((b64 "mimencode -b" "mimencode -u -b")
5853 (b64 "mmencode -b" "mmencode -u -b")
5854 (b64 "recode data..base64" "recode base64..data")
5855 (b64 tramp-perl-encode-with-module tramp-perl-decode-with-module)
5856 (b64 tramp-perl-encode tramp-perl-decode)
5857 (uu "uuencode xxx" "uudecode -o /dev/stdout")
5858 (uu "uuencode xxx" "uudecode -o -")
5859 (uu "uuencode xxx" "uudecode -p")
5860 (uu "uuencode xxx" tramp-uudecode)
5861 (pack
5862 "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'"
5863 "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'"))
5864 "List of remote coding commands for inline transfer.
5865Each item is a list that looks like this:
5866
5867\(FORMAT ENCODING DECODING)
5868
5869FORMAT is symbol describing the encoding/decoding format. It can be
5870`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
5871
5872ENCODING and DECODING can be strings, giving commands, or symbols,
5873giving variables. If they are strings, then they can contain
5874the \"%s\" format specifier. If that specifier is present, the input
5875filename will be put into the command line at that spot. If the
5876specifier is not present, the input should be read from standard
5877input.
5878
5879If they are variables, this variable is a string containing a Perl
5880implementation for this functionality. This Perl program will be transferred
5881to the remote host, and it is avalible as shell function with the same name.")
5882
5883(defun tramp-find-inline-encoding (vec)
ac474af1 5884 "Find an inline transfer encoding that works.
00d6fd04
MA
5885Goes through the list `tramp-local-coding-commands' and
5886`tramp-remote-coding-commands'."
5887 (save-excursion
5888 (let ((local-commands tramp-local-coding-commands)
5889 (magic "xyzzy")
5890 loc-enc loc-dec rem-enc rem-dec litem ritem found)
5891 (while (and local-commands (not found))
5892 (setq litem (pop local-commands))
5893 (catch 'wont-work-local
5894 (let ((format (nth 0 litem))
5895 (remote-commands tramp-remote-coding-commands))
5896 (setq loc-enc (nth 1 litem))
5897 (setq loc-dec (nth 2 litem))
5898 ;; If the local encoder or decoder is a string, the
5899 ;; corresponding command has to work locally.
5900 (if (not (stringp loc-enc))
5901 (tramp-message
5902 vec 5 "Checking local encoding function `%s'" loc-enc)
5903 (tramp-message
5904 vec 5 "Checking local encoding command `%s' for sanity" loc-enc)
5905 (unless (zerop (tramp-call-local-coding-command
5906 loc-enc nil nil))
5907 (throw 'wont-work-local nil)))
5908 (if (not (stringp loc-dec))
5909 (tramp-message
5910 vec 5 "Checking local decoding function `%s'" loc-dec)
5911 (tramp-message
5912 vec 5 "Checking local decoding command `%s' for sanity" loc-dec)
5913 (unless (zerop (tramp-call-local-coding-command
5914 loc-dec nil nil))
5915 (throw 'wont-work-local nil)))
5916 ;; Search for remote coding commands with the same format
5917 (while (and remote-commands (not found))
5918 (setq ritem (pop remote-commands))
5919 (catch 'wont-work-remote
5920 (when (equal format (nth 0 ritem))
5921 (setq rem-enc (nth 1 ritem))
5922 (setq rem-dec (nth 2 ritem))
5923 ;; Check if remote encoding and decoding commands can be
5924 ;; called remotely with null input and output. This makes
5925 ;; sure there are no syntax errors and the command is really
5926 ;; found. Note that we do not redirect stdout to /dev/null,
5927 ;; for two reasons: when checking the decoding command, we
5928 ;; actually check the output it gives. And also, when
5929 ;; redirecting "mimencode" output to /dev/null, then as root
5930 ;; it might change the permissions of /dev/null!
5931 (when (not (stringp rem-enc))
5932 (let ((name (symbol-name rem-enc)))
5933 (while (string-match (regexp-quote "-") name)
5934 (setq name (replace-match "_" nil t name)))
5935 (tramp-maybe-send-script vec (symbol-value rem-enc) name)
5936 (setq rem-enc name)))
5937 (tramp-message
5938 vec 5
5939 "Checking remote encoding command `%s' for sanity" rem-enc)
5940 (unless (zerop (tramp-send-command-and-check
5941 vec (format "%s </dev/null" rem-enc) t))
5942 (throw 'wont-work-remote nil))
5943
5944 (when (not (stringp rem-dec))
5945 (let ((name (symbol-name rem-dec)))
5946 (while (string-match (regexp-quote "-") name)
5947 (setq name (replace-match "_" nil t name)))
5948 (tramp-maybe-send-script vec (symbol-value rem-dec) name)
5949 (setq rem-dec name)))
5950 (tramp-message
5951 vec 5
5952 "Checking remote decoding command `%s' for sanity" rem-dec)
5953 (unless (zerop (tramp-send-command-and-check
5954 vec
5955 (format "echo %s | %s | %s"
5956 magic rem-enc rem-dec) t))
5957 (throw 'wont-work-remote nil))
5958
5959 (with-current-buffer (tramp-get-buffer vec)
5960 (goto-char (point-min))
5961 (unless (looking-at (regexp-quote magic))
5962 (throw 'wont-work-remote nil)))
5963
5964 ;; `rem-enc' and `rem-dec' could be a string meanwhile.
5965 (setq rem-enc (nth 1 ritem))
5966 (setq rem-dec (nth 2 ritem))
5967 (setq found t)))))))
5968
5969 ;; Did we find something? If not, issue an error.
5970 (unless found
5971 (kill-process (tramp-get-connection-process vec))
5972 (tramp-error
5973 vec 'file-error "Couldn't find an inline transfer encoding"))
5974
5975 ;; Set connection properties.
5976 (tramp-message vec 5 "Using local encoding `%s'" loc-enc)
5977 (tramp-set-connection-property vec "local-encoding" loc-enc)
5978 (tramp-message vec 5 "Using local decoding `%s'" loc-dec)
5979 (tramp-set-connection-property vec "local-decoding" loc-dec)
5980 (tramp-message vec 5 "Using remote encoding `%s'" rem-enc)
5981 (tramp-set-connection-property vec "remote-encoding" rem-enc)
5982 (tramp-message vec 5 "Using remote decoding `%s'" rem-dec)
5983 (tramp-set-connection-property vec "remote-decoding" rem-dec))))
16674e4f
KG
5984
5985(defun tramp-call-local-coding-command (cmd input output)
5986 "Call the local encoding or decoding command.
5987If CMD contains \"%s\", provide input file INPUT there in command.
5988Otherwise, INPUT is passed via standard input.
5989INPUT can also be nil which means `/dev/null'.
5990OUTPUT can be a string (which specifies a filename), or t (which
5991means standard output and thus the current buffer), or nil (which
5992means discard it)."
a4aeb9a4
MA
5993 (tramp-local-call-process
5994 tramp-encoding-shell
5995 (when (and input (not (string-match "%s" cmd))) input)
5996 (if (eq output t) t nil)
5997 nil
5998 tramp-encoding-command-switch
5999 (concat
6000 (if (string-match "%s" cmd) (format cmd input) cmd)
6001 (if (stringp output) (concat "> " output) ""))))
00d6fd04
MA
6002
6003(defun tramp-compute-multi-hops (vec)
6004 "Expands VEC according to `tramp-default-proxies-alist'.
6005Gateway hops are already opened."
6006 (let ((target-alist `(,vec))
6007 (choices tramp-default-proxies-alist)
6008 item proxy)
6009
6010 ;; Look for proxy hosts to be passed.
6011 (while choices
6012 (setq item (pop choices)
6013 proxy (nth 2 item))
6014 (when (and
6015 ;; host
6016 (string-match (or (nth 0 item) "")
6017 (or (tramp-file-name-host (car target-alist)) ""))
6018 ;; user
6019 (string-match (or (nth 1 item) "")
6020 (or (tramp-file-name-user (car target-alist)) "")))
6021 (if (null proxy)
6022 ;; No more hops needed.
6023 (setq choices nil)
6024 ;; Replace placeholders.
6025 (setq proxy
6026 (format-spec
6027 proxy
6028 `((?u . ,(or (tramp-file-name-user (car target-alist)) ""))
6029 (?h . ,(or (tramp-file-name-host (car target-alist)) "")))))
6030 (with-parsed-tramp-file-name proxy l
6031 ;; Add the hop.
6032 (add-to-list 'target-alist l)
6033 ;; Start next search.
6034 (setq choices tramp-default-proxies-alist)))))
6035
6036 ;; Handle gateways.
8a4438b6
MA
6037 (when (and (boundp 'tramp-gw-tunnel-method)
6038 (string-match (format
6039 "^\\(%s\\|%s\\)$"
6040 (symbol-value 'tramp-gw-tunnel-method)
6041 (symbol-value 'tramp-gw-socks-method))
6042 (tramp-file-name-method (car target-alist))))
00d6fd04
MA
6043 (let ((gw (pop target-alist))
6044 (hop (pop target-alist)))
6045 ;; Is the method prepared for gateways?
6046 (unless (tramp-get-method-parameter
6047 (tramp-file-name-method hop) 'tramp-default-port)
6048 (tramp-error
6049 vec 'file-error
6050 "Method `%s' is not supported for gateway access."
6051 (tramp-file-name-method hop)))
6052 ;; Add default port if needed.
6053 (unless
6054 (string-match
6055 tramp-host-with-port-regexp (tramp-file-name-host hop))
6056 (aset hop 2
6057 (concat
6058 (tramp-file-name-host hop) tramp-prefix-port-format
6059 (number-to-string
6060 (tramp-get-method-parameter
6061 (tramp-file-name-method hop) 'tramp-default-port)))))
6062 ;; Open the gateway connection.
6063 (add-to-list
6064 'target-alist
6065 (vector
6066 (tramp-file-name-method hop) (tramp-file-name-user hop)
9e6ab520 6067 (funcall (symbol-function 'tramp-gw-open-connection) vec gw hop) nil))
00d6fd04
MA
6068 ;; For the password prompt, we need the correct values.
6069 ;; Therefore, we must remember the gateway vector. But we
6070 ;; cannot do it as connection property, because it shouldn't
6071 ;; be persistent. And we have no started process yet either.
6072 (tramp-set-file-property (car target-alist) "" "gateway" hop)))
6073
6074 ;; Foreign and out-of-band methods are not supported for multi-hops.
6075 (when (cdr target-alist)
6076 (setq choices target-alist)
6077 (while choices
6078 (setq item (pop choices))
6079 (when
6080 (or
6081 (not
6082 (tramp-get-method-parameter
6083 (tramp-file-name-method item) 'tramp-login-program))
6084 (tramp-get-method-parameter
6085 (tramp-file-name-method item) 'tramp-copy-program))
6086 (tramp-error
6087 vec 'file-error
6088 "Method `%s' is not supported for multi-hops."
6089 (tramp-file-name-method item)))))
6090
2991e49f
MA
6091 ;; In case the host name is not used for the remote shell
6092 ;; command, the user could be misguided by applying a random
6093 ;; hostname.
6094 (let* ((v (car target-alist))
6095 (method (tramp-file-name-method v))
6096 (host (tramp-file-name-host v)))
6097 (unless
6098 (or
6099 ;; There are multi-hops.
6100 (cdr target-alist)
6101 ;; The host name is used for the remote shell command.
6102 (member
6103 '("%h") (tramp-get-method-parameter method 'tramp-login-args))
6104 ;; The host is local. We cannot use `tramp-local-host-p'
6105 ;; here, because it opens a connection as well.
6106 (string-match
6107 (concat "^" (regexp-opt (list "localhost" (system-name)) t) "$")
6108 host))
6109 (tramp-error
42bc9b6d
MA
6110 v 'file-error
6111 "Host `%s' looks like a remote host, `%s' can only use the local host"
6112 host method)))
2991e49f 6113
00d6fd04
MA
6114 ;; Result.
6115 target-alist))
6116
6117(defun tramp-maybe-open-connection (vec)
6118 "Maybe open a connection VEC.
fb7933a3
KG
6119Does not do anything if a connection is already open, but re-opens the
6120connection if a previous connection has died for some reason."
67932d94
MA
6121 (let ((p (tramp-get-connection-process vec))
6122 (process-environment (copy-sequence process-environment)))
00d6fd04 6123
ac474af1
KG
6124 ;; If too much time has passed since last command was sent, look
6125 ;; whether process is still alive. If it isn't, kill it. When
6126 ;; using ssh, it can sometimes happen that the remote end has hung
6127 ;; up but the local ssh client doesn't recognize this until it
6128 ;; tries to send some data to the remote end. So that's why we
6129 ;; try to send a command from time to time, then look again
6130 ;; whether the process is really alive.
1437876c
MA
6131 (condition-case nil
6132 (when (and (> (tramp-time-diff
6133 (current-time)
6134 (tramp-get-connection-property
6135 p "last-cmd-time" '(0 0 0)))
6136 60)
6137 p (processp p) (memq (process-status p) '(run open)))
6138 (tramp-send-command vec "echo are you awake" t t)
6139 (unless (and (memq (process-status p) '(run open))
6140 (tramp-wait-for-output p 10))
6141 ;; The error will be catched locally.
6142 (tramp-error vec 'file-error "Awake did fail")))
6143 (file-error
8a798e41
MA
6144 (tramp-flush-connection-property vec)
6145 (tramp-flush-connection-property p)
1437876c
MA
6146 (delete-process p)
6147 (setq p nil)))
00d6fd04
MA
6148
6149 ;; New connection must be opened.
ac474af1 6150 (unless (and p (processp p) (memq (process-status p) '(run open)))
00d6fd04
MA
6151
6152 ;; We call `tramp-get-buffer' in order to get a debug buffer for
6153 ;; messages from the beginning.
6154 (tramp-get-buffer vec)
6155 (if (zerop (length (tramp-file-name-user vec)))
6156 (tramp-message
6157 vec 3 "Opening connection for %s using %s..."
6158 (tramp-file-name-host vec)
6159 (tramp-file-name-method vec))
6160 (tramp-message
6161 vec 3 "Opening connection for %s@%s using %s..."
6162 (tramp-file-name-user vec)
6163 (tramp-file-name-host vec)
6164 (tramp-file-name-method vec)))
6165
6166 ;; Start new process.
fb7933a3 6167 (when (and p (processp p))
00d6fd04
MA
6168 (delete-process p))
6169 (setenv "TERM" tramp-terminal-type)
a7580c1c 6170 (setenv "LC_ALL" "C")
ce3f516f 6171 (setenv "PROMPT_COMMAND")
00d6fd04
MA
6172 (setenv "PS1" "$ ")
6173 (let* ((target-alist (tramp-compute-multi-hops vec))
00d6fd04 6174 (process-connection-type tramp-process-connection-type)
8d60099b 6175 (process-adaptive-read-buffering nil)
00d6fd04
MA
6176 (coding-system-for-read nil)
6177 ;; This must be done in order to avoid our file name handler.
9e6ab520
MA
6178 (p (let ((default-directory
6179 (tramp-compat-temporary-file-directory)))
00d6fd04
MA
6180 (start-process
6181 (or (tramp-get-connection-property vec "process-name" nil)
6182 (tramp-buffer-name vec))
6183 (tramp-get-connection-buffer vec)
6184 tramp-encoding-shell)))
6185 (first-hop t))
6186
6187 (tramp-message
6188 vec 6 "%s" (mapconcat 'identity (process-command p) " "))
6189
6190 ;; Check whether process is alive.
cfb5c0db 6191 (set-process-sentinel p 'tramp-process-sentinel)
00d6fd04
MA
6192 (tramp-set-process-query-on-exit-flag p nil)
6193 (tramp-message vec 3 "Waiting 60s for local shell to come up...")
6194 (tramp-barf-if-no-shell-prompt
6195 p 60 "Couldn't find local shell prompt %s" tramp-encoding-shell)
6196
6197 ;; Now do all the connections as specified.
6198 (while target-alist
6199 (let* ((hop (car target-alist))
6200 (l-method (tramp-file-name-method hop))
6201 (l-user (tramp-file-name-user hop))
6202 (l-host (tramp-file-name-host hop))
6203 (l-port nil)
6204 (login-program
6205 (tramp-get-method-parameter l-method 'tramp-login-program))
6206 (login-args
6207 (tramp-get-method-parameter l-method 'tramp-login-args))
6208 (gw-args
6209 (tramp-get-method-parameter l-method 'tramp-gw-args))
6210 (gw (tramp-get-file-property hop "" "gateway" nil))
6211 (g-method (and gw (tramp-file-name-method gw)))
6212 (g-user (and gw (tramp-file-name-user gw)))
6213 (g-host (and gw (tramp-file-name-host gw)))
6214 (command login-program)
9c13938d
MA
6215 ;; We don't create the temporary file. In fact, it
6216 ;; is just a prefix for the ControlPath option of
6217 ;; ssh; the real temporary file has another name, and
6218 ;; it is created and protected by ssh. It is also
6219 ;; removed by ssh, when the connection is closed.
6220 (tmpfile
6221 (tramp-set-connection-property
6222 p "temp-file"
6223 (make-temp-name
6224 (expand-file-name
6225 tramp-temp-name-prefix
6226 (tramp-compat-temporary-file-directory)))))
00d6fd04
MA
6227 spec)
6228
6229 ;; Add gateway arguments if necessary.
6230 (when (and gw gw-args)
6231 (setq login-args (append login-args gw-args)))
6232
6233 ;; Check for port number. Until now, there's no need for handling
6234 ;; like method, user, host.
6235 (when (string-match tramp-host-with-port-regexp l-host)
6236 (setq l-port (match-string 2 l-host)
6237 l-host (match-string 1 l-host)))
6238
6239 ;; Set variables for computing the prompt for reading password.
6240 ;; They can also be derived from a gatewy.
6241 (setq tramp-current-method (or g-method l-method)
6242 tramp-current-user (or g-user l-user)
6243 tramp-current-host (or g-host l-host))
6244
6245 ;; Replace login-args place holders.
6246 (setq
6247 l-host (or l-host "")
6248 l-user (or l-user "")
6249 l-port (or l-port "")
6250 spec `((?h . ,l-host) (?u . ,l-user) (?p . ,l-port)
9c13938d 6251 (?t . ,tmpfile))
00d6fd04
MA
6252 command
6253 (concat
6254 command " "
6255 (mapconcat
6256 '(lambda (x)
6257 (setq x (mapcar '(lambda (y) (format-spec y spec)) x))
6258 (unless (member "" x) (mapconcat 'identity x " ")))
6259 login-args " ")
6260 ;; String to detect failed connection. Every single word must
6261 ;; be enclosed with '\"'; otherwise it is detected
6262 ;; during connection setup.
6263 ;; Local shell could be a Windows COMSPEC. It doesn't know
6264 ;; the ";" syntax, but we must exit always for `start-process'.
6265 ;; "exec" does not work either.
6266 (if first-hop
6267 " && exit || exit"
6268 "; echo \"Tramp\" \"connection\" \"closed\"; sleep 1"))
6269 ;; We don't reach a Windows shell. Could be initial only.
6270 first-hop nil)
6271
6272 ;; Send the command.
6273 (tramp-message vec 3 "Sending command `%s'" command)
6274 (tramp-send-command vec command t t)
6275 (tramp-process-actions p vec tramp-actions-before-shell 60)
6276 (tramp-message vec 3 "Found remote shell prompt on `%s'" l-host))
6277 ;; Next hop.
6278 (setq target-alist (cdr target-alist)))
6279
6280 ;; Make initial shell settings.
6281 (tramp-open-connection-setup-interactive-shell p vec)))))
6282
6283(defun tramp-send-command (vec command &optional neveropen nooutput)
6284 "Send the COMMAND to connection VEC.
6285Erases temporary buffer before sending the command. If optional
6286arg NEVEROPEN is non-nil, never try to open the connection. This
6287is meant to be used from `tramp-maybe-open-connection' only. The
6288function waits for output unless NOOUTPUT is set."
6289 (unless neveropen (tramp-maybe-open-connection vec))
6290 (let ((p (tramp-get-connection-process vec)))
8950769a 6291 (when (tramp-get-connection-property p "remote-echo" nil)
00d6fd04
MA
6292 ;; We mark the command string that it can be erased in the output buffer.
6293 (tramp-set-connection-property p "check-remote-echo" t)
6294 (setq command (format "%s%s%s" tramp-echo-mark command tramp-echo-mark)))
6295 (tramp-message vec 6 "%s" command)
6296 (tramp-send-string vec command)
6297 (unless nooutput (tramp-wait-for-output p))))
6298
00d6fd04 6299(defun tramp-wait-for-output (proc &optional timeout)
fb7933a3 6300 "Wait for output from remote rsh command."
00d6fd04 6301 (with-current-buffer (process-buffer proc)
0664ff72
MA
6302 ;; Initially, `tramp-end-of-output' is "$ ". There might be
6303 ;; leading escape sequences, which must be ignored.
a0a5183a
MA
6304 (let* ((regexp
6305 (if (string-match (regexp-quote "\n") tramp-end-of-output)
6306 (mapconcat
6307 'identity (split-string tramp-end-of-output "\n") "\r?\n")
6308 (format "^[^$\n]*%s\r?$" (regexp-quote tramp-end-of-output))))
0664ff72 6309 (found (tramp-wait-for-regexp proc timeout regexp)))
00d6fd04
MA
6310 (if found
6311 (let (buffer-read-only)
6312 (goto-char (point-max))
0664ff72 6313 (re-search-backward regexp nil t)
00d6fd04
MA
6314 (delete-region (point) (point-max)))
6315 (if timeout
6316 (tramp-error
6317 proc 'file-error
6318 "[[Remote prompt `%s' not found in %d secs]]"
6319 tramp-end-of-output timeout)
6320 (tramp-error
6321 proc 'file-error
6322 "[[Remote prompt `%s' not found]]" tramp-end-of-output)))
6323 ;; Return value is whether end-of-output sentinel was found.
6324 found)))
fb7933a3 6325
00d6fd04 6326(defun tramp-send-command-and-check (vec command &optional subshell)
fb7933a3 6327 "Run COMMAND and check its exit status.
fb7933a3
KG
6328Sends `echo $?' along with the COMMAND for checking the exit status. If
6329COMMAND is nil, just sends `echo $?'. Returns the exit status found.
6330
6331If the optional argument SUBSHELL is non-nil, the command is executed in
6332a subshell, ie surrounded by parentheses."
00d6fd04
MA
6333 (tramp-send-command
6334 vec
6335 (concat (if subshell "( " "")
6336 command
6337 (if command " 2>/dev/null; " "")
6338 "echo tramp_exit_status $?"
6339 (if subshell " )" " ")))
6340 (with-current-buffer (tramp-get-connection-buffer vec)
6341 (goto-char (point-max))
6342 (unless (re-search-backward "tramp_exit_status [0-9]+" nil t)
6343 (tramp-error
6344 vec 'file-error "Couldn't find exit status of `%s'" command))
6345 (skip-chars-forward "^ ")
6346 (prog1
6347 (read (current-buffer))
6348 (let (buffer-read-only) (delete-region (match-beginning 0) (point-max))))))
6349
6350(defun tramp-barf-unless-okay (vec command fmt &rest args)
fb7933a3
KG
6351 "Run COMMAND, check exit status, throw error if exit status not okay.
6352Similar to `tramp-send-command-and-check' but accepts two more arguments
6353FMT and ARGS which are passed to `error'."
00d6fd04
MA
6354 (unless (zerop (tramp-send-command-and-check vec command))
6355 (apply 'tramp-error vec 'file-error fmt args)))
6356
6357(defun tramp-send-command-and-read (vec command)
6358 "Run COMMAND and return the output, which must be a Lisp expression.
6359In case there is no valid Lisp expression, it raises an error"
6360 (tramp-barf-unless-okay vec command "`%s' returns with error" command)
6361 (with-current-buffer (tramp-get-connection-buffer vec)
6362 ;; Read the expression.
6363 (goto-char (point-min))
6364 (condition-case nil
6365 (prog1 (read (current-buffer))
6366 ;; Error handling.
9e6ab520 6367 (when (re-search-forward "\\S-" (tramp-compat-line-end-position) t)
9ce8462a 6368 (error nil)))
00d6fd04
MA
6369 (error (tramp-error
6370 vec 'file-error
6371 "`%s' does not return a valid Lisp expression: `%s'"
6372 command (buffer-string))))))
fb7933a3 6373
7432277c
KG
6374;; It seems that Tru64 Unix does not like it if long strings are sent
6375;; to it in one go. (This happens when sending the Perl
6376;; `file-attributes' implementation, for instance.) Therefore, we
27e813fe 6377;; have this function which sends the string in chunks.
00d6fd04
MA
6378(defun tramp-send-string (vec string)
6379 "Send the STRING via connection VEC.
7432277c
KG
6380
6381The STRING is expected to use Unix line-endings, but the lines sent to
6382the remote host use line-endings as defined in the variable
00d6fd04
MA
6383`tramp-rsh-end-of-line'. The communication buffer is erased before sending."
6384 (let* ((p (tramp-get-connection-process vec))
6385 (chunksize (tramp-get-connection-property p "chunksize" nil)))
6386 (unless p
6387 (tramp-error
6388 vec 'file-error "Can't send string to remote host -- not logged in"))
6389 (tramp-set-connection-property p "last-cmd-time" (current-time))
6390 (tramp-message vec 10 "%s" string)
6391 (with-current-buffer (tramp-get-connection-buffer vec)
6392 ;; Clean up the buffer. We cannot call `erase-buffer' because
6393 ;; narrowing might be in effect.
6394 (let (buffer-read-only) (delete-region (point-min) (point-max)))
27e813fe 6395 ;; Replace "\n" by `tramp-rsh-end-of-line'.
00d6fd04
MA
6396 (setq string
6397 (mapconcat 'identity
6398 (split-string string "\n")
6399 tramp-rsh-end-of-line))
6400 (unless (or (string= string "")
6401 (string-equal (substring string -1) tramp-rsh-end-of-line))
6402 (setq string (concat string tramp-rsh-end-of-line)))
27e813fe 6403 ;; Send the string.
00d6fd04
MA
6404 (if (and chunksize (not (zerop chunksize)))
6405 (let ((pos 0)
6406 (end (length string)))
6407 (while (< pos end)
6408 (tramp-message
6409 vec 10 "Sending chunk from %s to %s"
6410 pos (min (+ pos chunksize) end))
6411 (process-send-string
6412 p (substring string pos (min (+ pos chunksize) end)))
6413 (setq pos (+ pos chunksize))))
6414 (process-send-string p string)))))
fb7933a3
KG
6415
6416(defun tramp-mode-string-to-int (mode-string)
6417 "Converts a ten-letter `drwxrwxrwx'-style mode string into mode bits."
f3c071dd
MA
6418 (let* (case-fold-search
6419 (mode-chars (string-to-vector mode-string))
fb7933a3
KG
6420 (owner-read (aref mode-chars 1))
6421 (owner-write (aref mode-chars 2))
6422 (owner-execute-or-setid (aref mode-chars 3))
6423 (group-read (aref mode-chars 4))
6424 (group-write (aref mode-chars 5))
6425 (group-execute-or-setid (aref mode-chars 6))
6426 (other-read (aref mode-chars 7))
6427 (other-write (aref mode-chars 8))
6428 (other-execute-or-sticky (aref mode-chars 9)))
6429 (save-match-data
6430 (logior
f3c071dd
MA
6431 (cond
6432 ((char-equal owner-read ?r) (tramp-octal-to-decimal "00400"))
6433 ((char-equal owner-read ?-) 0)
6434 (t (error "Second char `%c' must be one of `r-'" owner-read)))
6435 (cond
6436 ((char-equal owner-write ?w) (tramp-octal-to-decimal "00200"))
6437 ((char-equal owner-write ?-) 0)
6438 (t (error "Third char `%c' must be one of `w-'" owner-write)))
6439 (cond
6440 ((char-equal owner-execute-or-setid ?x)
6441 (tramp-octal-to-decimal "00100"))
6442 ((char-equal owner-execute-or-setid ?S)
6443 (tramp-octal-to-decimal "04000"))
6444 ((char-equal owner-execute-or-setid ?s)
6445 (tramp-octal-to-decimal "04100"))
6446 ((char-equal owner-execute-or-setid ?-) 0)
6447 (t (error "Fourth char `%c' must be one of `xsS-'"
6448 owner-execute-or-setid)))
6449 (cond
6450 ((char-equal group-read ?r) (tramp-octal-to-decimal "00040"))
6451 ((char-equal group-read ?-) 0)
6452 (t (error "Fifth char `%c' must be one of `r-'" group-read)))
6453 (cond
6454 ((char-equal group-write ?w) (tramp-octal-to-decimal "00020"))
6455 ((char-equal group-write ?-) 0)
6456 (t (error "Sixth char `%c' must be one of `w-'" group-write)))
6457 (cond
6458 ((char-equal group-execute-or-setid ?x)
6459 (tramp-octal-to-decimal "00010"))
6460 ((char-equal group-execute-or-setid ?S)
6461 (tramp-octal-to-decimal "02000"))
6462 ((char-equal group-execute-or-setid ?s)
6463 (tramp-octal-to-decimal "02010"))
6464 ((char-equal group-execute-or-setid ?-) 0)
6465 (t (error "Seventh char `%c' must be one of `xsS-'"
6466 group-execute-or-setid)))
6467 (cond
6468 ((char-equal other-read ?r)
6469 (tramp-octal-to-decimal "00004"))
6470 ((char-equal other-read ?-) 0)
6471 (t (error "Eighth char `%c' must be one of `r-'" other-read)))
6472 (cond
6473 ((char-equal other-write ?w) (tramp-octal-to-decimal "00002"))
6474 ((char-equal other-write ?-) 0)
fb7933a3 6475 (t (error "Nineth char `%c' must be one of `w-'" other-write)))
f3c071dd
MA
6476 (cond
6477 ((char-equal other-execute-or-sticky ?x)
6478 (tramp-octal-to-decimal "00001"))
6479 ((char-equal other-execute-or-sticky ?T)
6480 (tramp-octal-to-decimal "01000"))
6481 ((char-equal other-execute-or-sticky ?t)
6482 (tramp-octal-to-decimal "01001"))
6483 ((char-equal other-execute-or-sticky ?-) 0)
6484 (t (error "Tenth char `%c' must be one of `xtT-'"
6485 other-execute-or-sticky)))))))
fb7933a3 6486
00d6fd04
MA
6487(defun tramp-convert-file-attributes (vec attr)
6488 "Convert file-attributes ATTR generated by perl script, stat or ls.
c82c5727
LH
6489Convert file mode bits to string and set virtual device number.
6490Return ATTR."
00d6fd04
MA
6491 ;; Convert last access time.
6492 (unless (listp (nth 4 attr))
6493 (setcar (nthcdr 4 attr)
6494 (list (floor (nth 4 attr) 65536)
6495 (floor (mod (nth 4 attr) 65536)))))
6496 ;; Convert last modification time.
6497 (unless (listp (nth 5 attr))
6498 (setcar (nthcdr 5 attr)
6499 (list (floor (nth 5 attr) 65536)
6500 (floor (mod (nth 5 attr) 65536)))))
6501 ;; Convert last status change time.
6502 (unless (listp (nth 6 attr))
6503 (setcar (nthcdr 6 attr)
6504 (list (floor (nth 6 attr) 65536)
6505 (floor (mod (nth 6 attr) 65536)))))
d4443a0d
MA
6506 ;; Convert file size.
6507 (when (< (nth 7 attr) 0)
6508 (setcar (nthcdr 7 attr) -1))
9e6ab520
MA
6509 (when (and (floatp (nth 7 attr))
6510 (<= (nth 7 attr) (tramp-compat-most-positive-fixnum)))
d4443a0d 6511 (setcar (nthcdr 7 attr) (round (nth 7 attr))))
ca637b2a 6512 ;; Convert file mode bits to string.
c82c5727 6513 (unless (stringp (nth 8 attr))
c82c5727 6514 (setcar (nthcdr 8 attr) (tramp-file-mode-from-int (nth 8 attr))))
00d6fd04
MA
6515 ;; Convert directory indication bit.
6516 (if (string-match "^d" (nth 8 attr))
6517 (setcar attr t)
6518 (if (and (listp (car attr)) (stringp (caar attr))
6519 (string-match ".+ -> .\\(.+\\)." (caar attr)))
6520 (setcar attr (match-string 1 (caar attr)))
6521 (setcar attr nil)))
6522 ;; Set file's gid change bit.
6523 (setcar (nthcdr 9 attr)
6524 (if (numberp (nth 3 attr))
6525 (not (= (nth 3 attr)
6526 (tramp-get-remote-gid vec 'integer)))
6527 (not (string-equal
6528 (nth 3 attr)
6529 (tramp-get-remote-gid vec 'string)))))
6530 ;; Convert inode.
6531 (unless (listp (nth 10 attr))
6532 (setcar (nthcdr 10 attr)
ce3f516f
MA
6533 (condition-case nil
6534 (list (floor (nth 10 attr) 65536)
6535 (floor (mod (nth 10 attr) 65536)))
6536 ;; Inodes can be incredible huge. We must hide this.
6537 (error (tramp-get-inode vec)))))
c82c5727
LH
6538 ;; Set virtual device number.
6539 (setcar (nthcdr 11 attr)
00d6fd04 6540 (tramp-get-device vec))
c82c5727
LH
6541 attr)
6542
ce3f516f 6543(defun tramp-get-inode (vec)
00d6fd04
MA
6544 "Returns the virtual inode number.
6545If it doesn't exist, generate a new one."
ce3f516f
MA
6546 (let ((string (tramp-make-tramp-file-name
6547 (tramp-file-name-method vec)
6548 (tramp-file-name-user vec)
6549 (tramp-file-name-host vec)
6550 "")))
00d6fd04
MA
6551 (unless (assoc string tramp-inodes)
6552 (add-to-list 'tramp-inodes
6553 (list string (length tramp-inodes))))
6554 (nth 1 (assoc string tramp-inodes))))
6555
6556(defun tramp-get-device (vec)
c82c5727
LH
6557 "Returns the virtual device number.
6558If it doesn't exist, generate a new one."
00d6fd04
MA
6559 (let ((string (tramp-make-tramp-file-name
6560 (tramp-file-name-method vec)
6561 (tramp-file-name-user vec)
6562 (tramp-file-name-host vec)
6563 "")))
c82c5727
LH
6564 (unless (assoc string tramp-devices)
6565 (add-to-list 'tramp-devices
6566 (list string (length tramp-devices))))
6567 (list -1 (nth 1 (assoc string tramp-devices)))))
fb7933a3
KG
6568
6569(defun tramp-file-mode-from-int (mode)
6570 "Turn an integer representing a file mode into an ls(1)-like string."
6571 (let ((type (cdr (assoc (logand (lsh mode -12) 15) tramp-file-mode-type-map)))
6572 (user (logand (lsh mode -6) 7))
6573 (group (logand (lsh mode -3) 7))
6574 (other (logand (lsh mode -0) 7))
6575 (suid (> (logand (lsh mode -9) 4) 0))
6576 (sgid (> (logand (lsh mode -9) 2) 0))
6577 (sticky (> (logand (lsh mode -9) 1) 0)))
6578 (setq user (tramp-file-mode-permissions user suid "s"))
6579 (setq group (tramp-file-mode-permissions group sgid "s"))
6580 (setq other (tramp-file-mode-permissions other sticky "t"))
6581 (concat type user group other)))
6582
fb7933a3
KG
6583(defun tramp-file-mode-permissions (perm suid suid-text)
6584 "Convert a permission bitset into a string.
6585This is used internally by `tramp-file-mode-from-int'."
6586 (let ((r (> (logand perm 4) 0))
6587 (w (> (logand perm 2) 0))
6588 (x (> (logand perm 1) 0)))
6589 (concat (or (and r "r") "-")
6590 (or (and w "w") "-")
6591 (or (and suid x suid-text) ; suid, execute
6592 (and suid (upcase suid-text)) ; suid, !execute
6593 (and x "x") "-")))) ; !suid
6594
fb7933a3
KG
6595(defun tramp-decimal-to-octal (i)
6596 "Return a string consisting of the octal digits of I.
6597Not actually used. Use `(format \"%o\" i)' instead?"
6598 (cond ((< i 0) (error "Cannot convert negative number to octal"))
6599 ((not (integerp i)) (error "Cannot convert non-integer to octal"))
6600 ((zerop i) "0")
6601 (t (concat (tramp-decimal-to-octal (/ i 8))
6602 (number-to-string (% i 8))))))
6603
6604
fb7933a3
KG
6605;; Kudos to Gerd Moellmann for this suggestion.
6606(defun tramp-octal-to-decimal (ostr)
6607 "Given a string of octal digits, return a decimal number."
6608 (let ((x (or ostr "")))
6609 ;; `save-match' is in `tramp-mode-string-to-int' which calls this.
6610 (unless (string-match "\\`[0-7]*\\'" x)
6611 (error "Non-octal junk in string `%s'" x))
6612 (string-to-number ostr 8)))
6613
6614(defun tramp-shell-case-fold (string)
6615 "Converts STRING to shell glob pattern which ignores case."
6616 (mapconcat
6617 (lambda (c)
6618 (if (equal (downcase c) (upcase c))
6619 (vector c)
6620 (format "[%c%c]" (downcase c) (upcase c))))
6621 string
6622 ""))
6623
6624
bf247b6e 6625;; ------------------------------------------------------------
a4aeb9a4 6626;; -- Tramp file names --
bf247b6e 6627;; ------------------------------------------------------------
fb7933a3
KG
6628;; Conversion functions between external representation and
6629;; internal data structure. Convenience functions for internal
6630;; data structure.
6631
00d6fd04
MA
6632(defun tramp-file-name-p (vec)
6633 "Check whether VEC is a Tramp object."
6634 (and (vectorp vec) (= 4 (length vec))))
6635
6636(defun tramp-file-name-method (vec)
6637 "Return method component of VEC."
6638 (and (tramp-file-name-p vec) (aref vec 0)))
6639
6640(defun tramp-file-name-user (vec)
6641 "Return user component of VEC."
6642 (and (tramp-file-name-p vec) (aref vec 1)))
6643
6644(defun tramp-file-name-host (vec)
6645 "Return host component of VEC."
6646 (and (tramp-file-name-p vec) (aref vec 2)))
6647
6648(defun tramp-file-name-localname (vec)
6649 "Return localname component of VEC."
6650 (and (tramp-file-name-p vec) (aref vec 3)))
6651
6652;; The host part of a Tramp file name vector can be of kind
6653;; "host#port". Sometimes, we must extract these parts.
8a4438b6 6654(defun tramp-file-name-real-host (vec)
00d6fd04
MA
6655 "Return the host name of VEC without port."
6656 (let ((host (tramp-file-name-host vec)))
6657 (if (and (stringp host)
6658 (string-match tramp-host-with-port-regexp host))
6659 (match-string 1 host)
6660 host)))
6661
8a4438b6 6662(defun tramp-file-name-port (vec)
00d6fd04
MA
6663 "Return the port number of VEC."
6664 (let ((host (tramp-file-name-host vec)))
6665 (and (stringp host)
6666 (string-match tramp-host-with-port-regexp host)
6667 (string-to-number (match-string 2 host)))))
fb7933a3
KG
6668
6669(defun tramp-tramp-file-p (name)
a4aeb9a4 6670 "Return t if NAME is a Tramp file."
fb7933a3
KG
6671 (save-match-data
6672 (string-match tramp-file-name-regexp name)))
bf247b6e 6673
8a4438b6 6674(defun tramp-find-method (method user host)
00d6fd04
MA
6675 "Return the right method string to use.
6676This is METHOD, if non-nil. Otherwise, do a lookup in
6677`tramp-default-method-alist'."
6678 (or method
6679 (let ((choices tramp-default-method-alist)
6680 lmethod item)
6681 (while choices
6682 (setq item (pop choices))
6683 (when (and (string-match (or (nth 0 item) "") (or host ""))
6684 (string-match (or (nth 1 item) "") (or user "")))
6685 (setq lmethod (nth 2 item))
6686 (setq choices nil)))
6687 lmethod)
6688 tramp-default-method))
6689
8a4438b6 6690(defun tramp-find-user (method user host)
00d6fd04
MA
6691 "Return the right user string to use.
6692This is USER, if non-nil. Otherwise, do a lookup in
6693`tramp-default-user-alist'."
6694 (or user
6695 (let ((choices tramp-default-user-alist)
6696 luser item)
6697 (while choices
6698 (setq item (pop choices))
6699 (when (and (string-match (or (nth 0 item) "") (or method ""))
6700 (string-match (or (nth 1 item) "") (or host "")))
6701 (setq luser (nth 2 item))
6702 (setq choices nil)))
6703 luser)
6704 tramp-default-user))
6705
8a4438b6 6706(defun tramp-find-host (method user host)
00d6fd04
MA
6707 "Return the right host string to use.
6708This is HOST, if non-nil. Otherwise, it is `tramp-default-host'."
6709 (or (and (> (length host) 0) host)
6710 tramp-default-host))
6711
9ce8462a 6712(defun tramp-dissect-file-name (name &optional nodefault)
00d6fd04 6713 "Return a `tramp-file-name' structure.
9ce8462a
MA
6714The structure consists of remote method, remote user, remote host
6715and localname (file name on remote host). If NODEFAULT is
6716non-nil, the file name parts are not expanded to their default
6717values."
4007ba5b 6718 (save-match-data
00d6fd04 6719 (let ((match (string-match (nth 0 tramp-file-name-structure) name)))
a4aeb9a4 6720 (unless match (error "Not a Tramp file name: %s" name))
00d6fd04
MA
6721 (let ((method (match-string (nth 1 tramp-file-name-structure) name))
6722 (user (match-string (nth 2 tramp-file-name-structure) name))
6723 (host (match-string (nth 3 tramp-file-name-structure) name))
6724 (localname (match-string (nth 4 tramp-file-name-structure) name)))
5d449a36
MA
6725 (when (member method '("multi" "multiu"))
6726 (error
6727 "`%s' method is no longer supported, see (info \"(tramp)Multi-hops\")"
6728 method))
9ce8462a
MA
6729 (if nodefault
6730 (vector method user host localname)
6731 (vector
6732 (tramp-find-method method user host)
6733 (tramp-find-user method user host)
6734 (tramp-find-host method user host)
6735 localname))))))
00d6fd04
MA
6736
6737(defun tramp-equal-remote (file1 file2)
6738 "Checks, whether the remote parts of FILE1 and FILE2 are identical.
6739The check depends on method, user and host name of the files. If
6740one of the components is missing, the default values are used.
6741The local file name parts of FILE1 and FILE2 are not taken into
6742account.
fb7933a3 6743
00d6fd04
MA
6744Example:
6745
6746 (tramp-equal-remote \"/ssh::/etc\" \"/<your host name>:/home\")
6747
6748would yield `t'. On the other hand, the following check results in nil:
6749
6750 (tramp-equal-remote \"/sudo::/etc\" \"/su::/etc\")"
9e6ab520
MA
6751 (and (stringp (file-remote-p file1))
6752 (stringp (file-remote-p file2))
94be87e8 6753 (string-equal (file-remote-p file1) (file-remote-p file2))))
00d6fd04
MA
6754
6755(defun tramp-make-tramp-file-name (method user host localname)
6756 "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME."
6757 (concat tramp-prefix-format
6758 (when (not (zerop (length method)))
6759 (concat method tramp-postfix-method-format))
6760 (when (not (zerop (length user)))
6761 (concat user tramp-postfix-user-format))
6762 (when host host) tramp-postfix-host-format
6763 (when localname localname)))
6764
6765(defun tramp-completion-make-tramp-file-name (method user host localname)
6766 "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME.
6767It must not be a complete Tramp file name, but as long as there are
6768necessary only. This function will be used in file name completion."
6769 (concat tramp-prefix-format
6770 (when (not (zerop (length method)))
6771 (concat method tramp-postfix-method-format))
6772 (when (not (zerop (length user)))
6773 (concat user tramp-postfix-user-format))
6774 (when (not (zerop (length host)))
6775 (concat host tramp-postfix-host-format))
6776 (when localname localname)))
6777
6778(defun tramp-make-copy-program-file-name (vec)
6779 "Create a file name suitable to be passed to `rcp' and workalikes."
6780 (let ((user (tramp-file-name-user vec))
0f205eee 6781 (host (tramp-file-name-real-host vec))
00d6fd04
MA
6782 (localname (tramp-shell-quote-argument
6783 (tramp-file-name-localname vec))))
6784 (if (not (zerop (length user)))
6785 (format "%s@%s:%s" user host localname)
6786 (format "%s:%s" host localname))))
6787
6788(defun tramp-method-out-of-band-p (vec)
38c65fca 6789 "Return t if this is an out-of-band method, nil otherwise."
00d6fd04 6790 (tramp-get-method-parameter (tramp-file-name-method vec) 'tramp-copy-program))
fb7933a3 6791
0f205eee
MA
6792(defun tramp-local-host-p (vec)
6793 "Return t if this points to the local host, nil otherwise."
c992abdb
MA
6794 ;; We cannot use `tramp-file-name-real-host'. A port is an
6795 ;; indication for an ssh tunnel or alike.
6796 (let ((host (tramp-file-name-host vec)))
0f205eee
MA
6797 (and
6798 (stringp host)
6799 (string-match
a0a5183a
MA
6800 (concat "^" (regexp-opt (list "localhost" (system-name)) t) "$") host)
6801 ;; The local temp directory must be writable for the other user.
6802 (file-writable-p
6803 (tramp-make-tramp-file-name
6804 (tramp-file-name-method vec)
6805 (tramp-file-name-user vec)
6806 host
6807 (tramp-compat-temporary-file-directory))))))
0f205eee 6808
fb7933a3
KG
6809;; Variables local to connection.
6810
f84638eb
MA
6811(defun tramp-get-remote-path (vec)
6812 (with-connection-property vec "remote-path"
9e6ab520 6813 (let* ((remote-path (tramp-compat-copy-tree tramp-remote-path))
f84638eb
MA
6814 (elt (memq 'tramp-default-remote-path remote-path))
6815 (default-remote-path
6816 (when elt
6817 (condition-case nil
6818 (symbol-name
6819 (tramp-send-command-and-read vec "getconf PATH"))
6820 ;; Default if "getconf" is not available.
6821 (error
6822 (tramp-message
6823 vec 3
6824 "`getconf PATH' not successful, using default value \"%s\"."
6825 "/bin:/usr/bin")
6826 "/bin:/usr/bin")))))
6827 (when elt
6828 ;; Replace place holder `tramp-default-remote-path'.
6829 (setcdr elt
6830 (append
6831 (tramp-split-string default-remote-path ":")
6832 (cdr elt)))
6833 (setq remote-path (delq 'tramp-default-remote-path remote-path)))
6834
6835 ;; Remove non-existing directories.
6836 (delq
6837 nil
6838 (mapcar
6839 (lambda (x)
6840 (and
6841 (with-connection-property vec x
6842 (file-directory-p
6843 (tramp-make-tramp-file-name
6844 (tramp-file-name-method vec)
6845 (tramp-file-name-user vec)
6846 (tramp-file-name-host vec)
6847 x)))
6848 x))
6849 remote-path)))))
6850
a4aeb9a4
MA
6851(defun tramp-get-remote-tmpdir (vec)
6852 (with-connection-property vec "tmp-directory"
6853 (let ((dir (tramp-shell-quote-argument "/tmp")))
6854 (if (and (zerop
6855 (tramp-send-command-and-check
6856 vec (format "%s -d %s" (tramp-get-test-command vec) dir)))
6857 (zerop
6858 (tramp-send-command-and-check
6859 vec (format "%s -w %s" (tramp-get-test-command vec) dir))))
6860 dir
6861 (tramp-error vec 'file-error "Directory %s not accessible" dir)))))
6862
00d6fd04
MA
6863(defun tramp-get-ls-command (vec)
6864 (with-connection-property vec "ls"
6865 (with-current-buffer (tramp-get-buffer vec)
6866 (tramp-message vec 5 "Finding a suitable `ls' command")
6867 (or
6868 (catch 'ls-found
6869 (dolist (cmd '("ls" "gnuls" "gls"))
f84638eb 6870 (let ((dl (tramp-get-remote-path vec))
00d6fd04
MA
6871 result)
6872 (while
6873 (and
6874 dl
6875 (setq result
6876 (tramp-find-executable vec cmd dl t t)))
6877 ;; Check parameter.
6878 (when (zerop (tramp-send-command-and-check
6879 vec (format "%s -lnd /" result)))
6880 (throw 'ls-found result))
00d6fd04
MA
6881 (setq dl (cdr dl))))))
6882 (tramp-error vec 'file-error "Couldn't find a proper `ls' command")))))
6883
6884(defun tramp-get-test-command (vec)
6885 (with-connection-property vec "test"
6886 (with-current-buffer (tramp-get-buffer vec)
6887 (tramp-message vec 5 "Finding a suitable `test' command")
6888 (if (zerop (tramp-send-command-and-check vec "test 0"))
6889 "test"
f84638eb 6890 (tramp-find-executable vec "test" (tramp-get-remote-path vec))))))
00d6fd04
MA
6891
6892(defun tramp-get-test-nt-command (vec)
6893 ;; Does `test A -nt B' work? Use abominable `find' construct if it
6894 ;; doesn't. BSD/OS 4.0 wants the parentheses around the command,
6895 ;; for otherwise the shell crashes.
6896 (with-connection-property vec "test-nt"
6897 (or
6898 (progn
6899 (tramp-send-command
6900 vec (format "( %s / -nt / )" (tramp-get-test-command vec)))
6901 (with-current-buffer (tramp-get-buffer vec)
6902 (goto-char (point-min))
a0a5183a 6903 (when (looking-at (regexp-quote tramp-end-of-output))
00d6fd04
MA
6904 (format "%s %%s -nt %%s" (tramp-get-test-command vec)))))
6905 (progn
6906 (tramp-send-command
6907 vec
6908 (format
6909 "tramp_test_nt () {\n%s -n \"`find $1 -prune -newer $2 -print`\"\n}"
6910 (tramp-get-test-command vec)))
6911 "tramp_test_nt %s %s"))))
6912
6913(defun tramp-get-file-exists-command (vec)
6914 (with-connection-property vec "file-exists"
6915 (with-current-buffer (tramp-get-buffer vec)
6916 (tramp-message vec 5 "Finding command to check if file exists")
6917 (tramp-find-file-exists-command vec))))
6918
6919(defun tramp-get-remote-ln (vec)
6920 (with-connection-property vec "ln"
6921 (with-current-buffer (tramp-get-buffer vec)
6922 (tramp-message vec 5 "Finding a suitable `ln' command")
f84638eb 6923 (tramp-find-executable vec "ln" (tramp-get-remote-path vec)))))
00d6fd04
MA
6924
6925(defun tramp-get-remote-perl (vec)
6926 (with-connection-property vec "perl"
6927 (with-current-buffer (tramp-get-buffer vec)
6928 (tramp-message vec 5 "Finding a suitable `perl' command")
f84638eb
MA
6929 (or (tramp-find-executable vec "perl5" (tramp-get-remote-path vec))
6930 (tramp-find-executable vec "perl" (tramp-get-remote-path vec))))))
00d6fd04
MA
6931
6932(defun tramp-get-remote-stat (vec)
6933 (with-connection-property vec "stat"
6934 (with-current-buffer (tramp-get-buffer vec)
6935 (tramp-message vec 5 "Finding a suitable `stat' command")
f84638eb
MA
6936 (let ((result (tramp-find-executable
6937 vec "stat" (tramp-get-remote-path vec)))
00d6fd04
MA
6938 tmp)
6939 ;; Check whether stat(1) returns usable syntax.
6940 (when result
6941 (setq tmp
6942 ;; We don't want to display an error message.
6943 (with-temp-message (or (current-message) "")
6944 (condition-case nil
6945 (tramp-send-command-and-read
6946 vec (format "%s -c '(\"%%N\")' /" result))
6947 (error nil))))
6948 (unless (and (listp tmp) (stringp (car tmp))
6949 (string-match "^./.$" (car tmp)))
6950 (setq result nil)))
6951 result))))
fb7933a3 6952
00d6fd04
MA
6953(defun tramp-get-remote-id (vec)
6954 (with-connection-property vec "id"
6955 (with-current-buffer (tramp-get-buffer vec)
6956 (tramp-message vec 5 "Finding POSIX `id' command")
6957 (or
6958 (catch 'id-found
f84638eb 6959 (let ((dl (tramp-get-remote-path vec))
00d6fd04
MA
6960 result)
6961 (while
6962 (and
6963 dl
6964 (setq result
6965 (tramp-find-executable vec "id" dl t t)))
6966 ;; Check POSIX parameter.
6967 (when (zerop (tramp-send-command-and-check
6968 vec (format "%s -u" result)))
6969 (throw 'id-found result))
00d6fd04
MA
6970 (setq dl (cdr dl)))))
6971 (tramp-error vec 'file-error "Couldn't find a POSIX `id' command")))))
6972
6973(defun tramp-get-remote-uid (vec id-format)
6974 (with-connection-property vec (format "uid-%s" id-format)
6975 (let ((res (tramp-send-command-and-read
6976 vec
6977 (format "%s -u%s %s"
6978 (tramp-get-remote-id vec)
6979 (if (equal id-format 'integer) "" "n")
6980 (if (equal id-format 'integer)
6981 "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
6982 ;; The command might not always return a number.
6983 (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
6984
6985(defun tramp-get-remote-gid (vec id-format)
6986 (with-connection-property vec (format "gid-%s" id-format)
6987 (let ((res (tramp-send-command-and-read
6988 vec
6989 (format "%s -g%s %s"
6990 (tramp-get-remote-id vec)
6991 (if (equal id-format 'integer) "" "n")
6992 (if (equal id-format 'integer)
6993 "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/")))))
6994 ;; The command might not always return a number.
6995 (if (and (equal id-format 'integer) (not (integerp res))) -1 res))))
fb7933a3 6996
8d60099b
MA
6997(defun tramp-get-local-uid (id-format)
6998 (if (equal id-format 'integer) (user-uid) (user-login-name)))
6999
7000(defun tramp-get-local-gid (id-format)
9e6ab520 7001 (nth 3 (tramp-compat-file-attributes "~/" id-format)))
8d60099b 7002
00d6fd04
MA
7003;; Some predefined connection properties.
7004(defun tramp-get-remote-coding (vec prop)
7005 ;; Local coding handles properties like remote coding. So we could
7006 ;; call it without pain.
7007 (let ((ret (tramp-get-local-coding vec prop)))
7008 ;; The connection property might have been cached. So we must send
7009 ;; the script - maybe.
7010 (when (not (stringp ret))
7011 (let ((name (symbol-name ret)))
7012 (while (string-match (regexp-quote "-") name)
7013 (setq name (replace-match "_" nil t name)))
7014 (tramp-maybe-send-script vec (symbol-value ret) name)
7015 (setq ret name)))
7016 ;; Return the value.
7017 ret))
7018
7019(defun tramp-get-local-coding (vec prop)
bf0503cb 7020 (or
00d6fd04
MA
7021 (tramp-get-connection-property vec prop nil)
7022 (progn
7023 (tramp-find-inline-encoding vec)
7024 (tramp-get-connection-property vec prop nil))))
fb7933a3 7025
00d6fd04 7026(defun tramp-get-method-parameter (method param)
c951aecb 7027 "Return the method parameter PARAM.
00d6fd04
MA
7028If the `tramp-methods' entry does not exist, return NIL."
7029 (let ((entry (assoc param (assoc method tramp-methods))))
7030 (when entry (cadr entry))))
90f8dc03 7031
fb7933a3
KG
7032;; Auto saving to a special directory.
7033
00cec167 7034(defun tramp-exists-file-name-handler (operation &rest args)
00d6fd04
MA
7035 "Checks whether OPERATION runs a file name handler."
7036 ;; The file name handler is determined on base of either an
7037 ;; argument, `buffer-file-name', or `default-directory'.
7038 (condition-case nil
7039 (let* ((buffer-file-name "/")
7040 (default-directory "/")
7041 (fnha file-name-handler-alist)
7042 (check-file-name-operation operation)
7043 (file-name-handler-alist
7044 (list
7045 (cons "/"
7046 '(lambda (operation &rest args)
7047 "Returns OPERATION if it is the one to be checked."
7048 (if (equal check-file-name-operation operation)
7049 operation
7050 (let ((file-name-handler-alist fnha))
7051 (apply operation args))))))))
7052 (equal (apply operation args) operation))
7053 (error nil)))
c1105d05
MA
7054
7055(unless (tramp-exists-file-name-handler 'make-auto-save-file-name)
7056 (defadvice make-auto-save-file-name
7057 (around tramp-advice-make-auto-save-file-name () activate)
00d6fd04 7058 "Invoke `tramp-handle-make-auto-save-file-name' for Tramp files."
c1105d05 7059 (if (and (buffer-file-name) (tramp-tramp-file-p (buffer-file-name)))
00cec167 7060 (setq ad-return-value (tramp-handle-make-auto-save-file-name))
a69c01a0
MA
7061 ad-do-it))
7062 (add-hook 'tramp-unload-hook
7063 '(lambda () (ad-unadvise 'make-auto-save-file-name))))
fb7933a3 7064
340b8d4f
MA
7065;; In Emacs < 22 and XEmacs < 21.5 autosaved remote files have
7066;; permission 0666 minus umask. This is a security threat.
414da5ab
MA
7067
7068(defun tramp-set-auto-save-file-modes ()
7069 "Set permissions of autosaved remote files to the original permissions."
7070 (let ((bfn (buffer-file-name)))
7071 (when (and (stringp bfn)
7072 (tramp-tramp-file-p bfn)
b50dd0d2 7073 (buffer-modified-p)
414da5ab 7074 (stringp buffer-auto-save-file-name)
340b8d4f
MA
7075 (not (equal bfn buffer-auto-save-file-name)))
7076 (unless (file-exists-p buffer-auto-save-file-name)
7077 (write-region "" nil buffer-auto-save-file-name))
7078 ;; Permissions should be set always, because there might be an old
7079 ;; auto-saved file belonging to another original file. This could
7080 ;; be a security threat.
7177e2a3 7081 (set-file-modes buffer-auto-save-file-name
11948172 7082 (or (file-modes bfn) (tramp-octal-to-decimal "0600"))))))
414da5ab
MA
7083
7084(unless (or (> emacs-major-version 21)
7085 (and (featurep 'xemacs)
7086 (= emacs-major-version 21)
340b8d4f 7087 (> emacs-minor-version 4)))
a69c01a0
MA
7088 (add-hook 'auto-save-hook 'tramp-set-auto-save-file-modes)
7089 (add-hook 'tramp-unload-hook
7090 '(lambda ()
7091 (remove-hook 'auto-save-hook 'tramp-set-auto-save-file-modes))))
414da5ab 7092
fb7933a3
KG
7093(defun tramp-subst-strs-in-string (alist string)
7094 "Replace all occurrences of the string FROM with TO in STRING.
7095ALIST is of the form ((FROM . TO) ...)."
7096 (save-match-data
7097 (while alist
7098 (let* ((pr (car alist))
7099 (from (car pr))
7100 (to (cdr pr)))
7101 (while (string-match (regexp-quote from) string)
7102 (setq string (replace-match to t t string)))
7103 (setq alist (cdr alist))))
7104 string))
7105
fb7933a3
KG
7106;; ------------------------------------------------------------
7107;; -- Compatibility functions section --
7108;; ------------------------------------------------------------
7109
00d6fd04 7110(defun tramp-read-passwd (proc &optional prompt)
fb7933a3 7111 "Read a password from user (compat function).
5ec2cc41 7112Invokes `password-read' if available, `read-passwd' else."
00d6fd04
MA
7113 (let* ((key (tramp-make-tramp-file-name
7114 tramp-current-method tramp-current-user
7115 tramp-current-host ""))
7116 (pw-prompt
7117 (or prompt
7118 (with-current-buffer (process-buffer proc)
7119 (tramp-check-for-regexp proc tramp-password-prompt-regexp)
7120 (format "%s for %s " (capitalize (match-string 1)) key)))))
7121 (if (functionp 'password-read)
9e6ab520
MA
7122 (let ((password (funcall (symbol-function 'password-read)
7123 pw-prompt key)))
7124 (funcall (symbol-function 'password-cache-add) key password)
00d6fd04
MA
7125 password)
7126 (read-passwd pw-prompt))))
7127
9c13938d
MA
7128(defun tramp-clear-passwd (vec)
7129 "Clear password cache for connection related to VEC."
00d6fd04 7130 (when (functionp 'password-cache-remove)
9c13938d
MA
7131 (funcall
7132 (symbol-function 'password-cache-remove)
7133 (tramp-make-tramp-file-name
7134 (tramp-file-name-method vec)
7135 (tramp-file-name-user vec)
7136 (tramp-file-name-host vec)
7137 ""))))
00d6fd04
MA
7138
7139;; Snarfed code from time-date.el and parse-time.el
7140
7141(defconst tramp-half-a-year '(241 17024)
7142"Evaluated by \"(days-to-time 183)\".")
7143
7144(defconst tramp-parse-time-months
7145 '(("jan" . 1) ("feb" . 2) ("mar" . 3)
7146 ("apr" . 4) ("may" . 5) ("jun" . 6)
7147 ("jul" . 7) ("aug" . 8) ("sep" . 9)
7148 ("oct" . 10) ("nov" . 11) ("dec" . 12))
7149 "Alist mapping month names to integers.")
7150
7151(defun tramp-time-less-p (t1 t2)
7152 "Say whether time value T1 is less than time value T2."
7153 (unless t1 (setq t1 '(0 0)))
7154 (unless t2 (setq t2 '(0 0)))
7155 (or (< (car t1) (car t2))
7156 (and (= (car t1) (car t2))
7157 (< (nth 1 t1) (nth 1 t2)))))
7158
7159(defun tramp-time-subtract (t1 t2)
7160 "Subtract two time values.
7161Return the difference in the format of a time value."
7162 (unless t1 (setq t1 '(0 0)))
7163 (unless t2 (setq t2 '(0 0)))
7164 (let ((borrow (< (cadr t1) (cadr t2))))
7165 (list (- (car t1) (car t2) (if borrow 1 0))
7166 (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2)))))
fb7933a3
KG
7167
7168(defun tramp-time-diff (t1 t2)
7169 "Return the difference between the two times, in seconds.
1a762140 7170T1 and T2 are time values (as returned by `current-time' for example)."
fb7933a3 7171 ;; Pacify byte-compiler with `symbol-function'.
ea9d1443
KG
7172 (cond ((and (fboundp 'subtract-time)
7173 (fboundp 'float-time))
7174 (funcall (symbol-function 'float-time)
7175 (funcall (symbol-function 'subtract-time) t1 t2)))
7176 ((and (fboundp 'subtract-time)
7177 (fboundp 'time-to-seconds))
7178 (funcall (symbol-function 'time-to-seconds)
7179 (funcall (symbol-function 'subtract-time) t1 t2)))
fb7933a3 7180 ((fboundp 'itimer-time-difference)
1a762140
MA
7181 (funcall (symbol-function 'itimer-time-difference)
7182 (if (< (length t1) 3) (append t1 '(0)) t1)
7183 (if (< (length t2) 3) (append t2 '(0)) t2)))
fb7933a3 7184 (t
00d6fd04 7185 (let ((time (tramp-time-subtract t1 t2)))
ea9d1443
KG
7186 (+ (* (car time) 65536.0)
7187 (cadr time)
7188 (/ (or (nth 2 time) 0) 1000000.0))))))
fb7933a3
KG
7189
7190(defun tramp-coding-system-change-eol-conversion (coding-system eol-type)
7191 "Return a coding system like CODING-SYSTEM but with given EOL-TYPE.
7192EOL-TYPE can be one of `dos', `unix', or `mac'."
7193 (cond ((fboundp 'coding-system-change-eol-conversion)
9e6ab520
MA
7194 (funcall (symbol-function 'coding-system-change-eol-conversion)
7195 coding-system eol-type))
fb7933a3 7196 ((fboundp 'subsidiary-coding-system)
9e6ab520
MA
7197 (funcall (symbol-function 'subsidiary-coding-system)
7198 coding-system
7199 (cond ((eq eol-type 'dos) 'crlf)
7200 ((eq eol-type 'unix) 'lf)
7201 ((eq eol-type 'mac) 'cr)
7202 (t
7203 (error "Unknown EOL-TYPE `%s', must be %s"
7204 eol-type
7205 "`dos', `unix', or `mac'")))))
fb7933a3
KG
7206 (t (error "Can't change EOL conversion -- is MULE missing?"))))
7207
7208(defun tramp-split-string (string pattern)
7209 "Like `split-string' but omit empty strings.
7210In Emacs, (split-string \"/foo/bar\" \"/\") returns (\"foo\" \"bar\").
7211This is, the first, empty, element is omitted. In XEmacs, the first
7212element is not omitted.
7213
7214Note: this function has been written for `tramp-handle-file-truename'.
7215If you want to use it for something else, you'll have to check whether
7216it does the right thing."
7217 (delete "" (split-string string pattern)))
7218
19a87064
MA
7219(defun tramp-set-process-query-on-exit-flag (process flag)
7220 "Specify if query is needed for process when Emacs is exited.
7221If the second argument flag is non-nil, Emacs will query the user before
7222exiting if process is running."
7223 (if (fboundp 'set-process-query-on-exit-flag)
00d6fd04
MA
7224 (funcall (symbol-function 'set-process-query-on-exit-flag) process flag)
7225 (funcall (symbol-function 'process-kill-without-query) process flag)))
19a87064 7226
19a87064 7227
bf247b6e
KS
7228;; ------------------------------------------------------------
7229;; -- Kludges section --
7230;; ------------------------------------------------------------
fb7933a3
KG
7231
7232;; Currently (as of Emacs 20.5), the function `shell-quote-argument'
7233;; does not deal well with newline characters. Newline is replaced by
7234;; backslash newline. But if, say, the string `a backslash newline b'
7235;; is passed to a shell, the shell will expand this into "ab",
7236;; completely omitting the newline. This is not what was intended.
7237;; It does not appear to be possible to make the function
7238;; `shell-quote-argument' work with newlines without making it
7239;; dependent on the shell used. But within this package, we know that
7240;; we will always use a Bourne-like shell, so we use an approach which
7241;; groks newlines.
7242;;
7243;; The approach is simple: we call `shell-quote-argument', then
7244;; massage the newline part of the result.
7245;;
7246;; This function should produce a string which is grokked by a Unix
7247;; shell, even if the Emacs is running on Windows. Since this is the
7248;; kludges section, we bind `system-type' in such a way that
7249;; `shell-quote-arguments' behaves as if on Unix.
7250;;
7251;; Thanks to Mario DeWeerd for the hint that it is sufficient for this
7252;; function to work with Bourne-like shells.
7253;;
7254;; CCC: This function should be rewritten so that
7255;; `shell-quote-argument' is not used. This way, we are safe from
7256;; changes in `shell-quote-argument'.
7257(defun tramp-shell-quote-argument (s)
7258 "Similar to `shell-quote-argument', but groks newlines.
7259Only works for Bourne-like shells."
7260 (let ((system-type 'not-windows))
7261 (save-match-data
7262 (let ((result (shell-quote-argument s))
7263 (nl (regexp-quote (format "\\%s" tramp-rsh-end-of-line))))
7264 (when (and (>= (length result) 2)
7265 (string= (substring result 0 2) "\\~"))
7266 (setq result (substring result 1)))
7267 (while (string-match nl result)
7268 (setq result (replace-match (format "'%s'" tramp-rsh-end-of-line)
7269 t t result)))
7270 result))))
7271
16674e4f
KG
7272;; We currently (sometimes) use "[" and "]" in the filename format.
7273;; This means that Emacs wants to expand wildcards if
fb7933a3
KG
7274;; `find-file-wildcards' is non-nil, and then barfs because no
7275;; expansion could be found. We detect this situation and do
7276;; something really awful: we have `file-expand-wildcards' return the
7277;; original filename if it can't expand anything. Let's just hope
7278;; that this doesn't break anything else.
16674e4f
KG
7279;; CCC: This check is now also really awful; we should search all
7280;; of the filename format, not just the prefix.
7281(when (string-match "\\[" tramp-prefix-format)
1834b39f
MA
7282 (defadvice file-expand-wildcards
7283 (around tramp-advice-file-expand-wildcards activate)
d2a2c17f
MA
7284 (let ((name (ad-get-arg 0)))
7285 (if (tramp-tramp-file-p name)
7286 ;; If it's a Tramp file, dissect it and look if wildcards
7287 ;; need to be expanded at all.
1834b39f
MA
7288 (if (string-match
7289 "[[*?]"
7290 (tramp-file-name-localname (tramp-dissect-file-name name)))
7291 (setq ad-return-value (or ad-do-it (list name)))
7292 (setq ad-return-value (list name)))
d2a2c17f 7293 ;; If it is not a Tramp file, just run the original function.
1834b39f 7294 (setq ad-return-value (or ad-do-it (list name))))))
a69c01a0
MA
7295 (add-hook 'tramp-unload-hook
7296 '(lambda () (ad-unadvise 'file-expand-wildcards))))
fb7933a3 7297
a69c01a0
MA
7298;; Checklist for `tramp-unload-hook'
7299;; - Unload all `tramp-*' packages
7300;; - Reset `file-name-handler-alist'
7301;; - Cleanup hooks where Tramp functions are in
7302;; - Cleanup advised functions
7303;; - Cleanup autoloads
7304;;;###autoload
7305(defun tramp-unload-tramp ()
08b1eb21 7306 "Discard Tramp from loading remote files."
a69c01a0
MA
7307 (interactive)
7308 ;; When Tramp is not loaded yet, its autoloads are still active.
8c04e197 7309 (tramp-unload-file-name-handlers)
a69c01a0
MA
7310 ;; ange-ftp settings must be enabled.
7311 (when (functionp 'tramp-ftp-enable-ange-ftp)
7312 (funcall (symbol-function 'tramp-ftp-enable-ange-ftp)))
00d6fd04
MA
7313 ;; Maybe its not loaded yet.
7314 (condition-case nil
7315 (unload-feature 'tramp 'force)
a69c01a0
MA
7316 (error nil)))
7317
fb7933a3
KG
7318(provide 'tramp)
7319
fb7933a3
KG
7320;;; TODO:
7321
4007ba5b
KG
7322;; * Allow putting passwords in the filename.
7323;; This should be implemented via a general mechanism to add
7324;; parameters in filenames. There is currently a kludge for
7325;; putting the port number into the filename for ssh and ftp
7326;; files. This could be subsumed by the new mechanism as well.
7327;; Another approach is to read a netrc file like ~/.authinfo
7328;; from Gnus.
7329;; * Handle nonlocal exits such as C-g.
00d6fd04
MA
7330;; * But it would probably be better to use with-local-quit at the
7331;; place where it's actually needed: around any potentially
7332;; indefinitely blocking piece of code. In this case it would be
7333;; within Tramp around one of its calls to accept-process-output (or
7334;; around one of the loops that calls accept-process-output)
d037d501 7335;; (Stefan Monnier).
16674e4f 7336;; * Autodetect if remote `ls' groks the "--dired" switch.
fb7933a3 7337;; * Rewrite `tramp-shell-quote-argument' to abstain from using
b1d06e75 7338;; `shell-quote-argument'.
fb7933a3
KG
7339;; * In Emacs 21, `insert-directory' shows total number of bytes used
7340;; by the files in that directory. Add this here.
7341;; * Avoid screen blanking when hitting `g' in dired. (Eli Tziperman)
7342;; * Make ffap.el grok Tramp filenames. (Eli Tziperman)
7343;; * When logging in, keep looking for questions according to an alist
7344;; and then invoke the right function.
7345;; * Case-insensitive filename completion. (Norbert Goevert.)
fb7933a3
KG
7346;; * Don't use globbing for directories with many files, as this is
7347;; likely to produce long command lines, and some shells choke on
7348;; long command lines.
fb7933a3
KG
7349;; * `vc-directory' does not work. It never displays any files, even
7350;; if it does show files when run locally.
7351;; * Allow correction of passwords, if the remote end allows this.
7352;; (Mark Hershberger)
fb7933a3 7353;; * How to deal with MULE in `insert-file-contents' and `write-region'?
fb7933a3
KG
7354;; * Grok `append' parameter for `write-region'.
7355;; * Test remote ksh or bash for tilde expansion in `tramp-find-shell'?
7356;; * abbreviate-file-name
fb7933a3
KG
7357;; * better error checking. At least whenever we see something
7358;; strange when doing zerop, we should kill the process and start
7359;; again. (Greg Stark)
fb7933a3
KG
7360;; * Provide a local cache of old versions of remote files for the rsync
7361;; transfer method to use. (Greg Stark)
7362;; * Remove unneeded parameters from methods.
7363;; * Invoke rsync once for copying a whole directory hierarchy.
cdd44874 7364;; (Francesco Potortì)
fb7933a3
KG
7365;; * Make it work for different encodings, and for different file name
7366;; encodings, too. (Daniel Pittman)
fb7933a3 7367;; * Progress reports while copying files. (Michael Kifer)
fb7933a3
KG
7368;; * Don't search for perl5 and perl. Instead, only search for perl and
7369;; then look if it's the right version (with `perl -v').
7370;; * When editing a remote CVS controlled file as a different user, VC
7371;; gets confused about the file locking status. Try to find out why
7372;; the workaround doesn't work.
3cdaec13 7373;; * Username and hostname completion.
6c4e47fa 7374;; ** Try to avoid usage of `last-input-event' in `tramp-completion-mode-p'.
8daea7fc 7375;; ** Unify `tramp-parse-{rhosts,shosts,sconfig,hosts,passwd,netrc}'.
16674e4f 7376;; Code is nearly identical.
cfb5c0db
MA
7377;; * Allow out-of-band methods as _last_ multi-hop. Open a connection
7378;; until the last but one hop via `start-file-process'. Apply it
7379;; also for ftp and smb.
00d6fd04
MA
7380;; * WIBNI if we had a command "trampclient"? If I was editing in
7381;; some shell with root priviledges, it would be nice if I could
7382;; just call
7383;; trampclient filename.c
7384;; as an editor, and the _current_ shell would connect to an Emacs
7385;; server and would be used in an existing non-priviledged Emacs
7386;; session for doing the editing in question.
7387;; That way, I need not tell Emacs my password again and be afraid
7388;; that it makes it into core dumps or other ugly stuff (I had Emacs
7389;; once display a just typed password in the context of a keyboard
7390;; sequence prompt for a question immediately following in a shell
7391;; script run within Emacs -- nasty).
7392;; And if I have some ssh session running to a different computer,
7393;; having the possibility of passing a local file there to a local
7394;; Emacs session (in case I can arrange for a connection back) would
7395;; be nice.
a4aeb9a4 7396;; Likely the corresponding Tramp server should not allow the
00d6fd04
MA
7397;; equivalent of the emacsclient -eval option in order to make this
7398;; reasonably unproblematic. And maybe trampclient should have some
7399;; way of passing credentials, like by using an SSL socket or
7400;; something. (David Kastrup)
7401;; * Could Tramp reasonably look for a prompt after ^M rather than
7402;; only after ^J ? (Stefan Monnier)
00d6fd04
MA
7403;; * Reconnect directly to a compliant shell without first going
7404;; through the user's default shell. (Pete Forman)
00d6fd04 7405;; * Make `tramp-default-user' obsolete.
adb67129
MA
7406;; * Tramp shall reconnect automatically to its ssh connection when it
7407;; detects that the process "has died". (David Reitter)
fb7933a3
KG
7408
7409;; Functions for file-name-handler-alist:
7410;; diff-latest-backup-file -- in diff.el
fb7933a3
KG
7411;; dired-uncache -- this will be needed when we do insert-directory caching
7412;; file-name-as-directory -- use primitive?
fb7933a3 7413;; file-name-sans-versions -- use primitive?
fb7933a3 7414;; get-file-buffer -- use primitive
fb7933a3
KG
7415;; vc-registered
7416
cdd44874 7417;; arch-tag: 3a21a994-182b-48fa-b0cd-c1d9fede424a
fb7933a3 7418;;; tramp.el ends here
57671b72
MA
7419
7420;; Local Variables:
7421;; mode: Emacs-Lisp
7422;; coding: utf-8
7423;; End: