Skip to content

Commit 00787ed

Browse files
moygitster
authored andcommitted
Move gitmkstemps to path.c
This function used to be only a compatibility function, but we're going to extend it and actually use it, so make it part of Git. Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 7aba618 commit 00787ed

File tree

3 files changed

+69
-71
lines changed

3 files changed

+69
-71
lines changed

Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1200,7 +1200,6 @@ ifdef NO_MKDTEMP
12001200
endif
12011201
ifdef NO_MKSTEMPS
12021202
COMPAT_CFLAGS += -DNO_MKSTEMPS
1203-
COMPAT_OBJS += compat/mkstemps.o
12041203
endif
12051204
ifdef NO_UNSETENV
12061205
COMPAT_CFLAGS += -DNO_UNSETENV

compat/mkstemps.c

Lines changed: 0 additions & 70 deletions
This file was deleted.

path.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,75 @@ int git_mkstemps(char *path, size_t len, const char *template, int suffix_len)
157157
return mkstemps(path, suffix_len);
158158
}
159159

160+
/* Adapted from libiberty's mkstemp.c. */
161+
162+
#undef TMP_MAX
163+
#define TMP_MAX 16384
164+
165+
int gitmkstemps(char *pattern, int suffix_len)
166+
{
167+
static const char letters[] =
168+
"abcdefghijklmnopqrstuvwxyz"
169+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
170+
"0123456789";
171+
static const int num_letters = 62;
172+
uint64_t value;
173+
struct timeval tv;
174+
char *template;
175+
size_t len;
176+
int fd, count;
177+
178+
len = strlen(pattern);
179+
180+
if (len < 6 + suffix_len) {
181+
errno = EINVAL;
182+
return -1;
183+
}
184+
185+
if (strncmp(&pattern[len - 6 - suffix_len], "XXXXXX", 6)) {
186+
errno = EINVAL;
187+
return -1;
188+
}
189+
190+
/*
191+
* Replace pattern's XXXXXX characters with randomness.
192+
* Try TMP_MAX different filenames.
193+
*/
194+
gettimeofday(&tv, NULL);
195+
value = ((size_t)(tv.tv_usec << 16)) ^ tv.tv_sec ^ getpid();
196+
template = &pattern[len - 6 - suffix_len];
197+
for (count = 0; count < TMP_MAX; ++count) {
198+
uint64_t v = value;
199+
/* Fill in the random bits. */
200+
template[0] = letters[v % num_letters]; v /= num_letters;
201+
template[1] = letters[v % num_letters]; v /= num_letters;
202+
template[2] = letters[v % num_letters]; v /= num_letters;
203+
template[3] = letters[v % num_letters]; v /= num_letters;
204+
template[4] = letters[v % num_letters]; v /= num_letters;
205+
template[5] = letters[v % num_letters]; v /= num_letters;
206+
207+
fd = open(pattern, O_CREAT | O_EXCL | O_RDWR, 0600);
208+
if (fd > 0)
209+
return fd;
210+
/*
211+
* Fatal error (EPERM, ENOSPC etc).
212+
* It doesn't make sense to loop.
213+
*/
214+
if (errno != EEXIST)
215+
break;
216+
/*
217+
* This is a random value. It is only necessary that
218+
* the next TMP_MAX values generated by adding 7777 to
219+
* VALUE are different with (module 2^32).
220+
*/
221+
value += 7777;
222+
}
223+
/* We return the null string if we can't find a unique file name. */
224+
pattern[0] = '\0';
225+
errno = EINVAL;
226+
return -1;
227+
}
228+
160229
int validate_headref(const char *path)
161230
{
162231
struct stat st;

0 commit comments

Comments
 (0)