summaryrefslogtreecommitdiff
path: root/refs/files-backend.c
diff options
context:
space:
mode:
Diffstat (limited to 'refs/files-backend.c')
-rw-r--r--refs/files-backend.c33
1 files changed, 28 insertions, 5 deletions
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 088b52c740..01df32904b 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -648,6 +648,26 @@ static void unlock_ref(struct ref_lock *lock)
}
/*
+ * Check if the transaction has another update with a case-insensitive refname
+ * match.
+ *
+ * If the update is part of the transaction, we only check up to that index.
+ * Further updates are expected to call this function to match previous indices.
+ */
+static bool transaction_has_case_conflicting_update(struct ref_transaction *transaction,
+ struct ref_update *update)
+{
+ for (size_t i = 0; i < transaction->nr; i++) {
+ if (transaction->updates[i] == update)
+ break;
+
+ if (!strcasecmp(transaction->updates[i]->refname, update->refname))
+ return true;
+ }
+ return false;
+}
+
+/*
* Lock refname, without following symrefs, and set *lock_p to point
* at a newly-allocated lock object. Fill in lock->old_oid, referent,
* and type similarly to read_raw_ref().
@@ -677,16 +697,17 @@ static void unlock_ref(struct ref_lock *lock)
* - Generate informative error messages in the case of failure
*/
static enum ref_transaction_error lock_raw_ref(struct files_ref_store *refs,
- struct ref_update *update,
+ struct ref_transaction *transaction,
size_t update_idx,
int mustexist,
struct string_list *refnames_to_check,
- const struct string_list *extras,
struct ref_lock **lock_p,
struct strbuf *referent,
struct strbuf *err)
{
enum ref_transaction_error ret = REF_TRANSACTION_ERROR_GENERIC;
+ struct ref_update *update = transaction->updates[update_idx];
+ const struct string_list *extras = &transaction->refnames;
const char *refname = update->refname;
unsigned int *type = &update->type;
struct ref_lock *lock;
@@ -776,6 +797,9 @@ retry:
goto retry;
} else {
unable_to_lock_message(ref_file.buf, myerr, err);
+ if (myerr == EEXIST && ignore_case &&
+ transaction_has_case_conflicting_update(transaction, update))
+ ret = REF_TRANSACTION_ERROR_CASE_CONFLICT;
goto error_return;
}
}
@@ -2583,9 +2607,8 @@ static enum ref_transaction_error lock_ref_for_update(struct files_ref_store *re
if (lock) {
lock->count++;
} else {
- ret = lock_raw_ref(refs, update, update_idx, mustexist,
- refnames_to_check, &transaction->refnames,
- &lock, &referent, err);
+ ret = lock_raw_ref(refs, transaction, update_idx, mustexist,
+ refnames_to_check, &lock, &referent, err);
if (ret) {
char *reason;