From 536da23ed7690680b6245c780933aa9dc256d2f2 Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Sat, 7 Nov 2026 18:55:07 -1000 Subject: Refuse a config directory before reading it Git's build swaps in an fopen that refuses a directory, but only where it defines FREAD_READS_DIRECTORIES, and not every system's build does. There a directory opened, and only a failed read(2) reported it. POSIX leaves that failure to the system, and one that read the raw entries would have parsed them as settings. --- source/config.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'source/config.c') diff --git a/source/config.c b/source/config.c index bfd31b6..84c7293 100644 --- a/source/config.c +++ b/source/config.c @@ -103,6 +103,7 @@ int config_file_parse(const char *filename, config_file_value_fn fn) int outer_lines_read = lines_read; struct strbuf name = STRBUF_INIT; struct strbuf value = STRBUF_INIT; + struct stat st; FILE *f; int err = 0; @@ -112,12 +113,17 @@ int config_file_parse(const char *filename, config_file_value_fn fn) return 0; if (!(f = fopen(filename, "r"))) return errno; + // Git's fopen refuses a directory only where its build defines + // FREAD_READS_DIRECTORIES, and elsewhere read(2) need not fail on one. + if (!fstat(fileno(f), &st) && S_ISDIR(st.st_mode)) { + fclose(f); + return EISDIR; + } config_origin.file = filename; lines_read = 0; nesting++; while (read_entry(f, &name, &value, &config_origin.line)) fn(name.buf, value.buf); - // A directory opens like a file and fails only once it is read. if (ferror(f)) err = errno; nesting--; -- cgit 2.12.1