{"thread":{"id":"34391","subject":"[PATCH] TIG: Implement mkstemps() work-around for platforms lacking it","startedAt":"2013-07-09T15:33:12Z","lastAt":"2013-07-18T04:45:23Z","messageCount":2,"participants":["Drew Northup"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"222930","messageId":"1373383992-4298-1-git-send-email-n1xim.email@gmail.com","threadId":"34391","inReplyTo":null,"subject":"[PATCH] TIG: Implement mkstemps() work-around for platforms lacking it","fromName":"Drew Northup","fromEmail":"n1xim.email@gmail.com","sentAt":"2013-07-09T15:33:12Z","receivedAt":"2013-07-09T15:33:12Z","isPatch":true,"sender":{"key":"n1xim.email@gmail.com","avatar":null},"body":"The function mkstemps() isn't available in all libc implementations. In\nglibc it first became available in 2.11, so platforms such as RHEL 5 &\nSlackware 13 lack it. This is likely true of many non-LINUX platforms\nas well.\n\nThis fixes breakage that was introduced with a0fdac29 \"Create temporary\nfile with name as suffix.\"\n\nSigned-off-by: Drew Northup <n1xim.email@gmail.com>\n---\n\nThis work-around is taken from Git and was inspired by code in libiberty.\nIt is presumed that this isn't a problem due to compatible license terms.\n\nA (virtually identical) version of this available in\nhttps://github.com/n1xim/tig/tree/mkstemps_wkarnd (differences only in\nthe commit message).\n\n configure.ac |  4 ++++\n io.c         | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n io.h         | 14 +++++++++++\n 3 files changed, 95 insertions(+)\n\ndiff --git a/configure.ac b/configure.ac\nindex 8dd2508..40e1f85 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -21,6 +21,10 @@ AC_SUBST(CURSES_LIB)\n \n AM_ICONV\n \n+dnl  Not all platforms have mkstemps\n+AC_CHECK_FUNC([mkstemps], [AC_DEFINE([HAVE_MKSTEMPS], [1],\n+\t      [Define if mkstemps is available.])])\n+\n AC_PROG_CC\n \n AC_CHECK_PROGS(ASCIIDOC, [asciidoc], [false])\ndiff --git a/io.c b/io.c\nindex 3ff1d1c..f1b6fbc 100644\n--- a/io.c\n+++ b/io.c\n@@ -237,6 +237,83 @@ encoding_convert(struct encoding *encoding, char *line)\n }\n \n /*\n+ * Compatibility: no mkstemps()\n+ */\n+\n+/* Adapted from libiberty's mkstemp.c via Git's wrapper.c. */\n+\n+#undef TMP_MAX\n+#define TMP_MAX 16384\n+\n+int tig_mkstemps_mode(char *pattern, int suffix_len, int mode)\n+{\n+\tstatic const char letters[] =\n+\t\t\"abcdefghijklmnopqrstuvwxyz\"\n+\t\t\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n+\t\t\"0123456789\";\n+\tstatic const int num_letters = 62;\n+\tuint64_t value;\n+\tstruct timeval tv;\n+\tchar *template;\n+\tsize_t len;\n+\tint fd, count;\n+\n+\tlen = strlen(pattern);\n+\n+\tif (len < 6 + suffix_len) {\n+\t\terrno = EINVAL;\n+\t\treturn -1;\n+\t}\n+\n+\tif (strncmp(&pattern[len - 6 - suffix_len], \"XXXXXX\", 6)) {\n+\t\terrno = EINVAL;\n+\t\treturn -1;\n+\t}\n+\n+\t/*\n+\t * Replace pattern's XXXXXX characters with randomness.\n+\t * Try TMP_MAX different filenames.\n+\t */\n+\tgettimeofday(&tv, NULL);\n+\tvalue = ((size_t)(tv.tv_usec << 16)) ^ tv.tv_sec ^ getpid();\n+\ttemplate = &pattern[len - 6 - suffix_len];\n+\tfor (count = 0; count < TMP_MAX; ++count) {\n+\t\tuint64_t v = value;\n+\t\t/* Fill in the random bits. */\n+\t\ttemplate[0] = letters[v % num_letters]; v /= num_letters;\n+\t\ttemplate[1] = letters[v % num_letters]; v /= num_letters;\n+\t\ttemplate[2] = letters[v % num_letters]; v /= num_letters;\n+\t\ttemplate[3] = letters[v % num_letters]; v /= num_letters;\n+\t\ttemplate[4] = letters[v % num_letters]; v /= num_letters;\n+\t\ttemplate[5] = letters[v % num_letters]; v /= num_letters;\n+\n+\t\tfd = open(pattern, O_CREAT | O_EXCL | O_RDWR, mode);\n+\t\tif (fd > 0)\n+\t\t\treturn fd;\n+\t\t/*\n+\t\t * Fatal error (EPERM, ENOSPC etc).\n+\t\t * It doesn't make sense to loop.\n+\t\t */\n+\t\tif (errno != EEXIST)\n+\t\t\tbreak;\n+\t\t/*\n+\t\t * This is a random value.  It is only necessary that\n+\t\t * the next TMP_MAX values generated by adding 7777 to\n+\t\t * VALUE are different with (module 2^32).\n+\t\t */\n+\t\tvalue += 7777;\n+\t}\n+\t/* We return the null string if we can't find a unique file name.  */\n+\tpattern[0] = '\\0';\n+\treturn -1;\n+}\n+\n+int tigmkstemps(char *pattern, int suffix_len)\n+{\n+\treturn tig_mkstemps_mode(pattern, suffix_len, 0600);\n+}\n+\n+/*\n  * Executing external commands.\n  */\n \ndiff --git a/io.h b/io.h\nindex 646989d..8f43216 100644\n--- a/io.h\n+++ b/io.h\n@@ -16,6 +16,9 @@\n \n #include \"tig.h\"\n \n+/* Needed for mkstemps workaround */\n+#include <stdint.h>\n+\n /*\n  * Argument array helpers.\n  */\n@@ -41,6 +44,17 @@ struct encoding *encoding_open(const char *fromcode);\n char *encoding_convert(struct encoding *encoding, char *line);\n \n /*\n+ * Compatibility: no mkstemps()\n+ */\n+\n+#ifndef HAVE_MKSTEMPS\n+#define mkstemps tigmkstemps\n+#endif\n+\n+int tigmkstemps(char *, int);\n+int tig_mkstemps_mode(char *pattern, int suffix_len, int mode);\n+\n+/*\n  * Executing external commands.\n  */\n \n-- \n1.8.0\n"},{"id":"223634","messageId":"51E772E3.20008@gmail.com","threadId":"34391","inReplyTo":"1373383992-4298-1-git-send-email-n1xim.email@gmail.com","subject":"Re: [PATCH] TIG: Implement mkstemps() work-around for platforms lacking it","fromName":"Drew Northup","fromEmail":"n1xim.email@gmail.com","sentAt":"2013-07-18T04:45:23Z","receivedAt":"2013-07-18T04:45:23Z","isPatch":true,"sender":{"key":"n1xim.email@gmail.com","avatar":null},"body":"Giving this one last kick to make absolutely sure that nobody disagrees\nwith allowing this code to be included into tig, which does not limit\nto a specific version of the GPL (version 2 in the case of git, any\nversion equal to or newer than 2 in the case of tig), pursuant to\nparagraph 9 of said license.\n\nOn 07/09/2013 11:33 AM, Drew Northup wrote:\n> The function mkstemps() isn't available in all libc implementations. In\n> glibc it first became available in 2.11, so platforms such as RHEL 5&\n> Slackware 13 lack it. This is likely true of many non-LINUX platforms\n> as well.\n>\n> This fixes breakage that was introduced with a0fdac29 \"Create temporary\n> file with name as suffix.\"\n>\n> Signed-off-by: Drew Northup<n1xim.email@gmail.com>\n> ---\n>\n> This work-around is taken from Git and was inspired by code in libiberty.\n> It is presumed that this isn't a problem due to compatible license terms.\n>\n> A (virtually identical) version of this available in\n> https://github.com/n1xim/tig/tree/mkstemps_wkarnd (differences only in\n> the commit message).\n>\n>   configure.ac |  4 ++++\n>   io.c         | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n>   io.h         | 14 +++++++++++\n>   3 files changed, 95 insertions(+)\n>\n> diff --git a/configure.ac b/configure.ac\n> index 8dd2508..40e1f85 100644\n> --- a/configure.ac\n> +++ b/configure.ac\n> @@ -21,6 +21,10 @@ AC_SUBST(CURSES_LIB)\n>\n>   AM_ICONV\n>\n> +dnl  Not all platforms have mkstemps\n> +AC_CHECK_FUNC([mkstemps], [AC_DEFINE([HAVE_MKSTEMPS], [1],\n> +\t      [Define if mkstemps is available.])])\n> +\n>   AC_PROG_CC\n>\n>   AC_CHECK_PROGS(ASCIIDOC, [asciidoc], [false])\n> diff --git a/io.c b/io.c\n> index 3ff1d1c..f1b6fbc 100644\n> --- a/io.c\n> +++ b/io.c\n> @@ -237,6 +237,83 @@ encoding_convert(struct encoding *encoding, char *line)\n>   }\n>\n>   /*\n> + * Compatibility: no mkstemps()\n> + */\n> +\n> +/* Adapted from libiberty's mkstemp.c via Git's wrapper.c. */\n> +\n> +#undef TMP_MAX\n> +#define TMP_MAX 16384\n> +\n> +int tig_mkstemps_mode(char *pattern, int suffix_len, int mode)\n> +{\n> +\tstatic const char letters[] =\n> +\t\t\"abcdefghijklmnopqrstuvwxyz\"\n> +\t\t\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n> +\t\t\"0123456789\";\n> +\tstatic const int num_letters = 62;\n> +\tuint64_t value;\n> +\tstruct timeval tv;\n> +\tchar *template;\n> +\tsize_t len;\n> +\tint fd, count;\n> +\n> +\tlen = strlen(pattern);\n> +\n> +\tif (len<  6 + suffix_len) {\n> +\t\terrno = EINVAL;\n> +\t\treturn -1;\n> +\t}\n> +\n> +\tif (strncmp(&pattern[len - 6 - suffix_len], \"XXXXXX\", 6)) {\n> +\t\terrno = EINVAL;\n> +\t\treturn -1;\n> +\t}\n> +\n> +\t/*\n> +\t * Replace pattern's XXXXXX characters with randomness.\n> +\t * Try TMP_MAX different filenames.\n> +\t */\n> +\tgettimeofday(&tv, NULL);\n> +\tvalue = ((size_t)(tv.tv_usec<<  16)) ^ tv.tv_sec ^ getpid();\n> +\ttemplate =&pattern[len - 6 - suffix_len];\n> +\tfor (count = 0; count<  TMP_MAX; ++count) {\n> +\t\tuint64_t v = value;\n> +\t\t/* Fill in the random bits. */\n> +\t\ttemplate[0] = letters[v % num_letters]; v /= num_letters;\n> +\t\ttemplate[1] = letters[v % num_letters]; v /= num_letters;\n> +\t\ttemplate[2] = letters[v % num_letters]; v /= num_letters;\n> +\t\ttemplate[3] = letters[v % num_letters]; v /= num_letters;\n> +\t\ttemplate[4] = letters[v % num_letters]; v /= num_letters;\n> +\t\ttemplate[5] = letters[v % num_letters]; v /= num_letters;\n> +\n> +\t\tfd = open(pattern, O_CREAT | O_EXCL | O_RDWR, mode);\n> +\t\tif (fd>  0)\n> +\t\t\treturn fd;\n> +\t\t/*\n> +\t\t * Fatal error (EPERM, ENOSPC etc).\n> +\t\t * It doesn't make sense to loop.\n> +\t\t */\n> +\t\tif (errno != EEXIST)\n> +\t\t\tbreak;\n> +\t\t/*\n> +\t\t * This is a random value.  It is only necessary that\n> +\t\t * the next TMP_MAX values generated by adding 7777 to\n> +\t\t * VALUE are different with (module 2^32).\n> +\t\t */\n> +\t\tvalue += 7777;\n> +\t}\n> +\t/* We return the null string if we can't find a unique file name.  */\n> +\tpattern[0] = '\\0';\n> +\treturn -1;\n> +}\n> +\n> +int tigmkstemps(char *pattern, int suffix_len)\n> +{\n> +\treturn tig_mkstemps_mode(pattern, suffix_len, 0600);\n> +}\n> +\n> +/*\n>    * Executing external commands.\n>    */\n>\n> diff --git a/io.h b/io.h\n> index 646989d..8f43216 100644\n> --- a/io.h\n> +++ b/io.h\n> @@ -16,6 +16,9 @@\n>\n>   #include \"tig.h\"\n>\n> +/* Needed for mkstemps workaround */\n> +#include<stdint.h>\n> +\n>   /*\n>    * Argument array helpers.\n>    */\n> @@ -41,6 +44,17 @@ struct encoding *encoding_open(const char *fromcode);\n>   char *encoding_convert(struct encoding *encoding, char *line);\n>\n>   /*\n> + * Compatibility: no mkstemps()\n> + */\n> +\n> +#ifndef HAVE_MKSTEMPS\n> +#define mkstemps tigmkstemps\n> +#endif\n> +\n> +int tigmkstemps(char *, int);\n> +int tig_mkstemps_mode(char *pattern, int suffix_len, int mode);\n> +\n> +/*\n>    * Executing external commands.\n>    */\n>\n"}]}