summaryrefslogtreecommitdiff
path: root/refs
diff options
context:
space:
mode:
Diffstat (limited to 'refs')
-rw-r--r--refs/debug.c18
-rw-r--r--refs/files-backend.c263
-rw-r--r--refs/packed-backend.c21
-rw-r--r--refs/packed-backend.h2
-rw-r--r--refs/refs-internal.h32
5 files changed, 188 insertions, 148 deletions
diff --git a/refs/debug.c b/refs/debug.c
index 8667c64023..2b0771ca53 100644
--- a/refs/debug.c
+++ b/refs/debug.c
@@ -26,7 +26,8 @@ struct ref_store *maybe_debug_wrap_ref_store(const char *gitdir, struct ref_stor
be_copy->name = store->be->name;
trace_printf_key(&trace_refs, "ref_store for %s\n", gitdir);
res->refs = store;
- base_ref_store_init((struct ref_store *)res, be_copy);
+ base_ref_store_init((struct ref_store *)res, store->repo, gitdir,
+ be_copy);
return (struct ref_store *)res;
}
@@ -47,7 +48,8 @@ static int debug_transaction_prepare(struct ref_store *refs,
transaction->ref_store = drefs->refs;
res = drefs->refs->be->transaction_prepare(drefs->refs, transaction,
err);
- trace_printf_key(&trace_refs, "transaction_prepare: %d\n", res);
+ trace_printf_key(&trace_refs, "transaction_prepare: %d \"%s\"\n", res,
+ err->buf);
return res;
}
@@ -284,6 +286,7 @@ static int debug_print_reflog_ent(struct object_id *old_oid,
int ret;
char o[GIT_MAX_HEXSZ + 1] = "null";
char n[GIT_MAX_HEXSZ + 1] = "null";
+ char *msgend = strchrnul(msg, '\n');
if (old_oid)
oid_to_hex_r(o, old_oid);
if (new_oid)
@@ -291,8 +294,10 @@ static int debug_print_reflog_ent(struct object_id *old_oid,
ret = dbg->fn(old_oid, new_oid, committer, timestamp, tz, msg,
dbg->cb_data);
- trace_printf_key(&trace_refs, "reflog_ent %s (ret %d): %s -> %s, %s %ld \"%s\"\n",
- dbg->refname, ret, o, n, committer, (long int)timestamp, msg);
+ trace_printf_key(&trace_refs,
+ "reflog_ent %s (ret %d): %s -> %s, %s %ld \"%.*s\"\n",
+ dbg->refname, ret, o, n, committer,
+ (long int)timestamp, (int)(msgend - msg), msg);
return ret;
}
@@ -339,11 +344,10 @@ static int debug_reflog_exists(struct ref_store *ref_store, const char *refname)
}
static int debug_create_reflog(struct ref_store *ref_store, const char *refname,
- int force_create, struct strbuf *err)
+ struct strbuf *err)
{
struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
- int res = drefs->refs->be->create_reflog(drefs->refs, refname,
- force_create, err);
+ int res = drefs->refs->be->create_reflog(drefs->refs, refname, err);
trace_printf_key(&trace_refs, "create_reflog: %s: %d\n", refname, res);
return res;
}
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 151b0056fe..b529fdf237 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -16,8 +16,7 @@
* This backend uses the following flags in `ref_update::flags` for
* internal bookkeeping purposes. Their numerical values must not
* conflict with REF_NO_DEREF, REF_FORCE_CREATE_REFLOG, REF_HAVE_NEW,
- * REF_HAVE_OLD, or REF_IS_PRUNING, which are also stored in
- * `ref_update::flags`.
+ * or REF_HAVE_OLD, which are also stored in `ref_update::flags`.
*/
/*
@@ -87,16 +86,12 @@ static struct ref_store *files_ref_store_create(struct repository *repo,
struct ref_store *ref_store = (struct ref_store *)refs;
struct strbuf sb = STRBUF_INIT;
- ref_store->repo = repo;
- ref_store->gitdir = xstrdup(gitdir);
- base_ref_store_init(ref_store, &refs_be_files);
+ base_ref_store_init(ref_store, repo, gitdir, &refs_be_files);
refs->store_flags = flags;
-
get_common_dir_noenv(&sb, gitdir);
refs->gitcommondir = strbuf_detach(&sb, NULL);
- strbuf_addf(&sb, "%s/packed-refs", refs->gitcommondir);
- refs->packed_ref_store = packed_ref_store_create(repo, sb.buf, flags);
- strbuf_release(&sb);
+ refs->packed_ref_store =
+ packed_ref_store_create(repo, refs->gitcommondir, flags);
chdir_notify_reparent("files-backend $GIT_DIR", &refs->base.gitdir);
chdir_notify_reparent("files-backend $GIT_COMMONDIR",
@@ -282,10 +277,11 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
create_dir_entry(dir->cache, refname.buf,
refname.len));
} else {
+ int ignore_errno;
if (!refs_resolve_ref_unsafe(&refs->base,
refname.buf,
RESOLVE_REF_READING,
- &oid, &flag)) {
+ &oid, &flag, &ignore_errno)) {
oidclr(&oid);
flag |= REF_ISBROKEN;
} else if (is_null_oid(&oid)) {
@@ -357,6 +353,7 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
int fd;
int ret = -1;
int remaining_retries = 3;
+ int myerr = 0;
*type = 0;
strbuf_reset(&sb_path);
@@ -383,11 +380,14 @@ stat_ref:
goto out;
if (lstat(path, &st) < 0) {
- if (errno != ENOENT)
+ int ignore_errno;
+ myerr = errno;
+ errno = 0;
+ if (myerr != ENOENT)
goto out;
- if (refs_read_raw_ref(refs->packed_ref_store, refname,
- oid, referent, type)) {
- errno = ENOENT;
+ if (refs_read_raw_ref(refs->packed_ref_store, refname, oid,
+ referent, type, &ignore_errno)) {
+ myerr = ENOENT;
goto out;
}
ret = 0;
@@ -398,7 +398,9 @@ stat_ref:
if (S_ISLNK(st.st_mode)) {
strbuf_reset(&sb_contents);
if (strbuf_readlink(&sb_contents, path, st.st_size) < 0) {
- if (errno == ENOENT || errno == EINVAL)
+ myerr = errno;
+ errno = 0;
+ if (myerr == ENOENT || myerr == EINVAL)
/* inconsistent with lstat; retry */
goto stat_ref;
else
@@ -420,14 +422,15 @@ stat_ref:
/* Is it a directory? */
if (S_ISDIR(st.st_mode)) {
+ int ignore_errno;
/*
* Even though there is a directory where the loose
* ref is supposed to be, there could still be a
* packed ref:
*/
- if (refs_read_raw_ref(refs->packed_ref_store, refname,
- oid, referent, type)) {
- errno = EISDIR;
+ if (refs_read_raw_ref(refs->packed_ref_store, refname, oid,
+ referent, type, &ignore_errno)) {
+ myerr = EISDIR;
goto out;
}
ret = 0;
@@ -440,7 +443,8 @@ stat_ref:
*/
fd = open(path, O_RDONLY);
if (fd < 0) {
- if (errno == ENOENT && !S_ISLNK(st.st_mode))
+ myerr = errno;
+ if (myerr == ENOENT && !S_ISLNK(st.st_mode))
/* inconsistent with lstat; retry */
goto stat_ref;
else
@@ -448,26 +452,29 @@ stat_ref:
}
strbuf_reset(&sb_contents);
if (strbuf_read(&sb_contents, fd, 256) < 0) {
- int save_errno = errno;
+ myerr = errno;
close(fd);
- errno = save_errno;
goto out;
}
close(fd);
strbuf_rtrim(&sb_contents);
buf = sb_contents.buf;
- ret = parse_loose_ref_contents(buf, oid, referent, type);
+ ret = parse_loose_ref_contents(buf, oid, referent, type, &myerr);
out:
- *failure_errno = errno;
+ if (ret && !myerr)
+ BUG("returning non-zero %d, should have set myerr!", ret);
+ *failure_errno = myerr;
+
strbuf_release(&sb_path);
strbuf_release(&sb_contents);
return ret;
}
int parse_loose_ref_contents(const char *buf, struct object_id *oid,
- struct strbuf *referent, unsigned int *type)
+ struct strbuf *referent, unsigned int *type,
+ int *failure_errno)
{
const char *p;
if (skip_prefix(buf, "ref:", &buf)) {
@@ -486,7 +493,7 @@ int parse_loose_ref_contents(const char *buf, struct object_id *oid,
if (parse_oid_hex(buf, oid, &p) ||
(*p != '\0' && !isspace(*p))) {
*type |= REF_ISBROKEN;
- errno = EINVAL;
+ *failure_errno = EINVAL;
return -1;
}
return 0;
@@ -995,11 +1002,12 @@ static int create_reflock(const char *path, void *cb)
* Locks a ref returning the lock on success and NULL on failure.
*/
static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs,
- const char *refname, int *type,
+ const char *refname,
struct strbuf *err)
{
struct strbuf ref_file = STRBUF_INIT;
struct ref_lock *lock;
+ int ignore_errno;
files_assert_main_repository(refs, "lock_ref_oid_basic");
assert(err);
@@ -1007,16 +1015,6 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs,
CALLOC_ARRAY(lock, 1);
files_ref_path(refs, &ref_file, refname);
- if (!refs_resolve_ref_unsafe(&refs->base, refname,
- RESOLVE_REF_NO_RECURSE,
- &lock->old_oid, type)) {
- if (!refs_verify_refname_available(&refs->base, refname,
- NULL, NULL, err))
- strbuf_addf(err, "unable to resolve reference '%s': %s",
- refname, strerror(errno));
-
- goto error_return;
- }
/*
* If the ref did not exist and we are creating it, make sure
@@ -1036,9 +1034,8 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs,
goto error_return;
}
- if (refs_read_ref_full(&refs->base, lock->ref_name,
- 0,
- &lock->old_oid, NULL))
+ if (!refs_resolve_ref_unsafe(&refs->base, lock->ref_name, 0,
+ &lock->old_oid, NULL, &ignore_errno))
oidclr(&lock->old_oid);
goto out;
@@ -1352,12 +1349,42 @@ static int rename_tmp_log(struct files_ref_store *refs, const char *newrefname)
}
static int write_ref_to_lockfile(struct ref_lock *lock,
- const struct object_id *oid, struct strbuf *err);
+ const struct object_id *oid,
+ int skip_oid_verification, struct strbuf *err);
static int commit_ref_update(struct files_ref_store *refs,
struct ref_lock *lock,
const struct object_id *oid, const char *logmsg,
struct strbuf *err);
+/*
+ * Emit a better error message than lockfile.c's
+ * unable_to_lock_message() would in case there is a D/F conflict with
+ * another existing reference. If there would be a conflict, emit an error
+ * message and return false; otherwise, return true.
+ *
+ * Note that this function is not safe against all races with other
+ * processes, and that's not its job. We'll emit a more verbose error on D/f
+ * conflicts if we get past it into lock_ref_oid_basic().
+ */
+static int refs_rename_ref_available(struct ref_store *refs,
+ const char *old_refname,
+ const char *new_refname)
+{
+ struct string_list skip = STRING_LIST_INIT_NODUP;
+ struct strbuf err = STRBUF_INIT;
+ int ok;
+
+ string_list_insert(&skip, old_refname);
+ ok = !refs_verify_refname_available(refs, new_refname,
+ NULL, &skip, &err);
+ if (!ok)
+ error("%s", err.buf);
+
+ string_list_clear(&skip, 0);
+ strbuf_release(&err);
+ return ok;
+}
+
static int files_copy_or_rename_ref(struct ref_store *ref_store,
const char *oldrefname, const char *newrefname,
const char *logmsg, int copy)
@@ -1373,6 +1400,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
struct strbuf tmp_renamed_log = STRBUF_INIT;
int log, ret;
struct strbuf err = STRBUF_INIT;
+ int ignore_errno;
files_reflog_path(refs, &sb_oldref, oldrefname);
files_reflog_path(refs, &sb_newref, newrefname);
@@ -1386,7 +1414,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
if (!refs_resolve_ref_unsafe(&refs->base, oldrefname,
RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
- &orig_oid, &flag)) {
+ &orig_oid, &flag, &ignore_errno)) {
ret = error("refname %s not found", oldrefname);
goto out;
}
@@ -1430,9 +1458,9 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
* the safety anyway; we want to delete the reference whatever
* its current value.
*/
- if (!copy && !refs_read_ref_full(&refs->base, newrefname,
- RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
- NULL, NULL) &&
+ if (!copy && refs_resolve_ref_unsafe(&refs->base, newrefname,
+ RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
+ NULL, NULL, &ignore_errno) &&
refs_delete_ref(&refs->base, NULL, newrefname,
NULL, REF_NO_DEREF)) {
if (errno == EISDIR) {
@@ -1458,7 +1486,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
logmoved = log;
- lock = lock_ref_oid_basic(refs, newrefname, NULL, &err);
+ lock = lock_ref_oid_basic(refs, newrefname, &err);
if (!lock) {
if (copy)
error("unable to copy '%s' to '%s': %s", oldrefname, newrefname, err.buf);
@@ -1469,7 +1497,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
}
oidcpy(&lock->old_oid, &orig_oid);
- if (write_ref_to_lockfile(lock, &orig_oid, &err) ||
+ if (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||
commit_ref_update(refs, lock, &orig_oid, logmsg, &err)) {
error("unable to write current sha1 into %s: %s", newrefname, err.buf);
strbuf_release(&err);
@@ -1480,7 +1508,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
goto out;
rollback:
- lock = lock_ref_oid_basic(refs, oldrefname, NULL, &err);
+ lock = lock_ref_oid_basic(refs, oldrefname, &err);
if (!lock) {
error("unable to lock %s for rollback: %s", oldrefname, err.buf);
strbuf_release(&err);
@@ -1489,7 +1517,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
flag = log_all_ref_updates;
log_all_ref_updates = LOG_REFS_NONE;
- if (write_ref_to_lockfile(lock, &orig_oid, &err) ||
+ if (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||
commit_ref_update(refs, lock, &orig_oid, NULL, &err)) {
error("unable to write current sha1 into %s: %s", oldrefname, err.buf);
strbuf_release(&err);
@@ -1639,15 +1667,14 @@ error:
return -1;
}
-static int files_create_reflog(struct ref_store *ref_store,
- const char *refname, int force_create,
+static int files_create_reflog(struct ref_store *ref_store, const char *refname,
struct strbuf *err)
{
struct files_ref_store *refs =
files_downcast(ref_store, REF_STORE_WRITE, "create_reflog");
int fd;
- if (log_ref_setup(refs, refname, force_create, &fd, err))
+ if (log_ref_setup(refs, refname, 1, &fd, err))
return -1;
if (fd >= 0)
@@ -1725,26 +1752,31 @@ static int files_log_ref_write(struct files_ref_store *refs,
* errors, rollback the lockfile, fill in *err and return -1.
*/
static int write_ref_to_lockfile(struct ref_lock *lock,
- const struct object_id *oid, struct strbuf *err)
+ const struct object_id *oid,
+ int skip_oid_verification, struct strbuf *err)
{
static char term = '\n';
struct object *o;
int fd;
- o = parse_object(the_repository, oid);
- if (!o) {
- strbuf_addf(err,
- "trying to write ref '%s' with nonexistent object %s",
- lock->ref_name, oid_to_hex(oid));
- unlock_ref(lock);
- return -1;
- }
- if (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {
- strbuf_addf(err,
- "trying to write non-commit object %s to branch '%s'",
- oid_to_hex(oid), lock->ref_name);
- unlock_ref(lock);
- return -1;
+ if (!skip_oid_verification) {
+ o = parse_object(the_repository, oid);
+ if (!o) {
+ strbuf_addf(
+ err,
+ "trying to write ref '%s' with nonexistent object %s",
+ lock->ref_name, oid_to_hex(oid));
+ unlock_ref(lock);
+ return -1;
+ }
+ if (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {
+ strbuf_addf(
+ err,
+ "trying to write non-commit object %s to branch '%s'",
+ oid_to_hex(oid), lock->ref_name);
+ unlock_ref(lock);
+ return -1;
+ }
}
fd = get_lock_file_fd(&lock->lk);
if (write_in_full(fd, oid_to_hex(oid), the_hash_algo->hexsz) < 0 ||
@@ -1797,10 +1829,12 @@ static int commit_ref_update(struct files_ref_store *refs,
*/
int head_flag;
const char *head_ref;
+ int ignore_errno;
head_ref = refs_resolve_ref_unsafe(&refs->base, "HEAD",
RESOLVE_REF_READING,
- NULL, &head_flag);
+ NULL, &head_flag,
+ &ignore_errno);
if (head_ref && (head_flag & REF_ISSYMREF) &&
!strcmp(head_ref, lock->ref_name)) {
struct strbuf log_err = STRBUF_INIT;
@@ -1844,9 +1878,12 @@ static void update_symref_reflog(struct files_ref_store *refs,
{
struct strbuf err = STRBUF_INIT;
struct object_id new_oid;
+ int ignore_errno;
+
if (logmsg &&
- !refs_read_ref_full(&refs->base, target,
- RESOLVE_REF_READING, &new_oid, NULL) &&
+ refs_resolve_ref_unsafe(&refs->base, target,
+ RESOLVE_REF_READING, &new_oid, NULL,
+ &ignore_errno) &&
files_log_ref_write(refs, refname, &lock->old_oid,
&new_oid, logmsg, 0, &err)) {
error("%s", err.buf);
@@ -1887,7 +1924,7 @@ static int files_create_symref(struct ref_store *ref_store,
struct ref_lock *lock;
int ret;
- lock = lock_ref_oid_basic(refs, refname, NULL, &err);
+ lock = lock_ref_oid_basic(refs, refname, &err);
if (!lock) {
error("%s", err.buf);
strbuf_release(&err);
@@ -2120,6 +2157,7 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)
(struct files_reflog_iterator *)ref_iterator;
struct dir_iterator *diter = iter->dir_iterator;
int ok;
+ int ignore_errno;
while ((ok = dir_iterator_advance(diter)) == ITER_OK) {
int flags;
@@ -2131,9 +2169,10 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)
if (ends_with(diter->basename, ".lock"))
continue;
- if (refs_read_ref_full(iter->ref_store,
- diter->relative_path, 0,
- &iter->oid, &flags)) {
+ if (!refs_resolve_ref_unsafe(iter->ref_store,
+ diter->relative_path, 0,
+ &iter->oid, &flags,
+ &ignore_errno)) {
error("bad ref for %s", diter->path.buf);
continue;
}
@@ -2151,7 +2190,7 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)
}
static int files_reflog_iterator_peel(struct ref_iterator *ref_iterator,
- struct object_id *peeled)
+ struct object_id *peeled)
{
BUG("ref_iterator_peel() called for reflog_iterator");
}
@@ -2477,9 +2516,11 @@ static int lock_ref_for_update(struct files_ref_store *refs,
* the transaction, so we have to read it here
* to record and possibly check old_oid:
*/
- if (refs_read_ref_full(&refs->base,
- referent.buf, 0,
- &lock->old_oid, NULL)) {
+ int ignore_errno;
+ if (!refs_resolve_ref_unsafe(&refs->base,
+ referent.buf, 0,
+ &lock->old_oid, NULL,
+ &ignore_errno)) {
if (update->flags & REF_HAVE_OLD) {
strbuf_addf(err, "cannot lock ref '%s': "
"error reading reference",
@@ -2535,8 +2576,10 @@ static int lock_ref_for_update(struct files_ref_store *refs,
* The reference already has the desired
* value, so we don't need to write it.
*/
- } else if (write_ref_to_lockfile(lock, &update->new_oid,
- err)) {
+ } else if (write_ref_to_lockfile(
+ lock, &update->new_oid,
+ update->flags & REF_SKIP_OID_VERIFICATION,
+ err)) {
char *write_err = strbuf_detach(err, NULL);
/*
@@ -3039,11 +3082,12 @@ cleanup:
}
struct expire_reflog_cb {
- unsigned int flags;
reflog_expiry_should_prune_fn *should_prune_fn;
void *policy_cb;
FILE *newlog;
struct object_id last_kept_oid;
+ unsigned int rewrite:1,
+ dry_run:1;
};
static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
@@ -3051,33 +3095,27 @@ static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
const char *message, void *cb_data)
{
struct expire_reflog_cb *cb = cb_data;
- struct expire_reflog_policy_cb *policy_cb = cb->policy_cb;
+ reflog_expiry_should_prune_fn *fn = cb->should_prune_fn;
- if (cb->flags & EXPIRE_REFLOGS_REWRITE)
+ if (cb->rewrite)
ooid = &cb->last_kept_oid;
- if ((*cb->should_prune_fn)(ooid, noid, email, timestamp, tz,
- message, policy_cb)) {
- if (!cb->newlog)
- printf("would prune %s", message);
- else if (cb->flags & EXPIRE_REFLOGS_VERBOSE)
- printf("prune %s", message);
- } else {
- if (cb->newlog) {
- fprintf(cb->newlog, "%s %s %s %"PRItime" %+05d\t%s",
- oid_to_hex(ooid), oid_to_hex(noid),
- email, timestamp, tz, message);
- oidcpy(&cb->last_kept_oid, noid);
- }
- if (cb->flags & EXPIRE_REFLOGS_VERBOSE)
- printf("keep %s", message);
- }
+ if (fn(ooid, noid, email, timestamp, tz, message, cb->policy_cb))
+ return 0;
+
+ if (cb->dry_run)
+ return 0; /* --dry-run */
+
+ fprintf(cb->newlog, "%s %s %s %"PRItime" %+05d\t%s", oid_to_hex(ooid),
+ oid_to_hex(noid), email, timestamp, tz, message);
+ oidcpy(&cb->last_kept_oid, noid);
+
return 0;
}
static int files_reflog_expire(struct ref_store *ref_store,
const char *refname,
- unsigned int flags,
+ unsigned int expire_flags,
reflog_expiry_prepare_fn prepare_fn,
reflog_expiry_should_prune_fn should_prune_fn,
reflog_expiry_cleanup_fn cleanup_fn,
@@ -3091,12 +3129,12 @@ static int files_reflog_expire(struct ref_store *ref_store,
struct strbuf log_file_sb = STRBUF_INIT;
char *log_file;
int status = 0;
- int type;
struct strbuf err = STRBUF_INIT;
const struct object_id *oid;
memset(&cb, 0, sizeof(cb));
- cb.flags = flags;
+ cb.rewrite = !!(expire_flags & EXPIRE_REFLOGS_REWRITE);
+ cb.dry_run = !!(expire_flags & EXPIRE_REFLOGS_DRY_RUN);
cb.policy_cb = policy_cb_data;
cb.should_prune_fn = should_prune_fn;
@@ -3105,7 +3143,7 @@ static int files_reflog_expire(struct ref_store *ref_store,
* reference itself, plus we might need to update the
* reference if --updateref was specified:
*/
- lock = lock_ref_oid_basic(refs, refname, &type, &err);
+ lock = lock_ref_oid_basic(refs, refname, &err);
if (!lock) {
error("cannot lock ref '%s': %s", refname, err.buf);
strbuf_release(&err);
@@ -3132,7 +3170,7 @@ static int files_reflog_expire(struct ref_store *ref_store,
files_reflog_path(refs, &log_file_sb, refname);
log_file = strbuf_detach(&log_file_sb, NULL);
- if (!(flags & EXPIRE_REFLOGS_DRY_RUN)) {
+ if (!cb.dry_run) {
/*
* Even though holding $GIT_DIR/logs/$reflog.lock has
* no locking implications, we use the lock_file
@@ -3159,7 +3197,7 @@ static int files_reflog_expire(struct ref_store *ref_store,
refs_for_each_reflog_ent(ref_store, refname, expire_reflog_ent, &cb);
(*cleanup_fn)(cb.policy_cb);
- if (!(flags & EXPIRE_REFLOGS_DRY_RUN)) {
+ if (!cb.dry_run) {
/*
* It doesn't make sense to adjust a reference pointed
* to by a symbolic ref based on expiring entries in
@@ -3167,9 +3205,20 @@ static int files_reflog_expire(struct ref_store *ref_store,
* a reference if there are no remaining reflog
* entries.
*/
- int update = (flags & EXPIRE_REFLOGS_UPDATE_REF) &&
- !(type & REF_ISSYMREF) &&
- !is_null_oid(&cb.last_kept_oid);
+ int update = 0;
+
+ if ((expire_flags & EXPIRE_REFLOGS_UPDATE_REF) &&
+ !is_null_oid(&cb.last_kept_oid)) {
+ int ignore_errno;
+ int type;
+ const char *ref;
+
+ ref = refs_resolve_ref_unsafe(&refs->base, refname,
+ RESOLVE_REF_NO_RECURSE,
+ NULL, &type,
+ &ignore_errno);
+ update = !!(ref && !(type & REF_ISSYMREF));
+ }
if (close_lock_file_gently(&reflog_lock)) {
status |= error("couldn't write %s: %s", log_file,
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 1c5211b03e..d91a2018f6 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -194,20 +194,19 @@ static int release_snapshot(struct snapshot *snapshot)
}
struct ref_store *packed_ref_store_create(struct repository *repo,
- const char *path,
+ const char *gitdir,
unsigned int store_flags)
{
struct packed_ref_store *refs = xcalloc(1, sizeof(*refs));
struct ref_store *ref_store = (struct ref_store *)refs;
+ struct strbuf sb = STRBUF_INIT;
- base_ref_store_init(ref_store, &refs_be_packed);
- ref_store->repo = repo;
- ref_store->gitdir = xstrdup(path);
+ base_ref_store_init(ref_store, repo, gitdir, &refs_be_packed);
refs->store_flags = store_flags;
- refs->path = xstrdup(path);
+ strbuf_addf(&sb, "%s/packed-refs", gitdir);
+ refs->path = strbuf_detach(&sb, NULL);
chdir_notify_reparent("packed-refs", &refs->path);
-
return ref_store;
}
@@ -1354,6 +1353,7 @@ int is_packed_transaction_needed(struct ref_store *ref_store,
ret = 0;
for (i = 0; i < transaction->nr; i++) {
struct ref_update *update = transaction->updates[i];
+ int failure_errno;
unsigned int type;
struct object_id oid;
@@ -1364,9 +1364,9 @@ int is_packed_transaction_needed(struct ref_store *ref_store,
*/
continue;
- if (!refs_read_raw_ref(ref_store, update->refname,
- &oid, &referent, &type) ||
- errno != ENOENT) {
+ if (!refs_read_raw_ref(ref_store, update->refname, &oid,
+ &referent, &type, &failure_errno) ||
+ failure_errno != ENOENT) {
/*
* We have to actually delete that reference
* -> this transaction is needed.
@@ -1628,8 +1628,7 @@ static int packed_reflog_exists(struct ref_store *ref_store,
}
static int packed_create_reflog(struct ref_store *ref_store,
- const char *refname, int force_create,
- struct strbuf *err)
+ const char *refname, struct strbuf *err)
{
BUG("packed reference store does not support reflogs");
}
diff --git a/refs/packed-backend.h b/refs/packed-backend.h
index f61a73ec25..9dd8a344c3 100644
--- a/refs/packed-backend.h
+++ b/refs/packed-backend.h
@@ -14,7 +14,7 @@ struct ref_transaction;
*/
struct ref_store *packed_ref_store_create(struct repository *repo,
- const char *path,
+ const char *gitdir,
unsigned int store_flags);
/*
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index 12224742ed..7ff6fba4f0 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -150,9 +150,9 @@ struct ref_update {
const char refname[FLEX_ARRAY];
};
-int refs_read_raw_ref(struct ref_store *ref_store,
- const char *refname, struct object_id *oid,
- struct strbuf *referent, unsigned int *type);
+int refs_read_raw_ref(struct ref_store *ref_store, const char *refname,
+ struct object_id *oid, struct strbuf *referent,
+ unsigned int *type, int *failure_errno);
/*
* Write an error to `err` and return a nonzero value iff the same
@@ -229,20 +229,6 @@ const char *find_descendant_ref(const char *dirname,
const struct string_list *extras,
const struct string_list *skip);
-/*
- * Check whether an attempt to rename old_refname to new_refname would
- * cause a D/F conflict with any existing reference (other than
- * possibly old_refname). If there would be a conflict, emit an error
- * message and return false; otherwise, return true.
- *
- * Note that this function is not safe against all races with other
- * processes (though rename_ref() catches some races that might get by
- * this check).
- */
-int refs_rename_ref_available(struct ref_store *refs,
- const char *old_refname,
- const char *new_refname);
-
/* We allow "recursive" symbolic refs. Only within reason, though */
#define SYMREF_MAXDEPTH 5
@@ -606,7 +592,7 @@ typedef int for_each_reflog_ent_reverse_fn(struct ref_store *ref_store,
void *cb_data);
typedef int reflog_exists_fn(struct ref_store *ref_store, const char *refname);
typedef int create_reflog_fn(struct ref_store *ref_store, const char *refname,
- int force_create, struct strbuf *err);
+ struct strbuf *err);
typedef int delete_reflog_fn(struct ref_store *ref_store, const char *refname);
typedef int reflog_expire_fn(struct ref_store *ref_store,
const char *refname,
@@ -713,17 +699,19 @@ struct ref_store {
};
/*
- * Parse contents of a loose ref file.
+ * 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,
- struct strbuf *referent, unsigned int *type);
+ struct strbuf *referent, unsigned int *type,
+ int *failure_errno);
/*
* Fill in the generic part of refs and add it to our collection of
* reference stores.
*/
-void base_ref_store_init(struct ref_store *refs,
- const struct ref_storage_be *be);
+void base_ref_store_init(struct ref_store *refs, struct repository *repo,
+ const char *path, const struct ref_storage_be *be);
/*
* Support GIT_TRACE_REFS by optionally wrapping the given ref_store instance.