gout

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

commit 4100698bbc792f50bb38eca67839a37b0932f7be
parent e2641771bea38c1ff5bf9429eecd693932d179fe
Author: Chris Bracken <chris@bracken.jp>
Date:   Wed, 23 Jul 2025 16:28:59 -0700

Do not open files over 16MB in size

In order to prevent resource exhaustion -- either out-of-memory issues
while reading or filesystem free space exhaustion by emitting
exceedingly large files, set a 16MB maximum filesize limit. Anything
over 16MB will not be read, and instead "File too large to display" will
be emitted to the output instead.

Diffstat:
Mgit/file.h | 2++
Mgit/repo.c | 9++++++++-
Mwriter/gopher/fileblob.c | 7++++++-
Mwriter/html/fileblob.c | 7++++++-
4 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/git/file.h b/git/file.h @@ -17,6 +17,8 @@ const char* gitfile_repo_path(const GitFile* file); // Submodule commit OID. Empty string for files. const char* gitfile_commit_oid(const GitFile* file); ssize_t gitfile_size_bytes(const GitFile* file); + +// Returns file size in lines, or -1 if binary file, -2 if file too large. ssize_t gitfile_size_lines(const GitFile* file); const char* gitfile_content(const GitFile* file); diff --git a/git/repo.c b/git/repo.c @@ -46,6 +46,9 @@ static const size_t kLicensesLen = sizeof(kLicenses) / sizeof(char*); static const char* kReadmes[] = {"HEAD:README", "HEAD:README.md"}; static const size_t kReadmesLen = sizeof(kReadmes) / sizeof(char*); +/* Maximum file size to load into memory, in bytes. */ +static const ssize_t kMaxFileSizeBytes = 16 * 1024 * 1024; + /* Utilities */ static size_t string_count_lines(const char* str, ssize_t size_bytes); static bool string_ends_with(const char* str, const char* suffix); @@ -453,10 +456,14 @@ bool gitrepo_walk_tree_files(git_repository* repo, ssize_t size_bytes = git_blob_rawsize(blob); ssize_t size_lines = -1; const char* content = ""; - if (!git_blob_is_binary(blob)) { + + if (size_bytes > kMaxFileSizeBytes) { + size_lines = -2; /* oversized file */ + } else if (!git_blob_is_binary(blob)) { content = (const char*)git_blob_rawcontent(blob); size_lines = string_count_lines(content, size_bytes); } + char* filemode = format_filemode(git_tree_entry_filemode(entry)); GitFile* fileinfo = gitfile_create(kFileTypeFile, filemode, entrypath, entrypath, "", diff --git a/writer/gopher/fileblob.c b/writer/gopher/fileblob.c @@ -86,10 +86,15 @@ void gopher_fileblob_add_file(GopherFileBlob* blob, const GitFile* file) { fprintf(out, " (%zdB)\n", gitfile_size_bytes(file)); fprintf(out, "---\n"); - if (gitfile_size_lines(file) < 0) { + ssize_t size_lines = gitfile_size_lines(file); + if (size_lines == -1) { fprintf(out, "Binary file.\n"); return; } + if (size_lines == -2) { + fprintf(out, "File too large to display.\n"); + return; + } size_t i = 0; const char* content = gitfile_content(file); diff --git a/writer/html/fileblob.c b/writer/html/fileblob.c @@ -87,10 +87,15 @@ void html_fileblob_add_file(HtmlFileBlob* blob, const GitFile* file) { fprintf(out, " (%zdB)", gitfile_size_bytes(file)); fprintf(out, "</p><hr/>"); - if (gitfile_size_lines(file) < 0) { + ssize_t size_lines = gitfile_size_lines(file); + if (size_lines == -1) { fprintf(out, "<p>Binary file.</p>\n"); return; } + if (size_lines == -2) { + fprintf(out, "<p>File too large to display.</p>\n"); + return; + } fprintf(out, "<pre id=\"blob\">\n");