aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--refs/files-backend.c171
1 files changed, 11 insertions, 160 deletions
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 4185025ef..cf1c18cff 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -738,152 +738,6 @@ static struct ref_iterator *cache_ref_iterator_begin(struct ref_dir *dir)
return ref_iterator;
}
-struct nonmatching_ref_data {
- const struct string_list *skip;
- const char *conflicting_refname;
-};
-
-static int nonmatching_ref_fn(struct ref_entry *entry, void *vdata)
-{
- struct nonmatching_ref_data *data = vdata;
-
- if (data->skip && string_list_has_string(data->skip, entry->name))
- return 0;
-
- data->conflicting_refname = entry->name;
- return 1;
-}
-
-/*
- * Return 0 if a reference named refname could be created without
- * conflicting with the name of an existing reference in dir.
- * See verify_refname_available for more information.
- */
-static int verify_refname_available_dir(const char *refname,
- const struct string_list *extras,
- const struct string_list *skip,
- struct ref_dir *dir,
- struct strbuf *err)
-{
- const char *slash;
- const char *extra_refname;
- int pos;
- struct strbuf dirname = STRBUF_INIT;
- int ret = -1;
-
- /*
- * For the sake of comments in this function, suppose that
- * refname is "refs/foo/bar".
- */
-
- assert(err);
-
- strbuf_grow(&dirname, strlen(refname) + 1);
- for (slash = strchr(refname, '/'); slash; slash = strchr(slash + 1, '/')) {
- /* Expand dirname to the new prefix, not including the trailing slash: */
- strbuf_add(&dirname, refname + dirname.len, slash - refname - dirname.len);
-
- /*
- * We are still at a leading dir of the refname (e.g.,
- * "refs/foo"; if there is a reference with that name,
- * it is a conflict, *unless* it is in skip.
- */
- if (dir) {
- pos = search_ref_dir(dir, dirname.buf, dirname.len);
- if (pos >= 0 &&
- (!skip || !string_list_has_string(skip, dirname.buf))) {
- /*
- * We found a reference whose name is
- * a proper prefix of refname; e.g.,
- * "refs/foo", and is not in skip.
- */
- strbuf_addf(err, "'%s' exists; cannot create '%s'",
- dirname.buf, refname);
- goto cleanup;
- }
- }
-
- if (extras && string_list_has_string(extras, dirname.buf) &&
- (!skip || !string_list_has_string(skip, dirname.buf))) {
- strbuf_addf(err, "cannot process '%s' and '%s' at the same time",
- refname, dirname.buf);
- goto cleanup;
- }
-
- /*
- * Otherwise, we can try to continue our search with
- * the next component. So try to look up the
- * directory, e.g., "refs/foo/". If we come up empty,
- * we know there is nothing under this whole prefix,
- * but even in that case we still have to continue the
- * search for conflicts with extras.
- */
- strbuf_addch(&dirname, '/');
- if (dir) {
- pos = search_ref_dir(dir, dirname.buf, dirname.len);
- if (pos < 0) {
- /*
- * There was no directory "refs/foo/",
- * so there is nothing under this
- * whole prefix. So there is no need
- * to continue looking for conflicting
- * references. But we need to continue
- * looking for conflicting extras.
- */
- dir = NULL;
- } else {
- dir = get_ref_dir(dir->entries[pos]);
- }
- }
- }
-
- /*
- * We are at the leaf of our refname (e.g., "refs/foo/bar").
- * There is no point in searching for a reference with that
- * name, because a refname isn't considered to conflict with
- * itself. But we still need to check for references whose
- * names are in the "refs/foo/bar/" namespace, because they
- * *do* conflict.
- */
- strbuf_addstr(&dirname, refname + dirname.len);
- strbuf_addch(&dirname, '/');
-
- if (dir) {
- pos = search_ref_dir(dir, dirname.buf, dirname.len);
-
- if (pos >= 0) {
- /*
- * We found a directory named "$refname/"
- * (e.g., "refs/foo/bar/"). It is a problem
- * iff it contains any ref that is not in
- * "skip".
- */
- struct nonmatching_ref_data data;
-
- data.skip = skip;
- data.conflicting_refname = NULL;
- dir = get_ref_dir(dir->entries[pos]);
- sort_ref_dir(dir);
- if (do_for_each_entry_in_dir(dir, 0, nonmatching_ref_fn, &data)) {
- strbuf_addf(err, "'%s' exists; cannot create '%s'",
- data.conflicting_refname, refname);
- goto cleanup;
- }
- }
- }
-
- extra_refname = find_descendant_ref(dirname.buf, extras, skip);
- if (extra_refname)
- strbuf_addf(err, "cannot process '%s' and '%s' at the same time",
- refname, extra_refname);
- else
- ret = 0;
-
-cleanup:
- strbuf_release(&dirname);
- return ret;
-}
-
struct packed_ref_cache {
struct ref_entry *root;
@@ -1562,7 +1416,7 @@ static void unlock_ref(struct ref_lock *lock)
*
* If the reference doesn't already exist, verify that refname doesn't
* have a D/F conflict with any existing references. extras and skip
- * are passed to verify_refname_available_dir() for this check.
+ * are passed to refs_verify_refname_available() for this check.
*
* If mustexist is not set and the reference is not found or is
* broken, lock the reference anyway but clear sha1.
@@ -1577,7 +1431,7 @@ static void unlock_ref(struct ref_lock *lock)
*
* but it includes a lot more code to
* - Deal with possible races with other processes
- * - Avoid calling verify_refname_available_dir() when it can be
+ * - Avoid calling refs_verify_refname_available() when it can be
* avoided, namely if we were successfully able to read the ref
* - Generate informative error messages in the case of failure
*/
@@ -1634,7 +1488,8 @@ retry:
} else {
/*
* The error message set by
- * verify_refname_available_dir() is OK.
+ * refs_verify_refname_available() is
+ * OK.
*/
ret = TRANSACTION_NAME_CONFLICT;
}
@@ -1758,16 +1613,13 @@ retry:
/*
* If the ref did not exist and we are creating it,
- * make sure there is no existing packed ref whose
- * name begins with our refname, nor a packed ref
- * whose name is a proper prefix of our refname.
+ * make sure there is no existing ref that conflicts
+ * with refname:
*/
- if (verify_refname_available_dir(
- refname, extras, skip,
- get_packed_refs(refs),
- err)) {
+ if (refs_verify_refname_available(
+ &refs->base, refname,
+ extras, skip, err))
goto error_return;
- }
}
ret = 0;
@@ -2122,9 +1974,8 @@ static struct ref_lock *lock_ref_sha1_basic(struct files_ref_store *refs,
* our refname.
*/
if (is_null_oid(&lock->old_oid) &&
- verify_refname_available_dir(refname, extras, skip,
- get_packed_refs(refs),
- err)) {
+ refs_verify_refname_available(&refs->base, refname,
+ extras, skip, err)) {
last_errno = ENOTDIR;
goto error_return;
}