aboutsummaryrefslogtreecommitdiffstats
path: root/refs/files-backend.c
diff options
context:
space:
mode:
Diffstat (limited to 'refs/files-backend.c')
-rw-r--r--refs/files-backend.c188
1 files changed, 149 insertions, 39 deletions
diff --git a/refs/files-backend.c b/refs/files-backend.c
index d6f37963bc..44c5c3b201 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -89,9 +89,9 @@ static void clear_loose_ref_cache(struct files_ref_store *refs)
* Create a new submodule ref cache and add it to the internal
* set of caches.
*/
-static struct ref_store *files_ref_store_create(struct repository *repo,
- const char *gitdir,
- unsigned int flags)
+static struct ref_store *files_ref_store_init(struct repository *repo,
+ const char *gitdir,
+ unsigned int flags)
{
struct files_ref_store *refs = xcalloc(1, sizeof(*refs));
struct ref_store *ref_store = (struct ref_store *)refs;
@@ -102,7 +102,7 @@ static struct ref_store *files_ref_store_create(struct repository *repo,
get_common_dir_noenv(&sb, gitdir);
refs->gitcommondir = strbuf_detach(&sb, NULL);
refs->packed_ref_store =
- packed_ref_store_create(repo, refs->gitcommondir, flags);
+ packed_ref_store_init(repo, refs->gitcommondir, flags);
chdir_notify_reparent("files-backend $GIT_DIR", &refs->base.gitdir);
chdir_notify_reparent("files-backend $GIT_COMMONDIR",
@@ -149,6 +149,14 @@ static struct files_ref_store *files_downcast(struct ref_store *ref_store,
return refs;
}
+static void files_ref_store_release(struct ref_store *ref_store)
+{
+ struct files_ref_store *refs = files_downcast(ref_store, 0, "release");
+ free_ref_cache(refs->loose);
+ free(refs->gitcommondir);
+ ref_store_release(refs->packed_ref_store);
+}
+
static void files_reflog_path(struct files_ref_store *refs,
struct strbuf *sb,
const char *refname)
@@ -315,19 +323,15 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
add_per_worktree_entries_to_dir(dir, dirname);
}
-/*
- * Add pseudorefs to the ref dir by parsing the directory for any files
- * which follow the pseudoref syntax.
- */
-static void add_pseudoref_and_head_entries(struct ref_store *ref_store,
- struct ref_dir *dir,
- const char *dirname)
+static int for_each_root_ref(struct files_ref_store *refs,
+ int (*cb)(const char *refname, void *cb_data),
+ void *cb_data)
{
- struct files_ref_store *refs =
- files_downcast(ref_store, REF_STORE_READ, "fill_ref_dir");
struct strbuf path = STRBUF_INIT, refname = STRBUF_INIT;
+ const char *dirname = refs->loose->root->name;
struct dirent *de;
size_t dirnamelen;
+ int ret;
DIR *d;
files_ref_path(refs, &path, dirname);
@@ -335,7 +339,7 @@ static void add_pseudoref_and_head_entries(struct ref_store *ref_store,
d = opendir(path.buf);
if (!d) {
strbuf_release(&path);
- return;
+ return -1;
}
strbuf_addstr(&refname, dirname);
@@ -351,15 +355,49 @@ static void add_pseudoref_and_head_entries(struct ref_store *ref_store,
strbuf_addstr(&refname, de->d_name);
dtype = get_dtype(de, &path, 1);
- if (dtype == DT_REG && (is_pseudoref(ref_store, de->d_name) ||
- is_headref(ref_store, de->d_name)))
- loose_fill_ref_dir_regular_file(refs, refname.buf, dir);
+ if (dtype == DT_REG && is_root_ref(de->d_name)) {
+ ret = cb(refname.buf, cb_data);
+ if (ret)
+ goto done;
+ }
strbuf_setlen(&refname, dirnamelen);
}
+
+ ret = 0;
+
+done:
strbuf_release(&refname);
strbuf_release(&path);
closedir(d);
+ return ret;
+}
+
+struct fill_root_ref_data {
+ struct files_ref_store *refs;
+ struct ref_dir *dir;
+};
+
+static int fill_root_ref(const char *refname, void *cb_data)
+{
+ struct fill_root_ref_data *data = cb_data;
+ loose_fill_ref_dir_regular_file(data->refs, refname, data->dir);
+ return 0;
+}
+
+/*
+ * Add root refs to the ref dir by parsing the directory for any files which
+ * follow the root ref syntax.
+ */
+static void add_root_refs(struct files_ref_store *refs,
+ struct ref_dir *dir)
+{
+ struct fill_root_ref_data data = {
+ .refs = refs,
+ .dir = dir,
+ };
+
+ for_each_root_ref(refs, fill_root_ref, &data);
}
static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs,
@@ -381,8 +419,7 @@ static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs,
dir = get_ref_dir(refs->loose->root);
if (flags & DO_FOR_EACH_INCLUDE_ROOT_REFS)
- add_pseudoref_and_head_entries(dir->cache->ref_store, dir,
- refs->loose->root->name);
+ add_root_refs(refs, dir);
/*
* Add an incomplete entry for "refs/" (to be filled
@@ -794,8 +831,10 @@ retry:
*/
if (refs_verify_refname_available(
refs->packed_ref_store, refname,
- extras, NULL, err))
+ extras, NULL, err)) {
+ ret = TRANSACTION_NAME_CONFLICT;
goto error_return;
+ }
}
ret = 0;
@@ -1229,7 +1268,8 @@ static void prune_refs(struct files_ref_store *refs, struct ref_to_prune **refs_
/*
* Return true if the specified reference should be packed.
*/
-static int should_pack_ref(const char *refname,
+static int should_pack_ref(struct files_ref_store *refs,
+ const char *refname,
const struct object_id *oid, unsigned int ref_flags,
struct pack_refs_opts *opts)
{
@@ -1245,7 +1285,7 @@ static int should_pack_ref(const char *refname,
return 0;
/* Do not pack broken refs: */
- if (!ref_resolves_to_object(refname, the_repository, oid, ref_flags))
+ if (!ref_resolves_to_object(refname, refs->base.repo, oid, ref_flags))
return 0;
if (ref_excluded(opts->exclusions, refname))
@@ -1277,14 +1317,14 @@ static int files_pack_refs(struct ref_store *ref_store,
packed_refs_lock(refs->packed_ref_store, LOCK_DIE_ON_ERROR, &err);
iter = cache_ref_iterator_begin(get_loose_ref_cache(refs, 0), NULL,
- the_repository, 0);
+ refs->base.repo, 0);
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
/*
* If the loose reference can be packed, add an entry
* in the packed ref cache. If the reference should be
* pruned, also add it to refs_to_prune.
*/
- if (!should_pack_ref(iter->refname, iter->oid, iter->flags, opts))
+ if (!should_pack_ref(refs, iter->refname, iter->oid, iter->flags, opts))
continue;
/*
@@ -1381,7 +1421,8 @@ static int rename_tmp_log(struct files_ref_store *refs, const char *newrefname)
return ret;
}
-static int write_ref_to_lockfile(struct ref_lock *lock,
+static int write_ref_to_lockfile(struct files_ref_store *refs,
+ struct ref_lock *lock,
const struct object_id *oid,
int skip_oid_verification, struct strbuf *err);
static int commit_ref_update(struct files_ref_store *refs,
@@ -1529,7 +1570,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
}
oidcpy(&lock->old_oid, &orig_oid);
- if (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||
+ if (write_ref_to_lockfile(refs, lock, &orig_oid, 0, &err) ||
commit_ref_update(refs, lock, &orig_oid, logmsg, &err)) {
error("unable to write current sha1 into %s: %s", newrefname, err.buf);
strbuf_release(&err);
@@ -1549,7 +1590,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
flag = log_all_ref_updates;
log_all_ref_updates = LOG_REFS_NONE;
- if (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||
+ if (write_ref_to_lockfile(refs, lock, &orig_oid, 0, &err) ||
commit_ref_update(refs, lock, &orig_oid, NULL, &err)) {
error("unable to write current sha1 into %s: %s", oldrefname, err.buf);
strbuf_release(&err);
@@ -1741,6 +1782,9 @@ static int files_log_ref_write(struct files_ref_store *refs,
{
int logfd, result;
+ if (flags & REF_SKIP_CREATE_REFLOG)
+ return 0;
+
if (log_all_ref_updates == LOG_REFS_UNSET)
log_all_ref_updates = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
@@ -1783,7 +1827,8 @@ static int files_log_ref_write(struct files_ref_store *refs,
* Write oid into the open lockfile, then close the lockfile. On
* errors, rollback the lockfile, fill in *err and return -1.
*/
-static int write_ref_to_lockfile(struct ref_lock *lock,
+static int write_ref_to_lockfile(struct files_ref_store *refs,
+ struct ref_lock *lock,
const struct object_id *oid,
int skip_oid_verification, struct strbuf *err)
{
@@ -1792,7 +1837,7 @@ static int write_ref_to_lockfile(struct ref_lock *lock,
int fd;
if (!skip_oid_verification) {
- o = parse_object(the_repository, oid);
+ o = parse_object(refs->base.repo, oid);
if (!o) {
strbuf_addf(
err,
@@ -1811,7 +1856,7 @@ static int write_ref_to_lockfile(struct ref_lock *lock,
}
}
fd = get_lock_file_fd(&lock->lk);
- if (write_in_full(fd, oid_to_hex(oid), the_hash_algo->hexsz) < 0 ||
+ if (write_in_full(fd, oid_to_hex(oid), refs->base.repo->hash_algo->hexsz) < 0 ||
write_in_full(fd, &term, 1) < 0 ||
fsync_component(FSYNC_COMPONENT_REFERENCE, get_lock_file_fd(&lock->lk)) < 0 ||
close_ref_gently(lock) < 0) {
@@ -2241,6 +2286,7 @@ static int split_head_update(struct ref_update *update,
struct ref_update *new_update;
if ((update->flags & REF_LOG_ONLY) ||
+ (update->flags & REF_SKIP_CREATE_REFLOG) ||
(update->flags & REF_IS_PRUNING) ||
(update->flags & REF_UPDATE_VIA_HEAD))
return 0;
@@ -2547,7 +2593,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
* value, so we don't need to write it.
*/
} else if (write_ref_to_lockfile(
- lock, &update->new_oid,
+ refs, lock, &update->new_oid,
update->flags & REF_SKIP_OID_VERIFICATION,
err)) {
char *write_err = strbuf_detach(err, NULL);
@@ -3230,7 +3276,7 @@ static int files_reflog_expire(struct ref_store *ref_store,
rollback_lock_file(&reflog_lock);
} else if (update &&
(write_in_full(get_lock_file_fd(&lock->lk),
- oid_to_hex(&cb.last_kept_oid), the_hash_algo->hexsz) < 0 ||
+ oid_to_hex(&cb.last_kept_oid), refs->base.repo->hash_algo->hexsz) < 0 ||
write_str_in_full(get_lock_file_fd(&lock->lk), "\n") < 0 ||
close_ref_gently(lock) < 0)) {
status |= error("couldn't write %s",
@@ -3254,12 +3300,12 @@ static int files_reflog_expire(struct ref_store *ref_store,
return -1;
}
-static int files_init_db(struct ref_store *ref_store,
- int flags,
- struct strbuf *err UNUSED)
+static int files_ref_store_create_on_disk(struct ref_store *ref_store,
+ int flags,
+ struct strbuf *err UNUSED)
{
struct files_ref_store *refs =
- files_downcast(ref_store, REF_STORE_WRITE, "init_db");
+ files_downcast(ref_store, REF_STORE_WRITE, "create");
struct strbuf sb = STRBUF_INIT;
/*
@@ -3282,7 +3328,7 @@ static int files_init_db(struct ref_store *ref_store,
* There is no need to create directories for common refs when creating
* a worktree ref store.
*/
- if (!(flags & REFS_INIT_DB_IS_WORKTREE)) {
+ if (!(flags & REF_STORE_CREATE_ON_DISK_IS_WORKTREE)) {
/*
* Create .git/refs/{heads,tags}
*/
@@ -3299,10 +3345,74 @@ static int files_init_db(struct ref_store *ref_store,
return 0;
}
+struct remove_one_root_ref_data {
+ const char *gitdir;
+ struct strbuf *err;
+};
+
+static int remove_one_root_ref(const char *refname,
+ void *cb_data)
+{
+ struct remove_one_root_ref_data *data = cb_data;
+ struct strbuf buf = STRBUF_INIT;
+ int ret = 0;
+
+ strbuf_addf(&buf, "%s/%s", data->gitdir, refname);
+
+ ret = unlink(buf.buf);
+ if (ret < 0)
+ strbuf_addf(data->err, "could not delete %s: %s\n",
+ refname, strerror(errno));
+
+ strbuf_release(&buf);
+ return ret;
+}
+
+static int files_ref_store_remove_on_disk(struct ref_store *ref_store,
+ struct strbuf *err)
+{
+ struct files_ref_store *refs =
+ files_downcast(ref_store, REF_STORE_WRITE, "remove");
+ struct remove_one_root_ref_data data = {
+ .gitdir = refs->base.gitdir,
+ .err = err,
+ };
+ struct strbuf sb = STRBUF_INIT;
+ int ret = 0;
+
+ strbuf_addf(&sb, "%s/refs", refs->base.gitdir);
+ if (remove_dir_recursively(&sb, 0) < 0) {
+ strbuf_addf(err, "could not delete refs: %s",
+ strerror(errno));
+ ret = -1;
+ }
+ strbuf_reset(&sb);
+
+ strbuf_addf(&sb, "%s/logs", refs->base.gitdir);
+ if (remove_dir_recursively(&sb, 0) < 0) {
+ strbuf_addf(err, "could not delete logs: %s",
+ strerror(errno));
+ ret = -1;
+ }
+ strbuf_reset(&sb);
+
+ if (for_each_root_ref(refs, remove_one_root_ref, &data) < 0)
+ ret = -1;
+
+ if (ref_store_remove_on_disk(refs->packed_ref_store, err) < 0)
+ ret = -1;
+
+ strbuf_release(&sb);
+ return ret;
+}
+
struct ref_storage_be refs_be_files = {
.name = "files",
- .init = files_ref_store_create,
- .init_db = files_init_db,
+ .init = files_ref_store_init,
+ .release = files_ref_store_release,
+ .create_on_disk = files_ref_store_create_on_disk,
+ .remove_on_disk = files_ref_store_remove_on_disk,
+
.transaction_prepare = files_transaction_prepare,
.transaction_finish = files_transaction_finish,
.transaction_abort = files_transaction_abort,