zsh-workers
 help / color / mirror / code / Atom feed
From: Clinton Bunch <cdb_zsh@zentaur.org>
To: zsh-workers@zsh.org
Subject: [PATCH] replacement for mktemp and mkstemp code in Src/utils.c
Date: Fri, 19 Apr 2019 14:54:47 -0500	[thread overview]
Message-ID: <b72ceb70-aa91-4230-98fe-1ba5cdf0bb46@zentaur.org> (raw)

On at least one system mktemp produces very predictable names:

% () { print File: $1; cat $1 } =(print "Hello World")
File: /tmp/zsh010785
Hello World
% () { print File: $1; cat $1 } =(print "Hello World")
File: /tmp/zsh010785
Hello World
% () { print File: $1; cat $1 } =(print "Hello World")
File: /tmp/zsh010785
Hello World
% echo $$
10785

This provides an alternate implementation for generating and opening 
temp file names.  I considered only using this implementation on known 
bad systems, but I have no way of knowing all of them (or testing for 
them in configure).  I see no reason to expect system implementations of 
mktemp or mkstemp to be significantly faster than mine unless written in 
assembly (which seems unlikely).

This also provides the necessary utility function for my plans to 
introduce a builtin for managing tempfiles.


Patch:

diff --git a/Src/utils.c b/Src/utils.c
index 32f600858..06802c1a1 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -2174,9 +2174,92 @@ zcloselockfd(int fd)
      return 0;
  }

-#ifdef HAVE__MKTEMP
-extern char *_mktemp(char *);
+/*
+ *  Replacement for mktemp,mkstemp, and mkstemps. */
+
+static char 
sc[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+#ifdef HAVE_ERAND48
+static unsigned short seed[3]={0,0,0};
+#endif
+
+/**/
+mod_export int
+ztempfile(char *template,int slen,enum zmt_action action, int *fd)
+{
+       char *padptr, *p, *path;
+       int padlen=0,r,i,len,success=0,failure=0,attempts=0;
+       struct stat dummy;
+
+       len=ztrlen(template);
+       if((action == ZMT_FILE && !fd) || slen < 0 || slen >= len-6) {
+           errno=EINVAL;
+           return 0;
+       }
+#ifdef HAVE_ERAND48
+       if(seed[0]==0 && seed[1] == 0 && seed[2] == 0){
+           seed[0]=getppid();
+           seed[1]=time(NULL) & 0xFFFF;
+           seed[2]=getpid();
+       }
  #endif
+       if(!(path=ztrdup(template)))
+           return 0;
+       padptr=path+(len-slen-1);
+
+       while(*padptr == 'X') {
+           padlen++;
+           padptr--;
+       }
+       padptr++;
+       if(padlen < 6) {
+           errno=EINVAL;
+           return 0;
+       }
+       do {
+            for(p=padptr,i=0;i<padlen;i++)
+           {
+#ifdef HAVE_ERAND48
+               r=erand48(seed)*(sizeof(sc)-2)+0.5;
+#else
+                r=rand()%(sizeof(sc)-1);
+#endif
+               *p++=sc[r];
+           }
+           switch(action)
+           {
+                case ZMT_NAME:
+                   if(lstat(path,&dummy) < 0  && errno == ENOENT)
+                       success=1;
+                   break;
+               case ZMT_DIR:
+                   if(mkdir(path,0700)) {
+                       success=1;
+                   }else if(errno!=EEXIST) {
+                       failure=1;
+                   }
+                   break;
+               case ZMT_FILE:
+ if((*fd=open(path,O_RDWR|O_CREAT|O_EXCL,0600))<0) {
+                       if(errno!=EEXIST)
+                           failure=1;
+                   }else
+                       success=1;
+                   break;
+                default:
+                   errno=ENOTSUP;
+                   return 1;
+                   break;
+           }
+       } while(!success && !failure && ++attempts < 16);
+       if(success) {
+           ztrncpy(template,path,len);
+            errno = 0;
+        }
+       if(attempts >= 16)
+           errno=ECANCELED;
+       zsfree(path);
+       return success?1:0;
+}

  /* Get a unique filename for use as a temporary file.  If "prefix" is
   * NULL, the name is relative to $TMPPREFIX; If it is non-NULL, the
@@ -2198,12 +2281,11 @@ gettempname(const char *prefix, int use_heap)
      else
         ret = bicat(unmeta(prefix), suffix);

-#ifdef HAVE__MKTEMP
-    /* Zsh uses mktemp() safely, so silence the warnings */
-    ret = (char *) _mktemp(ret);
-#else
-    ret = (char *) mktemp(ret);
-#endif
+    if(!ztempfile(ret,0,ZMT_NAME,NULL)){
+        if (use_heap)
+           free(ret);
+       ret = NULL;
+    }
      unqueue_signals();

      return ret;
@@ -2219,7 +2301,6 @@ gettempfile(const char *prefix, int use_heap, char 
**tempname)
      char *fn;
      int fd;
      mode_t old_umask;
-#if HAVE_MKSTEMP
      char *suffix = prefix ? ".XXXXXX" : "XXXXXX";

      queue_signals();
@@ -2231,29 +2312,11 @@ gettempfile(const char *prefix, int use_heap, 
char **tempname)
      else
         fn = bicat(unmeta(prefix), suffix);

-    fd = mkstemp(fn);
-    if (fd < 0) {
+    if(!ztempfile(fn,0,ZMT_FILE,&fd)) {
         if (!use_heap)
             free(fn);
         fn = NULL;
      }
-#else
-    int failures = 0;
-
-    queue_signals();
-    old_umask = umask(0177);
-    do {
-       if (!(fn = gettempname(prefix, use_heap))) {
-           fd = -1;
-           break;
-       }
-       if ((fd = open(fn, O_RDWR | O_CREAT | O_EXCL, 0600)) >= 0)
-           break;
-       if (!use_heap)
-           free(fn);
-       fn = NULL;
-    } while (errno == EEXIST && ++failures < 16);
-#endif
      *tempname = fn;

      umask(old_umask);
diff --git a/Src/zsh.h b/Src/zsh.h
index fc3ed2127..684ff4e4b 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -3338,3 +3338,12 @@ typedef int convchar_t;
  #define ZWS(s) s

  #endif /* MULTIBYTE_SUPPORT */
+
+/*************************************
+ * Tempfile actions                  *
+ *************************************/
+enum zmt_action {
+  ZMT_FILE  = 0,
+  ZMT_DIR   = 1,
+  ZMT_NAME  = 2
+};
diff --git a/configure.ac b/configure.ac
index 8a2664ed2..29d014372 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1251,7 +1251,7 @@ AC_CHECK_FUNCS(strftime strptime mktime timelocal \
                readlink faccessx fchdir ftruncate \
                fstat lstat lchown fchown fchmod \
                fseeko ftello \
-              mkfifo _mktemp mkstemp \
+              mkfifo \
                waitpid wait3 \
                sigaction sigblock sighold sigrelse sigsetmask sigprocmask \
                killpg setpgid setpgrp tcsetpgrp tcgetattr nice \




             reply	other threads:[~2019-04-19 19:56 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-04-19 19:54 Clinton Bunch [this message]
2019-04-20  4:33 ` Matthew Martin
2019-04-20 10:27   ` Mikael Magnusson
2019-04-20 18:52     ` Clinton Bunch
2019-04-21  4:57       ` Matthew Martin
2019-04-21 20:08       ` Mikael Magnusson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b72ceb70-aa91-4230-98fe-1ba5cdf0bb46@zentaur.org \
    --to=cdb_zsh@zentaur.org \
    --cc=zsh-workers@zsh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).