refs: introduce enum-based transaction error types
Replace preprocessor-defined transaction errors with a strongly-typed enum `ref_transaction_error`. This change: - Improves type safety and function signature clarity. - Makes error handling more explicit and discoverable. - Maintains existing error cases, while adding new error cases for common scenarios. This refactoring paves the way for more comprehensive error handling which we will utilize in the upcoming commits to add batch reference update support. Signed-off-by: Karthik Nayak <karthik.188@gmail.com> Acked-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Karthik Nayak committed
Apr 8, 2025 at 10:51 UTC
76e760b99923cb9afb52ef08607f736ff3eeaad7
7 files changed
+207
-186
builtin/fetch.c
+1
-1
@@ -687,7 +687,7 @@ static int s_update_ref(const char *action,
687
switch (ref_transaction_commit(our_transaction, &err)) {
688
case 0:
689
break;
690
- case TRANSACTION_NAME_CONFLICT:
690
+ case REF_TRANSACTION_ERROR_NAME_CONFLICT:
691
ret = STORE_REF_ERROR_DF_CONFLICT;
692
goto out;
693
default:
refs.c
+26
-23
@@ -2271,7 +2271,7 @@ int refs_update_symref_extended(struct ref_store *refs, const char *ref,
2271
REF_NO_DEREF, logmsg, &err))
2272
goto error_return;
2273
prepret = ref_transaction_prepare(transaction, &err);
2274
- if (prepret && prepret != TRANSACTION_CREATE_EXISTS)
2274
+ if (prepret && prepret != REF_TRANSACTION_ERROR_CREATE_EXISTS)
2275
goto error_return;
2276
} else {
2277
if (ref_transaction_update(transaction, ref, NULL, NULL,
@@ -2289,7 +2289,7 @@ int refs_update_symref_extended(struct ref_store *refs, const char *ref,
2289
}
2290
}
2291
2292
- if (prepret == TRANSACTION_CREATE_EXISTS)
2292
+ if (prepret == REF_TRANSACTION_ERROR_CREATE_EXISTS)
2293
goto cleanup;
2294
2295
if (ref_transaction_commit(transaction, &err))
@@ -2425,7 +2425,7 @@ int ref_transaction_prepare(struct ref_transaction *transaction,
2425
2426
string_list_sort(&transaction->refnames);
2427
if (ref_update_reject_duplicates(&transaction->refnames, err))
2428
- return TRANSACTION_GENERIC_ERROR;
2428
+ return REF_TRANSACTION_ERROR_GENERIC;
2429
2430
ret = refs->be->transaction_prepare(refs, transaction, err);
2431
if (ret)
@@ -2497,19 +2497,19 @@ int ref_transaction_commit(struct ref_transaction *transaction,
2497
return ret;
2498
}
2499
2500
-int refs_verify_refnames_available(struct ref_store *refs,
2501
- const struct string_list *refnames,
2502
- const struct string_list *extras,
2503
- const struct string_list *skip,
2504
- unsigned int initial_transaction,
2505
- struct strbuf *err)
2500
+enum ref_transaction_error refs_verify_refnames_available(struct ref_store *refs,
2501
+ const struct string_list *refnames,
2502
+ const struct string_list *extras,
2503
+ const struct string_list *skip,
2504
+ unsigned int initial_transaction,
2505
+ struct strbuf *err)
2506
{
2507
struct strbuf dirname = STRBUF_INIT;
2508
struct strbuf referent = STRBUF_INIT;
2509
struct string_list_item *item;
2510
struct ref_iterator *iter = NULL;
2511
struct strset dirnames;
2512
- int ret = -1;
2512
+ int ret = REF_TRANSACTION_ERROR_NAME_CONFLICT;
2513
2514
/*
2515
* For the sake of comments in this function, suppose that
@@ -2625,12 +2625,13 @@ cleanup:
2625
return ret;
2626
}
2627
2628
-int refs_verify_refname_available(struct ref_store *refs,
2629
- const char *refname,
2630
- const struct string_list *extras,
2631
- const struct string_list *skip,
2632
- unsigned int initial_transaction,
2633
- struct strbuf *err)
2628
+enum ref_transaction_error refs_verify_refname_available(
2629
+ struct ref_store *refs,
2630
+ const char *refname,
2631
+ const struct string_list *extras,
2632
+ const struct string_list *skip,
2633
+ unsigned int initial_transaction,
2634
+ struct strbuf *err)
2635
{
2636
struct string_list_item item = { .string = (char *) refname };
2637
struct string_list refnames = {
@@ -2818,8 +2819,9 @@ int ref_update_has_null_new_value(struct ref_update *update)
2819
return !update->new_target && is_null_oid(&update->new_oid);
2820
}
2821
2821
-int ref_update_check_old_target(const char *referent, struct ref_update *update,
2822
- struct strbuf *err)
2822
+enum ref_transaction_error ref_update_check_old_target(const char *referent,
2823
+ struct ref_update *update,
2824
+ struct strbuf *err)
2825
{
2826
if (!update->old_target)
2827
BUG("called without old_target set");
@@ -2827,17 +2829,18 @@ int ref_update_check_old_target(const char *referent, struct ref_update *update,
2829
if (!strcmp(referent, update->old_target))
2830
return 0;
2831
2830
- if (!strcmp(referent, ""))
2832
+ if (!strcmp(referent, "")) {
2833
strbuf_addf(err, "verifying symref target: '%s': "
2834
"reference is missing but expected %s",
2835
ref_update_original_update_refname(update),
2836
update->old_target);
2835
- else
2836
- strbuf_addf(err, "verifying symref target: '%s': "
2837
- "is at %s but expected %s",
2837
+ return REF_TRANSACTION_ERROR_NONEXISTENT_REF;
2838
+ }
2839
+
2840
+ strbuf_addf(err, "verifying symref target: '%s': is at %s but expected %s",
2841
ref_update_original_update_refname(update),
2842
referent, update->old_target);
2840
- return -1;
2843
+ return REF_TRANSACTION_ERROR_INCORRECT_OLD_VALUE;
2844
}
2845
2846
struct migration_data {
refs.h
+29
-19
@@ -16,6 +16,23 @@ struct worktree;
16
enum ref_storage_format ref_storage_format_by_name(const char *name);
17
const char *ref_storage_format_to_name(enum ref_storage_format ref_storage_format);
18
19
+enum ref_transaction_error {
20
+ /* Default error code */
21
+ REF_TRANSACTION_ERROR_GENERIC = -1,
22
+ /* Ref name conflict like A vs A/B */
23
+ REF_TRANSACTION_ERROR_NAME_CONFLICT = -2,
24
+ /* Ref to be created already exists */
25
+ REF_TRANSACTION_ERROR_CREATE_EXISTS = -3,
26
+ /* ref expected but doesn't exist */
27
+ REF_TRANSACTION_ERROR_NONEXISTENT_REF = -4,
28
+ /* Provided old_oid or old_target of reference doesn't match actual */
29
+ REF_TRANSACTION_ERROR_INCORRECT_OLD_VALUE = -5,
30
+ /* Provided new_oid or new_target is invalid */
31
+ REF_TRANSACTION_ERROR_INVALID_NEW_VALUE = -6,
32
+ /* Expected ref to be symref, but is a regular ref */
33
+ REF_TRANSACTION_ERROR_EXPECTED_SYMREF = -7,
34
+};
35
+
36
/*
37
* Resolve a reference, recursively following symbolic references.
38
*
@@ -117,24 +134,24 @@ int refs_read_symbolic_ref(struct ref_store *ref_store, const char *refname,
134
*
135
* extras and skip must be sorted.
136
*/
120
-int refs_verify_refname_available(struct ref_store *refs,
121
- const char *refname,
122
- const struct string_list *extras,
123
- const struct string_list *skip,
124
- unsigned int initial_transaction,
125
- struct strbuf *err);
137
+enum ref_transaction_error refs_verify_refname_available(struct ref_store *refs,
138
+ const char *refname,
139
+ const struct string_list *extras,
140
+ const struct string_list *skip,
141
+ unsigned int initial_transaction,
142
+ struct strbuf *err);
143
144
/*
145
* Same as `refs_verify_refname_available()`, but checking for a list of
146
* refnames instead of only a single item. This is more efficient in the case
147
* where one needs to check multiple refnames.
148
*/
132
-int refs_verify_refnames_available(struct ref_store *refs,
133
- const struct string_list *refnames,
134
- const struct string_list *extras,
135
- const struct string_list *skip,
136
- unsigned int initial_transaction,
137
- struct strbuf *err);
149
+enum ref_transaction_error refs_verify_refnames_available(struct ref_store *refs,
150
+ const struct string_list *refnames,
151
+ const struct string_list *extras,
152
+ const struct string_list *skip,
153
+ unsigned int initial_transaction,
154
+ struct strbuf *err);
155
156
int refs_ref_exists(struct ref_store *refs, const char *refname);
157
@@ -830,13 +847,6 @@ int ref_transaction_verify(struct ref_transaction *transaction,
847
unsigned int flags,
848
struct strbuf *err);
849
833
-/* Naming conflict (for example, the ref names A and A/B conflict). */
834
-#define TRANSACTION_NAME_CONFLICT -1
835
-/* When only creation was requested, but the ref already exists. */
836
-#define TRANSACTION_CREATE_EXISTS -2
837
-/* All other errors. */
838
-#define TRANSACTION_GENERIC_ERROR -3
839
-
850
/*
851
* Perform the preparatory stages of committing `transaction`. Acquire
852
* any needed locks, check preconditions, etc.; basically, do as much
refs/files-backend.c
+102
-100
@@ -663,7 +663,7 @@ static void unlock_ref(struct ref_lock *lock)
663
* broken, lock the reference anyway but clear old_oid.
664
*
665
* Return 0 on success. On failure, write an error message to err and
666
- * return TRANSACTION_NAME_CONFLICT or TRANSACTION_GENERIC_ERROR.
666
+ * return REF_TRANSACTION_ERROR_NAME_CONFLICT or REF_TRANSACTION_ERROR_GENERIC.
667
*
668
* Implementation note: This function is basically
669
*
@@ -676,19 +676,20 @@ static void unlock_ref(struct ref_lock *lock)
676
* avoided, namely if we were successfully able to read the ref
677
* - Generate informative error messages in the case of failure
678
*/
679
-static int lock_raw_ref(struct files_ref_store *refs,
680
- const char *refname, int mustexist,
681
- struct string_list *refnames_to_check,
682
- const struct string_list *extras,
683
- struct ref_lock **lock_p,
684
- struct strbuf *referent,
685
- unsigned int *type,
686
- struct strbuf *err)
687
-{
679
+static enum ref_transaction_error lock_raw_ref(struct files_ref_store *refs,
680
+ const char *refname,
681
+ int mustexist,
682
+ struct string_list *refnames_to_check,
683
+ const struct string_list *extras,
684
+ struct ref_lock **lock_p,
685
+ struct strbuf *referent,
686
+ unsigned int *type,
687
+ struct strbuf *err)
688
+{
689
+ enum ref_transaction_error ret = REF_TRANSACTION_ERROR_GENERIC;
690
struct ref_lock *lock;
691
struct strbuf ref_file = STRBUF_INIT;
692
int attempts_remaining = 3;
691
- int ret = TRANSACTION_GENERIC_ERROR;
693
int failure_errno;
694
695
assert(err);
@@ -728,13 +729,14 @@ retry:
729
strbuf_reset(err);
730
strbuf_addf(err, "unable to resolve reference '%s'",
731
refname);
732
+ ret = REF_TRANSACTION_ERROR_NONEXISTENT_REF;
733
} else {
734
/*
735
* The error message set by
736
* refs_verify_refname_available() is
737
* OK.
738
*/
737
- ret = TRANSACTION_NAME_CONFLICT;
739
+ ret = REF_TRANSACTION_ERROR_NAME_CONFLICT;
740
}
741
} else {
742
/*
@@ -788,6 +790,7 @@ retry:
790
/* Garden variety missing reference. */
791
strbuf_addf(err, "unable to resolve reference '%s'",
792
refname);
793
+ ret = REF_TRANSACTION_ERROR_NONEXISTENT_REF;
794
goto error_return;
795
} else {
796
/*
@@ -820,6 +823,7 @@ retry:
823
/* Garden variety missing reference. */
824
strbuf_addf(err, "unable to resolve reference '%s'",
825
refname);
826
+ ret = REF_TRANSACTION_ERROR_NONEXISTENT_REF;
827
goto error_return;
828
} else if (remove_dir_recursively(&ref_file,
829
REMOVE_DIR_EMPTY_ONLY)) {
@@ -830,7 +834,7 @@ retry:
834
* The error message set by
835
* verify_refname_available() is OK.
836
*/
833
- ret = TRANSACTION_NAME_CONFLICT;
837
+ ret = REF_TRANSACTION_ERROR_NAME_CONFLICT;
838
goto error_return;
839
} else {
840
/*
@@ -1517,10 +1521,11 @@ static int rename_tmp_log(struct files_ref_store *refs, const char *newrefname)
1521
return ret;
1522
}
1523
1520
-static int write_ref_to_lockfile(struct files_ref_store *refs,
1521
- struct ref_lock *lock,
1522
- const struct object_id *oid,
1523
- int skip_oid_verification, struct strbuf *err);
1524
+static enum ref_transaction_error write_ref_to_lockfile(struct files_ref_store *refs,
1525
+ struct ref_lock *lock,
1526
+ const struct object_id *oid,
1527
+ int skip_oid_verification,
1528
+ struct strbuf *err);
1529
static int commit_ref_update(struct files_ref_store *refs,
1530
struct ref_lock *lock,
1531
const struct object_id *oid, const char *logmsg,
@@ -1926,10 +1931,11 @@ static int files_log_ref_write(struct files_ref_store *refs,
1931
* Write oid into the open lockfile, then close the lockfile. On
1932
* errors, rollback the lockfile, fill in *err and return -1.
1933
*/
1929
-static int write_ref_to_lockfile(struct files_ref_store *refs,
1930
- struct ref_lock *lock,
1931
- const struct object_id *oid,
1932
- int skip_oid_verification, struct strbuf *err)
1934
+static enum ref_transaction_error write_ref_to_lockfile(struct files_ref_store *refs,
1935
+ struct ref_lock *lock,
1936
+ const struct object_id *oid,
1937
+ int skip_oid_verification,
1938
+ struct strbuf *err)
1939
{
1940
static char term = '\n';
1941
struct object *o;
@@ -1943,7 +1949,7 @@ static int write_ref_to_lockfile(struct files_ref_store *refs,
1949
"trying to write ref '%s' with nonexistent object %s",
1950
lock->ref_name, oid_to_hex(oid));
1951
unlock_ref(lock);
1946
- return -1;
1952
+ return REF_TRANSACTION_ERROR_INVALID_NEW_VALUE;
1953
}
1954
if (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {
1955
strbuf_addf(
@@ -1951,7 +1957,7 @@ static int write_ref_to_lockfile(struct files_ref_store *refs,
1957
"trying to write non-commit object %s to branch '%s'",
1958
oid_to_hex(oid), lock->ref_name);
1959
unlock_ref(lock);
1954
- return -1;
1960
+ return REF_TRANSACTION_ERROR_INVALID_NEW_VALUE;
1961
}
1962
}
1963
fd = get_lock_file_fd(&lock->lk);
@@ -1962,7 +1968,7 @@ static int write_ref_to_lockfile(struct files_ref_store *refs,
1968
strbuf_addf(err,
1969
"couldn't write '%s'", get_lock_file_path(&lock->lk));
1970
unlock_ref(lock);
1965
- return -1;
1971
+ return REF_TRANSACTION_ERROR_GENERIC;
1972
}
1973
return 0;
1974
}
@@ -2376,9 +2382,10 @@ static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_st
2382
* If update is a direct update of head_ref (the reference pointed to
2383
* by HEAD), then add an extra REF_LOG_ONLY update for HEAD.
2384
*/
2379
-static int split_head_update(struct ref_update *update,
2380
- struct ref_transaction *transaction,
2381
- const char *head_ref, struct strbuf *err)
2385
+static enum ref_transaction_error split_head_update(struct ref_update *update,
2386
+ struct ref_transaction *transaction,
2387
+ const char *head_ref,
2388
+ struct strbuf *err)
2389
{
2390
struct ref_update *new_update;
2391
@@ -2402,7 +2409,7 @@ static int split_head_update(struct ref_update *update,
2409
"multiple updates for 'HEAD' (including one "
2410
"via its referent '%s') are not allowed",
2411
update->refname);
2405
- return TRANSACTION_NAME_CONFLICT;
2412
+ return REF_TRANSACTION_ERROR_NAME_CONFLICT;
2413
}
2414
2415
new_update = ref_transaction_add_update(
@@ -2430,10 +2437,10 @@ static int split_head_update(struct ref_update *update,
2437
* Note that the new update will itself be subject to splitting when
2438
* the iteration gets to it.
2439
*/
2433
-static int split_symref_update(struct ref_update *update,
2434
- const char *referent,
2435
- struct ref_transaction *transaction,
2436
- struct strbuf *err)
2440
+static enum ref_transaction_error split_symref_update(struct ref_update *update,
2441
+ const char *referent,
2442
+ struct ref_transaction *transaction,
2443
+ struct strbuf *err)
2444
{
2445
struct ref_update *new_update;
2446
unsigned int new_flags;
@@ -2450,7 +2457,7 @@ static int split_symref_update(struct ref_update *update,
2457
"multiple updates for '%s' (including one "
2458
"via symref '%s') are not allowed",
2459
referent, update->refname);
2453
- return TRANSACTION_NAME_CONFLICT;
2460
+ return REF_TRANSACTION_ERROR_NAME_CONFLICT;
2461
}
2462
2463
new_flags = update->flags;
@@ -2491,11 +2498,10 @@ static int split_symref_update(struct ref_update *update,
2498
* everything is OK, return 0; otherwise, write an error message to
2499
* err and return -1.
2500
*/
2494
-static int check_old_oid(struct ref_update *update, struct object_id *oid,
2495
- struct strbuf *err)
2501
+static enum ref_transaction_error check_old_oid(struct ref_update *update,
2502
+ struct object_id *oid,
2503
+ struct strbuf *err)
2504
{
2497
- int ret = TRANSACTION_GENERIC_ERROR;
2498
-
2505
if (!(update->flags & REF_HAVE_OLD) ||
2506
oideq(oid, &update->old_oid))
2507
return 0;
@@ -2504,21 +2510,20 @@ static int check_old_oid(struct ref_update *update, struct object_id *oid,
2510
strbuf_addf(err, "cannot lock ref '%s': "
2511
"reference already exists",
2512
ref_update_original_update_refname(update));
2507
- ret = TRANSACTION_CREATE_EXISTS;
2508
- }
2509
- else if (is_null_oid(oid))
2513
+ return REF_TRANSACTION_ERROR_CREATE_EXISTS;
2514
+ } else if (is_null_oid(oid)) {
2515
strbuf_addf(err, "cannot lock ref '%s': "
2516
"reference is missing but expected %s",
2517
ref_update_original_update_refname(update),
2518
oid_to_hex(&update->old_oid));
2514
- else
2515
- strbuf_addf(err, "cannot lock ref '%s': "
2516
- "is at %s but expected %s",
2517
- ref_update_original_update_refname(update),
2518
- oid_to_hex(oid),
2519
- oid_to_hex(&update->old_oid));
2519
+ return REF_TRANSACTION_ERROR_NONEXISTENT_REF;
2520
+ }
2521
2521
- return ret;
2522
+ strbuf_addf(err, "cannot lock ref '%s': is at %s but expected %s",
2523
+ ref_update_original_update_refname(update), oid_to_hex(oid),
2524
+ oid_to_hex(&update->old_oid));
2525
+
2526
+ return REF_TRANSACTION_ERROR_INCORRECT_OLD_VALUE;
2527
}
2528
2529
struct files_transaction_backend_data {
@@ -2540,17 +2545,17 @@ struct files_transaction_backend_data {
2545
* - If it is an update of head_ref, add a corresponding REF_LOG_ONLY
2546
* update of HEAD.
2547
*/
2543
-static int lock_ref_for_update(struct files_ref_store *refs,
2544
- struct ref_update *update,
2545
- struct ref_transaction *transaction,
2546
- const char *head_ref,
2547
- struct string_list *refnames_to_check,
2548
- struct strbuf *err)
2548
+static enum ref_transaction_error lock_ref_for_update(struct files_ref_store *refs,
2549
+ struct ref_update *update,
2550
+ struct ref_transaction *transaction,
2551
+ const char *head_ref,
2552
+ struct string_list *refnames_to_check,
2553
+ struct strbuf *err)
2554
{
2555
struct strbuf referent = STRBUF_INIT;
2556
int mustexist = ref_update_expects_existing_old_ref(update);
2557
struct files_transaction_backend_data *backend_data;
2553
- int ret = 0;
2558
+ enum ref_transaction_error ret = 0;
2559
struct ref_lock *lock;
2560
2561
files_assert_main_repository(refs, "lock_ref_for_update");
@@ -2602,22 +2607,17 @@ static int lock_ref_for_update(struct files_ref_store *refs,
2607
strbuf_addf(err, "cannot lock ref '%s': "
2608
"error reading reference",
2609
ref_update_original_update_refname(update));
2605
- ret = TRANSACTION_GENERIC_ERROR;
2610
+ ret = REF_TRANSACTION_ERROR_GENERIC;
2611
goto out;
2612
}
2613
}
2614
2610
- if (update->old_target) {
2611
- if (ref_update_check_old_target(referent.buf, update, err)) {
2612
- ret = TRANSACTION_GENERIC_ERROR;
2613
- goto out;
2614
- }
2615
- } else {
2615
+ if (update->old_target)
2616
+ ret = ref_update_check_old_target(referent.buf, update, err);
2617
+ else
2618
ret = check_old_oid(update, &lock->old_oid, err);
2617
- if (ret) {
2618
- goto out;
2619
- }
2620
- }
2619
+ if (ret)
2620
+ goto out;
2621
} else {
2622
/*
2623
* Create a new update for the reference this
@@ -2644,7 +2644,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
2644
"but is a regular ref"),
2645
ref_update_original_update_refname(update),
2646
update->old_target);
2647
- ret = TRANSACTION_GENERIC_ERROR;
2647
+ ret = REF_TRANSACTION_ERROR_EXPECTED_SYMREF;
2648
goto out;
2649
} else {
2650
ret = check_old_oid(update, &lock->old_oid, err);
@@ -2668,14 +2668,14 @@ static int lock_ref_for_update(struct files_ref_store *refs,
2668
2669
if (update->new_target && !(update->flags & REF_LOG_ONLY)) {
2670
if (create_symref_lock(lock, update->new_target, err)) {
2671
- ret = TRANSACTION_GENERIC_ERROR;
2671
+ ret = REF_TRANSACTION_ERROR_GENERIC;
2672
goto out;
2673
}
2674
2675
if (close_ref_gently(lock)) {
2676
strbuf_addf(err, "couldn't close '%s.lock'",
2677
update->refname);
2678
- ret = TRANSACTION_GENERIC_ERROR;
2678
+ ret = REF_TRANSACTION_ERROR_GENERIC;
2679
goto out;
2680
}
2681
@@ -2693,25 +2693,27 @@ static int lock_ref_for_update(struct files_ref_store *refs,
2693
* The reference already has the desired
2694
* value, so we don't need to write it.
2695
*/
2696
- } else if (write_ref_to_lockfile(
2697
- refs, lock, &update->new_oid,
2698
- update->flags & REF_SKIP_OID_VERIFICATION,
2699
- err)) {
2700
- char *write_err = strbuf_detach(err, NULL);
2701
-
2702
- /*
2703
- * The lock was freed upon failure of
2704
- * write_ref_to_lockfile():
2705
- */
2706
- update->backend_data = NULL;
2707
- strbuf_addf(err,
2708
- "cannot update ref '%s': %s",
2709
- update->refname, write_err);
2710
- free(write_err);
2711
- ret = TRANSACTION_GENERIC_ERROR;
2712
- goto out;
2696
} else {
2714
- update->flags |= REF_NEEDS_COMMIT;
2697
+ ret = write_ref_to_lockfile(
2698
+ refs, lock, &update->new_oid,
2699
+ update->flags & REF_SKIP_OID_VERIFICATION,
2700
+ err);
2701
+ if (ret) {
2702
+ char *write_err = strbuf_detach(err, NULL);
2703
+
2704
+ /*
2705
+ * The lock was freed upon failure of
2706
+ * write_ref_to_lockfile():
2707
+ */
2708
+ update->backend_data = NULL;
2709
+ strbuf_addf(err,
2710
+ "cannot update ref '%s': %s",
2711
+ update->refname, write_err);
2712
+ free(write_err);
2713
+ goto out;
2714
+ } else {
2715
+ update->flags |= REF_NEEDS_COMMIT;
2716
+ }
2717
}
2718
}
2719
if (!(update->flags & REF_NEEDS_COMMIT)) {
@@ -2723,7 +2725,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
2725
if (close_ref_gently(lock)) {
2726
strbuf_addf(err, "couldn't close '%s.lock'",
2727
update->refname);
2726
- ret = TRANSACTION_GENERIC_ERROR;
2728
+ ret = REF_TRANSACTION_ERROR_GENERIC;
2729
goto out;
2730
}
2731
}
@@ -2865,7 +2867,7 @@ static int files_transaction_prepare(struct ref_store *ref_store,
2867
refs->packed_ref_store,
2868
transaction->flags, err);
2869
if (!packed_transaction) {
2868
- ret = TRANSACTION_GENERIC_ERROR;
2870
+ ret = REF_TRANSACTION_ERROR_GENERIC;
2871
goto cleanup;
2872
}
2873
@@ -2897,13 +2899,13 @@ static int files_transaction_prepare(struct ref_store *ref_store,
2899
*/
2900
if (refs_verify_refnames_available(refs->packed_ref_store, &refnames_to_check,
2901
&transaction->refnames, NULL, 0, err)) {
2900
- ret = TRANSACTION_NAME_CONFLICT;
2902
+ ret = REF_TRANSACTION_ERROR_NAME_CONFLICT;
2903
goto cleanup;
2904
}
2905
2906
if (packed_transaction) {
2907
if (packed_refs_lock(refs->packed_ref_store, 0, err)) {
2906
- ret = TRANSACTION_GENERIC_ERROR;
2908
+ ret = REF_TRANSACTION_ERROR_GENERIC;
2909
goto cleanup;
2910
}
2911
backend_data->packed_refs_locked = 1;
@@ -2934,7 +2936,7 @@ static int files_transaction_prepare(struct ref_store *ref_store,
2936
*/
2937
backend_data->packed_transaction = NULL;
2938
if (ref_transaction_abort(packed_transaction, err)) {
2937
- ret = TRANSACTION_GENERIC_ERROR;
2939
+ ret = REF_TRANSACTION_ERROR_GENERIC;
2940
goto cleanup;
2941
}
2942
}
@@ -3035,7 +3037,7 @@ static int files_transaction_finish_initial(struct files_ref_store *refs,
3037
packed_transaction = ref_store_transaction_begin(refs->packed_ref_store,
3038
transaction->flags, err);
3039
if (!packed_transaction) {
3038
- ret = TRANSACTION_GENERIC_ERROR;
3040
+ ret = REF_TRANSACTION_ERROR_GENERIC;
3041
goto cleanup;
3042
}
3043
@@ -3058,7 +3060,7 @@ static int files_transaction_finish_initial(struct files_ref_store *refs,
3060
if (!loose_transaction) {
3061
loose_transaction = ref_store_transaction_begin(&refs->base, 0, err);
3062
if (!loose_transaction) {
3061
- ret = TRANSACTION_GENERIC_ERROR;
3063
+ ret = REF_TRANSACTION_ERROR_GENERIC;
3064
goto cleanup;
3065
}
3066
}
@@ -3083,19 +3085,19 @@ static int files_transaction_finish_initial(struct files_ref_store *refs,
3085
}
3086
3087
if (packed_refs_lock(refs->packed_ref_store, 0, err)) {
3086
- ret = TRANSACTION_GENERIC_ERROR;
3088
+ ret = REF_TRANSACTION_ERROR_GENERIC;
3089
goto cleanup;
3090
}
3091
3092
if (refs_verify_refnames_available(&refs->base, &refnames_to_check,
3093
&affected_refnames, NULL, 1, err)) {
3094
packed_refs_unlock(refs->packed_ref_store);
3093
- ret = TRANSACTION_NAME_CONFLICT;
3095
+ ret = REF_TRANSACTION_ERROR_NAME_CONFLICT;
3096
goto cleanup;
3097
}
3098
3099
if (ref_transaction_commit(packed_transaction, err)) {
3098
- ret = TRANSACTION_GENERIC_ERROR;
3100
+ ret = REF_TRANSACTION_ERROR_GENERIC;
3101
goto cleanup;
3102
}
3103
packed_refs_unlock(refs->packed_ref_store);
@@ -3103,7 +3105,7 @@ static int files_transaction_finish_initial(struct files_ref_store *refs,
3105
if (loose_transaction) {
3106
if (ref_transaction_prepare(loose_transaction, err) ||
3107
ref_transaction_commit(loose_transaction, err)) {
3106
- ret = TRANSACTION_GENERIC_ERROR;
3108
+ ret = REF_TRANSACTION_ERROR_GENERIC;
3109
goto cleanup;
3110
}
3111
}
@@ -3152,7 +3154,7 @@ static int files_transaction_finish(struct ref_store *ref_store,
3154
if (update->flags & REF_NEEDS_COMMIT ||
3155
update->flags & REF_LOG_ONLY) {
3156
if (parse_and_write_reflog(refs, update, lock, err)) {
3155
- ret = TRANSACTION_GENERIC_ERROR;
3157
+ ret = REF_TRANSACTION_ERROR_GENERIC;
3158
goto cleanup;
3159
}
3160
}
@@ -3171,7 +3173,7 @@ static int files_transaction_finish(struct ref_store *ref_store,
3173
strbuf_addf(err, "couldn't set '%s'", lock->ref_name);
3174
unlock_ref(lock);
3175
update->backend_data = NULL;
3174
- ret = TRANSACTION_GENERIC_ERROR;
3176
+ ret = REF_TRANSACTION_ERROR_GENERIC;
3177
goto cleanup;
3178
}
3179
}
@@ -3227,7 +3229,7 @@ static int files_transaction_finish(struct ref_store *ref_store,
3229
strbuf_reset(&sb);
3230
files_ref_path(refs, &sb, lock->ref_name);
3231
if (unlink_or_msg(sb.buf, err)) {
3230
- ret = TRANSACTION_GENERIC_ERROR;
3232
+ ret = REF_TRANSACTION_ERROR_GENERIC;
3233
goto cleanup;
3234
}
3235
}
refs/packed-backend.c
+14
-9
@@ -1326,10 +1326,11 @@ static int packed_ref_store_remove_on_disk(struct ref_store *ref_store,
1326
* The packfile must be locked before calling this function and will
1327
* remain locked when it is done.
1328
*/
1329
-static int write_with_updates(struct packed_ref_store *refs,
1330
- struct string_list *updates,
1331
- struct strbuf *err)
1329
+static enum ref_transaction_error write_with_updates(struct packed_ref_store *refs,
1330
+ struct string_list *updates,
1331
+ struct strbuf *err)
1332
{
1333
+ enum ref_transaction_error ret = REF_TRANSACTION_ERROR_GENERIC;
1334
struct ref_iterator *iter = NULL;
1335
size_t i;
1336
int ok;
@@ -1353,7 +1354,7 @@ static int write_with_updates(struct packed_ref_store *refs,
1354
strbuf_addf(err, "unable to create file %s: %s",
1355
sb.buf, strerror(errno));
1356
strbuf_release(&sb);
1356
- return -1;
1357
+ return REF_TRANSACTION_ERROR_GENERIC;
1358
}
1359
strbuf_release(&sb);
1360
@@ -1409,6 +1410,7 @@ static int write_with_updates(struct packed_ref_store *refs,
1410
strbuf_addf(err, "cannot update ref '%s': "
1411
"reference already exists",
1412
update->refname);
1413
+ ret = REF_TRANSACTION_ERROR_CREATE_EXISTS;
1414
goto error;
1415
} else if (!oideq(&update->old_oid, iter->oid)) {
1416
strbuf_addf(err, "cannot update ref '%s': "
@@ -1416,6 +1418,7 @@ static int write_with_updates(struct packed_ref_store *refs,
1418
update->refname,
1419
oid_to_hex(iter->oid),
1420
oid_to_hex(&update->old_oid));
1421
+ ret = REF_TRANSACTION_ERROR_INCORRECT_OLD_VALUE;
1422
goto error;
1423
}
1424
}
@@ -1452,6 +1455,7 @@ static int write_with_updates(struct packed_ref_store *refs,
1455
"reference is missing but expected %s",
1456
update->refname,
1457
oid_to_hex(&update->old_oid));
1458
+ ret = REF_TRANSACTION_ERROR_NONEXISTENT_REF;
1459
goto error;
1460
}
1461
}
@@ -1509,7 +1513,7 @@ static int write_with_updates(struct packed_ref_store *refs,
1513
strerror(errno));
1514
strbuf_release(&sb);
1515
delete_tempfile(&refs->tempfile);
1512
- return -1;
1516
+ return REF_TRANSACTION_ERROR_GENERIC;
1517
}
1518
1519
return 0;
@@ -1521,7 +1525,7 @@ write_error:
1525
error:
1526
ref_iterator_free(iter);
1527
delete_tempfile(&refs->tempfile);
1524
- return -1;
1528
+ return ret;
1529
}
1530
1531
int is_packed_transaction_needed(struct ref_store *ref_store,
@@ -1654,7 +1658,7 @@ static int packed_transaction_prepare(struct ref_store *ref_store,
1658
REF_STORE_READ | REF_STORE_WRITE | REF_STORE_ODB,
1659
"ref_transaction_prepare");
1660
struct packed_transaction_backend_data *data;
1657
- int ret = TRANSACTION_GENERIC_ERROR;
1661
+ enum ref_transaction_error ret = REF_TRANSACTION_ERROR_GENERIC;
1662
1663
/*
1664
* Note that we *don't* skip transactions with zero updates,
@@ -1675,7 +1679,8 @@ static int packed_transaction_prepare(struct ref_store *ref_store,
1679
data->own_lock = 1;
1680
}
1681
1678
- if (write_with_updates(refs, &transaction->refnames, err))
1682
+ ret = write_with_updates(refs, &transaction->refnames, err);
1683
+ if (ret)
1684
goto failure;
1685
1686
transaction->state = REF_TRANSACTION_PREPARED;
@@ -1707,7 +1712,7 @@ static int packed_transaction_finish(struct ref_store *ref_store,
1712
ref_store,
1713
REF_STORE_READ | REF_STORE_WRITE | REF_STORE_ODB,
1714
"ref_transaction_finish");
1710
- int ret = TRANSACTION_GENERIC_ERROR;
1715
+ int ret = REF_TRANSACTION_ERROR_GENERIC;
1716
char *packed_refs_path;
1717
1718
clear_snapshot(refs);
refs/refs-internal.h
+3
-2
@@ -770,8 +770,9 @@ int ref_update_has_null_new_value(struct ref_update *update);
770
* If everything is OK, return 0; otherwise, write an error message to
771
* err and return -1.
772
*/
773
-int ref_update_check_old_target(const char *referent, struct ref_update *update,
774
- struct strbuf *err);
773
+enum ref_transaction_error ref_update_check_old_target(const char *referent,
774
+ struct ref_update *update,
775
+ struct strbuf *err);
776
777
/*
778
* Check if the ref must exist, this means that the old_oid or
refs/reftable-backend.c
+32
-32
@@ -1069,20 +1069,20 @@ static int queue_transaction_update(struct reftable_ref_store *refs,
1069
return 0;
1070
}
1071
1072
-static int prepare_single_update(struct reftable_ref_store *refs,
1073
- struct reftable_transaction_data *tx_data,
1074
- struct ref_transaction *transaction,
1075
- struct reftable_backend *be,
1076
- struct ref_update *u,
1077
- struct string_list *refnames_to_check,
1078
- unsigned int head_type,
1079
- struct strbuf *head_referent,
1080
- struct strbuf *referent,
1081
- struct strbuf *err)
1072
+static enum ref_transaction_error prepare_single_update(struct reftable_ref_store *refs,
1073
+ struct reftable_transaction_data *tx_data,
1074
+ struct ref_transaction *transaction,
1075
+ struct reftable_backend *be,
1076
+ struct ref_update *u,
1077
+ struct string_list *refnames_to_check,
1078
+ unsigned int head_type,
1079
+ struct strbuf *head_referent,
1080
+ struct strbuf *referent,
1081
+ struct strbuf *err)
1082
{
1083
+ enum ref_transaction_error ret = 0;
1084
struct object_id current_oid = {0};
1085
const char *rewritten_ref;
1085
- int ret = 0;
1086
1087
/*
1088
* There is no need to reload the respective backends here as
@@ -1093,7 +1093,7 @@ static int prepare_single_update(struct reftable_ref_store *refs,
1093
*/
1094
ret = backend_for(&be, refs, u->refname, &rewritten_ref, 0);
1095
if (ret)
1096
- return ret;
1096
+ return REF_TRANSACTION_ERROR_GENERIC;
1097
1098
/* Verify that the new object ID is valid. */
1099
if ((u->flags & REF_HAVE_NEW) && !is_null_oid(&u->new_oid) &&
@@ -1104,13 +1104,13 @@ static int prepare_single_update(struct reftable_ref_store *refs,
1104
strbuf_addf(err,
1105
_("trying to write ref '%s' with nonexistent object %s"),
1106
u->refname, oid_to_hex(&u->new_oid));
1107
- return -1;
1107
+ return REF_TRANSACTION_ERROR_INVALID_NEW_VALUE;
1108
}
1109
1110
if (o->type != OBJ_COMMIT && is_branch(u->refname)) {
1111
strbuf_addf(err, _("trying to write non-commit object %s to branch '%s'"),
1112
oid_to_hex(&u->new_oid), u->refname);
1113
- return -1;
1113
+ return REF_TRANSACTION_ERROR_INVALID_NEW_VALUE;
1114
}
1115
}
1116
@@ -1134,7 +1134,7 @@ static int prepare_single_update(struct reftable_ref_store *refs,
1134
_("multiple updates for 'HEAD' (including one "
1135
"via its referent '%s') are not allowed"),
1136
u->refname);
1137
- return TRANSACTION_NAME_CONFLICT;
1137
+ return REF_TRANSACTION_ERROR_NAME_CONFLICT;
1138
}
1139
1140
ref_transaction_add_update(
@@ -1147,7 +1147,7 @@ static int prepare_single_update(struct reftable_ref_store *refs,
1147
ret = reftable_backend_read_ref(be, rewritten_ref,
1148
¤t_oid, referent, &u->type);
1149
if (ret < 0)
1150
- return ret;
1150
+ return REF_TRANSACTION_ERROR_GENERIC;
1151
if (ret > 0 && !ref_update_expects_existing_old_ref(u)) {
1152
/*
1153
* The reference does not exist, and we either have no
@@ -1168,7 +1168,7 @@ static int prepare_single_update(struct reftable_ref_store *refs,
1168
ret = queue_transaction_update(refs, tx_data, u,
1169
¤t_oid, err);
1170
if (ret)
1171
- return ret;
1171
+ return REF_TRANSACTION_ERROR_GENERIC;
1172
}
1173
1174
return 0;
@@ -1180,7 +1180,7 @@ static int prepare_single_update(struct reftable_ref_store *refs,
1180
1181
"unable to resolve reference '%s'"),
1182
ref_update_original_update_refname(u), u->refname);
1183
- return -1;
1183
+ return REF_TRANSACTION_ERROR_NONEXISTENT_REF;
1184
}
1185
1186
if (u->type & REF_ISSYMREF) {
@@ -1196,7 +1196,7 @@ static int prepare_single_update(struct reftable_ref_store *refs,
1196
if (u->flags & REF_HAVE_OLD && !resolved) {
1197
strbuf_addf(err, _("cannot lock ref '%s': "
1198
"error reading reference"), u->refname);
1199
- return -1;
1199
+ return REF_TRANSACTION_ERROR_GENERIC;
1200
}
1201
} else {
1202
struct ref_update *new_update;
@@ -1211,7 +1211,7 @@ static int prepare_single_update(struct reftable_ref_store *refs,
1211
_("multiple updates for '%s' (including one "
1212
"via symref '%s') are not allowed"),
1213
referent->buf, u->refname);
1214
- return TRANSACTION_NAME_CONFLICT;
1214
+ return REF_TRANSACTION_ERROR_NAME_CONFLICT;
1215
}
1216
1217
/*
@@ -1255,31 +1255,32 @@ static int prepare_single_update(struct reftable_ref_store *refs,
1255
"but is a regular ref"),
1256
ref_update_original_update_refname(u),
1257
u->old_target);
1258
- return -1;
1258
+ return REF_TRANSACTION_ERROR_EXPECTED_SYMREF;
1259
}
1260
1261
- if (ref_update_check_old_target(referent->buf, u, err)) {
1262
- return -1;
1263
- }
1261
+ ret = ref_update_check_old_target(referent->buf, u, err);
1262
+ if (ret)
1263
+ return ret;
1264
} else if ((u->flags & REF_HAVE_OLD) && !oideq(¤t_oid, &u->old_oid)) {
1265
if (is_null_oid(&u->old_oid)) {
1266
strbuf_addf(err, _("cannot lock ref '%s': "
1267
"reference already exists"),
1268
ref_update_original_update_refname(u));
1269
- return TRANSACTION_CREATE_EXISTS;
1270
- }
1271
- else if (is_null_oid(¤t_oid))
1269
+ return REF_TRANSACTION_ERROR_CREATE_EXISTS;
1270
+ } else if (is_null_oid(¤t_oid)) {
1271
strbuf_addf(err, _("cannot lock ref '%s': "
1272
"reference is missing but expected %s"),
1273
ref_update_original_update_refname(u),
1274
oid_to_hex(&u->old_oid));
1276
- else
1275
+ return REF_TRANSACTION_ERROR_NONEXISTENT_REF;
1276
+ } else {
1277
strbuf_addf(err, _("cannot lock ref '%s': "
1278
"is at %s but expected %s"),
1279
ref_update_original_update_refname(u),
1280
oid_to_hex(¤t_oid),
1281
oid_to_hex(&u->old_oid));
1282
- return TRANSACTION_NAME_CONFLICT;
1282
+ return REF_TRANSACTION_ERROR_INCORRECT_OLD_VALUE;
1283
+ }
1284
}
1285
1286
/*
@@ -1296,8 +1297,8 @@ static int prepare_single_update(struct reftable_ref_store *refs,
1297
if ((u->type & REF_ISSYMREF) ||
1298
(u->flags & REF_LOG_ONLY) ||
1299
(u->flags & REF_HAVE_NEW && !oideq(¤t_oid, &u->new_oid)))
1299
- return queue_transaction_update(refs, tx_data, u,
1300
- ¤t_oid, err);
1300
+ if (queue_transaction_update(refs, tx_data, u, ¤t_oid, err))
1301
+ return REF_TRANSACTION_ERROR_GENERIC;
1302
1303
return 0;
1304
}
@@ -1385,7 +1386,6 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
1386
transaction->state = REF_TRANSACTION_PREPARED;
1387
1388
done:
1388
- assert(ret != REFTABLE_API_ERROR);
1389
if (ret < 0) {
1390
free_transaction_data(tx_data);
1391
transaction->state = REF_TRANSACTION_CLOSED;