diff options
context:
space:
mode:
Diffstat (limited to 'source/ui-repolist.c')
-rw-r--r--source/ui-repolist.c29
1 file changed, 27 insertions, 2 deletions
diff --git a/source/ui-repolist.c b/source/ui-repolist.c
index 5174c5a..fc198e5 100644
--- a/source/ui-repolist.c
+++ b/source/ui-repolist.c
@@ -35,8 +35,10 @@ static time_t read_agefile(const char *path)
static int get_repo_modtime(const struct cgit_repo *repo, time_t *mtime)
{
struct strbuf path = STRBUF_INIT;
+ struct strbuf head = STRBUF_INIT;
struct stat s;
struct cgit_repo *r = (struct cgit_repo *)repo;
+ const char *branch;
if (repo->mtime != -1) {
*mtime = repo->mtime;
@@ -51,9 +53,31 @@ static int get_repo_modtime(const struct cgit_repo *repo, time_t *mtime)
}
}
+ /* Stat the tip of the default branch. Prefer a configured defbranch,
+ * otherwise read HEAD so a repo on "main" (or any branch name) is
+ * handled, not only "master".
+ */
+ branch = repo->defbranch;
+ if (!branch) {
+ strbuf_reset(&path);
+ strbuf_addf(&path, "%s/HEAD", repo->path);
+ if (strbuf_read_file(&head, path.buf, 0) > 0) {
+ strbuf_rtrim(&head);
+ if (!skip_prefix(head.buf, "ref: refs/heads/", &branch))
+ branch = NULL;
+ /* HEAD is repo-controlled, so a crafted target such as
+ * "ref: refs/heads/../../.." must not let the stat()
+ * below walk outside the repository. Git forbids ".."
+ * in ref names anyway. */
+ if (branch && strstr(branch, ".."))
+ branch = NULL;
+ }
+ if (!branch)
+ branch = "master";
+ }
+
strbuf_reset(&path);
- strbuf_addf(&path, "%s/refs/heads/%s", repo->path,
- repo->defbranch ? repo->defbranch : "master");
+ strbuf_addf(&path, "%s/refs/heads/%s", repo->path, branch);
if (stat(path.buf, &s) == 0) {
*mtime = s.st_mtime;
r->mtime = *mtime;
@@ -72,6 +96,7 @@ static int get_repo_modtime(const struct cgit_repo *repo, time_t *mtime)
r->mtime = *mtime;
end:
strbuf_release(&path);
+ strbuf_release(&head);
return (r->mtime != 0);
}