diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 000000000..f90540b55
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+*.c eol=lf
+*.h eol=lf
diff --git a/README.md b/README.md
index dae6a76bf..7cfde59f8 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,7 @@ Under Unix-like systems, like Linux, *BSD and Mac OS X, libgit2 expects `pthread
they should be installed by default on all systems. Under Windows, libgit2 uses the native Windows API
for threading.
-Additionally, he following libraries may be used as replacement for built-in functionality:
+Additionally, the following libraries may be used as replacement for built-in functionality:
* LibSSL **(optional)**
@@ -88,6 +88,9 @@ The waf build system for libgit2 accepts the following flags:
--with-sqlite
Enable sqlite support.
+ --with-redis
+ Enable redis support.
+
You can run `./waf --help` to see a full list of install options and
targets.
diff --git a/include/git2.h b/include/git2.h
index ff55aef2d..0d0e54898 100644
--- a/include/git2.h
+++ b/include/git2.h
@@ -26,9 +26,9 @@
#ifndef INCLUDE_git_git_h__
#define INCLUDE_git_git_h__
-#define LIBGIT2_VERSION "0.11.0"
+#define LIBGIT2_VERSION "0.12.0"
#define LIBGIT2_VER_MAJOR 0
-#define LIBGIT2_VER_MINOR 11
+#define LIBGIT2_VER_MINOR 12
#define LIBGIT2_VER_REVISION 0
#include "git2/common.h"
diff --git a/include/git2/common.h b/include/git2/common.h
index ab267e620..9a27ac2e5 100644
--- a/include/git2/common.h
+++ b/include/git2/common.h
@@ -84,92 +84,6 @@
* @{
*/
-/** Operation completed successfully. */
-#define GIT_SUCCESS 0
-
-/**
- * Operation failed, with unspecified reason.
- * This value also serves as the base error code; all other
- * error codes are subtracted from it such that all errors
- * are < 0, in typical POSIX C tradition.
- */
-#define GIT_ERROR -1
-
-/** Input was not a properly formatted Git object id. */
-#define GIT_ENOTOID (GIT_ERROR - 1)
-
-/** Input does not exist in the scope searched. */
-#define GIT_ENOTFOUND (GIT_ERROR - 2)
-
-/** Not enough space available. */
-#define GIT_ENOMEM (GIT_ERROR - 3)
-
-/** Consult the OS error information. */
-#define GIT_EOSERR (GIT_ERROR - 4)
-
-/** The specified object is of invalid type */
-#define GIT_EOBJTYPE (GIT_ERROR - 5)
-
-/** The specified object has its data corrupted */
-#define GIT_EOBJCORRUPTED (GIT_ERROR - 6)
-
-/** The specified repository is invalid */
-#define GIT_ENOTAREPO (GIT_ERROR - 7)
-
-/** The object or config variable type is invalid or doesn't match */
-#define GIT_EINVALIDTYPE (GIT_ERROR - 8)
-
-/** The object cannot be written because it's missing internal data */
-#define GIT_EMISSINGOBJDATA (GIT_ERROR - 9)
-
-/** The packfile for the ODB is corrupted */
-#define GIT_EPACKCORRUPTED (GIT_ERROR - 10)
-
-/** Failed to acquire or release a file lock */
-#define GIT_EFLOCKFAIL (GIT_ERROR - 11)
-
-/** The Z library failed to inflate/deflate an object's data */
-#define GIT_EZLIB (GIT_ERROR - 12)
-
-/** The queried object is currently busy */
-#define GIT_EBUSY (GIT_ERROR - 13)
-
-/** The index file is not backed up by an existing repository */
-#define GIT_EBAREINDEX (GIT_ERROR - 14)
-
-/** The name of the reference is not valid */
-#define GIT_EINVALIDREFNAME (GIT_ERROR - 15)
-
-/** The specified reference has its data corrupted */
-#define GIT_EREFCORRUPTED (GIT_ERROR - 16)
-
-/** The specified symbolic reference is too deeply nested */
-#define GIT_ETOONESTEDSYMREF (GIT_ERROR - 17)
-
-/** The pack-refs file is either corrupted or its format is not currently supported */
-#define GIT_EPACKEDREFSCORRUPTED (GIT_ERROR - 18)
-
-/** The path is invalid */
-#define GIT_EINVALIDPATH (GIT_ERROR - 19)
-
-/** The revision walker is empty; there are no more commits left to iterate */
-#define GIT_EREVWALKOVER (GIT_ERROR - 20)
-
-/** The state of the reference is not valid */
-#define GIT_EINVALIDREFSTATE (GIT_ERROR - 21)
-
-/** This feature has not been implemented yet */
-#define GIT_ENOTIMPLEMENTED (GIT_ERROR - 22)
-
-/** A reference with this name already exists */
-#define GIT_EEXISTS (GIT_ERROR - 23)
-
-/** The given integer literal is too large to be parsed */
-#define GIT_EOVERFLOW (GIT_ERROR - 24)
-
-/** The given literal is not a valid number */
-#define GIT_ENOTNUM (GIT_ERROR - 25)
-
GIT_BEGIN_DECL
typedef struct {
diff --git a/include/git2/errors.h b/include/git2/errors.h
index 627e67c70..7e957b803 100644
--- a/include/git2/errors.h
+++ b/include/git2/errors.h
@@ -25,6 +25,8 @@
#ifndef INCLUDE_git_errors_h__
#define INCLUDE_git_errors_h__
+#include "common.h"
+
/**
* @file git2/errors.h
* @brief Git error handling routines and variables
@@ -33,8 +35,106 @@
*/
GIT_BEGIN_DECL
+typedef enum {
+ GIT_SUCCESS = 0,
+ GIT_ERROR = -1,
+
+ /** Input was not a properly formatted Git object id. */
+ GIT_ENOTOID = -2,
+
+ /** Input does not exist in the scope searched. */
+ GIT_ENOTFOUND = -3,
+
+ /** Not enough space available. */
+ GIT_ENOMEM = -4,
+
+ /** Consult the OS error information. */
+ GIT_EOSERR = -5,
+
+ /** The specified object is of invalid type */
+ GIT_EOBJTYPE = -6,
+
+ /** The specified repository is invalid */
+ GIT_ENOTAREPO = -7,
+
+ /** The object type is invalid or doesn't match */
+ GIT_EINVALIDTYPE = -8,
+
+ /** The object cannot be written because it's missing internal data */
+ GIT_EMISSINGOBJDATA = -9,
+
+ /** The packfile for the ODB is corrupted */
+ GIT_EPACKCORRUPTED = -10,
+
+ /** Failed to acquire or release a file lock */
+ GIT_EFLOCKFAIL = -11,
+
+ /** The Z library failed to inflate/deflate an object's data */
+ GIT_EZLIB = -12,
+
+ /** The queried object is currently busy */
+ GIT_EBUSY = -13,
+
+ /** The index file is not backed up by an existing repository */
+ GIT_EBAREINDEX = -14,
+
+ /** The name of the reference is not valid */
+ GIT_EINVALIDREFNAME = -15,
+
+ /** The specified reference has its data corrupted */
+ GIT_EREFCORRUPTED = -16,
+
+ /** The specified symbolic reference is too deeply nested */
+ GIT_ETOONESTEDSYMREF = -17,
+
+ /** The pack-refs file is either corrupted or its format is not currently supported */
+ GIT_EPACKEDREFSCORRUPTED = -18,
+
+ /** The path is invalid */
+ GIT_EINVALIDPATH = -19,
+
+ /** The revision walker is empty; there are no more commits left to iterate */
+ GIT_EREVWALKOVER = -20,
+
+ /** The state of the reference is not valid */
+ GIT_EINVALIDREFSTATE = -21,
+
+ /** This feature has not been implemented yet */
+ GIT_ENOTIMPLEMENTED = -22,
+
+ /** A reference with this name already exists */
+ GIT_EEXISTS = -23,
+
+ /** The given integer literal is too large to be parsed */
+ GIT_EOVERFLOW = -24,
+
+ /** The given literal is not a valid number */
+ GIT_ENOTNUM = -25,
+
+ /** Streaming error */
+ GIT_ESTREAM = -26,
+
+ /** invalid arguments to function */
+ GIT_EINVALIDARGS = -27,
+
+ /** The specified object has its data corrupted */
+ GIT_EOBJCORRUPTED = -28,
+} git_error;
+
+/**
+ * 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_lasterror(void);
+
/**
* strerror() for the Git library
+ *
+ * Get a string description for a given error code.
+ * NOTE: This method will be eventually deprecated in favor
+ * of the new `git_lasterror`.
+ *
* @param num The error code to explain
* @return a string explaining the error code
*/
diff --git a/include/git2/index.h b/include/git2/index.h
index 7991de92e..2d8975ca1 100644
--- a/include/git2/index.h
+++ b/include/git2/index.h
@@ -232,10 +232,10 @@ GIT_EXTERN(int) git_index_append(git_index *index, const char *path, int stage);
* @param source_entry new entry object
* @return 0 on success, otherwise an error code
*/
-GIT_EXTERN(int) git_index_apppend2(git_index *index, const git_index_entry *source_entry);
+GIT_EXTERN(int) git_index_append2(git_index *index, const git_index_entry *source_entry);
/**
- * Remove an entry from the index
+ * Remove an entry from the index
*
* @param index an existing index object
* @param position position of the entry to remove
diff --git a/include/git2/thread-utils.h b/include/git2/thread-utils.h
index fb8644b93..e26876bea 100644
--- a/include/git2/thread-utils.h
+++ b/include/git2/thread-utils.h
@@ -35,6 +35,7 @@
#if defined(__APPLE__) && defined(__MACH__)
# undef GIT_TLS
+# define GIT_TLS
#elif defined(__GNUC__) || \
defined(__SUNPRO_C) || \
diff --git a/src/backends/hiredis.c b/src/backends/hiredis.c
index 707412bf6..2533a16da 100644
--- a/src/backends/hiredis.c
+++ b/src/backends/hiredis.c
@@ -53,7 +53,7 @@ int hiredis_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_backe
reply = redisCommand(backend->db, "HMGET %b %s %s", oid->id, GIT_OID_RAWSZ,
"type", "size");
- if (reply->type == REDIS_REPLY_ARRAY) {
+ if (reply && reply->type == REDIS_REPLY_ARRAY) {
if (reply->element[0]->type != REDIS_REPLY_NIL &&
reply->element[0]->type != REDIS_REPLY_NIL) {
*type_p = (git_otype) atoi(reply->element[0]->str);
@@ -83,7 +83,7 @@ int hiredis_backend__read(void **data_p, size_t *len_p, git_otype *type_p, git_o
reply = redisCommand(backend->db, "HMGET %b %s %s %s", oid->id, GIT_OID_RAWSZ,
"type", "size", "data");
- if (reply->type == REDIS_REPLY_ARRAY) {
+ if (reply && reply->type == REDIS_REPLY_ARRAY) {
if (reply->element[0]->type != REDIS_REPLY_NIL &&
reply->element[1]->type != REDIS_REPLY_NIL &&
reply->element[2]->type != REDIS_REPLY_NIL) {
@@ -118,7 +118,7 @@ int hiredis_backend__exists(git_odb_backend *_backend, const git_oid *oid) {
found = 0;
reply = redisCommand(backend->db, "exists %b", oid->id, GIT_OID_RAWSZ);
- if (reply->type != REDIS_REPLY_NIL && reply->type != REDIS_REPLY_ERROR)
+ if (reply && reply->type != REDIS_REPLY_NIL && reply->type != REDIS_REPLY_ERROR)
found = 1;
@@ -144,7 +144,8 @@ int hiredis_backend__write(git_oid *id, git_odb_backend *_backend, const void *d
"size %d "
"data %b ", id->id, GIT_OID_RAWSZ,
(int) type, len, data, len);
- error = reply->type == REDIS_REPLY_ERROR ? GIT_ERROR : GIT_SUCCESS;
+
+ error = (reply == NULL || reply->type == REDIS_REPLY_ERROR) ? GIT_ERROR : GIT_SUCCESS;
freeReplyObject(reply);
return error;
diff --git a/src/blob.c b/src/blob.c
index 5e3c22fbf..987169358 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -62,7 +62,7 @@ int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *b
git_odb_stream *stream;
if ((error = git_odb_open_wstream(&stream, repo->db, len, GIT_OBJ_BLOB)) < GIT_SUCCESS)
- return error;
+ return git__rethrow(error, "Failed to create blob. Can't open write stream");
stream->write(stream, buffer, len);
@@ -81,7 +81,7 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
git_odb_stream *stream;
if (repo->path_workdir == NULL)
- return GIT_ENOTFOUND;
+ return git__throw(GIT_ENOTFOUND, "Failed to create blob. No workdir given");
git__joinpath(full_path, repo->path_workdir, path);
@@ -106,7 +106,7 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
if (read_len < 0) {
gitfo_close(fd);
stream->free(stream);
- return GIT_EOSERR;
+ return git__throw(GIT_EOSERR, "Failed to create blob. Can't read full file");
}
stream->write(stream, buffer, read_len);
diff --git a/src/cache.c b/src/cache.c
index fd42e2c5b..433fc3d9c 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -29,10 +29,7 @@
#include "thread-utils.h"
#include "cache.h"
-#define GIT_CACHE_OPENADR 3
-
-
-void git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr)
+int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr)
{
size_t i;
@@ -52,12 +49,15 @@ void git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_p
cache->free_obj = free_ptr;
cache->nodes = git__malloc((size + 1) * sizeof(cache_node));
+ if (cache->nodes == NULL)
+ return GIT_ENOMEM;
for (i = 0; i < (size + 1); ++i) {
git_mutex_init(&cache->nodes[i].lock);
cache->nodes[i].ptr = NULL;
- cache->nodes[i].lru = 0;
}
+
+ return GIT_SUCCESS;
}
void git_cache_free(git_cache *cache)
@@ -77,85 +77,53 @@ void git_cache_free(git_cache *cache)
void *git_cache_get(git_cache *cache, const git_oid *oid)
{
const uint32_t *hash;
- size_t i, pos, found = 0;
cache_node *node = NULL;
+ void *result = NULL;
hash = (const uint32_t *)oid->id;
+ node = &cache->nodes[hash[0] & cache->size_mask];
- for (i = 0; !found && i < GIT_CACHE_OPENADR; ++i) {
- pos = hash[i] & cache->size_mask;
- node = &cache->nodes[pos];
-
- git_mutex_lock(&node->lock);
- {
- if (node->ptr && git_cached_obj_compare(node->ptr, oid) == 0) {
- git_cached_obj_incref(node->ptr);
- node->lru = ++cache->lru_count;
- found = 1;
- }
+ git_mutex_lock(&node->lock);
+ {
+ if (node->ptr && git_cached_obj_compare(node->ptr, oid) == 0) {
+ git_cached_obj_incref(node->ptr);
+ result = node->ptr;
}
- git_mutex_unlock(&node->lock);
}
+ git_mutex_unlock(&node->lock);
-
- return found ? node->ptr : NULL;
+ return result;
}
void *git_cache_try_store(git_cache *cache, void *entry)
{
- cache_node *nodes[GIT_CACHE_OPENADR], *lru_node;
const uint32_t *hash;
const git_oid *oid;
- size_t i;
+ cache_node *node = NULL;
oid = &((git_cached_obj*)entry)->oid;
hash = (const uint32_t *)oid->id;
+ node = &cache->nodes[hash[0] & cache->size_mask];
/* increase the refcount on this object, because
* the cache now owns it */
git_cached_obj_incref(entry);
+ git_mutex_lock(&node->lock);
- for (i = 0; i < GIT_CACHE_OPENADR; ++i) {
- size_t pos = hash[i] & cache->size_mask;
-
- nodes[i] = &cache->nodes[pos];
- git_mutex_lock(&nodes[i]->lock);
- }
-
- lru_node = nodes[0];
-
- for (i = 0; i < GIT_CACHE_OPENADR; ++i) {
-
- if (nodes[i]->ptr == NULL) {
- nodes[i]->ptr = entry;
- nodes[i]->lru = ++cache->lru_count;
- break;
- } else if (git_cached_obj_compare(nodes[i]->ptr, oid) == 0) {
- git_cached_obj_decref(entry, cache->free_obj);
- entry = nodes[i]->ptr;
- nodes[i]->lru = ++cache->lru_count;
- break;
- }
-
- if (nodes[i]->lru < lru_node->lru)
- lru_node = nodes[i];
- }
-
- if (i == GIT_CACHE_OPENADR) {
- void *old_entry = lru_node->ptr;
- assert(old_entry);
-
- git_cached_obj_decref(old_entry, cache->free_obj);
- lru_node->ptr = entry;
- lru_node->lru = ++cache->lru_count;
+ if (node->ptr == NULL) {
+ node->ptr = entry;
+ } else if (git_cached_obj_compare(node->ptr, oid) == 0) {
+ git_cached_obj_decref(entry, cache->free_obj);
+ entry = node->ptr;
+ } else {
+ git_cached_obj_decref(node->ptr, cache->free_obj);
+ node->ptr = entry;
}
/* increase the refcount again, because we are
* returning it to the user */
git_cached_obj_incref(entry);
-
- for (i = 0; i < GIT_CACHE_OPENADR; ++i)
- git_mutex_unlock(&nodes[i]->lock);
+ git_mutex_unlock(&node->lock);
return entry;
}
diff --git a/src/cache.h b/src/cache.h
index 975aaff7e..4794dea3a 100644
--- a/src/cache.h
+++ b/src/cache.h
@@ -19,7 +19,6 @@ typedef struct {
typedef struct {
git_cached_obj *ptr;
git_mutex lock;
- unsigned int lru;
} cache_node;
typedef struct {
@@ -31,7 +30,7 @@ typedef struct {
} git_cache;
-void git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr);
+int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr);
void git_cache_free(git_cache *cache);
void *git_cache_try_store(git_cache *cache, void *entry);
diff --git a/src/commit.c b/src/commit.c
index 0c37ec59b..54d7a47fe 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -286,7 +286,7 @@ int commit_parse_buffer(git_commit *commit, const void *data, size_t len)
if (buffer < buffer_end) {
const char *line_end;
- size_t message_len = buffer_end - buffer;
+ size_t message_len;
/* Long message */
message_len = buffer_end - buffer;
diff --git a/src/common.h b/src/common.h
index 5ad878e26..f4f11fd2f 100644
--- a/src/common.h
+++ b/src/common.h
@@ -50,10 +50,14 @@ typedef SSIZE_T ssize_t;
#include "git2/common.h"
#include "git2/types.h"
-#include "util.h"
+#include "git2/errors.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__ */
diff --git a/src/errors.c b/src/errors.c
index 1ef2baadb..1fb68ee65 100644
--- a/src/errors.c
+++ b/src/errors.c
@@ -1,6 +1,35 @@
+/*
+ * 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 */
+#include
+
+static GIT_TLS char g_last_error[1024];
+
static struct {
int num;
const char *str;
@@ -46,3 +75,38 @@ const char *git_strerror(int num)
return "Unknown error";
}
+
+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;
+
+ 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;
+}
+
diff --git a/src/fileops.c b/src/fileops.c
index 5dd4a3806..45dd8f444 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -10,7 +10,7 @@ int gitfo_mkdir_2file(const char *file_path)
error = git__dirname_r(target_folder_path, sizeof(target_folder_path), file_path);
if (error < GIT_SUCCESS)
- return error;
+ return git__throw(GIT_EINVALIDPATH, "Failed to recursively build `%s` tree structure. Unable to parse parent folder name", file_path);
/* Does the containing folder exist? */
if (gitfo_isdir(target_folder_path)) {
@@ -19,7 +19,7 @@ int gitfo_mkdir_2file(const char *file_path)
/* Let's create the tree structure */
error = gitfo_mkdir_recurs(target_folder_path, mode);
if (error < GIT_SUCCESS)
- return error;
+ return error; /* The callee already takes care of setting the correct error message. */
}
return GIT_SUCCESS;
@@ -164,19 +164,19 @@ int gitfo_read_file(gitfo_buf *obj, const char *path)
if (((size = gitfo_size(fd)) < 0) || !git__is_sizet(size+1)) {
gitfo_close(fd);
- return GIT_ERROR;
+ return git__throw(GIT_ERROR, "Failed to read file `%s`. Either an error occured while calculating its size or the file is too large", path);
}
len = (size_t) size;
if ((buff = git__malloc(len + 1)) == NULL) {
gitfo_close(fd);
- return GIT_ERROR;
+ return GIT_ENOMEM;
}
if (gitfo_read(fd, buff, len) < 0) {
gitfo_close(fd);
free(buff);
- return GIT_ERROR;
+ return git__throw(GIT_ERROR, "Failed to read file `%s`", path);
}
buff[len] = '\0';
@@ -197,13 +197,15 @@ void gitfo_free_buf(gitfo_buf *obj)
int gitfo_mv(const char *from, const char *to)
{
+ int error;
+
#ifdef GIT_WIN32
/*
* Win32 POSIX compilance my ass. If the destination
* file exists, the `rename` call fails. This is as
* close as it gets with the Win32 API.
*/
- return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? GIT_SUCCESS : GIT_EOSERR;
+ error = MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? GIT_SUCCESS : GIT_EOSERR;
#else
/* Don't even try this on Win32 */
if (!link(from, to)) {
@@ -214,16 +216,21 @@ int gitfo_mv(const char *from, const char *to)
if (!rename(from, to))
return GIT_SUCCESS;
- return GIT_EOSERR;
+ error = GIT_EOSERR;
#endif
+
+ if (error < GIT_SUCCESS)
+ return git__throw(error, "Failed to move file from `%s`to `%s`", from, to);
+
+ return GIT_SUCCESS;
}
int gitfo_mv_force(const char *from, const char *to)
{
if (gitfo_mkdir_2file(to) < GIT_SUCCESS)
- return GIT_EOSERR;
+ return GIT_EOSERR; /* The callee already takes care of setting the correct error message. */
- return gitfo_mv(from, to);
+ return gitfo_mv(from, to); /* The callee already takes care of setting the correct error message. */
}
int gitfo_map_ro(git_map *out, git_file fd, git_off_t begin, size_t len)
@@ -338,7 +345,7 @@ int gitfo_dirent(
struct dirent *de;
if (!wd_len || path_sz < wd_len + 2)
- return GIT_ERROR;
+ return git__throw(GIT_EINVALIDARGS, "Failed to process `%s` tree structure. Path is either empty or buffer size is too short", path);
while (path[wd_len - 1] == '/')
wd_len--;
@@ -347,7 +354,7 @@ int gitfo_dirent(
dir = opendir(path);
if (!dir)
- return GIT_EOSERR;
+ return git__throw(GIT_EOSERR, "Failed to process `%s` tree structure. An error occured while opening the directory", path);
while ((de = readdir(dir)) != NULL) {
size_t de_len;
@@ -364,14 +371,14 @@ int gitfo_dirent(
de_len = strlen(de->d_name);
if (path_sz < wd_len + de_len + 1) {
closedir(dir);
- return GIT_ERROR;
+ return git__throw(GIT_ERROR, "Failed to process `%s` tree structure. Buffer size is too short", path);
}
strcpy(path + wd_len, de->d_name);
result = fn(arg, path);
if (result < GIT_SUCCESS) {
closedir(dir);
- return result;
+ return result; /* The callee is reponsible for setting the correct error message */
}
if (result > 0) {
closedir(dir);
@@ -399,7 +406,7 @@ int retrieve_path_root_offset(const char *path)
if (*(path + offset) == '/')
return offset;
- return GIT_ERROR;
+ return -1; /* Not a real error. Rather a signal than the path is not rooted */
}
@@ -438,7 +445,11 @@ int gitfo_mkdir_recurs(const char *path, int mode)
error = gitfo_mkdir(path, mode);
free(path_copy);
- return error;
+
+ if (error < GIT_SUCCESS)
+ return git__throw(error, "Failed to recursively create `%s` tree structure", path);
+
+ return GIT_SUCCESS;
}
static int retrieve_previous_path_component_start(const char *path)
@@ -484,7 +495,7 @@ int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path)
if (root_path_offset < 0) {
error = gitfo_getcwd(buffer_out, size);
if (error < GIT_SUCCESS)
- return error;
+ return error; /* The callee already takes care of setting the correct error message. */
len = strlen(buffer_out);
buffer_out += len;
@@ -529,7 +540,7 @@ int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path)
/* Are we escaping out of the root dir? */
if (len < 0)
- return GIT_EINVALIDPATH;
+ return git__throw(GIT_EINVALIDPATH, "Failed to normalize path `%s`. The path escapes out of the root directory", path);
buffer_out = (char *)buffer_out_start + len;
continue;
@@ -537,7 +548,7 @@ int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path)
/* Guard against potential multiple dot path traversal (cf http://cwe.mitre.org/data/definitions/33.html) */
if (only_dots && segment_len > 0)
- return GIT_EINVALIDPATH;
+ return git__throw(GIT_EINVALIDPATH, "Failed to normalize path `%s`. The path contains a segment with three `.` or more", path);
*buffer_out++ = '/';
len++;
@@ -557,21 +568,21 @@ int gitfo_prettify_file_path(char *buffer_out, size_t size, const char *path)
/* Let's make sure the filename isn't empty nor a dot */
if (path_len == 0 || (path_len == 1 && *path == '.'))
- return GIT_EINVALIDPATH;
+ return git__throw(GIT_EINVALIDPATH, "Failed to normalize file path `%s`. The path is either empty or equals `.`", path);
/* Let's make sure the filename doesn't end with "/", "/." or "/.." */
for (i = 1; path_len > i && i < 4; i++) {
if (!strncmp(path + path_len - i, pattern, i))
- return GIT_EINVALIDPATH;
+ return git__throw(GIT_EINVALIDPATH, "Failed to normalize file path `%s`. The path points to a folder", path);
}
error = gitfo_prettify_dir_path(buffer_out, size, path);
if (error < GIT_SUCCESS)
- return error;
+ return error; /* The callee already takes care of setting the correct error message. */
path_len = strlen(buffer_out);
- if (path_len < 2)
- return GIT_EINVALIDPATH;
+ if (path_len < 2) /* TODO: Fixme. We should also take of detecting Windows rooted path (probably through usage of retrieve_path_root_offset) */
+ return git__throw(GIT_EINVALIDPATH, "Failed to normalize file path `%s`. The path points to a folder", path);
/* Remove the trailing slash */
buffer_out[path_len - 1] = '\0';
@@ -616,11 +627,11 @@ int gitfo_getcwd(char *buffer_out, size_t size)
#ifdef GIT_WIN32
cwd_buffer = _getcwd(buffer_out, size);
#else
- cwd_buffer = getcwd(buffer_out, size); //TODO: Fixme. Ensure the required headers are correctly included
+ cwd_buffer = getcwd(buffer_out, size);
#endif
if (cwd_buffer == NULL)
- return GIT_EOSERR;
+ return git__throw(GIT_EOSERR, "Failed to retrieve current working directory");
posixify_path(buffer_out);
diff --git a/src/index.c b/src/index.c
index 130d1fd36..f643e73fb 100644
--- a/src/index.c
+++ b/src/index.c
@@ -421,7 +421,7 @@ int git_index_add2(git_index *index, const git_index_entry *source_entry)
return index_insert(index, source_entry, 1);
}
-int git_index_apppend2(git_index *index, const git_index_entry *source_entry)
+int git_index_append2(git_index *index, const git_index_entry *source_entry)
{
return index_insert(index, source_entry, 0);
}
diff --git a/src/odb.c b/src/odb.c
index 43d0ef9a4..f09b6d7e9 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -221,7 +221,7 @@ static int init_fake_wstream(git_odb_stream **stream_p, git_odb_backend *backend
*
***********************************************************/
-int backend_sort_cmp(const void *a, const void *b)
+static int backend_sort_cmp(const void *a, const void *b)
{
const backend_internal *backend_a = *(const backend_internal **)(a);
const backend_internal *backend_b = *(const backend_internal **)(b);
@@ -234,15 +234,19 @@ int backend_sort_cmp(const void *a, const void *b)
int git_odb_new(git_odb **out)
{
+ int error;
+
git_odb *db = git__calloc(1, sizeof(*db));
if (!db)
return GIT_ENOMEM;
- git_cache_init(&db->cache, GIT_DEFAULT_CACHE_SIZE, &free_odb_object);
+ error = git_cache_init(&db->cache, GIT_DEFAULT_CACHE_SIZE, &free_odb_object);
+ if (error < GIT_SUCCESS)
+ return error;
- if (git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) {
+ if ((error = git_vector_init(&db->backends, 4, backend_sort_cmp)) < GIT_SUCCESS) {
free(db);
- return GIT_ENOMEM;
+ return error;
}
*out = db;
@@ -444,7 +448,7 @@ int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git
return error;
*len_p = object->raw.len;
- *type_p = object->raw.len;
+ *type_p = object->raw.type;
git_odb_object_close(object);
}
diff --git a/src/odb_loose.c b/src/odb_loose.c
index 4f475f2c3..873dbfa0a 100644
--- a/src/odb_loose.c
+++ b/src/odb_loose.c
@@ -336,7 +336,6 @@ static int inflate_disk_obj(git_rawobj *out, gitfo_buf *obj)
{
unsigned char head[64], *buf;
z_stream zs;
- int z_status;
obj_hdr hdr;
size_t used;
@@ -350,7 +349,7 @@ static int inflate_disk_obj(git_rawobj *out, gitfo_buf *obj)
* inflate the initial part of the io buffer in order
* to parse the object header (type and size).
*/
- if ((z_status = start_inflate(&zs, obj, head, sizeof(head))) < Z_OK)
+ if (start_inflate(&zs, obj, head, sizeof(head)) < Z_OK)
return GIT_ERROR;
if ((used = get_object_header(&hdr, head)) == 0)
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/repository.c b/src/repository.c
index 8cc2644ca..1072b22a1 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -124,16 +124,16 @@ static int check_repository_dirs(git_repository *repo)
char path_aux[GIT_PATH_MAX];
if (gitfo_isdir(repo->path_repository) < GIT_SUCCESS)
- return GIT_ENOTAREPO;
+ return git__throw(GIT_ENOTAREPO, "`%s` is not a folder", repo->path_repository);
/* Ensure GIT_OBJECT_DIRECTORY exists */
if (gitfo_isdir(repo->path_odb) < GIT_SUCCESS)
- return GIT_ENOTAREPO;
+ return git__throw(GIT_ENOTAREPO, "`%s` does not exist", repo->path_odb);
/* Ensure HEAD file exists */
git__joinpath(path_aux, repo->path_repository, GIT_HEAD_FILE);
if (gitfo_exists(path_aux) < 0)
- return GIT_ENOTAREPO;
+ return git__throw(GIT_ENOTAREPO, "HEAD file is missing");
return GIT_SUCCESS;
}
@@ -145,12 +145,12 @@ static int guess_repository_dirs(git_repository *repo, const char *repository_pa
/* Git directory name */
if (git__basename_r(buffer, sizeof(buffer), repository_path) < 0)
- return GIT_EINVALIDPATH;
+ return git__throw(GIT_EINVALIDPATH, "Unable to parse folder name from `%s`", repository_path);
if (strcmp(buffer, DOT_GIT) == 0) {
/* Path to working dir */
if (git__dirname_r(buffer, sizeof(buffer), repository_path) < 0)
- return GIT_EINVALIDPATH;
+ return git__throw(GIT_EINVALIDPATH, "Unable to parse parent folder name from `%s`", repository_path);
path_work_tree = buffer;
}
@@ -159,13 +159,19 @@ static int guess_repository_dirs(git_repository *repo, const char *repository_pa
static git_repository *repository_alloc()
{
+ int error;
+
git_repository *repo = git__malloc(sizeof(git_repository));
if (!repo)
return NULL;
memset(repo, 0x0, sizeof(git_repository));
- git_cache_init(&repo->objects, GIT_DEFAULT_CACHE_SIZE, &git_object__free);
+ error = git_cache_init(&repo->objects, GIT_DEFAULT_CACHE_SIZE, &git_object__free);
+ if (error < GIT_SUCCESS) {
+ free(repo);
+ return NULL;
+ }
if (git_repository__refcache_init(&repo->references) < GIT_SUCCESS) {
free(repo);
@@ -177,7 +183,7 @@ static git_repository *repository_alloc()
static int init_odb(git_repository *repo)
{
- return git_odb_open(&repo->db, repo->path_odb);
+ return git_odb_open(&repo->db, repo->path_odb); /* TODO: Move odb.c to new error handling */
}
int git_repository_open3(git_repository **repo_out,
@@ -192,7 +198,7 @@ int git_repository_open3(git_repository **repo_out,
assert(repo_out);
if (object_database == NULL)
- return GIT_ERROR;
+ return git__throw(GIT_EINVALIDARGS, "Failed to open repository. `object_database` can't be null");
repo = repository_alloc();
if (repo == NULL)
@@ -218,7 +224,7 @@ int git_repository_open3(git_repository **repo_out,
cleanup:
git_repository_free(repo);
- return error;
+ return git__rethrow(error, "Failed to open repository");
}
@@ -259,7 +265,7 @@ int git_repository_open2(git_repository **repo_out,
cleanup:
git_repository_free(repo);
- return error;
+ return git__rethrow(error, "Failed to open repository");
}
int git_repository_open(git_repository **repo_out, const char *path)
@@ -290,7 +296,7 @@ int git_repository_open(git_repository **repo_out, const char *path)
cleanup:
git_repository_free(repo);
- return error;
+ return git__rethrow(error, "Failed to open repository");
}
void git_repository_free(git_repository *repo)
@@ -322,7 +328,7 @@ int git_repository_index(git_index **index_out, git_repository *repo)
assert(index_out && repo);
if (repo->index == NULL) {
- error = git_index_open_inrepo(&repo->index, repo);
+ error = git_index_open_inrepo(&repo->index, repo); /* TODO: move index.c to new error handling */
if (error < GIT_SUCCESS)
return error;
@@ -349,7 +355,7 @@ static int repo_init_reinit(repo_init *results)
static int repo_init_createhead(git_repository *repo)
{
git_reference *head_reference;
- return git_reference_create_symbolic(&head_reference, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_MASTER_FILE);
+ return git_reference_create_symbolic(&head_reference, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_MASTER_FILE); /* TODO: finalize moving refs.c to new error handling */
}
static int repo_init_check_head_existence(char * repository_path)
@@ -363,6 +369,7 @@ static int repo_init_check_head_existence(char * repository_path)
static int repo_init_structure(repo_init *results)
{
const int mode = 0755; /* or 0777 ? */
+ int error;
char temp_path[GIT_PATH_MAX];
char *git_dir = results->path_repository;
@@ -372,23 +379,27 @@ static int repo_init_structure(repo_init *results)
/* Creates the '/objects/info/' directory */
git__joinpath(temp_path, git_dir, GIT_OBJECTS_INFO_DIR);
- if (gitfo_mkdir_recurs(temp_path, mode) < GIT_SUCCESS)
- return GIT_ERROR;
+ error = gitfo_mkdir_recurs(temp_path, mode);
+ if (error < GIT_SUCCESS)
+ return error;
/* Creates the '/objects/pack/' directory */
git__joinpath(temp_path, git_dir, GIT_OBJECTS_PACK_DIR);
- if (gitfo_mkdir(temp_path, mode))
- return GIT_ERROR;
+ error = gitfo_mkdir(temp_path, mode);
+ if (error < GIT_SUCCESS)
+ return git__throw(error, "Unable to create `%s` folder", temp_path);
/* Creates the '/refs/heads/' directory */
git__joinpath(temp_path, git_dir, GIT_REFS_HEADS_DIR);
- if (gitfo_mkdir_recurs(temp_path, mode))
- return GIT_ERROR;
+ error = gitfo_mkdir_recurs(temp_path, mode);
+ if (error < GIT_SUCCESS)
+ return error;
/* Creates the '/refs/tags/' directory */
git__joinpath(temp_path, git_dir, GIT_REFS_TAGS_DIR);
- if (gitfo_mkdir(temp_path, mode))
- return GIT_ERROR;
+ error = gitfo_mkdir(temp_path, mode);
+ if (error < GIT_SUCCESS)
+ return git__throw(error, "Unable to create `%s` folder", temp_path);
/* TODO: what's left? templates? */
@@ -467,7 +478,7 @@ int git_repository_init(git_repository **repo_out, const char *path, unsigned is
cleanup:
free(results.path_repository);
git_repository_free(repo);
- return error;
+ return git__rethrow(error, "Failed to (re)init the repository `%s`", path);
}
int git_repository_is_empty(git_repository *repo)
@@ -477,10 +488,10 @@ int git_repository_is_empty(git_repository *repo)
error = git_reference_lookup(&head, repo, "HEAD");
if (error < GIT_SUCCESS)
- return error;
+ return git__throw(error, "Failed to determine the emptiness of the repository. An error occured while retrieving the HEAD reference");
if (git_reference_type(head) != GIT_REF_SYMBOLIC)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to determine the emptiness of the repository. HEAD is probably in detached state");
return git_reference_resolve(&branch, head) == GIT_SUCCESS ? 0 : 1;
}
diff --git a/src/revwalk.c b/src/revwalk.c
index 78798480f..8163851a3 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -210,7 +210,7 @@ static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawo
git_oid oid;
if (git_oid_mkstr(&oid, (char *)buffer + STRLEN("parent ")) < GIT_SUCCESS)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse commit. Parent object is corrupted");
commit->parents[i] = commit_lookup(walk, &oid);
if (commit->parents[i] == NULL)
@@ -222,14 +222,14 @@ static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawo
commit->out_degree = (unsigned short)parents;
if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse commit. Object is corrupted");
buffer = memchr(buffer, '>', buffer_end - buffer);
if (buffer == NULL)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse commit. Can't find author");
if (git__strtol32(&commit_time, (char *)buffer + 2, NULL, 10) < GIT_SUCCESS)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse commit. Can't parse commit time");
commit->time = (time_t)commit_time;
commit->parsed = 1;
@@ -245,11 +245,11 @@ static int commit_parse(git_revwalk *walk, commit_object *commit)
return GIT_SUCCESS;
if ((error = git_odb_read(&obj, walk->repo->db, &commit->oid)) < GIT_SUCCESS)
- return error;
+ return git__rethrow(error, "Failed to parse commit. Can't read object");
if (obj->raw.type != GIT_OBJ_COMMIT) {
git_odb_object_close(obj);
- return GIT_EOBJTYPE;
+ return git__throw(GIT_EOBJTYPE, "Failed to parse commit. Object is no commit object");
}
error = commit_quick_parse(walk, commit, &obj->raw);
@@ -305,7 +305,7 @@ static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting)
commit = commit_lookup(walk, oid);
if (commit == NULL)
- return GIT_ENOTFOUND;
+ return git__throw(GIT_ENOTFOUND, "Failed to push commit. Object not found");
commit->uninteresting = uninteresting;
diff --git a/src/signature.c b/src/signature.c
index e8014620a..62bd28b9a 100644
--- a/src/signature.c
+++ b/src/signature.c
@@ -115,22 +115,22 @@ static int parse_timezone_offset(const char *buffer, long *offset_out)
}
if (offset_start[0] != '-' && offset_start[0] != '+')
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. It doesn't start with '+' or '-'");
if (git__strtol32(&dec_offset, offset_start + 1, &offset_end, 10) < GIT_SUCCESS)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. It isn't a number");
if (offset_end - offset_start != 5)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. Invalid length");
hours = dec_offset / 100;
mins = dec_offset % 100;
if (hours > 14) // see http://www.worldtimezone.com/faq.html
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. Hour value too large");;
if (mins > 59)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. Minute value too large");
offset = (hours * 60) + mins;
@@ -157,19 +157,19 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
line_end = memchr(buffer, '\n', buffer_end - buffer);
if (!line_end)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. No newline found");;
if (buffer + (header_len + 1) > line_end)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Signature too short");
if (memcmp(buffer, header, header_len) != 0)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Expected prefix '%s' doesn't match actual", header);
buffer += header_len;
/* Parse name */
if ((name_end = memchr(buffer, '<', buffer_end - buffer)) == NULL)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Can't find e-mail start");
name_length = name_end - buffer - 1;
sig->name = git__malloc(name_length + 1);
@@ -181,11 +181,11 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
buffer = name_end + 1;
if (buffer >= line_end)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Ended unexpectedly");
/* Parse email */
if ((email_end = memchr(buffer, '>', buffer_end - buffer)) == NULL)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Can't find e-mail end");
email_length = email_end - buffer;
sig->email = git__malloc(email_length + 1);
@@ -197,10 +197,10 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
buffer = email_end + 1;
if (buffer >= line_end)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Ended unexpectedly");
if (git__strtol32(&time, buffer, &buffer, 10) < GIT_SUCCESS)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Timestamp isn't a number");
sig->when.time = (time_t)time;
diff --git a/src/tag.c b/src/tag.c
index 148eb280c..849429b7e 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -90,13 +90,13 @@ static int parse_tag_buffer(git_tag *tag, const char *buffer, const char *buffer
int error;
if ((error = git__parse_oid(&tag->target, &buffer, buffer_end, "object ")) < 0)
- return error;
+ return git__rethrow(error, "Failed to parse tag. Object field invalid");
if (buffer + 5 >= buffer_end)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Object too short");
if (memcmp(buffer, "type ", 5) != 0)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Type field not found");
buffer += 5;
tag->type = GIT_OBJ_BAD;
@@ -105,7 +105,7 @@ static int parse_tag_buffer(git_tag *tag, const char *buffer, const char *buffer
size_t type_length = strlen(tag_types[i]);
if (buffer + type_length >= buffer_end)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Object too short");
if (memcmp(buffer, tag_types[i], type_length) == 0) {
tag->type = i;
@@ -115,18 +115,19 @@ static int parse_tag_buffer(git_tag *tag, const char *buffer, const char *buffer
}
if (tag->type == GIT_OBJ_BAD)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Invalid object type");
if (buffer + 4 >= buffer_end)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Object too short");
if (memcmp(buffer, "tag ", 4) != 0)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Tag field not found");
+
buffer += 4;
search = memchr(buffer, '\n', buffer_end - buffer);
if (search == NULL)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Object too short");
text_len = search - buffer;
@@ -218,7 +219,7 @@ static int tag_create(
}
if (!git_odb_exists(repo->db, target))
- return GIT_ENOTFOUND;
+ return git__throw(GIT_ENOTFOUND, "Failed to create tag. Object to tag doesn't exist");
/* Try to find out what the type is */
if (target_type == GIT_OBJ_ANY) {
diff --git a/src/tree.c b/src/tree.c
index b7daf39c4..6f9fc8607 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -151,15 +151,15 @@ static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buf
return GIT_ENOMEM;
if (git__strtol32((long *)&entry->attr, buffer, &buffer, 8) < GIT_SUCCESS)
- return GIT_EOBJCORRUPTED;
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tree. Can't parse attributes");
if (*buffer++ != ' ') {
- error = GIT_EOBJCORRUPTED;
+ error = git__throw(GIT_EOBJCORRUPTED, "Failed to parse tree. Object it corrupted");
break;
}
if (memchr(buffer, 0, buffer_end - buffer) == NULL) {
- error = GIT_EOBJCORRUPTED;
+ error = git__throw(GIT_EOBJCORRUPTED, "Failed to parse tree. Object it corrupted");
break;
}
@@ -274,7 +274,7 @@ int git_tree_create_fromindex(git_oid *oid, git_index *index)
int error;
if (index->repository == NULL)
- return GIT_EBAREINDEX;
+ return git__throw(GIT_EBAREINDEX, "Failed to create tree. The index file is not backed up by an existing repository");
error = write_index(oid, index, "", 0, 0, git_index_entrycount(index));
return (error < GIT_SUCCESS) ? error : GIT_SUCCESS;
@@ -343,7 +343,7 @@ int git_treebuilder_insert(git_tree_entry **entry_out, git_treebuilder *bld, con
assert(bld && id && filename);
if (!valid_attributes(attributes))
- return GIT_ERROR;
+ return git__throw(GIT_ERROR, "Failed to insert entry. Invalid atrributes");
if ((pos = git_vector_bsearch2(&bld->entries, entry_search_cmp, filename)) != GIT_ENOTFOUND) {
entry = git_vector_get(&bld->entries, pos);
@@ -400,7 +400,7 @@ int git_treebuilder_remove(git_treebuilder *bld, const char *filename)
git_tree_entry *remove_ptr = (git_tree_entry *)git_treebuilder_get(bld, filename);
if (remove_ptr == NULL || remove_ptr->removed)
- return GIT_ENOTFOUND;
+ return git__throw(GIT_ENOTFOUND, "Failed to remove entry. File isn't in the tree");
remove_ptr->removed = 1;
bld->entry_count--;
@@ -431,7 +431,7 @@ int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *b
}
if ((error = git_odb_open_wstream(&stream, git_repository_database(repo), size, GIT_OBJ_TREE)) < GIT_SUCCESS)
- return error;
+ return git__rethrow(error, "Failed to write tree. Can't open write stream");
for (i = 0; i < bld->entries.length; ++i) {
git_tree_entry *entry = bld->entries.contents[i];
diff --git a/src/util.h b/src/util.h
index 3dcdc3674..6724e8d41 100644
--- a/src/util.h
+++ b/src/util.h
@@ -6,17 +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
-#define git__strndup strndup
+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);
diff --git a/src/vector.c b/src/vector.c
index d0b0c5c56..1ddc26e3e 100644
--- a/src/vector.c
+++ b/src/vector.c
@@ -106,7 +106,7 @@ int git_vector_bsearch2(git_vector *v, git_vector_cmp key_lookup, const void *ke
/* need comparison function to sort the vector */
if (v->_cmp == NULL)
- return GIT_ENOTFOUND;
+ return git__throw(GIT_ENOTFOUND, "Can't sort vector. No comparison function set");
git_vector_sort(v);
@@ -114,7 +114,7 @@ int git_vector_bsearch2(git_vector *v, git_vector_cmp key_lookup, const void *ke
if (find != NULL)
return (int)(find - v->contents);
- return GIT_ENOTFOUND;
+ return git__throw(GIT_ENOTFOUND, "Can't find element");
}
int git_vector_search2(git_vector *v, git_vector_cmp key_lookup, const void *key)
@@ -128,7 +128,7 @@ int git_vector_search2(git_vector *v, git_vector_cmp key_lookup, const void *key
return i;
}
- return GIT_ENOTFOUND;
+ return git__throw(GIT_ENOTFOUND, "Can't find element");
}
static int strict_comparison(const void *a, const void *b)
@@ -143,9 +143,6 @@ int git_vector_search(git_vector *v, const void *entry)
int git_vector_bsearch(git_vector *v, const void *key)
{
- if (v->_cmp == NULL)
- return GIT_ENOTFOUND;
-
return git_vector_bsearch2(v, v->_cmp, key);
}
@@ -156,7 +153,7 @@ int git_vector_remove(git_vector *v, unsigned int idx)
assert(v);
if (idx >= v->length || v->length == 0)
- return GIT_ENOTFOUND;
+ return git__throw(GIT_ENOTFOUND, "Can't remove element. Index out of bounds");
for (i = idx; i < v->length - 1; ++i)
v->contents[i] = v->contents[i + 1];
diff --git a/src/win32/pthread.c b/src/win32/pthread.c
index f47364a76..7e17b6bdf 100644
--- a/src/win32/pthread.c
+++ b/src/win32/pthread.c
@@ -48,16 +48,15 @@ int pthread_join(pthread_t thread, void **value_ptr)
int pthread_mutex_init(pthread_mutex_t *GIT_RESTRICT mutex,
const pthread_mutexattr_t *GIT_RESTRICT GIT_UNUSED(mutexattr))
{
- GIT_UNUSED_ARG(mutexattr);
+ GIT_UNUSED_ARG(mutexattr);
InitializeCriticalSection(mutex);
return 0;
}
int pthread_mutex_destroy(pthread_mutex_t *mutex)
{
- int ret;
- ret = CloseHandle(mutex);
- return -(!ret);
+ DeleteCriticalSection(mutex);
+ return 0;
}
int pthread_mutex_lock(pthread_mutex_t *mutex)
diff --git a/tests/t10-refs.c b/tests/t10-refs.c
index db767a107..ee006a8ce 100644
--- a/tests/t10-refs.c
+++ b/tests/t10-refs.c
@@ -292,7 +292,7 @@ BEGIN_TEST(create2, "create a new OID reference")
/* Similar test with a fresh new repository */
must_pass(git_repository_open(&repo2, TEMP_REPO_FOLDER));
- must_pass(git_reference_lookup(&looked_up_ref, repo, new_head));
+ must_pass(git_reference_lookup(&looked_up_ref, repo2, new_head));
must_be_true(git_oid_cmp(&id, git_reference_oid(looked_up_ref)) == 0);
close_temp_repo(repo2);