From 00787ed55adbc2350efa911bf0bdebf6ca08c095 Mon Sep 17 00:00:00 2001 From: Matthieu Moy Date: Mon, 22 Feb 2010 23:32:12 +0100 Subject: 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 Signed-off-by: Junio C Hamano --- path.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) (limited to 'path.c') diff --git a/path.c b/path.c index 79aa104712..ab2e3687ab 100644 --- a/path.c +++ b/path.c @@ -157,6 +157,75 @@ int git_mkstemps(char *path, size_t len, const char *template, int suffix_len) return mkstemps(path, suffix_len); } +/* Adapted from libiberty's mkstemp.c. */ + +#undef TMP_MAX +#define TMP_MAX 16384 + +int gitmkstemps(char *pattern, int suffix_len) +{ + 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, 0600); + 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'; + errno = EINVAL; + return -1; +} + int validate_headref(const char *path) { struct stat st; -- cgit v1.2.1 From b862b61c03797fd00490bb8caf05be840b79c6cb Mon Sep 17 00:00:00 2001 From: Matthieu Moy Date: Mon, 22 Feb 2010 23:32:13 +0100 Subject: git_mkstemp_mode, xmkstemp_mode: variants of gitmkstemps with mode argument. gitmkstemps emulates the behavior of mkstemps, which is usually used to create files in a shared directory like /tmp/, hence, it creates files with permission 0600. Add git_mkstemps_mode() that allows us to specify the desired mode, and make git_mkstemps() a wrapper that always uses 0600 to call it. Later we will use git_mkstemps_mode() when creating pack files. Signed-off-by: Matthieu Moy Signed-off-by: Junio C Hamano --- path.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'path.c') diff --git a/path.c b/path.c index ab2e3687ab..03d284ba8b 100644 --- a/path.c +++ b/path.c @@ -162,7 +162,7 @@ int git_mkstemps(char *path, size_t len, const char *template, int suffix_len) #undef TMP_MAX #define TMP_MAX 16384 -int gitmkstemps(char *pattern, int suffix_len) +int git_mkstemps_mode(char *pattern, int suffix_len, int mode) { static const char letters[] = "abcdefghijklmnopqrstuvwxyz" @@ -204,7 +204,7 @@ int gitmkstemps(char *pattern, int suffix_len) 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, 0600); + fd = open(pattern, O_CREAT | O_EXCL | O_RDWR, mode); if (fd > 0) return fd; /* @@ -226,6 +226,17 @@ int gitmkstemps(char *pattern, int suffix_len) return -1; } +int git_mkstemp_mode(char *pattern, int mode) +{ + /* mkstemp is just mkstemps with no suffix */ + return git_mkstemps_mode(pattern, 0, mode); +} + +int gitmkstemps(char *pattern, int suffix_len) +{ + return git_mkstemps_mode(pattern, suffix_len, 0600); +} + int validate_headref(const char *path) { struct stat st; -- cgit v1.2.1 From 1d9740cb324f7f5d798ecfc259dc213b244ad9b7 Mon Sep 17 00:00:00 2001 From: Matthieu Moy Date: Mon, 22 Feb 2010 23:32:15 +0100 Subject: git_mkstemps_mode: don't set errno to EINVAL on exit. When reaching the end of git_mkstemps_mode, at least one call to open() has been done, and errno has been set accordingly. Setting errno is therefore not necessary, and actually harmfull since callers can't distinguish e.g. permanent failure from ENOENT, which can just mean that we need to create the containing directory. Signed-off-by: Matthieu Moy Signed-off-by: Junio C Hamano --- path.c | 1 - 1 file changed, 1 deletion(-) (limited to 'path.c') diff --git a/path.c b/path.c index 03d284ba8b..12ef731ace 100644 --- a/path.c +++ b/path.c @@ -222,7 +222,6 @@ int git_mkstemps_mode(char *pattern, int suffix_len, int mode) } /* We return the null string if we can't find a unique file name. */ pattern[0] = '\0'; - errno = EINVAL; return -1; } -- cgit v1.2.1