@ -738,152 +738,6 @@ static struct ref_iterator *cache_ref_iterator_begin(struct ref_dir *dir)
@@ -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)
@@ -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)
@@ -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:
@@ -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,17 +1613,14 @@ retry:
@@ -1758,17 +1613,14 @@ 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;
goto out;
@ -2122,9 +1974,8 @@ static struct ref_lock *lock_ref_sha1_basic(struct files_ref_store *refs,
@@ -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;
}