]> git.ipfire.org Git - thirdparty/git.git/blobdiff - refs/files-backend.c
Merge branch 'en/ort-perf-batch-9'
[thirdparty/git.git] / refs / files-backend.c
index dd8abe918508027ed46c3234bac1d91107c6ca94..119972ee16f89f629e96b552e520f0b8190e54a7 100644 (file)
  */
 #define REF_NEEDS_COMMIT (1 << 6)
 
-/*
- * Used as a flag in ref_update::flags when we want to log a ref
- * update but not actually perform it.  This is used when a symbolic
- * ref update is split up.
- */
-#define REF_LOG_ONLY (1 << 7)
-
 /*
  * Used as a flag in ref_update::flags when the ref_update was via an
  * update to HEAD.
@@ -67,7 +60,6 @@ struct files_ref_store {
        struct ref_store base;
        unsigned int store_flags;
 
-       char *gitdir;
        char *gitcommondir;
 
        struct ref_cache *loose;
@@ -94,18 +86,17 @@ static struct ref_store *files_ref_store_create(const char *gitdir,
        struct ref_store *ref_store = (struct ref_store *)refs;
        struct strbuf sb = STRBUF_INIT;
 
+       ref_store->gitdir = xstrdup(gitdir);
        base_ref_store_init(ref_store, &refs_be_files);
        refs->store_flags = flags;
 
-       refs->gitdir = xstrdup(gitdir);
        get_common_dir_noenv(&sb, gitdir);
        refs->gitcommondir = strbuf_detach(&sb, NULL);
        strbuf_addf(&sb, "%s/packed-refs", refs->gitcommondir);
        refs->packed_ref_store = packed_ref_store_create(sb.buf, flags);
        strbuf_release(&sb);
 
-       chdir_notify_reparent("files-backend $GIT_DIR",
-                             &refs->gitdir);
+       chdir_notify_reparent("files-backend $GIT_DIR", &refs->base.gitdir);
        chdir_notify_reparent("files-backend $GIT_COMMONDIR",
                              &refs->gitcommondir);
 
@@ -176,7 +167,7 @@ static void files_reflog_path(struct files_ref_store *refs,
        switch (ref_type(refname)) {
        case REF_TYPE_PER_WORKTREE:
        case REF_TYPE_PSEUDOREF:
-               strbuf_addf(sb, "%s/logs/%s", refs->gitdir, refname);
+               strbuf_addf(sb, "%s/logs/%s", refs->base.gitdir, refname);
                break;
        case REF_TYPE_OTHER_PSEUDOREF:
        case REF_TYPE_MAIN_PSEUDOREF:
@@ -198,7 +189,7 @@ static void files_ref_path(struct files_ref_store *refs,
        switch (ref_type(refname)) {
        case REF_TYPE_PER_WORKTREE:
        case REF_TYPE_PSEUDOREF:
-               strbuf_addf(sb, "%s/%s", refs->gitdir, refname);
+               strbuf_addf(sb, "%s/%s", refs->base.gitdir, refname);
                break;
        case REF_TYPE_MAIN_PSEUDOREF:
                if (!skip_prefix(refname, "main-worktree/", &refname))
@@ -214,6 +205,33 @@ static void files_ref_path(struct files_ref_store *refs,
        }
 }
 
+/*
+ * Manually add refs/bisect, refs/rewritten and refs/worktree, which, being
+ * per-worktree, might not appear in the directory listing for
+ * refs/ in the main repo.
+ */
+static void add_per_worktree_entries_to_dir(struct ref_dir *dir, const char *dirname)
+{
+       const char *prefixes[] = { "refs/bisect/", "refs/worktree/", "refs/rewritten/" };
+       int ip;
+
+       if (strcmp(dirname, "refs/"))
+               return;
+
+       for (ip = 0; ip < ARRAY_SIZE(prefixes); ip++) {
+               const char *prefix = prefixes[ip];
+               int prefix_len = strlen(prefix);
+               struct ref_entry *child_entry;
+               int pos;
+
+               pos = search_ref_dir(dir, prefix, prefix_len);
+               if (pos >= 0)
+                       continue;
+               child_entry = create_dir_entry(dir->cache, prefix, prefix_len, 1);
+               add_entry_to_dir(dir, child_entry);
+       }
+}
+
 /*
  * Read the loose references from the namespace dirname into dir
  * (without recursing).  dirname must end with '/'.  dir must be the
@@ -297,28 +315,7 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
        strbuf_release(&path);
        closedir(d);
 
-       /*
-        * Manually add refs/bisect and refs/worktree, which, being
-        * per-worktree, might not appear in the directory listing for
-        * refs/ in the main repo.
-        */
-       if (!strcmp(dirname, "refs/")) {
-               int pos = search_ref_dir(dir, "refs/bisect/", 12);
-
-               if (pos < 0) {
-                       struct ref_entry *child_entry = create_dir_entry(
-                                       dir->cache, "refs/bisect/", 12, 1);
-                       add_entry_to_dir(dir, child_entry);
-               }
-
-               pos = search_ref_dir(dir, "refs/worktree/", 11);
-
-               if (pos < 0) {
-                       struct ref_entry *child_entry = create_dir_entry(
-                                       dir->cache, "refs/worktree/", 11, 1);
-                       add_entry_to_dir(dir, child_entry);
-               }
-       }
+       add_per_worktree_entries_to_dir(dir, dirname);
 }
 
 static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs)
@@ -354,7 +351,6 @@ static int files_read_raw_ref(struct ref_store *ref_store,
        struct strbuf sb_path = STRBUF_INIT;
        const char *path;
        const char *buf;
-       const char *p;
        struct stat st;
        int fd;
        int ret = -1;
@@ -459,37 +455,41 @@ stat_ref:
        close(fd);
        strbuf_rtrim(&sb_contents);
        buf = sb_contents.buf;
-       if (starts_with(buf, "ref:")) {
-               buf += 4;
+
+       ret = parse_loose_ref_contents(buf, oid, referent, type);
+
+out:
+       save_errno = errno;
+       strbuf_release(&sb_path);
+       strbuf_release(&sb_contents);
+       errno = save_errno;
+       return ret;
+}
+
+int parse_loose_ref_contents(const char *buf, struct object_id *oid,
+                            struct strbuf *referent, unsigned int *type)
+{
+       const char *p;
+       if (skip_prefix(buf, "ref:", &buf)) {
                while (isspace(*buf))
                        buf++;
 
                strbuf_reset(referent);
                strbuf_addstr(referent, buf);
                *type |= REF_ISSYMREF;
-               ret = 0;
-               goto out;
+               return 0;
        }
 
        /*
-        * Please note that FETCH_HEAD has additional
-        * data after the sha.
+        * FETCH_HEAD has additional data after the sha.
         */
        if (parse_oid_hex(buf, oid, &p) ||
            (*p != '\0' && !isspace(*p))) {
                *type |= REF_ISBROKEN;
                errno = EINVAL;
-               goto out;
+               return -1;
        }
-
-       ret = 0;
-
-out:
-       save_errno = errno;
-       strbuf_release(&sb_path);
-       strbuf_release(&sb_contents);
-       errno = save_errno;
-       return ret;
+       return 0;
 }
 
 static void unlock_ref(struct ref_lock *lock)
@@ -549,7 +549,7 @@ static int lock_raw_ref(struct files_ref_store *refs,
 
        /* First lock the file so it can't change out from under us. */
 
-       *lock_p = lock = xcalloc(1, sizeof(*lock));
+       *lock_p = CALLOC_ARRAY(lock, 1);
 
        lock->ref_name = xstrdup(refname);
        files_ref_path(refs, &ref_file, refname);
@@ -843,7 +843,7 @@ static struct ref_iterator *files_ref_iterator_begin(
 
        overlay_iter = overlay_ref_iterator_begin(loose_iter, packed_iter);
 
-       iter = xcalloc(1, sizeof(*iter));
+       CALLOC_ARRAY(iter, 1);
        ref_iterator = &iter->base;
        base_ref_iterator_init(ref_iterator, &files_ref_iterator_vtable,
                               overlay_iter->ordered);
@@ -930,7 +930,7 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs,
        files_assert_main_repository(refs, "lock_ref_oid_basic");
        assert(err);
 
-       lock = xcalloc(1, sizeof(struct ref_lock));
+       CALLOC_ARRAY(lock, 1);
 
        if (mustexist)
                resolve_flags |= RESOLVE_REF_READING;
@@ -1321,7 +1321,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
 {
        struct files_ref_store *refs =
                files_downcast(ref_store, REF_STORE_WRITE, "rename_ref");
-       struct object_id oid, orig_oid;
+       struct object_id orig_oid;
        int flag = 0, logmoved = 0;
        struct ref_lock *lock;
        struct stat loginfo;
@@ -1389,7 +1389,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
         */
        if (!copy && !refs_read_ref_full(&refs->base, newrefname,
                                RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
-                               &oid, NULL) &&
+                               NULL, NULL) &&
            refs_delete_ref(&refs->base, NULL, newrefname,
                            NULL, REF_NO_DEREF)) {
                if (errno == EISDIR) {
@@ -1623,8 +1623,10 @@ static int log_ref_write_fd(int fd, const struct object_id *old_oid,
        int ret = 0;
 
        strbuf_addf(&sb, "%s %s %s", oid_to_hex(old_oid), oid_to_hex(new_oid), committer);
-       if (msg && *msg)
-               copy_reflog_msg(&sb, msg);
+       if (msg && *msg) {
+               strbuf_addch(&sb, '\t');
+               strbuf_addstr(&sb, msg);
+       }
        strbuf_addch(&sb, '\n');
        if (write_in_full(fd, sb.buf, sb.len) < 0)
                ret = -1;
@@ -1822,12 +1824,12 @@ static int create_symref_locked(struct files_ref_store *refs,
 
        if (!fdopen_lock_file(&lock->lk, "w"))
                return error("unable to fdopen %s: %s",
-                            lock->lk.tempfile->filename.buf, strerror(errno));
+                            get_lock_file_path(&lock->lk), strerror(errno));
 
        update_symref_reflog(refs, lock, refname, target, logmsg);
 
        /* no error check; commit_ref will check ferror */
-       fprintf(lock->lk.tempfile->fp, "ref: %s\n", target);
+       fprintf(get_lock_file_fp(&lock->lk), "ref: %s\n", target);
        if (commit_ref(lock) < 0)
                return error("unable to write symref for %s: %s", refname,
                             strerror(errno));
@@ -2137,13 +2139,24 @@ static struct ref_iterator_vtable files_reflog_iterator_vtable = {
 static struct ref_iterator *reflog_iterator_begin(struct ref_store *ref_store,
                                                  const char *gitdir)
 {
-       struct files_reflog_iterator *iter = xcalloc(1, sizeof(*iter));
-       struct ref_iterator *ref_iterator = &iter->base;
+       struct dir_iterator *diter;
+       struct files_reflog_iterator *iter;
+       struct ref_iterator *ref_iterator;
        struct strbuf sb = STRBUF_INIT;
 
-       base_ref_iterator_init(ref_iterator, &files_reflog_iterator_vtable, 0);
        strbuf_addf(&sb, "%s/logs", gitdir);
-       iter->dir_iterator = dir_iterator_begin(sb.buf);
+
+       diter = dir_iterator_begin(sb.buf, 0);
+       if (!diter) {
+               strbuf_release(&sb);
+               return empty_ref_iterator_begin();
+       }
+
+       CALLOC_ARRAY(iter, 1);
+       ref_iterator = &iter->base;
+
+       base_ref_iterator_init(ref_iterator, &files_reflog_iterator_vtable, 0);
+       iter->dir_iterator = diter;
        iter->ref_store = ref_store;
        strbuf_release(&sb);
 
@@ -2181,12 +2194,11 @@ static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_st
                files_downcast(ref_store, REF_STORE_READ,
                               "reflog_iterator_begin");
 
-       if (!strcmp(refs->gitdir, refs->gitcommondir)) {
+       if (!strcmp(refs->base.gitdir, refs->gitcommondir)) {
                return reflog_iterator_begin(ref_store, refs->gitcommondir);
        } else {
                return merge_ref_iterator_begin(
-                       0,
-                       reflog_iterator_begin(ref_store, refs->gitdir),
+                       0, reflog_iterator_begin(ref_store, refs->base.gitdir),
                        reflog_iterator_begin(ref_store, refs->gitcommondir),
                        reflog_iterator_select, refs);
        }
@@ -2254,8 +2266,7 @@ static int split_head_update(struct ref_update *update,
  * Note that the new update will itself be subject to splitting when
  * the iteration gets to it.
  */
-static int split_symref_update(struct files_ref_store *refs,
-                              struct ref_update *update,
+static int split_symref_update(struct ref_update *update,
                               const char *referent,
                               struct ref_transaction *transaction,
                               struct string_list *affected_refnames,
@@ -2449,7 +2460,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
                         * of processing the split-off update, so we
                         * don't have to do it here.
                         */
-                       ret = split_symref_update(refs, update,
+                       ret = split_symref_update(update,
                                                  referent.buf, transaction,
                                                  affected_refnames, err);
                        if (ret)
@@ -2550,16 +2561,18 @@ static void files_transaction_cleanup(struct files_ref_store *refs,
                }
        }
 
-       if (backend_data->packed_transaction &&
-           ref_transaction_abort(backend_data->packed_transaction, &err)) {
-               error("error aborting transaction: %s", err.buf);
-               strbuf_release(&err);
-       }
+       if (backend_data) {
+               if (backend_data->packed_transaction &&
+                   ref_transaction_abort(backend_data->packed_transaction, &err)) {
+                       error("error aborting transaction: %s", err.buf);
+                       strbuf_release(&err);
+               }
 
-       if (backend_data->packed_refs_locked)
-               packed_refs_unlock(refs->packed_ref_store);
+               if (backend_data->packed_refs_locked)
+                       packed_refs_unlock(refs->packed_ref_store);
 
-       free(backend_data);
+               free(backend_data);
+       }
 
        transaction->state = REF_TRANSACTION_CLOSED;
 }
@@ -2584,7 +2597,7 @@ static int files_transaction_prepare(struct ref_store *ref_store,
        if (!transaction->nr)
                goto cleanup;
 
-       backend_data = xcalloc(1, sizeof(*backend_data));
+       CALLOC_ARRAY(backend_data, 1);
        transaction->backend_data = backend_data;
 
        /*
@@ -2696,18 +2709,32 @@ static int files_transaction_prepare(struct ref_store *ref_store,
                if (is_packed_transaction_needed(refs->packed_ref_store,
                                                 packed_transaction)) {
                        ret = ref_transaction_prepare(packed_transaction, err);
+                       /*
+                        * A failure during the prepare step will abort
+                        * itself, but not free. Do that now, and disconnect
+                        * from the files_transaction so it does not try to
+                        * abort us when we hit the cleanup code below.
+                        */
+                       if (ret) {
+                               ref_transaction_free(packed_transaction);
+                               backend_data->packed_transaction = NULL;
+                       }
                } else {
                        /*
                         * We can skip rewriting the `packed-refs`
                         * file. But we do need to leave it locked, so
                         * that somebody else doesn't pack a reference
                         * that we are trying to delete.
+                        *
+                        * We need to disconnect our transaction from
+                        * backend_data, since the abort (whether successful or
+                        * not) will free it.
                         */
+                       backend_data->packed_transaction = NULL;
                        if (ref_transaction_abort(packed_transaction, err)) {
                                ret = TRANSACTION_GENERIC_ERROR;
                                goto cleanup;
                        }
-                       backend_data->packed_transaction = NULL;
                }
        }