summaryrefslogtreecommitdiff
path: root/refs
diff options
context:
space:
mode:
Diffstat (limited to 'refs')
-rw-r--r--refs/files-backend.c153
-rw-r--r--refs/packed-backend.c7
-rw-r--r--refs/refs-internal.h26
3 files changed, 113 insertions, 73 deletions
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 00f596dd68..237a2afb5d 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -282,10 +282,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 +358,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 +385,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 +403,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 +427,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 +448,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 +457,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 +498,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 +1007,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 +1020,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 +1039,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;
@@ -1358,6 +1360,35 @@ static int commit_ref_update(struct files_ref_store *refs,
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 +1404,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 +1418,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 +1462,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 +1490,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);
@@ -1480,7 +1512,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);
@@ -1796,10 +1828,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;
@@ -1843,9 +1877,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);
@@ -1886,7 +1923,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);
@@ -2119,6 +2156,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;
@@ -2130,9 +2168,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;
}
@@ -2476,9 +2515,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",
@@ -3090,7 +3131,6 @@ 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;
@@ -3104,7 +3144,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);
@@ -3166,9 +3206,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 ((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 472458b844..67152c664e 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -1354,6 +1354,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 +1365,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.
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index 5b40b3bbbf..46a839539e 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
@@ -713,10 +699,12 @@ 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