From: opencoti Subject: [PATCH 0071] cosmocc state-IO open fix (bug-269) opencoti F5 M7 (#349, bug-269). Orthogonal to Rolling KV (0070) — captured as its own slot. Fixes ALL llama_state_*_save/load_file in the cosmocc/llamafile build, which were broken before this: llama.cpp/src/llama-mmap.cpp's COSMOCC llama_file constructor routed every open() through llamafile_open_gguf(), which pread()s the GGUF magic at offset 0 (EBADF on a write-only "wb" fd) and zip-routes any non-GGUF read; and write_raw's fwrite(fp) ran with fp==NULL. KV-state files are neither GGUF nor zip and are opened for write, so model load was unaffected but state save/load never worked through the binary (the M2 bug-222 "state round-trip" was thus never actually exercised end-to-end). FIX (cosmocc/host-only; no CUDA, no kernel): * vendors/sources/llamafile/llamafile/llamafile.{c,h} (Mozilla-Ocho llamafile, Apache-2.0): add llamafile_open_plain() — a plain fopen-backed handle with no GGUF magic probe and no zip routing, for non-model files. It delegates to the existing static llamafile_open_file(). * llama.cpp/src/llama-mmap.cpp: the COSMOCC llama_file ctor falls back to llamafile_open_plain() when llamafile_open_gguf() returns NULL (models are unaffected — they still open via the gguf path) and sets fp = llamafile_fp(lfile) so write_raw has a valid stream. Provenance: opencoti-original. Touches Mozilla-Ocho llamafile.{c,h} (Apache-2.0) and upstream llama.cpp llama-mmap.cpp. Applies after 0070 (independent file set — order immaterial); reverse-applies clean. diff --git a/llama.cpp/src/llama-mmap.cpp b/llama.cpp/src/llama-mmap.cpp --- a/llama.cpp/src/llama-mmap.cpp +++ b/llama.cpp/src/llama-mmap.cpp @@ -186,11 +186,25 @@ struct llama_file::impl { #else impl(const char * fname, const char * mode, [[maybe_unused]] const bool use_direct_io = false) : fname(fname) { #ifdef COSMOCC - // [llamafile] Use llamafile_open_gguf for all file opening + // [llamafile] Use llamafile_open_gguf for model files (raw .gguf, + // foo.zip@weights, /zip/ paths, and .llamafile archives via zip routing). lfile = llamafile_open_gguf(fname, mode); + // opencoti bug-269: llamafile_open_gguf is model-oriented — it pread()s the + // GGUF magic at offset 0 and routes non-GGUF files into a zip parser. KV + // state files (llama_state_*_save_file) are neither GGUF nor zip and are + // opened for write ("wb" → pread EBADF). Both made every state save/restore + // fail in the cosmocc build. When the model opener declines, fall back to a + // plain fopen-backed handle (model loads are unaffected — they succeed above). + if (lfile == NULL) { + lfile = llamafile_open_plain(fname, mode); + } if (lfile == NULL) { throw std::runtime_error(format("failed to open %s: %s", fname, strerror(errno))); } + // write_raw() writes via std::fwrite(fp); the cosmocc open path left fp NULL + // (read-only design). Expose the underlying FILE* so state-save writes land. + // Harmless for reads (read_raw_unsafe uses llamafile_read(lfile)). + fp = llamafile_fp(lfile); size = llamafile_size(lfile); return; #endif diff --git a/llamafile/llamafile.c b/llamafile/llamafile.c --- a/llamafile/llamafile.c +++ b/llamafile/llamafile.c @@ -318,6 +318,15 @@ struct llamafile *llamafile_open_gguf(const char *fname, const char *mode) { return llamafile_open_zip(fname, 0, mode); } +// opencoti bug-269: plain fopen-backed handle for non-model files (KV state +// save/load). llamafile_open_gguf() is model-oriented — it pread()s the GGUF +// magic at offset 0 (which fails EBADF on a write-only "wb" fd) and routes any +// non-GGUF file into a zip parser. State files are neither GGUF nor zip and are +// opened for write, so they need a path with no magic probe and no zip routing. +struct llamafile *llamafile_open_plain(const char *fname, const char *mode) { + return llamafile_open_file(fname, mode); +} + FILE *llamafile_fp(struct llamafile *file) { return file->fp; } diff --git a/llamafile/llamafile.h b/llamafile/llamafile.h --- a/llamafile/llamafile.h +++ b/llamafile/llamafile.h @@ -46,6 +46,9 @@ extern int FLAG_verbose; // Verbose output (chatbot_main.cpp, metal.c, cu struct llamafile; struct llamafile *llamafile_open_gguf(const char *, const char *); // UNUSED externally +// opencoti bug-269: plain fopen-backed handle (no GGUF magic probe, no zip +// routing) for non-model files such as KV state save/load. +struct llamafile *llamafile_open_plain(const char *, const char *); void llamafile_close(struct llamafile *); // UNUSED externally long llamafile_read(struct llamafile *, void *, size_t); // UNUSED externally long llamafile_write(struct llamafile *, const void *, size_t); // UNUSED externally