Subject: Re: bug#57129: 29.0.50; Improve behavior of conditionals in Eshell

From: Paul Eggert <[email-masked]>
Date: Mon, 15 Aug 2022 13:55:35 -0700

On 8/15/22 11:58, Eli Zaretskii wrote:

> Ah, okay.  It's a (mis)feature of Gnulib's gen_tempname function
> (which is the guts of make-temp-file) in its implementation for
> MS-Windows (and maybe other platforms?): it always begins from the
> same "random" characters in the file name, and only generates other
> random characters if there's already a file by that name.

Not sure I'd call it a misfeature, as gen_tempname is generating a 
uniquely-named file that is exclusive to Emacs, which is all it's 
supposed to do.

I do see a comment saying that gen_tempname generates "hard-to-predict" 
names, which as you note is not correct on MS-DOS, nor even strictly 
speaking on all POSIX platforms. I installed the first attached patch 
into Gnulib to fix that comment.

I'm not sure I'm entirely understanding the Emacs problem, but it 
appears to be that Emacs has its own set of filenames that it thinks it 
knows about, and Emacs wants the new temporary file's name to not be a 
member of that set. If I'm right, does the second attached patch (this 
patch is to Emacs) address the problem? I haven't tested or installed it.

From a7ef21bf347da5e3a8b5492b849d633ef3252d62 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Mon, 15 Aug 2022 13:04:08 -0700
Subject: [PATCH] tempname: remove incorrect comment

* lib/tempname.c, lib/tempname.h: Remove incorrect comment,
as the names are not necessarily hard to predict (Bug#57129).
---
 ChangeLog      | 6 ++++++
 lib/tempname.c | 2 +-
 lib/tempname.h | 2 +-
 3 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index ba16b538f5..1e20db7e37 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2022-08-15  Paul Eggert  <[email-masked]>
+
+	tempname: remove incorrect comment
+	* lib/tempname.c, lib/tempname.h: Remove incorrect comment,
+	as the names are not necessarily hard to predict (Bug#57129).
+
 2022-08-14  Simon Josefsson  <[email-masked]>
 
 	bootstrap.conf: Use proper shell marker for Emacs.
diff --git a/lib/tempname.c b/lib/tempname.c
index 5fc5efe031..75a939e571 100644
--- a/lib/tempname.c
+++ b/lib/tempname.c
@@ -213,7 +213,7 @@ static const char letters[] =
                         and return a read-write fd.  The file is mode 0600.
    __GT_DIR:            create a directory, which will be mode 0700.
 
-   We use a clever algorithm to get hard-to-predict names. */
+   */
 #ifdef _LIBC
 static
 #endif
diff --git a/lib/tempname.h b/lib/tempname.h
index c172820f7f..5e3c5e1550 100644
--- a/lib/tempname.h
+++ b/lib/tempname.h
@@ -48,7 +48,7 @@ extern "C" {
                         and return a read-write fd.  The file is mode 0600.
    GT_DIR:              create a directory, which will be mode 0700.
 
-   We use a clever algorithm to get hard-to-predict names. */
+   */
 extern int gen_tempname (char *tmpl, int suffixlen, int flags, int kind);
 /* Similar, except X_SUFFIX_LEN gives the number of Xs.  */
 extern int gen_tempname_len (char *tmpl, int suffixlen, int flags, int kind,
-- 
2.34.1

From a0776984bc3630c8c0bd57b3fd1acca1f0b8cb5c Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Mon, 15 Aug 2022 12:55:40 -0700
Subject: [PATCH] =?UTF-8?q?Don=E2=80=99t=20create=20temp=20file=20with=20s?=
 =?UTF-8?q?ame=20name=20as=20visited?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Problem reported by Jim Porter (Bug#57129#47).
* src/fileio.c (create_tempname): New function.
(Fmake_temp_file_internal): Use it.
---
 src/fileio.c | 29 +++++++++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/src/fileio.c b/src/fileio.c
index 9697f6c8cf..4f134bbfa9 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -677,6 +677,27 @@ DEFUN ("directory-file-name", Fdirectory_file_name, Sdirectory_file_name,
   return val;
 }
 
+/* Create a temporary file whose encoded name is ENCODED_FILENAME, and
+   whose decoded name is *(Lisp_Object *) FLAGS.  Pretend the file
+   already exists if a live buffer is visiting it.  Return a file
+   descriptor if successful, -1 (setting errno) otherwise.  */
+static int
+create_tempname (char *encoded_filename, void *flags)
+{
+  Lisp_Object *addval = flags;
+  Lisp_Object filename = *addval;
+
+  if (!NILP (Fget_file_buffer (filename)))
+    {
+      errno = EEXIST;
+      return -1;
+    }
+
+  return open (encoded_filename,
+	       O_RDWR | O_BINARY | O_CLOEXEC | O_CREAT | O_EXCL,
+	       S_IRUSR | S_IWUSR);
+}
+
 DEFUN ("make-temp-file-internal", Fmake_temp_file_internal,
        Smake_temp_file_internal, 4, 4, 0,
        doc: /* Generate a new file whose name starts with PREFIX, a string.
@@ -707,18 +728,18 @@ DEFUN ("make-temp-file-internal", Fmake_temp_file_internal,
   memcpy (data, SSDATA (encoded_prefix), prefix_len);
   memset (data + prefix_len, 'X', nX);
   memcpy (data + prefix_len + nX, SSDATA (encoded_suffix), suffix_len);
+  Lisp_Object dval = DECODE_FILE (val), ddval = dval;
   int kind = (NILP (dir_flag) ? GT_FILE
 	      : BASE_EQ (dir_flag, make_fixnum (0)) ? GT_NOCREATE
 	      : GT_DIR);
-  int fd = gen_tempname (data, suffix_len, O_BINARY | O_CLOEXEC, kind);
+  int fd = try_tempname (data, suffix_len, &ddval, create_tempname);
   bool failed = fd < 0;
   if (!failed)
     {
       specpdl_ref count = SPECPDL_INDEX ();
       record_unwind_protect_int (close_file_unwind, fd);
-      val = DECODE_FILE (val);
       if (STRINGP (text) && SBYTES (text) != 0)
-	write_region (text, Qnil, val, Qnil, Qnil, Qnil, Qnil, fd);
+	write_region (text, Qnil, dval, Qnil, Qnil, Qnil, Qnil, fd);
       failed = NILP (dir_flag) && emacs_close (fd) != 0;
       /* Discard the unwind protect.  */
       specpdl_ptr = specpdl_ref_to_ptr (count);
@@ -733,7 +754,7 @@ DEFUN ("make-temp-file-internal", Fmake_temp_file_internal,
 	};
       report_file_error (kind_message[kind], prefix);
     }
-  return val;
+  return dval;
 }

-- 
2.37.1