Skip to content

Commit 1618033

Browse files
mhaggergitster
authored andcommitted
ref_transaction_verify(): new function to check a reference's value
If NULL is passed to ref_transaction_update()'s new_sha1 parameter, then just verify old_sha1 (under lock) without trying to change the new value of the reference. Use this functionality to add a new function ref_transaction_verify(), which checks the current value of the reference under lock but doesn't change it. Use ref_transaction_verify() in the implementation of "git update-ref --stdin"'s "verify" command to avoid the awkward need to "update" the reference to its existing value. Signed-off-by: Michael Haggerty <[email protected]> Reviewed-by: Stefan Beller <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 6029459 commit 1618033

File tree

3 files changed

+67
-21
lines changed

3 files changed

+67
-21
lines changed

builtin/update-ref.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,6 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
282282
{
283283
struct strbuf err = STRBUF_INIT;
284284
char *refname;
285-
unsigned char new_sha1[20];
286285
unsigned char old_sha1[20];
287286

288287
refname = parse_refname(input, &next);
@@ -293,13 +292,11 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
293292
PARSE_SHA1_OLD))
294293
hashclr(old_sha1);
295294

296-
hashcpy(new_sha1, old_sha1);
297-
298295
if (*next != line_termination)
299296
die("verify %s: extra input: %s", refname, next);
300297

301-
if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
302-
update_flags, msg, &err))
298+
if (ref_transaction_verify(transaction, refname, old_sha1,
299+
update_flags, &err))
303300
die("%s", err.buf);
304301

305302
update_flags = 0;

refs.c

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,17 @@ static unsigned char refname_disposition[256] = {
4646
*/
4747
#define REF_ISPRUNING 0x04
4848

49+
/*
50+
* Used as a flag in ref_update::flags when the reference should be
51+
* updated to new_sha1.
52+
*/
53+
#define REF_HAVE_NEW 0x08
54+
4955
/*
5056
* Used as a flag in ref_update::flags when old_sha1 should be
5157
* checked.
5258
*/
53-
#define REF_HAVE_OLD 0x08
59+
#define REF_HAVE_OLD 0x10
5460

5561
/*
5662
* Try to read one refname component from the front of refname.
@@ -3577,10 +3583,17 @@ int for_each_reflog(each_ref_fn fn, void *cb_data)
35773583
* not exist before update.
35783584
*/
35793585
struct ref_update {
3586+
/*
3587+
* If (flags & REF_HAVE_NEW), set the reference to this value:
3588+
*/
35803589
unsigned char new_sha1[20];
3590+
/*
3591+
* If (flags & REF_HAVE_OLD), check that the reference
3592+
* previously had this value:
3593+
*/
35813594
unsigned char old_sha1[20];
35823595
/*
3583-
* One or more of REF_HAVE_OLD, REF_NODEREF,
3596+
* One or more of REF_HAVE_NEW, REF_HAVE_OLD, REF_NODEREF,
35843597
* REF_DELETING, and REF_ISPRUNING:
35853598
*/
35863599
unsigned int flags;
@@ -3665,15 +3678,18 @@ int ref_transaction_update(struct ref_transaction *transaction,
36653678
if (transaction->state != REF_TRANSACTION_OPEN)
36663679
die("BUG: update called for transaction that is not open");
36673680

3668-
if (!is_null_sha1(new_sha1) &&
3681+
if (new_sha1 && !is_null_sha1(new_sha1) &&
36693682
check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
36703683
strbuf_addf(err, "refusing to update ref with bad name %s",
36713684
refname);
36723685
return -1;
36733686
}
36743687

36753688
update = add_update(transaction, refname);
3676-
hashcpy(update->new_sha1, new_sha1);
3689+
if (new_sha1) {
3690+
hashcpy(update->new_sha1, new_sha1);
3691+
flags |= REF_HAVE_NEW;
3692+
}
36773693
if (old_sha1) {
36783694
hashcpy(update->old_sha1, old_sha1);
36793695
flags |= REF_HAVE_OLD;
@@ -3709,6 +3725,19 @@ int ref_transaction_delete(struct ref_transaction *transaction,
37093725
flags, msg, err);
37103726
}
37113727

3728+
int ref_transaction_verify(struct ref_transaction *transaction,
3729+
const char *refname,
3730+
const unsigned char *old_sha1,
3731+
unsigned int flags,
3732+
struct strbuf *err)
3733+
{
3734+
if (!old_sha1)
3735+
die("BUG: verify called with old_sha1 set to NULL");
3736+
return ref_transaction_update(transaction, refname,
3737+
NULL, old_sha1,
3738+
flags, NULL, err);
3739+
}
3740+
37123741
int update_ref(const char *action, const char *refname,
37133742
const unsigned char *sha1, const unsigned char *oldval,
37143743
unsigned int flags, enum action_on_err onerr)
@@ -3797,7 +3826,7 @@ int ref_transaction_commit(struct ref_transaction *transaction,
37973826
struct ref_update *update = updates[i];
37983827
unsigned int flags = update->flags;
37993828

3800-
if (is_null_sha1(update->new_sha1))
3829+
if ((flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1))
38013830
flags |= REF_DELETING;
38023831
update->lock = lock_ref_sha1_basic(
38033832
update->refname,
@@ -3819,8 +3848,9 @@ int ref_transaction_commit(struct ref_transaction *transaction,
38193848
/* Perform updates first so live commits remain referenced */
38203849
for (i = 0; i < n; i++) {
38213850
struct ref_update *update = updates[i];
3851+
int flags = update->flags;
38223852

3823-
if (!is_null_sha1(update->new_sha1)) {
3853+
if ((flags & REF_HAVE_NEW) && !is_null_sha1(update->new_sha1)) {
38243854
if (write_ref_sha1(update->lock, update->new_sha1,
38253855
update->msg)) {
38263856
update->lock = NULL; /* freed by write_ref_sha1 */
@@ -3836,14 +3866,15 @@ int ref_transaction_commit(struct ref_transaction *transaction,
38363866
/* Perform deletes now that updates are safely completed */
38373867
for (i = 0; i < n; i++) {
38383868
struct ref_update *update = updates[i];
3869+
int flags = update->flags;
38393870

3840-
if (update->lock) {
3871+
if ((flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1)) {
38413872
if (delete_ref_loose(update->lock, update->type, err)) {
38423873
ret = TRANSACTION_GENERIC_ERROR;
38433874
goto cleanup;
38443875
}
38453876

3846-
if (!(update->flags & REF_ISPRUNING))
3877+
if (!(flags & REF_ISPRUNING))
38473878
string_list_append(&refs_to_delete,
38483879
update->lock->ref_name);
38493880
}

refs.h

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -263,14 +263,19 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);
263263
*/
264264

265265
/*
266-
* Add a reference update to transaction. new_sha1 is the value that
267-
* the reference should have after the update, or null_sha1 if it should
268-
* be deleted. If old_sha1 is non-NULL, then it is the value
269-
* that the reference should have had before the update, or null_sha1 if
270-
* it must not have existed beforehand.
271-
* Function returns 0 on success and non-zero on failure. A failure to update
272-
* means that the transaction as a whole has failed and will need to be
273-
* rolled back.
266+
* Add a reference update to transaction. new_sha1 is the value that
267+
* the reference should have after the update, or null_sha1 if it
268+
* should be deleted. If new_sha1 is NULL, then the reference is not
269+
* changed at all. old_sha1 is the value that the reference must have
270+
* before the update, or null_sha1 if it must not have existed
271+
* beforehand. The old value is checked after the lock is taken to
272+
* prevent races. If the old value doesn't agree with old_sha1, the
273+
* whole transaction fails. If old_sha1 is NULL, then the previous
274+
* value is not checked.
275+
*
276+
* Return 0 on success and non-zero on failure. Any failure in the
277+
* transaction means that the transaction as a whole has failed and
278+
* will need to be rolled back.
274279
*/
275280
int ref_transaction_update(struct ref_transaction *transaction,
276281
const char *refname,
@@ -308,6 +313,19 @@ int ref_transaction_delete(struct ref_transaction *transaction,
308313
unsigned int flags, const char *msg,
309314
struct strbuf *err);
310315

316+
/*
317+
* Verify, within a transaction, that refname has the value old_sha1,
318+
* or, if old_sha1 is null_sha1, then verify that the reference
319+
* doesn't exist. old_sha1 must be non-NULL. Function returns 0 on
320+
* success and non-zero on failure. A failure to verify means that the
321+
* transaction as a whole has failed and will need to be rolled back.
322+
*/
323+
int ref_transaction_verify(struct ref_transaction *transaction,
324+
const char *refname,
325+
const unsigned char *old_sha1,
326+
unsigned int flags,
327+
struct strbuf *err);
328+
311329
/*
312330
* Commit all of the changes that have been queued in transaction, as
313331
* atomically as possible.

0 commit comments

Comments
 (0)