Skip to content

Commit 5b12e16

Browse files
hanwengitster
authored andcommitted
refs: make errno output explicit for read_raw_ref_fn
This makes it explicit how alternative ref backends should report errors in read_raw_ref_fn. read_raw_ref_fn needs to supply a credible errno for a number of cases. These are primarily: 1) The files backend calls read_raw_ref from lock_raw_ref, and uses the resulting error codes to create/remove directories as needed. 2) ENOENT should be translated in a zero OID, optionally with REF_ISBROKEN set, returning the last successfully resolved symref. This is necessary so read_raw_ref("HEAD") on an empty repo returns refs/heads/main (or the default branch du-jour), and we know on which branch to create the first commit. Make this information flow explicit by adding a failure_errno to the signature of read_raw_ref. All errnos from the files backend are still propagated unchanged, even though inspection suggests only ENOTDIR, EISDIR and ENOENT are relevant. Signed-off-by: Han-Wen Nienhuys <hanwen@google.com> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 1ae6ed2 commit 5b12e16

File tree

5 files changed

+35
-31
lines changed

5 files changed

+35
-31
lines changed

refs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1682,7 +1682,7 @@ int refs_read_raw_ref(struct ref_store *ref_store,
16821682
}
16831683

16841684
return ref_store->be->read_raw_ref(ref_store, refname, oid, referent,
1685-
type);
1685+
type, &errno);
16861686
}
16871687

16881688
/* This function needs to return a meaningful errno on failure */

refs/debug.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,23 +238,22 @@ debug_ref_iterator_begin(struct ref_store *ref_store, const char *prefix,
238238

239239
static int debug_read_raw_ref(struct ref_store *ref_store, const char *refname,
240240
struct object_id *oid, struct strbuf *referent,
241-
unsigned int *type)
241+
unsigned int *type, int *failure_errno)
242242
{
243243
struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
244244
int res = 0;
245245

246246
oidcpy(oid, null_oid());
247-
errno = 0;
248247
res = drefs->refs->be->read_raw_ref(drefs->refs, refname, oid, referent,
249-
type);
248+
type, failure_errno);
250249

251250
if (res == 0) {
252251
trace_printf_key(&trace_refs, "read_raw_ref: %s: %s (=> %s) type %x: %d\n",
253252
refname, oid_to_hex(oid), referent->buf, *type, res);
254253
} else {
255254
trace_printf_key(&trace_refs,
256255
"read_raw_ref: %s: %d (errno %d)\n", refname,
257-
res, errno);
256+
res, *failure_errno);
258257
}
259258
return res;
260259
}

refs/files-backend.c

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -341,9 +341,9 @@ static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs)
341341
return refs->loose;
342342
}
343343

344-
static int files_read_raw_ref(struct ref_store *ref_store,
345-
const char *refname, struct object_id *oid,
346-
struct strbuf *referent, unsigned int *type)
344+
static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
345+
struct object_id *oid, struct strbuf *referent,
346+
unsigned int *type, int *failure_errno)
347347
{
348348
struct files_ref_store *refs =
349349
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,
354354
struct stat st;
355355
int fd;
356356
int ret = -1;
357-
int save_errno;
358357
int remaining_retries = 3;
359358

360359
*type = 0;
@@ -459,10 +458,9 @@ static int files_read_raw_ref(struct ref_store *ref_store,
459458
ret = parse_loose_ref_contents(buf, oid, referent, type);
460459

461460
out:
462-
save_errno = errno;
461+
*failure_errno = errno;
463462
strbuf_release(&sb_path);
464463
strbuf_release(&sb_contents);
465-
errno = save_errno;
466464
return ret;
467465
}
468466

@@ -540,6 +538,7 @@ static int lock_raw_ref(struct files_ref_store *refs,
540538
struct strbuf ref_file = STRBUF_INIT;
541539
int attempts_remaining = 3;
542540
int ret = TRANSACTION_GENERIC_ERROR;
541+
int failure_errno;
543542

544543
assert(err);
545544
files_assert_main_repository(refs, "lock_raw_ref");
@@ -610,15 +609,17 @@ static int lock_raw_ref(struct files_ref_store *refs,
610609
if (hold_lock_file_for_update_timeout(
611610
&lock->lk, ref_file.buf, LOCK_NO_DEREF,
612611
get_files_ref_lock_timeout_ms()) < 0) {
613-
if (errno == ENOENT && --attempts_remaining > 0) {
612+
int myerr = errno;
613+
errno = 0;
614+
if (myerr == ENOENT && --attempts_remaining > 0) {
614615
/*
615616
* Maybe somebody just deleted one of the
616617
* directories leading to ref_file. Try
617618
* again:
618619
*/
619620
goto retry;
620621
} else {
621-
unable_to_lock_message(ref_file.buf, errno, err);
622+
unable_to_lock_message(ref_file.buf, myerr, err);
622623
goto error_return;
623624
}
624625
}
@@ -628,9 +629,9 @@ static int lock_raw_ref(struct files_ref_store *refs,
628629
* fear that its value will change.
629630
*/
630631

631-
if (files_read_raw_ref(&refs->base, refname,
632-
&lock->old_oid, referent, type)) {
633-
if (errno == ENOENT) {
632+
if (files_read_raw_ref(&refs->base, refname, &lock->old_oid, referent,
633+
type, &failure_errno)) {
634+
if (failure_errno == ENOENT) {
634635
if (mustexist) {
635636
/* Garden variety missing reference. */
636637
strbuf_addf(err, "unable to resolve reference '%s'",
@@ -654,7 +655,7 @@ static int lock_raw_ref(struct files_ref_store *refs,
654655
* reference named "refs/foo/bar/baz".
655656
*/
656657
}
657-
} else if (errno == EISDIR) {
658+
} else if (failure_errno == EISDIR) {
658659
/*
659660
* There is a directory in the way. It might have
660661
* contained references that have been deleted. If
@@ -692,13 +693,13 @@ static int lock_raw_ref(struct files_ref_store *refs,
692693
goto error_return;
693694
}
694695
}
695-
} else if (errno == EINVAL && (*type & REF_ISBROKEN)) {
696+
} else if (failure_errno == EINVAL && (*type & REF_ISBROKEN)) {
696697
strbuf_addf(err, "unable to resolve reference '%s': "
697698
"reference broken", refname);
698699
goto error_return;
699700
} else {
700701
strbuf_addf(err, "unable to resolve reference '%s': %s",
701-
refname, strerror(errno));
702+
refname, strerror(failure_errno));
702703
goto error_return;
703704
}
704705

refs/packed-backend.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -724,9 +724,9 @@ static struct snapshot *get_snapshot(struct packed_ref_store *refs)
724724
return refs->snapshot;
725725
}
726726

727-
static int packed_read_raw_ref(struct ref_store *ref_store,
728-
const char *refname, struct object_id *oid,
729-
struct strbuf *referent, unsigned int *type)
727+
static int packed_read_raw_ref(struct ref_store *ref_store, const char *refname,
728+
struct object_id *oid, struct strbuf *referent,
729+
unsigned int *type, int *failure_errno)
730730
{
731731
struct packed_ref_store *refs =
732732
packed_downcast(ref_store, REF_STORE_READ, "read_raw_ref");
@@ -739,7 +739,7 @@ static int packed_read_raw_ref(struct ref_store *ref_store,
739739

740740
if (!rec) {
741741
/* refname is not a packed reference. */
742-
errno = ENOENT;
742+
*failure_errno = ENOENT;
743743
return -1;
744744
}
745745

refs/refs-internal.h

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -620,11 +620,15 @@ typedef int reflog_expire_fn(struct ref_store *ref_store,
620620
* properly-formatted or even safe reference name. NEITHER INPUT NOR
621621
* OUTPUT REFERENCE NAMES ARE VALIDATED WITHIN THIS FUNCTION.
622622
*
623-
* Return 0 on success. If the ref doesn't exist, set errno to ENOENT
624-
* and return -1. If the ref exists but is neither a symbolic ref nor
625-
* an object ID, it is broken; set REF_ISBROKEN in type, and return -1
626-
* (errno should not be ENOENT) If there is another error reading the
627-
* ref, set errno appropriately and return -1.
623+
* Return 0 on success, or -1 on failure. If the ref exists but is neither a
624+
* symbolic ref nor an object ID, it is broken. In this case set REF_ISBROKEN in
625+
* type, and return -1 (failure_errno should not be ENOENT)
626+
*
627+
* failure_errno provides errno codes that are interpreted beyond error
628+
* reporting. The following error codes have special meaning:
629+
* * ENOENT: the ref doesn't exist
630+
* * EISDIR: ref name is a directory
631+
* * ENOTDIR: ref prefix is not a directory
628632
*
629633
* Backend-specific flags might be set in type as well, regardless of
630634
* outcome.
@@ -638,9 +642,9 @@ typedef int reflog_expire_fn(struct ref_store *ref_store,
638642
* - in all other cases, referent will be untouched, and therefore
639643
* refname will still be valid and unchanged.
640644
*/
641-
typedef int read_raw_ref_fn(struct ref_store *ref_store,
642-
const char *refname, struct object_id *oid,
643-
struct strbuf *referent, unsigned int *type);
645+
typedef int read_raw_ref_fn(struct ref_store *ref_store, const char *refname,
646+
struct object_id *oid, struct strbuf *referent,
647+
unsigned int *type, int *failure_errno);
644648

645649
struct ref_storage_be {
646650
struct ref_storage_be *next;

0 commit comments

Comments
 (0)