]> git.ipfire.org Git - thirdparty/git.git/commitdiff
refs: make errno output explicit for read_raw_ref_fn
authorHan-Wen Nienhuys <hanwen@google.com>
Mon, 23 Aug 2021 11:52:40 +0000 (13:52 +0200)
committerJunio C Hamano <gitster@pobox.com>
Wed, 25 Aug 2021 20:30:26 +0000 (13:30 -0700)
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>
refs.c
refs/debug.c
refs/files-backend.c
refs/packed-backend.c
refs/refs-internal.h

diff --git a/refs.c b/refs.c
index 05944d8e72558bd783668fa0f4a5646fb404e041..da0cc82ca662b0383c58a38e8a55c94ce351f28a 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1682,7 +1682,7 @@ int refs_read_raw_ref(struct ref_store *ref_store,
        }
 
        return ref_store->be->read_raw_ref(ref_store, refname, oid, referent,
-                                          type);
+                                          type, &errno);
 }
 
 /* This function needs to return a meaningful errno on failure */
index 7793c9e1a3d3ac1bd6b6d69f83cc68c359253417..dfacf79e94bc633f898c0acfe5103de869a69103 100644 (file)
@@ -238,15 +238,14 @@ debug_ref_iterator_begin(struct ref_store *ref_store, const char *prefix,
 
 static int debug_read_raw_ref(struct ref_store *ref_store, const char *refname,
                              struct object_id *oid, struct strbuf *referent,
-                             unsigned int *type)
+                             unsigned int *type, int *failure_errno)
 {
        struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
        int res = 0;
 
        oidcpy(oid, null_oid());
-       errno = 0;
        res = drefs->refs->be->read_raw_ref(drefs->refs, refname, oid, referent,
-                                           type);
+                                           type, failure_errno);
 
        if (res == 0) {
                trace_printf_key(&trace_refs, "read_raw_ref: %s: %s (=> %s) type %x: %d\n",
@@ -254,7 +253,7 @@ static int debug_read_raw_ref(struct ref_store *ref_store, const char *refname,
        } else {
                trace_printf_key(&trace_refs,
                                 "read_raw_ref: %s: %d (errno %d)\n", refname,
-                                res, errno);
+                                res, *failure_errno);
        }
        return res;
 }
index c1794dcd295f214d3791050daff336ab0be21d5b..b3de363396912354f39c29e3d85b4bacf538882a 100644 (file)
@@ -341,9 +341,9 @@ static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs)
        return refs->loose;
 }
 
-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;
@@ -459,10 +458,9 @@ stat_ref:
        ret = parse_loose_ref_contents(buf, oid, referent, type);
 
 out:
-       save_errno = errno;
+       *failure_errno = errno;
        strbuf_release(&sb_path);
        strbuf_release(&sb_contents);
-       errno = save_errno;
        return ret;
 }
 
@@ -540,6 +538,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;
 
        assert(err);
        files_assert_main_repository(refs, "lock_raw_ref");
@@ -610,7 +609,9 @@ retry:
        if (hold_lock_file_for_update_timeout(
                            &lock->lk, ref_file.buf, LOCK_NO_DEREF,
                            get_files_ref_lock_timeout_ms()) < 0) {
-               if (errno == ENOENT && --attempts_remaining > 0) {
+               int myerr = errno;
+               errno = 0;
+               if (myerr == ENOENT && --attempts_remaining > 0) {
                        /*
                         * Maybe somebody just deleted one of the
                         * directories leading to ref_file.  Try
@@ -618,7 +619,7 @@ retry:
                         */
                        goto retry;
                } else {
-                       unable_to_lock_message(ref_file.buf, errno, err);
+                       unable_to_lock_message(ref_file.buf, myerr, err);
                        goto error_return;
                }
        }
@@ -628,9 +629,9 @@ retry:
         * 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'",
@@ -654,7 +655,7 @@ retry:
                                 *   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
@@ -692,13 +693,13 @@ retry:
                                        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;
                }
 
index 65ba4214b8dd724136bc2df5ee8f7492e924df56..47247a149178f364423f84572c5b2912772d10be 100644 (file)
@@ -724,9 +724,9 @@ static struct snapshot *get_snapshot(struct packed_ref_store *refs)
        return refs->snapshot;
 }
 
-static int packed_read_raw_ref(struct ref_store *ref_store,
-                              const char *refname, struct object_id *oid,
-                              struct strbuf *referent, unsigned int *type)
+static int packed_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 packed_ref_store *refs =
                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,
 
        if (!rec) {
                /* refname is not a packed reference. */
-               errno = ENOENT;
+               *failure_errno = ENOENT;
                return -1;
        }
 
index 1c6e5ab51d722e26b3f64cb8b58ff4d73b6b2c59..ddd6d7f8ebdc40847ba1b8608ccb7e661c22b696 100644 (file)
@@ -620,11 +620,15 @@ typedef int reflog_expire_fn(struct ref_store *ref_store,
  * properly-formatted or even safe reference name. NEITHER INPUT NOR
  * OUTPUT REFERENCE NAMES ARE VALIDATED WITHIN THIS FUNCTION.
  *
- * Return 0 on success. If the ref doesn't exist, set errno to ENOENT
- * and return -1. If the ref exists but is neither a symbolic ref nor
- * an object ID, it is broken; set REF_ISBROKEN in type, and return -1
- * (errno should not be ENOENT) If there is another error reading the
- * ref, set errno appropriately and return -1.
+ * Return 0 on success, or -1 on failure. If the ref exists but is neither a
+ * symbolic ref nor an object ID, it is broken. In this case set REF_ISBROKEN in
+ * type, and return -1 (failure_errno should not be ENOENT)
+ *
+ * failure_errno provides errno codes that are interpreted beyond error
+ * reporting. The following error codes have special meaning:
+ *    * ENOENT: the ref doesn't exist
+ *    * EISDIR: ref name is a directory
+ *    * ENOTDIR: ref prefix is not a directory
  *
  * Backend-specific flags might be set in type as well, regardless of
  * outcome.
@@ -638,9 +642,9 @@ typedef int reflog_expire_fn(struct ref_store *ref_store,
  * - in all other cases, referent will be untouched, and therefore
  *   refname will still be valid and unchanged.
  */
-typedef int read_raw_ref_fn(struct ref_store *ref_store,
-                           const char *refname, struct object_id *oid,
-                           struct strbuf *referent, unsigned int *type);
+typedef int read_raw_ref_fn(struct ref_store *ref_store, const char *refname,
+                           struct object_id *oid, struct strbuf *referent,
+                           unsigned int *type, int *failure_errno);
 
 struct ref_storage_be {
        struct ref_storage_be *next;