aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKai Großjohann2002-06-25 18:15:03 +0000
committerKai Großjohann2002-06-25 18:15:03 +0000
commitc62c9d08c7aadf65cfc46e7d94ab5d34e48119da (patch)
tree5ca2c80db42507fc23beb1b8e5ccde7f23792009
parent04f13f39be4b91818f297b5cca73ba05289ef251 (diff)
downloademacs-c62c9d08c7aadf65cfc46e7d94ab5d34e48119da.tar.gz
emacs-c62c9d08c7aadf65cfc46e7d94ab5d34e48119da.zip
(tramp-ftp-method): New user option.
(tramp-invoke-ange-ftp): New function to forward calls to Ange-FTP. (with-parsed-tramp-file-name): New macro for the usual big `let' statement to dissect a file-name. (tramp-handle-make-symbolic-link, tramp-handle-load) (tramp-handle-file-name-directory) (tramp-handle-file-name-nondirectory, tramp-handle-file-truename) (tramp-handle-file-truename, tramp-handle-file-directory-p) (tramp-handle-file-regular-p, tramp-handle-file-symlink-p) (tramp-handle-file-writable-p, tramp-handle-file-writable-p): Use the new macro and forward call to Ange-FTP if applicable. (tramp-make-ange-ftp-file-name): New helper function to convert a file name into an Ange-FTP file name, used by `tramp-invoke-ange-ftp'. (tramp-default-method-alist): New user option. (tramp-find-default-method): Use it. (tramp-sh-extra-args): New variable. (tramp-find-shell): Use it.
-rw-r--r--lisp/ChangeLog28
-rw-r--r--lisp/net/tramp.el2069
2 files changed, 1118 insertions, 979 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 933643649f6..59545cc56dc 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,31 @@
12002-06-25 Kai Gro,b_(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
2
3 * net/tramp.el (tramp-ftp-method): New user option.
4 (tramp-invoke-ange-ftp): New function to forward calls to
5 Ange-FTP.
6
7 (with-parsed-tramp-file-name): New macro for the usual big `let'
8 statement to dissect a file-name.
9
10 (tramp-handle-make-symbolic-link, tramp-handle-load)
11 (tramp-handle-file-name-directory)
12 (tramp-handle-file-name-nondirectory, tramp-handle-file-truename)
13 (tramp-handle-file-truename, tramp-handle-file-directory-p)
14 (tramp-handle-file-regular-p, tramp-handle-file-symlink-p)
15 (tramp-handle-file-writable-p, tramp-handle-file-writable-p):
16
17 Use the new macro and forward call to Ange-FTP if applicable.
18
19 (tramp-make-ange-ftp-file-name): New helper function to convert a
20 file name into an Ange-FTP file name, used by
21 `tramp-invoke-ange-ftp'.
22
23 (tramp-default-method-alist): New user option.
24 (tramp-find-default-method): Use it.
25
26 (tramp-sh-extra-args): New variable.
27 (tramp-find-shell): Use it.
28
12002-06-25 Andreas Schwab <schwab@suse.de> 292002-06-25 Andreas Schwab <schwab@suse.de>
2 30
3 * replace.el (occur-1): Avoid invalid message format string. 31 * replace.el (occur-1): Avoid invalid message format string.
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 585c5d46986..ae487fc81bb 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -52,24 +52,24 @@
52;; the same directory. 52;; the same directory.
53;; 53;;
54;; There's a mailing list for this, as well. Its name is: 54;; There's a mailing list for this, as well. Its name is:
55;; tramp-devel@lists.sourceforge.net 55;; tramp-devel@mail.freesoftware.fsf.org
56;; Send a mail with `help' in the subject (!) to the administration 56;; Send a mail with `help' in the subject (!) to the administration
57;; address for instructions on joining the list. The administration 57;; address for instructions on joining the list. The administration
58;; address is: 58;; address is:
59;; tramp-devel-request@lists.sourceforge.net 59;; tramp-devel-request@mail.freesoftware.fsf.org
60;; You can also use the Web to subscribe, under the following URL: 60;; You can also use the Web to subscribe, under the following URL:
61;; http://lists.sourceforge.net/lists/listinfo/tramp-devel 61;; http://mail.freesoftware.fsf.org/mailman/listinfo/tramp-devel
62;; 62;;
63;; For the adventurous, the current development sources are available 63;; For the adventurous, the current development sources are available
64;; via CVS. You can find instructions about this at the following URL: 64;; via CVS. You can find instructions about this at the following URL:
65;; http://sourceforge.net/projects/tramp/ 65;; http://savannah.gnu.org/projects/tramp/
66;; Click on "CVS" in the navigation bar near the top. 66;; Click on "CVS" in the navigation bar near the top.
67;; 67;;
68;; Don't forget to put on your asbestos longjohns, first! 68;; Don't forget to put on your asbestos longjohns, first!
69 69
70;;; Code: 70;;; Code:
71 71
72(defconst tramp-version "2.0.0" 72(defconst tramp-version "2.0.1"
73 "This version of tramp.") 73 "This version of tramp.")
74(defconst tramp-bug-report-address "tramp-devel@mail.freesoftware.fsf.org" 74(defconst tramp-bug-report-address "tramp-devel@mail.freesoftware.fsf.org"
75 "Email address to send bug reports to.") 75 "Email address to send bug reports to.")
@@ -776,7 +776,30 @@ various functions for details."
776 776
777(defcustom tramp-default-method "rcp" 777(defcustom tramp-default-method "rcp"
778 "*Default method to use for transferring files. 778 "*Default method to use for transferring files.
779See `tramp-methods' for possibilities." 779See `tramp-methods' for possibilities.
780Also see `tramp-default-method-alist'."
781 :group 'tramp
782 :type 'string)
783
784(defcustom tramp-default-method-alist nil
785 "*Default method to use for specific user/host pairs.
786This is an alist of items (HOST USER METHOD). The first matching item
787specifies the method to use for a file name which does not specify a
788method. HOST and USER are regular expressions or nil, which is
789interpreted as a regular expression which always matches. If no entry
790matches, the variable `tramp-default-method' takes effect.
791
792If the file name does not specify the user, lookup is done using the
793empty string for the user name.
794
795See `tramp-methods' for a list of possibilities for METHOD."
796 :group 'tramp
797 :type '(repeat (list (regexp :tag "Host regexp")
798 (regexp :tag "User regexp")
799 (string :tag "Method"))))
800
801(defcustom tramp-ftp-method "ftp"
802 "*When this method name is used, forward all calls to Ange-FTP."
780 :group 'tramp 803 :group 'tramp
781 :type 'string) 804 :type 'string)
782 805
@@ -840,6 +863,18 @@ Some shells send such garbage upon connection setup."
840 :group 'tramp 863 :group 'tramp
841 :type 'boolean) 864 :type 'boolean)
842 865
866(defcustom tramp-sh-extra-args '(("/bash\\'" . "--norc"))
867 "*Alist specifying extra arguments to pass to the remote shell.
868Entries are (REGEXP . ARGS) where REGEXP is a regular expression
869matching the shell file name and ARGS is a string specifying the
870arguments.
871
872This variable is only used when Tramp needs to start up another shell
873for tilde expansion. The extra arguments should typically prevent the
874shell from reading its init file."
875 :group 'tramp
876 :type '(alist :key-type string :value-type string))
877
843;; File name format. 878;; File name format.
844 879
845(defcustom tramp-file-name-structure 880(defcustom tramp-file-name-structure
@@ -1313,6 +1348,37 @@ own implementation."
1313 ((fboundp 'point-at-eol) (funcall 'point-at-eol)) 1348 ((fboundp 'point-at-eol) (funcall 'point-at-eol))
1314 (t (save-excursion (end-of-line) (point))))) 1349 (t (save-excursion (end-of-line) (point)))))
1315 1350
1351(defmacro with-parsed-tramp-file-name (filename var &rest body)
1352 "Parse a Tramp filename and make components available in the body.
1353
1354First arg FILENAME is evaluated and dissected into its components.
1355Second arg VAR is a symbol. It is used as a variable name to hold
1356the filename structure. It is also used as a prefix for the variables
1357holding the components. For example, if VAR is the symbol `foo', then
1358`foo' will be bound to the whole structure, `foo-multi-method' will
1359be bound to the multi-method component, and so on for `foo-method',
1360`foo-user', `foo-host', `foo-path'.
1361
1362Remaining args are Lisp expressions to be evaluated (inside an implicit
1363`progn').
1364
1365If VAR is nil, then we bind `v' to the structure and `multi-method',
1366`method', `user', `host', `path' to the components."
1367 `(let* ((,(or var 'v) (tramp-dissect-file-name ,filename))
1368 (,(if var (intern (concat (symbol-name var) "-multi-method")) 'multi-method)
1369 (tramp-file-name-multi-method ,(or var 'v)))
1370 (,(if var (intern (concat (symbol-name var) "-method")) 'method)
1371 (tramp-file-name-method ,(or var 'v)))
1372 (,(if var (intern (concat (symbol-name var) "-user")) 'user)
1373 (tramp-file-name-user ,(or var 'v)))
1374 (,(if var (intern (concat (symbol-name var) "-host")) 'host)
1375 (tramp-file-name-host ,(or var 'v)))
1376 (,(if var (intern (concat (symbol-name var) "-path")) 'path)
1377 (tramp-file-name-path ,(or var 'v))))
1378 ,@body))
1379
1380(put 'with-parsed-tramp-file-name 'lisp-indent-function 2)
1381
1316;;; File Name Handler Functions: 1382;;; File Name Handler Functions:
1317 1383
1318;; The following file name handler ops are not implemented (yet?). 1384;; The following file name handler ops are not implemented (yet?).
@@ -1320,104 +1386,87 @@ own implementation."
1320(defun tramp-handle-make-symbolic-link 1386(defun tramp-handle-make-symbolic-link
1321 (filename linkname &optional ok-if-already-exists) 1387 (filename linkname &optional ok-if-already-exists)
1322 "Like `make-symbolic-link' for tramp files. 1388 "Like `make-symbolic-link' for tramp files.
1323This function will raise an error if FILENAME and LINKNAME are not 1389The LINKNAME argument should look like \"/path/to/target\" or
1324on the same remote host." 1390\"relative-name\",and not like a Tramp filename."
1325 (unless (or (tramp-tramp-file-p filename) 1391 (error "Not implemented yet")
1326 (tramp-tramp-file-p linkname)) 1392 (with-parsed-tramp-file-name linkname l
1327 (tramp-run-real-handler 'make-symbolic-link 1393 (when (tramp-ange-ftp-file-name-p l-multi-method l-method)
1328 (list filename linkname ok-if-already-exists))) 1394 (tramp-invoke-ange-ftp 'make-symbolic-link
1329 (let* ((file (tramp-dissect-file-name filename)) 1395 filename linkname ok-if-already-exists))
1330 (link (tramp-dissect-file-name linkname)) 1396 (let ((ln (tramp-get-remote-ln l-multi l-method l-user l-host))
1331 (multi (tramp-file-name-multi-method file)) 1397 (cwd (file-name-directory l-path)))
1332 (method (tramp-file-name-method file)) 1398 (unless ln
1333 (user (tramp-file-name-user file)) 1399 (signal 'file-error
1334 (host (tramp-file-name-host file)) 1400 (list "Making a symbolic link."
1335 (l-multi (tramp-file-name-multi-method link)) 1401 "ln(1) does not exist on the remote host.")))
1336 (l-meth (tramp-file-name-method link)) 1402
1337 (l-user (tramp-file-name-user link)) 1403 ;; Do the 'confirm if exists' thing.
1338 (l-host (tramp-file-name-host link)) 1404 (when (file-exists-p (expand-file-name filename
1339 (ln (tramp-get-remote-ln multi method user host)) 1405 CCC))
1340 (cwd (file-name-directory (tramp-file-name-path file)))) 1406 ;; What to do?
1341 (unless ln 1407 (if (or (null ok-if-already-exists) ; not allowed to exist
1342 (signal 'file-error (list "Making a symbolic link." 1408 (and (numberp ok-if-already-exists)
1343 "ln(1) does not exist on the remote host."))) 1409 (not (yes-or-no-p
1344 1410 (format
1345 ;; Check that method, user, host are the same. 1411 "File %s already exists; make it a link anyway? "
1346 (unless (equal host l-host) 1412 l-path)))))
1347 (signal 'file-error (list "Can't make symlink across hosts" host l-host))) 1413 (signal 'file-already-exists (list "File already exists" l-path))))
1348 (unless (equal user l-user)
1349 (signal 'file-error (list "Can't make symlink for different users"
1350 user l-user)))
1351 (unless (and (equal multi l-multi)
1352 (equal method l-meth))
1353 (signal 'file-error (list "Method must be the same for making symlinks"
1354 multi l-multi method l-meth)))
1355
1356 ;; Do the 'confirm if exists' thing.
1357 (when (file-exists-p (tramp-file-name-path link))
1358 ;; What to do?
1359 (if (or (null ok-if-already-exists) ; not allowed to exist
1360 (and (numberp ok-if-already-exists)
1361 (not (yes-or-no-p
1362 (format "File %s already exists; make it a link anyway? "
1363 (tramp-file-name-path link))))))
1364 (signal 'file-already-exists (list "File already exists"
1365 (tramp-file-name-path link)))))
1366 1414
1367 ;; Right, they are on the same host, regardless of user, method, etc. 1415 ;; Right, they are on the same host, regardless of user, method, etc.
1368 ;; We now make the link on the remote machine. This will occur as the user 1416 ;; We now make the link on the remote machine. This will occur as the user
1369 ;; that FILENAME belongs to. 1417 ;; that FILENAME belongs to.
1370 (zerop 1418 (zerop
1371 (tramp-send-command-and-check 1419 (tramp-send-command-and-check
1372 multi method user host 1420 fn-multi fn-method fn-user fn-host
1373 (format "cd %s && %s -sf %s %s" 1421 (format "cd %s && %s -sf %s %s"
1374 cwd ln 1422 cwd ln
1375 (tramp-file-name-path file) ; target 1423 (tramp-file-name-path file) ; target
1376 (tramp-file-name-path link)) ; link name 1424 (tramp-file-name-path link)) ; link name
1377 t)))) 1425 t)))))
1378 1426
1379 1427
1380(defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix) 1428(defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix)
1381 "Like `load' for tramp files. Not implemented!" 1429 "Like `load' for tramp files. Not implemented!"
1382 (unless (file-name-absolute-p file) 1430 (unless (file-name-absolute-p file)
1383 (error "Tramp cannot `load' files without absolute path name")) 1431 (error "Tramp cannot `load' files without absolute path name"))
1384 (unless nosuffix 1432 (with-parsed-tramp-file-name file nil
1385 (cond ((file-exists-p (concat file ".elc")) 1433 (when (tramp-ange-ftp-file-name-p multi-method method)
1386 (setq file (concat file ".elc"))) 1434 (tramp-invoke-ange-ftp 'load
1387 ((file-exists-p (concat file ".el")) 1435 file noerror nomessage nosuffix must-suffix))
1388 (setq file (concat file ".el"))))) 1436 (unless nosuffix
1389 (when must-suffix 1437 (cond ((file-exists-p (concat file ".elc"))
1390 ;; The first condition is always true for absolute file names. 1438 (setq file (concat file ".elc")))
1391 ;; Included for safety's sake. 1439 ((file-exists-p (concat file ".el"))
1392 (unless (or (file-name-directory file) 1440 (setq file (concat file ".el")))))
1393 (string-match "\\.elc?\\'" file)) 1441 (when must-suffix
1394 (error "File `%s' does not include a `.el' or `.elc' suffix" 1442 ;; The first condition is always true for absolute file names.
1395 file))) 1443 ;; Included for safety's sake.
1396 (unless noerror 1444 (unless (or (file-name-directory file)
1397 (when (not (file-exists-p file)) 1445 (string-match "\\.elc?\\'" file))
1398 (error "Cannot load nonexistant file `%s'" file))) 1446 (error "File `%s' does not include a `.el' or `.elc' suffix"
1399 (if (not (file-exists-p file)) 1447 file)))
1400 nil 1448 (unless noerror
1401 (unless nomessage 1449 (when (not (file-exists-p file))
1402 (message "Loading %s..." file)) 1450 (error "Cannot load nonexistant file `%s'" file)))
1403 (let ((local-copy (file-local-copy file))) 1451 (if (not (file-exists-p file))
1404 ;; MUST-SUFFIX doesn't exist on XEmacs, so let it default to nil. 1452 nil
1405 (load local-copy noerror t t) 1453 (unless nomessage
1406 (delete-file local-copy)) 1454 (message "Loading %s..." file))
1407 (unless nomessage 1455 (let ((local-copy (file-local-copy file)))
1408 (message "Loading %s...done" file)) 1456 ;; MUST-SUFFIX doesn't exist on XEmacs, so let it default to nil.
1409 t)) 1457 (load local-copy noerror t t)
1458 (delete-file local-copy))
1459 (unless nomessage
1460 (message "Loading %s...done" file))
1461 t)))
1410 1462
1411;; Path manipulation functions that grok TRAMP paths... 1463;; Path manipulation functions that grok TRAMP paths...
1412(defun tramp-handle-file-name-directory (file) 1464(defun tramp-handle-file-name-directory (file)
1413 "Like `file-name-directory' but aware of TRAMP files." 1465 "Like `file-name-directory' but aware of TRAMP files."
1414 ;; everything except the last filename thing is the directory 1466 ;; everything except the last filename thing is the directory
1415 (let* ((v (tramp-dissect-file-name file)) 1467 (with-parsed-tramp-file-name file nil
1416 (multi-method (tramp-file-name-multi-method v)) 1468 (when (tramp-ange-ftp-file-name-p multi-method method)
1417 (method (tramp-file-name-method v)) 1469 (tramp-invoke-ange-ftp 'file-name-directory file))
1418 (user (tramp-file-name-user v))
1419 (host (tramp-file-name-host v))
1420 (path (tramp-file-name-path v)))
1421 (if (or (string= path "") (string= path "/")) 1470 (if (or (string= path "") (string= path "/"))
1422 ;; For a filename like "/[foo]", we return "/". The `else' 1471 ;; For a filename like "/[foo]", we return "/". The `else'
1423 ;; case would return "/[foo]" unchanged. But if we do that, 1472 ;; case would return "/[foo]" unchanged. But if we do that,
@@ -1434,98 +1483,95 @@ on the same remote host."
1434 1483
1435(defun tramp-handle-file-name-nondirectory (file) 1484(defun tramp-handle-file-name-nondirectory (file)
1436 "Like `file-name-nondirectory' but aware of TRAMP files." 1485 "Like `file-name-nondirectory' but aware of TRAMP files."
1437 (let ((v (tramp-dissect-file-name file))) 1486 (with-parsed-tramp-file-name file nil
1438 (file-name-nondirectory (tramp-file-name-path v)))) 1487 (when (tramp-ange-ftp-file-name-p multi-method method)
1488 (tramp-invoke-ange-ftp 'file-name-nondirectory file))
1489 (file-name-nondirectory path)))
1439 1490
1440(defun tramp-handle-file-truename (filename &optional counter prev-dirs) 1491(defun tramp-handle-file-truename (filename &optional counter prev-dirs)
1441 "Like `file-truename' for tramp files." 1492 "Like `file-truename' for tramp files."
1442 (let* ((v (tramp-dissect-file-name (tramp-handle-expand-file-name filename))) 1493 (with-parsed-tramp-file-name filename nil
1443 (multi-method (tramp-file-name-multi-method v)) 1494 ;; Ange-FTP does not support truename processing. It returns the
1444 (method (tramp-file-name-method v)) 1495 ;; file name as-is. So that's what we do, too.
1445 (user (tramp-file-name-user v)) 1496 (when (tramp-ange-ftp-file-name-p multi-method method)
1446 (host (tramp-file-name-host v)) 1497 filename)
1447 (path (tramp-file-name-path v)) 1498 (let* ((steps (tramp-split-string path "/"))
1448 (steps (tramp-split-string path "/")) 1499 (pathdir (let ((directory-sep-char ?/))
1449 (pathdir (let ((directory-sep-char ?/)) 1500 (file-name-as-directory path)))
1450 (file-name-as-directory path))) 1501 (is-dir (string= path pathdir))
1451 (is-dir (string= path pathdir)) 1502 (thisstep nil)
1452 (thisstep nil) 1503 (numchase 0)
1453 (numchase 0) 1504 ;; Don't make the following value larger than necessary.
1454 ;; Don't make the following value larger than necessary. 1505 ;; People expect an error message in a timely fashion when
1455 ;; People expect an error message in a timely fashion when 1506 ;; something is wrong; otherwise they might think that Emacs
1456 ;; something is wrong; otherwise they might think that Emacs 1507 ;; is hung. Of course, correctness has to come first.
1457 ;; is hung. Of course, correctness has to come first. 1508 (numchase-limit 20)
1458 (numchase-limit 20) 1509 (result nil) ;result steps in reverse order
1459 (result nil) ;result steps in reverse order 1510 (curstri "")
1460 (curstri "") 1511 symlink-target)
1461 symlink-target)
1462 (tramp-message-for-buffer
1463 multi-method method user host
1464 10 "Finding true name for `%s'" filename)
1465 (while (and steps (< numchase numchase-limit))
1466 (setq thisstep (pop steps))
1467 (tramp-message-for-buffer 1512 (tramp-message-for-buffer
1468 multi-method method user host 1513 multi-method method user host
1469 10 "Check %s" 1514 10 "Finding true name for `%s'" filename)
1470 (mapconcat 'identity 1515 (while (and steps (< numchase numchase-limit))
1471 (append '("") (reverse result) (list thisstep)) 1516 (setq thisstep (pop steps))
1472 "/")) 1517 (tramp-message-for-buffer
1473 (setq symlink-target 1518 multi-method method user host
1474 (nth 0 (tramp-handle-file-attributes 1519 10 "Check %s"
1475 (tramp-make-tramp-file-name 1520 (mapconcat 'identity
1476 multi-method method user host 1521 (append '("") (reverse result) (list thisstep))
1477 (mapconcat 'identity 1522 "/"))
1478 (append '("") (reverse result) (list thisstep)) 1523 (setq symlink-target
1479 "/"))))) 1524 (nth 0 (tramp-handle-file-attributes
1480 (cond ((string= "." thisstep) 1525 (tramp-make-tramp-file-name
1481 (tramp-message-for-buffer multi-method method user host 1526 multi-method method user host
1482 10 "Ignoring step `.'")) 1527 (mapconcat 'identity
1483 ((string= ".." thisstep) 1528 (append '("") (reverse result) (list thisstep))
1484 (tramp-message-for-buffer multi-method method user host 1529 "/")))))
1485 10 "Processing step `..'") 1530 (cond ((string= "." thisstep)
1486 (pop result)) 1531 (tramp-message-for-buffer multi-method method user host
1487 ((stringp symlink-target) 1532 10 "Ignoring step `.'"))
1488 ;; It's a symlink, follow it. 1533 ((string= ".." thisstep)
1489 (tramp-message-for-buffer 1534 (tramp-message-for-buffer multi-method method user host
1490 multi-method method user host 1535 10 "Processing step `..'")
1491 10 "Follow symlink to %s" symlink-target) 1536 (pop result))
1492 (setq numchase (1+ numchase)) 1537 ((stringp symlink-target)
1493 (when (file-name-absolute-p symlink-target) 1538 ;; It's a symlink, follow it.
1494 (setq result nil)) 1539 (tramp-message-for-buffer
1495 (setq steps 1540 multi-method method user host
1496 (append (tramp-split-string symlink-target "/") steps))) 1541 10 "Follow symlink to %s" symlink-target)
1497 (t 1542 (setq numchase (1+ numchase))
1498 ;; It's a file. 1543 (when (file-name-absolute-p symlink-target)
1499 (setq result (cons thisstep result))))) 1544 (setq result nil))
1500 (when (>= numchase numchase-limit) 1545 (setq steps
1501 (error "Maximum number (%d) of symlinks exceeded" numchase-limit)) 1546 (append (tramp-split-string symlink-target "/") steps)))
1502 (setq result (reverse result)) 1547 (t
1503 (tramp-message-for-buffer 1548 ;; It's a file.
1504 multi-method method user host 1549 (setq result (cons thisstep result)))))
1505 10 "True name of `%s' is `%s'" 1550 (when (>= numchase numchase-limit)
1506 filename (mapconcat 'identity (cons "" result) "/")) 1551 (error "Maximum number (%d) of symlinks exceeded" numchase-limit))
1507 (tramp-make-tramp-file-name 1552 (setq result (reverse result))
1508 multi-method method user host 1553 (tramp-message-for-buffer
1509 (concat (mapconcat 'identity (cons "" result) "/") 1554 multi-method method user host
1510 (if is-dir "/" ""))))) 1555 10 "True name of `%s' is `%s'"
1556 filename (mapconcat 'identity (cons "" result) "/"))
1557 (tramp-make-tramp-file-name
1558 multi-method method user host
1559 (concat (mapconcat 'identity (cons "" result) "/")
1560 (if is-dir "/" ""))))))
1511 1561
1512;; Basic functions. 1562;; Basic functions.
1513 1563
1514(defun tramp-handle-file-exists-p (filename) 1564(defun tramp-handle-file-exists-p (filename)
1515 "Like `file-exists-p' for tramp files." 1565 "Like `file-exists-p' for tramp files."
1516 (let ((v (tramp-dissect-file-name (tramp-handle-expand-file-name filename))) 1566 (with-parsed-tramp-file-name filename nil
1517 multi-method method user host path) 1567 (when (tramp-ange-ftp-file-name-p multi-method method)
1518 (setq multi-method (tramp-file-name-multi-method v)) 1568 (tramp-invoke-ange-ftp 'file-exists-p filename))
1519 (setq method (tramp-file-name-method v))
1520 (setq user (tramp-file-name-user v))
1521 (setq host (tramp-file-name-host v))
1522 (setq path (tramp-file-name-path v))
1523 (save-excursion 1569 (save-excursion
1524 (zerop (tramp-send-command-and-check 1570 (zerop (tramp-send-command-and-check
1525 multi-method method user host 1571 multi-method method user host
1526 (format 1572 (format
1527 (tramp-get-file-exists-command multi-method method user host) 1573 (tramp-get-file-exists-command multi-method method user host)
1528 (tramp-shell-quote-argument path))))))) 1574 (tramp-shell-quote-argument path)))))))
1529 1575
1530;; CCC: This should check for an error condition and signal failure 1576;; CCC: This should check for an error condition and signal failure
1531;; when something goes wrong. 1577;; when something goes wrong.
@@ -1537,15 +1583,14 @@ rather than as numbers."
1537 (if (tramp-handle-file-exists-p filename) 1583 (if (tramp-handle-file-exists-p filename)
1538 ;; file exists, find out stuff 1584 ;; file exists, find out stuff
1539 (save-excursion 1585 (save-excursion
1540 (let* ((v (tramp-dissect-file-name (tramp-handle-expand-file-name filename))) 1586 (with-parsed-tramp-file-name filename nil
1541 (multi-method (tramp-file-name-multi-method v)) 1587 (when (tramp-ange-ftp-file-name-p multi-method method)
1542 (method (tramp-file-name-method v)) 1588 (tramp-invoke-ange-ftp 'file-attributes file))
1543 (user (tramp-file-name-user v))
1544 (host (tramp-file-name-host v))
1545 (path (tramp-file-name-path v)))
1546 (if (tramp-get-remote-perl multi-method method user host) 1589 (if (tramp-get-remote-perl multi-method method user host)
1547 (tramp-handle-file-attributes-with-perl multi-method method user host path nonnumeric) 1590 (tramp-handle-file-attributes-with-perl
1548 (tramp-handle-file-attributes-with-ls multi-method method user host path nonnumeric)))) 1591 multi-method method user host path nonnumeric)
1592 (tramp-handle-file-attributes-with-ls
1593 multi-method method user host path nonnumeric))))
1549 nil)) ; no file 1594 nil)) ; no file
1550 1595
1551 1596
@@ -1653,56 +1698,22 @@ is initially created and is kept cached by the remote shell."
1653 (buffer-name))) 1698 (buffer-name)))
1654 (when time-list 1699 (when time-list
1655 (tramp-run-real-handler 'set-visited-file-modtime (list time-list))) 1700 (tramp-run-real-handler 'set-visited-file-modtime (list time-list)))
1656 (let* ((coding-system-used nil) 1701 (let ((f (buffer-file-name))
1657 (f (buffer-file-name)) 1702 (coding-system-used nil))
1658 (v (tramp-dissect-file-name f)) 1703 (with-parsed-tramp-file-name f nil
1659 (multi-method (tramp-file-name-multi-method v)) 1704 ;; This operation is not handled by Ange-FTP!
1660 (method (tramp-file-name-method v)) 1705 (when (tramp-ange-ftp-file-name-p multi-method method)
1661 (user (tramp-file-name-user v)) 1706 (throw 'tramp-forward-to-ange-ftp
1662 (host (tramp-file-name-host v)) 1707 (tramp-run-real-handler 'set-visited-file-modtime
1663 (path (tramp-file-name-path v)) 1708 (list time-list))))
1664 (attr (file-attributes f)) 1709 (let* ((attr (file-attributes f))
1665 (modtime (nth 5 attr))) 1710 (modtime (nth 5 attr)))
1666 ;; We use '(0 0) as a don't-know value. See also 1711 ;; We use '(0 0) as a don't-know value. See also
1667 ;; `tramp-handle-file-attributes-with-ls'. 1712 ;; `tramp-handle-file-attributes-with-ls'.
1668 (when (boundp 'last-coding-system-used) 1713 (when (boundp 'last-coding-system-used)
1669 (setq coding-system-used last-coding-system-used)) 1714 (setq coding-system-used last-coding-system-used))
1670 (if (not (equal modtime '(0 0)))
1671 (tramp-run-real-handler 'set-visited-file-modtime (list modtime))
1672 (save-excursion
1673 (tramp-send-command
1674 multi-method method user host
1675 (format "%s -ild %s"
1676 (tramp-get-ls-command multi-method method user host)
1677 (tramp-shell-quote-argument path)))
1678 (tramp-wait-for-output)
1679 (setq attr (buffer-substring (point)
1680 (progn (end-of-line) (point)))))
1681 (setq tramp-buffer-file-attributes attr))
1682 (when (boundp 'last-coding-system-used)
1683 (setq last-coding-system-used coding-system-used))
1684 nil))
1685
1686;; This function makes the same assumption as
1687;; `tramp-handle-set-visited-file-modtime'.
1688(defun tramp-handle-verify-visited-file-modtime (buf)
1689 "Like `verify-visited-file-modtime' for tramp files."
1690 (with-current-buffer buf
1691 (let* ((f (buffer-file-name))
1692 (v (tramp-dissect-file-name f))
1693 (multi-method (tramp-file-name-multi-method v))
1694 (method (tramp-file-name-method v))
1695 (user (tramp-file-name-user v))
1696 (host (tramp-file-name-host v))
1697 (path (tramp-file-name-path v))
1698 (attr (file-attributes f))
1699 (modtime (nth 5 attr)))
1700 (if attr
1701 (if (not (equal modtime '(0 0))) 1715 (if (not (equal modtime '(0 0)))
1702 ;; Why does `file-attributes' return a list (HIGH LOW), but 1716 (tramp-run-real-handler 'set-visited-file-modtime (list modtime))
1703 ;; `visited-file-modtime' returns a cons (HIGH . LOW)?
1704 (let ((mt (visited-file-modtime)))
1705 (< (abs (tramp-time-diff modtime (list (car mt) (cdr mt)))) 2))
1706 (save-excursion 1717 (save-excursion
1707 (tramp-send-command 1718 (tramp-send-command
1708 multi-method method user host 1719 multi-method method user host
@@ -1712,10 +1723,50 @@ is initially created and is kept cached by the remote shell."
1712 (tramp-wait-for-output) 1723 (tramp-wait-for-output)
1713 (setq attr (buffer-substring (point) 1724 (setq attr (buffer-substring (point)
1714 (progn (end-of-line) (point))))) 1725 (progn (end-of-line) (point)))))
1715 (equal tramp-buffer-file-attributes attr)) 1726 (setq tramp-buffer-file-attributes attr))
1716 ;; If file does not exist, say it is not modified. 1727 (when (boundp 'last-coding-system-used)
1728 (setq last-coding-system-used coding-system-used))
1717 nil)))) 1729 nil))))
1718 1730
1731;; CCC continue here
1732
1733;; This function makes the same assumption as
1734;; `tramp-handle-set-visited-file-modtime'.
1735(defun tramp-handle-verify-visited-file-modtime (buf)
1736 "Like `verify-visited-file-modtime' for tramp files."
1737 (with-current-buffer buf
1738 (let ((f (buffer-file-name)))
1739 (with-parsed-tramp-file-name f nil
1740 (when (tramp-ange-ftp-file-name-p f)
1741 ;; This one requires a hack since the file name is not passed
1742 ;; on the arg list.
1743 (let ((buffer-file-name (tramp-make-ange-ftp-file-name
1744 user host path)))
1745 (tramp-invoke-ange-ftp 'verify-visited-file-modtime buf)))
1746 (let* ((attr (file-attributes f))
1747 (modtime (nth 5 attr)))
1748 (cond ((and attr (not (equal modtime '(0 0))))
1749 ;; Why does `file-attributes' return a list (HIGH
1750 ;; LOW), but `visited-file-modtime' returns a cons
1751 ;; (HIGH . LOW)?
1752 (let ((mt (visited-file-modtime)))
1753 (< (abs (tramp-time-diff
1754 modtime (list (car mt) (cdr mt)))) 2)))
1755 (attr
1756 (save-excursion
1757 (tramp-send-command
1758 multi-method method user host
1759 (format "%s -ild %s"
1760 (tramp-get-ls-command multi-method method
1761 user host)
1762 (tramp-shell-quote-argument path)))
1763 (tramp-wait-for-output)
1764 (setq attr (buffer-substring
1765 (point) (progn (end-of-line) (point)))))
1766 (equal tramp-buffer-file-attributes attr))
1767 ;; If file does not exist, say it is not modified.
1768 nil))))))
1769
1719(defadvice clear-visited-file-modtime (after tramp activate) 1770(defadvice clear-visited-file-modtime (after tramp activate)
1720 "Set `tramp-buffer-file-attributes' back to nil. 1771 "Set `tramp-buffer-file-attributes' back to nil.
1721Tramp uses this variable as an emulation for the actual modtime of the file, 1772Tramp uses this variable as an emulation for the actual modtime of the file,
@@ -1724,17 +1775,15 @@ if the remote host can't provide the modtime."
1724 1775
1725(defun tramp-handle-set-file-modes (filename mode) 1776(defun tramp-handle-set-file-modes (filename mode)
1726 "Like `set-file-modes' for tramp files." 1777 "Like `set-file-modes' for tramp files."
1727 (let ((v (tramp-dissect-file-name filename))) 1778 (with-parsed-tramp-file-name filename nil
1779 (when (tramp-ange-ftp-file-name-p multi-method method)
1780 (tramp-invoke-ange-ftp 'set-file-modes filename mode))
1728 (save-excursion 1781 (save-excursion
1729 (unless (zerop (tramp-send-command-and-check 1782 (unless (zerop (tramp-send-command-and-check
1730 (tramp-file-name-multi-method v) 1783 multi-method method user host
1731 (tramp-file-name-method v) 1784 (format "chmod %s %s"
1732 (tramp-file-name-user v) 1785 (tramp-decimal-to-octal mode)
1733 (tramp-file-name-host v) 1786 (tramp-shell-quote-argument path))))
1734 (format "chmod %s %s"
1735 (tramp-decimal-to-octal mode)
1736 (tramp-shell-quote-argument
1737 (tramp-file-name-path v)))))
1738 (signal 'file-error 1787 (signal 'file-error
1739 (list "Doing chmod" 1788 (list "Doing chmod"
1740 ;; FIXME: extract the proper text from chmod's stderr. 1789 ;; FIXME: extract the proper text from chmod's stderr.
@@ -1745,17 +1794,26 @@ if the remote host can't provide the modtime."
1745 1794
1746(defun tramp-handle-file-executable-p (filename) 1795(defun tramp-handle-file-executable-p (filename)
1747 "Like `file-executable-p' for tramp files." 1796 "Like `file-executable-p' for tramp files."
1748 (zerop (tramp-run-test "-x" filename))) 1797 (with-parsed-tramp-file-name filename nil
1798 (when (tramp-ange-ftp-file-name-p multi-method method)
1799 (tramp-invoke-ange-ftp 'file-executable-p filename))
1800 (zerop (tramp-run-test "-x" filename))))
1749 1801
1750(defun tramp-handle-file-readable-p (filename) 1802(defun tramp-handle-file-readable-p (filename)
1751 "Like `file-readable-p' for tramp files." 1803 "Like `file-readable-p' for tramp files."
1752 (zerop (tramp-run-test "-r" filename))) 1804 (with-parsed-tramp-file-name filename nil
1805 (when (tramp-ange-ftp-file-name-p multi-method method)
1806 (tramp-invoke-ange-ftp 'file-readable-p filename))
1807 (zerop (tramp-run-test "-r" filename))))
1753 1808
1754(defun tramp-handle-file-accessible-directory-p (filename) 1809(defun tramp-handle-file-accessible-directory-p (filename)
1755 "Like `file-accessible-directory-p' for tramp files." 1810 "Like `file-accessible-directory-p' for tramp files."
1756 (and (zerop (tramp-run-test "-d" filename)) 1811 (with-parsed-tramp-file-name filename nil
1757 (zerop (tramp-run-test "-r" filename)) 1812 (when (tramp-ange-ftp-file-name-p multi-method method)
1758 (zerop (tramp-run-test "-x" filename)))) 1813 (tramp-invoke-ange-ftp 'file-accessible-directory-p filename))
1814 (and (zerop (tramp-run-test "-d" filename))
1815 (zerop (tramp-run-test "-r" filename))
1816 (zerop (tramp-run-test "-x" filename)))))
1759 1817
1760;; When the remote shell is started, it looks for a shell which groks 1818;; When the remote shell is started, it looks for a shell which groks
1761;; tilde expansion. Here, we assume that all shells which grok tilde 1819;; tilde expansion. Here, we assume that all shells which grok tilde
@@ -1768,42 +1826,44 @@ if the remote host can't provide the modtime."
1768 nil) 1826 nil)
1769 ((not (file-exists-p file2)) 1827 ((not (file-exists-p file2))
1770 t) 1828 t)
1771 ;; We are sure both files exist at this point. 1829 ;; We are sure both files exist at this point. We assume that
1830 ;; both files are Tramp files, otherwise we issue an error
1831 ;; message. Todo: make a better error message.
1772 (t 1832 (t
1773 (save-excursion 1833 (save-excursion
1774 (let* ((v1 (tramp-dissect-file-name file1)) 1834 (with-parsed-tramp-file-name file1 v1
1775 (mm1 (tramp-file-name-multi-method v1)) 1835 (with-parsed-tramp-file-name file2 v2
1776 (m1 (tramp-file-name-method v1)) 1836 (when (and (tramp-ange-ftp-file-name-p v1-multi-method v1-method)
1777 (u1 (tramp-file-name-user v1)) 1837 (tramp-ange-ftp-file-name-p v2-multi-method v2-method))
1778 (h1 (tramp-file-name-host v1)) 1838 (tramp-invoke-ange-ftp 'file-newer-than-file-p
1779 (v2 (tramp-dissect-file-name file2)) 1839 file1 file2))
1780 (mm2 (tramp-file-name-multi-method v2)) 1840 (unless (and (equal v1-multi-method v2-multi-method)
1781 (m2 (tramp-file-name-method v2)) 1841 (equal v1-method v2-method)
1782 (u2 (tramp-file-name-user v2)) 1842 (equal v1-user v2-user)
1783 (h2 (tramp-file-name-host v2))) 1843 (equal v1-host v2-host))
1784 (unless (and (equal mm1 mm2) 1844 (signal 'file-error
1785 (equal m1 m2) 1845 (list "Files must have same method, user, host"
1786 (equal u1 u2) 1846 file1 file2)))
1787 (equal h1 h2)) 1847 (unless (and (tramp-tramp-file-p file1)
1788 (signal 'file-error 1848 (tramp-tramp-file-p file2))
1789 (list "Files must have same method, user, host" 1849 (signal 'file-error
1790 file1 file2))) 1850 (list "Files must be tramp files on same host"
1791 (unless (and (tramp-tramp-file-p file1) 1851 file1 file2)))
1792 (tramp-tramp-file-p file2)) 1852 (if (tramp-get-test-groks-nt
1793 (signal 'file-error 1853 v1-multi-method v1-method v1-user v1-host)
1794 (list "Files must be tramp files on same host" 1854 (zerop (tramp-run-test2 "test" file1 file2 "-nt"))
1795 file1 file2))) 1855 (zerop (tramp-run-test2 "tramp_test_nt" file1 file2)))))))))
1796 (if (tramp-get-test-groks-nt mm1 m1 u1 h1)
1797 (zerop (tramp-run-test2 "test" file1 file2 "-nt"))
1798 (zerop (tramp-run-test2 "tramp_test_nt" file1 file2))))))))
1799 1856
1800;; Functions implemented using the basic functions above. 1857;; Functions implemented using the basic functions above.
1801 1858
1802(defun tramp-handle-file-modes (filename) 1859(defun tramp-handle-file-modes (filename)
1803 "Like `file-modes' for tramp files." 1860 "Like `file-modes' for tramp files."
1804 (when (file-exists-p filename) 1861 (with-parsed-tramp-file-name filename nil
1805 (tramp-mode-string-to-int 1862 (when (tramp-ange-ftp-file-name-p multi-method method)
1806 (nth 8 (tramp-handle-file-attributes filename))))) 1863 (tramp-invoke-ange-ftp 'file-modes filename))
1864 (when (file-exists-p filename)
1865 (tramp-mode-string-to-int
1866 (nth 8 (tramp-handle-file-attributes filename))))))
1807 1867
1808(defun tramp-handle-file-directory-p (filename) 1868(defun tramp-handle-file-directory-p (filename)
1809 "Like `file-directory-p' for tramp files." 1869 "Like `file-directory-p' for tramp files."
@@ -1815,40 +1875,55 @@ if the remote host can't provide the modtime."
1815 ;; we? 1875 ;; we?
1816 ;; 1876 ;;
1817 ;; Alternatives: `cd %s', `test -d %s' 1877 ;; Alternatives: `cd %s', `test -d %s'
1818 (save-excursion 1878 (with-parsed-tramp-file-name filename nil
1819 (let ((v (tramp-dissect-file-name filename))) 1879 (when (tramp-ange-ftp-file-name-p multi-method method)
1880 (tramp-invoke-ange-ftp 'file-directory-p filename))
1881 (save-excursion
1820 (zerop 1882 (zerop
1821 (tramp-send-command-and-check 1883 (tramp-send-command-and-check
1822 (tramp-file-name-multi-method v) (tramp-file-name-method v) 1884 multi-method method user host
1823 (tramp-file-name-user v) (tramp-file-name-host v) 1885 (format "test -d %s"
1824 (format "test -d %s" 1886 (tramp-shell-quote-argument path))
1825 (tramp-shell-quote-argument (tramp-file-name-path v))) 1887 t))))) ;run command in subshell
1826 t))))) ;run command in subshell
1827 1888
1828(defun tramp-handle-file-regular-p (filename) 1889(defun tramp-handle-file-regular-p (filename)
1829 "Like `file-regular-p' for tramp files." 1890 "Like `file-regular-p' for tramp files."
1830 (and (tramp-handle-file-exists-p filename) 1891 (with-parsed-tramp-file-name filename nil
1831 (eq ?- (aref (nth 8 (tramp-handle-file-attributes filename)) 0)))) 1892 (when (tramp-ange-ftp-file-name-p multi-method method)
1893 (tramp-invoke-ange-ftp 'file-regular-p filename))
1894 (and (tramp-handle-file-exists-p filename)
1895 (eq ?- (aref (nth 8 (tramp-handle-file-attributes filename)) 0)))))
1832 1896
1833(defun tramp-handle-file-symlink-p (filename) 1897(defun tramp-handle-file-symlink-p (filename)
1834 "Like `file-symlink-p' for tramp files." 1898 "Like `file-symlink-p' for tramp files."
1835 (let ((x (car (tramp-handle-file-attributes filename)))) 1899 (with-parsed-tramp-file-name filename nil
1836 (when (stringp x) x))) 1900 (when (tramp-ange-ftp-file-name-p multi-method method)
1901 (tramp-invoke-ange-ftp 'file-symlink-p filename))
1902 (let ((x (car (tramp-handle-file-attributes filename))))
1903 (when (stringp x) x))))
1837 1904
1838(defun tramp-handle-file-writable-p (filename) 1905(defun tramp-handle-file-writable-p (filename)
1839 "Like `file-writable-p' for tramp files." 1906 "Like `file-writable-p' for tramp files."
1840 (if (tramp-handle-file-exists-p filename) 1907 (with-parsed-tramp-file-name filename nil
1841 ;; Existing files must be writable. 1908 (when (tramp-ange-ftp-file-name-p multi-method method)
1842 (zerop (tramp-run-test "-w" filename)) 1909 (tramp-invoke-ange-ftp 'file-writable-p filename))
1843 ;; If file doesn't exist, check if directory is writable. 1910 (if (tramp-handle-file-exists-p filename)
1844 (and (zerop (tramp-run-test "-d" (tramp-handle-file-name-directory filename))) 1911 ;; Existing files must be writable.
1845 (zerop (tramp-run-test "-w" (tramp-handle-file-name-directory filename)))))) 1912 (zerop (tramp-run-test "-w" filename))
1913 ;; If file doesn't exist, check if directory is writable.
1914 (and (zerop (tramp-run-test
1915 "-d" (tramp-handle-file-name-directory filename)))
1916 (zerop (tramp-run-test
1917 "-w" (tramp-handle-file-name-directory filename)))))))
1846 1918
1847(defun tramp-handle-file-ownership-preserved-p (filename) 1919(defun tramp-handle-file-ownership-preserved-p (filename)
1848 "Like `file-ownership-preserved-p' for tramp files." 1920 "Like `file-ownership-preserved-p' for tramp files."
1849 (or (not (tramp-handle-file-exists-p filename)) 1921 (with-parsed-tramp-file-name filename nil
1850 ;; Existing files must be writable. 1922 (when (tramp-ange-ftp-file-name-p multi-method method)
1851 (zerop (tramp-run-test "-O" filename)))) 1923 (tramp-invoke-ange-ftp 'file-ownership-preserved-p filename))
1924 (or (not (tramp-handle-file-exists-p filename))
1925 ;; Existing files must be writable.
1926 (zerop (tramp-run-test "-O" filename)))))
1852 1927
1853;; Other file name ops. 1928;; Other file name ops.
1854 1929
@@ -1863,102 +1938,103 @@ if the remote host can't provide the modtime."
1863;; Philippe Troin <phil@fifi.org> 1938;; Philippe Troin <phil@fifi.org>
1864(defun tramp-handle-directory-file-name (directory) 1939(defun tramp-handle-directory-file-name (directory)
1865 "Like `directory-file-name' for tramp files." 1940 "Like `directory-file-name' for tramp files."
1866 (let ((directory-length-1 (1- (length directory)))) 1941 (with-parsed-tramp-file-name directory nil
1867 (save-match-data 1942 (when (tramp-ange-ftp-file-name-p multi-method method)
1868 (if (and (eq (aref directory directory-length-1) ?/) 1943 (tramp-invoke-ange-ftp 'directory-file-name directory))
1869 (eq (string-match tramp-file-name-regexp directory) 0) 1944 (let ((directory-length-1 (1- (length directory))))
1870 (/= (match-end 0) directory-length-1)) 1945 (save-match-data
1871 (substring directory 0 directory-length-1) 1946 (if (and (eq (aref directory directory-length-1) ?/)
1872 directory)))) 1947 (eq (string-match tramp-file-name-regexp directory) 0)
1948 (/= (match-end 0) directory-length-1))
1949 (substring directory 0 directory-length-1)
1950 directory)))))
1873 1951
1874;; Directory listings. 1952;; Directory listings.
1875 1953
1876(defun tramp-handle-directory-files (directory &optional full match nosort) 1954(defun tramp-handle-directory-files (directory &optional full match nosort)
1877 "Like `directory-files' for tramp files." 1955 "Like `directory-files' for tramp files."
1878 (let ((v (tramp-dissect-file-name (tramp-handle-expand-file-name directory))) 1956 (with-parsed-tramp-file-name directory nil
1879 multi-method method user host path result x) 1957 (when (tramp-ange-ftp-file-name-p multi-method method)
1880 (setq multi-method (tramp-file-name-multi-method v)) 1958 (tramp-invoke-ange-ftp 'directory-files
1881 (setq method (tramp-file-name-method v)) 1959 directory full match nosort))
1882 (setq user (tramp-file-name-user v)) 1960 (let (result x)
1883 (setq host (tramp-file-name-host v))
1884 (setq path (tramp-file-name-path v))
1885 (save-excursion
1886 (tramp-barf-unless-okay multi-method method user host
1887 (concat "cd " (tramp-shell-quote-argument path))
1888 nil
1889 'file-error
1890 "tramp-handle-directory-files: couldn't `cd %s'"
1891 (tramp-shell-quote-argument path))
1892 (tramp-send-command
1893 multi-method method user host
1894 (concat (tramp-get-ls-command multi-method method user host)
1895 " -a | cat"))
1896 (tramp-wait-for-output)
1897 (goto-char (point-max))
1898 (while (zerop (forward-line -1))
1899 (setq x (buffer-substring (point)
1900 (tramp-line-end-position)))
1901 (when (or (not match) (string-match match x))
1902 (if full
1903 (push (concat (file-name-as-directory directory)
1904 x)
1905 result)
1906 (push x result))))
1907 (tramp-send-command multi-method method user host "cd")
1908 (tramp-wait-for-output))
1909 result))
1910
1911;; This function should return "foo/" for directories and "bar" for
1912;; files. We use `ls -ad' to get a list of files (including
1913;; directories), and `find . -type d \! -name . -prune' to get a list
1914;; of directories.
1915(defun tramp-handle-file-name-all-completions (filename directory)
1916 "Like `file-name-all-completions' for tramp files."
1917 (unless (save-match-data (string-match "/" filename))
1918 (let* ((v (tramp-dissect-file-name directory))
1919 (multi-method (tramp-file-name-multi-method v))
1920 (method (tramp-file-name-method v))
1921 (user (tramp-file-name-user v))
1922 (host (tramp-file-name-host v))
1923 (path (tramp-file-name-path v))
1924 (nowild tramp-completion-without-shell-p)
1925 result)
1926 (save-excursion 1961 (save-excursion
1927 (tramp-barf-unless-okay 1962 (tramp-barf-unless-okay
1928 multi-method method user host 1963 multi-method method user host
1929 (format "cd %s" (tramp-shell-quote-argument path)) 1964 (concat "cd " (tramp-shell-quote-argument path))
1930 nil 'file-error 1965 nil
1931 "tramp-handle-file-name-all-completions: Couldn't `cd %s'" 1966 'file-error
1967 "tramp-handle-directory-files: couldn't `cd %s'"
1932 (tramp-shell-quote-argument path)) 1968 (tramp-shell-quote-argument path))
1933
1934 ;; Get a list of directories and files, including reliably
1935 ;; tagging the directories with a trailing '/'. Because I
1936 ;; rock. --daniel@danann.net
1937 (tramp-send-command 1969 (tramp-send-command
1938 multi-method method user host 1970 multi-method method user host
1939 (format (concat "%s -a %s 2>/dev/null | while read f; do " 1971 (concat (tramp-get-ls-command multi-method method user host)
1940 "if test -d \"$f\" 2>/dev/null; " 1972 " -a | cat"))
1941 "then echo \"$f/\"; else echo \"$f\"; fi; done")
1942 (tramp-get-ls-command multi-method method user host)
1943 (if (or nowild (zerop (length filename)))
1944 ""
1945 (format "-d %s*" (tramp-shell-quote-argument filename)))))
1946
1947 ;; Now grab the output.
1948 (tramp-wait-for-output) 1973 (tramp-wait-for-output)
1949 (goto-char (point-max)) 1974 (goto-char (point-max))
1950 (while (zerop (forward-line -1)) 1975 (while (zerop (forward-line -1))
1951 (push (buffer-substring (point) 1976 (setq x (buffer-substring (point)
1952 (tramp-line-end-position)) 1977 (tramp-line-end-position)))
1953 result)) 1978 (when (or (not match) (string-match match x))
1954 1979 (if full
1980 (push (concat (file-name-as-directory directory)
1981 x)
1982 result)
1983 (push x result))))
1955 (tramp-send-command multi-method method user host "cd") 1984 (tramp-send-command multi-method method user host "cd")
1956 (tramp-wait-for-output) 1985 (tramp-wait-for-output))
1986 result)))
1987
1988;; This function should return "foo/" for directories and "bar" for
1989;; files. We use `ls -ad' to get a list of files (including
1990;; directories), and `find . -type d \! -name . -prune' to get a list
1991;; of directories.
1992(defun tramp-handle-file-name-all-completions (filename directory)
1993 "Like `file-name-all-completions' for tramp files."
1994 (with-parsed-tramp-file-name directory nil
1995 (when (tramp-ange-ftp-file-name-p multi-method method)
1996 (tramp-invoke-ange-ftp 'file-name-all-completions
1997 filename directory))
1998 (unless (save-match-data (string-match "/" filename))
1999 (let* ((nowild tramp-completion-without-shell-p)
2000 result)
2001 (save-excursion
2002 (tramp-barf-unless-okay
2003 multi-method method user host
2004 (format "cd %s" (tramp-shell-quote-argument path))
2005 nil 'file-error
2006 "tramp-handle-file-name-all-completions: Couldn't `cd %s'"
2007 (tramp-shell-quote-argument path))
2008
2009 ;; Get a list of directories and files, including reliably
2010 ;; tagging the directories with a trailing '/'. Because I
2011 ;; rock. --daniel@danann.net
2012 (tramp-send-command
2013 multi-method method user host
2014 (format (concat "%s -a %s 2>/dev/null | while read f; do "
2015 "if test -d \"$f\" 2>/dev/null; "
2016 "then echo \"$f/\"; else echo \"$f\"; fi; done")
2017 (tramp-get-ls-command multi-method method user host)
2018 (if (or nowild (zerop (length filename)))
2019 ""
2020 (format "-d %s*"
2021 (tramp-shell-quote-argument filename)))))
2022
2023 ;; Now grab the output.
2024 (tramp-wait-for-output)
2025 (goto-char (point-max))
2026 (while (zerop (forward-line -1))
2027 (push (buffer-substring (point)
2028 (tramp-line-end-position))
2029 result))
2030
2031 (tramp-send-command multi-method method user host "cd")
2032 (tramp-wait-for-output)
1957 2033
1958 ;; Return the list. 2034 ;; Return the list.
1959 (if nowild 2035 (if nowild
1960 (all-completions filename (mapcar 'list result)) 2036 (all-completions filename (mapcar 'list result))
1961 result))))) 2037 result))))))
1962 2038
1963 2039
1964;; The following isn't needed for Emacs 20 but for 19.34? 2040;; The following isn't needed for Emacs 20 but for 19.34?
@@ -1968,54 +2044,56 @@ if the remote host can't provide the modtime."
1968 (error 2044 (error
1969 "tramp-handle-file-name-completion invoked on non-tramp directory `%s'" 2045 "tramp-handle-file-name-completion invoked on non-tramp directory `%s'"
1970 directory)) 2046 directory))
1971 ;(setq directory (tramp-handle-expand-file-name directory)) 2047 (with-parsed-tramp-file-name directory nil
1972 (try-completion 2048 (when (tramp-ange-ftp-file-name-p multi-method method)
1973 filename 2049 (tramp-invoke-ange-ftp 'file-name-completion
1974 (mapcar (lambda (x) (cons x nil)) 2050 filename directory))
1975 (tramp-handle-file-name-all-completions filename directory)))) 2051 (try-completion
2052 filename
2053 (mapcar (lambda (x) (cons x nil))
2054 (tramp-handle-file-name-all-completions filename directory)))))
1976 2055
1977;; cp, mv and ln 2056;; cp, mv and ln
1978 2057
1979(defun tramp-handle-add-name-to-file 2058(defun tramp-handle-add-name-to-file
1980 (filename newname &optional ok-if-already-exists) 2059 (filename newname &optional ok-if-already-exists)
1981 "Like `add-name-to-file' for tramp files." 2060 "Like `add-name-to-file' for tramp files."
1982 (let* ((v1 (when (tramp-tramp-file-p filename) 2061 (with-parsed-tramp-file-name filename v1
1983 (tramp-dissect-file-name (tramp-handle-expand-file-name filename)))) 2062 (with-parsed-tramp-file-name newname v2
1984 (v2 (when (tramp-tramp-file-p newname) 2063 (let ((ln (when v1 (tramp-get-remote-ln
1985 (tramp-dissect-file-name (tramp-handle-expand-file-name newname)))) 2064 v1-multi-method v1-method v1-user v1-host))))
1986 (mmeth1 (when v1 (tramp-file-name-multi-method v1))) 2065 (unless (and v1-method v2-method v1-user v2-user v1-host v2-host
1987 (mmeth2 (when v2 (tramp-file-name-multi-method v2))) 2066 (equal v1-multi-method v2-multi-method)
1988 (meth1 (when v1 (tramp-file-name-method v1))) 2067 (equal v1-method v2-method)
1989 (meth2 (when v2 (tramp-file-name-method v2))) 2068 (equal v1-user v2-user)
1990 (user1 (when v1 (tramp-file-name-user v1))) 2069 (equal v1-host v2-host))
1991 (user2 (when v2 (tramp-file-name-user v2))) 2070 (error "add-name-to-file: %s"
1992 (host1 (when v1 (tramp-file-name-host v1))) 2071 "only implemented for same method, same user, same host"))
1993 (host2 (when v2 (tramp-file-name-host v2))) 2072 (when (and (tramp-ange-ftp-file-name-p v1-multi-method v1-method)
1994 (path1 (when v1 (tramp-file-name-path v1))) 2073 (tramp-ange-ftp-file-name-p v2-multi-method v2-method))
1995 (path2 (when v2 (tramp-file-name-path v2))) 2074 (tramp-invoke-ange-ftp 'add-name-to-file
1996 (ln (when v1 (tramp-get-remote-ln mmeth1 meth1 user1 host1)))) 2075 filename newname ok-if-already-exists))
1997 (unless (and meth1 meth2 user1 user2 host1 host2 2076 (when (tramp-ange-ftp-file-name-p v1-multi-method v1-method)
1998 (equal mmeth1 mmeth2) 2077 (tramp-invoke-ange-ftp 'add-name-to-file
1999 (equal meth1 meth2) 2078 filename newname ok-if-already-exists))
2000 (equal user1 user2) 2079 (when (tramp-ange-ftp-file-name-p v2-multi-method v2-method)
2001 (equal host1 host2)) 2080 (tramp-invoke-ange-ftp 'add-name-to-file
2002 (error "add-name-to-file: %s" 2081 filename newname ok-if-already-exists))
2003 "only implemented for same method, same user, same host")) 2082 (when (and (not ok-if-already-exists)
2004 (when (and (not ok-if-already-exists) 2083 (file-exists-p newname)
2005 (file-exists-p newname) 2084 (not (numberp ok-if-already-exists))
2006 (not (numberp ok-if-already-exists)) 2085 (y-or-n-p
2007 (y-or-n-p 2086 (format
2008 (format 2087 "File %s already exists; make it a new name anyway? "
2009 "File %s already exists; make it a new name anyway? " 2088 newname)))
2010 newname))) 2089 (error "add-name-to-file: file %s already exists" newname))
2011 (error "add-name-to-file: file %s already exists" newname)) 2090 (tramp-barf-unless-okay
2012 (tramp-barf-unless-okay 2091 v1-multi-method v1-method v1-user v1-host
2013 mmeth1 meth1 user1 host1 2092 (format "%s %s %s" ln (tramp-shell-quote-argument v1-path)
2014 (format "%s %s %s" ln (tramp-shell-quote-argument path1) 2093 (tramp-shell-quote-argument v2-path))
2015 (tramp-shell-quote-argument path2)) 2094 nil 'file-error
2016 nil 'file-error 2095 "error with add-name-to-file, see buffer `%s' for details"
2017 "error with add-name-to-file, see buffer `%s' for details" 2096 (buffer-name))))))
2018 (buffer-name))))
2019 2097
2020(defun tramp-handle-copy-file 2098(defun tramp-handle-copy-file
2021 (filename newname &optional ok-if-already-exists keep-date) 2099 (filename newname &optional ok-if-already-exists keep-date)
@@ -2067,84 +2145,80 @@ and `rename'. FILENAME and NEWNAME must be absolute file names."
2067 (when (file-exists-p newname) 2145 (when (file-exists-p newname)
2068 (signal 'file-already-exists 2146 (signal 'file-already-exists
2069 (list newname)))) 2147 (list newname))))
2070 (let* ((v1 (when (tramp-tramp-file-p filename) 2148 (with-parsed-tramp-file-name filename v1
2071 (tramp-dissect-file-name (tramp-handle-expand-file-name filename)))) 2149 (with-parsed-tramp-file-name newname v2
2072 (v2 (when (tramp-tramp-file-p newname) 2150 (when (and (tramp-ange-ftp-file-name-p v1-multi-method v1-method)
2073 (tramp-dissect-file-name (tramp-handle-expand-file-name newname)))) 2151 (tramp-ange-ftp-file-name-p v2-multi-method v2-method))
2074 (mmeth1 (when v1 (tramp-file-name-multi-method v1))) 2152 (tramp-invoke-ange-ftp
2075 (mmeth2 (when v2 (tramp-file-name-multi-method v2))) 2153 (if (eq op 'copy) 'copy-file 'rename-file)
2076 (meth1 (when v1 (tramp-file-name-method v1))) 2154 filename newname ok-if-already-exists keep-date))
2077 (meth2 (when v2 (tramp-file-name-method v2))) 2155 (let* ((mmeth (tramp-file-name-multi-method (or v1 v2)))
2078 (mmeth (tramp-file-name-multi-method (or v1 v2))) 2156 (meth (tramp-file-name-method (or v1 v2)))
2079 (meth (tramp-file-name-method (or v1 v2))) 2157 (rcp-program (tramp-get-rcp-program mmeth meth))
2080 (rcp-program (tramp-get-rcp-program mmeth meth)) 2158 (rcp-args (tramp-get-rcp-args mmeth meth))
2081 (rcp-args (tramp-get-rcp-args mmeth meth)) 2159 (trampbuf (get-buffer-create "*tramp output*")))
2082 (trampbuf (get-buffer-create "*tramp output*"))) 2160 ;; Check if we can use a shortcut.
2083 ;; Check if we can use a shortcut. 2161 (if (and v1-method v2-method
2084 (if (and meth1 meth2 (equal mmeth1 mmeth2) (equal meth1 meth2) 2162 (equal v1-multi-method v2-multi-method)
2085 (equal (tramp-file-name-host v1) 2163 (equal v1-method v2-method)
2086 (tramp-file-name-host v2)) 2164 (equal v1-host v2-host)
2087 (equal (tramp-file-name-user v1) 2165 (equal v1-user v2-user))
2088 (tramp-file-name-user v2))) 2166 ;; Shortcut: if method, host, user are the same for both
2089 ;; Shortcut: if method, host, user are the same for both 2167 ;; files, we invoke `cp' or `mv' on the remote host directly.
2090 ;; files, we invoke `cp' or `mv' on the remote host directly. 2168 (tramp-do-copy-or-rename-file-directly
2091 (tramp-do-copy-or-rename-file-directly 2169 op
2092 op 2170 v1-multi-method v1-method v1-user v1-host v1-path v2-path
2093 (tramp-file-name-multi-method v1) 2171 keep-date)
2094 (tramp-file-name-method v1) 2172 ;; New algorithm: copy file first. Then, if operation is
2095 (tramp-file-name-user v1) 2173 ;; `rename', go back and delete the original file if the copy
2096 (tramp-file-name-host v1) 2174 ;; was successful.
2097 (tramp-file-name-path v1) (tramp-file-name-path v2) 2175 (if rcp-program
2098 keep-date) 2176 ;; The following code uses a tramp program to copy the file.
2099 ;; New algorithm: copy file first. Then, if operation is 2177 (let ((f1 (if (not v1)
2100 ;; `rename', go back and delete the original file if the copy 2178 filename
2101 ;; was successful. 2179 (tramp-make-rcp-program-file-name
2102 (if rcp-program 2180 v1-user v1-host
2103 ;; The following code uses a tramp program to copy the file. 2181 (tramp-shell-quote-argument v1-path))))
2104 (let ((f1 (if (not v1) 2182 (f2 (if (not v2)
2105 filename 2183 newname
2106 (tramp-make-rcp-program-file-name 2184 (tramp-make-rcp-program-file-name
2107 (tramp-file-name-user v1) 2185 v2-user v2-host
2108 (tramp-file-name-host v1) 2186 (tramp-shell-quote-argument v2-path))))
2109 (tramp-shell-quote-argument (tramp-file-name-path v1))))) 2187 (default-directory
2110 (f2 (if (not v2) 2188 (if (tramp-tramp-file-p default-directory)
2111 newname 2189 (tramp-temporary-file-directory)
2112 (tramp-make-rcp-program-file-name 2190 default-directory)))
2113 (tramp-file-name-user v2) 2191 (when keep-date
2114 (tramp-file-name-host v2) 2192 (add-to-list 'rcp-args
2115 (tramp-shell-quote-argument (tramp-file-name-path v2))))) 2193 (tramp-get-rcp-keep-date-arg mmeth meth)))
2116 (default-directory 2194 (save-excursion (set-buffer trampbuf) (erase-buffer))
2117 (if (tramp-tramp-file-p default-directory) 2195 (unless (equal 0 (apply #'call-process
2118 (tramp-temporary-file-directory) 2196 (tramp-get-rcp-program mmeth meth)
2119 default-directory))) 2197 nil trampbuf nil
2120 (when keep-date 2198 (append rcp-args (list f1 f2))))
2121 (add-to-list 'rcp-args (tramp-get-rcp-keep-date-arg mmeth meth))) 2199 (pop-to-buffer trampbuf)
2122 (save-excursion (set-buffer trampbuf) (erase-buffer)) 2200 (error (concat "tramp-do-copy-or-rename-file: %s"
2123 (unless 2201 " didn't work, see buffer `%s' for details")
2124 (equal 0 (apply #'call-process (tramp-get-rcp-program mmeth meth) 2202 (tramp-get-rcp-program mmeth meth) trampbuf)))
2125 nil trampbuf nil (append rcp-args (list f1 f2)))) 2203 ;; The following code uses an inline method for copying.
2126 (pop-to-buffer trampbuf) 2204 ;; Let's start with a simple-minded approach: we create a new
2127 (error (concat "tramp-do-copy-or-rename-file: %s" 2205 ;; buffer, insert the contents of the source file into it,
2128 " didn't work, see buffer `%s' for details") 2206 ;; then write out the buffer. This should work fine, whether
2129 (tramp-get-rcp-program mmeth meth) trampbuf))) 2207 ;; the source or the target files are tramp files.
2130 ;; The following code uses an inline method for copying. 2208 ;; CCC TODO: error checking
2131 ;; Let's start with a simple-minded approach: we create a new 2209 (when keep-date
2132 ;; buffer, insert the contents of the source file into it, 2210 (tramp-message
2133 ;; then write out the buffer. This should work fine, whether 2211 1 (concat "Warning: cannot preserve file time stamp"
2134 ;; the source or the target files are tramp files. 2212 " with inline copying across machines")))
2135 ;; CCC TODO: error checking 2213 (save-excursion
2136 (when keep-date 2214 (set-buffer trampbuf) (erase-buffer)
2137 (tramp-message 1 (concat "Warning: cannot preserve file time stamp" 2215 (insert-file-contents-literally filename)
2138 " with inline copying across machines"))) 2216 (let ((coding-system-for-write 'no-conversion))
2139 (save-excursion 2217 (write-region (point-min) (point-max) newname))))
2140 (set-buffer trampbuf) (erase-buffer) 2218
2141 (insert-file-contents-literally filename) 2219 ;; If the operation was `rename', delete the original file.
2142 (let ((coding-system-for-write 'no-conversion)) 2220 (unless (eq op 'copy)
2143 (write-region (point-min) (point-max) newname)))) 2221 (delete-file filename)))))))
2144
2145 ;; If the operation was `rename', delete the original file.
2146 (unless (eq op 'copy)
2147 (delete-file filename)))))
2148 2222
2149(defun tramp-do-copy-or-rename-file-directly 2223(defun tramp-do-copy-or-rename-file-directly
2150 (op multi-method method user host path1 path2 keep-date) 2224 (op multi-method method user host path1 path2 keep-date)
@@ -2174,41 +2248,41 @@ If KEEP-DATE is non-nil, preserve the time stamp when copying."
2174;; mkdir 2248;; mkdir
2175(defun tramp-handle-make-directory (dir &optional parents) 2249(defun tramp-handle-make-directory (dir &optional parents)
2176 "Like `make-directory' for tramp files." 2250 "Like `make-directory' for tramp files."
2177 (let ((v (tramp-dissect-file-name (tramp-handle-expand-file-name dir)))) 2251 (with-parsed-tramp-file-name dir nil
2252 (when (tramp-ange-ftp-file-name-p multi-method method)
2253 (tramp-invoke-ange-ftp 'make-directory dir parents))
2178 (tramp-barf-unless-okay 2254 (tramp-barf-unless-okay
2179 (tramp-file-name-multi-method v) (tramp-file-name-method v) 2255 multi-method method user host
2180 (tramp-file-name-user v) (tramp-file-name-host v)
2181 (format " %s %s" 2256 (format " %s %s"
2182 (if parents "mkdir -p" "mkdir") 2257 (if parents "mkdir -p" "mkdir")
2183 (tramp-shell-quote-argument (tramp-file-name-path v))) 2258 (tramp-shell-quote-argument path))
2184 nil 'file-error 2259 nil 'file-error
2185 "Couldn't make directory %s" dir))) 2260 "Couldn't make directory %s" dir)))
2186 2261
2187;; CCC error checking? 2262;; CCC error checking?
2188(defun tramp-handle-delete-directory (directory) 2263(defun tramp-handle-delete-directory (directory)
2189 "Like `delete-directory' for tramp files." 2264 "Like `delete-directory' for tramp files."
2190 (let ((v (tramp-dissect-file-name (tramp-handle-expand-file-name directory)))) 2265 (with-parsed-tramp-file-name directory nil
2266 (when (tramp-ange-ftp-file-name-p multi-method method)
2267 (tramp-invoke-ange-ftp 'delete-directory directory))
2191 (save-excursion 2268 (save-excursion
2192 (tramp-send-command 2269 (tramp-send-command
2193 (tramp-file-name-multi-method v) (tramp-file-name-method v) 2270 multi-method method user host
2194 (tramp-file-name-user v) (tramp-file-name-host v)
2195 (format "rmdir %s ; echo ok" 2271 (format "rmdir %s ; echo ok"
2196 (tramp-shell-quote-argument (tramp-file-name-path v)))) 2272 (tramp-shell-quote-argument path)))
2197 (tramp-wait-for-output)))) 2273 (tramp-wait-for-output))))
2198 2274
2199(defun tramp-handle-delete-file (filename) 2275(defun tramp-handle-delete-file (filename)
2200 "Like `delete-file' for tramp files." 2276 "Like `delete-file' for tramp files."
2201 (let ((v (tramp-dissect-file-name (tramp-handle-expand-file-name filename)))) 2277 (with-parsed-tramp-file-name filename nil
2202 (save-excursion 2278 (with-tramp-calling-ange-ftp
2203 (unless (zerop (tramp-send-command-and-check 2279 nil 'delete-file (list filename)
2204 (tramp-file-name-multi-method v) 2280 (save-excursion
2205 (tramp-file-name-method v) 2281 (unless (zerop (tramp-send-command-and-check
2206 (tramp-file-name-user v) 2282 multi-method method user host
2207 (tramp-file-name-host v) 2283 (format "rm -f %s"
2208 (format "rm -f %s" 2284 (tramp-shell-quote-argument path))))
2209 (tramp-shell-quote-argument 2285 (signal 'file-error "Couldn't delete Tramp file"))))))
2210 (tramp-file-name-path v)))))
2211 (signal 'file-error "Couldn't delete Tramp file")))))
2212 2286
2213;; Dired. 2287;; Dired.
2214 2288
@@ -2217,12 +2291,10 @@ If KEEP-DATE is non-nil, preserve the time stamp when copying."
2217(defun tramp-handle-dired-recursive-delete-directory (filename) 2291(defun tramp-handle-dired-recursive-delete-directory (filename)
2218 "Recursively delete the directory given. 2292 "Recursively delete the directory given.
2219This is like `dired-recursive-delete-directory' for tramp files." 2293This is like `dired-recursive-delete-directory' for tramp files."
2220 (let* ((v (tramp-dissect-file-name (tramp-handle-expand-file-name filename))) 2294 (with-parsed-tramp-file-name filename nil
2221 (multi-method (tramp-file-name-multi-method v)) 2295 (when (tramp-ange-ftp-file-name-p multi-method method)
2222 (method (tramp-file-name-method v)) 2296 (tramp-invoke-ange-ftp 'dired-recursive-delete-directory
2223 (user (tramp-file-name-user v)) 2297 filename))
2224 (host (tramp-file-name-host v))
2225 (path (tramp-file-name-path v)))
2226 ;; run a shell command 'rm -r <path>' 2298 ;; run a shell command 'rm -r <path>'
2227 ;; Code shamelessly stolen for the dired implementation and, um, hacked :) 2299 ;; Code shamelessly stolen for the dired implementation and, um, hacked :)
2228 (or (tramp-handle-file-exists-p filename) 2300 (or (tramp-handle-file-exists-p filename)
@@ -2231,7 +2303,7 @@ This is like `dired-recursive-delete-directory' for tramp files."
2231 (list "Removing old file name" "no such directory" filename))) 2303 (list "Removing old file name" "no such directory" filename)))
2232 ;; Which is better, -r or -R? (-r works for me <daniel@danann.net>) 2304 ;; Which is better, -r or -R? (-r works for me <daniel@danann.net>)
2233 (tramp-send-command multi-method method user host 2305 (tramp-send-command multi-method method user host
2234 (format "rm -r %s" (tramp-shell-quote-argument path))) 2306 (format "rm -r %s" (tramp-shell-quote-argument path)))
2235 ;; Wait for the remote system to return to us... 2307 ;; Wait for the remote system to return to us...
2236 ;; This might take a while, allow it plenty of time. 2308 ;; This might take a while, allow it plenty of time.
2237 (tramp-wait-for-output 120) 2309 (tramp-wait-for-output 120)
@@ -2242,14 +2314,12 @@ This is like `dired-recursive-delete-directory' for tramp files."
2242 2314
2243(defun tramp-handle-dired-call-process (program discard &rest arguments) 2315(defun tramp-handle-dired-call-process (program discard &rest arguments)
2244 "Like `dired-call-process' for tramp files." 2316 "Like `dired-call-process' for tramp files."
2245 (let ((v (tramp-dissect-file-name 2317 (with-parsed-tramp-file-name default-directory nil
2246 (tramp-handle-expand-file-name default-directory))) 2318 (when (tramp-ange-ftp-file-name-p multi-method method)
2247 multi-method method user host path) 2319 (let ((default-directory
2248 (setq multi-method (tramp-file-name-multi-method v)) 2320 (tramp-make-ange-ftp-file-name user host path)))
2249 (setq method (tramp-file-name-method v)) 2321 (tramp-invoke-ange-ftp 'dired-call-process
2250 (setq user (tramp-file-name-user v)) 2322 program discard arguments)))
2251 (setq host (tramp-file-name-host v))
2252 (setq path (tramp-file-name-path v))
2253 (save-excursion 2323 (save-excursion
2254 (tramp-barf-unless-okay 2324 (tramp-barf-unless-okay
2255 multi-method method user host 2325 multi-method method user host
@@ -2285,13 +2355,10 @@ This is like `dired-recursive-delete-directory' for tramp files."
2285(defun tramp-handle-insert-directory 2355(defun tramp-handle-insert-directory
2286 (filename switches &optional wildcard full-directory-p) 2356 (filename switches &optional wildcard full-directory-p)
2287 "Like `insert-directory' for tramp files." 2357 "Like `insert-directory' for tramp files."
2288 (let ((v (tramp-dissect-file-name (tramp-handle-expand-file-name filename))) 2358 (with-parsed-tramp-file-name filename nil
2289 multi-method method user host path) 2359 (when (tramp-ange-ftp-file-name-p multi-method method)
2290 (setq multi-method (tramp-file-name-multi-method v)) 2360 (tramp-invoke-ange-ftp 'insert-directory
2291 (setq method (tramp-file-name-method v)) 2361 filename switches wildcard full-directory-p))
2292 (setq user (tramp-file-name-user v))
2293 (setq host (tramp-file-name-host v))
2294 (setq path (tramp-file-name-path v))
2295 (tramp-message-for-buffer 2362 (tramp-message-for-buffer
2296 multi-method method user host 10 2363 multi-method method user host 10
2297 "Inserting directory `ls %s %s', wildcard %s, fulldir %s" 2364 "Inserting directory `ls %s %s', wildcard %s, fulldir %s"
@@ -2310,33 +2377,33 @@ This is like `dired-recursive-delete-directory' for tramp files."
2310 ;; If `full-directory-p', we just say `ls -l FILENAME'. 2377 ;; If `full-directory-p', we just say `ls -l FILENAME'.
2311 ;; Else we chdir to the parent directory, then say `ls -ld BASENAME'. 2378 ;; Else we chdir to the parent directory, then say `ls -ld BASENAME'.
2312 (if full-directory-p 2379 (if full-directory-p
2313 (tramp-send-command 2380 (tramp-send-command
2314 multi-method method user host 2381 multi-method method user host
2315 (format "%s %s %s" 2382 (format "%s %s %s"
2316 (tramp-get-ls-command multi-method method user host) 2383 (tramp-get-ls-command multi-method method user host)
2317 switches 2384 switches
2318 (if wildcard 2385 (if wildcard
2319 path 2386 path
2320 (tramp-shell-quote-argument (concat path "."))))) 2387 (tramp-shell-quote-argument (concat path ".")))))
2321 (tramp-barf-unless-okay 2388 (tramp-barf-unless-okay
2322 multi-method method user host 2389 multi-method method user host
2323 (format "cd %s" (tramp-shell-quote-argument 2390 (format "cd %s" (tramp-shell-quote-argument
2324 (file-name-directory path))) 2391 (file-name-directory path)))
2325 nil 'file-error 2392 nil 'file-error
2326 "Couldn't `cd %s'" 2393 "Couldn't `cd %s'"
2327 (tramp-shell-quote-argument (file-name-directory path))) 2394 (tramp-shell-quote-argument (file-name-directory path)))
2328 (tramp-send-command 2395 (tramp-send-command
2329 multi-method method user host 2396 multi-method method user host
2330 (format "%s %s %s" 2397 (format "%s %s %s"
2331 (tramp-get-ls-command multi-method method user host) 2398 (tramp-get-ls-command multi-method method user host)
2332 switches 2399 switches
2333 (if full-directory-p 2400 (if full-directory-p
2334 ;; Add "/." to make sure we got complete dir 2401 ;; Add "/." to make sure we got complete dir
2335 ;; listing for symlinks, too. 2402 ;; listing for symlinks, too.
2336 (concat (file-name-as-directory 2403 (concat (file-name-as-directory
2337 (file-name-nondirectory path)) ".") 2404 (file-name-nondirectory path)) ".")
2338 (file-name-nondirectory path))))) 2405 (file-name-nondirectory path)))))
2339 (sit-for 1) ;needed for rsh but not ssh? 2406 (sit-for 1) ;needed for rsh but not ssh?
2340 (tramp-wait-for-output)) 2407 (tramp-wait-for-output))
2341 (insert-buffer (tramp-get-buffer multi-method method user host)) 2408 (insert-buffer (tramp-get-buffer multi-method method user host))
2342 ;; On XEmacs, we want to call (exchange-point-and-mark t), but 2409 ;; On XEmacs, we want to call (exchange-point-and-mark t), but
@@ -2351,10 +2418,10 @@ This is like `dired-recursive-delete-directory' for tramp files."
2351 ;; Another XEmacs specialty follows. What's the right way to do 2418 ;; Another XEmacs specialty follows. What's the right way to do
2352 ;; it? 2419 ;; it?
2353 (when (and (featurep 'xemacs) 2420 (when (and (featurep 'xemacs)
2354 (eq major-mode 'dired-mode)) 2421 (eq major-mode 'dired-mode))
2355 (save-excursion 2422 (save-excursion
2356 (require 'dired) 2423 (require 'dired)
2357 (dired-insert-set-properties (point) (mark t)))))) 2424 (dired-insert-set-properties (point) (mark t))))))
2358 2425
2359;; Continuation of kluge to pacify byte-compiler. 2426;; Continuation of kluge to pacify byte-compiler.
2360;;(eval-when-compile 2427;;(eval-when-compile
@@ -2364,7 +2431,11 @@ This is like `dired-recursive-delete-directory' for tramp files."
2364;; CCC is this the right thing to do? 2431;; CCC is this the right thing to do?
2365(defun tramp-handle-unhandled-file-name-directory (filename) 2432(defun tramp-handle-unhandled-file-name-directory (filename)
2366 "Like `unhandled-file-name-directory' for tramp files." 2433 "Like `unhandled-file-name-directory' for tramp files."
2367 (expand-file-name "~/")) 2434 (with-parsed-tramp-file-name filename nil
2435 (when (tramp-ange-ftp-file-name-p multi-method method)
2436 (tramp-invoke-ange-ftp 'unhandled-file-name-directory
2437 filename))
2438 (expand-file-name "~/")))
2368 2439
2369;; Canonicalization of file names. 2440;; Canonicalization of file names.
2370 2441
@@ -2396,12 +2467,9 @@ Doesn't do anything if the NAME does not start with a drive letter."
2396 (tramp-run-real-handler 'expand-file-name 2467 (tramp-run-real-handler 'expand-file-name
2397 (list name nil)) 2468 (list name nil))
2398 ;; Dissect NAME. 2469 ;; Dissect NAME.
2399 (let* ((v (tramp-dissect-file-name name)) 2470 (with-parsed-tramp-file-name name nil
2400 (multi-method (tramp-file-name-multi-method v)) 2471 (when (tramp-ange-ftp-file-name-p multi-method method)
2401 (method (tramp-file-name-method v)) 2472 (tramp-invoke-ange-ftp 'expand-file-name name nil))
2402 (user (tramp-file-name-user v))
2403 (host (tramp-file-name-host v))
2404 (path (tramp-file-name-path v)))
2405 (unless (file-name-absolute-p path) 2473 (unless (file-name-absolute-p path)
2406 (setq path (concat "~/" path))) 2474 (setq path (concat "~/" path)))
2407 (save-excursion 2475 (save-excursion
@@ -2441,59 +2509,59 @@ Doesn't do anything if the NAME does not start with a drive letter."
2441This will break if COMMAND prints a newline, followed by the value of 2509This will break if COMMAND prints a newline, followed by the value of
2442`tramp-end-of-output', followed by another newline." 2510`tramp-end-of-output', followed by another newline."
2443 (if (tramp-tramp-file-p default-directory) 2511 (if (tramp-tramp-file-p default-directory)
2444 (let* ((v (tramp-dissect-file-name 2512 (with-parsed-tramp-file-name default-directory nil
2445 (tramp-handle-expand-file-name default-directory))) 2513 (when (tramp-ange-ftp-file-name-p multi-method method)
2446 (multi-method (tramp-file-name-multi-method v)) 2514 (let ((default-directory (tramp-make-ange-ftp-file-name
2447 (method (tramp-file-name-method v)) 2515 user host path)))
2448 (user (tramp-file-name-user v)) 2516 (tramp-invoke-ange-ftp 'shell-command
2449 (host (tramp-file-name-host v)) 2517 command output-buffer error-buffer)))
2450 (path (tramp-file-name-path v)) 2518 (let (status)
2451 status) 2519 (when (string-match "&[ \t]*\\'" command)
2452 (when (string-match "&[ \t]*\\'" command) 2520 (error "Tramp doesn't grok asynchronous shell commands, yet"))
2453 (error "Tramp doesn't grok asynchronous shell commands, yet")) 2521 (when error-buffer
2454 (when error-buffer 2522 (error "Tramp doesn't grok optional third arg ERROR-BUFFER, yet"))
2455 (error "Tramp doesn't grok optional third arg ERROR-BUFFER, yet")) 2523 (save-excursion
2456 (save-excursion 2524 (tramp-barf-unless-okay
2457 (tramp-barf-unless-okay 2525 multi-method method user host
2458 multi-method method user host 2526 (format "cd %s" (tramp-shell-quote-argument path))
2459 (format "cd %s" (tramp-shell-quote-argument path)) 2527 nil 'file-error
2460 nil 'file-error 2528 "tramp-handle-shell-command: Couldn't `cd %s'"
2461 "tramp-handle-shell-command: Couldn't `cd %s'" 2529 (tramp-shell-quote-argument path))
2462 (tramp-shell-quote-argument path)) 2530 (tramp-send-command multi-method method user host
2463 (tramp-send-command multi-method method user host 2531 (concat command "; tramp_old_status=$?"))
2464 (concat command "; tramp_old_status=$?")) 2532 ;; This will break if the shell command prints "/////"
2465 ;; This will break if the shell command prints "/////" 2533 ;; somewhere. Let's just hope for the best...
2466 ;; somewhere. Let's just hope for the best... 2534 (tramp-wait-for-output))
2467 (tramp-wait-for-output)) 2535 (unless output-buffer
2468 (unless output-buffer 2536 (setq output-buffer (get-buffer-create "*Shell Command Output*"))
2469 (setq output-buffer (get-buffer-create "*Shell Command Output*")) 2537 (set-buffer output-buffer)
2470 (set-buffer output-buffer) 2538 (erase-buffer))
2471 (erase-buffer)) 2539 (unless (bufferp output-buffer)
2472 (unless (bufferp output-buffer) 2540 (setq output-buffer (current-buffer)))
2473 (setq output-buffer (current-buffer))) 2541 (set-buffer output-buffer)
2474 (set-buffer output-buffer) 2542 (insert-buffer (tramp-get-buffer multi-method method user host))
2475 (insert-buffer (tramp-get-buffer multi-method method user host)) 2543 (save-excursion
2476 (save-excursion 2544 (tramp-send-command multi-method method user host "cd")
2477 (tramp-send-command multi-method method user host "cd") 2545 (tramp-wait-for-output)
2478 (tramp-wait-for-output) 2546 (tramp-send-command
2479 (tramp-send-command 2547 multi-method method user host
2480 multi-method method user host 2548 (concat "tramp_set_exit_status $tramp_old_status;"
2481 "tramp_set_exit_status $tramp_old_status; echo tramp_exit_status $?") 2549 " echo tramp_exit_status $?"))
2482 (tramp-wait-for-output) 2550 (tramp-wait-for-output)
2483 (goto-char (point-max)) 2551 (goto-char (point-max))
2484 (unless (search-backward "tramp_exit_status " nil t) 2552 (unless (search-backward "tramp_exit_status " nil t)
2485 (error "Couldn't find exit status of `%s'" command)) 2553 (error "Couldn't find exit status of `%s'" command))
2486 (skip-chars-forward "^ ") 2554 (skip-chars-forward "^ ")
2487 (setq status (read (current-buffer)))) 2555 (setq status (read (current-buffer))))
2488 (unless (zerop (buffer-size)) 2556 (unless (zerop (buffer-size))
2489 (pop-to-buffer output-buffer)) 2557 (pop-to-buffer output-buffer))
2490 status) 2558 status)))
2491 ;; The following is only executed if something strange was 2559 ;; The following is only executed if something strange was
2492 ;; happening. Emit a helpful message and do it anyway. 2560 ;; happening. Emit a helpful message and do it anyway.
2493 (message "tramp-handle-shell-command called with non-tramp directory: `%s'" 2561 (message "tramp-handle-shell-command called with non-tramp directory: `%s'"
2494 default-directory) 2562 default-directory)
2495 (tramp-run-real-handler 'shell-command 2563 (tramp-run-real-handler 'shell-command
2496 (list command output-buffer error-buffer)))) 2564 (list command output-buffer error-buffer)))
2497 2565
2498;; File Editing. 2566;; File Editing.
2499 2567
@@ -2504,104 +2572,106 @@ This will break if COMMAND prints a newline, followed by the value of
2504 2572
2505(defun tramp-handle-file-local-copy (filename) 2573(defun tramp-handle-file-local-copy (filename)
2506 "Like `file-local-copy' for tramp files." 2574 "Like `file-local-copy' for tramp files."
2507 (let* ((v (tramp-dissect-file-name (tramp-handle-expand-file-name filename))) 2575 (with-parsed-tramp-file-name filename nil
2508 (multi-method (tramp-file-name-multi-method v)) 2576 (when (tramp-ange-ftp-file-name-p multi-method method)
2509 (method (tramp-file-name-method v)) 2577 (tramp-invoke-ange-ftp 'file-local-copy filename))
2510 (user (tramp-file-name-user v)) 2578 (let ((trampbuf (get-buffer-create "*tramp output*"))
2511 (host (tramp-file-name-host v)) 2579 tmpfil)
2512 (path (tramp-file-name-path v)) 2580 (unless (file-exists-p filename)
2513 (trampbuf (get-buffer-create "*tramp output*")) 2581 (error "Cannot make local copy of non-existing file `%s'"
2514 tmpfil) 2582 filename))
2515 (unless (file-exists-p filename) 2583 (setq tmpfil (tramp-make-temp-file))
2516 (error "Cannot make local copy of non-existing file `%s'" 2584 (cond ((tramp-get-rcp-program multi-method method)
2517 filename)) 2585 ;; Use tramp-like program for file transfer.
2518 (setq tmpfil (tramp-make-temp-file)) 2586 (tramp-message-for-buffer
2519 (cond ((tramp-get-rcp-program multi-method method) 2587 multi-method method user host
2520 ;; Use tramp-like program for file transfer. 2588 5 "Fetching %s to tmp file %s..." filename tmpfil)
2521 (tramp-message-for-buffer 2589 (save-excursion (set-buffer trampbuf) (erase-buffer))
2522 multi-method method user host 2590 (unless (equal
2523 5 "Fetching %s to tmp file %s..." filename tmpfil) 2591 0
2524 (save-excursion (set-buffer trampbuf) (erase-buffer)) 2592 (apply #'call-process
2525 (unless (equal 0 2593 (tramp-get-rcp-program multi-method method)
2526 (apply #'call-process 2594 nil trampbuf nil
2527 (tramp-get-rcp-program multi-method method) 2595 (append (tramp-get-rcp-args multi-method method)
2528 nil trampbuf nil 2596 (list
2529 (append (tramp-get-rcp-args multi-method method) 2597 (tramp-make-rcp-program-file-name
2530 (list 2598 user host
2531 (tramp-make-rcp-program-file-name 2599 (tramp-shell-quote-argument path))
2532 user host 2600 tmpfil))))
2533 (tramp-shell-quote-argument path)) 2601 (pop-to-buffer trampbuf)
2534 tmpfil)))) 2602 (error
2535 (pop-to-buffer trampbuf) 2603 (concat "tramp-handle-file-local-copy: `%s' didn't work, "
2536 (error (concat "tramp-handle-file-local-copy: `%s' didn't work, " 2604 "see buffer `%s' for details")
2537 "see buffer `%s' for details") 2605 (tramp-get-rcp-program multi-method method) trampbuf))
2538 (tramp-get-rcp-program multi-method method) trampbuf)) 2606 (tramp-message-for-buffer
2539 (tramp-message-for-buffer 2607 multi-method method user host
2540 multi-method method user host 2608 5 "Fetching %s to tmp file %s...done" filename tmpfil))
2541 5 "Fetching %s to tmp file %s...done" filename tmpfil)) 2609 ((and (tramp-get-encoding-command multi-method method)
2542 ((and (tramp-get-encoding-command multi-method method)
2543 (tramp-get-decoding-command multi-method method))
2544 ;; Use inline encoding for file transfer.
2545 (save-excursion
2546 ;; Following line for setting tramp-current-method,
2547 ;; tramp-current-user, tramp-current-host.
2548 (set-buffer (tramp-get-buffer multi-method method user host))
2549 (tramp-message 5 "Encoding remote file %s..." filename)
2550 (tramp-barf-unless-okay
2551 multi-method method user host
2552 (concat (tramp-get-encoding-command multi-method method)
2553 " < " (tramp-shell-quote-argument path))
2554 nil 'file-error
2555 "Encoding remote file failed, see buffer `%s' for details"
2556 (tramp-get-buffer multi-method method user host))
2557 ;; Remove trailing status code
2558 (goto-char (point-max))
2559 (delete-region (point) (progn (forward-line -1) (point)))
2560
2561 (tramp-message 5 "Decoding remote file %s..." filename)
2562 (if (and (tramp-get-decoding-function multi-method method)
2563 (fboundp (tramp-get-decoding-function multi-method method)))
2564 ;; If tramp-decoding-function is defined for this
2565 ;; method, we call it.
2566 (let ((tmpbuf (get-buffer-create " *tramp tmp*")))
2567 (set-buffer tmpbuf)
2568 (erase-buffer)
2569 (insert-buffer (tramp-get-buffer multi-method method
2570 user host))
2571 (tramp-message-for-buffer
2572 multi-method method user host
2573 6 "Decoding remote file %s with function %s..."
2574 filename
2575 (tramp-get-decoding-function multi-method method))
2576 (set-buffer tmpbuf)
2577 (let ((coding-system-for-write 'no-conversion))
2578 (funcall (tramp-get-decoding-function multi-method method)
2579 (point-min)
2580 (point-max))
2581 (write-region (point-min) (point-max) tmpfil))
2582 (kill-buffer tmpbuf))
2583 ;; If tramp-decoding-function is not defined for this
2584 ;; method, we invoke tramp-decoding-command instead.
2585 (let ((tmpfil2 (tramp-make-temp-file)))
2586 (write-region (point-min) (point-max) tmpfil2)
2587 (tramp-message
2588 6 "Decoding remote file %s with command %s..."
2589 filename
2590 (tramp-get-decoding-command multi-method method)) 2610 (tramp-get-decoding-command multi-method method))
2591 (call-process 2611 ;; Use inline encoding for file transfer.
2592 tramp-sh-program 2612 (save-excursion
2593 tmpfil2 ;input 2613 ;; Following line for setting tramp-current-method,
2594 nil ;output 2614 ;; tramp-current-user, tramp-current-host.
2595 nil ;display 2615 (set-buffer (tramp-get-buffer multi-method method user host))
2596 "-c" (concat (tramp-get-decoding-command multi-method method) 2616 (tramp-message 5 "Encoding remote file %s..." filename)
2597 " > " tmpfil)) 2617 (tramp-barf-unless-okay
2598 (delete-file tmpfil2))) 2618 multi-method method user host
2599 (tramp-message-for-buffer 2619 (concat (tramp-get-encoding-command multi-method method)
2600 multi-method method user host 2620 " < " (tramp-shell-quote-argument path))
2601 5 "Decoding remote file %s...done" filename))) 2621 nil 'file-error
2602 2622 "Encoding remote file failed, see buffer `%s' for details"
2603 (t (error "Wrong method specification for `%s'" method))) 2623 (tramp-get-buffer multi-method method user host))
2604 tmpfil)) 2624 ;; Remove trailing status code
2625 (goto-char (point-max))
2626 (delete-region (point) (progn (forward-line -1) (point)))
2627
2628 (tramp-message 5 "Decoding remote file %s..." filename)
2629 (if (and (tramp-get-decoding-function multi-method method)
2630 (fboundp (tramp-get-decoding-function
2631 multi-method method)))
2632 ;; If tramp-decoding-function is defined for this
2633 ;; method, we call it.
2634 (let ((tmpbuf (get-buffer-create " *tramp tmp*")))
2635 (set-buffer tmpbuf)
2636 (erase-buffer)
2637 (insert-buffer (tramp-get-buffer multi-method method
2638 user host))
2639 (tramp-message-for-buffer
2640 multi-method method user host
2641 6 "Decoding remote file %s with function %s..."
2642 filename
2643 (tramp-get-decoding-function multi-method method))
2644 (set-buffer tmpbuf)
2645 (let ((coding-system-for-write 'no-conversion))
2646 (funcall (tramp-get-decoding-function
2647 multi-method method)
2648 (point-min)
2649 (point-max))
2650 (write-region (point-min) (point-max) tmpfil))
2651 (kill-buffer tmpbuf))
2652 ;; If tramp-decoding-function is not defined for this
2653 ;; method, we invoke tramp-decoding-command instead.
2654 (let ((tmpfil2 (tramp-make-temp-file)))
2655 (write-region (point-min) (point-max) tmpfil2)
2656 (tramp-message
2657 6 "Decoding remote file %s with command %s..."
2658 filename
2659 (tramp-get-decoding-command multi-method method))
2660 (call-process
2661 tramp-sh-program
2662 tmpfil2 ;input
2663 nil ;output
2664 nil ;display
2665 "-c" (concat (tramp-get-decoding-command
2666 multi-method method)
2667 " > " tmpfil))
2668 (delete-file tmpfil2)))
2669 (tramp-message-for-buffer
2670 multi-method method user host
2671 5 "Decoding remote file %s...done" filename)))
2672
2673 (t (error "Wrong method specification for `%s'" method)))
2674 tmpfil)))
2605 2675
2606 2676
2607(defun tramp-handle-insert-file-contents 2677(defun tramp-handle-insert-file-contents
@@ -2609,12 +2679,10 @@ This will break if COMMAND prints a newline, followed by the value of
2609 "Like `insert-file-contents' for tramp files." 2679 "Like `insert-file-contents' for tramp files."
2610 (barf-if-buffer-read-only) 2680 (barf-if-buffer-read-only)
2611 (setq filename (expand-file-name filename)) 2681 (setq filename (expand-file-name filename))
2612 (let* ((v (tramp-dissect-file-name (tramp-handle-expand-file-name filename))) 2682 (with-parsed-tramp-file-name filename nil
2613 (multi-method (tramp-file-name-multi-method v)) 2683 (when (tramp-ange-ftp-file-name-p multi-method method)
2614 (method (tramp-file-name-method v)) 2684 (tramp-invoke-ange-ftp 'insert-file-contents
2615 (user (tramp-file-name-user v)) 2685 filename visit beg end replace))
2616 (host (tramp-file-name-host v))
2617 (path (tramp-file-name-path v)))
2618 (if (not (tramp-handle-file-exists-p filename)) 2686 (if (not (tramp-handle-file-exists-p filename))
2619 (progn 2687 (progn
2620 (when visit 2688 (when visit
@@ -2654,189 +2722,194 @@ This will break if COMMAND prints a newline, followed by the value of
2654 (unless (eq append nil) 2722 (unless (eq append nil)
2655 (error "Cannot append to file using tramp (`%s')" filename)) 2723 (error "Cannot append to file using tramp (`%s')" filename))
2656 (setq filename (expand-file-name filename)) 2724 (setq filename (expand-file-name filename))
2657;; Following part commented out because we don't know what to do about 2725 ;; Following part commented out because we don't know what to do about
2658;; file locking, and it does not appear to be a problem to ignore it. 2726 ;; file locking, and it does not appear to be a problem to ignore it.
2659;; Ange-ftp ignores it, too. 2727 ;; Ange-ftp ignores it, too.
2660; (when (and lockname (stringp lockname)) 2728 ;; (when (and lockname (stringp lockname))
2661; (setq lockname (expand-file-name lockname))) 2729 ;; (setq lockname (expand-file-name lockname)))
2662; (unless (or (eq lockname nil) 2730 ;; (unless (or (eq lockname nil)
2663; (string= lockname filename)) 2731 ;; (string= lockname filename))
2664; (error "tramp-handle-write-region: LOCKNAME must be nil or equal FILENAME")) 2732 ;; (error
2733 ;; "tramp-handle-write-region: LOCKNAME must be nil or equal FILENAME"))
2665 ;; XEmacs takes a coding system as the sevent argument, not `confirm' 2734 ;; XEmacs takes a coding system as the sevent argument, not `confirm'
2666 (when (and (not (featurep 'xemacs)) 2735 (when (and (not (featurep 'xemacs))
2667 confirm (file-exists-p filename)) 2736 confirm (file-exists-p filename))
2668 (unless (y-or-n-p (format "File %s exists; overwrite anyway? " 2737 (unless (y-or-n-p (format "File %s exists; overwrite anyway? "
2669 filename)) 2738 filename))
2670 (error "File not overwritten"))) 2739 (error "File not overwritten")))
2671 (let* ((curbuf (current-buffer)) 2740 (with-parsed-tramp-file-name filename nil
2672 (v (tramp-dissect-file-name filename)) 2741 (when (tramp-ange-ftp-file-name-p multi-method method)
2673 (multi-method (tramp-file-name-multi-method v)) 2742 (tramp-invoke-ange-ftp 'write-region
2674 (method (tramp-file-name-method v)) 2743 start end filename append visit lockname confirm))
2675 (user (tramp-file-name-user v)) 2744 (let ((curbuf (current-buffer))
2676 (host (tramp-file-name-host v)) 2745 (rcp-program (tramp-get-rcp-program multi-method method))
2677 (path (tramp-file-name-path v)) 2746 (rcp-args (tramp-get-rcp-args multi-method method))
2678 (rcp-program (tramp-get-rcp-program multi-method method)) 2747 (encoding-command (tramp-get-encoding-command multi-method method))
2679 (rcp-args (tramp-get-rcp-args multi-method method)) 2748 (encoding-function
2680 (encoding-command (tramp-get-encoding-command multi-method method)) 2749 (tramp-get-encoding-function multi-method method))
2681 (encoding-function (tramp-get-encoding-function multi-method method)) 2750 (decoding-command (tramp-get-decoding-command multi-method method))
2682 (decoding-command (tramp-get-decoding-command multi-method method)) 2751 (trampbuf (get-buffer-create "*tramp output*"))
2683 (trampbuf (get-buffer-create "*tramp output*")) 2752 ;; We use this to save the value of `last-coding-system-used'
2684 ;; We use this to save the value of `last-coding-system-used' 2753 ;; after writing the tmp file. At the end of the function,
2685 ;; after writing the tmp file. At the end of the function, 2754 ;; we set `last-coding-system-used' to this saved value.
2686 ;; we set `last-coding-system-used' to this saved value. 2755 ;; This way, any intermediary coding systems used while
2687 ;; This way, any intermediary coding systems used while 2756 ;; talking to the remote shell or suchlike won't hose this
2688 ;; talking to the remote shell or suchlike won't hose this 2757 ;; variable. This approach was snarfed from ange-ftp.el.
2689 ;; variable. This approach was snarfed from ange-ftp.el. 2758 coding-system-used
2690 coding-system-used 2759 tmpfil)
2691 tmpfil) 2760 ;; Write region into a tmp file. This isn't really needed if we
2692 ;; Write region into a tmp file. This isn't really needed if we 2761 ;; use an encoding function, but currently we use it always
2693 ;; use an encoding function, but currently we use it always 2762 ;; because this makes the logic simpler.
2694 ;; because this makes the logic simpler. 2763 (setq tmpfil (tramp-make-temp-file))
2695 (setq tmpfil (tramp-make-temp-file)) 2764 ;; We say `no-message' here because we don't want the visited file
2696 ;; We say `no-message' here because we don't want the visited file 2765 ;; modtime data to be clobbered from the temp file. We call
2697 ;; modtime data to be clobbered from the temp file. We call 2766 ;; `set-visited-file-modtime' ourselves later on.
2698 ;; `set-visited-file-modtime' ourselves later on. 2767 (tramp-run-real-handler
2699 (tramp-run-real-handler 2768 'write-region
2700 'write-region 2769 (if confirm ; don't pass this arg unless defined for backward compat.
2701 (if confirm ; don't pass this arg unless defined for backward compat. 2770 (list start end tmpfil append 'no-message lockname confirm)
2702 (list start end tmpfil append 'no-message lockname confirm) 2771 (list start end tmpfil append 'no-message lockname)))
2703 (list start end tmpfil append 'no-message lockname))) 2772 ;; Now, `last-coding-system-used' has the right value. Remember it.
2704 ;; Now, `last-coding-system-used' has the right value. Remember it. 2773 (when (boundp 'last-coding-system-used)
2705 (when (boundp 'last-coding-system-used) 2774 (setq coding-system-used last-coding-system-used))
2706 (setq coding-system-used last-coding-system-used)) 2775 ;; This is a bit lengthy due to the different methods possible for
2707 ;; This is a bit lengthy due to the different methods possible for 2776 ;; file transfer. First, we check whether the method uses an rcp
2708 ;; file transfer. First, we check whether the method uses an rcp 2777 ;; program. If so, we call it. Otherwise, both encoding and
2709 ;; program. If so, we call it. Otherwise, both encoding and 2778 ;; decoding command must be specified. However, if the method
2710 ;; decoding command must be specified. However, if the method 2779 ;; _also_ specifies an encoding function, then that is used for
2711 ;; _also_ specifies an encoding function, then that is used for 2780 ;; encoding the contents of the tmp file.
2712 ;; encoding the contents of the tmp file. 2781 (cond (rcp-program
2713 (cond (rcp-program 2782 ;; use rcp-like program for file transfer
2714 ;; use rcp-like program for file transfer 2783 (let ((argl (append rcp-args
2715 (let ((argl (append rcp-args 2784 (list
2716 (list 2785 tmpfil
2717 tmpfil 2786 (tramp-make-rcp-program-file-name
2718 (tramp-make-rcp-program-file-name 2787 user host
2719 user host 2788 (tramp-shell-quote-argument path))))))
2720 (tramp-shell-quote-argument path)))))) 2789 (tramp-message-for-buffer
2721 (tramp-message-for-buffer 2790 multi-method method user host
2722 multi-method method user host 2791 6 "Writing tmp file using `%s'..." rcp-program)
2723 6 "Writing tmp file using `%s'..." rcp-program) 2792 (save-excursion (set-buffer trampbuf) (erase-buffer))
2724 (save-excursion (set-buffer trampbuf) (erase-buffer)) 2793 (when tramp-debug-buffer
2725 (when tramp-debug-buffer 2794 (save-excursion
2726 (save-excursion 2795 (set-buffer (tramp-get-debug-buffer multi-method
2727 (set-buffer (tramp-get-debug-buffer multi-method 2796 method user host))
2728 method user host)) 2797 (goto-char (point-max))
2729 (goto-char (point-max)) 2798 (tramp-insert-with-face
2730 (tramp-insert-with-face 2799 'bold (format "$ %s %s\n" rcp-program
2731 'bold (format "$ %s %s\n" rcp-program 2800 (mapconcat 'identity argl " ")))))
2732 (mapconcat 'identity argl " "))))) 2801 (unless (equal 0
2733 (unless (equal 0 2802 (apply #'call-process
2734 (apply #'call-process 2803 rcp-program nil trampbuf nil argl))
2735 rcp-program nil trampbuf nil argl)) 2804 (pop-to-buffer trampbuf)
2736 (pop-to-buffer trampbuf) 2805 (error
2737 (error "Cannot write region to file `%s', command `%s' failed" 2806 "Cannot write region to file `%s', command `%s' failed"
2738 filename rcp-program)) 2807 filename rcp-program))
2739 (tramp-message-for-buffer multi-method method user host 2808 (tramp-message-for-buffer
2740 6 "Transferring file using `%s'...done" 2809 multi-method method user host
2741 rcp-program))) 2810 6 "Transferring file using `%s'...done"
2742 ((and encoding-command decoding-command) 2811 rcp-program)))
2743 ;; Use inline file transfer 2812 ((and encoding-command decoding-command)
2744 (let ((tmpbuf (get-buffer-create " *tramp file transfer*"))) 2813 ;; Use inline file transfer
2745 (save-excursion 2814 (let ((tmpbuf (get-buffer-create " *tramp file transfer*")))
2746 ;; Encode tmpfil into tmpbuf 2815 (save-excursion
2747 (tramp-message-for-buffer multi-method method user host 2816 ;; Encode tmpfil into tmpbuf
2748 5 "Encoding region...") 2817 (tramp-message-for-buffer multi-method method user host
2749 (set-buffer tmpbuf) 2818 5 "Encoding region...")
2750 (erase-buffer) 2819 (set-buffer tmpbuf)
2751 ;; Use encoding function or command. 2820 (erase-buffer)
2752 (if (and encoding-function 2821 ;; Use encoding function or command.
2753 (fboundp encoding-function)) 2822 (if (and encoding-function
2754 (progn 2823 (fboundp encoding-function))
2755 (tramp-message-for-buffer 2824 (progn
2756 multi-method method user host 2825 (tramp-message-for-buffer
2757 6 "Encoding region using function...") 2826 multi-method method user host
2758 (insert-file-contents-literally tmpfil) 2827 6 "Encoding region using function...")
2759 ;; CCC. The following `let' is a workaround for 2828 (insert-file-contents-literally tmpfil)
2760 ;; the base64.el that comes with pgnus-0.84. If 2829 ;; CCC. The following `let' is a workaround for
2761 ;; both of the following conditions are 2830 ;; the base64.el that comes with pgnus-0.84. If
2762 ;; satisfied, it tries to write to a local file 2831 ;; both of the following conditions are
2763 ;; in default-directory, but at this point, 2832 ;; satisfied, it tries to write to a local file
2764 ;; default-directory is remote. 2833 ;; in default-directory, but at this point,
2765 ;; (CALL-PROCESS-REGION can't write to remote 2834 ;; default-directory is remote.
2766 ;; files, it seems.) The file in question is a 2835 ;; (CALL-PROCESS-REGION can't write to remote
2767 ;; tmp file anyway. 2836 ;; files, it seems.) The file in question is a
2768 (let ((default-directory (tramp-temporary-file-directory))) 2837 ;; tmp file anyway.
2769 (funcall encoding-function (point-min) (point-max))) 2838 (let ((default-directory
2770 (goto-char (point-max)) 2839 (tramp-temporary-file-directory)))
2771 (unless (bolp) 2840 (funcall encoding-function (point-min) (point-max)))
2772 (newline))) 2841 (goto-char (point-max))
2773 (tramp-message-for-buffer multi-method method user host 2842 (unless (bolp)
2774 6 "Encoding region using command...") 2843 (newline)))
2775 (unless (equal 0 2844 (tramp-message-for-buffer
2776 (call-process 2845 multi-method method user host
2777 tramp-sh-program 2846 6 "Encoding region using command...")
2778 tmpfil ;input = local tmp file 2847 (unless (equal 0
2779 t ;output is current buffer 2848 (call-process
2780 nil ;don't redisplay 2849 tramp-sh-program
2781 "-c" 2850 tmpfil ;input = local tmp file
2782 encoding-command)) 2851 t ;output is current buffer
2783 (pop-to-buffer trampbuf) 2852 nil ;don't redisplay
2784 (error (concat "Cannot write to `%s', local encoding" 2853 "-c"
2785 " command `%s' failed") 2854 encoding-command))
2786 filename encoding-command))) 2855 (pop-to-buffer trampbuf)
2787 ;; Send tmpbuf into remote decoding command which 2856 (error (concat "Cannot write to `%s', local encoding"
2788 ;; writes to remote file. Because this happens on the 2857 " command `%s' failed")
2789 ;; remote host, we cannot use the function. 2858 filename encoding-command)))
2790 (tramp-message-for-buffer 2859 ;; Send tmpbuf into remote decoding command which
2791 multi-method method user host 2860 ;; writes to remote file. Because this happens on the
2792 5 "Decoding region into remote file %s..." filename) 2861 ;; remote host, we cannot use the function.
2793 (tramp-send-command 2862 (tramp-message-for-buffer
2794 multi-method method user host 2863 multi-method method user host
2795 (format "%s >%s <<'EOF'" 2864 5 "Decoding region into remote file %s..." filename)
2796 decoding-command 2865 (tramp-send-command
2797 (tramp-shell-quote-argument path))) 2866 multi-method method user host
2798 (set-buffer tmpbuf) 2867 (format "%s >%s <<'EOF'"
2799 (tramp-message-for-buffer 2868 decoding-command
2800 multi-method method user host 2869 (tramp-shell-quote-argument path)))
2801 6 "Sending data to remote host...") 2870 (set-buffer tmpbuf)
2802 (tramp-send-region multi-method method user host 2871 (tramp-message-for-buffer
2803 (point-min) (point-max)) 2872 multi-method method user host
2804 ;; wait for remote decoding to complete 2873 6 "Sending data to remote host...")
2805 (tramp-message-for-buffer 2874 (tramp-send-region multi-method method user host
2806 multi-method method user host 6 "Sending end of data token...") 2875 (point-min) (point-max))
2807 (tramp-send-command 2876 ;; wait for remote decoding to complete
2808 multi-method method user host "EOF") 2877 (tramp-message-for-buffer
2809 (tramp-message-for-buffer 2878 multi-method method user host
2810 multi-method method user host 6 2879 6 "Sending end of data token...")
2811 "Waiting for remote host to process data...") 2880 (tramp-send-command
2812 (set-buffer (tramp-get-buffer multi-method method user host)) 2881 multi-method method user host "EOF")
2813 (tramp-wait-for-output) 2882 (tramp-message-for-buffer
2814 (tramp-barf-unless-okay 2883 multi-method method user host 6
2815 multi-method method user host nil nil 'file-error 2884 "Waiting for remote host to process data...")
2816 (concat "Couldn't write region to `%s'," 2885 (set-buffer (tramp-get-buffer multi-method method user host))
2817 " decode using `%s' failed") 2886 (tramp-wait-for-output)
2818 filename decoding-command) 2887 (tramp-barf-unless-okay
2819 (tramp-message 5 "Decoding region into remote file %s...done" 2888 multi-method method user host nil nil 'file-error
2820 filename) 2889 (concat "Couldn't write region to `%s',"
2821 (kill-buffer tmpbuf)))) 2890 " decode using `%s' failed")
2822 (t 2891 filename decoding-command)
2823 (error 2892 (tramp-message 5 "Decoding region into remote file %s...done"
2824 (concat "Method `%s' should specify both encoding and " 2893 filename)
2825 "decoding command or an rcp program") 2894 (kill-buffer tmpbuf))))
2826 method))) 2895 (t
2827 (delete-file tmpfil) 2896 (error
2828 (unless (equal curbuf (current-buffer)) 2897 (concat "Method `%s' should specify both encoding and "
2829 (error "Buffer has changed from `%s' to `%s'" 2898 "decoding command or an rcp program")
2830 curbuf (current-buffer))) 2899 method)))
2831 (when (eq visit t) 2900 (delete-file tmpfil)
2832 (set-visited-file-modtime)) 2901 (unless (equal curbuf (current-buffer))
2833 ;; Make `last-coding-system-used' have the right value. 2902 (error "Buffer has changed from `%s' to `%s'"
2834 (when (boundp 'last-coding-system-used) 2903 curbuf (current-buffer)))
2835 (setq last-coding-system-used coding-system-used)) 2904 (when (eq visit t)
2836 (when (or (eq visit t) 2905 (set-visited-file-modtime))
2837 (eq visit nil) 2906 ;; Make `last-coding-system-used' have the right value.
2838 (stringp visit)) 2907 (when (boundp 'last-coding-system-used)
2839 (message "Wrote %s" filename)))) 2908 (setq last-coding-system-used coding-system-used))
2909 (when (or (eq visit t)
2910 (eq visit nil)
2911 (stringp visit))
2912 (message "Wrote %s" filename)))))
2840 2913
2841;; Call down to the real handler. 2914;; Call down to the real handler.
2842;; Because EFS does not play nicely with TRAMP (both systems match an 2915;; Because EFS does not play nicely with TRAMP (both systems match an
@@ -2871,8 +2944,8 @@ This will break if COMMAND prints a newline, followed by the value of
2871 2944
2872(defun tramp-run-real-handler (operation args) 2945(defun tramp-run-real-handler (operation args)
2873 "Invoke normal file name handler for OPERATION. 2946 "Invoke normal file name handler for OPERATION.
2874First arg specifies the OPERATION, remaining ARGS are passed to the 2947First arg specifies the OPERATION, second arg is a list of arguments to
2875OPERATION." 2948pass to the OPERATION."
2876 (let ((inhibit-file-name-handlers 2949 (let ((inhibit-file-name-handlers
2877 (list 'tramp-file-name-handler 2950 (list 'tramp-file-name-handler
2878 (and (eq inhibit-file-name-operation operation) 2951 (and (eq inhibit-file-name-operation operation)
@@ -2880,17 +2953,15 @@ OPERATION."
2880 (inhibit-file-name-operation operation)) 2953 (inhibit-file-name-operation operation))
2881 (apply operation args))) 2954 (apply operation args)))
2882 2955
2883
2884;; Main function. 2956;; Main function.
2885;;;###autoload 2957;;;###autoload
2886(defun tramp-file-name-handler (operation &rest args) 2958(defun tramp-file-name-handler (operation &rest args)
2887 "Invoke tramp file name handler. 2959 "Invoke tramp file name handler.
2888Falls back to normal file name handler if no tramp file name handler exists." 2960Falls back to normal file name handler if no tramp file name handler exists."
2889 (let ((fn (assoc operation tramp-file-name-handler-alist))) 2961 (let ((fn (assoc operation tramp-file-name-handler-alist)))
2890 ;(message "Handling %s using %s" operation fn)
2891 (if fn 2962 (if fn
2892 (save-match-data 2963 (catch 'tramp-forward-to-ange-ftp
2893 (apply (cdr fn) args)) 2964 (save-match-data (apply (cdr fn) args)))
2894 (tramp-run-real-handler operation args)))) 2965 (tramp-run-real-handler operation args))))
2895 2966
2896;; Register in file name handler alist 2967;; Register in file name handler alist
@@ -2906,6 +2977,21 @@ Falls back to normal file name handler if no tramp file name handler exists."
2906 (setq file-name-handler-alist 2977 (setq file-name-handler-alist
2907 (cons jka (delete jka file-name-handler-alist))))) 2978 (cons jka (delete jka file-name-handler-alist)))))
2908 2979
2980(defun tramp-invoke-ange-ftp (operation &rest args)
2981 "Invoke the Ange-FTP handler function and throw."
2982 (let ((ange-ftp-name-format
2983 (list (nth 0 tramp-file-name-structure)
2984 (nth 3 tramp-file-name-structure)
2985 (nth 2 tramp-file-name-structure)
2986 (nth 4 tramp-file-name-structure))))
2987 (throw 'tramp-forward-to-ange-ftp
2988 (apply 'ange-ftp-hook-function operation args))))
2989
2990(defun tramp-ange-ftp-file-name-p (multi-method method)
2991 "Check if it's a filename that should be forwarded to Ange-FTP."
2992 (and (null multi-method) (string= method tramp-ftp-method)))
2993
2994
2909;;; Interactions with other packages: 2995;;; Interactions with other packages:
2910 2996
2911;; -- complete.el -- 2997;; -- complete.el --
@@ -2913,52 +2999,52 @@ Falls back to normal file name handler if no tramp file name handler exists."
2913;; This function contributed by Ed Sabol 2999;; This function contributed by Ed Sabol
2914(defun tramp-handle-expand-many-files (name) 3000(defun tramp-handle-expand-many-files (name)
2915 "Like `PC-expand-many-files' for tramp files." 3001 "Like `PC-expand-many-files' for tramp files."
2916 (save-match-data 3002 (with-parsed-tramp-file-name name nil
2917 (if (or (string-match "\\*" name) 3003 (when (tramp-ange-ftp-file-name-p multi-method method)
2918 (string-match "\\?" name) 3004 (tramp-invoke-ange-ftp 'expand-many-files name))
2919 (string-match "\\[.*\\]" name)) 3005 (save-match-data
2920 (save-excursion 3006 (if (or (string-match "\\*" name)
2921 ;; Dissect NAME. 3007 (string-match "\\?" name)
2922 (let* ((v (tramp-dissect-file-name name)) 3008 (string-match "\\[.*\\]" name))
2923 (multi-method (tramp-file-name-multi-method v)) 3009 (save-excursion
2924 (method (tramp-file-name-method v)) 3010 ;; Dissect NAME.
2925 (user (tramp-file-name-user v)) 3011 (let (bufstr)
2926 (host (tramp-file-name-host v)) 3012 ;; Perhaps invoke Ange-FTP.
2927 (path (tramp-file-name-path v)) 3013 (when (string= method tramp-ftp-method)
2928 bufstr) 3014 (signal 'tramp-run-ange-ftp (list 0)))
2929 ;; CCC: To do it right, we should quote certain characters 3015 ;; CCC: To do it right, we should quote certain characters
2930 ;; in the file name, but since the echo command is going to 3016 ;; in the file name, but since the echo command is going to
2931 ;; break anyway when there are spaces in the file names, we 3017 ;; break anyway when there are spaces in the file names, we
2932 ;; don't bother. 3018 ;; don't bother.
2933 ;;-(let ((comint-file-name-quote-list 3019 ;;-(let ((comint-file-name-quote-list
2934 ;;- (set-difference tramp-file-name-quote-list 3020 ;;- (set-difference tramp-file-name-quote-list
2935 ;;- '(?\* ?\? ?[ ?])))) 3021 ;;- '(?\* ?\? ?[ ?]))))
2936 ;;- (tramp-send-command 3022 ;;- (tramp-send-command
2937 ;;- multi-method method user host 3023 ;;- multi-method method user host
2938 ;;- (format "echo %s" (comint-quote-filename path))) 3024 ;;- (format "echo %s" (comint-quote-filename path)))
2939 ;;- (tramp-wait-for-output)) 3025 ;;- (tramp-wait-for-output))
2940 (tramp-send-command multi-method method user host 3026 (tramp-send-command multi-method method user host
2941 (format "echo %s" path)) 3027 (format "echo %s" path))
2942 (tramp-wait-for-output) 3028 (tramp-wait-for-output)
2943 (setq bufstr (buffer-substring (point-min) 3029 (setq bufstr (buffer-substring (point-min)
2944 (tramp-line-end-position))) 3030 (tramp-line-end-position)))
2945 (goto-char (point-min)) 3031 (goto-char (point-min))
2946 (if (string-equal path bufstr) 3032 (if (string-equal path bufstr)
2947 nil 3033 nil
2948 (insert "(\"") 3034 (insert "(\"")
2949 (while (search-forward " " nil t) 3035 (while (search-forward " " nil t)
2950 (delete-backward-char 1) 3036 (delete-backward-char 1)
2951 (insert "\" \"")) 3037 (insert "\" \""))
2952 (goto-char (point-max)) 3038 (goto-char (point-max))
2953 (delete-backward-char 1) 3039 (delete-backward-char 1)
2954 (insert "\")") 3040 (insert "\")")
2955 (goto-char (point-min)) 3041 (goto-char (point-min))
2956 (mapcar 3042 (mapcar
2957 (function (lambda (x) 3043 (function (lambda (x)
2958 (tramp-make-tramp-file-name multi-method method 3044 (tramp-make-tramp-file-name multi-method method
2959 user host x))) 3045 user host x)))
2960 (read (current-buffer)))))) 3046 (read (current-buffer))))))
2961 (list (tramp-handle-expand-file-name name))))) 3047 (list (tramp-handle-expand-file-name name))))))
2962 3048
2963;; Check for complete.el and override PC-expand-many-files if appropriate. 3049;; Check for complete.el and override PC-expand-many-files if appropriate.
2964(eval-when-compile 3050(eval-when-compile
@@ -3202,20 +3288,24 @@ file exists and nonzero exit status otherwise."
3202 ((string-match "^~root$" (buffer-string)) 3288 ((string-match "^~root$" (buffer-string))
3203 (setq shell 3289 (setq shell
3204 (or (tramp-find-executable multi-method method user host 3290 (or (tramp-find-executable multi-method method user host
3205 "bash" tramp-remote-path t) 3291 "bash" tramp-remote-path t)
3206 (tramp-find-executable multi-method method user host 3292 (tramp-find-executable multi-method method user host
3207 "ksh" tramp-remote-path t))) 3293 "ksh" tramp-remote-path t)))
3208 (unless shell 3294 (unless shell
3209 (error "Couldn't find a shell which groks tilde expansion")) 3295 (error "Couldn't find a shell which groks tilde expansion"))
3210 ;; Hack: avoid reading of ~/.bashrc. What we should do is have an 3296 ;; Find arguments for this shell.
3211 ;; alist for extra args to give to each shell... 3297 (let ((alist tramp-sh-extra-args)
3212 (when (string-match "/bash\\'" shell) 3298 item extra-args)
3213 (setq shell (concat shell " --norc"))) 3299 (while (and alist (null extra-args))
3300 (setq item (pop alist))
3301 (when (string-match (car item) shell)
3302 (setq extra-args (cdr item))))
3303 (when extra-args (setq shell (concat shell " " extra-args))))
3214 (tramp-message 3304 (tramp-message
3215 5 "Starting remote shell `%s' for tilde expansion..." shell) 3305 5 "Starting remote shell `%s' for tilde expansion..." shell)
3216 (tramp-send-command 3306 (tramp-send-command
3217 multi-method method user host 3307 multi-method method user host
3218 (concat "PS1='$ ' ; exec " shell)) 3308 (concat "PS1='$ ' ; exec " shell)) ;
3219 (unless (tramp-wait-for-regexp 3309 (unless (tramp-wait-for-regexp
3220 (get-buffer-process (current-buffer)) 3310 (get-buffer-process (current-buffer))
3221 60 (format "\\(\\$ *\\|\\(%s\\)\\'\\)" shell-prompt-pattern)) 3311 60 (format "\\(\\$ *\\|\\(%s\\)\\'\\)" shell-prompt-pattern))
@@ -3236,7 +3326,7 @@ file exists and nonzero exit status otherwise."
3236 shell (buffer-name)))) 3326 shell (buffer-name))))
3237 (tramp-message 5 "Waiting for remote `%s' to start up...done" shell)) 3327 (tramp-message 5 "Waiting for remote `%s' to start up...done" shell))
3238 (t (tramp-message 5 "Remote `%s' groks tilde expansion, good" 3328 (t (tramp-message 5 "Remote `%s' groks tilde expansion, good"
3239 (tramp-get-remote-sh multi-method method)))))) 3329 (tramp-get-remote-sh multi-method method))))))
3240 3330
3241(defun tramp-check-ls-command (multi-method method user host cmd) 3331(defun tramp-check-ls-command (multi-method method user host cmd)
3242 "Checks whether the given `ls' executable groks `-n'. 3332 "Checks whether the given `ls' executable groks `-n'.
@@ -4486,21 +4576,37 @@ remote path name."
4486 (save-match-data 4576 (save-match-data
4487 (unless (string-match (nth 0 tramp-file-name-structure) name) 4577 (unless (string-match (nth 0 tramp-file-name-structure) name)
4488 (error "Not a tramp file name: %s" name)) 4578 (error "Not a tramp file name: %s" name))
4489 (setq method (or (match-string (nth 1 tramp-file-name-structure) name) 4579 (setq method (match-string (nth 1 tramp-file-name-structure) name))
4490 tramp-default-method)) 4580 (if (and method (member method tramp-multi-methods))
4491 (if (member method tramp-multi-methods)
4492 ;; If it's a multi method, the file name structure contains 4581 ;; If it's a multi method, the file name structure contains
4493 ;; arrays of method, user and host. 4582 ;; arrays of method, user and host.
4494 (tramp-dissect-multi-file-name name) 4583 (tramp-dissect-multi-file-name name)
4495 ;; Normal method. 4584 ;; Normal method. First, find out default method.
4496 (make-tramp-file-name 4585 (let ((user (match-string (nth 2 tramp-file-name-structure) name))
4497 :multi-method nil 4586 (host (match-string (nth 3 tramp-file-name-structure) name))
4498 :method method 4587 (path (match-string (nth 4 tramp-file-name-structure) name)))
4499 :user (or (match-string (nth 2 tramp-file-name-structure) name) 4588 (when (not method)
4500 nil) 4589 (setq method (tramp-find-default-method user host)))
4501 :host (match-string (nth 3 tramp-file-name-structure) name) 4590 (make-tramp-file-name
4502 :path (match-string (nth 4 tramp-file-name-structure) name)))))) 4591 :multi-method nil
4503 4592 :method method
4593 :user (or user nil)
4594 :host host
4595 :path path))))))
4596
4597(defun tramp-find-default-method (user host)
4598 "Look up the right method to use in `tramp-default-method-alist'."
4599 (let ((choices tramp-default-method-alist)
4600 (method tramp-default-method)
4601 item)
4602 (while choices
4603 (setq item (pop choices))
4604 (when (and (string-match (nth 0 item) host)
4605 (string-match (nth 1 item) (or user "")))
4606 (setq method (nth 2 item))
4607 (setq choices nil)))
4608 method))
4609
4504;; HHH: Not Changed. Multi method. Will probably not handle the case where 4610;; HHH: Not Changed. Multi method. Will probably not handle the case where
4505;; a user name is not provided in the "file name" very well. 4611;; a user name is not provided in the "file name" very well.
4506(defun tramp-dissect-multi-file-name (name) 4612(defun tramp-dissect-multi-file-name (name)
@@ -4581,14 +4687,18 @@ remote path name."
4581 (incf i))) 4687 (incf i)))
4582 (concat prefix hops path))) 4688 (concat prefix hops path)))
4583 4689
4584;; HHH: Changed. Handles the case where no user name is given in the
4585;; file name.
4586(defun tramp-make-rcp-program-file-name (user host path) 4690(defun tramp-make-rcp-program-file-name (user host path)
4587 "Create a file name suitable to be passed to `rcp'." 4691 "Create a file name suitable to be passed to `rcp'."
4588 (if user 4692 (if user
4589 (format "%s@%s:%s" user host path) 4693 (format "%s@%s:%s" user host path)
4590 (format "%s:%s" host path))) 4694 (format "%s:%s" host path)))
4591 4695
4696(defun tramp-make-ange-ftp-file-name (user host path)
4697 "Given user, host, and path, return an Ange-FTP filename."
4698 (if user
4699 (format "/%s@%s:%s" user host path)
4700 (format "/%s:%s" host path)))
4701
4592(defun tramp-method-out-of-band-p (multi-method method) 4702(defun tramp-method-out-of-band-p (multi-method method)
4593 "Return t if this is an out-of-band method, nil otherwise. 4703 "Return t if this is an out-of-band method, nil otherwise.
4594It is important to check for this condition, since it is not possible 4704It is important to check for this condition, since it is not possible
@@ -5047,6 +5157,7 @@ TRAMP.
5047 5157
5048;;; TODO: 5158;;; TODO:
5049 5159
5160;; * Revise the comments near the beginning of the file.
5050;; * Cooperate with PCL-CVS. It uses start-process, which doesn't 5161;; * Cooperate with PCL-CVS. It uses start-process, which doesn't
5051;; work for remote files. 5162;; work for remote files.
5052;; * Allow /[method/user@host:port] syntax for the ssh "-p" argument. 5163;; * Allow /[method/user@host:port] syntax for the ssh "-p" argument.