Subject: bug#28023: closed (Re: bug#28023: fix make-temp-file race on local host)

From: [email-masked] (GNU bug Tracking System)
Date: Sun, 13 Aug 2017 07:22:02 +0000

Your bug report

#28023: fix make-temp-file race on local host

which was filed against the emacs package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
28023: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=28023
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#28023: fix make-temp-file race on local host
From: Paul Eggert <[email-masked]>
To: Michael Albinus <[email-masked]>
Cc: [email-masked]
Date: Sun, 13 Aug 2017 00:21:03 -0700
List-Id: <debbugs-submit.debbugs.gnu.org>

Michael Albinus wrote:
> Paul Eggert<[email-masked]>  writes:
> 
>> Tramp needs to support a new method make-temp-file that creates a file
>> (or directory) atomically, as make-temp-file does locally now.
> That means, make-temp-file shall be converted into a magic file name
> operation. I'll do my best, but I don't know whether we could get an
> implementation for all Tramp methods w/o a race condition.
> 
>> Tramp also needs to support the excl flag of write-region (currently
>> it ignores that flag).
> This sounds trivial. And yes, it will help.

Thanks for doing that. Because of that, I'm no longer seeing a race in 
make-temp-file, even for Tramp files. That is, although my proposed patch is 
still a performance win on local files, I don't see how it is a correctness win 
any more. It's still worth installing for the performance reasons, though, so I 
did that and I am marking this bug as done.

>> I was planning to write this up as a bug report after the patch goes
>> in.
> Pls do.

To some extent this is moot now, if I understand things correctly. That is, the 
only reason to write this up now would be for performance reasons, not a race 
condition.

There is still a race involving destination directories, for both Tramp and 
non-Tramp versions. I plan to take a look at that next.

Subject: fix make-temp-file race on local host
From: Paul Eggert <[email-masked]>
To: Emacs bug reports and feature requests <[email-masked]>
Date: Tue, 8 Aug 2017 22:38:05 -0700
List-Id: <debbugs-submit.debbugs.gnu.org>

Tags: patch
Severity: important

I plan to install the attached patch in master soon, and am sending it for 
review to bug-gnu-emacs first in case there's some problem with it on 
MS-Windows. Although this patch does not fix all instances of the race in Gnu 
Emacs (notably, Tramp access is still affected) it's a good start.
From 0f536834ae618adc38883fc331f75a2847a8411c Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Tue, 8 Aug 2017 22:22:48 -0700
Subject: [PATCH] Fix make-temp-file race on local files

For the motivation behind this patch, please see:
http://emacshorrors.com/posts/make-temp-name.html
The race still exists for magic file names;
fixing this will require Tramp surgery.
* admin/merge-gnulib (GNULIB_MODULES): Add tempname, now
that Emacs is using it directly.
* configure.ac (AUTO_DEPEND): Remove AC_SYS_LONG_FILE_NAMES;
no longer needed.
* lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate.
* lisp/files.el (files--make-magic-temp-file): Rename from
make-temp-file.  Add comment describing race bug.
(make-temp-file): Use fileio--make-temp-file for
non-magic files names.
* src/fileio.c: Include tempname.h.
(make_temp_name_tbl, make_temp_name_count)
(make_temp_name_count_initialized_p, make_temp_name): Remove.
(Ffileio__make_temp_file): New function.
(Fmake_temp_name): Use it.
* src/filelock.c (get_boot_time): Use Ffileio__make_temp_file
instead of make_temp_name; this avoids a race.
---
 admin/CPP-DEFINES  |   1 -
 admin/merge-gnulib |   4 +-
 configure.ac       |   3 -
 lib/gnulib.mk.in   |   8 +--
 lisp/files.el      |  15 +++++
 m4/gnulib-comp.m4  |  34 +++--------
 src/buffer.c       |   1 -
 src/fileio.c       | 170 ++++++++++++++---------------------------------------
 src/filelock.c     |  11 ++--
 src/lisp.h         |   1 -
 10 files changed, 75 insertions(+), 173 deletions(-)

diff --git a/admin/CPP-DEFINES b/admin/CPP-DEFINES
index cead305aee..10b558d1ad 100644
--- a/admin/CPP-DEFINES
+++ b/admin/CPP-DEFINES
@@ -205,7 +205,6 @@ HAVE_LIBXML2
 HAVE_LIBXMU
 HAVE_LOCALTIME_R
 HAVE_LOCAL_SOCKETS
-HAVE_LONG_FILE_NAMES
 HAVE_LONG_LONG_INT
 HAVE_LRAND48
 HAVE_LSTAT
diff --git a/admin/merge-gnulib b/admin/merge-gnulib
index c23e8a40ea..c7a7a1d7c9 100755
--- a/admin/merge-gnulib
+++ b/admin/merge-gnulib
@@ -39,8 +39,8 @@ GNULIB_MODULES=
   manywarnings memrchr minmax mkostemp mktime nstrftime
   pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat
   sig2str socklen stat-time std-gnu11 stdalign stddef stdio
-  stpcpy strtoimax symlink sys_stat
-  sys_time time time_r time_rz timegm timer-time timespec-add timespec-sub
+  stpcpy strtoimax symlink sys_stat sys_time
+  tempname time time_r time_rz timegm timer-time timespec-add timespec-sub
   update-copyright unlocked-io utimens
   vla warnings
 '
diff --git a/configure.ac b/configure.ac
index 9f80620a80..86d5b3e94f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1779,9 +1779,6 @@ AC_DEFUN
 fi
 AC_SUBST(AUTO_DEPEND)
 
-dnl checks for operating system services
-AC_SYS_LONG_FILE_NAMES
-
 #### Choose a window system.
 
 ## We leave window_system equal to none if
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in
index a385c8c838..8b34ee6354 100644
--- a/lib/gnulib.mk.in
+++ b/lib/gnulib.mk.in
@@ -21,7 +21,7 @@
 # the same distribution terms as the rest of that program.
 #
 # Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=setenv --avoid=sigprocmask --avoid=stat --avoid=stdarg --avoid=stdbool --avoid=threadlib --avoid=tzset --avoid=unsetenv --avoid=utime --avoid=utime-h --gnu-make --makefile-name=gnulib.mk.in --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-leading-zeros count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 d-type diffseq dtoastr dtotimespec dup2 environ execinfo explicit_bzero faccessat fcntl fcntl-h fdatasync fdopendir filemode filevercmp flexmember fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog ignore-value intprops largefile lstat manywarnings memrchr minmax mkostemp mktime nstrftime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time std-gnu11 stdalign stddef stdio stpcpy strtoimax symlink sys_stat sys_time time time_r time_rz timegm timer-time timespec-add timespec-sub unlocked-io update-copyright utimens vla warnings
+# Reproduce by: gnulib-tool --import --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=setenv --avoid=sigprocmask --avoid=stat --avoid=stdarg --avoid=stdbool --avoid=threadlib --avoid=tzset --avoid=unsetenv --avoid=utime --avoid=utime-h --gnu-make --makefile-name=gnulib.mk.in --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-leading-zeros count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 d-type diffseq dtoastr dtotimespec dup2 environ execinfo explicit_bzero faccessat fcntl fcntl-h fdatasync fdopendir filemode filevercmp flexmember fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog ignore-value intprops largefile lstat manywarnings memrchr minmax mkostemp mktime nstrftime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time std-gnu11 stdalign stddef stdio stpcpy strtoimax symlink sys_stat sys_time tempname time time_r time_rz timegm timer-time timespec-add timespec-sub unlocked-io update-copyright utimens vla warnings

 MOSTLYCLEANFILES += core *.stackdump
@@ -903,9 +903,7 @@ gl_GNULIB_ENABLED_dosname = @gl_GNULIB_ENABLED_dosname@
 gl_GNULIB_ENABLED_euidaccess = @gl_GNULIB_ENABLED_euidaccess@
 gl_GNULIB_ENABLED_getdtablesize = @gl_GNULIB_ENABLED_getdtablesize@
 gl_GNULIB_ENABLED_getgroups = @gl_GNULIB_ENABLED_getgroups@
-gl_GNULIB_ENABLED_secure_getenv = @gl_GNULIB_ENABLED_secure_getenv@
 gl_GNULIB_ENABLED_strtoll = @gl_GNULIB_ENABLED_strtoll@
-gl_GNULIB_ENABLED_tempname = @gl_GNULIB_ENABLED_tempname@
 gl_LIBOBJS = @gl_LIBOBJS@
 gl_LTLIBOBJS = @gl_LTLIBOBJS@
 gltests_LIBOBJS = @gltests_LIBOBJS@
@@ -1915,9 +1913,7 @@ endif
 ## begin gnulib module secure_getenv
 ifeq (,$(OMIT_GNULIB_MODULE_secure_getenv))
 
-ifneq (,$(gl_GNULIB_ENABLED_secure_getenv))
 
-endif
 EXTRA_DIST += secure_getenv.c
 
 EXTRA_libgnu_a_SOURCES += secure_getenv.c
@@ -2715,10 +2711,8 @@ endif
 ## begin gnulib module tempname
 ifeq (,$(OMIT_GNULIB_MODULE_tempname))
 
-ifneq (,$(gl_GNULIB_ENABLED_tempname))
 libgnu_a_SOURCES += tempname.c
 
-endif
 EXTRA_DIST += tempname.h
 
 endif
diff --git a/lisp/files.el b/lisp/files.el
index f2758ab18c..3ed36d24db 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -1417,6 +1417,19 @@ make-temp-file
 If DIR-FLAG is non-nil, create a new empty directory instead of a file.
 
 If SUFFIX is non-nil, add that at the end of the file name."
+  (let ((absolute-prefix (expand-file-name prefix temporary-file-directory)))
+    ;; FIXME: Establish make-temp-file file name handlers,
+    ;; to create temporary files and directories without races.
+    ;; For now, if the prefix is magic, fall back on the traditional,
+    ;; insecure way to create temporary files.
+    (if (find-file-name-handler absolute-prefix 'write-region)
+        (files--make-magic-temp-file prefix dir-flag suffix)
+      (fileio--make-temp-file absolute-prefix
+                              (if dir-flag t) (or suffix "")))))
+
+(defun files--make-magic-temp-file (prefix &optional dir-flag suffix)
+  "Implement (make-temp-file PREFIX DIR-FLAG SUFFIX),
+even if the result is a magic file name."
   ;; Create temp files with strict access rights.  It's easy to
   ;; loosen them later, whereas it's impossible to close the
   ;; time-window of loose permissions otherwise.
@@ -1435,6 +1448,8 @@ make-temp-file
 		       (setq file (concat file suffix)))
 		   (if dir-flag
 		       (make-directory file)
+                     ;; FIXME: The 'excl is only aspirational; it is
+                     ;; actually a no-op if FILE is a magic file name.
 		     (write-region "" nil file nil 'silent nil 'excl))
 		   nil)
 	       (file-already-exists t))
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
index 188c116c85..fc86237ee9 100644
--- a/m4/gnulib-comp.m4
+++ b/m4/gnulib-comp.m4
@@ -347,6 +347,12 @@ AC_DEFUN
     AC_LIBOBJ([readlinkat])
   fi
   gl_UNISTD_MODULE_INDICATOR([readlinkat])
+  gl_FUNC_SECURE_GETENV
+  if test $HAVE_SECURE_GETENV = 0; then
+    AC_LIBOBJ([secure_getenv])
+    gl_PREREQ_SECURE_GETENV
+  fi
+  gl_STDLIB_MODULE_INDICATOR([secure_getenv])
   gl_FUNC_SIG2STR
   if test $ac_cv_func_sig2str = no; then
     AC_LIBOBJ([sig2str])
@@ -388,6 +394,7 @@ AC_DEFUN
   AC_PROG_MKDIR_P
   gl_SYS_TYPES_H
   AC_PROG_MKDIR_P
+  gl_FUNC_GEN_TEMPNAME
   gl_HEADER_TIME_H
   gl_TIME_R
   if test $HAVE_LOCALTIME_R = 0 || test $REPLACE_LOCALTIME_R = 1; then
@@ -424,9 +431,7 @@ AC_DEFUN
   gl_gnulib_enabled_5264294aa0a5557541b53c8c741f7f31=false
   gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7=false
   gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=false
-  gl_gnulib_enabled_secure_getenv=false
   gl_gnulib_enabled_strtoll=false
-  gl_gnulib_enabled_tempname=false
   gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=false
   func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b ()
   {
@@ -550,18 +555,6 @@ AC_DEFUN
       gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=true
     fi
   }
-  func_gl_gnulib_m4code_secure_getenv ()
-  {
-    if ! $gl_gnulib_enabled_secure_getenv; then
-      gl_FUNC_SECURE_GETENV
-      if test $HAVE_SECURE_GETENV = 0; then
-        AC_LIBOBJ([secure_getenv])
-        gl_PREREQ_SECURE_GETENV
-      fi
-      gl_STDLIB_MODULE_INDICATOR([secure_getenv])
-      gl_gnulib_enabled_secure_getenv=true
-    fi
-  }
   func_gl_gnulib_m4code_strtoll ()
   {
     if ! $gl_gnulib_enabled_strtoll; then
@@ -574,14 +567,6 @@ AC_DEFUN
       gl_gnulib_enabled_strtoll=true
     fi
   }
-  func_gl_gnulib_m4code_tempname ()
-  {
-    if ! $gl_gnulib_enabled_tempname; then
-      gl_FUNC_GEN_TEMPNAME
-      gl_gnulib_enabled_tempname=true
-      func_gl_gnulib_m4code_secure_getenv
-    fi
-  }
   func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec ()
   {
     if ! $gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec; then
@@ -627,9 +612,6 @@ AC_DEFUN
   if test $REPLACE_LSTAT = 1; then
     func_gl_gnulib_m4code_dosname
   fi
-  if test $HAVE_MKOSTEMP = 0; then
-    func_gl_gnulib_m4code_tempname
-  fi
   if test $HAVE_READLINKAT = 0; then
     func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b
   fi
@@ -658,9 +640,7 @@ AC_DEFUN
   AM_CONDITIONAL([gl_GNULIB_ENABLED_5264294aa0a5557541b53c8c741f7f31], [$gl_gnulib_enabled_5264294aa0a5557541b53c8c741f7f31])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_03e0aaad4cb89ca757653bd367a6ccb7], [$gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c], [$gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c])
-  AM_CONDITIONAL([gl_GNULIB_ENABLED_secure_getenv], [$gl_gnulib_enabled_secure_getenv])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoll], [$gl_gnulib_enabled_strtoll])
-  AM_CONDITIONAL([gl_GNULIB_ENABLED_tempname], [$gl_gnulib_enabled_tempname])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec], [$gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec])
   # End of code from modules
   m4_ifval(gl_LIBSOURCES_LIST, [
diff --git a/src/buffer.c b/src/buffer.c
index 0d0f43e937..2d508f35cf 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1085,7 +1085,6 @@ is first appended to NAME, to speed up finding a non-existent buffer.  */)
     genbase = name;
   else
     {
-      /* Note fileio.c:make_temp_name does random differently.  */
       char number[sizeof "-999999"];
       int i = XFASTINT (Frandom (make_number (999999)));
       AUTO_STRING_WITH_LEN (lnumber, number, sprintf (number, "-%d", i));
diff --git a/src/fileio.c b/src/fileio.c
index 15845e3914..1ef9bfa82b 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -97,6 +97,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <allocator.h>
 #include <careadlinkat.h>
 #include <stat-time.h>
+#include <tempname.h>
 
 #include <binary-io.h>
 
@@ -623,149 +624,67 @@ In Unix-syntax, this function just removes the final slash.  */)
   return val;
 }
 
-static const char make_temp_name_tbl[64] =
-{
-  'A','B','C','D','E','F','G','H',
-  'I','J','K','L','M','N','O','P',
-  'Q','R','S','T','U','V','W','X',
-  'Y','Z','a','b','c','d','e','f',
-  'g','h','i','j','k','l','m','n',
-  'o','p','q','r','s','t','u','v',
-  'w','x','y','z','0','1','2','3',
-  '4','5','6','7','8','9','-','_'
-};
-
-static unsigned make_temp_name_count, make_temp_name_count_initialized_p;
-
-/* Value is a temporary file name starting with PREFIX, a string.
+DEFUN ("fileio--make-temp-file", Ffileio__make_temp_file,
+       Sfileio__make_temp_file, 3, 3, 0,
+       doc: /* Generate a new file whose name starts with PREFIX, a string.
+Return the name of the generated file.  If DIR-FLAG is zero, do not
+create the file, just its name.  Otherwise, if DIR-FLAG is non-nil,
+create an empty directory.  The file name should end in SUFFIX.
 
-   The Emacs process number forms part of the result, so there is
-   no danger of generating a name being used by another process.
-   In addition, this function makes an attempt to choose a name
-   which has no existing file.  To make this work, PREFIX should be
-   an absolute file name.
+Signal an error if the file could not be created.
 
-   BASE64_P means add the pid as 3 characters in base64
-   encoding.  In this case, 6 characters will be added to PREFIX to
-   form the file name.  Otherwise, if Emacs is running on a system
-   with long file names, add the pid as a decimal number.
-
-   This function signals an error if no unique file name could be
-   generated.  */
-
-Lisp_Object
-make_temp_name (Lisp_Object prefix, bool base64_p)
+This function does not grok magic file names.  */)
+  (Lisp_Object prefix, Lisp_Object dir_flag, Lisp_Object suffix)
 {
-  Lisp_Object val, encoded_prefix;
-  ptrdiff_t len;
-  printmax_t pid;
-  char *p, *data;
-  char pidbuf[INT_BUFSIZE_BOUND (printmax_t)];
-  int pidlen;
-
-  CHECK_STRING (prefix);
-
-  /* VAL is created by adding 6 characters to PREFIX.  The first
-     three are the PID of this process, in base 64, and the second
-     three are incremented if the file already exists.  This ensures
-     262144 unique file names per PID per PREFIX.  */
-
-  pid = getpid ();
-
-  if (base64_p)
-    {
-      pidbuf[0] = make_temp_name_tbl[pid & 63], pid >>= 6;
-      pidbuf[1] = make_temp_name_tbl[pid & 63], pid >>= 6;
-      pidbuf[2] = make_temp_name_tbl[pid & 63], pid >>= 6;
-      pidlen = 3;
-    }
-  else
+  bool make_temp_name = EQ (dir_flag, make_number (0));
+  CHECK_STRING (suffix);
+  if (!make_temp_name)
+    prefix = Fexpand_file_name (prefix, Vtemporary_file_directory);
+
+  Lisp_Object encoded_prefix = ENCODE_FILE (prefix);
+  Lisp_Object encoded_suffix = ENCODE_FILE (suffix);
+  ptrdiff_t prefix_len = SBYTES (encoded_prefix);
+  ptrdiff_t suffix_len = SBYTES (encoded_suffix);
+  if (INT_MAX < suffix_len)
+    args_out_of_range (prefix, suffix);
+  int nX = 6;
+  Lisp_Object val = make_uninit_string (prefix_len + nX + suffix_len);
+  char *data = SSDATA (val);
+  memcpy (data, SSDATA (encoded_prefix), prefix_len);
+  memset (data + prefix_len, 'X', nX);
+  memcpy (data + prefix_len + nX, SSDATA (encoded_suffix), suffix_len);
+  int kind = (NILP (dir_flag) ? GT_FILE
+	      : make_temp_name ? GT_NOCREATE
+	      : GT_DIR);
+  int fd = gen_tempname (data, suffix_len, O_BINARY | O_CLOEXEC, kind);
+  if (fd < 0 || (NILP (dir_flag) && emacs_close (fd) != 0))
     {
-#ifdef HAVE_LONG_FILE_NAMES
-      pidlen = sprintf (pidbuf, "%"pMd, pid);
-#else
-      pidbuf[0] = make_temp_name_tbl[pid & 63], pid >>= 6;
-      pidbuf[1] = make_temp_name_tbl[pid & 63], pid >>= 6;
-      pidbuf[2] = make_temp_name_tbl[pid & 63], pid >>= 6;
-      pidlen = 3;
-#endif
-    }
-
-  encoded_prefix = ENCODE_FILE (prefix);
-  len = SBYTES (encoded_prefix);
-  val = make_uninit_string (len + 3 + pidlen);
-  data = SSDATA (val);
-  memcpy (data, SSDATA (encoded_prefix), len);
-  p = data + len;
-
-  memcpy (p, pidbuf, pidlen);
-  p += pidlen;
-
-  /* Here we try to minimize useless stat'ing when this function is
-     invoked many times successively with the same PREFIX.  We achieve
-     this by initializing count to a random value, and incrementing it
-     afterwards.
-
-     We don't want make-temp-name to be called while dumping,
-     because then make_temp_name_count_initialized_p would get set
-     and then make_temp_name_count would not be set when Emacs starts.  */
-
-  if (!make_temp_name_count_initialized_p)
-    {
-      make_temp_name_count = time (NULL);
-      make_temp_name_count_initialized_p = 1;
-    }
-
-  while (1)
-    {
-      unsigned num = make_temp_name_count;
-
-      p[0] = make_temp_name_tbl[num & 63], num >>= 6;
-      p[1] = make_temp_name_tbl[num & 63], num >>= 6;
-      p[2] = make_temp_name_tbl[num & 63], num >>= 6;
-
-      /* Poor man's congruential RN generator.  Replace with
-         ++make_temp_name_count for debugging.  */
-      make_temp_name_count += 25229;
-      make_temp_name_count %= 225307;
-
-      if (!check_existing (data))
+      static char const kind_message[][32] =
 	{
-	  /* We want to return only if errno is ENOENT.  */
-	  if (errno == ENOENT)
-	    return DECODE_FILE (val);
-	  else
-	    /* The error here is dubious, but there is little else we
-	       can do.  The alternatives are to return nil, which is
-	       as bad as (and in many cases worse than) throwing the
-	       error, or to ignore the error, which will likely result
-	       in looping through 225307 stat's, which is not only
-	       dog-slow, but also useless since eventually nil would
-	       have to be returned anyway.  */
-	    report_file_error ("Cannot create temporary name for prefix",
-			       prefix);
-	  /* not reached */
-	}
+	  [GT_FILE] = "Creating file with prefix",
+	  [GT_DIR] = "Creating directory with prefix",
+	  [GT_NOCREATE] = "Creating file name with prefix"
+	};
+      report_file_error (kind_message[kind], prefix);
     }
+  return DECODE_FILE (val);
 }

 DEFUN ("make-temp-name", Fmake_temp_name, Smake_temp_name, 1, 1, 0,
        doc: /* Generate temporary file name (string) starting with PREFIX (a string).
-The Emacs process number forms part of the result, so there is no
-danger of generating a name being used by another Emacs process
-\(so long as only a single host can access the containing directory...).
 
 This function tries to choose a name that has no existing file.
 For this to work, PREFIX should be an absolute file name, and PREFIX
 and the returned string should both be non-magic.
 
-There is a race condition between calling `make-temp-name' and creating the
-file, which opens all kinds of security holes.  For that reason, you should
-normally use `make-temp-file' instead.  */)
+There is a race condition between calling `make-temp-name' and
+later creating the file, which opens all kinds of security holes.
+For that reason, you should normally use `make-temp-file' instead.  */)
   (Lisp_Object prefix)
 {
-  return make_temp_name (prefix, 0);
+  return Ffileio__make_temp_file (prefix, make_number (0),
+				  empty_unibyte_string);
 }
 
 DEFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
@@ -6167,6 +6086,7 @@ This includes interactive calls to `delete-file' and
   defsubr (&Sunhandled_file_name_directory);
   defsubr (&Sfile_name_as_directory);
   defsubr (&Sdirectory_file_name);
+  defsubr (&Sfileio__make_temp_file);
   defsubr (&Smake_temp_name);
   defsubr (&Sexpand_file_name);
   defsubr (&Ssubstitute_in_file_name);
diff --git a/src/filelock.c b/src/filelock.c
index dd8cb28c42..de0ca01052 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -206,14 +206,13 @@ get_boot_time (void)
 					    WTMP_FILE, counter);
 	  if (! NILP (Ffile_exists_p (tempname)))
 	    {
-	      /* The utmp functions on mescaline.gnu.org accept only
-		 file names up to 8 characters long.  Choose a 2
-		 character long prefix, and call make_temp_file with
-		 second arg non-zero, so that it will add not more
-		 than 6 characters to the prefix.  */
+	      /* The utmp functions on older systems accept only file
+		 names up to 8 bytes long.  Choose a 2 byte prefix, so
+		 the 6-byte suffix does not make the name too long.  */
 	      filename = Fexpand_file_name (build_string ("wt"),
 					    Vtemporary_file_directory);
-	      filename = make_temp_name (filename, 1);
+	      filename = Ffileio__make_temp_file (filename, Qnil,
+						  empty_unibyte_string);
 	      CALLN (Fcall_process, build_string ("gzip"), Qnil,
 		     list2 (QCfile, filename), Qnil,
 		     build_string ("-cd"), tempname);
diff --git a/src/lisp.h b/src/lisp.h
index 4de6fc85ec..a65cc9684a 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4013,7 +4013,6 @@ extern bool file_directory_p (const char *);
 extern bool file_accessible_directory_p (Lisp_Object);
 extern void init_fileio (void);
 extern void syms_of_fileio (void);
-extern Lisp_Object make_temp_name (Lisp_Object, bool);
 
 /* Defined in search.c.  */
 extern void shrink_regexp_cache (void);
-- 
2.13.3