-
Notifications
You must be signed in to change notification settings - Fork 25.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refs: cleanup errno sideband ref related functions #1012
Changes from all commits
d6a41c3
9502508
7feedb9
ef91f5c
6918c21
85a14bd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1653,7 +1653,8 @@ int for_each_fullref_in_prefixes(const char *namespace, | |
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the Git mailing list, Ævar Arnfjörð Bjarmason wrote (reply to this):
|
||
static int refs_read_special_head(struct ref_store *ref_store, | ||
const char *refname, struct object_id *oid, | ||
struct strbuf *referent, unsigned int *type) | ||
struct strbuf *referent, unsigned int *type, | ||
int *failure_errno) | ||
{ | ||
struct strbuf full_path = STRBUF_INIT; | ||
struct strbuf content = STRBUF_INIT; | ||
|
@@ -1663,36 +1664,42 @@ static int refs_read_special_head(struct ref_store *ref_store, | |
if (strbuf_read_file(&content, full_path.buf, 0) < 0) | ||
goto done; | ||
|
||
result = parse_loose_ref_contents(content.buf, oid, referent, type); | ||
result = parse_loose_ref_contents(content.buf, oid, referent, type, | ||
failure_errno); | ||
|
||
done: | ||
strbuf_release(&full_path); | ||
strbuf_release(&content); | ||
return result; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the Git mailing list, Ævar Arnfjörð Bjarmason wrote (reply to this):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the Git mailing list, Ævar Arnfjörð Bjarmason wrote (reply to this):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the Git mailing list, Ævar Arnfjörð Bjarmason wrote (reply to this):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the Git mailing list, Han-Wen Nienhuys wrote (reply to this):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the Git mailing list, Ævar Arnfjörð Bjarmason wrote (reply to this):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the Git mailing list, Han-Wen Nienhuys wrote (reply to this):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the Git mailing list, Junio C Hamano wrote (reply to this):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the Git mailing list, Ævar Arnfjörð Bjarmason wrote (reply to this):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the Git mailing list, Han-Wen Nienhuys wrote (reply to this):
|
||
} | ||
|
||
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) | ||
{ | ||
int unused_errno; | ||
if (!failure_errno) | ||
failure_errno = &unused_errno; | ||
*failure_errno = 0; | ||
if (!strcmp(refname, "FETCH_HEAD") || !strcmp(refname, "MERGE_HEAD")) { | ||
return refs_read_special_head(ref_store, refname, oid, referent, | ||
type); | ||
type, failure_errno); | ||
} | ||
|
||
return ref_store->be->read_raw_ref(ref_store, refname, oid, referent, | ||
type); | ||
type, failure_errno); | ||
} | ||
|
||
/* This function needs to return a meaningful errno on failure */ | ||
const char *refs_resolve_ref_unsafe(struct ref_store *refs, | ||
const char *refname, | ||
int resolve_flags, | ||
struct object_id *oid, int *flags) | ||
const char *refs_resolve_ref_unsafe_with_errno(struct ref_store *refs, | ||
const char *refname, | ||
int resolve_flags, | ||
struct object_id *oid, | ||
int *flags, int *failure_errno) | ||
{ | ||
static struct strbuf sb_refname = STRBUF_INIT; | ||
struct object_id unused_oid; | ||
int unused_flags; | ||
int unused_errno; | ||
int symref_count; | ||
|
||
if (!oid) | ||
|
@@ -1701,6 +1708,9 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, | |
flags = &unused_flags; | ||
|
||
*flags = 0; | ||
if (!failure_errno) | ||
failure_errno = &unused_errno; | ||
*failure_errno = 0; | ||
|
||
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { | ||
if (!(resolve_flags & RESOLVE_REF_ALLOW_BAD_NAME) || | ||
|
@@ -1722,11 +1732,14 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, | |
|
||
for (symref_count = 0; symref_count < SYMREF_MAXDEPTH; symref_count++) { | ||
unsigned int read_flags = 0; | ||
int read_failure = 0; | ||
|
||
if (refs_read_raw_ref(refs, refname, | ||
oid, &sb_refname, &read_flags)) { | ||
if (refs_read_raw_ref(refs, refname, oid, &sb_refname, | ||
&read_flags, &read_failure)) { | ||
*flags |= read_flags; | ||
|
||
*failure_errno = read_failure; | ||
|
||
/* In reading mode, refs must eventually resolve */ | ||
if (resolve_flags & RESOLVE_REF_READING) | ||
return NULL; | ||
|
@@ -1736,9 +1749,8 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, | |
* may show errors besides ENOENT if there are | ||
* similarly-named refs. | ||
*/ | ||
if (errno != ENOENT && | ||
errno != EISDIR && | ||
errno != ENOTDIR) | ||
if (read_failure != ENOENT && read_failure != EISDIR && | ||
read_failure != ENOTDIR) | ||
return NULL; | ||
|
||
oidclr(oid); | ||
|
@@ -1777,6 +1789,15 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, | |
return NULL; | ||
} | ||
|
||
const char *refs_resolve_ref_unsafe(struct ref_store *refs, const char *refname, | ||
int resolve_flags, struct object_id *oid, | ||
int *flags) | ||
{ | ||
int ignore = 0; | ||
return refs_resolve_ref_unsafe_with_errno(refs, refname, resolve_flags, | ||
oid, flags, &ignore); | ||
} | ||
|
||
/* backend functions */ | ||
int refs_init_db(struct strbuf *err) | ||
{ | ||
|
@@ -2238,7 +2259,8 @@ int refs_verify_refname_available(struct ref_store *refs, | |
if (skip && string_list_has_string(skip, dirname.buf)) | ||
continue; | ||
|
||
if (!refs_read_raw_ref(refs, dirname.buf, &oid, &referent, &type)) { | ||
if (!refs_read_raw_ref(refs, dirname.buf, &oid, &referent, | ||
&type, NULL)) { | ||
strbuf_addf(err, _("'%s' exists; cannot create '%s'"), | ||
dirname.buf, refname); | ||
goto cleanup; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -341,9 +341,9 @@ static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs) | |
return refs->loose; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the Git mailing list, Ævar Arnfjörð Bjarmason wrote (reply to this):
|
||
} | ||
|
||
static int files_read_raw_ref(struct ref_store *ref_store, | ||
const char *refname, struct object_id *oid, | ||
struct strbuf *referent, unsigned int *type) | ||
static int files_read_raw_ref(struct ref_store *ref_store, const char *refname, | ||
struct object_id *oid, struct strbuf *referent, | ||
unsigned int *type, int *failure_errno) | ||
{ | ||
struct files_ref_store *refs = | ||
files_downcast(ref_store, REF_STORE_READ, "read_raw_ref"); | ||
|
@@ -354,7 +354,6 @@ static int files_read_raw_ref(struct ref_store *ref_store, | |
struct stat st; | ||
int fd; | ||
int ret = -1; | ||
int save_errno; | ||
int remaining_retries = 3; | ||
|
||
*type = 0; | ||
|
@@ -384,8 +383,8 @@ static int files_read_raw_ref(struct ref_store *ref_store, | |
if (lstat(path, &st) < 0) { | ||
if (errno != ENOENT) | ||
goto out; | ||
if (refs_read_raw_ref(refs->packed_ref_store, refname, | ||
oid, referent, type)) { | ||
if (refs_read_raw_ref(refs->packed_ref_store, refname, oid, | ||
referent, type, NULL)) { | ||
errno = ENOENT; | ||
goto out; | ||
} | ||
|
@@ -424,8 +423,8 @@ static int files_read_raw_ref(struct ref_store *ref_store, | |
* 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)) { | ||
if (refs_read_raw_ref(refs->packed_ref_store, refname, oid, | ||
referent, type, NULL)) { | ||
errno = EISDIR; | ||
goto out; | ||
} | ||
|
@@ -456,18 +455,23 @@ static int files_read_raw_ref(struct ref_store *ref_store, | |
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, failure_errno); | ||
errno = *failure_errno; | ||
out: | ||
save_errno = errno; | ||
/* | ||
* Many system calls in this function can fail with ENOTDIR/EISDIR, and | ||
* we want to collect all of them, so simply copy the error out from | ||
* errno. | ||
*/ | ||
*failure_errno = errno; | ||
strbuf_release(&sb_path); | ||
strbuf_release(&sb_contents); | ||
errno = save_errno; | ||
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 +490,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; | ||
|
@@ -541,6 +545,7 @@ static int lock_raw_ref(struct files_ref_store *refs, | |
struct strbuf ref_file = STRBUF_INIT; | ||
int attempts_remaining = 3; | ||
int ret = TRANSACTION_GENERIC_ERROR; | ||
int failure_errno = 0; | ||
|
||
assert(err); | ||
files_assert_main_repository(refs, "lock_raw_ref"); | ||
|
@@ -629,9 +634,9 @@ static int lock_raw_ref(struct files_ref_store *refs, | |
* fear that its value will change. | ||
*/ | ||
|
||
if (files_read_raw_ref(&refs->base, refname, | ||
&lock->old_oid, referent, type)) { | ||
if (errno == ENOENT) { | ||
if (files_read_raw_ref(&refs->base, refname, &lock->old_oid, referent, | ||
type, &failure_errno)) { | ||
if (failure_errno == ENOENT) { | ||
if (mustexist) { | ||
/* Garden variety missing reference. */ | ||
strbuf_addf(err, "unable to resolve reference '%s'", | ||
|
@@ -655,7 +660,7 @@ static int lock_raw_ref(struct files_ref_store *refs, | |
* reference named "refs/foo/bar/baz". | ||
*/ | ||
} | ||
} else if (errno == EISDIR) { | ||
} else if (failure_errno == EISDIR) { | ||
/* | ||
* There is a directory in the way. It might have | ||
* contained references that have been deleted. If | ||
|
@@ -693,13 +698,13 @@ static int lock_raw_ref(struct files_ref_store *refs, | |
goto error_return; | ||
} | ||
} | ||
} else if (errno == EINVAL && (*type & REF_ISBROKEN)) { | ||
} else if (failure_errno == EINVAL && (*type & REF_ISBROKEN)) { | ||
strbuf_addf(err, "unable to resolve reference '%s': " | ||
"reference broken", refname); | ||
goto error_return; | ||
} else { | ||
strbuf_addf(err, "unable to resolve reference '%s': %s", | ||
refname, strerror(errno)); | ||
refname, strerror(failure_errno)); | ||
goto error_return; | ||
} | ||
|
||
|
@@ -910,7 +915,6 @@ static int create_reflock(const char *path, void *cb) | |
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the Git mailing list, Junio C Hamano wrote (reply to this):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the Git mailing list, Han-Wen Nienhuys wrote (reply to this):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the Git mailing list, Ævar Arnfjörð Bjarmason wrote (reply to this):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the Git mailing list, Han-Wen Nienhuys wrote (reply to this):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the Git mailing list, Ævar Arnfjörð Bjarmason wrote (reply to this):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the Git mailing list, Han-Wen Nienhuys wrote (reply to this):
|
||
/* | ||
* Locks a ref returning the lock on success and NULL on failure. | ||
* On failure errno is set to something meaningful. | ||
*/ | ||
static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs, | ||
const char *refname, | ||
|
@@ -922,10 +926,10 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs, | |
{ | ||
struct strbuf ref_file = STRBUF_INIT; | ||
struct ref_lock *lock; | ||
int last_errno = 0; | ||
int mustexist = (old_oid && !is_null_oid(old_oid)); | ||
int resolve_flags = RESOLVE_REF_NO_RECURSE; | ||
int resolved; | ||
int resolve_errno = 0; | ||
|
||
files_assert_main_repository(refs, "lock_ref_oid_basic"); | ||
assert(err); | ||
|
@@ -938,18 +942,18 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs, | |
resolve_flags |= RESOLVE_REF_ALLOW_BAD_NAME; | ||
|
||
files_ref_path(refs, &ref_file, refname); | ||
resolved = !!refs_resolve_ref_unsafe(&refs->base, | ||
refname, resolve_flags, | ||
&lock->old_oid, type); | ||
if (!resolved && errno == EISDIR) { | ||
resolved = !!refs_resolve_ref_unsafe_with_errno(&refs->base, refname, | ||
resolve_flags, | ||
&lock->old_oid, type, | ||
&resolve_errno); | ||
if (!resolved && resolve_errno == EISDIR) { | ||
/* | ||
* we are trying to lock foo but we used to | ||
* have foo/bar which now does not exist; | ||
* it is normal for the empty directory 'foo' | ||
* to remain. | ||
*/ | ||
if (remove_empty_directories(&ref_file)) { | ||
last_errno = errno; | ||
if (!refs_verify_refname_available( | ||
&refs->base, | ||
refname, extras, skip, err)) | ||
|
@@ -962,12 +966,14 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs, | |
&lock->old_oid, type); | ||
} | ||
if (!resolved) { | ||
last_errno = errno; | ||
if (last_errno != ENOTDIR || | ||
!refs_verify_refname_available(&refs->base, refname, | ||
extras, skip, err)) | ||
if (resolve_errno != ENOTDIR || | ||
/* in case of D/F conflict, try to generate a better error | ||
* message. If that fails, fall back to strerror(ENOTDIR). | ||
*/ | ||
!refs_verify_refname_available(&refs->base, refname, extras, | ||
skip, err)) | ||
strbuf_addf(err, "unable to resolve reference '%s': %s", | ||
refname, strerror(last_errno)); | ||
refname, strerror(resolve_errno)); | ||
|
||
goto error_return; | ||
} | ||
|
@@ -981,20 +987,17 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs, | |
if (is_null_oid(&lock->old_oid) && | ||
refs_verify_refname_available(refs->packed_ref_store, refname, | ||
extras, skip, err)) { | ||
last_errno = ENOTDIR; | ||
goto error_return; | ||
} | ||
|
||
lock->ref_name = xstrdup(refname); | ||
|
||
if (raceproof_create_file(ref_file.buf, create_reflock, &lock->lk)) { | ||
last_errno = errno; | ||
unable_to_lock_message(ref_file.buf, errno, err); | ||
goto error_return; | ||
} | ||
|
||
if (verify_lock(&refs->base, lock, old_oid, mustexist, err)) { | ||
last_errno = errno; | ||
goto error_return; | ||
} | ||
goto out; | ||
|
@@ -1005,7 +1008,6 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs, | |
|
||
out: | ||
strbuf_release(&ref_file); | ||
errno = last_errno; | ||
return lock; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Han-Wen Nienhuys wrote (reply to this):