mirror of
https://git.proxmox.com/git/libgit2
synced 2025-08-06 10:32:56 +00:00
posix: Portable vsnprintf
Our good, lovely folks at Microsoft decided that there was no good reason to make `vsnprintf` compilant with the C standard, so that function in Windows returns -1 on overflow, instead of returning the actual byte count needed to write the full string. We now handle this situation more gracefully with the POSIX compatibility layer, by returning the needed byte size using an auxiliary method instead of blindly resizing the target buffer until it fits. This means we can now support `printf`s of any size by allocating a temporary buffer. That's good.
This commit is contained in:
parent
d483a911b8
commit
2fc78e700c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user