diff options
| author | Michael Albinus | 2009-10-26 09:29:12 +0000 |
|---|---|---|
| committer | Michael Albinus | 2009-10-26 09:29:12 +0000 |
| commit | 293c24f9ad59130eb8ae53b3adbd61b5fb634084 (patch) | |
| tree | 73974be71a1677648d053bf5b996a280974f6618 | |
| parent | 36f1267e808dcc3ff406da564a29c0b7180315d9 (diff) | |
| download | emacs-293c24f9ad59130eb8ae53b3adbd61b5fb634084.tar.gz emacs-293c24f9ad59130eb8ae53b3adbd61b5fb634084.zip | |
* net/tramp.el (tramp-perl-file-truename): New defconst. Perl
code contributed by yary <not.com@gmail.com> (tiny change).
(tramp-handle-file-truename, tramp-get-remote-perl): Use it.
Check also for "perl-file-spec" and "perl-cwd-realpath"
properties.
(tramp-handle-write-region): In case of APPEND, reuse the tmpfile
name.
* net/tramp.el (tramp-perl-file-name-all-completions): New
defconst.
(tramp-get-remote-readlink): New defun.
(tramp-handle-file-truename): Use it.
(tramp-handle-file-exists-p): Check file-attributes cache, assume
file exists if cache value present.
(tramp-check-cached-permissions) New defun.
(tramp-handle-file-readable-p): Use it.
(tramp-handle-file-writable-p): Likewise.
(tramp-handle-file-executable-p): Likewise.
(tramp-handle-file-name-all-completions): Try using Perl to get
partial completions. When perl not available, combine `cd' and
`ls' into single remote operation and use shell expansion to get
partial remote directory contents. Set `file-exists-p' cache for
directory and any files returned by ls. Change cache handling to
support partial directory contents. Use error message emitted by
remote `cd' or Perl code for local tramp-error.
(tramp-do-copy-or-rename-file-directly): Avoid separate
tramp-send-command-and-check call.
(tramp-handle-process-file): Merge three remote ops into one. Do
not flush all caches when `process-file-side-effects' is set.
(tramp-handle-write-region): Avoid tramp-set-file-uid-gid if
file-attributes shows uid/gid to be set already.
| -rw-r--r-- | lisp/ChangeLog | 40 | ||||
| -rw-r--r-- | lisp/net/tramp.el | 589 |
2 files changed, 476 insertions, 153 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 9e72d7d8bdf..1442396b746 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,43 @@ | |||
| 1 | 2009-10-26 Michael Albinus <michael.albinus@gmx.de> | ||
| 2 | |||
| 3 | * net/tramp.el (tramp-perl-file-truename): New defconst. Perl | ||
| 4 | code contributed by yary <not.com@gmail.com> (tiny change). | ||
| 5 | (tramp-handle-file-truename, tramp-get-remote-perl): Use it. | ||
| 6 | Check also for "perl-file-spec" and "perl-cwd-realpath" | ||
| 7 | properties. | ||
| 8 | (tramp-handle-write-region): In case of APPEND, reuse the tmpfile | ||
| 9 | name. | ||
| 10 | |||
| 11 | * net/tramp-imap.el (tramp-imap-file-name-handler-alist): Ignore | ||
| 12 | `dired-call-process'. | ||
| 13 | (tramp-imap-make-iht): Use `user' and `ssl' with `imap-hash-make'. | ||
| 14 | |||
| 15 | 2009-10-26 Julian Scheid <julians37@gmail.com> | ||
| 16 | |||
| 17 | * net/tramp.el (tramp-perl-file-name-all-completions): New | ||
| 18 | defconst. | ||
| 19 | (tramp-get-remote-readlink): New defun. | ||
| 20 | (tramp-handle-file-truename): Use it. | ||
| 21 | (tramp-handle-file-exists-p): Check file-attributes cache, assume | ||
| 22 | file exists if cache value present. | ||
| 23 | (tramp-check-cached-permissions) New defun. | ||
| 24 | (tramp-handle-file-readable-p): Use it. | ||
| 25 | (tramp-handle-file-writable-p): Likewise. | ||
| 26 | (tramp-handle-file-executable-p): Likewise. | ||
| 27 | (tramp-handle-file-name-all-completions): Try using Perl to get | ||
| 28 | partial completions. When perl not available, combine `cd' and | ||
| 29 | `ls' into single remote operation and use shell expansion to get | ||
| 30 | partial remote directory contents. Set `file-exists-p' cache for | ||
| 31 | directory and any files returned by ls. Change cache handling to | ||
| 32 | support partial directory contents. Use error message emitted by | ||
| 33 | remote `cd' or Perl code for local tramp-error. | ||
| 34 | (tramp-do-copy-or-rename-file-directly): Avoid separate | ||
| 35 | tramp-send-command-and-check call. | ||
| 36 | (tramp-handle-process-file): Merge three remote ops into one. Do | ||
| 37 | not flush all caches when `process-file-side-effects' is set. | ||
| 38 | (tramp-handle-write-region): Avoid tramp-set-file-uid-gid if | ||
| 39 | file-attributes shows uid/gid to be set already. | ||
| 40 | |||
| 1 | 2009-10-26 Dan Nicolaescu <dann@ics.uci.edu> | 41 | 2009-10-26 Dan Nicolaescu <dann@ics.uci.edu> |
| 2 | 42 | ||
| 3 | * textmodes/tex-mode.el (tex-dvi-view-command) | 43 | * textmodes/tex-mode.el (tex-dvi-view-command) |
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index bd1e7f46d9d..f89c32102e2 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el | |||
| @@ -1613,6 +1613,75 @@ Many systems support `uudecode -o /dev/stdout' or `uudecode -o -' | |||
| 1613 | for this or `uudecode -p', but some systems don't, and for them | 1613 | for this or `uudecode -p', but some systems don't, and for them |
| 1614 | we have this shell function.") | 1614 | we have this shell function.") |
| 1615 | 1615 | ||
| 1616 | (defconst tramp-perl-file-truename | ||
| 1617 | "%s -e ' | ||
| 1618 | use File::Spec; | ||
| 1619 | use Cwd \"realpath\"; | ||
| 1620 | |||
| 1621 | sub recursive { | ||
| 1622 | my ($volume, @dirs) = @_; | ||
| 1623 | my $real = realpath(File::Spec->catpath( | ||
| 1624 | $volume, File::Spec->catdir(@dirs), \"\")); | ||
| 1625 | if ($real) { | ||
| 1626 | my ($vol, $dir) = File::Spec->splitpath($real, 1); | ||
| 1627 | return ($vol, File::Spec->splitdir($dir)); | ||
| 1628 | } | ||
| 1629 | else { | ||
| 1630 | my $last = pop(@dirs); | ||
| 1631 | ($volume, @dirs) = recursive($volume, @dirs); | ||
| 1632 | push(@dirs, $last); | ||
| 1633 | return ($volume, @dirs); | ||
| 1634 | } | ||
| 1635 | } | ||
| 1636 | |||
| 1637 | $result = realpath($ARGV[0]); | ||
| 1638 | if (!$result) { | ||
| 1639 | my ($vol, $dir) = File::Spec->splitpath($ARGV[0], 1); | ||
| 1640 | ($vol, @dirs) = recursive($vol, File::Spec->splitdir($dir)); | ||
| 1641 | |||
| 1642 | $result = File::Spec->catpath($vol, File::Spec->catdir(@dirs), \"\"); | ||
| 1643 | } | ||
| 1644 | |||
| 1645 | if ($ARGV[0] =~ /\\/$/) { | ||
| 1646 | $result = $result . \"/\"; | ||
| 1647 | } | ||
| 1648 | |||
| 1649 | print \"\\\"$result\\\"\\n\"; | ||
| 1650 | ' \"$1\" 2>/dev/null" | ||
| 1651 | "Perl script to produce output suitable for use with `file-truename' | ||
| 1652 | on the remote file system. | ||
| 1653 | Escape sequence %s is replaced with name of Perl binary. | ||
| 1654 | This string is passed to `format', so percent characters need to be doubled.") | ||
| 1655 | |||
| 1656 | (defconst tramp-perl-file-name-all-completions | ||
| 1657 | "%s -e 'sub case { | ||
| 1658 | my $str = shift; | ||
| 1659 | if ($ARGV[2]) { | ||
| 1660 | return lc($str); | ||
| 1661 | } | ||
| 1662 | else { | ||
| 1663 | return $str; | ||
| 1664 | } | ||
| 1665 | } | ||
| 1666 | opendir(d, $ARGV[0]) || die(\"$ARGV[0]: $!\\nfail\\n\"); | ||
| 1667 | @files = readdir(d); closedir(d); | ||
| 1668 | foreach $f (@files) { | ||
| 1669 | if (case(substr($f, 0, length($ARGV[1]))) eq case($ARGV[1])) { | ||
| 1670 | if (-d \"$ARGV[0]/$f\") { | ||
| 1671 | print \"$f/\\n\"; | ||
| 1672 | } | ||
| 1673 | else { | ||
| 1674 | print \"$f\\n\"; | ||
| 1675 | } | ||
| 1676 | } | ||
| 1677 | } | ||
| 1678 | print \"ok\\n\" | ||
| 1679 | ' \"$1\" \"$2\" \"$3\" 2>/dev/null" | ||
| 1680 | "Perl script to produce output suitable for use with | ||
| 1681 | `file-name-all-completions' on the remote file system. Escape | ||
| 1682 | sequence %s is replaced with name of Perl binary. This string is | ||
| 1683 | passed to `format', so percent characters need to be doubled.") | ||
| 1684 | |||
| 1616 | ;; Perl script to implement `file-attributes' in a Lisp `read'able | 1685 | ;; Perl script to implement `file-attributes' in a Lisp `read'able |
| 1617 | ;; output. If you are hacking on this, note that you get *no* output | 1686 | ;; output. If you are hacking on this, note that you get *no* output |
| 1618 | ;; unless this spits out a complete line, including the '\n' at the | 1687 | ;; unless this spits out a complete line, including the '\n' at the |
| @@ -2430,78 +2499,105 @@ target of the symlink differ." | |||
| 2430 | "Like `file-truename' for Tramp files." | 2499 | "Like `file-truename' for Tramp files." |
| 2431 | (with-parsed-tramp-file-name (expand-file-name filename) nil | 2500 | (with-parsed-tramp-file-name (expand-file-name filename) nil |
| 2432 | (with-file-property v localname "file-truename" | 2501 | (with-file-property v localname "file-truename" |
| 2433 | (let* ((directory-sep-char ?/) ; for XEmacs | 2502 | (let ((result nil)) ; result steps in reverse order |
| 2434 | (steps (tramp-compat-split-string localname "/")) | ||
| 2435 | (localnamedir (tramp-run-real-handler | ||
| 2436 | 'file-name-as-directory (list localname))) | ||
| 2437 | (is-dir (string= localname localnamedir)) | ||
| 2438 | (thisstep nil) | ||
| 2439 | (numchase 0) | ||
| 2440 | ;; Don't make the following value larger than necessary. | ||
| 2441 | ;; People expect an error message in a timely fashion when | ||
| 2442 | ;; something is wrong; otherwise they might think that Emacs | ||
| 2443 | ;; is hung. Of course, correctness has to come first. | ||
| 2444 | (numchase-limit 20) | ||
| 2445 | (result nil) ;result steps in reverse order | ||
| 2446 | symlink-target) | ||
| 2447 | (tramp-message v 4 "Finding true name for `%s'" filename) | 2503 | (tramp-message v 4 "Finding true name for `%s'" filename) |
| 2448 | (while (and steps (< numchase numchase-limit)) | 2504 | (cond |
| 2449 | (setq thisstep (pop steps)) | 2505 | ;; Use GNU readlink --canonicalize-missing where available. |
| 2450 | (tramp-message | 2506 | ((tramp-get-remote-readlink v) |
| 2451 | v 5 "Check %s" | 2507 | (setq result |
| 2452 | (mapconcat 'identity | 2508 | (tramp-send-command-and-read |
| 2453 | (append '("") (reverse result) (list thisstep)) | 2509 | v |
| 2510 | (format "echo \"\\\"`%s --canonicalize-missing %s`\\\"\"" | ||
| 2511 | (tramp-get-remote-readlink v) | ||
| 2512 | (tramp-shell-quote-argument localname))))) | ||
| 2513 | |||
| 2514 | ;; Use Perl implementation. | ||
| 2515 | ((and (tramp-get-remote-perl v) | ||
| 2516 | (tramp-get-connection-property v "perl-file-spec" nil) | ||
| 2517 | (tramp-get-connection-property v "perl-cwd-realpath" nil)) | ||
| 2518 | (tramp-maybe-send-script | ||
| 2519 | v tramp-perl-file-truename "tramp_perl_file_truename") | ||
| 2520 | (setq result | ||
| 2521 | (tramp-send-command-and-read | ||
| 2522 | v | ||
| 2523 | (format "tramp_perl_file_truename %s" | ||
| 2524 | (tramp-shell-quote-argument localname))))) | ||
| 2525 | |||
| 2526 | ;; Do it yourself. We bind `directory-sep-char' here for | ||
| 2527 | ;; XEmacs on Windows, which would otherwise use backslash. | ||
| 2528 | (t (let* ((directory-sep-char ?/) | ||
| 2529 | (steps (tramp-compat-split-string localname "/")) | ||
| 2530 | (localnamedir (tramp-run-real-handler | ||
| 2531 | 'file-name-as-directory (list localname))) | ||
| 2532 | (is-dir (string= localname localnamedir)) | ||
| 2533 | (thisstep nil) | ||
| 2534 | (numchase 0) | ||
| 2535 | ;; Don't make the following value larger than | ||
| 2536 | ;; necessary. People expect an error message in a | ||
| 2537 | ;; timely fashion when something is wrong; | ||
| 2538 | ;; otherwise they might think that Emacs is hung. | ||
| 2539 | ;; Of course, correctness has to come first. | ||
| 2540 | (numchase-limit 20) | ||
| 2541 | symlink-target) | ||
| 2542 | (while (and steps (< numchase numchase-limit)) | ||
| 2543 | (setq thisstep (pop steps)) | ||
| 2544 | (tramp-message | ||
| 2545 | v 5 "Check %s" | ||
| 2546 | (mapconcat 'identity | ||
| 2547 | (append '("") (reverse result) (list thisstep)) | ||
| 2548 | "/")) | ||
| 2549 | (setq symlink-target | ||
| 2550 | (nth 0 (file-attributes | ||
| 2551 | (tramp-make-tramp-file-name | ||
| 2552 | method user host | ||
| 2553 | (mapconcat 'identity | ||
| 2554 | (append '("") | ||
| 2555 | (reverse result) | ||
| 2556 | (list thisstep)) | ||
| 2557 | "/"))))) | ||
| 2558 | (cond ((string= "." thisstep) | ||
| 2559 | (tramp-message v 5 "Ignoring step `.'")) | ||
| 2560 | ((string= ".." thisstep) | ||
| 2561 | (tramp-message v 5 "Processing step `..'") | ||
| 2562 | (pop result)) | ||
| 2563 | ((stringp symlink-target) | ||
| 2564 | ;; It's a symlink, follow it. | ||
| 2565 | (tramp-message v 5 "Follow symlink to %s" symlink-target) | ||
| 2566 | (setq numchase (1+ numchase)) | ||
| 2567 | (when (file-name-absolute-p symlink-target) | ||
| 2568 | (setq result nil)) | ||
| 2569 | ;; If the symlink was absolute, we'll get a string like | ||
| 2570 | ;; "/user@host:/some/target"; extract the | ||
| 2571 | ;; "/some/target" part from it. | ||
| 2572 | (when (tramp-tramp-file-p symlink-target) | ||
| 2573 | (unless (tramp-equal-remote filename symlink-target) | ||
| 2574 | (tramp-error | ||
| 2575 | v 'file-error | ||
| 2576 | "Symlink target `%s' on wrong host" symlink-target)) | ||
| 2577 | (setq symlink-target localname)) | ||
| 2578 | (setq steps | ||
| 2579 | (append (tramp-compat-split-string | ||
| 2580 | symlink-target "/") | ||
| 2581 | steps))) | ||
| 2582 | (t | ||
| 2583 | ;; It's a file. | ||
| 2584 | (setq result (cons thisstep result))))) | ||
| 2585 | (when (>= numchase numchase-limit) | ||
| 2586 | (tramp-error | ||
| 2587 | v 'file-error | ||
| 2588 | "Maximum number (%d) of symlinks exceeded" numchase-limit)) | ||
| 2589 | (setq result (reverse result)) | ||
| 2590 | ;; Combine list to form string. | ||
| 2591 | (setq result | ||
| 2592 | (if result | ||
| 2593 | (mapconcat 'identity (cons "" result) "/") | ||
| 2454 | "/")) | 2594 | "/")) |
| 2455 | (setq symlink-target | 2595 | (when (and is-dir (or (string= "" result) |
| 2456 | (nth 0 (file-attributes | 2596 | (not (string= (substring result -1) "/")))) |
| 2457 | (tramp-make-tramp-file-name | 2597 | (setq result (concat result "/")))))) |
| 2458 | method user host | 2598 | |
| 2459 | (mapconcat 'identity | 2599 | (tramp-message v 4 "True name of `%s' is `%s'" filename result) |
| 2460 | (append '("") | 2600 | (tramp-make-tramp-file-name method user host result))))) |
| 2461 | (reverse result) | ||
| 2462 | (list thisstep)) | ||
| 2463 | "/"))))) | ||
| 2464 | (cond ((string= "." thisstep) | ||
| 2465 | (tramp-message v 5 "Ignoring step `.'")) | ||
| 2466 | ((string= ".." thisstep) | ||
| 2467 | (tramp-message v 5 "Processing step `..'") | ||
| 2468 | (pop result)) | ||
| 2469 | ((stringp symlink-target) | ||
| 2470 | ;; It's a symlink, follow it. | ||
| 2471 | (tramp-message v 5 "Follow symlink to %s" symlink-target) | ||
| 2472 | (setq numchase (1+ numchase)) | ||
| 2473 | (when (file-name-absolute-p symlink-target) | ||
| 2474 | (setq result nil)) | ||
| 2475 | ;; If the symlink was absolute, we'll get a string like | ||
| 2476 | ;; "/user@host:/some/target"; extract the | ||
| 2477 | ;; "/some/target" part from it. | ||
| 2478 | (when (tramp-tramp-file-p symlink-target) | ||
| 2479 | (unless (tramp-equal-remote filename symlink-target) | ||
| 2480 | (tramp-error | ||
| 2481 | v 'file-error | ||
| 2482 | "Symlink target `%s' on wrong host" symlink-target)) | ||
| 2483 | (setq symlink-target localname)) | ||
| 2484 | (setq steps | ||
| 2485 | (append (tramp-compat-split-string symlink-target "/") | ||
| 2486 | steps))) | ||
| 2487 | (t | ||
| 2488 | ;; It's a file. | ||
| 2489 | (setq result (cons thisstep result))))) | ||
| 2490 | (when (>= numchase numchase-limit) | ||
| 2491 | (tramp-error | ||
| 2492 | v 'file-error | ||
| 2493 | "Maximum number (%d) of symlinks exceeded" numchase-limit)) | ||
| 2494 | (setq result (reverse result)) | ||
| 2495 | ;; Combine list to form string. | ||
| 2496 | (setq result | ||
| 2497 | (if result | ||
| 2498 | (mapconcat 'identity (cons "" result) "/") | ||
| 2499 | "/")) | ||
| 2500 | (when (and is-dir (or (string= "" result) | ||
| 2501 | (not (string= (substring result -1) "/")))) | ||
| 2502 | (setq result (concat result "/"))) | ||
| 2503 | (tramp-message v 4 "True name of `%s' is `%s'" filename result) | ||
| 2504 | (tramp-make-tramp-file-name method user host result))))) | ||
| 2505 | 2601 | ||
| 2506 | ;; Basic functions. | 2602 | ;; Basic functions. |
| 2507 | 2603 | ||
| @@ -2509,12 +2605,16 @@ target of the symlink differ." | |||
| 2509 | "Like `file-exists-p' for Tramp files." | 2605 | "Like `file-exists-p' for Tramp files." |
| 2510 | (with-parsed-tramp-file-name filename nil | 2606 | (with-parsed-tramp-file-name filename nil |
| 2511 | (with-file-property v localname "file-exists-p" | 2607 | (with-file-property v localname "file-exists-p" |
| 2512 | (zerop (tramp-send-command-and-check | 2608 | (or (not (null (tramp-get-file-property |
| 2513 | v | 2609 | v localname "file-attributes-integer" nil))) |
| 2514 | (format | 2610 | (not (null (tramp-get-file-property |
| 2515 | "%s %s" | 2611 | v localname "file-attributes-string" nil))) |
| 2516 | (tramp-get-file-exists-command v) | 2612 | (zerop (tramp-send-command-and-check |
| 2517 | (tramp-shell-quote-argument localname))))))) | 2613 | v |
| 2614 | (format | ||
| 2615 | "%s %s" | ||
| 2616 | (tramp-get-file-exists-command v) | ||
| 2617 | (tramp-shell-quote-argument localname)))))))) | ||
| 2518 | 2618 | ||
| 2519 | ;; Inodes don't exist for some file systems. Therefore we must | 2619 | ;; Inodes don't exist for some file systems. Therefore we must |
| 2520 | ;; generate virtual ones. Used in `find-buffer-visiting'. The method | 2620 | ;; generate virtual ones. Used in `find-buffer-visiting'. The method |
| @@ -2843,13 +2943,19 @@ and gid of the corresponding user is taken. Both parameters must be integers." | |||
| 2843 | "Like `file-executable-p' for Tramp files." | 2943 | "Like `file-executable-p' for Tramp files." |
| 2844 | (with-parsed-tramp-file-name filename nil | 2944 | (with-parsed-tramp-file-name filename nil |
| 2845 | (with-file-property v localname "file-executable-p" | 2945 | (with-file-property v localname "file-executable-p" |
| 2846 | (zerop (tramp-run-test "-x" filename))))) | 2946 | ;; Examine `file-attributes' cache to see if request can be |
| 2947 | ;; satisfied without remote operation. | ||
| 2948 | (or (tramp-check-cached-permissions v ?x) | ||
| 2949 | (zerop (tramp-run-test "-x" filename)))))) | ||
| 2847 | 2950 | ||
| 2848 | (defun tramp-handle-file-readable-p (filename) | 2951 | (defun tramp-handle-file-readable-p (filename) |
| 2849 | "Like `file-readable-p' for Tramp files." | 2952 | "Like `file-readable-p' for Tramp files." |
| 2850 | (with-parsed-tramp-file-name filename nil | 2953 | (with-parsed-tramp-file-name filename nil |
| 2851 | (with-file-property v localname "file-readable-p" | 2954 | (with-file-property v localname "file-readable-p" |
| 2852 | (zerop (tramp-run-test "-r" filename))))) | 2955 | ;; Examine `file-attributes' cache to see if request can be |
| 2956 | ;; satisfied without remote operation. | ||
| 2957 | (or (tramp-check-cached-permissions v ?r) | ||
| 2958 | (zerop (tramp-run-test "-r" filename)))))) | ||
| 2853 | 2959 | ||
| 2854 | ;; When the remote shell is started, it looks for a shell which groks | 2960 | ;; When the remote shell is started, it looks for a shell which groks |
| 2855 | ;; tilde expansion. Here, we assume that all shells which grok tilde | 2961 | ;; tilde expansion. Here, we assume that all shells which grok tilde |
| @@ -2939,8 +3045,10 @@ value of `default-file-modes', without execute permissions." | |||
| 2939 | (with-parsed-tramp-file-name filename nil | 3045 | (with-parsed-tramp-file-name filename nil |
| 2940 | (with-file-property v localname "file-writable-p" | 3046 | (with-file-property v localname "file-writable-p" |
| 2941 | (if (file-exists-p filename) | 3047 | (if (file-exists-p filename) |
| 2942 | ;; Existing files must be writable. | 3048 | ;; Examine `file-attributes' cache to see if request can be |
| 2943 | (zerop (tramp-run-test "-w" filename)) | 3049 | ;; satisfied without remote operation. |
| 3050 | (or (tramp-check-cached-permissions v ?w) | ||
| 3051 | (zerop (tramp-run-test "-w" filename))) | ||
| 2944 | ;; If file doesn't exist, check if directory is writable. | 3052 | ;; If file doesn't exist, check if directory is writable. |
| 2945 | (and (zerop (tramp-run-test | 3053 | (and (zerop (tramp-run-test |
| 2946 | "-d" (file-name-directory filename))) | 3054 | "-d" (file-name-directory filename))) |
| @@ -3074,50 +3182,149 @@ value of `default-file-modes', without execute permissions." | |||
| 3074 | "Like `file-name-all-completions' for Tramp files." | 3182 | "Like `file-name-all-completions' for Tramp files." |
| 3075 | (unless (save-match-data (string-match "/" filename)) | 3183 | (unless (save-match-data (string-match "/" filename)) |
| 3076 | (with-parsed-tramp-file-name (expand-file-name directory) nil | 3184 | (with-parsed-tramp-file-name (expand-file-name directory) nil |
| 3077 | ;; Flush the directory cache. There could be changed directory | ||
| 3078 | ;; contents. | ||
| 3079 | (when (and (integerp tramp-completion-reread-directory-timeout) | ||
| 3080 | (> (tramp-time-diff | ||
| 3081 | (current-time) | ||
| 3082 | (tramp-get-file-property | ||
| 3083 | v localname "last-completion" '(0 0 0))) | ||
| 3084 | tramp-completion-reread-directory-timeout)) | ||
| 3085 | (tramp-flush-file-property v localname)) | ||
| 3086 | 3185 | ||
| 3087 | (all-completions | 3186 | (all-completions |
| 3088 | filename | 3187 | filename |
| 3089 | (mapcar | 3188 | (mapcar |
| 3090 | 'list | 3189 | 'list |
| 3091 | (with-file-property v localname "file-name-all-completions" | 3190 | (or |
| 3092 | (let (result) | 3191 | ;; Try cache first |
| 3093 | (tramp-barf-unless-okay | 3192 | (and |
| 3094 | v | 3193 | ;; Ignore if expired |
| 3095 | (format "cd %s" (tramp-shell-quote-argument localname)) | 3194 | (or (not (integerp tramp-completion-reread-directory-timeout)) |
| 3096 | "tramp-handle-file-name-all-completions: Couldn't `cd %s'" | 3195 | (<= (tramp-time-diff |
| 3097 | (tramp-shell-quote-argument localname)) | 3196 | (current-time) |
| 3098 | 3197 | (tramp-get-file-property | |
| 3099 | ;; Get a list of directories and files, including reliably | 3198 | v localname "last-completion" '(0 0 0))) |
| 3100 | ;; tagging the directories with a trailing '/'. Because I | 3199 | tramp-completion-reread-directory-timeout)) |
| 3101 | ;; rock. --daniel@danann.net | 3200 | |
| 3102 | (tramp-send-command | 3201 | ;; Try cache entries for filename, filename with last |
| 3103 | v | 3202 | ;; character removed, filename with last two characters |
| 3104 | (format (concat "%s -a 2>/dev/null | while read f; do " | 3203 | ;; removed, ..., and finally the empty string - all |
| 3105 | "if %s -d \"$f\" 2>/dev/null; " | 3204 | ;; concatenated to the local directory name |
| 3106 | "then echo \"$f/\"; else echo \"$f\"; fi; done") | 3205 | |
| 3107 | (tramp-get-ls-command v) | 3206 | ;; This is inefficient for very long filenames, pity |
| 3108 | (tramp-get-test-command v))) | 3207 | ;; `reduce' is not available... |
| 3109 | 3208 | (car | |
| 3110 | ;; Now grab the output. | 3209 | (apply |
| 3111 | (with-current-buffer (tramp-get-buffer v) | 3210 | 'append |
| 3112 | (goto-char (point-max)) | 3211 | (mapcar |
| 3113 | (while (zerop (forward-line -1)) | 3212 | (lambda (x) |
| 3114 | (push (buffer-substring | 3213 | (let ((cache-hit |
| 3115 | (point) (tramp-compat-line-end-position)) | 3214 | (tramp-get-file-property |
| 3116 | result))) | 3215 | v |
| 3117 | 3216 | (concat localname (substring filename 0 x)) | |
| 3118 | (tramp-set-file-property | 3217 | "file-name-all-completions" |
| 3119 | v localname "last-completion" (current-time)) | 3218 | nil))) |
| 3120 | result))))))) | 3219 | (when cache-hit (list cache-hit)))) |
| 3220 | (tramp-compat-number-sequence (length filename) 0 -1))))) | ||
| 3221 | |||
| 3222 | ;; Cache expired or no matching cache entry found so we need | ||
| 3223 | ;; to perform a remote operation | ||
| 3224 | (let (result) | ||
| 3225 | ;; Get a list of directories and files, including reliably | ||
| 3226 | ;; tagging the directories with a trailing '/'. Because I | ||
| 3227 | ;; rock. --daniel@danann.net | ||
| 3228 | |||
| 3229 | ;; Changed to perform `cd' in the same remote op and only | ||
| 3230 | ;; get entries starting with `filename'. Capture any `cd' | ||
| 3231 | ;; error messages. Ensure any `cd' and `echo' aliases are | ||
| 3232 | ;; ignored. | ||
| 3233 | (tramp-send-command | ||
| 3234 | v | ||
| 3235 | (if (tramp-get-remote-perl v) | ||
| 3236 | (progn | ||
| 3237 | (tramp-maybe-send-script | ||
| 3238 | v tramp-perl-file-name-all-completions | ||
| 3239 | "tramp_perl_file_name_all_completions") | ||
| 3240 | (format "tramp_perl_file_name_all_completions %s %s %d" | ||
| 3241 | (tramp-shell-quote-argument localname) | ||
| 3242 | (tramp-shell-quote-argument filename) | ||
| 3243 | (if (symbol-value | ||
| 3244 | 'read-file-name-completion-ignore-case) | ||
| 3245 | 1 0))) | ||
| 3246 | |||
| 3247 | (format (concat | ||
| 3248 | "(\\cd %s 2>&1 && (%s %s -a 2>/dev/null" | ||
| 3249 | ;; `ls' with wildcard might fail with `Argument | ||
| 3250 | ;; list too long' error in some corner cases; if | ||
| 3251 | ;; `ls' fails after `cd' succeeded, chances are | ||
| 3252 | ;; that's the case, so let's retry without | ||
| 3253 | ;; wildcard. This will return "too many" entries | ||
| 3254 | ;; but that isn't harmful. | ||
| 3255 | " || %s -a 2>/dev/null)" | ||
| 3256 | " | while read f; do" | ||
| 3257 | " if %s -d \"$f\" 2>/dev/null;" | ||
| 3258 | " then \\echo \"$f/\"; else \\echo \"$f\"; fi; done" | ||
| 3259 | " && \\echo ok) || \\echo fail") | ||
| 3260 | (tramp-shell-quote-argument localname) | ||
| 3261 | (tramp-get-ls-command v) | ||
| 3262 | ;; When `filename' is empty, just `ls' without | ||
| 3263 | ;; filename argument is more efficient than `ls *' | ||
| 3264 | ;; for very large directories and might avoid the | ||
| 3265 | ;; `Argument list too long' error. | ||
| 3266 | ;; | ||
| 3267 | ;; With and only with wildcard, we need to add | ||
| 3268 | ;; `-d' to prevent `ls' from descending into | ||
| 3269 | ;; sub-directories. | ||
| 3270 | (if (zerop (length filename)) | ||
| 3271 | "." | ||
| 3272 | (concat (tramp-shell-quote-argument filename) "* -d")) | ||
| 3273 | (tramp-get-ls-command v) | ||
| 3274 | (tramp-get-test-command v)))) | ||
| 3275 | |||
| 3276 | ;; Now grab the output. | ||
| 3277 | (with-current-buffer (tramp-get-buffer v) | ||
| 3278 | (goto-char (point-max)) | ||
| 3279 | |||
| 3280 | ;; Check result code, found in last line of output | ||
| 3281 | (forward-line -1) | ||
| 3282 | (if (looking-at "^fail$") | ||
| 3283 | (progn | ||
| 3284 | ;; Grab error message from line before last line | ||
| 3285 | ;; (it was put there by `cd 2>&1') | ||
| 3286 | (forward-line -1) | ||
| 3287 | (tramp-error | ||
| 3288 | v 'file-error | ||
| 3289 | "tramp-handle-file-name-all-completions: %s" | ||
| 3290 | (buffer-substring | ||
| 3291 | (point) (tramp-compat-line-end-position)))) | ||
| 3292 | ;; For peace of mind, if buffer doesn't end in `fail' | ||
| 3293 | ;; then it should end in `ok'. If neither are in the | ||
| 3294 | ;; buffer something went seriously wrong on the remote | ||
| 3295 | ;; side. | ||
| 3296 | (unless (looking-at "^ok$") | ||
| 3297 | (tramp-error | ||
| 3298 | v 'file-error | ||
| 3299 | "\ | ||
| 3300 | tramp-handle-file-name-all-completions: internal error accessing `%s': `%s'" | ||
| 3301 | (tramp-shell-quote-argument localname) (buffer-string)))) | ||
| 3302 | |||
| 3303 | (while (zerop (forward-line -1)) | ||
| 3304 | (push (buffer-substring | ||
| 3305 | (point) (tramp-compat-line-end-position)) | ||
| 3306 | result))) | ||
| 3307 | |||
| 3308 | ;; Because the remote op went through OK we know the | ||
| 3309 | ;; directory we `cd'-ed to exists | ||
| 3310 | (tramp-set-file-property | ||
| 3311 | v localname "file-exists-p" t) | ||
| 3312 | |||
| 3313 | ;; Because the remote op went through OK we know every | ||
| 3314 | ;; file listed by `ls' exists. | ||
| 3315 | (mapc (lambda (entry) | ||
| 3316 | (tramp-set-file-property | ||
| 3317 | v (concat localname entry) "file-exists-p" t)) | ||
| 3318 | result) | ||
| 3319 | |||
| 3320 | (tramp-set-file-property | ||
| 3321 | v localname "last-completion" (current-time)) | ||
| 3322 | |||
| 3323 | ;; Store result in the cache | ||
| 3324 | (tramp-set-file-property | ||
| 3325 | v (concat localname filename) | ||
| 3326 | "file-name-all-completions" | ||
| 3327 | result)))))))) | ||
| 3121 | 3328 | ||
| 3122 | ;; The following isn't needed for Emacs 20 but for 19.34? | 3329 | ;; The following isn't needed for Emacs 20 but for 19.34? |
| 3123 | (defun tramp-handle-file-name-completion | 3330 | (defun tramp-handle-file-name-completion |
| @@ -3380,16 +3587,18 @@ the uid and gid from FILENAME." | |||
| 3380 | (if t1 (tramp-handle-file-remote-p filename 'localname) filename)) | 3587 | (if t1 (tramp-handle-file-remote-p filename 'localname) filename)) |
| 3381 | (localname2 | 3588 | (localname2 |
| 3382 | (if t2 (tramp-handle-file-remote-p newname 'localname) newname)) | 3589 | (if t2 (tramp-handle-file-remote-p newname 'localname) newname)) |
| 3383 | (prefix (file-remote-p (if t1 filename newname)))) | 3590 | (prefix (file-remote-p (if t1 filename newname))) |
| 3591 | cmd-result) | ||
| 3384 | 3592 | ||
| 3385 | (cond | 3593 | (cond |
| 3386 | ;; Both files are on a remote host, with same user. | 3594 | ;; Both files are on a remote host, with same user. |
| 3387 | ((and t1 t2) | 3595 | ((and t1 t2) |
| 3388 | (tramp-send-command | 3596 | (setq cmd-result |
| 3389 | v | 3597 | (tramp-send-command-and-check |
| 3390 | (format "%s %s %s" cmd | 3598 | v |
| 3391 | (tramp-shell-quote-argument localname1) | 3599 | (format "%s %s %s" cmd |
| 3392 | (tramp-shell-quote-argument localname2))) | 3600 | (tramp-shell-quote-argument localname1) |
| 3601 | (tramp-shell-quote-argument localname2)))) | ||
| 3393 | (with-current-buffer (tramp-get-buffer v) | 3602 | (with-current-buffer (tramp-get-buffer v) |
| 3394 | (goto-char (point-min)) | 3603 | (goto-char (point-min)) |
| 3395 | (unless | 3604 | (unless |
| @@ -3398,7 +3607,7 @@ the uid and gid from FILENAME." | |||
| 3398 | ;; Mask cp -f error. | 3607 | ;; Mask cp -f error. |
| 3399 | (re-search-forward | 3608 | (re-search-forward |
| 3400 | tramp-operation-not-permitted-regexp nil t)) | 3609 | tramp-operation-not-permitted-regexp nil t)) |
| 3401 | (zerop (tramp-send-command-and-check v nil))) | 3610 | (zerop cmd-result)) |
| 3402 | (tramp-error-with-buffer | 3611 | (tramp-error-with-buffer |
| 3403 | nil v 'file-error | 3612 | nil v 'file-error |
| 3404 | "Copying directly failed, see buffer `%s' for details." | 3613 | "Copying directly failed, see buffer `%s' for details." |
| @@ -4128,20 +4337,20 @@ beginning of local filename are not substituted." | |||
| 4128 | (setq outbuf (current-buffer)))) | 4337 | (setq outbuf (current-buffer)))) |
| 4129 | (when stderr (setq command (format "%s 2>%s" command stderr))) | 4338 | (when stderr (setq command (format "%s 2>%s" command stderr))) |
| 4130 | 4339 | ||
| 4131 | ;; Goto working directory. | ||
| 4132 | (tramp-send-command | ||
| 4133 | v (format "cd %s" (tramp-shell-quote-argument localname))) | ||
| 4134 | ;; Send the command. It might not return in time, so we protect it. | 4340 | ;; Send the command. It might not return in time, so we protect it. |
| 4135 | (condition-case nil | 4341 | (condition-case nil |
| 4136 | (unwind-protect | 4342 | (unwind-protect |
| 4137 | (tramp-send-command v command) | 4343 | (setq ret |
| 4344 | (tramp-send-command-and-check | ||
| 4345 | v (format "\\cd %s; %s" | ||
| 4346 | (tramp-shell-quote-argument localname) | ||
| 4347 | command))) | ||
| 4138 | ;; We should show the output anyway. | 4348 | ;; We should show the output anyway. |
| 4139 | (when outbuf | 4349 | (when outbuf |
| 4140 | (let ((output-string | 4350 | (with-current-buffer outbuf |
| 4141 | (with-current-buffer (tramp-get-connection-buffer v) | 4351 | (insert |
| 4142 | (buffer-substring (point-min) (point-max))))) | 4352 | (with-current-buffer (tramp-get-connection-buffer v) |
| 4143 | (with-current-buffer outbuf | 4353 | (buffer-string)))) |
| 4144 | (insert output-string))) | ||
| 4145 | (when display (display-buffer outbuf)))) | 4354 | (when display (display-buffer outbuf)))) |
| 4146 | ;; When the user did interrupt, we should do it also. We use | 4355 | ;; When the user did interrupt, we should do it also. We use |
| 4147 | ;; return code -1 as marker. | 4356 | ;; return code -1 as marker. |
| @@ -4153,8 +4362,6 @@ beginning of local filename are not substituted." | |||
| 4153 | (kill-buffer (tramp-get-connection-buffer v)) | 4362 | (kill-buffer (tramp-get-connection-buffer v)) |
| 4154 | (setq ret 1))) | 4363 | (setq ret 1))) |
| 4155 | 4364 | ||
| 4156 | ;; Check return code. | ||
| 4157 | (unless ret (setq ret (tramp-send-command-and-check v nil))) | ||
| 4158 | ;; Provide error file. | 4365 | ;; Provide error file. |
| 4159 | (when tmpstderr (rename-file tmpstderr (cadr destination) t)) | 4366 | (when tmpstderr (rename-file tmpstderr (cadr destination) t)) |
| 4160 | 4367 | ||
| @@ -4672,13 +4879,13 @@ Returns a file name in `tramp-auto-save-directory' for autosaving this file." | |||
| 4672 | ;; Write region into a tmp file. This isn't really | 4879 | ;; Write region into a tmp file. This isn't really |
| 4673 | ;; needed if we use an encoding function, but currently | 4880 | ;; needed if we use an encoding function, but currently |
| 4674 | ;; we use it always because this makes the logic | 4881 | ;; we use it always because this makes the logic |
| 4675 | ;; simpler. If `append' is non-nil, we copy the file | 4882 | ;; simpler. |
| 4676 | ;; locally, and let the native `write-region' | 4883 | (tmpfile (or tramp-temp-buffer-file-name |
| 4677 | ;; implementation do the job. | 4884 | (tramp-compat-make-temp-file filename)))) |
| 4678 | (tmpfile (if append | 4885 | |
| 4679 | (file-local-copy filename) | 4886 | ;; If `append' is non-nil, we copy the file locally, and let |
| 4680 | (or tramp-temp-buffer-file-name | 4887 | ;; the native `write-region' implementation do the job. |
| 4681 | (tramp-compat-make-temp-file filename))))) | 4888 | (when append (copy-file filename tmpfile 'ok)) |
| 4682 | 4889 | ||
| 4683 | ;; We say `no-message' here because we don't want the | 4890 | ;; We say `no-message' here because we don't want the |
| 4684 | ;; visited file modtime data to be clobbered from the temp | 4891 | ;; visited file modtime data to be clobbered from the temp |
| @@ -4836,17 +5043,22 @@ Returns a file name in `tramp-auto-save-directory' for autosaving this file." | |||
| 4836 | 5043 | ||
| 4837 | ;; We must protect `last-coding-system-used', now we have set it | 5044 | ;; We must protect `last-coding-system-used', now we have set it |
| 4838 | ;; to its correct value. | 5045 | ;; to its correct value. |
| 4839 | (let (last-coding-system-used) | 5046 | (let (last-coding-system-used (need-chown t)) |
| 4840 | ;; Set file modification time. | 5047 | ;; Set file modification time. |
| 4841 | (when (or (eq visit t) (stringp visit)) | 5048 | (when (or (eq visit t) (stringp visit)) |
| 4842 | (set-visited-file-modtime | 5049 | (let ((file-attr (file-attributes filename))) |
| 4843 | ;; We must pass modtime explicitely, because filename can | 5050 | (set-visited-file-modtime |
| 4844 | ;; be different from (buffer-file-name), f.e. if | 5051 | ;; We must pass modtime explicitely, because filename can |
| 4845 | ;; `file-precious-flag' is set. | 5052 | ;; be different from (buffer-file-name), f.e. if |
| 4846 | (nth 5 (file-attributes filename)))) | 5053 | ;; `file-precious-flag' is set. |
| 5054 | (nth 5 file-attr)) | ||
| 5055 | (when (and (eq (nth 2 file-attr) uid) | ||
| 5056 | (eq (nth 3 file-attr) gid)) | ||
| 5057 | (setq need-chown nil)))) | ||
| 4847 | 5058 | ||
| 4848 | ;; Set the ownership. | 5059 | ;; Set the ownership. |
| 4849 | (tramp-set-file-uid-gid filename uid gid) | 5060 | (when need-chown |
| 5061 | (tramp-set-file-uid-gid filename uid gid)) | ||
| 4850 | (when (or (eq visit t) (null visit) (stringp visit)) | 5062 | (when (or (eq visit t) (null visit) (stringp visit)) |
| 4851 | (tramp-message v 0 "Wrote %s" filename)) | 5063 | (tramp-message v 0 "Wrote %s" filename)) |
| 4852 | (run-hooks 'tramp-handle-write-region-hook))))) | 5064 | (run-hooks 'tramp-handle-write-region-hook))))) |
| @@ -7244,6 +7456,49 @@ Return ATTR." | |||
| 7244 | (tramp-get-device vec)) | 7456 | (tramp-get-device vec)) |
| 7245 | attr)) | 7457 | attr)) |
| 7246 | 7458 | ||
| 7459 | (defun tramp-check-cached-permissions (vec access) | ||
| 7460 | "Check `file-attributes' caches for VEC. | ||
| 7461 | Return t if according to the cache access type ACCESS is known to | ||
| 7462 | be granted." | ||
| 7463 | (let ((result nil) | ||
| 7464 | (offset (cond | ||
| 7465 | ((eq ?r access) 1) | ||
| 7466 | ((eq ?w access) 2) | ||
| 7467 | ((eq ?x access) 3)))) | ||
| 7468 | (dolist (suffix '("string" "integer") result) | ||
| 7469 | (setq | ||
| 7470 | result | ||
| 7471 | (or | ||
| 7472 | result | ||
| 7473 | (let ((file-attr | ||
| 7474 | (tramp-get-file-property | ||
| 7475 | vec (tramp-file-name-localname vec) | ||
| 7476 | (concat "file-attributes-" suffix) nil)) | ||
| 7477 | (remote-uid | ||
| 7478 | (tramp-get-connection-property | ||
| 7479 | vec (concat "uid-" suffix) nil)) | ||
| 7480 | (remote-gid | ||
| 7481 | (tramp-get-connection-property | ||
| 7482 | vec (concat "gid-" suffix) nil))) | ||
| 7483 | (and | ||
| 7484 | file-attr | ||
| 7485 | (or | ||
| 7486 | ;; Not a symlink | ||
| 7487 | (eq t (car file-attr)) | ||
| 7488 | (null (car file-attr))) | ||
| 7489 | (or | ||
| 7490 | ;; World accessible. | ||
| 7491 | (eq access (aref (nth 8 file-attr) (+ offset 6))) | ||
| 7492 | ;; User accessible and owned by user. | ||
| 7493 | (and | ||
| 7494 | (eq access (aref (nth 8 file-attr) offset)) | ||
| 7495 | (equal remote-uid (nth 2 file-attr))) | ||
| 7496 | ;; Group accessible and owned by user's | ||
| 7497 | ;; principal group. | ||
| 7498 | (and | ||
| 7499 | (eq access (aref (nth 8 file-attr) (+ offset 3))) | ||
| 7500 | (equal remote-gid (nth 3 file-attr))))))))))) | ||
| 7501 | |||
| 7247 | (defun tramp-get-inode (vec) | 7502 | (defun tramp-get-inode (vec) |
| 7248 | "Returns the virtual inode number. | 7503 | "Returns the virtual inode number. |
| 7249 | If it doesn't exist, generate a new one." | 7504 | If it doesn't exist, generate a new one." |
| @@ -7707,8 +7962,21 @@ necessary only. This function will be used in file name completion." | |||
| 7707 | (defun tramp-get-remote-perl (vec) | 7962 | (defun tramp-get-remote-perl (vec) |
| 7708 | (with-connection-property vec "perl" | 7963 | (with-connection-property vec "perl" |
| 7709 | (tramp-message vec 5 "Finding a suitable `perl' command") | 7964 | (tramp-message vec 5 "Finding a suitable `perl' command") |
| 7710 | (or (tramp-find-executable vec "perl5" (tramp-get-remote-path vec)) | 7965 | (let ((result |
| 7711 | (tramp-find-executable vec "perl" (tramp-get-remote-path vec))))) | 7966 | (or (tramp-find-executable vec "perl5" (tramp-get-remote-path vec)) |
| 7967 | (tramp-find-executable | ||
| 7968 | vec "perl" (tramp-get-remote-path vec))))) | ||
| 7969 | ;; We must check also for some Perl modules. | ||
| 7970 | (when result | ||
| 7971 | (with-connection-property vec "perl-file-spec" | ||
| 7972 | (zerop | ||
| 7973 | (tramp-send-command-and-check | ||
| 7974 | vec (format "%s -e 'use File::Spec;'" result)))) | ||
| 7975 | (with-connection-property vec "perl-cwd-realpath" | ||
| 7976 | (zerop | ||
| 7977 | (tramp-send-command-and-check | ||
| 7978 | vec (format "%s -e 'use Cwd \"realpath\";'" result))))) | ||
| 7979 | result))) | ||
| 7712 | 7980 | ||
| 7713 | (defun tramp-get-remote-stat (vec) | 7981 | (defun tramp-get-remote-stat (vec) |
| 7714 | (with-connection-property vec "stat" | 7982 | (with-connection-property vec "stat" |
| @@ -7732,6 +8000,21 @@ necessary only. This function will be used in file name completion." | |||
| 7732 | (setq result nil))) | 8000 | (setq result nil))) |
| 7733 | result))) | 8001 | result))) |
| 7734 | 8002 | ||
| 8003 | (defun tramp-get-remote-readlink (vec) | ||
| 8004 | (with-connection-property vec "readlink" | ||
| 8005 | (tramp-message vec 5 "Finding a suitable `readlink' command") | ||
| 8006 | (let ((result (tramp-find-executable | ||
| 8007 | vec "readlink" (tramp-get-remote-path vec)))) | ||
| 8008 | (when (and result | ||
| 8009 | ;; We don't want to display an error message. | ||
| 8010 | (with-temp-message (or (current-message) "") | ||
| 8011 | (condition-case nil | ||
| 8012 | (zerop | ||
| 8013 | (tramp-send-command-and-check | ||
| 8014 | vec (format "%s --canonicalize-missing /" result))) | ||
| 8015 | (error nil)))) | ||
| 8016 | result)))) | ||
| 8017 | |||
| 7735 | (defun tramp-get-remote-id (vec) | 8018 | (defun tramp-get-remote-id (vec) |
| 7736 | (with-connection-property vec "id" | 8019 | (with-connection-property vec "id" |
| 7737 | (tramp-message vec 5 "Finding POSIX `id' command") | 8020 | (tramp-message vec 5 "Finding POSIX `id' command") |