tramp.el 231 KB
Newer Older
Kai Großjohann's avatar
Kai Großjohann committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
;;; tramp.el --- Transparent Remote Access, Multiple Protocol -*- coding: iso-8859-1; -*- 

;; Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.

;; Author: Kai.Grossjohann@CS.Uni-Dortmund.DE 
;; Keywords: comm, processes

;; This file is part of GNU Emacs.

;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;; Commentary:

;; This package provides remote file editing, similar to ange-ftp.
;; The difference is that ange-ftp uses FTP to transfer files between
;; the local and the remote host, whereas tramp.el uses a combination
;; of rsh and rcp or other work-alike programs, such as ssh/scp.
;;
;; For more detailed instructions, please see the info file, which is
;; included in the file `tramp.tar.gz' mentioned below.
;;
;; Notes:
;; -----
;; 
;; This package only works for Emacs 20 and higher, and for XEmacs 21
;; and higher.  (XEmacs 20 is missing the `with-timeout' macro.  Emacs
;; 19 is reported to have other problems.  For XEmacs 21, you need the
;; package `fsf-compat' for the `with-timeout' macro.)
;;
;; This version might not work with pre-Emacs 21 VC unless VC is
;; loaded before tramp.el.  Could you please test this and tell me about
;; the result?  Thanks.
;;
;; Also see the todo list at the bottom of this file.
;;
;; The current version of tramp.el can be retrieved from the following
;; URL:  ftp://ls6-ftp.cs.uni-dortmund.de/pub/src/emacs/tramp.tar.gz
;; For your convenience, the *.el file is available separately from
;; the same directory.
;;
;; There's a mailing list for this, as well.  Its name is:
55
;;                tramp-devel@mail.freesoftware.fsf.org
Kai Großjohann's avatar
Kai Großjohann committed
56 57 58
;; Send a mail with `help' in the subject (!) to the administration
;; address for instructions on joining the list.  The administration
;; address is:
59
;;            tramp-devel-request@mail.freesoftware.fsf.org
Kai Großjohann's avatar
Kai Großjohann committed
60
;; You can also use the Web to subscribe, under the following URL:
61
;;            http://mail.freesoftware.fsf.org/mailman/listinfo/tramp-devel
Kai Großjohann's avatar
Kai Großjohann committed
62 63 64
;;
;; For the adventurous, the current development sources are available
;; via CVS.  You can find instructions about this at the following URL:
65
;;            http://savannah.gnu.org/projects/tramp/
Kai Großjohann's avatar
Kai Großjohann committed
66 67 68 69 70 71
;; Click on "CVS" in the navigation bar near the top.
;;
;; Don't forget to put on your asbestos longjohns, first!

;;; Code:

72
(defconst tramp-version "2.0.1"
Kai Großjohann's avatar
Kai Großjohann committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
  "This version of tramp.")
(defconst tramp-bug-report-address "tramp-devel@mail.freesoftware.fsf.org"
  "Email address to send bug reports to.")

(require 'timer)
(require 'format-spec)                  ;from Gnus 5.8, also in tar ball
(require 'base64)                       ;for the mimencode methods
(require 'shell)
(require 'advice)

;; ;; It does not work to load EFS after loading TRAMP.  
;; (when (fboundp 'efs-file-handler-function)
;;   (require 'efs))

(eval-when-compile
  (require 'cl)
  (require 'custom)
  ;; Emacs 19.34 compatibility hack -- is this needed?
  (or (>= emacs-major-version 20)
      (load "cl-seq")))

(unless (boundp 'custom-print-functions)
  (defvar custom-print-functions nil))	; not autoloaded before Emacs 20.4

;;; User Customizable Internal Variables:

(defgroup tramp nil
  "Edit remote files with a combination of rsh and rcp or similar programs."
  :group 'files)

(defcustom tramp-verbose 10
  "*Verbosity level for tramp.el.  0 means be silent, 10 is most verbose."
  :group 'tramp
  :type 'integer)

(defcustom tramp-debug-buffer nil
  "*Whether to send all commands and responses to a debug buffer."
  :group 'tramp
  :type 'boolean)

(defcustom tramp-auto-save-directory nil
  "*Put auto-save files in this directory, if set.
The idea is to use a local directory so that auto-saving is faster."
  :group 'tramp
  :type '(choice (const nil)
                 string))

(defcustom tramp-sh-program "/bin/sh"
  "*Use this program for shell commands on the local host.
This MUST be a Bourne-like shell.  This shell is used to execute
the encoding and decoding command on the local host, so if you
want to use `~' in those commands, you should choose a shell here
which groks tilde expansion.  `/bin/sh' normally does not
understand tilde expansion.

Note that this variable is not used for remote commands.  There are
mechanisms in tramp.el which automatically determine the right shell to
use for the remote host."
  :group 'tramp
  :type '(file :must-match t))

;; CCC I have changed all occurrences of comint-quote-filename with
;; tramp-shell-quote-argument, except in tramp-handle-expand-many-files.
;; There, comint-quote-filename was removed altogether.  If it turns
;; out to be necessary there, something will need to be done.
;;-(defcustom tramp-file-name-quote-list
;;-  '(?] ?[ ?\| ?& ?< ?> ?\( ?\) ?\; ?\  ?\* ?\? ?\! ?\" ?\' ?\` ?# ?\@ ?\+ )
;;-  "*Protect these characters from the remote shell.
;;-Any character in this list is quoted (preceded with a backslash)
;;-because it means something special to the shell.  This takes effect
;;-when sending file and directory names to the remote shell.
;;-
;;-See `comint-file-name-quote-list' for details."
;;-  :group 'tramp
;;-  :type '(repeat character))

(defcustom tramp-methods
  '( ("rcp"   (tramp-connection-function  tramp-open-connection-rsh)
              (tramp-rsh-program          "rsh")
              (tramp-rcp-program          "rcp")
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             nil)
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    "-p")
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     nil)
              (tramp-decoding-command     nil)
              (tramp-encoding-function    nil)
              (tramp-decoding-function    nil)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("scp"   (tramp-connection-function  tramp-open-connection-rsh)
              (tramp-rsh-program          "ssh")
              (tramp-rcp-program          "scp")
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             ("-e" "none"))
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    "-p")
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     nil)
              (tramp-decoding-command     nil)
              (tramp-encoding-function    nil)
              (tramp-decoding-function    nil)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("scp1"  (tramp-connection-function  tramp-open-connection-rsh)
              (tramp-rsh-program          "ssh1")
              (tramp-rcp-program          "scp1")
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             ("-e" "none"))
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    "-p")
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     nil)
              (tramp-decoding-command     nil)
              (tramp-encoding-function    nil)
              (tramp-decoding-function    nil)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("scp2"  (tramp-connection-function  tramp-open-connection-rsh)
              (tramp-rsh-program          "ssh2")
              (tramp-rcp-program          "scp2")
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             ("-e" "none"))
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    "-p")
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     nil)
              (tramp-decoding-command     nil)
              (tramp-encoding-function    nil)
              (tramp-decoding-function    nil)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("rsync" (tramp-connection-function  tramp-open-connection-rsh)
              (tramp-rsh-program          "ssh")
              (tramp-rcp-program          "rsync")
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             ("-e" "none"))
              (tramp-rcp-args             ("-e" "ssh"))
              (tramp-rcp-keep-date-arg    "-t")
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     nil)
              (tramp-decoding-command     nil)
              (tramp-encoding-function    nil)
              (tramp-decoding-function    nil)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("ru"    (tramp-connection-function  tramp-open-connection-rsh)
              (tramp-rsh-program          "rsh")
              (tramp-rcp-program          nil)
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             nil)
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    nil)
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     "uuencode xxx")
              (tramp-decoding-command
               "( uudecode -o - 2>/dev/null || uudecode -p 2>/dev/null )")
              (tramp-encoding-function    nil)
              (tramp-decoding-function    uudecode-decode-region)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("su"    (tramp-connection-function  tramp-open-connection-rsh)
              (tramp-rsh-program          "ssh")
              (tramp-rcp-program          nil)
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             ("-e" "none"))
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    nil)
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     "uuencode xxx")
              (tramp-decoding-command
               "( uudecode -o - 2>/dev/null || uudecode -p 2>/dev/null )")
              (tramp-encoding-function    nil)
              (tramp-decoding-function    uudecode-decode-region)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("su1"   (tramp-connection-function  tramp-open-connection-rsh)
              (tramp-rsh-program          "ssh1")
              (tramp-rcp-program          nil)
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             ("-e" "none"))
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    nil)
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     "uuencode xxx")
              (tramp-decoding-command
               "( uudecode -o - 2>/dev/null || uudecode -p 2>/dev/null )")
              (tramp-encoding-function    nil)
              (tramp-decoding-function    uudecode-decode-region)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("su2"   (tramp-connection-function  tramp-open-connection-rsh)
              (tramp-rsh-program          "ssh2")
              (tramp-rcp-program          nil)
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             ("-e" "none"))
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    nil)
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     "uuencode xxx")
              (tramp-decoding-command
               "( uudecode -o - 2>/dev/null || uudecode -p 2>/dev/null )")
              (tramp-encoding-function    nil)
              (tramp-decoding-function    uudecode-decode-region)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("rm"    (tramp-connection-function  tramp-open-connection-rsh)
              (tramp-rsh-program          "rsh")
              (tramp-rcp-program          nil)
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             nil)
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    nil)
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     "mimencode -b")
              (tramp-decoding-command     "mimencode -u -b")
              (tramp-encoding-function    base64-encode-region)
              (tramp-decoding-function    base64-decode-region)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("sm"    (tramp-connection-function  tramp-open-connection-rsh)
              (tramp-rsh-program          "ssh")
              (tramp-rcp-program          nil)
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             ("-e" "none"))
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    nil)
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     "mimencode -b")
              (tramp-decoding-command     "mimencode -u -b")
              (tramp-encoding-function    base64-encode-region)
              (tramp-decoding-function    base64-decode-region)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("smp"   (tramp-connection-function  tramp-open-connection-rsh)
              (tramp-rsh-program          "ssh")
              (tramp-rcp-program          nil)
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             ("-e" "none"))
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    nil)
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     "tramp_mimencode")
              (tramp-decoding-command     "tramp_mimedecode")
              (tramp-encoding-function    base64-encode-region)
              (tramp-decoding-function    base64-decode-region)
              (tramp-telnet-program       nil))
     ("sm1"   (tramp-connection-function  tramp-open-connection-rsh)
              (tramp-rsh-program          "ssh1")
              (tramp-rcp-program          nil)
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             ("-e" "none"))
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    nil)
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     "mimencode -b")
              (tramp-decoding-command     "mimencode -u -b")
              (tramp-encoding-function    base64-encode-region)
              (tramp-decoding-function    base64-decode-region)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("sm2"   (tramp-connection-function  tramp-open-connection-rsh)
              (tramp-rsh-program          "ssh2")
              (tramp-rcp-program          nil)
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             ("-e" "none"))
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    nil)
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     "mimencode -b")
              (tramp-decoding-command     "mimencode -u -b")
              (tramp-encoding-function    base64-encode-region)
              (tramp-decoding-function    base64-decode-region)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("tm"    (tramp-connection-function  tramp-open-connection-telnet)
              (tramp-rsh-program          nil)
              (tramp-rcp-program          nil)
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             nil)
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    nil)
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     "mimencode -b")
              (tramp-decoding-command     "mimencode -u -b")
              (tramp-encoding-function    base64-encode-region)
              (tramp-decoding-function    base64-decode-region)
              (tramp-telnet-program       "telnet")
              (tramp-telnet-args          nil))
     ("tu"    (tramp-connection-function  tramp-open-connection-telnet)
              (tramp-rsh-program          nil)
              (tramp-rcp-program          nil)
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             nil)
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    nil)
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     "uuencode xxx")
              (tramp-decoding-command
               "( uudecode -o - 2>/dev/null || uudecode -p 2>/dev/null )")
              (tramp-encoding-function    nil)
              (tramp-decoding-function    uudecode-decode-region)
              (tramp-telnet-program       "telnet")
              (tramp-telnet-args          nil))
     ("sum"   (tramp-connection-function  tramp-open-connection-su)
              (tramp-rsh-program          nil)
              (tramp-rcp-program          nil)
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             nil)
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    nil)
              (tramp-su-program           "su")
              (tramp-su-args              ("-" "%u"))
              (tramp-encoding-command     "mimencode -b")
              (tramp-decoding-command     "mimencode -u -b")
              (tramp-encoding-function    base64-encode-region)
              (tramp-decoding-function    base64-decode-region)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("suu"   (tramp-connection-function  tramp-open-connection-su)
              (tramp-rsh-program          nil)
              (tramp-rcp-program          nil)
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             nil)
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    nil)
              (tramp-su-program           "su")
              (tramp-su-args              ("-" "%u"))
              (tramp-encoding-command     "uuencode xxx")
              (tramp-decoding-command
               "( uudecode -o - 2>/dev/null || uudecode -p 2>/dev/null )")
              (tramp-encoding-function    nil)
              (tramp-decoding-function    uudecode-decode-region)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("sudm"  (tramp-connection-function  tramp-open-connection-su)
              (tramp-rsh-program          nil)
              (tramp-rcp-program          nil)
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             nil)
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    nil)
              (tramp-su-program           "sudo")
              (tramp-su-args              ("-u" "%u" "-s"))
              (tramp-encoding-command     "mimencode -b")
              (tramp-decoding-command     "mimencode -u -b")
              (tramp-encoding-function    base64-encode-region)
              (tramp-decoding-function    base64-decode-region)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("sudu"  (tramp-connection-function  tramp-open-connection-su)
              (tramp-rsh-program          nil)
              (tramp-rcp-program          nil)
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             nil)
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    nil)
              (tramp-su-program           "sudo")
              (tramp-su-args              ("-u" "%u" "-s"))
              (tramp-encoding-command     "uuencode xxx")
              (tramp-decoding-command
               "( uudecode -o - 2>/dev/null || uudecode -p 2>/dev/null )")
              (tramp-encoding-function    nil)
              (tramp-decoding-function    uudecode-decode-region)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("multi" (tramp-connection-function  tramp-open-connection-multi)
              (tramp-rsh-program          nil)
              (tramp-rcp-program          nil)
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             nil)
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    nil)
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     "mimencode -b")
              (tramp-decoding-command     "mimencode -u -b")
              (tramp-encoding-function    base64-encode-region)
              (tramp-decoding-function    base64-decode-region)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("multiu" (tramp-connection-function  tramp-open-connection-multi)
              (tramp-rsh-program          nil)
              (tramp-rcp-program          nil)
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             nil)
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    nil)
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     "uuencode xxx")
              (tramp-decoding-command
               "( uudecode -o - 2>/dev/null || uudecode -p 2>/dev/null )")
              (tramp-encoding-function    nil)
              (tramp-decoding-function    uudecode-decode-region)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("scpx"  (tramp-connection-function  tramp-open-connection-rsh)
              (tramp-rsh-program          "ssh")
              (tramp-rcp-program          "scp")
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             ("-e" "none" "-t" "-t" "/bin/sh"))
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    "-p")
              (tramp-encoding-command     nil)
              (tramp-decoding-command     nil)
              (tramp-encoding-function    nil)
              (tramp-decoding-function    nil)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("smx"   (tramp-connection-function  tramp-open-connection-rsh)
              (tramp-rsh-program          "ssh")
              (tramp-rcp-program          nil)
              (tramp-remote-sh            "/bin/sh")
              (tramp-rsh-args             ("-e" "none" "-t" "-t" "/bin/sh"))
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    nil)
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     "mimencode -b")
              (tramp-decoding-command     "mimencode -u -b")
              (tramp-encoding-function    base64-encode-region)
              (tramp-decoding-function    base64-decode-region)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("km"
              (tramp-connection-function  tramp-open-connection-rsh)
	      (tramp-rsh-program          "krlogin")
	      (tramp-rcp-program          nil)
	      (tramp-remote-sh            "/bin/sh")
	      (tramp-rsh-args             ("-x"))
	      (tramp-rcp-args             nil)
	      (tramp-rcp-keep-date-arg    nil)
	      (tramp-su-program           nil)
	      (tramp-su-args              nil)
	      (tramp-encoding-command     "mimencode -b")
	      (tramp-decoding-command     "mimencode -u -b")
	      (tramp-encoding-function    base64-encode-region)
	      (tramp-decoding-function    base64-decode-region)
	      (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("plinku"
              (tramp-connection-function  tramp-open-connection-rsh)
	      (tramp-rsh-program          "plink")
	      (tramp-rcp-program          nil)
	      (tramp-remote-sh            "/bin/sh")
	      (tramp-rsh-args             ("-ssh")) ;optionally add "-v"
	      (tramp-rcp-args             nil)
	      (tramp-rcp-keep-date-arg    nil)
	      (tramp-su-program           nil)
	      (tramp-su-args              nil)
              (tramp-encoding-command     "uuencode xxx")
              (tramp-decoding-command
               "( uudecode -o - 2>/dev/null || uudecode -p 2>/dev/null )")
	      (tramp-encoding-function    nil)
	      (tramp-decoding-function    uudecode-decode-region)
	      (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("plinkm"
              (tramp-connection-function  tramp-open-connection-rsh)
	      (tramp-rsh-program          "plink")
	      (tramp-rcp-program          nil)
	      (tramp-remote-sh            "/bin/sh")
	      (tramp-rsh-args             ("-ssh")) ;optionally add "-v"
	      (tramp-rcp-args             nil)
	      (tramp-rcp-keep-date-arg    nil)
	      (tramp-su-program           nil)
	      (tramp-su-args              nil)
	      (tramp-encoding-command     "mimencode -b")
	      (tramp-decoding-command     "mimencode -u -b")
	      (tramp-encoding-function    base64-encode-region)
	      (tramp-decoding-function    base64-decode-region)
	      (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("pscp"
              (tramp-connection-function  tramp-open-connection-rsh)
	      (tramp-rsh-program          "plink")
	      (tramp-rcp-program          "pscp")
	      (tramp-remote-sh            "/bin/sh")
	      (tramp-rsh-args             ("-ssh"))
	      (tramp-rcp-args             nil)
	      (tramp-rcp-keep-date-arg    "-p")
	      (tramp-su-program           nil)
	      (tramp-su-args              nil)
	      (tramp-encoding-command     nil)
	      (tramp-decoding-command     nil)
	      (tramp-encoding-function    nil)
	      (tramp-decoding-function    nil)
	      (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     ("fcp"   
	      (tramp-connection-function  tramp-open-connection-rsh)
              (tramp-rsh-program          "fsh")
              (tramp-rcp-program          "fcp")
              (tramp-remote-sh            "/bin/sh -i")
              (tramp-rsh-args             ("sh" "-i"))
              (tramp-rcp-args             nil)
              (tramp-rcp-keep-date-arg    "-p")
              (tramp-su-program           nil)
              (tramp-su-args              nil)
              (tramp-encoding-command     nil)
              (tramp-decoding-command     nil)
              (tramp-encoding-function    nil)
              (tramp-decoding-function    nil)
              (tramp-telnet-program       nil)
              (tramp-telnet-args          nil))
     )
  "*Alist of methods for remote files.
This is a list of entries of the form (NAME PARAM1 PARAM2 ...).
Each NAME stands for a remote access method.  Each PARAM is a
pair of the form (KEY VALUE).  The following KEYs are defined:
  * `tramp-connection-function'
    This specifies the function to use to connect to the remote host.
    Currently, `tramp-open-connection-rsh', `tramp-open-connection-telnet'
    and `tramp-open-connection-su' are defined.  See the documentation
    of these functions for more details.
  * `tramp-remote-sh'
    This specifies the Bourne shell to use on the remote host.  This
    MUST be a Bourne-like shell.  It is normally not necessary to set
    this to any value other than \"/bin/sh\": tramp wants to use a shell
    which groks tilde expansion, but it can search for it.  Also note
    that \"/bin/sh\" exists on all Unixen, this might not be true for
    the value that you decide to use.  You Have Been Warned.
  * `tramp-rsh-program'
    This specifies the name of the program to use for rsh; this might be
    the full path to rsh or the name of a workalike program.
  * `tramp-rsh-args'
    This specifies the list of arguments to pass to the above
    mentioned program.  Please note that this is a list of arguments,
    that is, normally you don't want to put \"-a -b\" or \"-f foo\"
    here.  Instead, you want two list elements, one for \"-a\" and one
    for \"-b\", or one for \"-f\" and one for \"foo\".
  * `tramp-rcp-program'
    This specifies the name of the program to use for rcp; this might be
    the full path to rcp or the name of a workalike program.
  * `tramp-rcp-args'
    This specifies the list of parameters to pass to the above mentioned
    program, the hints for `tramp-rsh-args' also apply here.
  * `tramp-rcp-keep-date-arg'
    This specifies the parameter to use for `rcp' when the timestamp
    of the original file should be kept.  For `rcp', use `-p', for
    `rsync', use `-t'.
  * `tramp-su-program'
    This specifies the name of the program to use for `su'.
  * `tramp-su-args'
    This specifies the list of arguments to pass to `su'.
    \"%u\" is replaced by the user name, use \"%%\" for a literal
    percent character.
  * `tramp-encoding-command'
    This specifies a command to use to encode the file contents for
    transfer.  The command should read the raw file contents from
    standard input and write the encoded file contents to standard
    output.  In this string, the percent escape \"%f\" should be used
    to indicate the file to convert.  Use \"%%\" if you need a literal
    percent character in your command.
  * `tramp-decoding-command'
    This specifies a command to use to decode file contents encoded
    with `tramp-encoding-command'.  The command should read from standard
    input and write to standard output.
  * `tramp-encoding-function'
    This specifies a function to be called to encode the file contents
    on the local side.  This function should accept two arguments
    START and END, the beginning and end of the region to encode.  The
    region should be replaced with the encoded contents.
  * `tramp-decoding-function'
    Same for decoding on the local side.
  * `tramp-telnet-program'
    Specifies the telnet program to use when using
    `tramp-open-connection-telnet' to log in.
  * `tramp-telnet-args'
    Specifies list of arguments to pass to `telnet'.  The hints for
    `tramp-rsh-args' also apply here.

What does all this mean?  Well, you should specify `tramp-rsh-program',
`tramp-telnet-program' or `tramp-su-program' for all methods; this program
is used to log in to the remote site.  Then, there are two ways to
actually transfer the files between the local and the remote side.
One way is using an additional rcp-like program.  If you want to do
this, set `tramp-rcp-program' in the method.

Another possibility for file transfer is inline transfer, i.e. the
file is passed through the same buffer used by `tramp-rsh-program'.  In
this case, the file contents need to be protected since the
`tramp-rsh-program' might use escape codes or the connection might not
be eight-bit clean.  Therefore, file contents are encoded for transit.

Two possibilities for encoding are uuencode/uudecode and mimencode.
For uuencode/uudecode you want to set `tramp-encoding-command' to
something like \"uuencode\" and `tramp-decoding-command' to \"uudecode
-p\".  For mimencode you want to set `tramp-encoding-command' to
something like \"mimencode -b\" and `tramp-decoding-command' to
\"mimencode -b -u\".

When using inline transfer, you can use a program or a Lisp function
on the local side to encode or decode the file contents.  Set the
`tramp-encoding-function' and `tramp-decoding-function' parameters to nil
in order to use the commands or to the function to use.  It is
possible to specify one function and the other parameter as nil.

So, to summarize: if the method is an inline method, you must specify
`tramp-encoding-command' and `tramp-decoding-command', and
`tramp-rcp-program' must be nil.  If the method is out of band, then
you must specify `tramp-rcp-program' and `tramp-rcp-args' and
`tramp-encoding-command' and `tramp-decoding-command' must be nil.
Every method, inline or out of band, must specify
`tramp-connection-function' plus the associated arguments (for
example, the telnet program if you chose
`tramp-open-connection-telnet').

Notes:

When using `tramp-open-connection-su' the phrase `open connection to a
remote host' sounds strange, but it is used nevertheless, for
consistency.  No connection is opened to a remote host, but `su' is
started on the local host.  You are not allowed to specify a remote
host other than `localhost' or the name of the local host.

Using a uuencode/uudecode inline method is discouraged, please use one
of the base64 methods instead since base64 encoding is much more
reliable and the commands are more standardized between the different
Unix versions.  But if you can't use base64 for some reason, please
note that the default uudecode command does not work well for some
Unices, in particular AIX and Irix.  For AIX, you might want to use
the following command for uudecode:

    sed '/^begin/d;/^[` ]$/d;/^end/d' | iconv -f uucode -t ISO8859-1

For Irix, no solution is known yet."
  :group 'tramp
  :type '(repeat
          (cons string
                (set (list (const tramp-connection-function) function)
                     (list (const tramp-rsh-program)
			   (choice (const nil) string))
                     (list (const tramp-rcp-program)
			   (choice (const nil) string))
                     (list (const tramp-remote-sh)
			   (choice (const nil) string))
                     (list (const tramp-rsh-args) (repeat string))
                     (list (const tramp-rcp-args) (repeat string))
                     (list (const tramp-rcp-keep-date-arg)
			   (choice (const nil) string))
                     (list (const tramp-su-program)
			   (choice (const nil) string))
                     (list (const tramp-su-args) (repeat string))
                     (list (const tramp-encoding-command)
			   (choice (const nil) string))
                     (list (const tramp-decoding-command)
			   (choice (const nil) string))
                     (list (const tramp-encoding-function)
			   (choice (const nil) function))
                     (list (const tramp-decoding-function)
			   (choice (const nil) function))
                     (list (const tramp-telnet-program)
			   (choice (const nil) string))
                     (list (const tramp-telnet-args) (repeat string))))))

(defcustom tramp-multi-methods '("multi" "multiu")
  "*List of multi-hop methods.
Each entry in this list should be a method name as mentioned in the
variable `tramp-methods'."
  :group 'tramp
  :type '(repeat string))

(defcustom tramp-multi-connection-function-alist
  '(("telnet" tramp-multi-connect-telnet "telnet %h%n")
    ("rsh"    tramp-multi-connect-rlogin "rsh %h -l %u%n")
    ("ssh"    tramp-multi-connect-rlogin "ssh %h -l %u%n")
    ("su"     tramp-multi-connect-su     "su - %u%n")
    ("sudo"   tramp-multi-connect-su     "sudo -u %u -s%n"))
  "*List of connection functions for multi-hop methods.
Each list item is a list of three items (METHOD FUNCTION COMMAND),
where METHOD is the name as used in the file name, FUNCTION is the
function to be executed, and COMMAND is the shell command used for
connecting.

COMMAND may contain percent escapes.  `%u' will be replaced with the
user name, `%h' will be replaced with the host name, and `%n' will be
replaced with an end-of-line character, as specified in the variable
`tramp-rsh-end-of-line'.  Use `%%' for a literal percent character.
Note that the interpretation of the percent escapes also depends on
the FUNCTION.  For example, the `%u' escape is forbidden with the
function `tramp-multi-connect-telnet'.  See the documentation of the
various functions for details."
  :group 'tramp
  :type '(repeat (list string function string)))

777 778
(defcustom tramp-default-method "sm"
  ;;(if (featurep 'xemacs) "sm" "ftp")
Kai Großjohann's avatar
Kai Großjohann committed
779
  "*Default method to use for transferring files.
780
See `tramp-methods' for possibilities.
781 782 783 784 785 786
Also see `tramp-default-method-alist'.

Emacs uses a unified filename syntax for Tramp and Ange-FTP.
For backward compatibility, the default value of this variable
is \"ftp\" on Emacs.  But XEmacs uses a separate filename syntax
for Tramp and EFS, so there the default method is \"sm\"."
787 788 789
  :group 'tramp
  :type 'string)

790 791 792 793 794
(defcustom tramp-default-method-alist
  (if (featurep 'xemacs)
      nil
    '(("\\`ftp\\." "" "ftp")
      ("" "\\`\\(anonymous\\|ftp\\)\\'" "ftp")))
795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812
  "*Default method to use for specific user/host pairs.
This is an alist of items (HOST USER METHOD).  The first matching item
specifies the method to use for a file name which does not specify a
method.  HOST and USER are regular expressions or nil, which is
interpreted as a regular expression which always matches.  If no entry
matches, the variable `tramp-default-method' takes effect.

If the file name does not specify the user, lookup is done using the
empty string for the user name.

See `tramp-methods' for a list of possibilities for METHOD."
  :group 'tramp
  :type '(repeat (list (regexp :tag "Host regexp")
		       (regexp :tag "User regexp")
		       (string :tag "Method"))))

(defcustom tramp-ftp-method "ftp"
  "*When this method name is used, forward all calls to Ange-FTP."
Kai Großjohann's avatar
Kai Großjohann committed
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
  :group 'tramp
  :type 'string)

(defcustom tramp-rsh-end-of-line "\n"
  "*String used for end of line in rsh connections.
I don't think this ever needs to be changed, so please tell me about it
if you need to change this."
  :group 'tramp
  :type 'string)

(defcustom tramp-remote-path
  '("/bin" "/usr/bin" "/usr/sbin" "/usr/local/bin" "/usr/ccs/bin"
    "/local/bin" "/local/freeware/bin" "/local/gnu/bin"
    "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin")
  "*List of directories to search for executables on remote host.
Please notify me about other semi-standard directories to include here.

You can use `~' in this list, but when searching for a shell which groks
tilde expansion, all directory names starting with `~' will be ignored."
  :group 'tramp
  :type '(repeat string))

(defcustom tramp-login-prompt-regexp
  ".*ogin: *$"
  "*Regexp matching login-like prompts.
The regexp should match the whole line."
  :group 'tramp
  :type 'regexp)

(defcustom tramp-password-prompt-regexp
  "^.*\\([pP]assword\\|passphrase.*\\):\^@? *$"
  "*Regexp matching password-like prompts.
The regexp should match the whole line.

The `sudo' program appears to insert a `^@' character into the prompt."
  :group 'tramp
  :type 'regexp)

(defcustom tramp-wrong-passwd-regexp
  (concat "^.*\\(Permission denied.\\|Login [Ii]ncorrect\\|"
          "Received signal [0-9]+\\|Connection \\(refused\\|closed\\)\\|"
          "Sorry, try again.\\|Name or service not known\\).*$")
  "*Regexp matching a `login failed' message.
The regexp should match the whole line."
  :group 'tramp
  :type 'regexp)

(defcustom tramp-temp-name-prefix "tramp."
  "*Prefix to use for temporary files.
If this is a relative file name (such as \"tramp.\"), it is considered
relative to the directory name returned by the function
`tramp-temporary-file-directory' (which see).  It may also be an
absolute file name; don't forget to include a prefix for the filename
part, though."
  :group 'tramp
  :type 'string)

(defcustom tramp-discard-garbage nil
  "*If non-nil, try to discard garbage sent by remote shell.
Some shells send such garbage upon connection setup."
  :group 'tramp
  :type 'boolean)

876 877 878 879 880 881 882 883 884 885 886 887
(defcustom tramp-sh-extra-args '(("/bash\\'" . "--norc"))
  "*Alist specifying extra arguments to pass to the remote shell.
Entries are (REGEXP . ARGS) where REGEXP is a regular expression
matching the shell file name and ARGS is a string specifying the
arguments.

This variable is only used when Tramp needs to start up another shell
for tilde expansion.  The extra arguments should typically prevent the
shell from reading its init file."
  :group 'tramp
  :type '(alist :key-type string :value-type string))

Kai Großjohann's avatar
Kai Großjohann committed
888 889
;; File name format.

890 891 892 893 894 895 896 897 898 899 900
(defconst tramp-file-name-structure-unified
  (list (concat "\\`/\\(\\([a-zA-Z0-9]+\\):\\)?" ;method
		      "\\(\\([^:@/]+\\)@\\)?" ;user
		      "\\([^:/]+\\):"	;host
		      "\\(.*\\)\\'")	;path
	      2 4 5 6)
  "Default value for `tramp-file-name-structure' for unified remoting.
On Emacs (not XEmacs), the Tramp and Ange-FTP packages use a unified
filename space.  This value is used for this unified namespace.")

(defconst tramp-file-name-structure-separate
Kai Großjohann's avatar
Kai Großjohann committed
901 902 903 904
  (list (concat "\\`/\\[\\(\\([a-zA-Z0-9]+\\)/\\)?" ;method
		"\\(\\([-a-zA-Z0-9_#/:]+\\)@\\)?" ;user
		"\\([-a-zA-Z0-9_#/:@.]+\\)\\]" ;host
		"\\(.*\\)\\'")		;path
Kai Großjohann's avatar
Kai Großjohann committed
905
        2 4 5 6)
906 907 908 909 910 911 912 913 914
  "Default value for `tramp-file-name-structure' for separate remoting.
On XEmacs, the Tramp and EFS packages use a separate namespace for
remote filenames.  This value is used in that case.  It is designed
not to clash with the EFS filename syntax.")

(defcustom tramp-file-name-structure
  (if (featurep 'xemacs)
      tramp-file-name-structure-separate
    tramp-file-name-structure-unified)
Kai Großjohann's avatar
Kai Großjohann committed
915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937
  "*List of five elements (REGEXP METHOD USER HOST FILE), detailing \
the tramp file name structure.

The first element REGEXP is a regular expression matching a tramp file
name.  The regex should contain parentheses around the method name,
the user name, the host name, and the file name parts.

The second element METHOD is a number, saying which pair of
parentheses matches the method name.  The third element USER is
similar, but for the user name.  The fourth element HOST is similar,
but for the host name.  The fifth element FILE is for the file name.
These numbers are passed directly to `match-string', which see.  That
means the opening parentheses are counted to identify the pair.

See also `tramp-file-name-regexp' and `tramp-make-tramp-file-format'."
  :group 'tramp
  :type '(list (regexp :tag "File name regexp")
               (integer :tag "Paren pair for method name")
               (integer :tag "Paren pair for user name  ")
               (integer :tag "Paren pair for host name  ")
               (integer :tag "Paren pair for file name  ")))

;;;###autoload
938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955
(defconst tramp-file-name-regexp-unified
  "\\`/[^/:]+:"
  "Value for `tramp-file-name-regexp' for unified remoting.
Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and
Tramp.  See `tramp-file-name-structure-unified' for more explanations.")

;;;###autoload
(defconst tramp-file-name-regexp-separate
  "\\`/\\[.*\\]"
  "Value for `tramp-file-name-regexp' for separate remoting.
XEmacs uses a separate filename syntax for Tramp and EFS.
See `tramp-file-name-structure-separate' for more explanations.")

;;;###autoload
(defcustom tramp-file-name-regexp
  (if (featurep 'xemacs)
      tramp-file-name-regexp-separate
    tramp-file-name-regexp-unified)
Kai Großjohann's avatar
Kai Großjohann committed
956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
  "*Regular expression matching file names handled by tramp.
This regexp should match tramp file names but no other file names.
\(When tramp.el is loaded, this regular expression is prepended to
`file-name-handler-alist', and that is searched sequentially.  Thus,
if the tramp entry appears rather early in the `file-name-handler-alist'
and is a bit too general, then some files might be considered tramp
files which are not really tramp files.

Please note that the entry in `file-name-handler-alist' is made when
this file (tramp.el) is loaded.  This means that this variable must be set
before loading tramp.el.  Alternatively, `file-name-handler-alist' can be
updated after changing this variable.

Also see `tramp-file-name-structure' and `tramp-make-tramp-file-format'."
  :group 'tramp
  :type 'regexp)

973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988
(defconst tramp-make-tramp-file-format-unified
   "/%m:%u@%h:%p"
   "Value for `tramp-make-tramp-file-format' for unified remoting.
Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and Tramp.
See `tramp-file-name-structure-unified' for more details.")

(defconst tramp-make-tramp-file-format-separate
  "/[%m/%u@%h]%p"
  "Value for `tramp-make-tramp-file-format' for separate remoting.
XEmacs uses a separate filename syntax for EFS and Tramp.
See `tramp-file-name-structure-separate' for more details.")

(defcustom tramp-make-tramp-file-format
  (if (featurep 'xemacs)
      tramp-make-tramp-file-format-separate
    tramp-make-tramp-file-format-unified)
Kai Großjohann's avatar
Kai Großjohann committed
989 990 991 992 993 994 995 996 997 998 999
  "*Format string saying how to construct tramp file name.
`%m' is replaced by the method name.
`%u' is replaced by the user name.
`%h' is replaced by the host name.
`%p' is replaced by the file name.
`%%' is replaced by %.

Also see `tramp-file-name-structure' and `tramp-file-name-regexp'."
  :group 'tramp
  :type 'string)

1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
(defconst tramp-make-tramp-file-user-nil-format-unified
  "/%m:%h:%p"
  "Value of `tramp-make-tramp-file-user-nil-format' for unified remoting.
Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and Tramp.
See `tramp-file-name-structure-unified' for details.")

(defconst tramp-make-tramp-file-user-nil-format-separate
  "/[%m/%h]%p"
  "Value of `tramp-make-tramp-file-user-nil-format' for separate remoting.
XEmacs uses a separate filename syntax for EFS and Tramp.
See `tramp-file-name-structure-separate' for details.")

(defcustom tramp-make-tramp-file-user-nil-format
  (if (featurep 'xemacs)
      tramp-make-tramp-file-user-nil-format-separate
    tramp-make-tramp-file-user-nil-format-unified)
Kai Großjohann's avatar
Kai Großjohann committed
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
  "*Format string saying how to construct tramp file name when the user name is not known.
`%m' is replaced by the method name.
`%h' is replaced by the host name.
`%p' is replaced by the file name.
`%%' is replaced by %.

Also see `tramp-make-tramp-file-format', `tramp-file-name-structure', and `tramp-file-name-regexp'."
  :group 'tramp
  :type 'string)

1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
(defconst tramp-multi-file-name-structure-unified
  (list (concat "\\`\\([a-zA-Z0-9]+\\)\\)?" ;method
		"\\(\\(%s\\)+\\)"	;hops
		":\\(.*\\)\\'")		;path
	2 3 -1)
  "Value for `tramp-multi-file-name-structure' for unified remoting.
Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and Tramp.
See `tramp-file-name-structure-unified' for details.")

(defconst tramp-file-name-structure-separate
Kai Großjohann's avatar
Kai Großjohann committed
1036 1037 1038
  (list (concat
         ;; prefix
         "\\`/\\[\\(\\([a-z0-9]+\\)\\)?"
Kai Großjohann's avatar
Kai Großjohann committed
1039
         ;; regexp specifying the hops
Kai Großjohann's avatar
Kai Großjohann committed
1040 1041 1042 1043 1044 1045
         "\\(\\(%s\\)+\\)"
         ;; path name
         "\\]\\(.*\\)\\'")
        2                               ;number of pair to match method
        3                               ;number of pair to match hops
        -1)                             ;number of pair to match path
1046 1047 1048 1049 1050 1051 1052 1053
  "Value of `tramp-multi-file-name-structure' for separate remoting.
XEmacs uses a separate filename syntax for EFS and Tramp.
See `tramp-file-name-structure-separate' for details.")

(defcustom tramp-multi-file-name-structure
  (if (featurep 'xemacs)
      tramp-multi-file-name-structure-separate
    tramp-multi-file-name-structure-unified)
Kai Großjohann's avatar
Kai Großjohann committed
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080
  "*Describes the file name structure of `multi' files.
Multi files allow you to contact a remote host in several hops.
This is a list of four elements (REGEXP METHOD HOP PATH).

The first element, REGEXP, gives a regular expression to match against
the file name.  In this regular expression, `%s' is replaced with the
value of `tramp-multi-file-name-hop-structure'.  (Note: in order to
allow multiple hops, you normally want to use something like
\"\\\\(\\\\(%s\\\\)+\\\\)\" in the regular expression.  The outer pair
of parentheses is used for the HOP element, see below.)

All remaining elements are numbers.  METHOD gives the number of the
paren pair which matches the method name.  HOP gives the number of the
paren pair which matches the hop sequence.  PATH gives the number of
the paren pair which matches the path name on the remote host.

PATH can also be negative, which means to count from the end.  Ie, a
value of -1 means the last paren pair.

I think it would be good if the regexp matches the whole of the
string, but I haven't actually tried what happens if it doesn't..."
  :group 'tramp
  :type '(list (regexp :tag "File name regexp")
               (integer :tag "Paren pair for method name")
               (integer :tag "Paren pair for hops")
               (integer :tag "Paren pair to match path")))

1081 1082 1083 1084 1085 1086 1087 1088 1089 1090
(defconst tramp-multi-file-name-hop-structure-unified
  (list (concat ":\\([a-zA-z0-9_]+\\):" ;hop method
		"\\([^@:/]+\\)@"	;user
		"\\([^:/]+\\)")		;host
	1 2 3)
  "Value of `tramp-multi-file-name-hop-structure' for unified remoting.
Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and Tramp.
See `tramp-file-name-structure-unified' for details.")

(defconst tramp-multi-file-name-hop-structure-separate
Kai Großjohann's avatar
Kai Großjohann committed
1091 1092 1093
  (list (concat "/\\([a-z0-9_]+\\):"	;hop method
		"\\([a-z0-9_]+\\)@"	;user
		"\\([a-z0-9.-]+\\)")	;host
Kai Großjohann's avatar
Kai Großjohann committed
1094
        1 2 3)
1095 1096 1097 1098 1099 1100 1101 1102
  "Value of `tramp-multi-file-name-hop-structure' for separate remoting.
XEmacs uses a separate filename syntax for EFS and Tramp.
See `tramp-file-name-structure-separate' for details.")

(defcustom tramp-multi-file-name-hop-structure
  (if (featurep 'xemacs)
      tramp-multi-file-name-hop-structure-separate
    tramp-multi-file-name-hop-structure-unified)
Kai Großjohann's avatar
Kai Großjohann committed
1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115
  "*Describes the structure of a hop in multi files.
This is a list of four elements (REGEXP METHOD USER HOST).  First
element REGEXP is used to match against the hop.  Pair number METHOD
matches the method of one hop, pair number USER matches the user of
one hop, pair number HOST matches the host of one hop.

This regular expression should match exactly all of one hop."
  :group 'tramp
  :type '(list (regexp :tag "Hop regexp")
               (integer :tag "Paren pair for method name")
               (integer :tag "Paren pair for user name")
               (integer :tag "Paren pair for host name")))

1116 1117 1118 1119 1120 1121 1122
(defconst tramp-make-multi-tramp-file-format-unified
  (list "/%m" ":%m:%u@%h" ":%p")
  "Value of `tramp-make-multi-tramp-file-format' for unified remoting.
Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and Tramp.
See `tramp-file-name-structure-unified' for details.")

(defconst tramp-make-multi-tramp-file-format-separate
Kai Großjohann's avatar
Kai Großjohann committed
1123
  (list "/[%m" "/%m:%u@%h" "]%p")
1124 1125 1126 1127 1128 1129 1130 1131
  "Value of `tramp-make-multi-tramp-file-format' for separate remoting.
XEmacs uses a separate filename syntax for EFS and Tramp.
See `tramp-file-name-structure-separate' for details.")

(defcustom tramp-make-multi-tramp-file-format
  (if (featurep 'xemacs)
      tramp-make-multi-tramp-file-format-separate
    tramp-make-multi-tramp-file-format-unified)
Kai Großjohann's avatar
Kai Großjohann committed
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476
  "*Describes how to construct a `multi' file name.
This is a list of three elements PREFIX, HOP and PATH.

The first element PREFIX says how to construct the prefix, the second
element HOP specifies what each hop looks like, and the final element
PATH says how to construct the path name.

In PREFIX, `%%' means `%' and `%m' means the method name.

In HOP, `%%' means `%' and `%m', `%u', `%h' mean the hop method, hop
user and hop host, respectively.

In PATH, `%%' means `%' and `%p' means the path name.

The resulting file name always contains one copy of PREFIX and one
copy of PATH, but there is one copy of HOP for each hop in the file
name.

Note: the current implementation requires the prefix to contain the
method name, followed by all the hops, and the path name must come
last."
  :group 'tramp
  :type '(list string string string))

(defcustom tramp-terminal-type "dumb"
  "*Value of TERM environment variable for logging in to remote host.
Because Tramp wants to parse the output of the remote shell, it is easily
confused by ANSI color escape sequences and suchlike.  Often, shell init
files conditionalize this setup based on the TERM environment variable."
  :group 'tramp
  :type 'string)

(defcustom tramp-completion-without-shell-p nil
  "*If nil, use shell wildcards for completion, else rely on Lisp only.
Using shell wildcards for completions has the advantage that it can be
fast even in large directories, but completion is always
case-sensitive.  Relying on Lisp only means that case-insensitive
completion is possible (subject to the variable `completion-ignore-case'),
but it might be slow on large directories."
  :group 'tramp
  :type 'boolean)

;;; Internal Variables:

(defvar tramp-buffer-file-attributes nil
  "Holds the `ls -ild' output for the current buffer.
This variable is local to each buffer.  It is not used if the remote
machine groks Perl.  If it is used, it's used as an emulation for
the visited file modtime.")
(make-variable-buffer-local 'tramp-buffer-file-attributes)

(defvar tramp-end-of-output "/////"
  "String used to recognize end of output.")

(defvar tramp-connection-function nil
  "This internal variable holds a parameter for `tramp-methods'.
In the connection buffer, this variable has the value of the like-named
method parameter, as specified in `tramp-methods' (which see).")

(defvar tramp-remote-sh nil
  "This internal variable holds a parameter for `tramp-methods'.
In the connection buffer, this variable has the value of the like-named
method parameter, as specified in `tramp-methods' (which see).")

(defvar tramp-rsh-program nil
  "This internal variable holds a parameter for `tramp-methods'.
In the connection buffer, this variable has the value of the like-named
method parameter, as specified in `tramp-methods' (which see).")

(defvar tramp-rsh-args nil
  "This internal variable holds a parameter for `tramp-methods'.
In the connection buffer, this variable has the value of the like-named
method parameter, as specified in `tramp-methods' (which see).")

(defvar tramp-rcp-program nil
  "This internal variable holds a parameter for `tramp-methods'.
In the connection buffer, this variable has the value of the like-named
method parameter, as specified in `tramp-methods' (which see).")

(defvar tramp-rcp-args nil
  "This internal variable holds a parameter for `tramp-methods'.
In the connection buffer, this variable has the value of the like-named
method parameter, as specified in `tramp-methods' (which see).")

(defvar tramp-rcp-keep-date-arg nil
  "This internal variable holds a parameter for `tramp-methods'.
In the connection buffer, this variable has the value of the like-named
method parameter, as specified in `tramp-methods' (which see).")

(defvar tramp-encoding-command nil
  "This internal variable holds a parameter for `tramp-methods'.
In the connection buffer, this variable has the value of the like-named
method parameter, as specified in `tramp-methods' (which see).")

(defvar tramp-decoding-command nil
  "This internal variable holds a parameter for `tramp-methods'.
In the connection buffer, this variable has the value of the like-named
method parameter, as specified in `tramp-methods' (which see).")

(defvar tramp-encoding-function nil
  "This internal variable holds a parameter for `tramp-methods'.
In the connection buffer, this variable has the value of the like-named
method parameter, as specified in `tramp-methods' (which see).")

(defvar tramp-decoding-function nil
  "This internal variable holds a parameter for `tramp-methods'.
In the connection buffer, this variable has the value of the like-named
method parameter, as specified in `tramp-methods' (which see).")

(defvar tramp-telnet-program nil
  "This internal variable holds a parameter for `tramp-methods'.
In the connection buffer, this variable has the value of the like-named
method parameter, as specified in `tramp-methods' (which see).")

(defvar tramp-telnet-args nil
  "This internal variable holds a parameter for `tramp-methods'.
In the connection buffer, this variable has the value of the like-named
method parameter, as specified in `tramp-methods' (which see).")

;; CCC `local in each buffer'?
(defvar tramp-ls-command nil
  "This command is used to get a long listing with numeric user and group ids.
This variable is automatically made buffer-local to each rsh process buffer
upon opening the connection.")

(defvar tramp-current-multi-method nil
  "Name of `multi' connection method for this *tramp* buffer, or nil if not multi.
This variable is automatically made buffer-local to each rsh process buffer
upon opening the connection.")

(defvar tramp-current-method nil
  "Connection method for this *tramp* buffer.
This variable is automatically made buffer-local to each rsh process buffer
upon opening the connection.")

(defvar tramp-current-user nil
  "Remote login name for this *tramp* buffer.
This variable is automatically made buffer-local to each rsh process buffer
upon opening the connection.")

(defvar tramp-current-host nil
  "Remote host for this *tramp* buffer.
This variable is automatically made buffer-local to each rsh process buffer
upon opening the connection.")

(defvar tramp-test-groks-nt nil
  "Whether the `test' command groks the `-nt' switch.
\(`test A -nt B' tests if file A is newer than file B.)
This variable is automatically made buffer-local to each rsh process buffer
upon opening the connection.")

(defvar tramp-file-exists-command nil
  "Command to use for checking if a file exists.
This variable is automatically made buffer-local to each rsh process buffer
upon opening the connection.")

;; Perl script to implement `file-attributes' in a Lisp `read'able output.
;; If you are hacking on this, note that you get *no* output unless this
;; spits out a complete line, including the '\n' at the end.
(defconst tramp-perl-file-attributes (concat
 "$f = $ARGV[0];
@s = lstat($f);
if (($s[2] & 0170000) == 0120000) { $l = readlink($f); $l = \"\\\"$l\\\"\"; }
elsif (($s[2] & 0170000) == 040000) { $l = \"t\"; }
else { $l = \"nil\" };
printf(\"(%s %u %u %u (%u %u) (%u %u) (%u %u) %u %u t (%u . %u) (%u %u))\\n\",
$l, $s[3], $s[4], $s[5], $s[8] >> 16 & 0xffff, $s[8] & 0xffff,
$s[9] >> 16 & 0xffff, $s[9] & 0xffff, $s[10] >> 16 & 0xffff, $s[10] & 0xffff,
$s[7], $s[2], $s[1] >> 16 & 0xffff, $s[1] & 0xffff, $s[0] >> 16 & 0xffff, $s[0] & 0xffff);"
 )
  "Perl script to produce output suitable for use with `file-attributes'
on the remote file system.")

;; Perl script to implement `mime-encode'
(defvar tramp-perl-mime-encode (concat
 "sub encode_base64 ($);
  my $buf;
  while(read(STDIN, $buf, 60*57)) { print encode_base64($buf) }
  sub encode_base64 ($) {
    my $res = \"\";
    my $eol = \"\n\";
    pos($_[0]) = 0;                          # ensure start at the beginning
    while ($_[0] =~ /(.{1,45})/gs) {
	$res .= substr(pack(\"u\", $1), 1);
	chop($res);
    }
    $res =~ tr|` -_|AA-Za-z0-9+/|;               # `# help emacs
    # fix padding at the end
    my $padding = (3 - length($_[0]) % 3) % 3;
    $res =~ s/.{$padding}$/\"=\" x $padding/e if $padding;
    # break encoded string into lines of no more than 76 characters each
    if (length $eol) {
	$res =~ s/(.{1,76})/$1$eol/g;
    }
    $res;}"))

;; Perl script to implement `mime-decode'
(defvar tramp-perl-mime-decode (concat
 "sub decode_base64 ($);
  my $buf;
  while(read(STDIN, $buf, 60*57)) { print decode_base64($buf) }
  sub decode_base64 ($) {
    local($^W) = 0; # unpack(\"u\",...) gives bogus warning in 5.00[123]

    my $str = shift;
    my $res = \"\";

    $str =~ tr|A-Za-z0-9+=/||cd;            # remove non-base64 chars
    if (length($str) % 4) {
	warn(\"Length of base64 data not a multiple of 4\")
    }
    $str =~ s/=+$//;                        # remove padding
    $str =~ tr|A-Za-z0-9+/| -_|;            # convert to uuencoded format
    while ($str =~ /(.{1,60})/gs) {
	my $len = chr(32 + length($1)*3/4); # compute length byte
	$res .= unpack(\"u\", $len . $1 );    # uudecode
    }
    $res;}"))

; These values conform to `file-attributes' from XEmacs 21.2.
; GNU Emacs and other tools not checked.
(defconst tramp-file-mode-type-map '((0  . "-")  ; Normal file (SVID-v2 and XPG2)
				     (1  . "p")  ; fifo
				     (2  . "c")  ; character device
				     (3  . "m")  ; multiplexed character device (v7)
				     (4  . "d")  ; directory
				     (5  . "?")  ; Named special file (XENIX)
				     (6  . "b")  ; block device
				     (7  . "?")  ; multiplexed block device (v7)
				     (8  . "-")  ; regular file
				     (9  . "n")  ; network special file (HP-UX)
				     (10 . "l")  ; symlink
				     (11 . "?")  ; ACL shadow inode (Solaris, not userspace)
				     (12 . "s")  ; socket
				     (13 . "D")  ; door special (Solaris)
				     (14 . "w")) ; whiteout (BSD)
  "A list of file types returned from the `stat' system call.
This is used to map a mode number to a permission string.")

(defvar tramp-dos-coding-system
  (if (and (fboundp 'coding-system-p)
           (funcall 'coding-system-p '(dos)))
      'dos
    'undecided-dos)
  "Some Emacsen know the `dos' coding system, others need `undecided-dos'.")


;; New handlers should be added here.  The following operations can be
;; handled using the normal primitives: file-name-as-directory,
;; file-name-directory, file-name-nondirectory,
;; file-name-sans-versions, get-file-buffer.
(defconst tramp-file-name-handler-alist
  '(
    (load . tramp-handle-load)
    (make-symbolic-link . tramp-handle-make-symbolic-link)
    (file-name-directory . tramp-handle-file-name-directory)
    (file-name-nondirectory . tramp-handle-file-name-nondirectory)
    (file-truename . tramp-handle-file-truename)
    (file-exists-p . tramp-handle-file-exists-p)
    (file-directory-p . tramp-handle-file-directory-p)
    (file-executable-p . tramp-handle-file-executable-p)
    (file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
    (file-readable-p . tramp-handle-file-readable-p)
    (file-regular-p . tramp-handle-file-regular-p)
    (file-symlink-p . tramp-handle-file-symlink-p)
    (file-writable-p . tramp-handle-file-writable-p)
    (file-ownership-preserved-p . tramp-handle-file-ownership-preserved-p)
    (file-newer-than-file-p . tramp-handle-file-newer-than-file-p)
    (file-attributes . tramp-handle-file-attributes)
    (file-modes . tramp-handle-file-modes)
    (file-directory-files . tramp-handle-file-directory-files)
    (directory-files . tramp-handle-directory-files)
    (file-name-all-completions . tramp-handle-file-name-all-completions)
    (file-name-completion . tramp-handle-file-name-completion)
    (add-name-to-file . tramp-handle-add-name-to-file)
    (copy-file . tramp-handle-copy-file)
    (rename-file . tramp-handle-rename-file)
    (set-file-modes . tramp-handle-set-file-modes)
    (make-directory . tramp-handle-make-directory)
    (delete-directory . tramp-handle-delete-directory)
    (delete-file . tramp-handle-delete-file)
    (directory-file-name . tramp-handle-directory-file-name)
    (shell-command . tramp-handle-shell-command)
    (insert-directory . tramp-handle-insert-directory)
    (expand-file-name . tramp-handle-expand-file-name)
    (file-local-copy . tramp-handle-file-local-copy)
    (insert-file-contents . tramp-handle-insert-file-contents)
    (write-region . tramp-handle-write-region)
    (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
    (dired-call-process . tramp-handle-dired-call-process)
    (dired-recursive-delete-directory
     . tramp-handle-dired-recursive-delete-directory)
    (set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
    (verify-visited-file-modtime . tramp-handle-verify-visited-file-modtime))
        "Alist of handler functions.
Operations not mentioned here will be handled by the normal Emacs functions.")

;;; For better error reporting.

(defun tramp-version (arg)
  "Print version number of tramp.el in minibuffer or current buffer."
  (interactive "P")
  (if arg (insert tramp-version) (message tramp-version)))

;;; Internal functions which must come first.

(defsubst tramp-message (level fmt-string &rest args)
  "Emit a message depending on verbosity level.
First arg LEVEL says to be quiet if `tramp-verbose' is less than LEVEL.  The
message is emitted only if `tramp-verbose' is greater than or equal to LEVEL.
Calls function `message' with FMT-STRING as control string and the remaining
ARGS to actually emit the message (if applicable).

This function expects to be called from the tramp buffer only!"
  (when (<= level tramp-verbose)
    (apply #'message (concat "tramp: " fmt-string) args)
    (when tramp-debug-buffer
      (save-excursion
        (set-buffer
         (tramp-get-debug-buffer
	  tramp-current-multi-method tramp-current-method
	  tramp-current-user tramp-current-host))
        (goto-char (point-max))
        (tramp-insert-with-face
         'italic
         (concat "# " (apply #'format fmt-string args) "\n"))))))

(defun tramp-message-for-buffer
  (multi-method method user host level fmt-string &rest args)
  "Like `tramp-message' but temporarily switches to the tramp buffer.
First three args METHOD, USER, and HOST identify the tramp buffer to use,
remaining args passed to `tramp-message'."
  (save-excursion
    (set-buffer (tramp-get-buffer multi-method method user host))
    (apply 'tramp-message level fmt-string args)))

(defsubst tramp-line-end-position nil
  "Return point at end of line.
Calls `line-end-position' or `point-at-eol' if defined, else
own implementation."
  (cond
   ((fboundp 'line-end-position) (funcall 'line-end-position))
   ((fboundp 'point-at-eol) 	 (funcall 'point-at-eol))
   (t (save-excursion (end-of-line) (point)))))

1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507
(defmacro with-parsed-tramp-file-name (filename var &rest body)
  "Parse a Tramp filename and make components available in the body.

First arg FILENAME is evaluated and dissected into its components.
Second arg VAR is a symbol.  It is used as a variable name to hold
the filename structure.  It is also used as a prefix for the variables
holding the components.  For example, if VAR is the symbol `foo', then
`foo' will be bound to the whole structure, `foo-multi-method' will
be bound to the multi-method component, and so on for `foo-method',
`foo-user', `foo-host', `foo-path'.

Remaining args are Lisp expressions to be evaluated (inside an implicit
`progn').

If VAR is nil, then we bind `v' to the structure and `multi-method',
`method', `user', `host', `path' to the components."
  `(let* ((,(or var 'v) (tramp-dissect-file-name ,filename))
	  (,(if var (intern (concat (symbol-name var) "-multi-method")) 'multi-method)
	   (tramp-file-name-multi-method ,(or var 'v)))
	  (,(if var (intern (concat (symbol-name var) "-method")) 'method)
	   (tramp-file-name-method ,(or var 'v)))
	  (,(if var (intern (concat (symbol-name var) "-user")) 'user)
	   (tramp-file-name-user ,(or var 'v)))
	  (,(if var (intern (concat (symbol-name var) "-host")) 'host)
	   (tramp-file-name-host ,(or var 'v)))
	  (,(if var (intern (concat (symbol-name var) "-path")) 'path)
	   (tramp-file-name-path ,(or var 'v))))
     ,@body))

(put 'with-parsed-tramp-file-name 'lisp-indent-function 2)

Kai Großjohann's avatar
Kai Großjohann committed
1508 1509 1510 1511 1512 1513 1514
;;; File Name Handler Functions:

;; The following file name handler ops are not implemented (yet?).

(defun tramp-handle-make-symbolic-link
  (filename linkname &optional ok-if-already-exists)
  "Like `make-symbolic-link' for tramp files.
1515 1516 1517 1518 1519 1520 1521
The LINKNAME argument should look like \"/path/to/target\" or
\"relative-name\",and not like a Tramp filename."
  (error "Not implemented yet")
  (with-parsed-tramp-file-name linkname l
    (when (tramp-ange-ftp-file-name-p l-multi-method l-method)
      (tramp-invoke-ange-ftp 'make-symbolic-link
			     filename linkname ok-if-already-exists))
Kai Großjohann's avatar
Kai Großjohann committed
1522
    (let ((ln (tramp-get-remote-ln l-multi-method l-method l-user l-host))
1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539
	  (cwd (file-name-directory l-path)))
      (unless ln
	(signal 'file-error
		(list "Making a symbolic link."
		      "ln(1) does not exist on the remote host.")))

      ;; Do the 'confirm if exists' thing.
      (when (file-exists-p (expand-file-name filename
					     CCC))
	;; What to do?
	(if (or (null ok-if-already-exists) ; not allowed to exist
		(and (numberp ok-if-already-exists)
		     (not (yes-or-no-p
			   (format
			    "File %s already exists; make it a link anyway? "
			    l-path)))))
	    (signal 'file-already-exists (list "File already exists" l-path))))
Kai Großjohann's avatar
Kai Großjohann committed
1540
    
1541 1542 1543 1544 1545
      ;; Right, they are on the same host, regardless of user, method, etc.
      ;; We now make the link on the remote machine. This will occur as the user
      ;; that FILENAME belongs to.
      (zerop
       (tramp-send-command-and-check
Kai Großjohann's avatar
Kai Großjohann committed
1546
	l-multi-method l-method l-user l-host
1547 1548
	(format "cd %s && %s -sf %s %s"
		cwd ln
Kai Großjohann's avatar
Kai Großjohann committed
1549 1550
		l-path 
		filename)
1551
	t)))))
Kai Großjohann's avatar
Kai Großjohann committed
1552 1553 1554 1555 1556 1557


(defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix)
  "Like `load' for tramp files.  Not implemented!"
  (unless (file-name-absolute-p file)
    (error "Tramp cannot `load' files without absolute path name"))
1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587
  (with-parsed-tramp-file-name file nil
    (when (tramp-ange-ftp-file-name-p multi-method method)
      (tramp-invoke-ange-ftp 'load
			     file noerror nomessage nosuffix must-suffix))
    (unless nosuffix
      (cond ((file-exists-p (concat file ".elc"))
	     (setq file (concat file ".elc")))
	    ((file-exists-p (concat file ".el"))
	     (setq file (concat file ".el")))))
    (when must-suffix
      ;; The first condition is always true for absolute file names.
      ;; Included for safety's sake.
      (unless (or (file-name-directory file)
		  (string-match "\\.elc?\\'" file))
	(error "File `%s' does not include a `.el' or `.elc' suffix"
	       file)))
    (unless noerror
      (when (not (file-exists-p file))
	(error "Cannot load nonexistant file `%s'" file)))
    (if (not (file-exists-p file))
	nil
      (unless nomessage
	(message "Loading %s..." file))
      (let ((local-copy (file-local-copy file)))
	;; MUST-SUFFIX doesn't exist on XEmacs, so let it default to nil.
	(load local-copy noerror t t)
	(delete-file local-copy))
      (unless nomessage
	(message "Loading %s...done" file))
      t)))
Kai Großjohann's avatar
Kai Großjohann committed
1588 1589 1590 1591 1592

;; Path manipulation functions that grok TRAMP paths...
(defun tramp-handle-file-name-directory (file)
  "Like `file-name-directory' but aware of TRAMP files."
  ;; everything except the last filename thing is the directory
1593 1594 1595
  (with-parsed-tramp-file-name file nil
    (when (tramp-ange-ftp-file-name-p multi-method method)
      (tramp-invoke-ange-ftp 'file-name-directory file))
1596 1597 1598 1599 1600 1601 1602 1603
    ;; For the following condition, two possibilities should be tried:
    ;; (1) (string= path "")
    ;; (2) (or (string= path "") (string= path "/"))
    ;; The second variant fails when completing a "/" directory on
    ;; the remote host, that is a filename which looks like
    ;; "/user@host:/".  But maybe wildcards fail with the first variant.
    ;; We should do some investigation.
    (if (string= path "")
Kai Großjohann's avatar
Kai Großjohann committed
1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618
	;; For a filename like "/[foo]", we return "/".  The `else'
	;; case would return "/[foo]" unchanged.  But if we do that,
	;; then `file-expand-wildcards' ceases to work.  It's not
	;; quite clear to me what's the intuition that tells that this
	;; behavior is the right behavior, but oh, well.
	"/"
      ;; run the command on the path portion only
      ;; CCC: This should take into account the remote machine type, no?
      ;;  --daniel <daniel@danann.net>
      (tramp-make-tramp-file-name multi-method method user host
				  ;; This will not recurse...
				  (or (file-name-directory path) "")))))

(defun tramp-handle-file-name-nondirectory (file)
  "Like `file-name-nondirectory' but aware of TRAMP files."
1619 1620 1621 1622
  (with-parsed-tramp-file-name file nil
    (when (tramp-ange-ftp-file-name-p multi-method method)
      (tramp-invoke-ange-ftp 'file-name-nondirectory file))
    (file-name-nondirectory path)))
Kai Großjohann's avatar
Kai Großjohann committed
1623 1624 1625

(defun tramp-handle-file-truename (filename &optional counter prev-dirs)
  "Like `file-truename' for tramp files."
1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644
  (with-parsed-tramp-file-name filename nil
    ;; Ange-FTP does not support truename processing.  It returns the
    ;; file name as-is.  So that's what we do, too.
    (when (tramp-ange-ftp-file-name-p multi-method method)
      filename)
    (let* ((steps        (tramp-split-string path "/"))
	   (pathdir (let ((directory-sep-char ?/))
		      (file-name-as-directory path)))
	   (is-dir (string= path pathdir))
	   (thisstep nil)
	   (numchase 0)
	   ;; Don't make the following value larger than necessary.
	   ;; People expect an error message in a timely fashion when
	   ;; something is wrong; otherwise they might think that Emacs
	   ;; is hung.  Of course, correctness has to come first.
	   (numchase-limit 20)
	   (result nil)			;result steps in reverse order
	   (curstri "")
	   symlink-target)
Kai Großjohann's avatar
Kai Großjohann committed
1645 1646
      (tramp-message-for-buffer
       multi-method method user host
1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693
       10 "Finding true name for `%s'" filename)
      (while (and steps (< numchase numchase-limit))
	(setq thisstep (pop steps))
	(tramp-message-for-buffer
	 multi-method method user host
	 10 "Check %s"
	 (mapconcat 'identity
		    (append '("") (reverse result) (list thisstep))
		    "/"))
	(setq symlink-target
	      (nth 0 (tramp-handle-file-attributes
		      (tramp-make-tramp-file-name
		       multi-method method user host
		       (mapconcat 'identity
				  (append '("") (reverse result) (list thisstep))
				  "/")))))
	(cond ((string= "." thisstep)
	       (tramp-message-for-buffer multi-method method user host
					 10 "Ignoring step `.'"))
	      ((string= ".." thisstep)
	       (tramp-message-for-buffer multi-method method user host
					 10 "Processing step `..'")
	       (pop result))
	      ((stringp symlink-target)
	       ;; It's a symlink, follow it.
	       (tramp-message-for-buffer
		multi-method method user host
		10 "Follow symlink to %s" symlink-target)
	       (setq numchase (1+ numchase))
	       (when (file-name-absolute-p symlink-target)
		 (setq result nil))
	       (setq steps
		     (append (tramp-split-string symlink-target "/") steps)))
	      (t
	       ;; It's a file.
	       (setq result (cons thisstep result)))))
      (when (>= numchase numchase-limit)
	(error "Maximum number (%d) of symlinks exceeded" numchase-limit))
      (setq result (reverse result))
      (tramp-message-for-buffer
       multi-method method user host
       10 "True name of `%s' is `%s'"
       filename (mapconcat 'identity (cons "" result) "/"))
      (tramp-make-tramp-file-name
       multi-method method user host
       (concat (mapconcat 'identity (cons "" result) "/")
	       (if is-dir "/" ""))))))
Kai Großjohann's avatar
Kai Großjohann committed
1694 1695 1696 1697 1698

;; Basic functions.

(defun tramp-handle-file-exists-p (filename)
  "Like `file-exists-p' for tramp files."
1699 1700 1701
  (with-parsed-tramp-file-name filename nil
    (when (tramp-ange-ftp-file-name-p multi-method method)
      (tramp-invoke-ange-ftp 'file-exists-p filename))
Kai Großjohann's avatar
Kai Großjohann committed
1702 1703 1704 1705
    (save-excursion
      (zerop (tramp-send-command-and-check
	      multi-method method user host
	      (format
1706 1707
	       (tramp-get-file-exists-command multi-method method user host)
	       (tramp-shell-quote-argument path)))))))
Kai Großjohann's avatar
Kai Großjohann committed
1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718

;; CCC: This should check for an error condition and signal failure
;;      when something goes wrong.
;; Daniel Pittman <daniel@danann.net>
(defun tramp-handle-file-attributes (filename &optional nonnumeric)
  "Like `file-attributes' for tramp files.
Optional argument NONNUMERIC means return user and group name
rather than as numbers."
  (if (tramp-handle-file-exists-p filename)
      ;; file exists, find out stuff
      (save-excursion
1719 1720 1721
	(with-parsed-tramp-file-name filename nil
	  (when (tramp-ange-ftp-file-name-p multi-method method)
	    (tramp-invoke-ange-ftp 'file-attributes file))
Kai Großjohann's avatar
Kai Großjohann committed
1722
	  (if (tramp-get-remote-perl multi-method method user host)
1723 1724 1725 1726
	      (tramp-handle-file-attributes-with-perl
	       multi-method method user host path nonnumeric)
	    (tramp-handle-file-attributes-with-ls
	     multi-method method user host path nonnumeric))))
Kai Großjohann's avatar
Kai Großjohann committed
1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833
    nil))				; no file


(defun tramp-handle-file-attributes-with-ls
  (multi-method method user host path &optional nonnumeric)
  "Implement `file-attributes' for tramp files using the ls(1) command."
  (let (symlinkp dirp
		 res-inode res-filemodes res-numlinks
		 res-uid res-gid res-size res-symlink-target)
    (tramp-send-command
     multi-method method user host
     (format "%s %s %s"
	     (tramp-get-ls-command multi-method method user host)
	     (if nonnumeric "-ild" "-ildn")
	     (tramp-shell-quote-argument path)))
    (tramp-wait-for-output)
    ;; parse `ls -l' output ...
    ;; ... inode
    (setq res-inode
	  (condition-case err
	      (read (current-buffer))
	    (invalid-read-syntax
	     (when (and (equal (cadr err)
			       "Integer constant overflow in reader")
			(string-match
			 "^[0-9]+\\([0-9][0-9][0-9][0-9][0-9]\\)\\'"
			 (caddr err)))
	       (let* ((big (read (substring (caddr err) 0
					    (match-beginning 1))))
		      (small (read (match-string 1 (caddr err))))
		      (twiddle (/ small 65536)))
		 (cons (+ big twiddle)
		       (- small (* twiddle 65536))))))))
    ;; ... file mode flags
    (setq res-filemodes (symbol-name (read (current-buffer))))
    ;; ... number links
    (setq res-numlinks (read (current-buffer)))
    ;; ... uid and gid
    (setq res-uid (read (current-buffer)))
    (setq res-gid (read (current-buffer)))
    (unless nonnumeric
      (unless (numberp res-uid) (setq res-uid -1))
      (unless (numberp res-gid) (setq res-gid -1)))
    ;; ... size
    (setq res-size (read (current-buffer)))
    ;; From the file modes, figure out other stuff.
    (setq symlinkp (eq ?l (aref res-filemodes 0)))
    (setq dirp (eq ?d (aref res-filemodes 0)))
    ;; if symlink, find out file name pointed to
    (when symlinkp
      (search-forward "-> ")
      (setq res-symlink-target
	    (buffer-substring (point)
			      (tramp-line-end-position))))
    ;; return data gathered
    (list
     ;; 0. t for directory, string (name linked to) for symbolic
     ;; link, or nil.
     (or dirp res-symlink-target nil)
     ;; 1. Number of links to file.
     res-numlinks
     ;; 2. File uid.
     res-uid
     ;; 3. File gid.
     res-gid
     ;; 4. Last access time, as a list of two integers. First
     ;; integer has high-order 16 bits of time, second has low 16
     ;; bits.
     ;; 5. Last modification time, likewise.
     ;; 6. Last status change time, likewise.
     '(0 0) '(0 0) '(0 0)		;CCC how to find out?
     ;; 7. Size in bytes (-1, if number is out of range).
     res-size
     ;; 8. File modes, as a string of ten letters or dashes as in ls -l.
     res-filemodes
     ;; 9. t iff file's gid would change if file were deleted and
     ;; recreated.
     nil				;hm?
     ;; 10. inode number.
     res-inode
     ;; 11. Device number.
     -1					;hm?
     )))

(defun tramp-handle-file-attributes-with-perl
  (multi-method method user host path &optional nonnumeric)
  "Implement `file-attributes' for tramp files using a Perl script.

The Perl command is sent to the remote machine when the connection
is initially created and is kept cached by the remote shell."
  (tramp-send-command
   multi-method method user host
   (format "tramp_file_attributes %s" 
	   (tramp-shell-quote-argument path)))
  (tramp-wait-for-output)
  (let ((result (read (current-buffer))))
    (setcar (nthcdr 8 result)
	    (tramp-file-mode-from-int (nth 8 result)))
    result))

(defun tramp-handle-set-visited-file-modtime (&optional time-list)
  "Like `set-visited-file-modtime' for tramp files."
  (unless (buffer-file-name)
    (error "Can't set-visited-file-modtime: buffer `%s' not visiting a file"
	   (buffer-name)))
  (when time-list
    (tramp-run-real-handler 'set-visited-file-modtime (list time-list)))
1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847
  (let ((f (buffer-file-name))
	(coding-system-used nil))
    (with-parsed-tramp-file-name f nil
      ;; This operation is not handled by Ange-FTP!
      (when (tramp-ange-ftp-file-name-p multi-method method)
	(throw 'tramp-forward-to-ange-ftp
	       (tramp-run-real-handler 'set-visited-file-modtime
				       (list time-list))))
      (let* ((attr (file-attributes f))
	     (modtime (nth 5 attr)))
	;; We use '(0 0) as a don't-know value.  See also
	;; `tramp-handle-file-attributes-with-ls'.
	(when (boundp 'last-coding-system-used)
	  (setq coding-system-used last-coding-system-used))
Kai Großjohann's avatar
Kai Großjohann committed
1848
	(if (not (equal modtime '(0 0)))
1849
	    (tramp-run-real-handler 'set-visited-file-modtime (list modtime))
Kai Großjohann's avatar
Kai Großjohann committed
1850 1851 1852 1853 1854 1855 1856 1857 1858
	  (save-excursion
	    (tramp-send-command
	     multi-method method user host
	     (format "%s -ild %s"
		     (tramp-get-ls-command multi-method method user host)
		     (tramp-shell-quote-argument path)))
	    (tramp-wait-for-output)
	    (setq attr (buffer-substring (point)
					 (progn (end-of-line) (point)))))
1859 1860 1861
	  (setq tramp-buffer-file-attributes attr))
	(when (boundp 'last-coding-system-used)
	  (setq last-coding-system-used coding-system-used))
Kai Großjohann's avatar
Kai Großjohann committed
1862 1863
	nil))))

1864 1865 1866 1867 1868 1869 1870 1871 1872
;; CCC continue here

;; This function makes the same assumption as
;; `tramp-handle-set-visited-file-modtime'.
(defun tramp-handle-verify-visited-file-modtime (buf)
  "Like `verify-visited-file-modtime' for tramp files."
  (with-current-buffer buf
    (let ((f (buffer-file-name)))
      (with-parsed-tramp-file-name f nil
Kai Großjohann's avatar
Kai Großjohann committed
1873
	(when (tramp-ange-ftp-file-name-p multi-method method)
1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900
	  ;; This one requires a hack since the file name is not passed
	  ;; on the arg list.
	  (let ((buffer-file-name (tramp-make-ange-ftp-file-name
				   user host path)))
	    (tramp-invoke-ange-ftp 'verify-visited-file-modtime buf)))
	(let* ((attr (file-attributes f))
	       (modtime (nth 5 attr)))
	  (cond ((and attr (not (equal modtime '(0 0))))
		 ;; Why does `file-attributes' return a list (HIGH
		 ;; LOW), but `visited-file-modtime' returns a cons
		 ;; (HIGH . LOW)?
		 (let ((mt (visited-file-modtime)))
		   (< (abs (tramp-time-diff
			    modtime (list (car mt) (cdr mt)))) 2)))
		(attr
		 (save-excursion
		   (tramp-send-command
		    multi-method method user host
		    (format "%s -ild %s"
			    (tramp-get-ls-command multi-method method
						  user host)
			    (tramp-shell-quote-argument path)))
		   (tramp-wait-for-output)
		   (setq attr (buffer-substring
			       (point) (progn (end-of-line) (point)))))
		 (equal tramp-buffer-file-attributes attr))
		;; If file does not exist, say it is not modified.
Kai Großjohann's avatar
Kai Großjohann committed
1901
		(t nil)))))))
1902

Kai Großjohann's avatar
Kai Großjohann committed
1903 1904 1905 1906 1907 1908 1909 1910
(defadvice clear-visited-file-modtime (after tramp activate)
  "Set `tramp-buffer-file-attributes' back to nil.
Tramp uses this variable as an emulation for the actual modtime of the file,
if the remote host can't provide the modtime."
  (setq tramp-buffer-file-attributes nil))

(defun tramp-handle-set-file-modes (filename mode)
  "Like `set-file-modes' for tramp files."
1911 1912 1913
  (with-parsed-tramp-file-name filename nil
    (when (tramp-ange-ftp-file-name-p multi-method method)
      (tramp-invoke-ange-ftp 'set-file-modes filename mode))
Kai Großjohann's avatar
Kai Großjohann committed
1914 1915
    (save-excursion
      (unless (zerop (tramp-send-command-and-check
1916 1917 1918 1919
		      multi-method method user host
		      (format "chmod %s %s"
			      (tramp-decimal-to-octal mode)
			      (tramp-shell-quote-argument path))))
Kai Großjohann's avatar
Kai Großjohann committed
1920 1921 1922 1923 1924 1925 1926 1927 1928 1929
	(signal 'file-error
		(list "Doing chmod"
		      ;; FIXME: extract the proper text from chmod's stderr.
		      "error while changing file's mode"
		      filename))))))

;; Simple functions using the `test' command.

(defun tramp-handle-file-executable-p (filename)
  "Like `file-executable-p' for tramp files."
1930 1931 1932 1933
  (with-parsed-tramp-file-name filename nil
    (when (tramp-ange-ftp-file-name-p multi-method method)
      (tramp-invoke-ange-ftp 'file-executable-p filename))
    (zerop (tramp-run-test "-x" filename))))
Kai Großjohann's avatar
Kai Großjohann committed
1934 1935 1936

(defun tramp-handle-file-readable-p (filename)
  "Like `file-readable-p' for tramp files."
1937 1938 1939 1940
  (with-parsed-tramp-file-name filename nil
    (when (tramp-ange-ftp-file-name-p multi-method method)
      (tramp-invoke-ange-ftp 'file-readable-p filename))
    (zerop (tramp-run-test "-r" filename))))
Kai Großjohann's avatar
Kai Großjohann committed
1941 1942 1943

(defun tramp-handle-file-accessible-directory-p (filename)
  "Like `file-accessible-directory-p' for tramp files."
1944 1945 1946 1947 1948 1949
  (with-parsed-tramp-file-name filename nil
    (when (tramp-ange-ftp-file-name-p multi-method method)
      (tramp-invoke-ange-ftp 'file-accessible-directory-p filename))
    (and (zerop (tramp-run-test "-d" filename))
	 (zerop (tramp-run-test "-r" filename))
	 (zerop (tramp-run-test "-x" filename)))))
Kai Großjohann's avatar
Kai Großjohann committed
1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961

;; When the remote shell is started, it looks for a shell which groks
;; tilde expansion.  Here, we assume that all shells which grok tilde
;; expansion will also provide a `test' command which groks `-nt' (for
;; newer than).  If this breaks, tell me about it and I'll try to do
;; something smarter about it.
(defun tramp-handle-file-newer-than-file-p (file1 file2)
  "Like `file-newer-than-file-p' for tramp files."
  (cond ((not (file-exists-p file1))
         nil)
        ((not (file-exists-p file2))
         t)
1962 1963 1964
        ;; We are sure both files exist at this point.  We assume that
	;; both files are Tramp files, otherwise we issue an error
	;; message.  Todo: make a better error message.
Kai Großjohann's avatar
Kai Großjohann committed
1965 1966
        (t
         (save-excursion
1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988
	   (with-parsed-tramp-file-name file1 v1
	     (with-parsed-tramp-file-name file2 v2
	       (when (and (tramp-ange-ftp-file-name-p v1-multi-method v1-method)
			  (tramp-ange-ftp-file-name-p v2-multi-method v2-method))
		 (tramp-invoke-ange-ftp 'file-newer-than-file-p
					file1 file2))
	       (unless (and (equal v1-multi-method v2-multi-method)
			    (equal v1-method v2-method)
			    (equal v1-user v2-user)
			    (equal v1-host v2-host))
		 (signal 'file-error
			 (list "Files must have same method, user, host"
			       file1 file2)))
	       (unless (and (tramp-tramp-file-p file1)
			    (tramp-tramp-file-p file2))
		 (signal 'file-error
			 (list "Files must be tramp files on same host"
			       file1 file2)))
	       (if (tramp-get-test-groks-nt
		    v1-multi-method v1-method v1-user v1-host)
		   (zerop (tramp-run-test2 "test" file1 file2 "-nt"))
		 (zerop (tramp-run-test2 "tramp_test_nt" file1 file2)))))))))
Kai Großjohann's avatar
Kai Großjohann committed
1989 1990 1991 1992 1993

;; Functions implemented using the basic functions above.

(defun tramp-handle-file-modes (filename)
  "Like `file-modes' for tramp files."
1994 1995 1996 1997 1998 1999
  (with-parsed-tramp-file-name filename nil
    (when (tramp-ange-ftp-file-name-p multi-method method)
      (tramp-invoke-ange-ftp 'file-modes filename))
    (when (file-exists-p filename)
      (tramp-mode-string-to-int
       (nth 8 (tramp-handle-file-attributes filename))))))
Kai Großjohann's avatar
Kai Großjohann committed
2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010

(defun tramp-handle-file-directory-p (filename)
  "Like `file-directory-p' for tramp files."
  ;; Care must be taken that this function returns `t' for symlinks
  ;; pointing to directories.  Surely the most obvious implementation
  ;; would be `test -d', but that returns false for such symlinks.
  ;; CCC: Stefan Monnier says that `test -d' follows symlinks.  And
  ;; I now think he's right.  So we could be using `test -d', couldn't
  ;; we?
  ;;
  ;; Alternatives: `cd %s', `test -d %s'
2011 2012 2013 2014
  (with-parsed-tramp-file-name filename nil
    (when (tramp-ange-ftp-file-name-p multi-method method)
      (tramp-invoke-ange-ftp 'file-directory-p filename))
    (save-excursion
Kai Großjohann's avatar
Kai Großjohann committed
2015 2016
      (zerop
       (tramp-send-command-and-check
2017 2018 2019 2020
	multi-method method user host
	(format "test -d %s"
		(tramp-shell-quote-argument path))
	t)))))				;run command in subshell
Kai Großjohann's avatar
Kai Großjohann committed
2021 2022 2023

(defun tramp-handle-file-regular-p (filename)
  "Like `file-regular-p' for tramp files."
2024 2025 2026 2027 2028
  (with-parsed-tramp-file-name filename nil
    (when (tramp-ange-ftp-file-name-p multi-method method)
      (tramp-invoke-ange-ftp 'file-regular-p filename))
    (and (tramp-handle-file-exists-p filename)
	 (eq ?- (aref (nth 8 (tramp-handle-file-attributes filename)) 0)))))
Kai Großjohann's avatar
Kai Großjohann committed
2029 2030 2031

(defun tramp-handle-file-symlink-p (filename)
  "Like `file-symlink-p' for tramp files."
2032 2033 2034 2035 2036
  (with-parsed-tramp-file-name filename nil
    (when (tramp-ange-ftp-file-name-p multi-method method)
      (tramp-invoke-ange-ftp 'file-symlink-p filename))
    (let ((x (car (tramp-handle-file-attributes filename))))
      (when (stringp x) x))))
Kai Großjohann's avatar
Kai Großjohann committed
2037 2038 2039

(defun tramp-handle-file-writable-p (filename)
  "Like `file-writable-p' for tramp files."
2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050
  (with-parsed-tramp-file-name filename nil
    (when (tramp-ange-ftp-file-name-p multi-method method)
      (tramp-invoke-ange-ftp 'file-writable-p filename))
    (if (tramp-handle-file-exists-p filename)
	;; Existing files must be writable.
	(zerop (tramp-run-test "-w" filename))
      ;; If file doesn't exist, check if directory is writable.
      (and (zerop (tramp-run-test
		   "-d" (tramp-handle-file-name-directory filename)))
	   (zerop (tramp-run-test
		   "-w" (tramp-handle-file-name-directory filename)))))))
Kai Großjohann's avatar
Kai Großjohann committed
2051 2052 2053

(defun tramp-handle-file-ownership-preserved-p (filename)
  "Like `file-ownership-preserved-p' for tramp files."
2054 2055 2056 2057 2058 2059
  (with-parsed-tramp-file-name filename nil
    (when (tramp-ange-ftp-file-name-p multi-method method)
      (tramp-invoke-ange-ftp 'file-ownership-preserved-p filename))
    (or (not (tramp-handle-file-exists-p filename))
	;; Existing files must be writable.
	(zerop (tramp-run-test "-O" filename)))))
Kai Großjohann's avatar
Kai Großjohann committed
2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073

;; Other file name ops.

;; ;; Matthias Köppe <mkoeppe@mail.math.uni-magdeburg.de>
;; (defun tramp-handle-directory-file-name (directory)
;;   "Like `directory-file-name' for tramp files."
;;   (if (and (eq (aref directory (- (length directory) 1)) ?/)
;; 	   (not (eq (aref directory (- (length directory) 2)) ?:)))
;;       (substring directory 0 (- (length directory) 1))
;;     directory))

;; Philippe Troin <phil@fifi.org>
(defun tramp-handle-directory-file-name (directory)
  "Like `directory-file-name' for tramp files."
2074 2075 2076 2077 2078 2079 2080 2081 2082 2083
  (with-parsed-tramp-file-name directory nil
    (when (tramp-ange-ftp-file-name-p multi-method method)
      (tramp-invoke-ange-ftp 'directory-file-name directory))
    (let ((directory-length-1 (1- (length directory))))
      (save-match-data
	(if (and (eq (aref directory directory-length-1) ?/)
		 (eq (string-match tramp-file-name-regexp directory) 0)
		 (/= (match-end 0) directory-length-1))
	    (substring directory 0 directory-length-1)
	  directory)))))
Kai Großjohann's avatar
Kai Großjohann committed
2084 2085 2086 2087 2088

;; Directory listings.

(defun tramp-handle-directory-files (directory &optional full match nosort)
  "Like `directory-files' for tramp files."
2089 2090 2091 2092 2093
  (with-parsed-tramp-file-name directory nil
    (when (tramp-ange-ftp-file-name-p multi-method method)
      (tramp-invoke-ange-ftp 'directory-files
			     directory full match nosort))
    (let (result x)
Kai Großjohann's avatar
Kai Großjohann committed
2094 2095 2096
      (save-excursion
	(tramp-barf-unless-okay
	 multi-method method user host
2097 2098 2099 2100
	 (concat "cd " (tramp-shell-quote-argument path))
	 nil
	 'file-error
	 "tramp-handle-directory-files: couldn't `cd %s'"
Kai Großjohann's avatar
Kai Großjohann committed
2101 2102 2103
	 (tramp-shell-quote-argument path))
	(tramp-send-command
	 multi-method method user host
2104 2105
	 (concat (tramp-get-ls-command multi-method method user host)
		 " -a | cat"))
Kai Großjohann's avatar
Kai Großjohann committed
2106 2107 2108
	(tramp-wait-for-output)
	(goto-char (point-max))
	(while (zerop (forward-line -1))
2109 2110 2111 2112 2113 2114 2115 2116
	  (setq x (buffer-substring (point)
				    (tramp-line-end-position)))
	  (when (or (not match) (string-match match x))
	    (if full
		(push (concat (file-name-as-directory directory)
			      x)
		      result)
	      (push x result))))
Kai Großjohann's avatar
Kai Großjohann committed
2117
	(tramp-send-command multi-method method user host "cd")