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