]> diplodocus.org Git - nmh/commitdiff
Added m_mktemps(), which creates a temporary file with a specified
authorDavid Levine <levinedl@acm.org>
Sun, 2 Feb 2014 14:46:25 +0000 (08:46 -0600)
committerDavid Levine <levinedl@acm.org>
Sun, 2 Feb 2014 14:46:25 +0000 (08:46 -0600)
suffix.  It uses mkstemps(3) where available, which should be most
modern platforms.  If not available, it tries link(2), and if that
fails, rename(2).

configure.ac
docs/pending-release-notes
h/prototypes.h
sbr/m_mktemp.c
uip/mhparse.c

index 35118f3..7c35047 100644 (file)
@@ -341,7 +341,7 @@ AC_CHECK_HEADER([sys/ptem.h], AC_DEFINE(WINSIZE_IN_PTEM,1,
 dnl ---------------
 dnl CHECK FUNCTIONS
 dnl ---------------
-AC_CHECK_FUNCS([wcwidth mbtowc getutxent arc4random])
+AC_CHECK_FUNCS([wcwidth mbtowc getutxent arc4random mkstemps])
 
 dnl Check for multibyte character set support
 AS_IF([test "x$ac_cv_header_wchar_h" = "xyes" -a \
index 1adbc85..464554b 100644 (file)
@@ -120,9 +120,7 @@ OBSOLETE FEATURES
 - Temporary files are stored in the first non-null location of
   {MHTMPDIR environment variable, TMPDIR environment variable, MH Path}.
   They are no longer be stored in the location specified by the TMP
-  environment variable.  As part of this change, suffixes were removed
-  from filenames of temporary files.  This will break the use of display
-  applications that rely on the suffix to determine the file type.
+  environment variable.
 
 -------------------
 DEPRECATED FEATURES
index e8be9fe..fceef40 100644 (file)
@@ -191,6 +191,7 @@ int m_putenv (char *, char *);
 int m_rand (unsigned char *, size_t);
 char *m_mktemp(const char *, int *, FILE **);
 char *m_mktemp2(const char *, const char *, int *, FILE **);
+char *m_mktemps(const char *pfx, const char *, int *, FILE **);
 char *get_temp_dir();
 void m_unknown(m_getfld_state_t *, FILE *);
 int makedir (char *);
index a9dab5a..17cf745 100644 (file)
@@ -132,6 +132,119 @@ m_mktemp2 (
 }
 
 
+/*
+ * This version supports a suffix for the temp filename.
+ * It has two other differences from m_mktemp() and m_mktemp2():
+ * 1) It does not support specification of a directory for the temp
+ *    file.  Instead it always uses get_temp_dir().
+ * 2) It returns a dynamically allocated string.  The caller is
+ *    responsible for freeing the allocated memory.
+ */
+char *
+m_mktemps(
+    const char *pfx_in,   /* Basename prefix for temp file. */
+    const char *suffix,   /* Suffix, including any '.', for temp file. */
+    int *fd_ret,          /* (return,optional) File descriptor to temp file. */
+    FILE **fp_ret         /* (return,optional) FILE pointer to temp file. */
+)
+{
+    char *tmpfil;
+    int fd = -1;
+    int keep_open = 0;
+    mode_t oldmode = umask(077);
+
+    if (suffix == NULL) {
+        if ((tmpfil = m_mktemp2(NULL, pfx_in, fd_ret, fp_ret))) {
+            return add(tmpfil, NULL);
+        } else {
+            return NULL;
+        }
+    }
+
+#if HAVE_MKSTEMPS
+    if (pfx_in == NULL) {
+        tmpfil = concat(get_temp_dir(), "/nmhXXXXXX", suffix, NULL);
+    } else {
+        tmpfil = concat(get_temp_dir(), "/", pfx_in, "XXXXXX", suffix, NULL);
+    }
+
+    fd = mkstemps(tmpfil, (int) strlen(suffix));
+#else  /* ! HAVE_MKSTEMPS */
+    /* Solaris 10, e.g. */
+
+    if (pfx_in == NULL) {
+        tmpfil = concat(get_temp_dir(), "/nmhXXXXXX", NULL);
+    } else {
+        tmpfil = concat(get_temp_dir(), "/", pfx_in, "XXXXXX", NULL);
+    }
+
+    fd = mkstemp(tmpfil);
+    {
+        char *oldfilename = tmpfil;
+
+        tmpfil = concat(oldfilename, suffix, NULL);
+
+        /* link(2) requires that the new path not exist.  And if we
+           have to resort to rename(2), at least try to remove a file
+           that would be in the way. */
+        if (unlink(tmpfil) != 0  &&  errno != ENOENT) {
+            advise("unlink", "Failed to unlink \"%s\"", tmpfil);
+            (void) unlink(oldfilename);
+            free(oldfilename);
+            free(tmpfil);
+            return NULL;
+        }
+
+        /* link() doesn't always work, such as on Windows FAT
+           filesystems.  If it fails, try rename(). */
+        if (link(oldfilename, tmpfil) != 0  &&
+            rename(oldfilename, tmpfil) != 0) {
+            (void) unlink(oldfilename);
+            free(oldfilename);
+            free(tmpfil);
+            return NULL;
+        }
+
+        (void) unlink(oldfilename);
+        free(oldfilename);
+    }
+#endif /* ! HAVE_MKSTEMPS */
+
+    if (fd < 0) {
+        umask(oldmode);
+        free(tmpfil);
+        return NULL;
+    }
+
+    register_for_removal(tmpfil);
+
+    if (fd_ret != NULL) {
+        *fd_ret = fd;
+        keep_open = 1;
+    }
+    if (fp_ret != NULL) {
+        FILE *fp = fdopen(fd, "w+");
+        if (fp == NULL) {
+            int olderr = errno;
+            (void) m_unlink(tmpfil);
+            close(fd);
+            errno = olderr;
+            umask(oldmode);
+            free(tmpfil);
+            return NULL;
+        }
+        *fp_ret = fp;
+        keep_open = 1;
+    }
+    if (!keep_open) {
+        close(fd);
+    }
+    umask(oldmode);
+
+    return tmpfil;
+}
+
+
 char *
 get_temp_dir()
 {
index d12fbb3..8af2690 100644 (file)
@@ -1700,12 +1700,6 @@ openBase64 (CT ct, char **file)
     }
 
     if (*file == NULL) {
-       char *tempfile;
-       if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) {
-           adios(NULL, "unable to create temporary file in %s",
-                 get_temp_dir());
-       }
-       ce->ce_file = add (tempfile, NULL);
        ce->ce_unlink = 1;
     } else {
        ce->ce_file = add (*file, NULL);
@@ -1723,9 +1717,22 @@ openBase64 (CT ct, char **file)
         cp = context_find (buffer);
     }
     if (cp != NULL && *cp != '\0') {
-        if (! ce->ce_unlink) {
-            ce->ce_file = add (cp, ce->ce_file);
-        }
+       if (ce->ce_unlink) {
+           /* Create temporary file with filename extension. */
+           if ((ce->ce_file = m_mktemps(invo_name, cp, NULL, NULL)) == NULL) {
+               adios(NULL, "unable to create temporary file in %s",
+                     get_temp_dir());
+           }
+       } else {
+           ce->ce_file = add (cp, ce->ce_file);
+       }
+    } else if (*file == NULL) {
+       char *tempfile;
+       if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) {
+           adios(NULL, "unable to create temporary file in %s",
+                 get_temp_dir());
+       }
+       ce->ce_file = add (tempfile, NULL);
     }
 
     if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) {
@@ -1932,12 +1939,6 @@ openQuoted (CT ct, char **file)
     }
 
     if (*file == NULL) {
-       char *tempfile;
-       if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) {
-           adios(NULL, "unable to create temporary file in %s",
-                 get_temp_dir());
-       }
-       ce->ce_file = add (tempfile, NULL);
        ce->ce_unlink = 1;
     } else {
        ce->ce_file = add (*file, NULL);
@@ -1955,9 +1956,22 @@ openQuoted (CT ct, char **file)
         cp = context_find (buffer);
     }
     if (cp != NULL && *cp != '\0') {
-        if (! ce->ce_unlink) {
-            ce->ce_file = add (cp, ce->ce_file);
-        }
+       if (ce->ce_unlink) {
+           /* Create temporary file with filename extension. */
+           if ((ce->ce_file = m_mktemps(invo_name, cp, NULL, NULL)) == NULL) {
+               adios(NULL, "unable to create temporary file in %s",
+                     get_temp_dir());
+           }
+       } else {
+           ce->ce_file = add (cp, ce->ce_file);
+       }
+    } else if (*file == NULL) {
+       char *tempfile;
+       if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) {
+           adios(NULL, "unable to create temporary file in %s",
+                 get_temp_dir());
+       }
+       ce->ce_file = add (tempfile, NULL);
     }
 
     if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) {
@@ -2151,12 +2165,6 @@ open7Bit (CT ct, char **file)
     }
 
     if (*file == NULL) {
-       char *tempfile;
-       if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) {
-           adios(NULL, "unable to create temporary file in %s",
-                 get_temp_dir());
-       }
-       ce->ce_file = add (tempfile, NULL);
        ce->ce_unlink = 1;
     } else {
        ce->ce_file = add (*file, NULL);
@@ -2174,9 +2182,22 @@ open7Bit (CT ct, char **file)
         cp = context_find (buffer);
     }
     if (cp != NULL && *cp != '\0') {
-        if (! ce->ce_unlink) {
-            ce->ce_file = add (cp, ce->ce_file);
-        }
+       if (ce->ce_unlink) {
+           /* Create temporary file with filename extension. */
+           if ((ce->ce_file = m_mktemps(invo_name, cp, NULL, NULL)) == NULL) {
+               adios(NULL, "unable to create temporary file in %s",
+                     get_temp_dir());
+           }
+       } else {
+           ce->ce_file = add (cp, ce->ce_file);
+       }
+    } else if (*file == NULL) {
+       char *tempfile;
+       if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) {
+           adios(NULL, "unable to create temporary file in %s",
+                 get_temp_dir());
+       }
+       ce->ce_file = add (tempfile, NULL);
     }
 
     if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) {