diff --git a/include/git2/common.h b/include/git2/common.h index 1d2d3a3e9..2aae648fb 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -173,6 +173,9 @@ /** Streaming error */ #define GIT_ESTREAM (GIT_ERROR - 26) +/** invalid arguments to function */ +#define GIT_EINVALIDARGS (GIT_ERROR - 27) + GIT_BEGIN_DECL typedef struct { diff --git a/src/common.h b/src/common.h index 351d6696f..e5b9f15ed 100644 --- a/src/common.h +++ b/src/common.h @@ -54,7 +54,8 @@ typedef SSIZE_T ssize_t; #include "bswap.h" #define GIT_PATH_MAX 4096 -extern int git__error(int error, const char *, ...) GIT_FORMAT_PRINTF(2, 3); +extern int git__throw(int error, const char *, ...) GIT_FORMAT_PRINTF(2, 3); +extern int git__rethrow(int error, const char *, ...) GIT_FORMAT_PRINTF(2, 3); #include "util.h" diff --git a/src/errors.c b/src/errors.c index 73df2e209..40b0feb91 100644 --- a/src/errors.c +++ b/src/errors.c @@ -30,7 +30,25 @@ static GIT_TLS char g_last_error[1024]; -int git__error(int error, const char *msg, ...) +int git__rethrow(int error, const char *msg, ...) +{ + char new_error[1024]; + char *old_error = NULL; + + va_list va; + + va_start(va, msg); + vsnprintf(new_error, sizeof(new_error), msg, va); + va_end(va); + + old_error = strdup(g_last_error); + snprintf(g_last_error, sizeof(g_last_error), "%s \n - %s", new_error, old_error); + free(old_error); + + return error; +} + +int git__throw(int error, const char *msg, ...) { va_list va; diff --git a/src/refs.c b/src/refs.c index ea968196f..c4d3d6ae6 100644 --- a/src/refs.c +++ b/src/refs.c @@ -122,7 +122,8 @@ static int reference_create( else if (type == GIT_REF_OID) size = sizeof(reference_oid); else - return GIT_EINVALIDREFSTATE; + return git__throw(GIT_EINVALIDARGS, + "Invalid reference type. Use either GIT_REF_OID or GIT_REF_SYMBOLIC as type specifier"); reference = git__malloc(size); if (reference == NULL) @@ -159,11 +160,9 @@ static int reference_read(gitfo_buf *file_content, time_t *mtime, const char *re /* Determine the full path of the file */ git__joinpath(path, repo_path, ref_name); - if (gitfo_stat(path, &st) < 0) - return GIT_ENOTFOUND; - - if (S_ISDIR(st.st_mode)) - return GIT_EOBJCORRUPTED; + if (gitfo_stat(path, &st) < 0 || S_ISDIR(st.st_mode)) + return git__throw(GIT_ENOTFOUND, + "Cannot read reference file '%s'", ref_name); if (mtime) *mtime = st.st_mtime; @@ -205,7 +204,8 @@ static int loose_update(git_reference *ref) else if (ref->type == GIT_REF_OID) error = loose_parse_oid(ref, &ref_file); else - error = GIT_EINVALIDREFSTATE; + error = git__throw(GIT_EOBJCORRUPTED, + "Invalid reference type (%d) for loose reference", ref->type); gitfo_free_buf(&ref_file); @@ -229,7 +229,8 @@ static int loose_parse_symbolic(git_reference *ref, gitfo_buf *file_content) ref_sym = (reference_symbolic *)ref; if (file_content->len < (header_len + 1)) - return GIT_EREFCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, + "Failed to parse loose reference. Object too short"); /* * Assume we have already checked for the header @@ -246,7 +247,8 @@ static int loose_parse_symbolic(git_reference *ref, gitfo_buf *file_content) /* remove newline at the end of file */ eol = strchr(ref_sym->target, '\n'); if (eol == NULL) - return GIT_EREFCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, + "Failed to parse loose reference. Missing EOL"); *eol = '\0'; if (eol[-1] == '\r') @@ -257,6 +259,7 @@ static int loose_parse_symbolic(git_reference *ref, gitfo_buf *file_content) static int loose_parse_oid(git_reference *ref, gitfo_buf *file_content) { + int error; reference_oid *ref_oid; char *buffer; @@ -265,17 +268,19 @@ static int loose_parse_oid(git_reference *ref, gitfo_buf *file_content) /* File format: 40 chars (OID) + newline */ if (file_content->len < GIT_OID_HEXSZ + 1) - return GIT_EREFCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, + "Failed to parse loose reference. Reference too short"); - if (git_oid_mkstr(&ref_oid->oid, buffer) < GIT_SUCCESS) - return GIT_EREFCORRUPTED; + if ((error = git_oid_mkstr(&ref_oid->oid, buffer)) < GIT_SUCCESS) + return git__rethrow(GIT_EOBJCORRUPTED, "Failed to parse loose reference."); buffer = buffer + GIT_OID_HEXSZ; if (*buffer == '\r') buffer++; if (*buffer != '\n') - return GIT_EREFCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, + "Failed to parse loose reference. Missing EOL"); return GIT_SUCCESS; } @@ -387,7 +392,7 @@ static int loose_write(git_reference *ref) strcpy(ref_contents, GIT_SYMREF); strcat(ref_contents, ref_sym->target); } else { - error = GIT_EINVALIDREFSTATE; + error = git__throw(GIT_EOBJCORRUPTED, "Failed to write reference. Invalid reference type"); goto unlock; } diff --git a/src/util.h b/src/util.h index f5f0b8662..6724e8d41 100644 --- a/src/util.h +++ b/src/util.h @@ -14,7 +14,7 @@ GIT_INLINE(void *) git__malloc(size_t len) { void *ptr = malloc(len); if (!ptr) - git__error(GIT_ENOMEM, "Out of memory. Failed to allocate %d bytes.", (int)len); + git__throw(GIT_ENOMEM, "Out of memory. Failed to allocate %d bytes.", (int)len); return ptr; } @@ -22,7 +22,7 @@ GIT_INLINE(void *) git__calloc(size_t nelem, size_t elsize) { void *ptr = calloc(nelem, elsize); if (!ptr) - git__error(GIT_ENOMEM, "Out of memory. Failed to allocate %d bytes.", (int)elsize); + git__throw(GIT_ENOMEM, "Out of memory. Failed to allocate %d bytes.", (int)elsize); return ptr; } @@ -30,7 +30,7 @@ GIT_INLINE(char *) git__strdup(const char *str) { char *ptr = strdup(str); if (!ptr) - git__error(GIT_ENOMEM, "Out of memory. Failed to duplicate string"); + git__throw(GIT_ENOMEM, "Out of memory. Failed to duplicate string"); return ptr; } @@ -38,7 +38,7 @@ GIT_INLINE(void *) git__realloc(void *ptr, size_t size) { void *new_ptr = realloc(ptr, size); if (!new_ptr) - git__error(GIT_ENOMEM, "Out of memory. Failed to allocate %d bytes.", (int)size); + git__throw(GIT_ENOMEM, "Out of memory. Failed to allocate %d bytes.", (int)size); return new_ptr; }