Subject: bug#14030: 24.3; expand-file-name expands remote file name on Windows incorrectly

From: Eli Zaretskii <[email-masked]>
Date: Sun, 24 Mar 2013 18:10:44 +0200

> From: Michael Albinus <[email-masked]>
> Cc: [email-masked],  [email-masked]
> Date: Sat, 23 Mar 2013 22:37:48 +0100
> 
> >>       (let ((directory-sep-char ?/)
> >> 	    (default-directory (tramp-compat-temporary-file-directory)))
> >> 	(tramp-make-tramp-file-name
> >> 	 method user host
> >> 	 (tramp-drop-volume-letter
> >> 	  (tramp-run-real-handler
> >> 	   'expand-file-name (list localname)))
> >> 	 hop)))))
> >> 
> >> In Emacs 24.3, `tramp-drop-volume-letter' is not executed:
> >> 
> >> | | | | 5 -> tramp-run-real-handler: operation=expand-file-name
> >> | | | | args=("/root/")
> >> | | | | 5 <- tramp-run-real-handler: "c:/root/"
> >> | | | | 5 -> tramp-make-tramp-file-name: method="plink" user=nil
> >> | | | | host="ford" localname="c:/root/" hop=nil
> >> | | | | 5 <- tramp-make-tramp-file-name: "/plink:ford:c:/root/"
> >> 
> >> When I use Emacs 24.3.50, the latest snapshot, that function is
> >> executed:
> >> 
> >> | | | | 5 -> (tramp-run-real-handler expand-file-name ("/root/"))
> >> | | | | 5 <- tramp-run-real-handler: "c:/root/"
> >> | | | | 5 -> (tramp-drop-volume-letter "c:/root/")
> >> | | | | 5 <- tramp-drop-volume-letter: "/root/"
> >> | | | | 5 -> (tramp-make-tramp-file-name "plink" nil "ford" "/root/" nil)
> >> | | | | 5 <- tramp-make-tramp-file-name: "/plink:ford:/root/"
> >> 
> >> I have no idea, what prevents `tramp-drop-volume-letter' to be called.

My crystal ball says that your 24.3.50 snapshot was bootstrapped on
MS-Windows, or at least Tramp was compiled on Windows.  See below.

> > Or maybe it somehow takes the 'identity route?
> 
> No.
> 
> (tramp-drop-volume-letter "c:/root/")
>   => "/root/"

That's not the same, because the call to tramp-drop-volume-letter in
tramp-sh-handle-expand-file-name could still be expanded to 'identity'
(= nothing) by the byte compiler when tramp-sh.elc was compiled.  And
indeed, disassembling tramp-sh-handle-expand-file-name from
tramp-sh.elc provided in the Emacs 24.3 tarball shows this:

  336	varbind	  default-directory
  337	varbind	  directory-sep-char
  339	constant  tramp-make-tramp-file-name
  340	varref	  method
  341	varref	  user
  342	varref	  host
  344	constant  tramp-run-real-handler
  345	constant  expand-file-name
  346	varref	  localname
  348	list1	  
  349	call	  2
  350	varref	  hop
  352	call	  5
  353	unbind	  8
  355	return	  

"Look, ma: no tramp-drop-volume-letter!"

If I now byte-compile tramp-sh.el on MS-Windows, I get this
disassembly:

  336	varbind	  default-directory
  337	varbind	  directory-sep-char
  339	constant  tramp-make-tramp-file-name
  340	varref	  method
  341	varref	  user
  342	varref	  host
  344	constant  tramp-drop-volume-letter  <<<<<<<<<<<<<<<<<<<<<<<<
  345	constant  tramp-run-real-handler
  346	constant  expand-file-name
  347	varref	  localname
  349	list1	  
  350	call	  2
  351	call	  1
  352	varref	  hop
  354	call	  5
  355	unbind	  8
  357	return	  

(And, btw, the .elc file I get is 50KB smaller than the one in the
tarball -- why?)

If I compile tramp-sh.el on GNU/Linux with the latest trunk, I still
don't see tramp-drop-volume-letter in the disassembly of
tramp-sh-handle-expand-file-name.  So the problem is still there in
the current trunk.  By contrast, if I compile tramp-sh.el with Emacs
24.2, I do see the call to tramp-drop-volume-letter in the
disassembly.

So, somehow, compiling tramp-sh.el on Unix replaces the call to
tramp-drop-volume-letter with nothing.  Perhaps the condition, viz.

  (defalias 'tramp-drop-volume-letter
    (if (memq system-type '(cygwin windows-nt))  <<<<<<<<<<<<<<<<<<<
	(lambda (name)
	  "Cut off unnecessary drive letter from file NAME.
  The functions `tramp-*-handle-expand-file-name' call `expand-file-name'
  locally on a remote file name.  When the local system is a W32 system
  but the remote system is Unix, this introduces a superfluous drive
  letter into the file name.  This function removes it."
	  (save-match-data
	    (if (string-match "\\`[a-zA-Z]:/" name)
		(replace-match "/" nil t name)
	      name)))

      'identity))

is expanded at byte-compile time, instead of at run time?

And I guess whatever has this effect was introduced between the
release of 24.2 and 24.3 (which was the trunk until 24.2 release).