delete_refs(): bail early if the packed-refs file cannot be rewritten

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>
This commit is contained in:
Michael Haggerty 2015-06-22 16:02:57 +02:00 committed by Junio C Hamano
parent 5d97861b9b
commit 7fa7dc8904

25
refs.c
View file

@ -2835,9 +2835,26 @@ int delete_refs(struct string_list *refnames)
struct strbuf err = STRBUF_INIT; struct strbuf err = STRBUF_INIT;
int i, result = 0; int i, result = 0;
if (repack_without_refs(refnames, &err)) if (!refnames->nr)
result |= error("%s", err.buf); return 0;
strbuf_release(&err);
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++) { for (i = 0; i < refnames->nr; i++) {
const char *refname = refnames->items[i].string; 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); result |= error(_("could not remove reference %s"), refname);
} }
out:
strbuf_release(&err);
return result; return result;
} }