aboutsummaryrefslogtreecommitdiffstats
path: root/refs
diff options
context:
space:
mode:
Diffstat (limited to 'refs')
-rw-r--r--refs/files-backend.c168
-rw-r--r--refs/packed-backend.c27
-rw-r--r--refs/ref-cache.c2
-rw-r--r--refs/ref-cache.h2
-rw-r--r--refs/refs-internal.h16
-rw-r--r--refs/reftable-backend.c158
6 files changed, 292 insertions, 81 deletions
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 324c59b096..c73f95ecf2 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -246,7 +246,7 @@ static void loose_fill_ref_dir_regular_file(struct files_ref_store *refs,
if (!refs_resolve_ref_unsafe(&refs->base, refname, RESOLVE_REF_READING,
&oid, &flag)) {
- oidclr(&oid);
+ oidclr(&oid, refs->base.repo->hash_algo);
flag |= REF_ISBROKEN;
} else if (is_null_oid(&oid)) {
/*
@@ -263,7 +263,7 @@ static void loose_fill_ref_dir_regular_file(struct files_ref_store *refs,
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
if (!refname_is_safe(refname))
die("loose refname is dangerous: %s", refname);
- oidclr(&oid);
+ oidclr(&oid, refs->base.repo->hash_algo);
flag |= REF_BAD_NAME | REF_ISBROKEN;
}
add_entry_to_dir(dir, create_ref_entry(refname, &oid, flag));
@@ -323,19 +323,15 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
add_per_worktree_entries_to_dir(dir, dirname);
}
-/*
- * Add pseudorefs to the ref dir by parsing the directory for any files
- * which follow the pseudoref syntax.
- */
-static void add_pseudoref_and_head_entries(struct ref_store *ref_store,
- struct ref_dir *dir,
- const char *dirname)
+static int for_each_root_ref(struct files_ref_store *refs,
+ int (*cb)(const char *refname, void *cb_data),
+ void *cb_data)
{
- struct files_ref_store *refs =
- files_downcast(ref_store, REF_STORE_READ, "fill_ref_dir");
struct strbuf path = STRBUF_INIT, refname = STRBUF_INIT;
+ const char *dirname = refs->loose->root->name;
struct dirent *de;
size_t dirnamelen;
+ int ret;
DIR *d;
files_ref_path(refs, &path, dirname);
@@ -343,7 +339,7 @@ static void add_pseudoref_and_head_entries(struct ref_store *ref_store,
d = opendir(path.buf);
if (!d) {
strbuf_release(&path);
- return;
+ return -1;
}
strbuf_addstr(&refname, dirname);
@@ -359,14 +355,49 @@ static void add_pseudoref_and_head_entries(struct ref_store *ref_store,
strbuf_addstr(&refname, de->d_name);
dtype = get_dtype(de, &path, 1);
- if (dtype == DT_REG && is_root_ref(de->d_name))
- loose_fill_ref_dir_regular_file(refs, refname.buf, dir);
+ if (dtype == DT_REG && is_root_ref(de->d_name)) {
+ ret = cb(refname.buf, cb_data);
+ if (ret)
+ goto done;
+ }
strbuf_setlen(&refname, dirnamelen);
}
+
+ ret = 0;
+
+done:
strbuf_release(&refname);
strbuf_release(&path);
closedir(d);
+ return ret;
+}
+
+struct fill_root_ref_data {
+ struct files_ref_store *refs;
+ struct ref_dir *dir;
+};
+
+static int fill_root_ref(const char *refname, void *cb_data)
+{
+ struct fill_root_ref_data *data = cb_data;
+ loose_fill_ref_dir_regular_file(data->refs, refname, data->dir);
+ return 0;
+}
+
+/*
+ * Add root refs to the ref dir by parsing the directory for any files which
+ * follow the root ref syntax.
+ */
+static void add_root_refs(struct files_ref_store *refs,
+ struct ref_dir *dir)
+{
+ struct fill_root_ref_data data = {
+ .refs = refs,
+ .dir = dir,
+ };
+
+ for_each_root_ref(refs, fill_root_ref, &data);
}
static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs,
@@ -388,8 +419,7 @@ static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs,
dir = get_ref_dir(refs->loose->root);
if (flags & DO_FOR_EACH_INCLUDE_ROOT_REFS)
- add_pseudoref_and_head_entries(dir->cache->ref_store, dir,
- refs->loose->root->name);
+ add_root_refs(refs, dir);
/*
* Add an incomplete entry for "refs/" (to be filled
@@ -520,7 +550,8 @@ stat_ref:
strbuf_rtrim(&sb_contents);
buf = sb_contents.buf;
- ret = parse_loose_ref_contents(buf, oid, referent, type, &myerr);
+ ret = parse_loose_ref_contents(ref_store->repo->hash_algo, buf,
+ oid, referent, type, &myerr);
out:
if (ret && !myerr)
@@ -554,7 +585,8 @@ static int files_read_symbolic_ref(struct ref_store *ref_store, const char *refn
return !(type & REF_ISSYMREF);
}
-int parse_loose_ref_contents(const char *buf, struct object_id *oid,
+int parse_loose_ref_contents(const struct git_hash_algo *algop,
+ const char *buf, struct object_id *oid,
struct strbuf *referent, unsigned int *type,
int *failure_errno)
{
@@ -572,7 +604,7 @@ int parse_loose_ref_contents(const char *buf, struct object_id *oid,
/*
* FETCH_HEAD has additional data after the sha.
*/
- if (parse_oid_hex(buf, oid, &p) ||
+ if (parse_oid_hex_algop(buf, oid, &p, algop) ||
(*p != '\0' && !isspace(*p))) {
*type |= REF_ISBROKEN;
*failure_errno = EINVAL;
@@ -1120,7 +1152,7 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs,
if (!refs_resolve_ref_unsafe(&refs->base, lock->ref_name, 0,
&lock->old_oid, NULL))
- oidclr(&lock->old_oid);
+ oidclr(&lock->old_oid, refs->base.repo->hash_algo);
goto out;
error_return:
@@ -1752,6 +1784,9 @@ static int files_log_ref_write(struct files_ref_store *refs,
{
int logfd, result;
+ if (flags & REF_SKIP_CREATE_REFLOG)
+ return 0;
+
if (log_all_ref_updates == LOG_REFS_UNSET)
log_all_ref_updates = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
@@ -1963,7 +1998,8 @@ static int files_delete_reflog(struct ref_store *ref_store,
return ret;
}
-static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *cb_data)
+static int show_one_reflog_ent(struct files_ref_store *refs, struct strbuf *sb,
+ each_reflog_ent_fn fn, void *cb_data)
{
struct object_id ooid, noid;
char *email_end, *message;
@@ -1973,8 +2009,8 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c
/* old SP new SP name <email> SP time TAB msg LF */
if (!sb->len || sb->buf[sb->len - 1] != '\n' ||
- parse_oid_hex(p, &ooid, &p) || *p++ != ' ' ||
- parse_oid_hex(p, &noid, &p) || *p++ != ' ' ||
+ parse_oid_hex_algop(p, &ooid, &p, refs->base.repo->hash_algo) || *p++ != ' ' ||
+ parse_oid_hex_algop(p, &noid, &p, refs->base.repo->hash_algo) || *p++ != ' ' ||
!(email_end = strchr(p, '>')) ||
email_end[1] != ' ' ||
!(timestamp = parse_timestamp(email_end + 2, &message, 10)) ||
@@ -2073,7 +2109,7 @@ static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store,
strbuf_splice(&sb, 0, 0, bp + 1, endp - (bp + 1));
scanp = bp;
endp = bp + 1;
- ret = show_one_reflog_ent(&sb, fn, cb_data);
+ ret = show_one_reflog_ent(refs, &sb, fn, cb_data);
strbuf_reset(&sb);
if (ret)
break;
@@ -2085,7 +2121,7 @@ static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store,
* Process it, and we can end the loop.
*/
strbuf_splice(&sb, 0, 0, buf, endp - buf);
- ret = show_one_reflog_ent(&sb, fn, cb_data);
+ ret = show_one_reflog_ent(refs, &sb, fn, cb_data);
strbuf_reset(&sb);
break;
}
@@ -2135,7 +2171,7 @@ static int files_for_each_reflog_ent(struct ref_store *ref_store,
return -1;
while (!ret && !strbuf_getwholeline(&sb, logfp, '\n'))
- ret = show_one_reflog_ent(&sb, fn, cb_data);
+ ret = show_one_reflog_ent(refs, &sb, fn, cb_data);
fclose(logfp);
strbuf_release(&sb);
return ret;
@@ -2253,6 +2289,7 @@ static int split_head_update(struct ref_update *update,
struct ref_update *new_update;
if ((update->flags & REF_LOG_ONLY) ||
+ (update->flags & REF_SKIP_CREATE_REFLOG) ||
(update->flags & REF_IS_PRUNING) ||
(update->flags & REF_UPDATE_VIA_HEAD))
return 0;
@@ -2423,8 +2460,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
struct strbuf *err)
{
struct strbuf referent = STRBUF_INIT;
- int mustexist = (update->flags & REF_HAVE_OLD) &&
- !is_null_oid(&update->old_oid);
+ int mustexist = ref_update_expects_existing_old_ref(update);
int ret = 0;
struct ref_lock *lock;
@@ -2503,14 +2539,16 @@ static int lock_ref_for_update(struct files_ref_store *refs,
/*
* Even if the ref is a regular ref, if `old_target` is set, we
- * check the referent value. Ideally `old_target` should only
- * be set for symrefs, but we're strict about its usage.
+ * fail with an error.
*/
if (update->old_target) {
- if (ref_update_check_old_target(referent.buf, update, err)) {
- ret = TRANSACTION_GENERIC_ERROR;
- goto out;
- }
+ strbuf_addf(err, _("cannot lock ref '%s': "
+ "expected symref with target '%s': "
+ "but is a regular ref"),
+ ref_update_original_update_refname(update),
+ update->old_target);
+ ret = TRANSACTION_GENERIC_ERROR;
+ goto out;
} else if (check_old_oid(update, &lock->old_oid, err)) {
ret = TRANSACTION_GENERIC_ERROR;
goto out;
@@ -3310,11 +3348,73 @@ static int files_ref_store_create_on_disk(struct ref_store *ref_store,
return 0;
}
+struct remove_one_root_ref_data {
+ const char *gitdir;
+ struct strbuf *err;
+};
+
+static int remove_one_root_ref(const char *refname,
+ void *cb_data)
+{
+ struct remove_one_root_ref_data *data = cb_data;
+ struct strbuf buf = STRBUF_INIT;
+ int ret = 0;
+
+ strbuf_addf(&buf, "%s/%s", data->gitdir, refname);
+
+ ret = unlink(buf.buf);
+ if (ret < 0)
+ strbuf_addf(data->err, "could not delete %s: %s\n",
+ refname, strerror(errno));
+
+ strbuf_release(&buf);
+ return ret;
+}
+
+static int files_ref_store_remove_on_disk(struct ref_store *ref_store,
+ struct strbuf *err)
+{
+ struct files_ref_store *refs =
+ files_downcast(ref_store, REF_STORE_WRITE, "remove");
+ struct remove_one_root_ref_data data = {
+ .gitdir = refs->base.gitdir,
+ .err = err,
+ };
+ struct strbuf sb = STRBUF_INIT;
+ int ret = 0;
+
+ strbuf_addf(&sb, "%s/refs", refs->base.gitdir);
+ if (remove_dir_recursively(&sb, 0) < 0) {
+ strbuf_addf(err, "could not delete refs: %s",
+ strerror(errno));
+ ret = -1;
+ }
+ strbuf_reset(&sb);
+
+ strbuf_addf(&sb, "%s/logs", refs->base.gitdir);
+ if (remove_dir_recursively(&sb, 0) < 0) {
+ strbuf_addf(err, "could not delete logs: %s",
+ strerror(errno));
+ ret = -1;
+ }
+ strbuf_reset(&sb);
+
+ if (for_each_root_ref(refs, remove_one_root_ref, &data) < 0)
+ ret = -1;
+
+ if (ref_store_remove_on_disk(refs->packed_ref_store, err) < 0)
+ ret = -1;
+
+ strbuf_release(&sb);
+ return ret;
+}
+
struct ref_storage_be refs_be_files = {
.name = "files",
.init = files_ref_store_init,
.release = files_ref_store_release,
.create_on_disk = files_ref_store_create_on_disk,
+ .remove_on_disk = files_ref_store_remove_on_disk,
.transaction_prepare = files_transaction_prepare,
.transaction_finish = files_transaction_finish,
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 2789fd92f5..89976aa359 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -1,5 +1,6 @@
#include "../git-compat-util.h"
#include "../config.h"
+#include "../dir.h"
#include "../gettext.h"
#include "../hash.h"
#include "../hex.h"
@@ -791,7 +792,7 @@ static int packed_read_raw_ref(struct ref_store *ref_store, const char *refname,
return -1;
}
- if (get_oid_hex(rec, oid))
+ if (get_oid_hex_algop(rec, oid, ref_store->repo->hash_algo))
die_invalid_line(refs->path, rec, snapshot->eof - rec);
*type = REF_ISPACKED;
@@ -876,7 +877,7 @@ static int next_record(struct packed_ref_iterator *iter)
p = iter->pos;
if (iter->eof - p < snapshot_hexsz(iter->snapshot) + 2 ||
- parse_oid_hex(p, &iter->oid, &p) ||
+ parse_oid_hex_algop(p, &iter->oid, &p, iter->repo->hash_algo) ||
!isspace(*p++))
die_invalid_line(iter->snapshot->refs->path,
iter->pos, iter->eof - iter->pos);
@@ -893,7 +894,7 @@ static int next_record(struct packed_ref_iterator *iter)
if (!refname_is_safe(iter->base.refname))
die("packed refname is dangerous: %s",
iter->base.refname);
- oidclr(&iter->oid);
+ oidclr(&iter->oid, iter->repo->hash_algo);
iter->base.flags |= REF_BAD_NAME | REF_ISBROKEN;
}
if (iter->snapshot->peeled == PEELED_FULLY ||
@@ -906,7 +907,7 @@ static int next_record(struct packed_ref_iterator *iter)
if (iter->pos < iter->eof && *iter->pos == '^') {
p = iter->pos + 1;
if (iter->eof - p < snapshot_hexsz(iter->snapshot) + 1 ||
- parse_oid_hex(p, &iter->peeled, &p) ||
+ parse_oid_hex_algop(p, &iter->peeled, &p, iter->repo->hash_algo) ||
*p++ != '\n')
die_invalid_line(iter->snapshot->refs->path,
iter->pos, iter->eof - iter->pos);
@@ -918,13 +919,13 @@ static int next_record(struct packed_ref_iterator *iter)
* we suppress it if the reference is broken:
*/
if ((iter->base.flags & REF_ISBROKEN)) {
- oidclr(&iter->peeled);
+ oidclr(&iter->peeled, iter->repo->hash_algo);
iter->base.flags &= ~REF_KNOWS_PEELED;
} else {
iter->base.flags |= REF_KNOWS_PEELED;
}
} else {
- oidclr(&iter->peeled);
+ oidclr(&iter->peeled, iter->repo->hash_algo);
}
return ITER_OK;
@@ -1266,6 +1267,19 @@ static int packed_ref_store_create_on_disk(struct ref_store *ref_store UNUSED,
return 0;
}
+static int packed_ref_store_remove_on_disk(struct ref_store *ref_store,
+ struct strbuf *err)
+{
+ struct packed_ref_store *refs = packed_downcast(ref_store, 0, "remove");
+
+ if (remove_path(refs->path) < 0) {
+ strbuf_addstr(err, "could not delete packed-refs");
+ return -1;
+ }
+
+ return 0;
+}
+
/*
* Write the packed refs from the current snapshot to the packed-refs
* tempfile, incorporating any changes from `updates`. `updates` must
@@ -1724,6 +1738,7 @@ struct ref_storage_be refs_be_packed = {
.init = packed_ref_store_init,
.release = packed_ref_store_release,
.create_on_disk = packed_ref_store_create_on_disk,
+ .remove_on_disk = packed_ref_store_remove_on_disk,
.transaction_prepare = packed_transaction_prepare,
.transaction_finish = packed_transaction_finish,
diff --git a/refs/ref-cache.c b/refs/ref-cache.c
index b6c53fc8ed..4ce519bbc8 100644
--- a/refs/ref-cache.c
+++ b/refs/ref-cache.c
@@ -71,6 +71,8 @@ static void free_ref_entry(struct ref_entry *entry)
void free_ref_cache(struct ref_cache *cache)
{
+ if (!cache)
+ return;
free_ref_entry(cache->root);
free(cache);
}
diff --git a/refs/ref-cache.h b/refs/ref-cache.h
index 95c76e27c8..31ebe24f6c 100644
--- a/refs/ref-cache.h
+++ b/refs/ref-cache.h
@@ -1,7 +1,7 @@
#ifndef REFS_REF_CACHE_H
#define REFS_REF_CACHE_H
-#include "hash-ll.h"
+#include "hash.h"
struct ref_dir;
struct ref_store;
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index 33749fbd83..309b382284 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -517,6 +517,12 @@ typedef int ref_store_create_on_disk_fn(struct ref_store *refs,
int flags,
struct strbuf *err);
+/*
+ * Remove the reference store from disk.
+ */
+typedef int ref_store_remove_on_disk_fn(struct ref_store *refs,
+ struct strbuf *err);
+
typedef int ref_transaction_prepare_fn(struct ref_store *refs,
struct ref_transaction *transaction,
struct strbuf *err);
@@ -649,6 +655,7 @@ struct ref_storage_be {
ref_store_init_fn *init;
ref_store_release_fn *release;
ref_store_create_on_disk_fn *create_on_disk;
+ ref_store_remove_on_disk_fn *remove_on_disk;
ref_transaction_prepare_fn *transaction_prepare;
ref_transaction_finish_fn *transaction_finish;
@@ -698,7 +705,8 @@ struct ref_store {
* Parse contents of a loose ref file. *failure_errno maybe be set to EINVAL for
* invalid contents.
*/
-int parse_loose_ref_contents(const char *buf, struct object_id *oid,
+int parse_loose_ref_contents(const struct git_hash_algo *algop,
+ const char *buf, struct object_id *oid,
struct strbuf *referent, unsigned int *type,
int *failure_errno);
@@ -735,4 +743,10 @@ int ref_update_has_null_new_value(struct ref_update *update);
int ref_update_check_old_target(const char *referent, struct ref_update *update,
struct strbuf *err);
+/*
+ * Check if the ref must exist, this means that the old_oid or
+ * old_target is non NULL.
+ */
+int ref_update_expects_existing_old_ref(struct ref_update *update);
+
#endif /* REFS_REFS_INTERNAL_H */
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index 438b5c478b..bf4446afd3 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -2,6 +2,7 @@
#include "../abspath.h"
#include "../chdir-notify.h"
#include "../config.h"
+#include "../dir.h"
#include "../environment.h"
#include "../gettext.h"
#include "../hash.h"
@@ -198,7 +199,8 @@ static void fill_reftable_log_record(struct reftable_log_record *log, const stru
log->value.update.tz_offset = sign * atoi(tz_begin);
}
-static int read_ref_without_reload(struct reftable_stack *stack,
+static int read_ref_without_reload(struct reftable_ref_store *refs,
+ struct reftable_stack *stack,
const char *refname,
struct object_id *oid,
struct strbuf *referent,
@@ -216,7 +218,8 @@ static int read_ref_without_reload(struct reftable_stack *stack,
strbuf_addstr(referent, ref.value.symref);
*type |= REF_ISSYMREF;
} else if (reftable_ref_record_val1(&ref)) {
- oidread(oid, reftable_ref_record_val1(&ref));
+ oidread(oid, reftable_ref_record_val1(&ref),
+ refs->base.repo->hash_algo);
} else {
/* We got a tombstone, which should not happen. */
BUG("unhandled reference value type %d", ref.value_type);
@@ -383,6 +386,56 @@ static int reftable_be_create_on_disk(struct ref_store *ref_store,
return 0;
}
+static int reftable_be_remove_on_disk(struct ref_store *ref_store,
+ struct strbuf *err)
+{
+ struct reftable_ref_store *refs =
+ reftable_be_downcast(ref_store, REF_STORE_WRITE, "remove");
+ struct strbuf sb = STRBUF_INIT;
+ int ret = 0;
+
+ /*
+ * Release the ref store such that all stacks are closed. This is
+ * required so that the "tables.list" file is not open anymore, which
+ * would otherwise make it impossible to remove the file on Windows.
+ */
+ reftable_be_release(ref_store);
+
+ strbuf_addf(&sb, "%s/reftable", refs->base.gitdir);
+ if (remove_dir_recursively(&sb, 0) < 0) {
+ strbuf_addf(err, "could not delete reftables: %s",
+ strerror(errno));
+ ret = -1;
+ }
+ strbuf_reset(&sb);
+
+ strbuf_addf(&sb, "%s/HEAD", refs->base.gitdir);
+ if (unlink(sb.buf) < 0) {
+ strbuf_addf(err, "could not delete stub HEAD: %s",
+ strerror(errno));
+ ret = -1;
+ }
+ strbuf_reset(&sb);
+
+ strbuf_addf(&sb, "%s/refs/heads", refs->base.gitdir);
+ if (unlink(sb.buf) < 0) {
+ strbuf_addf(err, "could not delete stub heads: %s",
+ strerror(errno));
+ ret = -1;
+ }
+ strbuf_reset(&sb);
+
+ strbuf_addf(&sb, "%s/refs", refs->base.gitdir);
+ if (rmdir(sb.buf) < 0) {
+ strbuf_addf(err, "could not delete refs directory: %s",
+ strerror(errno));
+ ret = -1;
+ }
+
+ strbuf_release(&sb);
+ return ret;
+}
+
struct reftable_ref_iterator {
struct ref_iterator base;
struct reftable_ref_store *refs;
@@ -432,15 +485,17 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
switch (iter->ref.value_type) {
case REFTABLE_REF_VAL1:
- oidread(&iter->oid, iter->ref.value.val1);
+ oidread(&iter->oid, iter->ref.value.val1,
+ refs->base.repo->hash_algo);
break;
case REFTABLE_REF_VAL2:
- oidread(&iter->oid, iter->ref.value.val2.value);
+ oidread(&iter->oid, iter->ref.value.val2.value,
+ refs->base.repo->hash_algo);
break;
case REFTABLE_REF_SYMREF:
if (!refs_resolve_ref_unsafe(&iter->refs->base, iter->ref.refname,
RESOLVE_REF_READING, &iter->oid, &flags))
- oidclr(&iter->oid);
+ oidclr(&iter->oid, refs->base.repo->hash_algo);
break;
default:
BUG("unhandled reference value type %d", iter->ref.value_type);
@@ -452,7 +507,7 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
if (check_refname_format(iter->ref.refname, REFNAME_ALLOW_ONELEVEL)) {
if (!refname_is_safe(iter->ref.refname))
die(_("refname is dangerous: %s"), iter->ref.refname);
- oidclr(&iter->oid);
+ oidclr(&iter->oid, refs->base.repo->hash_algo);
flags |= REF_BAD_NAME | REF_ISBROKEN;
}
@@ -494,7 +549,8 @@ static int reftable_ref_iterator_peel(struct ref_iterator *ref_iterator,
(struct reftable_ref_iterator *)ref_iterator;
if (iter->ref.value_type == REFTABLE_REF_VAL2) {
- oidread(peeled, iter->ref.value.val2.target_value);
+ oidread(peeled, iter->ref.value.val2.target_value,
+ iter->refs->base.repo->hash_algo);
return 0;
}
@@ -602,7 +658,7 @@ static int reftable_be_read_raw_ref(struct ref_store *ref_store,
if (ret)
return ret;
- ret = read_ref_without_reload(stack, refname, oid, referent, type);
+ ret = read_ref_without_reload(refs, stack, refname, oid, referent, type);
if (ret < 0)
return ret;
if (ret > 0) {
@@ -811,8 +867,8 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
goto done;
}
- ret = read_ref_without_reload(stack_for(refs, "HEAD", NULL), "HEAD", &head_oid,
- &head_referent, &head_type);
+ ret = read_ref_without_reload(refs, stack_for(refs, "HEAD", NULL), "HEAD",
+ &head_oid, &head_referent, &head_type);
if (ret < 0)
goto done;
ret = 0;
@@ -879,11 +935,11 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
string_list_insert(&affected_refnames, new_update->refname);
}
- ret = read_ref_without_reload(stack, rewritten_ref,
+ ret = read_ref_without_reload(refs, stack, rewritten_ref,
&current_oid, &referent, &u->type);
if (ret < 0)
goto done;
- if (ret > 0 && (!(u->flags & REF_HAVE_OLD) || is_null_oid(&u->old_oid))) {
+ if (ret > 0 && !ref_update_expects_existing_old_ref(u)) {
/*
* The reference does not exist, and we either have no
* old object ID or expect the reference to not exist.
@@ -954,8 +1010,9 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
*/
new_update = ref_transaction_add_update(
transaction, referent.buf, new_flags,
- &u->new_oid, &u->old_oid, u->new_target,
- u->old_target, u->msg);
+ u->new_target ? NULL : &u->new_oid,
+ u->old_target ? NULL : &u->old_oid,
+ u->new_target, u->old_target, u->msg);
new_update->parent_update = u;
@@ -987,6 +1044,16 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
* backend returns, which keeps our tests happy.
*/
if (u->old_target) {
+ if (!(u->type & REF_ISSYMREF)) {
+ strbuf_addf(err, _("cannot lock ref '%s': "
+ "expected symref with target '%s': "
+ "but is a regular ref"),
+ ref_update_original_update_refname(u),
+ u->old_target);
+ ret = -1;
+ goto done;
+ }
+
if (ref_update_check_old_target(referent.buf, u, err)) {
ret = -1;
goto done;
@@ -1141,7 +1208,8 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
if (ret)
goto done;
- } else if (u->flags & REF_HAVE_NEW &&
+ } else if (!(u->flags & REF_SKIP_CREATE_REFLOG) &&
+ (u->flags & REF_HAVE_NEW) &&
(u->flags & REF_FORCE_CREATE_REFLOG ||
should_write_log(&arg->refs->base, u->refname))) {
struct reftable_log_record *log;
@@ -1398,10 +1466,10 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
* old reference.
*/
refs[0] = old_ref;
- refs[0].refname = (char *)arg->newname;
+ refs[0].refname = xstrdup(arg->newname);
refs[0].update_index = creation_ts;
if (arg->delete_old) {
- refs[1].refname = (char *)arg->oldname;
+ refs[1].refname = xstrdup(arg->oldname);
refs[1].value_type = REFTABLE_REF_DELETION;
refs[1].update_index = deletion_ts;
}
@@ -1424,14 +1492,15 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
ALLOC_GROW(logs, logs_nr + 1, logs_alloc);
memset(&logs[logs_nr], 0, sizeof(logs[logs_nr]));
fill_reftable_log_record(&logs[logs_nr], &committer_ident);
- logs[logs_nr].refname = (char *)arg->newname;
+ logs[logs_nr].refname = xstrdup(arg->newname);
logs[logs_nr].update_index = deletion_ts;
logs[logs_nr].value.update.message =
xstrndup(arg->logmsg, arg->refs->write_options.block_size / 2);
memcpy(logs[logs_nr].value.update.old_hash, old_ref.value.val1, GIT_MAX_RAWSZ);
logs_nr++;
- ret = read_ref_without_reload(arg->stack, "HEAD", &head_oid, &head_referent, &head_type);
+ ret = read_ref_without_reload(arg->refs, arg->stack, "HEAD", &head_oid,
+ &head_referent, &head_type);
if (ret < 0)
goto done;
append_head_reflog = (head_type & REF_ISSYMREF) && !strcmp(head_referent.buf, arg->oldname);
@@ -1445,7 +1514,13 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
if (append_head_reflog) {
ALLOC_GROW(logs, logs_nr + 1, logs_alloc);
logs[logs_nr] = logs[logs_nr - 1];
- logs[logs_nr].refname = "HEAD";
+ logs[logs_nr].refname = xstrdup("HEAD");
+ logs[logs_nr].value.update.name =
+ xstrdup(logs[logs_nr].value.update.name);
+ logs[logs_nr].value.update.email =
+ xstrdup(logs[logs_nr].value.update.email);
+ logs[logs_nr].value.update.message =
+ xstrdup(logs[logs_nr].value.update.message);
logs_nr++;
}
}
@@ -1456,7 +1531,7 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
ALLOC_GROW(logs, logs_nr + 1, logs_alloc);
memset(&logs[logs_nr], 0, sizeof(logs[logs_nr]));
fill_reftable_log_record(&logs[logs_nr], &committer_ident);
- logs[logs_nr].refname = (char *)arg->newname;
+ logs[logs_nr].refname = xstrdup(arg->newname);
logs[logs_nr].update_index = creation_ts;
logs[logs_nr].value.update.message =
xstrndup(arg->logmsg, arg->refs->write_options.block_size / 2);
@@ -1489,7 +1564,7 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
*/
ALLOC_GROW(logs, logs_nr + 1, logs_alloc);
logs[logs_nr] = old_log;
- logs[logs_nr].refname = (char *)arg->newname;
+ logs[logs_nr].refname = xstrdup(arg->newname);
logs_nr++;
/*
@@ -1498,7 +1573,7 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
if (arg->delete_old) {
ALLOC_GROW(logs, logs_nr + 1, logs_alloc);
memset(&logs[logs_nr], 0, sizeof(logs[logs_nr]));
- logs[logs_nr].refname = (char *)arg->oldname;
+ logs[logs_nr].refname = xstrdup(arg->oldname);
logs[logs_nr].value_type = REFTABLE_LOG_DELETION;
logs[logs_nr].update_index = old_log.update_index;
logs_nr++;
@@ -1521,13 +1596,11 @@ done:
reftable_iterator_destroy(&it);
string_list_clear(&skip, 0);
strbuf_release(&errbuf);
- for (i = 0; i < logs_nr; i++) {
- if (!strcmp(logs[i].refname, "HEAD"))
- continue;
- logs[i].refname = NULL;
+ for (i = 0; i < logs_nr; i++)
reftable_log_record_release(&logs[i]);
- }
free(logs);
+ for (i = 0; i < ARRAY_SIZE(refs); i++)
+ reftable_ref_record_release(&refs[i]);
reftable_ref_record_release(&old_ref);
reftable_log_record_release(&old_log);
return ret;
@@ -1717,15 +1790,16 @@ static struct ref_iterator *reftable_be_reflog_iterator_begin(struct ref_store *
ref_iterator_select, NULL);
}
-static int yield_log_record(struct reftable_log_record *log,
+static int yield_log_record(struct reftable_ref_store *refs,
+ struct reftable_log_record *log,
each_reflog_ent_fn fn,
void *cb_data)
{
struct object_id old_oid, new_oid;
const char *full_committer;
- oidread(&old_oid, log->value.update.old_hash);
- oidread(&new_oid, log->value.update.new_hash);
+ oidread(&old_oid, log->value.update.old_hash, refs->base.repo->hash_algo);
+ oidread(&new_oid, log->value.update.new_hash, refs->base.repo->hash_algo);
/*
* When both the old object ID and the new object ID are null
@@ -1768,7 +1842,7 @@ static int reftable_be_for_each_reflog_ent_reverse(struct ref_store *ref_store,
break;
}
- ret = yield_log_record(&log, fn, cb_data);
+ ret = yield_log_record(refs, &log, fn, cb_data);
if (ret)
break;
}
@@ -1813,7 +1887,7 @@ static int reftable_be_for_each_reflog_ent(struct ref_store *ref_store,
}
for (i = logs_nr; i--;) {
- ret = yield_log_record(&logs[i], fn, cb_data);
+ ret = yield_log_record(refs, &logs[i], fn, cb_data);
if (ret)
goto done;
}
@@ -2126,7 +2200,8 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
if (ret < 0)
goto done;
if (reftable_ref_record_val1(&ref_record))
- oidread(&oid, reftable_ref_record_val1(&ref_record));
+ oidread(&oid, reftable_ref_record_val1(&ref_record),
+ ref_store->repo->hash_algo);
prepare_fn(refname, &oid, policy_cb_data);
while (1) {
@@ -2141,8 +2216,10 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
break;
}
- oidread(&old_oid, log.value.update.old_hash);
- oidread(&new_oid, log.value.update.new_hash);
+ oidread(&old_oid, log.value.update.old_hash,
+ ref_store->repo->hash_algo);
+ oidread(&new_oid, log.value.update.new_hash,
+ ref_store->repo->hash_algo);
/*
* Skip over the reflog existence marker. We will add it back
@@ -2173,8 +2250,10 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
struct object_id old_oid, new_oid;
*dest = logs[i];
- oidread(&old_oid, logs[i].value.update.old_hash);
- oidread(&new_oid, logs[i].value.update.new_hash);
+ oidread(&old_oid, logs[i].value.update.old_hash,
+ ref_store->repo->hash_algo);
+ oidread(&new_oid, logs[i].value.update.new_hash,
+ ref_store->repo->hash_algo);
if (should_prune_fn(&old_oid, &new_oid, logs[i].value.update.email,
(timestamp_t)logs[i].value.update.time,
@@ -2191,7 +2270,7 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
if (flags & EXPIRE_REFLOGS_UPDATE_REF && last_hash &&
reftable_ref_record_val1(&ref_record))
- oidread(&arg.update_oid, last_hash);
+ oidread(&arg.update_oid, last_hash, ref_store->repo->hash_algo);
arg.refs = refs;
arg.records = rewritten;
@@ -2230,6 +2309,7 @@ struct ref_storage_be refs_be_reftable = {
.init = reftable_be_init,
.release = reftable_be_release,
.create_on_disk = reftable_be_create_on_disk,
+ .remove_on_disk = reftable_be_remove_on_disk,
.transaction_prepare = reftable_be_transaction_prepare,
.transaction_finish = reftable_be_transaction_finish,