summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/git2/errors.h3
-rw-r--r--src/path.c27
-rw-r--r--src/refs.c511
3 files changed, 258 insertions, 283 deletions
diff --git a/include/git2/errors.h b/include/git2/errors.h
index 54da869b4..e3f5f4cb0 100644
--- a/include/git2/errors.h
+++ b/include/git2/errors.h
@@ -122,9 +122,12 @@ typedef struct {
typedef enum {
GITERR_NOMEMORY,
+ GITERR_REFERENCE,
} git_error_class;
+#define GITERR_CHECK_ALLOC(ptr, error) if (ptr == NULL) { giterr_set_oom(error); return -1 }
+
GIT_EXTERN(void) giterr_set(git_error **error_out, int error_class, const char *string, ...);
GIT_EXTERN(void) giterr_set_oom(git_error **error);
GIT_EXTERN(void) giterr_free(git_error *error);
diff --git a/src/path.c b/src/path.c
index d2c292bf2..c882fe387 100644
--- a/src/path.c
+++ b/src/path.c
@@ -486,20 +486,23 @@ GIT_INLINE(int) is_dot_or_dotdot(const char *name)
int git_path_direach(
git_buf *path,
- int (*fn)(void *, git_buf *),
- void *arg)
+ int (*fn)(void *, git_buf *, git_error **),
+ void *arg,
+ git_error **error)
{
ssize_t wd_len;
DIR *dir;
struct dirent de_buf, *de;
- if (git_path_to_dir(path) < GIT_SUCCESS)
- return git_buf_lasterror(path);
+ if (git_path_to_dir(path, error) < 0)
+ return -1;
wd_len = path->size;
dir = opendir(path->ptr);
- if (!dir)
- return git__throw(GIT_EOSERR, "Failed to process `%s` tree structure. An error occured while opening the directory", path->ptr);
+ if (!dir) {
+ giterr_set(error, GITERR_OS, "Failed to `opendir` %s: %s", path->ptr, strerror(errno));
+ return -1;
+ }
while (p_readdir_r(dir, &de_buf, &de) == 0 && de != NULL) {
int result;
@@ -507,16 +510,18 @@ int git_path_direach(
if (is_dot_or_dotdot(de->d_name))
continue;
- if (git_buf_puts(path, de->d_name) < GIT_SUCCESS)
- return git_buf_lasterror(path);
+ if (git_buf_puts(path, de->d_name) < 0) {
+ giterr_set_oom(error);
+ return -1;
+ }
- result = fn(arg, path);
+ result = fn(arg, path, error);
git_buf_truncate(path, wd_len); /* restore path */
- if (result != GIT_SUCCESS) {
+ if (result < 0) {
closedir(dir);
- return result; /* The callee is reponsible for setting the correct error message */
+ return -1;
}
}
diff --git a/src/refs.c b/src/refs.c
index f3388bf53..ebfabc635 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -62,7 +62,7 @@ static int packed_write(git_repository *repo);
/* internal helpers */
static int reference_available(git_repository *repo,
- const char *ref, const char *old_ref);
+ const char *ref, const char *old_ref, git_error **error);
static int reference_delete(git_reference *ref);
static int reference_lookup(git_reference *ref);
@@ -521,7 +521,7 @@ struct dirent_list_data {
void *callback_payload;
};
-static int _dirent_loose_listall(void *_data, git_buf *full_path)
+static int _dirent_loose_listall(void *_data, git_buf *full_path, git_error **error)
{
struct dirent_list_data *data = (struct dirent_list_data *)_data;
const char *file_path = full_path->ptr + data->repo_path_len;
@@ -844,49 +844,55 @@ cleanup:
return error;
}
+struct reference_available_t {
+ const char *new_ref;
+ const char *old_ref;
+ int available;
+};
+
static int _reference_available_cb(const char *ref, void *data)
{
- const char *new, *old;
- const char **refs;
+ struct reference_available_t *d;
assert(ref && data);
+ d = (reference_available_t *)data;
refs = (const char **)data;
- new = (const char *)refs[0];
- old = (const char *)refs[1];
-
- if (!old || strcmp(old, ref)) {
+ if (!d->old_ref || strcmp(d->old_ref, ref)) {
int reflen = strlen(ref);
- int newlen = strlen(new);
+ int newlen = strlen(d->new_ref);
int cmplen = reflen < newlen ? reflen : newlen;
- const char *lead = reflen < newlen ? new : ref;
+ const char *lead = reflen < newlen ? d->new_ref : ref;
- if (!strncmp(new, ref, cmplen) &&
- lead[cmplen] == '/')
- return GIT_EEXISTS;
+ if (!strncmp(d->new_ref, ref, cmplen) && lead[cmplen] == '/') {
+ d->available = 0;
+ return -1;
+ }
}
- return GIT_SUCCESS;
+ return 0;
}
static int reference_available(
+ int *available,
git_repository *repo,
const char *ref,
- const char* old_ref)
+ const char* old_ref,
+ git_error **error)
{
- const char *refs[2];
+ struct reference_available_t data;
- refs[0] = ref;
- refs[1] = old_ref;
+ data.new_ref = ref;
+ data.old_ref = old_ref;
+ data.available = 1;
if (git_reference_foreach(repo, GIT_REF_LISTALL,
- _reference_available_cb, (void *)refs) < 0) {
- return git__throw(GIT_EEXISTS,
- "Reference name `%s` conflicts with existing reference", ref);
- }
+ _reference_available_cb, (void *)&data, error) < 0)
+ return -1;
- return GIT_SUCCESS;
+ *available = data.available;
+ return 0;
}
static int reference_exists(int *exists, git_repository *repo, const char *ref_name)
@@ -946,17 +952,17 @@ static int packed_lookup(git_reference *ref)
return GIT_SUCCESS;
}
-static int reference_lookup(git_reference *ref)
+static int reference_lookup(git_reference *ref, git_error **error)
{
- int error_loose, error_packed;
+ int result;
- error_loose = loose_lookup(ref);
- if (error_loose == GIT_SUCCESS)
- return GIT_SUCCESS;
+ result = loose_lookup(ref, error);
+ if (result != GIT_ENOTFOUND)
+ return result;
- error_packed = packed_lookup(ref);
- if (error_packed == GIT_SUCCESS)
- return GIT_SUCCESS;
+ result = packed_lookup(ref, error);
+ if (result != GIT_ENOTFOUND)
+ return result;
git_reference_free(ref);
@@ -974,9 +980,9 @@ static int reference_lookup(git_reference *ref)
* This is an internal method; the reference is removed
* from disk or the packfile, but the pointer is not freed
*/
-static int reference_delete(git_reference *ref)
+static int reference_delete(git_reference *ref, git_error **error)
{
- int error;
+ int result;
assert(ref);
@@ -986,15 +992,19 @@ static int reference_delete(git_reference *ref)
if (ref->flags & GIT_REF_PACKED) {
struct packref *packref;
/* load the existing packfile */
- if ((error = packed_load(ref->owner)) < GIT_SUCCESS)
- return git__rethrow(error, "Failed to delete reference");
+ if (packed_load(ref->owner, error) < 0)
+ return -1;
if (git_hashtable_remove2(ref->owner->references.packfile,
- ref->name, (void **) &packref) < GIT_SUCCESS)
- return git__throw(GIT_ENOTFOUND, "Reference not found");
+ ref->name, (void **) &packref) < 0) {
+ giterr_set(error, GITERR_REFERENCE,
+ "Reference %s stopped existing in the packfile", ref->name);
+ return -1;
+ }
- git__free (packref);
- error = packed_write(ref->owner);
+ git__free(packref);
+ if (packed_write(ref->owner, error) < 0)
+ return -1;
/* If the reference is loose, we can just remove the reference
* from the filesystem */
@@ -1002,66 +1012,55 @@ static int reference_delete(git_reference *ref)
git_reference *ref_in_pack;
git_buf full_path = GIT_BUF_INIT;
- error = git_buf_joinpath(&full_path, ref->owner->path_repository, ref->name);
- if (error < GIT_SUCCESS)
- goto cleanup;
+ if (git_buf_joinpath(&full_path, ref->owner->path_repository, ref->name) < 0) {
+ giterr_set_oom(error);
+ return -1;
+ }
- error = p_unlink(full_path.ptr);
+ result = p_unlink(full_path.ptr);
git_buf_free(&full_path); /* done with path at this point */
- if (error < GIT_SUCCESS)
- goto cleanup;
+
+ if (result < 0) {
+ giterr_set(error, GITERR_OS,
+ "Failed to unlink '%s': %s", full_path.ptr, strerror(errno));
+ return -1;
+ }
/* When deleting a loose reference, we have to ensure that an older
* packed version of it doesn't exist */
- if (git_reference_lookup(&ref_in_pack, ref->owner,
- ref->name) == GIT_SUCCESS) {
+ if (git_reference_lookup(&ref_in_pack, ref->owner, ref->name, NULL) == GIT_SUCCESS) {
assert((ref_in_pack->flags & GIT_REF_PACKED) != 0);
- error = git_reference_delete(ref_in_pack);
+ return git_reference_delete(ref_in_pack, error);
}
}
-cleanup:
- return error == GIT_SUCCESS ?
- GIT_SUCCESS :
- git__rethrow(error, "Failed to delete reference");
+ return 0;
}
-int git_reference_delete(git_reference *ref)
+int git_reference_delete(git_reference *ref, git_error **error)
{
- int error = reference_delete(ref);
- if (error < GIT_SUCCESS)
- return error;
-
+ int result = reference_delete(ref, error);
git_reference_free(ref);
- return GIT_SUCCESS;
+ return result;
}
int git_reference_lookup(git_reference **ref_out,
- git_repository *repo, const char *name)
+ git_repository *repo, const char *name, git_error **error)
{
- int error;
char normalized_name[GIT_REFNAME_MAX];
git_reference *ref = NULL;
assert(ref_out && repo && name);
- *ref_out = NULL;
+ if (normalize_name(normalized_name, sizeof(normalized_name), name, 0, error) < 0)
+ return -1;
- error = normalize_name(normalized_name, sizeof(normalized_name), name, 0);
- if (error < GIT_SUCCESS)
- return git__rethrow(error, "Failed to lookup reference");
-
- error = reference_alloc(&ref, repo, normalized_name);
- if (error < GIT_SUCCESS)
- return git__rethrow(error, "Failed to lookup reference");
-
- error = reference_lookup(ref);
- if (error < GIT_SUCCESS)
- return git__rethrow(error, "Failed to lookup reference");
+ if (reference_alloc(&ref, repo, normalized_name, error) < 0)
+ return -1;
*ref_out = ref;
- return GIT_SUCCESS;
+ return reference_lookup(ref, error);
}
/**
@@ -1123,46 +1122,43 @@ int git_reference_create_symbolic(
git_repository *repo,
const char *name,
const char *target,
- int force)
+ int force,
+ git_error **error)
{
char normalized[GIT_REFNAME_MAX];
- int ref_exists, error = GIT_SUCCESS;
+ int exists;
git_reference *ref = NULL;
- error = normalize_name(normalized, sizeof(normalized), name, 0);
- if (error < GIT_SUCCESS)
- goto cleanup;
+ if (normalize_name(normalized, sizeof(normalized), name, 0, error) < 0)
+ return -1;
- if ((error = reference_exists(&ref_exists, repo, normalized) < GIT_SUCCESS))
- return git__rethrow(error, "Failed to create symbolic reference");
+ if (reference_exists(&exists, repo, normalized, error) < 0)
+ return -1;
- if (ref_exists && !force)
- return git__throw(GIT_EEXISTS,
- "Failed to create symbolic reference. Reference already exists");
+ if (exists && !force) {
+ giterr_set(error, GITERR_REFERENCE,
+ "A reference with that name (%s) already exists");
+ return GIT_EEXISTS;
+ }
- error = reference_alloc(&ref, repo, normalized);
- if (error < GIT_SUCCESS)
- goto cleanup;
+ if (reference_alloc(&ref, repo, normalized, error) < 0)
+ return -1;
ref->flags |= GIT_REF_SYMBOLIC;
/* set the target; this will normalize the name automatically
* and write the reference on disk */
- error = git_reference_set_target(ref, target);
- if (error < GIT_SUCCESS)
- goto cleanup;
-
+ if (git_reference_set_target(ref, target, error) < 0) {
+ git_reference_free(ref);
+ return -1;
+ }
if (ref_out == NULL) {
git_reference_free(ref);
} else {
*ref_out = ref;
}
- return GIT_SUCCESS;
-
-cleanup:
- git_reference_free(ref);
- return git__rethrow(error, "Failed to create symbolic reference");
+ return 0;
}
int git_reference_create_oid(
@@ -1170,36 +1166,35 @@ int git_reference_create_oid(
git_repository *repo,
const char *name,
const git_oid *id,
- int force)
+ int force,
+ git_error **error)
{
- int error = GIT_SUCCESS, ref_exists;
+ int exists;
git_reference *ref = NULL;
char normalized[GIT_REFNAME_MAX];
- error = normalize_name(normalized, sizeof(normalized), name, 1);
- if (error < GIT_SUCCESS)
- goto cleanup;
-
- if ((error = reference_exists(&ref_exists, repo, normalized) < GIT_SUCCESS))
- return git__rethrow(error, "Failed to create OID reference");
+ if (normalize_name(normalized, sizeof(normalized), name, 1, error) < 0)
+ return -1;
- if (ref_exists && !force)
- return git__throw(GIT_EEXISTS,
- "Failed to create OID reference. Reference already exists");
+ if (reference_exists(&exists, repo, normalized, error) < 0)
+ return -1;
- if ((error = reference_available(repo, name, NULL)) < GIT_SUCCESS)
- return git__rethrow(error, "Failed to create reference");
+ if (exists && !force) {
+ giterr_set(error, GITERR_REFERENCE,
+ "A reference with that name (%s) already exists");
+ return GIT_EEXISTS;
+ }
- error = reference_alloc(&ref, repo, name);
- if (error < GIT_SUCCESS)
- goto cleanup;
+ if (reference_alloc(&ref, repo, name, error) < 0)
+ return -1;
ref->flags |= GIT_REF_OID;
/* set the oid; this will write the reference on disk */
- error = git_reference_set_oid(ref, id);
- if (error < GIT_SUCCESS)
- goto cleanup;
+ if (git_reference_set_oid(ref, id, error) < 0) {
+ git_reference_free(ref);
+ return -1;
+ }
if (ref_out == NULL) {
git_reference_free(ref);
@@ -1207,13 +1202,8 @@ int git_reference_create_oid(
*ref_out = ref;
}
- return GIT_SUCCESS;
-
-cleanup:
- git_reference_free(ref);
- return git__rethrow(error, "Failed to create reference OID");
+ return 0;
}
-
/*
* Change the OID target of a reference.
*
@@ -1223,40 +1213,34 @@ cleanup:
* We do not repack packed references because of performance
* reasons.
*/
-int git_reference_set_oid(git_reference *ref, const git_oid *id)
+int git_reference_set_oid(git_reference *ref, const git_oid *id, git_error **error)
{
- int error = GIT_SUCCESS, exists;
git_odb *odb = NULL;
- if ((ref->flags & GIT_REF_OID) == 0)
- return git__throw(GIT_EINVALIDREFSTATE,
- "Failed to set OID target of reference. Not an OID reference");
+ if ((ref->flags & GIT_REF_OID) == 0) {
+ giterr_set(error, GITERR_REFERENCE,
+ "Cannot set OID on symbolic reference");
+ return -1;
+ }
assert(ref->owner);
- error = git_repository_odb__weakptr(&odb, ref->owner);
- if (error < GIT_SUCCESS)
- return error;
-
- exists = git_odb_exists(odb, id);
-
- git_odb_free(odb);
+ if (git_repository_odb__weakptr(&odb, ref->owner, error) < 0)
+ return -1;
/* Don't let the user create references to OIDs that
* don't exist in the ODB */
- if (!exists)
- return git__throw(GIT_ENOTFOUND,
- "Failed to set OID target of reference. OID doesn't exist in ODB");
+ if (!git_odb_exists(odb, id)) {
+ giterr_set(error, GITERR_REFERENCE,
+ "Target OID for the reference doesn't exist on the repository");
+ return -1;
+ }
/* Update the OID value on `ref` */
git_oid_cpy(&ref->target.oid, id);
/* Write back to disk */
- error = loose_write(ref);
- if (error < GIT_SUCCESS)
- return git__rethrow(error, "Failed to set OID target of reference");
-
- return GIT_SUCCESS;
+ return loose_write(ref, error);
}
/*
@@ -1266,84 +1250,72 @@ int git_reference_set_oid(git_reference *ref, const git_oid *id)
* a pack. We just change the target in memory
* and overwrite the file on disk.
*/
-int git_reference_set_target(git_reference *ref, const char *target)
+int git_reference_set_target(git_reference *ref, const char *target, git_error **error)
{
- int error;
char normalized[GIT_REFNAME_MAX];
- if ((ref->flags & GIT_REF_SYMBOLIC) == 0)
- return git__throw(GIT_EINVALIDREFSTATE,
- "Failed to set reference target. Not a symbolic reference");
+ if ((ref->flags & GIT_REF_SYMBOLIC) == 0) {
+ giterr_set(error, GITERR_REFERENCE,
+ "Cannot set symbolic target on a direct reference");
+ return -1;
+ }
- error = normalize_name(normalized, sizeof(normalized), target, 0);
- if (error < GIT_SUCCESS)
- return git__rethrow(error,
- "Failed to set reference target. Invalid target name");
+ if (normalize_name(normalized, sizeof(normalized), target, 0, error))
+ return -1;
git__free(ref->target.symbolic);
ref->target.symbolic = git__strdup(normalized);
- if (ref->target.symbolic == NULL)
- return GIT_ENOMEM;
+ GITERR_CHECK_ALLOC(ref->target.symbolic, error);
- return loose_write(ref);
+ return loose_write(ref, error);
}
-int git_reference_rename(git_reference *ref, const char *new_name, int force)
+int git_reference_rename(git_reference *ref, const char *new_name, int force, git_error **error)
{
- int error;
+ int result, ref_available;
git_buf aux_path = GIT_BUF_INIT;
char normalized[GIT_REFNAME_MAX];
const char *head_target = NULL;
git_reference *existing_ref = NULL, *head = NULL;
- error = normalize_name(normalized, sizeof(normalized),
- new_name, ref->flags & GIT_REF_OID);
-
- if (error < GIT_SUCCESS)
- return git__rethrow(error, "Failed to rename reference. Invalid name");
+ if (normalize_name(normalized, sizeof(normalized),
+ new_name, ref->flags & GIT_REF_OID, error) < 0)
+ return -1;
new_name = normalized;
- /* If we are forcing the rename, try to lookup a reference with the
- * new one. If the lookup succeeds, we need to delete that ref
- * before the renaming can proceed */
- if (force) {
- error = git_reference_lookup(&existing_ref, ref->owner, new_name);
-
- if (error == GIT_SUCCESS) {
- error = git_reference_delete(existing_ref);
- if (error < GIT_SUCCESS)
- return git__rethrow(error,
- "Failed to rename reference. "
- "The existing reference cannot be deleted");
- } else if (error != GIT_ENOTFOUND)
- goto cleanup;
-
- /* If we're not forcing the rename, check if the reference exists.
- * If it does, renaming cannot continue */
- } else {
- int exists;
+ /* see if the reference already exists */
+ if (reference_available(&ref_available, ref->owner, new_name, ref->name, error) < 0)
+ return -1;
- error = reference_exists(&exists, ref->owner, normalized);
- if (error < GIT_SUCCESS)
- goto cleanup;
-
- if (exists)
- return git__throw(GIT_EEXISTS,
- "Failed to rename reference. Reference already exists");
+ /* We cannot proceed if the reference already exists and we're not forcing
+ * the rename; the existing one would be overwritten */
+ if (!force && !ref_available) {
+ giterr_set(error, GITERR_REFERENCE,
+ "A reference with the same name (%s) already exists", normalized);
+ return GIT_EEXISTS;
}
- if ((error = reference_available(ref->owner, new_name, ref->name)) < GIT_SUCCESS)
- return git__rethrow(error,
- "Failed to rename reference. Reference already exists");
+ /* FIXME: if the reference exists and we are forcing, do we really need to
+ * remove the reference first?
+ *
+ * Two cases:
+ *
+ * - the reference already exists and is loose: not a problem, the file
+ * gets overwritten on disk
+ *
+ * - the reference already exists and is packed: we write a new one as
+ * loose, which by all means renders the packed one useless
+ */
/* Initialize path now so we won't get an allocation failure once
* we actually start removing things.
*/
- error = git_buf_joinpath(&aux_path, ref->owner->path_repository, new_name);
- if (error < GIT_SUCCESS)
- goto cleanup;
+ if (git_buf_joinpath(&aux_path, ref->owner->path_repository, new_name) < 0) {
+ giterr_set_oom(error);
+ return -1;
+ }
/*
* Now delete the old ref and remove an possibly existing directory
@@ -1351,12 +1323,12 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
* method deletes the ref from disk but doesn't free the pointer, so
* we can still access the ref's attributes for creating the new one
*/
- if ((error = reference_delete(ref)) < GIT_SUCCESS)
+ if (reference_delete(ref, error) < 0)
goto cleanup;
if (git_path_exists(aux_path.ptr) == GIT_SUCCESS) {
if (git_path_isdir(aux_path.ptr) == GIT_SUCCESS) {
- if ((error = git_futils_rmdir_r(aux_path.ptr, 0)) < GIT_SUCCESS)
+ if (git_futils_rmdir_r(aux_path.ptr, 0, error) < 0)
goto rollback;
} else goto rollback;
}
@@ -1365,43 +1337,48 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
* Finally we can create the new reference.
*/
if (ref->flags & GIT_REF_SYMBOLIC) {
- error = git_reference_create_symbolic(
- NULL, ref->owner, new_name, ref->target.symbolic, 0);
+ result = git_reference_create_symbolic(
+ NULL, ref->owner, new_name, ref->target.symbolic, force, error);
} else {
- error = git_reference_create_oid(
- NULL, ref->owner, new_name, &ref->target.oid, 0);
+ result = git_reference_create_oid(
+ NULL, ref->owner, new_name, &ref->target.oid, force, error);
}
- if (error < GIT_SUCCESS)
+ if (result < 0)
goto rollback;
/*
* Check if we have to update HEAD.
*/
- error = git_reference_lookup(&head, ref->owner, GIT_HEAD_FILE);
- if (error < GIT_SUCCESS)
+ if (git_reference_lookup(&head, ref->owner, GIT_HEAD_FILE, NULL) < 0) {
+ giterr_set(error, GITERR_REFERENCE,
+ "Failed to update HEAD after renaming reference");
goto cleanup;
+ }
head_target = git_reference_target(head);
if (head_target && !strcmp(head_target, ref->name)) {
- error = git_reference_create_symbolic(
- &head, ref->owner, "HEAD", new_name, 1);
-
- if (error < GIT_SUCCESS)
+ if (git_reference_create_symbolic(&head, ref->owner, "HEAD", new_name, 1, NULL) < 0) {
+ giterr_set(error, GITERR_REFERENCE,
+ "Failed to update HEAD after renaming reference");
goto cleanup;
+ }
}
/*
* Rename the reflog file.
*/
- error = git_buf_join_n(&aux_path, '/', 3, ref->owner->path_repository,
- GIT_REFLOG_DIR, ref->name);
- if (error < GIT_SUCCESS)
+ if (git_buf_join_n(&aux_path, '/', 3, ref->owner->path_repository,
+ GIT_REFLOG_DIR, ref->name) < 0) {
+ giterr_set_oom(error);
goto cleanup;
+ }
- if (git_path_exists(aux_path.ptr) == GIT_SUCCESS)
- error = git_reflog_rename(ref, new_name);
+ if (git_path_exists(aux_path.ptr) == 0) {
+ if (git_reflog_rename(ref, new_name, error) < 0)
+ goto cleanup;
+ }
/*
* Change the name of the reference given by the user.
@@ -1412,38 +1389,37 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
/* The reference is no longer packed */
ref->flags &= ~GIT_REF_PACKED;
+ git_reference_free(head);
+ git_buf_free(&aux_path);
+ return 0;
+
cleanup:
- /* We no longer need the newly created reference nor the head */
git_reference_free(head);
git_buf_free(&aux_path);
- return error == GIT_SUCCESS ?
- GIT_SUCCESS :
- git__rethrow(error, "Failed to rename reference");
+ return -1;
rollback:
/*
- * Try to create the old reference again.
+ * Try to create the old reference again, ignore failures
*/
if (ref->flags & GIT_REF_SYMBOLIC)
- error = git_reference_create_symbolic(
- NULL, ref->owner, ref->name, ref->target.symbolic, 0);
+ git_reference_create_symbolic(
+ NULL, ref->owner, ref->name, ref->target.symbolic, 0, NULL);
else
- error = git_reference_create_oid(
- NULL, ref->owner, ref->name, &ref->target.oid, 0);
+ git_reference_create_oid(
+ NULL, ref->owner, ref->name, &ref->target.oid, 0. NULL);
/* The reference is no longer packed */
ref->flags &= ~GIT_REF_PACKED;
git_buf_free(&aux_path);
- return error == GIT_SUCCESS ?
- git__rethrow(GIT_ERROR, "Failed to rename reference. Did rollback") :
- git__rethrow(error, "Failed to rename reference. Failed to rollback");
+ return -1;
}
-int git_reference_resolve(git_reference **ref_out, git_reference *ref)
+int git_reference_resolve(git_reference **ref_out, git_reference *ref, git_error **error)
{
- int error, i = 0;
+ int result, i = 0;
git_repository *repo;
assert(ref);
@@ -1455,15 +1431,15 @@ int git_reference_resolve(git_reference **ref_out, git_reference *ref)
* copy. Instead of duplicating `ref`, we look it up again to
* ensure the copy is out to date */
if (ref->flags & GIT_REF_OID)
- return git_reference_lookup(ref_out, ref->owner, ref->name);
+ return git_reference_lookup(ref_out, ref->owner, ref->name, error);
/* Otherwise, keep iterating until the reference is resolved */
for (i = 0; i < MAX_NESTING_LEVEL; ++i) {
git_reference *new_ref;
- error = git_reference_lookup(&new_ref, repo, ref->target.symbolic);
- if (error < GIT_SUCCESS)
- return git__rethrow(error, "Failed to resolve reference");
+ result = git_reference_lookup(&new_ref, repo, ref->target.symbolic, error);
+ if (result < 0)
+ return result;
/* Free intermediate references, except for the original one
* we've received */
@@ -1480,33 +1456,30 @@ int git_reference_resolve(git_reference **ref_out, git_reference *ref)
}
}
- return git__throw(GIT_ENOMEM,
- "Failed to resolve reference. Reference is too nested");
+ giterr_set(error, GITERR_REFERENCE,
+ "Symbolic reference too nested (%d levels deep)", MAX_NESTING_LEVEL);
+
+ return -1;
}
-int git_reference_packall(git_repository *repo)
+int git_reference_packall(git_repository *repo, git_error **error)
{
- int error;
-
- /* load the existing packfile */
- if ((error = packed_load(repo)) < GIT_SUCCESS)
- return git__rethrow(error, "Failed to pack references");
+ if (packed_load(repo, error) < 0 || /* load the existing packfile */
+ packed_loadloose(repo, error) < 0 || /* add all the loose refs */
+ packed_write(repo, error) < 0) /* write back to disk */
+ return -1;
- /* update it in-memory with all the loose references */
- if ((error = packed_loadloose(repo)) < GIT_SUCCESS)
- return git__rethrow(error, "Failed to pack references");
-
- /* write it back to disk */
- return packed_write(repo);
+ return 0;
}
int git_reference_foreach(
git_repository *repo,
unsigned int list_flags,
int (*callback)(const char *, void *),
- void *payload)
+ void *payload,
+ git_error **error)
{
- int error;
+ int result;
struct dirent_list_data data;
git_buf refs_path = GIT_BUF_INIT;
@@ -1514,13 +1487,12 @@ int git_reference_foreach(
if (list_flags & GIT_REF_PACKED) {
const char *ref_name;
- if ((error = packed_load(repo)) < GIT_SUCCESS)
- return git__rethrow(error, "Failed to list references");
+ if (packed_load(repo, error) < 0)
+ return -1;
- GIT_HASHTABLE_FOREACH_KEY(repo->references.packfile, ref_name,
- if ((error = callback(ref_name, payload)) < GIT_SUCCESS)
- return git__throw(error,
- "Failed to list references. User callback failed");
+ GIT_HASHTABLE_FOREACH(repo->references.packfile, ref_name, _unused,
+ if (callback(ref_name, payload) < 0)
+ return 0;
);
}
@@ -1533,15 +1505,15 @@ int git_reference_foreach(
data.callback = callback;
data.callback_payload = payload;
- if ((error = git_buf_joinpath(&refs_path,
- repo->path_repository, GIT_REFS_DIR)) < GIT_SUCCESS)
- return git__rethrow(error, "Failed to alloc space for references");
-
- error = git_path_direach(&refs_path, _dirent_loose_listall, &data);
+ if (git_buf_joinpath(&refs_path, repo->path_repository, GIT_REFS_DIR) < 0) {
+ giterr_set_oom(error);
+ return -1;
+ }
+ result = git_path_direach(&refs_path, _dirent_loose_listall, &data, error);
git_buf_free(&refs_path);
- return error;
+ return result;
}
static int cb__reflist_add(const char *ref, void *data)
@@ -1552,9 +1524,10 @@ static int cb__reflist_add(const char *ref, void *data)
int git_reference_listall(
git_strarray *array,
git_repository *repo,
- unsigned int list_flags)
+ unsigned int list_flags,
+ git_error **error)
{
- int error;
+ int result;
git_vector ref_list;
assert(array && repo);
@@ -1562,15 +1535,15 @@ int git_reference_listall(
array->strings = NULL;
array->count = 0;
- if (git_vector_init(&ref_list, 8, NULL) < GIT_SUCCESS)
- return GIT_ENOMEM;
-
- error = git_reference_foreach(
- repo, list_flags, &cb__reflist_add, (void *)&ref_list);
+ if (git_vector_init(&ref_list, 8, NULL) < GIT_SUCCESS) {
+ giterr_set_oom(error);
+ return -1;
+ }
- if (error < GIT_SUCCESS) {
+ if (git_reference_foreach(
+ repo, list_flags, &cb__reflist_add, (void *)&ref_list, error) < 0) {
git_vector_free(&ref_list);
- return error;
+ return -1;
}
array->strings = (char **)ref_list.contents;
@@ -1578,17 +1551,11 @@ int git_reference_listall(
return GIT_SUCCESS;
}
-int git_reference_reload(git_reference *ref)
+int git_reference_reload(git_reference *ref, git_error **error)
{
- int error = reference_lookup(ref);
-
- if (error < GIT_SUCCESS)
- return git__rethrow(error, "Failed to reload reference");
-
- return GIT_SUCCESS;
+ return reference_lookup(ref, error);
}
-
void git_repository__refcache_free(git_refcache *refs)
{
assert(refs);