From dce9812e5f4b5b2bb520ffc93b9847cb6fcb2075 Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Sat, 31 Oct 2026 17:48:01 -1000 Subject: Key the cached scan on every setting it uses Two cgitrc files sharing a cache-root read one list, so strict-export and trust-scan-config set in one applied to the other, and a changed setting stayed stale until the list expired. The first request after an upgrade scans again, and the files under the old names are never read. --- source/cgit.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 5 deletions(-) (limited to 'source/cgit.c') diff --git a/source/cgit.c b/source/cgit.c index f8795d7..3571bc4 100644 --- a/source/cgit.c +++ b/source/cgit.c @@ -376,18 +376,70 @@ out: */ static void apply_config(const char *name, const char *value); +/* + * The cached list is read back as trusted config, so it is kept under a name + * drawn from every setting that changes what the scan writes, from the scan + * itself to the defaults cgit_add_repo hands each repository. Two sites + * sharing a cache-root, or one that changed a setting, would otherwise read + * a list scanned under other settings until it expired. + */ +static void build_scan_key(struct strbuf *key, const char *path) +{ + const char *texts[] = { + path, + ctx.cfg.project_list, + ctx.cfg.strict_export, + ctx.cfg.section, + ctx.cfg.module_link, + ctx.cfg.clone_url, + }; + const int numbers[] = { + ctx.cfg.scan_hidden_path, + ctx.cfg.remove_suffix, + ctx.cfg.section_from_path, + ctx.cfg.enable_git_config, + ctx.cfg.trust_scan_config, + ctx.cfg.snapshots, + ctx.cfg.max_stats, + ctx.cfg.branch_sort, + ctx.cfg.commit_sort, + ctx.cfg.enable_blame, + ctx.cfg.enable_commit_graph, + ctx.cfg.enable_commit_trailers, + ctx.cfg.enable_follow_links, + ctx.cfg.enable_gitmodules_links, + ctx.cfg.enable_html_serving, + ctx.cfg.enable_log_filecount, + ctx.cfg.enable_log_linecount, + ctx.cfg.enable_mailmap, + ctx.cfg.enable_remote_branches, + ctx.cfg.enable_subject_links, + }; + size_t i; + + // Each text goes behind its length so no value can run into the next, + // and an unset one is told apart from an empty one. + for (i = 0; i < ARRAY_SIZE(texts); i++) { + if (texts[i]) + strbuf_addf(key, "%zu|%s", strlen(texts[i]), texts[i]); + else + strbuf_addch(key, '-'); + } + for (i = 0; i < ARRAY_SIZE(numbers); i++) + strbuf_addf(key, "%d|", numbers[i]); +} + static void process_cached_repolist(const char *path) { struct stat st; + struct strbuf key = STRBUF_INIT; struct strbuf cached_rc = STRBUF_INIT; time_t age; - unsigned long hash; int devnull; - hash = cache_hash_str(path); - if (ctx.cfg.project_list) - hash += cache_hash_str(ctx.cfg.project_list); - strbuf_addf(&cached_rc, "%s/rc-%8lx", ctx.cfg.cache_root, hash); + build_scan_key(&key, path); + strbuf_addf(&cached_rc, "%s/rc-%8lx", ctx.cfg.cache_root, cache_hash_str(key.buf)); + strbuf_release(&key); if (stat(cached_rc.buf, &st)) { // Nothing is cached yet, so this request scans in its own -- cgit 2.12.1