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