worktree: refactor infer_backlink() to use *strbuf

This lays the groundwork for the next patch, which needs the backlink returned from infer_backlink() as a `strbuf`. It seemed inefficient to convert from `strbuf` to `char*` and back to `strbuf` again. This refactors infer_backlink() to return an integer result and use a pre-allocated `strbuf` for the inferred backlink path, replacing the previous `char*` return type and improving efficiency. Signed-off-by: Caleb White <cdwhite3@pm.me> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Caleb White committed Oct 7, 2024 at 22:12 UTC bb4a883584ab13500921325617e022142633e53a
1 file changed +24 -24
worktree.c
+24 -24
@@ -642,10 +642,9 @@ static int is_main_worktree_path(const char *path)
642 * be able to infer the gitdir by manually reading /path/to/worktree/.git,
643 * extracting the <id>, and checking if <repo>/worktrees/<id> exists.
644 */
645 -static char *infer_backlink(const char *gitfile)
645 +static int infer_backlink(const char *gitfile, struct strbuf *inferred)
646 {
647 struct strbuf actual = STRBUF_INIT;
648 - struct strbuf inferred = STRBUF_INIT;
648 const char *id;
649
650 if (strbuf_read_file(&actual, gitfile, 0) < 0)
@@ -658,17 +657,18 @@ static char *infer_backlink(const char *gitfile)
657 id++; /* advance past '/' to point at <id> */
658 if (!*id)
659 goto error;
661 - strbuf_git_common_path(&inferred, the_repository, "worktrees/%s", id);
662 - if (!is_directory(inferred.buf))
660 + strbuf_reset(inferred);
661 + strbuf_git_common_path(inferred, the_repository, "worktrees/%s", id);
662 + if (!is_directory(inferred->buf))
663 goto error;
664
665 strbuf_release(&actual);
666 - return strbuf_detach(&inferred, NULL);
666 + return 1;
667
668 error:
669 strbuf_release(&actual);
670 - strbuf_release(&inferred);
671 - return NULL;
670 + strbuf_reset(inferred); /* clear invalid path */
671 + return 0;
672 }
673
674 /*
@@ -680,10 +680,11 @@ void repair_worktree_at_path(const char *path,
680 {
681 struct strbuf dotgit = STRBUF_INIT;
682 struct strbuf realdotgit = STRBUF_INIT;
683 + struct strbuf backlink = STRBUF_INIT;
684 + struct strbuf inferred_backlink = STRBUF_INIT;
685 struct strbuf gitdir = STRBUF_INIT;
686 struct strbuf olddotgit = STRBUF_INIT;
685 - char *backlink = NULL;
686 - char *inferred_backlink = NULL;
687 + char *dotgit_contents = NULL;
688 const char *repair = NULL;
689 int err;
690
@@ -699,23 +700,23 @@ void repair_worktree_at_path(const char *path,
700 goto done;
701 }
702
702 - inferred_backlink = infer_backlink(realdotgit.buf);
703 - backlink = xstrdup_or_null(read_gitfile_gently(realdotgit.buf, &err));
704 - if (err == READ_GITFILE_ERR_NOT_A_FILE) {
703 + infer_backlink(realdotgit.buf, &inferred_backlink);
704 + dotgit_contents = xstrdup_or_null(read_gitfile_gently(realdotgit.buf, &err));
705 + if (dotgit_contents) {
706 + strbuf_addstr(&backlink, dotgit_contents);
707 + } else if (err == READ_GITFILE_ERR_NOT_A_FILE) {
708 fn(1, realdotgit.buf, _("unable to locate repository; .git is not a file"), cb_data);
709 goto done;
710 } else if (err == READ_GITFILE_ERR_NOT_A_REPO) {
708 - if (inferred_backlink) {
711 + if (inferred_backlink.len) {
712 /*
713 * Worktree's .git file does not point at a repository
714 * but we found a .git/worktrees/<id> in this
715 * repository with the same <id> as recorded in the
716 * worktree's .git file so make the worktree point at
714 - * the discovered .git/worktrees/<id>. (Note: backlink
715 - * is already NULL, so no need to free it first.)
717 + * the discovered .git/worktrees/<id>.
718 */
717 - backlink = inferred_backlink;
718 - inferred_backlink = NULL;
719 + strbuf_swap(&backlink, &inferred_backlink);
720 } else {
721 fn(1, realdotgit.buf, _("unable to locate repository; .git file does not reference a repository"), cb_data);
722 goto done;
@@ -743,13 +744,11 @@ void repair_worktree_at_path(const char *path,
744 * in the "copy" repository. In this case, point the "copy" worktree's
745 * .git file at the "copy" repository.
746 */
746 - if (inferred_backlink && fspathcmp(backlink, inferred_backlink)) {
747 - free(backlink);
748 - backlink = inferred_backlink;
749 - inferred_backlink = NULL;
747 + if (inferred_backlink.len && fspathcmp(backlink.buf, inferred_backlink.buf)) {
748 + strbuf_swap(&backlink, &inferred_backlink);
749 }
750
752 - strbuf_addf(&gitdir, "%s/gitdir", backlink);
751 + strbuf_addf(&gitdir, "%s/gitdir", backlink.buf);
752 if (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0)
753 repair = _("gitdir unreadable");
754 else {
@@ -763,9 +762,10 @@ void repair_worktree_at_path(const char *path,
762 write_file(gitdir.buf, "%s", realdotgit.buf);
763 }
764 done:
766 - free(backlink);
767 - free(inferred_backlink);
765 + free(dotgit_contents);
766 strbuf_release(&olddotgit);
767 + strbuf_release(&backlink);
768 + strbuf_release(&inferred_backlink);
769 strbuf_release(&gitdir);
770 strbuf_release(&realdotgit);
771 strbuf_release(&dotgit);