From f02de746f64f0879e1d8dc754293a121b686646b Mon Sep 17 00:00:00 2001 From: David Levine Date: Sun, 2 Feb 2014 08:46:25 -0600 Subject: [PATCH] Added m_mktemps(), which creates a temporary file with a specified 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 | 2 +- docs/pending-release-notes | 4 +- h/prototypes.h | 1 + sbr/m_mktemp.c | 113 +++++++++++++++++++++++++++++++++++++ uip/mhparse.c | 75 +++++++++++++++--------- 5 files changed, 164 insertions(+), 31 deletions(-) diff --git a/configure.ac b/configure.ac index 35118f34..7c35047a 100644 --- a/configure.ac +++ b/configure.ac @@ -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 \ diff --git a/docs/pending-release-notes b/docs/pending-release-notes index 1adbc857..464554b0 100644 --- a/docs/pending-release-notes +++ b/docs/pending-release-notes @@ -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 diff --git a/h/prototypes.h b/h/prototypes.h index e8be9fe6..fceef407 100644 --- a/h/prototypes.h +++ b/h/prototypes.h @@ -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 *); diff --git a/sbr/m_mktemp.c b/sbr/m_mktemp.c index a9dab5a2..17cf7458 100644 --- a/sbr/m_mktemp.c +++ b/sbr/m_mktemp.c @@ -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() { diff --git a/uip/mhparse.c b/uip/mhparse.c index d12fbb30..8af26906 100644 --- a/uip/mhparse.c +++ b/uip/mhparse.c @@ -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) { -- 2.56.0