threads / patch / 34391

patchTIG: Implement mkstemps() work-around for platforms lacking it

Subject: [PATCH] TIG: Implement mkstemps() work-around for platforms lacking it

## tl;dr

2 messages between Jul 9, 2013 and Jul 18, 2013. Diffs are folded; open one to read it.

replies: 1people: 1as markdown or json

Drew Northup· Jul 9, 2013, 15:33 UTC · lore

The function mkstemps() isn't available in all libc implementations. In glibc it first became available in 2.11, so platforms such as RHEL 5 & Slackware 13 lack it. This is likely true of many non-LINUX platforms as well.

This fixes breakage that was introduced with a0fdac29 "Create temporary file with name as suffix."

Signed-off-by: Drew Northup <n1xim.email@gmail.com>
---

This work-around is taken from Git and was inspired by code in libiberty. It is presumed that this isn't a problem due to compatible license terms.

A (virtually identical) version of this available in https://github.com/n1xim/tig/tree/mkstemps_wkarnd (differences only in the commit message).

 configure.ac |  4 ++++
 io.c         | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 io.h         | 14 +++++++++++
 3 files changed, 95 insertions(+)
Show changes to 3 files +95 −0

configure.ac, io.c, io.h

diff --git a/configure.ac b/configure.ac
index 8dd2508..40e1f85 100644
--- a/configure.ac
+++ b/configure.ac
@@ -21,6 +21,10 @@ AC_SUBST(CURSES_LIB)
 
 AM_ICONV
 
+dnl  Not all platforms have mkstemps
+AC_CHECK_FUNC([mkstemps], [AC_DEFINE([HAVE_MKSTEMPS], [1],
+	      [Define if mkstemps is available.])])
+
 AC_PROG_CC
 
 AC_CHECK_PROGS(ASCIIDOC, [asciidoc], [false])
diff --git a/io.c b/io.c
index 3ff1d1c..f1b6fbc 100644
--- a/io.c
+++ b/io.c
@@ -237,6 +237,83 @@ encoding_convert(struct encoding *encoding, char *line)
 }
 
 /*
+ * Compatibility: no mkstemps()
+ */
+
+/* Adapted from libiberty's mkstemp.c via Git's wrapper.c. */
+
+#undef TMP_MAX
+#define TMP_MAX 16384
+
+int tig_mkstemps_mode(char *pattern, int suffix_len, int mode)
+{
+	static const char letters[] =
+		"abcdefghijklmnopqrstuvwxyz"
+		"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+		"0123456789";
+	static const int num_letters = 62;
+	uint64_t value;
+	struct timeval tv;
+	char *template;
+	size_t len;
+	int fd, count;
+
+	len = strlen(pattern);
+
+	if (len < 6 + suffix_len) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (strncmp(&pattern[len - 6 - suffix_len], "XXXXXX", 6)) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	/*
+	 * Replace pattern's XXXXXX characters with randomness.
+	 * Try TMP_MAX different filenames.
+	 */
+	gettimeofday(&tv, NULL);
+	value = ((size_t)(tv.tv_usec << 16)) ^ tv.tv_sec ^ getpid();
+	template = &pattern[len - 6 - suffix_len];
+	for (count = 0; count < TMP_MAX; ++count) {
+		uint64_t v = value;
+		/* Fill in the random bits. */
+		template[0] = letters[v % num_letters]; v /= num_letters;
+		template[1] = letters[v % num_letters]; v /= num_letters;
+		template[2] = letters[v % num_letters]; v /= num_letters;
+		template[3] = letters[v % num_letters]; v /= num_letters;
+		template[4] = letters[v % num_letters]; v /= num_letters;
+		template[5] = letters[v % num_letters]; v /= num_letters;
+
+		fd = open(pattern, O_CREAT | O_EXCL | O_RDWR, mode);
+		if (fd > 0)
+			return fd;
+		/*
+		 * Fatal error (EPERM, ENOSPC etc).
+		 * It doesn't make sense to loop.
+		 */
+		if (errno != EEXIST)
+			break;
+		/*
+		 * This is a random value.  It is only necessary that
+		 * the next TMP_MAX values generated by adding 7777 to
+		 * VALUE are different with (module 2^32).
+		 */
+		value += 7777;
+	}
+	/* We return the null string if we can't find a unique file name.  */
+	pattern[0] = '\0';
+	return -1;
+}
+
+int tigmkstemps(char *pattern, int suffix_len)
+{
+	return tig_mkstemps_mode(pattern, suffix_len, 0600);
+}
+
+/*
  * Executing external commands.
  */
 
diff --git a/io.h b/io.h
index 646989d..8f43216 100644
--- a/io.h
+++ b/io.h
@@ -16,6 +16,9 @@
 
 #include "tig.h"
 
+/* Needed for mkstemps workaround */
+#include <stdint.h>
+
 /*
  * Argument array helpers.
  */
@@ -41,6 +44,17 @@ struct encoding *encoding_open(const char *fromcode);
 char *encoding_convert(struct encoding *encoding, char *line);
 
 /*
+ * Compatibility: no mkstemps()
+ */
+
+#ifndef HAVE_MKSTEMPS
+#define mkstemps tigmkstemps
+#endif
+
+int tigmkstemps(char *, int);
+int tig_mkstemps_mode(char *pattern, int suffix_len, int mode);
+
+/*
  * Executing external commands.
  */
 
-- 
1.8.0
Drew Northup· Jul 18, 2013, 04:45 UTC · re: Drew Northup · lore

Re: [PATCH] TIG: Implement mkstemps() work-around for platforms lacking it

Giving this one last kick to make absolutely sure that nobody disagrees with allowing this code to be included into tig, which does not limit to a specific version of the GPL (version 2 in the case of git, any version equal to or newer than 2 in the case of tig), pursuant to paragraph 9 of said license.

On 07/09/2013 11:33 AM, Drew Northup wrote:
Show 158 quoted lines
> The function mkstemps() isn't available in all libc implementations. In
> glibc it first became available in 2.11, so platforms such as RHEL 5&
> Slackware 13 lack it. This is likely true of many non-LINUX platforms
> as well.
>
> This fixes breakage that was introduced with a0fdac29 "Create temporary
> file with name as suffix."
>
> Signed-off-by: Drew Northup<n1xim.email@gmail.com>
> ---
>
> This work-around is taken from Git and was inspired by code in libiberty.
> It is presumed that this isn't a problem due to compatible license terms.
>
> A (virtually identical) version of this available in
> https://github.com/n1xim/tig/tree/mkstemps_wkarnd (differences only in
> the commit message).
>
>   configure.ac |  4 ++++
>   io.c         | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   io.h         | 14 +++++++++++
>   3 files changed, 95 insertions(+)
>
> diff --git a/configure.ac b/configure.ac
> index 8dd2508..40e1f85 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -21,6 +21,10 @@ AC_SUBST(CURSES_LIB)
>
>   AM_ICONV
>
> +dnl  Not all platforms have mkstemps
> +AC_CHECK_FUNC([mkstemps], [AC_DEFINE([HAVE_MKSTEMPS], [1],
> +	      [Define if mkstemps is available.])])
> +
>   AC_PROG_CC
>
>   AC_CHECK_PROGS(ASCIIDOC, [asciidoc], [false])
> diff --git a/io.c b/io.c
> index 3ff1d1c..f1b6fbc 100644
> --- a/io.c
> +++ b/io.c
> @@ -237,6 +237,83 @@ encoding_convert(struct encoding *encoding, char *line)
>   }
>
>   /*
> + * Compatibility: no mkstemps()
> + */
> +
> +/* Adapted from libiberty's mkstemp.c via Git's wrapper.c. */
> +
> +#undef TMP_MAX
> +#define TMP_MAX 16384
> +
> +int tig_mkstemps_mode(char *pattern, int suffix_len, int mode)
> +{
> +	static const char letters[] =
> +		"abcdefghijklmnopqrstuvwxyz"
> +		"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
> +		"0123456789";
> +	static const int num_letters = 62;
> +	uint64_t value;
> +	struct timeval tv;
> +	char *template;
> +	size_t len;
> +	int fd, count;
> +
> +	len = strlen(pattern);
> +
> +	if (len<  6 + suffix_len) {
> +		errno = EINVAL;
> +		return -1;
> +	}
> +
> +	if (strncmp(&pattern[len - 6 - suffix_len], "XXXXXX", 6)) {
> +		errno = EINVAL;
> +		return -1;
> +	}
> +
> +	/*
> +	 * Replace pattern's XXXXXX characters with randomness.
> +	 * Try TMP_MAX different filenames.
> +	 */
> +	gettimeofday(&tv, NULL);
> +	value = ((size_t)(tv.tv_usec<<  16)) ^ tv.tv_sec ^ getpid();
> +	template =&pattern[len - 6 - suffix_len];
> +	for (count = 0; count<  TMP_MAX; ++count) {
> +		uint64_t v = value;
> +		/* Fill in the random bits. */
> +		template[0] = letters[v % num_letters]; v /= num_letters;
> +		template[1] = letters[v % num_letters]; v /= num_letters;
> +		template[2] = letters[v % num_letters]; v /= num_letters;
> +		template[3] = letters[v % num_letters]; v /= num_letters;
> +		template[4] = letters[v % num_letters]; v /= num_letters;
> +		template[5] = letters[v % num_letters]; v /= num_letters;
> +
> +		fd = open(pattern, O_CREAT | O_EXCL | O_RDWR, mode);
> +		if (fd>  0)
> +			return fd;
> +		/*
> +		 * Fatal error (EPERM, ENOSPC etc).
> +		 * It doesn't make sense to loop.
> +		 */
> +		if (errno != EEXIST)
> +			break;
> +		/*
> +		 * This is a random value.  It is only necessary that
> +		 * the next TMP_MAX values generated by adding 7777 to
> +		 * VALUE are different with (module 2^32).
> +		 */
> +		value += 7777;
> +	}
> +	/* We return the null string if we can't find a unique file name.  */
> +	pattern[0] = '\0';
> +	return -1;
> +}
> +
> +int tigmkstemps(char *pattern, int suffix_len)
> +{
> +	return tig_mkstemps_mode(pattern, suffix_len, 0600);
> +}
> +
> +/*
>    * Executing external commands.
>    */
>
> diff --git a/io.h b/io.h
> index 646989d..8f43216 100644
> --- a/io.h
> +++ b/io.h
> @@ -16,6 +16,9 @@
>
>   #include "tig.h"
>
> +/* Needed for mkstemps workaround */
> +#include<stdint.h>
> +
>   /*
>    * Argument array helpers.
>    */
> @@ -41,6 +44,17 @@ struct encoding *encoding_open(const char *fromcode);
>   char *encoding_convert(struct encoding *encoding, char *line);
>
>   /*
> + * Compatibility: no mkstemps()
> + */
> +
> +#ifndef HAVE_MKSTEMPS
> +#define mkstemps tigmkstemps
> +#endif
> +
> +int tigmkstemps(char *, int);
> +int tig_mkstemps_mode(char *pattern, int suffix_len, int mode);
> +
> +/*
>    * Executing external commands.
>    */
>

← back to recent threads