aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Albinus2009-10-26 09:29:12 +0000
committerMichael Albinus2009-10-26 09:29:12 +0000
commit293c24f9ad59130eb8ae53b3adbd61b5fb634084 (patch)
tree73974be71a1677648d053bf5b996a280974f6618
parent36f1267e808dcc3ff406da564a29c0b7180315d9 (diff)
downloademacs-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/ChangeLog40
-rw-r--r--lisp/net/tramp.el589
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 @@
12009-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
152009-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
12009-10-26 Dan Nicolaescu <dann@ics.uci.edu> 412009-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 -'
1613for this or `uudecode -p', but some systems don't, and for them 1613for this or `uudecode -p', but some systems don't, and for them
1614we have this shell function.") 1614we have this shell function.")
1615 1615
1616(defconst tramp-perl-file-truename
1617 "%s -e '
1618use File::Spec;
1619use Cwd \"realpath\";
1620
1621sub 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]);
1638if (!$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
1645if ($ARGV[0] =~ /\\/$/) {
1646 $result = $result . \"/\";
1647}
1648
1649print \"\\\"$result\\\"\\n\";
1650' \"$1\" 2>/dev/null"
1651 "Perl script to produce output suitable for use with `file-truename'
1652on the remote file system.
1653Escape sequence %s is replaced with name of Perl binary.
1654This 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}
1666opendir(d, $ARGV[0]) || die(\"$ARGV[0]: $!\\nfail\\n\");
1667@files = readdir(d); closedir(d);
1668foreach $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}
1678print \"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
1682sequence %s is replaced with name of Perl binary. This string is
1683passed 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 "\
3300tramp-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.
7461Return t if according to the cache access type ACCESS is known to
7462be 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.
7249If it doesn't exist, generate a new one." 7504If 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")