diff options
Diffstat (limited to 'wrapper.c')
-rw-r--r-- | wrapper.c | 244 |
1 files changed, 136 insertions, 108 deletions
@@ -3,16 +3,17 @@ */ #include "cache.h" -static void try_to_free_builtin(size_t size) +static void do_nothing(size_t size) { - release_pack_memory(size, -1); } -static void (*try_to_free_routine)(size_t size) = try_to_free_builtin; +static void (*try_to_free_routine)(size_t size) = do_nothing; try_to_free_t set_try_to_free_routine(try_to_free_t routine) { try_to_free_t old = try_to_free_routine; + if (!routine) + routine = do_nothing; try_to_free_routine = routine; return old; } @@ -52,7 +53,7 @@ void *xmalloc(size_t size) void *xmallocz(size_t size) { void *ret; - if (size + 1 < size) + if (unsigned_add_overflows(size, 1)) die("Data too large to fit into virtual memory space."); ret = xmalloc(size + 1); ((char*)ret)[size] = 0; @@ -108,21 +109,6 @@ void *xcalloc(size_t nmemb, size_t size) return ret; } -void *xmmap(void *start, size_t length, - int prot, int flags, int fd, off_t offset) -{ - void *ret = mmap(start, length, prot, flags, fd, offset); - if (ret == MAP_FAILED) { - if (!length) - return NULL; - release_pack_memory(length, fd); - ret = mmap(start, length, prot, flags, fd, offset); - if (ret == MAP_FAILED) - die_errno("Out of memory? mmap failed"); - } - return ret; -} - /* * xread() is the same a read(), but it automatically restarts read() * operations with a recoverable error (EAGAIN and EINTR). xread() @@ -162,8 +148,10 @@ ssize_t read_in_full(int fd, void *buf, size_t count) while (count > 0) { ssize_t loaded = xread(fd, p, count); - if (loaded <= 0) - return total ? total : loaded; + if (loaded < 0) + return -1; + if (loaded == 0) + return total; count -= loaded; p += loaded; total += loaded; @@ -212,118 +200,158 @@ FILE *xfdopen(int fd, const char *mode) int xmkstemp(char *template) { int fd; + char origtemplate[PATH_MAX]; + strlcpy(origtemplate, template, sizeof(origtemplate)); fd = mkstemp(template); - if (fd < 0) - die_errno("Unable to create temporary file"); - return fd; -} + if (fd < 0) { + int saved_errno = errno; + const char *nonrelative_template; -int xmkstemp_mode(char *template, int mode) -{ - int fd; + if (!template[0]) + template = origtemplate; - fd = git_mkstemp_mode(template, mode); - if (fd < 0) - die_errno("Unable to create temporary file"); + nonrelative_template = absolute_path(template); + errno = saved_errno; + die_errno("Unable to create temporary file '%s'", + nonrelative_template); + } return fd; } -/* - * zlib wrappers to make sure we don't silently miss errors - * at init time. - */ -void git_inflate_init(z_streamp strm) +/* git_mkstemp() - create tmp file honoring TMPDIR variable */ +int git_mkstemp(char *path, size_t len, const char *template) { - const char *err; - - switch (inflateInit(strm)) { - case Z_OK: - return; - - case Z_MEM_ERROR: - err = "out of memory"; - break; - case Z_VERSION_ERROR: - err = "wrong version"; - break; - default: - err = "error"; + const char *tmp; + size_t n; + + tmp = getenv("TMPDIR"); + if (!tmp) + tmp = "/tmp"; + n = snprintf(path, len, "%s/%s", tmp, template); + if (len <= n) { + errno = ENAMETOOLONG; + return -1; } - die("inflateInit: %s (%s)", err, strm->msg ? strm->msg : "no message"); + return mkstemp(path); } -void git_inflate_end(z_streamp strm) +/* git_mkstemps() - create tmp file with suffix honoring TMPDIR variable. */ +int git_mkstemps(char *path, size_t len, const char *template, int suffix_len) { - if (inflateEnd(strm) != Z_OK) - error("inflateEnd: %s", strm->msg ? strm->msg : "failed"); + const char *tmp; + size_t n; + + tmp = getenv("TMPDIR"); + if (!tmp) + tmp = "/tmp"; + n = snprintf(path, len, "%s/%s", tmp, template); + if (len <= n) { + errno = ENAMETOOLONG; + return -1; + } + return mkstemps(path, suffix_len); } -int git_inflate(z_streamp strm, int flush) +/* Adapted from libiberty's mkstemp.c. */ + +#undef TMP_MAX +#define TMP_MAX 16384 + +int git_mkstemps_mode(char *pattern, int suffix_len, int mode) { - int ret = inflate(strm, flush); - const char *err; - - switch (ret) { - /* Out of memory is fatal. */ - case Z_MEM_ERROR: - die("inflate: out of memory"); - - /* Data corruption errors: we may want to recover from them (fsck) */ - case Z_NEED_DICT: - err = "needs dictionary"; break; - case Z_DATA_ERROR: - err = "data stream error"; break; - case Z_STREAM_ERROR: - err = "stream consistency error"; break; - default: - err = "unknown error"; break; - - /* Z_BUF_ERROR: normal, needs more space in the output buffer */ - case Z_BUF_ERROR: - case Z_OK: - case Z_STREAM_END: - return ret; + 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; } - error("inflate: %s (%s)", err, strm->msg ? strm->msg : "no message"); - return ret; -} -int odb_mkstemp(char *template, size_t limit, const char *pattern) -{ - int fd; /* - * we let the umask do its job, don't try to be more - * restrictive except to remove write permission. + * Replace pattern's XXXXXX characters with randomness. + * Try TMP_MAX different filenames. */ - int mode = 0444; - snprintf(template, limit, "%s/%s", - get_object_directory(), pattern); - fd = git_mkstemp_mode(template, mode); - if (0 <= fd) - return fd; - - /* slow path */ - /* some mkstemp implementations erase template on failure */ - snprintf(template, limit, "%s/%s", - get_object_directory(), pattern); - safe_create_leading_directories(template); - return xmkstemp_mode(template, mode); + 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 git_mkstemp_mode(char *pattern, int mode) +{ + /* mkstemp is just mkstemps with no suffix */ + return git_mkstemps_mode(pattern, 0, mode); } -int odb_pack_keep(char *name, size_t namesz, unsigned char *sha1) +int gitmkstemps(char *pattern, int suffix_len) +{ + return git_mkstemps_mode(pattern, suffix_len, 0600); +} + +int xmkstemp_mode(char *template, int mode) { int fd; + char origtemplate[PATH_MAX]; + strlcpy(origtemplate, template, sizeof(origtemplate)); - snprintf(name, namesz, "%s/pack/pack-%s.keep", - get_object_directory(), sha1_to_hex(sha1)); - fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0600); - if (0 <= fd) - return fd; + fd = git_mkstemp_mode(template, mode); + if (fd < 0) { + int saved_errno = errno; + const char *nonrelative_template; + + if (!template[0]) + template = origtemplate; - /* slow path */ - safe_create_leading_directories(name); - return open(name, O_RDWR|O_CREAT|O_EXCL, 0600); + nonrelative_template = absolute_path(template); + errno = saved_errno; + die_errno("Unable to create temporary file '%s'", + nonrelative_template); + } + return fd; } static int warn_if_unremovable(const char *op, const char *file, int rc) |