diff options
| author | Paul Eggert | 2017-08-12 14:00:17 -0700 |
|---|---|---|
| committer | Paul Eggert | 2017-08-12 15:14:45 -0700 |
| commit | a6ad98ad66e1d0c0dac5f25ba91e11d0cf9da725 (patch) | |
| tree | 183748df6a5b71f1b48deecc824eef27939ff2f8 | |
| parent | 9eb30cb03613ae158c870d603a05a6a6393dc485 (diff) | |
| download | emacs-a6ad98ad66e1d0c0dac5f25ba91e11d0cf9da725.tar.gz emacs-a6ad98ad66e1d0c0dac5f25ba91e11d0cf9da725.zip | |
Improve make-temp-file performance on local files
For the motivation behind this patch, please see Bug#28023 and:
http://emacshorrors.com/posts/make-temp-name.html
Although, given the recent changes to Tramp, the related security
problem in make-temp-file is already fixed, make-temp-file still has
several unnecessary system calls. In the typical case on GNU/Linux,
this patch replaces 8 syscalls (symlink, open, close, readlinkat, uname,
getpid, unlink, umask) by 2 (open, close).
* 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.
(make-temp-file): Use make-temp-file-internal for
non-magic file 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.
(Fmake_temp_file_internal): New function.
(Fmake_temp_name): Use it.
* src/filelock.c (get_boot_time): Use Fmake_temp_file_internal
instead of make_temp_name.
| -rw-r--r-- | admin/CPP-DEFINES | 1 | ||||
| -rwxr-xr-x | admin/merge-gnulib | 4 | ||||
| -rw-r--r-- | configure.ac | 3 | ||||
| -rw-r--r-- | lib/gnulib.mk.in | 5 | ||||
| -rw-r--r-- | lisp/files.el | 9 | ||||
| -rw-r--r-- | m4/gnulib-comp.m4 | 13 | ||||
| -rw-r--r-- | src/buffer.c | 1 | ||||
| -rw-r--r-- | src/fileio.c | 170 | ||||
| -rw-r--r-- | src/filelock.c | 13 | ||||
| -rw-r--r-- | src/lisp.h | 1 |
10 files changed, 63 insertions, 157 deletions
diff --git a/admin/CPP-DEFINES b/admin/CPP-DEFINES index cead305aee1..10b558d1ada 100644 --- a/admin/CPP-DEFINES +++ b/admin/CPP-DEFINES | |||
| @@ -205,7 +205,6 @@ HAVE_LIBXML2 | |||
| 205 | HAVE_LIBXMU | 205 | HAVE_LIBXMU |
| 206 | HAVE_LOCALTIME_R | 206 | HAVE_LOCALTIME_R |
| 207 | HAVE_LOCAL_SOCKETS | 207 | HAVE_LOCAL_SOCKETS |
| 208 | HAVE_LONG_FILE_NAMES | ||
| 209 | HAVE_LONG_LONG_INT | 208 | HAVE_LONG_LONG_INT |
| 210 | HAVE_LRAND48 | 209 | HAVE_LRAND48 |
| 211 | HAVE_LSTAT | 210 | HAVE_LSTAT |
diff --git a/admin/merge-gnulib b/admin/merge-gnulib index a16d7fa53ea..7eca64305de 100755 --- a/admin/merge-gnulib +++ b/admin/merge-gnulib | |||
| @@ -39,8 +39,8 @@ GNULIB_MODULES=' | |||
| 39 | manywarnings memrchr minmax mkostemp mktime nstrftime | 39 | manywarnings memrchr minmax mkostemp mktime nstrftime |
| 40 | pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat | 40 | pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat |
| 41 | sig2str socklen stat-time std-gnu11 stdalign stddef stdio | 41 | sig2str socklen stat-time std-gnu11 stdalign stddef stdio |
| 42 | stpcpy strtoimax symlink sys_stat | 42 | stpcpy strtoimax symlink sys_stat sys_time |
| 43 | sys_time time time_r time_rz timegm timer-time timespec-add timespec-sub | 43 | tempname time time_r time_rz timegm timer-time timespec-add timespec-sub |
| 44 | update-copyright unlocked-io utimens | 44 | update-copyright unlocked-io utimens |
| 45 | vla warnings | 45 | vla warnings |
| 46 | ' | 46 | ' |
diff --git a/configure.ac b/configure.ac index 9f80620a807..86d5b3e94f9 100644 --- a/configure.ac +++ b/configure.ac | |||
| @@ -1779,9 +1779,6 @@ if test "$GCC" = yes && test "$ac_enable_autodepend" = yes; then | |||
| 1779 | fi | 1779 | fi |
| 1780 | AC_SUBST(AUTO_DEPEND) | 1780 | AC_SUBST(AUTO_DEPEND) |
| 1781 | 1781 | ||
| 1782 | dnl checks for operating system services | ||
| 1783 | AC_SYS_LONG_FILE_NAMES | ||
| 1784 | |||
| 1785 | #### Choose a window system. | 1782 | #### Choose a window system. |
| 1786 | 1783 | ||
| 1787 | ## We leave window_system equal to none if | 1784 | ## We leave window_system equal to none if |
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index c5df3f42e47..30986b4ed7f 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | # the same distribution terms as the rest of that program. | 21 | # the same distribution terms as the rest of that program. |
| 22 | # | 22 | # |
| 23 | # Generated by gnulib-tool. | 23 | # Generated by gnulib-tool. |
| 24 | # 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 | 24 | # 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 |
| 25 | 25 | ||
| 26 | 26 | ||
| 27 | MOSTLYCLEANFILES += core *.stackdump | 27 | MOSTLYCLEANFILES += core *.stackdump |
| @@ -904,7 +904,6 @@ gl_GNULIB_ENABLED_euidaccess = @gl_GNULIB_ENABLED_euidaccess@ | |||
| 904 | gl_GNULIB_ENABLED_getdtablesize = @gl_GNULIB_ENABLED_getdtablesize@ | 904 | gl_GNULIB_ENABLED_getdtablesize = @gl_GNULIB_ENABLED_getdtablesize@ |
| 905 | gl_GNULIB_ENABLED_getgroups = @gl_GNULIB_ENABLED_getgroups@ | 905 | gl_GNULIB_ENABLED_getgroups = @gl_GNULIB_ENABLED_getgroups@ |
| 906 | gl_GNULIB_ENABLED_strtoll = @gl_GNULIB_ENABLED_strtoll@ | 906 | gl_GNULIB_ENABLED_strtoll = @gl_GNULIB_ENABLED_strtoll@ |
| 907 | gl_GNULIB_ENABLED_tempname = @gl_GNULIB_ENABLED_tempname@ | ||
| 908 | gl_LIBOBJS = @gl_LIBOBJS@ | 907 | gl_LIBOBJS = @gl_LIBOBJS@ |
| 909 | gl_LTLIBOBJS = @gl_LTLIBOBJS@ | 908 | gl_LTLIBOBJS = @gl_LTLIBOBJS@ |
| 910 | gltests_LIBOBJS = @gltests_LIBOBJS@ | 909 | gltests_LIBOBJS = @gltests_LIBOBJS@ |
| @@ -2701,10 +2700,8 @@ endif | |||
| 2701 | ## begin gnulib module tempname | 2700 | ## begin gnulib module tempname |
| 2702 | ifeq (,$(OMIT_GNULIB_MODULE_tempname)) | 2701 | ifeq (,$(OMIT_GNULIB_MODULE_tempname)) |
| 2703 | 2702 | ||
| 2704 | ifneq (,$(gl_GNULIB_ENABLED_tempname)) | ||
| 2705 | libgnu_a_SOURCES += tempname.c | 2703 | libgnu_a_SOURCES += tempname.c |
| 2706 | 2704 | ||
| 2707 | endif | ||
| 2708 | EXTRA_DIST += tempname.h | 2705 | EXTRA_DIST += tempname.h |
| 2709 | 2706 | ||
| 2710 | endif | 2707 | endif |
diff --git a/lisp/files.el b/lisp/files.el index 0fe7f9c522a..19573cdf7b2 100644 --- a/lisp/files.el +++ b/lisp/files.el | |||
| @@ -1407,6 +1407,15 @@ You can then use `write-region' to write new data into the file. | |||
| 1407 | If DIR-FLAG is non-nil, create a new empty directory instead of a file. | 1407 | If DIR-FLAG is non-nil, create a new empty directory instead of a file. |
| 1408 | 1408 | ||
| 1409 | If SUFFIX is non-nil, add that at the end of the file name." | 1409 | If SUFFIX is non-nil, add that at the end of the file name." |
| 1410 | (let ((absolute-prefix (expand-file-name prefix temporary-file-directory))) | ||
| 1411 | (if (find-file-name-handler absolute-prefix 'write-region) | ||
| 1412 | (files--make-magic-temp-file prefix dir-flag suffix) | ||
| 1413 | (make-temp-file-internal absolute-prefix | ||
| 1414 | (if dir-flag t) (or suffix ""))))) | ||
| 1415 | |||
| 1416 | (defun files--make-magic-temp-file (prefix &optional dir-flag suffix) | ||
| 1417 | "Implement (make-temp-file PREFIX DIR-FLAG SUFFIX). | ||
| 1418 | This implementation works on magic file names." | ||
| 1410 | ;; Create temp files with strict access rights. It's easy to | 1419 | ;; Create temp files with strict access rights. It's easy to |
| 1411 | ;; loosen them later, whereas it's impossible to close the | 1420 | ;; loosen them later, whereas it's impossible to close the |
| 1412 | ;; time-window of loose permissions otherwise. | 1421 | ;; time-window of loose permissions otherwise. |
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index 69d77229bf7..d1089860e19 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 | |||
| @@ -387,6 +387,7 @@ AC_DEFUN([gl_INIT], | |||
| 387 | AC_PROG_MKDIR_P | 387 | AC_PROG_MKDIR_P |
| 388 | gl_SYS_TYPES_H | 388 | gl_SYS_TYPES_H |
| 389 | AC_PROG_MKDIR_P | 389 | AC_PROG_MKDIR_P |
| 390 | gl_FUNC_GEN_TEMPNAME | ||
| 390 | gl_HEADER_TIME_H | 391 | gl_HEADER_TIME_H |
| 391 | gl_TIME_R | 392 | gl_TIME_R |
| 392 | if test $HAVE_LOCALTIME_R = 0 || test $REPLACE_LOCALTIME_R = 1; then | 393 | if test $HAVE_LOCALTIME_R = 0 || test $REPLACE_LOCALTIME_R = 1; then |
| @@ -424,7 +425,6 @@ AC_DEFUN([gl_INIT], | |||
| 424 | gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7=false | 425 | gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7=false |
| 425 | gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=false | 426 | gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=false |
| 426 | gl_gnulib_enabled_strtoll=false | 427 | gl_gnulib_enabled_strtoll=false |
| 427 | gl_gnulib_enabled_tempname=false | ||
| 428 | gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=false | 428 | gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=false |
| 429 | func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b () | 429 | func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b () |
| 430 | { | 430 | { |
| @@ -560,13 +560,6 @@ AC_DEFUN([gl_INIT], | |||
| 560 | gl_gnulib_enabled_strtoll=true | 560 | gl_gnulib_enabled_strtoll=true |
| 561 | fi | 561 | fi |
| 562 | } | 562 | } |
| 563 | func_gl_gnulib_m4code_tempname () | ||
| 564 | { | ||
| 565 | if ! $gl_gnulib_enabled_tempname; then | ||
| 566 | gl_FUNC_GEN_TEMPNAME | ||
| 567 | gl_gnulib_enabled_tempname=true | ||
| 568 | fi | ||
| 569 | } | ||
| 570 | func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec () | 563 | func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec () |
| 571 | { | 564 | { |
| 572 | if ! $gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec; then | 565 | if ! $gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec; then |
| @@ -612,9 +605,6 @@ AC_DEFUN([gl_INIT], | |||
| 612 | if test $REPLACE_LSTAT = 1; then | 605 | if test $REPLACE_LSTAT = 1; then |
| 613 | func_gl_gnulib_m4code_dosname | 606 | func_gl_gnulib_m4code_dosname |
| 614 | fi | 607 | fi |
| 615 | if test $HAVE_MKOSTEMP = 0; then | ||
| 616 | func_gl_gnulib_m4code_tempname | ||
| 617 | fi | ||
| 618 | if test $HAVE_READLINKAT = 0; then | 608 | if test $HAVE_READLINKAT = 0; then |
| 619 | func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b | 609 | func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b |
| 620 | fi | 610 | fi |
| @@ -644,7 +634,6 @@ AC_DEFUN([gl_INIT], | |||
| 644 | AM_CONDITIONAL([gl_GNULIB_ENABLED_03e0aaad4cb89ca757653bd367a6ccb7], [$gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7]) | 634 | AM_CONDITIONAL([gl_GNULIB_ENABLED_03e0aaad4cb89ca757653bd367a6ccb7], [$gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7]) |
| 645 | AM_CONDITIONAL([gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c], [$gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c]) | 635 | AM_CONDITIONAL([gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c], [$gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c]) |
| 646 | AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoll], [$gl_gnulib_enabled_strtoll]) | 636 | AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoll], [$gl_gnulib_enabled_strtoll]) |
| 647 | AM_CONDITIONAL([gl_GNULIB_ENABLED_tempname], [$gl_gnulib_enabled_tempname]) | ||
| 648 | AM_CONDITIONAL([gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec], [$gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec]) | 637 | AM_CONDITIONAL([gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec], [$gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec]) |
| 649 | # End of code from modules | 638 | # End of code from modules |
| 650 | m4_ifval(gl_LIBSOURCES_LIST, [ | 639 | m4_ifval(gl_LIBSOURCES_LIST, [ |
diff --git a/src/buffer.c b/src/buffer.c index 0d0f43e937b..2d508f35cf6 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. */) | |||
| 1085 | genbase = name; | 1085 | genbase = name; |
| 1086 | else | 1086 | else |
| 1087 | { | 1087 | { |
| 1088 | /* Note fileio.c:make_temp_name does random differently. */ | ||
| 1089 | char number[sizeof "-999999"]; | 1088 | char number[sizeof "-999999"]; |
| 1090 | int i = XFASTINT (Frandom (make_number (999999))); | 1089 | int i = XFASTINT (Frandom (make_number (999999))); |
| 1091 | AUTO_STRING_WITH_LEN (lnumber, number, sprintf (number, "-%d", i)); | 1090 | AUTO_STRING_WITH_LEN (lnumber, number, sprintf (number, "-%d", i)); |
diff --git a/src/fileio.c b/src/fileio.c index 31fd84512e1..b7e3b71a475 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/>. */ | |||
| 97 | #include <allocator.h> | 97 | #include <allocator.h> |
| 98 | #include <careadlinkat.h> | 98 | #include <careadlinkat.h> |
| 99 | #include <stat-time.h> | 99 | #include <stat-time.h> |
| 100 | #include <tempname.h> | ||
| 100 | 101 | ||
| 101 | #include <binary-io.h> | 102 | #include <binary-io.h> |
| 102 | 103 | ||
| @@ -655,149 +656,67 @@ In Unix-syntax, this function just removes the final slash. */) | |||
| 655 | return val; | 656 | return val; |
| 656 | } | 657 | } |
| 657 | 658 | ||
| 658 | static const char make_temp_name_tbl[64] = | 659 | DEFUN ("make-temp-file-internal", Fmake_temp_file_internal, |
| 659 | { | 660 | Smake_temp_file_internal, 3, 3, 0, |
| 660 | 'A','B','C','D','E','F','G','H', | 661 | doc: /* Generate a new file whose name starts with PREFIX, a string. |
| 661 | 'I','J','K','L','M','N','O','P', | 662 | Return the name of the generated file. If DIR-FLAG is zero, do not |
| 662 | 'Q','R','S','T','U','V','W','X', | 663 | create the file, just its name. Otherwise, if DIR-FLAG is non-nil, |
| 663 | 'Y','Z','a','b','c','d','e','f', | 664 | create an empty directory. The file name should end in SUFFIX. |
| 664 | 'g','h','i','j','k','l','m','n', | ||
| 665 | 'o','p','q','r','s','t','u','v', | ||
| 666 | 'w','x','y','z','0','1','2','3', | ||
| 667 | '4','5','6','7','8','9','-','_' | ||
| 668 | }; | ||
| 669 | |||
| 670 | static unsigned make_temp_name_count, make_temp_name_count_initialized_p; | ||
| 671 | |||
| 672 | /* Value is a temporary file name starting with PREFIX, a string. | ||
| 673 | 665 | ||
| 674 | The Emacs process number forms part of the result, so there is | 666 | Signal an error if the file could not be created. |
| 675 | no danger of generating a name being used by another process. | ||
| 676 | In addition, this function makes an attempt to choose a name | ||
| 677 | which has no existing file. To make this work, PREFIX should be | ||
| 678 | an absolute file name. | ||
| 679 | 667 | ||
| 680 | BASE64_P means add the pid as 3 characters in base64 | 668 | This function does not grok magic file names. */) |
| 681 | encoding. In this case, 6 characters will be added to PREFIX to | 669 | (Lisp_Object prefix, Lisp_Object dir_flag, Lisp_Object suffix) |
| 682 | form the file name. Otherwise, if Emacs is running on a system | ||
| 683 | with long file names, add the pid as a decimal number. | ||
| 684 | |||
| 685 | This function signals an error if no unique file name could be | ||
| 686 | generated. */ | ||
| 687 | |||
| 688 | Lisp_Object | ||
| 689 | make_temp_name (Lisp_Object prefix, bool base64_p) | ||
| 690 | { | 670 | { |
| 691 | Lisp_Object val, encoded_prefix; | 671 | bool make_temp_name = EQ (dir_flag, make_number (0)); |
| 692 | ptrdiff_t len; | 672 | CHECK_STRING (suffix); |
| 693 | printmax_t pid; | 673 | if (!make_temp_name) |
| 694 | char *p, *data; | 674 | prefix = Fexpand_file_name (prefix, Vtemporary_file_directory); |
| 695 | char pidbuf[INT_BUFSIZE_BOUND (printmax_t)]; | 675 | |
| 696 | int pidlen; | 676 | Lisp_Object encoded_prefix = ENCODE_FILE (prefix); |
| 697 | 677 | Lisp_Object encoded_suffix = ENCODE_FILE (suffix); | |
| 698 | CHECK_STRING (prefix); | 678 | ptrdiff_t prefix_len = SBYTES (encoded_prefix); |
| 699 | 679 | ptrdiff_t suffix_len = SBYTES (encoded_suffix); | |
| 700 | /* VAL is created by adding 6 characters to PREFIX. The first | 680 | if (INT_MAX < suffix_len) |
| 701 | three are the PID of this process, in base 64, and the second | 681 | args_out_of_range (prefix, suffix); |
| 702 | three are incremented if the file already exists. This ensures | 682 | int nX = 6; |
| 703 | 262144 unique file names per PID per PREFIX. */ | 683 | Lisp_Object val = make_uninit_string (prefix_len + nX + suffix_len); |
| 704 | 684 | char *data = SSDATA (val); | |
| 705 | pid = getpid (); | 685 | memcpy (data, SSDATA (encoded_prefix), prefix_len); |
| 706 | 686 | memset (data + prefix_len, 'X', nX); | |
| 707 | if (base64_p) | 687 | memcpy (data + prefix_len + nX, SSDATA (encoded_suffix), suffix_len); |
| 708 | { | 688 | int kind = (NILP (dir_flag) ? GT_FILE |
| 709 | pidbuf[0] = make_temp_name_tbl[pid & 63], pid >>= 6; | 689 | : make_temp_name ? GT_NOCREATE |
| 710 | pidbuf[1] = make_temp_name_tbl[pid & 63], pid >>= 6; | 690 | : GT_DIR); |
| 711 | pidbuf[2] = make_temp_name_tbl[pid & 63], pid >>= 6; | 691 | int fd = gen_tempname (data, suffix_len, O_BINARY | O_CLOEXEC, kind); |
| 712 | pidlen = 3; | 692 | if (fd < 0 || (NILP (dir_flag) && emacs_close (fd) != 0)) |
| 713 | } | ||
| 714 | else | ||
| 715 | { | 693 | { |
| 716 | #ifdef HAVE_LONG_FILE_NAMES | 694 | static char const kind_message[][32] = |
| 717 | pidlen = sprintf (pidbuf, "%"pMd, pid); | ||
| 718 | #else | ||
| 719 | pidbuf[0] = make_temp_name_tbl[pid & 63], pid >>= 6; | ||
| 720 | pidbuf[1] = make_temp_name_tbl[pid & 63], pid >>= 6; | ||
| 721 | pidbuf[2] = make_temp_name_tbl[pid & 63], pid >>= 6; | ||
| 722 | pidlen = 3; | ||
| 723 | #endif | ||
| 724 | } | ||
| 725 | |||
| 726 | encoded_prefix = ENCODE_FILE (prefix); | ||
| 727 | len = SBYTES (encoded_prefix); | ||
| 728 | val = make_uninit_string (len + 3 + pidlen); | ||
| 729 | data = SSDATA (val); | ||
| 730 | memcpy (data, SSDATA (encoded_prefix), len); | ||
| 731 | p = data + len; | ||
| 732 | |||
| 733 | memcpy (p, pidbuf, pidlen); | ||
| 734 | p += pidlen; | ||
| 735 | |||
| 736 | /* Here we try to minimize useless stat'ing when this function is | ||
| 737 | invoked many times successively with the same PREFIX. We achieve | ||
| 738 | this by initializing count to a random value, and incrementing it | ||
| 739 | afterwards. | ||
| 740 | |||
| 741 | We don't want make-temp-name to be called while dumping, | ||
| 742 | because then make_temp_name_count_initialized_p would get set | ||
| 743 | and then make_temp_name_count would not be set when Emacs starts. */ | ||
| 744 | |||
| 745 | if (!make_temp_name_count_initialized_p) | ||
| 746 | { | ||
| 747 | make_temp_name_count = time (NULL); | ||
| 748 | make_temp_name_count_initialized_p = 1; | ||
| 749 | } | ||
| 750 | |||
| 751 | while (1) | ||
| 752 | { | ||
| 753 | unsigned num = make_temp_name_count; | ||
| 754 | |||
| 755 | p[0] = make_temp_name_tbl[num & 63], num >>= 6; | ||
| 756 | p[1] = make_temp_name_tbl[num & 63], num >>= 6; | ||
| 757 | p[2] = make_temp_name_tbl[num & 63], num >>= 6; | ||
| 758 | |||
| 759 | /* Poor man's congruential RN generator. Replace with | ||
| 760 | ++make_temp_name_count for debugging. */ | ||
| 761 | make_temp_name_count += 25229; | ||
| 762 | make_temp_name_count %= 225307; | ||
| 763 | |||
| 764 | if (!check_existing (data)) | ||
| 765 | { | 695 | { |
| 766 | /* We want to return only if errno is ENOENT. */ | 696 | [GT_FILE] = "Creating file with prefix", |
| 767 | if (errno == ENOENT) | 697 | [GT_DIR] = "Creating directory with prefix", |
| 768 | return DECODE_FILE (val); | 698 | [GT_NOCREATE] = "Creating file name with prefix" |
| 769 | else | 699 | }; |
| 770 | /* The error here is dubious, but there is little else we | 700 | report_file_error (kind_message[kind], prefix); |
| 771 | can do. The alternatives are to return nil, which is | ||
| 772 | as bad as (and in many cases worse than) throwing the | ||
| 773 | error, or to ignore the error, which will likely result | ||
| 774 | in looping through 225307 stat's, which is not only | ||
| 775 | dog-slow, but also useless since eventually nil would | ||
| 776 | have to be returned anyway. */ | ||
| 777 | report_file_error ("Cannot create temporary name for prefix", | ||
| 778 | prefix); | ||
| 779 | /* not reached */ | ||
| 780 | } | ||
| 781 | } | 701 | } |
| 702 | return DECODE_FILE (val); | ||
| 782 | } | 703 | } |
| 783 | 704 | ||
| 784 | 705 | ||
| 785 | DEFUN ("make-temp-name", Fmake_temp_name, Smake_temp_name, 1, 1, 0, | 706 | DEFUN ("make-temp-name", Fmake_temp_name, Smake_temp_name, 1, 1, 0, |
| 786 | doc: /* Generate temporary file name (string) starting with PREFIX (a string). | 707 | doc: /* Generate temporary file name (string) starting with PREFIX (a string). |
| 787 | The Emacs process number forms part of the result, so there is no | ||
| 788 | danger of generating a name being used by another Emacs process | ||
| 789 | \(so long as only a single host can access the containing directory...). | ||
| 790 | 708 | ||
| 791 | This function tries to choose a name that has no existing file. | 709 | This function tries to choose a name that has no existing file. |
| 792 | For this to work, PREFIX should be an absolute file name, and PREFIX | 710 | For this to work, PREFIX should be an absolute file name, and PREFIX |
| 793 | and the returned string should both be non-magic. | 711 | and the returned string should both be non-magic. |
| 794 | 712 | ||
| 795 | There is a race condition between calling `make-temp-name' and creating the | 713 | There is a race condition between calling `make-temp-name' and |
| 796 | file, which opens all kinds of security holes. For that reason, you should | 714 | later creating the file, which opens all kinds of security holes. |
| 797 | normally use `make-temp-file' instead. */) | 715 | For that reason, you should normally use `make-temp-file' instead. */) |
| 798 | (Lisp_Object prefix) | 716 | (Lisp_Object prefix) |
| 799 | { | 717 | { |
| 800 | return make_temp_name (prefix, 0); | 718 | return Fmake_temp_file_internal (prefix, make_number (0), |
| 719 | empty_unibyte_string); | ||
| 801 | } | 720 | } |
| 802 | 721 | ||
| 803 | DEFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0, | 722 | DEFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0, |
| @@ -6168,6 +6087,7 @@ This includes interactive calls to `delete-file' and | |||
| 6168 | defsubr (&Sfile_name_as_directory); | 6087 | defsubr (&Sfile_name_as_directory); |
| 6169 | defsubr (&Sdirectory_name_p); | 6088 | defsubr (&Sdirectory_name_p); |
| 6170 | defsubr (&Sdirectory_file_name); | 6089 | defsubr (&Sdirectory_file_name); |
| 6090 | defsubr (&Smake_temp_file_internal); | ||
| 6171 | defsubr (&Smake_temp_name); | 6091 | defsubr (&Smake_temp_name); |
| 6172 | defsubr (&Sexpand_file_name); | 6092 | defsubr (&Sexpand_file_name); |
| 6173 | defsubr (&Ssubstitute_in_file_name); | 6093 | defsubr (&Ssubstitute_in_file_name); |
diff --git a/src/filelock.c b/src/filelock.c index dd8cb28c425..3d6941695ae 100644 --- a/src/filelock.c +++ b/src/filelock.c | |||
| @@ -206,14 +206,11 @@ get_boot_time (void) | |||
| 206 | WTMP_FILE, counter); | 206 | WTMP_FILE, counter); |
| 207 | if (! NILP (Ffile_exists_p (tempname))) | 207 | if (! NILP (Ffile_exists_p (tempname))) |
| 208 | { | 208 | { |
| 209 | /* The utmp functions on mescaline.gnu.org accept only | 209 | /* The utmp functions on older systems accept only file |
| 210 | file names up to 8 characters long. Choose a 2 | 210 | names up to 8 bytes long. Choose a 2 byte prefix, so |
| 211 | character long prefix, and call make_temp_file with | 211 | the 6-byte suffix does not make the name too long. */ |
| 212 | second arg non-zero, so that it will add not more | 212 | filename = Fmake_temp_file_internal (build_string ("wt"), Qnil, |
| 213 | than 6 characters to the prefix. */ | 213 | empty_unibyte_string); |
| 214 | filename = Fexpand_file_name (build_string ("wt"), | ||
| 215 | Vtemporary_file_directory); | ||
| 216 | filename = make_temp_name (filename, 1); | ||
| 217 | CALLN (Fcall_process, build_string ("gzip"), Qnil, | 214 | CALLN (Fcall_process, build_string ("gzip"), Qnil, |
| 218 | list2 (QCfile, filename), Qnil, | 215 | list2 (QCfile, filename), Qnil, |
| 219 | build_string ("-cd"), tempname); | 216 | build_string ("-cd"), tempname); |
diff --git a/src/lisp.h b/src/lisp.h index 25be5c0ceea..48cf3b30709 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -4014,7 +4014,6 @@ extern bool file_directory_p (const char *); | |||
| 4014 | extern bool file_accessible_directory_p (Lisp_Object); | 4014 | extern bool file_accessible_directory_p (Lisp_Object); |
| 4015 | extern void init_fileio (void); | 4015 | extern void init_fileio (void); |
| 4016 | extern void syms_of_fileio (void); | 4016 | extern void syms_of_fileio (void); |
| 4017 | extern Lisp_Object make_temp_name (Lisp_Object, bool); | ||
| 4018 | 4017 | ||
| 4019 | /* Defined in search.c. */ | 4018 | /* Defined in search.c. */ |
| 4020 | extern void shrink_regexp_cache (void); | 4019 | extern void shrink_regexp_cache (void); |