gout

A static git page generator
git clone https://git.bracken.jp/gout.git
Log | Files | Refs | README | LICENSE

commit f4a2c59b7cf12d727e11f12d98ccb0688c3070f0
parent d1c012787ee97eddea5d0f5ef79f62a3705f6614
Author: Chris Bracken <chris@bracken.jp>
Date:   Fri, 20 Feb 2026 18:56:25 +0900

cache: centralise cachefile creation/closing

Diffstat:
Msrc/writer/cache/cache.c | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/writer/cache/cache.h | 21++++++++++++++++++++-
Msrc/writer/gopher/log.c | 57++-------------------------------------------------------
Msrc/writer/html/log.c | 57++-------------------------------------------------------
4 files changed, 110 insertions(+), 111 deletions(-)

diff --git a/src/writer/cache/cache.c b/src/writer/cache/cache.c @@ -11,7 +11,16 @@ #include "git/git.h" #include "utils.h" +static const char* kTempCachePath = "cache.XXXXXXXXXXXX"; +static const mode_t kReadWriteAll = + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + struct Cache { + const FileSystem* fs; + char* cache_path; + char* temp_cache_path; + bool owns_streams; + bool can_add_commits; WriteCommitRow write_commit_row; FILE* cache_in; @@ -50,10 +59,55 @@ Cache* cache_create(FILE* cache_in, return cache; } +Cache* cache_open(const FileSystem* fs, + const char* path, + WriteCommitRow write_func) { + assert(fs != NULL); + assert(path != NULL); + assert(write_func != NULL); + + char* temp_cache_path = estrdup(kTempCachePath); + FILE* cache_in = fs->fopen(path, "r"); + int out_fd = fs->mkstemp(temp_cache_path); + if (out_fd == -1) { + free(temp_cache_path); + if (cache_in) { + fs->fclose(cache_in); + } + err(1, "mkstemp: %s", temp_cache_path); + } + FILE* cache_out = fs->fdopen(out_fd, "w"); + if (!cache_out) { + fs->close(out_fd); + free(temp_cache_path); + if (cache_in) { + fs->fclose(cache_in); + } + err(1, "fdopen: %s", temp_cache_path); + } + + Cache* cache = cache_create(cache_in, cache_out, write_func); + cache->fs = fs; + cache->cache_path = estrdup(path); + cache->temp_cache_path = temp_cache_path; + cache->owns_streams = true; + return cache; +} + void cache_free(Cache* cache) { if (!cache) { return; } + if (cache->owns_streams) { + if (cache->cache_in) { + cache->fs->fclose(cache->cache_in); + } + if (cache->cache_out) { + cache->fs->fclose(cache->cache_out); + } + } + free(cache->cache_path); + free(cache->temp_cache_path); free(cache->lastoid_in); cache->lastoid_in = NULL; free(cache); @@ -104,6 +158,38 @@ void cache_finish(Cache* cache) { } } +void cache_close_and_replace(Cache* cache, FILE* out) { + assert(cache != NULL); + assert(cache->owns_streams); + assert(out != NULL); + + cache_finish(cache); + + if (cache->cache_in) { + cache->fs->fclose(cache->cache_in); + cache->cache_in = NULL; + } + cache->fs->fclose(cache->cache_out); + cache->cache_out = NULL; + + if (cache->fs->rename(cache->temp_cache_path, cache->cache_path)) { + err(1, "rename: %s -> %s", cache->temp_cache_path, cache->cache_path); + } + + mode_t mask; + umask(mask = umask(0)); + if (cache->fs->chmod(cache->cache_path, kReadWriteAll & ~mask)) { + err(1, "chmod: %s", cache->cache_path); + } + + FILE* fcache = cache->fs->fopen(cache->cache_path, "r"); + if (!fcache) { + err(1, "fopen: %s", cache->cache_path); + } + cache_copy_log(fcache, out); + cache->fs->fclose(fcache); +} + void cache_copy_log(FILE* fcache, FILE* out) { assert(fcache != NULL); assert(out != NULL); diff --git a/src/writer/cache/cache.h b/src/writer/cache/cache.h @@ -5,6 +5,7 @@ #include <stdio.h> #include "git/commit.h" +#include "utils.h" /* Commit log cache file. * @@ -52,7 +53,20 @@ typedef void (*WriteCommitRow)(FILE* out, const GitCommit* commit); */ Cache* cache_create(FILE* cache_in, FILE* cache_out, WriteCommitRow write_func); -/* Frees the specified cache. */ +/* Higher-level API that manages its own files. + * + * Opens the cache at the specified path for reading, and creates a temporary + * file for writing the updated cache. + * + * Returns a Cache object that owns the opened file streams and paths. + */ +Cache* cache_open(const FileSystem* fs, + const char* path, + WriteCommitRow write_func); + +/* Frees the specified cache. If the cache was created via cache_open, the + * associated file streams and paths are also freed. + */ void cache_free(Cache* cache); /* Returns true if commits can be added to the cache. @@ -75,6 +89,11 @@ void cache_add_commit_row(Cache* cache, const GitCommit* commit); */ void cache_finish(Cache* cache); +/* Finishes, closes files, renames the temporary cache file to the final path, + * and copies the log contents to the specified output stream. + */ +void cache_close_and_replace(Cache* cache, FILE* out); + /* Copies the contents of the cache stream to the specified output stream, * skipping the OID header. */ diff --git a/src/writer/gopher/log.c b/src/writer/gopher/log.c @@ -18,10 +18,6 @@ struct GopherLog { const FileSystem* fs; FILE* out; Cache* cache; - char* cache_path; - char* temp_cache_path; - FILE* cache_in; - FILE* cache_out; GopherPage* page; size_t remaining_commits; size_t unlogged_commits; @@ -29,10 +25,6 @@ struct GopherLog { static void write_commit_row(FILE* out, const GitCommit* commit); -static const char* kTempCachePath = "cache.XXXXXXXXXXXX"; -static const mode_t kReadWriteAll = - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; - GopherLog* gopher_log_create(const GitRepo* repo, const FileSystem* fs) { assert(repo != NULL); assert(fs != NULL); @@ -57,14 +49,6 @@ void gopher_log_free(GopherLog* log) { log->out = NULL; cache_free(log->cache); log->cache = NULL; - free(log->cache_path); - free(log->temp_cache_path); - if (log->cache_in) { - log->fs->fclose(log->cache_in); - } - if (log->cache_out) { - log->fs->fclose(log->cache_out); - } gopher_page_free(log->page); log->page = NULL; free(log); @@ -73,21 +57,7 @@ void gopher_log_free(GopherLog* log) { void gopher_log_set_cachefile(GopherLog* log, const char* cachefile) { assert(log != NULL); assert(cachefile != NULL); - log->cache_path = estrdup(cachefile); - log->temp_cache_path = estrdup(kTempCachePath); - - log->cache_in = log->fs->fopen(cachefile, "r"); - int out_fd = log->fs->mkstemp(log->temp_cache_path); - if (out_fd == -1) { - err(1, "mkstemp: %s", log->temp_cache_path); - } - log->cache_out = log->fs->fdopen(out_fd, "w"); - if (!log->cache_out) { - log->fs->close(out_fd); - err(1, "fdopen: %s", log->temp_cache_path); - } - - log->cache = cache_create(log->cache_in, log->cache_out, write_commit_row); + log->cache = cache_open(log->fs, cachefile, write_commit_row); } void gopher_log_set_commit_limit(GopherLog* log, size_t count) { @@ -126,30 +96,7 @@ void gopher_log_end(GopherLog* log) { assert(log != NULL); FILE* out = log->out; if (log->cache) { - cache_finish(log->cache); - if (log->cache_in) { - log->fs->fclose(log->cache_in); - log->cache_in = NULL; - } - log->fs->fclose(log->cache_out); - log->cache_out = NULL; - - if (log->fs->rename(log->temp_cache_path, log->cache_path)) { - err(1, "rename: %s -> %s", log->temp_cache_path, log->cache_path); - } - - mode_t mask; - umask(mask = umask(0)); - if (log->fs->chmod(log->cache_path, kReadWriteAll & ~mask)) { - err(1, "chmod: %s", log->cache_path); - } - - FILE* fcache = log->fs->fopen(log->cache_path, "r"); - if (!fcache) { - err(1, "fopen: %s", log->cache_path); - } - cache_copy_log(fcache, log->out); - log->fs->fclose(fcache); + cache_close_and_replace(log->cache, log->out); } else if (log->unlogged_commits > 0) { size_t count = log->unlogged_commits; fprintf(out, "%16.16s %zu more commits remaining, fetch the repository\n", diff --git a/src/writer/html/log.c b/src/writer/html/log.c @@ -18,10 +18,6 @@ struct HtmlLog { const FileSystem* fs; FILE* out; Cache* cache; - char* cache_path; - char* temp_cache_path; - FILE* cache_in; - FILE* cache_out; HtmlPage* page; size_t remaining_commits; size_t unlogged_commits; @@ -29,10 +25,6 @@ struct HtmlLog { static void write_commit_row(FILE* out, const GitCommit* commit); -static const char* kTempCachePath = "cache.XXXXXXXXXXXX"; -static const mode_t kReadWriteAll = - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; - HtmlLog* html_log_create(const GitRepo* repo, const FileSystem* fs) { assert(repo != NULL); assert(fs != NULL); @@ -57,14 +49,6 @@ void html_log_free(HtmlLog* log) { log->out = NULL; cache_free(log->cache); log->cache = NULL; - free(log->cache_path); - free(log->temp_cache_path); - if (log->cache_in) { - log->fs->fclose(log->cache_in); - } - if (log->cache_out) { - log->fs->fclose(log->cache_out); - } html_page_free(log->page); log->page = NULL; free(log); @@ -73,21 +57,7 @@ void html_log_free(HtmlLog* log) { void html_log_set_cachefile(HtmlLog* log, const char* cachefile) { assert(log != NULL); assert(cachefile != NULL); - log->cache_path = estrdup(cachefile); - log->temp_cache_path = estrdup(kTempCachePath); - - log->cache_in = log->fs->fopen(cachefile, "r"); - int out_fd = log->fs->mkstemp(log->temp_cache_path); - if (out_fd == -1) { - err(1, "mkstemp: %s", log->temp_cache_path); - } - log->cache_out = log->fs->fdopen(out_fd, "w"); - if (!log->cache_out) { - log->fs->close(out_fd); - err(1, "fdopen: %s", log->temp_cache_path); - } - - log->cache = cache_create(log->cache_in, log->cache_out, write_commit_row); + log->cache = cache_open(log->fs, cachefile, write_commit_row); } void html_log_set_commit_limit(HtmlLog* log, size_t count) { @@ -133,30 +103,7 @@ void html_log_end(HtmlLog* log) { assert(log != NULL); FILE* out = log->out; if (log->cache) { - cache_finish(log->cache); - if (log->cache_in) { - log->fs->fclose(log->cache_in); - log->cache_in = NULL; - } - log->fs->fclose(log->cache_out); - log->cache_out = NULL; - - if (log->fs->rename(log->temp_cache_path, log->cache_path)) { - err(1, "rename: %s -> %s", log->temp_cache_path, log->cache_path); - } - - mode_t mask; - umask(mask = umask(0)); - if (log->fs->chmod(log->cache_path, kReadWriteAll & ~mask)) { - err(1, "chmod: %s", log->cache_path); - } - - FILE* fcache = log->fs->fopen(log->cache_path, "r"); - if (!fcache) { - err(1, "fopen: %s", log->cache_path); - } - cache_copy_log(fcache, log->out); - log->fs->fclose(fcache); + cache_close_and_replace(log->cache, log->out); } else if (log->unlogged_commits > 0) { size_t count = log->unlogged_commits; fprintf(out, "<tr><td></td><td colspan=\"5\">");