From 0b60827ba7bbbefd991a99dfcae4973d51387f82 Mon Sep 17 00:00:00 2001
From: Steve Bennett <steveb@workware.net.au>
Date: Sun, 3 Aug 2014 17:40:11 +1000
Subject: [PATCH] Temporary file creation should respect $TMPDIR

This applies to [exec] and [file tempfile]

Reported-by: Jakub Wilk
Signed-off-by: Steve Bennett <steveb@workware.net.au>
---
 jim-aio.c  | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 jim-exec.c |  8 +++-----
 jim-file.c | 19 +------------------
 jim.h      |  1 +
 4 files changed, 54 insertions(+), 23 deletions(-)

--- a/jim-aio.c
+++ b/jim-aio.c
@@ -45,6 +45,7 @@
 #include <fcntl.h>
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#include <sys/stat.h>
 #endif
 
 #include "jim.h"
@@ -1410,6 +1411,54 @@
 }
 #endif /* JIM_BOOTSTRAP */
 
+/**
+ * Returns the file descriptor of a writable, newly created temp file
+ * or -1 on error.
+ * 
+ * On success, leaves the filename in the interpreter result, otherwise
+ * leaves an error message.
+ */
+int Jim_MakeTempFile(Jim_Interp *interp, const char *template)
+{
+#ifdef HAVE_MKSTEMP
+    int fd;
+    mode_t mask;
+    Jim_Obj *filenameObj;
+
+    if (template == NULL) {
+        const char *tmpdir = getenv("TMPDIR");
+        if (tmpdir == NULL || *tmpdir == '\0' || access(tmpdir, W_OK) != 0) {
+            tmpdir = "/tmp/";
+        }
+        filenameObj = Jim_NewStringObj(interp, tmpdir, -1);
+        if (tmpdir[0] && tmpdir[strlen(tmpdir) - 1] != '/') {
+            Jim_AppendString(interp, filenameObj, "/", 1);
+        }
+        Jim_AppendString(interp, filenameObj, "tcl.tmp.XXXXXX", -1);
+    }
+    else {
+        filenameObj = Jim_NewStringObj(interp, template, -1);
+    }
+
+    mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
+
+    /* Update the template name directly with the filename */
+    fd = mkstemp(filenameObj->bytes);
+    umask(mask);
+    if (fd < 0) {
+        Jim_SetResultString(interp, "Failed to create tempfile", -1);
+        Jim_FreeNewObj(interp, filenameObj);
+        return -1;
+    }
+
+    Jim_SetResult(interp, filenameObj);
+    return fd;
+#else
+    Jim_SetResultString(interp, "tempfile not supported", -1);
+    return -1;
+#endif
+}
+
 FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command)
 {
     Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG);
--- a/jim-exec.c
+++ b/jim-exec.c
@@ -1575,14 +1575,13 @@
 
 static int JimCreateTemp(Jim_Interp *interp, const char *contents, int len)
 {
-    char inName[] = "/tmp/tcl.tmp.XXXXXX";
+    int fd = Jim_MakeTempFile(interp, NULL);
 
-    int fd = mkstemp(inName);
     if (fd == JIM_BAD_FD) {
         Jim_SetResultErrno(interp, "couldn't create temp file");
         return -1;
     }
-    unlink(inName);
+    unlink(Jim_String(Jim_GetResult(interp)));
     if (contents) {
         if (write(fd, contents, len) != len) {
             Jim_SetResultErrno(interp, "couldn't write temp file");
--- a/jim-file.c
+++ b/jim-file.c
@@ -483,29 +483,17 @@
     return JIM_OK;
 }
 
-#ifdef HAVE_MKSTEMP
 static int file_cmd_tempfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
-    int fd;
-    char *filename;
-    const char *template = "/tmp/tcl.tmp.XXXXXX";
+    int fd = Jim_MakeTempFile(interp, (argc >= 1) ? Jim_String(argv[0]) : NULL);
 
-    if (argc >= 1) {
-        template = Jim_String(argv[0]);
-    }
-    filename = Jim_StrDup(template);
-
-    fd = mkstemp(filename);
     if (fd < 0) {
-        Jim_SetResultString(interp, "Failed to create tempfile", -1);
         return JIM_ERR;
     }
     close(fd);
 
-    Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, filename, -1));
     return JIM_OK;
 }
-#endif
 
 static int file_cmd_rename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
@@ -823,7 +811,6 @@
         -1,
         /* Description: Creates the directories */
     },
-#ifdef HAVE_MKSTEMP
     {   "tempfile",
         "?template?",
         file_cmd_tempfile,
@@ -831,7 +818,6 @@
         1,
         /* Description: Creates a temporary filename */
     },
-#endif
     {   "rename",
         "?-force? source dest",
         file_cmd_rename,
--- a/jim.h
+++ b/jim.h
@@ -614,6 +614,7 @@
 /* environment */
 JIM_EXPORT char **Jim_GetEnviron(void);
 JIM_EXPORT void Jim_SetEnviron(char **env);
+JIM_EXPORT int Jim_MakeTempFile(Jim_Interp *interp, const char *template);
 
 /* evaluation */
 JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script);
