diff options
author | Carlos Martín Nieto <cmn@dwim.me> | 2014-02-05 11:07:34 +0100 |
---|---|---|
committer | Carlos Martín Nieto <cmn@dwim.me> | 2014-02-05 12:07:57 +0100 |
commit | 7ee8c7e6776a3c5b3a45cfd10ccf205eebb3f3fe (patch) | |
tree | 5607d35a6c22f62bfe3412c57a35d653bbc063f2 | |
parent | f8621dde4057aba2df8d7585f6fbf2d6ee4fc023 (diff) | |
download | libgit2-7ee8c7e6776a3c5b3a45cfd10ccf205eebb3f3fe.tar.gz |
refs: placeholder conditional delete
We don't actually pass the old value yet.
-rw-r--r-- | include/git2/sys/refdb_backend.h | 2 | ||||
-rw-r--r-- | src/refdb.c | 4 | ||||
-rw-r--r-- | src/refdb.h | 2 | ||||
-rw-r--r-- | src/refdb_fs.c | 66 | ||||
-rw-r--r-- | src/refs.c | 2 |
5 files changed, 49 insertions, 27 deletions
diff --git a/include/git2/sys/refdb_backend.h b/include/git2/sys/refdb_backend.h index 13ce9a026..aa5ef9ecc 100644 --- a/include/git2/sys/refdb_backend.h +++ b/include/git2/sys/refdb_backend.h @@ -106,7 +106,7 @@ struct git_refdb_backend { * Deletes the given reference from the refdb. A refdb implementation * must provide this function. */ - int (*del)(git_refdb_backend *backend, const char *ref_name); + int (*del)(git_refdb_backend *backend, const char *ref_name, const git_oid *old_id, const char *old_target); /** * Suggests that the given refdb compress or optimize its references. diff --git a/src/refdb.c b/src/refdb.c index 66d943e86..984c3c7f6 100644 --- a/src/refdb.c +++ b/src/refdb.c @@ -201,10 +201,10 @@ int git_refdb_rename( return 0; } -int git_refdb_delete(struct git_refdb *db, const char *ref_name) +int git_refdb_delete(struct git_refdb *db, const char *ref_name, const git_oid *old_id, const char *old_target) { assert(db && db->backend); - return db->backend->del(db->backend, ref_name); + return db->backend->del(db->backend, ref_name, old_id, old_target); } int git_refdb_reflog_read(git_reflog **out, git_refdb *db, const char *name) diff --git a/src/refdb.h b/src/refdb.h index eabb5969b..cbad86faf 100644 --- a/src/refdb.h +++ b/src/refdb.h @@ -43,7 +43,7 @@ int git_refdb_iterator_next_name(const char **out, git_reference_iterator *iter) void git_refdb_iterator_free(git_reference_iterator *iter); int git_refdb_write(git_refdb *refdb, git_reference *ref, int force, const git_signature *who, const char *message, const git_oid *old_id, const char *old_target); -int git_refdb_delete(git_refdb *refdb, const char *ref_name); +int git_refdb_delete(git_refdb *refdb, const char *ref_name, const git_oid *old_id, const char *old_target); int git_refdb_reflog_read(git_reflog **out, git_refdb *db, const char *name); int git_refdb_reflog_write(git_reflog *reflog); diff --git a/src/refdb_fs.c b/src/refdb_fs.c index d1b20f8e3..c9f9c0f1c 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -688,20 +688,20 @@ static int reference_path_available( return 0; } -static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const git_reference *ref) +static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *name) { int error; git_buf ref_path = GIT_BUF_INIT; - assert(file && backend && ref); + assert(file && backend && name); /* Remove a possibly existing empty directory hierarchy * which name would collide with the reference name */ - if (git_futils_rmdir_r(ref->name, backend->path, GIT_RMDIR_SKIP_NONEMPTY) < 0) + if (git_futils_rmdir_r(name, backend->path, GIT_RMDIR_SKIP_NONEMPTY) < 0) return -1; - if (git_buf_joinpath(&ref_path, backend->path, ref->name) < 0) + if (git_buf_joinpath(&ref_path, backend->path, name) < 0) return -1; error = git_filebuf_open(file, ref_path.ptr, GIT_FILEBUF_FORCE, GIT_REFS_FILE_MODE); @@ -930,7 +930,7 @@ static bool should_write_reflog(git_repository *repo, const char *name) return 0; } -static int cmp_old_ref(int *cmp, git_refdb_backend *backend, const git_reference *ref, +static int cmp_old_ref(int *cmp, git_refdb_backend *backend, const char *name, const git_oid *old_id, const char *old_target) { int error = 0; @@ -938,7 +938,7 @@ static int cmp_old_ref(int *cmp, git_refdb_backend *backend, const git_reference *cmp = 0; if (old_id || old_target) { - if ((error = refdb_fs_backend__lookup(&old_ref, backend, ref->name)) < 0) + if ((error = refdb_fs_backend__lookup(&old_ref, backend, name)) < 0) goto out; } @@ -965,7 +965,6 @@ static int refdb_fs_backend__write( { refdb_fs_backend *backend = (refdb_fs_backend *)_backend; git_filebuf file = GIT_FILEBUF_INIT; - git_reference *old_ref = NULL; int error = 0, cmp = 0; assert(backend); @@ -975,10 +974,10 @@ static int refdb_fs_backend__write( return error; /* We need to perform the reflog append and old value check under the ref's lock */ - if ((error = loose_lock(&file, backend, ref)) < 0) + if ((error = loose_lock(&file, backend, ref->name)) < 0) return error; - if ((error = cmp_old_ref(&cmp, _backend, ref, old_id, old_target)) < 0) + if ((error = cmp_old_ref(&cmp, _backend, ref->name, old_id, old_target)) < 0) goto on_error; if (cmp) { @@ -1002,16 +1001,32 @@ on_error: static int refdb_fs_backend__delete( git_refdb_backend *_backend, - const char *ref_name) + const char *ref_name, + const git_oid *old_id, const char *old_target) { refdb_fs_backend *backend = (refdb_fs_backend *)_backend; git_buf loose_path = GIT_BUF_INIT; - size_t pack_pos; - int error = 0; + size_t pack_pos +; git_filebuf file = GIT_FILEBUF_INIT; + int error = 0, cmp = 0; bool loose_deleted = 0; assert(backend && ref_name); + if ((error = loose_lock(&file, backend, ref_name)) < 0) + return error; + + error = cmp_old_ref(&cmp, _backend, ref_name, old_id, old_target); + //git_filebuf_cleanup(&file); + if (error < 0) + goto cleanup; + + if (cmp) { + giterr_set(GITERR_REFERENCE, "old reference value does not match"); + error = GIT_EMODIFIED; + goto cleanup; + } + /* If a loose reference exists, remove it from the filesystem */ if (git_buf_joinpath(&loose_path, backend->path, ref_name) < 0) return -1; @@ -1024,14 +1039,14 @@ static int refdb_fs_backend__delete( git_buf_free(&loose_path); if (error != 0) - return error; + goto cleanup; - if (packed_reload(backend) < 0) - return -1; + if ((error = packed_reload(backend)) < 0) + goto cleanup; /* If a packed reference exists, remove it from the packfile and repack */ - if (git_sortedcache_wlock(backend->refcache) < 0) - return -1; + if ((error = git_sortedcache_wlock(backend->refcache)) < 0) + goto cleanup; if (!(error = git_sortedcache_lookup_index( &pack_pos, backend->refcache, ref_name))) @@ -1039,10 +1054,17 @@ static int refdb_fs_backend__delete( git_sortedcache_wunlock(backend->refcache); - if (error == GIT_ENOTFOUND) - return loose_deleted ? 0 : ref_error_notfound(ref_name); + if (error == GIT_ENOTFOUND) { + error = loose_deleted ? 0 : ref_error_notfound(ref_name); + goto cleanup; + } + + error = packed_write(backend); - return packed_write(backend); +cleanup: + git_filebuf_cleanup(&file); + + return error; } static int refdb_reflog_fs__rename(git_refdb_backend *_backend, const char *old_name, const char *new_name); @@ -1068,7 +1090,7 @@ static int refdb_fs_backend__rename( (error = refdb_fs_backend__lookup(&old, _backend, old_name)) < 0) return error; - if ((error = refdb_fs_backend__delete(_backend, old_name)) < 0) { + if ((error = refdb_fs_backend__delete(_backend, old_name, NULL, NULL)) < 0) { git_reference_free(old); return error; } @@ -1079,7 +1101,7 @@ static int refdb_fs_backend__rename( return -1; } - if ((error = loose_lock(&file, backend, new)) < 0) { + if ((error = loose_lock(&file, backend, new->name)) < 0) { git_reference_free(new); return error; } diff --git a/src/refs.c b/src/refs.c index 864bfce59..f45c64246 100644 --- a/src/refs.c +++ b/src/refs.c @@ -116,7 +116,7 @@ void git_reference_free(git_reference *reference) int git_reference_delete(git_reference *ref) { - return git_refdb_delete(ref->db, ref->name); + return git_refdb_delete(ref->db, ref->name, NULL, NULL); } int git_reference_lookup(git_reference **ref_out, |