{"thread":{"id":"19554","subject":"[PATCH v3 1/2] compat: add a mkstemps() compatibility function","startedAt":"2009-05-28T09:43:50Z","lastAt":"2009-06-03T23:33:36Z","messageCount":6,"participants":["David Aguilar","Antriksh Pany","Johannes Sixt"],"isPatch":true,"patchVersion":3,"patchTotal":2},"messages":[{"id":"114912","messageId":"1243503831-17993-1-git-send-email-davvid@gmail.com","threadId":"19554","inReplyTo":null,"subject":"[PATCH v3 1/2] compat: add a mkstemps() compatibility function","fromName":"David Aguilar","fromEmail":"davvid@gmail.com","sentAt":"2009-05-28T09:43:50Z","receivedAt":"2009-05-28T09:43:50Z","isPatch":true,"sender":{"key":"davvid@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13196?v=4"},"body":"mkstemps() is a BSD extension so provide an implementation\nfor cross-platform use.\n\nSigned-off-by: David Aguilar <davvid@gmail.com>\nTested-by: Johannes Sixt <j6t@kdbg.org> (Windows)\n---\n Makefile          |   19 +++++++++++++++\n compat/mkstemps.c |   67 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n config.mak.in     |    1 +\n configure.ac      |    6 ++++\n git-compat-util.h |    5 ++++\n 5 files changed, 98 insertions(+), 0 deletions(-)\n create mode 100644 compat/mkstemps.c\n\ndiff --git a/Makefile b/Makefile\nindex eaae45d..a70b5f0 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -52,6 +52,8 @@ all::\n #\n # Define NO_MKDTEMP if you don't have mkdtemp in the C library.\n #\n+# Define NO_MKSTEMPS if you don't have mkstemps in the C library.\n+#\n # Define NO_SYS_SELECT_H if you don't have sys/select.h.\n #\n # Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link.\n@@ -636,10 +638,12 @@ EXTLIBS =\n \n ifeq ($(uname_S),Linux)\n \tNO_STRLCPY = YesPlease\n+\tNO_MKSTEMPS = YesPlease\n \tTHREADED_DELTA_SEARCH = YesPlease\n endif\n ifeq ($(uname_S),GNU/kFreeBSD)\n \tNO_STRLCPY = YesPlease\n+\tNO_MKSTEMPS = YesPlease\n \tTHREADED_DELTA_SEARCH = YesPlease\n endif\n ifeq ($(uname_S),UnixWare)\n@@ -651,6 +655,7 @@ ifeq ($(uname_S),UnixWare)\n \tSHELL_PATH = /usr/local/bin/bash\n \tNO_IPV6 = YesPlease\n \tNO_HSTRERROR = YesPlease\n+\tNO_MKSTEMPS = YesPlease\n \tBASIC_CFLAGS += -Kthread\n \tBASIC_CFLAGS += -I/usr/local/include\n \tBASIC_LDFLAGS += -L/usr/local/lib\n@@ -674,6 +679,7 @@ ifeq ($(uname_S),SCO_SV)\n \tSHELL_PATH = /usr/bin/bash\n \tNO_IPV6 = YesPlease\n \tNO_HSTRERROR = YesPlease\n+\tNO_MKSTEMPS = YesPlease\n \tBASIC_CFLAGS += -I/usr/local/include\n \tBASIC_LDFLAGS += -L/usr/local/lib\n \tNO_STRCASESTR = YesPlease\n@@ -702,6 +708,7 @@ ifeq ($(uname_S),SunOS)\n \tNO_MEMMEM = YesPlease\n \tNO_HSTRERROR = YesPlease\n \tNO_MKDTEMP = YesPlease\n+\tNO_MKSTEMPS = YesPlease\n \tOLD_ICONV = UnfortunatelyYes\n \tifeq ($(uname_R),5.8)\n \t\tNO_UNSETENV = YesPlease\n@@ -724,6 +731,7 @@ ifeq ($(uname_O),Cygwin)\n \tNO_D_INO_IN_DIRENT = YesPlease\n \tNO_STRCASESTR = YesPlease\n \tNO_MEMMEM = YesPlease\n+\tNO_MKSTEMPS = YesPlease\n \tNO_SYMLINK_HEAD = YesPlease\n \tNEEDS_LIBICONV = YesPlease\n \tNO_FAST_WORKING_DIRECTORY = UnfortunatelyYes\n@@ -767,11 +775,13 @@ ifeq ($(uname_S),NetBSD)\n \tBASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib\n \tTHREADED_DELTA_SEARCH = YesPlease\n \tUSE_ST_TIMESPEC = YesPlease\n+\tNO_MKSTEMPS = YesPlease\n endif\n ifeq ($(uname_S),AIX)\n \tNO_STRCASESTR=YesPlease\n \tNO_MEMMEM = YesPlease\n \tNO_MKDTEMP = YesPlease\n+\tNO_MKSTEMPS = YesPlease\n \tNO_STRLCPY = YesPlease\n \tNO_NSEC = YesPlease\n \tFREAD_READS_DIRECTORIES = UnfortunatelyYes\n@@ -787,12 +797,14 @@ endif\n ifeq ($(uname_S),GNU)\n \t# GNU/Hurd\n \tNO_STRLCPY=YesPlease\n+\tNO_MKSTEMPS = YesPlease\n endif\n ifeq ($(uname_S),IRIX64)\n \tNO_IPV6=YesPlease\n \tNO_SETENV=YesPlease\n \tNO_STRCASESTR=YesPlease\n \tNO_MEMMEM = YesPlease\n+\tNO_MKSTEMPS = YesPlease\n \tNO_STRLCPY = YesPlease\n \tNO_SOCKADDR_STORAGE=YesPlease\n \tSHELL_PATH=/usr/gnu/bin/bash\n@@ -805,6 +817,7 @@ ifeq ($(uname_S),HP-UX)\n \tNO_SETENV=YesPlease\n \tNO_STRCASESTR=YesPlease\n \tNO_MEMMEM = YesPlease\n+\tNO_MKSTEMPS = YesPlease\n \tNO_STRLCPY = YesPlease\n \tNO_MKDTEMP = YesPlease\n \tNO_UNSETENV = YesPlease\n@@ -834,6 +847,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))\n \tNO_C99_FORMAT = YesPlease\n \tNO_STRTOUMAX = YesPlease\n \tNO_MKDTEMP = YesPlease\n+\tNO_MKSTEMPS = YesPlease\n \tSNPRINTF_RETURNS_BOGUS = YesPlease\n \tNO_SVN_TESTS = YesPlease\n \tNO_PERL_MAKEMAKER = YesPlease\n@@ -853,6 +867,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))\n endif\n ifneq (,$(findstring arm,$(uname_M)))\n \tARM_SHA1 = YesPlease\n+\tNO_MKSTEMPS = YesPlease\n endif\n \n -include config.mak.autogen\n@@ -1011,6 +1026,10 @@ ifdef NO_MKDTEMP\n \tCOMPAT_CFLAGS += -DNO_MKDTEMP\n \tCOMPAT_OBJS += compat/mkdtemp.o\n endif\n+ifdef NO_MKSTEMPS\n+\tCOMPAT_CFLAGS += -DNO_MKSTEMPS\n+\tCOMPAT_OBJS += compat/mkstemps.o\n+endif\n ifdef NO_UNSETENV\n \tCOMPAT_CFLAGS += -DNO_UNSETENV\n \tCOMPAT_OBJS += compat/unsetenv.o\ndiff --git a/compat/mkstemps.c b/compat/mkstemps.c\nnew file mode 100644\nindex 0000000..87ebc2a\n--- /dev/null\n+++ b/compat/mkstemps.c\n@@ -0,0 +1,67 @@\n+#include \"../git-compat-util.h\"\n+\n+#ifndef TMP_MAX\n+#define TMP_MAX 16384\n+#endif\n+\n+/* Adapted from libiberty's mkstemp.c. */\n+int gitmkstemps(char *pattern, int suffix_len)\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/* 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, 0600);\n+\t\tif (fd > 0)\n+\t\t\treturn fd;\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/* 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+\terrno = EINVAL;\n+\treturn -1;\n+}\ndiff --git a/config.mak.in b/config.mak.in\nindex 7cce0c1..b6619af 100644\n--- a/config.mak.in\n+++ b/config.mak.in\n@@ -46,6 +46,7 @@ NO_STRTOUMAX=@NO_STRTOUMAX@\n NO_SETENV=@NO_SETENV@\n NO_UNSETENV=@NO_UNSETENV@\n NO_MKDTEMP=@NO_MKDTEMP@\n+NO_MKSTEMPS=@NO_MKSTEMPS@\n NO_ICONV=@NO_ICONV@\n OLD_ICONV=@OLD_ICONV@\n NO_DEFLATE_BOUND=@NO_DEFLATE_BOUND@\ndiff --git a/configure.ac b/configure.ac\nindex 4e728bc..95dccd4 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -676,6 +676,12 @@ GIT_CHECK_FUNC(mkdtemp,\n [NO_MKDTEMP=],\n [NO_MKDTEMP=YesPlease])\n AC_SUBST(NO_MKDTEMP)\n+# Define NO_MKSTEMPS if you don't have mkstemps in the C library.\n+GIT_CHECK_FUNC(mkstemps,\n+[NO_MKSTEMPS=],\n+[NO_MKSTEMPS=YesPlease])\n+AC_SUBST(NO_MKSTEMPS)\n+#\n #\n # Define NO_MMAP if you want to avoid mmap.\n #\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex c7cf2d5..f7217ad 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -232,6 +232,11 @@ extern int gitsetenv(const char *, const char *, int);\n extern char *gitmkdtemp(char *);\n #endif\n \n+#ifdef NO_MKSTEMPS\n+#define mkstemps gitmkstemps\n+extern int gitmkstemps(char *, int);\n+#endif\n+\n #ifdef NO_UNSETENV\n #define unsetenv gitunsetenv\n extern void gitunsetenv(const char *);\n-- \n1.6.3.1.169.g33fd\n"},{"id":"114913","messageId":"1243503831-17993-2-git-send-email-davvid@gmail.com","threadId":"19554","inReplyTo":"1243503831-17993-1-git-send-email-davvid@gmail.com","subject":"[PATCH v3 2/2] diff: generate prettier filenames when using GIT_EXTERNAL_DIFF","fromName":"David Aguilar","fromEmail":"davvid@gmail.com","sentAt":"2009-05-28T09:43:51Z","receivedAt":"2009-05-28T09:43:51Z","isPatch":true,"sender":{"key":"davvid@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13196?v=4"},"body":"Naturally, prep_temp_blob() did not care about filenames.\nAs a result, scripts that use GIT_EXTERNAL_DIFF ended up\nwith filenames such as \".diff_XXXXXX\".\n\nThis specializes the GIT_EXTERNAL_DIFF code to generate\nuser-friendly filenames when creating temporary files.\n\nDiffing \"name.ext\" now generates \"XXXXXX_name.ext\".\n\nSigned-off-by: David Aguilar <davvid@gmail.com>\nTested-by: Johannes Sixt <j6t@kdbg.org> (Windows)\n---\n cache.h                  |    2 ++\n diff.c                   |   45 +++++++++++++++++++++++++++++++++++++--------\n path.c                   |   19 +++++++++++++++++++\n t/t4020-diff-external.sh |    9 +++++++++\n 4 files changed, 67 insertions(+), 8 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex b8503ad..871c984 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -614,6 +614,8 @@ extern int is_empty_blob_sha1(const unsigned char *sha1);\n \n int git_mkstemp(char *path, size_t n, const char *template);\n \n+int git_mkstemps(char *path, size_t n, const char *template, int suffix_len);\n+\n /*\n  * NOTE NOTE NOTE!!\n  *\ndiff --git a/diff.c b/diff.c\nindex dcfbcb0..60f07a0 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1960,12 +1960,37 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp,\n \t\t\t   void *blob,\n \t\t\t   unsigned long size,\n \t\t\t   const unsigned char *sha1,\n-\t\t\t   int mode)\n+\t\t\t   int mode,\n+\t\t\t   int pretty_filename)\n {\n \tint fd;\n \tstruct strbuf buf = STRBUF_INIT;\n \n-\tfd = git_mkstemp(temp->tmp_path, PATH_MAX, \".diff_XXXXXX\");\n+\tif (pretty_filename) {\n+\t\t/* Generate \"XXXXXX_filename\" */\n+\t\tstruct strbuf pretty_name = STRBUF_INIT;\n+\t\tchar *basename = ((char*)path) + strlen(path) - 1;\n+\n+\t\t/* Windows lacks basename() */\n+\t\twhile(*basename && basename > path) {\n+\t\t\tbasename--;\n+\t\t\tif (is_dir_sep(*basename)) {\n+\t\t\t\tbasename++;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tstrbuf_addstr(&pretty_name, \"XXXXXX_\");\n+\t\tstrbuf_addstr(&pretty_name, basename);\n+\n+\t\tfd = git_mkstemps(temp->tmp_path, PATH_MAX,\n+\t\t\tpretty_name.buf, strlen(basename) + 1);\n+\n+\t\tstrbuf_release(&pretty_name);\n+\t}\n+\telse {\n+\t\tfd = git_mkstemp(temp->tmp_path, PATH_MAX, \".diff_XXXXXX\");\n+\t}\n \tif (fd < 0)\n \t\tdie(\"unable to create temp-file: %s\", strerror(errno));\n \tif (convert_to_working_tree(path,\n@@ -1984,7 +2009,8 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp,\n }\n \n static struct diff_tempfile *prepare_temp_file(const char *name,\n-\t\tstruct diff_filespec *one)\n+\t\tstruct diff_filespec *one,\n+\t\tint pretty_filename)\n {\n \tstruct diff_tempfile *temp = claim_diff_tempfile();\n \n@@ -2021,7 +2047,8 @@ static struct diff_tempfile *prepare_temp_file(const char *name,\n \t\t\t\t       (one->sha1_valid ?\n \t\t\t\t\tone->sha1 : null_sha1),\n \t\t\t\t       (one->sha1_valid ?\n-\t\t\t\t\tone->mode : S_IFLNK));\n+\t\t\t\t\tone->mode : S_IFLNK),\n+\t\t\t\t       pretty_filename);\n \t\t\tstrbuf_release(&sb);\n \t\t}\n \t\telse {\n@@ -2045,7 +2072,7 @@ static struct diff_tempfile *prepare_temp_file(const char *name,\n \t\tif (diff_populate_filespec(one, 0))\n \t\t\tdie(\"cannot read data blob for %s\", one->path);\n \t\tprep_temp_blob(name, temp, one->data, one->size,\n-\t\t\t       one->sha1, one->mode);\n+\t\t\t       one->sha1, one->mode, pretty_filename);\n \t}\n \treturn temp;\n }\n@@ -2071,8 +2098,9 @@ static void run_external_diff(const char *pgm,\n \tif (one && two) {\n \t\tstruct diff_tempfile *temp_one, *temp_two;\n \t\tconst char *othername = (other ? other : name);\n-\t\ttemp_one = prepare_temp_file(name, one);\n-\t\ttemp_two = prepare_temp_file(othername, two);\n+\t\tint pretty_filename = 1;\n+\t\ttemp_one = prepare_temp_file(name, one, pretty_filename);\n+\t\ttemp_two = prepare_temp_file(othername, two, pretty_filename);\n \t\t*arg++ = pgm;\n \t\t*arg++ = name;\n \t\t*arg++ = temp_one->name;\n@@ -3574,8 +3602,9 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec,\n \tconst char **arg = argv;\n \tstruct child_process child;\n \tstruct strbuf buf = STRBUF_INIT;\n+\tint pretty_filename = 0;\n \n-\ttemp = prepare_temp_file(spec->path, spec);\n+\ttemp = prepare_temp_file(spec->path, spec, pretty_filename);\n \t*arg++ = pgm;\n \t*arg++ = temp->name;\n \t*arg = NULL;\ndiff --git a/path.c b/path.c\nindex 8a0a674..090b490 100644\n--- a/path.c\n+++ b/path.c\n@@ -140,6 +140,25 @@ int git_mkstemp(char *path, size_t len, const char *template)\n }\n \n \n+\n+/* git_mkstemps() - create tmp file with suffix honoring TMPDIR variable. */\n+int git_mkstemps(char *path, size_t len, const char *template, int suffix_len)\n+{\n+\tconst char *tmp;\n+\tsize_t n;\n+\n+\ttmp = getenv(\"TMPDIR\");\n+\tif (!tmp)\n+\t\ttmp = \"/tmp\";\n+\tn = snprintf(path, len, \"%s/%s\", tmp, template);\n+\tif (len <= n) {\n+\t\terrno = ENAMETOOLONG;\n+\t\treturn -1;\n+\t}\n+\treturn mkstemps(path, suffix_len);\n+}\n+\n+\n int validate_headref(const char *path)\n {\n \tstruct stat st;\ndiff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh\nindex 0720001..4ea42e0 100755\n--- a/t/t4020-diff-external.sh\n+++ b/t/t4020-diff-external.sh\n@@ -136,6 +136,15 @@ test_expect_success 'GIT_EXTERNAL_DIFF with more than one changed files' '\n \tGIT_EXTERNAL_DIFF=echo git diff\n '\n \n+test_expect_success 'GIT_EXTERNAL_DIFF generates pretty paths' '\n+\ttouch file.ext &&\n+\tgit add file.ext &&\n+\techo with extension > file.ext &&\n+\tGIT_EXTERNAL_DIFF=echo git diff file.ext | grep ......_file\\.ext &&\n+\tgit update-index --force-remove file.ext &&\n+\trm file.ext\n+'\n+\n echo \"#!$SHELL_PATH\" >fake-diff.sh\n cat >> fake-diff.sh <<\\EOF\n cat $2 >> crlfed.txt\n-- \n1.6.3.1.169.g33fd\n"},{"id":"115238","messageId":"e6cd6cf90906020535m24d588eau40b800555c9e906f@mail.gmail.com","threadId":"19554","inReplyTo":"1243503831-17993-1-git-send-email-davvid@gmail.com","subject":"Re: [PATCH v3 1/2] compat: add a mkstemps() compatibility function","fromName":"Antriksh Pany","fromEmail":"antriksh.pany@gmail.com","sentAt":"2009-06-02T12:35:39Z","receivedAt":"2009-06-02T12:35:39Z","isPatch":true,"sender":{"key":"antriksh.pany@gmail.com","avatar":null},"body":"Hi David\n\nI think I see a few minor issues with the code dealing with random six\nletters generation. Please correct me if I am wrong.\n\nOn Thu, May 28, 2009 at 3:13 PM, David Aguilar <davvid@gmail.com> wrote:\n> mkstemps() is a BSD extension so provide an implementation\n> for cross-platform use.\n>\n> Signed-off-by: David Aguilar <davvid@gmail.com>\n> Tested-by: Johannes Sixt <j6t@kdbg.org> (Windows)\n> ---\n>  Makefile          |   19 +++++++++++++++\n>  compat/mkstemps.c |   67 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n>  config.mak.in     |    1 +\n>  configure.ac      |    6 ++++\n>  git-compat-util.h |    5 ++++\n>  5 files changed, 98 insertions(+), 0 deletions(-)\n>  create mode 100644 compat/mkstemps.c\n>\n> diff --git a/Makefile b/Makefile\n> index eaae45d..a70b5f0 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -52,6 +52,8 @@ all::\n>  #\n>  # Define NO_MKDTEMP if you don't have mkdtemp in the C library.\n>  #\n> +# Define NO_MKSTEMPS if you don't have mkstemps in the C library.\n> +#\n>  # Define NO_SYS_SELECT_H if you don't have sys/select.h.\n>  #\n>  # Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link.\n> @@ -636,10 +638,12 @@ EXTLIBS =\n>\n>  ifeq ($(uname_S),Linux)\n>        NO_STRLCPY = YesPlease\n> +       NO_MKSTEMPS = YesPlease\n>        THREADED_DELTA_SEARCH = YesPlease\n>  endif\n>  ifeq ($(uname_S),GNU/kFreeBSD)\n>        NO_STRLCPY = YesPlease\n> +       NO_MKSTEMPS = YesPlease\n>        THREADED_DELTA_SEARCH = YesPlease\n>  endif\n>  ifeq ($(uname_S),UnixWare)\n> @@ -651,6 +655,7 @@ ifeq ($(uname_S),UnixWare)\n>        SHELL_PATH = /usr/local/bin/bash\n>        NO_IPV6 = YesPlease\n>        NO_HSTRERROR = YesPlease\n> +       NO_MKSTEMPS = YesPlease\n>        BASIC_CFLAGS += -Kthread\n>        BASIC_CFLAGS += -I/usr/local/include\n>        BASIC_LDFLAGS += -L/usr/local/lib\n> @@ -674,6 +679,7 @@ ifeq ($(uname_S),SCO_SV)\n>        SHELL_PATH = /usr/bin/bash\n>        NO_IPV6 = YesPlease\n>        NO_HSTRERROR = YesPlease\n> +       NO_MKSTEMPS = YesPlease\n>        BASIC_CFLAGS += -I/usr/local/include\n>        BASIC_LDFLAGS += -L/usr/local/lib\n>        NO_STRCASESTR = YesPlease\n> @@ -702,6 +708,7 @@ ifeq ($(uname_S),SunOS)\n>        NO_MEMMEM = YesPlease\n>        NO_HSTRERROR = YesPlease\n>        NO_MKDTEMP = YesPlease\n> +       NO_MKSTEMPS = YesPlease\n>        OLD_ICONV = UnfortunatelyYes\n>        ifeq ($(uname_R),5.8)\n>                NO_UNSETENV = YesPlease\n> @@ -724,6 +731,7 @@ ifeq ($(uname_O),Cygwin)\n>        NO_D_INO_IN_DIRENT = YesPlease\n>        NO_STRCASESTR = YesPlease\n>        NO_MEMMEM = YesPlease\n> +       NO_MKSTEMPS = YesPlease\n>        NO_SYMLINK_HEAD = YesPlease\n>        NEEDS_LIBICONV = YesPlease\n>        NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes\n> @@ -767,11 +775,13 @@ ifeq ($(uname_S),NetBSD)\n>        BASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib\n>        THREADED_DELTA_SEARCH = YesPlease\n>        USE_ST_TIMESPEC = YesPlease\n> +       NO_MKSTEMPS = YesPlease\n>  endif\n>  ifeq ($(uname_S),AIX)\n>        NO_STRCASESTR=YesPlease\n>        NO_MEMMEM = YesPlease\n>        NO_MKDTEMP = YesPlease\n> +       NO_MKSTEMPS = YesPlease\n>        NO_STRLCPY = YesPlease\n>        NO_NSEC = YesPlease\n>        FREAD_READS_DIRECTORIES = UnfortunatelyYes\n> @@ -787,12 +797,14 @@ endif\n>  ifeq ($(uname_S),GNU)\n>        # GNU/Hurd\n>        NO_STRLCPY=YesPlease\n> +       NO_MKSTEMPS = YesPlease\n>  endif\n>  ifeq ($(uname_S),IRIX64)\n>        NO_IPV6=YesPlease\n>        NO_SETENV=YesPlease\n>        NO_STRCASESTR=YesPlease\n>        NO_MEMMEM = YesPlease\n> +       NO_MKSTEMPS = YesPlease\n>        NO_STRLCPY = YesPlease\n>        NO_SOCKADDR_STORAGE=YesPlease\n>        SHELL_PATH=/usr/gnu/bin/bash\n> @@ -805,6 +817,7 @@ ifeq ($(uname_S),HP-UX)\n>        NO_SETENV=YesPlease\n>        NO_STRCASESTR=YesPlease\n>        NO_MEMMEM = YesPlease\n> +       NO_MKSTEMPS = YesPlease\n>        NO_STRLCPY = YesPlease\n>        NO_MKDTEMP = YesPlease\n>        NO_UNSETENV = YesPlease\n> @@ -834,6 +847,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))\n>        NO_C99_FORMAT = YesPlease\n>        NO_STRTOUMAX = YesPlease\n>        NO_MKDTEMP = YesPlease\n> +       NO_MKSTEMPS = YesPlease\n>        SNPRINTF_RETURNS_BOGUS = YesPlease\n>        NO_SVN_TESTS = YesPlease\n>        NO_PERL_MAKEMAKER = YesPlease\n> @@ -853,6 +867,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))\n>  endif\n>  ifneq (,$(findstring arm,$(uname_M)))\n>        ARM_SHA1 = YesPlease\n> +       NO_MKSTEMPS = YesPlease\n>  endif\n>\n>  -include config.mak.autogen\n> @@ -1011,6 +1026,10 @@ ifdef NO_MKDTEMP\n>        COMPAT_CFLAGS += -DNO_MKDTEMP\n>        COMPAT_OBJS += compat/mkdtemp.o\n>  endif\n> +ifdef NO_MKSTEMPS\n> +       COMPAT_CFLAGS += -DNO_MKSTEMPS\n> +       COMPAT_OBJS += compat/mkstemps.o\n> +endif\n>  ifdef NO_UNSETENV\n>        COMPAT_CFLAGS += -DNO_UNSETENV\n>        COMPAT_OBJS += compat/unsetenv.o\n> diff --git a/compat/mkstemps.c b/compat/mkstemps.c\n> new file mode 100644\n> index 0000000..87ebc2a\n> --- /dev/null\n> +++ b/compat/mkstemps.c\n> @@ -0,0 +1,67 @@\n> +#include \"../git-compat-util.h\"\n> +\n> +#ifndef TMP_MAX\n> +#define TMP_MAX 16384\n> +#endif\n> +\n> +/* Adapted from libiberty's mkstemp.c. */\n> +int gitmkstemps(char *pattern, int suffix_len)\n> +{\n> +       static const char letters[] =\n> +               \"abcdefghijklmnopqrstuvwxyz\"\n> +               \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n> +               \"0123456789\";\n> +       static const int num_letters = 62;\n> +       uint64_t value;\n> +       struct timeval tv;\n> +       char *template;\n> +       size_t len;\n> +       int fd, count;\n> +\n> +       len = strlen(pattern);\n> +\n> +       if (len < 6 + suffix_len) {\n> +               errno = EINVAL;\n> +               return -1;\n> +       }\n> +\n> +       if (strncmp(&pattern[len - 6 - suffix_len], \"XXXXXX\", 6)) {\n> +               errno = EINVAL;\n> +               return -1;\n> +       }\n> +\n> +       /* Replace pattern's XXXXXX characters with randomness.\n> +        * Try TMP_MAX different filenames.\n> +        */\n> +       gettimeofday(&tv, NULL);\n> +       value = ((size_t)(tv.tv_usec << 16)) ^ tv.tv_sec ^ getpid();\n> +       template = &pattern[len - 6 - suffix_len];\n> +       for (count = 0; count < TMP_MAX; ++count) {\n> +               uint64_t v = value;\n> +               /* Fill in the random bits. */\n> +               template[0] = letters[v % num_letters]; v/= num_letters;\n> +               template[1] = letters[v % num_letters]; v/= num_letters;\n> +               template[2] = letters[v % num_letters]; v/= num_letters;\n> +               template[3] = letters[v % num_letters]; v/= num_letters;\n> +               template[4] = letters[v % num_letters]; v/= num_letters;\n> +               template[5] = letters[v % num_letters]; v/= num_letters;\n\nv is divided 6 times by 62, and a decent amount of randomness shall be\nensured only if 'value' is usually greater than 62^6.\n\nIf it is assumed to be ok for 'v' to become zero in the last one odd\nsteps sometimes (in fact, _frequently_), then you may ignore what I am\npointing out here.\n\n1. On a couple of systems that I checked on, all variables/types on\nthe right hand side of\n      value = ((size_t)(tv.tv_usec << 16)) ^ tv.tv_sec ^ getpid();\nare 4 bytes long. So 'value' is ultimately going to be assigned a\nnumber that fits in 4 bytes, ie value < 2^32 (at least on a few\nsystems).\nThe systems that I checked on have these `uname -a` outputs:\n-   Linux host 2.6.9-55.ELsmp #1 SMP Fri Apr 20 17:03:35 EDT 2007 i686\ni686 i386 GNU/Linux\n-   Linux host 2.4.21-50.ELsmp #1 SMP Tue May 8 17:18:29 EDT 2007 i686\ni686 i386 GNU/Linux\n\nAlso, even if size_t were 64 bits, typecasting _after_ the shift does\nnot help much. And given the uncertainty about sizeof (size_t), we\ncould use:\n  ((uint64_t) tv.tv_usec) << 16)\n\n\n2. tv_usec has a decimal value range of 0-999999  (10^6 usec make 1\nsec). Which means that tv_usec fits completely in 20 bits (or less).\n(tv_usec << 16) yields a number that fits completely in 36 bits (or\nless). Max value of this number is 999999 * 2^16, or for convenience,\nabout M = 10^6 * 2^16. This number (in the range of 0 to M) goes on to\nbe divided by D=62^6. Also, M > D. Thus, there is about a  D / M * 100\n~ 87 % probability of the division M / D working out to be zero. i.e,\nin 87% cases, the last division (v/= num_letters) will cause 'v' to\nbecome 0.\nTherefore, I think an additional shift of 7 or more bits will help in\nimproving randomness of template[5]. I would suggest left shifting by\n24 bits. This seemed ok in some tests I did.\n\n\nCombining #1 and #2, I guess we could have the computation of 'value' as:\n      value = (((uint64_t)tv.tv_usec) << 24) ^ tv.tv_sec ^ getpid();\n\n\n- Antriksh\n"},{"id":"115241","messageId":"4A252381.9000103@viscovery.net","threadId":"19554","inReplyTo":"e6cd6cf90906020535m24d588eau40b800555c9e906f@mail.gmail.com","subject":"Re: [PATCH v3 1/2] compat: add a mkstemps() compatibility function","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2009-06-02T13:05:05Z","receivedAt":"2009-06-02T13:05:05Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Antriksh Pany schrieb:\n> 2. tv_usec has a decimal value range of 0-999999  (10^6 usec make 1\n> sec). Which means that tv_usec fits completely in 20 bits (or less).\n> (tv_usec << 16) yields a number that fits completely in 36 bits (or\n> less). Max value of this number is 999999 * 2^16, or for convenience,\n> about M = 10^6 * 2^16. This number (in the range of 0 to M) goes on to\n> be divided by D=62^6. Also, M > D. Thus, there is about a  D / M * 100\n> ~ 87 % probability of the division M / D working out to be zero. i.e,\n> in 87% cases, the last division (v/= num_letters) will cause 'v' to\n> become 0.\n\nBut this value (after the 6th division, mind you) is not used. v is used\nthe last time after the 5th division; at this time it still carries enough\nrandomness: 62^5 < 2^32.\n\n-- Hannes\n"},{"id":"115350","messageId":"e6cd6cf90906030859m2725856cl77e210d87e261df0@mail.gmail.com","threadId":"19554","inReplyTo":"4A252381.9000103@viscovery.net","subject":"Re: [PATCH v3 1/2] compat: add a mkstemps() compatibility function","fromName":"Antriksh Pany","fromEmail":"antriksh.pany@gmail.com","sentAt":"2009-06-03T15:59:06Z","receivedAt":"2009-06-03T15:59:06Z","isPatch":true,"sender":{"key":"antriksh.pany@gmail.com","avatar":null},"body":"Oh ok, didn't realize the sixth division was not used. In which case,\nwe needn't have the sixth division.\n\nAlso, 62^5 compared to 2^32 still gives a ~ 21% probability of the\nfifth division becoming zero, fairly high perhaps.\n\nThe suggestion to change the code to\n   ((uint64_t) tv.tv_usec) << 16)\nmight help here. This would still leave about a 1.4% chance of v\nbecoming zero, higher than (being pedantic!) what perfect randomness\nwould require. Livable. But (just curious), do we see any loss in\nshifting a few more positions?\n\n- Antriksh\n\n\nOn Tue, Jun 2, 2009 at 6:35 PM, Johannes Sixt <j.sixt@viscovery.net> wrote:\n> Antriksh Pany schrieb:\n>> 2. tv_usec has a decimal value range of 0-999999  (10^6 usec make 1\n>> sec). Which means that tv_usec fits completely in 20 bits (or less).\n>> (tv_usec << 16) yields a number that fits completely in 36 bits (or\n>> less). Max value of this number is 999999 * 2^16, or for convenience,\n>> about M = 10^6 * 2^16. This number (in the range of 0 to M) goes on to\n>> be divided by D=62^6. Also, M > D. Thus, there is about a  D / M * 100\n>> ~ 87 % probability of the division M / D working out to be zero. i.e,\n>> in 87% cases, the last division (v/= num_letters) will cause 'v' to\n>> become 0.\n>\n> But this value (after the 6th division, mind you) is not used. v is used\n> the last time after the 5th division; at this time it still carries enough\n> randomness: 62^5 < 2^32.\n>\n> -- Hannes\n>\n>\n"},{"id":"115397","messageId":"20090603233335.GB8362@gmail.com","threadId":"19554","inReplyTo":"e6cd6cf90906030859m2725856cl77e210d87e261df0@mail.gmail.com","subject":"Re: [PATCH v3 1/2] compat: add a mkstemps() compatibility function","fromName":"David Aguilar","fromEmail":"davvid@gmail.com","sentAt":"2009-06-03T23:33:36Z","receivedAt":"2009-06-03T23:33:36Z","isPatch":true,"sender":{"key":"davvid@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13196?v=4"},"body":"On Wed, Jun 03, 2009 at 09:29:06PM +0530, Antriksh Pany wrote:\n> Oh ok, didn't realize the sixth division was not used. In which case,\n> we needn't have the sixth division.\n> \n> Also, 62^5 compared to 2^32 still gives a ~ 21% probability of the\n> fifth division becoming zero, fairly high perhaps.\n> \n> The suggestion to change the code to\n>    ((uint64_t) tv.tv_usec) << 16)\n> might help here. This would still leave about a 1.4% chance of v\n> becoming zero, higher than (being pedantic!) what perfect randomness\n> would require. Livable. But (just curious), do we see any loss in\n> shifting a few more positions?\n> \n> - Antriksh\n\n\nJust a small note -- our mkstemps was adapted from\nlibiberty's mkstemps.c (gcc-4.something), so if there is\nindeed something to fix here then we should let them know.\n\nI looked in libiberty since I assumed that the code in there\nwas battle-tested and stable.\n\nI feel okay with it as-is, but that's just me.\n\n\n\n> On Tue, Jun 2, 2009 at 6:35 PM, Johannes Sixt <j.sixt@viscovery.net> wrote:\n> > Antriksh Pany schrieb:\n> >> 2. tv_usec has a decimal value range of 0-999999  (10^6 usec make 1\n> >> sec). Which means that tv_usec fits completely in 20 bits (or less).\n> >> (tv_usec << 16) yields a number that fits completely in 36 bits (or\n> >> less). Max value of this number is 999999 * 2^16, or for convenience,\n> >> about M = 10^6 * 2^16. This number (in the range of 0 to M) goes on to\n> >> be divided by D=62^6. Also, M > D. Thus, there is about a  D / M * 100\n> >> ~ 87 % probability of the division M / D working out to be zero. i.e,\n> >> in 87% cases, the last division (v/= num_letters) will cause 'v' to\n> >> become 0.\n> >\n> > But this value (after the 6th division, mind you) is not used. v is used\n> > the last time after the 5th division; at this time it still carries enough\n> > randomness: 62^5 < 2^32.\n> >\n> > -- Hannes\n> >\n> >\n\n-- \n\t\tDavid\n"}]}