log_ref_setup(): improve robustness against races
[gitweb.git] / worktree.c
index f7869f8d6072c98c3e9be3387a9a3c19508e13ea..eb6121263b0d56b6b7ea7c5024e9ceb68256c1c5 100644 (file)
@@ -88,21 +88,13 @@ static struct worktree *get_main_worktree(void)
 
        strbuf_addf(&path, "%s/HEAD", get_git_common_dir());
 
-       if (parse_ref(path.buf, &head_ref, &is_detached) < 0)
-               goto done;
-
-       worktree = xmalloc(sizeof(struct worktree));
+       worktree = xcalloc(1, sizeof(*worktree));
        worktree->path = strbuf_detach(&worktree_path, NULL);
-       worktree->id = NULL;
        worktree->is_bare = is_bare;
-       worktree->head_ref = NULL;
        worktree->is_detached = is_detached;
-       worktree->is_current = 0;
-       add_head_info(&head_ref, worktree);
-       worktree->lock_reason = NULL;
-       worktree->lock_reason_valid = 0;
+       if (!parse_ref(path.buf, &head_ref, &is_detached))
+               add_head_info(&head_ref, worktree);
 
-done:
        strbuf_release(&path);
        strbuf_release(&worktree_path);
        strbuf_release(&head_ref);
@@ -138,16 +130,11 @@ static struct worktree *get_linked_worktree(const char *id)
        if (parse_ref(path.buf, &head_ref, &is_detached) < 0)
                goto done;
 
-       worktree = xmalloc(sizeof(struct worktree));
+       worktree = xcalloc(1, sizeof(*worktree));
        worktree->path = strbuf_detach(&worktree_path, NULL);
        worktree->id = xstrdup(id);
-       worktree->is_bare = 0;
-       worktree->head_ref = NULL;
        worktree->is_detached = is_detached;
-       worktree->is_current = 0;
        add_head_info(&head_ref, worktree);
-       worktree->lock_reason = NULL;
-       worktree->lock_reason_valid = 0;
 
 done:
        strbuf_release(&path);
@@ -173,7 +160,14 @@ static void mark_current_worktree(struct worktree **worktrees)
        free(git_dir);
 }
 
-struct worktree **get_worktrees(void)
+static int compare_worktree(const void *a_, const void *b_)
+{
+       const struct worktree *const *a = a_;
+       const struct worktree *const *b = b_;
+       return fspathcmp((*a)->path, (*b)->path);
+}
+
+struct worktree **get_worktrees(unsigned flags)
 {
        struct worktree **list = NULL;
        struct strbuf path = STRBUF_INIT;
@@ -183,8 +177,7 @@ struct worktree **get_worktrees(void)
 
        list = xmalloc(alloc * sizeof(struct worktree *));
 
-       if ((list[counter] = get_main_worktree()))
-               counter++;
+       list[counter++] = get_main_worktree();
 
        strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
        dir = opendir(path.buf);
@@ -205,6 +198,13 @@ struct worktree **get_worktrees(void)
        ALLOC_GROW(list, counter + 1, alloc);
        list[counter] = NULL;
 
+       if (flags & GWT_SORT_LINKED)
+               /*
+                * don't sort the first item (main worktree), which will
+                * always be the first
+                */
+               QSORT(list + 1, counter - 1, compare_worktree);
+
        mark_current_worktree(list);
        return list;
 }
@@ -341,7 +341,7 @@ const struct worktree *find_shared_symref(const char *symref,
 
        if (worktrees)
                free_worktrees(worktrees);
-       worktrees = get_worktrees();
+       worktrees = get_worktrees(0);
 
        for (i = 0; worktrees[i]; i++) {
                struct worktree *wt = worktrees[i];