if (dir->sorted == dir->nr)
return;
- qsort(dir->entries, dir->nr, sizeof(*dir->entries), ref_entry_cmp);
+ QSORT(dir->entries, dir->nr, ref_entry_cmp);
/* Remove any duplicates: */
for (i = 0, j = 0; j < dir->nr; j++) {
return (struct files_ref_store *)ref_store;
}
-/*
- * Return a pointer to the reference store for the specified
- * submodule. For the main repository, use submodule==NULL; such a
- * call cannot fail. For a submodule, the submodule must exist and be
- * a nonbare repository, otherwise return NULL. Verify that the
- * reference store is a files_ref_store, and cast it to that type
- * before returning it.
- */
-static struct files_ref_store *get_files_ref_store(const char *submodule,
- const char *caller)
-{
- struct ref_store *refs = get_ref_store(submodule);
-
- return refs ? files_downcast(refs, 1, caller) : NULL;
-}
-
/* The length of a peeled reference line in packed-refs, including EOL: */
#define PEELED_LINE_LENGTH 42
struct strbuf refname;
struct strbuf path = STRBUF_INIT;
size_t path_baselen;
+ int err = 0;
if (*refs->base.submodule)
- strbuf_git_path_submodule(&path, refs->base.submodule, "%s", dirname);
+ err = strbuf_git_path_submodule(&path, refs->base.submodule, "%s", dirname);
else
strbuf_git_path(&path, "%s", dirname);
path_baselen = path.len;
+ if (err) {
+ strbuf_release(&path);
+ return;
+ }
+
d = opendir(path.buf);
if (!d) {
strbuf_release(&path);
int ok;
while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {
+ if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
+ ref_type(iter->iter0->refname) != REF_TYPE_PER_WORKTREE)
+ continue;
+
if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
!ref_resolves_to_object(iter->iter0->refname,
iter->iter0->oid,
errno = save_errno;
return -1;
} else {
- hashclr(lock->old_oid.hash);
+ oidclr(&lock->old_oid);
return 0;
}
}
if (old_sha1 && hashcmp(lock->old_oid.hash, old_sha1)) {
strbuf_addf(err, "ref '%s' is at %s but expected %s",
lock->ref_name,
- sha1_to_hex(lock->old_oid.hash),
+ oid_to_hex(&lock->old_oid),
sha1_to_hex(old_sha1));
errno = EBUSY;
return -1;
return 0;
}
-int delete_refs(struct string_list *refnames, unsigned int flags)
+static int files_delete_refs(struct ref_store *ref_store,
+ struct string_list *refnames, unsigned int flags)
{
struct files_ref_store *refs =
- get_files_ref_store(NULL, "delete_refs");
+ files_downcast(ref_store, 0, "delete_refs");
struct strbuf err = STRBUF_INIT;
int i, result = 0;
const unsigned char *sha1, const char *logmsg,
struct strbuf *err);
-int rename_ref(const char *oldrefname, const char *newrefname, const char *logmsg)
+static int files_rename_ref(struct ref_store *ref_store,
+ const char *oldrefname, const char *newrefname,
+ const char *logmsg)
{
- struct files_ref_store *refs = get_files_ref_store(NULL, "rename_ref");
+ struct files_ref_store *refs =
+ files_downcast(ref_store, 0, "rename_ref");
unsigned char sha1[20], orig_sha1[20];
int flag = 0, logmoved = 0;
struct ref_lock *lock;
return update->refname;
}
+/*
+ * Check whether the REF_HAVE_OLD and old_oid values stored in update
+ * are consistent with oid, which is the reference's current value. If
+ * everything is OK, return 0; otherwise, write an error message to
+ * err and return -1.
+ */
+static int check_old_oid(struct ref_update *update, struct object_id *oid,
+ struct strbuf *err)
+{
+ if (!(update->flags & REF_HAVE_OLD) ||
+ !hashcmp(oid->hash, update->old_sha1))
+ return 0;
+
+ if (is_null_sha1(update->old_sha1))
+ strbuf_addf(err, "cannot lock ref '%s': "
+ "reference already exists",
+ original_update_refname(update));
+ else if (is_null_oid(oid))
+ strbuf_addf(err, "cannot lock ref '%s': "
+ "reference is missing but expected %s",
+ original_update_refname(update),
+ sha1_to_hex(update->old_sha1));
+ else
+ strbuf_addf(err, "cannot lock ref '%s': "
+ "is at %s but expected %s",
+ original_update_refname(update),
+ oid_to_hex(oid),
+ sha1_to_hex(update->old_sha1));
+
+ return -1;
+}
+
/*
* Prepare for carrying out update:
* - Lock the reference referred to by update.
ret = lock_raw_ref(refs, update->refname, mustexist,
affected_refnames, NULL,
- &update->lock, &referent,
+ &lock, &referent,
&update->type, err);
-
if (ret) {
char *reason;
reason = strbuf_detach(err, NULL);
strbuf_addf(err, "cannot lock ref '%s': %s",
- update->refname, reason);
+ original_update_refname(update), reason);
free(reason);
return ret;
}
- lock = update->lock;
+ update->backend_data = lock;
if (update->type & REF_ISSYMREF) {
if (update->flags & REF_NODEREF) {
* the transaction, so we have to read it here
* to record and possibly check old_sha1:
*/
- if (read_ref_full(update->refname,
- mustexist ? RESOLVE_REF_READING : 0,
+ if (read_ref_full(referent.buf, 0,
lock->old_oid.hash, NULL)) {
if (update->flags & REF_HAVE_OLD) {
strbuf_addf(err, "cannot lock ref '%s': "
- "can't resolve old value",
- update->refname);
- return TRANSACTION_GENERIC_ERROR;
- } else {
- hashclr(lock->old_oid.hash);
+ "error reading reference",
+ original_update_refname(update));
+ return -1;
}
- }
- if ((update->flags & REF_HAVE_OLD) &&
- hashcmp(lock->old_oid.hash, update->old_sha1)) {
- strbuf_addf(err, "cannot lock ref '%s': "
- "is at %s but expected %s",
- update->refname,
- sha1_to_hex(lock->old_oid.hash),
- sha1_to_hex(update->old_sha1));
+ } else if (check_old_oid(update, &lock->old_oid, err)) {
return TRANSACTION_GENERIC_ERROR;
}
-
} else {
/*
* Create a new update for the reference this
} else {
struct ref_update *parent_update;
+ if (check_old_oid(update, &lock->old_oid, err))
+ return TRANSACTION_GENERIC_ERROR;
+
/*
* If this update is happening indirectly because of a
* symref update, record the old SHA-1 in the parent
for (parent_update = update->parent_update;
parent_update;
parent_update = parent_update->parent_update) {
- oidcpy(&parent_update->lock->old_oid, &lock->old_oid);
- }
-
- if ((update->flags & REF_HAVE_OLD) &&
- hashcmp(lock->old_oid.hash, update->old_sha1)) {
- if (is_null_sha1(update->old_sha1))
- strbuf_addf(err, "cannot lock ref '%s': reference already exists",
- original_update_refname(update));
- else
- strbuf_addf(err, "cannot lock ref '%s': is at %s but expected %s",
- original_update_refname(update),
- sha1_to_hex(lock->old_oid.hash),
- sha1_to_hex(update->old_sha1));
-
- return TRANSACTION_GENERIC_ERROR;
+ struct ref_lock *parent_lock = parent_update->backend_data;
+ oidcpy(&parent_lock->old_oid, &lock->old_oid);
}
}
* The lock was freed upon failure of
* write_ref_to_lockfile():
*/
- update->lock = NULL;
+ update->backend_data = NULL;
strbuf_addf(err,
- "cannot update the ref '%s': %s",
+ "cannot update ref '%s': %s",
update->refname, write_err);
free(write_err);
return TRANSACTION_GENERIC_ERROR;
/* Perform updates first so live commits remain referenced */
for (i = 0; i < transaction->nr; i++) {
struct ref_update *update = transaction->updates[i];
- struct ref_lock *lock = update->lock;
+ struct ref_lock *lock = update->backend_data;
if (update->flags & REF_NEEDS_COMMIT ||
update->flags & REF_LOG_ONLY) {
lock->ref_name, old_msg);
free(old_msg);
unlock_ref(lock);
- update->lock = NULL;
+ update->backend_data = NULL;
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
}
if (commit_ref(lock)) {
strbuf_addf(err, "couldn't set '%s'", lock->ref_name);
unlock_ref(lock);
- update->lock = NULL;
+ update->backend_data = NULL;
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
}
/* Perform deletes now that updates are safely completed */
for (i = 0; i < transaction->nr; i++) {
struct ref_update *update = transaction->updates[i];
+ struct ref_lock *lock = update->backend_data;
if (update->flags & REF_DELETING &&
!(update->flags & REF_LOG_ONLY)) {
- if (delete_ref_loose(update->lock, update->type, err)) {
+ if (delete_ref_loose(lock, update->type, err)) {
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
}
if (!(update->flags & REF_ISPRUNING))
string_list_append(&refs_to_delete,
- update->lock->ref_name);
+ lock->ref_name);
}
}
transaction->state = REF_TRANSACTION_CLOSED;
for (i = 0; i < transaction->nr; i++)
- if (transaction->updates[i]->lock)
- unlock_ref(transaction->updates[i]->lock);
+ if (transaction->updates[i]->backend_data)
+ unlock_ref(transaction->updates[i]->backend_data);
string_list_clear(&refs_to_delete, 0);
free(head_ref);
string_list_clear(&affected_refnames, 0);
return string_list_has_string(affected_refnames, refname);
}
-int initial_ref_transaction_commit(struct ref_transaction *transaction,
- struct strbuf *err)
+static int files_initial_transaction_commit(struct ref_store *ref_store,
+ struct ref_transaction *transaction,
+ struct strbuf *err)
{
struct files_ref_store *refs =
- get_files_ref_store(NULL, "initial_ref_transaction_commit");
+ files_downcast(ref_store, 0, "initial_ref_transaction_commit");
int ret = 0, i;
struct string_list affected_refnames = STRING_LIST_INIT_NODUP;
return -1;
}
+static int files_init_db(struct ref_store *ref_store, struct strbuf *err)
+{
+ /* Check validity (but we don't need the result): */
+ files_downcast(ref_store, 0, "init_db");
+
+ /*
+ * Create .git/refs/{heads,tags}
+ */
+ safe_create_dir(git_path("refs/heads"), 1);
+ safe_create_dir(git_path("refs/tags"), 1);
+ if (get_shared_repository()) {
+ adjust_shared_perm(git_path("refs/heads"));
+ adjust_shared_perm(git_path("refs/tags"));
+ }
+ return 0;
+}
+
struct ref_storage_be refs_be_files = {
NULL,
"files",
files_ref_store_create,
+ files_init_db,
files_transaction_commit,
+ files_initial_transaction_commit,
files_pack_refs,
files_peel_ref,
files_create_symref,
+ files_delete_refs,
+ files_rename_ref,
files_ref_iterator_begin,
files_read_raw_ref,