Commit 5711ca93 by Vicent Marti

Merge branch 'error-handling' into development

parents cd2cc2dc fa59f18d
......@@ -170,6 +170,12 @@
/** The given literal is not a valid number */
#define GIT_ENOTNUM (GIT_ERROR - 25)
/** Streaming error */
#define GIT_ESTREAM (GIT_ERROR - 26)
/** invalid arguments to function */
#define GIT_EINVALIDARGS (GIT_ERROR - 27)
GIT_BEGIN_DECL
typedef struct {
......
......@@ -34,11 +34,11 @@
GIT_BEGIN_DECL
/**
* strerror() for the Git library
* @param num The error code to explain
* @return a string explaining the error code
* Return a detailed error string with the latest error
* that occurred in the library.
* @return a string explaining the error
*/
GIT_EXTERN(const char *) git_strerror(int num);
GIT_EXTERN(const char *) git_lasterror(void);
/** @} */
GIT_END_DECL
......
......@@ -35,6 +35,7 @@
#if defined(__APPLE__) && defined(__MACH__)
# undef GIT_TLS
# define GIT_TLS
#elif defined(__GNUC__) || \
defined(__SUNPRO_C) || \
......
......@@ -50,10 +50,13 @@ typedef SSIZE_T ssize_t;
#include "git2/common.h"
#include "git2/types.h"
#include "util.h"
#include "thread-utils.h"
#include "bswap.h"
#define GIT_PATH_MAX 4096
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"
#endif /* INCLUDE_common_h__ */
/*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
* as published by the Free Software Foundation.
*
* In addition to the permissions in the GNU General Public License,
* the authors give you unlimited permission to link the compiled
* version of this file into combinations with other programs,
* and to distribute those combinations without any restriction
* coming from the use of this file. (The General Public License
* restrictions do apply in other respects; for example, they cover
* modification of the file, and distribution when not linked into
* a combined executable.)
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "common.h"
#include "git2/thread-utils.h" /* for GIT_TLS */
#include "thread-utils.h" /* for GIT_TLS */
static struct {
int num;
const char *str;
} error_codes[] = {
{GIT_ERROR, "Unspecified error"},
{GIT_ENOTOID, "Input was not a properly formatted Git object id."},
{GIT_ENOTFOUND, "Object does not exist in the scope searched."},
{GIT_ENOMEM, "Not enough space available."},
{GIT_EOSERR, "Consult the OS error information."},
{GIT_EOBJTYPE, "The specified object is of invalid type"},
{GIT_EOBJCORRUPTED, "The specified object has its data corrupted"},
{GIT_ENOTAREPO, "The specified repository is invalid"},
{GIT_EINVALIDTYPE, "The object type is invalid or doesn't match"},
{GIT_EMISSINGOBJDATA, "The object cannot be written that because it's missing internal data"},
{GIT_EPACKCORRUPTED, "The packfile for the ODB is corrupted"},
{GIT_EFLOCKFAIL, "Failed to adquire or release a file lock"},
{GIT_EZLIB, "The Z library failed to inflate/deflate an object's data"},
{GIT_EBUSY, "The queried object is currently busy"},
{GIT_EINVALIDPATH, "The path is invalid"},
{GIT_EBAREINDEX, "The index file is not backed up by an existing repository"},
{GIT_EINVALIDREFNAME, "The name of the reference is not valid"},
{GIT_EREFCORRUPTED, "The specified reference has its data corrupted"},
{GIT_ETOONESTEDSYMREF, "The specified symbolic reference is too deeply nested"},
{GIT_EPACKEDREFSCORRUPTED, "The pack-refs file is either corrupted of its format is not currently supported"},
{GIT_EINVALIDPATH, "The path is invalid" },
{GIT_EREVWALKOVER, "The revision walker is empty; there are no more commits left to iterate"},
{GIT_EINVALIDREFSTATE, "The state of the reference is not valid"},
{GIT_ENOTIMPLEMENTED, "This feature has not been implemented yet"},
{GIT_EEXISTS, "A reference with this name already exists"},
{GIT_EOVERFLOW, "The given integer literal is too large to be parsed"},
{GIT_ENOTNUM, "The given literal is not a valid number"},
};
const char *git_strerror(int num)
#include <stdarg.h>
static GIT_TLS char g_last_error[1024];
int git__rethrow(int error, const char *msg, ...)
{
size_t i;
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);
if (num == GIT_EOSERR)
return strerror(errno);
for (i = 0; i < ARRAY_SIZE(error_codes); i++)
if (num == error_codes[i].num)
return error_codes[i].str;
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 "Unknown error";
return error;
}
int git__throw(int error, const char *msg, ...)
{
va_list va;
va_start(va, msg);
vsnprintf(g_last_error, sizeof(g_last_error), msg, va);
va_end(va);
return error;
}
const char *git_lasterror(void)
{
return g_last_error;
}
......@@ -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;
}
......
......@@ -6,16 +6,41 @@
#define MSB(x, bits) ((x) & (~0ULL << (bitsizeof(x) - (bits))))
/*
* Don't wrap malloc/calloc.
* Use the default versions in glibc, and make
* sure that any methods that allocate memory
* return a GIT_ENOMEM error when allocation
* fails.
* Custom memory allocation wrappers
* that set error code and error message
* on allocation failure
*/
#define git__malloc malloc
#define git__calloc calloc
#define git__realloc realloc
#define git__strdup strdup
GIT_INLINE(void *) git__malloc(size_t len)
{
void *ptr = malloc(len);
if (!ptr)
git__throw(GIT_ENOMEM, "Out of memory. Failed to allocate %d bytes.", (int)len);
return ptr;
}
GIT_INLINE(void *) git__calloc(size_t nelem, size_t elsize)
{
void *ptr = calloc(nelem, elsize);
if (!ptr)
git__throw(GIT_ENOMEM, "Out of memory. Failed to allocate %d bytes.", (int)elsize);
return ptr;
}
GIT_INLINE(char *) git__strdup(const char *str)
{
char *ptr = strdup(str);
if (!ptr)
git__throw(GIT_ENOMEM, "Out of memory. Failed to duplicate string");
return ptr;
}
GIT_INLINE(void *) git__realloc(void *ptr, size_t size)
{
void *new_ptr = realloc(ptr, size);
if (!new_ptr)
git__throw(GIT_ENOMEM, "Out of memory. Failed to allocate %d bytes.", (int)size);
return new_ptr;
}
extern int git__fmt(char *, size_t, const char *, ...)
GIT_FORMAT_PRINTF(3, 4);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment