delete_refs(): bail early if the packed-refs file cannot be rewritten
authorMichael Haggerty <mhagger@alum.mit.edu>
Mon, 22 Jun 2015 14:02:57 +0000 (16:02 +0200)
committerJunio C Hamano <gitster@pobox.com>
Mon, 22 Jun 2015 20:17:10 +0000 (13:17 -0700)
If we fail to delete the doomed references from the packed-refs file,
then it is unsafe to delete their loose references, because doing so
might expose a value from the packed-refs file that is obsolete and
perhaps even points at an object that has been garbage collected.

So if repack_without_refs() fails, emit a more explicit error message
and bail.

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
refs.c
diff --git a/refs.c b/refs.c
index cebabc5cd4bce8615487f512f73db704c7b1b9fb..e40989431fc6c5adaaf23de59dedc65e62306470 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -2835,9 +2835,26 @@ int delete_refs(struct string_list *refnames)
        struct strbuf err = STRBUF_INIT;
        int i, result = 0;
 
-       if (repack_without_refs(refnames, &err))
-               result |= error("%s", err.buf);
-       strbuf_release(&err);
+       if (!refnames->nr)
+               return 0;
+
+       result = repack_without_refs(refnames, &err);
+       if (result) {
+               /*
+                * If we failed to rewrite the packed-refs file, then
+                * it is unsafe to try to remove loose refs, because
+                * doing so might expose an obsolete packed value for
+                * a reference that might even point at an object that
+                * has been garbage collected.
+                */
+               if (refnames->nr == 1)
+                       error(_("could not delete reference %s: %s"),
+                             refnames->items[0].string, err.buf);
+               else
+                       error(_("could not delete references: %s"), err.buf);
+
+               goto out;
+       }
 
        for (i = 0; i < refnames->nr; i++) {
                const char *refname = refnames->items[i].string;
@@ -2846,6 +2863,8 @@ int delete_refs(struct string_list *refnames)
                        result |= error(_("could not remove reference %s"), refname);
        }
 
+out:
+       strbuf_release(&err);
        return result;
 }