Subject: bug#39057: 27.0.60; copy-file interactive VS from lisp disagreement

From: Stefan Monnier <[email-masked]>
Date: Wed, 15 Jan 2020 15:35:37 -0500

> Answering myself: this is a problem with completion routines: when the
> user types a file name that is exactly identical to the default (or
> just presses RET, which is the same), then the completion code in
> read-file-name-internal returns a value that has the trailing slash
> stripped.  And we now require a trailing slash to recognize NEWNAME as
> a directory.

The problem seems to be linked to the value "" passed as `initial` to
`read-file-name`, it doesn't show up with a nil value for `initial`.

It seems to come from the following lines at the beginning of
read-file-name-default:

      (unless default-filename
        (setq default-filename (if initial (expand-file-name initial dir)
                                 buffer-file-name)))

because:

    M-: (expand-file-name "" "/tmp/")
    => "/tmp"

`copy-file` uses a "" argument via the `G` interactive code:

	case 'F':		/* Possibly nonexistent file name.  */
	  args[i] = read_file_name (Qnil, Qnil, Qnil, Qnil);
	  break;

	case 'G':		/* Possibly nonexistent file name,
				   default to directory alone.  */
	  args[i] = read_file_name (Qnil, Qnil, empty_unibyte_string, Qnil);
	  break;

IOW it uses `G` since otherwise hitting just RET would return the
`buffer-file-name` rather than the `default-directory`.

I propose the patch below.

        Stefan

diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 4a33d61afc..e12f7b1156 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -3027,8 +3027,13 @@ read-file-name-default
   (unless dir (setq dir (or default-directory "~/")))
   (unless (file-name-absolute-p dir) (setq dir (expand-file-name dir)))
   (unless default-filename
-    (setq default-filename (if initial (expand-file-name initial dir)
-                             buffer-file-name)))
+    (setq default-filename
+          (cond
+           ((null initial) buffer-file-name)
+           ;; Special-case "" because (expand-file-name "" "/tmp/") returns
+           ;; "/tmp" rather than "/tmp/" (bug#39057).
+           ((equal "" initial) dir)
+           (t (expand-file-name initial dir)))))
   ;; If dir starts with user's homedir, change that to ~.
   (setq dir (abbreviate-file-name dir))
   ;; Likewise for default-filename.