diff --git a/src/filebuf.c b/src/filebuf.c index acfdcd141..86a643d38 100644 --- a/src/filebuf.c +++ b/src/filebuf.c @@ -360,29 +360,48 @@ int git_filebuf_reserve(git_filebuf *file, void **buffer, size_t len) int git_filebuf_printf(git_filebuf *file, const char *format, ...) { va_list arglist; - size_t space_left = file->buf_size - file->buf_pos; + size_t space_left; int len, error; + char *tmp_buffer; - va_start(arglist, format); - len = vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist); - va_end(arglist); + space_left = file->buf_size - file->buf_pos; + + do { + va_start(arglist, format); + len = p_vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist); + va_end(arglist); + + if (len < 0) + return git__throw(GIT_EOSERR, "Failed to format string"); + + if ((size_t)len <= space_left) { + file->buf_pos += len; + return GIT_SUCCESS; + } - if (len < 0 || (size_t)len >= space_left) { if ((error = flush_buffer(file)) < GIT_SUCCESS) return git__rethrow(error, "Failed to output to buffer"); space_left = file->buf_size - file->buf_pos; - va_start(arglist, format); - len = vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist); - va_end(arglist); + } while ((size_t)len <= space_left); - if (len < 0 || (size_t)len > file->buf_size) - return GIT_ENOMEM; + tmp_buffer = git__malloc(len + 1); + if (!tmp_buffer) + return GIT_ENOMEM; + + va_start(arglist, format); + len = p_vsnprintf(tmp_buffer, len + 1, format, arglist); + va_end(arglist); + + if (len < 0) { + free(tmp_buffer); + return git__throw(GIT_EOSERR, "Failed to format string"); } - file->buf_pos += len; - return GIT_SUCCESS; + error = git_filebuf_write(file, tmp_buffer, len); + free(tmp_buffer); + return error; } diff --git a/src/unix/posix.h b/src/unix/posix.h index d52aa095c..16daf15bd 100644 --- a/src/unix/posix.h +++ b/src/unix/posix.h @@ -12,5 +12,6 @@ #define p_fsync(fd) fsync(fd) #define p_realpath(p, po) realpath(p, po) #define p_fnmatch(p, s, f) fnmatch(p, s, f) +#define p_vsnprintf(b, c, f, a) vsnprintf(b, c, f, a) #endif diff --git a/src/win32/posix.c b/src/win32/posix.c index dfa4e1a2c..c4d9eb387 100644 --- a/src/win32/posix.c +++ b/src/win32/posix.c @@ -209,3 +209,12 @@ char *p_realpath(const char *orig_path, char *buffer) return buffer; } +int p_vsnprintf(char *buffer, size_t count, const char *format, va_list argptr) +{ +#ifdef _MSV_VER + int len = _vsnprintf(buffer, count, format, argptr); + return (len < 0) ? _vscprintf(format, argptr) : len; +#else /* MinGW */ + return vsnprintf(buffer, count, format, argptr); +#endif +} diff --git a/src/win32/posix.h b/src/win32/posix.h index 503c5d874..efac68e74 100644 --- a/src/win32/posix.h +++ b/src/win32/posix.h @@ -23,5 +23,6 @@ extern int p_lstat(const char *file_name, struct stat *buf); extern int p_readlink(const char *link, char *target, size_t target_len); extern int p_hide_directory__w32(const char *path); extern char *p_realpath(const char *orig_path, char *buffer); +extern int p_vsnprintf(char *buffer, size_t count, const char *format, va_list argptr); #endif