mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-04 21:46:22 +00:00
error-handling: On-disk config file backend
Includes: - Proper error reporting when encountering syntax errors in a config file (file, line number, column). - Rewritten `config_write`, now with 99% less goto-spaghetti - Error state in `git_filebuf`: filebuf write functions no longer need to be checked for error returns. If any of the writes performed on a buffer fail, the last call to `git_filebuf_commit` or `git_filebuf_hash` will fail accordingly and set the appropiate error message. Baller!
This commit is contained in:
parent
6af24ce31f
commit
dda708e78f
@ -127,14 +127,9 @@ typedef enum {
|
||||
GITERR_ZLIB,
|
||||
GITERR_REPOSITORY,
|
||||
GITERR_CONFIG,
|
||||
GITERR_REGEX,
|
||||
} git_error_class;
|
||||
|
||||
#define GITERR_CHECK_ALLOC(ptr) if (ptr == NULL) { return -1; }
|
||||
|
||||
GIT_EXTERN(void) giterr_set_oom(void);
|
||||
GIT_EXTERN(void) giterr_set(int error_class, const char *string, ...);
|
||||
GIT_EXTERN(void) giterr_clear(void);
|
||||
|
||||
/**
|
||||
* Return a detailed error string with the latest error
|
||||
* that occurred in the library.
|
||||
|
12
src/common.h
12
src/common.h
@ -46,6 +46,8 @@
|
||||
#include "thread-utils.h"
|
||||
#include "bswap.h"
|
||||
|
||||
#include <regex.h>
|
||||
|
||||
extern void git___throw(const char *, ...) GIT_FORMAT_PRINTF(1, 2);
|
||||
#define git__throw(error, ...) \
|
||||
(git___throw(__VA_ARGS__), error)
|
||||
@ -54,6 +56,16 @@ extern void git___rethrow(const char *, ...) GIT_FORMAT_PRINTF(1, 2);
|
||||
#define git__rethrow(error, ...) \
|
||||
(git___rethrow(__VA_ARGS__), error)
|
||||
|
||||
|
||||
#define GITERR_CHECK_ALLOC(ptr) if (ptr == NULL) { return -1; }
|
||||
|
||||
void giterr_set_oom(void);
|
||||
void giterr_set(int error_class, const char *string, ...);
|
||||
void giterr_clear(void);
|
||||
void giterr_set_str(int error_class, const char *string);
|
||||
void giterr_set_regex(const regex_t *regex, int error_code);
|
||||
|
||||
|
||||
#include "util.h"
|
||||
|
||||
|
||||
|
@ -401,13 +401,15 @@ int git_config_get_string(git_config *cfg, const char *name, const char **out)
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
|
||||
/* File backend doesn't set error message on variable
|
||||
* not found */
|
||||
if (ret == GIT_ENOTFOUND)
|
||||
continue;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
giterr_set(GITERR_CONFIG, "Config value '%s' not found", name);
|
||||
giterr_set(GITERR_CONFIG, "Config variable '%s' not found", name);
|
||||
return GIT_ENOTFOUND;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
28
src/errors.c
28
src/errors.c
@ -122,25 +122,28 @@ void giterr_set(int error_class, const char *string, ...)
|
||||
{
|
||||
char error_str[1024];
|
||||
va_list arglist;
|
||||
git_error *error;
|
||||
const char *oserr =
|
||||
(error_class == GITERR_OS && errno != 0) ? strerror(errno) : NULL;
|
||||
|
||||
error = &GIT_GLOBAL->error_t;
|
||||
free(error->message);
|
||||
|
||||
va_start(arglist, string);
|
||||
p_vsnprintf(error_str, sizeof(error_str), string, arglist);
|
||||
va_end(arglist);
|
||||
|
||||
/* automatically suffix strerror(errno) for GITERR_OS errors */
|
||||
if (oserr != NULL) {
|
||||
if (error_class == GITERR_OS) {
|
||||
strncat(error_str, ": ", sizeof(error_str));
|
||||
strncat(error_str, oserr, sizeof(error_str));
|
||||
strncat(error_str, strerror(errno), sizeof(error_str));
|
||||
errno = 0;
|
||||
}
|
||||
|
||||
error->message = git__strdup(error_str);
|
||||
giterr_set_str(error_class, error_str);
|
||||
}
|
||||
|
||||
void giterr_set_str(int error_class, const char *string)
|
||||
{
|
||||
git_error *error = &GIT_GLOBAL->error_t;
|
||||
|
||||
free(error->message);
|
||||
|
||||
error->message = git__strdup(string);
|
||||
error->klass = error_class;
|
||||
|
||||
if (error->message == NULL) {
|
||||
@ -151,6 +154,13 @@ void giterr_set(int error_class, const char *string, ...)
|
||||
GIT_GLOBAL->last_error = error;
|
||||
}
|
||||
|
||||
void giterr_set_regex(const regex_t *regex, int error_code)
|
||||
{
|
||||
char error_buf[1024];
|
||||
regerror(error_code, regex, error_buf, sizeof(error_buf));
|
||||
giterr_set_str(GITERR_REGEX, error_buf);
|
||||
}
|
||||
|
||||
void giterr_clear(void)
|
||||
{
|
||||
GIT_GLOBAL->last_error = NULL;
|
||||
|
150
src/filebuf.c
150
src/filebuf.c
@ -14,6 +14,36 @@
|
||||
|
||||
static const size_t WRITE_BUFFER_SIZE = (4096 * 2);
|
||||
|
||||
enum buferr_t {
|
||||
BUFERR_OK = 0,
|
||||
BUFERR_WRITE,
|
||||
BUFERR_ZLIB,
|
||||
BUFERR_MEM
|
||||
};
|
||||
|
||||
#define ENSURE_BUF_OK(buf) if ((buf)->last_error != BUFERR_OK) { return -1; }
|
||||
|
||||
static int verify_last_error(git_filebuf *file)
|
||||
{
|
||||
switch (file->last_error) {
|
||||
case BUFERR_WRITE:
|
||||
giterr_set(GITERR_OS, "Failed to write out file");
|
||||
return -1;
|
||||
|
||||
case BUFERR_MEM:
|
||||
giterr_set_oom();
|
||||
return -1;
|
||||
|
||||
case BUFERR_ZLIB:
|
||||
giterr_set(GITERR_ZLIB,
|
||||
"Buffer error when writing out ZLib data");
|
||||
return -1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int lock_file(git_filebuf *file, int flags)
|
||||
{
|
||||
if (git_path_exists(file->path_lock) == true) {
|
||||
@ -100,20 +130,21 @@ GIT_INLINE(int) flush_buffer(git_filebuf *file)
|
||||
|
||||
static int write_normal(git_filebuf *file, void *source, size_t len)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (len > 0) {
|
||||
result = p_write(file->fd, (void *)source, len);
|
||||
if (p_write(file->fd, (void *)source, len) < 0) {
|
||||
file->last_error = BUFERR_WRITE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (file->digest)
|
||||
git_hash_update(file->digest, source, len);
|
||||
}
|
||||
|
||||
return result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_deflate(git_filebuf *file, void *source, size_t len)
|
||||
{
|
||||
int result = Z_OK;
|
||||
z_stream *zs = &file->zs;
|
||||
|
||||
if (len > 0 || file->flush_mode == Z_FINISH) {
|
||||
@ -126,14 +157,17 @@ static int write_deflate(git_filebuf *file, void *source, size_t len)
|
||||
zs->next_out = file->z_buf;
|
||||
zs->avail_out = (uInt)file->buf_size;
|
||||
|
||||
result = deflate(zs, file->flush_mode);
|
||||
if (result == Z_STREAM_ERROR)
|
||||
return git__throw(GIT_ERROR, "Failed to deflate input");
|
||||
if (deflate(zs, file->flush_mode) == Z_STREAM_ERROR) {
|
||||
file->last_error = BUFERR_ZLIB;
|
||||
return -1;
|
||||
}
|
||||
|
||||
have = file->buf_size - (size_t)zs->avail_out;
|
||||
|
||||
if (p_write(file->fd, file->z_buf, have) < GIT_SUCCESS)
|
||||
return git__throw(GIT_EOSERR, "Failed to write to file");
|
||||
if (p_write(file->fd, file->z_buf, have) < 0) {
|
||||
file->last_error = BUFERR_WRITE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
} while (zs->avail_out == 0);
|
||||
|
||||
@ -143,7 +177,7 @@ static int write_deflate(git_filebuf *file, void *source, size_t len)
|
||||
git_hash_update(file->digest, source, len);
|
||||
}
|
||||
|
||||
return GIT_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_filebuf_open(git_filebuf *file, const char *path, int flags)
|
||||
@ -161,6 +195,7 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags)
|
||||
file->buf_size = WRITE_BUFFER_SIZE;
|
||||
file->buf_pos = 0;
|
||||
file->fd = -1;
|
||||
file->last_error = BUFERR_OK;
|
||||
|
||||
/* Allocate the main cache buffer */
|
||||
file->buffer = git__malloc(file->buf_size);
|
||||
@ -237,58 +272,61 @@ cleanup:
|
||||
|
||||
int git_filebuf_hash(git_oid *oid, git_filebuf *file)
|
||||
{
|
||||
int error;
|
||||
|
||||
assert(oid && file && file->digest);
|
||||
|
||||
if ((error = flush_buffer(file)) < GIT_SUCCESS)
|
||||
return git__rethrow(error, "Failed to get hash for file");
|
||||
flush_buffer(file);
|
||||
|
||||
if (verify_last_error(file) < 0)
|
||||
return -1;
|
||||
|
||||
git_hash_final(oid, file->digest);
|
||||
git_hash_free_ctx(file->digest);
|
||||
file->digest = NULL;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_filebuf_commit_at(git_filebuf *file, const char *path, mode_t mode)
|
||||
{
|
||||
git__free(file->path_original);
|
||||
file->path_original = git__strdup(path);
|
||||
if (file->path_original == NULL)
|
||||
return GIT_ENOMEM;
|
||||
GITERR_CHECK_ALLOC(file->path_original);
|
||||
|
||||
return git_filebuf_commit(file, mode);
|
||||
}
|
||||
|
||||
int git_filebuf_commit(git_filebuf *file, mode_t mode)
|
||||
{
|
||||
int error;
|
||||
|
||||
/* temporary files cannot be committed */
|
||||
assert(file && file->path_original);
|
||||
|
||||
file->flush_mode = Z_FINISH;
|
||||
if ((error = flush_buffer(file)) < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
flush_buffer(file);
|
||||
|
||||
if (verify_last_error(file) < 0)
|
||||
goto on_error;
|
||||
|
||||
p_close(file->fd);
|
||||
file->fd = -1;
|
||||
|
||||
if (p_chmod(file->path_lock, mode)) {
|
||||
error = git__throw(GIT_EOSERR, "Failed to chmod locked file before committing");
|
||||
goto cleanup;
|
||||
giterr_set(GITERR_OS, "Failed to set attributes for file at '%s'", file->path_lock);
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
p_unlink(file->path_original);
|
||||
|
||||
error = p_rename(file->path_lock, file->path_original);
|
||||
if (p_rename(file->path_lock, file->path_original) < 0) {
|
||||
giterr_set(GITERR_OS, "Failed to rename lockfile to '%s'", file->path_original);
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
git_filebuf_cleanup(file);
|
||||
if (error < GIT_SUCCESS)
|
||||
return git__rethrow(error, "Failed to commit locked file from buffer");
|
||||
return GIT_SUCCESS;
|
||||
return 0;
|
||||
|
||||
on_error:
|
||||
git_filebuf_cleanup(file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
GIT_INLINE(void) add_to_cache(git_filebuf *file, const void *buf, size_t len)
|
||||
@ -299,22 +337,22 @@ GIT_INLINE(void) add_to_cache(git_filebuf *file, const void *buf, size_t len)
|
||||
|
||||
int git_filebuf_write(git_filebuf *file, const void *buff, size_t len)
|
||||
{
|
||||
int error;
|
||||
const unsigned char *buf = buff;
|
||||
|
||||
ENSURE_BUF_OK(file);
|
||||
|
||||
for (;;) {
|
||||
size_t space_left = file->buf_size - file->buf_pos;
|
||||
|
||||
/* cache if it's small */
|
||||
if (space_left > len) {
|
||||
add_to_cache(file, buf, len);
|
||||
return GIT_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
add_to_cache(file, buf, space_left);
|
||||
|
||||
if ((error = flush_buffer(file)) < GIT_SUCCESS)
|
||||
return git__rethrow(error, "Failed to write to buffer");
|
||||
if (flush_buffer(file) < 0)
|
||||
return -1;
|
||||
|
||||
len -= space_left;
|
||||
buf += space_left;
|
||||
@ -323,32 +361,37 @@ int git_filebuf_write(git_filebuf *file, const void *buff, size_t len)
|
||||
|
||||
int git_filebuf_reserve(git_filebuf *file, void **buffer, size_t len)
|
||||
{
|
||||
int error;
|
||||
size_t space_left = file->buf_size - file->buf_pos;
|
||||
|
||||
*buffer = NULL;
|
||||
|
||||
if (len > file->buf_size)
|
||||
return GIT_ENOMEM;
|
||||
ENSURE_BUF_OK(file);
|
||||
|
||||
if (len > file->buf_size) {
|
||||
file->last_error = BUFERR_MEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (space_left <= len) {
|
||||
if ((error = flush_buffer(file)) < GIT_SUCCESS)
|
||||
return git__rethrow(error, "Failed to reserve buffer");
|
||||
if (flush_buffer(file) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
*buffer = (file->buffer + file->buf_pos);
|
||||
file->buf_pos += len;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_filebuf_printf(git_filebuf *file, const char *format, ...)
|
||||
{
|
||||
va_list arglist;
|
||||
size_t space_left;
|
||||
int len, error;
|
||||
int len, res;
|
||||
char *tmp_buffer;
|
||||
|
||||
ENSURE_BUF_OK(file);
|
||||
|
||||
space_left = file->buf_size - file->buf_pos;
|
||||
|
||||
do {
|
||||
@ -356,24 +399,28 @@ int git_filebuf_printf(git_filebuf *file, const char *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 (len < 0) {
|
||||
file->last_error = BUFERR_MEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((size_t)len + 1 <= space_left) {
|
||||
file->buf_pos += len;
|
||||
return GIT_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((error = flush_buffer(file)) < GIT_SUCCESS)
|
||||
return git__rethrow(error, "Failed to output to buffer");
|
||||
if (flush_buffer(file) < 0)
|
||||
return -1;
|
||||
|
||||
space_left = file->buf_size - file->buf_pos;
|
||||
|
||||
} while ((size_t)len + 1 <= space_left);
|
||||
|
||||
tmp_buffer = git__malloc(len + 1);
|
||||
if (!tmp_buffer)
|
||||
return GIT_ENOMEM;
|
||||
if (!tmp_buffer) {
|
||||
file->last_error = BUFERR_MEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
va_start(arglist, format);
|
||||
len = p_vsnprintf(tmp_buffer, len + 1, format, arglist);
|
||||
@ -381,12 +428,13 @@ int git_filebuf_printf(git_filebuf *file, const char *format, ...)
|
||||
|
||||
if (len < 0) {
|
||||
git__free(tmp_buffer);
|
||||
return git__throw(GIT_EOSERR, "Failed to format string");
|
||||
file->last_error = BUFERR_MEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
error = git_filebuf_write(file, tmp_buffer, len);
|
||||
res = git_filebuf_write(file, tmp_buffer, len);
|
||||
git__free(tmp_buffer);
|
||||
|
||||
return error;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -40,25 +40,35 @@ struct git_filebuf {
|
||||
|
||||
size_t buf_size, buf_pos;
|
||||
git_file fd;
|
||||
int last_error;
|
||||
};
|
||||
|
||||
typedef struct git_filebuf git_filebuf;
|
||||
|
||||
#define GIT_FILEBUF_INIT {0}
|
||||
|
||||
/* The git_filebuf object lifecycle is:
|
||||
/*
|
||||
* The git_filebuf object lifecycle is:
|
||||
* - Allocate git_filebuf, preferably using GIT_FILEBUF_INIT.
|
||||
*
|
||||
* - Call git_filebuf_open() to initialize the filebuf for use.
|
||||
*
|
||||
* - Make as many calls to git_filebuf_write(), git_filebuf_printf(),
|
||||
* git_filebuf_reserve() as you like.
|
||||
* git_filebuf_reserve() as you like. The error codes for these
|
||||
* functions don't need to be checked. They are stored internally
|
||||
* by the file buffer.
|
||||
*
|
||||
* - While you are writing, you may call git_filebuf_hash() to get
|
||||
* the hash of all you have written so far.
|
||||
* the hash of all you have written so far. This function will
|
||||
* fail if any of the previous writes to the buffer failed.
|
||||
*
|
||||
* - To close the git_filebuf, you may call git_filebuf_commit() or
|
||||
* git_filebuf_commit_at() to save the file, or
|
||||
* git_filebuf_cleanup() to abandon the file. All of these will
|
||||
* clear the git_filebuf object.
|
||||
* free the git_filebuf object. Likewise, all of these will fail
|
||||
* if any of the previous writes to the buffer failed, and set
|
||||
* an error code accordingly.
|
||||
*/
|
||||
|
||||
int git_filebuf_write(git_filebuf *lock, const void *buff, size_t len);
|
||||
int git_filebuf_reserve(git_filebuf *file, void **buff, size_t len);
|
||||
int git_filebuf_printf(git_filebuf *file, const char *format, ...) GIT_FORMAT_PRINTF(2, 3);
|
||||
|
@ -227,11 +227,11 @@ int git_hashtable_remove2(git_hashtable *self, const void *key, void **old_value
|
||||
node->key = NULL;
|
||||
node->value = NULL;
|
||||
self->key_count--;
|
||||
return GIT_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return git__throw(GIT_ENOTFOUND, "Entry not found in hash table");
|
||||
return GIT_ENOTFOUND;
|
||||
}
|
||||
|
||||
int git_hashtable_merge(git_hashtable *self, git_hashtable *other)
|
||||
|
18
src/posix.c
18
src/posix.c
@ -31,10 +31,9 @@ int p_getcwd(char *buffer_out, size_t size)
|
||||
cwd_buffer = getcwd(buffer_out, size);
|
||||
|
||||
if (cwd_buffer == NULL)
|
||||
return git__throw(GIT_EOSERR, "Failed to retrieve current working directory");
|
||||
return -1;
|
||||
|
||||
git_path_mkposix(buffer_out);
|
||||
|
||||
git_path_string_to_dir(buffer_out, size); //Ensure the path ends with a trailing slash
|
||||
|
||||
return GIT_SUCCESS;
|
||||
@ -44,14 +43,13 @@ int p_rename(const char *from, const char *to)
|
||||
{
|
||||
if (!link(from, to)) {
|
||||
p_unlink(from);
|
||||
return GIT_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!rename(from, to))
|
||||
return GIT_SUCCESS;
|
||||
|
||||
return GIT_ERROR;
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -64,7 +62,7 @@ int p_read(git_file fd, void *buf, size_t cnt)
|
||||
if (r < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
return GIT_EOSERR;
|
||||
return -1;
|
||||
}
|
||||
if (!r)
|
||||
break;
|
||||
@ -82,14 +80,14 @@ int p_write(git_file fd, const void *buf, size_t cnt)
|
||||
if (r < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
return GIT_EOSERR;
|
||||
return -1;
|
||||
}
|
||||
if (!r) {
|
||||
errno = EPIPE;
|
||||
return GIT_EOSERR;
|
||||
return -1;
|
||||
}
|
||||
cnt -= r;
|
||||
b += r;
|
||||
}
|
||||
return GIT_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
|
16
src/util.h
16
src/util.h
@ -7,8 +7,6 @@
|
||||
#ifndef INCLUDE_util_h__
|
||||
#define INCLUDE_util_h__
|
||||
|
||||
#include "git2/errors.h"
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
||||
#define bitsizeof(x) (CHAR_BIT * sizeof(x))
|
||||
#define MSB(x, bits) ((x) & (~0ULL << (bitsizeof(x) - (bits))))
|
||||
@ -24,24 +22,21 @@
|
||||
GIT_INLINE(void *) git__malloc(size_t len)
|
||||
{
|
||||
void *ptr = malloc(len);
|
||||
if (!ptr)
|
||||
giterr_set(GITERR_NOMEMORY, "Out of memory. Failed to allocate %d bytes.", (int)len);
|
||||
if (!ptr) giterr_set_oom();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
GIT_INLINE(void *) git__calloc(size_t nelem, size_t elsize)
|
||||
{
|
||||
void *ptr = calloc(nelem, elsize);
|
||||
if (!ptr)
|
||||
giterr_set(GITERR_NOMEMORY, "Out of memory. Failed to allocate %d bytes.", (int)nelem*elsize);
|
||||
if (!ptr) giterr_set_oom();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
GIT_INLINE(char *) git__strdup(const char *str)
|
||||
{
|
||||
char *ptr = strdup(str);
|
||||
if (!ptr)
|
||||
giterr_set(GITERR_NOMEMORY, "Out of memory. Failed to duplicate string");
|
||||
if (!ptr) giterr_set_oom();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@ -56,7 +51,7 @@ GIT_INLINE(char *) git__strndup(const char *str, size_t n)
|
||||
|
||||
ptr = (char*)malloc(length + 1);
|
||||
if (!ptr) {
|
||||
giterr_set(GITERR_NOMEMORY, "Out of memory. Failed to duplicate string");
|
||||
giterr_set_oom();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -69,8 +64,7 @@ GIT_INLINE(char *) git__strndup(const char *str, size_t n)
|
||||
GIT_INLINE(void *) git__realloc(void *ptr, size_t size)
|
||||
{
|
||||
void *new_ptr = realloc(ptr, size);
|
||||
if (!new_ptr)
|
||||
giterr_set(GITERR_NOMEMORY, "Out of memory. Failed to allocate %d bytes.", (int)size);
|
||||
if (!new_ptr) giterr_set_oom();
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user