Re: tramp hangs opening a file, Emacs 30.1 tramp-version "2.7.1.30.1" and "2.8.0-pre"
Michael Albinus <[email protected]> Thu, 03 Apr 2025 17:04:32 +0200
| Newsgroups | gmane.emacs.tramp |
|---|---|
| Message-ID | <[email protected]> |
Stacey Marshall <[email protected]> writes: Hi Stacey, Thanks for this exhaustive bug report, and the proper analysis. > 3. In another terminal session clear up caches, start emacs, and access > directory via tramp path > > rm -rf ~/.cache/emacs ~/.emacs.d/tramp > emacs -nw -Q --eval '(add-to-list `load-path "~/emacs/tramp/lisp/")' \ > --eval '(require `tramp)' --eval '(setq tramp-verbose 11)' \ > --eval '(find-file "/scp:foobar@localhost:/export/home/foobar/tmp/is_it_the_length_of_path_and_not_the_d")' > > At this point, if necessary accept the connection and type password > as required... And then emacs appears hung. A C-g (Control-G) > aborts the transfer. Switching to the debug buffer > `(switch-to-buffer "*debug tramp/scp foobar@localhost*")` and > duplicating it (M-n) (before it gets contaminated/removed). > It shows some output, though this tends to differ slightly each time! Yep. According to the debug buffer you've sent, Tramp has sent the following command: --8<---------------cut here---------------start------------->8--- 16:34:47.760152 tramp-send-command (6) # (if test -h "/export/home/foobar/tmp/is_it_the_length_of_path_and_not_the_d/"; then echo t; else echo nil; fi) && /usr/bin/readlink --canonicalize-missing /export/home/foobar/tmp/is_it_the_length_of_path_and_not_the_d/ 2>/dev/null; echo tramp_exit_status $? --8<---------------cut here---------------end--------------->8--- The "(if test ... tramp_exit_status $?" sequence is 257 characters long, it seems to exceed the shell line length on Solaris. The problem is, that the looooongish file name is used twice. > diff --git a/lisp/tramp-sh.el b/lisp/tramp-sh.el > index 047d93a5..e0ccc0ce 100644 > --- a/lisp/tramp-sh.el > +++ b/lisp/tramp-sh.el > @@ -1292,20 +1292,12 @@ Operations not mentioned here will be handled by the normal Emacs functions.") > ;; Use GNU readlink --canonicalize-missing where available. > ((tramp-get-remote-readlink v) > (tramp-send-command-and-check > - v (format > - (concat > - "(if %s -h \"%s\"; then echo t; else echo nil; fi) && " > - "%s --canonicalize-missing %s") > - (tramp-get-test-command v) > - (tramp-shell-quote-argument localname) > - (tramp-get-remote-readlink v) > - (tramp-shell-quote-argument localname))) > + v (format "%s --canonicalize-missing %s" > + (tramp-get-remote-readlink v) > + (tramp-shell-quote-argument localname))) > (with-current-buffer (tramp-get-connection-buffer v) > (goto-char (point-min)) > - (tramp-set-file-property v localname "file-symlink-marker" (read (current-buffer))) > - ;; We cannot call `read', the file name isn't quoted. > - (forward-line) > - (buffer-substring (point) (line-end-position)))) > + (buffer-substring (point-min) (line-end-position)))) Yes. But this removes the performance optimization, to return both the information, whether a give file is a symlink, and its true name. This optimization avoids one round trip. > At this point I thought I should raise it with yourselves. Instead, I've puzzled the attached patch, which uses a shell function instead. Could you please check? > Stace Best regards, Michael.
(unnamed)
(text/x-patch, 1.6 KB)
diff --git a/lisp/tramp-sh.el b/lisp/tramp-sh.el
index 047d93a5..481a3979 100644
--- a/lisp/tramp-sh.el
+++ b/lisp/tramp-sh.el
@@ -648,6 +648,14 @@ we have this shell function.
Format specifiers are replaced by `tramp-expand-script', percent
characters need to be doubled.")
+(defconst tramp-readlink-file-truename
+ "if %s -h \"$1\"; then echo t; else echo nil; fi
+%s --canonicalize-missing \"$1\""
+ "Shell script to produce output suitable for use with `file-truename'
+on the remote file system.
+Format specifiers are replaced by `tramp-expand-script', percent
+characters need to be doubled.")
+
(defconst tramp-perl-file-truename
"%p -e '
use File::Spec;
@@ -1291,14 +1299,12 @@ Operations not mentioned here will be handled by the normal Emacs functions.")
(cond
;; Use GNU readlink --canonicalize-missing where available.
((tramp-get-remote-readlink v)
+ (tramp-maybe-send-script
+ v (format tramp-readlink-file-truename
+ (tramp-get-test-command v) (tramp-get-remote-readlink v))
+ "tramp_readlink_file_truename")
(tramp-send-command-and-check
- v (format
- (concat
- "(if %s -h \"%s\"; then echo t; else echo nil; fi) && "
- "%s --canonicalize-missing %s")
- (tramp-get-test-command v)
- (tramp-shell-quote-argument localname)
- (tramp-get-remote-readlink v)
- (tramp-shell-quote-argument localname)))
+ v (format "tramp_readlink_file_truename %s"
+ (tramp-shell-quote-argument localname)))
(with-current-buffer (tramp-get-connection-buffer v)
(goto-char (point-min))
(tramp-set-file-property v localname "file-symlink-marker" (read (current-buffer)))